Fix markup, add index entries, make the DVI output prettier.
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
1c7e22fd 2 Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000
06a2c219 3 Free Software Foundation, Inc.
dc6f92b8
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4746118a 9the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
dc6f92b8 21
06a2c219 22/* New display code by Gerd Moellmann <gerd@gnu.org>. */
3afe33e7
RS
23/* Xt features made by Fred Pierresteguy. */
24
68c45bf0
PE
25#include <config.h>
26
039440c4 27/* On 4.3 these lose if they come after xterm.h. */
039440c4 28/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
29#include <signal.h>
30
4846819e
RS
31#include <stdio.h>
32
dc6f92b8
JB
33#ifdef HAVE_X_WINDOWS
34
35#include "lisp.h"
9ac0d9e0 36#include "blockinput.h"
dc6f92b8 37
ae79c227
AS
38/* Need syssignal.h for various externs and definitions that may be required
39 by some configurations for calls to signal later in this source file. */
40#include "syssignal.h"
41
dc6f92b8
JB
42/* This may include sys/types.h, and that somehow loses
43 if this is not done before the other system files. */
44#include "xterm.h"
f451eb13 45#include <X11/cursorfont.h>
dc6f92b8
JB
46
47/* Load sys/types.h if not already loaded.
48 In some systems loading it twice is suicidal. */
49#ifndef makedev
50#include <sys/types.h>
c118dd06 51#endif /* makedev */
dc6f92b8 52
6df54671 53#ifdef BSD_SYSTEM
dc6f92b8 54#include <sys/ioctl.h>
6df54671 55#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 56
2d368234 57#include "systty.h"
3a2712f9 58#include "systime.h"
dc6f92b8 59
b8009dd1 60#ifndef INCLUDED_FCNTL
dc6f92b8 61#include <fcntl.h>
b8009dd1 62#endif
dc6f92b8
JB
63#include <ctype.h>
64#include <errno.h>
65#include <setjmp.h>
66#include <sys/stat.h>
a0a7635f
RS
67/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
68/* #include <sys/param.h> */
dc6f92b8 69
dc43ef94 70#include "charset.h"
379b5ac0 71#include "coding.h"
dc43ef94 72#include "ccl.h"
7a13e894 73#include "frame.h"
dc6f92b8 74#include "dispextern.h"
ee569018 75#include "fontset.h"
dc6f92b8
JB
76#include "termhooks.h"
77#include "termopts.h"
78#include "termchar.h"
79#if 0
80#include "sink.h"
81#include "sinkmask.h"
c118dd06 82#endif /* ! 0 */
dc6f92b8 83#include "gnu.h"
dc6f92b8 84#include "disptab.h"
dc6f92b8 85#include "buffer.h"
f451eb13 86#include "window.h"
3b2fa4e6 87#include "keyboard.h"
bde7c500 88#include "intervals.h"
dfcf069d 89#include "process.h"
bffcfca9 90#include "atimer.h"
dc6f92b8 91
d2bd6bc4
RS
92#ifdef USE_X_TOOLKIT
93#include <X11/Shell.h>
94#endif
95
06a2c219
GM
96#ifdef HAVE_SYS_TIME_H
97#include <sys/time.h>
98#endif
99#ifdef HAVE_UNISTD_H
100#include <unistd.h>
101#endif
102
3afe33e7 103#ifdef USE_X_TOOLKIT
06a2c219 104
952291d9
GM
105extern void free_frame_menubar P_ ((struct frame *));
106extern struct frame *x_menubar_window_to_frame P_ ((struct x_display_info *,
107 int));
06a2c219 108
0fdff6bb
RS
109#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
110#define HACK_EDITRES
111extern void _XEditResCheckMessages ();
112#endif /* not NO_EDITRES */
06a2c219
GM
113
114/* Include toolkit specific headers for the scroll bar widget. */
115
116#ifdef USE_TOOLKIT_SCROLL_BARS
117#if defined USE_MOTIF
118#include <Xm/Xm.h> /* for LESSTIF_VERSION */
119#include <Xm/ScrollBar.h>
120#include <Xm/ScrollBarP.h>
ec18280f
SM
121#else /* !USE_MOTIF i.e. use Xaw */
122
123#ifdef HAVE_XAW3D
06a2c219 124#include <X11/Xaw3d/Simple.h>
06a2c219
GM
125#include <X11/Xaw3d/Scrollbar.h>
126#define ARROW_SCROLLBAR
127#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
128#else /* !HAVE_XAW3D */
129#include <X11/Xaw/Simple.h>
130#include <X11/Xaw/Scrollbar.h>
131#endif /* !HAVE_XAW3D */
132#ifndef XtNpickTop
133#define XtNpickTop "pickTop"
134#endif /* !XtNpickTop */
135#endif /* !USE_MOTIF */
06a2c219
GM
136#endif /* USE_TOOLKIT_SCROLL_BARS */
137
3afe33e7
RS
138#endif /* USE_X_TOOLKIT */
139
b849c413
RS
140#ifndef USE_X_TOOLKIT
141#define x_any_window_to_frame x_window_to_frame
5627c40e 142#define x_top_window_to_frame x_window_to_frame
b849c413
RS
143#endif
144
546e6d5b 145#ifdef USE_X_TOOLKIT
d067ea8b 146#include "widget.h"
546e6d5b
RS
147#ifndef XtNinitialState
148#define XtNinitialState "initialState"
149#endif
150#endif
151
e4b68333 152#ifndef min
06a2c219 153#define min(a,b) ((a) < (b) ? (a) : (b))
e4b68333
RS
154#endif
155#ifndef max
06a2c219
GM
156#define max(a,b) ((a) > (b) ? (a) : (b))
157#endif
158
159#define abs(x) ((x) < 0 ? -(x) : (x))
160
161#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
162
163\f
164/* Bitmaps for truncated lines. */
165
166enum bitmap_type
167{
168 NO_BITMAP,
169 LEFT_TRUNCATION_BITMAP,
170 RIGHT_TRUNCATION_BITMAP,
171 OVERLAY_ARROW_BITMAP,
172 CONTINUED_LINE_BITMAP,
173 CONTINUATION_LINE_BITMAP,
174 ZV_LINE_BITMAP
175};
176
177/* Bitmap drawn to indicate lines not displaying text if
178 `indicate-empty-lines' is non-nil. */
179
180#define zv_width 8
181#define zv_height 8
182static unsigned char zv_bits[] = {
183 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
184
185/* An arrow like this: `<-'. */
186
187#define left_width 8
188#define left_height 8
189static unsigned char left_bits[] = {
190 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
191
110859fc
GM
192/* Right truncation arrow bitmap `->'. */
193
194#define right_width 8
195#define right_height 8
196static unsigned char right_bits[] = {
197 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
198
06a2c219
GM
199/* Marker for continued lines. */
200
201#define continued_width 8
202#define continued_height 8
203static unsigned char continued_bits[] = {
110859fc
GM
204 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
205
206/* Marker for continuation lines. */
06a2c219
GM
207
208#define continuation_width 8
209#define continuation_height 8
210static unsigned char continuation_bits[] = {
110859fc 211 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 212
110859fc 213/* Overlay arrow bitmap. */
06a2c219 214
110859fc
GM
215#if 0
216/* A bomb. */
06a2c219
GM
217#define ov_width 8
218#define ov_height 8
219static unsigned char ov_bits[] = {
220 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 221#else
110859fc 222/* A triangular arrow. */
06a2c219
GM
223#define ov_width 8
224#define ov_height 8
225static unsigned char ov_bits[] = {
110859fc
GM
226 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
227
e4b68333 228#endif
06a2c219
GM
229
230extern Lisp_Object Qhelp_echo;
231
69388238 232\f
06a2c219
GM
233/* Non-zero means Emacs uses toolkit scroll bars. */
234
235int x_toolkit_scroll_bars_p;
236
237/* If a string, XTread_socket generates an event to display that string.
238 (The display is done in read_char.) */
239
240static Lisp_Object help_echo;
7cea38bc 241static Lisp_Object help_echo_window;
be010514
GM
242static Lisp_Object help_echo_object;
243static int help_echo_pos;
06a2c219
GM
244
245/* Temporary variable for XTread_socket. */
246
247static Lisp_Object previous_help_echo;
248
249/* Non-zero means that a HELP_EVENT has been generated since Emacs
250 start. */
251
252static int any_help_event_p;
253
254/* Non-zero means draw block and hollow cursor as wide as the glyph
255 under it. For example, if a block cursor is over a tab, it will be
256 drawn as wide as that tab on the display. */
257
258int x_stretch_cursor_p;
259
260/* This is a chain of structures for all the X displays currently in
261 use. */
262
334208b7 263struct x_display_info *x_display_list;
dc6f92b8 264
06a2c219
GM
265/* This is a list of cons cells, each of the form (NAME
266 . FONT-LIST-CACHE), one for each element of x_display_list and in
267 the same order. NAME is the name of the frame. FONT-LIST-CACHE
268 records previous values returned by x-list-fonts. */
269
7a13e894 270Lisp_Object x_display_name_list;
f451eb13 271
987d2ad1 272/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
273 This is set by update_begin and looked at by all the XT functions.
274 It is zero while not inside an update. In that case, the XT
275 functions assume that `selected_frame' is the frame to apply to. */
276
d0386f2a 277extern struct frame *updating_frame;
dc6f92b8 278
dfcf069d 279extern int waiting_for_input;
0e81d8cd 280
06a2c219
GM
281/* This is a frame waiting to be auto-raised, within XTread_socket. */
282
0134a210
RS
283struct frame *pending_autoraise_frame;
284
7f9c7f94
RS
285#ifdef USE_X_TOOLKIT
286/* The application context for Xt use. */
287XtAppContext Xt_app_con;
06a2c219
GM
288static String Xt_default_resources[] = {0};
289#endif /* USE_X_TOOLKIT */
665881ad 290
06a2c219
GM
291/* Nominal cursor position -- where to draw output.
292 HPOS and VPOS are window relative glyph matrix coordinates.
293 X and Y are window relative pixel coordinates. */
dc6f92b8 294
06a2c219 295struct cursor_pos output_cursor;
dc6f92b8 296
bffcfca9
GM
297/* Non-zero means user is interacting with a toolkit scroll bar. */
298
299static int toolkit_scroll_bar_interaction;
dc6f92b8 300
69388238
RS
301/* Mouse movement.
302
06a2c219 303 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
304 so that we would have to call XQueryPointer after each MotionNotify
305 event to ask for another such event. However, this made mouse tracking
306 slow, and there was a bug that made it eventually stop.
307
308 Simply asking for MotionNotify all the time seems to work better.
309
69388238
RS
310 In order to avoid asking for motion events and then throwing most
311 of them away or busy-polling the server for mouse positions, we ask
312 the server for pointer motion hints. This means that we get only
313 one event per group of mouse movements. "Groups" are delimited by
314 other kinds of events (focus changes and button clicks, for
315 example), or by XQueryPointer calls; when one of these happens, we
316 get another MotionNotify event the next time the mouse moves. This
317 is at least as efficient as getting motion events when mouse
318 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 319 is off. */
69388238
RS
320
321/* Where the mouse was last time we reported a mouse event. */
69388238 322
06a2c219
GM
323FRAME_PTR last_mouse_frame;
324static XRectangle last_mouse_glyph;
2237cac9
RS
325static Lisp_Object last_mouse_press_frame;
326
69388238
RS
327/* The scroll bar in which the last X motion event occurred.
328
06a2c219
GM
329 If the last X motion event occurred in a scroll bar, we set this so
330 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
331 an ordinary motion.
332
06a2c219
GM
333 If the last X motion event didn't occur in a scroll bar, we set
334 this to Qnil, to tell XTmouse_position to return an ordinary motion
335 event. */
336
69388238
RS
337static Lisp_Object last_mouse_scroll_bar;
338
69388238
RS
339/* This is a hack. We would really prefer that XTmouse_position would
340 return the time associated with the position it returns, but there
06a2c219 341 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
342 along with the position query. So, we just keep track of the time
343 of the last movement we received, and return that in hopes that
344 it's somewhat accurate. */
06a2c219 345
69388238
RS
346static Time last_mouse_movement_time;
347
06a2c219
GM
348/* Incremented by XTread_socket whenever it really tries to read
349 events. */
350
c0a04927
RS
351#ifdef __STDC__
352static int volatile input_signal_count;
353#else
354static int input_signal_count;
355#endif
356
7a13e894 357/* Used locally within XTread_socket. */
06a2c219 358
7a13e894 359static int x_noop_count;
dc6f92b8 360
7a13e894 361/* Initial values of argv and argc. */
06a2c219 362
7a13e894
RS
363extern char **initial_argv;
364extern int initial_argc;
dc6f92b8 365
7a13e894 366extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 367
06a2c219 368/* Tells if a window manager is present or not. */
7a13e894
RS
369
370extern Lisp_Object Vx_no_window_manager;
dc6f92b8 371
c2df547c 372extern Lisp_Object Qface, Qmouse_face;
b8009dd1 373
dc6f92b8
JB
374extern int errno;
375
dfeccd2d 376/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 377
64bb1782
RS
378extern int extra_keyboard_modifiers;
379
59e755be
KH
380static Lisp_Object Qvendor_specific_keysyms;
381
952291d9
GM
382extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
383extern Lisp_Object x_icon_type P_ ((struct frame *));
c32cdd9a 384
7a13e894 385
06a2c219
GM
386/* Enumeration for overriding/changing the face to use for drawing
387 glyphs in x_draw_glyphs. */
388
389enum draw_glyphs_face
390{
391 DRAW_NORMAL_TEXT,
392 DRAW_INVERSE_VIDEO,
393 DRAW_CURSOR,
394 DRAW_MOUSE_FACE,
395 DRAW_IMAGE_RAISED,
396 DRAW_IMAGE_SUNKEN
397};
398
f04e1297 399static const XColor *x_color_cells P_ ((struct frame *, int *));
71b8321e 400static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
401static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
402void x_delete_display P_ ((struct x_display_info *));
403static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
404 unsigned));
405static int fast_find_position P_ ((struct window *, int, int *, int *,
406 int *, int *));
407static void set_output_cursor P_ ((struct cursor_pos *));
408static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
409 int *, int *, int *));
410static void note_mode_line_highlight P_ ((struct window *, int, int));
06a2c219 411static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
412static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
413static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
414static void show_mouse_face P_ ((struct x_display_info *,
415 enum draw_glyphs_face));
416static int x_io_error_quitter P_ ((Display *));
417int x_catch_errors P_ ((Display *));
418void x_uncatch_errors P_ ((Display *, int));
419void x_lower_frame P_ ((struct frame *));
420void x_scroll_bar_clear P_ ((struct frame *));
421int x_had_errors_p P_ ((Display *));
422void x_wm_set_size_hint P_ ((struct frame *, long, int));
423void x_raise_frame P_ ((struct frame *));
424void x_set_window_size P_ ((struct frame *, int, int, int));
425void x_wm_set_window_state P_ ((struct frame *, int));
426void x_wm_set_icon_pixmap P_ ((struct frame *, int));
427void x_initialize P_ ((void));
428static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
429static int x_compute_min_glyph_bounds P_ ((struct frame *));
430static void x_draw_phys_cursor_glyph P_ ((struct window *,
431 struct glyph_row *,
432 enum draw_glyphs_face));
433static void x_update_end P_ ((struct frame *));
434static void XTframe_up_to_date P_ ((struct frame *));
435static void XTreassert_line_highlight P_ ((int, int));
436static void x_change_line_highlight P_ ((int, int, int, int));
437static void XTset_terminal_modes P_ ((void));
438static void XTreset_terminal_modes P_ ((void));
439static void XTcursor_to P_ ((int, int, int, int));
440static void x_write_glyphs P_ ((struct glyph *, int));
441static void x_clear_end_of_line P_ ((int));
442static void x_clear_frame P_ ((void));
443static void x_clear_cursor P_ ((struct window *));
444static void frame_highlight P_ ((struct frame *));
445static void frame_unhighlight P_ ((struct frame *));
446static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
447static void XTframe_rehighlight P_ ((struct frame *));
448static void x_frame_rehighlight P_ ((struct x_display_info *));
449static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 450static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
451static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
452 XRectangle *));
453static void expose_frame P_ ((struct frame *, int, int, int, int));
454static void expose_window_tree P_ ((struct window *, XRectangle *));
455static void expose_window P_ ((struct window *, XRectangle *));
456static void expose_area P_ ((struct window *, struct glyph_row *,
457 XRectangle *, enum glyph_row_area));
458static void expose_line P_ ((struct window *, struct glyph_row *,
459 XRectangle *));
460static void x_update_cursor_in_window_tree P_ ((struct window *, int));
461static void x_update_window_cursor P_ ((struct window *, int));
462static void x_erase_phys_cursor P_ ((struct window *));
463void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
464static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
465 enum bitmap_type));
466
467static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
468 GC, int));
469static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
470static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
471static void note_overwritten_text_cursor P_ ((struct window *, int, int));
472static void x_flush P_ ((struct frame *f));
952291d9
GM
473static void x_update_begin P_ ((struct frame *));
474static void x_update_window_begin P_ ((struct window *));
475static void x_draw_vertical_border P_ ((struct window *));
476static void x_after_update_window_line P_ ((struct glyph_row *));
477static INLINE void take_vertical_position_into_account P_ ((struct it *));
478static void x_produce_stretch_glyph P_ ((struct it *));
479
06a2c219
GM
480
481/* Flush display of frame F, or of all frames if F is null. */
482
483static void
484x_flush (f)
485 struct frame *f;
486{
487 BLOCK_INPUT;
488 if (f == NULL)
489 {
490 Lisp_Object rest, frame;
491 FOR_EACH_FRAME (rest, frame)
492 x_flush (XFRAME (frame));
493 }
494 else if (FRAME_X_P (f))
495 XFlush (FRAME_X_DISPLAY (f));
496 UNBLOCK_INPUT;
497}
498
dc6f92b8 499
06a2c219
GM
500/* Remove calls to XFlush by defining XFlush to an empty replacement.
501 Calls to XFlush should be unnecessary because the X output buffer
502 is flushed automatically as needed by calls to XPending,
503 XNextEvent, or XWindowEvent according to the XFlush man page.
504 XTread_socket calls XPending. Removing XFlush improves
505 performance. */
506
507#define XFlush(DISPLAY) (void) 0
b8009dd1 508
334208b7 509\f
06a2c219
GM
510/***********************************************************************
511 Debugging
512 ***********************************************************************/
513
9382638d 514#if 0
06a2c219
GM
515
516/* This is a function useful for recording debugging information about
517 the sequence of occurrences in this file. */
9382638d
KH
518
519struct record
520{
521 char *locus;
522 int type;
523};
524
525struct record event_record[100];
526
527int event_record_index;
528
529record_event (locus, type)
530 char *locus;
531 int type;
532{
533 if (event_record_index == sizeof (event_record) / sizeof (struct record))
534 event_record_index = 0;
535
536 event_record[event_record_index].locus = locus;
537 event_record[event_record_index].type = type;
538 event_record_index++;
539}
540
541#endif /* 0 */
06a2c219
GM
542
543
9382638d 544\f
334208b7
RS
545/* Return the struct x_display_info corresponding to DPY. */
546
547struct x_display_info *
548x_display_info_for_display (dpy)
549 Display *dpy;
550{
551 struct x_display_info *dpyinfo;
552
553 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
554 if (dpyinfo->display == dpy)
555 return dpyinfo;
16bd92ea 556
334208b7
RS
557 return 0;
558}
f451eb13 559
06a2c219
GM
560
561\f
562/***********************************************************************
563 Starting and ending an update
564 ***********************************************************************/
565
566/* Start an update of frame F. This function is installed as a hook
567 for update_begin, i.e. it is called when update_begin is called.
568 This function is called prior to calls to x_update_window_begin for
569 each window being updated. Currently, there is nothing to do here
570 because all interesting stuff is done on a window basis. */
dc6f92b8 571
dfcf069d 572static void
06a2c219 573x_update_begin (f)
f676886a 574 struct frame *f;
58769bee 575{
06a2c219
GM
576 /* Nothing to do. */
577}
dc6f92b8 578
dc6f92b8 579
06a2c219
GM
580/* Start update of window W. Set the global variable updated_window
581 to the window being updated and set output_cursor to the cursor
582 position of W. */
dc6f92b8 583
06a2c219
GM
584static void
585x_update_window_begin (w)
586 struct window *w;
587{
588 struct frame *f = XFRAME (WINDOW_FRAME (w));
589 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
590
591 updated_window = w;
592 set_output_cursor (&w->cursor);
b8009dd1 593
06a2c219 594 BLOCK_INPUT;
d1bc4182 595
06a2c219 596 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 597 {
514e4681 598 /* Don't do highlighting for mouse motion during the update. */
06a2c219 599 display_info->mouse_face_defer = 1;
37c2c98b 600
06a2c219
GM
601 /* If F needs to be redrawn, simply forget about any prior mouse
602 highlighting. */
9f67f20b 603 if (FRAME_GARBAGED_P (f))
06a2c219
GM
604 display_info->mouse_face_window = Qnil;
605
64f26cf5
GM
606#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
607 their mouse_face_p flag set, which means that they are always
608 unequal to rows in a desired matrix which never have that
609 flag set. So, rows containing mouse-face glyphs are never
610 scrolled, and we don't have to switch the mouse highlight off
611 here to prevent it from being scrolled. */
612
06a2c219
GM
613 /* Can we tell that this update does not affect the window
614 where the mouse highlight is? If so, no need to turn off.
615 Likewise, don't do anything if the frame is garbaged;
616 in that case, the frame's current matrix that we would use
617 is all wrong, and we will redisplay that line anyway. */
618 if (!NILP (display_info->mouse_face_window)
619 && w == XWINDOW (display_info->mouse_face_window))
514e4681 620 {
06a2c219 621 int i;
514e4681 622
06a2c219
GM
623 for (i = 0; i < w->desired_matrix->nrows; ++i)
624 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
625 break;
626
06a2c219
GM
627 if (i < w->desired_matrix->nrows)
628 clear_mouse_face (display_info);
514e4681 629 }
64f26cf5 630#endif /* 0 */
b8009dd1 631 }
6ccf47d1 632
dc6f92b8
JB
633 UNBLOCK_INPUT;
634}
635
06a2c219
GM
636
637/* Draw a vertical window border to the right of window W if W doesn't
638 have vertical scroll bars. */
639
dfcf069d 640static void
06a2c219
GM
641x_draw_vertical_border (w)
642 struct window *w;
58769bee 643{
06a2c219
GM
644 struct frame *f = XFRAME (WINDOW_FRAME (w));
645
646 /* Redraw borders between horizontally adjacent windows. Don't
647 do it for frames with vertical scroll bars because either the
648 right scroll bar of a window, or the left scroll bar of its
649 neighbor will suffice as a border. */
650 if (!WINDOW_RIGHTMOST_P (w)
651 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
652 {
653 int x0, x1, y0, y1;
dc6f92b8 654
06a2c219 655 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 656 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
657 y1 -= 1;
658
659 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
660 f->output_data.x->normal_gc, x1, y0, x1, y1);
661 }
662}
663
664
71b8321e
GM
665/* End update of window W (which is equal to updated_window).
666
667 Draw vertical borders between horizontally adjacent windows, and
668 display W's cursor if CURSOR_ON_P is non-zero.
669
670 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
671 glyphs in mouse-face were overwritten. In that case we have to
672 make sure that the mouse-highlight is properly redrawn.
673
674 W may be a menu bar pseudo-window in case we don't have X toolkit
675 support. Such windows don't have a cursor, so don't display it
676 here. */
06a2c219
GM
677
678static void
71b8321e 679x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 680 struct window *w;
71b8321e 681 int cursor_on_p, mouse_face_overwritten_p;
06a2c219
GM
682{
683 if (!w->pseudo_window_p)
684 {
71b8321e
GM
685 struct x_display_info *dpyinfo
686 = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
687
06a2c219 688 BLOCK_INPUT;
71b8321e
GM
689
690 /* If a row with mouse-face was overwritten, arrange for
691 XTframe_up_to_date to redisplay the mouse highlight. */
692 if (mouse_face_overwritten_p)
693 {
694 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
695 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
696 dpyinfo->mouse_face_window = Qnil;
697 }
698
06a2c219
GM
699 if (cursor_on_p)
700 x_display_and_set_cursor (w, 1, output_cursor.hpos,
701 output_cursor.vpos,
702 output_cursor.x, output_cursor.y);
71b8321e 703
06a2c219
GM
704 x_draw_vertical_border (w);
705 UNBLOCK_INPUT;
706 }
707
708 updated_window = NULL;
709}
dc6f92b8 710
dc6f92b8 711
06a2c219
GM
712/* End update of frame F. This function is installed as a hook in
713 update_end. */
714
715static void
716x_update_end (f)
717 struct frame *f;
718{
719 /* Mouse highlight may be displayed again. */
aa8bff2e 720 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 721
06a2c219 722 BLOCK_INPUT;
334208b7 723 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
724 UNBLOCK_INPUT;
725}
b8009dd1 726
06a2c219
GM
727
728/* This function is called from various places in xdisp.c whenever a
729 complete update has been performed. The global variable
730 updated_window is not available here. */
b8009dd1 731
dfcf069d 732static void
b8009dd1 733XTframe_up_to_date (f)
06a2c219 734 struct frame *f;
b8009dd1 735{
06a2c219 736 if (FRAME_X_P (f))
514e4681 737 {
06a2c219 738 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 739
06a2c219
GM
740 if (dpyinfo->mouse_face_deferred_gc
741 || f == dpyinfo->mouse_face_mouse_frame)
742 {
743 BLOCK_INPUT;
744 if (dpyinfo->mouse_face_mouse_frame)
745 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
746 dpyinfo->mouse_face_mouse_x,
747 dpyinfo->mouse_face_mouse_y);
748 dpyinfo->mouse_face_deferred_gc = 0;
749 UNBLOCK_INPUT;
750 }
514e4681 751 }
b8009dd1 752}
06a2c219
GM
753
754
755/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
756 arrow bitmaps, or clear the areas where they would be displayed
757 before DESIRED_ROW is made current. The window being updated is
758 found in updated_window. This function It is called from
759 update_window_line only if it is known that there are differences
760 between bitmaps to be drawn between current row and DESIRED_ROW. */
761
762static void
763x_after_update_window_line (desired_row)
764 struct glyph_row *desired_row;
765{
766 struct window *w = updated_window;
767
768 xassert (w);
769
770 if (!desired_row->mode_line_p && !w->pseudo_window_p)
771 {
772 BLOCK_INPUT;
773 x_draw_row_bitmaps (w, desired_row);
774
775 /* When a window has disappeared, make sure that no rest of
776 full-width rows stays visible in the internal border. */
777 if (windows_or_buffers_changed)
778 {
779 struct frame *f = XFRAME (w->frame);
780 int width = FRAME_INTERNAL_BORDER_WIDTH (f);
781 int height = desired_row->visible_height;
110859fc
GM
782 int x = (window_box_right (w, -1)
783 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
784 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
785
786 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
787 x, y, width, height, False);
788 }
789
790 UNBLOCK_INPUT;
791 }
792}
793
794
795/* Draw the bitmap WHICH in one of the areas to the left or right of
796 window W. ROW is the glyph row for which to display the bitmap; it
797 determines the vertical position at which the bitmap has to be
798 drawn. */
799
800static void
801x_draw_bitmap (w, row, which)
802 struct window *w;
803 struct glyph_row *row;
804 enum bitmap_type which;
805{
806 struct frame *f = XFRAME (WINDOW_FRAME (w));
807 Display *display = FRAME_X_DISPLAY (f);
808 Window window = FRAME_X_WINDOW (f);
809 int x, y, wd, h, dy;
810 unsigned char *bits;
811 Pixmap pixmap;
812 GC gc = f->output_data.x->normal_gc;
813 struct face *face;
814 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
815
816 /* Must clip because of partially visible lines. */
817 x_clip_to_row (w, row, gc, 1);
818
819 switch (which)
820 {
821 case LEFT_TRUNCATION_BITMAP:
822 wd = left_width;
823 h = left_height;
824 bits = left_bits;
825 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
826 - wd
110859fc 827 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
828 break;
829
830 case OVERLAY_ARROW_BITMAP:
831 wd = left_width;
832 h = left_height;
833 bits = ov_bits;
834 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
835 - wd
110859fc 836 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
837 break;
838
839 case RIGHT_TRUNCATION_BITMAP:
840 wd = right_width;
841 h = right_height;
842 bits = right_bits;
843 x = window_box_right (w, -1);
110859fc 844 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
845 break;
846
847 case CONTINUED_LINE_BITMAP:
848 wd = right_width;
849 h = right_height;
850 bits = continued_bits;
851 x = window_box_right (w, -1);
110859fc 852 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
853 break;
854
855 case CONTINUATION_LINE_BITMAP:
856 wd = continuation_width;
857 h = continuation_height;
858 bits = continuation_bits;
859 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
860 - wd
110859fc 861 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
862 break;
863
864 case ZV_LINE_BITMAP:
865 wd = zv_width;
866 h = zv_height;
867 bits = zv_bits;
868 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
869 - wd
110859fc 870 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
871 break;
872
873 default:
874 abort ();
875 }
876
877 /* Convert to frame coordinates. Set dy to the offset in the row to
878 start drawing the bitmap. */
879 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
880 dy = (row->height - h) / 2;
881
882 /* Draw the bitmap. I believe these small pixmaps can be cached
883 by the server. */
884 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
885 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
886 face->foreground,
887 face->background, depth);
888 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
889 XFreePixmap (display, pixmap);
890 XSetClipMask (display, gc, None);
891}
892
893
894/* Draw flags bitmaps for glyph row ROW on window W. Call this
895 function with input blocked. */
896
897static void
898x_draw_row_bitmaps (w, row)
899 struct window *w;
900 struct glyph_row *row;
901{
902 struct frame *f = XFRAME (w->frame);
903 enum bitmap_type bitmap;
904 struct face *face;
045dee35 905 int header_line_height = -1;
06a2c219
GM
906
907 xassert (interrupt_input_blocked);
908
909 /* If row is completely invisible, because of vscrolling, we
910 don't have to draw anything. */
911 if (row->visible_height <= 0)
912 return;
913
914 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
915 PREPARE_FACE_FOR_DISPLAY (f, face);
916
917 /* Decide which bitmap to draw at the left side. */
918 if (row->overlay_arrow_p)
919 bitmap = OVERLAY_ARROW_BITMAP;
920 else if (row->truncated_on_left_p)
921 bitmap = LEFT_TRUNCATION_BITMAP;
922 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
923 bitmap = CONTINUATION_LINE_BITMAP;
924 else if (row->indicate_empty_line_p)
925 bitmap = ZV_LINE_BITMAP;
926 else
927 bitmap = NO_BITMAP;
928
929 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
930 the flags area. */
931 if (bitmap == NO_BITMAP
110859fc 932 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
933 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
934 {
935 /* If W has a vertical border to its left, don't draw over it. */
936 int border = ((XFASTINT (w->left) > 0
937 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
938 ? 1 : 0);
939 int left = window_box_left (w, -1);
940
045dee35
GM
941 if (header_line_height < 0)
942 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
943
944 /* In case the same realized face is used for bitmap areas and
945 for something displayed in the text (e.g. face `region' on
946 mono-displays, the fill style may have been changed to
947 FillSolid in x_draw_glyph_string_background. */
948 if (face->stipple)
949 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
950 else
951 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
952
06a2c219
GM
953 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
954 face->gc,
955 (left
110859fc 956 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 957 + border),
045dee35 958 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 959 row->y)),
110859fc 960 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 961 row->visible_height);
dcd08bfb
GM
962 if (!face->stipple)
963 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
964 }
965
966 /* Draw the left bitmap. */
967 if (bitmap != NO_BITMAP)
968 x_draw_bitmap (w, row, bitmap);
969
970 /* Decide which bitmap to draw at the right side. */
971 if (row->truncated_on_right_p)
972 bitmap = RIGHT_TRUNCATION_BITMAP;
973 else if (row->continued_p)
974 bitmap = CONTINUED_LINE_BITMAP;
975 else
976 bitmap = NO_BITMAP;
977
978 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
979 the flags area. */
980 if (bitmap == NO_BITMAP
110859fc 981 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
982 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
983 {
984 int right = window_box_right (w, -1);
985
045dee35
GM
986 if (header_line_height < 0)
987 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
988
989 /* In case the same realized face is used for bitmap areas and
990 for something displayed in the text (e.g. face `region' on
991 mono-displays, the fill style may have been changed to
992 FillSolid in x_draw_glyph_string_background. */
993 if (face->stipple)
994 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
995 else
996 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
997 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
998 face->gc,
999 right,
045dee35 1000 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 1001 row->y)),
110859fc 1002 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 1003 row->visible_height);
dcd08bfb
GM
1004 if (!face->stipple)
1005 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
1006 }
1007
1008 /* Draw the right bitmap. */
1009 if (bitmap != NO_BITMAP)
1010 x_draw_bitmap (w, row, bitmap);
1011}
1012
dc6f92b8 1013\f
06a2c219
GM
1014/***********************************************************************
1015 Line Highlighting
1016 ***********************************************************************/
dc6f92b8 1017
06a2c219
GM
1018/* External interface to control of standout mode. Not used for X
1019 frames. Aborts when called. */
1020
1021static void
dc6f92b8
JB
1022XTreassert_line_highlight (new, vpos)
1023 int new, vpos;
1024{
06a2c219 1025 abort ();
dc6f92b8
JB
1026}
1027
06a2c219
GM
1028
1029/* Call this when about to modify line at position VPOS and change
1030 whether it is highlighted. Not used for X frames. Aborts when
1031 called. */
dc6f92b8 1032
dfcf069d 1033static void
06a2c219
GM
1034x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1035 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1036{
06a2c219 1037 abort ();
dc6f92b8
JB
1038}
1039
06a2c219
GM
1040
1041/* This is called when starting Emacs and when restarting after
1042 suspend. When starting Emacs, no X window is mapped. And nothing
1043 must be done to Emacs's own window if it is suspended (though that
1044 rarely happens). */
dc6f92b8 1045
dfcf069d 1046static void
dc6f92b8
JB
1047XTset_terminal_modes ()
1048{
1049}
1050
06a2c219
GM
1051/* This is called when exiting or suspending Emacs. Exiting will make
1052 the X-windows go away, and suspending requires no action. */
dc6f92b8 1053
dfcf069d 1054static void
dc6f92b8
JB
1055XTreset_terminal_modes ()
1056{
dc6f92b8 1057}
06a2c219
GM
1058
1059
dc6f92b8 1060\f
06a2c219
GM
1061/***********************************************************************
1062 Output Cursor
1063 ***********************************************************************/
1064
1065/* Set the global variable output_cursor to CURSOR. All cursor
1066 positions are relative to updated_window. */
dc6f92b8 1067
dfcf069d 1068static void
06a2c219
GM
1069set_output_cursor (cursor)
1070 struct cursor_pos *cursor;
dc6f92b8 1071{
06a2c219
GM
1072 output_cursor.hpos = cursor->hpos;
1073 output_cursor.vpos = cursor->vpos;
1074 output_cursor.x = cursor->x;
1075 output_cursor.y = cursor->y;
1076}
1077
1078
1079/* Set a nominal cursor position.
dc6f92b8 1080
06a2c219
GM
1081 HPOS and VPOS are column/row positions in a window glyph matrix. X
1082 and Y are window text area relative pixel positions.
1083
1084 If this is done during an update, updated_window will contain the
1085 window that is being updated and the position is the future output
1086 cursor position for that window. If updated_window is null, use
1087 selected_window and display the cursor at the given position. */
1088
1089static void
1090XTcursor_to (vpos, hpos, y, x)
1091 int vpos, hpos, y, x;
1092{
1093 struct window *w;
1094
1095 /* If updated_window is not set, work on selected_window. */
1096 if (updated_window)
1097 w = updated_window;
1098 else
1099 w = XWINDOW (selected_window);
dbcb258a 1100
06a2c219
GM
1101 /* Set the output cursor. */
1102 output_cursor.hpos = hpos;
1103 output_cursor.vpos = vpos;
1104 output_cursor.x = x;
1105 output_cursor.y = y;
dc6f92b8 1106
06a2c219
GM
1107 /* If not called as part of an update, really display the cursor.
1108 This will also set the cursor position of W. */
1109 if (updated_window == NULL)
dc6f92b8
JB
1110 {
1111 BLOCK_INPUT;
06a2c219 1112 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1113 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1114 UNBLOCK_INPUT;
1115 }
1116}
dc43ef94 1117
06a2c219
GM
1118
1119\f
1120/***********************************************************************
1121 Display Iterator
1122 ***********************************************************************/
1123
1124/* Function prototypes of this page. */
1125
1126static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1127 struct glyph *,
ee569018
KH
1128 XChar2b *,
1129 int *));
06a2c219
GM
1130static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1131 int, XChar2b *, int));
1132static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1133static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1134static void x_append_glyph P_ ((struct it *));
b4192550 1135static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1136static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1137 int, int, double));
1138static void x_produce_glyphs P_ ((struct it *));
06a2c219 1139static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1140
1141
1142/* Return a pointer to per-char metric information in FONT of a
1143 character pointed by B which is a pointer to an XChar2b. */
1144
1145#define PER_CHAR_METRIC(font, b) \
1146 ((font)->per_char \
1147 ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
1148 + (((font)->min_byte1 || (font)->max_byte1) \
1149 ? (((b)->byte1 - (font)->min_byte1) \
1150 * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
1151 : 0)) \
1152 : &((font)->max_bounds))
dc43ef94 1153
dc6f92b8 1154
e2ef8ee6
GM
1155/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1156 is not contained in the font. */
dc43ef94 1157
06a2c219 1158static INLINE XCharStruct *
ee569018 1159x_per_char_metric (font, char2b)
06a2c219
GM
1160 XFontStruct *font;
1161 XChar2b *char2b;
1162{
1163 /* The result metric information. */
1164 XCharStruct *pcm = NULL;
dc6f92b8 1165
06a2c219 1166 xassert (font && char2b);
dc6f92b8 1167
06a2c219 1168 if (font->per_char != NULL)
dc6f92b8 1169 {
06a2c219 1170 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1171 {
06a2c219
GM
1172 /* min_char_or_byte2 specifies the linear character index
1173 corresponding to the first element of the per_char array,
1174 max_char_or_byte2 is the index of the last character. A
1175 character with non-zero CHAR2B->byte1 is not in the font.
1176 A character with byte2 less than min_char_or_byte2 or
1177 greater max_char_or_byte2 is not in the font. */
1178 if (char2b->byte1 == 0
1179 && char2b->byte2 >= font->min_char_or_byte2
1180 && char2b->byte2 <= font->max_char_or_byte2)
1181 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1182 }
06a2c219 1183 else
dc6f92b8 1184 {
06a2c219
GM
1185 /* If either min_byte1 or max_byte1 are nonzero, both
1186 min_char_or_byte2 and max_char_or_byte2 are less than
1187 256, and the 2-byte character index values corresponding
1188 to the per_char array element N (counting from 0) are:
1189
1190 byte1 = N/D + min_byte1
1191 byte2 = N\D + min_char_or_byte2
1192
1193 where:
1194
1195 D = max_char_or_byte2 - min_char_or_byte2 + 1
1196 / = integer division
1197 \ = integer modulus */
1198 if (char2b->byte1 >= font->min_byte1
1199 && char2b->byte1 <= font->max_byte1
1200 && char2b->byte2 >= font->min_char_or_byte2
1201 && char2b->byte2 <= font->max_char_or_byte2)
1202 {
1203 pcm = (font->per_char
1204 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1205 * (char2b->byte1 - font->min_byte1))
1206 + (char2b->byte2 - font->min_char_or_byte2));
1207 }
dc6f92b8 1208 }
06a2c219
GM
1209 }
1210 else
1211 {
1212 /* If the per_char pointer is null, all glyphs between the first
1213 and last character indexes inclusive have the same
1214 information, as given by both min_bounds and max_bounds. */
1215 if (char2b->byte2 >= font->min_char_or_byte2
1216 && char2b->byte2 <= font->max_char_or_byte2)
1217 pcm = &font->max_bounds;
1218 }
dc6f92b8 1219
ee569018 1220 return ((pcm == NULL
3e71d8f2 1221 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1222 ? NULL : pcm);
06a2c219 1223}
b73b6aaf 1224
57b03282 1225
06a2c219
GM
1226/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1227 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1228
06a2c219
GM
1229static INLINE void
1230x_encode_char (c, char2b, font_info)
1231 int c;
1232 XChar2b *char2b;
1233 struct font_info *font_info;
1234{
1235 int charset = CHAR_CHARSET (c);
1236 XFontStruct *font = font_info->font;
1237
1238 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1239 This may be either a program in a special encoder language or a
1240 fixed encoding. */
1241 if (font_info->font_encoder)
1242 {
1243 /* It's a program. */
1244 struct ccl_program *ccl = font_info->font_encoder;
1245
1246 if (CHARSET_DIMENSION (charset) == 1)
1247 {
1248 ccl->reg[0] = charset;
1249 ccl->reg[1] = char2b->byte2;
1250 }
1251 else
1252 {
1253 ccl->reg[0] = charset;
1254 ccl->reg[1] = char2b->byte1;
1255 ccl->reg[2] = char2b->byte2;
1256 }
1257
1258 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1259
1260 /* We assume that MSBs are appropriately set/reset by CCL
1261 program. */
1262 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1263 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1264 else
1265 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1266 }
1267 else if (font_info->encoding[charset])
1268 {
1269 /* Fixed encoding scheme. See fontset.h for the meaning of the
1270 encoding numbers. */
1271 int enc = font_info->encoding[charset];
1272
1273 if ((enc == 1 || enc == 2)
1274 && CHARSET_DIMENSION (charset) == 2)
1275 char2b->byte1 |= 0x80;
1276
1277 if (enc == 1 || enc == 3)
1278 char2b->byte2 |= 0x80;
1279 }
1280}
1281
1282
1283/* Get face and two-byte form of character C in face FACE_ID on frame
1284 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1285 means we want to display multibyte text. Value is a pointer to a
1286 realized face that is ready for display. */
1287
1288static INLINE struct face *
1289x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1290 struct frame *f;
1291 int c, face_id;
1292 XChar2b *char2b;
1293 int multibyte_p;
1294{
1295 struct face *face = FACE_FROM_ID (f, face_id);
1296
1297 if (!multibyte_p)
1298 {
1299 /* Unibyte case. We don't have to encode, but we have to make
1300 sure to use a face suitable for unibyte. */
1301 char2b->byte1 = 0;
1302 char2b->byte2 = c;
ee569018
KH
1303 face_id = FACE_FOR_CHAR (f, face, c);
1304 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1305 }
1306 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1307 {
1308 /* Case of ASCII in a face known to fit ASCII. */
1309 char2b->byte1 = 0;
1310 char2b->byte2 = c;
1311 }
1312 else
1313 {
1314 int c1, c2, charset;
1315
1316 /* Split characters into bytes. If c2 is -1 afterwards, C is
1317 really a one-byte character so that byte1 is zero. */
1318 SPLIT_CHAR (c, charset, c1, c2);
1319 if (c2 > 0)
1320 char2b->byte1 = c1, char2b->byte2 = c2;
1321 else
1322 char2b->byte1 = 0, char2b->byte2 = c1;
1323
06a2c219 1324 /* Maybe encode the character in *CHAR2B. */
ee569018 1325 if (face->font != NULL)
06a2c219
GM
1326 {
1327 struct font_info *font_info
1328 = FONT_INFO_FROM_ID (f, face->font_info_id);
1329 if (font_info)
ee569018 1330 x_encode_char (c, char2b, font_info);
06a2c219
GM
1331 }
1332 }
1333
1334 /* Make sure X resources of the face are allocated. */
1335 xassert (face != NULL);
1336 PREPARE_FACE_FOR_DISPLAY (f, face);
1337
1338 return face;
1339}
1340
1341
1342/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1343 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1344 a pointer to a realized face that is ready for display. */
1345
1346static INLINE struct face *
ee569018 1347x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1348 struct frame *f;
1349 struct glyph *glyph;
1350 XChar2b *char2b;
ee569018 1351 int *two_byte_p;
06a2c219
GM
1352{
1353 struct face *face;
1354
1355 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1356 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1357
ee569018
KH
1358 if (two_byte_p)
1359 *two_byte_p = 0;
1360
06a2c219
GM
1361 if (!glyph->multibyte_p)
1362 {
1363 /* Unibyte case. We don't have to encode, but we have to make
1364 sure to use a face suitable for unibyte. */
1365 char2b->byte1 = 0;
43d120d8 1366 char2b->byte2 = glyph->u.ch;
06a2c219 1367 }
43d120d8
KH
1368 else if (glyph->u.ch < 128
1369 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1370 {
1371 /* Case of ASCII in a face known to fit ASCII. */
1372 char2b->byte1 = 0;
43d120d8 1373 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1374 }
1375 else
1376 {
1377 int c1, c2, charset;
1378
1379 /* Split characters into bytes. If c2 is -1 afterwards, C is
1380 really a one-byte character so that byte1 is zero. */
43d120d8 1381 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1382 if (c2 > 0)
1383 char2b->byte1 = c1, char2b->byte2 = c2;
1384 else
1385 char2b->byte1 = 0, char2b->byte2 = c1;
1386
1387 /* Maybe encode the character in *CHAR2B. */
1388 if (charset != CHARSET_ASCII)
1389 {
1390 struct font_info *font_info
1391 = FONT_INFO_FROM_ID (f, face->font_info_id);
1392 if (font_info)
1393 {
43d120d8 1394 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1395 if (two_byte_p)
1396 *two_byte_p
1397 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1398 }
1399 }
1400 }
1401
1402 /* Make sure X resources of the face are allocated. */
1403 xassert (face != NULL);
1404 PREPARE_FACE_FOR_DISPLAY (f, face);
1405 return face;
1406}
1407
1408
1409/* Store one glyph for IT->char_to_display in IT->glyph_row.
1410 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1411
1412static INLINE void
1413x_append_glyph (it)
1414 struct it *it;
1415{
1416 struct glyph *glyph;
1417 enum glyph_row_area area = it->area;
1418
1419 xassert (it->glyph_row);
1420 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1421
1422 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1423 if (glyph < it->glyph_row->glyphs[area + 1])
1424 {
06a2c219
GM
1425 glyph->charpos = CHARPOS (it->position);
1426 glyph->object = it->object;
88d75730 1427 glyph->pixel_width = it->pixel_width;
06a2c219 1428 glyph->voffset = it->voffset;
88d75730 1429 glyph->type = CHAR_GLYPH;
06a2c219 1430 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1431 glyph->left_box_line_p = it->start_of_box_run_p;
1432 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1433 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1434 || it->phys_descent > it->descent);
88d75730 1435 glyph->padding_p = 0;
ee569018 1436 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1437 glyph->face_id = it->face_id;
1438 glyph->u.ch = it->char_to_display;
06a2c219
GM
1439 ++it->glyph_row->used[area];
1440 }
1441}
1442
b4192550
KH
1443/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1444 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1445
1446static INLINE void
1447x_append_composite_glyph (it)
1448 struct it *it;
1449{
1450 struct glyph *glyph;
1451 enum glyph_row_area area = it->area;
1452
1453 xassert (it->glyph_row);
1454
1455 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1456 if (glyph < it->glyph_row->glyphs[area + 1])
1457 {
b4192550
KH
1458 glyph->charpos = CHARPOS (it->position);
1459 glyph->object = it->object;
88d75730 1460 glyph->pixel_width = it->pixel_width;
b4192550 1461 glyph->voffset = it->voffset;
88d75730 1462 glyph->type = COMPOSITE_GLYPH;
b4192550 1463 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1464 glyph->left_box_line_p = it->start_of_box_run_p;
1465 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1466 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1467 || it->phys_descent > it->descent);
88d75730
GM
1468 glyph->padding_p = 0;
1469 glyph->glyph_not_available_p = 0;
1470 glyph->face_id = it->face_id;
1471 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1472 ++it->glyph_row->used[area];
1473 }
1474}
1475
06a2c219
GM
1476
1477/* Change IT->ascent and IT->height according to the setting of
1478 IT->voffset. */
1479
1480static INLINE void
1481take_vertical_position_into_account (it)
1482 struct it *it;
1483{
1484 if (it->voffset)
1485 {
1486 if (it->voffset < 0)
1487 /* Increase the ascent so that we can display the text higher
1488 in the line. */
1489 it->ascent += abs (it->voffset);
1490 else
1491 /* Increase the descent so that we can display the text lower
1492 in the line. */
1493 it->descent += it->voffset;
1494 }
1495}
1496
1497
1498/* Produce glyphs/get display metrics for the image IT is loaded with.
1499 See the description of struct display_iterator in dispextern.h for
1500 an overview of struct display_iterator. */
1501
1502static void
1503x_produce_image_glyph (it)
1504 struct it *it;
1505{
1506 struct image *img;
1507 struct face *face;
1508
1509 xassert (it->what == IT_IMAGE);
1510
1511 face = FACE_FROM_ID (it->f, it->face_id);
1512 img = IMAGE_FROM_ID (it->f, it->image_id);
1513 xassert (img);
1514
1515 /* Make sure X resources of the face and image are loaded. */
1516 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1517 prepare_image_for_display (it->f, img);
1518
95af8492 1519 it->ascent = it->phys_ascent = image_ascent (img, face);
66ac4b0e 1520 it->descent = it->phys_descent = img->height + 2 * img->margin - it->ascent;
06a2c219
GM
1521 it->pixel_width = img->width + 2 * img->margin;
1522
1523 it->nglyphs = 1;
1524
1525 if (face->box != FACE_NO_BOX)
1526 {
1527 it->ascent += face->box_line_width;
1528 it->descent += face->box_line_width;
1529
1530 if (it->start_of_box_run_p)
1531 it->pixel_width += face->box_line_width;
1532 if (it->end_of_box_run_p)
1533 it->pixel_width += face->box_line_width;
1534 }
1535
1536 take_vertical_position_into_account (it);
1537
1538 if (it->glyph_row)
1539 {
1540 struct glyph *glyph;
1541 enum glyph_row_area area = it->area;
1542
1543 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1544 if (glyph < it->glyph_row->glyphs[area + 1])
1545 {
06a2c219
GM
1546 glyph->charpos = CHARPOS (it->position);
1547 glyph->object = it->object;
88d75730 1548 glyph->pixel_width = it->pixel_width;
06a2c219 1549 glyph->voffset = it->voffset;
88d75730 1550 glyph->type = IMAGE_GLYPH;
06a2c219 1551 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1552 glyph->left_box_line_p = it->start_of_box_run_p;
1553 glyph->right_box_line_p = it->end_of_box_run_p;
1554 glyph->overlaps_vertically_p = 0;
1555 glyph->padding_p = 0;
1556 glyph->glyph_not_available_p = 0;
1557 glyph->face_id = it->face_id;
1558 glyph->u.img_id = img->id;
06a2c219
GM
1559 ++it->glyph_row->used[area];
1560 }
1561 }
1562}
1563
1564
1565/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1566 of the glyph, WIDTH and HEIGHT are the width and height of the
1567 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1568 ascent of the glyph (0 <= ASCENT <= 1). */
1569
1570static void
1571x_append_stretch_glyph (it, object, width, height, ascent)
1572 struct it *it;
1573 Lisp_Object object;
1574 int width, height;
1575 double ascent;
1576{
1577 struct glyph *glyph;
1578 enum glyph_row_area area = it->area;
1579
1580 xassert (ascent >= 0 && ascent <= 1);
1581
1582 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1583 if (glyph < it->glyph_row->glyphs[area + 1])
1584 {
06a2c219
GM
1585 glyph->charpos = CHARPOS (it->position);
1586 glyph->object = object;
88d75730 1587 glyph->pixel_width = width;
06a2c219 1588 glyph->voffset = it->voffset;
88d75730 1589 glyph->type = STRETCH_GLYPH;
06a2c219 1590 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1591 glyph->left_box_line_p = it->start_of_box_run_p;
1592 glyph->right_box_line_p = it->end_of_box_run_p;
1593 glyph->overlaps_vertically_p = 0;
1594 glyph->padding_p = 0;
1595 glyph->glyph_not_available_p = 0;
1596 glyph->face_id = it->face_id;
1597 glyph->u.stretch.ascent = height * ascent;
1598 glyph->u.stretch.height = height;
06a2c219
GM
1599 ++it->glyph_row->used[area];
1600 }
1601}
1602
1603
1604/* Produce a stretch glyph for iterator IT. IT->object is the value
1605 of the glyph property displayed. The value must be a list
1606 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1607 being recognized:
1608
1609 1. `:width WIDTH' specifies that the space should be WIDTH *
1610 canonical char width wide. WIDTH may be an integer or floating
1611 point number.
1612
1613 2. `:relative-width FACTOR' specifies that the width of the stretch
1614 should be computed from the width of the first character having the
1615 `glyph' property, and should be FACTOR times that width.
1616
1617 3. `:align-to HPOS' specifies that the space should be wide enough
1618 to reach HPOS, a value in canonical character units.
1619
1620 Exactly one of the above pairs must be present.
1621
1622 4. `:height HEIGHT' specifies that the height of the stretch produced
1623 should be HEIGHT, measured in canonical character units.
1624
1625 5. `:relative-height FACTOR' specifies that the height of the the
1626 stretch should be FACTOR times the height of the characters having
1627 the glyph property.
1628
1629 Either none or exactly one of 4 or 5 must be present.
1630
1631 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1632 of the stretch should be used for the ascent of the stretch.
1633 ASCENT must be in the range 0 <= ASCENT <= 100. */
1634
1635#define NUMVAL(X) \
1636 ((INTEGERP (X) || FLOATP (X)) \
1637 ? XFLOATINT (X) \
1638 : - 1)
1639
1640
1641static void
1642x_produce_stretch_glyph (it)
1643 struct it *it;
1644{
1645 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1646#if GLYPH_DEBUG
1647 extern Lisp_Object Qspace;
1648#endif
1649 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1650 extern Lisp_Object QCrelative_width, QCrelative_height;
1651 extern Lisp_Object QCalign_to;
1652 Lisp_Object prop, plist;
1653 double width = 0, height = 0, ascent = 0;
1654 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1655 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1656
1657 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1658
1659 /* List should start with `space'. */
1660 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1661 plist = XCDR (it->object);
1662
1663 /* Compute the width of the stretch. */
1664 if (prop = Fplist_get (plist, QCwidth),
1665 NUMVAL (prop) > 0)
1666 /* Absolute width `:width WIDTH' specified and valid. */
1667 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1668 else if (prop = Fplist_get (plist, QCrelative_width),
1669 NUMVAL (prop) > 0)
1670 {
1671 /* Relative width `:relative-width FACTOR' specified and valid.
1672 Compute the width of the characters having the `glyph'
1673 property. */
1674 struct it it2;
1675 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1676
1677 it2 = *it;
1678 if (it->multibyte_p)
1679 {
1680 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1681 - IT_BYTEPOS (*it));
1682 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1683 }
1684 else
1685 it2.c = *p, it2.len = 1;
1686
1687 it2.glyph_row = NULL;
1688 it2.what = IT_CHARACTER;
1689 x_produce_glyphs (&it2);
1690 width = NUMVAL (prop) * it2.pixel_width;
1691 }
1692 else if (prop = Fplist_get (plist, QCalign_to),
1693 NUMVAL (prop) > 0)
1694 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1695 else
1696 /* Nothing specified -> width defaults to canonical char width. */
1697 width = CANON_X_UNIT (it->f);
1698
1699 /* Compute height. */
1700 if (prop = Fplist_get (plist, QCheight),
1701 NUMVAL (prop) > 0)
1702 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1703 else if (prop = Fplist_get (plist, QCrelative_height),
1704 NUMVAL (prop) > 0)
1705 height = FONT_HEIGHT (font) * NUMVAL (prop);
1706 else
1707 height = FONT_HEIGHT (font);
1708
1709 /* Compute percentage of height used for ascent. If
1710 `:ascent ASCENT' is present and valid, use that. Otherwise,
1711 derive the ascent from the font in use. */
1712 if (prop = Fplist_get (plist, QCascent),
1713 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1714 ascent = NUMVAL (prop) / 100.0;
1715 else
1716 ascent = (double) font->ascent / FONT_HEIGHT (font);
1717
1718 if (width <= 0)
1719 width = 1;
1720 if (height <= 0)
1721 height = 1;
1722
1723 if (it->glyph_row)
1724 {
1725 Lisp_Object object = it->stack[it->sp - 1].string;
1726 if (!STRINGP (object))
1727 object = it->w->buffer;
1728 x_append_stretch_glyph (it, object, width, height, ascent);
1729 }
1730
1731 it->pixel_width = width;
66ac4b0e
GM
1732 it->ascent = it->phys_ascent = height * ascent;
1733 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1734 it->nglyphs = 1;
1735
1736 if (face->box != FACE_NO_BOX)
1737 {
1738 it->ascent += face->box_line_width;
1739 it->descent += face->box_line_width;
1740
1741 if (it->start_of_box_run_p)
1742 it->pixel_width += face->box_line_width;
1743 if (it->end_of_box_run_p)
1744 it->pixel_width += face->box_line_width;
1745 }
1746
1747 take_vertical_position_into_account (it);
1748}
1749
b4192550
KH
1750/* Return proper value to be used as baseline offset of font that has
1751 ASCENT and DESCENT to draw characters by the font at the vertical
1752 center of the line of frame F.
1753
1754 Here, out task is to find the value of BOFF in the following figure;
1755
1756 -------------------------+-----------+-
1757 -+-+---------+-+ | |
1758 | | | | | |
1759 | | | | F_ASCENT F_HEIGHT
1760 | | | ASCENT | |
1761 HEIGHT | | | | |
1762 | | |-|-+------+-----------|------- baseline
1763 | | | | BOFF | |
1764 | |---------|-+-+ | |
1765 | | | DESCENT | |
1766 -+-+---------+-+ F_DESCENT |
1767 -------------------------+-----------+-
1768
1769 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1770 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1771 DESCENT = FONT->descent
1772 HEIGHT = FONT_HEIGHT (FONT)
1773 F_DESCENT = (F->output_data.x->font->descent
1774 - F->output_data.x->baseline_offset)
1775 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1776*/
1777
458f45fa
KH
1778#define VCENTER_BASELINE_OFFSET(FONT, F) \
1779 ((FONT)->descent \
1780 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
1781 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
1782 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1783
1784/* Produce glyphs/get display metrics for the display element IT is
1785 loaded with. See the description of struct display_iterator in
1786 dispextern.h for an overview of struct display_iterator. */
1787
1788static void
1789x_produce_glyphs (it)
1790 struct it *it;
1791{
ee569018
KH
1792 it->glyph_not_available_p = 0;
1793
06a2c219
GM
1794 if (it->what == IT_CHARACTER)
1795 {
1796 XChar2b char2b;
1797 XFontStruct *font;
ee569018 1798 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1799 XCharStruct *pcm;
06a2c219 1800 int font_not_found_p;
b4192550
KH
1801 struct font_info *font_info;
1802 int boff; /* baseline offset */
a4249304
KH
1803 /* We may change it->multibyte_p upon unibyte<->multibyte
1804 conversion. So, save the current value now and restore it
1805 later.
1806
1807 Note: It seems that we don't have to record multibyte_p in
1808 struct glyph because the character code itself tells if or
1809 not the character is multibyte. Thus, in the future, we must
1810 consider eliminating the field `multibyte_p' in the struct
1811 glyph.
1812 */
1813 int saved_multibyte_p = it->multibyte_p;
06a2c219 1814
ee569018
KH
1815 /* Maybe translate single-byte characters to multibyte, or the
1816 other way. */
06a2c219 1817 it->char_to_display = it->c;
ee569018 1818 if (!ASCII_BYTE_P (it->c))
06a2c219 1819 {
ee569018
KH
1820 if (unibyte_display_via_language_environment
1821 && SINGLE_BYTE_CHAR_P (it->c)
1822 && (it->c >= 0240
1823 || !NILP (Vnonascii_translation_table)))
1824 {
1825 it->char_to_display = unibyte_char_to_multibyte (it->c);
a4249304 1826 it->multibyte_p = 1;
ee569018
KH
1827 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1828 face = FACE_FROM_ID (it->f, it->face_id);
1829 }
1830 else if (!SINGLE_BYTE_CHAR_P (it->c)
1831 && !it->multibyte_p)
1832 {
1833 it->char_to_display = multibyte_char_to_unibyte (it->c, Qnil);
a4249304 1834 it->multibyte_p = 0;
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 }
06a2c219
GM
1838 }
1839
ee569018
KH
1840 /* Get font to use. Encode IT->char_to_display. */
1841 x_get_char_face_and_encoding (it->f, it->char_to_display,
1842 it->face_id, &char2b,
1843 it->multibyte_p);
06a2c219
GM
1844 font = face->font;
1845
1846 /* When no suitable font found, use the default font. */
1847 font_not_found_p = font == NULL;
1848 if (font_not_found_p)
b4192550
KH
1849 {
1850 font = FRAME_FONT (it->f);
1851 boff = it->f->output_data.x->baseline_offset;
1852 font_info = NULL;
1853 }
1854 else
1855 {
1856 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1857 boff = font_info->baseline_offset;
1858 if (font_info->vertical_centering)
1859 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1860 }
06a2c219
GM
1861
1862 if (it->char_to_display >= ' '
1863 && (!it->multibyte_p || it->char_to_display < 128))
1864 {
1865 /* Either unibyte or ASCII. */
1866 int stretched_p;
1867
1868 it->nglyphs = 1;
06a2c219
GM
1869
1870 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1871 it->ascent = font->ascent + boff;
1872 it->descent = font->descent - boff;
474848ac
GM
1873
1874 if (pcm)
1875 {
1876 it->phys_ascent = pcm->ascent + boff;
1877 it->phys_descent = pcm->descent - boff;
1878 it->pixel_width = pcm->width;
1879 }
1880 else
1881 {
1882 it->glyph_not_available_p = 1;
1883 it->phys_ascent = font->ascent + boff;
1884 it->phys_descent = font->descent - boff;
1885 it->pixel_width = FONT_WIDTH (font);
1886 }
06a2c219
GM
1887
1888 /* If this is a space inside a region of text with
1889 `space-width' property, change its width. */
1890 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1891 if (stretched_p)
1892 it->pixel_width *= XFLOATINT (it->space_width);
1893
1894 /* If face has a box, add the box thickness to the character
1895 height. If character has a box line to the left and/or
1896 right, add the box line width to the character's width. */
1897 if (face->box != FACE_NO_BOX)
1898 {
1899 int thick = face->box_line_width;
1900
1901 it->ascent += thick;
1902 it->descent += thick;
1903
1904 if (it->start_of_box_run_p)
1905 it->pixel_width += thick;
1906 if (it->end_of_box_run_p)
1907 it->pixel_width += thick;
1908 }
1909
1910 /* If face has an overline, add the height of the overline
1911 (1 pixel) and a 1 pixel margin to the character height. */
1912 if (face->overline_p)
1913 it->ascent += 2;
1914
1915 take_vertical_position_into_account (it);
1916
1917 /* If we have to actually produce glyphs, do it. */
1918 if (it->glyph_row)
1919 {
1920 if (stretched_p)
1921 {
1922 /* Translate a space with a `space-width' property
1923 into a stretch glyph. */
1924 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1925 x_append_stretch_glyph (it, it->object, it->pixel_width,
1926 it->ascent + it->descent, ascent);
1927 }
1928 else
1929 x_append_glyph (it);
1930
1931 /* If characters with lbearing or rbearing are displayed
1932 in this line, record that fact in a flag of the
1933 glyph row. This is used to optimize X output code. */
1c7e22fd 1934 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1935 it->glyph_row->contains_overlapping_glyphs_p = 1;
1936 }
1937 }
1938 else if (it->char_to_display == '\n')
1939 {
1940 /* A newline has no width but we need the height of the line. */
1941 it->pixel_width = 0;
1942 it->nglyphs = 0;
b4192550
KH
1943 it->ascent = it->phys_ascent = font->ascent + boff;
1944 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1945
1946 if (face->box != FACE_NO_BOX)
1947 {
1948 int thick = face->box_line_width;
1949 it->ascent += thick;
1950 it->descent += thick;
1951 }
1952 }
1953 else if (it->char_to_display == '\t')
1954 {
1955 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1956 int x = it->current_x + it->continuation_lines_width;
06a2c219 1957 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2a32b5ea
GM
1958
1959 /* If the distance from the current position to the next tab
1960 stop is less than a canonical character width, use the
1961 tab stop after that. */
1962 if (next_tab_x - x < CANON_X_UNIT (it->f))
1963 next_tab_x += tab_width;
06a2c219
GM
1964
1965 it->pixel_width = next_tab_x - x;
1966 it->nglyphs = 1;
b4192550
KH
1967 it->ascent = it->phys_ascent = font->ascent + boff;
1968 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1969
1970 if (it->glyph_row)
1971 {
1972 double ascent = (double) it->ascent / (it->ascent + it->descent);
1973 x_append_stretch_glyph (it, it->object, it->pixel_width,
1974 it->ascent + it->descent, ascent);
1975 }
1976 }
1977 else
1978 {
1979 /* A multi-byte character. Assume that the display width of the
1980 character is the width of the character multiplied by the
b4192550 1981 width of the font. */
06a2c219 1982
b4192550
KH
1983 /* If we found a font, this font should give us the right
1984 metrics. If we didn't find a font, use the frame's
1985 default font and calculate the width of the character
1986 from the charset width; this is what old redisplay code
1987 did. */
1988 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1989 if (font_not_found_p || !pcm)
1990 {
1991 int charset = CHAR_CHARSET (it->char_to_display);
1992
1993 it->glyph_not_available_p = 1;
1994 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
1995 * CHARSET_WIDTH (charset));
1996 it->phys_ascent = font->ascent + boff;
1997 it->phys_descent = font->descent - boff;
1998 }
1999 else
2000 {
2001 it->pixel_width = pcm->width;
2002 it->phys_ascent = pcm->ascent + boff;
2003 it->phys_descent = pcm->descent - boff;
2004 if (it->glyph_row
2005 && (pcm->lbearing < 0
2006 || pcm->rbearing > pcm->width))
2007 it->glyph_row->contains_overlapping_glyphs_p = 1;
2008 }
b4192550
KH
2009 it->nglyphs = 1;
2010 it->ascent = font->ascent + boff;
2011 it->descent = font->descent - boff;
06a2c219
GM
2012 if (face->box != FACE_NO_BOX)
2013 {
2014 int thick = face->box_line_width;
2015 it->ascent += thick;
2016 it->descent += thick;
2017
2018 if (it->start_of_box_run_p)
2019 it->pixel_width += thick;
2020 if (it->end_of_box_run_p)
2021 it->pixel_width += thick;
2022 }
2023
2024 /* If face has an overline, add the height of the overline
2025 (1 pixel) and a 1 pixel margin to the character height. */
2026 if (face->overline_p)
2027 it->ascent += 2;
2028
2029 take_vertical_position_into_account (it);
2030
2031 if (it->glyph_row)
2032 x_append_glyph (it);
2033 }
a4249304 2034 it->multibyte_p = saved_multibyte_p;
06a2c219 2035 }
b4192550
KH
2036 else if (it->what == IT_COMPOSITION)
2037 {
2038 /* Note: A composition is represented as one glyph in the
2039 glyph matrix. There are no padding glyphs. */
2040 XChar2b char2b;
2041 XFontStruct *font;
ee569018 2042 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2043 XCharStruct *pcm;
2044 int font_not_found_p;
2045 struct font_info *font_info;
2046 int boff; /* baseline offset */
2047 struct composition *cmp = composition_table[it->cmp_id];
2048
2049 /* Maybe translate single-byte characters to multibyte. */
2050 it->char_to_display = it->c;
2051 if (unibyte_display_via_language_environment
2052 && SINGLE_BYTE_CHAR_P (it->c)
2053 && (it->c >= 0240
2054 || (it->c >= 0200
2055 && !NILP (Vnonascii_translation_table))))
2056 {
2057 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2058 }
2059
2060 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2061 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2062 face = FACE_FROM_ID (it->f, it->face_id);
2063 x_get_char_face_and_encoding (it->f, it->char_to_display,
2064 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2065 font = face->font;
2066
2067 /* When no suitable font found, use the default font. */
2068 font_not_found_p = font == NULL;
2069 if (font_not_found_p)
2070 {
2071 font = FRAME_FONT (it->f);
2072 boff = it->f->output_data.x->baseline_offset;
2073 font_info = NULL;
2074 }
2075 else
2076 {
2077 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2078 boff = font_info->baseline_offset;
2079 if (font_info->vertical_centering)
2080 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2081 }
2082
2083 /* There are no padding glyphs, so there is only one glyph to
2084 produce for the composition. Important is that pixel_width,
2085 ascent and descent are the values of what is drawn by
2086 draw_glyphs (i.e. the values of the overall glyphs composed). */
2087 it->nglyphs = 1;
2088
2089 /* If we have not yet calculated pixel size data of glyphs of
2090 the composition for the current face font, calculate them
2091 now. Theoretically, we have to check all fonts for the
2092 glyphs, but that requires much time and memory space. So,
2093 here we check only the font of the first glyph. This leads
2094 to incorrect display very rarely, and C-l (recenter) can
2095 correct the display anyway. */
2096 if (cmp->font != (void *) font)
2097 {
2098 /* Ascent and descent of the font of the first character of
2099 this composition (adjusted by baseline offset). Ascent
2100 and descent of overall glyphs should not be less than
2101 them respectively. */
2102 int font_ascent = font->ascent + boff;
2103 int font_descent = font->descent - boff;
2104 /* Bounding box of the overall glyphs. */
2105 int leftmost, rightmost, lowest, highest;
329bed06 2106 int i, width, ascent, descent;
b4192550
KH
2107
2108 cmp->font = (void *) font;
2109
2110 /* Initialize the bounding box. */
1bdeec2e
KH
2111 if (font_info
2112 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2113 {
2114 width = pcm->width;
2115 ascent = pcm->ascent;
2116 descent = pcm->descent;
2117 }
2118 else
2119 {
2120 width = FONT_WIDTH (font);
2121 ascent = font->ascent;
2122 descent = font->descent;
2123 }
2124
2125 rightmost = width;
2126 lowest = - descent + boff;
2127 highest = ascent + boff;
b4192550 2128 leftmost = 0;
329bed06 2129
b4192550
KH
2130 if (font_info
2131 && font_info->default_ascent
2132 && CHAR_TABLE_P (Vuse_default_ascent)
2133 && !NILP (Faref (Vuse_default_ascent,
2134 make_number (it->char_to_display))))
2135 highest = font_info->default_ascent + boff;
2136
2137 /* Draw the first glyph at the normal position. It may be
2138 shifted to right later if some other glyphs are drawn at
2139 the left. */
2140 cmp->offsets[0] = 0;
2141 cmp->offsets[1] = boff;
2142
2143 /* Set cmp->offsets for the remaining glyphs. */
2144 for (i = 1; i < cmp->glyph_len; i++)
2145 {
2146 int left, right, btm, top;
2147 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2148 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2149
2150 face = FACE_FROM_ID (it->f, face_id);
2151 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2152 it->multibyte_p);
b4192550
KH
2153 font = face->font;
2154 if (font == NULL)
2155 {
2156 font = FRAME_FONT (it->f);
2157 boff = it->f->output_data.x->baseline_offset;
2158 font_info = NULL;
2159 }
2160 else
2161 {
2162 font_info
2163 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2164 boff = font_info->baseline_offset;
2165 if (font_info->vertical_centering)
2166 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2167 }
2168
1bdeec2e
KH
2169 if (font_info
2170 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2171 {
2172 width = pcm->width;
2173 ascent = pcm->ascent;
2174 descent = pcm->descent;
2175 }
2176 else
2177 {
2178 width = FONT_WIDTH (font);
1bdeec2e
KH
2179 ascent = 1;
2180 descent = 0;
329bed06 2181 }
b4192550
KH
2182
2183 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2184 {
2185 /* Relative composition with or without
2186 alternate chars. */
329bed06
GM
2187 left = (leftmost + rightmost - width) / 2;
2188 btm = - descent + boff;
b4192550
KH
2189 if (font_info && font_info->relative_compose
2190 && (! CHAR_TABLE_P (Vignore_relative_composition)
2191 || NILP (Faref (Vignore_relative_composition,
2192 make_number (ch)))))
2193 {
2194
329bed06 2195 if (- descent >= font_info->relative_compose)
b4192550
KH
2196 /* One extra pixel between two glyphs. */
2197 btm = highest + 1;
329bed06 2198 else if (ascent <= 0)
b4192550 2199 /* One extra pixel between two glyphs. */
329bed06 2200 btm = lowest - 1 - ascent - descent;
b4192550
KH
2201 }
2202 }
2203 else
2204 {
2205 /* A composition rule is specified by an integer
2206 value that encodes global and new reference
2207 points (GREF and NREF). GREF and NREF are
2208 specified by numbers as below:
2209
2210 0---1---2 -- ascent
2211 | |
2212 | |
2213 | |
2214 9--10--11 -- center
2215 | |
2216 ---3---4---5--- baseline
2217 | |
2218 6---7---8 -- descent
2219 */
2220 int rule = COMPOSITION_RULE (cmp, i);
2221 int gref, nref, grefx, grefy, nrefx, nrefy;
2222
2223 COMPOSITION_DECODE_RULE (rule, gref, nref);
2224 grefx = gref % 3, nrefx = nref % 3;
2225 grefy = gref / 3, nrefy = nref / 3;
2226
2227 left = (leftmost
2228 + grefx * (rightmost - leftmost) / 2
329bed06 2229 - nrefx * width / 2);
b4192550
KH
2230 btm = ((grefy == 0 ? highest
2231 : grefy == 1 ? 0
2232 : grefy == 2 ? lowest
2233 : (highest + lowest) / 2)
329bed06
GM
2234 - (nrefy == 0 ? ascent + descent
2235 : nrefy == 1 ? descent - boff
b4192550 2236 : nrefy == 2 ? 0
329bed06 2237 : (ascent + descent) / 2));
b4192550
KH
2238 }
2239
2240 cmp->offsets[i * 2] = left;
329bed06 2241 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2242
2243 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2244 right = left + width;
2245 top = btm + descent + ascent;
b4192550
KH
2246 if (left < leftmost)
2247 leftmost = left;
2248 if (right > rightmost)
2249 rightmost = right;
2250 if (top > highest)
2251 highest = top;
2252 if (btm < lowest)
2253 lowest = btm;
2254 }
2255
2256 /* If there are glyphs whose x-offsets are negative,
2257 shift all glyphs to the right and make all x-offsets
2258 non-negative. */
2259 if (leftmost < 0)
2260 {
2261 for (i = 0; i < cmp->glyph_len; i++)
2262 cmp->offsets[i * 2] -= leftmost;
2263 rightmost -= leftmost;
2264 }
2265
2266 cmp->pixel_width = rightmost;
2267 cmp->ascent = highest;
2268 cmp->descent = - lowest;
2269 if (cmp->ascent < font_ascent)
2270 cmp->ascent = font_ascent;
2271 if (cmp->descent < font_descent)
2272 cmp->descent = font_descent;
2273 }
2274
2275 it->pixel_width = cmp->pixel_width;
2276 it->ascent = it->phys_ascent = cmp->ascent;
2277 it->descent = it->phys_descent = cmp->descent;
2278
2279 if (face->box != FACE_NO_BOX)
2280 {
2281 int thick = face->box_line_width;
2282 it->ascent += thick;
2283 it->descent += thick;
2284
2285 if (it->start_of_box_run_p)
2286 it->pixel_width += thick;
2287 if (it->end_of_box_run_p)
2288 it->pixel_width += thick;
2289 }
2290
2291 /* If face has an overline, add the height of the overline
2292 (1 pixel) and a 1 pixel margin to the character height. */
2293 if (face->overline_p)
2294 it->ascent += 2;
2295
2296 take_vertical_position_into_account (it);
2297
2298 if (it->glyph_row)
2299 x_append_composite_glyph (it);
2300 }
06a2c219
GM
2301 else if (it->what == IT_IMAGE)
2302 x_produce_image_glyph (it);
2303 else if (it->what == IT_STRETCH)
2304 x_produce_stretch_glyph (it);
2305
3017fdd1
GM
2306 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2307 because this isn't true for images with `:ascent 100'. */
2308 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2309 if (it->area == TEXT_AREA)
2310 it->current_x += it->pixel_width;
66ac4b0e 2311
d365f5bb
GM
2312 it->descent += it->extra_line_spacing;
2313
06a2c219
GM
2314 it->max_ascent = max (it->max_ascent, it->ascent);
2315 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2316 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2317 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2318}
2319
2320
2321/* Estimate the pixel height of the mode or top line on frame F.
2322 FACE_ID specifies what line's height to estimate. */
2323
2324int
2325x_estimate_mode_line_height (f, face_id)
2326 struct frame *f;
2327 enum face_id face_id;
2328{
43281ee3 2329 int height = FONT_HEIGHT (FRAME_FONT (f));
06a2c219
GM
2330
2331 /* This function is called so early when Emacs starts that the face
2332 cache and mode line face are not yet initialized. */
2333 if (FRAME_FACE_CACHE (f))
2334 {
2335 struct face *face = FACE_FROM_ID (f, face_id);
2336 if (face)
43281ee3
GM
2337 {
2338 if (face->font)
2339 height = FONT_HEIGHT (face->font);
2340 height += 2 * face->box_line_width;
2341 }
06a2c219
GM
2342 }
2343
2344 return height;
2345}
2346
2347\f
2348/***********************************************************************
2349 Glyph display
2350 ***********************************************************************/
2351
2352/* A sequence of glyphs to be drawn in the same face.
2353
2354 This data structure is not really completely X specific, so it
2355 could possibly, at least partially, be useful for other systems. It
2356 is currently not part of the external redisplay interface because
2357 it's not clear what other systems will need. */
2358
2359struct glyph_string
2360{
2361 /* X-origin of the string. */
2362 int x;
2363
2364 /* Y-origin and y-position of the base line of this string. */
2365 int y, ybase;
2366
2367 /* The width of the string, not including a face extension. */
2368 int width;
2369
2370 /* The width of the string, including a face extension. */
2371 int background_width;
2372
2373 /* The height of this string. This is the height of the line this
2374 string is drawn in, and can be different from the height of the
2375 font the string is drawn in. */
2376 int height;
2377
2378 /* Number of pixels this string overwrites in front of its x-origin.
2379 This number is zero if the string has an lbearing >= 0; it is
2380 -lbearing, if the string has an lbearing < 0. */
2381 int left_overhang;
2382
2383 /* Number of pixels this string overwrites past its right-most
2384 nominal x-position, i.e. x + width. Zero if the string's
2385 rbearing is <= its nominal width, rbearing - width otherwise. */
2386 int right_overhang;
2387
2388 /* The frame on which the glyph string is drawn. */
2389 struct frame *f;
2390
2391 /* The window on which the glyph string is drawn. */
2392 struct window *w;
2393
2394 /* X display and window for convenience. */
2395 Display *display;
2396 Window window;
2397
2398 /* The glyph row for which this string was built. It determines the
2399 y-origin and height of the string. */
2400 struct glyph_row *row;
2401
2402 /* The area within row. */
2403 enum glyph_row_area area;
2404
2405 /* Characters to be drawn, and number of characters. */
2406 XChar2b *char2b;
2407 int nchars;
2408
06a2c219
GM
2409 /* A face-override for drawing cursors, mouse face and similar. */
2410 enum draw_glyphs_face hl;
2411
2412 /* Face in which this string is to be drawn. */
2413 struct face *face;
2414
2415 /* Font in which this string is to be drawn. */
2416 XFontStruct *font;
2417
2418 /* Font info for this string. */
2419 struct font_info *font_info;
2420
b4192550
KH
2421 /* Non-null means this string describes (part of) a composition.
2422 All characters from char2b are drawn composed. */
2423 struct composition *cmp;
06a2c219
GM
2424
2425 /* Index of this glyph string's first character in the glyph
b4192550
KH
2426 definition of CMP. If this is zero, this glyph string describes
2427 the first character of a composition. */
06a2c219
GM
2428 int gidx;
2429
2430 /* 1 means this glyph strings face has to be drawn to the right end
2431 of the window's drawing area. */
2432 unsigned extends_to_end_of_line_p : 1;
2433
2434 /* 1 means the background of this string has been drawn. */
2435 unsigned background_filled_p : 1;
2436
2437 /* 1 means glyph string must be drawn with 16-bit functions. */
2438 unsigned two_byte_p : 1;
2439
2440 /* 1 means that the original font determined for drawing this glyph
2441 string could not be loaded. The member `font' has been set to
2442 the frame's default font in this case. */
2443 unsigned font_not_found_p : 1;
2444
2445 /* 1 means that the face in which this glyph string is drawn has a
2446 stipple pattern. */
2447 unsigned stippled_p : 1;
2448
66ac4b0e
GM
2449 /* 1 means only the foreground of this glyph string must be drawn,
2450 and we should use the physical height of the line this glyph
2451 string appears in as clip rect. */
2452 unsigned for_overlaps_p : 1;
2453
06a2c219
GM
2454 /* The GC to use for drawing this glyph string. */
2455 GC gc;
2456
2457 /* A pointer to the first glyph in the string. This glyph
2458 corresponds to char2b[0]. Needed to draw rectangles if
2459 font_not_found_p is 1. */
2460 struct glyph *first_glyph;
2461
2462 /* Image, if any. */
2463 struct image *img;
2464
2465 struct glyph_string *next, *prev;
2466};
2467
2468
5c187dee 2469#if 0
06a2c219
GM
2470
2471static void
2472x_dump_glyph_string (s)
2473 struct glyph_string *s;
2474{
2475 fprintf (stderr, "glyph string\n");
2476 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2477 s->x, s->y, s->width, s->height);
2478 fprintf (stderr, " ybase = %d\n", s->ybase);
2479 fprintf (stderr, " hl = %d\n", s->hl);
2480 fprintf (stderr, " left overhang = %d, right = %d\n",
2481 s->left_overhang, s->right_overhang);
2482 fprintf (stderr, " nchars = %d\n", s->nchars);
2483 fprintf (stderr, " extends to end of line = %d\n",
2484 s->extends_to_end_of_line_p);
2485 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2486 fprintf (stderr, " bg width = %d\n", s->background_width);
2487}
2488
2489#endif /* GLYPH_DEBUG */
2490
2491
2492
2493static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2494 struct glyph_string **,
2495 struct glyph_string *,
2496 struct glyph_string *));
2497static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2498 struct glyph_string **,
2499 struct glyph_string *,
2500 struct glyph_string *));
2501static void x_append_glyph_string P_ ((struct glyph_string **,
2502 struct glyph_string **,
2503 struct glyph_string *));
2504static int x_left_overwritten P_ ((struct glyph_string *));
2505static int x_left_overwriting P_ ((struct glyph_string *));
2506static int x_right_overwritten P_ ((struct glyph_string *));
2507static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2508static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2509 int));
06a2c219
GM
2510static void x_init_glyph_string P_ ((struct glyph_string *,
2511 XChar2b *, struct window *,
2512 struct glyph_row *,
2513 enum glyph_row_area, int,
2514 enum draw_glyphs_face));
2515static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2516 enum glyph_row_area, int, int,
66ac4b0e 2517 enum draw_glyphs_face, int *, int *, int));
06a2c219
GM
2518static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2519static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2520static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2521 int));
2522static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2523static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2524static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2525static void x_draw_glyph_string P_ ((struct glyph_string *));
2526static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2527static void x_set_cursor_gc P_ ((struct glyph_string *));
2528static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2529static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2530static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2531 int *, int *));
2532static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2533static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2534 unsigned long *, double, int));
06a2c219 2535static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2536 double, int, unsigned long));
06a2c219
GM
2537static void x_setup_relief_colors P_ ((struct glyph_string *));
2538static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2539static void x_draw_image_relief P_ ((struct glyph_string *));
2540static void x_draw_image_foreground P_ ((struct glyph_string *));
2541static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2542static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2543static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2544 int, int, int));
2545static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2546 int, int, int, int, XRectangle *));
2547static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2548 int, int, int, XRectangle *));
66ac4b0e
GM
2549static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2550 enum glyph_row_area));
209f68d9
GM
2551static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2552 struct glyph_row *,
2553 enum glyph_row_area, int, int));
06a2c219 2554
163dcff3
GM
2555#if GLYPH_DEBUG
2556static void x_check_font P_ ((struct frame *, XFontStruct *));
2557#endif
2558
06a2c219 2559
06a2c219
GM
2560/* Append the list of glyph strings with head H and tail T to the list
2561 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2562
2563static INLINE void
2564x_append_glyph_string_lists (head, tail, h, t)
2565 struct glyph_string **head, **tail;
2566 struct glyph_string *h, *t;
2567{
2568 if (h)
2569 {
2570 if (*head)
2571 (*tail)->next = h;
2572 else
2573 *head = h;
2574 h->prev = *tail;
2575 *tail = t;
2576 }
2577}
2578
2579
2580/* Prepend the list of glyph strings with head H and tail T to the
2581 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2582 result. */
2583
2584static INLINE void
2585x_prepend_glyph_string_lists (head, tail, h, t)
2586 struct glyph_string **head, **tail;
2587 struct glyph_string *h, *t;
2588{
2589 if (h)
2590 {
2591 if (*head)
2592 (*head)->prev = t;
2593 else
2594 *tail = t;
2595 t->next = *head;
2596 *head = h;
2597 }
2598}
2599
2600
2601/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2602 Set *HEAD and *TAIL to the resulting list. */
2603
2604static INLINE void
2605x_append_glyph_string (head, tail, s)
2606 struct glyph_string **head, **tail;
2607 struct glyph_string *s;
2608{
2609 s->next = s->prev = NULL;
2610 x_append_glyph_string_lists (head, tail, s, s);
2611}
2612
2613
2614/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2615 face. */
2616
2617static void
2618x_set_cursor_gc (s)
2619 struct glyph_string *s;
2620{
2621 if (s->font == FRAME_FONT (s->f)
2622 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2623 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2624 && !s->cmp)
06a2c219
GM
2625 s->gc = s->f->output_data.x->cursor_gc;
2626 else
2627 {
2628 /* Cursor on non-default face: must merge. */
2629 XGCValues xgcv;
2630 unsigned long mask;
2631
2632 xgcv.background = s->f->output_data.x->cursor_pixel;
2633 xgcv.foreground = s->face->background;
2634
2635 /* If the glyph would be invisible, try a different foreground. */
2636 if (xgcv.foreground == xgcv.background)
2637 xgcv.foreground = s->face->foreground;
2638 if (xgcv.foreground == xgcv.background)
2639 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2640 if (xgcv.foreground == xgcv.background)
2641 xgcv.foreground = s->face->foreground;
2642
2643 /* Make sure the cursor is distinct from text in this face. */
2644 if (xgcv.background == s->face->background
2645 && xgcv.foreground == s->face->foreground)
2646 {
2647 xgcv.background = s->face->foreground;
2648 xgcv.foreground = s->face->background;
2649 }
2650
2651 IF_DEBUG (x_check_font (s->f, s->font));
2652 xgcv.font = s->font->fid;
2653 xgcv.graphics_exposures = False;
2654 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2655
2656 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2657 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2658 mask, &xgcv);
2659 else
2660 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2661 = XCreateGC (s->display, s->window, mask, &xgcv);
2662
2663 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2664 }
2665}
2666
2667
2668/* Set up S->gc of glyph string S for drawing text in mouse face. */
2669
2670static void
2671x_set_mouse_face_gc (s)
2672 struct glyph_string *s;
2673{
2674 int face_id;
ee569018 2675 struct face *face;
06a2c219
GM
2676
2677 /* What face has to be used for the mouse face? */
2678 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2679 face = FACE_FROM_ID (s->f, face_id);
033e3e18
GM
2680 if (s->first_glyph->type == CHAR_GLYPH)
2681 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2682 else
2683 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2684 s->face = FACE_FROM_ID (s->f, face_id);
2685 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2686
2687 /* If font in this face is same as S->font, use it. */
2688 if (s->font == s->face->font)
2689 s->gc = s->face->gc;
2690 else
2691 {
2692 /* Otherwise construct scratch_cursor_gc with values from FACE
2693 but font FONT. */
2694 XGCValues xgcv;
2695 unsigned long mask;
2696
2697 xgcv.background = s->face->background;
2698 xgcv.foreground = s->face->foreground;
2699 IF_DEBUG (x_check_font (s->f, s->font));
2700 xgcv.font = s->font->fid;
2701 xgcv.graphics_exposures = False;
2702 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2703
2704 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2705 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2706 mask, &xgcv);
2707 else
2708 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2709 = XCreateGC (s->display, s->window, mask, &xgcv);
2710
2711 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2712 }
2713
2714 xassert (s->gc != 0);
2715}
2716
2717
2718/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2719 Faces to use in the mode line have already been computed when the
2720 matrix was built, so there isn't much to do, here. */
2721
2722static INLINE void
2723x_set_mode_line_face_gc (s)
2724 struct glyph_string *s;
2725{
2726 s->gc = s->face->gc;
06a2c219
GM
2727}
2728
2729
2730/* Set S->gc of glyph string S for drawing that glyph string. Set
2731 S->stippled_p to a non-zero value if the face of S has a stipple
2732 pattern. */
2733
2734static INLINE void
2735x_set_glyph_string_gc (s)
2736 struct glyph_string *s;
2737{
209f68d9
GM
2738 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2739
06a2c219
GM
2740 if (s->hl == DRAW_NORMAL_TEXT)
2741 {
2742 s->gc = s->face->gc;
2743 s->stippled_p = s->face->stipple != 0;
2744 }
2745 else if (s->hl == DRAW_INVERSE_VIDEO)
2746 {
2747 x_set_mode_line_face_gc (s);
2748 s->stippled_p = s->face->stipple != 0;
2749 }
2750 else if (s->hl == DRAW_CURSOR)
2751 {
2752 x_set_cursor_gc (s);
2753 s->stippled_p = 0;
2754 }
2755 else if (s->hl == DRAW_MOUSE_FACE)
2756 {
2757 x_set_mouse_face_gc (s);
2758 s->stippled_p = s->face->stipple != 0;
2759 }
2760 else if (s->hl == DRAW_IMAGE_RAISED
2761 || s->hl == DRAW_IMAGE_SUNKEN)
2762 {
2763 s->gc = s->face->gc;
2764 s->stippled_p = s->face->stipple != 0;
2765 }
2766 else
2767 {
2768 s->gc = s->face->gc;
2769 s->stippled_p = s->face->stipple != 0;
2770 }
2771
2772 /* GC must have been set. */
2773 xassert (s->gc != 0);
2774}
2775
2776
2777/* Return in *R the clipping rectangle for glyph string S. */
2778
2779static void
2780x_get_glyph_string_clip_rect (s, r)
2781 struct glyph_string *s;
2782 XRectangle *r;
2783{
2784 if (s->row->full_width_p)
2785 {
2786 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2787 int canon_x = CANON_X_UNIT (s->f);
2788
2789 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2790 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2791
2792 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2793 {
1da3fd71 2794 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2795 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2796 r->x -= width;
2797 }
2798
b9432a85 2799 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2800
06a2c219
GM
2801 /* Unless displaying a mode or menu bar line, which are always
2802 fully visible, clip to the visible part of the row. */
2803 if (s->w->pseudo_window_p)
2804 r->height = s->row->visible_height;
2805 else
2806 r->height = s->height;
2807 }
2808 else
2809 {
2810 /* This is a text line that may be partially visible. */
2811 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2812 r->width = window_box_width (s->w, s->area);
2813 r->height = s->row->visible_height;
2814 }
2815
2816 /* Don't use S->y for clipping because it doesn't take partially
2817 visible lines into account. For example, it can be negative for
2818 partially visible lines at the top of a window. */
2819 if (!s->row->full_width_p
2820 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
045dee35 2821 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
06a2c219
GM
2822 else
2823 r->y = max (0, s->row->y);
06a2c219 2824
9ea173e8 2825 /* If drawing a tool-bar window, draw it over the internal border
06a2c219 2826 at the top of the window. */
9ea173e8 2827 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219 2828 r->y -= s->f->output_data.x->internal_border_width;
66ac4b0e
GM
2829
2830 /* If S draws overlapping rows, it's sufficient to use the top and
2831 bottom of the window for clipping because this glyph string
2832 intentionally draws over other lines. */
2833 if (s->for_overlaps_p)
2834 {
045dee35 2835 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2836 r->height = window_text_bottom_y (s->w) - r->y;
2837 }
2838
2839 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2840}
2841
2842
2843/* Set clipping for output of glyph string S. S may be part of a mode
2844 line or menu if we don't have X toolkit support. */
2845
2846static INLINE void
2847x_set_glyph_string_clipping (s)
2848 struct glyph_string *s;
2849{
2850 XRectangle r;
2851 x_get_glyph_string_clip_rect (s, &r);
2852 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2853}
2854
2855
2856/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2857 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2858
2859static INLINE void
2860x_compute_glyph_string_overhangs (s)
2861 struct glyph_string *s;
2862{
b4192550 2863 if (s->cmp == NULL
06a2c219
GM
2864 && s->first_glyph->type == CHAR_GLYPH)
2865 {
2866 XCharStruct cs;
2867 int direction, font_ascent, font_descent;
2868 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2869 &font_ascent, &font_descent, &cs);
2870 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2871 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2872 }
2873}
2874
2875
2876/* Compute overhangs and x-positions for glyph string S and its
2877 predecessors, or successors. X is the starting x-position for S.
2878 BACKWARD_P non-zero means process predecessors. */
2879
2880static void
2881x_compute_overhangs_and_x (s, x, backward_p)
2882 struct glyph_string *s;
2883 int x;
2884 int backward_p;
2885{
2886 if (backward_p)
2887 {
2888 while (s)
2889 {
2890 x_compute_glyph_string_overhangs (s);
2891 x -= s->width;
2892 s->x = x;
2893 s = s->prev;
2894 }
2895 }
2896 else
2897 {
2898 while (s)
2899 {
2900 x_compute_glyph_string_overhangs (s);
2901 s->x = x;
2902 x += s->width;
2903 s = s->next;
2904 }
2905 }
2906}
2907
2908
2909/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2910 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2911 assumed to be zero. */
06a2c219
GM
2912
2913static void
2914x_get_glyph_overhangs (glyph, f, left, right)
2915 struct glyph *glyph;
2916 struct frame *f;
2917 int *left, *right;
2918{
06a2c219
GM
2919 *left = *right = 0;
2920
b4192550 2921 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2922 {
2923 XFontStruct *font;
2924 struct face *face;
2925 struct font_info *font_info;
2926 XChar2b char2b;
ee569018
KH
2927 XCharStruct *pcm;
2928
2929 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2930 font = face->font;
2931 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2932 if (font
2933 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2934 {
06a2c219
GM
2935 if (pcm->rbearing > pcm->width)
2936 *right = pcm->rbearing - pcm->width;
2937 if (pcm->lbearing < 0)
2938 *left = -pcm->lbearing;
2939 }
2940 }
2941}
2942
2943
2944/* Return the index of the first glyph preceding glyph string S that
2945 is overwritten by S because of S's left overhang. Value is -1
2946 if no glyphs are overwritten. */
2947
2948static int
2949x_left_overwritten (s)
2950 struct glyph_string *s;
2951{
2952 int k;
2953
2954 if (s->left_overhang)
2955 {
2956 int x = 0, i;
2957 struct glyph *glyphs = s->row->glyphs[s->area];
2958 int first = s->first_glyph - glyphs;
2959
2960 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2961 x -= glyphs[i].pixel_width;
2962
2963 k = i + 1;
2964 }
2965 else
2966 k = -1;
2967
2968 return k;
2969}
2970
2971
2972/* Return the index of the first glyph preceding glyph string S that
2973 is overwriting S because of its right overhang. Value is -1 if no
2974 glyph in front of S overwrites S. */
2975
2976static int
2977x_left_overwriting (s)
2978 struct glyph_string *s;
2979{
2980 int i, k, x;
2981 struct glyph *glyphs = s->row->glyphs[s->area];
2982 int first = s->first_glyph - glyphs;
2983
2984 k = -1;
2985 x = 0;
2986 for (i = first - 1; i >= 0; --i)
2987 {
2988 int left, right;
2989 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2990 if (x + right > 0)
2991 k = i;
2992 x -= glyphs[i].pixel_width;
2993 }
2994
2995 return k;
2996}
2997
2998
2999/* Return the index of the last glyph following glyph string S that is
3000 not overwritten by S because of S's right overhang. Value is -1 if
3001 no such glyph is found. */
3002
3003static int
3004x_right_overwritten (s)
3005 struct glyph_string *s;
3006{
3007 int k = -1;
3008
3009 if (s->right_overhang)
3010 {
3011 int x = 0, i;
3012 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3013 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3014 int end = s->row->used[s->area];
3015
3016 for (i = first; i < end && s->right_overhang > x; ++i)
3017 x += glyphs[i].pixel_width;
3018
3019 k = i;
3020 }
3021
3022 return k;
3023}
3024
3025
3026/* Return the index of the last glyph following glyph string S that
3027 overwrites S because of its left overhang. Value is negative
3028 if no such glyph is found. */
3029
3030static int
3031x_right_overwriting (s)
3032 struct glyph_string *s;
3033{
3034 int i, k, x;
3035 int end = s->row->used[s->area];
3036 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3037 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3038
3039 k = -1;
3040 x = 0;
3041 for (i = first; i < end; ++i)
3042 {
3043 int left, right;
3044 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3045 if (x - left < 0)
3046 k = i;
3047 x += glyphs[i].pixel_width;
3048 }
3049
3050 return k;
3051}
3052
3053
3054/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3055
3056static INLINE void
3057x_clear_glyph_string_rect (s, x, y, w, h)
3058 struct glyph_string *s;
3059 int x, y, w, h;
3060{
3061 XGCValues xgcv;
3062 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3063 XSetForeground (s->display, s->gc, xgcv.background);
3064 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3065 XSetForeground (s->display, s->gc, xgcv.foreground);
3066}
3067
3068
3069/* Draw the background of glyph_string S. If S->background_filled_p
3070 is non-zero don't draw it. FORCE_P non-zero means draw the
3071 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3072 when a string preceding S draws into the background of S, or S
3073 contains the first component of a composition. */
06a2c219
GM
3074
3075static void
3076x_draw_glyph_string_background (s, force_p)
3077 struct glyph_string *s;
3078 int force_p;
3079{
3080 /* Nothing to do if background has already been drawn or if it
3081 shouldn't be drawn in the first place. */
3082 if (!s->background_filled_p)
3083 {
b4192550 3084 if (s->stippled_p)
06a2c219
GM
3085 {
3086 /* Fill background with a stipple pattern. */
3087 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3088 XFillRectangle (s->display, s->window, s->gc, s->x,
3089 s->y + s->face->box_line_width,
3090 s->background_width,
3091 s->height - 2 * s->face->box_line_width);
3092 XSetFillStyle (s->display, s->gc, FillSolid);
3093 s->background_filled_p = 1;
3094 }
3095 else if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
3096 || s->font_not_found_p
3097 || s->extends_to_end_of_line_p
06a2c219
GM
3098 || force_p)
3099 {
3100 x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
3101 s->background_width,
3102 s->height - 2 * s->face->box_line_width);
3103 s->background_filled_p = 1;
3104 }
3105 }
3106}
3107
3108
3109/* Draw the foreground of glyph string S. */
3110
3111static void
3112x_draw_glyph_string_foreground (s)
3113 struct glyph_string *s;
3114{
3115 int i, x;
3116
3117 /* If first glyph of S has a left box line, start drawing the text
3118 of S to the right of that box line. */
3119 if (s->face->box != FACE_NO_BOX
3120 && s->first_glyph->left_box_line_p)
3121 x = s->x + s->face->box_line_width;
3122 else
3123 x = s->x;
3124
b4192550
KH
3125 /* Draw characters of S as rectangles if S's font could not be
3126 loaded. */
3127 if (s->font_not_found_p)
06a2c219 3128 {
b4192550 3129 for (i = 0; i < s->nchars; ++i)
06a2c219 3130 {
b4192550
KH
3131 struct glyph *g = s->first_glyph + i;
3132 XDrawRectangle (s->display, s->window,
3133 s->gc, x, s->y, g->pixel_width - 1,
3134 s->height - 1);
3135 x += g->pixel_width;
06a2c219
GM
3136 }
3137 }
3138 else
3139 {
b4192550
KH
3140 char *char1b = (char *) s->char2b;
3141 int boff = s->font_info->baseline_offset;
06a2c219 3142
b4192550
KH
3143 if (s->font_info->vertical_centering)
3144 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3145
3146 /* If we can use 8-bit functions, condense S->char2b. */
3147 if (!s->two_byte_p)
3148 for (i = 0; i < s->nchars; ++i)
3149 char1b[i] = s->char2b[i].byte2;
3150
3151 /* Draw text with XDrawString if background has already been
3152 filled. Otherwise, use XDrawImageString. (Note that
3153 XDrawImageString is usually faster than XDrawString.) Always
3154 use XDrawImageString when drawing the cursor so that there is
3155 no chance that characters under a box cursor are invisible. */
3156 if (s->for_overlaps_p
3157 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3158 {
3159 /* Draw characters with 16-bit or 8-bit functions. */
3160 if (s->two_byte_p)
3161 XDrawString16 (s->display, s->window, s->gc, x,
3162 s->ybase - boff, s->char2b, s->nchars);
3163 else
3164 XDrawString (s->display, s->window, s->gc, x,
3165 s->ybase - boff, char1b, s->nchars);
3166 }
06a2c219
GM
3167 else
3168 {
b4192550
KH
3169 if (s->two_byte_p)
3170 XDrawImageString16 (s->display, s->window, s->gc, x,
3171 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3172 else
b4192550
KH
3173 XDrawImageString (s->display, s->window, s->gc, x,
3174 s->ybase - boff, char1b, s->nchars);
3175 }
3176 }
3177}
06a2c219 3178
b4192550 3179/* Draw the foreground of composite glyph string S. */
06a2c219 3180
b4192550
KH
3181static void
3182x_draw_composite_glyph_string_foreground (s)
3183 struct glyph_string *s;
3184{
3185 int i, x;
06a2c219 3186
b4192550
KH
3187 /* If first glyph of S has a left box line, start drawing the text
3188 of S to the right of that box line. */
3189 if (s->face->box != FACE_NO_BOX
3190 && s->first_glyph->left_box_line_p)
3191 x = s->x + s->face->box_line_width;
3192 else
3193 x = s->x;
06a2c219 3194
b4192550
KH
3195 /* S is a glyph string for a composition. S->gidx is the index of
3196 the first character drawn for glyphs of this composition.
3197 S->gidx == 0 means we are drawing the very first character of
3198 this composition. */
06a2c219 3199
b4192550
KH
3200 /* Draw a rectangle for the composition if the font for the very
3201 first character of the composition could not be loaded. */
3202 if (s->font_not_found_p)
3203 {
3204 if (s->gidx == 0)
3205 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3206 s->width - 1, s->height - 1);
3207 }
3208 else
3209 {
3210 for (i = 0; i < s->nchars; i++, ++s->gidx)
3211 XDrawString16 (s->display, s->window, s->gc,
3212 x + s->cmp->offsets[s->gidx * 2],
3213 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3214 s->char2b + i, 1);
06a2c219
GM
3215 }
3216}
3217
3218
80c32bcc
GM
3219#ifdef USE_X_TOOLKIT
3220
3e71d8f2 3221static struct frame *x_frame_of_widget P_ ((Widget));
80c32bcc 3222
3e71d8f2
GM
3223
3224/* Return the frame on which widget WIDGET is used.. Abort if frame
3225 cannot be determined. */
3226
e851c833 3227static struct frame *
3e71d8f2 3228x_frame_of_widget (widget)
80c32bcc 3229 Widget widget;
80c32bcc 3230{
80c32bcc 3231 struct x_display_info *dpyinfo;
5c187dee 3232 Lisp_Object tail;
3e71d8f2
GM
3233 struct frame *f;
3234
80c32bcc
GM
3235 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3236
3237 /* Find the top-level shell of the widget. Note that this function
3238 can be called when the widget is not yet realized, so XtWindow
3239 (widget) == 0. That's the reason we can't simply use
3240 x_any_window_to_frame. */
3241 while (!XtIsTopLevelShell (widget))
3242 widget = XtParent (widget);
3243
3244 /* Look for a frame with that top-level widget. Allocate the color
3245 on that frame to get the right gamma correction value. */
3246 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3247 if (GC_FRAMEP (XCAR (tail))
3248 && (f = XFRAME (XCAR (tail)),
3249 (f->output_data.nothing != 1
3250 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3251 && f->output_data.x->widget == widget)
3e71d8f2 3252 return f;
80c32bcc
GM
3253
3254 abort ();
3255}
3256
3e71d8f2
GM
3257
3258/* Allocate the color COLOR->pixel on the screen and display of
3259 widget WIDGET in colormap CMAP. If an exact match cannot be
3260 allocated, try the nearest color available. Value is non-zero
3261 if successful. This is called from lwlib. */
3262
3263int
3264x_alloc_nearest_color_for_widget (widget, cmap, color)
3265 Widget widget;
3266 Colormap cmap;
3267 XColor *color;
3268{
3269 struct frame *f = x_frame_of_widget (widget);
3270 return x_alloc_nearest_color (f, cmap, color);
3271}
3272
3273
46d516e5
MB
3274/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3275 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3276 If this produces the same color as PIXEL, try a color where all RGB
3277 values have DELTA added. Return the allocated color in *PIXEL.
3278 DISPLAY is the X display, CMAP is the colormap to operate on.
3279 Value is non-zero if successful. */
3280
3281int
3282x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
3283 Widget widget;
3284 Display *display;
3285 Colormap cmap;
3286 unsigned long *pixel;
3287 double factor;
3288 int delta;
3289{
3290 struct frame *f = x_frame_of_widget (widget);
3291 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
3292}
3293
3294
80c32bcc
GM
3295#endif /* USE_X_TOOLKIT */
3296
3297
f04e1297
GM
3298/* Value is an array of XColor structures for the contents of the
3299 color map of frame F. Set *NCELLS to the size of the array.
3300 Note that this probably shouldn't be called for large color maps,
3301 say a 24-bit TrueColor map. */
3302
3303static const XColor *
3304x_color_cells (f, ncells)
3305 struct frame *f;
3306 int *ncells;
3307{
3308 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3309
3310 if (dpyinfo->color_cells == NULL)
3311 {
3312 Display *display = FRAME_X_DISPLAY (f);
3313 Screen *screen = FRAME_X_SCREEN (f);
3314 int i;
3315
3316 dpyinfo->ncolor_cells
3317 = XDisplayCells (display, XScreenNumberOfScreen (screen));
3318 dpyinfo->color_cells
3319 = (XColor *) xmalloc (dpyinfo->ncolor_cells
3320 * sizeof *dpyinfo->color_cells);
3321
3322 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
3323 dpyinfo->color_cells[i].pixel = i;
3324
3325 XQueryColors (display, FRAME_X_COLORMAP (f),
3326 dpyinfo->color_cells, dpyinfo->ncolor_cells);
3327 }
3328
3329 *ncells = dpyinfo->ncolor_cells;
3330 return dpyinfo->color_cells;
3331}
3332
3333
3334/* On frame F, translate pixel colors to RGB values for the NCOLORS
3335 colors in COLORS. Use cached information, if available. */
3336
3337void
3338x_query_colors (f, colors, ncolors)
3339 struct frame *f;
3340 XColor *colors;
3341 int ncolors;
3342{
3343 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3344
3345 if (dpyinfo->color_cells)
3346 {
3347 int i;
3348 for (i = 0; i < ncolors; ++i)
3349 {
3350 unsigned long pixel = colors[i].pixel;
3351 xassert (pixel < dpyinfo->ncolor_cells);
3352 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
3353 colors[i] = dpyinfo->color_cells[pixel];
3354 }
3355 }
3356 else
3357 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
3358}
3359
3360
3361/* On frame F, translate pixel color to RGB values for the color in
3362 COLOR. Use cached information, if available. */
3363
3364void
3365x_query_color (f, color)
3366 struct frame *f;
3367 XColor *color;
3368{
3369 x_query_colors (f, color, 1);
3370}
3371
3372
06a2c219
GM
3373/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3374 CMAP. If an exact match can't be allocated, try the nearest color
3375 available. Value is non-zero if successful. Set *COLOR to the
3376 color allocated. */
3377
3378int
80c32bcc
GM
3379x_alloc_nearest_color (f, cmap, color)
3380 struct frame *f;
06a2c219
GM
3381 Colormap cmap;
3382 XColor *color;
3383{
80c32bcc
GM
3384 Display *display = FRAME_X_DISPLAY (f);
3385 Screen *screen = FRAME_X_SCREEN (f);
3386 int rc;
3387
3388 gamma_correct (f, color);
3389 rc = XAllocColor (display, cmap, color);
06a2c219
GM
3390 if (rc == 0)
3391 {
3392 /* If we got to this point, the colormap is full, so we're going
3393 to try to get the next closest color. The algorithm used is
3394 a least-squares matching, which is what X uses for closest
3395 color matching with StaticColor visuals. */
3396 int nearest, i;
3397 unsigned long nearest_delta = ~0;
f04e1297
GM
3398 int ncells;
3399 const XColor *cells = x_color_cells (f, &ncells);
06a2c219
GM
3400
3401 for (nearest = i = 0; i < ncells; ++i)
3402 {
3403 long dred = (color->red >> 8) - (cells[i].red >> 8);
3404 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3405 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3406 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3407
3408 if (delta < nearest_delta)
3409 {
3410 nearest = i;
3411 nearest_delta = delta;
3412 }
3413 }
3414
3415 color->red = cells[nearest].red;
3416 color->green = cells[nearest].green;
3417 color->blue = cells[nearest].blue;
3418 rc = XAllocColor (display, cmap, color);
3419 }
35efe0a1
GM
3420 else
3421 {
3422 /* If allocation succeeded, and the allocated pixel color is not
3423 equal to a cached pixel color recorded earlier, there was a
3424 change in the colormap, so clear the color cache. */
3425 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3426 XColor *cached_color;
3427
3428 if (dpyinfo->color_cells
3429 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
3430 (cached_color->red != color->red
3431 || cached_color->blue != color->blue
3432 || cached_color->green != color->green)))
35efe0a1
GM
3433 {
3434 xfree (dpyinfo->color_cells);
3435 dpyinfo->color_cells = NULL;
3436 dpyinfo->ncolor_cells = 0;
3437 }
3438 }
06a2c219 3439
d9c545da
GM
3440#ifdef DEBUG_X_COLORS
3441 if (rc)
3442 register_color (color->pixel);
3443#endif /* DEBUG_X_COLORS */
3444
06a2c219
GM
3445 return rc;
3446}
3447
3448
d9c545da
GM
3449/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3450 It's necessary to do this instead of just using PIXEL directly to
3451 get color reference counts right. */
3452
3453unsigned long
3454x_copy_color (f, pixel)
3455 struct frame *f;
3456 unsigned long pixel;
3457{
3458 XColor color;
3459
3460 color.pixel = pixel;
3461 BLOCK_INPUT;
f04e1297 3462 x_query_color (f, &color);
d9c545da
GM
3463 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3464 UNBLOCK_INPUT;
3465#ifdef DEBUG_X_COLORS
3466 register_color (pixel);
3467#endif
3468 return color.pixel;
3469}
3470
3471
3e71d8f2
GM
3472/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3473 It's necessary to do this instead of just using PIXEL directly to
3474 get color reference counts right. */
3475
3476unsigned long
3477x_copy_dpy_color (dpy, cmap, pixel)
3478 Display *dpy;
3479 Colormap cmap;
3480 unsigned long pixel;
3481{
3482 XColor color;
3483
3484 color.pixel = pixel;
3485 BLOCK_INPUT;
3486 XQueryColor (dpy, cmap, &color);
3487 XAllocColor (dpy, cmap, &color);
3488 UNBLOCK_INPUT;
3489#ifdef DEBUG_X_COLORS
3490 register_color (pixel);
3491#endif
3492 return color.pixel;
3493}
3494
3495
6d8b0acd 3496/* Brightness beyond which a color won't have its highlight brightness
d7361edf 3497 boosted.
6d8b0acd 3498
d7361edf
MB
3499 Nominally, highlight colors for `3d' faces are calculated by
3500 brightening an object's color by a constant scale factor, but this
3501 doesn't yield good results for dark colors, so for colors who's
3502 brightness is less than this value (on a scale of 0-65535) have an
3503 use an additional additive factor.
6d8b0acd
MB
3504
3505 The value here is set so that the default menu-bar/mode-line color
3506 (grey75) will not have its highlights changed at all. */
3507#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
3508
3509
06a2c219
GM
3510/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3511 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3512 If this produces the same color as PIXEL, try a color where all RGB
3513 values have DELTA added. Return the allocated color in *PIXEL.
3514 DISPLAY is the X display, CMAP is the colormap to operate on.
3515 Value is non-zero if successful. */
3516
3517static int
3518x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3519 struct frame *f;
3520 Display *display;
3521 Colormap cmap;
3522 unsigned long *pixel;
68c45bf0 3523 double factor;
06a2c219
GM
3524 int delta;
3525{
3526 XColor color, new;
6d8b0acd 3527 long bright;
06a2c219
GM
3528 int success_p;
3529
3530 /* Get RGB color values. */
3531 color.pixel = *pixel;
f04e1297 3532 x_query_color (f, &color);
06a2c219
GM
3533
3534 /* Change RGB values by specified FACTOR. Avoid overflow! */
3535 xassert (factor >= 0);
3536 new.red = min (0xffff, factor * color.red);
3537 new.green = min (0xffff, factor * color.green);
3538 new.blue = min (0xffff, factor * color.blue);
3539
d7361edf
MB
3540 /* Calculate brightness of COLOR. */
3541 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
3542
3543 /* We only boost colors that are darker than
3544 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3545 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3546 /* Make an additive adjustment to NEW, because it's dark enough so
3547 that scaling by FACTOR alone isn't enough. */
3548 {
3549 /* How far below the limit this color is (0 - 1, 1 being darker). */
3550 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3551 /* The additive adjustment. */
d7361edf 3552 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
3553
3554 if (factor < 1)
3555 {
6d8b0acd
MB
3556 new.red = max (0, new.red - min_delta);
3557 new.green = max (0, new.green - min_delta);
3558 new.blue = max (0, new.blue - min_delta);
3559 }
3560 else
3561 {
3562 new.red = min (0xffff, min_delta + new.red);
3563 new.green = min (0xffff, min_delta + new.green);
3564 new.blue = min (0xffff, min_delta + new.blue);
3565 }
3566 }
3567
06a2c219 3568 /* Try to allocate the color. */
80c32bcc 3569 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3570 if (success_p)
3571 {
3572 if (new.pixel == *pixel)
3573 {
3574 /* If we end up with the same color as before, try adding
3575 delta to the RGB values. */
0d605c67 3576 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3577
3578 new.red = min (0xffff, delta + color.red);
3579 new.green = min (0xffff, delta + color.green);
3580 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3581 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3582 }
3583 else
3584 success_p = 1;
3585 *pixel = new.pixel;
3586 }
3587
3588 return success_p;
3589}
3590
3591
3592/* Set up the foreground color for drawing relief lines of glyph
3593 string S. RELIEF is a pointer to a struct relief containing the GC
3594 with which lines will be drawn. Use a color that is FACTOR or
3595 DELTA lighter or darker than the relief's background which is found
3596 in S->f->output_data.x->relief_background. If such a color cannot
3597 be allocated, use DEFAULT_PIXEL, instead. */
3598
3599static void
3600x_setup_relief_color (f, relief, factor, delta, default_pixel)
3601 struct frame *f;
3602 struct relief *relief;
68c45bf0 3603 double factor;
06a2c219
GM
3604 int delta;
3605 unsigned long default_pixel;
3606{
3607 XGCValues xgcv;
3608 struct x_output *di = f->output_data.x;
3609 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3610 unsigned long pixel;
3611 unsigned long background = di->relief_background;
43bd1b2b 3612 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3613 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3614 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3615
3616 xgcv.graphics_exposures = False;
3617 xgcv.line_width = 1;
3618
3619 /* Free previously allocated color. The color cell will be reused
3620 when it has been freed as many times as it was allocated, so this
3621 doesn't affect faces using the same colors. */
3622 if (relief->gc
3623 && relief->allocated_p)
3624 {
0d605c67 3625 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3626 relief->allocated_p = 0;
3627 }
3628
3629 /* Allocate new color. */
3630 xgcv.foreground = default_pixel;
3631 pixel = background;
dcd08bfb
GM
3632 if (dpyinfo->n_planes != 1
3633 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3634 {
3635 relief->allocated_p = 1;
3636 xgcv.foreground = relief->pixel = pixel;
3637 }
3638
3639 if (relief->gc == 0)
3640 {
dcd08bfb 3641 xgcv.stipple = dpyinfo->gray;
06a2c219 3642 mask |= GCStipple;
dcd08bfb 3643 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3644 }
3645 else
dcd08bfb 3646 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3647}
3648
3649
3650/* Set up colors for the relief lines around glyph string S. */
3651
3652static void
3653x_setup_relief_colors (s)
3654 struct glyph_string *s;
3655{
3656 struct x_output *di = s->f->output_data.x;
3657 unsigned long color;
3658
3659 if (s->face->use_box_color_for_shadows_p)
3660 color = s->face->box_color;
3661 else
3662 {
3663 XGCValues xgcv;
3664
3665 /* Get the background color of the face. */
3666 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3667 color = xgcv.background;
3668 }
3669
3670 if (di->white_relief.gc == 0
3671 || color != di->relief_background)
3672 {
3673 di->relief_background = color;
3674 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3675 WHITE_PIX_DEFAULT (s->f));
3676 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3677 BLACK_PIX_DEFAULT (s->f));
3678 }
3679}
3680
3681
3682/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3683 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3684 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3685 relief. LEFT_P non-zero means draw a relief on the left side of
3686 the rectangle. RIGHT_P non-zero means draw a relief on the right
3687 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3688 when drawing. */
3689
3690static void
3691x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3692 raised_p, left_p, right_p, clip_rect)
3693 struct frame *f;
3694 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3695 XRectangle *clip_rect;
3696{
3697 int i;
3698 GC gc;
3699
3700 if (raised_p)
3701 gc = f->output_data.x->white_relief.gc;
3702 else
3703 gc = f->output_data.x->black_relief.gc;
3704 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3705
3706 /* Top. */
3707 for (i = 0; i < width; ++i)
3708 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3709 left_x + i * left_p, top_y + i,
3710 right_x + 1 - i * right_p, top_y + i);
3711
3712 /* Left. */
3713 if (left_p)
3714 for (i = 0; i < width; ++i)
3715 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3716 left_x + i, top_y + i, left_x + i, bottom_y - i);
3717
3718 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3719 if (raised_p)
3720 gc = f->output_data.x->black_relief.gc;
3721 else
3722 gc = f->output_data.x->white_relief.gc;
3723 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3724
3725 /* Bottom. */
3726 for (i = 0; i < width; ++i)
3727 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3728 left_x + i * left_p, bottom_y - i,
3729 right_x + 1 - i * right_p, bottom_y - i);
3730
3731 /* Right. */
3732 if (right_p)
3733 for (i = 0; i < width; ++i)
3734 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3735 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3736
3737 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3738}
3739
3740
3741/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3742 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3743 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3744 left side of the rectangle. RIGHT_P non-zero means draw a line
3745 on the right side of the rectangle. CLIP_RECT is the clipping
3746 rectangle to use when drawing. */
3747
3748static void
3749x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3750 left_p, right_p, clip_rect)
3751 struct glyph_string *s;
3752 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3753 XRectangle *clip_rect;
3754{
3755 XGCValues xgcv;
3756
3757 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3758 XSetForeground (s->display, s->gc, s->face->box_color);
3759 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3760
3761 /* Top. */
3762 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3763 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3764
3765 /* Left. */
3766 if (left_p)
3767 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3768 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3769
3770 /* Bottom. */
3771 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3772 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
06a2c219
GM
3773
3774 /* Right. */
3775 if (right_p)
3776 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3777 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3778
3779 XSetForeground (s->display, s->gc, xgcv.foreground);
3780 XSetClipMask (s->display, s->gc, None);
3781}
3782
3783
3784/* Draw a box around glyph string S. */
3785
3786static void
3787x_draw_glyph_string_box (s)
3788 struct glyph_string *s;
3789{
3790 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3791 int left_p, right_p;
3792 struct glyph *last_glyph;
3793 XRectangle clip_rect;
3794
3795 last_x = window_box_right (s->w, s->area);
3796 if (s->row->full_width_p
3797 && !s->w->pseudo_window_p)
3798 {
110859fc 3799 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3800 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3801 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3802 }
3803
3804 /* The glyph that may have a right box line. */
b4192550 3805 last_glyph = (s->cmp || s->img
06a2c219
GM
3806 ? s->first_glyph
3807 : s->first_glyph + s->nchars - 1);
3808
3809 width = s->face->box_line_width;
3810 raised_p = s->face->box == FACE_RAISED_BOX;
3811 left_x = s->x;
3812 right_x = ((s->row->full_width_p
1da3fd71 3813 ? last_x - 1
a7aeb2de 3814 : min (last_x, s->x + s->background_width) - 1));
06a2c219
GM
3815 top_y = s->y;
3816 bottom_y = top_y + s->height - 1;
3817
3818 left_p = (s->first_glyph->left_box_line_p
3819 || (s->hl == DRAW_MOUSE_FACE
3820 && (s->prev == NULL
3821 || s->prev->hl != s->hl)));
3822 right_p = (last_glyph->right_box_line_p
3823 || (s->hl == DRAW_MOUSE_FACE
3824 && (s->next == NULL
3825 || s->next->hl != s->hl)));
3826
3827 x_get_glyph_string_clip_rect (s, &clip_rect);
3828
3829 if (s->face->box == FACE_SIMPLE_BOX)
3830 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3831 left_p, right_p, &clip_rect);
3832 else
3833 {
3834 x_setup_relief_colors (s);
3835 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3836 width, raised_p, left_p, right_p, &clip_rect);
3837 }
3838}
3839
3840
3841/* Draw foreground of image glyph string S. */
3842
3843static void
3844x_draw_image_foreground (s)
3845 struct glyph_string *s;
3846{
3847 int x;
95af8492 3848 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3849
3850 /* If first glyph of S has a left box line, start drawing it to the
3851 right of that line. */
3852 if (s->face->box != FACE_NO_BOX
3853 && s->first_glyph->left_box_line_p)
3854 x = s->x + s->face->box_line_width;
3855 else
3856 x = s->x;
3857
3858 /* If there is a margin around the image, adjust x- and y-position
3859 by that margin. */
3860 if (s->img->margin)
3861 {
3862 x += s->img->margin;
3863 y += s->img->margin;
3864 }
3865
3866 if (s->img->pixmap)
3867 {
3868 if (s->img->mask)
3869 {
3870 /* We can't set both a clip mask and use XSetClipRectangles
3871 because the latter also sets a clip mask. We also can't
3872 trust on the shape extension to be available
3873 (XShapeCombineRegion). So, compute the rectangle to draw
3874 manually. */
3875 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3876 | GCFunction);
3877 XGCValues xgcv;
3878 XRectangle clip_rect, image_rect, r;
3879
3880 xgcv.clip_mask = s->img->mask;
3881 xgcv.clip_x_origin = x;
3882 xgcv.clip_y_origin = y;
3883 xgcv.function = GXcopy;
3884 XChangeGC (s->display, s->gc, mask, &xgcv);
3885
3886 x_get_glyph_string_clip_rect (s, &clip_rect);
3887 image_rect.x = x;
3888 image_rect.y = y;
3889 image_rect.width = s->img->width;
3890 image_rect.height = s->img->height;
3891 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
3892 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3893 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
3894 }
3895 else
3896 {
49ad1d99
GM
3897 unsigned long mask = GCClipXOrigin | GCClipYOrigin | GCFunction;
3898 XGCValues xgcv;
3899 XRectangle clip_rect, image_rect, r;
3900
3901 x_get_glyph_string_clip_rect (s, &clip_rect);
3902 image_rect.x = x;
3903 image_rect.y = y;
3904 image_rect.width = s->img->width;
3905 image_rect.height = s->img->height;
3906 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
3907 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3908 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
06a2c219
GM
3909
3910 /* When the image has a mask, we can expect that at
3911 least part of a mouse highlight or a block cursor will
3912 be visible. If the image doesn't have a mask, make
3913 a block cursor visible by drawing a rectangle around
3914 the image. I believe it's looking better if we do
3915 nothing here for mouse-face. */
3916 if (s->hl == DRAW_CURSOR)
3917 XDrawRectangle (s->display, s->window, s->gc, x, y,
3918 s->img->width - 1, s->img->height - 1);
3919 }
3920 }
3921 else
3922 /* Draw a rectangle if image could not be loaded. */
3923 XDrawRectangle (s->display, s->window, s->gc, x, y,
3924 s->img->width - 1, s->img->height - 1);
3925}
3926
3927
3928/* Draw a relief around the image glyph string S. */
3929
3930static void
3931x_draw_image_relief (s)
3932 struct glyph_string *s;
3933{
3934 int x0, y0, x1, y1, thick, raised_p;
3935 XRectangle r;
3936 int x;
95af8492 3937 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3938
3939 /* If first glyph of S has a left box line, start drawing it to the
3940 right of that line. */
3941 if (s->face->box != FACE_NO_BOX
3942 && s->first_glyph->left_box_line_p)
3943 x = s->x + s->face->box_line_width;
3944 else
3945 x = s->x;
3946
3947 /* If there is a margin around the image, adjust x- and y-position
3948 by that margin. */
3949 if (s->img->margin)
3950 {
3951 x += s->img->margin;
3952 y += s->img->margin;
3953 }
3954
3955 if (s->hl == DRAW_IMAGE_SUNKEN
3956 || s->hl == DRAW_IMAGE_RAISED)
3957 {
9ea173e8 3958 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
3959 raised_p = s->hl == DRAW_IMAGE_RAISED;
3960 }
3961 else
3962 {
3963 thick = abs (s->img->relief);
3964 raised_p = s->img->relief > 0;
3965 }
3966
3967 x0 = x - thick;
3968 y0 = y - thick;
3969 x1 = x + s->img->width + thick - 1;
3970 y1 = y + s->img->height + thick - 1;
3971
3972 x_setup_relief_colors (s);
3973 x_get_glyph_string_clip_rect (s, &r);
3974 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
3975}
3976
3977
3978/* Draw the foreground of image glyph string S to PIXMAP. */
3979
3980static void
3981x_draw_image_foreground_1 (s, pixmap)
3982 struct glyph_string *s;
3983 Pixmap pixmap;
3984{
3985 int x;
95af8492 3986 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
3987
3988 /* If first glyph of S has a left box line, start drawing it to the
3989 right of that line. */
3990 if (s->face->box != FACE_NO_BOX
3991 && s->first_glyph->left_box_line_p)
3992 x = s->face->box_line_width;
3993 else
3994 x = 0;
3995
3996 /* If there is a margin around the image, adjust x- and y-position
3997 by that margin. */
3998 if (s->img->margin)
3999 {
4000 x += s->img->margin;
4001 y += s->img->margin;
4002 }
dc43ef94 4003
06a2c219
GM
4004 if (s->img->pixmap)
4005 {
4006 if (s->img->mask)
4007 {
4008 /* We can't set both a clip mask and use XSetClipRectangles
4009 because the latter also sets a clip mask. We also can't
4010 trust on the shape extension to be available
4011 (XShapeCombineRegion). So, compute the rectangle to draw
4012 manually. */
4013 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4014 | GCFunction);
4015 XGCValues xgcv;
4016
4017 xgcv.clip_mask = s->img->mask;
4018 xgcv.clip_x_origin = x;
4019 xgcv.clip_y_origin = y;
4020 xgcv.function = GXcopy;
4021 XChangeGC (s->display, s->gc, mask, &xgcv);
4022
4023 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4024 0, 0, s->img->width, s->img->height, x, y);
4025 XSetClipMask (s->display, s->gc, None);
4026 }
4027 else
4028 {
4029 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4030 0, 0, s->img->width, s->img->height, x, y);
4031
4032 /* When the image has a mask, we can expect that at
4033 least part of a mouse highlight or a block cursor will
4034 be visible. If the image doesn't have a mask, make
4035 a block cursor visible by drawing a rectangle around
4036 the image. I believe it's looking better if we do
4037 nothing here for mouse-face. */
4038 if (s->hl == DRAW_CURSOR)
4039 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4040 s->img->width - 1, s->img->height - 1);
4041 }
4042 }
4043 else
4044 /* Draw a rectangle if image could not be loaded. */
4045 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4046 s->img->width - 1, s->img->height - 1);
4047}
dc43ef94 4048
990ba854 4049
06a2c219
GM
4050/* Draw part of the background of glyph string S. X, Y, W, and H
4051 give the rectangle to draw. */
a9a5b0a5 4052
06a2c219
GM
4053static void
4054x_draw_glyph_string_bg_rect (s, x, y, w, h)
4055 struct glyph_string *s;
4056 int x, y, w, h;
4057{
4058 if (s->stippled_p)
4059 {
4060 /* Fill background with a stipple pattern. */
4061 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4062 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4063 XSetFillStyle (s->display, s->gc, FillSolid);
4064 }
4065 else
4066 x_clear_glyph_string_rect (s, x, y, w, h);
4067}
07e34cb0 4068
b5210ea7 4069
06a2c219 4070/* Draw image glyph string S.
dc43ef94 4071
06a2c219
GM
4072 s->y
4073 s->x +-------------------------
4074 | s->face->box
4075 |
4076 | +-------------------------
4077 | | s->img->margin
4078 | |
4079 | | +-------------------
4080 | | | the image
dc43ef94 4081
06a2c219 4082 */
dc43ef94 4083
06a2c219
GM
4084static void
4085x_draw_image_glyph_string (s)
4086 struct glyph_string *s;
4087{
4088 int x, y;
4089 int box_line_width = s->face->box_line_width;
4090 int margin = s->img->margin;
4091 int height;
4092 Pixmap pixmap = None;
4093
4094 height = s->height - 2 * box_line_width;
4095
4096 /* Fill background with face under the image. Do it only if row is
4097 taller than image or if image has a clip mask to reduce
4098 flickering. */
4099 s->stippled_p = s->face->stipple != 0;
4100 if (height > s->img->height
4101 || margin
4102 || s->img->mask
4103 || s->img->pixmap == 0
4104 || s->width != s->background_width)
4105 {
4106 if (box_line_width && s->first_glyph->left_box_line_p)
4107 x = s->x + box_line_width;
4108 else
4109 x = s->x;
4110
4111 y = s->y + box_line_width;
4112
4113 if (s->img->mask)
4114 {
f9b5db02
GM
4115 /* Create a pixmap as large as the glyph string. Fill it
4116 with the background color. Copy the image to it, using
4117 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4118 Screen *screen = FRAME_X_SCREEN (s->f);
4119 int depth = DefaultDepthOfScreen (screen);
4120
4121 /* Create a pixmap as large as the glyph string. */
4122 pixmap = XCreatePixmap (s->display, s->window,
4123 s->background_width,
4124 s->height, depth);
4125
4126 /* Don't clip in the following because we're working on the
4127 pixmap. */
4128 XSetClipMask (s->display, s->gc, None);
4129
4130 /* Fill the pixmap with the background color/stipple. */
4131 if (s->stippled_p)
4132 {
4133 /* Fill background with a stipple pattern. */
4134 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4135 XFillRectangle (s->display, pixmap, s->gc,
4136 0, 0, s->background_width, s->height);
4137 XSetFillStyle (s->display, s->gc, FillSolid);
4138 }
4139 else
4140 {
4141 XGCValues xgcv;
4142 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4143 &xgcv);
4144 XSetForeground (s->display, s->gc, xgcv.background);
4145 XFillRectangle (s->display, pixmap, s->gc,
4146 0, 0, s->background_width, s->height);
4147 XSetForeground (s->display, s->gc, xgcv.foreground);
4148 }
4149 }
4150 else
06a2c219
GM
4151 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4152
4153 s->background_filled_p = 1;
4154 }
dc43ef94 4155
06a2c219
GM
4156 /* Draw the foreground. */
4157 if (pixmap != None)
4158 {
4159 x_draw_image_foreground_1 (s, pixmap);
4160 x_set_glyph_string_clipping (s);
4161 XCopyArea (s->display, pixmap, s->window, s->gc,
4162 0, 0, s->background_width, s->height, s->x, s->y);
4163 XFreePixmap (s->display, pixmap);
4164 }
4165 else
4166 x_draw_image_foreground (s);
b5210ea7 4167
06a2c219
GM
4168 /* If we must draw a relief around the image, do it. */
4169 if (s->img->relief
4170 || s->hl == DRAW_IMAGE_RAISED
4171 || s->hl == DRAW_IMAGE_SUNKEN)
4172 x_draw_image_relief (s);
4173}
8c1a6a84 4174
990ba854 4175
06a2c219 4176/* Draw stretch glyph string S. */
dc43ef94 4177
06a2c219
GM
4178static void
4179x_draw_stretch_glyph_string (s)
4180 struct glyph_string *s;
4181{
4182 xassert (s->first_glyph->type == STRETCH_GLYPH);
4183 s->stippled_p = s->face->stipple != 0;
990ba854 4184
06a2c219
GM
4185 if (s->hl == DRAW_CURSOR
4186 && !x_stretch_cursor_p)
4187 {
4188 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4189 as wide as the stretch glyph. */
4190 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4191
06a2c219
GM
4192 /* Draw cursor. */
4193 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4194
06a2c219
GM
4195 /* Clear rest using the GC of the original non-cursor face. */
4196 if (width < s->background_width)
4197 {
4198 GC gc = s->face->gc;
4199 int x = s->x + width, y = s->y;
4200 int w = s->background_width - width, h = s->height;
4201 XRectangle r;
dc43ef94 4202
06a2c219
GM
4203 x_get_glyph_string_clip_rect (s, &r);
4204 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
97210f4e 4205
06a2c219
GM
4206 if (s->face->stipple)
4207 {
4208 /* Fill background with a stipple pattern. */
4209 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4210 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4211 XSetFillStyle (s->display, gc, FillSolid);
4212 }
4213 else
4214 {
4215 XGCValues xgcv;
4216 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4217 XSetForeground (s->display, gc, xgcv.background);
4218 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4219 XSetForeground (s->display, gc, xgcv.foreground);
4220 }
4221 }
4222 }
4223 else
4224 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4225 s->height);
4226
4227 s->background_filled_p = 1;
4228}
4229
4230
4231/* Draw glyph string S. */
4232
4233static void
4234x_draw_glyph_string (s)
4235 struct glyph_string *s;
4236{
4237 /* If S draws into the background of its successor, draw the
4238 background of the successor first so that S can draw into it.
4239 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4240 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4241 {
4242 xassert (s->next->img == NULL);
4243 x_set_glyph_string_gc (s->next);
4244 x_set_glyph_string_clipping (s->next);
4245 x_draw_glyph_string_background (s->next, 1);
4246 }
97210f4e 4247
06a2c219
GM
4248 /* Set up S->gc, set clipping and draw S. */
4249 x_set_glyph_string_gc (s);
4250 x_set_glyph_string_clipping (s);
4251
4252 switch (s->first_glyph->type)
4253 {
4254 case IMAGE_GLYPH:
4255 x_draw_image_glyph_string (s);
4256 break;
4257
4258 case STRETCH_GLYPH:
4259 x_draw_stretch_glyph_string (s);
4260 break;
4261
4262 case CHAR_GLYPH:
66ac4b0e
GM
4263 if (s->for_overlaps_p)
4264 s->background_filled_p = 1;
4265 else
4266 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4267 x_draw_glyph_string_foreground (s);
4268 break;
4269
b4192550
KH
4270 case COMPOSITE_GLYPH:
4271 if (s->for_overlaps_p || s->gidx > 0)
4272 s->background_filled_p = 1;
4273 else
4274 x_draw_glyph_string_background (s, 1);
4275 x_draw_composite_glyph_string_foreground (s);
4276 break;
4277
06a2c219
GM
4278 default:
4279 abort ();
4280 }
4281
66ac4b0e 4282 if (!s->for_overlaps_p)
06a2c219 4283 {
66ac4b0e
GM
4284 /* Draw underline. */
4285 if (s->face->underline_p)
4286 {
e24e84cc
GM
4287 unsigned long tem, h;
4288 int y;
06a2c219 4289
e24e84cc 4290 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4291 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4292 h = 1;
e24e84cc
GM
4293
4294 /* Get the underline position. This is the recommended
4295 vertical offset in pixels from the baseline to the top of
4296 the underline. This is a signed value according to the
4297 specs, and its default is
4298
4299 ROUND ((maximum descent) / 2), with
4300 ROUND(x) = floor (x + 0.5) */
4301
4302 if (XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
4303 y = s->ybase + (long) tem;
4304 else if (s->face->font)
4305 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4306 else
4307 y = s->height - h;
06a2c219 4308
66ac4b0e 4309 if (s->face->underline_defaulted_p)
e24e84cc
GM
4310 XFillRectangle (s->display, s->window, s->gc,
4311 s->x, y, s->width, h);
66ac4b0e
GM
4312 else
4313 {
4314 XGCValues xgcv;
4315 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4316 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4317 XFillRectangle (s->display, s->window, s->gc,
4318 s->x, y, s->width, h);
66ac4b0e
GM
4319 XSetForeground (s->display, s->gc, xgcv.foreground);
4320 }
dc6f92b8 4321 }
07e34cb0 4322
66ac4b0e
GM
4323 /* Draw overline. */
4324 if (s->face->overline_p)
06a2c219 4325 {
66ac4b0e
GM
4326 unsigned long dy = 0, h = 1;
4327
4328 if (s->face->overline_color_defaulted_p)
4329 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4330 s->width, h);
4331 else
4332 {
4333 XGCValues xgcv;
4334 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4335 XSetForeground (s->display, s->gc, s->face->overline_color);
4336 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4337 s->width, h);
4338 XSetForeground (s->display, s->gc, xgcv.foreground);
4339 }
06a2c219 4340 }
06a2c219 4341
66ac4b0e
GM
4342 /* Draw strike-through. */
4343 if (s->face->strike_through_p)
06a2c219 4344 {
66ac4b0e
GM
4345 unsigned long h = 1;
4346 unsigned long dy = (s->height - h) / 2;
4347
4348 if (s->face->strike_through_color_defaulted_p)
4349 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4350 s->width, h);
4351 else
4352 {
4353 XGCValues xgcv;
4354 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4355 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4356 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4357 s->width, h);
4358 XSetForeground (s->display, s->gc, xgcv.foreground);
4359 }
06a2c219 4360 }
06a2c219 4361
66ac4b0e
GM
4362 /* Draw relief. */
4363 if (s->face->box != FACE_NO_BOX)
4364 x_draw_glyph_string_box (s);
4365 }
06a2c219
GM
4366
4367 /* Reset clipping. */
4368 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4369}
07e34cb0 4370
06a2c219 4371
b4192550
KH
4372static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4373 struct face **, int));
06a2c219 4374
06a2c219 4375
209f68d9
GM
4376/* Fill glyph string S with composition components specified by S->cmp.
4377
b4192550
KH
4378 FACES is an array of faces for all components of this composition.
4379 S->gidx is the index of the first component for S.
4380 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4381 use its physical height for clipping.
06a2c219 4382
b4192550 4383 Value is the index of a component not in S. */
07e34cb0 4384
b4192550
KH
4385static int
4386x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4387 struct glyph_string *s;
b4192550 4388 struct face **faces;
66ac4b0e 4389 int overlaps_p;
07e34cb0 4390{
b4192550 4391 int i;
06a2c219 4392
b4192550 4393 xassert (s);
06a2c219 4394
b4192550 4395 s->for_overlaps_p = overlaps_p;
06a2c219 4396
b4192550
KH
4397 s->face = faces[s->gidx];
4398 s->font = s->face->font;
4399 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4400
b4192550
KH
4401 /* For all glyphs of this composition, starting at the offset
4402 S->gidx, until we reach the end of the definition or encounter a
4403 glyph that requires the different face, add it to S. */
4404 ++s->nchars;
4405 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4406 ++s->nchars;
06a2c219 4407
b4192550
KH
4408 /* All glyph strings for the same composition has the same width,
4409 i.e. the width set for the first component of the composition. */
06a2c219 4410
06a2c219
GM
4411 s->width = s->first_glyph->pixel_width;
4412
4413 /* If the specified font could not be loaded, use the frame's
4414 default font, but record the fact that we couldn't load it in
4415 the glyph string so that we can draw rectangles for the
4416 characters of the glyph string. */
4417 if (s->font == NULL)
4418 {
4419 s->font_not_found_p = 1;
4420 s->font = FRAME_FONT (s->f);
4421 }
4422
4423 /* Adjust base line for subscript/superscript text. */
4424 s->ybase += s->first_glyph->voffset;
4425
4426 xassert (s->face && s->face->gc);
4427
4428 /* This glyph string must always be drawn with 16-bit functions. */
4429 s->two_byte_p = 1;
b4192550
KH
4430
4431 return s->gidx + s->nchars;
06a2c219
GM
4432}
4433
4434
209f68d9
GM
4435/* Fill glyph string S from a sequence of character glyphs.
4436
06a2c219 4437 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4438 first glyph to consider, END is the index of the last + 1.
4439 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4440 use its physical height for clipping.
66ac4b0e
GM
4441
4442 Value is the index of the first glyph not in S. */
06a2c219
GM
4443
4444static int
66ac4b0e 4445x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4446 struct glyph_string *s;
4447 int face_id;
66ac4b0e 4448 int start, end, overlaps_p;
06a2c219
GM
4449{
4450 struct glyph *glyph, *last;
4451 int voffset;
ee569018 4452 int glyph_not_available_p;
06a2c219 4453
06a2c219
GM
4454 xassert (s->f == XFRAME (s->w->frame));
4455 xassert (s->nchars == 0);
4456 xassert (start >= 0 && end > start);
4457
66ac4b0e 4458 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4459 glyph = s->row->glyphs[s->area] + start;
4460 last = s->row->glyphs[s->area] + end;
4461 voffset = glyph->voffset;
4462
ee569018
KH
4463 glyph_not_available_p = glyph->glyph_not_available_p;
4464
06a2c219
GM
4465 while (glyph < last
4466 && glyph->type == CHAR_GLYPH
4467 && glyph->voffset == voffset
ee569018
KH
4468 /* Same face id implies same font, nowadays. */
4469 && glyph->face_id == face_id
4470 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4471 {
ee569018
KH
4472 int two_byte_p;
4473
06a2c219 4474 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4475 s->char2b + s->nchars,
4476 &two_byte_p);
4477 s->two_byte_p = two_byte_p;
06a2c219
GM
4478 ++s->nchars;
4479 xassert (s->nchars <= end - start);
4480 s->width += glyph->pixel_width;
4481 ++glyph;
4482 }
4483
4484 s->font = s->face->font;
4485 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4486
4487 /* If the specified font could not be loaded, use the frame's font,
4488 but record the fact that we couldn't load it in
4489 S->font_not_found_p so that we can draw rectangles for the
4490 characters of the glyph string. */
ee569018 4491 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4492 {
4493 s->font_not_found_p = 1;
4494 s->font = FRAME_FONT (s->f);
4495 }
4496
4497 /* Adjust base line for subscript/superscript text. */
4498 s->ybase += voffset;
66ac4b0e 4499
06a2c219
GM
4500 xassert (s->face && s->face->gc);
4501 return glyph - s->row->glyphs[s->area];
07e34cb0 4502}
dc6f92b8 4503
06a2c219
GM
4504
4505/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4506
dfcf069d 4507static void
06a2c219
GM
4508x_fill_image_glyph_string (s)
4509 struct glyph_string *s;
4510{
4511 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4512 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4513 xassert (s->img);
43d120d8 4514 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4515 s->font = s->face->font;
4516 s->width = s->first_glyph->pixel_width;
4517
4518 /* Adjust base line for subscript/superscript text. */
4519 s->ybase += s->first_glyph->voffset;
4520}
4521
4522
209f68d9 4523/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4524
209f68d9
GM
4525 ROW is the glyph row in which the glyphs are found, AREA is the
4526 area within the row. START is the index of the first glyph to
4527 consider, END is the index of the last + 1.
4528
4529 Value is the index of the first glyph not in S. */
4530
4531static int
4532x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4533 struct glyph_string *s;
209f68d9
GM
4534 struct glyph_row *row;
4535 enum glyph_row_area area;
4536 int start, end;
06a2c219 4537{
209f68d9
GM
4538 struct glyph *glyph, *last;
4539 int voffset, face_id;
4540
06a2c219 4541 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4542
4543 glyph = s->row->glyphs[s->area] + start;
4544 last = s->row->glyphs[s->area] + end;
4545 face_id = glyph->face_id;
4546 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4547 s->font = s->face->font;
209f68d9
GM
4548 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4549 s->width = glyph->pixel_width;
4550 voffset = glyph->voffset;
4551
4552 for (++glyph;
4553 (glyph < last
4554 && glyph->type == STRETCH_GLYPH
4555 && glyph->voffset == voffset
4556 && glyph->face_id == face_id);
4557 ++glyph)
4558 s->width += glyph->pixel_width;
06a2c219
GM
4559
4560 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4561 s->ybase += voffset;
4562
4563 xassert (s->face && s->face->gc);
4564 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4565}
4566
4567
4568/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4569 of XChar2b structures for S; it can't be allocated in
4570 x_init_glyph_string because it must be allocated via `alloca'. W
4571 is the window on which S is drawn. ROW and AREA are the glyph row
4572 and area within the row from which S is constructed. START is the
4573 index of the first glyph structure covered by S. HL is a
4574 face-override for drawing S. */
4575
4576static void
4577x_init_glyph_string (s, char2b, w, row, area, start, hl)
4578 struct glyph_string *s;
4579 XChar2b *char2b;
4580 struct window *w;
4581 struct glyph_row *row;
4582 enum glyph_row_area area;
4583 int start;
4584 enum draw_glyphs_face hl;
4585{
4586 bzero (s, sizeof *s);
4587 s->w = w;
4588 s->f = XFRAME (w->frame);
4589 s->display = FRAME_X_DISPLAY (s->f);
4590 s->window = FRAME_X_WINDOW (s->f);
4591 s->char2b = char2b;
4592 s->hl = hl;
4593 s->row = row;
4594 s->area = area;
4595 s->first_glyph = row->glyphs[area] + start;
4596 s->height = row->height;
4597 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4598
9ea173e8
GM
4599 /* Display the internal border below the tool-bar window. */
4600 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4601 s->y -= s->f->output_data.x->internal_border_width;
4602
4603 s->ybase = s->y + row->ascent;
4604}
4605
4606
4607/* Set background width of glyph string S. START is the index of the
4608 first glyph following S. LAST_X is the right-most x-position + 1
4609 in the drawing area. */
4610
4611static INLINE void
4612x_set_glyph_string_background_width (s, start, last_x)
4613 struct glyph_string *s;
4614 int start;
4615 int last_x;
4616{
4617 /* If the face of this glyph string has to be drawn to the end of
4618 the drawing area, set S->extends_to_end_of_line_p. */
4619 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4620
4621 if (start == s->row->used[s->area]
4622 && s->hl == DRAW_NORMAL_TEXT
4623 && ((s->area == TEXT_AREA && s->row->fill_line_p)
4624 || s->face->background != default_face->background
4625 || s->face->stipple != default_face->stipple))
4626 s->extends_to_end_of_line_p = 1;
4627
4628 /* If S extends its face to the end of the line, set its
4629 background_width to the distance to the right edge of the drawing
4630 area. */
4631 if (s->extends_to_end_of_line_p)
1da3fd71 4632 s->background_width = last_x - s->x + 1;
06a2c219
GM
4633 else
4634 s->background_width = s->width;
4635}
4636
4637
4638/* Add a glyph string for a stretch glyph to the list of strings
4639 between HEAD and TAIL. START is the index of the stretch glyph in
4640 row area AREA of glyph row ROW. END is the index of the last glyph
4641 in that glyph row area. X is the current output position assigned
4642 to the new glyph string constructed. HL overrides that face of the
4643 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4644 is the right-most x-position of the drawing area. */
4645
8abee2e1
DL
4646/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4647 and below -- keep them on one line. */
4648#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4649 do \
4650 { \
4651 s = (struct glyph_string *) alloca (sizeof *s); \
4652 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4653 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4654 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4655 s->x = (X); \
4656 } \
4657 while (0)
4658
4659
4660/* Add a glyph string for an image glyph to the list of strings
4661 between HEAD and TAIL. START is the index of the image glyph in
4662 row area AREA of glyph row ROW. END is the index of the last glyph
4663 in that glyph row area. X is the current output position assigned
4664 to the new glyph string constructed. HL overrides that face of the
4665 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4666 is the right-most x-position of the drawing area. */
4667
8abee2e1 4668#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4669 do \
4670 { \
4671 s = (struct glyph_string *) alloca (sizeof *s); \
4672 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4673 x_fill_image_glyph_string (s); \
4674 x_append_glyph_string (&HEAD, &TAIL, s); \
4675 ++START; \
4676 s->x = (X); \
4677 } \
4678 while (0)
4679
4680
4681/* Add a glyph string for a sequence of character glyphs to the list
4682 of strings between HEAD and TAIL. START is the index of the first
4683 glyph in row area AREA of glyph row ROW that is part of the new
4684 glyph string. END is the index of the last glyph in that glyph row
4685 area. X is the current output position assigned to the new glyph
4686 string constructed. HL overrides that face of the glyph; e.g. it
4687 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4688 right-most x-position of the drawing area. */
4689
8abee2e1 4690#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4691 do \
4692 { \
3e71d8f2 4693 int c, face_id; \
06a2c219
GM
4694 XChar2b *char2b; \
4695 \
43d120d8 4696 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4697 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4698 \
b4192550
KH
4699 s = (struct glyph_string *) alloca (sizeof *s); \
4700 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4701 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4702 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4703 s->x = (X); \
4704 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4705 OVERLAPS_P); \
06a2c219
GM
4706 } \
4707 while (0)
4708
4709
b4192550
KH
4710/* Add a glyph string for a composite sequence to the list of strings
4711 between HEAD and TAIL. START is the index of the first glyph in
4712 row area AREA of glyph row ROW that is part of the new glyph
4713 string. END is the index of the last glyph in that glyph row area.
4714 X is the current output position assigned to the new glyph string
4715 constructed. HL overrides that face of the glyph; e.g. it is
4716 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4717 x-position of the drawing area. */
4718
6c27ec25 4719#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4720 do { \
43d120d8
KH
4721 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4722 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4723 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4724 struct composition *cmp = composition_table[cmp_id]; \
4725 int glyph_len = cmp->glyph_len; \
4726 XChar2b *char2b; \
4727 struct face **faces; \
4728 struct glyph_string *first_s = NULL; \
4729 int n; \
4730 \
ee569018 4731 base_face = base_face->ascii_face; \
b4192550
KH
4732 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4733 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4734 /* At first, fill in `char2b' and `faces'. */ \
4735 for (n = 0; n < glyph_len; n++) \
4736 { \
43d120d8 4737 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4738 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4739 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4740 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4741 this_face_id, char2b + n, 1); \
b4192550
KH
4742 } \
4743 \
4744 /* Make glyph_strings for each glyph sequence that is drawable by \
4745 the same face, and append them to HEAD/TAIL. */ \
4746 for (n = 0; n < cmp->glyph_len;) \
4747 { \
4748 s = (struct glyph_string *) alloca (sizeof *s); \
4749 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4750 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4751 s->cmp = cmp; \
4752 s->gidx = n; \
b4192550
KH
4753 s->x = (X); \
4754 \
4755 if (n == 0) \
4756 first_s = s; \
4757 \
4758 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4759 } \
4760 \
4761 ++START; \
4762 s = first_s; \
4763 } while (0)
4764
4765
06a2c219
GM
4766/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4767 of AREA of glyph row ROW on window W between indices START and END.
4768 HL overrides the face for drawing glyph strings, e.g. it is
4769 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4770 x-positions of the drawing area.
4771
4772 This is an ugly monster macro construct because we must use alloca
4773 to allocate glyph strings (because x_draw_glyphs can be called
4774 asynchronously). */
4775
8abee2e1 4776#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4777 do \
4778 { \
4779 HEAD = TAIL = NULL; \
4780 while (START < END) \
4781 { \
4782 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4783 switch (first_glyph->type) \
4784 { \
4785 case CHAR_GLYPH: \
4786 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4787 TAIL, HL, X, LAST_X, \
4788 OVERLAPS_P); \
06a2c219
GM
4789 break; \
4790 \
b4192550
KH
4791 case COMPOSITE_GLYPH: \
4792 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
4793 HEAD, TAIL, HL, X, LAST_X,\
4794 OVERLAPS_P); \
4795 break; \
4796 \
06a2c219
GM
4797 case STRETCH_GLYPH: \
4798 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
4799 HEAD, TAIL, HL, X, LAST_X); \
4800 break; \
4801 \
4802 case IMAGE_GLYPH: \
4803 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
4804 TAIL, HL, X, LAST_X); \
4805 break; \
4806 \
4807 default: \
4808 abort (); \
4809 } \
4810 \
4811 x_set_glyph_string_background_width (s, START, LAST_X); \
4812 (X) += s->width; \
4813 } \
4814 } \
4815 while (0)
4816
4817
4818/* Draw glyphs between START and END in AREA of ROW on window W,
4819 starting at x-position X. X is relative to AREA in W. HL is a
4820 face-override with the following meaning:
4821
4822 DRAW_NORMAL_TEXT draw normally
4823 DRAW_CURSOR draw in cursor face
4824 DRAW_MOUSE_FACE draw in mouse face.
4825 DRAW_INVERSE_VIDEO draw in mode line face
4826 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
4827 DRAW_IMAGE_RAISED draw an image with a raised relief around it
4828
4829 If REAL_START is non-null, return in *REAL_START the real starting
4830 position for display. This can be different from START in case
4831 overlapping glyphs must be displayed. If REAL_END is non-null,
4832 return in *REAL_END the real end position for display. This can be
4833 different from END in case overlapping glyphs must be displayed.
4834
66ac4b0e
GM
4835 If OVERLAPS_P is non-zero, draw only the foreground of characters
4836 and clip to the physical height of ROW.
4837
06a2c219
GM
4838 Value is the x-position reached, relative to AREA of W. */
4839
4840static int
66ac4b0e
GM
4841x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
4842 overlaps_p)
06a2c219
GM
4843 struct window *w;
4844 int x;
4845 struct glyph_row *row;
4846 enum glyph_row_area area;
4847 int start, end;
4848 enum draw_glyphs_face hl;
4849 int *real_start, *real_end;
66ac4b0e 4850 int overlaps_p;
dc6f92b8 4851{
06a2c219
GM
4852 struct glyph_string *head, *tail;
4853 struct glyph_string *s;
4854 int last_x, area_width;
4855 int x_reached;
4856 int i, j;
4857
4858 /* Let's rather be paranoid than getting a SEGV. */
06a2c219 4859 end = min (end, row->used[area]);
a8710abf
GM
4860 start = max (0, start);
4861 start = min (end, start);
06a2c219
GM
4862 if (real_start)
4863 *real_start = start;
4864 if (real_end)
4865 *real_end = end;
4866
4867 /* Translate X to frame coordinates. Set last_x to the right
4868 end of the drawing area. */
4869 if (row->full_width_p)
4870 {
4871 /* X is relative to the left edge of W, without scroll bars
4872 or flag areas. */
4873 struct frame *f = XFRAME (w->frame);
110859fc 4874 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 4875 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 4876
06a2c219
GM
4877 x += window_left_x;
4878 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
4879 last_x = window_left_x + area_width;
4880
4881 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4882 {
110859fc 4883 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
4884 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
4885 last_x += width;
4886 else
4887 x -= width;
4888 }
dc6f92b8 4889
b9432a85
GM
4890 x += FRAME_INTERNAL_BORDER_WIDTH (f);
4891 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
4892 }
4893 else
dc6f92b8 4894 {
06a2c219
GM
4895 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
4896 area_width = window_box_width (w, area);
4897 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
4898 }
4899
06a2c219
GM
4900 /* Build a doubly-linked list of glyph_string structures between
4901 head and tail from what we have to draw. Note that the macro
4902 BUILD_GLYPH_STRINGS will modify its start parameter. That's
4903 the reason we use a separate variable `i'. */
4904 i = start;
66ac4b0e
GM
4905 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
4906 overlaps_p);
06a2c219
GM
4907 if (tail)
4908 x_reached = tail->x + tail->background_width;
4909 else
4910 x_reached = x;
90e65f07 4911
06a2c219
GM
4912 /* If there are any glyphs with lbearing < 0 or rbearing > width in
4913 the row, redraw some glyphs in front or following the glyph
4914 strings built above. */
a8710abf 4915 if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
4916 {
4917 int dummy_x = 0;
4918 struct glyph_string *h, *t;
4919
4920 /* Compute overhangs for all glyph strings. */
4921 for (s = head; s; s = s->next)
4922 x_compute_glyph_string_overhangs (s);
4923
4924 /* Prepend glyph strings for glyphs in front of the first glyph
4925 string that are overwritten because of the first glyph
4926 string's left overhang. The background of all strings
4927 prepended must be drawn because the first glyph string
4928 draws over it. */
4929 i = x_left_overwritten (head);
4930 if (i >= 0)
4931 {
4932 j = i;
4933 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
4934 DRAW_NORMAL_TEXT, dummy_x, last_x,
4935 overlaps_p);
06a2c219
GM
4936 start = i;
4937 if (real_start)
4938 *real_start = start;
4939 x_compute_overhangs_and_x (t, head->x, 1);
4940 x_prepend_glyph_string_lists (&head, &tail, h, t);
4941 }
58769bee 4942
06a2c219
GM
4943 /* Prepend glyph strings for glyphs in front of the first glyph
4944 string that overwrite that glyph string because of their
4945 right overhang. For these strings, only the foreground must
4946 be drawn, because it draws over the glyph string at `head'.
4947 The background must not be drawn because this would overwrite
4948 right overhangs of preceding glyphs for which no glyph
4949 strings exist. */
4950 i = x_left_overwriting (head);
4951 if (i >= 0)
4952 {
4953 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
4954 DRAW_NORMAL_TEXT, dummy_x, last_x,
4955 overlaps_p);
06a2c219
GM
4956 for (s = h; s; s = s->next)
4957 s->background_filled_p = 1;
4958 if (real_start)
4959 *real_start = i;
4960 x_compute_overhangs_and_x (t, head->x, 1);
4961 x_prepend_glyph_string_lists (&head, &tail, h, t);
4962 }
dbcb258a 4963
06a2c219
GM
4964 /* Append glyphs strings for glyphs following the last glyph
4965 string tail that are overwritten by tail. The background of
4966 these strings has to be drawn because tail's foreground draws
4967 over it. */
4968 i = x_right_overwritten (tail);
4969 if (i >= 0)
4970 {
4971 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4972 DRAW_NORMAL_TEXT, x, last_x,
4973 overlaps_p);
06a2c219
GM
4974 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4975 x_append_glyph_string_lists (&head, &tail, h, t);
4976 if (real_end)
4977 *real_end = i;
4978 }
dc6f92b8 4979
06a2c219
GM
4980 /* Append glyph strings for glyphs following the last glyph
4981 string tail that overwrite tail. The foreground of such
4982 glyphs has to be drawn because it writes into the background
4983 of tail. The background must not be drawn because it could
4984 paint over the foreground of following glyphs. */
4985 i = x_right_overwriting (tail);
4986 if (i >= 0)
4987 {
4988 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4989 DRAW_NORMAL_TEXT, x, last_x,
4990 overlaps_p);
06a2c219
GM
4991 for (s = h; s; s = s->next)
4992 s->background_filled_p = 1;
4993 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4994 x_append_glyph_string_lists (&head, &tail, h, t);
4995 if (real_end)
4996 *real_end = i;
4997 }
4998 }
58769bee 4999
06a2c219
GM
5000 /* Draw all strings. */
5001 for (s = head; s; s = s->next)
5002 x_draw_glyph_string (s);
dc6f92b8 5003
06a2c219
GM
5004 /* Value is the x-position up to which drawn, relative to AREA of W.
5005 This doesn't include parts drawn because of overhangs. */
5006 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5007 if (!row->full_width_p)
5008 {
5009 if (area > LEFT_MARGIN_AREA)
5010 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5011 if (area > TEXT_AREA)
5012 x_reached -= window_box_width (w, TEXT_AREA);
5013 }
a8710abf 5014
06a2c219
GM
5015 return x_reached;
5016}
dc6f92b8 5017
dc6f92b8 5018
66ac4b0e
GM
5019/* Fix the display of area AREA of overlapping row ROW in window W. */
5020
5021static void
5022x_fix_overlapping_area (w, row, area)
5023 struct window *w;
5024 struct glyph_row *row;
5025 enum glyph_row_area area;
5026{
5027 int i, x;
5028
5029 BLOCK_INPUT;
5030
5031 if (area == LEFT_MARGIN_AREA)
5032 x = 0;
5033 else if (area == TEXT_AREA)
5034 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5035 else
5036 x = (window_box_width (w, LEFT_MARGIN_AREA)
5037 + window_box_width (w, TEXT_AREA));
5038
5039 for (i = 0; i < row->used[area];)
5040 {
5041 if (row->glyphs[area][i].overlaps_vertically_p)
5042 {
5043 int start = i, start_x = x;
5044
5045 do
5046 {
5047 x += row->glyphs[area][i].pixel_width;
5048 ++i;
5049 }
5050 while (i < row->used[area]
5051 && row->glyphs[area][i].overlaps_vertically_p);
5052
5053 x_draw_glyphs (w, start_x, row, area, start, i,
5054 (row->inverse_p
5055 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
5056 NULL, NULL, 1);
5057 }
5058 else
5059 {
5060 x += row->glyphs[area][i].pixel_width;
5061 ++i;
5062 }
5063 }
5064
5065 UNBLOCK_INPUT;
5066}
5067
5068
06a2c219
GM
5069/* Output LEN glyphs starting at START at the nominal cursor position.
5070 Advance the nominal cursor over the text. The global variable
5071 updated_window contains the window being updated, updated_row is
5072 the glyph row being updated, and updated_area is the area of that
5073 row being updated. */
dc6f92b8 5074
06a2c219
GM
5075static void
5076x_write_glyphs (start, len)
5077 struct glyph *start;
5078 int len;
5079{
5080 int x, hpos, real_start, real_end;
d9cdbb3d 5081
06a2c219 5082 xassert (updated_window && updated_row);
dc6f92b8 5083 BLOCK_INPUT;
06a2c219
GM
5084
5085 /* Write glyphs. */
dc6f92b8 5086
06a2c219
GM
5087 hpos = start - updated_row->glyphs[updated_area];
5088 x = x_draw_glyphs (updated_window, output_cursor.x,
5089 updated_row, updated_area,
5090 hpos, hpos + len,
5091 (updated_row->inverse_p
5092 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
66ac4b0e 5093 &real_start, &real_end, 0);
b30ec466 5094
06a2c219
GM
5095 /* If we drew over the cursor, note that it is not visible any more. */
5096 note_overwritten_text_cursor (updated_window, real_start,
5097 real_end - real_start);
dc6f92b8
JB
5098
5099 UNBLOCK_INPUT;
06a2c219
GM
5100
5101 /* Advance the output cursor. */
5102 output_cursor.hpos += len;
5103 output_cursor.x = x;
dc6f92b8
JB
5104}
5105
0cdd0c9f 5106
06a2c219 5107/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 5108
06a2c219
GM
5109static void
5110x_insert_glyphs (start, len)
5111 struct glyph *start;
5112 register int len;
5113{
5114 struct frame *f;
5115 struct window *w;
5116 int line_height, shift_by_width, shifted_region_width;
5117 struct glyph_row *row;
5118 struct glyph *glyph;
5119 int frame_x, frame_y, hpos, real_start, real_end;
58769bee 5120
06a2c219 5121 xassert (updated_window && updated_row);
0cdd0c9f 5122 BLOCK_INPUT;
06a2c219
GM
5123 w = updated_window;
5124 f = XFRAME (WINDOW_FRAME (w));
5125
5126 /* Get the height of the line we are in. */
5127 row = updated_row;
5128 line_height = row->height;
5129
5130 /* Get the width of the glyphs to insert. */
5131 shift_by_width = 0;
5132 for (glyph = start; glyph < start + len; ++glyph)
5133 shift_by_width += glyph->pixel_width;
5134
5135 /* Get the width of the region to shift right. */
5136 shifted_region_width = (window_box_width (w, updated_area)
5137 - output_cursor.x
5138 - shift_by_width);
5139
5140 /* Shift right. */
5141 frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x);
5142 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5143 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5144 f->output_data.x->normal_gc,
5145 frame_x, frame_y,
5146 shifted_region_width, line_height,
5147 frame_x + shift_by_width, frame_y);
5148
5149 /* Write the glyphs. */
5150 hpos = start - row->glyphs[updated_area];
5151 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
66ac4b0e 5152 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
06a2c219
GM
5153 note_overwritten_text_cursor (w, real_start, real_end - real_start);
5154
5155 /* Advance the output cursor. */
5156 output_cursor.hpos += len;
5157 output_cursor.x += shift_by_width;
0cdd0c9f
RS
5158 UNBLOCK_INPUT;
5159}
0cdd0c9f 5160
0cdd0c9f 5161
06a2c219
GM
5162/* Delete N glyphs at the nominal cursor position. Not implemented
5163 for X frames. */
c83febd7
RS
5164
5165static void
06a2c219
GM
5166x_delete_glyphs (n)
5167 register int n;
c83febd7 5168{
06a2c219 5169 abort ();
c83febd7
RS
5170}
5171
0cdd0c9f 5172
06a2c219
GM
5173/* Erase the current text line from the nominal cursor position
5174 (inclusive) to pixel column TO_X (exclusive). The idea is that
5175 everything from TO_X onward is already erased.
5176
5177 TO_X is a pixel position relative to updated_area of
5178 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 5179
06a2c219
GM
5180static void
5181x_clear_end_of_line (to_x)
5182 int to_x;
5183{
5184 struct frame *f;
5185 struct window *w = updated_window;
5186 int max_x, min_y, max_y;
5187 int from_x, from_y, to_y;
5188
5189 xassert (updated_window && updated_row);
5190 f = XFRAME (w->frame);
5191
5192 if (updated_row->full_width_p)
5193 {
5194 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5195 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5196 && !w->pseudo_window_p)
5197 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5198 }
06a2c219
GM
5199 else
5200 max_x = window_box_width (w, updated_area);
5201 max_y = window_text_bottom_y (w);
dc6f92b8 5202
06a2c219
GM
5203 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5204 of window. For TO_X > 0, truncate to end of drawing area. */
5205 if (to_x == 0)
5206 return;
5207 else if (to_x < 0)
5208 to_x = max_x;
5209 else
5210 to_x = min (to_x, max_x);
dbc4e1c1 5211
06a2c219
GM
5212 to_y = min (max_y, output_cursor.y + updated_row->height);
5213
5214 /* Notice if the cursor will be cleared by this operation. */
5215 if (!updated_row->full_width_p)
5216 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
dbc4e1c1 5217
06a2c219
GM
5218 from_x = output_cursor.x;
5219
5220 /* Translate to frame coordinates. */
5221 if (updated_row->full_width_p)
5222 {
5223 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5224 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5225 }
0cdd0c9f
RS
5226 else
5227 {
06a2c219
GM
5228 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5229 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5230 }
5231
045dee35 5232 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5233 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5234 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5235
5236 /* Prevent inadvertently clearing to end of the X window. */
5237 if (to_x > from_x && to_y > from_y)
5238 {
5239 BLOCK_INPUT;
5240 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5241 from_x, from_y, to_x - from_x, to_y - from_y,
5242 False);
5243 UNBLOCK_INPUT;
0cdd0c9f 5244 }
0cdd0c9f 5245}
dbc4e1c1 5246
0cdd0c9f 5247
06a2c219 5248/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5249 frame. Otherwise clear the selected frame. */
06a2c219
GM
5250
5251static void
5252x_clear_frame ()
0cdd0c9f 5253{
06a2c219 5254 struct frame *f;
0cdd0c9f 5255
06a2c219
GM
5256 if (updating_frame)
5257 f = updating_frame;
0cdd0c9f 5258 else
b86bd3dd 5259 f = SELECTED_FRAME ();
58769bee 5260
06a2c219
GM
5261 /* Clearing the frame will erase any cursor, so mark them all as no
5262 longer visible. */
5263 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5264 output_cursor.hpos = output_cursor.vpos = 0;
5265 output_cursor.x = -1;
5266
5267 /* We don't set the output cursor here because there will always
5268 follow an explicit cursor_to. */
5269 BLOCK_INPUT;
5270 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5271
5272 /* We have to clear the scroll bars, too. If we have changed
5273 colors or something like that, then they should be notified. */
5274 x_scroll_bar_clear (f);
0cdd0c9f 5275
06a2c219
GM
5276 XFlush (FRAME_X_DISPLAY (f));
5277 UNBLOCK_INPUT;
dc6f92b8 5278}
06a2c219
GM
5279
5280
dc6f92b8 5281\f
dbc4e1c1
JB
5282/* Invert the middle quarter of the frame for .15 sec. */
5283
06a2c219
GM
5284/* We use the select system call to do the waiting, so we have to make
5285 sure it's available. If it isn't, we just won't do visual bells. */
5286
dbc4e1c1
JB
5287#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5288
06a2c219
GM
5289
5290/* Subtract the `struct timeval' values X and Y, storing the result in
5291 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5292
5293static int
5294timeval_subtract (result, x, y)
5295 struct timeval *result, x, y;
5296{
06a2c219
GM
5297 /* Perform the carry for the later subtraction by updating y. This
5298 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5299 if (x.tv_usec < y.tv_usec)
5300 {
5301 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5302 y.tv_usec -= 1000000 * nsec;
5303 y.tv_sec += nsec;
5304 }
06a2c219 5305
dbc4e1c1
JB
5306 if (x.tv_usec - y.tv_usec > 1000000)
5307 {
5308 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5309 y.tv_usec += 1000000 * nsec;
5310 y.tv_sec -= nsec;
5311 }
5312
06a2c219
GM
5313 /* Compute the time remaining to wait. tv_usec is certainly
5314 positive. */
dbc4e1c1
JB
5315 result->tv_sec = x.tv_sec - y.tv_sec;
5316 result->tv_usec = x.tv_usec - y.tv_usec;
5317
06a2c219
GM
5318 /* Return indication of whether the result should be considered
5319 negative. */
dbc4e1c1
JB
5320 return x.tv_sec < y.tv_sec;
5321}
dc6f92b8 5322
dfcf069d 5323void
f676886a
JB
5324XTflash (f)
5325 struct frame *f;
dc6f92b8 5326{
dbc4e1c1 5327 BLOCK_INPUT;
dc6f92b8 5328
dbc4e1c1
JB
5329 {
5330 GC gc;
dc6f92b8 5331
06a2c219
GM
5332 /* Create a GC that will use the GXxor function to flip foreground
5333 pixels into background pixels. */
dbc4e1c1
JB
5334 {
5335 XGCValues values;
dc6f92b8 5336
dbc4e1c1 5337 values.function = GXxor;
7556890b
RS
5338 values.foreground = (f->output_data.x->foreground_pixel
5339 ^ f->output_data.x->background_pixel);
58769bee 5340
334208b7 5341 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5342 GCFunction | GCForeground, &values);
5343 }
dc6f92b8 5344
dbc4e1c1 5345 {
e84e14c3
RS
5346 /* Get the height not including a menu bar widget. */
5347 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5348 /* Height of each line to flash. */
5349 int flash_height = FRAME_LINE_HEIGHT (f);
5350 /* These will be the left and right margins of the rectangles. */
5351 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5352 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5353
5354 int width;
5355
5356 /* Don't flash the area between a scroll bar and the frame
5357 edge it is next to. */
5358 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5359 {
5360 case vertical_scroll_bar_left:
5361 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5362 break;
5363
5364 case vertical_scroll_bar_right:
5365 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5366 break;
06a2c219
GM
5367
5368 default:
5369 break;
e84e14c3
RS
5370 }
5371
5372 width = flash_right - flash_left;
5373
5374 /* If window is tall, flash top and bottom line. */
5375 if (height > 3 * FRAME_LINE_HEIGHT (f))
5376 {
5377 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5378 flash_left,
5379 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5380 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5381 width, flash_height);
5382 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5383 flash_left,
5384 (height - flash_height
5385 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5386 width, flash_height);
5387 }
5388 else
5389 /* If it is short, flash it all. */
5390 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5391 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5392 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5393
06a2c219 5394 x_flush (f);
dc6f92b8 5395
dbc4e1c1 5396 {
06a2c219 5397 struct timeval wakeup;
dc6f92b8 5398
66c30ea1 5399 EMACS_GET_TIME (wakeup);
dc6f92b8 5400
dbc4e1c1
JB
5401 /* Compute time to wait until, propagating carry from usecs. */
5402 wakeup.tv_usec += 150000;
5403 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5404 wakeup.tv_usec %= 1000000;
5405
5406 /* Keep waiting until past the time wakeup. */
5407 while (1)
5408 {
5409 struct timeval timeout;
5410
66c30ea1 5411 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
5412
5413 /* In effect, timeout = wakeup - timeout.
5414 Break if result would be negative. */
5415 if (timeval_subtract (&timeout, wakeup, timeout))
5416 break;
5417
5418 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5419 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5420 }
5421 }
58769bee 5422
e84e14c3
RS
5423 /* If window is tall, flash top and bottom line. */
5424 if (height > 3 * FRAME_LINE_HEIGHT (f))
5425 {
5426 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5427 flash_left,
5428 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5429 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5430 width, flash_height);
5431 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5432 flash_left,
5433 (height - flash_height
5434 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5435 width, flash_height);
5436 }
5437 else
5438 /* If it is short, flash it all. */
5439 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5440 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5441 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5442
334208b7 5443 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5444 x_flush (f);
dc6f92b8 5445 }
dbc4e1c1
JB
5446 }
5447
5448 UNBLOCK_INPUT;
dc6f92b8
JB
5449}
5450
06a2c219 5451#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5452
5453
dc6f92b8
JB
5454/* Make audible bell. */
5455
dfcf069d 5456void
dc6f92b8
JB
5457XTring_bell ()
5458{
b86bd3dd
GM
5459 struct frame *f = SELECTED_FRAME ();
5460
5461 if (FRAME_X_DISPLAY (f))
5462 {
dbc4e1c1 5463#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5464 if (visible_bell)
5465 XTflash (f);
5466 else
dbc4e1c1 5467#endif
b86bd3dd
GM
5468 {
5469 BLOCK_INPUT;
5470 XBell (FRAME_X_DISPLAY (f), 0);
5471 XFlush (FRAME_X_DISPLAY (f));
5472 UNBLOCK_INPUT;
5473 }
dc6f92b8
JB
5474 }
5475}
06a2c219 5476
dc6f92b8 5477\f
06a2c219
GM
5478/* Specify how many text lines, from the top of the window,
5479 should be affected by insert-lines and delete-lines operations.
5480 This, and those operations, are used only within an update
5481 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5482
dfcf069d 5483static void
06a2c219
GM
5484XTset_terminal_window (n)
5485 register int n;
dc6f92b8 5486{
06a2c219 5487 /* This function intentionally left blank. */
dc6f92b8
JB
5488}
5489
06a2c219
GM
5490
5491\f
5492/***********************************************************************
5493 Line Dance
5494 ***********************************************************************/
5495
5496/* Perform an insert-lines or delete-lines operation, inserting N
5497 lines or deleting -N lines at vertical position VPOS. */
5498
dfcf069d 5499static void
06a2c219
GM
5500x_ins_del_lines (vpos, n)
5501 int vpos, n;
dc6f92b8
JB
5502{
5503 abort ();
5504}
06a2c219
GM
5505
5506
5507/* Scroll part of the display as described by RUN. */
dc6f92b8 5508
dfcf069d 5509static void
06a2c219
GM
5510x_scroll_run (w, run)
5511 struct window *w;
5512 struct run *run;
dc6f92b8 5513{
06a2c219
GM
5514 struct frame *f = XFRAME (w->frame);
5515 int x, y, width, height, from_y, to_y, bottom_y;
5516
5517 /* Get frame-relative bounding box of the text display area of W,
5518 without mode lines. Include in this box the flags areas to the
5519 left and right of W. */
5520 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5521 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5522 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5523
5524 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5525 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5526 bottom_y = y + height;
dc6f92b8 5527
06a2c219
GM
5528 if (to_y < from_y)
5529 {
5530 /* Scrolling up. Make sure we don't copy part of the mode
5531 line at the bottom. */
5532 if (from_y + run->height > bottom_y)
5533 height = bottom_y - from_y;
5534 else
5535 height = run->height;
5536 }
dc6f92b8 5537 else
06a2c219
GM
5538 {
5539 /* Scolling down. Make sure we don't copy over the mode line.
5540 at the bottom. */
5541 if (to_y + run->height > bottom_y)
5542 height = bottom_y - to_y;
5543 else
5544 height = run->height;
5545 }
7a13e894 5546
06a2c219
GM
5547 BLOCK_INPUT;
5548
5549 /* Cursor off. Will be switched on again in x_update_window_end. */
5550 updated_window = w;
5551 x_clear_cursor (w);
5552
5553 XCopyArea (FRAME_X_DISPLAY (f),
5554 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5555 f->output_data.x->normal_gc,
5556 x, from_y,
5557 width, height,
5558 x, to_y);
5559
5560 UNBLOCK_INPUT;
5561}
dc6f92b8 5562
dc6f92b8 5563
06a2c219
GM
5564\f
5565/***********************************************************************
5566 Exposure Events
5567 ***********************************************************************/
5568
5569/* Redisplay an exposed area of frame F. X and Y are the upper-left
5570 corner of the exposed rectangle. W and H are width and height of
5571 the exposed area. All are pixel values. W or H zero means redraw
5572 the entire frame. */
dc6f92b8 5573
06a2c219
GM
5574static void
5575expose_frame (f, x, y, w, h)
5576 struct frame *f;
5577 int x, y, w, h;
dc6f92b8 5578{
06a2c219 5579 XRectangle r;
dc6f92b8 5580
06a2c219 5581 TRACE ((stderr, "expose_frame "));
dc6f92b8 5582
06a2c219
GM
5583 /* No need to redraw if frame will be redrawn soon. */
5584 if (FRAME_GARBAGED_P (f))
dc6f92b8 5585 {
06a2c219
GM
5586 TRACE ((stderr, " garbaged\n"));
5587 return;
5588 }
5589
5590 /* If basic faces haven't been realized yet, there is no point in
5591 trying to redraw anything. This can happen when we get an expose
5592 event while Emacs is starting, e.g. by moving another window. */
5593 if (FRAME_FACE_CACHE (f) == NULL
5594 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5595 {
5596 TRACE ((stderr, " no faces\n"));
5597 return;
58769bee 5598 }
06a2c219
GM
5599
5600 if (w == 0 || h == 0)
58769bee 5601 {
06a2c219
GM
5602 r.x = r.y = 0;
5603 r.width = CANON_X_UNIT (f) * f->width;
5604 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5605 }
5606 else
5607 {
06a2c219
GM
5608 r.x = x;
5609 r.y = y;
5610 r.width = w;
5611 r.height = h;
5612 }
5613
5614 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
5615 expose_window_tree (XWINDOW (f->root_window), &r);
5616
9ea173e8 5617 if (WINDOWP (f->tool_bar_window))
06a2c219 5618 {
9ea173e8 5619 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
5620 XRectangle window_rect;
5621 XRectangle intersection_rect;
5622 int window_x, window_y, window_width, window_height;
5623
5624
5625 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5626 window_rect.x = window_x;
5627 window_rect.y = window_y;
5628 window_rect.width = window_width;
5629 window_rect.height = window_height;
5630
5631 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5632 expose_window (w, &intersection_rect);
5633 }
5634
5635#ifndef USE_X_TOOLKIT
5636 if (WINDOWP (f->menu_bar_window))
5637 {
5638 struct window *w = XWINDOW (f->menu_bar_window);
5639 XRectangle window_rect;
5640 XRectangle intersection_rect;
5641 int window_x, window_y, window_width, window_height;
5642
5643
5644 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5645 window_rect.x = window_x;
5646 window_rect.y = window_y;
5647 window_rect.width = window_width;
5648 window_rect.height = window_height;
5649
5650 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5651 expose_window (w, &intersection_rect);
dc6f92b8 5652 }
06a2c219 5653#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5654}
5655
06a2c219
GM
5656
5657/* Redraw (parts) of all windows in the window tree rooted at W that
5658 intersect R. R contains frame pixel coordinates. */
5659
58769bee 5660static void
06a2c219
GM
5661expose_window_tree (w, r)
5662 struct window *w;
5663 XRectangle *r;
dc6f92b8 5664{
06a2c219
GM
5665 while (w)
5666 {
5667 if (!NILP (w->hchild))
5668 expose_window_tree (XWINDOW (w->hchild), r);
5669 else if (!NILP (w->vchild))
5670 expose_window_tree (XWINDOW (w->vchild), r);
5671 else
5672 {
5673 XRectangle window_rect;
5674 XRectangle intersection_rect;
5675 struct frame *f = XFRAME (w->frame);
5676 int window_x, window_y, window_width, window_height;
5677
5678 /* Frame-relative pixel rectangle of W. */
5679 window_box (w, -1, &window_x, &window_y, &window_width,
5680 &window_height);
5681 window_rect.x
5682 = (window_x
110859fc 5683 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
714dc26c 5684 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
06a2c219
GM
5685 window_rect.y = window_y;
5686 window_rect.width
5687 = (window_width
110859fc 5688 + FRAME_X_FLAGS_AREA_WIDTH (f)
06a2c219
GM
5689 + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
5690 window_rect.height
5691 = window_height + CURRENT_MODE_LINE_HEIGHT (w);
5692
5693 if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
5694 expose_window (w, &intersection_rect);
5695 }
58769bee 5696
06a2c219
GM
5697 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5698 }
5699}
58769bee 5700
dc6f92b8 5701
06a2c219
GM
5702/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5703 which intersects rectangle R. R is in window-relative coordinates. */
5704
5705static void
5706expose_area (w, row, r, area)
5707 struct window *w;
5708 struct glyph_row *row;
5709 XRectangle *r;
5710 enum glyph_row_area area;
5711{
5712 int x;
5713 struct glyph *first = row->glyphs[area];
5714 struct glyph *end = row->glyphs[area] + row->used[area];
5715 struct glyph *last;
5716 int first_x;
5717
5718 /* Set x to the window-relative start position for drawing glyphs of
5719 AREA. The first glyph of the text area can be partially visible.
5720 The first glyphs of other areas cannot. */
5721 if (area == LEFT_MARGIN_AREA)
5722 x = 0;
5723 else if (area == TEXT_AREA)
5724 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5725 else
5726 x = (window_box_width (w, LEFT_MARGIN_AREA)
5727 + window_box_width (w, TEXT_AREA));
5728
6fb13182
GM
5729 if (area == TEXT_AREA && row->fill_line_p)
5730 /* If row extends face to end of line write the whole line. */
5731 x_draw_glyphs (w, x, row, area,
5732 0, row->used[area],
06a2c219 5733 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5734 NULL, NULL, 0);
6fb13182
GM
5735 else
5736 {
5737 /* Find the first glyph that must be redrawn. */
5738 while (first < end
5739 && x + first->pixel_width < r->x)
5740 {
5741 x += first->pixel_width;
5742 ++first;
5743 }
5744
5745 /* Find the last one. */
5746 last = first;
5747 first_x = x;
5748 while (last < end
5749 && x < r->x + r->width)
5750 {
5751 x += last->pixel_width;
5752 ++last;
5753 }
5754
5755 /* Repaint. */
5756 if (last > first)
5757 x_draw_glyphs (w, first_x, row, area,
5758 first - row->glyphs[area],
5759 last - row->glyphs[area],
5760 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5761 NULL, NULL, 0);
5762 }
06a2c219
GM
5763}
5764
58769bee 5765
06a2c219
GM
5766/* Redraw the parts of the glyph row ROW on window W intersecting
5767 rectangle R. R is in window-relative coordinates. */
dc6f92b8 5768
06a2c219
GM
5769static void
5770expose_line (w, row, r)
5771 struct window *w;
5772 struct glyph_row *row;
5773 XRectangle *r;
5774{
5775 xassert (row->enabled_p);
5776
5777 if (row->mode_line_p || w->pseudo_window_p)
5778 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5779 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5780 NULL, NULL, 0);
06a2c219
GM
5781 else
5782 {
5783 if (row->used[LEFT_MARGIN_AREA])
5784 expose_area (w, row, r, LEFT_MARGIN_AREA);
5785 if (row->used[TEXT_AREA])
5786 expose_area (w, row, r, TEXT_AREA);
5787 if (row->used[RIGHT_MARGIN_AREA])
5788 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5789 x_draw_row_bitmaps (w, row);
5790 }
5791}
dc6f92b8 5792
58769bee 5793
06a2c219
GM
5794/* Return non-zero if W's cursor intersects rectangle R. */
5795
5796static int
5797x_phys_cursor_in_rect_p (w, r)
5798 struct window *w;
5799 XRectangle *r;
5800{
5801 XRectangle cr, result;
5802 struct glyph *cursor_glyph;
5803
5804 cursor_glyph = get_phys_cursor_glyph (w);
5805 if (cursor_glyph)
5806 {
5807 cr.x = w->phys_cursor.x;
5808 cr.y = w->phys_cursor.y;
5809 cr.width = cursor_glyph->pixel_width;
5810 cr.height = w->phys_cursor_height;
5811 return x_intersect_rectangles (&cr, r, &result);
5812 }
5813 else
5814 return 0;
dc6f92b8 5815}
dc6f92b8 5816
06a2c219
GM
5817
5818/* Redraw a rectangle of window W. R is a rectangle in window
5819 relative coordinates. Call this function with input blocked. */
dc6f92b8
JB
5820
5821static void
06a2c219
GM
5822expose_window (w, r)
5823 struct window *w;
5824 XRectangle *r;
dc6f92b8 5825{
06a2c219
GM
5826 struct glyph_row *row;
5827 int y;
5828 int yb = window_text_bottom_y (w);
5829 int cursor_cleared_p;
dc6f92b8 5830
80c32bcc
GM
5831 /* If window is not yet fully initialized, do nothing. This can
5832 happen when toolkit scroll bars are used and a window is split.
5833 Reconfiguring the scroll bar will generate an expose for a newly
5834 created window. */
5835 if (w->current_matrix == NULL)
5836 return;
5837
06a2c219
GM
5838 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
5839 r->x, r->y, r->width, r->height));
dc6f92b8 5840
06a2c219
GM
5841 /* Convert to window coordinates. */
5842 r->x = FRAME_TO_WINDOW_PIXEL_X (w, r->x);
5843 r->y = FRAME_TO_WINDOW_PIXEL_Y (w, r->y);
dc6f92b8 5844
06a2c219
GM
5845 /* Turn off the cursor. */
5846 if (!w->pseudo_window_p
5847 && x_phys_cursor_in_rect_p (w, r))
5848 {
5849 x_clear_cursor (w);
5850 cursor_cleared_p = 1;
5851 }
5852 else
5853 cursor_cleared_p = 0;
5854
5855 /* Find the first row intersecting the rectangle R. */
5856 row = w->current_matrix->rows;
5857 y = 0;
5858 while (row->enabled_p
5859 && y < yb
5860 && y + row->height < r->y)
5861 {
5862 y += row->height;
5863 ++row;
5864 }
5865
dc6f92b8 5866 /* Display the text in the rectangle, one text line at a time. */
06a2c219
GM
5867 while (row->enabled_p
5868 && y < yb
5869 && y < r->y + r->height)
5870 {
5871 expose_line (w, row, r);
5872 y += row->height;
5873 ++row;
5874 }
5875
5876 /* Display the mode line if there is one. */
5877 if (WINDOW_WANTS_MODELINE_P (w)
5878 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
5879 row->enabled_p)
5880 && row->y < r->y + r->height)
5881 expose_line (w, row, r);
dc6f92b8 5882
06a2c219 5883 if (!w->pseudo_window_p)
dc6f92b8 5884 {
06a2c219
GM
5885 /* Draw border between windows. */
5886 x_draw_vertical_border (w);
5887
5888 /* Turn the cursor on again. */
5889 if (cursor_cleared_p)
5890 x_update_window_cursor (w, 1);
5891 }
5892}
dc6f92b8 5893
dc6f92b8 5894
06a2c219
GM
5895/* Determine the intersection of two rectangles R1 and R2. Return
5896 the intersection in *RESULT. Value is non-zero if RESULT is not
5897 empty. */
5898
5899static int
5900x_intersect_rectangles (r1, r2, result)
5901 XRectangle *r1, *r2, *result;
5902{
5903 XRectangle *left, *right;
5904 XRectangle *upper, *lower;
5905 int intersection_p = 0;
5906
5907 /* Rearrange so that R1 is the left-most rectangle. */
5908 if (r1->x < r2->x)
5909 left = r1, right = r2;
5910 else
5911 left = r2, right = r1;
5912
5913 /* X0 of the intersection is right.x0, if this is inside R1,
5914 otherwise there is no intersection. */
5915 if (right->x <= left->x + left->width)
5916 {
5917 result->x = right->x;
5918
5919 /* The right end of the intersection is the minimum of the
5920 the right ends of left and right. */
5921 result->width = (min (left->x + left->width, right->x + right->width)
5922 - result->x);
5923
5924 /* Same game for Y. */
5925 if (r1->y < r2->y)
5926 upper = r1, lower = r2;
5927 else
5928 upper = r2, lower = r1;
5929
5930 /* The upper end of the intersection is lower.y0, if this is inside
5931 of upper. Otherwise, there is no intersection. */
5932 if (lower->y <= upper->y + upper->height)
dc43ef94 5933 {
06a2c219
GM
5934 result->y = lower->y;
5935
5936 /* The lower end of the intersection is the minimum of the lower
5937 ends of upper and lower. */
5938 result->height = (min (lower->y + lower->height,
5939 upper->y + upper->height)
5940 - result->y);
5941 intersection_p = 1;
dc43ef94 5942 }
dc6f92b8
JB
5943 }
5944
06a2c219 5945 return intersection_p;
dc6f92b8 5946}
06a2c219
GM
5947
5948
5949
5950
dc6f92b8 5951\f
dc6f92b8 5952static void
334208b7
RS
5953frame_highlight (f)
5954 struct frame *f;
dc6f92b8 5955{
b3e1e05c
JB
5956 /* We used to only do this if Vx_no_window_manager was non-nil, but
5957 the ICCCM (section 4.1.6) says that the window's border pixmap
5958 and border pixel are window attributes which are "private to the
5959 client", so we can always change it to whatever we want. */
5960 BLOCK_INPUT;
334208b7 5961 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5962 f->output_data.x->border_pixel);
b3e1e05c 5963 UNBLOCK_INPUT;
5d46f928 5964 x_update_cursor (f, 1);
dc6f92b8
JB
5965}
5966
5967static void
334208b7
RS
5968frame_unhighlight (f)
5969 struct frame *f;
dc6f92b8 5970{
b3e1e05c
JB
5971 /* We used to only do this if Vx_no_window_manager was non-nil, but
5972 the ICCCM (section 4.1.6) says that the window's border pixmap
5973 and border pixel are window attributes which are "private to the
5974 client", so we can always change it to whatever we want. */
5975 BLOCK_INPUT;
334208b7 5976 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5977 f->output_data.x->border_tile);
b3e1e05c 5978 UNBLOCK_INPUT;
5d46f928 5979 x_update_cursor (f, 1);
dc6f92b8 5980}
dc6f92b8 5981
f676886a
JB
5982/* The focus has changed. Update the frames as necessary to reflect
5983 the new situation. Note that we can't change the selected frame
c5acd733 5984 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 5985 Each event gets marked with the frame in which it occurred, so the
c5acd733 5986 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 5987
6d4238f3 5988static void
0f941935
KH
5989x_new_focus_frame (dpyinfo, frame)
5990 struct x_display_info *dpyinfo;
f676886a 5991 struct frame *frame;
dc6f92b8 5992{
0f941935 5993 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 5994
0f941935 5995 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 5996 {
58769bee 5997 /* Set this before calling other routines, so that they see
f676886a 5998 the correct value of x_focus_frame. */
0f941935 5999 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6000
6001 if (old_focus && old_focus->auto_lower)
f676886a 6002 x_lower_frame (old_focus);
dc6f92b8
JB
6003
6004#if 0
f676886a 6005 selected_frame = frame;
e0c1aef2
KH
6006 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6007 selected_frame);
f676886a
JB
6008 Fselect_window (selected_frame->selected_window);
6009 choose_minibuf_frame ();
c118dd06 6010#endif /* ! 0 */
dc6f92b8 6011
0f941935
KH
6012 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6013 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6014 else
6015 pending_autoraise_frame = 0;
6d4238f3 6016 }
dc6f92b8 6017
0f941935 6018 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6019}
6020
37c2c98b
RS
6021/* Handle an event saying the mouse has moved out of an Emacs frame. */
6022
6023void
0f941935
KH
6024x_mouse_leave (dpyinfo)
6025 struct x_display_info *dpyinfo;
37c2c98b 6026{
0f941935 6027 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6028}
6d4238f3 6029
f451eb13
JB
6030/* The focus has changed, or we have redirected a frame's focus to
6031 another frame (this happens when a frame uses a surrogate
06a2c219 6032 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6033
6034 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6035 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6036 the appropriate X display info. */
06a2c219 6037
6d4238f3 6038static void
0f941935
KH
6039XTframe_rehighlight (frame)
6040 struct frame *frame;
6d4238f3 6041{
0f941935
KH
6042 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6043}
6d4238f3 6044
0f941935
KH
6045static void
6046x_frame_rehighlight (dpyinfo)
6047 struct x_display_info *dpyinfo;
6048{
6049 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6050
6051 if (dpyinfo->x_focus_frame)
6d4238f3 6052 {
0f941935
KH
6053 dpyinfo->x_highlight_frame
6054 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6055 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6056 : dpyinfo->x_focus_frame);
6057 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6058 {
0f941935
KH
6059 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6060 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6061 }
dc6f92b8 6062 }
6d4238f3 6063 else
0f941935 6064 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6065
0f941935 6066 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6067 {
6068 if (old_highlight)
f676886a 6069 frame_unhighlight (old_highlight);
0f941935
KH
6070 if (dpyinfo->x_highlight_frame)
6071 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6072 }
dc6f92b8 6073}
06a2c219
GM
6074
6075
dc6f92b8 6076\f
06a2c219 6077/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6078
28430d3c
JB
6079/* Initialize mode_switch_bit and modifier_meaning. */
6080static void
334208b7
RS
6081x_find_modifier_meanings (dpyinfo)
6082 struct x_display_info *dpyinfo;
28430d3c 6083{
f689eb05 6084 int min_code, max_code;
28430d3c
JB
6085 KeySym *syms;
6086 int syms_per_code;
6087 XModifierKeymap *mods;
6088
334208b7
RS
6089 dpyinfo->meta_mod_mask = 0;
6090 dpyinfo->shift_lock_mask = 0;
6091 dpyinfo->alt_mod_mask = 0;
6092 dpyinfo->super_mod_mask = 0;
6093 dpyinfo->hyper_mod_mask = 0;
58769bee 6094
9658a521 6095#ifdef HAVE_X11R4
334208b7 6096 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6097#else
4a60f8c5
RS
6098 min_code = dpyinfo->display->min_keycode;
6099 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6100#endif
6101
334208b7 6102 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6103 min_code, max_code - min_code + 1,
6104 &syms_per_code);
334208b7 6105 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6106
58769bee 6107 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6108 Alt keysyms are on. */
28430d3c 6109 {
06a2c219 6110 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6111
6112 for (row = 3; row < 8; row++)
6113 for (col = 0; col < mods->max_keypermod; col++)
6114 {
0299d313
RS
6115 KeyCode code
6116 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6117
af92970c
KH
6118 /* Zeroes are used for filler. Skip them. */
6119 if (code == 0)
6120 continue;
6121
28430d3c
JB
6122 /* Are any of this keycode's keysyms a meta key? */
6123 {
6124 int code_col;
6125
6126 for (code_col = 0; code_col < syms_per_code; code_col++)
6127 {
f689eb05 6128 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6129
f689eb05 6130 switch (sym)
28430d3c 6131 {
f689eb05
JB
6132 case XK_Meta_L:
6133 case XK_Meta_R:
334208b7 6134 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6135 break;
f689eb05
JB
6136
6137 case XK_Alt_L:
6138 case XK_Alt_R:
334208b7 6139 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6140 break;
6141
6142 case XK_Hyper_L:
6143 case XK_Hyper_R:
334208b7 6144 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6145 break;
6146
6147 case XK_Super_L:
6148 case XK_Super_R:
334208b7 6149 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6150 break;
11edeb03
JB
6151
6152 case XK_Shift_Lock:
6153 /* Ignore this if it's not on the lock modifier. */
6154 if ((1 << row) == LockMask)
334208b7 6155 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6156 break;
28430d3c
JB
6157 }
6158 }
6159 }
6160 }
6161 }
6162
f689eb05 6163 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6164 if (! dpyinfo->meta_mod_mask)
a3c44b14 6165 {
334208b7
RS
6166 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6167 dpyinfo->alt_mod_mask = 0;
a3c44b14 6168 }
f689eb05 6169
148c4b70
RS
6170 /* If some keys are both alt and meta,
6171 make them just meta, not alt. */
334208b7 6172 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6173 {
334208b7 6174 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6175 }
58769bee 6176
28430d3c 6177 XFree ((char *) syms);
f689eb05 6178 XFreeModifiermap (mods);
28430d3c
JB
6179}
6180
dfeccd2d
JB
6181/* Convert between the modifier bits X uses and the modifier bits
6182 Emacs uses. */
06a2c219 6183
7c5283e4 6184static unsigned int
334208b7
RS
6185x_x_to_emacs_modifiers (dpyinfo, state)
6186 struct x_display_info *dpyinfo;
dc6f92b8
JB
6187 unsigned int state;
6188{
334208b7
RS
6189 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
6190 | ((state & ControlMask) ? ctrl_modifier : 0)
6191 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
6192 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
6193 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
6194 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
6195}
6196
dfeccd2d 6197static unsigned int
334208b7
RS
6198x_emacs_to_x_modifiers (dpyinfo, state)
6199 struct x_display_info *dpyinfo;
dfeccd2d
JB
6200 unsigned int state;
6201{
334208b7
RS
6202 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6203 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6204 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6205 | ((state & shift_modifier) ? ShiftMask : 0)
6206 | ((state & ctrl_modifier) ? ControlMask : 0)
6207 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6208}
d047c4eb
KH
6209
6210/* Convert a keysym to its name. */
6211
6212char *
6213x_get_keysym_name (keysym)
6214 KeySym keysym;
6215{
6216 char *value;
6217
6218 BLOCK_INPUT;
6219 value = XKeysymToString (keysym);
6220 UNBLOCK_INPUT;
6221
6222 return value;
6223}
06a2c219
GM
6224
6225
e4571a43
JB
6226\f
6227/* Mouse clicks and mouse movement. Rah. */
e4571a43 6228
06a2c219
GM
6229/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6230 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6231 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6232 not force the value into range. */
69388238 6233
c8dba240 6234void
69388238 6235pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6236 FRAME_PTR f;
69388238 6237 register int pix_x, pix_y;
e4571a43
JB
6238 register int *x, *y;
6239 XRectangle *bounds;
69388238 6240 int noclip;
e4571a43 6241{
06a2c219 6242 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6243 even for negative values. */
6244 if (pix_x < 0)
7556890b 6245 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6246 if (pix_y < 0)
7556890b 6247 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6248
e4571a43
JB
6249 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6250 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6251
6252 if (bounds)
6253 {
7556890b
RS
6254 bounds->width = FONT_WIDTH (f->output_data.x->font);
6255 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6256 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6257 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6258 }
6259
69388238
RS
6260 if (!noclip)
6261 {
6262 if (pix_x < 0)
6263 pix_x = 0;
3cbd2e0b
RS
6264 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6265 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6266
6267 if (pix_y < 0)
6268 pix_y = 0;
6269 else if (pix_y > f->height)
6270 pix_y = f->height;
6271 }
e4571a43
JB
6272
6273 *x = pix_x;
6274 *y = pix_y;
6275}
6276
06a2c219
GM
6277
6278/* Given HPOS/VPOS in the current matrix of W, return corresponding
6279 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6280 can't tell the positions because W's display is not up to date,
6281 return 0. */
6282
6283int
6284glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6285 struct window *w;
6286 int hpos, vpos;
6287 int *frame_x, *frame_y;
2b5c9e71 6288{
06a2c219
GM
6289 int success_p;
6290
6291 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6292 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6293
6294 if (display_completed)
6295 {
6296 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6297 struct glyph *glyph = row->glyphs[TEXT_AREA];
6298 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6299
6300 *frame_y = row->y;
6301 *frame_x = row->x;
6302 while (glyph < end)
6303 {
6304 *frame_x += glyph->pixel_width;
6305 ++glyph;
6306 }
6307
6308 success_p = 1;
6309 }
6310 else
6311 {
6312 *frame_y = *frame_x = 0;
6313 success_p = 0;
6314 }
6315
6316 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6317 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6318 return success_p;
2b5c9e71
RS
6319}
6320
06a2c219 6321
dc6f92b8
JB
6322/* Prepare a mouse-event in *RESULT for placement in the input queue.
6323
6324 If the event is a button press, then note that we have grabbed
f451eb13 6325 the mouse. */
dc6f92b8
JB
6326
6327static Lisp_Object
f451eb13 6328construct_mouse_click (result, event, f)
dc6f92b8
JB
6329 struct input_event *result;
6330 XButtonEvent *event;
f676886a 6331 struct frame *f;
dc6f92b8 6332{
f451eb13 6333 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6334 otherwise. */
f451eb13 6335 result->kind = mouse_click;
69388238 6336 result->code = event->button - Button1;
1113d9db 6337 result->timestamp = event->time;
334208b7
RS
6338 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6339 event->state)
f689eb05 6340 | (event->type == ButtonRelease
58769bee 6341 ? up_modifier
f689eb05 6342 : down_modifier));
dc6f92b8 6343
06a2c219
GM
6344 XSETINT (result->x, event->x);
6345 XSETINT (result->y, event->y);
6346 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6347 result->arg = Qnil;
06a2c219 6348 return Qnil;
dc6f92b8 6349}
b849c413 6350
69388238 6351\f
90e65f07
JB
6352/* Function to report a mouse movement to the mainstream Emacs code.
6353 The input handler calls this.
6354
6355 We have received a mouse movement event, which is given in *event.
6356 If the mouse is over a different glyph than it was last time, tell
6357 the mainstream emacs code by setting mouse_moved. If not, ask for
6358 another motion event, so we can check again the next time it moves. */
b8009dd1 6359
06a2c219
GM
6360static XMotionEvent last_mouse_motion_event;
6361static Lisp_Object last_mouse_motion_frame;
6362
90e65f07 6363static void
12ba150f 6364note_mouse_movement (frame, event)
f676886a 6365 FRAME_PTR frame;
90e65f07 6366 XMotionEvent *event;
90e65f07 6367{
e5d77022 6368 last_mouse_movement_time = event->time;
06a2c219
GM
6369 last_mouse_motion_event = *event;
6370 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6371
27f338af
RS
6372 if (event->window != FRAME_X_WINDOW (frame))
6373 {
39d8bb4d 6374 frame->mouse_moved = 1;
27f338af 6375 last_mouse_scroll_bar = Qnil;
27f338af 6376 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6377 }
6378
90e65f07 6379 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6380 else if (event->x < last_mouse_glyph.x
6381 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6382 || event->y < last_mouse_glyph.y
6383 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6384 {
39d8bb4d 6385 frame->mouse_moved = 1;
ab648270 6386 last_mouse_scroll_bar = Qnil;
b8009dd1 6387 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6388 }
6389}
6390
bf1c0ba1 6391/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6392
06a2c219
GM
6393 int disable_mouse_highlight;
6394
6395
6396\f
6397/************************************************************************
6398 Mouse Face
6399 ************************************************************************/
6400
6401/* Find the glyph under window-relative coordinates X/Y in window W.
6402 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6403 strings. Return in *HPOS and *VPOS the row and column number of
6404 the glyph found. Return in *AREA the glyph area containing X.
6405 Value is a pointer to the glyph found or null if X/Y is not on
6406 text, or we can't tell because W's current matrix is not up to
6407 date. */
6408
6409static struct glyph *
6410x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
6411 struct window *w;
6412 int x, y;
6413 int *hpos, *vpos, *area;
6414{
6415 struct glyph *glyph, *end;
3e71d8f2 6416 struct glyph_row *row = NULL;
06a2c219
GM
6417 int x0, i, left_area_width;
6418
6419 /* Find row containing Y. Give up if some row is not enabled. */
6420 for (i = 0; i < w->current_matrix->nrows; ++i)
6421 {
6422 row = MATRIX_ROW (w->current_matrix, i);
6423 if (!row->enabled_p)
6424 return NULL;
6425 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6426 break;
6427 }
6428
6429 *vpos = i;
6430 *hpos = 0;
6431
6432 /* Give up if Y is not in the window. */
6433 if (i == w->current_matrix->nrows)
6434 return NULL;
6435
6436 /* Get the glyph area containing X. */
6437 if (w->pseudo_window_p)
6438 {
6439 *area = TEXT_AREA;
6440 x0 = 0;
6441 }
6442 else
6443 {
6444 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6445 if (x < left_area_width)
6446 {
6447 *area = LEFT_MARGIN_AREA;
6448 x0 = 0;
6449 }
6450 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6451 {
6452 *area = TEXT_AREA;
6453 x0 = row->x + left_area_width;
6454 }
6455 else
6456 {
6457 *area = RIGHT_MARGIN_AREA;
6458 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6459 }
6460 }
6461
6462 /* Find glyph containing X. */
6463 glyph = row->glyphs[*area];
6464 end = glyph + row->used[*area];
6465 while (glyph < end)
6466 {
6467 if (x < x0 + glyph->pixel_width)
6468 {
6469 if (w->pseudo_window_p)
6470 break;
6471 else if (BUFFERP (glyph->object))
6472 break;
6473 }
6474
6475 x0 += glyph->pixel_width;
6476 ++glyph;
6477 }
6478
6479 if (glyph == end)
6480 return NULL;
6481
6482 *hpos = glyph - row->glyphs[*area];
6483 return glyph;
6484}
6485
6486
6487/* Convert frame-relative x/y to coordinates relative to window W.
6488 Takes pseudo-windows into account. */
6489
6490static void
6491frame_to_window_pixel_xy (w, x, y)
6492 struct window *w;
6493 int *x, *y;
6494{
6495 if (w->pseudo_window_p)
6496 {
6497 /* A pseudo-window is always full-width, and starts at the
6498 left edge of the frame, plus a frame border. */
6499 struct frame *f = XFRAME (w->frame);
6500 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6501 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6502 }
6503 else
6504 {
6505 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6506 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6507 }
6508}
6509
6510
e371a781 6511/* Take proper action when mouse has moved to the mode or header line of
06a2c219
GM
6512 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6513 mode line. X is relative to the start of the text display area of
6514 W, so the width of bitmap areas and scroll bars must be subtracted
6515 to get a position relative to the start of the mode line. */
6516
6517static void
6518note_mode_line_highlight (w, x, mode_line_p)
6519 struct window *w;
6520 int x, mode_line_p;
6521{
6522 struct frame *f = XFRAME (w->frame);
6523 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6524 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6525 struct glyph_row *row;
6526
6527 if (mode_line_p)
6528 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6529 else
045dee35 6530 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
e371a781 6531
06a2c219
GM
6532 if (row->enabled_p)
6533 {
6534 struct glyph *glyph, *end;
6535 Lisp_Object help, map;
6536 int x0;
6537
6538 /* Find the glyph under X. */
6539 glyph = row->glyphs[TEXT_AREA];
6540 end = glyph + row->used[TEXT_AREA];
6541 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6542 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
e371a781 6543
06a2c219
GM
6544 while (glyph < end
6545 && x >= x0 + glyph->pixel_width)
6546 {
6547 x0 += glyph->pixel_width;
6548 ++glyph;
6549 }
6550
6551 if (glyph < end
6552 && STRINGP (glyph->object)
6553 && XSTRING (glyph->object)->intervals
6554 && glyph->charpos >= 0
6555 && glyph->charpos < XSTRING (glyph->object)->size)
6556 {
6557 /* If we're on a string with `help-echo' text property,
6558 arrange for the help to be displayed. This is done by
6559 setting the global variable help_echo to the help string. */
6560 help = Fget_text_property (make_number (glyph->charpos),
6561 Qhelp_echo, glyph->object);
b7e80413 6562 if (!NILP (help))
be010514
GM
6563 {
6564 help_echo = help;
7cea38bc 6565 XSETWINDOW (help_echo_window, w);
be010514
GM
6566 help_echo_object = glyph->object;
6567 help_echo_pos = glyph->charpos;
6568 }
06a2c219
GM
6569
6570 /* Change the mouse pointer according to what is under X/Y. */
6571 map = Fget_text_property (make_number (glyph->charpos),
6572 Qlocal_map, glyph->object);
02067692 6573 if (KEYMAPP (map))
06a2c219 6574 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6575 else
6576 {
6577 map = Fget_text_property (make_number (glyph->charpos),
6578 Qkeymap, glyph->object);
02067692 6579 if (KEYMAPP (map))
be010514
GM
6580 cursor = f->output_data.x->nontext_cursor;
6581 }
06a2c219
GM
6582 }
6583 }
6584
6585 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6586}
6587
6588
6589/* Take proper action when the mouse has moved to position X, Y on
6590 frame F as regards highlighting characters that have mouse-face
6591 properties. Also de-highlighting chars where the mouse was before.
27f338af 6592 X and Y can be negative or out of range. */
b8009dd1
RS
6593
6594static void
6595note_mouse_highlight (f, x, y)
06a2c219 6596 struct frame *f;
c32cdd9a 6597 int x, y;
b8009dd1 6598{
06a2c219
GM
6599 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6600 int portion;
b8009dd1
RS
6601 Lisp_Object window;
6602 struct window *w;
6603
06a2c219
GM
6604 /* When a menu is active, don't highlight because this looks odd. */
6605#ifdef USE_X_TOOLKIT
6606 if (popup_activated ())
6607 return;
6608#endif
6609
04fff9c0
GM
6610 if (disable_mouse_highlight
6611 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6612 return;
6613
06a2c219
GM
6614 dpyinfo->mouse_face_mouse_x = x;
6615 dpyinfo->mouse_face_mouse_y = y;
6616 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6617
06a2c219 6618 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6619 return;
6620
514e4681
RS
6621 if (gc_in_progress)
6622 {
06a2c219 6623 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6624 return;
6625 }
6626
b8009dd1 6627 /* Which window is that in? */
06a2c219 6628 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6629
6630 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6631 if (! EQ (window, dpyinfo->mouse_face_window))
6632 clear_mouse_face (dpyinfo);
6633
6634 /* Not on a window -> return. */
6635 if (!WINDOWP (window))
6636 return;
6637
6638 /* Convert to window-relative pixel coordinates. */
6639 w = XWINDOW (window);
6640 frame_to_window_pixel_xy (w, &x, &y);
6641
9ea173e8 6642 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6643 buffer. */
9ea173e8 6644 if (EQ (window, f->tool_bar_window))
06a2c219 6645 {
9ea173e8 6646 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6647 return;
6648 }
6649
6650 if (portion == 1 || portion == 3)
6651 {
6652 /* Mouse is on the mode or top line. */
6653 note_mode_line_highlight (w, x, portion == 1);
6654 return;
6655 }
e371a781
GM
6656 else if (portion == 2)
6657 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6658 f->output_data.x->horizontal_drag_cursor);
06a2c219
GM
6659 else
6660 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6661 f->output_data.x->text_cursor);
b8009dd1 6662
0cdd0c9f
RS
6663 /* Are we in a window whose display is up to date?
6664 And verify the buffer's text has not changed. */
06a2c219
GM
6665 if (/* Within text portion of the window. */
6666 portion == 0
0cdd0c9f 6667 && EQ (w->window_end_valid, w->buffer)
26459b28
KH
6668 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
6669 && (XFASTINT (w->last_overlay_modified)
6670 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
b8009dd1 6671 {
06a2c219
GM
6672 int hpos, vpos, pos, i, area;
6673 struct glyph *glyph;
b8009dd1 6674
06a2c219
GM
6675 /* Find the glyph under X/Y. */
6676 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
6677
6678 /* Clear mouse face if X/Y not over text. */
6679 if (glyph == NULL
6680 || area != TEXT_AREA
6681 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6682 {
06a2c219
GM
6683 clear_mouse_face (dpyinfo);
6684 return;
6685 }
6686
6687 pos = glyph->charpos;
6688 xassert (w->pseudo_window_p || BUFFERP (glyph->object));
6689
6690 /* Check for mouse-face and help-echo. */
6691 {
6692 Lisp_Object mouse_face, overlay, position;
6693 Lisp_Object *overlay_vec;
6694 int len, noverlays;
6695 struct buffer *obuf;
6696 int obegv, ozv;
6697
6698 /* If we get an out-of-range value, return now; avoid an error. */
6699 if (pos > BUF_Z (XBUFFER (w->buffer)))
6700 return;
6701
6702 /* Make the window's buffer temporarily current for
6703 overlays_at and compute_char_face. */
6704 obuf = current_buffer;
6705 current_buffer = XBUFFER (w->buffer);
6706 obegv = BEGV;
6707 ozv = ZV;
6708 BEGV = BEG;
6709 ZV = Z;
6710
6711 /* Is this char mouse-active or does it have help-echo? */
6712 XSETINT (position, pos);
6713
6714 /* Put all the overlays we want in a vector in overlay_vec.
6715 Store the length in len. If there are more than 10, make
6716 enough space for all, and try again. */
6717 len = 10;
6718 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
bc592036 6719 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
06a2c219
GM
6720 if (noverlays > len)
6721 {
6722 len = noverlays;
6723 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
bc592036 6724 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
06a2c219 6725 }
f8349001
GM
6726
6727 /* Sort overlays into increasing priority order. */
06a2c219
GM
6728 noverlays = sort_overlays (overlay_vec, noverlays, w);
6729
6730 /* Check mouse-face highlighting. */
6731 if (! (EQ (window, dpyinfo->mouse_face_window)
6732 && vpos >= dpyinfo->mouse_face_beg_row
6733 && vpos <= dpyinfo->mouse_face_end_row
6734 && (vpos > dpyinfo->mouse_face_beg_row
6735 || hpos >= dpyinfo->mouse_face_beg_col)
6736 && (vpos < dpyinfo->mouse_face_end_row
6737 || hpos < dpyinfo->mouse_face_end_col
6738 || dpyinfo->mouse_face_past_end)))
6739 {
6740 /* Clear the display of the old active region, if any. */
6741 clear_mouse_face (dpyinfo);
6742
6743 /* Find the highest priority overlay that has a mouse-face prop. */
6744 overlay = Qnil;
f8349001 6745 for (i = noverlays - 1; i >= 0; --i)
06a2c219
GM
6746 {
6747 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6748 if (!NILP (mouse_face))
6749 {
6750 overlay = overlay_vec[i];
6751 break;
6752 }
6753 }
6754
6755 /* If no overlay applies, get a text property. */
6756 if (NILP (overlay))
6757 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6758
6759 /* Handle the overlay case. */
6760 if (! NILP (overlay))
6761 {
6762 /* Find the range of text around this char that
6763 should be active. */
6764 Lisp_Object before, after;
6765 int ignore;
6766
6767 before = Foverlay_start (overlay);
6768 after = Foverlay_end (overlay);
6769 /* Record this as the current active region. */
6770 fast_find_position (w, XFASTINT (before),
6771 &dpyinfo->mouse_face_beg_col,
6772 &dpyinfo->mouse_face_beg_row,
6773 &dpyinfo->mouse_face_beg_x,
6774 &dpyinfo->mouse_face_beg_y);
6775 dpyinfo->mouse_face_past_end
6776 = !fast_find_position (w, XFASTINT (after),
6777 &dpyinfo->mouse_face_end_col,
6778 &dpyinfo->mouse_face_end_row,
6779 &dpyinfo->mouse_face_end_x,
6780 &dpyinfo->mouse_face_end_y);
6781 dpyinfo->mouse_face_window = window;
6782 dpyinfo->mouse_face_face_id
6783 = face_at_buffer_position (w, pos, 0, 0,
6784 &ignore, pos + 1, 1);
6785
6786 /* Display it as active. */
6787 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6788 }
6789 /* Handle the text property case. */
6790 else if (! NILP (mouse_face))
6791 {
6792 /* Find the range of text around this char that
6793 should be active. */
6794 Lisp_Object before, after, beginning, end;
6795 int ignore;
6796
6797 beginning = Fmarker_position (w->start);
6798 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
6799 - XFASTINT (w->window_end_pos)));
6800 before
6801 = Fprevious_single_property_change (make_number (pos + 1),
6802 Qmouse_face,
6803 w->buffer, beginning);
6804 after
6805 = Fnext_single_property_change (position, Qmouse_face,
6806 w->buffer, end);
6807 /* Record this as the current active region. */
6808 fast_find_position (w, XFASTINT (before),
6809 &dpyinfo->mouse_face_beg_col,
6810 &dpyinfo->mouse_face_beg_row,
6811 &dpyinfo->mouse_face_beg_x,
6812 &dpyinfo->mouse_face_beg_y);
6813 dpyinfo->mouse_face_past_end
6814 = !fast_find_position (w, XFASTINT (after),
6815 &dpyinfo->mouse_face_end_col,
6816 &dpyinfo->mouse_face_end_row,
6817 &dpyinfo->mouse_face_end_x,
6818 &dpyinfo->mouse_face_end_y);
6819 dpyinfo->mouse_face_window = window;
6820 dpyinfo->mouse_face_face_id
6821 = face_at_buffer_position (w, pos, 0, 0,
6822 &ignore, pos + 1, 1);
6823
6824 /* Display it as active. */
6825 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6826 }
6827 }
6828
6829 /* Look for a `help-echo' property. */
6830 {
743934db 6831 Lisp_Object help, overlay;
06a2c219
GM
6832
6833 /* Check overlays first. */
f9b5db02 6834 help = overlay = Qnil;
f8349001 6835 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
743934db
GM
6836 {
6837 overlay = overlay_vec[i];
6838 help = Foverlay_get (overlay, Qhelp_echo);
6839 }
be010514
GM
6840
6841 if (!NILP (help))
6842 {
6843 help_echo = help;
7cea38bc 6844 help_echo_window = window;
743934db 6845 help_echo_object = overlay;
be010514
GM
6846 help_echo_pos = pos;
6847 }
6848 else
6849 {
6850 /* Try text properties. */
6851 if ((STRINGP (glyph->object)
06a2c219
GM
6852 && glyph->charpos >= 0
6853 && glyph->charpos < XSTRING (glyph->object)->size)
6854 || (BUFFERP (glyph->object)
6855 && glyph->charpos >= BEGV
be010514
GM
6856 && glyph->charpos < ZV))
6857 help = Fget_text_property (make_number (glyph->charpos),
6858 Qhelp_echo, glyph->object);
06a2c219 6859
be010514
GM
6860 if (!NILP (help))
6861 {
6862 help_echo = help;
7cea38bc 6863 help_echo_window = window;
be010514
GM
6864 help_echo_object = glyph->object;
6865 help_echo_pos = glyph->charpos;
6866 }
6867 }
06a2c219
GM
6868 }
6869
6870 BEGV = obegv;
6871 ZV = ozv;
6872 current_buffer = obuf;
6873 }
6874 }
6875}
6876
6877static void
6878redo_mouse_highlight ()
6879{
6880 if (!NILP (last_mouse_motion_frame)
6881 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
6882 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
6883 last_mouse_motion_event.x,
6884 last_mouse_motion_event.y);
6885}
6886
6887
6888\f
6889/***********************************************************************
9ea173e8 6890 Tool-bars
06a2c219
GM
6891 ***********************************************************************/
6892
9ea173e8
GM
6893static int x_tool_bar_item P_ ((struct frame *, int, int,
6894 struct glyph **, int *, int *, int *));
06a2c219 6895
9ea173e8 6896/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
6897 or -1. */
6898
9ea173e8 6899static int last_tool_bar_item;
06a2c219
GM
6900
6901
9ea173e8
GM
6902/* Get information about the tool-bar item at position X/Y on frame F.
6903 Return in *GLYPH a pointer to the glyph of the tool-bar item in
6904 the current matrix of the tool-bar window of F, or NULL if not
6905 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 6906 item in F->tool_bar_items. Value is
06a2c219 6907
9ea173e8 6908 -1 if X/Y is not on a tool-bar item
06a2c219
GM
6909 0 if X/Y is on the same item that was highlighted before.
6910 1 otherwise. */
6911
6912static int
9ea173e8 6913x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
6914 struct frame *f;
6915 int x, y;
6916 struct glyph **glyph;
6917 int *hpos, *vpos, *prop_idx;
6918{
6919 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6920 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6921 int area;
6922
6923 /* Find the glyph under X/Y. */
6924 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
6925 if (*glyph == NULL)
6926 return -1;
6927
9ea173e8 6928 /* Get the start of this tool-bar item's properties in
8daf1204 6929 f->tool_bar_items. */
9ea173e8 6930 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
6931 return -1;
6932
6933 /* Is mouse on the highlighted item? */
9ea173e8 6934 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
6935 && *vpos >= dpyinfo->mouse_face_beg_row
6936 && *vpos <= dpyinfo->mouse_face_end_row
6937 && (*vpos > dpyinfo->mouse_face_beg_row
6938 || *hpos >= dpyinfo->mouse_face_beg_col)
6939 && (*vpos < dpyinfo->mouse_face_end_row
6940 || *hpos < dpyinfo->mouse_face_end_col
6941 || dpyinfo->mouse_face_past_end))
6942 return 0;
6943
6944 return 1;
6945}
6946
6947
9ea173e8 6948/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
6949 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
6950 or ButtonRelase. */
6951
6952static void
9ea173e8 6953x_handle_tool_bar_click (f, button_event)
06a2c219
GM
6954 struct frame *f;
6955 XButtonEvent *button_event;
6956{
6957 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6958 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6959 int hpos, vpos, prop_idx;
6960 struct glyph *glyph;
6961 Lisp_Object enabled_p;
6962 int x = button_event->x;
6963 int y = button_event->y;
6964
9ea173e8 6965 /* If not on the highlighted tool-bar item, return. */
06a2c219 6966 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 6967 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
6968 return;
6969
6970 /* If item is disabled, do nothing. */
8daf1204 6971 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
6972 if (NILP (enabled_p))
6973 return;
6974
6975 if (button_event->type == ButtonPress)
6976 {
6977 /* Show item in pressed state. */
6978 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
6979 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 6980 last_tool_bar_item = prop_idx;
06a2c219
GM
6981 }
6982 else
6983 {
6984 Lisp_Object key, frame;
6985 struct input_event event;
6986
6987 /* Show item in released state. */
6988 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
6989 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
6990
8daf1204 6991 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
6992
6993 XSETFRAME (frame, f);
9ea173e8 6994 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
6995 event.frame_or_window = frame;
6996 event.arg = frame;
06a2c219
GM
6997 kbd_buffer_store_event (&event);
6998
9ea173e8 6999 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7000 event.frame_or_window = frame;
7001 event.arg = key;
06a2c219
GM
7002 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7003 button_event->state);
7004 kbd_buffer_store_event (&event);
9ea173e8 7005 last_tool_bar_item = -1;
06a2c219
GM
7006 }
7007}
7008
7009
9ea173e8
GM
7010/* Possibly highlight a tool-bar item on frame F when mouse moves to
7011 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7012 note_mouse_highlight. */
7013
7014static void
9ea173e8 7015note_tool_bar_highlight (f, x, y)
06a2c219
GM
7016 struct frame *f;
7017 int x, y;
7018{
9ea173e8 7019 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7020 struct window *w = XWINDOW (window);
7021 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7022 int hpos, vpos;
7023 struct glyph *glyph;
7024 struct glyph_row *row;
5c187dee 7025 int i;
06a2c219
GM
7026 Lisp_Object enabled_p;
7027 int prop_idx;
7028 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
5c187dee 7029 int mouse_down_p, rc;
06a2c219
GM
7030
7031 /* Function note_mouse_highlight is called with negative x(y
7032 values when mouse moves outside of the frame. */
7033 if (x <= 0 || y <= 0)
7034 {
7035 clear_mouse_face (dpyinfo);
7036 return;
7037 }
7038
9ea173e8 7039 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7040 if (rc < 0)
7041 {
9ea173e8 7042 /* Not on tool-bar item. */
06a2c219
GM
7043 clear_mouse_face (dpyinfo);
7044 return;
7045 }
7046 else if (rc == 0)
9ea173e8 7047 /* On same tool-bar item as before. */
06a2c219 7048 goto set_help_echo;
b8009dd1 7049
06a2c219
GM
7050 clear_mouse_face (dpyinfo);
7051
9ea173e8 7052 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7053 mouse_down_p = (dpyinfo->grabbed
7054 && f == last_mouse_frame
7055 && FRAME_LIVE_P (f));
7056 if (mouse_down_p
9ea173e8 7057 && last_tool_bar_item != prop_idx)
06a2c219
GM
7058 return;
7059
7060 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7061 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7062
9ea173e8 7063 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7064 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7065 if (!NILP (enabled_p))
7066 {
7067 /* Compute the x-position of the glyph. In front and past the
7068 image is a space. We include this is the highlighted area. */
7069 row = MATRIX_ROW (w->current_matrix, vpos);
7070 for (i = x = 0; i < hpos; ++i)
7071 x += row->glyphs[TEXT_AREA][i].pixel_width;
7072
7073 /* Record this as the current active region. */
7074 dpyinfo->mouse_face_beg_col = hpos;
7075 dpyinfo->mouse_face_beg_row = vpos;
7076 dpyinfo->mouse_face_beg_x = x;
7077 dpyinfo->mouse_face_beg_y = row->y;
7078 dpyinfo->mouse_face_past_end = 0;
7079
7080 dpyinfo->mouse_face_end_col = hpos + 1;
7081 dpyinfo->mouse_face_end_row = vpos;
7082 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7083 dpyinfo->mouse_face_end_y = row->y;
7084 dpyinfo->mouse_face_window = window;
9ea173e8 7085 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
7086
7087 /* Display it as active. */
7088 show_mouse_face (dpyinfo, draw);
7089 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7090 }
06a2c219
GM
7091
7092 set_help_echo:
7093
9ea173e8 7094 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 7095 XTread_socket does the rest. */
7cea38bc 7096 help_echo_object = help_echo_window = Qnil;
be010514 7097 help_echo_pos = -1;
8daf1204 7098 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7099 if (NILP (help_echo))
8daf1204 7100 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7101}
4d73d038 7102
06a2c219
GM
7103
7104\f
7105/* Find the glyph matrix position of buffer position POS in window W.
7106 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7107 current glyphs must be up to date. If POS is above window start
7108 return (0, 0, 0, 0). If POS is after end of W, return end of
7109 last line in W. */
b8009dd1
RS
7110
7111static int
06a2c219
GM
7112fast_find_position (w, pos, hpos, vpos, x, y)
7113 struct window *w;
b8009dd1 7114 int pos;
06a2c219 7115 int *hpos, *vpos, *x, *y;
b8009dd1 7116{
b8009dd1 7117 int i;
bf1c0ba1 7118 int lastcol;
06a2c219
GM
7119 int maybe_next_line_p = 0;
7120 int line_start_position;
7121 int yb = window_text_bottom_y (w);
7122 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
7123 struct glyph_row *best_row = row;
7124 int row_vpos = 0, best_row_vpos = 0;
7125 int current_x;
7126
7127 while (row->y < yb)
b8009dd1 7128 {
06a2c219
GM
7129 if (row->used[TEXT_AREA])
7130 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7131 else
7132 line_start_position = 0;
7133
7134 if (line_start_position > pos)
b8009dd1 7135 break;
77b68646
RS
7136 /* If the position sought is the end of the buffer,
7137 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7138 else if (line_start_position == pos
7139 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7140 {
06a2c219 7141 maybe_next_line_p = 1;
77b68646
RS
7142 break;
7143 }
06a2c219
GM
7144 else if (line_start_position > 0)
7145 {
7146 best_row = row;
7147 best_row_vpos = row_vpos;
7148 }
4b0bb6f3
GM
7149
7150 if (row->y + row->height >= yb)
7151 break;
06a2c219
GM
7152
7153 ++row;
7154 ++row_vpos;
b8009dd1 7155 }
06a2c219
GM
7156
7157 /* Find the right column within BEST_ROW. */
7158 lastcol = 0;
7159 current_x = best_row->x;
7160 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7161 {
06a2c219
GM
7162 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7163 int charpos;
7164
7165 charpos = glyph->charpos;
7166 if (charpos == pos)
bf1c0ba1 7167 {
06a2c219
GM
7168 *hpos = i;
7169 *vpos = best_row_vpos;
7170 *x = current_x;
7171 *y = best_row->y;
bf1c0ba1
RS
7172 return 1;
7173 }
06a2c219 7174 else if (charpos > pos)
4d73d038 7175 break;
06a2c219
GM
7176 else if (charpos > 0)
7177 lastcol = i;
7178
7179 current_x += glyph->pixel_width;
bf1c0ba1 7180 }
b8009dd1 7181
77b68646
RS
7182 /* If we're looking for the end of the buffer,
7183 and we didn't find it in the line we scanned,
7184 use the start of the following line. */
06a2c219 7185 if (maybe_next_line_p)
77b68646 7186 {
06a2c219
GM
7187 ++best_row;
7188 ++best_row_vpos;
7189 lastcol = 0;
7190 current_x = best_row->x;
77b68646
RS
7191 }
7192
06a2c219
GM
7193 *vpos = best_row_vpos;
7194 *hpos = lastcol + 1;
7195 *x = current_x;
7196 *y = best_row->y;
b8009dd1
RS
7197 return 0;
7198}
7199
06a2c219 7200
b8009dd1
RS
7201/* Display the active region described by mouse_face_*
7202 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7203
7204static void
06a2c219 7205show_mouse_face (dpyinfo, draw)
7a13e894 7206 struct x_display_info *dpyinfo;
06a2c219 7207 enum draw_glyphs_face draw;
b8009dd1 7208{
7a13e894 7209 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7210 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 7211 int i;
06a2c219
GM
7212 int cursor_off_p = 0;
7213 struct cursor_pos saved_cursor;
7214
7215 saved_cursor = output_cursor;
7216
7217 /* If window is in the process of being destroyed, don't bother
7218 to do anything. */
7219 if (w->current_matrix == NULL)
7220 goto set_x_cursor;
7221
7222 /* Recognize when we are called to operate on rows that don't exist
7223 anymore. This can happen when a window is split. */
7224 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
7225 goto set_x_cursor;
7226
7227 set_output_cursor (&w->phys_cursor);
7228
7229 /* Note that mouse_face_beg_row etc. are window relative. */
7230 for (i = dpyinfo->mouse_face_beg_row;
7231 i <= dpyinfo->mouse_face_end_row;
7232 i++)
7233 {
7234 int start_hpos, end_hpos, start_x;
7235 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
7236
7237 /* Don't do anything if row doesn't have valid contents. */
7238 if (!row->enabled_p)
7239 continue;
7240
7241 /* For all but the first row, the highlight starts at column 0. */
7242 if (i == dpyinfo->mouse_face_beg_row)
7243 {
7244 start_hpos = dpyinfo->mouse_face_beg_col;
7245 start_x = dpyinfo->mouse_face_beg_x;
7246 }
7247 else
7248 {
7249 start_hpos = 0;
7250 start_x = 0;
7251 }
7252
7253 if (i == dpyinfo->mouse_face_end_row)
7254 end_hpos = dpyinfo->mouse_face_end_col;
7255 else
7256 end_hpos = row->used[TEXT_AREA];
7257
7258 /* If the cursor's in the text we are about to rewrite, turn the
7259 cursor off. */
7260 if (!w->pseudo_window_p
7261 && i == output_cursor.vpos
7262 && output_cursor.hpos >= start_hpos - 1
7263 && output_cursor.hpos <= end_hpos)
514e4681 7264 {
06a2c219
GM
7265 x_update_window_cursor (w, 0);
7266 cursor_off_p = 1;
514e4681 7267 }
b8009dd1 7268
06a2c219 7269 if (end_hpos > start_hpos)
64f26cf5
GM
7270 {
7271 row->mouse_face_p = draw == DRAW_MOUSE_FACE;
7272 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7273 start_hpos, end_hpos, draw, NULL, NULL, 0);
7274 }
b8009dd1
RS
7275 }
7276
514e4681 7277 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
7278 if (cursor_off_p)
7279 x_display_cursor (w, 1,
7280 output_cursor.hpos, output_cursor.vpos,
7281 output_cursor.x, output_cursor.y);
2729a2b5 7282
06a2c219 7283 output_cursor = saved_cursor;
fb3b7de5 7284
06a2c219
GM
7285 set_x_cursor:
7286
7287 /* Change the mouse cursor. */
7288 if (draw == DRAW_NORMAL_TEXT)
7289 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7290 f->output_data.x->text_cursor);
7291 else if (draw == DRAW_MOUSE_FACE)
334208b7 7292 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7293 f->output_data.x->cross_cursor);
27ead1d5 7294 else
334208b7 7295 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7296 f->output_data.x->nontext_cursor);
b8009dd1
RS
7297}
7298
7299/* Clear out the mouse-highlighted active region.
06a2c219 7300 Redraw it un-highlighted first. */
b8009dd1 7301
06a2c219 7302void
7a13e894
RS
7303clear_mouse_face (dpyinfo)
7304 struct x_display_info *dpyinfo;
b8009dd1 7305{
06a2c219
GM
7306 if (tip_frame)
7307 return;
7308
7a13e894 7309 if (! NILP (dpyinfo->mouse_face_window))
06a2c219 7310 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
b8009dd1 7311
7a13e894
RS
7312 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7313 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7314 dpyinfo->mouse_face_window = Qnil;
b8009dd1 7315}
e687d06e 7316
71b8321e
GM
7317
7318/* Clear any mouse-face on window W. This function is part of the
7319 redisplay interface, and is called from try_window_id and similar
7320 functions to ensure the mouse-highlight is off. */
7321
7322static void
7323x_clear_mouse_face (w)
7324 struct window *w;
7325{
7326 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7327 Lisp_Object window;
7328
2e636f9d 7329 BLOCK_INPUT;
71b8321e
GM
7330 XSETWINDOW (window, w);
7331 if (EQ (window, dpyinfo->mouse_face_window))
7332 clear_mouse_face (dpyinfo);
2e636f9d 7333 UNBLOCK_INPUT;
71b8321e
GM
7334}
7335
7336
e687d06e
RS
7337/* Just discard the mouse face information for frame F, if any.
7338 This is used when the size of F is changed. */
7339
dfcf069d 7340void
e687d06e
RS
7341cancel_mouse_face (f)
7342 FRAME_PTR f;
7343{
7344 Lisp_Object window;
7345 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7346
7347 window = dpyinfo->mouse_face_window;
7348 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7349 {
7350 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7351 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7352 dpyinfo->mouse_face_window = Qnil;
7353 }
7354}
b8009dd1 7355\f
ab648270
JB
7356static struct scroll_bar *x_window_to_scroll_bar ();
7357static void x_scroll_bar_report_motion ();
12ba150f 7358
90e65f07 7359/* Return the current position of the mouse.
2d7fc7e8 7360 *fp should be a frame which indicates which display to ask about.
90e65f07 7361
2d7fc7e8 7362 If the mouse movement started in a scroll bar, set *fp, *bar_window,
ab648270 7363 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 7364 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 7365 position on the scroll bar.
12ba150f 7366
2d7fc7e8 7367 If the mouse movement started elsewhere, set *fp to the frame the
12ba150f
JB
7368 mouse is on, *bar_window to nil, and *x and *y to the character cell
7369 the mouse is over.
7370
06a2c219 7371 Set *time to the server time-stamp for the time at which the mouse
12ba150f
JB
7372 was at this position.
7373
a135645a
RS
7374 Don't store anything if we don't have a valid set of values to report.
7375
90e65f07 7376 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7377 movement. */
90e65f07
JB
7378
7379static void
1cf412ec 7380XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7381 FRAME_PTR *fp;
1cf412ec 7382 int insist;
12ba150f 7383 Lisp_Object *bar_window;
ab648270 7384 enum scroll_bar_part *part;
90e65f07 7385 Lisp_Object *x, *y;
e5d77022 7386 unsigned long *time;
90e65f07 7387{
a135645a
RS
7388 FRAME_PTR f1;
7389
90e65f07
JB
7390 BLOCK_INPUT;
7391
8bcee03e 7392 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7393 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7394 else
7395 {
12ba150f
JB
7396 Window root;
7397 int root_x, root_y;
90e65f07 7398
12ba150f
JB
7399 Window dummy_window;
7400 int dummy;
7401
39d8bb4d
KH
7402 Lisp_Object frame, tail;
7403
7404 /* Clear the mouse-moved flag for every frame on this display. */
7405 FOR_EACH_FRAME (tail, frame)
7406 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7407 XFRAME (frame)->mouse_moved = 0;
7408
ab648270 7409 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7410
7411 /* Figure out which root window we're on. */
334208b7
RS
7412 XQueryPointer (FRAME_X_DISPLAY (*fp),
7413 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7414
7415 /* The root window which contains the pointer. */
7416 &root,
7417
7418 /* Trash which we can't trust if the pointer is on
7419 a different screen. */
7420 &dummy_window,
7421
7422 /* The position on that root window. */
58769bee 7423 &root_x, &root_y,
12ba150f
JB
7424
7425 /* More trash we can't trust. */
7426 &dummy, &dummy,
7427
7428 /* Modifier keys and pointer buttons, about which
7429 we don't care. */
7430 (unsigned int *) &dummy);
7431
7432 /* Now we have a position on the root; find the innermost window
7433 containing the pointer. */
7434 {
7435 Window win, child;
7436 int win_x, win_y;
06a2c219 7437 int parent_x = 0, parent_y = 0;
e99db5a1 7438 int count;
12ba150f
JB
7439
7440 win = root;
69388238 7441
2d7fc7e8
RS
7442 /* XTranslateCoordinates can get errors if the window
7443 structure is changing at the same time this function
7444 is running. So at least we must not crash from them. */
7445
e99db5a1 7446 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 7447
334208b7 7448 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 7449 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 7450 {
69388238
RS
7451 /* If mouse was grabbed on a frame, give coords for that frame
7452 even if the mouse is now outside it. */
334208b7 7453 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 7454
12ba150f 7455 /* From-window, to-window. */
69388238 7456 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
7457
7458 /* From-position, to-position. */
7459 root_x, root_y, &win_x, &win_y,
7460
7461 /* Child of win. */
7462 &child);
69388238
RS
7463 f1 = last_mouse_frame;
7464 }
7465 else
7466 {
7467 while (1)
7468 {
334208b7 7469 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 7470
69388238
RS
7471 /* From-window, to-window. */
7472 root, win,
12ba150f 7473
69388238
RS
7474 /* From-position, to-position. */
7475 root_x, root_y, &win_x, &win_y,
7476
7477 /* Child of win. */
7478 &child);
7479
9af3143a 7480 if (child == None || child == win)
69388238
RS
7481 break;
7482
7483 win = child;
7484 parent_x = win_x;
7485 parent_y = win_y;
7486 }
12ba150f 7487
69388238
RS
7488 /* Now we know that:
7489 win is the innermost window containing the pointer
7490 (XTC says it has no child containing the pointer),
7491 win_x and win_y are the pointer's position in it
7492 (XTC did this the last time through), and
7493 parent_x and parent_y are the pointer's position in win's parent.
7494 (They are what win_x and win_y were when win was child.
7495 If win is the root window, it has no parent, and
7496 parent_{x,y} are invalid, but that's okay, because we'll
7497 never use them in that case.) */
7498
7499 /* Is win one of our frames? */
19126e11 7500 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
7501
7502#ifdef USE_X_TOOLKIT
7503 /* If we end up with the menu bar window, say it's not
7504 on the frame. */
7505 if (f1 != NULL
7506 && f1->output_data.x->menubar_widget
7507 && win == XtWindow (f1->output_data.x->menubar_widget))
7508 f1 = NULL;
7509#endif /* USE_X_TOOLKIT */
69388238 7510 }
58769bee 7511
2d7fc7e8
RS
7512 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
7513 f1 = 0;
7514
e99db5a1 7515 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 7516
ab648270 7517 /* If not, is it one of our scroll bars? */
a135645a 7518 if (! f1)
12ba150f 7519 {
ab648270 7520 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
7521
7522 if (bar)
7523 {
a135645a 7524 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
7525 win_x = parent_x;
7526 win_y = parent_y;
7527 }
7528 }
90e65f07 7529
8bcee03e 7530 if (f1 == 0 && insist > 0)
b86bd3dd 7531 f1 = SELECTED_FRAME ();
1cf412ec 7532
a135645a 7533 if (f1)
12ba150f 7534 {
06a2c219
GM
7535 /* Ok, we found a frame. Store all the values.
7536 last_mouse_glyph is a rectangle used to reduce the
7537 generation of mouse events. To not miss any motion
7538 events, we must divide the frame into rectangles of the
7539 size of the smallest character that could be displayed
7540 on it, i.e. into the same rectangles that matrices on
7541 the frame are divided into. */
7542
7543#if OLD_REDISPLAY_CODE
2b5c9e71 7544 int ignore1, ignore2;
2b5c9e71 7545 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
334208b7 7546 &last_mouse_glyph,
1cf412ec
RS
7547 FRAME_X_DISPLAY_INFO (f1)->grabbed
7548 || insist);
06a2c219
GM
7549#else
7550 {
7551 int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
7552 int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
7553 int x = win_x;
7554 int y = win_y;
7555
7556 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
7557 round down even for negative values. */
7558 if (x < 0)
7559 x -= width - 1;
7560 if (y < 0)
7561 y -= height - 1;
7562
7563 last_mouse_glyph.width = width;
7564 last_mouse_glyph.height = height;
7565 last_mouse_glyph.x = (x + width - 1) / width * width;
7566 last_mouse_glyph.y = (y + height - 1) / height * height;
7567 }
7568#endif
12ba150f
JB
7569
7570 *bar_window = Qnil;
7571 *part = 0;
334208b7 7572 *fp = f1;
e0c1aef2
KH
7573 XSETINT (*x, win_x);
7574 XSETINT (*y, win_y);
12ba150f
JB
7575 *time = last_mouse_movement_time;
7576 }
7577 }
7578 }
90e65f07
JB
7579
7580 UNBLOCK_INPUT;
7581}
f451eb13 7582
06a2c219 7583
06a2c219 7584#ifdef USE_X_TOOLKIT
bffcfca9
GM
7585
7586/* Atimer callback function for TIMER. Called every 0.1s to process
7587 Xt timeouts, if needed. We must avoid calling XtAppPending as
7588 much as possible because that function does an implicit XFlush
7589 that slows us down. */
7590
7591static void
7592x_process_timeouts (timer)
7593 struct atimer *timer;
7594{
7595 if (toolkit_scroll_bar_interaction || popup_activated_flag)
7596 {
7597 BLOCK_INPUT;
7598 while (XtAppPending (Xt_app_con) & XtIMTimer)
7599 XtAppProcessEvent (Xt_app_con, XtIMTimer);
7600 UNBLOCK_INPUT;
7601 }
06a2c219
GM
7602}
7603
bffcfca9 7604#endif /* USE_X_TOOLKIT */
06a2c219
GM
7605
7606\f
7607/* Scroll bar support. */
7608
7609/* Given an X window ID, find the struct scroll_bar which manages it.
7610 This can be called in GC, so we have to make sure to strip off mark
7611 bits. */
bffcfca9 7612
06a2c219
GM
7613static struct scroll_bar *
7614x_window_to_scroll_bar (window_id)
7615 Window window_id;
7616{
7617 Lisp_Object tail;
7618
7619 for (tail = Vframe_list;
7620 XGCTYPE (tail) == Lisp_Cons;
8e713be6 7621 tail = XCDR (tail))
06a2c219
GM
7622 {
7623 Lisp_Object frame, bar, condemned;
7624
8e713be6 7625 frame = XCAR (tail);
06a2c219
GM
7626 /* All elements of Vframe_list should be frames. */
7627 if (! GC_FRAMEP (frame))
7628 abort ();
7629
7630 /* Scan this frame's scroll bar list for a scroll bar with the
7631 right window ID. */
7632 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
7633 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
7634 /* This trick allows us to search both the ordinary and
7635 condemned scroll bar lists with one loop. */
7636 ! GC_NILP (bar) || (bar = condemned,
7637 condemned = Qnil,
7638 ! GC_NILP (bar));
7639 bar = XSCROLL_BAR (bar)->next)
7640 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
7641 return XSCROLL_BAR (bar);
7642 }
7643
7644 return 0;
7645}
7646
7647
7648\f
7649/************************************************************************
7650 Toolkit scroll bars
7651 ************************************************************************/
7652
eccc05db 7653#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
7654
7655static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
7656static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
7657static void x_create_toolkit_scroll_bar P_ ((struct frame *,
7658 struct scroll_bar *));
7659static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
7660 int, int, int));
7661
7662
7663/* Id of action hook installed for scroll bars. */
7664
7665static XtActionHookId action_hook_id;
7666
7667/* Lisp window being scrolled. Set when starting to interact with
7668 a toolkit scroll bar, reset to nil when ending the interaction. */
7669
7670static Lisp_Object window_being_scrolled;
7671
7672/* Last scroll bar part sent in xm_scroll_callback. */
7673
7674static int last_scroll_bar_part;
7675
ec18280f
SM
7676/* Whether this is an Xaw with arrow-scrollbars. This should imply
7677 that movements of 1/20 of the screen size are mapped to up/down. */
7678
7679static Boolean xaw3d_arrow_scroll;
7680
7681/* Whether the drag scrolling maintains the mouse at the top of the
7682 thumb. If not, resizing the thumb needs to be done more carefully
7683 to avoid jerkyness. */
7684
7685static Boolean xaw3d_pick_top;
7686
06a2c219
GM
7687
7688/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 7689 bars are used.. The hook is responsible for detecting when
06a2c219
GM
7690 the user ends an interaction with the scroll bar, and generates
7691 a `end-scroll' scroll_bar_click' event if so. */
7692
7693static void
7694xt_action_hook (widget, client_data, action_name, event, params,
7695 num_params)
7696 Widget widget;
7697 XtPointer client_data;
7698 String action_name;
7699 XEvent *event;
7700 String *params;
7701 Cardinal *num_params;
7702{
7703 int scroll_bar_p;
7704 char *end_action;
7705
7706#ifdef USE_MOTIF
7707 scroll_bar_p = XmIsScrollBar (widget);
7708 end_action = "Release";
ec18280f 7709#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7710 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
7711 end_action = "EndScroll";
ec18280f 7712#endif /* USE_MOTIF */
06a2c219 7713
06a2c219
GM
7714 if (scroll_bar_p
7715 && strcmp (action_name, end_action) == 0
7716 && WINDOWP (window_being_scrolled))
7717 {
7718 struct window *w;
7719
7720 x_send_scroll_bar_event (window_being_scrolled,
7721 scroll_bar_end_scroll, 0, 0);
7722 w = XWINDOW (window_being_scrolled);
7723 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
7724 window_being_scrolled = Qnil;
7725 last_scroll_bar_part = -1;
bffcfca9
GM
7726
7727 /* Xt timeouts no longer needed. */
7728 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
7729 }
7730}
7731
07b3d16e
GM
7732/* A vector of windows used for communication between
7733 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
7734
7735static struct window **scroll_bar_windows;
7736static int scroll_bar_windows_size;
7737
06a2c219
GM
7738
7739/* Send a client message with message type Xatom_Scrollbar for a
7740 scroll action to the frame of WINDOW. PART is a value identifying
7741 the part of the scroll bar that was clicked on. PORTION is the
7742 amount to scroll of a whole of WHOLE. */
7743
7744static void
7745x_send_scroll_bar_event (window, part, portion, whole)
7746 Lisp_Object window;
7747 int part, portion, whole;
7748{
7749 XEvent event;
7750 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
7751 struct window *w = XWINDOW (window);
7752 struct frame *f = XFRAME (w->frame);
7753 int i;
06a2c219 7754
07b3d16e
GM
7755 BLOCK_INPUT;
7756
06a2c219
GM
7757 /* Construct a ClientMessage event to send to the frame. */
7758 ev->type = ClientMessage;
7759 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
7760 ev->display = FRAME_X_DISPLAY (f);
7761 ev->window = FRAME_X_WINDOW (f);
7762 ev->format = 32;
07b3d16e
GM
7763
7764 /* We can only transfer 32 bits in the XClientMessageEvent, which is
7765 not enough to store a pointer or Lisp_Object on a 64 bit system.
7766 So, store the window in scroll_bar_windows and pass the index
7767 into that array in the event. */
7768 for (i = 0; i < scroll_bar_windows_size; ++i)
7769 if (scroll_bar_windows[i] == NULL)
7770 break;
7771
7772 if (i == scroll_bar_windows_size)
7773 {
7774 int new_size = max (10, 2 * scroll_bar_windows_size);
7775 size_t nbytes = new_size * sizeof *scroll_bar_windows;
7776 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
7777
7778 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
7779 nbytes);
7780 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
7781 scroll_bar_windows_size = new_size;
7782 }
7783
7784 scroll_bar_windows[i] = w;
7785 ev->data.l[0] = (long) i;
06a2c219
GM
7786 ev->data.l[1] = (long) part;
7787 ev->data.l[2] = (long) 0;
7788 ev->data.l[3] = (long) portion;
7789 ev->data.l[4] = (long) whole;
7790
bffcfca9
GM
7791 /* Make Xt timeouts work while the scroll bar is active. */
7792 toolkit_scroll_bar_interaction = 1;
7793
06a2c219
GM
7794 /* Setting the event mask to zero means that the message will
7795 be sent to the client that created the window, and if that
7796 window no longer exists, no event will be sent. */
06a2c219
GM
7797 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
7798 UNBLOCK_INPUT;
7799}
7800
7801
7802/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
7803 in *IEVENT. */
7804
7805static void
7806x_scroll_bar_to_input_event (event, ievent)
7807 XEvent *event;
7808 struct input_event *ievent;
7809{
7810 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
7811 Lisp_Object window;
7812 struct frame *f;
07b3d16e
GM
7813 struct window *w;
7814
7815 w = scroll_bar_windows[ev->data.l[0]];
7816 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 7817
07b3d16e
GM
7818 XSETWINDOW (window, w);
7819 f = XFRAME (w->frame);
06a2c219
GM
7820
7821 ievent->kind = scroll_bar_click;
7822 ievent->frame_or_window = window;
0f8aabe9 7823 ievent->arg = Qnil;
06a2c219
GM
7824 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
7825 ievent->part = ev->data.l[1];
7826 ievent->code = ev->data.l[2];
7827 ievent->x = make_number ((int) ev->data.l[3]);
7828 ievent->y = make_number ((int) ev->data.l[4]);
7829 ievent->modifiers = 0;
7830}
7831
7832
7833#ifdef USE_MOTIF
7834
7835/* Minimum and maximum values used for Motif scroll bars. */
7836
7837#define XM_SB_MIN 1
7838#define XM_SB_MAX 10000000
7839#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
7840
7841
7842/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
7843 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
7844 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
7845
7846static void
7847xm_scroll_callback (widget, client_data, call_data)
7848 Widget widget;
7849 XtPointer client_data, call_data;
7850{
7851 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7852 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
7853 double percent;
7854 int part = -1, whole = 0, portion = 0;
7855
7856 switch (cs->reason)
7857 {
7858 case XmCR_DECREMENT:
7859 bar->dragging = Qnil;
7860 part = scroll_bar_up_arrow;
7861 break;
7862
7863 case XmCR_INCREMENT:
7864 bar->dragging = Qnil;
7865 part = scroll_bar_down_arrow;
7866 break;
7867
7868 case XmCR_PAGE_DECREMENT:
7869 bar->dragging = Qnil;
7870 part = scroll_bar_above_handle;
7871 break;
7872
7873 case XmCR_PAGE_INCREMENT:
7874 bar->dragging = Qnil;
7875 part = scroll_bar_below_handle;
7876 break;
7877
7878 case XmCR_TO_TOP:
7879 bar->dragging = Qnil;
7880 part = scroll_bar_to_top;
7881 break;
7882
7883 case XmCR_TO_BOTTOM:
7884 bar->dragging = Qnil;
7885 part = scroll_bar_to_bottom;
7886 break;
7887
7888 case XmCR_DRAG:
7889 {
7890 int slider_size;
7891 int dragging_down_p = (INTEGERP (bar->dragging)
7892 && XINT (bar->dragging) <= cs->value);
7893
7894 /* Get the slider size. */
7895 BLOCK_INPUT;
7896 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
7897 UNBLOCK_INPUT;
7898
7899 /* At the max position of the scroll bar, do a line-wise
7900 movement. Without doing anything, the LessTif scroll bar
7901 calls us with the same cs->value again and again. If we
7902 want to make sure that we can reach the end of the buffer,
7903 we have to do something.
7904
7905 Implementation note: setting bar->dragging always to
7906 cs->value gives a smoother movement at the max position.
7907 Setting it to nil when doing line-wise movement gives
7908 a better slider behavior. */
7909
7910 if (cs->value + slider_size == XM_SB_MAX
7911 || (dragging_down_p
7912 && last_scroll_bar_part == scroll_bar_down_arrow))
7913 {
7914 part = scroll_bar_down_arrow;
7915 bar->dragging = Qnil;
7916 }
7917 else
7918 {
7919 whole = XM_SB_RANGE;
7920 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
7921 part = scroll_bar_handle;
7922 bar->dragging = make_number (cs->value);
7923 }
7924 }
7925 break;
7926
7927 case XmCR_VALUE_CHANGED:
7928 break;
7929 };
7930
7931 if (part >= 0)
7932 {
7933 window_being_scrolled = bar->window;
7934 last_scroll_bar_part = part;
7935 x_send_scroll_bar_event (bar->window, part, portion, whole);
7936 }
7937}
7938
7939
ec18280f 7940#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
7941
7942
ec18280f 7943/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
7944 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
7945 scroll bar struct. CALL_DATA is a pointer to a float saying where
7946 the thumb is. */
7947
7948static void
ec18280f 7949xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
7950 Widget widget;
7951 XtPointer client_data, call_data;
7952{
7953 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7954 float top = *(float *) call_data;
7955 float shown;
ec18280f
SM
7956 int whole, portion, height;
7957 int part;
06a2c219
GM
7958
7959 /* Get the size of the thumb, a value between 0 and 1. */
7960 BLOCK_INPUT;
ec18280f 7961 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
7962 UNBLOCK_INPUT;
7963
7964 whole = 10000000;
7965 portion = shown < 1 ? top * whole : 0;
06a2c219 7966
ec18280f
SM
7967 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
7968 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
7969 the bottom, so we force the scrolling whenever we see that we're
7970 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
7971 we try to ensure that we always stay two pixels away from the
7972 bottom). */
06a2c219
GM
7973 part = scroll_bar_down_arrow;
7974 else
7975 part = scroll_bar_handle;
7976
7977 window_being_scrolled = bar->window;
7978 bar->dragging = make_number (portion);
7979 last_scroll_bar_part = part;
7980 x_send_scroll_bar_event (bar->window, part, portion, whole);
7981}
7982
7983
ec18280f
SM
7984/* Xaw scroll bar callback. Invoked for incremental scrolling.,
7985 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
7986 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
7987 the scroll bar. CALL_DATA is an integer specifying the action that
7988 has taken place. It's magnitude is in the range 0..height of the
7989 scroll bar. Negative values mean scroll towards buffer start.
7990 Values < height of scroll bar mean line-wise movement. */
7991
7992static void
ec18280f 7993xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
7994 Widget widget;
7995 XtPointer client_data, call_data;
7996{
7997 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7998 int position = (int) call_data;
7999 Dimension height;
8000 int part;
8001
8002 /* Get the height of the scroll bar. */
8003 BLOCK_INPUT;
8004 XtVaGetValues (widget, XtNheight, &height, NULL);
8005 UNBLOCK_INPUT;
8006
ec18280f
SM
8007 if (abs (position) >= height)
8008 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8009
8010 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8011 it maps line-movement to call_data = max(5, height/20). */
8012 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8013 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8014 else
ec18280f 8015 part = scroll_bar_move_ratio;
06a2c219
GM
8016
8017 window_being_scrolled = bar->window;
8018 bar->dragging = Qnil;
8019 last_scroll_bar_part = part;
ec18280f 8020 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8021}
8022
8023
8024#endif /* not USE_MOTIF */
8025
8026
8027/* Create the widget for scroll bar BAR on frame F. Record the widget
8028 and X window of the scroll bar in BAR. */
8029
8030static void
8031x_create_toolkit_scroll_bar (f, bar)
8032 struct frame *f;
8033 struct scroll_bar *bar;
8034{
8035 Window xwindow;
8036 Widget widget;
8037 Arg av[20];
8038 int ac = 0;
8039 char *scroll_bar_name = "verticalScrollBar";
8040 unsigned long pixel;
8041
8042 BLOCK_INPUT;
8043
8044#ifdef USE_MOTIF
8045 /* LessTif 0.85, problems:
8046
8047 1. When the mouse if over the scroll bar, the scroll bar will
8048 get keyboard events. I didn't find a way to turn this off.
8049
8050 2. Do we have to explicitly set the cursor to get an arrow
8051 cursor (see below)? */
8052
8053 /* Set resources. Create the widget. */
8054 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8055 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8056 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8057 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8058 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8059 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8060 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8061
8062 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8063 if (pixel != -1)
8064 {
8065 XtSetArg (av[ac], XmNforeground, pixel);
8066 ++ac;
8067 }
8068
8069 pixel = f->output_data.x->scroll_bar_background_pixel;
8070 if (pixel != -1)
8071 {
8072 XtSetArg (av[ac], XmNbackground, pixel);
8073 ++ac;
8074 }
8075
8076 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8077 scroll_bar_name, av, ac);
8078
8079 /* Add one callback for everything that can happen. */
8080 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8081 (XtPointer) bar);
8082 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8083 (XtPointer) bar);
8084 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8085 (XtPointer) bar);
8086 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8087 (XtPointer) bar);
8088 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8089 (XtPointer) bar);
8090 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8091 (XtPointer) bar);
8092 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8093 (XtPointer) bar);
8094
8095 /* Realize the widget. Only after that is the X window created. */
8096 XtRealizeWidget (widget);
8097
8098 /* Set the cursor to an arrow. I didn't find a resource to do that.
8099 And I'm wondering why it hasn't an arrow cursor by default. */
8100 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8101 f->output_data.x->nontext_cursor);
8102
ec18280f 8103#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8104
8105 /* Set resources. Create the widget. The background of the
8106 Xaw3d scroll bar widget is a little bit light for my taste.
8107 We don't alter it here to let users change it according
8108 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8109 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8110 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8111 /* For smoother scrolling with Xaw3d -sm */
8112 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
8113 /* XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac; */
06a2c219
GM
8114
8115 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8116 if (pixel != -1)
8117 {
8118 XtSetArg (av[ac], XtNforeground, pixel);
8119 ++ac;
8120 }
8121
8122 pixel = f->output_data.x->scroll_bar_background_pixel;
8123 if (pixel != -1)
8124 {
8125 XtSetArg (av[ac], XtNbackground, pixel);
8126 ++ac;
8127 }
8128
8129 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8130 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8131
8132 {
8133 char *initial = "";
8134 char *val = initial;
8135 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8136 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8137 if (val == initial)
8138 { /* ARROW_SCROLL */
8139 xaw3d_arrow_scroll = True;
8140 /* Isn't that just a personal preference ? -sm */
8141 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8142 }
8143 }
06a2c219
GM
8144
8145 /* Define callbacks. */
ec18280f
SM
8146 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8147 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
8148 (XtPointer) bar);
8149
8150 /* Realize the widget. Only after that is the X window created. */
8151 XtRealizeWidget (widget);
8152
ec18280f 8153#endif /* !USE_MOTIF */
06a2c219
GM
8154
8155 /* Install an action hook that let's us detect when the user
8156 finishes interacting with a scroll bar. */
8157 if (action_hook_id == 0)
8158 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
8159
8160 /* Remember X window and widget in the scroll bar vector. */
8161 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8162 xwindow = XtWindow (widget);
8163 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8164
8165 UNBLOCK_INPUT;
8166}
8167
8168
8169/* Set the thumb size and position of scroll bar BAR. We are currently
8170 displaying PORTION out of a whole WHOLE, and our position POSITION. */
8171
8172static void
8173x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
8174 struct scroll_bar *bar;
8175 int portion, position, whole;
f451eb13 8176{
e83dc917
GM
8177 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8178 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 8179 float top, shown;
f451eb13 8180
06a2c219
GM
8181 if (whole == 0)
8182 top = 0, shown = 1;
8183 else
f451eb13 8184 {
06a2c219
GM
8185 top = (float) position / whole;
8186 shown = (float) portion / whole;
8187 }
f451eb13 8188
06a2c219 8189 BLOCK_INPUT;
f451eb13 8190
06a2c219
GM
8191#ifdef USE_MOTIF
8192 {
8193 int size, value;
8194 Boolean arrow1_selected, arrow2_selected;
8195 unsigned char flags;
8196 XmScrollBarWidget sb;
8197
ec18280f 8198 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
8199 is the scroll bar's maximum and MIN is the scroll bar's minimum
8200 value. */
8201 size = shown * XM_SB_RANGE;
8202 size = min (size, XM_SB_RANGE);
8203 size = max (size, 1);
8204
8205 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
8206 value = top * XM_SB_RANGE;
8207 value = min (value, XM_SB_MAX - size);
8208 value = max (value, XM_SB_MIN);
8209
8210 /* LessTif: Calling XmScrollBarSetValues after an increment or
8211 decrement turns off auto-repeat LessTif-internally. This can
8212 be seen in ScrollBar.c which resets Arrow1Selected and
8213 Arrow2Selected. It also sets internal flags so that LessTif
8214 believes the mouse is in the slider. We either have to change
8215 our code, or work around that by accessing private data. */
8216
8217 sb = (XmScrollBarWidget) widget;
8218 arrow1_selected = sb->scrollBar.arrow1_selected;
8219 arrow2_selected = sb->scrollBar.arrow2_selected;
8220 flags = sb->scrollBar.flags;
8221
8222 if (NILP (bar->dragging))
8223 XmScrollBarSetValues (widget, value, size, 0, 0, False);
8224 else if (last_scroll_bar_part == scroll_bar_down_arrow)
8225 /* This has the negative side effect that the slider value is
ec18280f 8226 not what it would be if we scrolled here using line-wise or
06a2c219
GM
8227 page-wise movement. */
8228 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
8229 else
8230 {
8231 /* If currently dragging, only update the slider size.
8232 This reduces flicker effects. */
8233 int old_value, old_size, increment, page_increment;
8234
8235 XmScrollBarGetValues (widget, &old_value, &old_size,
8236 &increment, &page_increment);
8237 XmScrollBarSetValues (widget, old_value,
8238 min (size, XM_SB_RANGE - old_value),
8239 0, 0, False);
8240 }
8241
8242 sb->scrollBar.arrow1_selected = arrow1_selected;
8243 sb->scrollBar.arrow2_selected = arrow2_selected;
8244 sb->scrollBar.flags = flags;
8245 }
ec18280f 8246#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8247 {
ec18280f
SM
8248 float old_top, old_shown;
8249 Dimension height;
8250 XtVaGetValues (widget,
8251 XtNtopOfThumb, &old_top,
8252 XtNshown, &old_shown,
8253 XtNheight, &height,
8254 NULL);
8255
8256 /* Massage the top+shown values. */
8257 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8258 top = max (0, min (1, top));
8259 else
8260 top = old_top;
8261 /* Keep two pixels available for moving the thumb down. */
8262 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8263
8264 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8265 check that your system's configuration file contains a define
8266 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8267 if (top != old_top || shown != old_shown)
eb393530 8268 {
ec18280f 8269 if (NILP (bar->dragging))
eb393530 8270 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8271 else
8272 {
ec18280f
SM
8273#ifdef HAVE_XAW3D
8274 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8275 int scroll_mode = 0;
ec18280f
SM
8276
8277 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8278 if (xaw3d_arrow_scroll)
8279 {
8280 /* Xaw3d stupidly ignores resize requests while dragging
8281 so we have to make it believe it's not in dragging mode. */
8282 scroll_mode = sb->scrollbar.scroll_mode;
8283 if (scroll_mode == 2)
8284 sb->scrollbar.scroll_mode = 0;
8285 }
8286#endif
8287 /* Try to make the scrolling a tad smoother. */
8288 if (!xaw3d_pick_top)
8289 shown = min (shown, old_shown);
8290
8291 XawScrollbarSetThumb (widget, top, shown);
8292
8293#ifdef HAVE_XAW3D
8294 if (xaw3d_arrow_scroll && scroll_mode == 2)
8295 sb->scrollbar.scroll_mode = scroll_mode;
8296#endif
06a2c219 8297 }
06a2c219
GM
8298 }
8299 }
ec18280f 8300#endif /* !USE_MOTIF */
06a2c219
GM
8301
8302 UNBLOCK_INPUT;
f451eb13
JB
8303}
8304
06a2c219
GM
8305#endif /* USE_TOOLKIT_SCROLL_BARS */
8306
8307
8308\f
8309/************************************************************************
8310 Scroll bars, general
8311 ************************************************************************/
8312
8313/* Create a scroll bar and return the scroll bar vector for it. W is
8314 the Emacs window on which to create the scroll bar. TOP, LEFT,
8315 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8316 scroll bar. */
8317
ab648270 8318static struct scroll_bar *
06a2c219
GM
8319x_scroll_bar_create (w, top, left, width, height)
8320 struct window *w;
f451eb13
JB
8321 int top, left, width, height;
8322{
06a2c219 8323 struct frame *f = XFRAME (w->frame);
334208b7
RS
8324 struct scroll_bar *bar
8325 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8326
8327 BLOCK_INPUT;
8328
eccc05db 8329#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8330 x_create_toolkit_scroll_bar (f, bar);
8331#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8332 {
8333 XSetWindowAttributes a;
8334 unsigned long mask;
5c187dee 8335 Window window;
06a2c219
GM
8336
8337 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8338 if (a.background_pixel == -1)
8339 a.background_pixel = f->output_data.x->background_pixel;
8340
12ba150f 8341 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8342 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8343 | ExposureMask);
7a13e894 8344 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8345
dbc4e1c1 8346 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8347
06a2c219
GM
8348 /* Clear the area of W that will serve as a scroll bar. This is
8349 for the case that a window has been split horizontally. In
8350 this case, no clear_frame is generated to reduce flickering. */
8351 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8352 left, top, width,
8353 window_box_height (w), False);
8354
8355 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8356 /* Position and size of scroll bar. */
8357 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8358 top,
8359 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8360 height,
8361 /* Border width, depth, class, and visual. */
8362 0,
8363 CopyFromParent,
8364 CopyFromParent,
8365 CopyFromParent,
8366 /* Attributes. */
8367 mask, &a);
8368 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8369 }
06a2c219 8370#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8371
06a2c219 8372 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8373 XSETINT (bar->top, top);
8374 XSETINT (bar->left, left);
8375 XSETINT (bar->width, width);
8376 XSETINT (bar->height, height);
8377 XSETINT (bar->start, 0);
8378 XSETINT (bar->end, 0);
12ba150f 8379 bar->dragging = Qnil;
f451eb13
JB
8380
8381 /* Add bar to its frame's list of scroll bars. */
334208b7 8382 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8383 bar->prev = Qnil;
334208b7 8384 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 8385 if (!NILP (bar->next))
e0c1aef2 8386 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 8387
06a2c219 8388 /* Map the window/widget. */
eccc05db 8389#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
8390 {
8391 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
8392 XtConfigureWidget (scroll_bar,
06a2c219
GM
8393 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8394 top,
8395 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8396 height, 0);
e83dc917
GM
8397 XtMapWidget (scroll_bar);
8398 }
06a2c219 8399#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 8400 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 8401#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8402
8403 UNBLOCK_INPUT;
12ba150f 8404 return bar;
f451eb13
JB
8405}
8406
06a2c219 8407
12ba150f 8408/* Draw BAR's handle in the proper position.
06a2c219 8409
12ba150f
JB
8410 If the handle is already drawn from START to END, don't bother
8411 redrawing it, unless REBUILD is non-zero; in that case, always
8412 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 8413 events.)
12ba150f
JB
8414
8415 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
8416 fit inside its rectangle, but if the user is dragging the scroll
8417 bar handle, we want to let them drag it down all the way, so that
8418 the bar's top is as far down as it goes; otherwise, there's no way
8419 to move to the very end of the buffer. */
8420
5c187dee
GM
8421#ifndef USE_TOOLKIT_SCROLL_BARS
8422
f451eb13 8423static void
ab648270
JB
8424x_scroll_bar_set_handle (bar, start, end, rebuild)
8425 struct scroll_bar *bar;
f451eb13 8426 int start, end;
12ba150f 8427 int rebuild;
f451eb13 8428{
12ba150f 8429 int dragging = ! NILP (bar->dragging);
ab648270 8430 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8431 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8432 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
8433
8434 /* If the display is already accurate, do nothing. */
8435 if (! rebuild
8436 && start == XINT (bar->start)
8437 && end == XINT (bar->end))
8438 return;
8439
f451eb13
JB
8440 BLOCK_INPUT;
8441
8442 {
d9cdbb3d
RS
8443 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
8444 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
8445 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
8446
8447 /* Make sure the values are reasonable, and try to preserve
8448 the distance between start and end. */
12ba150f
JB
8449 {
8450 int length = end - start;
8451
8452 if (start < 0)
8453 start = 0;
8454 else if (start > top_range)
8455 start = top_range;
8456 end = start + length;
8457
8458 if (end < start)
8459 end = start;
8460 else if (end > top_range && ! dragging)
8461 end = top_range;
8462 }
f451eb13 8463
ab648270 8464 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
8465 XSETINT (bar->start, start);
8466 XSETINT (bar->end, end);
f451eb13 8467
12ba150f
JB
8468 /* Clip the end position, just for display. */
8469 if (end > top_range)
8470 end = top_range;
f451eb13 8471
ab648270 8472 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
8473 below top positions, to make sure the handle is always at least
8474 that many pixels tall. */
ab648270 8475 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 8476
12ba150f
JB
8477 /* Draw the empty space above the handle. Note that we can't clear
8478 zero-height areas; that means "clear to end of window." */
8479 if (0 < start)
334208b7 8480 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8481
12ba150f 8482 /* x, y, width, height, and exposures. */
ab648270
JB
8483 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8484 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
8485 inside_width, start,
8486 False);
f451eb13 8487
06a2c219
GM
8488 /* Change to proper foreground color if one is specified. */
8489 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8490 XSetForeground (FRAME_X_DISPLAY (f), gc,
8491 f->output_data.x->scroll_bar_foreground_pixel);
8492
12ba150f 8493 /* Draw the handle itself. */
334208b7 8494 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 8495
12ba150f 8496 /* x, y, width, height */
ab648270
JB
8497 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8498 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 8499 inside_width, end - start);
f451eb13 8500
06a2c219
GM
8501 /* Restore the foreground color of the GC if we changed it above. */
8502 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8503 XSetForeground (FRAME_X_DISPLAY (f), gc,
8504 f->output_data.x->foreground_pixel);
f451eb13 8505
12ba150f
JB
8506 /* Draw the empty space below the handle. Note that we can't
8507 clear zero-height areas; that means "clear to end of window." */
8508 if (end < inside_height)
334208b7 8509 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8510
12ba150f 8511 /* x, y, width, height, and exposures. */
ab648270
JB
8512 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8513 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
8514 inside_width, inside_height - end,
8515 False);
f451eb13 8516
f451eb13
JB
8517 }
8518
f451eb13
JB
8519 UNBLOCK_INPUT;
8520}
8521
5c187dee 8522#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 8523
06a2c219
GM
8524/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
8525 nil. */
58769bee 8526
12ba150f 8527static void
ab648270
JB
8528x_scroll_bar_remove (bar)
8529 struct scroll_bar *bar;
12ba150f 8530{
e83dc917 8531 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8532 BLOCK_INPUT;
8533
eccc05db 8534#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
8535 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
8536#else
8537 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
8538#endif
06a2c219 8539
ab648270
JB
8540 /* Disassociate this scroll bar from its window. */
8541 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
8542
8543 UNBLOCK_INPUT;
8544}
8545
06a2c219 8546
12ba150f
JB
8547/* Set the handle of the vertical scroll bar for WINDOW to indicate
8548 that we are displaying PORTION characters out of a total of WHOLE
ab648270 8549 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 8550 create one. */
06a2c219 8551
12ba150f 8552static void
06a2c219
GM
8553XTset_vertical_scroll_bar (w, portion, whole, position)
8554 struct window *w;
f451eb13
JB
8555 int portion, whole, position;
8556{
06a2c219 8557 struct frame *f = XFRAME (w->frame);
ab648270 8558 struct scroll_bar *bar;
3c6ede7b 8559 int top, height, left, sb_left, width, sb_width;
06a2c219 8560 int window_x, window_y, window_width, window_height;
06a2c219 8561
3c6ede7b 8562 /* Get window dimensions. */
06a2c219 8563 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
8564 top = window_y;
8565 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
8566 height = window_height;
06a2c219 8567
3c6ede7b 8568 /* Compute the left edge of the scroll bar area. */
06a2c219 8569 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
8570 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
8571 else
8572 left = XFASTINT (w->left);
8573 left *= CANON_X_UNIT (f);
8574 left += FRAME_INTERNAL_BORDER_WIDTH (f);
8575
8576 /* Compute the width of the scroll bar which might be less than
8577 the width of the area reserved for the scroll bar. */
8578 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
8579 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 8580 else
3c6ede7b 8581 sb_width = width;
12ba150f 8582
3c6ede7b
GM
8583 /* Compute the left edge of the scroll bar. */
8584#ifdef USE_TOOLKIT_SCROLL_BARS
8585 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8586 sb_left = left + width - sb_width - (width - sb_width) / 2;
8587 else
8588 sb_left = left + (width - sb_width) / 2;
8589#else
8590 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8591 sb_left = left + width - sb_width;
8592 else
8593 sb_left = left;
8594#endif
8595
ab648270 8596 /* Does the scroll bar exist yet? */
06a2c219 8597 if (NILP (w->vertical_scroll_bar))
3c6ede7b 8598 {
80c32bcc 8599 BLOCK_INPUT;
3c6ede7b
GM
8600 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8601 left, top, width, height, False);
80c32bcc 8602 UNBLOCK_INPUT;
3c6ede7b
GM
8603 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
8604 }
f451eb13 8605 else
12ba150f
JB
8606 {
8607 /* It may just need to be moved and resized. */
06a2c219
GM
8608 unsigned int mask = 0;
8609
8610 bar = XSCROLL_BAR (w->vertical_scroll_bar);
8611
8612 BLOCK_INPUT;
8613
3c6ede7b 8614 if (sb_left != XINT (bar->left))
06a2c219 8615 mask |= CWX;
3c6ede7b 8616 if (top != XINT (bar->top))
06a2c219 8617 mask |= CWY;
3c6ede7b 8618 if (sb_width != XINT (bar->width))
06a2c219 8619 mask |= CWWidth;
3c6ede7b 8620 if (height != XINT (bar->height))
06a2c219
GM
8621 mask |= CWHeight;
8622
8623#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
8624
8625 /* Since toolkit scroll bars are smaller than the space reserved
8626 for them on the frame, we have to clear "under" them. */
8627 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3c6ede7b 8628 left, top, width, height, False);
06a2c219
GM
8629
8630 /* Move/size the scroll bar widget. */
8631 if (mask)
e83dc917 8632 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
8633 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8634 top,
8635 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8636 height, 0);
06a2c219
GM
8637
8638#else /* not USE_TOOLKIT_SCROLL_BARS */
8639
e1f6572f
RS
8640 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
8641 {
8642 /* Clear areas not covered by the scroll bar. This makes sure a
8643 previous mode line display is cleared after C-x 2 C-x 1, for
8644 example. Non-toolkit scroll bars are as wide as the area
8645 reserved for scroll bars - trim at both sides. */
8646 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8647 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8648 height, False);
8649 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8650 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8651 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8652 height, False);
8653 }
06a2c219
GM
8654
8655 /* Move/size the scroll bar window. */
8656 if (mask)
8657 {
8658 XWindowChanges wc;
8659
3c6ede7b
GM
8660 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
8661 wc.y = top;
8662 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
8663 wc.height = height;
06a2c219
GM
8664 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
8665 mask, &wc);
8666 }
8667
8668#endif /* not USE_TOOLKIT_SCROLL_BARS */
8669
8670 /* Remember new settings. */
3c6ede7b
GM
8671 XSETINT (bar->left, sb_left);
8672 XSETINT (bar->top, top);
8673 XSETINT (bar->width, sb_width);
8674 XSETINT (bar->height, height);
06a2c219
GM
8675
8676 UNBLOCK_INPUT;
12ba150f 8677 }
f451eb13 8678
eccc05db 8679#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8680 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
8681#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 8682 /* Set the scroll bar's current state, unless we're currently being
f451eb13 8683 dragged. */
12ba150f 8684 if (NILP (bar->dragging))
f451eb13 8685 {
92857db0 8686 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 8687
12ba150f 8688 if (whole == 0)
ab648270 8689 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
8690 else
8691 {
43f868f5
JB
8692 int start = ((double) position * top_range) / whole;
8693 int end = ((double) (position + portion) * top_range) / whole;
ab648270 8694 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 8695 }
f451eb13 8696 }
06a2c219 8697#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8698
06a2c219 8699 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
8700}
8701
12ba150f 8702
f451eb13 8703/* The following three hooks are used when we're doing a thorough
ab648270 8704 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 8705 are going to be deleted, because keeping track of when windows go
12ba150f
JB
8706 away is a real pain - "Can you say set-window-configuration, boys
8707 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 8708 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 8709 from the fiery pit when we actually redisplay its window. */
f451eb13 8710
ab648270
JB
8711/* Arrange for all scroll bars on FRAME to be removed at the next call
8712 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
8713 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
8714
58769bee 8715static void
ab648270 8716XTcondemn_scroll_bars (frame)
f451eb13
JB
8717 FRAME_PTR frame;
8718{
f9e24cb9
RS
8719 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
8720 while (! NILP (FRAME_SCROLL_BARS (frame)))
8721 {
8722 Lisp_Object bar;
8723 bar = FRAME_SCROLL_BARS (frame);
8724 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
8725 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
8726 XSCROLL_BAR (bar)->prev = Qnil;
8727 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
8728 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
8729 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
8730 }
f451eb13
JB
8731}
8732
fa2dfc30 8733
06a2c219 8734/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 8735 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 8736
f451eb13 8737static void
ab648270 8738XTredeem_scroll_bar (window)
12ba150f 8739 struct window *window;
f451eb13 8740{
ab648270 8741 struct scroll_bar *bar;
fa2dfc30 8742 struct frame *f;
12ba150f 8743
ab648270
JB
8744 /* We can't redeem this window's scroll bar if it doesn't have one. */
8745 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
8746 abort ();
8747
ab648270 8748 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
8749
8750 /* Unlink it from the condemned list. */
fa2dfc30
GM
8751 f = XFRAME (WINDOW_FRAME (window));
8752 if (NILP (bar->prev))
8753 {
8754 /* If the prev pointer is nil, it must be the first in one of
8755 the lists. */
8756 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
8757 /* It's not condemned. Everything's fine. */
8758 return;
8759 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
8760 window->vertical_scroll_bar))
8761 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
8762 else
8763 /* If its prev pointer is nil, it must be at the front of
8764 one or the other! */
8765 abort ();
8766 }
8767 else
8768 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 8769
fa2dfc30
GM
8770 if (! NILP (bar->next))
8771 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 8772
fa2dfc30
GM
8773 bar->next = FRAME_SCROLL_BARS (f);
8774 bar->prev = Qnil;
8775 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
8776 if (! NILP (bar->next))
8777 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
8778}
8779
ab648270
JB
8780/* Remove all scroll bars on FRAME that haven't been saved since the
8781 last call to `*condemn_scroll_bars_hook'. */
06a2c219 8782
f451eb13 8783static void
ab648270 8784XTjudge_scroll_bars (f)
12ba150f 8785 FRAME_PTR f;
f451eb13 8786{
12ba150f 8787 Lisp_Object bar, next;
f451eb13 8788
ab648270 8789 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
8790
8791 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
8792 more events on the hapless scroll bars. */
8793 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
8794
8795 for (; ! NILP (bar); bar = next)
f451eb13 8796 {
ab648270 8797 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 8798
ab648270 8799 x_scroll_bar_remove (b);
12ba150f
JB
8800
8801 next = b->next;
8802 b->next = b->prev = Qnil;
f451eb13 8803 }
12ba150f 8804
ab648270 8805 /* Now there should be no references to the condemned scroll bars,
12ba150f 8806 and they should get garbage-collected. */
f451eb13
JB
8807}
8808
8809
06a2c219
GM
8810/* Handle an Expose or GraphicsExpose event on a scroll bar. This
8811 is a no-op when using toolkit scroll bars.
ab648270
JB
8812
8813 This may be called from a signal handler, so we have to ignore GC
8814 mark bits. */
06a2c219 8815
f451eb13 8816static void
ab648270
JB
8817x_scroll_bar_expose (bar, event)
8818 struct scroll_bar *bar;
f451eb13
JB
8819 XEvent *event;
8820{
06a2c219
GM
8821#ifndef USE_TOOLKIT_SCROLL_BARS
8822
ab648270 8823 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8824 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8825 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 8826 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 8827
f451eb13
JB
8828 BLOCK_INPUT;
8829
ab648270 8830 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 8831
06a2c219 8832 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 8833 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
8834
8835 /* x, y, width, height */
d9cdbb3d 8836 0, 0,
3cbd2e0b 8837 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
8838 XINT (bar->height) - 1);
8839
f451eb13 8840 UNBLOCK_INPUT;
06a2c219
GM
8841
8842#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8843}
8844
ab648270
JB
8845/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8846 is set to something other than no_event, it is enqueued.
8847
8848 This may be called from a signal handler, so we have to ignore GC
8849 mark bits. */
06a2c219 8850
5c187dee
GM
8851#ifndef USE_TOOLKIT_SCROLL_BARS
8852
f451eb13 8853static void
ab648270
JB
8854x_scroll_bar_handle_click (bar, event, emacs_event)
8855 struct scroll_bar *bar;
f451eb13
JB
8856 XEvent *event;
8857 struct input_event *emacs_event;
8858{
0299d313 8859 if (! GC_WINDOWP (bar->window))
12ba150f
JB
8860 abort ();
8861
ab648270 8862 emacs_event->kind = scroll_bar_click;
69388238 8863 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
8864 emacs_event->modifiers
8865 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
8866 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
8867 event->xbutton.state)
8868 | (event->type == ButtonRelease
8869 ? up_modifier
8870 : down_modifier));
12ba150f 8871 emacs_event->frame_or_window = bar->window;
0f8aabe9 8872 emacs_event->arg = Qnil;
f451eb13 8873 emacs_event->timestamp = event->xbutton.time;
12ba150f 8874 {
06a2c219 8875#if 0
d9cdbb3d 8876 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 8877 int internal_height
d9cdbb3d 8878 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8879#endif
0299d313 8880 int top_range
d9cdbb3d 8881 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 8882 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
8883
8884 if (y < 0) y = 0;
8885 if (y > top_range) y = top_range;
8886
8887 if (y < XINT (bar->start))
ab648270
JB
8888 emacs_event->part = scroll_bar_above_handle;
8889 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8890 emacs_event->part = scroll_bar_handle;
12ba150f 8891 else
ab648270 8892 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
8893
8894 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
8895 they want to drag it. Lisp code needs to be able to decide
8896 whether or not we're dragging. */
929787e1 8897#if 0
12ba150f
JB
8898 /* If the user has just clicked on the handle, record where they're
8899 holding it. */
8900 if (event->type == ButtonPress
ab648270 8901 && emacs_event->part == scroll_bar_handle)
e0c1aef2 8902 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 8903#endif
12ba150f
JB
8904
8905 /* If the user has released the handle, set it to its final position. */
8906 if (event->type == ButtonRelease
8907 && ! NILP (bar->dragging))
8908 {
8909 int new_start = y - XINT (bar->dragging);
8910 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 8911
ab648270 8912 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
8913 bar->dragging = Qnil;
8914 }
f451eb13 8915
5116f055
JB
8916 /* Same deal here as the other #if 0. */
8917#if 0
58769bee 8918 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 8919 the handle. */
ab648270 8920 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
8921 emacs_event->x = bar->start;
8922 else
e0c1aef2 8923 XSETINT (emacs_event->x, y);
5116f055 8924#else
e0c1aef2 8925 XSETINT (emacs_event->x, y);
5116f055 8926#endif
f451eb13 8927
e0c1aef2 8928 XSETINT (emacs_event->y, top_range);
12ba150f
JB
8929 }
8930}
f451eb13 8931
ab648270
JB
8932/* Handle some mouse motion while someone is dragging the scroll bar.
8933
8934 This may be called from a signal handler, so we have to ignore GC
8935 mark bits. */
06a2c219 8936
f451eb13 8937static void
ab648270
JB
8938x_scroll_bar_note_movement (bar, event)
8939 struct scroll_bar *bar;
f451eb13
JB
8940 XEvent *event;
8941{
39d8bb4d
KH
8942 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
8943
f451eb13
JB
8944 last_mouse_movement_time = event->xmotion.time;
8945
39d8bb4d 8946 f->mouse_moved = 1;
e0c1aef2 8947 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
8948
8949 /* If we're dragging the bar, display it. */
ab648270 8950 if (! GC_NILP (bar->dragging))
f451eb13
JB
8951 {
8952 /* Where should the handle be now? */
12ba150f 8953 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 8954
12ba150f 8955 if (new_start != XINT (bar->start))
f451eb13 8956 {
12ba150f 8957 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 8958
ab648270 8959 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
8960 }
8961 }
f451eb13
JB
8962}
8963
5c187dee
GM
8964#endif /* !USE_TOOLKIT_SCROLL_BARS */
8965
12ba150f 8966/* Return information to the user about the current position of the mouse
ab648270 8967 on the scroll bar. */
06a2c219 8968
12ba150f 8969static void
334208b7
RS
8970x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
8971 FRAME_PTR *fp;
12ba150f 8972 Lisp_Object *bar_window;
ab648270 8973 enum scroll_bar_part *part;
12ba150f
JB
8974 Lisp_Object *x, *y;
8975 unsigned long *time;
8976{
ab648270 8977 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
8978 Window w = SCROLL_BAR_X_WINDOW (bar);
8979 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 8980 int win_x, win_y;
559cb2fb
JB
8981 Window dummy_window;
8982 int dummy_coord;
8983 unsigned int dummy_mask;
12ba150f 8984
cf7cb199
JB
8985 BLOCK_INPUT;
8986
ab648270 8987 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 8988 report that. */
334208b7 8989 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 8990
559cb2fb
JB
8991 /* Root, child, root x and root y. */
8992 &dummy_window, &dummy_window,
8993 &dummy_coord, &dummy_coord,
12ba150f 8994
559cb2fb
JB
8995 /* Position relative to scroll bar. */
8996 &win_x, &win_y,
12ba150f 8997
559cb2fb
JB
8998 /* Mouse buttons and modifier keys. */
8999 &dummy_mask))
7a13e894 9000 ;
559cb2fb
JB
9001 else
9002 {
06a2c219 9003#if 0
559cb2fb 9004 int inside_height
d9cdbb3d 9005 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9006#endif
559cb2fb 9007 int top_range
d9cdbb3d 9008 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9009
9010 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9011
9012 if (! NILP (bar->dragging))
9013 win_y -= XINT (bar->dragging);
9014
9015 if (win_y < 0)
9016 win_y = 0;
9017 if (win_y > top_range)
9018 win_y = top_range;
9019
334208b7 9020 *fp = f;
7a13e894 9021 *bar_window = bar->window;
559cb2fb
JB
9022
9023 if (! NILP (bar->dragging))
9024 *part = scroll_bar_handle;
9025 else if (win_y < XINT (bar->start))
9026 *part = scroll_bar_above_handle;
9027 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9028 *part = scroll_bar_handle;
9029 else
9030 *part = scroll_bar_below_handle;
12ba150f 9031
e0c1aef2
KH
9032 XSETINT (*x, win_y);
9033 XSETINT (*y, top_range);
12ba150f 9034
39d8bb4d 9035 f->mouse_moved = 0;
559cb2fb
JB
9036 last_mouse_scroll_bar = Qnil;
9037 }
12ba150f 9038
559cb2fb 9039 *time = last_mouse_movement_time;
cf7cb199 9040
cf7cb199 9041 UNBLOCK_INPUT;
12ba150f
JB
9042}
9043
f451eb13 9044
dbc4e1c1 9045/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9046 background colors, and the scroll bars may need to be redrawn.
9047 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9048 redraw them. */
9049
dfcf069d 9050void
ab648270 9051x_scroll_bar_clear (f)
dbc4e1c1
JB
9052 FRAME_PTR f;
9053{
06a2c219 9054#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9055 Lisp_Object bar;
9056
b80c363e
RS
9057 /* We can have scroll bars even if this is 0,
9058 if we just turned off scroll bar mode.
9059 But in that case we should not clear them. */
9060 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9061 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9062 bar = XSCROLL_BAR (bar)->next)
9063 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
9064 0, 0, 0, 0, True);
06a2c219 9065#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9066}
9067
06a2c219 9068/* This processes Expose events from the menu-bar specific X event
19126e11 9069 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9070 when handling menu-bar or pop-up items. */
3afe33e7 9071
06a2c219 9072int
3afe33e7
RS
9073process_expose_from_menu (event)
9074 XEvent event;
9075{
9076 FRAME_PTR f;
19126e11 9077 struct x_display_info *dpyinfo;
06a2c219 9078 int frame_exposed_p = 0;
3afe33e7 9079
f94397b5
KH
9080 BLOCK_INPUT;
9081
19126e11
KH
9082 dpyinfo = x_display_info_for_display (event.xexpose.display);
9083 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9084 if (f)
9085 {
9086 if (f->async_visible == 0)
9087 {
9088 f->async_visible = 1;
9089 f->async_iconified = 0;
06c488fd 9090 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9091 SET_FRAME_GARBAGED (f);
9092 }
9093 else
9094 {
06a2c219
GM
9095 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9096 event.xexpose.x, event.xexpose.y,
9097 event.xexpose.width, event.xexpose.height);
9098 frame_exposed_p = 1;
3afe33e7
RS
9099 }
9100 }
9101 else
9102 {
9103 struct scroll_bar *bar
9104 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9105
3afe33e7
RS
9106 if (bar)
9107 x_scroll_bar_expose (bar, &event);
9108 }
f94397b5
KH
9109
9110 UNBLOCK_INPUT;
06a2c219 9111 return frame_exposed_p;
3afe33e7 9112}
09756a85
RS
9113\f
9114/* Define a queue to save up SelectionRequest events for later handling. */
9115
9116struct selection_event_queue
9117 {
9118 XEvent event;
9119 struct selection_event_queue *next;
9120 };
9121
9122static struct selection_event_queue *queue;
9123
9124/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9125
09756a85
RS
9126static int x_queue_selection_requests;
9127
9128/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9129
09756a85 9130static void
334208b7
RS
9131x_queue_event (f, event)
9132 FRAME_PTR f;
09756a85
RS
9133 XEvent *event;
9134{
9135 struct selection_event_queue *queue_tmp
06a2c219 9136 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9137
58769bee 9138 if (queue_tmp != NULL)
09756a85
RS
9139 {
9140 queue_tmp->event = *event;
9141 queue_tmp->next = queue;
9142 queue = queue_tmp;
9143 }
9144}
9145
9146/* Take all the queued events and put them back
9147 so that they get processed afresh. */
9148
9149static void
db3906fd
RS
9150x_unqueue_events (display)
9151 Display *display;
09756a85 9152{
58769bee 9153 while (queue != NULL)
09756a85
RS
9154 {
9155 struct selection_event_queue *queue_tmp = queue;
db3906fd 9156 XPutBackEvent (display, &queue_tmp->event);
09756a85 9157 queue = queue_tmp->next;
06a2c219 9158 xfree ((char *)queue_tmp);
09756a85
RS
9159 }
9160}
9161
9162/* Start queuing SelectionRequest events. */
9163
9164void
db3906fd
RS
9165x_start_queuing_selection_requests (display)
9166 Display *display;
09756a85
RS
9167{
9168 x_queue_selection_requests++;
9169}
9170
9171/* Stop queuing SelectionRequest events. */
9172
9173void
db3906fd
RS
9174x_stop_queuing_selection_requests (display)
9175 Display *display;
09756a85
RS
9176{
9177 x_queue_selection_requests--;
db3906fd 9178 x_unqueue_events (display);
09756a85 9179}
f451eb13
JB
9180\f
9181/* The main X event-reading loop - XTread_socket. */
dc6f92b8 9182
06a2c219 9183/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
9184 but we have to put it out here, since static variables within functions
9185 sometimes don't work. */
06a2c219 9186
dc6f92b8
JB
9187static Time enter_timestamp;
9188
11edeb03 9189/* This holds the state XLookupString needs to implement dead keys
58769bee 9190 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
9191 says that a portable program can't use this, but Stephen Gildea assures
9192 me that letting the compiler initialize it to zeros will work okay.
9193
9194 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
9195 given for enter_time stamp, above. */
9196
11edeb03
JB
9197static XComposeStatus compose_status;
9198
10e6549c
RS
9199/* Record the last 100 characters stored
9200 to help debug the loss-of-chars-during-GC problem. */
06a2c219 9201
2224b905
RS
9202static int temp_index;
9203static short temp_buffer[100];
10e6549c 9204
7a13e894
RS
9205/* Set this to nonzero to fake an "X I/O error"
9206 on a particular display. */
06a2c219 9207
7a13e894
RS
9208struct x_display_info *XTread_socket_fake_io_error;
9209
2224b905
RS
9210/* When we find no input here, we occasionally do a no-op command
9211 to verify that the X server is still running and we can still talk with it.
9212 We try all the open displays, one by one.
9213 This variable is used for cycling thru the displays. */
06a2c219 9214
2224b905
RS
9215static struct x_display_info *next_noop_dpyinfo;
9216
06a2c219
GM
9217#define SET_SAVED_MENU_EVENT(size) \
9218 do \
9219 { \
9220 if (f->output_data.x->saved_menu_event == 0) \
9221 f->output_data.x->saved_menu_event \
9222 = (XEvent *) xmalloc (sizeof (XEvent)); \
9223 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9224 if (numchars >= 1) \
9225 { \
9226 bufp->kind = menu_bar_activate_event; \
9227 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 9228 bufp->arg = Qnil; \
06a2c219
GM
9229 bufp++; \
9230 count++; \
9231 numchars--; \
9232 } \
9233 } \
9234 while (0)
9235
8805890a 9236#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 9237#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 9238
dc6f92b8
JB
9239/* Read events coming from the X server.
9240 This routine is called by the SIGIO handler.
9241 We return as soon as there are no more events to be read.
9242
9243 Events representing keys are stored in buffer BUFP,
9244 which can hold up to NUMCHARS characters.
9245 We return the number of characters stored into the buffer,
9246 thus pretending to be `read'.
9247
dc6f92b8
JB
9248 EXPECTED is nonzero if the caller knows input is available. */
9249
7c5283e4 9250int
f66868ba 9251XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9252 register int sd;
8805890a
KH
9253 /* register */ struct input_event *bufp;
9254 /* register */ int numchars;
dc6f92b8
JB
9255 int expected;
9256{
9257 int count = 0;
9258 int nbytes = 0;
dc6f92b8 9259 XEvent event;
f676886a 9260 struct frame *f;
66f55a9d 9261 int event_found = 0;
334208b7 9262 struct x_display_info *dpyinfo;
379b5ac0 9263 struct coding_system coding;
dc6f92b8 9264
9ac0d9e0 9265 if (interrupt_input_blocked)
dc6f92b8 9266 {
9ac0d9e0 9267 interrupt_input_pending = 1;
dc6f92b8
JB
9268 return -1;
9269 }
9270
9ac0d9e0 9271 interrupt_input_pending = 0;
dc6f92b8 9272 BLOCK_INPUT;
c0a04927
RS
9273
9274 /* So people can tell when we have read the available input. */
9275 input_signal_count++;
9276
dc6f92b8 9277 if (numchars <= 0)
06a2c219 9278 abort (); /* Don't think this happens. */
dc6f92b8 9279
bde5503b
GM
9280 ++handling_signal;
9281
379b5ac0
KH
9282 /* The input should be decoded if it is from XIM. Currently the
9283 locale of XIM is the same as that of the system. So, we can use
9284 Vlocale_coding_system which is initialized properly at Emacs
9285 startup time. */
9286 setup_coding_system (Vlocale_coding_system, &coding);
9287 coding.src_multibyte = 0;
9288 coding.dst_multibyte = 1;
9289 /* The input is converted to events, thus we can't handle
9290 composition. Anyway, there's no XIM that gives us composition
9291 information. */
9292 coding.composing = COMPOSITION_DISABLED;
9293
7a13e894
RS
9294 /* Find the display we are supposed to read input for.
9295 It's the one communicating on descriptor SD. */
9296 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9297 {
9298#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9299#ifdef FIOSNBIO
7a13e894
RS
9300 /* If available, Xlib uses FIOSNBIO to make the socket
9301 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9302 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9303 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9304 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9305#endif /* ! defined (FIOSNBIO) */
7a13e894 9306#endif
dc6f92b8 9307
7a13e894
RS
9308#if 0 /* This code can't be made to work, with multiple displays,
9309 and appears not to be used on any system any more.
9310 Also keyboard.c doesn't turn O_NDELAY on and off
9311 for X connections. */
dc6f92b8
JB
9312#ifndef SIGIO
9313#ifndef HAVE_SELECT
7a13e894
RS
9314 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9315 {
9316 extern int read_alarm_should_throw;
9317 read_alarm_should_throw = 1;
9318 XPeekEvent (dpyinfo->display, &event);
9319 read_alarm_should_throw = 0;
9320 }
c118dd06
JB
9321#endif /* HAVE_SELECT */
9322#endif /* SIGIO */
7a13e894 9323#endif
dc6f92b8 9324
7a13e894
RS
9325 /* For debugging, this gives a way to fake an I/O error. */
9326 if (dpyinfo == XTread_socket_fake_io_error)
9327 {
9328 XTread_socket_fake_io_error = 0;
9329 x_io_error_quitter (dpyinfo->display);
9330 }
dc6f92b8 9331
06a2c219 9332 while (XPending (dpyinfo->display))
dc6f92b8 9333 {
7a13e894 9334 XNextEvent (dpyinfo->display, &event);
06a2c219 9335
531483fb 9336#ifdef HAVE_X_I18N
d1bc4182 9337 {
f2be1146
GM
9338 /* Filter events for the current X input method.
9339 XFilterEvent returns non-zero if the input method has
9340 consumed the event. We pass the frame's X window to
9341 XFilterEvent because that's the one for which the IC
9342 was created. */
f5d11644
GM
9343 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9344 event.xclient.window);
9345 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9346 break;
9347 }
0cd6403b 9348#endif
7a13e894
RS
9349 event_found = 1;
9350
9351 switch (event.type)
9352 {
9353 case ClientMessage:
c047688c 9354 {
7a13e894
RS
9355 if (event.xclient.message_type
9356 == dpyinfo->Xatom_wm_protocols
9357 && event.xclient.format == 32)
c047688c 9358 {
7a13e894
RS
9359 if (event.xclient.data.l[0]
9360 == dpyinfo->Xatom_wm_take_focus)
c047688c 9361 {
8c1a6a84
RS
9362 /* Use x_any_window_to_frame because this
9363 could be the shell widget window
9364 if the frame has no title bar. */
9365 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
9366#ifdef HAVE_X_I18N
9367 /* Not quite sure this is needed -pd */
8c1a6a84 9368 if (f && FRAME_XIC (f))
6c183ba5
RS
9369 XSetICFocus (FRAME_XIC (f));
9370#endif
f1da8f06
GM
9371#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
9372 instructs the WM to set the input focus automatically for
9373 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
9374 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
9375 it has set the focus. So, XSetInputFocus below is not
9376 needed.
9377
9378 The call to XSetInputFocus below has also caused trouble. In
9379 cases where the XSetInputFocus done by the WM and the one
9380 below are temporally close (on a fast machine), the call
9381 below can generate additional FocusIn events which confuse
9382 Emacs. */
9383
bf7253f4
RS
9384 /* Since we set WM_TAKE_FOCUS, we must call
9385 XSetInputFocus explicitly. But not if f is null,
9386 since that might be an event for a deleted frame. */
7a13e894 9387 if (f)
bf7253f4
RS
9388 {
9389 Display *d = event.xclient.display;
9390 /* Catch and ignore errors, in case window has been
9391 iconified by a window manager such as GWM. */
9392 int count = x_catch_errors (d);
9393 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
9394 /* The ICCCM says this is
9395 the only valid choice. */
9396 RevertToParent,
bf7253f4
RS
9397 event.xclient.data.l[1]);
9398 /* This is needed to detect the error
9399 if there is an error. */
9400 XSync (d, False);
9401 x_uncatch_errors (d, count);
9402 }
7a13e894 9403 /* Not certain about handling scroll bars here */
f1da8f06 9404#endif /* 0 */
c047688c 9405 }
7a13e894
RS
9406 else if (event.xclient.data.l[0]
9407 == dpyinfo->Xatom_wm_save_yourself)
9408 {
9409 /* Save state modify the WM_COMMAND property to
06a2c219 9410 something which can reinstate us. This notifies
7a13e894
RS
9411 the session manager, who's looking for such a
9412 PropertyNotify. Can restart processing when
06a2c219 9413 a keyboard or mouse event arrives. */
7a13e894
RS
9414 if (numchars > 0)
9415 {
19126e11
KH
9416 f = x_top_window_to_frame (dpyinfo,
9417 event.xclient.window);
7a13e894
RS
9418
9419 /* This is just so we only give real data once
9420 for a single Emacs process. */
b86bd3dd 9421 if (f == SELECTED_FRAME ())
7a13e894
RS
9422 XSetCommand (FRAME_X_DISPLAY (f),
9423 event.xclient.window,
9424 initial_argv, initial_argc);
f000f5c5 9425 else if (f)
7a13e894
RS
9426 XSetCommand (FRAME_X_DISPLAY (f),
9427 event.xclient.window,
9428 0, 0);
9429 }
9430 }
9431 else if (event.xclient.data.l[0]
9432 == dpyinfo->Xatom_wm_delete_window)
1fb20991 9433 {
19126e11
KH
9434 struct frame *f
9435 = x_any_window_to_frame (dpyinfo,
9436 event.xclient.window);
1fb20991 9437
7a13e894
RS
9438 if (f)
9439 {
9440 if (numchars == 0)
9441 abort ();
1fb20991 9442
7a13e894
RS
9443 bufp->kind = delete_window_event;
9444 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9445 bufp->arg = Qnil;
7a13e894
RS
9446 bufp++;
9447
9448 count += 1;
9449 numchars -= 1;
9450 }
1fb20991 9451 }
c047688c 9452 }
7a13e894
RS
9453 else if (event.xclient.message_type
9454 == dpyinfo->Xatom_wm_configure_denied)
9455 {
9456 }
9457 else if (event.xclient.message_type
9458 == dpyinfo->Xatom_wm_window_moved)
9459 {
9460 int new_x, new_y;
19126e11
KH
9461 struct frame *f
9462 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 9463
7a13e894
RS
9464 new_x = event.xclient.data.s[0];
9465 new_y = event.xclient.data.s[1];
1fb20991 9466
7a13e894
RS
9467 if (f)
9468 {
7556890b
RS
9469 f->output_data.x->left_pos = new_x;
9470 f->output_data.x->top_pos = new_y;
7a13e894 9471 }
1fb20991 9472 }
0fdff6bb 9473#ifdef HACK_EDITRES
7a13e894
RS
9474 else if (event.xclient.message_type
9475 == dpyinfo->Xatom_editres)
9476 {
19126e11
KH
9477 struct frame *f
9478 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 9479 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 9480 &event, NULL);
7a13e894 9481 }
0fdff6bb 9482#endif /* HACK_EDITRES */
06a2c219
GM
9483 else if ((event.xclient.message_type
9484 == dpyinfo->Xatom_DONE)
9485 || (event.xclient.message_type
9486 == dpyinfo->Xatom_PAGE))
9487 {
9488 /* Ghostview job completed. Kill it. We could
9489 reply with "Next" if we received "Page", but we
9490 currently never do because we are interested in
9491 images, only, which should have 1 page. */
06a2c219
GM
9492 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
9493 struct frame *f
9494 = x_window_to_frame (dpyinfo, event.xclient.window);
9495 x_kill_gs_process (pixmap, f);
9496 expose_frame (f, 0, 0, 0, 0);
9497 }
9498#ifdef USE_TOOLKIT_SCROLL_BARS
9499 /* Scroll bar callbacks send a ClientMessage from which
9500 we construct an input_event. */
9501 else if (event.xclient.message_type
9502 == dpyinfo->Xatom_Scrollbar)
9503 {
9504 x_scroll_bar_to_input_event (&event, bufp);
9505 ++bufp, ++count, --numchars;
9506 goto out;
9507 }
9508#endif /* USE_TOOLKIT_SCROLL_BARS */
9509 else
9510 goto OTHER;
7a13e894
RS
9511 }
9512 break;
dc6f92b8 9513
7a13e894 9514 case SelectionNotify:
3afe33e7 9515#ifdef USE_X_TOOLKIT
19126e11 9516 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 9517 goto OTHER;
3afe33e7 9518#endif /* not USE_X_TOOLKIT */
dfcf069d 9519 x_handle_selection_notify (&event.xselection);
7a13e894 9520 break;
d56a553a 9521
06a2c219 9522 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 9523#ifdef USE_X_TOOLKIT
19126e11 9524 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 9525 goto OTHER;
3afe33e7 9526#endif /* USE_X_TOOLKIT */
7a13e894
RS
9527 {
9528 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 9529
7a13e894
RS
9530 if (numchars == 0)
9531 abort ();
d56a553a 9532
7a13e894
RS
9533 bufp->kind = selection_clear_event;
9534 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9535 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9536 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9537 bufp->frame_or_window = Qnil;
0f8aabe9 9538 bufp->arg = Qnil;
7a13e894 9539 bufp++;
d56a553a 9540
7a13e894
RS
9541 count += 1;
9542 numchars -= 1;
9543 }
9544 break;
dc6f92b8 9545
06a2c219 9546 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 9547#ifdef USE_X_TOOLKIT
19126e11 9548 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 9549 goto OTHER;
3afe33e7 9550#endif /* USE_X_TOOLKIT */
7a13e894 9551 if (x_queue_selection_requests)
19126e11 9552 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
9553 &event);
9554 else
9555 {
9556 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 9557
7a13e894
RS
9558 if (numchars == 0)
9559 abort ();
9560
9561 bufp->kind = selection_request_event;
9562 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9563 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
9564 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9565 SELECTION_EVENT_TARGET (bufp) = eventp->target;
9566 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
9567 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9568 bufp->frame_or_window = Qnil;
0f8aabe9 9569 bufp->arg = Qnil;
7a13e894
RS
9570 bufp++;
9571
9572 count += 1;
9573 numchars -= 1;
9574 }
9575 break;
9576
9577 case PropertyNotify:
3afe33e7 9578#ifdef USE_X_TOOLKIT
19126e11 9579 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 9580 goto OTHER;
3afe33e7 9581#endif /* not USE_X_TOOLKIT */
dfcf069d 9582 x_handle_property_notify (&event.xproperty);
7a13e894 9583 break;
dc6f92b8 9584
7a13e894 9585 case ReparentNotify:
19126e11 9586 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
9587 if (f)
9588 {
9589 int x, y;
7556890b 9590 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 9591 x_real_positions (f, &x, &y);
7556890b
RS
9592 f->output_data.x->left_pos = x;
9593 f->output_data.x->top_pos = y;
7a13e894
RS
9594 }
9595 break;
3bd330d4 9596
7a13e894 9597 case Expose:
19126e11 9598 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 9599 if (f)
dc6f92b8 9600 {
7a13e894
RS
9601 if (f->async_visible == 0)
9602 {
9603 f->async_visible = 1;
9604 f->async_iconified = 0;
06c488fd 9605 f->output_data.x->has_been_visible = 1;
7a13e894
RS
9606 SET_FRAME_GARBAGED (f);
9607 }
9608 else
06a2c219
GM
9609 expose_frame (x_window_to_frame (dpyinfo,
9610 event.xexpose.window),
9611 event.xexpose.x, event.xexpose.y,
9612 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
9613 }
9614 else
7a13e894 9615 {
06a2c219
GM
9616#ifdef USE_TOOLKIT_SCROLL_BARS
9617 /* Dispatch event to the widget. */
9618 goto OTHER;
9619#else /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9620 struct scroll_bar *bar
9621 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9622
7a13e894
RS
9623 if (bar)
9624 x_scroll_bar_expose (bar, &event);
3afe33e7 9625#ifdef USE_X_TOOLKIT
7a13e894
RS
9626 else
9627 goto OTHER;
3afe33e7 9628#endif /* USE_X_TOOLKIT */
06a2c219 9629#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9630 }
9631 break;
dc6f92b8 9632
7a13e894
RS
9633 case GraphicsExpose: /* This occurs when an XCopyArea's
9634 source area was obscured or not
9635 available.*/
19126e11 9636 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
9637 if (f)
9638 {
06a2c219
GM
9639 expose_frame (f,
9640 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
9641 event.xgraphicsexpose.width,
9642 event.xgraphicsexpose.height);
7a13e894 9643 }
3afe33e7 9644#ifdef USE_X_TOOLKIT
7a13e894
RS
9645 else
9646 goto OTHER;
3afe33e7 9647#endif /* USE_X_TOOLKIT */
7a13e894 9648 break;
dc6f92b8 9649
7a13e894 9650 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
9651 source area was completely
9652 available */
7a13e894 9653 break;
dc6f92b8 9654
7a13e894 9655 case UnmapNotify:
06a2c219
GM
9656 /* Redo the mouse-highlight after the tooltip has gone. */
9657 if (event.xmap.window == tip_window)
9658 {
9659 tip_window = 0;
9660 redo_mouse_highlight ();
9661 }
9662
91ea2a7a 9663 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
9664 if (f) /* F may no longer exist if
9665 the frame was deleted. */
9666 {
9667 /* While a frame is unmapped, display generation is
9668 disabled; you don't want to spend time updating a
9669 display that won't ever be seen. */
9670 f->async_visible = 0;
9671 /* We can't distinguish, from the event, whether the window
9672 has become iconified or invisible. So assume, if it
9673 was previously visible, than now it is iconified.
1aa6072f
RS
9674 But x_make_frame_invisible clears both
9675 the visible flag and the iconified flag;
9676 and that way, we know the window is not iconified now. */
7a13e894 9677 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
9678 {
9679 f->async_iconified = 1;
bddd097c 9680
1aa6072f
RS
9681 bufp->kind = iconify_event;
9682 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9683 bufp->arg = Qnil;
1aa6072f
RS
9684 bufp++;
9685 count++;
9686 numchars--;
9687 }
7a13e894 9688 }
7a13e894 9689 goto OTHER;
dc6f92b8 9690
7a13e894 9691 case MapNotify:
06a2c219
GM
9692 if (event.xmap.window == tip_window)
9693 /* The tooltip has been drawn already. Avoid
9694 the SET_FRAME_GARBAGED below. */
9695 goto OTHER;
9696
9697 /* We use x_top_window_to_frame because map events can
9698 come for sub-windows and they don't mean that the
9699 frame is visible. */
19126e11 9700 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
9701 if (f)
9702 {
9703 f->async_visible = 1;
9704 f->async_iconified = 0;
06c488fd 9705 f->output_data.x->has_been_visible = 1;
dc6f92b8 9706
7a13e894
RS
9707 /* wait_reading_process_input will notice this and update
9708 the frame's display structures. */
9709 SET_FRAME_GARBAGED (f);
bddd097c 9710
d806e720
RS
9711 if (f->iconified)
9712 {
9713 bufp->kind = deiconify_event;
9714 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9715 bufp->arg = Qnil;
d806e720
RS
9716 bufp++;
9717 count++;
9718 numchars--;
9719 }
e73ec6fa 9720 else if (! NILP (Vframe_list)
8e713be6 9721 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
9722 /* Force a redisplay sooner or later
9723 to update the frame titles
9724 in case this is the second frame. */
9725 record_asynch_buffer_change ();
7a13e894 9726 }
7a13e894 9727 goto OTHER;
dc6f92b8 9728
7a13e894 9729 case KeyPress:
19126e11 9730 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 9731
eccc05db 9732#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9733 /* I couldn't find a way to prevent LessTif scroll bars
9734 from consuming key events. */
9735 if (f == 0)
9736 {
9737 Widget widget = XtWindowToWidget (dpyinfo->display,
9738 event.xkey.window);
9739 if (widget && XmIsScrollBar (widget))
9740 {
9741 widget = XtParent (widget);
9742 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
9743 }
9744 }
eccc05db 9745#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 9746
7a13e894
RS
9747 if (f != 0)
9748 {
9749 KeySym keysym, orig_keysym;
379b5ac0
KH
9750 /* al%imercury@uunet.uu.net says that making this 81
9751 instead of 80 fixed a bug whereby meta chars made
9752 his Emacs hang.
9753
9754 It seems that some version of XmbLookupString has
9755 a bug of not returning XBufferOverflow in
9756 status_return even if the input is too long to
9757 fit in 81 bytes. So, we must prepare sufficient
9758 bytes for copy_buffer. 513 bytes (256 chars for
9759 two-byte character set) seems to be a faily good
9760 approximation. -- 2000.8.10 handa@etl.go.jp */
9761 unsigned char copy_buffer[513];
9762 unsigned char *copy_bufptr = copy_buffer;
9763 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 9764 int modifiers;
64bb1782 9765
7a13e894
RS
9766 event.xkey.state
9767 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
9768 extra_keyboard_modifiers);
9769 modifiers = event.xkey.state;
3a2712f9 9770
7a13e894 9771 /* This will have to go some day... */
752a043f 9772
7a13e894
RS
9773 /* make_lispy_event turns chars into control chars.
9774 Don't do it here because XLookupString is too eager. */
9775 event.xkey.state &= ~ControlMask;
5d46f928
RS
9776 event.xkey.state &= ~(dpyinfo->meta_mod_mask
9777 | dpyinfo->super_mod_mask
9778 | dpyinfo->hyper_mod_mask
9779 | dpyinfo->alt_mod_mask);
9780
1cf4a0d1
RS
9781 /* In case Meta is ComposeCharacter,
9782 clear its status. According to Markus Ehrnsperger
9783 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
9784 this enables ComposeCharacter to work whether or
9785 not it is combined with Meta. */
9786 if (modifiers & dpyinfo->meta_mod_mask)
9787 bzero (&compose_status, sizeof (compose_status));
9788
6c183ba5
RS
9789#ifdef HAVE_X_I18N
9790 if (FRAME_XIC (f))
9791 {
f5d11644
GM
9792 Status status_return;
9793
6c183ba5 9794 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
9795 &event.xkey, copy_bufptr,
9796 copy_bufsiz, &keysym,
6c183ba5 9797 &status_return);
f5d11644
GM
9798 if (status_return == XBufferOverflow)
9799 {
9800 copy_bufsiz = nbytes + 1;
9801 copy_bufptr = (char *) alloca (copy_bufsiz);
9802 nbytes = XmbLookupString (FRAME_XIC (f),
9803 &event.xkey, copy_bufptr,
9804 copy_bufsiz, &keysym,
9805 &status_return);
9806 }
9807
1decb680
PE
9808 if (status_return == XLookupNone)
9809 break;
9810 else if (status_return == XLookupChars)
fdd9d55e
GM
9811 {
9812 keysym = NoSymbol;
9813 modifiers = 0;
9814 }
1decb680
PE
9815 else if (status_return != XLookupKeySym
9816 && status_return != XLookupBoth)
9817 abort ();
6c183ba5
RS
9818 }
9819 else
379b5ac0
KH
9820 nbytes = XLookupString (&event.xkey, copy_bufptr,
9821 copy_bufsiz, &keysym,
9822 &compose_status);
6c183ba5 9823#else
379b5ac0
KH
9824 nbytes = XLookupString (&event.xkey, copy_bufptr,
9825 copy_bufsiz, &keysym,
9826 &compose_status);
6c183ba5 9827#endif
dc6f92b8 9828
7a13e894 9829 orig_keysym = keysym;
55123275 9830
7a13e894
RS
9831 if (numchars > 1)
9832 {
9833 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
9834 || keysym == XK_Delete
1097aea0 9835#ifdef XK_ISO_Left_Tab
441affdb 9836 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 9837#endif
852bff8f 9838 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
9839 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
9840 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 9841#ifdef HPUX
7a13e894
RS
9842 /* This recognizes the "extended function keys".
9843 It seems there's no cleaner way.
9844 Test IsModifierKey to avoid handling mode_switch
9845 incorrectly. */
9846 || ((unsigned) (keysym) >= XK_Select
9847 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
9848#endif
9849#ifdef XK_dead_circumflex
7a13e894 9850 || orig_keysym == XK_dead_circumflex
69388238
RS
9851#endif
9852#ifdef XK_dead_grave
7a13e894 9853 || orig_keysym == XK_dead_grave
69388238
RS
9854#endif
9855#ifdef XK_dead_tilde
7a13e894 9856 || orig_keysym == XK_dead_tilde
69388238
RS
9857#endif
9858#ifdef XK_dead_diaeresis
7a13e894 9859 || orig_keysym == XK_dead_diaeresis
69388238
RS
9860#endif
9861#ifdef XK_dead_macron
7a13e894 9862 || orig_keysym == XK_dead_macron
69388238
RS
9863#endif
9864#ifdef XK_dead_degree
7a13e894 9865 || orig_keysym == XK_dead_degree
69388238
RS
9866#endif
9867#ifdef XK_dead_acute
7a13e894 9868 || orig_keysym == XK_dead_acute
69388238
RS
9869#endif
9870#ifdef XK_dead_cedilla
7a13e894 9871 || orig_keysym == XK_dead_cedilla
69388238
RS
9872#endif
9873#ifdef XK_dead_breve
7a13e894 9874 || orig_keysym == XK_dead_breve
69388238
RS
9875#endif
9876#ifdef XK_dead_ogonek
7a13e894 9877 || orig_keysym == XK_dead_ogonek
69388238
RS
9878#endif
9879#ifdef XK_dead_caron
7a13e894 9880 || orig_keysym == XK_dead_caron
69388238
RS
9881#endif
9882#ifdef XK_dead_doubleacute
7a13e894 9883 || orig_keysym == XK_dead_doubleacute
69388238
RS
9884#endif
9885#ifdef XK_dead_abovedot
7a13e894 9886 || orig_keysym == XK_dead_abovedot
c34790e0 9887#endif
7a13e894
RS
9888 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
9889 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
9890 /* Any "vendor-specific" key is ok. */
9891 || (orig_keysym & (1 << 28)))
9892 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
9893#ifndef HAVE_X11R5
9894#ifdef XK_Mode_switch
7a13e894 9895 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
9896#endif
9897#ifdef XK_Num_Lock
7a13e894 9898 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
9899#endif
9900#endif /* not HAVE_X11R5 */
7a13e894 9901 ))
dc6f92b8 9902 {
10e6549c
RS
9903 if (temp_index == sizeof temp_buffer / sizeof (short))
9904 temp_index = 0;
7a13e894
RS
9905 temp_buffer[temp_index++] = keysym;
9906 bufp->kind = non_ascii_keystroke;
9907 bufp->code = keysym;
e0c1aef2 9908 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9909 bufp->arg = Qnil;
334208b7
RS
9910 bufp->modifiers
9911 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9912 modifiers);
1113d9db 9913 bufp->timestamp = event.xkey.time;
dc6f92b8 9914 bufp++;
7a13e894
RS
9915 count++;
9916 numchars--;
dc6f92b8 9917 }
7a13e894
RS
9918 else if (numchars > nbytes)
9919 {
9920 register int i;
379b5ac0
KH
9921 register int c;
9922 unsigned char *p, *pend;
9923 int nchars, len;
7a13e894
RS
9924
9925 for (i = 0; i < nbytes; i++)
9926 {
379b5ac0
KH
9927 if (temp_index == (sizeof temp_buffer
9928 / sizeof (short)))
7a13e894 9929 temp_index = 0;
379b5ac0
KH
9930 temp_buffer[temp_index++] = copy_bufptr[i];
9931 }
9932
9933 if (/* If the event is not from XIM, */
9934 event.xkey.keycode != 0
9935 /* or the current locale doesn't request
9936 decoding of the intup data, ... */
9937 || coding.type == coding_type_raw_text
9938 || coding.type == coding_type_no_conversion)
9939 {
9940 /* ... we can use the input data as is. */
9941 nchars = nbytes;
9942 }
9943 else
9944 {
9945 /* We have to decode the input data. */
9946 int require;
9947 unsigned char *p;
9948
9949 require = decoding_buffer_size (&coding, nbytes);
9950 p = (unsigned char *) alloca (require);
9951 coding.mode |= CODING_MODE_LAST_BLOCK;
9952 decode_coding (&coding, copy_bufptr, p,
9953 nbytes, require);
9954 nbytes = coding.produced;
9955 nchars = coding.produced_char;
9956 copy_bufptr = p;
9957 }
9958
9959 /* Convert the input data to a sequence of
9960 character events. */
9961 for (i = 0; i < nbytes; i += len)
9962 {
9963 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
9964 nbytes - i, len);
9965 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
9966 ? ascii_keystroke
9967 : multibyte_char_keystroke);
9968 bufp->code = c;
7a13e894 9969 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9970 bufp->arg = Qnil;
7a13e894
RS
9971 bufp->modifiers
9972 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9973 modifiers);
9974 bufp->timestamp = event.xkey.time;
9975 bufp++;
9976 }
9977
379b5ac0
KH
9978 count += nchars;
9979 numchars -= nchars;
1decb680
PE
9980
9981 if (keysym == NoSymbol)
9982 break;
7a13e894
RS
9983 }
9984 else
9985 abort ();
dc6f92b8 9986 }
10e6549c
RS
9987 else
9988 abort ();
dc6f92b8 9989 }
59ddecde
GM
9990#ifdef HAVE_X_I18N
9991 /* Don't dispatch this event since XtDispatchEvent calls
9992 XFilterEvent, and two calls in a row may freeze the
9993 client. */
9994 break;
9995#else
717ca130 9996 goto OTHER;
59ddecde 9997#endif
f451eb13 9998
f5d11644 9999 case KeyRelease:
59ddecde
GM
10000#ifdef HAVE_X_I18N
10001 /* Don't dispatch this event since XtDispatchEvent calls
10002 XFilterEvent, and two calls in a row may freeze the
10003 client. */
10004 break;
10005#else
f5d11644 10006 goto OTHER;
59ddecde 10007#endif
f5d11644 10008
7a13e894 10009 /* Here's a possible interpretation of the whole
06a2c219
GM
10010 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
10011 you get a FocusIn event, you have to get a FocusOut
10012 event before you relinquish the focus. If you
10013 haven't received a FocusIn event, then a mere
10014 LeaveNotify is enough to free you. */
f451eb13 10015
7a13e894 10016 case EnterNotify:
06a2c219
GM
10017 {
10018 int from_menu_bar_p = 0;
10019
10020 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10021
10022#ifdef LESSTIF_VERSION
10023 /* When clicking outside of a menu bar popup to close
10024 it, we get a FocusIn/ EnterNotify sequence of
10025 events. The flag event.xcrossing.focus is not set
10026 in the EnterNotify event of that sequence because
10027 the focus is in the menu bar,
10028 event.xcrossing.window is the frame's X window.
10029 Unconditionally setting the focus frame to null in
10030 this case is not the right thing, because no event
10031 follows that could set the focus frame to the right
10032 value.
10033
10034 This could be a LessTif bug, but I wasn't able to
10035 reproduce the behavior in a simple test program.
10036
10037 (gerd, LessTif 0.88.1). */
10038
10039 if (!event.xcrossing.focus
10040 && f
10041 && f->output_data.x->menubar_widget)
10042 {
10043 Window focus;
10044 int revert;
10045
10046 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
10047 if (focus == XtWindow (f->output_data.x->menubar_widget))
10048 from_menu_bar_p = 1;
10049 }
10050#endif /* LESSTIF_VERSION */
6d4238f3 10051
06a2c219
GM
10052 if (event.xcrossing.focus || from_menu_bar_p)
10053 {
10054 /* Avoid nasty pop/raise loops. */
10055 if (f && (!(f->auto_raise)
10056 || !(f->auto_lower)
10057 || (event.xcrossing.time - enter_timestamp) > 500))
10058 {
10059 x_new_focus_frame (dpyinfo, f);
10060 enter_timestamp = event.xcrossing.time;
10061 }
10062 }
10063 else if (f == dpyinfo->x_focus_frame)
10064 x_new_focus_frame (dpyinfo, 0);
10065
10066 /* EnterNotify counts as mouse movement,
10067 so update things that depend on mouse position. */
10068 if (f && !f->output_data.x->busy_p)
10069 note_mouse_movement (f, &event.xmotion);
10070 goto OTHER;
10071 }
dc6f92b8 10072
7a13e894 10073 case FocusIn:
19126e11 10074 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10075 if (event.xfocus.detail != NotifyPointer)
0f941935 10076 dpyinfo->x_focus_event_frame = f;
7a13e894 10077 if (f)
eb72635f
GM
10078 {
10079 x_new_focus_frame (dpyinfo, f);
10080
10081 /* Don't stop displaying the initial startup message
10082 for a switch-frame event we don't need. */
10083 if (GC_NILP (Vterminal_frame)
10084 && GC_CONSP (Vframe_list)
10085 && !GC_NILP (XCDR (Vframe_list)))
10086 {
10087 bufp->kind = FOCUS_IN_EVENT;
10088 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10089 bufp->arg = Qnil;
eb72635f
GM
10090 ++bufp, ++count, --numchars;
10091 }
10092 }
f9e24cb9 10093
6c183ba5
RS
10094#ifdef HAVE_X_I18N
10095 if (f && FRAME_XIC (f))
10096 XSetICFocus (FRAME_XIC (f));
10097#endif
10098
7a13e894 10099 goto OTHER;
10c5e63d 10100
7a13e894 10101 case LeaveNotify:
19126e11 10102 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10103 if (f)
10c5e63d 10104 {
06a2c219
GM
10105 Lisp_Object frame;
10106 int from_menu_bar_p = 0;
10107
7a13e894 10108 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10109 {
10110 /* If we move outside the frame, then we're
10111 certainly no longer on any text in the frame. */
10112 clear_mouse_face (dpyinfo);
10113 dpyinfo->mouse_face_mouse_frame = 0;
10114 }
10115
10116 /* Generate a nil HELP_EVENT to cancel a help-echo.
10117 Do it only if there's something to cancel.
10118 Otherwise, the startup message is cleared when
10119 the mouse leaves the frame. */
10120 if (any_help_event_p)
10121 {
be010514
GM
10122 Lisp_Object frame;
10123 int n;
10124
06a2c219 10125 XSETFRAME (frame, f);
5ab2570d
GM
10126 n = gen_help_event (bufp, numchars,
10127 Qnil, frame, Qnil, Qnil, 0);
be010514 10128 bufp += n, count += n, numchars -= n;
06a2c219 10129 }
7a13e894 10130
06a2c219
GM
10131#ifdef LESSTIF_VERSION
10132 /* Please see the comment at the start of the
10133 EnterNotify case. */
10134 if (!event.xcrossing.focus
10135 && f->output_data.x->menubar_widget)
10136 {
10137 Window focus;
10138 int revert;
10139 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
10140 if (focus == XtWindow (f->output_data.x->menubar_widget))
10141 from_menu_bar_p = 1;
10142 }
10143#endif /* LESSTIF_VERSION */
10144
10145 if (event.xcrossing.focus || from_menu_bar_p)
0f941935 10146 x_mouse_leave (dpyinfo);
10c5e63d 10147 else
7a13e894 10148 {
0f941935
KH
10149 if (f == dpyinfo->x_focus_event_frame)
10150 dpyinfo->x_focus_event_frame = 0;
10151 if (f == dpyinfo->x_focus_frame)
10152 x_new_focus_frame (dpyinfo, 0);
7a13e894 10153 }
10c5e63d 10154 }
7a13e894 10155 goto OTHER;
dc6f92b8 10156
7a13e894 10157 case FocusOut:
19126e11 10158 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10159 if (event.xfocus.detail != NotifyPointer
0f941935
KH
10160 && f == dpyinfo->x_focus_event_frame)
10161 dpyinfo->x_focus_event_frame = 0;
10162 if (f && f == dpyinfo->x_focus_frame)
10163 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 10164
6c183ba5
RS
10165#ifdef HAVE_X_I18N
10166 if (f && FRAME_XIC (f))
10167 XUnsetICFocus (FRAME_XIC (f));
10168#endif
10169
7a13e894 10170 goto OTHER;
dc6f92b8 10171
7a13e894 10172 case MotionNotify:
dc6f92b8 10173 {
06a2c219 10174 previous_help_echo = help_echo;
7cea38bc 10175 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 10176 help_echo_pos = -1;
06a2c219 10177
7a13e894
RS
10178 if (dpyinfo->grabbed && last_mouse_frame
10179 && FRAME_LIVE_P (last_mouse_frame))
10180 f = last_mouse_frame;
10181 else
19126e11 10182 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 10183
7a13e894
RS
10184 if (f)
10185 note_mouse_movement (f, &event.xmotion);
10186 else
10187 {
e88b3c50 10188#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10189 struct scroll_bar *bar
10190 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 10191
7a13e894
RS
10192 if (bar)
10193 x_scroll_bar_note_movement (bar, &event);
e88b3c50 10194#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 10195
06a2c219
GM
10196 /* If we move outside the frame, then we're
10197 certainly no longer on any text in the frame. */
7a13e894
RS
10198 clear_mouse_face (dpyinfo);
10199 }
06a2c219
GM
10200
10201 /* If the contents of the global variable help_echo
10202 has changed, generate a HELP_EVENT. */
b7e80413
SM
10203 if (!NILP (help_echo)
10204 || !NILP (previous_help_echo))
06a2c219
GM
10205 {
10206 Lisp_Object frame;
be010514 10207 int n;
06a2c219
GM
10208
10209 if (f)
10210 XSETFRAME (frame, f);
10211 else
10212 frame = Qnil;
10213
10214 any_help_event_p = 1;
5ab2570d 10215 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
10216 help_echo_window, help_echo_object,
10217 help_echo_pos);
be010514 10218 bufp += n, count += n, numchars -= n;
06a2c219
GM
10219 }
10220
10221 goto OTHER;
dc6f92b8 10222 }
dc6f92b8 10223
7a13e894 10224 case ConfigureNotify:
9829ddba
RS
10225 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
10226 if (f)
af395ec1 10227 {
5c187dee 10228#ifndef USE_X_TOOLKIT
bf1b7b30
KH
10229 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
10230 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 10231
2d7fc7e8
RS
10232 /* In the toolkit version, change_frame_size
10233 is called by the code that handles resizing
10234 of the EmacsFrame widget. */
7a13e894 10235
7a13e894
RS
10236 /* Even if the number of character rows and columns has
10237 not changed, the font size may have changed, so we need
10238 to check the pixel dimensions as well. */
10239 if (columns != f->width
10240 || rows != f->height
7556890b
RS
10241 || event.xconfigure.width != f->output_data.x->pixel_width
10242 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 10243 {
7d1e984f 10244 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 10245 SET_FRAME_GARBAGED (f);
e687d06e 10246 cancel_mouse_face (f);
7a13e894 10247 }
2d7fc7e8 10248#endif
af395ec1 10249
7556890b
RS
10250 f->output_data.x->pixel_width = event.xconfigure.width;
10251 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
10252
10253 /* What we have now is the position of Emacs's own window.
10254 Convert that to the position of the window manager window. */
dcb07ae9
RS
10255 x_real_positions (f, &f->output_data.x->left_pos,
10256 &f->output_data.x->top_pos);
10257
f5d11644
GM
10258#ifdef HAVE_X_I18N
10259 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
10260 xic_set_statusarea (f);
10261#endif
10262
dcb07ae9
RS
10263 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
10264 {
10265 /* Since the WM decorations come below top_pos now,
10266 we must put them below top_pos in the future. */
10267 f->output_data.x->win_gravity = NorthWestGravity;
10268 x_wm_set_size_hint (f, (long) 0, 0);
10269 }
8f08dc93
KH
10270#ifdef USE_MOTIF
10271 /* Some window managers pass (0,0) as the location of
10272 the window, and the Motif event handler stores it
10273 in the emacs widget, which messes up Motif menus. */
10274 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
10275 {
10276 event.xconfigure.x = f->output_data.x->widget->core.x;
10277 event.xconfigure.y = f->output_data.x->widget->core.y;
10278 }
06a2c219 10279#endif /* USE_MOTIF */
7a13e894 10280 }
2d7fc7e8 10281 goto OTHER;
dc6f92b8 10282
7a13e894
RS
10283 case ButtonPress:
10284 case ButtonRelease:
10285 {
10286 /* If we decide we want to generate an event to be seen
10287 by the rest of Emacs, we put it here. */
10288 struct input_event emacs_event;
9ea173e8 10289 int tool_bar_p = 0;
06a2c219 10290
7a13e894 10291 emacs_event.kind = no_event;
7a13e894 10292 bzero (&compose_status, sizeof (compose_status));
9b07615b 10293
06a2c219
GM
10294 if (dpyinfo->grabbed
10295 && last_mouse_frame
9f67f20b
RS
10296 && FRAME_LIVE_P (last_mouse_frame))
10297 f = last_mouse_frame;
10298 else
2224b905 10299 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 10300
06a2c219
GM
10301 if (f)
10302 {
9ea173e8
GM
10303 /* Is this in the tool-bar? */
10304 if (WINDOWP (f->tool_bar_window)
10305 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
10306 {
10307 Lisp_Object window;
10308 int p, x, y;
10309
10310 x = event.xbutton.x;
10311 y = event.xbutton.y;
10312
10313 /* Set x and y. */
10314 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10315 if (EQ (window, f->tool_bar_window))
06a2c219 10316 {
9ea173e8
GM
10317 x_handle_tool_bar_click (f, &event.xbutton);
10318 tool_bar_p = 1;
06a2c219
GM
10319 }
10320 }
10321
9ea173e8 10322 if (!tool_bar_p)
06a2c219
GM
10323 if (!dpyinfo->x_focus_frame
10324 || f == dpyinfo->x_focus_frame)
10325 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10326 }
10327 else
10328 {
06a2c219 10329#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10330 struct scroll_bar *bar
10331 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10332
7a13e894
RS
10333 if (bar)
10334 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10335#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10336 }
10337
10338 if (event.type == ButtonPress)
10339 {
10340 dpyinfo->grabbed |= (1 << event.xbutton.button);
10341 last_mouse_frame = f;
edad46f6
KH
10342 /* Ignore any mouse motion that happened
10343 before this event; any subsequent mouse-movement
10344 Emacs events should reflect only motion after
10345 the ButtonPress. */
a00e91cd
KH
10346 if (f != 0)
10347 f->mouse_moved = 0;
06a2c219 10348
9ea173e8
GM
10349 if (!tool_bar_p)
10350 last_tool_bar_item = -1;
7a13e894 10351 }
3afe33e7
RS
10352 else
10353 {
7a13e894 10354 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10355 }
23faf38f 10356
7a13e894
RS
10357 if (numchars >= 1 && emacs_event.kind != no_event)
10358 {
10359 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10360 bufp++;
10361 count++;
10362 numchars--;
10363 }
3afe33e7
RS
10364
10365#ifdef USE_X_TOOLKIT
2224b905
RS
10366 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10367 /* For a down-event in the menu bar,
10368 don't pass it to Xt right now.
10369 Instead, save it away
10370 and we will pass it to Xt from kbd_buffer_get_event.
10371 That way, we can run some Lisp code first. */
91375f8f
RS
10372 if (f && event.type == ButtonPress
10373 /* Verify the event is really within the menu bar
10374 and not just sent to it due to grabbing. */
10375 && event.xbutton.x >= 0
10376 && event.xbutton.x < f->output_data.x->pixel_width
10377 && event.xbutton.y >= 0
10378 && event.xbutton.y < f->output_data.x->menubar_height
10379 && event.xbutton.same_screen)
2224b905 10380 {
8805890a 10381 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
10382 XSETFRAME (last_mouse_press_frame, f);
10383 }
10384 else if (event.type == ButtonPress)
10385 {
10386 last_mouse_press_frame = Qnil;
30e671c3 10387 goto OTHER;
ce89ef46 10388 }
06a2c219 10389
2237cac9
RS
10390#ifdef USE_MOTIF /* This should do not harm for Lucid,
10391 but I am trying to be cautious. */
ce89ef46
RS
10392 else if (event.type == ButtonRelease)
10393 {
2237cac9 10394 if (!NILP (last_mouse_press_frame))
f10ded1c 10395 {
2237cac9
RS
10396 f = XFRAME (last_mouse_press_frame);
10397 if (f->output_data.x)
06a2c219 10398 SET_SAVED_BUTTON_EVENT;
f10ded1c 10399 }
06a2c219 10400 else
30e671c3 10401 goto OTHER;
2224b905 10402 }
2237cac9 10403#endif /* USE_MOTIF */
2224b905
RS
10404 else
10405 goto OTHER;
3afe33e7 10406#endif /* USE_X_TOOLKIT */
7a13e894
RS
10407 }
10408 break;
dc6f92b8 10409
7a13e894 10410 case CirculateNotify:
06a2c219
GM
10411 goto OTHER;
10412
7a13e894 10413 case CirculateRequest:
06a2c219
GM
10414 goto OTHER;
10415
10416 case VisibilityNotify:
10417 goto OTHER;
dc6f92b8 10418
7a13e894
RS
10419 case MappingNotify:
10420 /* Someone has changed the keyboard mapping - update the
10421 local cache. */
10422 switch (event.xmapping.request)
10423 {
10424 case MappingModifier:
10425 x_find_modifier_meanings (dpyinfo);
10426 /* This is meant to fall through. */
10427 case MappingKeyboard:
10428 XRefreshKeyboardMapping (&event.xmapping);
10429 }
7a13e894 10430 goto OTHER;
dc6f92b8 10431
7a13e894 10432 default:
7a13e894 10433 OTHER:
717ca130 10434#ifdef USE_X_TOOLKIT
7a13e894
RS
10435 BLOCK_INPUT;
10436 XtDispatchEvent (&event);
10437 UNBLOCK_INPUT;
3afe33e7 10438#endif /* USE_X_TOOLKIT */
7a13e894
RS
10439 break;
10440 }
dc6f92b8
JB
10441 }
10442 }
10443
06a2c219
GM
10444 out:;
10445
9a5196d0
RS
10446 /* On some systems, an X bug causes Emacs to get no more events
10447 when the window is destroyed. Detect that. (1994.) */
58769bee 10448 if (! event_found)
ef2a22d0 10449 {
ef2a22d0
RS
10450 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
10451 One XNOOP in 100 loops will make Emacs terminate.
10452 B. Bretthauer, 1994 */
10453 x_noop_count++;
58769bee 10454 if (x_noop_count >= 100)
ef2a22d0
RS
10455 {
10456 x_noop_count=0;
2224b905
RS
10457
10458 if (next_noop_dpyinfo == 0)
10459 next_noop_dpyinfo = x_display_list;
10460
10461 XNoOp (next_noop_dpyinfo->display);
10462
10463 /* Each time we get here, cycle through the displays now open. */
10464 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
10465 }
10466 }
502add23 10467
06a2c219 10468 /* If the focus was just given to an auto-raising frame,
0134a210 10469 raise it now. */
7a13e894 10470 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
10471 if (pending_autoraise_frame)
10472 {
10473 x_raise_frame (pending_autoraise_frame);
10474 pending_autoraise_frame = 0;
10475 }
0134a210 10476
dc6f92b8 10477 UNBLOCK_INPUT;
bde5503b 10478 --handling_signal;
dc6f92b8
JB
10479 return count;
10480}
06a2c219
GM
10481
10482
10483
dc6f92b8 10484\f
06a2c219
GM
10485/***********************************************************************
10486 Text Cursor
10487 ***********************************************************************/
10488
10489/* Note if the text cursor of window W has been overwritten by a
10490 drawing operation that outputs N glyphs starting at HPOS in the
10491 line given by output_cursor.vpos. N < 0 means all the rest of the
10492 line after HPOS has been written. */
10493
10494static void
10495note_overwritten_text_cursor (w, hpos, n)
10496 struct window *w;
10497 int hpos, n;
10498{
10499 if (updated_area == TEXT_AREA
10500 && output_cursor.vpos == w->phys_cursor.vpos
10501 && hpos <= w->phys_cursor.hpos
10502 && (n < 0
10503 || hpos + n > w->phys_cursor.hpos))
10504 w->phys_cursor_on_p = 0;
10505}
f451eb13
JB
10506
10507
06a2c219
GM
10508/* Set clipping for output in glyph row ROW. W is the window in which
10509 we operate. GC is the graphics context to set clipping in.
10510 WHOLE_LINE_P non-zero means include the areas used for truncation
10511 mark display and alike in the clipping rectangle.
10512
10513 ROW may be a text row or, e.g., a mode line. Text rows must be
10514 clipped to the interior of the window dedicated to text display,
10515 mode lines must be clipped to the whole window. */
dc6f92b8
JB
10516
10517static void
06a2c219
GM
10518x_clip_to_row (w, row, gc, whole_line_p)
10519 struct window *w;
10520 struct glyph_row *row;
10521 GC gc;
10522 int whole_line_p;
dc6f92b8 10523{
06a2c219
GM
10524 struct frame *f = XFRAME (WINDOW_FRAME (w));
10525 XRectangle clip_rect;
10526 int window_x, window_y, window_width, window_height;
dc6f92b8 10527
06a2c219 10528 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 10529
06a2c219
GM
10530 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
10531 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
10532 clip_rect.y = max (clip_rect.y, window_y);
10533 clip_rect.width = window_width;
10534 clip_rect.height = row->visible_height;
5c1aae96 10535
06a2c219
GM
10536 /* If clipping to the whole line, including trunc marks, extend
10537 the rectangle to the left and increase its width. */
10538 if (whole_line_p)
10539 {
110859fc
GM
10540 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
10541 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 10542 }
5c1aae96 10543
06a2c219 10544 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
10545}
10546
06a2c219
GM
10547
10548/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
10549
10550static void
06a2c219
GM
10551x_draw_hollow_cursor (w, row)
10552 struct window *w;
10553 struct glyph_row *row;
dc6f92b8 10554{
06a2c219
GM
10555 struct frame *f = XFRAME (WINDOW_FRAME (w));
10556 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10557 Display *dpy = FRAME_X_DISPLAY (f);
10558 int x, y, wd, h;
10559 XGCValues xgcv;
10560 struct glyph *cursor_glyph;
10561 GC gc;
10562
10563 /* Compute frame-relative coordinates from window-relative
10564 coordinates. */
10565 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10566 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
10567 + row->ascent - w->phys_cursor_ascent);
10568 h = row->height - 1;
10569
10570 /* Get the glyph the cursor is on. If we can't tell because
10571 the current matrix is invalid or such, give up. */
10572 cursor_glyph = get_phys_cursor_glyph (w);
10573 if (cursor_glyph == NULL)
dc6f92b8
JB
10574 return;
10575
06a2c219
GM
10576 /* Compute the width of the rectangle to draw. If on a stretch
10577 glyph, and `x-stretch-block-cursor' is nil, don't draw a
10578 rectangle as wide as the glyph, but use a canonical character
10579 width instead. */
10580 wd = cursor_glyph->pixel_width - 1;
10581 if (cursor_glyph->type == STRETCH_GLYPH
10582 && !x_stretch_cursor_p)
10583 wd = min (CANON_X_UNIT (f), wd);
10584
10585 /* The foreground of cursor_gc is typically the same as the normal
10586 background color, which can cause the cursor box to be invisible. */
10587 xgcv.foreground = f->output_data.x->cursor_pixel;
10588 if (dpyinfo->scratch_cursor_gc)
10589 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
10590 else
10591 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
10592 GCForeground, &xgcv);
10593 gc = dpyinfo->scratch_cursor_gc;
10594
10595 /* Set clipping, draw the rectangle, and reset clipping again. */
10596 x_clip_to_row (w, row, gc, 0);
10597 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
10598 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
10599}
10600
06a2c219
GM
10601
10602/* Draw a bar cursor on window W in glyph row ROW.
10603
10604 Implementation note: One would like to draw a bar cursor with an
10605 angle equal to the one given by the font property XA_ITALIC_ANGLE.
10606 Unfortunately, I didn't find a font yet that has this property set.
10607 --gerd. */
dc6f92b8
JB
10608
10609static void
f02d8aa0 10610x_draw_bar_cursor (w, row, width)
06a2c219
GM
10611 struct window *w;
10612 struct glyph_row *row;
f02d8aa0 10613 int width;
dc6f92b8 10614{
92f424df
GM
10615 struct frame *f = XFRAME (w->frame);
10616 struct glyph *cursor_glyph;
10617 GC gc;
10618 int x;
10619 unsigned long mask;
10620 XGCValues xgcv;
10621 Display *dpy;
10622 Window window;
06a2c219 10623
92f424df
GM
10624 /* If cursor is out of bounds, don't draw garbage. This can happen
10625 in mini-buffer windows when switching between echo area glyphs
10626 and mini-buffer. */
10627 cursor_glyph = get_phys_cursor_glyph (w);
10628 if (cursor_glyph == NULL)
10629 return;
06a2c219 10630
92f424df
GM
10631 /* If on an image, draw like a normal cursor. That's usually better
10632 visible than drawing a bar, esp. if the image is large so that
10633 the bar might not be in the window. */
10634 if (cursor_glyph->type == IMAGE_GLYPH)
10635 {
10636 struct glyph_row *row;
10637 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
10638 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
10639 }
10640 else
10641 {
06a2c219
GM
10642 xgcv.background = f->output_data.x->cursor_pixel;
10643 xgcv.foreground = f->output_data.x->cursor_pixel;
10644 xgcv.graphics_exposures = 0;
10645 mask = GCForeground | GCBackground | GCGraphicsExposures;
10646 dpy = FRAME_X_DISPLAY (f);
10647 window = FRAME_X_WINDOW (f);
10648 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
92f424df 10649
06a2c219
GM
10650 if (gc)
10651 XChangeGC (dpy, gc, mask, &xgcv);
10652 else
10653 {
10654 gc = XCreateGC (dpy, window, mask, &xgcv);
10655 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
10656 }
92f424df 10657
f02d8aa0
GM
10658 if (width < 0)
10659 width = f->output_data.x->cursor_width;
92f424df 10660
06a2c219
GM
10661 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10662 x_clip_to_row (w, row, gc, 0);
10663 XFillRectangle (dpy, window, gc,
10664 x,
10665 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 10666 min (cursor_glyph->pixel_width, width),
06a2c219
GM
10667 row->height);
10668 XSetClipMask (dpy, gc, None);
10669 }
dc6f92b8
JB
10670}
10671
06a2c219
GM
10672
10673/* Clear the cursor of window W to background color, and mark the
10674 cursor as not shown. This is used when the text where the cursor
10675 is is about to be rewritten. */
10676
dc6f92b8 10677static void
06a2c219
GM
10678x_clear_cursor (w)
10679 struct window *w;
dc6f92b8 10680{
06a2c219
GM
10681 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
10682 x_update_window_cursor (w, 0);
10683}
90e65f07 10684
dbc4e1c1 10685
06a2c219
GM
10686/* Draw the cursor glyph of window W in glyph row ROW. See the
10687 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 10688
06a2c219
GM
10689static void
10690x_draw_phys_cursor_glyph (w, row, hl)
10691 struct window *w;
10692 struct glyph_row *row;
10693 enum draw_glyphs_face hl;
10694{
10695 /* If cursor hpos is out of bounds, don't draw garbage. This can
10696 happen in mini-buffer windows when switching between echo area
10697 glyphs and mini-buffer. */
10698 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
10699 {
10700 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
10701 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
10702 hl, 0, 0, 0);
10703
10704 /* When we erase the cursor, and ROW is overlapped by other
10705 rows, make sure that these overlapping parts of other rows
10706 are redrawn. */
10707 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
10708 {
10709 if (row > w->current_matrix->rows
10710 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
10711 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
10712
10713 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
10714 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
10715 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
10716 }
10717 }
06a2c219 10718}
dbc4e1c1 10719
eea6af04 10720
06a2c219 10721/* Erase the image of a cursor of window W from the screen. */
eea6af04 10722
06a2c219
GM
10723static void
10724x_erase_phys_cursor (w)
10725 struct window *w;
10726{
10727 struct frame *f = XFRAME (w->frame);
10728 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10729 int hpos = w->phys_cursor.hpos;
10730 int vpos = w->phys_cursor.vpos;
10731 int mouse_face_here_p = 0;
10732 struct glyph_matrix *active_glyphs = w->current_matrix;
10733 struct glyph_row *cursor_row;
10734 struct glyph *cursor_glyph;
10735 enum draw_glyphs_face hl;
10736
10737 /* No cursor displayed or row invalidated => nothing to do on the
10738 screen. */
10739 if (w->phys_cursor_type == NO_CURSOR)
10740 goto mark_cursor_off;
10741
10742 /* VPOS >= active_glyphs->nrows means that window has been resized.
10743 Don't bother to erase the cursor. */
10744 if (vpos >= active_glyphs->nrows)
10745 goto mark_cursor_off;
10746
10747 /* If row containing cursor is marked invalid, there is nothing we
10748 can do. */
10749 cursor_row = MATRIX_ROW (active_glyphs, vpos);
10750 if (!cursor_row->enabled_p)
10751 goto mark_cursor_off;
10752
10753 /* This can happen when the new row is shorter than the old one.
10754 In this case, either x_draw_glyphs or clear_end_of_line
10755 should have cleared the cursor. Note that we wouldn't be
10756 able to erase the cursor in this case because we don't have a
10757 cursor glyph at hand. */
10758 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
10759 goto mark_cursor_off;
10760
10761 /* If the cursor is in the mouse face area, redisplay that when
10762 we clear the cursor. */
8801a864
KR
10763 if (! NILP (dpyinfo->mouse_face_window)
10764 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
10765 && (vpos > dpyinfo->mouse_face_beg_row
10766 || (vpos == dpyinfo->mouse_face_beg_row
10767 && hpos >= dpyinfo->mouse_face_beg_col))
10768 && (vpos < dpyinfo->mouse_face_end_row
10769 || (vpos == dpyinfo->mouse_face_end_row
10770 && hpos < dpyinfo->mouse_face_end_col))
10771 /* Don't redraw the cursor's spot in mouse face if it is at the
10772 end of a line (on a newline). The cursor appears there, but
10773 mouse highlighting does not. */
10774 && cursor_row->used[TEXT_AREA] > hpos)
10775 mouse_face_here_p = 1;
10776
10777 /* Maybe clear the display under the cursor. */
10778 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
10779 {
10780 int x;
045dee35 10781 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 10782
06a2c219
GM
10783 cursor_glyph = get_phys_cursor_glyph (w);
10784 if (cursor_glyph == NULL)
10785 goto mark_cursor_off;
dbc4e1c1 10786
06a2c219
GM
10787 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
10788
10789 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10790 x,
045dee35 10791 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219
GM
10792 cursor_row->y)),
10793 cursor_glyph->pixel_width,
10794 cursor_row->visible_height,
10795 False);
dbc4e1c1 10796 }
06a2c219
GM
10797
10798 /* Erase the cursor by redrawing the character underneath it. */
10799 if (mouse_face_here_p)
10800 hl = DRAW_MOUSE_FACE;
10801 else if (cursor_row->inverse_p)
10802 hl = DRAW_INVERSE_VIDEO;
10803 else
10804 hl = DRAW_NORMAL_TEXT;
10805 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 10806
06a2c219
GM
10807 mark_cursor_off:
10808 w->phys_cursor_on_p = 0;
10809 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
10810}
10811
10812
06a2c219
GM
10813/* Display or clear cursor of window W. If ON is zero, clear the
10814 cursor. If it is non-zero, display the cursor. If ON is nonzero,
10815 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 10816
06a2c219
GM
10817void
10818x_display_and_set_cursor (w, on, hpos, vpos, x, y)
10819 struct window *w;
10820 int on, hpos, vpos, x, y;
dbc4e1c1 10821{
06a2c219
GM
10822 struct frame *f = XFRAME (w->frame);
10823 int new_cursor_type;
f02d8aa0 10824 int new_cursor_width;
06a2c219
GM
10825 struct glyph_matrix *current_glyphs;
10826 struct glyph_row *glyph_row;
10827 struct glyph *glyph;
dbc4e1c1 10828
49d838ea 10829 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
10830 windows and frames; in the latter case, the frame or window may
10831 be in the midst of changing its size, and x and y may be off the
10832 window. */
10833 if (! FRAME_VISIBLE_P (f)
10834 || FRAME_GARBAGED_P (f)
10835 || vpos >= w->current_matrix->nrows
10836 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
10837 return;
10838
10839 /* If cursor is off and we want it off, return quickly. */
06a2c219 10840 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
10841 return;
10842
06a2c219
GM
10843 current_glyphs = w->current_matrix;
10844 glyph_row = MATRIX_ROW (current_glyphs, vpos);
10845 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
10846
10847 /* If cursor row is not enabled, we don't really know where to
10848 display the cursor. */
10849 if (!glyph_row->enabled_p)
10850 {
10851 w->phys_cursor_on_p = 0;
10852 return;
10853 }
10854
10855 xassert (interrupt_input_blocked);
10856
10857 /* Set new_cursor_type to the cursor we want to be displayed. In a
10858 mini-buffer window, we want the cursor only to appear if we are
10859 reading input from this window. For the selected window, we want
10860 the cursor type given by the frame parameter. If explicitly
10861 marked off, draw no cursor. In all other cases, we want a hollow
10862 box cursor. */
f02d8aa0 10863 new_cursor_width = -1;
9b4a7047
GM
10864 if (cursor_in_echo_area
10865 && FRAME_HAS_MINIBUF_P (f)
10866 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 10867 {
9b4a7047
GM
10868 if (w == XWINDOW (echo_area_window))
10869 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
10870 else
10871 new_cursor_type = HOLLOW_BOX_CURSOR;
10872 }
06a2c219 10873 else
9b4a7047
GM
10874 {
10875 if (w != XWINDOW (selected_window)
10876 || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
10877 {
e55a0b79
GM
10878 extern int cursor_in_non_selected_windows;
10879
5cefa566
GM
10880 if (MINI_WINDOW_P (w)
10881 || !cursor_in_non_selected_windows
10882 || NILP (XBUFFER (w->buffer)->cursor_type))
9b4a7047
GM
10883 new_cursor_type = NO_CURSOR;
10884 else
10885 new_cursor_type = HOLLOW_BOX_CURSOR;
10886 }
10887 else if (w->cursor_off_p)
10888 new_cursor_type = NO_CURSOR;
10889 else
f02d8aa0
GM
10890 {
10891 struct buffer *b = XBUFFER (w->buffer);
10892
10893 if (EQ (b->cursor_type, Qt))
10894 new_cursor_type = FRAME_DESIRED_CURSOR (f);
10895 else
10896 new_cursor_type = x_specified_cursor_type (b->cursor_type,
10897 &new_cursor_width);
10898 }
9b4a7047 10899 }
06a2c219
GM
10900
10901 /* If cursor is currently being shown and we don't want it to be or
10902 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 10903 erase it. */
06a2c219 10904 if (w->phys_cursor_on_p
dc6f92b8 10905 && (!on
06a2c219
GM
10906 || w->phys_cursor.x != x
10907 || w->phys_cursor.y != y
10908 || new_cursor_type != w->phys_cursor_type))
10909 x_erase_phys_cursor (w);
10910
10911 /* If the cursor is now invisible and we want it to be visible,
10912 display it. */
10913 if (on && !w->phys_cursor_on_p)
10914 {
10915 w->phys_cursor_ascent = glyph_row->ascent;
10916 w->phys_cursor_height = glyph_row->height;
10917
10918 /* Set phys_cursor_.* before x_draw_.* is called because some
10919 of them may need the information. */
10920 w->phys_cursor.x = x;
10921 w->phys_cursor.y = glyph_row->y;
10922 w->phys_cursor.hpos = hpos;
10923 w->phys_cursor.vpos = vpos;
10924 w->phys_cursor_type = new_cursor_type;
10925 w->phys_cursor_on_p = 1;
10926
10927 switch (new_cursor_type)
dc6f92b8 10928 {
06a2c219
GM
10929 case HOLLOW_BOX_CURSOR:
10930 x_draw_hollow_cursor (w, glyph_row);
10931 break;
10932
10933 case FILLED_BOX_CURSOR:
10934 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
10935 break;
10936
10937 case BAR_CURSOR:
f02d8aa0 10938 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
10939 break;
10940
10941 case NO_CURSOR:
10942 break;
dc6f92b8 10943
06a2c219
GM
10944 default:
10945 abort ();
10946 }
59ddecde
GM
10947
10948#ifdef HAVE_X_I18N
10949 if (w == XWINDOW (f->selected_window))
10950 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
10951 xic_set_preeditarea (w, x, y);
10952#endif
dc6f92b8
JB
10953 }
10954
06a2c219 10955#ifndef XFlush
f676886a 10956 if (updating_frame != f)
334208b7 10957 XFlush (FRAME_X_DISPLAY (f));
06a2c219 10958#endif
dc6f92b8
JB
10959}
10960
06a2c219
GM
10961
10962/* Display the cursor on window W, or clear it. X and Y are window
10963 relative pixel coordinates. HPOS and VPOS are glyph matrix
10964 positions. If W is not the selected window, display a hollow
10965 cursor. ON non-zero means display the cursor at X, Y which
10966 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 10967
dfcf069d 10968void
06a2c219
GM
10969x_display_cursor (w, on, hpos, vpos, x, y)
10970 struct window *w;
10971 int on, hpos, vpos, x, y;
dc6f92b8 10972{
f94397b5 10973 BLOCK_INPUT;
06a2c219 10974 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
10975 UNBLOCK_INPUT;
10976}
10977
06a2c219
GM
10978
10979/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
10980 Don't change the cursor's position. */
10981
dfcf069d 10982void
06a2c219 10983x_update_cursor (f, on_p)
5d46f928 10984 struct frame *f;
5d46f928 10985{
06a2c219
GM
10986 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
10987}
10988
10989
10990/* Call x_update_window_cursor with parameter ON_P on all leaf windows
10991 in the window tree rooted at W. */
10992
10993static void
10994x_update_cursor_in_window_tree (w, on_p)
10995 struct window *w;
10996 int on_p;
10997{
10998 while (w)
10999 {
11000 if (!NILP (w->hchild))
11001 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11002 else if (!NILP (w->vchild))
11003 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11004 else
11005 x_update_window_cursor (w, on_p);
11006
11007 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11008 }
11009}
5d46f928 11010
f94397b5 11011
06a2c219
GM
11012/* Switch the display of W's cursor on or off, according to the value
11013 of ON. */
11014
11015static void
11016x_update_window_cursor (w, on)
11017 struct window *w;
11018 int on;
11019{
16b5d424
GM
11020 /* Don't update cursor in windows whose frame is in the process
11021 of being deleted. */
11022 if (w->current_matrix)
11023 {
11024 BLOCK_INPUT;
11025 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11026 w->phys_cursor.x, w->phys_cursor.y);
11027 UNBLOCK_INPUT;
11028 }
dc6f92b8 11029}
06a2c219
GM
11030
11031
11032
dc6f92b8
JB
11033\f
11034/* Icons. */
11035
f676886a 11036/* Refresh bitmap kitchen sink icon for frame F
06a2c219 11037 when we get an expose event for it. */
dc6f92b8 11038
dfcf069d 11039void
f676886a
JB
11040refreshicon (f)
11041 struct frame *f;
dc6f92b8 11042{
06a2c219 11043 /* Normally, the window manager handles this function. */
dc6f92b8
JB
11044}
11045
dbc4e1c1 11046/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11047
11048int
990ba854 11049x_bitmap_icon (f, file)
f676886a 11050 struct frame *f;
990ba854 11051 Lisp_Object file;
dc6f92b8 11052{
06a2c219 11053 int bitmap_id;
dc6f92b8 11054
c118dd06 11055 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11056 return 1;
11057
990ba854 11058 /* Free up our existing icon bitmap if any. */
7556890b
RS
11059 if (f->output_data.x->icon_bitmap > 0)
11060 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11061 f->output_data.x->icon_bitmap = 0;
990ba854
RS
11062
11063 if (STRINGP (file))
7f2ae036
RS
11064 bitmap_id = x_create_bitmap_from_file (f, file);
11065 else
11066 {
990ba854 11067 /* Create the GNU bitmap if necessary. */
5bf01b68 11068 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
11069 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
11070 = x_create_bitmap_from_data (f, gnu_bits,
11071 gnu_width, gnu_height);
990ba854
RS
11072
11073 /* The first time we create the GNU bitmap,
06a2c219 11074 this increments the ref-count one extra time.
990ba854
RS
11075 As a result, the GNU bitmap is never freed.
11076 That way, we don't have to worry about allocating it again. */
334208b7 11077 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 11078
334208b7 11079 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
11080 }
11081
11082 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 11083 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
11084
11085 return 0;
11086}
11087
11088
1be2d067
KH
11089/* Make the x-window of frame F use a rectangle with text.
11090 Use ICON_NAME as the text. */
dc6f92b8
JB
11091
11092int
f676886a
JB
11093x_text_icon (f, icon_name)
11094 struct frame *f;
dc6f92b8
JB
11095 char *icon_name;
11096{
c118dd06 11097 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11098 return 1;
11099
1be2d067
KH
11100#ifdef HAVE_X11R4
11101 {
11102 XTextProperty text;
11103 text.value = (unsigned char *) icon_name;
11104 text.encoding = XA_STRING;
11105 text.format = 8;
11106 text.nitems = strlen (icon_name);
11107#ifdef USE_X_TOOLKIT
7556890b 11108 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
11109 &text);
11110#else /* not USE_X_TOOLKIT */
11111 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
11112#endif /* not USE_X_TOOLKIT */
11113 }
11114#else /* not HAVE_X11R4 */
11115 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
11116#endif /* not HAVE_X11R4 */
58769bee 11117
7556890b
RS
11118 if (f->output_data.x->icon_bitmap > 0)
11119 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11120 f->output_data.x->icon_bitmap = 0;
b1c884c3 11121 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
11122
11123 return 0;
11124}
11125\f
e99db5a1
RS
11126#define X_ERROR_MESSAGE_SIZE 200
11127
11128/* If non-nil, this should be a string.
11129 It means catch X errors and store the error message in this string. */
11130
11131static Lisp_Object x_error_message_string;
11132
11133/* An X error handler which stores the error message in
11134 x_error_message_string. This is called from x_error_handler if
11135 x_catch_errors is in effect. */
11136
06a2c219 11137static void
e99db5a1
RS
11138x_error_catcher (display, error)
11139 Display *display;
11140 XErrorEvent *error;
11141{
11142 XGetErrorText (display, error->error_code,
11143 XSTRING (x_error_message_string)->data,
11144 X_ERROR_MESSAGE_SIZE);
11145}
11146
11147/* Begin trapping X errors for display DPY. Actually we trap X errors
11148 for all displays, but DPY should be the display you are actually
11149 operating on.
11150
11151 After calling this function, X protocol errors no longer cause
11152 Emacs to exit; instead, they are recorded in the string
11153 stored in x_error_message_string.
11154
11155 Calling x_check_errors signals an Emacs error if an X error has
11156 occurred since the last call to x_catch_errors or x_check_errors.
11157
11158 Calling x_uncatch_errors resumes the normal error handling. */
11159
11160void x_check_errors ();
11161static Lisp_Object x_catch_errors_unwind ();
11162
11163int
11164x_catch_errors (dpy)
11165 Display *dpy;
11166{
11167 int count = specpdl_ptr - specpdl;
11168
11169 /* Make sure any errors from previous requests have been dealt with. */
11170 XSync (dpy, False);
11171
11172 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
11173
11174 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
11175 XSTRING (x_error_message_string)->data[0] = 0;
11176
11177 return count;
11178}
11179
11180/* Unbind the binding that we made to check for X errors. */
11181
11182static Lisp_Object
11183x_catch_errors_unwind (old_val)
11184 Lisp_Object old_val;
11185{
11186 x_error_message_string = old_val;
11187 return Qnil;
11188}
11189
11190/* If any X protocol errors have arrived since the last call to
11191 x_catch_errors or x_check_errors, signal an Emacs error using
11192 sprintf (a buffer, FORMAT, the x error message text) as the text. */
11193
11194void
11195x_check_errors (dpy, format)
11196 Display *dpy;
11197 char *format;
11198{
11199 /* Make sure to catch any errors incurred so far. */
11200 XSync (dpy, False);
11201
11202 if (XSTRING (x_error_message_string)->data[0])
11203 error (format, XSTRING (x_error_message_string)->data);
11204}
11205
9829ddba
RS
11206/* Nonzero if we had any X protocol errors
11207 since we did x_catch_errors on DPY. */
e99db5a1
RS
11208
11209int
11210x_had_errors_p (dpy)
11211 Display *dpy;
11212{
11213 /* Make sure to catch any errors incurred so far. */
11214 XSync (dpy, False);
11215
11216 return XSTRING (x_error_message_string)->data[0] != 0;
11217}
11218
9829ddba
RS
11219/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
11220
06a2c219 11221void
9829ddba
RS
11222x_clear_errors (dpy)
11223 Display *dpy;
11224{
11225 XSTRING (x_error_message_string)->data[0] = 0;
11226}
11227
e99db5a1
RS
11228/* Stop catching X protocol errors and let them make Emacs die.
11229 DPY should be the display that was passed to x_catch_errors.
11230 COUNT should be the value that was returned by
11231 the corresponding call to x_catch_errors. */
11232
11233void
11234x_uncatch_errors (dpy, count)
11235 Display *dpy;
11236 int count;
11237{
11238 unbind_to (count, Qnil);
11239}
11240
11241#if 0
11242static unsigned int x_wire_count;
11243x_trace_wire ()
11244{
11245 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
11246}
11247#endif /* ! 0 */
11248
11249\f
11250/* Handle SIGPIPE, which can happen when the connection to a server
11251 simply goes away. SIGPIPE is handled by x_connection_signal.
11252 Don't need to do anything, because the write which caused the
11253 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 11254 which will do the appropriate cleanup for us. */
e99db5a1
RS
11255
11256static SIGTYPE
11257x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 11258 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
11259{
11260#ifdef USG
11261 /* USG systems forget handlers when they are used;
11262 must reestablish each time */
11263 signal (signalnum, x_connection_signal);
11264#endif /* USG */
11265}
11266\f
4746118a
JB
11267/* Handling X errors. */
11268
7a13e894 11269/* Handle the loss of connection to display DISPLAY. */
16bd92ea 11270
4746118a 11271static SIGTYPE
7a13e894
RS
11272x_connection_closed (display, error_message)
11273 Display *display;
11274 char *error_message;
4746118a 11275{
7a13e894
RS
11276 struct x_display_info *dpyinfo = x_display_info_for_display (display);
11277 Lisp_Object frame, tail;
11278
6186a4a0
RS
11279 /* Indicate that this display is dead. */
11280
2e465cdd 11281#if 0 /* Closing the display caused a bus error on OpenWindows. */
f613a4c8 11282#ifdef USE_X_TOOLKIT
adabc3a9 11283 XtCloseDisplay (display);
2e465cdd 11284#endif
f613a4c8 11285#endif
adabc3a9 11286
9e80b57d
KR
11287 if (dpyinfo)
11288 dpyinfo->display = 0;
6186a4a0 11289
06a2c219 11290 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
11291 that are on the dead display. */
11292 FOR_EACH_FRAME (tail, frame)
11293 {
11294 Lisp_Object minibuf_frame;
11295 minibuf_frame
11296 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
11297 if (FRAME_X_P (XFRAME (frame))
11298 && FRAME_X_P (XFRAME (minibuf_frame))
11299 && ! EQ (frame, minibuf_frame)
11300 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
11301 Fdelete_frame (frame, Qt);
11302 }
11303
11304 /* Now delete all remaining frames on the dead display.
06a2c219 11305 We are now sure none of these is used as the mini-buffer
7a13e894
RS
11306 for another frame that we need to delete. */
11307 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
11308 if (FRAME_X_P (XFRAME (frame))
11309 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
11310 {
11311 /* Set this to t so that Fdelete_frame won't get confused
11312 trying to find a replacement. */
11313 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
11314 Fdelete_frame (frame, Qt);
11315 }
7a13e894 11316
482a1bd2
KH
11317 if (dpyinfo)
11318 x_delete_display (dpyinfo);
7a13e894
RS
11319
11320 if (x_display_list == 0)
11321 {
f8d07b62 11322 fprintf (stderr, "%s\n", error_message);
7a13e894
RS
11323 shut_down_emacs (0, 0, Qnil);
11324 exit (70);
11325 }
12ba150f 11326
7a13e894
RS
11327 /* Ordinary stack unwind doesn't deal with these. */
11328#ifdef SIGIO
11329 sigunblock (sigmask (SIGIO));
11330#endif
11331 sigunblock (sigmask (SIGALRM));
11332 TOTALLY_UNBLOCK_INPUT;
11333
aa4d9a9e 11334 clear_waiting_for_input ();
182334bd 11335 handling_signal = 0;
7a13e894 11336 error ("%s", error_message);
4746118a
JB
11337}
11338
7a13e894
RS
11339/* This is the usual handler for X protocol errors.
11340 It kills all frames on the display that we got the error for.
11341 If that was the only one, it prints an error message and kills Emacs. */
11342
06a2c219 11343static void
c118dd06
JB
11344x_error_quitter (display, error)
11345 Display *display;
11346 XErrorEvent *error;
11347{
7a13e894 11348 char buf[256], buf1[356];
dc6f92b8 11349
58769bee 11350 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 11351 original error handler. */
dc6f92b8 11352
c118dd06 11353 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 11354 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 11355 buf, error->request_code);
7a13e894 11356 x_connection_closed (display, buf1);
dc6f92b8
JB
11357}
11358
e99db5a1
RS
11359/* This is the first-level handler for X protocol errors.
11360 It calls x_error_quitter or x_error_catcher. */
7a13e894 11361
8922af5f 11362static int
e99db5a1 11363x_error_handler (display, error)
8922af5f 11364 Display *display;
e99db5a1 11365 XErrorEvent *error;
8922af5f 11366{
e99db5a1
RS
11367 if (! NILP (x_error_message_string))
11368 x_error_catcher (display, error);
11369 else
11370 x_error_quitter (display, error);
06a2c219 11371 return 0;
f9e24cb9 11372}
c118dd06 11373
e99db5a1
RS
11374/* This is the handler for X IO errors, always.
11375 It kills all frames on the display that we lost touch with.
11376 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 11377
c118dd06 11378static int
e99db5a1 11379x_io_error_quitter (display)
c118dd06 11380 Display *display;
c118dd06 11381{
e99db5a1 11382 char buf[256];
dc6f92b8 11383
e99db5a1
RS
11384 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
11385 x_connection_closed (display, buf);
06a2c219 11386 return 0;
dc6f92b8 11387}
dc6f92b8 11388\f
f451eb13
JB
11389/* Changing the font of the frame. */
11390
76bcdf39
RS
11391/* Give frame F the font named FONTNAME as its default font, and
11392 return the full name of that font. FONTNAME may be a wildcard
11393 pattern; in that case, we choose some font that fits the pattern.
11394 The return value shows which font we chose. */
11395
b5cf7a0e 11396Lisp_Object
f676886a
JB
11397x_new_font (f, fontname)
11398 struct frame *f;
dc6f92b8
JB
11399 register char *fontname;
11400{
dc43ef94 11401 struct font_info *fontp
ee569018 11402 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 11403
dc43ef94
KH
11404 if (!fontp)
11405 return Qnil;
2224a5fc 11406
dc43ef94 11407 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 11408 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
11409 f->output_data.x->fontset = -1;
11410
b2cad826
KH
11411 /* Compute the scroll bar width in character columns. */
11412 if (f->scroll_bar_pixel_width > 0)
11413 {
7556890b 11414 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
11415 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
11416 }
11417 else
4e61bddf
RS
11418 {
11419 int wid = FONT_WIDTH (f->output_data.x->font);
11420 f->scroll_bar_cols = (14 + wid - 1) / wid;
11421 }
b2cad826 11422
f676886a 11423 /* Now make the frame display the given font. */
c118dd06 11424 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 11425 {
7556890b
RS
11426 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
11427 f->output_data.x->font->fid);
11428 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
11429 f->output_data.x->font->fid);
11430 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
11431 f->output_data.x->font->fid);
f676886a 11432
a27f9f86 11433 frame_update_line_height (f);
0134a210 11434 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 11435 }
a27f9f86
RS
11436 else
11437 /* If we are setting a new frame's font for the first time,
11438 there are no faces yet, so this font's height is the line height. */
7556890b 11439 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 11440
dc43ef94
KH
11441 return build_string (fontp->full_name);
11442}
11443
11444/* Give frame F the fontset named FONTSETNAME as its default font, and
11445 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
11446 pattern; in that case, we choose some fontset that fits the pattern.
11447 The return value shows which fontset we chose. */
b5cf7a0e 11448
dc43ef94
KH
11449Lisp_Object
11450x_new_fontset (f, fontsetname)
11451 struct frame *f;
11452 char *fontsetname;
11453{
ee569018 11454 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 11455 Lisp_Object result;
b5cf7a0e 11456
dc43ef94
KH
11457 if (fontset < 0)
11458 return Qnil;
b5cf7a0e 11459
2da424f1
KH
11460 if (f->output_data.x->fontset == fontset)
11461 /* This fontset is already set in frame F. There's nothing more
11462 to do. */
ee569018 11463 return fontset_name (fontset);
dc43ef94 11464
ee569018 11465 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
11466
11467 if (!STRINGP (result))
11468 /* Can't load ASCII font. */
11469 return Qnil;
11470
11471 /* Since x_new_font doesn't update any fontset information, do it now. */
11472 f->output_data.x->fontset = fontset;
dc43ef94 11473
f5d11644
GM
11474#ifdef HAVE_X_I18N
11475 if (FRAME_XIC (f)
11476 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 11477 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
11478#endif
11479
dc43ef94 11480 return build_string (fontsetname);
dc6f92b8 11481}
f5d11644
GM
11482
11483\f
11484/***********************************************************************
11485 X Input Methods
11486 ***********************************************************************/
11487
11488#ifdef HAVE_X_I18N
11489
11490#ifdef HAVE_X11R6
11491
11492/* XIM destroy callback function, which is called whenever the
11493 connection to input method XIM dies. CLIENT_DATA contains a
11494 pointer to the x_display_info structure corresponding to XIM. */
11495
11496static void
11497xim_destroy_callback (xim, client_data, call_data)
11498 XIM xim;
11499 XPointer client_data;
11500 XPointer call_data;
11501{
11502 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
11503 Lisp_Object frame, tail;
11504
11505 BLOCK_INPUT;
11506
11507 /* No need to call XDestroyIC.. */
11508 FOR_EACH_FRAME (tail, frame)
11509 {
11510 struct frame *f = XFRAME (frame);
11511 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
11512 {
11513 FRAME_XIC (f) = NULL;
11514 if (FRAME_XIC_FONTSET (f))
11515 {
11516 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
11517 FRAME_XIC_FONTSET (f) = NULL;
11518 }
11519 }
11520 }
11521
11522 /* No need to call XCloseIM. */
11523 dpyinfo->xim = NULL;
11524 XFree (dpyinfo->xim_styles);
11525 UNBLOCK_INPUT;
11526}
11527
11528#endif /* HAVE_X11R6 */
11529
11530/* Open the connection to the XIM server on display DPYINFO.
11531 RESOURCE_NAME is the resource name Emacs uses. */
11532
11533static void
11534xim_open_dpy (dpyinfo, resource_name)
11535 struct x_display_info *dpyinfo;
11536 char *resource_name;
11537{
287f7dd6 11538#ifdef USE_XIM
f5d11644
GM
11539 XIM xim;
11540
11541 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
11542 dpyinfo->xim = xim;
11543
11544 if (xim)
11545 {
f5d11644
GM
11546#ifdef HAVE_X11R6
11547 XIMCallback destroy;
11548#endif
11549
11550 /* Get supported styles and XIM values. */
11551 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
11552
11553#ifdef HAVE_X11R6
11554 destroy.callback = xim_destroy_callback;
11555 destroy.client_data = (XPointer)dpyinfo;
68642df6 11556 /* This isn't prptotyped in OSF 5.0. */
f5d11644
GM
11557 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
11558#endif
11559 }
287f7dd6
GM
11560
11561#else /* not USE_XIM */
11562 dpyinfo->xim = NULL;
11563#endif /* not USE_XIM */
f5d11644
GM
11564}
11565
11566
b9de836c 11567#ifdef HAVE_X11R6_XIM
f5d11644
GM
11568
11569struct xim_inst_t
11570{
11571 struct x_display_info *dpyinfo;
11572 char *resource_name;
11573};
11574
11575/* XIM instantiate callback function, which is called whenever an XIM
11576 server is available. DISPLAY is teh display of the XIM.
11577 CLIENT_DATA contains a pointer to an xim_inst_t structure created
11578 when the callback was registered. */
11579
11580static void
11581xim_instantiate_callback (display, client_data, call_data)
11582 Display *display;
11583 XPointer client_data;
11584 XPointer call_data;
11585{
11586 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
11587 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
11588
11589 /* We don't support multiple XIM connections. */
11590 if (dpyinfo->xim)
11591 return;
11592
11593 xim_open_dpy (dpyinfo, xim_inst->resource_name);
11594
11595 /* Create XIC for the existing frames on the same display, as long
11596 as they have no XIC. */
11597 if (dpyinfo->xim && dpyinfo->reference_count > 0)
11598 {
11599 Lisp_Object tail, frame;
11600
11601 BLOCK_INPUT;
11602 FOR_EACH_FRAME (tail, frame)
11603 {
11604 struct frame *f = XFRAME (frame);
11605
11606 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
11607 if (FRAME_XIC (f) == NULL)
11608 {
11609 create_frame_xic (f);
11610 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
11611 xic_set_statusarea (f);
11612 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
11613 {
11614 struct window *w = XWINDOW (f->selected_window);
11615 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
11616 }
11617 }
11618 }
11619
11620 UNBLOCK_INPUT;
11621 }
11622}
11623
b9de836c 11624#endif /* HAVE_X11R6_XIM */
f5d11644
GM
11625
11626
11627/* Open a connection to the XIM server on display DPYINFO.
11628 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
11629 connection only at the first time. On X11R6, open the connection
11630 in the XIM instantiate callback function. */
11631
11632static void
11633xim_initialize (dpyinfo, resource_name)
11634 struct x_display_info *dpyinfo;
11635 char *resource_name;
11636{
287f7dd6 11637#ifdef USE_XIM
b9de836c 11638#ifdef HAVE_X11R6_XIM
f5d11644
GM
11639 struct xim_inst_t *xim_inst;
11640 int len;
11641
11642 dpyinfo->xim = NULL;
11643 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
11644 xim_inst->dpyinfo = dpyinfo;
11645 len = strlen (resource_name);
11646 xim_inst->resource_name = (char *) xmalloc (len + 1);
11647 bcopy (resource_name, xim_inst->resource_name, len + 1);
11648 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11649 resource_name, EMACS_CLASS,
11650 xim_instantiate_callback,
2ebb2f8b
DL
11651 /* Fixme: This is XPointer in
11652 XFree86 but (XPointer *) on
11653 Tru64, at least. */
11654 (XPointer) xim_inst);
b9de836c 11655#else /* not HAVE_X11R6_XIM */
f5d11644
GM
11656 dpyinfo->xim = NULL;
11657 xim_open_dpy (dpyinfo, resource_name);
b9de836c 11658#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
11659
11660#else /* not USE_XIM */
11661 dpyinfo->xim = NULL;
11662#endif /* not USE_XIM */
f5d11644
GM
11663}
11664
11665
11666/* Close the connection to the XIM server on display DPYINFO. */
11667
11668static void
11669xim_close_dpy (dpyinfo)
11670 struct x_display_info *dpyinfo;
11671{
287f7dd6 11672#ifdef USE_XIM
b9de836c 11673#ifdef HAVE_X11R6_XIM
f5d11644
GM
11674 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11675 NULL, EMACS_CLASS,
11676 xim_instantiate_callback, NULL);
b9de836c 11677#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11678 XCloseIM (dpyinfo->xim);
11679 dpyinfo->xim = NULL;
11680 XFree (dpyinfo->xim_styles);
287f7dd6 11681#endif /* USE_XIM */
f5d11644
GM
11682}
11683
b9de836c 11684#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11685
11686
dc6f92b8 11687\f
2e365682
RS
11688/* Calculate the absolute position in frame F
11689 from its current recorded position values and gravity. */
11690
dfcf069d 11691void
43bca5d5 11692x_calc_absolute_position (f)
f676886a 11693 struct frame *f;
dc6f92b8 11694{
06a2c219 11695 Window child;
6dba1858 11696 int win_x = 0, win_y = 0;
7556890b 11697 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
11698 int this_window;
11699
9829ddba
RS
11700 /* We have nothing to do if the current position
11701 is already for the top-left corner. */
11702 if (! ((flags & XNegative) || (flags & YNegative)))
11703 return;
11704
c81412a0 11705#ifdef USE_X_TOOLKIT
7556890b 11706 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
11707#else
11708 this_window = FRAME_X_WINDOW (f);
11709#endif
6dba1858
RS
11710
11711 /* Find the position of the outside upper-left corner of
9829ddba
RS
11712 the inner window, with respect to the outer window.
11713 But do this only if we will need the results. */
7556890b 11714 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 11715 {
9829ddba
RS
11716 int count;
11717
6dba1858 11718 BLOCK_INPUT;
9829ddba
RS
11719 count = x_catch_errors (FRAME_X_DISPLAY (f));
11720 while (1)
11721 {
11722 x_clear_errors (FRAME_X_DISPLAY (f));
11723 XTranslateCoordinates (FRAME_X_DISPLAY (f),
11724
11725 /* From-window, to-window. */
11726 this_window,
11727 f->output_data.x->parent_desc,
11728
11729 /* From-position, to-position. */
11730 0, 0, &win_x, &win_y,
11731
11732 /* Child of win. */
11733 &child);
11734 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
11735 {
11736 Window newroot, newparent = 0xdeadbeef;
11737 Window *newchildren;
2ebb2f8b 11738 unsigned int nchildren;
9829ddba
RS
11739
11740 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
11741 &newparent, &newchildren, &nchildren))
11742 break;
58769bee 11743
7c3c78a3 11744 XFree ((char *) newchildren);
6dba1858 11745
9829ddba
RS
11746 f->output_data.x->parent_desc = newparent;
11747 }
11748 else
11749 break;
11750 }
6dba1858 11751
9829ddba 11752 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
11753 UNBLOCK_INPUT;
11754 }
11755
11756 /* Treat negative positions as relative to the leftmost bottommost
11757 position that fits on the screen. */
20f55f9a 11758 if (flags & XNegative)
7556890b 11759 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
11760 - 2 * f->output_data.x->border_width - win_x
11761 - PIXEL_WIDTH (f)
11762 + f->output_data.x->left_pos);
dc6f92b8 11763
7708ced0
GM
11764 {
11765 int height = PIXEL_HEIGHT (f);
06a2c219 11766
7708ced0
GM
11767#if defined USE_X_TOOLKIT && defined USE_MOTIF
11768 /* Something is fishy here. When using Motif, starting Emacs with
11769 `-g -0-0', the frame appears too low by a few pixels.
11770
11771 This seems to be so because initially, while Emacs is starting,
11772 the column widget's height and the frame's pixel height are
11773 different. The column widget's height is the right one. In
11774 later invocations, when Emacs is up, the frame's pixel height
11775 is right, though.
11776
11777 It's not obvious where the initial small difference comes from.
11778 2000-12-01, gerd. */
11779
11780 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 11781#endif
2e365682 11782
7708ced0
GM
11783 if (flags & YNegative)
11784 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
11785 - 2 * f->output_data.x->border_width
11786 - win_y
11787 - height
11788 + f->output_data.x->top_pos);
11789 }
11790
3a35ab44
RS
11791 /* The left_pos and top_pos
11792 are now relative to the top and left screen edges,
11793 so the flags should correspond. */
7556890b 11794 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
11795}
11796
3a35ab44
RS
11797/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
11798 to really change the position, and 0 when calling from
11799 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
11800 position values). It is -1 when calling from x_set_frame_parameters,
11801 which means, do adjust for borders but don't change the gravity. */
3a35ab44 11802
dfcf069d 11803void
dc05a16b 11804x_set_offset (f, xoff, yoff, change_gravity)
f676886a 11805 struct frame *f;
dc6f92b8 11806 register int xoff, yoff;
dc05a16b 11807 int change_gravity;
dc6f92b8 11808{
4a4cbdd5
KH
11809 int modified_top, modified_left;
11810
aa3ff7c9 11811 if (change_gravity > 0)
3a35ab44 11812 {
7556890b
RS
11813 f->output_data.x->top_pos = yoff;
11814 f->output_data.x->left_pos = xoff;
11815 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 11816 if (xoff < 0)
7556890b 11817 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 11818 if (yoff < 0)
7556890b
RS
11819 f->output_data.x->size_hint_flags |= YNegative;
11820 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 11821 }
43bca5d5 11822 x_calc_absolute_position (f);
dc6f92b8
JB
11823
11824 BLOCK_INPUT;
c32cdd9a 11825 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 11826
7556890b
RS
11827 modified_left = f->output_data.x->left_pos;
11828 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
11829#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
11830 this seems to be unnecessary and incorrect. rms, 4/17/97. */
11831 /* It is a mystery why we need to add the border_width here
11832 when the frame is already visible, but experiment says we do. */
aa3ff7c9 11833 if (change_gravity != 0)
4a4cbdd5 11834 {
7556890b
RS
11835 modified_left += f->output_data.x->border_width;
11836 modified_top += f->output_data.x->border_width;
4a4cbdd5 11837 }
e73ec6fa 11838#endif
4a4cbdd5 11839
3afe33e7 11840#ifdef USE_X_TOOLKIT
7556890b 11841 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 11842 modified_left, modified_top);
3afe33e7 11843#else /* not USE_X_TOOLKIT */
334208b7 11844 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 11845 modified_left, modified_top);
3afe33e7 11846#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11847 UNBLOCK_INPUT;
11848}
11849
bc20ebbf
FP
11850/* Call this to change the size of frame F's x-window.
11851 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
11852 for this size change and subsequent size changes.
11853 Otherwise we leave the window gravity unchanged. */
dc6f92b8 11854
dfcf069d 11855void
bc20ebbf 11856x_set_window_size (f, change_gravity, cols, rows)
f676886a 11857 struct frame *f;
bc20ebbf 11858 int change_gravity;
b1c884c3 11859 int cols, rows;
dc6f92b8 11860{
06a2c219 11861#ifndef USE_X_TOOLKIT
dc6f92b8 11862 int pixelwidth, pixelheight;
06a2c219 11863#endif
dc6f92b8 11864
80fd1fe2 11865 BLOCK_INPUT;
aee9a898
RS
11866
11867#ifdef USE_X_TOOLKIT
3a20653d
RS
11868 {
11869 /* The x and y position of the widget is clobbered by the
11870 call to XtSetValues within EmacsFrameSetCharSize.
11871 This is a real kludge, but I don't understand Xt so I can't
11872 figure out a correct fix. Can anyone else tell me? -- rms. */
7556890b
RS
11873 int xpos = f->output_data.x->widget->core.x;
11874 int ypos = f->output_data.x->widget->core.y;
11875 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
11876 f->output_data.x->widget->core.x = xpos;
11877 f->output_data.x->widget->core.y = ypos;
3a20653d 11878 }
80fd1fe2
FP
11879
11880#else /* not USE_X_TOOLKIT */
11881
b1c884c3 11882 check_frame_size (f, &rows, &cols);
7556890b 11883 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
11884 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
11885 ? 0
11886 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 11887 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 11888 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 11889 f->output_data.x->flags_areas_extra
110859fc 11890 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
11891 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
11892 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 11893
7556890b 11894 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 11895 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 11896
334208b7
RS
11897 XSync (FRAME_X_DISPLAY (f), False);
11898 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11899 pixelwidth, pixelheight);
b1c884c3
JB
11900
11901 /* Now, strictly speaking, we can't be sure that this is accurate,
11902 but the window manager will get around to dealing with the size
11903 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
11904 ConfigureNotify event gets here.
11905
11906 We could just not bother storing any of this information here,
11907 and let the ConfigureNotify event set everything up, but that
fddd5ceb 11908 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 11909 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
11910 point in the future when the ConfigureNotify event arrives.
11911
11912 We pass 1 for DELAY since we can't run Lisp code inside of
11913 a BLOCK_INPUT. */
7d1e984f 11914 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
11915 PIXEL_WIDTH (f) = pixelwidth;
11916 PIXEL_HEIGHT (f) = pixelheight;
11917
aee9a898
RS
11918 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
11919 receive in the ConfigureNotify event; if we get what we asked
11920 for, then the event won't cause the screen to become garbaged, so
11921 we have to make sure to do it here. */
11922 SET_FRAME_GARBAGED (f);
11923
11924 XFlush (FRAME_X_DISPLAY (f));
11925
11926#endif /* not USE_X_TOOLKIT */
11927
4d73d038 11928 /* If cursor was outside the new size, mark it as off. */
06a2c219 11929 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 11930
aee9a898
RS
11931 /* Clear out any recollection of where the mouse highlighting was,
11932 since it might be in a place that's outside the new frame size.
11933 Actually checking whether it is outside is a pain in the neck,
11934 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 11935 cancel_mouse_face (f);
dbc4e1c1 11936
dc6f92b8
JB
11937 UNBLOCK_INPUT;
11938}
dc6f92b8 11939\f
d047c4eb 11940/* Mouse warping. */
dc6f92b8 11941
9b378208 11942void
f676886a
JB
11943x_set_mouse_position (f, x, y)
11944 struct frame *f;
dc6f92b8
JB
11945 int x, y;
11946{
11947 int pix_x, pix_y;
11948
7556890b
RS
11949 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
11950 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
11951
11952 if (pix_x < 0) pix_x = 0;
11953 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
11954
11955 if (pix_y < 0) pix_y = 0;
11956 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
11957
11958 BLOCK_INPUT;
dc6f92b8 11959
334208b7
RS
11960 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11961 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
11962 UNBLOCK_INPUT;
11963}
11964
9b378208
RS
11965/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
11966
11967void
11968x_set_mouse_pixel_position (f, pix_x, pix_y)
11969 struct frame *f;
11970 int pix_x, pix_y;
11971{
11972 BLOCK_INPUT;
11973
334208b7
RS
11974 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11975 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
11976 UNBLOCK_INPUT;
11977}
d047c4eb
KH
11978\f
11979/* focus shifting, raising and lowering. */
9b378208 11980
dfcf069d 11981void
f676886a
JB
11982x_focus_on_frame (f)
11983 struct frame *f;
dc6f92b8 11984{
1fb20991 11985#if 0 /* This proves to be unpleasant. */
f676886a 11986 x_raise_frame (f);
1fb20991 11987#endif
6d4238f3
JB
11988#if 0
11989 /* I don't think that the ICCCM allows programs to do things like this
11990 without the interaction of the window manager. Whatever you end up
f676886a 11991 doing with this code, do it to x_unfocus_frame too. */
334208b7 11992 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 11993 RevertToPointerRoot, CurrentTime);
c118dd06 11994#endif /* ! 0 */
dc6f92b8
JB
11995}
11996
dfcf069d 11997void
f676886a
JB
11998x_unfocus_frame (f)
11999 struct frame *f;
dc6f92b8 12000{
6d4238f3 12001#if 0
f676886a 12002 /* Look at the remarks in x_focus_on_frame. */
0f941935 12003 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 12004 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 12005 RevertToPointerRoot, CurrentTime);
c118dd06 12006#endif /* ! 0 */
dc6f92b8
JB
12007}
12008
f676886a 12009/* Raise frame F. */
dc6f92b8 12010
dfcf069d 12011void
f676886a
JB
12012x_raise_frame (f)
12013 struct frame *f;
dc6f92b8 12014{
3a88c238 12015 if (f->async_visible)
dc6f92b8
JB
12016 {
12017 BLOCK_INPUT;
3afe33e7 12018#ifdef USE_X_TOOLKIT
7556890b 12019 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12020#else /* not USE_X_TOOLKIT */
334208b7 12021 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12022#endif /* not USE_X_TOOLKIT */
334208b7 12023 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12024 UNBLOCK_INPUT;
12025 }
12026}
12027
f676886a 12028/* Lower frame F. */
dc6f92b8 12029
dfcf069d 12030void
f676886a
JB
12031x_lower_frame (f)
12032 struct frame *f;
dc6f92b8 12033{
3a88c238 12034 if (f->async_visible)
dc6f92b8
JB
12035 {
12036 BLOCK_INPUT;
3afe33e7 12037#ifdef USE_X_TOOLKIT
7556890b 12038 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12039#else /* not USE_X_TOOLKIT */
334208b7 12040 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12041#endif /* not USE_X_TOOLKIT */
334208b7 12042 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12043 UNBLOCK_INPUT;
12044 }
12045}
12046
dbc4e1c1 12047static void
6b0442dc 12048XTframe_raise_lower (f, raise_flag)
dbc4e1c1 12049 FRAME_PTR f;
6b0442dc 12050 int raise_flag;
dbc4e1c1 12051{
6b0442dc 12052 if (raise_flag)
dbc4e1c1
JB
12053 x_raise_frame (f);
12054 else
12055 x_lower_frame (f);
12056}
d047c4eb
KH
12057\f
12058/* Change of visibility. */
dc6f92b8 12059
9382638d
KH
12060/* This tries to wait until the frame is really visible.
12061 However, if the window manager asks the user where to position
12062 the frame, this will return before the user finishes doing that.
12063 The frame will not actually be visible at that time,
12064 but it will become visible later when the window manager
12065 finishes with it. */
12066
dfcf069d 12067void
f676886a
JB
12068x_make_frame_visible (f)
12069 struct frame *f;
dc6f92b8 12070{
990ba854 12071 Lisp_Object type;
1aa6072f 12072 int original_top, original_left;
31be9251
GM
12073 int retry_count = 2;
12074
12075 retry:
dc6f92b8 12076
dc6f92b8 12077 BLOCK_INPUT;
dc6f92b8 12078
990ba854
RS
12079 type = x_icon_type (f);
12080 if (!NILP (type))
12081 x_bitmap_icon (f, type);
bdcd49ba 12082
f676886a 12083 if (! FRAME_VISIBLE_P (f))
90e65f07 12084 {
1aa6072f
RS
12085 /* We test FRAME_GARBAGED_P here to make sure we don't
12086 call x_set_offset a second time
12087 if we get to x_make_frame_visible a second time
12088 before the window gets really visible. */
12089 if (! FRAME_ICONIFIED_P (f)
12090 && ! f->output_data.x->asked_for_visible)
12091 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
12092
12093 f->output_data.x->asked_for_visible = 1;
12094
90e65f07 12095 if (! EQ (Vx_no_window_manager, Qt))
f676886a 12096 x_wm_set_window_state (f, NormalState);
3afe33e7 12097#ifdef USE_X_TOOLKIT
d7a38a2e 12098 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12099 XtMapWidget (f->output_data.x->widget);
3afe33e7 12100#else /* not USE_X_TOOLKIT */
7f9c7f94 12101 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12102#endif /* not USE_X_TOOLKIT */
0134a210
RS
12103#if 0 /* This seems to bring back scroll bars in the wrong places
12104 if the window configuration has changed. They seem
12105 to come back ok without this. */
ab648270 12106 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 12107 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 12108#endif
90e65f07 12109 }
dc6f92b8 12110
334208b7 12111 XFlush (FRAME_X_DISPLAY (f));
90e65f07 12112
0dacf791
RS
12113 /* Synchronize to ensure Emacs knows the frame is visible
12114 before we do anything else. We do this loop with input not blocked
12115 so that incoming events are handled. */
12116 {
12117 Lisp_Object frame;
12ce2351 12118 int count;
28c01ffe
RS
12119 /* This must be before UNBLOCK_INPUT
12120 since events that arrive in response to the actions above
12121 will set it when they are handled. */
12122 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
12123
12124 original_left = f->output_data.x->left_pos;
12125 original_top = f->output_data.x->top_pos;
c0a04927
RS
12126
12127 /* This must come after we set COUNT. */
12128 UNBLOCK_INPUT;
12129
2745e6c4 12130 /* We unblock here so that arriving X events are processed. */
1aa6072f 12131
dcb07ae9
RS
12132 /* Now move the window back to where it was "supposed to be".
12133 But don't do it if the gravity is negative.
12134 When the gravity is negative, this uses a position
28c01ffe
RS
12135 that is 3 pixels too low. Perhaps that's really the border width.
12136
12137 Don't do this if the window has never been visible before,
12138 because the window manager may choose the position
12139 and we don't want to override it. */
1aa6072f 12140
4d3f5d9a 12141 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 12142 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 12143 && previously_visible)
1aa6072f 12144 {
2745e6c4
RS
12145 Drawable rootw;
12146 int x, y;
12147 unsigned int width, height, border, depth;
06a2c219 12148
1aa6072f 12149 BLOCK_INPUT;
9829ddba 12150
06a2c219
GM
12151 /* On some window managers (such as FVWM) moving an existing
12152 window, even to the same place, causes the window manager
12153 to introduce an offset. This can cause the window to move
12154 to an unexpected location. Check the geometry (a little
12155 slow here) and then verify that the window is in the right
12156 place. If the window is not in the right place, move it
12157 there, and take the potential window manager hit. */
2745e6c4
RS
12158 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12159 &rootw, &x, &y, &width, &height, &border, &depth);
12160
12161 if (original_left != x || original_top != y)
12162 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12163 original_left, original_top);
12164
1aa6072f
RS
12165 UNBLOCK_INPUT;
12166 }
9829ddba 12167
e0c1aef2 12168 XSETFRAME (frame, f);
c0a04927 12169
12ce2351
GM
12170 /* Wait until the frame is visible. Process X events until a
12171 MapNotify event has been seen, or until we think we won't get a
12172 MapNotify at all.. */
12173 for (count = input_signal_count + 10;
12174 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 12175 {
12ce2351 12176 /* Force processing of queued events. */
334208b7 12177 x_sync (f);
12ce2351
GM
12178
12179 /* Machines that do polling rather than SIGIO have been
12180 observed to go into a busy-wait here. So we'll fake an
12181 alarm signal to let the handler know that there's something
12182 to be read. We used to raise a real alarm, but it seems
12183 that the handler isn't always enabled here. This is
12184 probably a bug. */
8b2f8d4e 12185 if (input_polling_used ())
3b2fa4e6 12186 {
12ce2351
GM
12187 /* It could be confusing if a real alarm arrives while
12188 processing the fake one. Turn it off and let the
12189 handler reset it. */
3e71d8f2 12190 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
12191 int old_poll_suppress_count = poll_suppress_count;
12192 poll_suppress_count = 1;
12193 poll_for_input_1 ();
12194 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 12195 }
12ce2351
GM
12196
12197 /* See if a MapNotify event has been processed. */
12198 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 12199 }
31be9251
GM
12200
12201 /* 2000-09-28: In
12202
12203 (let ((f (selected-frame)))
12204 (iconify-frame f)
12205 (raise-frame f))
12206
12207 the frame is not raised with various window managers on
12208 FreeBSD, Linux and Solaris. It turns out that, for some
12209 unknown reason, the call to XtMapWidget is completely ignored.
12210 Mapping the widget a second time works. */
12211
12212 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
12213 goto retry;
0dacf791 12214 }
dc6f92b8
JB
12215}
12216
06a2c219 12217/* Change from mapped state to withdrawn state. */
dc6f92b8 12218
d047c4eb
KH
12219/* Make the frame visible (mapped and not iconified). */
12220
dfcf069d 12221void
f676886a
JB
12222x_make_frame_invisible (f)
12223 struct frame *f;
dc6f92b8 12224{
546e6d5b
RS
12225 Window window;
12226
12227#ifdef USE_X_TOOLKIT
12228 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 12229 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
12230#else /* not USE_X_TOOLKIT */
12231 window = FRAME_X_WINDOW (f);
12232#endif /* not USE_X_TOOLKIT */
dc6f92b8 12233
9319ae23 12234 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12235 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12236 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12237
5627c40e 12238#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 12239 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 12240 return;
5627c40e 12241#endif
dc6f92b8
JB
12242
12243 BLOCK_INPUT;
c118dd06 12244
af31d76f
RS
12245 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
12246 that the current position of the window is user-specified, rather than
12247 program-specified, so that when the window is mapped again, it will be
12248 placed at the same location, without forcing the user to position it
12249 by hand again (they have already done that once for this window.) */
c32cdd9a 12250 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 12251
c118dd06
JB
12252#ifdef HAVE_X11R4
12253
334208b7
RS
12254 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
12255 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
12256 {
12257 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12258 error ("Can't notify window manager of window withdrawal");
c118dd06 12259 }
c118dd06 12260#else /* ! defined (HAVE_X11R4) */
16bd92ea 12261
c118dd06 12262 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
12263 if (! EQ (Vx_no_window_manager, Qt))
12264 {
16bd92ea 12265 XEvent unmap;
dc6f92b8 12266
16bd92ea 12267 unmap.xunmap.type = UnmapNotify;
546e6d5b 12268 unmap.xunmap.window = window;
334208b7 12269 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 12270 unmap.xunmap.from_configure = False;
334208b7
RS
12271 if (! XSendEvent (FRAME_X_DISPLAY (f),
12272 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 12273 False,
06a2c219 12274 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
12275 &unmap))
12276 {
12277 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12278 error ("Can't notify window manager of withdrawal");
16bd92ea 12279 }
dc6f92b8
JB
12280 }
12281
16bd92ea 12282 /* Unmap the window ourselves. Cheeky! */
334208b7 12283 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 12284#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 12285
5627c40e
RS
12286 /* We can't distinguish this from iconification
12287 just by the event that we get from the server.
12288 So we can't win using the usual strategy of letting
12289 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
12290 and synchronize with the server to make sure we agree. */
12291 f->visible = 0;
12292 FRAME_ICONIFIED_P (f) = 0;
12293 f->async_visible = 0;
12294 f->async_iconified = 0;
12295
334208b7 12296 x_sync (f);
5627c40e 12297
dc6f92b8
JB
12298 UNBLOCK_INPUT;
12299}
12300
06a2c219 12301/* Change window state from mapped to iconified. */
dc6f92b8 12302
dfcf069d 12303void
f676886a
JB
12304x_iconify_frame (f)
12305 struct frame *f;
dc6f92b8 12306{
3afe33e7 12307 int result;
990ba854 12308 Lisp_Object type;
dc6f92b8 12309
9319ae23 12310 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12311 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12312 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12313
3a88c238 12314 if (f->async_iconified)
dc6f92b8
JB
12315 return;
12316
3afe33e7 12317 BLOCK_INPUT;
546e6d5b 12318
9af3143a
RS
12319 FRAME_SAMPLE_VISIBILITY (f);
12320
990ba854
RS
12321 type = x_icon_type (f);
12322 if (!NILP (type))
12323 x_bitmap_icon (f, type);
bdcd49ba
RS
12324
12325#ifdef USE_X_TOOLKIT
12326
546e6d5b
RS
12327 if (! FRAME_VISIBLE_P (f))
12328 {
12329 if (! EQ (Vx_no_window_manager, Qt))
12330 x_wm_set_window_state (f, IconicState);
12331 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12332 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
12333 /* The server won't give us any event to indicate
12334 that an invisible frame was changed to an icon,
12335 so we have to record it here. */
12336 f->iconified = 1;
1e6bc770 12337 f->visible = 1;
9cf30a30 12338 f->async_iconified = 1;
1e6bc770 12339 f->async_visible = 0;
546e6d5b
RS
12340 UNBLOCK_INPUT;
12341 return;
12342 }
12343
334208b7 12344 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 12345 XtWindow (f->output_data.x->widget),
334208b7 12346 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
12347 UNBLOCK_INPUT;
12348
12349 if (!result)
546e6d5b 12350 error ("Can't notify window manager of iconification");
3afe33e7
RS
12351
12352 f->async_iconified = 1;
1e6bc770
RS
12353 f->async_visible = 0;
12354
8c002a25
KH
12355
12356 BLOCK_INPUT;
334208b7 12357 XFlush (FRAME_X_DISPLAY (f));
8c002a25 12358 UNBLOCK_INPUT;
3afe33e7
RS
12359#else /* not USE_X_TOOLKIT */
12360
fd13dbb2
RS
12361 /* Make sure the X server knows where the window should be positioned,
12362 in case the user deiconifies with the window manager. */
12363 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 12364 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 12365
16bd92ea
JB
12366 /* Since we don't know which revision of X we're running, we'll use both
12367 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
12368
12369 /* X11R4: send a ClientMessage to the window manager using the
12370 WM_CHANGE_STATE type. */
12371 {
12372 XEvent message;
58769bee 12373
c118dd06 12374 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 12375 message.xclient.type = ClientMessage;
334208b7 12376 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
12377 message.xclient.format = 32;
12378 message.xclient.data.l[0] = IconicState;
12379
334208b7
RS
12380 if (! XSendEvent (FRAME_X_DISPLAY (f),
12381 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
12382 False,
12383 SubstructureRedirectMask | SubstructureNotifyMask,
12384 &message))
dc6f92b8
JB
12385 {
12386 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12387 error ("Can't notify window manager of iconification");
dc6f92b8 12388 }
16bd92ea 12389 }
dc6f92b8 12390
58769bee 12391 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
12392 IconicState. */
12393 x_wm_set_window_state (f, IconicState);
dc6f92b8 12394
a9c00105
RS
12395 if (!FRAME_VISIBLE_P (f))
12396 {
12397 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 12398 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
12399 }
12400
3a88c238 12401 f->async_iconified = 1;
1e6bc770 12402 f->async_visible = 0;
dc6f92b8 12403
334208b7 12404 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 12405 UNBLOCK_INPUT;
8c002a25 12406#endif /* not USE_X_TOOLKIT */
dc6f92b8 12407}
d047c4eb 12408\f
c0ff3fab 12409/* Destroy the X window of frame F. */
dc6f92b8 12410
dfcf069d 12411void
c0ff3fab 12412x_destroy_window (f)
f676886a 12413 struct frame *f;
dc6f92b8 12414{
7f9c7f94
RS
12415 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12416
dc6f92b8 12417 BLOCK_INPUT;
c0ff3fab 12418
6186a4a0
RS
12419 /* If a display connection is dead, don't try sending more
12420 commands to the X server. */
12421 if (dpyinfo->display != 0)
12422 {
12423 if (f->output_data.x->icon_desc != 0)
12424 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
31f41daf 12425#ifdef HAVE_X_I18N
f5d11644
GM
12426 if (FRAME_XIC (f))
12427 free_frame_xic (f);
31f41daf 12428#endif
6186a4a0 12429 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->window_desc);
3afe33e7 12430#ifdef USE_X_TOOLKIT
06a2c219
GM
12431 if (f->output_data.x->widget)
12432 XtDestroyWidget (f->output_data.x->widget);
6186a4a0 12433 free_frame_menubar (f);
3afe33e7
RS
12434#endif /* USE_X_TOOLKIT */
12435
3e71d8f2
GM
12436 unload_color (f, f->output_data.x->foreground_pixel);
12437 unload_color (f, f->output_data.x->background_pixel);
12438 unload_color (f, f->output_data.x->cursor_pixel);
12439 unload_color (f, f->output_data.x->cursor_foreground_pixel);
12440 unload_color (f, f->output_data.x->border_pixel);
12441 unload_color (f, f->output_data.x->mouse_pixel);
12442 if (f->output_data.x->scroll_bar_background_pixel != -1)
12443 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
12444 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
12445 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
12446 if (f->output_data.x->white_relief.allocated_p)
12447 unload_color (f, f->output_data.x->white_relief.pixel);
12448 if (f->output_data.x->black_relief.allocated_p)
12449 unload_color (f, f->output_data.x->black_relief.pixel);
12450
6186a4a0
RS
12451 free_frame_faces (f);
12452 XFlush (FRAME_X_DISPLAY (f));
12453 }
dc6f92b8 12454
df89d8a4 12455 if (f->output_data.x->saved_menu_event)
06a2c219 12456 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 12457
7556890b
RS
12458 xfree (f->output_data.x);
12459 f->output_data.x = 0;
0f941935
KH
12460 if (f == dpyinfo->x_focus_frame)
12461 dpyinfo->x_focus_frame = 0;
12462 if (f == dpyinfo->x_focus_event_frame)
12463 dpyinfo->x_focus_event_frame = 0;
12464 if (f == dpyinfo->x_highlight_frame)
12465 dpyinfo->x_highlight_frame = 0;
c0ff3fab 12466
7f9c7f94
RS
12467 dpyinfo->reference_count--;
12468
12469 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 12470 {
7f9c7f94
RS
12471 dpyinfo->mouse_face_beg_row
12472 = dpyinfo->mouse_face_beg_col = -1;
12473 dpyinfo->mouse_face_end_row
12474 = dpyinfo->mouse_face_end_col = -1;
12475 dpyinfo->mouse_face_window = Qnil;
21323706
RS
12476 dpyinfo->mouse_face_deferred_gc = 0;
12477 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 12478 }
0134a210 12479
c0ff3fab 12480 UNBLOCK_INPUT;
dc6f92b8
JB
12481}
12482\f
f451eb13
JB
12483/* Setting window manager hints. */
12484
af31d76f
RS
12485/* Set the normal size hints for the window manager, for frame F.
12486 FLAGS is the flags word to use--or 0 meaning preserve the flags
12487 that the window now has.
12488 If USER_POSITION is nonzero, we set the USPosition
12489 flag (this is useful when FLAGS is 0). */
6dba1858 12490
dfcf069d 12491void
af31d76f 12492x_wm_set_size_hint (f, flags, user_position)
f676886a 12493 struct frame *f;
af31d76f
RS
12494 long flags;
12495 int user_position;
dc6f92b8
JB
12496{
12497 XSizeHints size_hints;
3afe33e7
RS
12498
12499#ifdef USE_X_TOOLKIT
7e4f2521
FP
12500 Arg al[2];
12501 int ac = 0;
12502 Dimension widget_width, widget_height;
7556890b 12503 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 12504#else /* not USE_X_TOOLKIT */
c118dd06 12505 Window window = FRAME_X_WINDOW (f);
3afe33e7 12506#endif /* not USE_X_TOOLKIT */
dc6f92b8 12507
b72a58fd
RS
12508 /* Setting PMaxSize caused various problems. */
12509 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 12510
7556890b
RS
12511 size_hints.x = f->output_data.x->left_pos;
12512 size_hints.y = f->output_data.x->top_pos;
7553a6b7 12513
7e4f2521
FP
12514#ifdef USE_X_TOOLKIT
12515 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
12516 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 12517 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
12518 size_hints.height = widget_height;
12519 size_hints.width = widget_width;
12520#else /* not USE_X_TOOLKIT */
f676886a
JB
12521 size_hints.height = PIXEL_HEIGHT (f);
12522 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 12523#endif /* not USE_X_TOOLKIT */
7553a6b7 12524
7556890b
RS
12525 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
12526 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
12527 size_hints.max_width
12528 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
12529 size_hints.max_height
12530 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 12531
d067ea8b
KH
12532 /* Calculate the base and minimum sizes.
12533
12534 (When we use the X toolkit, we don't do it here.
12535 Instead we copy the values that the widgets are using, below.) */
12536#ifndef USE_X_TOOLKIT
b1c884c3 12537 {
b0342f17 12538 int base_width, base_height;
0134a210 12539 int min_rows = 0, min_cols = 0;
b0342f17 12540
f451eb13
JB
12541 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
12542 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 12543
0134a210 12544 check_frame_size (f, &min_rows, &min_cols);
b0342f17 12545
0134a210
RS
12546 /* The window manager uses the base width hints to calculate the
12547 current number of rows and columns in the frame while
12548 resizing; min_width and min_height aren't useful for this
12549 purpose, since they might not give the dimensions for a
12550 zero-row, zero-column frame.
58769bee 12551
0134a210
RS
12552 We use the base_width and base_height members if we have
12553 them; otherwise, we set the min_width and min_height members
12554 to the size for a zero x zero frame. */
b0342f17
JB
12555
12556#ifdef HAVE_X11R4
0134a210
RS
12557 size_hints.flags |= PBaseSize;
12558 size_hints.base_width = base_width;
12559 size_hints.base_height = base_height;
12560 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
12561 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 12562#else
0134a210
RS
12563 size_hints.min_width = base_width;
12564 size_hints.min_height = base_height;
b0342f17 12565#endif
b1c884c3 12566 }
dc6f92b8 12567
d067ea8b 12568 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 12569 if (flags)
dc6f92b8 12570 {
d067ea8b
KH
12571 size_hints.flags |= flags;
12572 goto no_read;
12573 }
12574#endif /* not USE_X_TOOLKIT */
12575
12576 {
12577 XSizeHints hints; /* Sometimes I hate X Windows... */
12578 long supplied_return;
12579 int value;
af31d76f
RS
12580
12581#ifdef HAVE_X11R4
d067ea8b
KH
12582 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
12583 &supplied_return);
af31d76f 12584#else
d067ea8b 12585 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 12586#endif
58769bee 12587
d067ea8b
KH
12588#ifdef USE_X_TOOLKIT
12589 size_hints.base_height = hints.base_height;
12590 size_hints.base_width = hints.base_width;
12591 size_hints.min_height = hints.min_height;
12592 size_hints.min_width = hints.min_width;
12593#endif
12594
12595 if (flags)
12596 size_hints.flags |= flags;
12597 else
12598 {
12599 if (value == 0)
12600 hints.flags = 0;
12601 if (hints.flags & PSize)
12602 size_hints.flags |= PSize;
12603 if (hints.flags & PPosition)
12604 size_hints.flags |= PPosition;
12605 if (hints.flags & USPosition)
12606 size_hints.flags |= USPosition;
12607 if (hints.flags & USSize)
12608 size_hints.flags |= USSize;
12609 }
12610 }
12611
06a2c219 12612#ifndef USE_X_TOOLKIT
d067ea8b 12613 no_read:
06a2c219 12614#endif
0134a210 12615
af31d76f 12616#ifdef PWinGravity
7556890b 12617 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 12618 size_hints.flags |= PWinGravity;
dc05a16b 12619
af31d76f 12620 if (user_position)
6dba1858 12621 {
af31d76f
RS
12622 size_hints.flags &= ~ PPosition;
12623 size_hints.flags |= USPosition;
6dba1858 12624 }
2554751d 12625#endif /* PWinGravity */
6dba1858 12626
b0342f17 12627#ifdef HAVE_X11R4
334208b7 12628 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12629#else
334208b7 12630 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12631#endif
dc6f92b8
JB
12632}
12633
12634/* Used for IconicState or NormalState */
06a2c219 12635
dfcf069d 12636void
f676886a
JB
12637x_wm_set_window_state (f, state)
12638 struct frame *f;
dc6f92b8
JB
12639 int state;
12640{
3afe33e7 12641#ifdef USE_X_TOOLKIT
546e6d5b
RS
12642 Arg al[1];
12643
12644 XtSetArg (al[0], XtNinitialState, state);
7556890b 12645 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 12646#else /* not USE_X_TOOLKIT */
c118dd06 12647 Window window = FRAME_X_WINDOW (f);
dc6f92b8 12648
7556890b
RS
12649 f->output_data.x->wm_hints.flags |= StateHint;
12650 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 12651
7556890b 12652 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 12653#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12654}
12655
dfcf069d 12656void
7f2ae036 12657x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 12658 struct frame *f;
7f2ae036 12659 int pixmap_id;
dc6f92b8 12660{
d2bd6bc4
RS
12661 Pixmap icon_pixmap;
12662
06a2c219 12663#ifndef USE_X_TOOLKIT
c118dd06 12664 Window window = FRAME_X_WINDOW (f);
75231bad 12665#endif
dc6f92b8 12666
7f2ae036 12667 if (pixmap_id > 0)
dbc4e1c1 12668 {
d2bd6bc4 12669 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 12670 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
12671 }
12672 else
68568555
RS
12673 {
12674 /* It seems there is no way to turn off use of an icon pixmap.
12675 The following line does it, only if no icon has yet been created,
12676 for some window managers. But with mwm it crashes.
12677 Some people say it should clear the IconPixmapHint bit in this case,
12678 but that doesn't work, and the X consortium said it isn't the
12679 right thing at all. Since there is no way to win,
12680 best to explicitly give up. */
12681#if 0
12682 f->output_data.x->wm_hints.icon_pixmap = None;
12683#else
12684 return;
12685#endif
12686 }
b1c884c3 12687
d2bd6bc4
RS
12688#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
12689
12690 {
12691 Arg al[1];
12692 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
12693 XtSetValues (f->output_data.x->widget, al, 1);
12694 }
12695
12696#else /* not USE_X_TOOLKIT */
12697
7556890b
RS
12698 f->output_data.x->wm_hints.flags |= IconPixmapHint;
12699 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
12700
12701#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12702}
12703
dfcf069d 12704void
f676886a
JB
12705x_wm_set_icon_position (f, icon_x, icon_y)
12706 struct frame *f;
dc6f92b8
JB
12707 int icon_x, icon_y;
12708{
75231bad 12709#ifdef USE_X_TOOLKIT
7556890b 12710 Window window = XtWindow (f->output_data.x->widget);
75231bad 12711#else
c118dd06 12712 Window window = FRAME_X_WINDOW (f);
75231bad 12713#endif
dc6f92b8 12714
7556890b
RS
12715 f->output_data.x->wm_hints.flags |= IconPositionHint;
12716 f->output_data.x->wm_hints.icon_x = icon_x;
12717 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 12718
7556890b 12719 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
12720}
12721
12722\f
06a2c219
GM
12723/***********************************************************************
12724 Fonts
12725 ***********************************************************************/
dc43ef94
KH
12726
12727/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 12728
dc43ef94
KH
12729struct font_info *
12730x_get_font_info (f, font_idx)
12731 FRAME_PTR f;
12732 int font_idx;
12733{
12734 return (FRAME_X_FONT_TABLE (f) + font_idx);
12735}
12736
12737
12738/* Return a list of names of available fonts matching PATTERN on frame
12739 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
12740 to be listed. Frame F NULL means we have not yet created any
12741 frame on X, and consult the first display in x_display_list.
12742 MAXNAMES sets a limit on how many fonts to match. */
12743
12744Lisp_Object
12745x_list_fonts (f, pattern, size, maxnames)
12746 FRAME_PTR f;
12747 Lisp_Object pattern;
12748 int size;
12749 int maxnames;
12750{
06a2c219
GM
12751 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
12752 Lisp_Object tem, second_best;
dc43ef94 12753 Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
09c6077f 12754 int try_XLoadQueryFont = 0;
53ca4657 12755 int count;
dc43ef94 12756
6b0efe73 12757 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
12758 if (NILP (patterns))
12759 patterns = Fcons (pattern, Qnil);
81ba44e5 12760
09c6077f
KH
12761 if (maxnames == 1 && !size)
12762 /* We can return any single font matching PATTERN. */
12763 try_XLoadQueryFont = 1;
9a32686f 12764
8e713be6 12765 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 12766 {
dc43ef94 12767 int num_fonts;
3e71d8f2 12768 char **names = NULL;
dc43ef94 12769
8e713be6 12770 pattern = XCAR (patterns);
536f4067
RS
12771 /* See if we cached the result for this particular query.
12772 The cache is an alist of the form:
12773 (((PATTERN . MAXNAMES) (FONTNAME . WIDTH) ...) ...)
12774 */
8e713be6 12775 if (f && (tem = XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element),
b5210ea7
KH
12776 key = Fcons (pattern, make_number (maxnames)),
12777 !NILP (list = Fassoc (key, tem))))
12778 {
12779 list = Fcdr_safe (list);
12780 /* We have a cashed list. Don't have to get the list again. */
12781 goto label_cached;
12782 }
12783
12784 /* At first, put PATTERN in the cache. */
09c6077f 12785
dc43ef94 12786 BLOCK_INPUT;
17d85edc
KH
12787 count = x_catch_errors (dpy);
12788
09c6077f
KH
12789 if (try_XLoadQueryFont)
12790 {
12791 XFontStruct *font;
12792 unsigned long value;
12793
12794 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
12795 if (x_had_errors_p (dpy))
12796 {
12797 /* This error is perhaps due to insufficient memory on X
12798 server. Let's just ignore it. */
12799 font = NULL;
12800 x_clear_errors (dpy);
12801 }
12802
09c6077f
KH
12803 if (font
12804 && XGetFontProperty (font, XA_FONT, &value))
12805 {
12806 char *name = (char *) XGetAtomName (dpy, (Atom) value);
12807 int len = strlen (name);
01c752b5 12808 char *tmp;
09c6077f 12809
6f6512e8
KH
12810 /* If DXPC (a Differential X Protocol Compressor)
12811 Ver.3.7 is running, XGetAtomName will return null
12812 string. We must avoid such a name. */
12813 if (len == 0)
12814 try_XLoadQueryFont = 0;
12815 else
12816 {
12817 num_fonts = 1;
12818 names = (char **) alloca (sizeof (char *));
12819 /* Some systems only allow alloca assigned to a
12820 simple var. */
12821 tmp = (char *) alloca (len + 1); names[0] = tmp;
12822 bcopy (name, names[0], len + 1);
12823 XFree (name);
12824 }
09c6077f
KH
12825 }
12826 else
12827 try_XLoadQueryFont = 0;
a083fd23
RS
12828
12829 if (font)
12830 XFreeFont (dpy, font);
09c6077f
KH
12831 }
12832
12833 if (!try_XLoadQueryFont)
17d85edc
KH
12834 {
12835 /* We try at least 10 fonts because XListFonts will return
12836 auto-scaled fonts at the head. */
12837 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
12838 &num_fonts);
12839 if (x_had_errors_p (dpy))
12840 {
12841 /* This error is perhaps due to insufficient memory on X
12842 server. Let's just ignore it. */
12843 names = NULL;
12844 x_clear_errors (dpy);
12845 }
12846 }
12847
12848 x_uncatch_errors (dpy, count);
dc43ef94
KH
12849 UNBLOCK_INPUT;
12850
12851 if (names)
12852 {
12853 int i;
dc43ef94
KH
12854
12855 /* Make a list of all the fonts we got back.
12856 Store that in the font cache for the display. */
12857 for (i = 0; i < num_fonts; i++)
12858 {
06a2c219 12859 int width = 0;
dc43ef94 12860 char *p = names[i];
06a2c219
GM
12861 int average_width = -1, dashes = 0;
12862
dc43ef94 12863 /* Count the number of dashes in NAMES[I]. If there are
b5210ea7
KH
12864 14 dashes, and the field value following 12th dash
12865 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
12866 is usually too ugly to be used for editing. Let's
12867 ignore it. */
dc43ef94
KH
12868 while (*p)
12869 if (*p++ == '-')
12870 {
12871 dashes++;
12872 if (dashes == 7) /* PIXEL_SIZE field */
12873 width = atoi (p);
12874 else if (dashes == 12) /* AVERAGE_WIDTH field */
12875 average_width = atoi (p);
12876 }
12877 if (dashes < 14 || average_width != 0)
12878 {
12879 tem = build_string (names[i]);
12880 if (NILP (Fassoc (tem, list)))
12881 {
12882 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
12883 && ((fast_c_string_match_ignore_case
12884 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
12885 >= 0))
12886 /* We can set the value of PIXEL_SIZE to the
b5210ea7 12887 width of this font. */
dc43ef94
KH
12888 list = Fcons (Fcons (tem, make_number (width)), list);
12889 else
12890 /* For the moment, width is not known. */
12891 list = Fcons (Fcons (tem, Qnil), list);
12892 }
12893 }
12894 }
09c6077f
KH
12895 if (!try_XLoadQueryFont)
12896 XFreeFontNames (names);
dc43ef94
KH
12897 }
12898
b5210ea7 12899 /* Now store the result in the cache. */
dc43ef94 12900 if (f != NULL)
8e713be6 12901 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element)
dc43ef94 12902 = Fcons (Fcons (key, list),
8e713be6 12903 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
dc43ef94 12904
b5210ea7
KH
12905 label_cached:
12906 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 12907
b5210ea7
KH
12908 newlist = second_best = Qnil;
12909 /* Make a list of the fonts that have the right width. */
8e713be6 12910 for (; CONSP (list); list = XCDR (list))
b5210ea7 12911 {
536f4067
RS
12912 int found_size;
12913
8e713be6 12914 tem = XCAR (list);
dc43ef94 12915
8e713be6 12916 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
12917 continue;
12918 if (!size)
12919 {
8e713be6 12920 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
12921 continue;
12922 }
dc43ef94 12923
8e713be6 12924 if (!INTEGERP (XCDR (tem)))
dc43ef94 12925 {
b5210ea7
KH
12926 /* Since we have not yet known the size of this font, we
12927 must try slow function call XLoadQueryFont. */
dc43ef94
KH
12928 XFontStruct *thisinfo;
12929
12930 BLOCK_INPUT;
17d85edc 12931 count = x_catch_errors (dpy);
dc43ef94 12932 thisinfo = XLoadQueryFont (dpy,
8e713be6 12933 XSTRING (XCAR (tem))->data);
17d85edc
KH
12934 if (x_had_errors_p (dpy))
12935 {
12936 /* This error is perhaps due to insufficient memory on X
12937 server. Let's just ignore it. */
12938 thisinfo = NULL;
12939 x_clear_errors (dpy);
12940 }
12941 x_uncatch_errors (dpy, count);
dc43ef94
KH
12942 UNBLOCK_INPUT;
12943
12944 if (thisinfo)
12945 {
8e713be6 12946 XCDR (tem)
536f4067
RS
12947 = (thisinfo->min_bounds.width == 0
12948 ? make_number (0)
12949 : make_number (thisinfo->max_bounds.width));
dc43ef94
KH
12950 XFreeFont (dpy, thisinfo);
12951 }
12952 else
b5210ea7 12953 /* For unknown reason, the previous call of XListFont had
06a2c219 12954 returned a font which can't be opened. Record the size
b5210ea7 12955 as 0 not to try to open it again. */
8e713be6 12956 XCDR (tem) = make_number (0);
dc43ef94 12957 }
536f4067 12958
8e713be6 12959 found_size = XINT (XCDR (tem));
536f4067 12960 if (found_size == size)
8e713be6 12961 newlist = Fcons (XCAR (tem), newlist);
536f4067 12962 else if (found_size > 0)
b5210ea7 12963 {
536f4067 12964 if (NILP (second_best))
b5210ea7 12965 second_best = tem;
536f4067
RS
12966 else if (found_size < size)
12967 {
8e713be6
KR
12968 if (XINT (XCDR (second_best)) > size
12969 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
12970 second_best = tem;
12971 }
12972 else
12973 {
8e713be6
KR
12974 if (XINT (XCDR (second_best)) > size
12975 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
12976 second_best = tem;
12977 }
b5210ea7
KH
12978 }
12979 }
12980 if (!NILP (newlist))
12981 break;
12982 else if (!NILP (second_best))
12983 {
8e713be6 12984 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 12985 break;
dc43ef94 12986 }
dc43ef94
KH
12987 }
12988
12989 return newlist;
12990}
12991
06a2c219
GM
12992
12993#if GLYPH_DEBUG
12994
12995/* Check that FONT is valid on frame F. It is if it can be found in F's
12996 font table. */
12997
12998static void
12999x_check_font (f, font)
13000 struct frame *f;
13001 XFontStruct *font;
13002{
13003 int i;
13004 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13005
13006 xassert (font != NULL);
13007
13008 for (i = 0; i < dpyinfo->n_fonts; i++)
13009 if (dpyinfo->font_table[i].name
13010 && font == dpyinfo->font_table[i].font)
13011 break;
13012
13013 xassert (i < dpyinfo->n_fonts);
13014}
13015
13016#endif /* GLYPH_DEBUG != 0 */
13017
13018/* Set *W to the minimum width, *H to the minimum font height of FONT.
13019 Note: There are (broken) X fonts out there with invalid XFontStruct
13020 min_bounds contents. For example, handa@etl.go.jp reports that
13021 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
13022 have font->min_bounds.width == 0. */
13023
13024static INLINE void
13025x_font_min_bounds (font, w, h)
13026 XFontStruct *font;
13027 int *w, *h;
13028{
13029 *h = FONT_HEIGHT (font);
13030 *w = font->min_bounds.width;
13031
13032 /* Try to handle the case where FONT->min_bounds has invalid
13033 contents. Since the only font known to have invalid min_bounds
13034 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
13035 if (*w <= 0)
13036 *w = font->max_bounds.width;
13037}
13038
13039
13040/* Compute the smallest character width and smallest font height over
13041 all fonts available on frame F. Set the members smallest_char_width
13042 and smallest_font_height in F's x_display_info structure to
13043 the values computed. Value is non-zero if smallest_font_height or
13044 smallest_char_width become smaller than they were before. */
13045
13046static int
13047x_compute_min_glyph_bounds (f)
13048 struct frame *f;
13049{
13050 int i;
13051 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13052 XFontStruct *font;
13053 int old_width = dpyinfo->smallest_char_width;
13054 int old_height = dpyinfo->smallest_font_height;
13055
13056 dpyinfo->smallest_font_height = 100000;
13057 dpyinfo->smallest_char_width = 100000;
13058
13059 for (i = 0; i < dpyinfo->n_fonts; ++i)
13060 if (dpyinfo->font_table[i].name)
13061 {
13062 struct font_info *fontp = dpyinfo->font_table + i;
13063 int w, h;
13064
13065 font = (XFontStruct *) fontp->font;
13066 xassert (font != (XFontStruct *) ~0);
13067 x_font_min_bounds (font, &w, &h);
13068
13069 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
13070 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
13071 }
13072
13073 xassert (dpyinfo->smallest_char_width > 0
13074 && dpyinfo->smallest_font_height > 0);
13075
13076 return (dpyinfo->n_fonts == 1
13077 || dpyinfo->smallest_char_width < old_width
13078 || dpyinfo->smallest_font_height < old_height);
13079}
13080
13081
dc43ef94
KH
13082/* Load font named FONTNAME of the size SIZE for frame F, and return a
13083 pointer to the structure font_info while allocating it dynamically.
13084 If SIZE is 0, load any size of font.
13085 If loading is failed, return NULL. */
13086
13087struct font_info *
13088x_load_font (f, fontname, size)
13089 struct frame *f;
13090 register char *fontname;
13091 int size;
13092{
13093 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13094 Lisp_Object font_names;
d645aaa4 13095 int count;
dc43ef94
KH
13096
13097 /* Get a list of all the fonts that match this name. Once we
13098 have a list of matching fonts, we compare them against the fonts
13099 we already have by comparing names. */
09c6077f 13100 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
13101
13102 if (!NILP (font_names))
13103 {
13104 Lisp_Object tail;
13105 int i;
13106
13107 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 13108 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
13109 if (dpyinfo->font_table[i].name
13110 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 13111 XSTRING (XCAR (tail))->data)
06a2c219 13112 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 13113 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
13114 return (dpyinfo->font_table + i);
13115 }
13116
13117 /* Load the font and add it to the table. */
13118 {
13119 char *full_name;
13120 XFontStruct *font;
13121 struct font_info *fontp;
13122 unsigned long value;
06a2c219 13123 int i;
dc43ef94 13124
2da424f1
KH
13125 /* If we have found fonts by x_list_font, load one of them. If
13126 not, we still try to load a font by the name given as FONTNAME
13127 because XListFonts (called in x_list_font) of some X server has
13128 a bug of not finding a font even if the font surely exists and
13129 is loadable by XLoadQueryFont. */
e1d6d5b9 13130 if (size > 0 && !NILP (font_names))
8e713be6 13131 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
13132
13133 BLOCK_INPUT;
d645aaa4 13134 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 13135 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
13136 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
13137 {
13138 /* This error is perhaps due to insufficient memory on X
13139 server. Let's just ignore it. */
13140 font = NULL;
13141 x_clear_errors (FRAME_X_DISPLAY (f));
13142 }
13143 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 13144 UNBLOCK_INPUT;
b5210ea7 13145 if (!font)
dc43ef94
KH
13146 return NULL;
13147
06a2c219
GM
13148 /* Find a free slot in the font table. */
13149 for (i = 0; i < dpyinfo->n_fonts; ++i)
13150 if (dpyinfo->font_table[i].name == NULL)
13151 break;
13152
13153 /* If no free slot found, maybe enlarge the font table. */
13154 if (i == dpyinfo->n_fonts
13155 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 13156 {
06a2c219
GM
13157 int sz;
13158 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
13159 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 13160 dpyinfo->font_table
06a2c219 13161 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
13162 }
13163
06a2c219
GM
13164 fontp = dpyinfo->font_table + i;
13165 if (i == dpyinfo->n_fonts)
13166 ++dpyinfo->n_fonts;
dc43ef94
KH
13167
13168 /* Now fill in the slots of *FONTP. */
13169 BLOCK_INPUT;
13170 fontp->font = font;
06a2c219 13171 fontp->font_idx = i;
dc43ef94
KH
13172 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
13173 bcopy (fontname, fontp->name, strlen (fontname) + 1);
13174
13175 /* Try to get the full name of FONT. Put it in FULL_NAME. */
13176 full_name = 0;
13177 if (XGetFontProperty (font, XA_FONT, &value))
13178 {
13179 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
13180 char *p = name;
13181 int dashes = 0;
13182
13183 /* Count the number of dashes in the "full name".
13184 If it is too few, this isn't really the font's full name,
13185 so don't use it.
13186 In X11R4, the fonts did not come with their canonical names
13187 stored in them. */
13188 while (*p)
13189 {
13190 if (*p == '-')
13191 dashes++;
13192 p++;
13193 }
13194
13195 if (dashes >= 13)
13196 {
13197 full_name = (char *) xmalloc (p - name + 1);
13198 bcopy (name, full_name, p - name + 1);
13199 }
13200
13201 XFree (name);
13202 }
13203
13204 if (full_name != 0)
13205 fontp->full_name = full_name;
13206 else
13207 fontp->full_name = fontp->name;
13208
13209 fontp->size = font->max_bounds.width;
d5749adb
KH
13210 fontp->height = FONT_HEIGHT (font);
13211 {
13212 /* For some font, ascent and descent in max_bounds field is
13213 larger than the above value. */
13214 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
13215 if (max_height > fontp->height)
74848a96 13216 fontp->height = max_height;
d5749adb 13217 }
dc43ef94 13218
2da424f1
KH
13219 if (NILP (font_names))
13220 {
13221 /* We come here because of a bug of XListFonts mentioned at
13222 the head of this block. Let's store this information in
13223 the cache for x_list_fonts. */
13224 Lisp_Object lispy_name = build_string (fontname);
13225 Lisp_Object lispy_full_name = build_string (fontp->full_name);
13226
8e713be6 13227 XCDR (dpyinfo->name_list_element)
2da424f1
KH
13228 = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
13229 Fcons (Fcons (lispy_full_name,
13230 make_number (fontp->size)),
13231 Qnil)),
8e713be6 13232 XCDR (dpyinfo->name_list_element));
2da424f1 13233 if (full_name)
8e713be6 13234 XCDR (dpyinfo->name_list_element)
2da424f1
KH
13235 = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
13236 Fcons (Fcons (lispy_full_name,
13237 make_number (fontp->size)),
13238 Qnil)),
8e713be6 13239 XCDR (dpyinfo->name_list_element));
2da424f1
KH
13240 }
13241
dc43ef94
KH
13242 /* The slot `encoding' specifies how to map a character
13243 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
13244 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
13245 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 13246 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 13247 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
13248 which is never used by any charset. If mapping can't be
13249 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
13250 fontp->encoding[1]
13251 = (font->max_byte1 == 0
13252 /* 1-byte font */
13253 ? (font->min_char_or_byte2 < 0x80
13254 ? (font->max_char_or_byte2 < 0x80
13255 ? 0 /* 0x20..0x7F */
8ff102bd 13256 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
13257 : 1) /* 0xA0..0xFF */
13258 /* 2-byte font */
13259 : (font->min_byte1 < 0x80
13260 ? (font->max_byte1 < 0x80
13261 ? (font->min_char_or_byte2 < 0x80
13262 ? (font->max_char_or_byte2 < 0x80
13263 ? 0 /* 0x2020..0x7F7F */
8ff102bd 13264 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 13265 : 3) /* 0x20A0..0x7FFF */
8ff102bd 13266 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
13267 : (font->min_char_or_byte2 < 0x80
13268 ? (font->max_char_or_byte2 < 0x80
13269 ? 2 /* 0xA020..0xFF7F */
8ff102bd 13270 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
13271 : 1))); /* 0xA0A0..0xFFFF */
13272
13273 fontp->baseline_offset
13274 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
13275 ? (long) value : 0);
13276 fontp->relative_compose
13277 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
13278 ? (long) value : 0);
f78798df
KH
13279 fontp->default_ascent
13280 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
13281 ? (long) value : 0);
dc43ef94 13282
06a2c219
GM
13283 /* Set global flag fonts_changed_p to non-zero if the font loaded
13284 has a character with a smaller width than any other character
13285 before, or if the font loaded has a smalle>r height than any
13286 other font loaded before. If this happens, it will make a
13287 glyph matrix reallocation necessary. */
13288 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 13289 UNBLOCK_INPUT;
dc43ef94
KH
13290 return fontp;
13291 }
13292}
13293
06a2c219
GM
13294
13295/* Return a pointer to struct font_info of a font named FONTNAME for
13296 frame F. If no such font is loaded, return NULL. */
13297
dc43ef94
KH
13298struct font_info *
13299x_query_font (f, fontname)
13300 struct frame *f;
13301 register char *fontname;
13302{
13303 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13304 int i;
13305
13306 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
13307 if (dpyinfo->font_table[i].name
13308 && (!strcmp (dpyinfo->font_table[i].name, fontname)
13309 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
13310 return (dpyinfo->font_table + i);
13311 return NULL;
13312}
13313
06a2c219
GM
13314
13315/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
13316 `encoder' of the structure. */
13317
13318void
13319x_find_ccl_program (fontp)
13320 struct font_info *fontp;
13321{
a42f54e6 13322 Lisp_Object list, elt;
a6582676 13323
f9b5db02 13324 elt = Qnil;
8e713be6 13325 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 13326 {
8e713be6 13327 elt = XCAR (list);
a6582676 13328 if (CONSP (elt)
8e713be6 13329 && STRINGP (XCAR (elt))
9f2feff6
KH
13330 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
13331 >= 0)
13332 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
13333 >= 0)))
a42f54e6
KH
13334 break;
13335 }
f9b5db02 13336
a42f54e6
KH
13337 if (! NILP (list))
13338 {
d27f8ca7
KH
13339 struct ccl_program *ccl
13340 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 13341
8e713be6 13342 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
13343 xfree (ccl);
13344 else
13345 fontp->font_encoder = ccl;
a6582676
KH
13346 }
13347}
13348
06a2c219 13349
dc43ef94 13350\f
06a2c219
GM
13351/***********************************************************************
13352 Initialization
13353 ***********************************************************************/
f451eb13 13354
3afe33e7
RS
13355#ifdef USE_X_TOOLKIT
13356static XrmOptionDescRec emacs_options[] = {
13357 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
13358 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
13359
13360 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
13361 XrmoptionSepArg, NULL},
13362 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
13363
13364 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13365 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13366 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13367 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13368 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13369 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
13370 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
13371};
13372#endif /* USE_X_TOOLKIT */
13373
7a13e894
RS
13374static int x_initialized;
13375
29b38361
KH
13376#ifdef MULTI_KBOARD
13377/* Test whether two display-name strings agree up to the dot that separates
13378 the screen number from the server number. */
13379static int
13380same_x_server (name1, name2)
13381 char *name1, *name2;
13382{
13383 int seen_colon = 0;
cf591cc1
RS
13384 unsigned char *system_name = XSTRING (Vsystem_name)->data;
13385 int system_name_length = strlen (system_name);
13386 int length_until_period = 0;
13387
13388 while (system_name[length_until_period] != 0
13389 && system_name[length_until_period] != '.')
13390 length_until_period++;
13391
13392 /* Treat `unix' like an empty host name. */
13393 if (! strncmp (name1, "unix:", 5))
13394 name1 += 4;
13395 if (! strncmp (name2, "unix:", 5))
13396 name2 += 4;
13397 /* Treat this host's name like an empty host name. */
13398 if (! strncmp (name1, system_name, system_name_length)
13399 && name1[system_name_length] == ':')
13400 name1 += system_name_length;
13401 if (! strncmp (name2, system_name, system_name_length)
13402 && name2[system_name_length] == ':')
13403 name2 += system_name_length;
13404 /* Treat this host's domainless name like an empty host name. */
13405 if (! strncmp (name1, system_name, length_until_period)
13406 && name1[length_until_period] == ':')
13407 name1 += length_until_period;
13408 if (! strncmp (name2, system_name, length_until_period)
13409 && name2[length_until_period] == ':')
13410 name2 += length_until_period;
13411
29b38361
KH
13412 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
13413 {
13414 if (*name1 == ':')
13415 seen_colon++;
13416 if (seen_colon && *name1 == '.')
13417 return 1;
13418 }
13419 return (seen_colon
13420 && (*name1 == '.' || *name1 == '\0')
13421 && (*name2 == '.' || *name2 == '\0'));
13422}
13423#endif
13424
334208b7 13425struct x_display_info *
1f8255f2 13426x_term_init (display_name, xrm_option, resource_name)
334208b7 13427 Lisp_Object display_name;
1f8255f2
RS
13428 char *xrm_option;
13429 char *resource_name;
dc6f92b8 13430{
334208b7 13431 int connection;
7a13e894 13432 Display *dpy;
334208b7
RS
13433 struct x_display_info *dpyinfo;
13434 XrmDatabase xrdb;
13435
60439948
KH
13436 BLOCK_INPUT;
13437
7a13e894
RS
13438 if (!x_initialized)
13439 {
13440 x_initialize ();
13441 x_initialized = 1;
13442 }
dc6f92b8 13443
3afe33e7 13444#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
13445 /* weiner@footloose.sps.mot.com reports that this causes
13446 errors with X11R5:
13447 X protocol error: BadAtom (invalid Atom parameter)
13448 on protocol request 18skiloaf.
13449 So let's not use it until R6. */
13450#ifdef HAVE_X11XTR6
bdcd49ba
RS
13451 XtSetLanguageProc (NULL, NULL, NULL);
13452#endif
13453
7f9c7f94
RS
13454 {
13455 int argc = 0;
13456 char *argv[3];
13457
13458 argv[0] = "";
13459 argc = 1;
13460 if (xrm_option)
13461 {
13462 argv[argc++] = "-xrm";
13463 argv[argc++] = xrm_option;
13464 }
13465 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
13466 resource_name, EMACS_CLASS,
13467 emacs_options, XtNumber (emacs_options),
13468 &argc, argv);
39d8bb4d
KH
13469
13470#ifdef HAVE_X11XTR6
10537cb1 13471 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 13472 fixup_locale ();
39d8bb4d 13473#endif
7f9c7f94 13474 }
3afe33e7
RS
13475
13476#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
13477#ifdef HAVE_X11R5
13478 XSetLocaleModifiers ("");
13479#endif
7a13e894 13480 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 13481#endif /* not USE_X_TOOLKIT */
334208b7 13482
7a13e894
RS
13483 /* Detect failure. */
13484 if (dpy == 0)
60439948
KH
13485 {
13486 UNBLOCK_INPUT;
13487 return 0;
13488 }
7a13e894
RS
13489
13490 /* We have definitely succeeded. Record the new connection. */
13491
13492 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 13493 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 13494
29b38361
KH
13495#ifdef MULTI_KBOARD
13496 {
13497 struct x_display_info *share;
13498 Lisp_Object tail;
13499
13500 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
13501 share = share->next, tail = XCDR (tail))
13502 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
13503 XSTRING (display_name)->data))
13504 break;
13505 if (share)
13506 dpyinfo->kboard = share->kboard;
13507 else
13508 {
13509 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13510 init_kboard (dpyinfo->kboard);
59e755be
KH
13511 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
13512 {
13513 char *vendor = ServerVendor (dpy);
9b6ed9f3 13514 UNBLOCK_INPUT;
59e755be
KH
13515 dpyinfo->kboard->Vsystem_key_alist
13516 = call1 (Qvendor_specific_keysyms,
13517 build_string (vendor ? vendor : ""));
9b6ed9f3 13518 BLOCK_INPUT;
59e755be
KH
13519 }
13520
29b38361
KH
13521 dpyinfo->kboard->next_kboard = all_kboards;
13522 all_kboards = dpyinfo->kboard;
0ad5446c
KH
13523 /* Don't let the initial kboard remain current longer than necessary.
13524 That would cause problems if a file loaded on startup tries to
06a2c219 13525 prompt in the mini-buffer. */
0ad5446c
KH
13526 if (current_kboard == initial_kboard)
13527 current_kboard = dpyinfo->kboard;
29b38361
KH
13528 }
13529 dpyinfo->kboard->reference_count++;
13530 }
b9737ad3
KH
13531#endif
13532
7a13e894
RS
13533 /* Put this display on the chain. */
13534 dpyinfo->next = x_display_list;
13535 x_display_list = dpyinfo;
13536
13537 /* Put it on x_display_name_list as well, to keep them parallel. */
13538 x_display_name_list = Fcons (Fcons (display_name, Qnil),
13539 x_display_name_list);
8e713be6 13540 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
13541
13542 dpyinfo->display = dpy;
dc6f92b8 13543
dc6f92b8 13544#if 0
7a13e894 13545 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 13546#endif /* ! 0 */
7a13e894
RS
13547
13548 dpyinfo->x_id_name
fc932ac6
RS
13549 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
13550 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
13551 + 2);
13552 sprintf (dpyinfo->x_id_name, "%s@%s",
13553 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
13554
13555 /* Figure out which modifier bits mean what. */
334208b7 13556 x_find_modifier_meanings (dpyinfo);
f451eb13 13557
ab648270 13558 /* Get the scroll bar cursor. */
7a13e894 13559 dpyinfo->vertical_scroll_bar_cursor
334208b7 13560 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 13561
334208b7
RS
13562 xrdb = x_load_resources (dpyinfo->display, xrm_option,
13563 resource_name, EMACS_CLASS);
13564#ifdef HAVE_XRMSETDATABASE
13565 XrmSetDatabase (dpyinfo->display, xrdb);
13566#else
13567 dpyinfo->display->db = xrdb;
13568#endif
547d9db8 13569 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
13570 all versions. */
13571 dpyinfo->xrdb = xrdb;
334208b7
RS
13572
13573 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
13574 DefaultScreen (dpyinfo->display));
5ff67d81 13575 select_visual (dpyinfo);
43bd1b2b 13576 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
13577 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
13578 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
13579 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
13580 dpyinfo->grabbed = 0;
13581 dpyinfo->reference_count = 0;
13582 dpyinfo->icon_bitmap_id = -1;
06a2c219 13583 dpyinfo->font_table = NULL;
7a13e894
RS
13584 dpyinfo->n_fonts = 0;
13585 dpyinfo->font_table_size = 0;
13586 dpyinfo->bitmaps = 0;
13587 dpyinfo->bitmaps_size = 0;
13588 dpyinfo->bitmaps_last = 0;
13589 dpyinfo->scratch_cursor_gc = 0;
13590 dpyinfo->mouse_face_mouse_frame = 0;
13591 dpyinfo->mouse_face_deferred_gc = 0;
13592 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
13593 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 13594 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894
RS
13595 dpyinfo->mouse_face_window = Qnil;
13596 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
13597 dpyinfo->mouse_face_defer = 0;
0f941935
KH
13598 dpyinfo->x_focus_frame = 0;
13599 dpyinfo->x_focus_event_frame = 0;
13600 dpyinfo->x_highlight_frame = 0;
06a2c219 13601 dpyinfo->image_cache = make_image_cache ();
334208b7 13602
43bd1b2b 13603 /* See if a private colormap is requested. */
5ff67d81
GM
13604 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
13605 {
13606 if (dpyinfo->visual->class == PseudoColor)
13607 {
13608 Lisp_Object value;
13609 value = display_x_get_resource (dpyinfo,
13610 build_string ("privateColormap"),
13611 build_string ("PrivateColormap"),
13612 Qnil, Qnil);
13613 if (STRINGP (value)
13614 && (!strcmp (XSTRING (value)->data, "true")
13615 || !strcmp (XSTRING (value)->data, "on")))
13616 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
13617 }
43bd1b2b 13618 }
5ff67d81
GM
13619 else
13620 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
13621 dpyinfo->visual, AllocNone);
43bd1b2b 13622
06a2c219
GM
13623 {
13624 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
13625 double pixels = DisplayHeight (dpyinfo->display, screen_number);
13626 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
13627 dpyinfo->resy = pixels * 25.4 / mm;
13628 pixels = DisplayWidth (dpyinfo->display, screen_number);
13629 mm = DisplayWidthMM (dpyinfo->display, screen_number);
13630 dpyinfo->resx = pixels * 25.4 / mm;
13631 }
13632
334208b7
RS
13633 dpyinfo->Xatom_wm_protocols
13634 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
13635 dpyinfo->Xatom_wm_take_focus
13636 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
13637 dpyinfo->Xatom_wm_save_yourself
13638 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
13639 dpyinfo->Xatom_wm_delete_window
13640 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
13641 dpyinfo->Xatom_wm_change_state
13642 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
13643 dpyinfo->Xatom_wm_configure_denied
13644 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
13645 dpyinfo->Xatom_wm_window_moved
13646 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
13647 dpyinfo->Xatom_editres
13648 = XInternAtom (dpyinfo->display, "Editres", False);
13649 dpyinfo->Xatom_CLIPBOARD
13650 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
13651 dpyinfo->Xatom_TIMESTAMP
13652 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
13653 dpyinfo->Xatom_TEXT
13654 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
13655 dpyinfo->Xatom_COMPOUND_TEXT
13656 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
13657 dpyinfo->Xatom_DELETE
13658 = XInternAtom (dpyinfo->display, "DELETE", False);
13659 dpyinfo->Xatom_MULTIPLE
13660 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
13661 dpyinfo->Xatom_INCR
13662 = XInternAtom (dpyinfo->display, "INCR", False);
13663 dpyinfo->Xatom_EMACS_TMP
13664 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
13665 dpyinfo->Xatom_TARGETS
13666 = XInternAtom (dpyinfo->display, "TARGETS", False);
13667 dpyinfo->Xatom_NULL
13668 = XInternAtom (dpyinfo->display, "NULL", False);
13669 dpyinfo->Xatom_ATOM_PAIR
13670 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
13671 /* For properties of font. */
13672 dpyinfo->Xatom_PIXEL_SIZE
13673 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
13674 dpyinfo->Xatom_MULE_BASELINE_OFFSET
13675 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
13676 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
13677 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
13678 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
13679 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 13680
06a2c219
GM
13681 /* Ghostscript support. */
13682 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
13683 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
13684
13685 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
13686 False);
13687
547d9db8
KH
13688 dpyinfo->cut_buffers_initialized = 0;
13689
334208b7
RS
13690 connection = ConnectionNumber (dpyinfo->display);
13691 dpyinfo->connection = connection;
13692
dc43ef94 13693 {
5d7cc324
RS
13694 char null_bits[1];
13695
13696 null_bits[0] = 0x00;
dc43ef94
KH
13697
13698 dpyinfo->null_pixel
13699 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13700 null_bits, 1, 1, (long) 0, (long) 0,
13701 1);
13702 }
13703
06a2c219
GM
13704 {
13705 extern int gray_bitmap_width, gray_bitmap_height;
13706 extern unsigned char *gray_bitmap_bits;
13707 dpyinfo->gray
13708 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13709 gray_bitmap_bits,
13710 gray_bitmap_width, gray_bitmap_height,
13711 (unsigned long) 1, (unsigned long) 0, 1);
13712 }
13713
f5d11644
GM
13714#ifdef HAVE_X_I18N
13715 xim_initialize (dpyinfo, resource_name);
13716#endif
13717
87485d6f
MW
13718#ifdef subprocesses
13719 /* This is only needed for distinguishing keyboard and process input. */
334208b7 13720 if (connection != 0)
7a13e894 13721 add_keyboard_wait_descriptor (connection);
87485d6f 13722#endif
6d4238f3 13723
041b69ac 13724#ifndef F_SETOWN_BUG
dc6f92b8 13725#ifdef F_SETOWN
dc6f92b8 13726#ifdef F_SETOWN_SOCK_NEG
61c3ce62 13727 /* stdin is a socket here */
334208b7 13728 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 13729#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 13730 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
13731#endif /* ! defined (F_SETOWN_SOCK_NEG) */
13732#endif /* ! defined (F_SETOWN) */
041b69ac 13733#endif /* F_SETOWN_BUG */
dc6f92b8
JB
13734
13735#ifdef SIGIO
eee20f6a
KH
13736 if (interrupt_input)
13737 init_sigio (connection);
c118dd06 13738#endif /* ! defined (SIGIO) */
dc6f92b8 13739
51b592fb 13740#ifdef USE_LUCID
f8c39f51 13741#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
13742 /* Make sure that we have a valid font for dialog boxes
13743 so that Xt does not crash. */
13744 {
13745 Display *dpy = dpyinfo->display;
13746 XrmValue d, fr, to;
13747 Font font;
e99db5a1 13748 int count;
51b592fb
RS
13749
13750 d.addr = (XPointer)&dpy;
13751 d.size = sizeof (Display *);
13752 fr.addr = XtDefaultFont;
13753 fr.size = sizeof (XtDefaultFont);
13754 to.size = sizeof (Font *);
13755 to.addr = (XPointer)&font;
e99db5a1 13756 count = x_catch_errors (dpy);
51b592fb
RS
13757 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
13758 abort ();
13759 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
13760 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 13761 x_uncatch_errors (dpy, count);
51b592fb
RS
13762 }
13763#endif
f8c39f51 13764#endif
51b592fb 13765
34e23e5a
GM
13766 /* See if we should run in synchronous mode. This is useful
13767 for debugging X code. */
13768 {
13769 Lisp_Object value;
13770 value = display_x_get_resource (dpyinfo,
13771 build_string ("synchronous"),
13772 build_string ("Synchronous"),
13773 Qnil, Qnil);
13774 if (STRINGP (value)
13775 && (!strcmp (XSTRING (value)->data, "true")
13776 || !strcmp (XSTRING (value)->data, "on")))
13777 XSynchronize (dpyinfo->display, True);
13778 }
13779
60439948
KH
13780 UNBLOCK_INPUT;
13781
7a13e894
RS
13782 return dpyinfo;
13783}
13784\f
13785/* Get rid of display DPYINFO, assuming all frames are already gone,
13786 and without sending any more commands to the X server. */
dc6f92b8 13787
7a13e894
RS
13788void
13789x_delete_display (dpyinfo)
13790 struct x_display_info *dpyinfo;
13791{
13792 delete_keyboard_wait_descriptor (dpyinfo->connection);
13793
13794 /* Discard this display from x_display_name_list and x_display_list.
13795 We can't use Fdelq because that can quit. */
13796 if (! NILP (x_display_name_list)
8e713be6
KR
13797 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
13798 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
13799 else
13800 {
13801 Lisp_Object tail;
13802
13803 tail = x_display_name_list;
8e713be6 13804 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 13805 {
bffcfca9 13806 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 13807 {
8e713be6 13808 XCDR (tail) = XCDR (XCDR (tail));
7a13e894
RS
13809 break;
13810 }
8e713be6 13811 tail = XCDR (tail);
7a13e894
RS
13812 }
13813 }
13814
9bda743f
GM
13815 if (next_noop_dpyinfo == dpyinfo)
13816 next_noop_dpyinfo = dpyinfo->next;
13817
7a13e894
RS
13818 if (x_display_list == dpyinfo)
13819 x_display_list = dpyinfo->next;
7f9c7f94
RS
13820 else
13821 {
13822 struct x_display_info *tail;
7a13e894 13823
7f9c7f94
RS
13824 for (tail = x_display_list; tail; tail = tail->next)
13825 if (tail->next == dpyinfo)
13826 tail->next = tail->next->next;
13827 }
7a13e894 13828
0d777288
RS
13829#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
13830#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
13831 XrmDestroyDatabase (dpyinfo->xrdb);
13832#endif
0d777288 13833#endif
29b38361
KH
13834#ifdef MULTI_KBOARD
13835 if (--dpyinfo->kboard->reference_count == 0)
39f79001 13836 delete_kboard (dpyinfo->kboard);
b9737ad3 13837#endif
f5d11644
GM
13838#ifdef HAVE_X_I18N
13839 if (dpyinfo->xim)
13840 xim_close_dpy (dpyinfo);
13841#endif
13842
b9737ad3
KH
13843 xfree (dpyinfo->font_table);
13844 xfree (dpyinfo->x_id_name);
f04e1297 13845 xfree (dpyinfo->color_cells);
b9737ad3 13846 xfree (dpyinfo);
7a13e894 13847}
f04e1297 13848
7a13e894
RS
13849\f
13850/* Set up use of X before we make the first connection. */
13851
06a2c219
GM
13852static struct redisplay_interface x_redisplay_interface =
13853{
13854 x_produce_glyphs,
13855 x_write_glyphs,
13856 x_insert_glyphs,
13857 x_clear_end_of_line,
13858 x_scroll_run,
13859 x_after_update_window_line,
13860 x_update_window_begin,
13861 x_update_window_end,
13862 XTcursor_to,
13863 x_flush,
71b8321e 13864 x_clear_mouse_face,
66ac4b0e
GM
13865 x_get_glyph_overhangs,
13866 x_fix_overlapping_area
06a2c219
GM
13867};
13868
dfcf069d 13869void
7a13e894
RS
13870x_initialize ()
13871{
06a2c219
GM
13872 rif = &x_redisplay_interface;
13873
13874 clear_frame_hook = x_clear_frame;
13875 ins_del_lines_hook = x_ins_del_lines;
13876 change_line_highlight_hook = x_change_line_highlight;
13877 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
13878 ring_bell_hook = XTring_bell;
13879 reset_terminal_modes_hook = XTreset_terminal_modes;
13880 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
13881 update_begin_hook = x_update_begin;
13882 update_end_hook = x_update_end;
dc6f92b8
JB
13883 set_terminal_window_hook = XTset_terminal_window;
13884 read_socket_hook = XTread_socket;
b8009dd1 13885 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 13886 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 13887 mouse_position_hook = XTmouse_position;
f451eb13 13888 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 13889 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
13890 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13891 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13892 redeem_scroll_bar_hook = XTredeem_scroll_bar;
13893 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 13894 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 13895
f676886a 13896 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
13897 char_ins_del_ok = 0; /* just as fast to write the line */
13898 line_ins_del_ok = 1; /* we'll just blt 'em */
13899 fast_clear_end_of_line = 1; /* X does this well */
58769bee 13900 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
13901 off the bottom */
13902 baud_rate = 19200;
13903
7a13e894 13904 x_noop_count = 0;
9ea173e8 13905 last_tool_bar_item = -1;
06a2c219
GM
13906 any_help_event_p = 0;
13907
b30b24cb
RS
13908 /* Try to use interrupt input; if we can't, then start polling. */
13909 Fset_input_mode (Qt, Qnil, Qt, Qnil);
13910
7f9c7f94
RS
13911#ifdef USE_X_TOOLKIT
13912 XtToolkitInitialize ();
13913 Xt_app_con = XtCreateApplicationContext ();
665881ad 13914 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
13915
13916 /* Install an asynchronous timer that processes Xt timeout events
13917 every 0.1s. This is necessary because some widget sets use
13918 timeouts internally, for example the LessTif menu bar, or the
13919 Xaw3d scroll bar. When Xt timouts aren't processed, these
13920 widgets don't behave normally. */
13921 {
13922 EMACS_TIME interval;
13923 EMACS_SET_SECS_USECS (interval, 0, 100000);
13924 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
13925 }
db74249b 13926#endif
bffcfca9 13927
eccc05db 13928#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
13929 xaw3d_arrow_scroll = False;
13930 xaw3d_pick_top = True;
7f9c7f94
RS
13931#endif
13932
58769bee 13933 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 13934 original error handler. */
e99db5a1 13935 XSetErrorHandler (x_error_handler);
334208b7 13936 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 13937
06a2c219 13938 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
13939#ifdef SIGWINCH
13940 signal (SIGWINCH, SIG_DFL);
c118dd06 13941#endif /* ! defined (SIGWINCH) */
dc6f92b8 13942
92e2441b 13943 signal (SIGPIPE, x_connection_signal);
dc6f92b8 13944}
55123275 13945
06a2c219 13946
55123275
JB
13947void
13948syms_of_xterm ()
13949{
e99db5a1
RS
13950 staticpro (&x_error_message_string);
13951 x_error_message_string = Qnil;
13952
7a13e894
RS
13953 staticpro (&x_display_name_list);
13954 x_display_name_list = Qnil;
334208b7 13955
ab648270 13956 staticpro (&last_mouse_scroll_bar);
e53cb100 13957 last_mouse_scroll_bar = Qnil;
59e755be
KH
13958
13959 staticpro (&Qvendor_specific_keysyms);
13960 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
13961
13962 staticpro (&last_mouse_press_frame);
13963 last_mouse_press_frame = Qnil;
06a2c219 13964
06a2c219 13965 help_echo = Qnil;
be010514
GM
13966 staticpro (&help_echo);
13967 help_echo_object = Qnil;
13968 staticpro (&help_echo_object);
7cea38bc
GM
13969 help_echo_window = Qnil;
13970 staticpro (&help_echo_window);
06a2c219 13971 previous_help_echo = Qnil;
be010514
GM
13972 staticpro (&previous_help_echo);
13973 help_echo_pos = -1;
06a2c219
GM
13974
13975 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
13976 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
13977For example, if a block cursor is over a tab, it will be drawn as\n\
13978wide as that tab on the display.");
13979 x_stretch_cursor_p = 0;
13980
13981 DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
13982 "If not nil, Emacs uses toolkit scroll bars.");
eccc05db 13983#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
13984 x_toolkit_scroll_bars_p = 1;
13985#else
13986 x_toolkit_scroll_bars_p = 0;
13987#endif
13988
06a2c219
GM
13989 staticpro (&last_mouse_motion_frame);
13990 last_mouse_motion_frame = Qnil;
55123275 13991}
6cf0ae86
RS
13992
13993#endif /* not HAVE_X_WINDOWS */