(x_set_background_color): Remove unused variable(s).
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
06a2c219
GM
2 Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999
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
039440c4
RS
25/* On 4.3 these lose if they come after xterm.h. */
26/* On HP-UX 8.0 signal.h loses if it comes after config.h. */
27/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
28#include <signal.h>
29
18160b98 30#include <config.h>
dc6f92b8 31
4846819e 32#include <stdio.h>
06a2c219
GM
33#ifdef STDC_HEADERS
34#include <stdlib.h>
35#endif
4846819e 36
dc6f92b8
JB
37#ifdef HAVE_X_WINDOWS
38
39#include "lisp.h"
9ac0d9e0 40#include "blockinput.h"
dc6f92b8 41
ae79c227
AS
42/* Need syssignal.h for various externs and definitions that may be required
43 by some configurations for calls to signal later in this source file. */
44#include "syssignal.h"
45
dc6f92b8
JB
46/* This may include sys/types.h, and that somehow loses
47 if this is not done before the other system files. */
48#include "xterm.h"
f451eb13 49#include <X11/cursorfont.h>
dc6f92b8 50
16bd92ea 51#ifndef USG
dc6f92b8
JB
52/* Load sys/types.h if not already loaded.
53 In some systems loading it twice is suicidal. */
54#ifndef makedev
55#include <sys/types.h>
c118dd06
JB
56#endif /* makedev */
57#endif /* USG */
dc6f92b8 58
6df54671 59#ifdef BSD_SYSTEM
dc6f92b8 60#include <sys/ioctl.h>
6df54671 61#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 62
2d368234 63#include "systty.h"
3a2712f9 64#include "systime.h"
dc6f92b8 65
b8009dd1 66#ifndef INCLUDED_FCNTL
dc6f92b8 67#include <fcntl.h>
b8009dd1 68#endif
dc6f92b8
JB
69#include <ctype.h>
70#include <errno.h>
71#include <setjmp.h>
72#include <sys/stat.h>
a0a7635f
RS
73/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
74/* #include <sys/param.h> */
dc6f92b8 75
dc43ef94
KH
76#include "charset.h"
77#include "ccl.h"
7a13e894 78#include "frame.h"
a1dfb88a 79#include "fontset.h"
dc6f92b8
JB
80#include "dispextern.h"
81#include "termhooks.h"
82#include "termopts.h"
83#include "termchar.h"
84#if 0
85#include "sink.h"
86#include "sinkmask.h"
c118dd06 87#endif /* ! 0 */
dc6f92b8 88#include "gnu.h"
dc6f92b8 89#include "disptab.h"
dc6f92b8 90#include "buffer.h"
f451eb13 91#include "window.h"
3b2fa4e6 92#include "keyboard.h"
bde7c500 93#include "intervals.h"
dfcf069d 94#include "process.h"
dc6f92b8 95
d2bd6bc4
RS
96#ifdef USE_X_TOOLKIT
97#include <X11/Shell.h>
98#endif
99
06a2c219
GM
100#include <sys/types.h>
101#ifdef HAVE_SYS_TIME_H
102#include <sys/time.h>
103#endif
104#ifdef HAVE_UNISTD_H
105#include <unistd.h>
106#endif
107
3afe33e7 108#ifdef USE_X_TOOLKIT
06a2c219 109
9d7e2e3e 110extern void free_frame_menubar ();
2224b905 111extern FRAME_PTR x_menubar_window_to_frame ();
06a2c219 112
0fdff6bb
RS
113#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
114#define HACK_EDITRES
115extern void _XEditResCheckMessages ();
116#endif /* not NO_EDITRES */
06a2c219
GM
117
118/* Include toolkit specific headers for the scroll bar widget. */
119
120#ifdef USE_TOOLKIT_SCROLL_BARS
121#if defined USE_MOTIF
122#include <Xm/Xm.h> /* for LESSTIF_VERSION */
123#include <Xm/ScrollBar.h>
124#include <Xm/ScrollBarP.h>
125#elif defined HAVE_XAW3D
126#include <X11/Xaw3d/Simple.h>
127#include <X11/Xaw3d/ThreeD.h>
128#include <X11/Xaw3d/Scrollbar.h>
129#define ARROW_SCROLLBAR
130#include <X11/Xaw3d/ScrollbarP.h>
131#endif /* HAVE_XAW3D */
132#endif /* USE_TOOLKIT_SCROLL_BARS */
133
3afe33e7
RS
134#endif /* USE_X_TOOLKIT */
135
b849c413
RS
136#ifndef USE_X_TOOLKIT
137#define x_any_window_to_frame x_window_to_frame
5627c40e 138#define x_top_window_to_frame x_window_to_frame
b849c413
RS
139#endif
140
546e6d5b 141#ifdef USE_X_TOOLKIT
d067ea8b 142#include "widget.h"
546e6d5b
RS
143#ifndef XtNinitialState
144#define XtNinitialState "initialState"
145#endif
146#endif
147
10537cb1 148#ifdef HAVE_SETLOCALE
39d8bb4d
KH
149/* So we can do setlocale. */
150#include <locale.h>
151#endif
152
80528801
KH
153#ifdef SOLARIS2
154/* memmove will be defined as a macro in Xfuncs.h unless
155 <string.h> is included beforehand. The declaration for memmove in
156 <string.h> will cause a syntax error when Xfuncs.h later includes it. */
157#include <string.h>
158#endif
159
e4b68333 160#ifndef min
06a2c219 161#define min(a,b) ((a) < (b) ? (a) : (b))
e4b68333
RS
162#endif
163#ifndef max
06a2c219
GM
164#define max(a,b) ((a) > (b) ? (a) : (b))
165#endif
166
167#define abs(x) ((x) < 0 ? -(x) : (x))
168
169#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
170
171\f
172/* Bitmaps for truncated lines. */
173
174enum bitmap_type
175{
176 NO_BITMAP,
177 LEFT_TRUNCATION_BITMAP,
178 RIGHT_TRUNCATION_BITMAP,
179 OVERLAY_ARROW_BITMAP,
180 CONTINUED_LINE_BITMAP,
181 CONTINUATION_LINE_BITMAP,
182 ZV_LINE_BITMAP
183};
184
185/* Bitmap drawn to indicate lines not displaying text if
186 `indicate-empty-lines' is non-nil. */
187
188#define zv_width 8
189#define zv_height 8
190static unsigned char zv_bits[] = {
191 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
192
193/* An arrow like this: `<-'. */
194
195#define left_width 8
196#define left_height 8
197static unsigned char left_bits[] = {
198 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
199
110859fc
GM
200/* Right truncation arrow bitmap `->'. */
201
202#define right_width 8
203#define right_height 8
204static unsigned char right_bits[] = {
205 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
206
06a2c219
GM
207/* Marker for continued lines. */
208
209#define continued_width 8
210#define continued_height 8
211static unsigned char continued_bits[] = {
110859fc
GM
212 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
213
214/* Marker for continuation lines. */
06a2c219
GM
215
216#define continuation_width 8
217#define continuation_height 8
218static unsigned char continuation_bits[] = {
110859fc 219 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 220
110859fc 221/* Overlay arrow bitmap. */
06a2c219 222
110859fc
GM
223#if 0
224/* A bomb. */
06a2c219
GM
225#define ov_width 8
226#define ov_height 8
227static unsigned char ov_bits[] = {
228 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 229#else
110859fc 230/* A triangular arrow. */
06a2c219
GM
231#define ov_width 8
232#define ov_height 8
233static unsigned char ov_bits[] = {
110859fc
GM
234 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
235
e4b68333 236#endif
06a2c219
GM
237
238extern Lisp_Object Qhelp_echo;
239
69388238 240\f
06a2c219
GM
241/* Non-zero means Emacs uses toolkit scroll bars. */
242
243int x_toolkit_scroll_bars_p;
244
245/* If a string, XTread_socket generates an event to display that string.
246 (The display is done in read_char.) */
247
248static Lisp_Object help_echo;
249
250/* Temporary variable for XTread_socket. */
251
252static Lisp_Object previous_help_echo;
253
254/* Non-zero means that a HELP_EVENT has been generated since Emacs
255 start. */
256
257static int any_help_event_p;
258
259/* Non-zero means draw block and hollow cursor as wide as the glyph
260 under it. For example, if a block cursor is over a tab, it will be
261 drawn as wide as that tab on the display. */
262
263int x_stretch_cursor_p;
264
265/* This is a chain of structures for all the X displays currently in
266 use. */
267
334208b7 268struct x_display_info *x_display_list;
dc6f92b8 269
06a2c219
GM
270/* This is a list of cons cells, each of the form (NAME
271 . FONT-LIST-CACHE), one for each element of x_display_list and in
272 the same order. NAME is the name of the frame. FONT-LIST-CACHE
273 records previous values returned by x-list-fonts. */
274
7a13e894 275Lisp_Object x_display_name_list;
f451eb13 276
987d2ad1 277/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
278 This is set by update_begin and looked at by all the XT functions.
279 It is zero while not inside an update. In that case, the XT
280 functions assume that `selected_frame' is the frame to apply to. */
281
d0386f2a 282extern struct frame *updating_frame;
dc6f92b8 283
dfcf069d 284extern int waiting_for_input;
0e81d8cd 285
06a2c219
GM
286/* This is a frame waiting to be auto-raised, within XTread_socket. */
287
0134a210
RS
288struct frame *pending_autoraise_frame;
289
7f9c7f94
RS
290#ifdef USE_X_TOOLKIT
291/* The application context for Xt use. */
292XtAppContext Xt_app_con;
06a2c219
GM
293static String Xt_default_resources[] = {0};
294#endif /* USE_X_TOOLKIT */
665881ad 295
06a2c219
GM
296/* Nominal cursor position -- where to draw output.
297 HPOS and VPOS are window relative glyph matrix coordinates.
298 X and Y are window relative pixel coordinates. */
dc6f92b8 299
06a2c219 300struct cursor_pos output_cursor;
dc6f92b8 301
dc6f92b8 302
69388238
RS
303/* Mouse movement.
304
06a2c219 305 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
306 so that we would have to call XQueryPointer after each MotionNotify
307 event to ask for another such event. However, this made mouse tracking
308 slow, and there was a bug that made it eventually stop.
309
310 Simply asking for MotionNotify all the time seems to work better.
311
69388238
RS
312 In order to avoid asking for motion events and then throwing most
313 of them away or busy-polling the server for mouse positions, we ask
314 the server for pointer motion hints. This means that we get only
315 one event per group of mouse movements. "Groups" are delimited by
316 other kinds of events (focus changes and button clicks, for
317 example), or by XQueryPointer calls; when one of these happens, we
318 get another MotionNotify event the next time the mouse moves. This
319 is at least as efficient as getting motion events when mouse
320 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 321 is off. */
69388238
RS
322
323/* Where the mouse was last time we reported a mouse event. */
69388238 324
06a2c219
GM
325FRAME_PTR last_mouse_frame;
326static XRectangle last_mouse_glyph;
2237cac9
RS
327static Lisp_Object last_mouse_press_frame;
328
69388238
RS
329/* The scroll bar in which the last X motion event occurred.
330
06a2c219
GM
331 If the last X motion event occurred in a scroll bar, we set this so
332 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
333 an ordinary motion.
334
06a2c219
GM
335 If the last X motion event didn't occur in a scroll bar, we set
336 this to Qnil, to tell XTmouse_position to return an ordinary motion
337 event. */
338
69388238
RS
339static Lisp_Object last_mouse_scroll_bar;
340
69388238
RS
341/* This is a hack. We would really prefer that XTmouse_position would
342 return the time associated with the position it returns, but there
06a2c219 343 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
344 along with the position query. So, we just keep track of the time
345 of the last movement we received, and return that in hopes that
346 it's somewhat accurate. */
06a2c219 347
69388238
RS
348static Time last_mouse_movement_time;
349
06a2c219
GM
350/* Incremented by XTread_socket whenever it really tries to read
351 events. */
352
c0a04927
RS
353#ifdef __STDC__
354static int volatile input_signal_count;
355#else
356static int input_signal_count;
357#endif
358
7a13e894 359/* Used locally within XTread_socket. */
06a2c219 360
7a13e894 361static int x_noop_count;
dc6f92b8 362
7a13e894 363/* Initial values of argv and argc. */
06a2c219 364
7a13e894
RS
365extern char **initial_argv;
366extern int initial_argc;
dc6f92b8 367
7a13e894 368extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 369
06a2c219 370/* Tells if a window manager is present or not. */
7a13e894
RS
371
372extern Lisp_Object Vx_no_window_manager;
dc6f92b8 373
c2df547c 374extern Lisp_Object Qface, Qmouse_face;
b8009dd1 375
dc6f92b8
JB
376extern int errno;
377
dfeccd2d 378/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 379
64bb1782
RS
380extern int extra_keyboard_modifiers;
381
59e755be
KH
382static Lisp_Object Qvendor_specific_keysyms;
383
334208b7 384extern XrmDatabase x_load_resources ();
c32cdd9a
KH
385extern Lisp_Object x_icon_type ();
386
7a13e894 387
06a2c219
GM
388/* Enumeration for overriding/changing the face to use for drawing
389 glyphs in x_draw_glyphs. */
390
391enum draw_glyphs_face
392{
393 DRAW_NORMAL_TEXT,
394 DRAW_INVERSE_VIDEO,
395 DRAW_CURSOR,
396 DRAW_MOUSE_FACE,
397 DRAW_IMAGE_RAISED,
398 DRAW_IMAGE_SUNKEN
399};
400
401static void x_update_window_end P_ ((struct window *, int));
402static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
403void x_delete_display P_ ((struct x_display_info *));
404static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
405 unsigned));
406static int fast_find_position P_ ((struct window *, int, int *, int *,
407 int *, int *));
408static void set_output_cursor P_ ((struct cursor_pos *));
409static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
410 int *, int *, int *));
411static void note_mode_line_highlight P_ ((struct window *, int, int));
412static void x_check_font P_ ((struct frame *, XFontStruct *));
413static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
414static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
415static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
416static void show_mouse_face P_ ((struct x_display_info *,
417 enum draw_glyphs_face));
418static int x_io_error_quitter P_ ((Display *));
419int x_catch_errors P_ ((Display *));
420void x_uncatch_errors P_ ((Display *, int));
421void x_lower_frame P_ ((struct frame *));
422void x_scroll_bar_clear P_ ((struct frame *));
423int x_had_errors_p P_ ((Display *));
424void x_wm_set_size_hint P_ ((struct frame *, long, int));
425void x_raise_frame P_ ((struct frame *));
426void x_set_window_size P_ ((struct frame *, int, int, int));
427void x_wm_set_window_state P_ ((struct frame *, int));
428void x_wm_set_icon_pixmap P_ ((struct frame *, int));
429void x_initialize P_ ((void));
430static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
431static int x_compute_min_glyph_bounds P_ ((struct frame *));
432static void x_draw_phys_cursor_glyph P_ ((struct window *,
433 struct glyph_row *,
434 enum draw_glyphs_face));
435static void x_update_end P_ ((struct frame *));
436static void XTframe_up_to_date P_ ((struct frame *));
437static void XTreassert_line_highlight P_ ((int, int));
438static void x_change_line_highlight P_ ((int, int, int, int));
439static void XTset_terminal_modes P_ ((void));
440static void XTreset_terminal_modes P_ ((void));
441static void XTcursor_to P_ ((int, int, int, int));
442static void x_write_glyphs P_ ((struct glyph *, int));
443static void x_clear_end_of_line P_ ((int));
444static void x_clear_frame P_ ((void));
445static void x_clear_cursor P_ ((struct window *));
446static void frame_highlight P_ ((struct frame *));
447static void frame_unhighlight P_ ((struct frame *));
448static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
449static void XTframe_rehighlight P_ ((struct frame *));
450static void x_frame_rehighlight P_ ((struct x_display_info *));
451static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
452static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *));
453static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
454 XRectangle *));
455static void expose_frame P_ ((struct frame *, int, int, int, int));
456static void expose_window_tree P_ ((struct window *, XRectangle *));
457static void expose_window P_ ((struct window *, XRectangle *));
458static void expose_area P_ ((struct window *, struct glyph_row *,
459 XRectangle *, enum glyph_row_area));
460static void expose_line P_ ((struct window *, struct glyph_row *,
461 XRectangle *));
462static void x_update_cursor_in_window_tree P_ ((struct window *, int));
463static void x_update_window_cursor P_ ((struct window *, int));
464static void x_erase_phys_cursor P_ ((struct window *));
465void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
466static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
467 enum bitmap_type));
468
469static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
470 GC, int));
471static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
472static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
473static void note_overwritten_text_cursor P_ ((struct window *, int, int));
474static void x_flush P_ ((struct frame *f));
475
476
477/* Flush display of frame F, or of all frames if F is null. */
478
479static void
480x_flush (f)
481 struct frame *f;
482{
483 BLOCK_INPUT;
484 if (f == NULL)
485 {
486 Lisp_Object rest, frame;
487 FOR_EACH_FRAME (rest, frame)
488 x_flush (XFRAME (frame));
489 }
490 else if (FRAME_X_P (f))
491 XFlush (FRAME_X_DISPLAY (f));
492 UNBLOCK_INPUT;
493}
494
dc6f92b8 495
06a2c219
GM
496/* Remove calls to XFlush by defining XFlush to an empty replacement.
497 Calls to XFlush should be unnecessary because the X output buffer
498 is flushed automatically as needed by calls to XPending,
499 XNextEvent, or XWindowEvent according to the XFlush man page.
500 XTread_socket calls XPending. Removing XFlush improves
501 performance. */
502
503#define XFlush(DISPLAY) (void) 0
b8009dd1 504
334208b7 505\f
06a2c219
GM
506/***********************************************************************
507 Debugging
508 ***********************************************************************/
509
9382638d 510#if 0
06a2c219
GM
511
512/* This is a function useful for recording debugging information about
513 the sequence of occurrences in this file. */
9382638d
KH
514
515struct record
516{
517 char *locus;
518 int type;
519};
520
521struct record event_record[100];
522
523int event_record_index;
524
525record_event (locus, type)
526 char *locus;
527 int type;
528{
529 if (event_record_index == sizeof (event_record) / sizeof (struct record))
530 event_record_index = 0;
531
532 event_record[event_record_index].locus = locus;
533 event_record[event_record_index].type = type;
534 event_record_index++;
535}
536
537#endif /* 0 */
06a2c219
GM
538
539
9382638d 540\f
334208b7
RS
541/* Return the struct x_display_info corresponding to DPY. */
542
543struct x_display_info *
544x_display_info_for_display (dpy)
545 Display *dpy;
546{
547 struct x_display_info *dpyinfo;
548
549 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
550 if (dpyinfo->display == dpy)
551 return dpyinfo;
16bd92ea 552
334208b7
RS
553 return 0;
554}
f451eb13 555
06a2c219
GM
556
557\f
558/***********************************************************************
559 Starting and ending an update
560 ***********************************************************************/
561
562/* Start an update of frame F. This function is installed as a hook
563 for update_begin, i.e. it is called when update_begin is called.
564 This function is called prior to calls to x_update_window_begin for
565 each window being updated. Currently, there is nothing to do here
566 because all interesting stuff is done on a window basis. */
dc6f92b8 567
dfcf069d 568static void
06a2c219 569x_update_begin (f)
f676886a 570 struct frame *f;
58769bee 571{
06a2c219
GM
572 /* Nothing to do. */
573}
dc6f92b8 574
dc6f92b8 575
06a2c219
GM
576/* Start update of window W. Set the global variable updated_window
577 to the window being updated and set output_cursor to the cursor
578 position of W. */
dc6f92b8 579
06a2c219
GM
580static void
581x_update_window_begin (w)
582 struct window *w;
583{
584 struct frame *f = XFRAME (WINDOW_FRAME (w));
585 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
586
587 updated_window = w;
588 set_output_cursor (&w->cursor);
b8009dd1 589
06a2c219 590 BLOCK_INPUT;
d1bc4182 591
06a2c219 592 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 593 {
514e4681 594 /* Don't do highlighting for mouse motion during the update. */
06a2c219 595 display_info->mouse_face_defer = 1;
37c2c98b 596
06a2c219
GM
597 /* If F needs to be redrawn, simply forget about any prior mouse
598 highlighting. */
9f67f20b 599 if (FRAME_GARBAGED_P (f))
06a2c219
GM
600 display_info->mouse_face_window = Qnil;
601
602 /* Can we tell that this update does not affect the window
603 where the mouse highlight is? If so, no need to turn off.
604 Likewise, don't do anything if the frame is garbaged;
605 in that case, the frame's current matrix that we would use
606 is all wrong, and we will redisplay that line anyway. */
607 if (!NILP (display_info->mouse_face_window)
608 && w == XWINDOW (display_info->mouse_face_window))
514e4681 609 {
06a2c219 610 int i;
514e4681 611
06a2c219
GM
612 for (i = 0; i < w->desired_matrix->nrows; ++i)
613 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
614 break;
615
06a2c219
GM
616 if (i < w->desired_matrix->nrows)
617 clear_mouse_face (display_info);
514e4681 618 }
b8009dd1 619 }
6ccf47d1 620
dc6f92b8
JB
621 UNBLOCK_INPUT;
622}
623
06a2c219
GM
624
625/* Draw a vertical window border to the right of window W if W doesn't
626 have vertical scroll bars. */
627
dfcf069d 628static void
06a2c219
GM
629x_draw_vertical_border (w)
630 struct window *w;
58769bee 631{
06a2c219
GM
632 struct frame *f = XFRAME (WINDOW_FRAME (w));
633
634 /* Redraw borders between horizontally adjacent windows. Don't
635 do it for frames with vertical scroll bars because either the
636 right scroll bar of a window, or the left scroll bar of its
637 neighbor will suffice as a border. */
638 if (!WINDOW_RIGHTMOST_P (w)
639 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
640 {
641 int x0, x1, y0, y1;
dc6f92b8 642
06a2c219 643 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 644 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
645 y1 -= 1;
646
647 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
648 f->output_data.x->normal_gc, x1, y0, x1, y1);
649 }
650}
651
652
653/* End update of window W (which is equal to updated_window). Draw
654 vertical borders between horizontally adjacent windows, and display
655 W's cursor if CURSOR_ON_P is non-zero. W may be a menu bar
656 pseudo-window in case we don't have X toolkit support. Such
657 windows don't have a cursor, so don't display it here. */
658
659static void
660x_update_window_end (w, cursor_on_p)
661 struct window *w;
662 int cursor_on_p;
663{
664 if (!w->pseudo_window_p)
665 {
666 BLOCK_INPUT;
667 if (cursor_on_p)
668 x_display_and_set_cursor (w, 1, output_cursor.hpos,
669 output_cursor.vpos,
670 output_cursor.x, output_cursor.y);
671 x_draw_vertical_border (w);
672 UNBLOCK_INPUT;
673 }
674
675 updated_window = NULL;
676}
dc6f92b8 677
dc6f92b8 678
06a2c219
GM
679/* End update of frame F. This function is installed as a hook in
680 update_end. */
681
682static void
683x_update_end (f)
684 struct frame *f;
685{
686 /* Mouse highlight may be displayed again. */
aa8bff2e 687 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 688
06a2c219 689 BLOCK_INPUT;
334208b7 690 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
691 UNBLOCK_INPUT;
692}
b8009dd1 693
06a2c219
GM
694
695/* This function is called from various places in xdisp.c whenever a
696 complete update has been performed. The global variable
697 updated_window is not available here. */
b8009dd1 698
dfcf069d 699static void
b8009dd1 700XTframe_up_to_date (f)
06a2c219 701 struct frame *f;
b8009dd1 702{
06a2c219 703 if (FRAME_X_P (f))
514e4681 704 {
06a2c219
GM
705 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
706 if (dpyinfo->mouse_face_deferred_gc
707 || f == dpyinfo->mouse_face_mouse_frame)
708 {
709 BLOCK_INPUT;
710 if (dpyinfo->mouse_face_mouse_frame)
711 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
712 dpyinfo->mouse_face_mouse_x,
713 dpyinfo->mouse_face_mouse_y);
714 dpyinfo->mouse_face_deferred_gc = 0;
715 UNBLOCK_INPUT;
716 }
514e4681 717 }
b8009dd1 718}
06a2c219
GM
719
720
721/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
722 arrow bitmaps, or clear the areas where they would be displayed
723 before DESIRED_ROW is made current. The window being updated is
724 found in updated_window. This function It is called from
725 update_window_line only if it is known that there are differences
726 between bitmaps to be drawn between current row and DESIRED_ROW. */
727
728static void
729x_after_update_window_line (desired_row)
730 struct glyph_row *desired_row;
731{
732 struct window *w = updated_window;
733
734 xassert (w);
735
736 if (!desired_row->mode_line_p && !w->pseudo_window_p)
737 {
738 BLOCK_INPUT;
739 x_draw_row_bitmaps (w, desired_row);
740
741 /* When a window has disappeared, make sure that no rest of
742 full-width rows stays visible in the internal border. */
743 if (windows_or_buffers_changed)
744 {
745 struct frame *f = XFRAME (w->frame);
746 int width = FRAME_INTERNAL_BORDER_WIDTH (f);
747 int height = desired_row->visible_height;
110859fc
GM
748 int x = (window_box_right (w, -1)
749 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
750 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
751
752 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
753 x, y, width, height, False);
754 }
755
756 UNBLOCK_INPUT;
757 }
758}
759
760
761/* Draw the bitmap WHICH in one of the areas to the left or right of
762 window W. ROW is the glyph row for which to display the bitmap; it
763 determines the vertical position at which the bitmap has to be
764 drawn. */
765
766static void
767x_draw_bitmap (w, row, which)
768 struct window *w;
769 struct glyph_row *row;
770 enum bitmap_type which;
771{
772 struct frame *f = XFRAME (WINDOW_FRAME (w));
773 Display *display = FRAME_X_DISPLAY (f);
774 Window window = FRAME_X_WINDOW (f);
775 int x, y, wd, h, dy;
776 unsigned char *bits;
777 Pixmap pixmap;
778 GC gc = f->output_data.x->normal_gc;
779 struct face *face;
780 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
781
782 /* Must clip because of partially visible lines. */
783 x_clip_to_row (w, row, gc, 1);
784
785 switch (which)
786 {
787 case LEFT_TRUNCATION_BITMAP:
788 wd = left_width;
789 h = left_height;
790 bits = left_bits;
791 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
792 - wd
110859fc 793 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
794 break;
795
796 case OVERLAY_ARROW_BITMAP:
797 wd = left_width;
798 h = left_height;
799 bits = ov_bits;
800 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
801 - wd
110859fc 802 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
803 break;
804
805 case RIGHT_TRUNCATION_BITMAP:
806 wd = right_width;
807 h = right_height;
808 bits = right_bits;
809 x = window_box_right (w, -1);
110859fc 810 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
811 break;
812
813 case CONTINUED_LINE_BITMAP:
814 wd = right_width;
815 h = right_height;
816 bits = continued_bits;
817 x = window_box_right (w, -1);
110859fc 818 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
819 break;
820
821 case CONTINUATION_LINE_BITMAP:
822 wd = continuation_width;
823 h = continuation_height;
824 bits = continuation_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 ZV_LINE_BITMAP:
831 wd = zv_width;
832 h = zv_height;
833 bits = zv_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 default:
840 abort ();
841 }
842
843 /* Convert to frame coordinates. Set dy to the offset in the row to
844 start drawing the bitmap. */
845 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
846 dy = (row->height - h) / 2;
847
848 /* Draw the bitmap. I believe these small pixmaps can be cached
849 by the server. */
850 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
851 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
852 face->foreground,
853 face->background, depth);
854 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
855 XFreePixmap (display, pixmap);
856 XSetClipMask (display, gc, None);
857}
858
859
860/* Draw flags bitmaps for glyph row ROW on window W. Call this
861 function with input blocked. */
862
863static void
864x_draw_row_bitmaps (w, row)
865 struct window *w;
866 struct glyph_row *row;
867{
868 struct frame *f = XFRAME (w->frame);
869 enum bitmap_type bitmap;
870 struct face *face;
045dee35 871 int header_line_height = -1;
06a2c219
GM
872
873 xassert (interrupt_input_blocked);
874
875 /* If row is completely invisible, because of vscrolling, we
876 don't have to draw anything. */
877 if (row->visible_height <= 0)
878 return;
879
880 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
881 PREPARE_FACE_FOR_DISPLAY (f, face);
882
883 /* Decide which bitmap to draw at the left side. */
884 if (row->overlay_arrow_p)
885 bitmap = OVERLAY_ARROW_BITMAP;
886 else if (row->truncated_on_left_p)
887 bitmap = LEFT_TRUNCATION_BITMAP;
888 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
889 bitmap = CONTINUATION_LINE_BITMAP;
890 else if (row->indicate_empty_line_p)
891 bitmap = ZV_LINE_BITMAP;
892 else
893 bitmap = NO_BITMAP;
894
895 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
896 the flags area. */
897 if (bitmap == NO_BITMAP
110859fc 898 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
899 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
900 {
901 /* If W has a vertical border to its left, don't draw over it. */
902 int border = ((XFASTINT (w->left) > 0
903 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
904 ? 1 : 0);
905 int left = window_box_left (w, -1);
906
045dee35
GM
907 if (header_line_height < 0)
908 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
909
910 /* In case the same realized face is used for bitmap areas and
911 for something displayed in the text (e.g. face `region' on
912 mono-displays, the fill style may have been changed to
913 FillSolid in x_draw_glyph_string_background. */
914 if (face->stipple)
915 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
916 else
917 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
918
06a2c219
GM
919 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
920 face->gc,
921 (left
110859fc 922 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 923 + border),
045dee35 924 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 925 row->y)),
110859fc 926 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 927 row->visible_height);
dcd08bfb
GM
928 if (!face->stipple)
929 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
930 }
931
932 /* Draw the left bitmap. */
933 if (bitmap != NO_BITMAP)
934 x_draw_bitmap (w, row, bitmap);
935
936 /* Decide which bitmap to draw at the right side. */
937 if (row->truncated_on_right_p)
938 bitmap = RIGHT_TRUNCATION_BITMAP;
939 else if (row->continued_p)
940 bitmap = CONTINUED_LINE_BITMAP;
941 else
942 bitmap = NO_BITMAP;
943
944 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
945 the flags area. */
946 if (bitmap == NO_BITMAP
110859fc 947 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
948 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
949 {
950 int right = window_box_right (w, -1);
951
045dee35
GM
952 if (header_line_height < 0)
953 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
954
955 /* In case the same realized face is used for bitmap areas and
956 for something displayed in the text (e.g. face `region' on
957 mono-displays, the fill style may have been changed to
958 FillSolid in x_draw_glyph_string_background. */
959 if (face->stipple)
960 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
961 else
962 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
963 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
964 face->gc,
965 right,
045dee35 966 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 967 row->y)),
110859fc 968 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 969 row->visible_height);
dcd08bfb
GM
970 if (!face->stipple)
971 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
972 }
973
974 /* Draw the right bitmap. */
975 if (bitmap != NO_BITMAP)
976 x_draw_bitmap (w, row, bitmap);
977}
978
dc6f92b8 979\f
06a2c219
GM
980/***********************************************************************
981 Line Highlighting
982 ***********************************************************************/
dc6f92b8 983
06a2c219
GM
984/* External interface to control of standout mode. Not used for X
985 frames. Aborts when called. */
986
987static void
dc6f92b8
JB
988XTreassert_line_highlight (new, vpos)
989 int new, vpos;
990{
06a2c219 991 abort ();
dc6f92b8
JB
992}
993
06a2c219
GM
994
995/* Call this when about to modify line at position VPOS and change
996 whether it is highlighted. Not used for X frames. Aborts when
997 called. */
dc6f92b8 998
dfcf069d 999static void
06a2c219
GM
1000x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1001 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1002{
06a2c219 1003 abort ();
dc6f92b8
JB
1004}
1005
06a2c219
GM
1006
1007/* This is called when starting Emacs and when restarting after
1008 suspend. When starting Emacs, no X window is mapped. And nothing
1009 must be done to Emacs's own window if it is suspended (though that
1010 rarely happens). */
dc6f92b8 1011
dfcf069d 1012static void
dc6f92b8
JB
1013XTset_terminal_modes ()
1014{
1015}
1016
06a2c219
GM
1017/* This is called when exiting or suspending Emacs. Exiting will make
1018 the X-windows go away, and suspending requires no action. */
dc6f92b8 1019
dfcf069d 1020static void
dc6f92b8
JB
1021XTreset_terminal_modes ()
1022{
dc6f92b8 1023}
06a2c219
GM
1024
1025
dc6f92b8 1026\f
06a2c219
GM
1027/***********************************************************************
1028 Output Cursor
1029 ***********************************************************************/
1030
1031/* Set the global variable output_cursor to CURSOR. All cursor
1032 positions are relative to updated_window. */
dc6f92b8 1033
dfcf069d 1034static void
06a2c219
GM
1035set_output_cursor (cursor)
1036 struct cursor_pos *cursor;
dc6f92b8 1037{
06a2c219
GM
1038 output_cursor.hpos = cursor->hpos;
1039 output_cursor.vpos = cursor->vpos;
1040 output_cursor.x = cursor->x;
1041 output_cursor.y = cursor->y;
1042}
1043
1044
1045/* Set a nominal cursor position.
dc6f92b8 1046
06a2c219
GM
1047 HPOS and VPOS are column/row positions in a window glyph matrix. X
1048 and Y are window text area relative pixel positions.
1049
1050 If this is done during an update, updated_window will contain the
1051 window that is being updated and the position is the future output
1052 cursor position for that window. If updated_window is null, use
1053 selected_window and display the cursor at the given position. */
1054
1055static void
1056XTcursor_to (vpos, hpos, y, x)
1057 int vpos, hpos, y, x;
1058{
1059 struct window *w;
1060
1061 /* If updated_window is not set, work on selected_window. */
1062 if (updated_window)
1063 w = updated_window;
1064 else
1065 w = XWINDOW (selected_window);
dbcb258a 1066
06a2c219
GM
1067 /* Set the output cursor. */
1068 output_cursor.hpos = hpos;
1069 output_cursor.vpos = vpos;
1070 output_cursor.x = x;
1071 output_cursor.y = y;
dc6f92b8 1072
06a2c219
GM
1073 /* If not called as part of an update, really display the cursor.
1074 This will also set the cursor position of W. */
1075 if (updated_window == NULL)
dc6f92b8
JB
1076 {
1077 BLOCK_INPUT;
06a2c219 1078 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1079 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1080 UNBLOCK_INPUT;
1081 }
1082}
dc43ef94 1083
06a2c219
GM
1084
1085\f
1086/***********************************************************************
1087 Display Iterator
1088 ***********************************************************************/
1089
1090/* Function prototypes of this page. */
1091
1092static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1093 struct glyph *,
1094 XChar2b *));
1095static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1096 int, XChar2b *, int));
1097static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1098static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1099static void x_append_glyph P_ ((struct it *));
1100static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1101 int, int, double));
1102static void x_produce_glyphs P_ ((struct it *));
1103static void x_produce_special_glyphs P_ ((struct it *, enum display_element_type));
1104static void x_produce_image_glyph P_ ((struct it *it));
1105
1106
1107/* Return a pointer to per-char metric information in FONT of a
1108 character pointed by B which is a pointer to an XChar2b. */
dc43ef94
KH
1109
1110#define PER_CHAR_METRIC(font, b) \
1111 ((font)->per_char \
1112 ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
1113 + (((font)->min_byte1 || (font)->max_byte1) \
1114 ? (((b)->byte1 - (font)->min_byte1) \
1115 * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
1116 : 0)) \
1117 : &((font)->max_bounds))
1118
dc6f92b8 1119
06a2c219
GM
1120/* Get metrics of character CHAR2B in FONT. Value is always non-null.
1121 If CHAR2B is not contained in FONT, the font's default character
1122 metric is returned. */
dc43ef94 1123
06a2c219
GM
1124static INLINE XCharStruct *
1125x_per_char_metric (font, char2b)
1126 XFontStruct *font;
1127 XChar2b *char2b;
1128{
1129 /* The result metric information. */
1130 XCharStruct *pcm = NULL;
dc6f92b8 1131
06a2c219 1132 xassert (font && char2b);
dc6f92b8 1133
06a2c219 1134 if (font->per_char != NULL)
dc6f92b8 1135 {
06a2c219 1136 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1137 {
06a2c219
GM
1138 /* min_char_or_byte2 specifies the linear character index
1139 corresponding to the first element of the per_char array,
1140 max_char_or_byte2 is the index of the last character. A
1141 character with non-zero CHAR2B->byte1 is not in the font.
1142 A character with byte2 less than min_char_or_byte2 or
1143 greater max_char_or_byte2 is not in the font. */
1144 if (char2b->byte1 == 0
1145 && char2b->byte2 >= font->min_char_or_byte2
1146 && char2b->byte2 <= font->max_char_or_byte2)
1147 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1148 }
06a2c219 1149 else
dc6f92b8 1150 {
06a2c219
GM
1151 /* If either min_byte1 or max_byte1 are nonzero, both
1152 min_char_or_byte2 and max_char_or_byte2 are less than
1153 256, and the 2-byte character index values corresponding
1154 to the per_char array element N (counting from 0) are:
1155
1156 byte1 = N/D + min_byte1
1157 byte2 = N\D + min_char_or_byte2
1158
1159 where:
1160
1161 D = max_char_or_byte2 - min_char_or_byte2 + 1
1162 / = integer division
1163 \ = integer modulus */
1164 if (char2b->byte1 >= font->min_byte1
1165 && char2b->byte1 <= font->max_byte1
1166 && char2b->byte2 >= font->min_char_or_byte2
1167 && char2b->byte2 <= font->max_char_or_byte2)
1168 {
1169 pcm = (font->per_char
1170 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1171 * (char2b->byte1 - font->min_byte1))
1172 + (char2b->byte2 - font->min_char_or_byte2));
1173 }
dc6f92b8 1174 }
06a2c219
GM
1175 }
1176 else
1177 {
1178 /* If the per_char pointer is null, all glyphs between the first
1179 and last character indexes inclusive have the same
1180 information, as given by both min_bounds and max_bounds. */
1181 if (char2b->byte2 >= font->min_char_or_byte2
1182 && char2b->byte2 <= font->max_char_or_byte2)
1183 pcm = &font->max_bounds;
1184 }
dc6f92b8 1185
4a4dc352 1186
06a2c219
GM
1187 if (pcm == NULL || pcm->width == 0)
1188 {
1189 /* Character not contained in the font. FONT->default_char
1190 gives the character that will be printed. FONT->default_char
1191 is a 16-bit character code with byte1 in the most significant
1192 byte and byte2 in the least significant byte. */
1193 XChar2b default_char;
1194 default_char.byte1 = (font->default_char >> BITS_PER_CHAR) & 0xff;
1195 default_char.byte2 = font->default_char & 0xff;
1196
1197 /* Avoid an endless recursion if FONT->default_char itself
1198 hasn't per char metrics. handa@etl.go.jp reports that some
1199 fonts have this problem. */
1200 if (default_char.byte1 != char2b->byte1
1201 || default_char.byte2 != char2b->byte2)
1202 pcm = x_per_char_metric (font, &default_char);
1203 else
1204 pcm = &font->max_bounds;
1205 }
1206
1207 return pcm;
1208}
b73b6aaf 1209
57b03282 1210
06a2c219
GM
1211/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1212 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1213
06a2c219
GM
1214static INLINE void
1215x_encode_char (c, char2b, font_info)
1216 int c;
1217 XChar2b *char2b;
1218 struct font_info *font_info;
1219{
1220 int charset = CHAR_CHARSET (c);
1221 XFontStruct *font = font_info->font;
1222
1223 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1224 This may be either a program in a special encoder language or a
1225 fixed encoding. */
1226 if (font_info->font_encoder)
1227 {
1228 /* It's a program. */
1229 struct ccl_program *ccl = font_info->font_encoder;
1230
1231 if (CHARSET_DIMENSION (charset) == 1)
1232 {
1233 ccl->reg[0] = charset;
1234 ccl->reg[1] = char2b->byte2;
1235 }
1236 else
1237 {
1238 ccl->reg[0] = charset;
1239 ccl->reg[1] = char2b->byte1;
1240 ccl->reg[2] = char2b->byte2;
1241 }
1242
1243 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1244
1245 /* We assume that MSBs are appropriately set/reset by CCL
1246 program. */
1247 if (font->max_byte1 == 0) /* 1-byte font */
1248 char2b->byte2 = ccl->reg[1];
1249 else
1250 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1251 }
1252 else if (font_info->encoding[charset])
1253 {
1254 /* Fixed encoding scheme. See fontset.h for the meaning of the
1255 encoding numbers. */
1256 int enc = font_info->encoding[charset];
1257
1258 if ((enc == 1 || enc == 2)
1259 && CHARSET_DIMENSION (charset) == 2)
1260 char2b->byte1 |= 0x80;
1261
1262 if (enc == 1 || enc == 3)
1263 char2b->byte2 |= 0x80;
1264 }
1265}
1266
1267
1268/* Get face and two-byte form of character C in face FACE_ID on frame
1269 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1270 means we want to display multibyte text. Value is a pointer to a
1271 realized face that is ready for display. */
1272
1273static INLINE struct face *
1274x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1275 struct frame *f;
1276 int c, face_id;
1277 XChar2b *char2b;
1278 int multibyte_p;
1279{
1280 struct face *face = FACE_FROM_ID (f, face_id);
1281
1282 if (!multibyte_p)
1283 {
1284 /* Unibyte case. We don't have to encode, but we have to make
1285 sure to use a face suitable for unibyte. */
1286 char2b->byte1 = 0;
1287 char2b->byte2 = c;
1288
1289 if (!FACE_SUITABLE_FOR_CHARSET_P (face, -1))
1290 {
1291 face_id = FACE_FOR_CHARSET (f, face_id, -1);
1292 face = FACE_FROM_ID (f, face_id);
1293 }
1294 }
1295 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1296 {
1297 /* Case of ASCII in a face known to fit ASCII. */
1298 char2b->byte1 = 0;
1299 char2b->byte2 = c;
1300 }
1301 else
1302 {
1303 int c1, c2, charset;
1304
1305 /* Split characters into bytes. If c2 is -1 afterwards, C is
1306 really a one-byte character so that byte1 is zero. */
1307 SPLIT_CHAR (c, charset, c1, c2);
1308 if (c2 > 0)
1309 char2b->byte1 = c1, char2b->byte2 = c2;
1310 else
1311 char2b->byte1 = 0, char2b->byte2 = c1;
1312
1313 /* Get the face for displaying C. If `face' is not suitable for
1314 charset, get the one that fits. (This can happen for the
1315 translations of composite characters where the glyph
1316 specifies a face for ASCII, but translations have a different
1317 charset.) */
1318 if (!FACE_SUITABLE_FOR_CHARSET_P (face, charset))
1319 {
1320 face_id = FACE_FOR_CHARSET (f, face_id, charset);
1321 face = FACE_FROM_ID (f, face_id);
1322 }
1323
1324 /* Maybe encode the character in *CHAR2B. */
1325 if (charset != CHARSET_ASCII)
1326 {
1327 struct font_info *font_info
1328 = FONT_INFO_FROM_ID (f, face->font_info_id);
1329 if (font_info)
1330 {
1331 x_encode_char (c, char2b, font_info);
1332 if (charset == charset_latin_iso8859_1)
1333 {
1334 xassert (((XFontStruct *) font_info->font)->max_char_or_byte2
1335 >= 0x80);
1336 char2b->byte2 |= 0x80;
1337 }
1338 }
1339 }
1340 }
1341
1342 /* Make sure X resources of the face are allocated. */
1343 xassert (face != NULL);
1344 PREPARE_FACE_FOR_DISPLAY (f, face);
1345
1346 return face;
1347}
1348
1349
1350/* Get face and two-byte form of character glyph GLYPH on frame F.
1351 The encoding of GLYPH->u.ch.code is returned in *CHAR2B. Value is
1352 a pointer to a realized face that is ready for display. */
1353
1354static INLINE struct face *
1355x_get_glyph_face_and_encoding (f, glyph, char2b)
1356 struct frame *f;
1357 struct glyph *glyph;
1358 XChar2b *char2b;
1359{
1360 struct face *face;
1361
1362 xassert (glyph->type == CHAR_GLYPH);
1363 face = FACE_FROM_ID (f, glyph->u.ch.face_id);
1364
1365 if (!glyph->multibyte_p)
1366 {
1367 /* Unibyte case. We don't have to encode, but we have to make
1368 sure to use a face suitable for unibyte. */
1369 char2b->byte1 = 0;
1370 char2b->byte2 = glyph->u.ch.code;
1371 }
1372 else if (glyph->u.ch.code < 128
1373 && glyph->u.ch.face_id < BASIC_FACE_ID_SENTINEL)
1374 {
1375 /* Case of ASCII in a face known to fit ASCII. */
1376 char2b->byte1 = 0;
1377 char2b->byte2 = glyph->u.ch.code;
1378 }
1379 else
1380 {
1381 int c1, c2, charset;
1382
1383 /* Split characters into bytes. If c2 is -1 afterwards, C is
1384 really a one-byte character so that byte1 is zero. */
1385 SPLIT_CHAR (glyph->u.ch.code, charset, c1, c2);
1386 if (c2 > 0)
1387 char2b->byte1 = c1, char2b->byte2 = c2;
1388 else
1389 char2b->byte1 = 0, char2b->byte2 = c1;
1390
1391 /* Maybe encode the character in *CHAR2B. */
1392 if (charset != CHARSET_ASCII)
1393 {
1394 struct font_info *font_info
1395 = FONT_INFO_FROM_ID (f, face->font_info_id);
1396 if (font_info)
1397 {
1398 x_encode_char (glyph->u.ch.code, char2b, font_info);
1399 if (charset == charset_latin_iso8859_1)
1400 char2b->byte2 |= 0x80;
1401 }
1402 }
1403 }
1404
1405 /* Make sure X resources of the face are allocated. */
1406 xassert (face != NULL);
1407 PREPARE_FACE_FOR_DISPLAY (f, face);
1408 return face;
1409}
1410
1411
1412/* Store one glyph for IT->char_to_display in IT->glyph_row.
1413 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1414
1415static INLINE void
1416x_append_glyph (it)
1417 struct it *it;
1418{
1419 struct glyph *glyph;
1420 enum glyph_row_area area = it->area;
1421
1422 xassert (it->glyph_row);
1423 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1424
1425 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1426 if (glyph < it->glyph_row->glyphs[area + 1])
1427 {
1428 /* Play it safe. If sub-structures of the glyph are not all the
1429 same size, it otherwise be that some bits stay set. This
1430 would prevent a comparison with GLYPH_EQUAL_P. */
1431 glyph->u.val = 0;
1432
1433 glyph->type = CHAR_GLYPH;
1434 glyph->pixel_width = it->pixel_width;
1435 glyph->u.ch.code = it->char_to_display;
1436 glyph->u.ch.face_id = it->face_id;
1437 glyph->charpos = CHARPOS (it->position);
1438 glyph->object = it->object;
1439 glyph->left_box_line_p = it->start_of_box_run_p;
1440 glyph->right_box_line_p = it->end_of_box_run_p;
1441 glyph->voffset = it->voffset;
1442 glyph->multibyte_p = it->multibyte_p;
66ac4b0e
GM
1443 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1444 || it->phys_descent > it->descent);
06a2c219
GM
1445 ++it->glyph_row->used[area];
1446 }
1447}
1448
1449
1450/* Change IT->ascent and IT->height according to the setting of
1451 IT->voffset. */
1452
1453static INLINE void
1454take_vertical_position_into_account (it)
1455 struct it *it;
1456{
1457 if (it->voffset)
1458 {
1459 if (it->voffset < 0)
1460 /* Increase the ascent so that we can display the text higher
1461 in the line. */
1462 it->ascent += abs (it->voffset);
1463 else
1464 /* Increase the descent so that we can display the text lower
1465 in the line. */
1466 it->descent += it->voffset;
1467 }
1468}
1469
1470
1471/* Produce glyphs/get display metrics for the image IT is loaded with.
1472 See the description of struct display_iterator in dispextern.h for
1473 an overview of struct display_iterator. */
1474
1475static void
1476x_produce_image_glyph (it)
1477 struct it *it;
1478{
1479 struct image *img;
1480 struct face *face;
1481
1482 xassert (it->what == IT_IMAGE);
1483
1484 face = FACE_FROM_ID (it->f, it->face_id);
1485 img = IMAGE_FROM_ID (it->f, it->image_id);
1486 xassert (img);
1487
1488 /* Make sure X resources of the face and image are loaded. */
1489 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1490 prepare_image_for_display (it->f, img);
1491
66ac4b0e
GM
1492 it->ascent = it->phys_ascent = IMAGE_ASCENT (img);
1493 it->descent = it->phys_descent = img->height + 2 * img->margin - it->ascent;
06a2c219
GM
1494 it->pixel_width = img->width + 2 * img->margin;
1495
1496 it->nglyphs = 1;
1497
1498 if (face->box != FACE_NO_BOX)
1499 {
1500 it->ascent += face->box_line_width;
1501 it->descent += face->box_line_width;
1502
1503 if (it->start_of_box_run_p)
1504 it->pixel_width += face->box_line_width;
1505 if (it->end_of_box_run_p)
1506 it->pixel_width += face->box_line_width;
1507 }
1508
1509 take_vertical_position_into_account (it);
1510
1511 if (it->glyph_row)
1512 {
1513 struct glyph *glyph;
1514 enum glyph_row_area area = it->area;
1515
1516 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1517 if (glyph < it->glyph_row->glyphs[area + 1])
1518 {
1519 glyph->type = IMAGE_GLYPH;
1520 glyph->u.img.id = img->id;
1521 glyph->u.img.face_id = it->face_id;
1522 glyph->pixel_width = it->pixel_width;
1523 glyph->charpos = CHARPOS (it->position);
1524 glyph->object = it->object;
1525 glyph->left_box_line_p = it->start_of_box_run_p;
1526 glyph->right_box_line_p = it->end_of_box_run_p;
1527 glyph->voffset = it->voffset;
1528 glyph->multibyte_p = it->multibyte_p;
1529 ++it->glyph_row->used[area];
1530 }
1531 }
1532}
1533
1534
1535/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1536 of the glyph, WIDTH and HEIGHT are the width and height of the
1537 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1538 ascent of the glyph (0 <= ASCENT <= 1). */
1539
1540static void
1541x_append_stretch_glyph (it, object, width, height, ascent)
1542 struct it *it;
1543 Lisp_Object object;
1544 int width, height;
1545 double ascent;
1546{
1547 struct glyph *glyph;
1548 enum glyph_row_area area = it->area;
1549
1550 xassert (ascent >= 0 && ascent <= 1);
1551
1552 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1553 if (glyph < it->glyph_row->glyphs[area + 1])
1554 {
1555 glyph->type = STRETCH_GLYPH;
1556 glyph->u.stretch.ascent = height * ascent;
1557 glyph->u.stretch.height = height;
1558 glyph->u.stretch.face_id = it->face_id;
1559 glyph->pixel_width = width;
1560 glyph->charpos = CHARPOS (it->position);
1561 glyph->object = object;
1562 glyph->left_box_line_p = it->start_of_box_run_p;
1563 glyph->right_box_line_p = it->end_of_box_run_p;
1564 glyph->voffset = it->voffset;
1565 glyph->multibyte_p = it->multibyte_p;
1566 ++it->glyph_row->used[area];
1567 }
1568}
1569
1570
1571/* Produce a stretch glyph for iterator IT. IT->object is the value
1572 of the glyph property displayed. The value must be a list
1573 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1574 being recognized:
1575
1576 1. `:width WIDTH' specifies that the space should be WIDTH *
1577 canonical char width wide. WIDTH may be an integer or floating
1578 point number.
1579
1580 2. `:relative-width FACTOR' specifies that the width of the stretch
1581 should be computed from the width of the first character having the
1582 `glyph' property, and should be FACTOR times that width.
1583
1584 3. `:align-to HPOS' specifies that the space should be wide enough
1585 to reach HPOS, a value in canonical character units.
1586
1587 Exactly one of the above pairs must be present.
1588
1589 4. `:height HEIGHT' specifies that the height of the stretch produced
1590 should be HEIGHT, measured in canonical character units.
1591
1592 5. `:relative-height FACTOR' specifies that the height of the the
1593 stretch should be FACTOR times the height of the characters having
1594 the glyph property.
1595
1596 Either none or exactly one of 4 or 5 must be present.
1597
1598 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1599 of the stretch should be used for the ascent of the stretch.
1600 ASCENT must be in the range 0 <= ASCENT <= 100. */
1601
1602#define NUMVAL(X) \
1603 ((INTEGERP (X) || FLOATP (X)) \
1604 ? XFLOATINT (X) \
1605 : - 1)
1606
1607
1608static void
1609x_produce_stretch_glyph (it)
1610 struct it *it;
1611{
1612 /* (space :width WIDTH :height HEIGHT. */
1613 extern Lisp_Object QCwidth, QCheight, QCascent, Qspace;
1614 extern Lisp_Object QCrelative_width, QCrelative_height;
1615 extern Lisp_Object QCalign_to;
1616 Lisp_Object prop, plist;
1617 double width = 0, height = 0, ascent = 0;
1618 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1619 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1620
1621 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1622
1623 /* List should start with `space'. */
1624 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1625 plist = XCDR (it->object);
1626
1627 /* Compute the width of the stretch. */
1628 if (prop = Fplist_get (plist, QCwidth),
1629 NUMVAL (prop) > 0)
1630 /* Absolute width `:width WIDTH' specified and valid. */
1631 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1632 else if (prop = Fplist_get (plist, QCrelative_width),
1633 NUMVAL (prop) > 0)
1634 {
1635 /* Relative width `:relative-width FACTOR' specified and valid.
1636 Compute the width of the characters having the `glyph'
1637 property. */
1638 struct it it2;
1639 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1640
1641 it2 = *it;
1642 if (it->multibyte_p)
1643 {
1644 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1645 - IT_BYTEPOS (*it));
1646 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1647 }
1648 else
1649 it2.c = *p, it2.len = 1;
1650
1651 it2.glyph_row = NULL;
1652 it2.what = IT_CHARACTER;
1653 x_produce_glyphs (&it2);
1654 width = NUMVAL (prop) * it2.pixel_width;
1655 }
1656 else if (prop = Fplist_get (plist, QCalign_to),
1657 NUMVAL (prop) > 0)
1658 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1659 else
1660 /* Nothing specified -> width defaults to canonical char width. */
1661 width = CANON_X_UNIT (it->f);
1662
1663 /* Compute height. */
1664 if (prop = Fplist_get (plist, QCheight),
1665 NUMVAL (prop) > 0)
1666 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1667 else if (prop = Fplist_get (plist, QCrelative_height),
1668 NUMVAL (prop) > 0)
1669 height = FONT_HEIGHT (font) * NUMVAL (prop);
1670 else
1671 height = FONT_HEIGHT (font);
1672
1673 /* Compute percentage of height used for ascent. If
1674 `:ascent ASCENT' is present and valid, use that. Otherwise,
1675 derive the ascent from the font in use. */
1676 if (prop = Fplist_get (plist, QCascent),
1677 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1678 ascent = NUMVAL (prop) / 100.0;
1679 else
1680 ascent = (double) font->ascent / FONT_HEIGHT (font);
1681
1682 if (width <= 0)
1683 width = 1;
1684 if (height <= 0)
1685 height = 1;
1686
1687 if (it->glyph_row)
1688 {
1689 Lisp_Object object = it->stack[it->sp - 1].string;
1690 if (!STRINGP (object))
1691 object = it->w->buffer;
1692 x_append_stretch_glyph (it, object, width, height, ascent);
1693 }
1694
1695 it->pixel_width = width;
66ac4b0e
GM
1696 it->ascent = it->phys_ascent = height * ascent;
1697 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1698 it->nglyphs = 1;
1699
1700 if (face->box != FACE_NO_BOX)
1701 {
1702 it->ascent += face->box_line_width;
1703 it->descent += face->box_line_width;
1704
1705 if (it->start_of_box_run_p)
1706 it->pixel_width += face->box_line_width;
1707 if (it->end_of_box_run_p)
1708 it->pixel_width += face->box_line_width;
1709 }
1710
1711 take_vertical_position_into_account (it);
1712}
1713
1714
1715/* Produce glyphs/get display metrics for the display element IT is
1716 loaded with. See the description of struct display_iterator in
1717 dispextern.h for an overview of struct display_iterator. */
1718
1719static void
1720x_produce_glyphs (it)
1721 struct it *it;
1722{
1723 if (it->what == IT_CHARACTER)
1724 {
1725 XChar2b char2b;
1726 XFontStruct *font;
1727 struct face *face;
1728 XCharStruct *pcm;
1729 struct it ci;
1730 int font_not_found_p;
1731 int c;
1732
1733 /* Maybe translate single-byte characters to multibyte. */
1734 it->char_to_display = it->c;
1735 if (unibyte_display_via_language_environment
1736 && SINGLE_BYTE_CHAR_P (it->c)
1737 && (it->c >= 0240
1738 || (it->c >= 0200
1739 && !NILP (Vnonascii_translation_table))))
1740 {
1741 it->char_to_display = unibyte_char_to_multibyte (it->c);
1742 it->charset = CHAR_CHARSET (it->char_to_display);
1743 }
1744
1745 /* Get face and font to use. Encode IT->char_to_display. */
1746 face = x_get_char_face_and_encoding (it->f, it->char_to_display,
1747 it->face_id, &char2b,
1748 it->multibyte_p);
1749 font = face->font;
1750
1751 /* When no suitable font found, use the default font. */
1752 font_not_found_p = font == NULL;
1753 if (font_not_found_p)
1754 font = FRAME_FONT (it->f);
1755
1756 if (it->char_to_display >= ' '
1757 && (!it->multibyte_p || it->char_to_display < 128))
1758 {
1759 /* Either unibyte or ASCII. */
1760 int stretched_p;
1761
1762 it->nglyphs = 1;
06a2c219
GM
1763
1764 pcm = x_per_char_metric (font, &char2b);
66ac4b0e
GM
1765 it->ascent = font->ascent;
1766 it->descent = font->descent;
1767 it->phys_ascent = pcm->ascent;
1768 it->phys_descent = pcm->descent;
06a2c219
GM
1769 it->pixel_width = pcm->width;
1770
1771 /* If this is a space inside a region of text with
1772 `space-width' property, change its width. */
1773 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1774 if (stretched_p)
1775 it->pixel_width *= XFLOATINT (it->space_width);
1776
1777 /* If face has a box, add the box thickness to the character
1778 height. If character has a box line to the left and/or
1779 right, add the box line width to the character's width. */
1780 if (face->box != FACE_NO_BOX)
1781 {
1782 int thick = face->box_line_width;
1783
1784 it->ascent += thick;
1785 it->descent += thick;
1786
1787 if (it->start_of_box_run_p)
1788 it->pixel_width += thick;
1789 if (it->end_of_box_run_p)
1790 it->pixel_width += thick;
1791 }
1792
1793 /* If face has an overline, add the height of the overline
1794 (1 pixel) and a 1 pixel margin to the character height. */
1795 if (face->overline_p)
1796 it->ascent += 2;
1797
1798 take_vertical_position_into_account (it);
1799
1800 /* If we have to actually produce glyphs, do it. */
1801 if (it->glyph_row)
1802 {
1803 if (stretched_p)
1804 {
1805 /* Translate a space with a `space-width' property
1806 into a stretch glyph. */
1807 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1808 x_append_stretch_glyph (it, it->object, it->pixel_width,
1809 it->ascent + it->descent, ascent);
1810 }
1811 else
1812 x_append_glyph (it);
1813
1814 /* If characters with lbearing or rbearing are displayed
1815 in this line, record that fact in a flag of the
1816 glyph row. This is used to optimize X output code. */
1817 if (pcm->lbearing < 0
1818 || pcm->rbearing > pcm->width)
1819 it->glyph_row->contains_overlapping_glyphs_p = 1;
1820 }
1821 }
1822 else if (it->char_to_display == '\n')
1823 {
1824 /* A newline has no width but we need the height of the line. */
1825 it->pixel_width = 0;
1826 it->nglyphs = 0;
66ac4b0e
GM
1827 it->ascent = it->phys_ascent = font->ascent;
1828 it->descent = it->phys_descent = font->descent;
06a2c219
GM
1829
1830 if (face->box != FACE_NO_BOX)
1831 {
1832 int thick = face->box_line_width;
1833 it->ascent += thick;
1834 it->descent += thick;
1835 }
1836 }
1837 else if (it->char_to_display == '\t')
1838 {
1839 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
1840 int x = (it->current_x
1841 - it->prompt_width
1842 + it->continuation_lines_width);
1843 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
1844
1845 it->pixel_width = next_tab_x - x;
1846 it->nglyphs = 1;
66ac4b0e
GM
1847 it->ascent = it->phys_ascent = font->ascent;
1848 it->descent = it->phys_descent = font->descent;
06a2c219
GM
1849
1850 if (it->glyph_row)
1851 {
1852 double ascent = (double) it->ascent / (it->ascent + it->descent);
1853 x_append_stretch_glyph (it, it->object, it->pixel_width,
1854 it->ascent + it->descent, ascent);
1855 }
1856 }
1857 else
1858 {
1859 /* A multi-byte character. Assume that the display width of the
1860 character is the width of the character multiplied by the
1861 width of the font. There has to be better support for
1862 variable sizes in cmpchar_info to do anything better than
1863 that.
1864
1865 Note: composite characters are represented as one glyph in
1866 the glyph matrix. There are no padding glyphs. */
1867 if (it->charset == CHARSET_COMPOSITION)
1868 {
1869 struct cmpchar_info *cmpcharp;
1870 int idx;
1871
1872 idx = COMPOSITE_CHAR_ID (it->char_to_display);
1873 cmpcharp = cmpchar_table[idx];
1874 it->pixel_width = font->max_bounds.width * cmpcharp->width;
1875
1876 /* There are no padding glyphs, so there is only one glyph
1877 to produce for the composite char. Important is that
1878 pixel_width, ascent and descent are the values of what is
1879 drawn by draw_glyphs. */
1880 it->nglyphs = 1;
1881
1882 /* These settings may not be correct. We must have more
1883 information in cmpcharp to do the correct setting. */
1884 it->ascent = font->ascent;
1885 it->descent = font->descent;
66ac4b0e
GM
1886 it->phys_ascent = font->max_bounds.ascent;
1887 it->phys_descent = font->max_bounds.descent;
06a2c219
GM
1888 }
1889 else
1890 {
1891 /* If we found a font, this font should give us the right
1892 metrics. If we didn't find a font, use the frame's
1893 default font and calculate the width of the character
1894 from the charset width; this is what old redisplay code
1895 did. */
1896 pcm = x_per_char_metric (font, &char2b);
1897 it->pixel_width = pcm->width;
1898 if (font_not_found_p)
1899 it->pixel_width *= CHARSET_WIDTH (it->charset);
1900 it->nglyphs = 1;
1901 it->ascent = font->ascent;
1902 it->descent = font->descent;
66ac4b0e
GM
1903 it->phys_ascent = pcm->ascent;
1904 it->phys_descent = pcm->descent;
06a2c219
GM
1905 if (it->glyph_row
1906 && (pcm->lbearing < 0
1907 || pcm->rbearing > pcm->width))
1908 it->glyph_row->contains_overlapping_glyphs_p = 1;
1909 }
1910
1911 if (face->box != FACE_NO_BOX)
1912 {
1913 int thick = face->box_line_width;
1914 it->ascent += thick;
1915 it->descent += thick;
1916
1917 if (it->start_of_box_run_p)
1918 it->pixel_width += thick;
1919 if (it->end_of_box_run_p)
1920 it->pixel_width += thick;
1921 }
1922
1923 /* If face has an overline, add the height of the overline
1924 (1 pixel) and a 1 pixel margin to the character height. */
1925 if (face->overline_p)
1926 it->ascent += 2;
1927
1928 take_vertical_position_into_account (it);
1929
1930 if (it->glyph_row)
1931 x_append_glyph (it);
1932 }
1933 }
1934 else if (it->what == IT_IMAGE)
1935 x_produce_image_glyph (it);
1936 else if (it->what == IT_STRETCH)
1937 x_produce_stretch_glyph (it);
1938
1939 /* Accumulate dimensions. */
1940 xassert (it->ascent >= 0 && it->descent > 0);
1941 if (it->area == TEXT_AREA)
1942 it->current_x += it->pixel_width;
66ac4b0e 1943
06a2c219
GM
1944 it->max_ascent = max (it->max_ascent, it->ascent);
1945 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
1946 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
1947 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
1948}
1949
1950
1951/* Estimate the pixel height of the mode or top line on frame F.
1952 FACE_ID specifies what line's height to estimate. */
1953
1954int
1955x_estimate_mode_line_height (f, face_id)
1956 struct frame *f;
1957 enum face_id face_id;
1958{
1959 int height = 1;
1960
1961 /* This function is called so early when Emacs starts that the face
1962 cache and mode line face are not yet initialized. */
1963 if (FRAME_FACE_CACHE (f))
1964 {
1965 struct face *face = FACE_FROM_ID (f, face_id);
1966 if (face)
1967 height = FONT_HEIGHT (face->font) + 2 * face->box_line_width;
1968 }
1969
1970 return height;
1971}
1972
1973\f
1974/***********************************************************************
1975 Glyph display
1976 ***********************************************************************/
1977
1978/* A sequence of glyphs to be drawn in the same face.
1979
1980 This data structure is not really completely X specific, so it
1981 could possibly, at least partially, be useful for other systems. It
1982 is currently not part of the external redisplay interface because
1983 it's not clear what other systems will need. */
1984
1985struct glyph_string
1986{
1987 /* X-origin of the string. */
1988 int x;
1989
1990 /* Y-origin and y-position of the base line of this string. */
1991 int y, ybase;
1992
1993 /* The width of the string, not including a face extension. */
1994 int width;
1995
1996 /* The width of the string, including a face extension. */
1997 int background_width;
1998
1999 /* The height of this string. This is the height of the line this
2000 string is drawn in, and can be different from the height of the
2001 font the string is drawn in. */
2002 int height;
2003
2004 /* Number of pixels this string overwrites in front of its x-origin.
2005 This number is zero if the string has an lbearing >= 0; it is
2006 -lbearing, if the string has an lbearing < 0. */
2007 int left_overhang;
2008
2009 /* Number of pixels this string overwrites past its right-most
2010 nominal x-position, i.e. x + width. Zero if the string's
2011 rbearing is <= its nominal width, rbearing - width otherwise. */
2012 int right_overhang;
2013
2014 /* The frame on which the glyph string is drawn. */
2015 struct frame *f;
2016
2017 /* The window on which the glyph string is drawn. */
2018 struct window *w;
2019
2020 /* X display and window for convenience. */
2021 Display *display;
2022 Window window;
2023
2024 /* The glyph row for which this string was built. It determines the
2025 y-origin and height of the string. */
2026 struct glyph_row *row;
2027
2028 /* The area within row. */
2029 enum glyph_row_area area;
2030
2031 /* Characters to be drawn, and number of characters. */
2032 XChar2b *char2b;
2033 int nchars;
2034
2035 /* Character set of this glyph string. */
2036 int charset;
2037
2038 /* A face-override for drawing cursors, mouse face and similar. */
2039 enum draw_glyphs_face hl;
2040
2041 /* Face in which this string is to be drawn. */
2042 struct face *face;
2043
2044 /* Font in which this string is to be drawn. */
2045 XFontStruct *font;
2046
2047 /* Font info for this string. */
2048 struct font_info *font_info;
2049
2050 /* Non-null means this string describes (part of) a composite
2051 character. All characters from char2b are drawn at the same
2052 x-origin in that case. */
2053 struct cmpchar_info *cmpcharp;
2054
2055 /* Index of this glyph string's first character in the glyph
2056 definition of cmpcharp. If this is zero, this glyph string
2057 describes the first character of a composite character. */
2058 int gidx;
2059
2060 /* 1 means this glyph strings face has to be drawn to the right end
2061 of the window's drawing area. */
2062 unsigned extends_to_end_of_line_p : 1;
2063
2064 /* 1 means the background of this string has been drawn. */
2065 unsigned background_filled_p : 1;
2066
2067 /* 1 means glyph string must be drawn with 16-bit functions. */
2068 unsigned two_byte_p : 1;
2069
2070 /* 1 means that the original font determined for drawing this glyph
2071 string could not be loaded. The member `font' has been set to
2072 the frame's default font in this case. */
2073 unsigned font_not_found_p : 1;
2074
2075 /* 1 means that the face in which this glyph string is drawn has a
2076 stipple pattern. */
2077 unsigned stippled_p : 1;
2078
66ac4b0e
GM
2079 /* 1 means only the foreground of this glyph string must be drawn,
2080 and we should use the physical height of the line this glyph
2081 string appears in as clip rect. */
2082 unsigned for_overlaps_p : 1;
2083
06a2c219
GM
2084 /* The GC to use for drawing this glyph string. */
2085 GC gc;
2086
2087 /* A pointer to the first glyph in the string. This glyph
2088 corresponds to char2b[0]. Needed to draw rectangles if
2089 font_not_found_p is 1. */
2090 struct glyph *first_glyph;
2091
2092 /* Image, if any. */
2093 struct image *img;
2094
2095 struct glyph_string *next, *prev;
2096};
2097
2098
2099#if GLYPH_DEBUG
2100
2101static void
2102x_dump_glyph_string (s)
2103 struct glyph_string *s;
2104{
2105 fprintf (stderr, "glyph string\n");
2106 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2107 s->x, s->y, s->width, s->height);
2108 fprintf (stderr, " ybase = %d\n", s->ybase);
2109 fprintf (stderr, " hl = %d\n", s->hl);
2110 fprintf (stderr, " left overhang = %d, right = %d\n",
2111 s->left_overhang, s->right_overhang);
2112 fprintf (stderr, " nchars = %d\n", s->nchars);
2113 fprintf (stderr, " extends to end of line = %d\n",
2114 s->extends_to_end_of_line_p);
2115 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2116 fprintf (stderr, " bg width = %d\n", s->background_width);
2117}
2118
2119#endif /* GLYPH_DEBUG */
2120
2121
2122
2123static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2124 struct glyph_string **,
2125 struct glyph_string *,
2126 struct glyph_string *));
2127static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2128 struct glyph_string **,
2129 struct glyph_string *,
2130 struct glyph_string *));
2131static void x_append_glyph_string P_ ((struct glyph_string **,
2132 struct glyph_string **,
2133 struct glyph_string *));
2134static int x_left_overwritten P_ ((struct glyph_string *));
2135static int x_left_overwriting P_ ((struct glyph_string *));
2136static int x_right_overwritten P_ ((struct glyph_string *));
2137static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2138static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2139 int));
06a2c219
GM
2140static void x_init_glyph_string P_ ((struct glyph_string *,
2141 XChar2b *, struct window *,
2142 struct glyph_row *,
2143 enum glyph_row_area, int,
2144 enum draw_glyphs_face));
2145static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2146 enum glyph_row_area, int, int,
66ac4b0e 2147 enum draw_glyphs_face, int *, int *, int));
06a2c219
GM
2148static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2149static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2150static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2151 int));
2152static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
2153static void x_draw_glyph_string_underline P_ ((struct glyph_string *));
2154static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2155static void x_draw_glyph_string P_ ((struct glyph_string *));
2156static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2157static void x_set_cursor_gc P_ ((struct glyph_string *));
2158static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2159static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2160static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2161 int *, int *));
2162static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2163static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
2164 unsigned long *, float, int));
2165static void x_setup_relief_color P_ ((struct frame *, struct relief *,
2166 float, int, unsigned long));
2167static void x_setup_relief_colors P_ ((struct glyph_string *));
2168static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2169static void x_draw_image_relief P_ ((struct glyph_string *));
2170static void x_draw_image_foreground P_ ((struct glyph_string *));
2171static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2172static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2173static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2174 int, int, int));
2175static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2176 int, int, int, int, XRectangle *));
2177static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2178 int, int, int, XRectangle *));
66ac4b0e
GM
2179static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2180 enum glyph_row_area));
06a2c219
GM
2181
2182
06a2c219
GM
2183/* Append the list of glyph strings with head H and tail T to the list
2184 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2185
2186static INLINE void
2187x_append_glyph_string_lists (head, tail, h, t)
2188 struct glyph_string **head, **tail;
2189 struct glyph_string *h, *t;
2190{
2191 if (h)
2192 {
2193 if (*head)
2194 (*tail)->next = h;
2195 else
2196 *head = h;
2197 h->prev = *tail;
2198 *tail = t;
2199 }
2200}
2201
2202
2203/* Prepend the list of glyph strings with head H and tail T to the
2204 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2205 result. */
2206
2207static INLINE void
2208x_prepend_glyph_string_lists (head, tail, h, t)
2209 struct glyph_string **head, **tail;
2210 struct glyph_string *h, *t;
2211{
2212 if (h)
2213 {
2214 if (*head)
2215 (*head)->prev = t;
2216 else
2217 *tail = t;
2218 t->next = *head;
2219 *head = h;
2220 }
2221}
2222
2223
2224/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2225 Set *HEAD and *TAIL to the resulting list. */
2226
2227static INLINE void
2228x_append_glyph_string (head, tail, s)
2229 struct glyph_string **head, **tail;
2230 struct glyph_string *s;
2231{
2232 s->next = s->prev = NULL;
2233 x_append_glyph_string_lists (head, tail, s, s);
2234}
2235
2236
2237/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2238 face. */
2239
2240static void
2241x_set_cursor_gc (s)
2242 struct glyph_string *s;
2243{
2244 if (s->font == FRAME_FONT (s->f)
2245 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2246 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
2247 && !s->cmpcharp)
2248 s->gc = s->f->output_data.x->cursor_gc;
2249 else
2250 {
2251 /* Cursor on non-default face: must merge. */
2252 XGCValues xgcv;
2253 unsigned long mask;
2254
2255 xgcv.background = s->f->output_data.x->cursor_pixel;
2256 xgcv.foreground = s->face->background;
2257
2258 /* If the glyph would be invisible, try a different foreground. */
2259 if (xgcv.foreground == xgcv.background)
2260 xgcv.foreground = s->face->foreground;
2261 if (xgcv.foreground == xgcv.background)
2262 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2263 if (xgcv.foreground == xgcv.background)
2264 xgcv.foreground = s->face->foreground;
2265
2266 /* Make sure the cursor is distinct from text in this face. */
2267 if (xgcv.background == s->face->background
2268 && xgcv.foreground == s->face->foreground)
2269 {
2270 xgcv.background = s->face->foreground;
2271 xgcv.foreground = s->face->background;
2272 }
2273
2274 IF_DEBUG (x_check_font (s->f, s->font));
2275 xgcv.font = s->font->fid;
2276 xgcv.graphics_exposures = False;
2277 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2278
2279 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2280 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2281 mask, &xgcv);
2282 else
2283 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2284 = XCreateGC (s->display, s->window, mask, &xgcv);
2285
2286 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2287 }
2288}
2289
2290
2291/* Set up S->gc of glyph string S for drawing text in mouse face. */
2292
2293static void
2294x_set_mouse_face_gc (s)
2295 struct glyph_string *s;
2296{
2297 int face_id;
2298
2299 /* What face has to be used for the mouse face? */
2300 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
2301 face_id = FACE_FOR_CHARSET (s->f, face_id, s->charset);
2302 s->face = FACE_FROM_ID (s->f, face_id);
2303 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2304
2305 /* If font in this face is same as S->font, use it. */
2306 if (s->font == s->face->font)
2307 s->gc = s->face->gc;
2308 else
2309 {
2310 /* Otherwise construct scratch_cursor_gc with values from FACE
2311 but font FONT. */
2312 XGCValues xgcv;
2313 unsigned long mask;
2314
2315 xgcv.background = s->face->background;
2316 xgcv.foreground = s->face->foreground;
2317 IF_DEBUG (x_check_font (s->f, s->font));
2318 xgcv.font = s->font->fid;
2319 xgcv.graphics_exposures = False;
2320 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2321
2322 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2323 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2324 mask, &xgcv);
2325 else
2326 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2327 = XCreateGC (s->display, s->window, mask, &xgcv);
2328
2329 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2330 }
2331
2332 xassert (s->gc != 0);
2333}
2334
2335
2336/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2337 Faces to use in the mode line have already been computed when the
2338 matrix was built, so there isn't much to do, here. */
2339
2340static INLINE void
2341x_set_mode_line_face_gc (s)
2342 struct glyph_string *s;
2343{
2344 s->gc = s->face->gc;
2345 xassert (s->gc != 0);
2346}
2347
2348
2349/* Set S->gc of glyph string S for drawing that glyph string. Set
2350 S->stippled_p to a non-zero value if the face of S has a stipple
2351 pattern. */
2352
2353static INLINE void
2354x_set_glyph_string_gc (s)
2355 struct glyph_string *s;
2356{
2357 if (s->hl == DRAW_NORMAL_TEXT)
2358 {
2359 s->gc = s->face->gc;
2360 s->stippled_p = s->face->stipple != 0;
2361 }
2362 else if (s->hl == DRAW_INVERSE_VIDEO)
2363 {
2364 x_set_mode_line_face_gc (s);
2365 s->stippled_p = s->face->stipple != 0;
2366 }
2367 else if (s->hl == DRAW_CURSOR)
2368 {
2369 x_set_cursor_gc (s);
2370 s->stippled_p = 0;
2371 }
2372 else if (s->hl == DRAW_MOUSE_FACE)
2373 {
2374 x_set_mouse_face_gc (s);
2375 s->stippled_p = s->face->stipple != 0;
2376 }
2377 else if (s->hl == DRAW_IMAGE_RAISED
2378 || s->hl == DRAW_IMAGE_SUNKEN)
2379 {
2380 s->gc = s->face->gc;
2381 s->stippled_p = s->face->stipple != 0;
2382 }
2383 else
2384 {
2385 s->gc = s->face->gc;
2386 s->stippled_p = s->face->stipple != 0;
2387 }
2388
2389 /* GC must have been set. */
2390 xassert (s->gc != 0);
2391}
2392
2393
2394/* Return in *R the clipping rectangle for glyph string S. */
2395
2396static void
2397x_get_glyph_string_clip_rect (s, r)
2398 struct glyph_string *s;
2399 XRectangle *r;
2400{
2401 if (s->row->full_width_p)
2402 {
2403 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2404 int canon_x = CANON_X_UNIT (s->f);
2405
2406 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2407 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2408
2409 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2410 {
1da3fd71 2411 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2412 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2413 r->x -= width;
2414 }
2415
b9432a85 2416 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2417
06a2c219
GM
2418 /* Unless displaying a mode or menu bar line, which are always
2419 fully visible, clip to the visible part of the row. */
2420 if (s->w->pseudo_window_p)
2421 r->height = s->row->visible_height;
2422 else
2423 r->height = s->height;
2424 }
2425 else
2426 {
2427 /* This is a text line that may be partially visible. */
2428 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2429 r->width = window_box_width (s->w, s->area);
2430 r->height = s->row->visible_height;
2431 }
2432
2433 /* Don't use S->y for clipping because it doesn't take partially
2434 visible lines into account. For example, it can be negative for
2435 partially visible lines at the top of a window. */
2436 if (!s->row->full_width_p
2437 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
045dee35 2438 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
06a2c219
GM
2439 else
2440 r->y = max (0, s->row->y);
06a2c219 2441
9ea173e8 2442 /* If drawing a tool-bar window, draw it over the internal border
06a2c219 2443 at the top of the window. */
9ea173e8 2444 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219 2445 r->y -= s->f->output_data.x->internal_border_width;
66ac4b0e
GM
2446
2447 /* If S draws overlapping rows, it's sufficient to use the top and
2448 bottom of the window for clipping because this glyph string
2449 intentionally draws over other lines. */
2450 if (s->for_overlaps_p)
2451 {
045dee35 2452 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2453 r->height = window_text_bottom_y (s->w) - r->y;
2454 }
2455
2456 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2457}
2458
2459
2460/* Set clipping for output of glyph string S. S may be part of a mode
2461 line or menu if we don't have X toolkit support. */
2462
2463static INLINE void
2464x_set_glyph_string_clipping (s)
2465 struct glyph_string *s;
2466{
2467 XRectangle r;
2468 x_get_glyph_string_clip_rect (s, &r);
2469 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2470}
2471
2472
2473/* Compute left and right overhang of glyph string S. If S is a glyph
2474 string for a composite character, assume overhangs don't exist. */
2475
2476static INLINE void
2477x_compute_glyph_string_overhangs (s)
2478 struct glyph_string *s;
2479{
2480 if (s->cmpcharp == NULL
2481 && s->first_glyph->type == CHAR_GLYPH)
2482 {
2483 XCharStruct cs;
2484 int direction, font_ascent, font_descent;
2485 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2486 &font_ascent, &font_descent, &cs);
2487 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2488 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2489 }
2490}
2491
2492
2493/* Compute overhangs and x-positions for glyph string S and its
2494 predecessors, or successors. X is the starting x-position for S.
2495 BACKWARD_P non-zero means process predecessors. */
2496
2497static void
2498x_compute_overhangs_and_x (s, x, backward_p)
2499 struct glyph_string *s;
2500 int x;
2501 int backward_p;
2502{
2503 if (backward_p)
2504 {
2505 while (s)
2506 {
2507 x_compute_glyph_string_overhangs (s);
2508 x -= s->width;
2509 s->x = x;
2510 s = s->prev;
2511 }
2512 }
2513 else
2514 {
2515 while (s)
2516 {
2517 x_compute_glyph_string_overhangs (s);
2518 s->x = x;
2519 x += s->width;
2520 s = s->next;
2521 }
2522 }
2523}
2524
2525
2526/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
2527 frame F. Overhangs of glyphs other than type CHAR_GLYPH or of
2528 character glyphs for composite characters are assumed to be zero. */
2529
2530static void
2531x_get_glyph_overhangs (glyph, f, left, right)
2532 struct glyph *glyph;
2533 struct frame *f;
2534 int *left, *right;
2535{
2536 int c;
2537
2538 *left = *right = 0;
2539
2540 if (glyph->type == CHAR_GLYPH
2541 && (c = glyph->u.ch.code,
2542 CHAR_CHARSET (c) != CHARSET_COMPOSITION))
2543 {
2544 XFontStruct *font;
2545 struct face *face;
2546 struct font_info *font_info;
2547 XChar2b char2b;
2548
2549 face = x_get_glyph_face_and_encoding (f, glyph, &char2b);
2550 font = face->font;
2551 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
2552 if (font)
2553 {
2554 XCharStruct *pcm = x_per_char_metric (font, &char2b);
2555
2556 if (pcm->rbearing > pcm->width)
2557 *right = pcm->rbearing - pcm->width;
2558 if (pcm->lbearing < 0)
2559 *left = -pcm->lbearing;
2560 }
2561 }
2562}
2563
2564
2565/* Return the index of the first glyph preceding glyph string S that
2566 is overwritten by S because of S's left overhang. Value is -1
2567 if no glyphs are overwritten. */
2568
2569static int
2570x_left_overwritten (s)
2571 struct glyph_string *s;
2572{
2573 int k;
2574
2575 if (s->left_overhang)
2576 {
2577 int x = 0, i;
2578 struct glyph *glyphs = s->row->glyphs[s->area];
2579 int first = s->first_glyph - glyphs;
2580
2581 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2582 x -= glyphs[i].pixel_width;
2583
2584 k = i + 1;
2585 }
2586 else
2587 k = -1;
2588
2589 return k;
2590}
2591
2592
2593/* Return the index of the first glyph preceding glyph string S that
2594 is overwriting S because of its right overhang. Value is -1 if no
2595 glyph in front of S overwrites S. */
2596
2597static int
2598x_left_overwriting (s)
2599 struct glyph_string *s;
2600{
2601 int i, k, x;
2602 struct glyph *glyphs = s->row->glyphs[s->area];
2603 int first = s->first_glyph - glyphs;
2604
2605 k = -1;
2606 x = 0;
2607 for (i = first - 1; i >= 0; --i)
2608 {
2609 int left, right;
2610 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2611 if (x + right > 0)
2612 k = i;
2613 x -= glyphs[i].pixel_width;
2614 }
2615
2616 return k;
2617}
2618
2619
2620/* Return the index of the last glyph following glyph string S that is
2621 not overwritten by S because of S's right overhang. Value is -1 if
2622 no such glyph is found. */
2623
2624static int
2625x_right_overwritten (s)
2626 struct glyph_string *s;
2627{
2628 int k = -1;
2629
2630 if (s->right_overhang)
2631 {
2632 int x = 0, i;
2633 struct glyph *glyphs = s->row->glyphs[s->area];
2634 int first = (s->first_glyph - glyphs) + (s->cmpcharp ? 1 : s->nchars);
2635 int end = s->row->used[s->area];
2636
2637 for (i = first; i < end && s->right_overhang > x; ++i)
2638 x += glyphs[i].pixel_width;
2639
2640 k = i;
2641 }
2642
2643 return k;
2644}
2645
2646
2647/* Return the index of the last glyph following glyph string S that
2648 overwrites S because of its left overhang. Value is negative
2649 if no such glyph is found. */
2650
2651static int
2652x_right_overwriting (s)
2653 struct glyph_string *s;
2654{
2655 int i, k, x;
2656 int end = s->row->used[s->area];
2657 struct glyph *glyphs = s->row->glyphs[s->area];
2658 int first = (s->first_glyph - glyphs) + (s->cmpcharp ? 1 : s->nchars);
2659
2660 k = -1;
2661 x = 0;
2662 for (i = first; i < end; ++i)
2663 {
2664 int left, right;
2665 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2666 if (x - left < 0)
2667 k = i;
2668 x += glyphs[i].pixel_width;
2669 }
2670
2671 return k;
2672}
2673
2674
2675/* Fill rectangle X, Y, W, H with background color of glyph string S. */
2676
2677static INLINE void
2678x_clear_glyph_string_rect (s, x, y, w, h)
2679 struct glyph_string *s;
2680 int x, y, w, h;
2681{
2682 XGCValues xgcv;
2683 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
2684 XSetForeground (s->display, s->gc, xgcv.background);
2685 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
2686 XSetForeground (s->display, s->gc, xgcv.foreground);
2687}
2688
2689
2690/* Draw the background of glyph_string S. If S->background_filled_p
2691 is non-zero don't draw it. FORCE_P non-zero means draw the
2692 background even if it wouldn't be drawn normally. This is used
2693 when a string preceding S draws into the background of S. */
2694
2695static void
2696x_draw_glyph_string_background (s, force_p)
2697 struct glyph_string *s;
2698 int force_p;
2699{
2700 /* Nothing to do if background has already been drawn or if it
2701 shouldn't be drawn in the first place. */
2702 if (!s->background_filled_p)
2703 {
2704 if (s->cmpcharp
2705 && s->gidx > 0
2706 && !s->font_not_found_p
2707 && !s->extends_to_end_of_line_p)
2708 {
2709 /* Don't draw background for glyphs of a composite
2710 characters, except for the first one. */
2711 s->background_filled_p = 1;
2712 }
2713 else if (s->stippled_p)
2714 {
2715 /* Fill background with a stipple pattern. */
2716 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
2717 XFillRectangle (s->display, s->window, s->gc, s->x,
2718 s->y + s->face->box_line_width,
2719 s->background_width,
2720 s->height - 2 * s->face->box_line_width);
2721 XSetFillStyle (s->display, s->gc, FillSolid);
2722 s->background_filled_p = 1;
2723 }
2724 else if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
2725 || s->font_not_found_p
2726 || s->extends_to_end_of_line_p
2727 || s->cmpcharp
2728 || force_p)
2729 {
2730 x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
2731 s->background_width,
2732 s->height - 2 * s->face->box_line_width);
2733 s->background_filled_p = 1;
2734 }
2735 }
2736}
2737
2738
2739/* Draw the foreground of glyph string S. */
2740
2741static void
2742x_draw_glyph_string_foreground (s)
2743 struct glyph_string *s;
2744{
2745 int i, x;
2746
2747 /* If first glyph of S has a left box line, start drawing the text
2748 of S to the right of that box line. */
2749 if (s->face->box != FACE_NO_BOX
2750 && s->first_glyph->left_box_line_p)
2751 x = s->x + s->face->box_line_width;
2752 else
2753 x = s->x;
2754
2755 if (s->cmpcharp == NULL)
2756 {
2757 /* Not a composite character. Draw characters of S as
2758 rectangles if S's font could not be loaded. */
2759 if (s->font_not_found_p)
2760 {
2761 for (i = 0; i < s->nchars; ++i)
2762 {
2763 struct glyph *g = s->first_glyph + i;
2764 XDrawRectangle (s->display, s->window,
2765 s->gc, x, s->y, g->pixel_width - 1,
2766 s->height - 1);
2767 x += g->pixel_width;
2768 }
2769 }
2770 else
2771 {
2772 char *char1b = (char *) s->char2b;
2773
2774 /* If we can use 8-bit functions, condense S->char2b. */
2775 if (!s->two_byte_p)
2776 for (i = 0; i < s->nchars; ++i)
2777 char1b[i] = s->char2b[i].byte2;
2778
2779 /* Draw text with XDrawString if background has already been
2780 filled. Otherwise, use XDrawImageString. (Note that
2781 XDrawImageString is usually faster than XDrawString.)
2782 Always use XDrawImageString when drawing the cursor so
2783 that there is no chance that characters under a box
2784 cursor are invisible. */
66ac4b0e
GM
2785 if (s->for_overlaps_p
2786 || (s->background_filled_p && s->hl != DRAW_CURSOR))
06a2c219
GM
2787 {
2788 /* Draw characters with 16-bit or 8-bit functions. */
2789 if (s->two_byte_p)
2790 XDrawString16 (s->display, s->window, s->gc, x, s->ybase,
2791 s->char2b, s->nchars);
2792 else
2793 XDrawString (s->display, s->window, s->gc, x, s->ybase,
2794 char1b, s->nchars);
2795 }
2796 else
2797 {
2798 if (s->two_byte_p)
2799 XDrawImageString16 (s->display, s->window, s->gc,
2800 x, s->ybase, s->char2b, s->nchars);
2801 else
2802 XDrawImageString (s->display, s->window, s->gc,
2803 x, s->ybase, char1b, s->nchars);
2804 }
2805 }
2806 }
2807 else
2808 {
2809 /* S is a glyph string for a composite character. S->gidx is the
2810 index of the first character drawn in the vector
2811 S->cmpcharp->glyph. S->gidx == 0 means we are drawing the
2812 very first component character of a composite char. */
2813
2814 /* Draw a single rectangle for the composite character if S's
2815 font could not be loaded. */
2816 if (s->font_not_found_p && s->gidx == 0)
2817 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
2818 s->width - 1, s->height - 1);
2819 else
2820 {
2821 XCharStruct *pcm;
2822 int relative_compose, default_ascent, i;
2823 int highest = 0, lowest = 0;
2824
2825 /* The value of font_info my be null if we couldn't find it
2826 in x_get_char_face_and_encoding. */
2827 if (s->cmpcharp->cmp_rule == NULL && s->font_info)
2828 {
2829 relative_compose = s->font_info->relative_compose;
2830 default_ascent = s->font_info->default_ascent;
2831 }
2832 else
2833 relative_compose = default_ascent = 0;
2834
2835 if ((s->cmpcharp->cmp_rule || relative_compose)
2836 && s->gidx == 0)
2837 {
2838 /* This is the first character. Initialize variables.
2839 Highest is the highest position of glyphs ever
2840 written, lowest the lowest position. */
2841 int x_offset = 0;
2842 int first_ch = s->first_glyph->u.ch.code;
2843
2844 if (default_ascent
2845 && CHAR_TABLE_P (Vuse_default_ascent)
2846 && !NILP (Faref (Vuse_default_ascent, first_ch)))
2847 {
2848 highest = default_ascent;
2849 lowest = 0;
2850 }
2851 else
2852 {
2853 pcm = PER_CHAR_METRIC (s->font, s->char2b);
2854 highest = pcm->ascent + 1;
2855 lowest = - pcm->descent;
2856 }
2857
2858 if (s->cmpcharp->cmp_rule)
2859 x_offset = (s->cmpcharp->col_offset[0]
2860 * FONT_WIDTH (s->f->output_data.x->font));
2861
2862 /* Draw the first character at the normal position. */
2863 XDrawString16 (s->display, s->window, s->gc,
2864 x + x_offset,
2865 s->ybase, s->char2b, 1);
2866 i = 1;
2867 ++s->gidx;
2868 }
2869 else
2870 i = 0;
2871
2872 for (; i < s->nchars; i++, ++s->gidx)
2873 {
2874 int x_offset = 0, y_offset = 0;
2875
2876 if (relative_compose)
2877 {
2878 pcm = PER_CHAR_METRIC (s->font, s->char2b + i);
2879 if (NILP (Vignore_relative_composition)
2880 || NILP (Faref (Vignore_relative_composition,
2881 make_number (s->cmpcharp->glyph[s->gidx]))))
2882 {
2883 if (- pcm->descent >= relative_compose)
2884 {
2885 /* Draw above the current glyphs. */
2886 y_offset = highest + pcm->descent;
2887 highest += pcm->ascent + pcm->descent;
2888 }
2889 else if (pcm->ascent <= 0)
2890 {
2891 /* Draw beneath the current glyphs. */
2892 y_offset = lowest - pcm->ascent;
2893 lowest -= pcm->ascent + pcm->descent;
2894 }
2895 }
2896 else
2897 {
2898 /* Draw the glyph at normal position. If
2899 it sticks out of HIGHEST or LOWEST,
2900 update them appropriately. */
2901 if (pcm->ascent > highest)
2902 highest = pcm->ascent;
2903 else if (- pcm->descent < lowest)
2904 lowest = - pcm->descent;
2905 }
2906 }
2907 else if (s->cmpcharp->cmp_rule)
2908 {
2909 int gref = (s->cmpcharp->cmp_rule[s->gidx] - 0xA0) / 9;
2910 int nref = (s->cmpcharp->cmp_rule[s->gidx] - 0xA0) % 9;
2911 int bottom, top;
2912
2913 /* Re-encode GREF and NREF so that they specify
2914 only Y-axis information:
2915 0:top, 1:base, 2:bottom, 3:center */
2916 gref = gref / 3 + (gref == 4) * 2;
2917 nref = nref / 3 + (nref == 4) * 2;
2918
2919 pcm = PER_CHAR_METRIC (s->font, s->char2b + i);
2920 bottom = ((gref == 0 ? highest : gref == 1 ? 0
2921 : gref == 2 ? lowest
2922 : (highest + lowest) / 2)
2923 - (nref == 0 ? pcm->ascent + pcm->descent
2924 : nref == 1 ? pcm->descent : nref == 2 ? 0
2925 : (pcm->ascent + pcm->descent) / 2));
2926 top = bottom + (pcm->ascent + pcm->descent);
2927 if (top > highest)
2928 highest = top;
2929 if (bottom < lowest)
2930 lowest = bottom;
2931 y_offset = bottom + pcm->descent;
2932 x_offset = (s->cmpcharp->col_offset[s->gidx]
2933 * FONT_WIDTH (FRAME_FONT (s->f)));
2934 }
2935
2936 XDrawString16 (s->display, s->window, s->gc,
2937 x + x_offset, s->ybase - y_offset,
2938 s->char2b + i, 1);
2939 }
2940 }
2941 }
2942}
2943
2944
80c32bcc
GM
2945#ifdef USE_X_TOOLKIT
2946
2947/* Allocate the color COLOR->pixel on the screen and display of
2948 widget WIDGET in colormap CMAP. If an exact match cannot be
2949 allocated, try the nearest color available. Value is non-zero
2950 if successful. This is called from lwlib. */
2951
2952int
2953x_alloc_nearest_color_for_widget (widget, cmap, color)
2954 Widget widget;
2955 Colormap cmap;
2956 XColor *color;
2957{
2958 struct frame *f;
2959 struct x_display_info *dpyinfo;
2960 Lisp_Object tail, frame;
2961 Widget parent;
2962
2963 dpyinfo = x_display_info_for_display (XtDisplay (widget));
2964
2965 /* Find the top-level shell of the widget. Note that this function
2966 can be called when the widget is not yet realized, so XtWindow
2967 (widget) == 0. That's the reason we can't simply use
2968 x_any_window_to_frame. */
2969 while (!XtIsTopLevelShell (widget))
2970 widget = XtParent (widget);
2971
2972 /* Look for a frame with that top-level widget. Allocate the color
2973 on that frame to get the right gamma correction value. */
2974 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
2975 if (GC_FRAMEP (XCAR (tail))
2976 && (f = XFRAME (XCAR (tail)),
2977 (f->output_data.nothing != 1
2978 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
2979 && f->output_data.x->widget == widget)
2980 return x_alloc_nearest_color (f, cmap, color);
2981
2982 abort ();
2983}
2984
2985#endif /* USE_X_TOOLKIT */
2986
2987
06a2c219
GM
2988/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
2989 CMAP. If an exact match can't be allocated, try the nearest color
2990 available. Value is non-zero if successful. Set *COLOR to the
2991 color allocated. */
2992
2993int
80c32bcc
GM
2994x_alloc_nearest_color (f, cmap, color)
2995 struct frame *f;
06a2c219
GM
2996 Colormap cmap;
2997 XColor *color;
2998{
80c32bcc
GM
2999 Display *display = FRAME_X_DISPLAY (f);
3000 Screen *screen = FRAME_X_SCREEN (f);
3001 int rc;
3002
3003 gamma_correct (f, color);
3004 rc = XAllocColor (display, cmap, color);
06a2c219
GM
3005 if (rc == 0)
3006 {
3007 /* If we got to this point, the colormap is full, so we're going
3008 to try to get the next closest color. The algorithm used is
3009 a least-squares matching, which is what X uses for closest
3010 color matching with StaticColor visuals. */
3011 int nearest, i;
3012 unsigned long nearest_delta = ~0;
3013 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3014 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3015
3016 for (i = 0; i < ncells; ++i)
3017 cells[i].pixel = i;
3018 XQueryColors (display, cmap, cells, ncells);
3019
3020 for (nearest = i = 0; i < ncells; ++i)
3021 {
3022 long dred = (color->red >> 8) - (cells[i].red >> 8);
3023 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3024 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3025 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3026
3027 if (delta < nearest_delta)
3028 {
3029 nearest = i;
3030 nearest_delta = delta;
3031 }
3032 }
3033
3034 color->red = cells[nearest].red;
3035 color->green = cells[nearest].green;
3036 color->blue = cells[nearest].blue;
3037 rc = XAllocColor (display, cmap, color);
3038 }
3039
3040 return rc;
3041}
3042
3043
3044/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3045 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3046 If this produces the same color as PIXEL, try a color where all RGB
3047 values have DELTA added. Return the allocated color in *PIXEL.
3048 DISPLAY is the X display, CMAP is the colormap to operate on.
3049 Value is non-zero if successful. */
3050
3051static int
3052x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3053 struct frame *f;
3054 Display *display;
3055 Colormap cmap;
3056 unsigned long *pixel;
3057 float factor;
3058 int delta;
3059{
3060 XColor color, new;
3061 int success_p;
3062
3063 /* Get RGB color values. */
3064 color.pixel = *pixel;
3065 XQueryColor (display, cmap, &color);
3066
3067 /* Change RGB values by specified FACTOR. Avoid overflow! */
3068 xassert (factor >= 0);
3069 new.red = min (0xffff, factor * color.red);
3070 new.green = min (0xffff, factor * color.green);
3071 new.blue = min (0xffff, factor * color.blue);
3072
3073 /* Try to allocate the color. */
80c32bcc 3074 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3075 if (success_p)
3076 {
3077 if (new.pixel == *pixel)
3078 {
3079 /* If we end up with the same color as before, try adding
3080 delta to the RGB values. */
3081 int class = FRAME_X_DISPLAY_INFO (f)->visual->class;
3082
3083 /* If display has an immutable color map, freeing colors is
3084 not necessary and some servers don't allow it. So don't
3085 do it. */
3086 if (class != StaticColor
3087 && class != StaticGray
3088 && class != TrueColor)
3089 XFreeColors (display, cmap, &new.pixel, 1, 0);
3090
3091 new.red = min (0xffff, delta + color.red);
3092 new.green = min (0xffff, delta + color.green);
3093 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3094 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3095 }
3096 else
3097 success_p = 1;
3098 *pixel = new.pixel;
3099 }
3100
3101 return success_p;
3102}
3103
3104
3105/* Set up the foreground color for drawing relief lines of glyph
3106 string S. RELIEF is a pointer to a struct relief containing the GC
3107 with which lines will be drawn. Use a color that is FACTOR or
3108 DELTA lighter or darker than the relief's background which is found
3109 in S->f->output_data.x->relief_background. If such a color cannot
3110 be allocated, use DEFAULT_PIXEL, instead. */
3111
3112static void
3113x_setup_relief_color (f, relief, factor, delta, default_pixel)
3114 struct frame *f;
3115 struct relief *relief;
3116 float factor;
3117 int delta;
3118 unsigned long default_pixel;
3119{
3120 XGCValues xgcv;
3121 struct x_output *di = f->output_data.x;
3122 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3123 unsigned long pixel;
3124 unsigned long background = di->relief_background;
3125 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
dcd08bfb
GM
3126 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3127 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3128
3129 xgcv.graphics_exposures = False;
3130 xgcv.line_width = 1;
3131
3132 /* Free previously allocated color. The color cell will be reused
3133 when it has been freed as many times as it was allocated, so this
3134 doesn't affect faces using the same colors. */
3135 if (relief->gc
3136 && relief->allocated_p)
3137 {
3138 /* If display has an immutable color map, freeing colors is not
3139 necessary and some servers don't allow it. So don't do it. */
dcd08bfb 3140 int class = dpyinfo->visual->class;
06a2c219
GM
3141 if (class != StaticColor
3142 && class != StaticGray
3143 && class != TrueColor)
dcd08bfb 3144 XFreeColors (dpy, cmap, &relief->pixel, 1, 0);
06a2c219
GM
3145 relief->allocated_p = 0;
3146 }
3147
3148 /* Allocate new color. */
3149 xgcv.foreground = default_pixel;
3150 pixel = background;
dcd08bfb
GM
3151 if (dpyinfo->n_planes != 1
3152 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3153 {
3154 relief->allocated_p = 1;
3155 xgcv.foreground = relief->pixel = pixel;
3156 }
3157
3158 if (relief->gc == 0)
3159 {
dcd08bfb 3160 xgcv.stipple = dpyinfo->gray;
06a2c219 3161 mask |= GCStipple;
dcd08bfb 3162 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3163 }
3164 else
dcd08bfb 3165 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3166}
3167
3168
3169/* Set up colors for the relief lines around glyph string S. */
3170
3171static void
3172x_setup_relief_colors (s)
3173 struct glyph_string *s;
3174{
3175 struct x_output *di = s->f->output_data.x;
3176 unsigned long color;
3177
3178 if (s->face->use_box_color_for_shadows_p)
3179 color = s->face->box_color;
3180 else
3181 {
3182 XGCValues xgcv;
3183
3184 /* Get the background color of the face. */
3185 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3186 color = xgcv.background;
3187 }
3188
3189 if (di->white_relief.gc == 0
3190 || color != di->relief_background)
3191 {
3192 di->relief_background = color;
3193 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3194 WHITE_PIX_DEFAULT (s->f));
3195 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3196 BLACK_PIX_DEFAULT (s->f));
3197 }
3198}
3199
3200
3201/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3202 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3203 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3204 relief. LEFT_P non-zero means draw a relief on the left side of
3205 the rectangle. RIGHT_P non-zero means draw a relief on the right
3206 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3207 when drawing. */
3208
3209static void
3210x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3211 raised_p, left_p, right_p, clip_rect)
3212 struct frame *f;
3213 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3214 XRectangle *clip_rect;
3215{
3216 int i;
3217 GC gc;
3218
3219 if (raised_p)
3220 gc = f->output_data.x->white_relief.gc;
3221 else
3222 gc = f->output_data.x->black_relief.gc;
3223 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3224
3225 /* Top. */
3226 for (i = 0; i < width; ++i)
3227 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3228 left_x + i * left_p, top_y + i,
3229 right_x + 1 - i * right_p, top_y + i);
3230
3231 /* Left. */
3232 if (left_p)
3233 for (i = 0; i < width; ++i)
3234 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3235 left_x + i, top_y + i, left_x + i, bottom_y - i);
3236
3237 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3238 if (raised_p)
3239 gc = f->output_data.x->black_relief.gc;
3240 else
3241 gc = f->output_data.x->white_relief.gc;
3242 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3243
3244 /* Bottom. */
3245 for (i = 0; i < width; ++i)
3246 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3247 left_x + i * left_p, bottom_y - i,
3248 right_x + 1 - i * right_p, bottom_y - i);
3249
3250 /* Right. */
3251 if (right_p)
3252 for (i = 0; i < width; ++i)
3253 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3254 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3255
3256 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3257}
3258
3259
3260/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3261 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3262 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3263 left side of the rectangle. RIGHT_P non-zero means draw a line
3264 on the right side of the rectangle. CLIP_RECT is the clipping
3265 rectangle to use when drawing. */
3266
3267static void
3268x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3269 left_p, right_p, clip_rect)
3270 struct glyph_string *s;
3271 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3272 XRectangle *clip_rect;
3273{
3274 XGCValues xgcv;
3275
3276 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3277 XSetForeground (s->display, s->gc, s->face->box_color);
3278 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3279
3280 /* Top. */
3281 XFillRectangle (s->display, s->window, s->gc,
3282 left_x, top_y, right_x - left_x, width);
3283
3284 /* Left. */
3285 if (left_p)
3286 XFillRectangle (s->display, s->window, s->gc,
3287 left_x, top_y, width, bottom_y - top_y);
3288
3289 /* Bottom. */
3290 XFillRectangle (s->display, s->window, s->gc,
3291 left_x, bottom_y - width, right_x - left_x, width);
3292
3293 /* Right. */
3294 if (right_p)
3295 XFillRectangle (s->display, s->window, s->gc,
3296 right_x - width, top_y, width, bottom_y - top_y);
3297
3298 XSetForeground (s->display, s->gc, xgcv.foreground);
3299 XSetClipMask (s->display, s->gc, None);
3300}
3301
3302
3303/* Draw a box around glyph string S. */
3304
3305static void
3306x_draw_glyph_string_box (s)
3307 struct glyph_string *s;
3308{
3309 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3310 int left_p, right_p;
3311 struct glyph *last_glyph;
3312 XRectangle clip_rect;
3313
3314 last_x = window_box_right (s->w, s->area);
3315 if (s->row->full_width_p
3316 && !s->w->pseudo_window_p)
3317 {
110859fc 3318 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3319 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3320 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3321 }
3322
3323 /* The glyph that may have a right box line. */
3324 last_glyph = (s->cmpcharp || s->img
3325 ? s->first_glyph
3326 : s->first_glyph + s->nchars - 1);
3327
3328 width = s->face->box_line_width;
3329 raised_p = s->face->box == FACE_RAISED_BOX;
3330 left_x = s->x;
3331 right_x = ((s->row->full_width_p
1da3fd71 3332 ? last_x - 1
a7aeb2de 3333 : min (last_x, s->x + s->background_width) - 1));
06a2c219
GM
3334 top_y = s->y;
3335 bottom_y = top_y + s->height - 1;
3336
3337 left_p = (s->first_glyph->left_box_line_p
3338 || (s->hl == DRAW_MOUSE_FACE
3339 && (s->prev == NULL
3340 || s->prev->hl != s->hl)));
3341 right_p = (last_glyph->right_box_line_p
3342 || (s->hl == DRAW_MOUSE_FACE
3343 && (s->next == NULL
3344 || s->next->hl != s->hl)));
3345
3346 x_get_glyph_string_clip_rect (s, &clip_rect);
3347
3348 if (s->face->box == FACE_SIMPLE_BOX)
3349 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3350 left_p, right_p, &clip_rect);
3351 else
3352 {
3353 x_setup_relief_colors (s);
3354 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3355 width, raised_p, left_p, right_p, &clip_rect);
3356 }
3357}
3358
3359
3360/* Draw foreground of image glyph string S. */
3361
3362static void
3363x_draw_image_foreground (s)
3364 struct glyph_string *s;
3365{
3366 int x;
3367 int y = s->ybase - IMAGE_ASCENT (s->img);
3368
3369 /* If first glyph of S has a left box line, start drawing it to the
3370 right of that line. */
3371 if (s->face->box != FACE_NO_BOX
3372 && s->first_glyph->left_box_line_p)
3373 x = s->x + s->face->box_line_width;
3374 else
3375 x = s->x;
3376
3377 /* If there is a margin around the image, adjust x- and y-position
3378 by that margin. */
3379 if (s->img->margin)
3380 {
3381 x += s->img->margin;
3382 y += s->img->margin;
3383 }
3384
3385 if (s->img->pixmap)
3386 {
3387 if (s->img->mask)
3388 {
3389 /* We can't set both a clip mask and use XSetClipRectangles
3390 because the latter also sets a clip mask. We also can't
3391 trust on the shape extension to be available
3392 (XShapeCombineRegion). So, compute the rectangle to draw
3393 manually. */
3394 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3395 | GCFunction);
3396 XGCValues xgcv;
3397 XRectangle clip_rect, image_rect, r;
3398
3399 xgcv.clip_mask = s->img->mask;
3400 xgcv.clip_x_origin = x;
3401 xgcv.clip_y_origin = y;
3402 xgcv.function = GXcopy;
3403 XChangeGC (s->display, s->gc, mask, &xgcv);
3404
3405 x_get_glyph_string_clip_rect (s, &clip_rect);
3406 image_rect.x = x;
3407 image_rect.y = y;
3408 image_rect.width = s->img->width;
3409 image_rect.height = s->img->height;
3410 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
3411 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3412 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
3413 }
3414 else
3415 {
3416 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3417 0, 0, s->img->width, s->img->height, x, y);
3418
3419 /* When the image has a mask, we can expect that at
3420 least part of a mouse highlight or a block cursor will
3421 be visible. If the image doesn't have a mask, make
3422 a block cursor visible by drawing a rectangle around
3423 the image. I believe it's looking better if we do
3424 nothing here for mouse-face. */
3425 if (s->hl == DRAW_CURSOR)
3426 XDrawRectangle (s->display, s->window, s->gc, x, y,
3427 s->img->width - 1, s->img->height - 1);
3428 }
3429 }
3430 else
3431 /* Draw a rectangle if image could not be loaded. */
3432 XDrawRectangle (s->display, s->window, s->gc, x, y,
3433 s->img->width - 1, s->img->height - 1);
3434}
3435
3436
3437/* Draw a relief around the image glyph string S. */
3438
3439static void
3440x_draw_image_relief (s)
3441 struct glyph_string *s;
3442{
3443 int x0, y0, x1, y1, thick, raised_p;
3444 XRectangle r;
3445 int x;
3446 int y = s->ybase - IMAGE_ASCENT (s->img);
3447
3448 /* If first glyph of S has a left box line, start drawing it to the
3449 right of that line. */
3450 if (s->face->box != FACE_NO_BOX
3451 && s->first_glyph->left_box_line_p)
3452 x = s->x + s->face->box_line_width;
3453 else
3454 x = s->x;
3455
3456 /* If there is a margin around the image, adjust x- and y-position
3457 by that margin. */
3458 if (s->img->margin)
3459 {
3460 x += s->img->margin;
3461 y += s->img->margin;
3462 }
3463
3464 if (s->hl == DRAW_IMAGE_SUNKEN
3465 || s->hl == DRAW_IMAGE_RAISED)
3466 {
9ea173e8 3467 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
3468 raised_p = s->hl == DRAW_IMAGE_RAISED;
3469 }
3470 else
3471 {
3472 thick = abs (s->img->relief);
3473 raised_p = s->img->relief > 0;
3474 }
3475
3476 x0 = x - thick;
3477 y0 = y - thick;
3478 x1 = x + s->img->width + thick - 1;
3479 y1 = y + s->img->height + thick - 1;
3480
3481 x_setup_relief_colors (s);
3482 x_get_glyph_string_clip_rect (s, &r);
3483 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
3484}
3485
3486
3487/* Draw the foreground of image glyph string S to PIXMAP. */
3488
3489static void
3490x_draw_image_foreground_1 (s, pixmap)
3491 struct glyph_string *s;
3492 Pixmap pixmap;
3493{
3494 int x;
3495 int y = s->ybase - s->y - IMAGE_ASCENT (s->img);
3496
3497 /* If first glyph of S has a left box line, start drawing it to the
3498 right of that line. */
3499 if (s->face->box != FACE_NO_BOX
3500 && s->first_glyph->left_box_line_p)
3501 x = s->face->box_line_width;
3502 else
3503 x = 0;
3504
3505 /* If there is a margin around the image, adjust x- and y-position
3506 by that margin. */
3507 if (s->img->margin)
3508 {
3509 x += s->img->margin;
3510 y += s->img->margin;
3511 }
dc43ef94 3512
06a2c219
GM
3513 if (s->img->pixmap)
3514 {
3515 if (s->img->mask)
3516 {
3517 /* We can't set both a clip mask and use XSetClipRectangles
3518 because the latter also sets a clip mask. We also can't
3519 trust on the shape extension to be available
3520 (XShapeCombineRegion). So, compute the rectangle to draw
3521 manually. */
3522 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3523 | GCFunction);
3524 XGCValues xgcv;
3525
3526 xgcv.clip_mask = s->img->mask;
3527 xgcv.clip_x_origin = x;
3528 xgcv.clip_y_origin = y;
3529 xgcv.function = GXcopy;
3530 XChangeGC (s->display, s->gc, mask, &xgcv);
3531
3532 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3533 0, 0, s->img->width, s->img->height, x, y);
3534 XSetClipMask (s->display, s->gc, None);
3535 }
3536 else
3537 {
3538 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3539 0, 0, s->img->width, s->img->height, x, y);
3540
3541 /* When the image has a mask, we can expect that at
3542 least part of a mouse highlight or a block cursor will
3543 be visible. If the image doesn't have a mask, make
3544 a block cursor visible by drawing a rectangle around
3545 the image. I believe it's looking better if we do
3546 nothing here for mouse-face. */
3547 if (s->hl == DRAW_CURSOR)
3548 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3549 s->img->width - 1, s->img->height - 1);
3550 }
3551 }
3552 else
3553 /* Draw a rectangle if image could not be loaded. */
3554 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3555 s->img->width - 1, s->img->height - 1);
3556}
dc43ef94 3557
990ba854 3558
06a2c219
GM
3559/* Draw part of the background of glyph string S. X, Y, W, and H
3560 give the rectangle to draw. */
a9a5b0a5 3561
06a2c219
GM
3562static void
3563x_draw_glyph_string_bg_rect (s, x, y, w, h)
3564 struct glyph_string *s;
3565 int x, y, w, h;
3566{
3567 if (s->stippled_p)
3568 {
3569 /* Fill background with a stipple pattern. */
3570 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3571 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3572 XSetFillStyle (s->display, s->gc, FillSolid);
3573 }
3574 else
3575 x_clear_glyph_string_rect (s, x, y, w, h);
3576}
07e34cb0 3577
b5210ea7 3578
06a2c219 3579/* Draw image glyph string S.
dc43ef94 3580
06a2c219
GM
3581 s->y
3582 s->x +-------------------------
3583 | s->face->box
3584 |
3585 | +-------------------------
3586 | | s->img->margin
3587 | |
3588 | | +-------------------
3589 | | | the image
dc43ef94 3590
06a2c219 3591 */
dc43ef94 3592
06a2c219
GM
3593static void
3594x_draw_image_glyph_string (s)
3595 struct glyph_string *s;
3596{
3597 int x, y;
3598 int box_line_width = s->face->box_line_width;
3599 int margin = s->img->margin;
3600 int height;
3601 Pixmap pixmap = None;
3602
3603 height = s->height - 2 * box_line_width;
3604
3605 /* Fill background with face under the image. Do it only if row is
3606 taller than image or if image has a clip mask to reduce
3607 flickering. */
3608 s->stippled_p = s->face->stipple != 0;
3609 if (height > s->img->height
3610 || margin
3611 || s->img->mask
3612 || s->img->pixmap == 0
3613 || s->width != s->background_width)
3614 {
3615 if (box_line_width && s->first_glyph->left_box_line_p)
3616 x = s->x + box_line_width;
3617 else
3618 x = s->x;
3619
3620 y = s->y + box_line_width;
3621
3622 if (s->img->mask)
3623 {
3624 /* Create a pixmap as large as the glyph string Fill it with
3625 the background color. Copy the image to it, using its
3626 mask. Copy the temporary pixmap to the display. */
3627 Screen *screen = FRAME_X_SCREEN (s->f);
3628 int depth = DefaultDepthOfScreen (screen);
3629
3630 /* Create a pixmap as large as the glyph string. */
3631 pixmap = XCreatePixmap (s->display, s->window,
3632 s->background_width,
3633 s->height, depth);
3634
3635 /* Don't clip in the following because we're working on the
3636 pixmap. */
3637 XSetClipMask (s->display, s->gc, None);
3638
3639 /* Fill the pixmap with the background color/stipple. */
3640 if (s->stippled_p)
3641 {
3642 /* Fill background with a stipple pattern. */
3643 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3644 XFillRectangle (s->display, pixmap, s->gc,
3645 0, 0, s->background_width, s->height);
3646 XSetFillStyle (s->display, s->gc, FillSolid);
3647 }
3648 else
3649 {
3650 XGCValues xgcv;
3651 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
3652 &xgcv);
3653 XSetForeground (s->display, s->gc, xgcv.background);
3654 XFillRectangle (s->display, pixmap, s->gc,
3655 0, 0, s->background_width, s->height);
3656 XSetForeground (s->display, s->gc, xgcv.foreground);
3657 }
3658 }
3659 else
3660 /* Implementation idea: Is it possible to construct a mask?
3661 We could look at the color at the margins of the image, and
3662 say that this color is probably the background color of the
3663 image. */
3664 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3665
3666 s->background_filled_p = 1;
3667 }
dc43ef94 3668
06a2c219
GM
3669 /* Draw the foreground. */
3670 if (pixmap != None)
3671 {
3672 x_draw_image_foreground_1 (s, pixmap);
3673 x_set_glyph_string_clipping (s);
3674 XCopyArea (s->display, pixmap, s->window, s->gc,
3675 0, 0, s->background_width, s->height, s->x, s->y);
3676 XFreePixmap (s->display, pixmap);
3677 }
3678 else
3679 x_draw_image_foreground (s);
b5210ea7 3680
06a2c219
GM
3681 /* If we must draw a relief around the image, do it. */
3682 if (s->img->relief
3683 || s->hl == DRAW_IMAGE_RAISED
3684 || s->hl == DRAW_IMAGE_SUNKEN)
3685 x_draw_image_relief (s);
3686}
8c1a6a84 3687
990ba854 3688
06a2c219 3689/* Draw stretch glyph string S. */
dc43ef94 3690
06a2c219
GM
3691static void
3692x_draw_stretch_glyph_string (s)
3693 struct glyph_string *s;
3694{
3695 xassert (s->first_glyph->type == STRETCH_GLYPH);
3696 s->stippled_p = s->face->stipple != 0;
990ba854 3697
06a2c219
GM
3698 if (s->hl == DRAW_CURSOR
3699 && !x_stretch_cursor_p)
3700 {
3701 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3702 as wide as the stretch glyph. */
3703 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 3704
06a2c219
GM
3705 /* Draw cursor. */
3706 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 3707
06a2c219
GM
3708 /* Clear rest using the GC of the original non-cursor face. */
3709 if (width < s->background_width)
3710 {
3711 GC gc = s->face->gc;
3712 int x = s->x + width, y = s->y;
3713 int w = s->background_width - width, h = s->height;
3714 XRectangle r;
dc43ef94 3715
06a2c219
GM
3716 x_get_glyph_string_clip_rect (s, &r);
3717 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
97210f4e 3718
06a2c219
GM
3719 if (s->face->stipple)
3720 {
3721 /* Fill background with a stipple pattern. */
3722 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3723 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3724 XSetFillStyle (s->display, gc, FillSolid);
3725 }
3726 else
3727 {
3728 XGCValues xgcv;
3729 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
3730 XSetForeground (s->display, gc, xgcv.background);
3731 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3732 XSetForeground (s->display, gc, xgcv.foreground);
3733 }
3734 }
3735 }
3736 else
3737 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
3738 s->height);
3739
3740 s->background_filled_p = 1;
3741}
3742
3743
3744/* Draw glyph string S. */
3745
3746static void
3747x_draw_glyph_string (s)
3748 struct glyph_string *s;
3749{
3750 /* If S draws into the background of its successor, draw the
3751 background of the successor first so that S can draw into it.
3752 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 3753 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
3754 {
3755 xassert (s->next->img == NULL);
3756 x_set_glyph_string_gc (s->next);
3757 x_set_glyph_string_clipping (s->next);
3758 x_draw_glyph_string_background (s->next, 1);
3759 }
97210f4e 3760
06a2c219
GM
3761 /* Set up S->gc, set clipping and draw S. */
3762 x_set_glyph_string_gc (s);
3763 x_set_glyph_string_clipping (s);
3764
3765 switch (s->first_glyph->type)
3766 {
3767 case IMAGE_GLYPH:
3768 x_draw_image_glyph_string (s);
3769 break;
3770
3771 case STRETCH_GLYPH:
3772 x_draw_stretch_glyph_string (s);
3773 break;
3774
3775 case CHAR_GLYPH:
66ac4b0e
GM
3776 if (s->for_overlaps_p)
3777 s->background_filled_p = 1;
3778 else
3779 x_draw_glyph_string_background (s, 0);
06a2c219
GM
3780 x_draw_glyph_string_foreground (s);
3781 break;
3782
3783 default:
3784 abort ();
3785 }
3786
66ac4b0e 3787 if (!s->for_overlaps_p)
06a2c219 3788 {
66ac4b0e
GM
3789 /* Draw underline. */
3790 if (s->face->underline_p)
3791 {
3792 unsigned long dy, h;
06a2c219 3793
66ac4b0e
GM
3794 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
3795 h = 1;
3796 if (!XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &dy))
3797 dy = s->height - h;
06a2c219 3798
66ac4b0e
GM
3799 if (s->face->underline_defaulted_p)
3800 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3801 s->width, h);
3802 else
3803 {
3804 XGCValues xgcv;
3805 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3806 XSetForeground (s->display, s->gc, s->face->underline_color);
3807 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3808 s->width, h);
3809 XSetForeground (s->display, s->gc, xgcv.foreground);
3810 }
dc6f92b8 3811 }
07e34cb0 3812
66ac4b0e
GM
3813 /* Draw overline. */
3814 if (s->face->overline_p)
06a2c219 3815 {
66ac4b0e
GM
3816 unsigned long dy = 0, h = 1;
3817
3818 if (s->face->overline_color_defaulted_p)
3819 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3820 s->width, h);
3821 else
3822 {
3823 XGCValues xgcv;
3824 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3825 XSetForeground (s->display, s->gc, s->face->overline_color);
3826 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3827 s->width, h);
3828 XSetForeground (s->display, s->gc, xgcv.foreground);
3829 }
06a2c219 3830 }
06a2c219 3831
66ac4b0e
GM
3832 /* Draw strike-through. */
3833 if (s->face->strike_through_p)
06a2c219 3834 {
66ac4b0e
GM
3835 unsigned long h = 1;
3836 unsigned long dy = (s->height - h) / 2;
3837
3838 if (s->face->strike_through_color_defaulted_p)
3839 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3840 s->width, h);
3841 else
3842 {
3843 XGCValues xgcv;
3844 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3845 XSetForeground (s->display, s->gc, s->face->strike_through_color);
3846 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3847 s->width, h);
3848 XSetForeground (s->display, s->gc, xgcv.foreground);
3849 }
06a2c219 3850 }
06a2c219 3851
66ac4b0e
GM
3852 /* Draw relief. */
3853 if (s->face->box != FACE_NO_BOX)
3854 x_draw_glyph_string_box (s);
3855 }
06a2c219
GM
3856
3857 /* Reset clipping. */
3858 XSetClipMask (s->display, s->gc, None);
dc6f92b8 3859}
07e34cb0 3860
06a2c219
GM
3861
3862/* A work-list entry used during the construction of glyph_string
3863 structures for a composite character. */
3864
3865struct work
3866{
3867 /* Pointer to composite char info defining has the composite
3868 character is drawn. */
3869 struct cmpchar_info *cmpcharp;
3870
3871 /* Start index in compcharp->glyph[]. */
3872 int gidx;
3873
3874 /* Next in stack. */
3875 struct work *next;
3876};
3877
3878
3879static void x_fill_composite_glyph_string P_ ((struct glyph_string *,
3880 int, struct work **,
66ac4b0e 3881 struct work **, int));
06a2c219
GM
3882
3883
3884/* Load glyph string S with information from the top of *STACK for a
3885 composite character. FACE_ID is the id of the face in which S is
3886 drawn. *NEW is a pointer to a struct work not on the stack, that
3887 can be used if this function needs to push a new structure on the
66ac4b0e
GM
3888 stack. If it uses it, *NEW is set to null. OVERLAPS_P non-zero
3889 means S should draw the foreground only, and use its lines physical
3890 height for clipping. */
07e34cb0
JB
3891
3892static void
66ac4b0e 3893x_fill_composite_glyph_string (s, face_id, stack, new, overlaps_p)
06a2c219
GM
3894 struct glyph_string *s;
3895 int face_id;
3896 struct work **stack, **new;
66ac4b0e 3897 int overlaps_p;
07e34cb0 3898{
06a2c219
GM
3899 int i, c;
3900 struct work *work;
3901
3902 xassert (s && *new && *stack);
3903
66ac4b0e
GM
3904 s->for_overlaps_p = 1;
3905
06a2c219
GM
3906 /* Pop the work stack. */
3907 work = *stack;
3908 *stack = work->next;
3909
3910 /* For all glyphs of cmpcharp->glyph, starting at the offset
3911 work->offset, until we reach the end of the definition or
3912 encounter another composite char, get the font and face to use,
3913 and add it to S. */
3914 for (i = work->gidx; i < work->cmpcharp->glyph_len; ++i)
3915 {
3916 c = FAST_GLYPH_CHAR (work->cmpcharp->glyph[i]);
3917 if (CHAR_CHARSET (c) == CHARSET_COMPOSITION)
3918 break;
3919 s->face = x_get_char_face_and_encoding (s->f, c, face_id,
3920 s->char2b + s->nchars, 1);
3921 s->font = s->face->font;
3922 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
3923 ++s->nchars;
3924 }
3925
3926 /* If we find another composite char in the glyph definition of
3927 work->cmpcharp, put back the rest of the glyphs on the work
3928 stack, and make a new entry for the composite char. */
3929 if (i < work->cmpcharp->glyph_len)
3930 {
3931 /* Push back an unprocessed rest of this glyph spec. */
3932 if (i < work->cmpcharp->glyph_len - 1)
3933 {
3934 work->gidx = i + 1;
3935 work->next = *stack;
3936 *stack = work;
3937 work = *new;
3938 *new = NULL;
3939 }
3940
3941 /* Make an entry for the composite char on the work stack. */
3942 work->cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (c)];
3943 work->gidx = 0;
3944 work->next = *stack;
3945 *stack = work;
3946 }
3947
3948 /* The width of this glyph string equals the width of the first
3949 glyph. All characters are drawn at the same x-position. */
3950 s->width = s->first_glyph->pixel_width;
3951
3952 /* If the specified font could not be loaded, use the frame's
3953 default font, but record the fact that we couldn't load it in
3954 the glyph string so that we can draw rectangles for the
3955 characters of the glyph string. */
3956 if (s->font == NULL)
3957 {
3958 s->font_not_found_p = 1;
3959 s->font = FRAME_FONT (s->f);
3960 }
3961
3962 /* Adjust base line for subscript/superscript text. */
3963 s->ybase += s->first_glyph->voffset;
3964
3965 xassert (s->face && s->face->gc);
3966
3967 /* This glyph string must always be drawn with 16-bit functions. */
3968 s->two_byte_p = 1;
3969}
3970
3971
3972/* Load glyph string S with a sequence of non-composite characters.
3973 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
3974 first glyph to consider, END is the index of the last + 1.
3975 OVERLAPS_P non-zero means S should draw the foreground only, and
3976 use its lines physical height for clipping.
3977
3978 Value is the index of the first glyph not in S. */
06a2c219
GM
3979
3980static int
66ac4b0e 3981x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
3982 struct glyph_string *s;
3983 int face_id;
66ac4b0e 3984 int start, end, overlaps_p;
06a2c219
GM
3985{
3986 struct glyph *glyph, *last;
3987 int voffset;
3988
3989 xassert (s->charset != CHARSET_COMPOSITION);
3990 xassert (s->f == XFRAME (s->w->frame));
3991 xassert (s->nchars == 0);
3992 xassert (start >= 0 && end > start);
3993
66ac4b0e 3994 s->for_overlaps_p = overlaps_p,
06a2c219
GM
3995 glyph = s->row->glyphs[s->area] + start;
3996 last = s->row->glyphs[s->area] + end;
3997 voffset = glyph->voffset;
3998
3999 while (glyph < last
4000 && glyph->type == CHAR_GLYPH
4001 && glyph->voffset == voffset
4002 /* Same face id implies same charset, nowadays. */
4003 && glyph->u.ch.face_id == face_id)
4004 {
4005 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
4006 s->char2b + s->nchars);
4007 if (s->char2b[s->nchars].byte2 != 0)
4008 s->two_byte_p = 1;
4009
4010 ++s->nchars;
4011 xassert (s->nchars <= end - start);
4012 s->width += glyph->pixel_width;
4013 ++glyph;
4014 }
4015
4016 s->font = s->face->font;
4017 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4018
4019 /* If the specified font could not be loaded, use the frame's font,
4020 but record the fact that we couldn't load it in
4021 S->font_not_found_p so that we can draw rectangles for the
4022 characters of the glyph string. */
4023 if (s->font == NULL)
4024 {
4025 s->font_not_found_p = 1;
4026 s->font = FRAME_FONT (s->f);
4027 }
4028
4029 /* Adjust base line for subscript/superscript text. */
4030 s->ybase += voffset;
66ac4b0e 4031
06a2c219
GM
4032 xassert (s->face && s->face->gc);
4033 return glyph - s->row->glyphs[s->area];
07e34cb0 4034}
dc6f92b8 4035
06a2c219
GM
4036
4037/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4038
dfcf069d 4039static void
06a2c219
GM
4040x_fill_image_glyph_string (s)
4041 struct glyph_string *s;
4042{
4043 xassert (s->first_glyph->type == IMAGE_GLYPH);
4044 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img.id);
4045 xassert (s->img);
4046 s->face = FACE_FROM_ID (s->f, s->first_glyph->u.img.face_id);
4047 s->font = s->face->font;
4048 s->width = s->first_glyph->pixel_width;
4049
4050 /* Adjust base line for subscript/superscript text. */
4051 s->ybase += s->first_glyph->voffset;
4052}
4053
4054
4055/* Fill glyph string S from stretch glyph S->first_glyph. */
4056
4057static void
4058x_fill_stretch_glyph_string (s)
4059 struct glyph_string *s;
4060{
4061 xassert (s->first_glyph->type == STRETCH_GLYPH);
4062 s->face = FACE_FROM_ID (s->f, s->first_glyph->u.stretch.face_id);
4063 s->font = s->face->font;
4064 s->width = s->first_glyph->pixel_width;
4065
4066 /* Adjust base line for subscript/superscript text. */
4067 s->ybase += s->first_glyph->voffset;
4068}
4069
4070
4071/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4072 of XChar2b structures for S; it can't be allocated in
4073 x_init_glyph_string because it must be allocated via `alloca'. W
4074 is the window on which S is drawn. ROW and AREA are the glyph row
4075 and area within the row from which S is constructed. START is the
4076 index of the first glyph structure covered by S. HL is a
4077 face-override for drawing S. */
4078
4079static void
4080x_init_glyph_string (s, char2b, w, row, area, start, hl)
4081 struct glyph_string *s;
4082 XChar2b *char2b;
4083 struct window *w;
4084 struct glyph_row *row;
4085 enum glyph_row_area area;
4086 int start;
4087 enum draw_glyphs_face hl;
4088{
4089 bzero (s, sizeof *s);
4090 s->w = w;
4091 s->f = XFRAME (w->frame);
4092 s->display = FRAME_X_DISPLAY (s->f);
4093 s->window = FRAME_X_WINDOW (s->f);
4094 s->char2b = char2b;
4095 s->hl = hl;
4096 s->row = row;
4097 s->area = area;
4098 s->first_glyph = row->glyphs[area] + start;
4099 s->height = row->height;
4100 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4101
9ea173e8
GM
4102 /* Display the internal border below the tool-bar window. */
4103 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4104 s->y -= s->f->output_data.x->internal_border_width;
4105
4106 s->ybase = s->y + row->ascent;
4107}
4108
4109
4110/* Set background width of glyph string S. START is the index of the
4111 first glyph following S. LAST_X is the right-most x-position + 1
4112 in the drawing area. */
4113
4114static INLINE void
4115x_set_glyph_string_background_width (s, start, last_x)
4116 struct glyph_string *s;
4117 int start;
4118 int last_x;
4119{
4120 /* If the face of this glyph string has to be drawn to the end of
4121 the drawing area, set S->extends_to_end_of_line_p. */
4122 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4123
4124 if (start == s->row->used[s->area]
4125 && s->hl == DRAW_NORMAL_TEXT
4126 && ((s->area == TEXT_AREA && s->row->fill_line_p)
4127 || s->face->background != default_face->background
4128 || s->face->stipple != default_face->stipple))
4129 s->extends_to_end_of_line_p = 1;
4130
4131 /* If S extends its face to the end of the line, set its
4132 background_width to the distance to the right edge of the drawing
4133 area. */
4134 if (s->extends_to_end_of_line_p)
1da3fd71 4135 s->background_width = last_x - s->x + 1;
06a2c219
GM
4136 else
4137 s->background_width = s->width;
4138}
4139
4140
4141/* Add a glyph string for a stretch glyph to the list of strings
4142 between HEAD and TAIL. START is the index of the stretch glyph in
4143 row area AREA of glyph row ROW. END is the index of the last glyph
4144 in that glyph row area. X is the current output position assigned
4145 to the new glyph string constructed. HL overrides that face of the
4146 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4147 is the right-most x-position of the drawing area. */
4148
8abee2e1
DL
4149/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4150 and below -- keep them on one line. */
4151#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4152 do \
4153 { \
4154 s = (struct glyph_string *) alloca (sizeof *s); \
4155 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4156 x_fill_stretch_glyph_string (s); \
4157 x_append_glyph_string (&HEAD, &TAIL, s); \
4158 ++START; \
4159 s->x = (X); \
4160 } \
4161 while (0)
4162
4163
4164/* Add a glyph string for an image glyph to the list of strings
4165 between HEAD and TAIL. START is the index of the image glyph in
4166 row area AREA of glyph row ROW. END is the index of the last glyph
4167 in that glyph row area. X is the current output position assigned
4168 to the new glyph string constructed. HL overrides that face of the
4169 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4170 is the right-most x-position of the drawing area. */
4171
8abee2e1 4172#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4173 do \
4174 { \
4175 s = (struct glyph_string *) alloca (sizeof *s); \
4176 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4177 x_fill_image_glyph_string (s); \
4178 x_append_glyph_string (&HEAD, &TAIL, s); \
4179 ++START; \
4180 s->x = (X); \
4181 } \
4182 while (0)
4183
4184
4185/* Add a glyph string for a sequence of character glyphs to the list
4186 of strings between HEAD and TAIL. START is the index of the first
4187 glyph in row area AREA of glyph row ROW that is part of the new
4188 glyph string. END is the index of the last glyph in that glyph row
4189 area. X is the current output position assigned to the new glyph
4190 string constructed. HL overrides that face of the glyph; e.g. it
4191 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4192 right-most x-position of the drawing area. */
4193
8abee2e1 4194#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4195 do \
4196 { \
4197 int c, charset, face_id; \
4198 XChar2b *char2b; \
4199 \
4200 c = (ROW)->glyphs[AREA][START].u.ch.code; \
4201 charset = CHAR_CHARSET (c); \
4202 face_id = (ROW)->glyphs[AREA][START].u.ch.face_id; \
4203 \
4204 if (charset == CHARSET_COMPOSITION) \
4205 { \
4206 struct work *stack, *work, *new = NULL; \
4207 int n = 0; \
4208 struct glyph_string *first_s = NULL; \
4209 \
4210 /* Push an initial entry for character c on the stack. */ \
4211 stack = NULL; \
4212 work = (struct work *) alloca (sizeof *work); \
4213 work->cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (c)]; \
4214 work->gidx = 0; \
4215 work->next = stack; \
4216 stack = work; \
4217 \
4218 /* While the stack is not empty, append glyph_strings \
4219 to head/tail for glyphs to draw. */ \
4220 while (stack) \
4221 { \
4222 s = (struct glyph_string *) alloca (sizeof *s); \
4223 char2b = (XChar2b *) alloca (stack->cmpcharp->glyph_len \
4224 * sizeof (XChar2b)); \
4225 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4226 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4227 s->cmpcharp = stack->cmpcharp; \
4228 s->gidx = stack->gidx; \
4229 s->charset = charset; \
4230 s->x = (X); \
4231 \
4232 if (n == 0) \
4233 { \
4234 /* Don't draw the background except for the \
4235 first glyph string. */ \
4236 s->background_filled_p = n > 0; \
4237 first_s = s; \
4238 } \
4239 ++n; \
4240 \
4241 if (new == NULL) \
4242 new = (struct work *) alloca (sizeof *new); \
4243 x_fill_composite_glyph_string (s, face_id, &stack, \
66ac4b0e 4244 &new, OVERLAPS_P); \
06a2c219
GM
4245 } \
4246 \
4247 ++START; \
4248 s = first_s; \
4249 } \
4250 else \
4251 { \
4252 s = (struct glyph_string *) alloca (sizeof *s); \
4253 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4254 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4255 x_append_glyph_string (&HEAD, &TAIL, s); \
4256 s->charset = charset; \
4257 s->x = (X); \
66ac4b0e
GM
4258 START = x_fill_glyph_string (s, face_id, START, END, \
4259 OVERLAPS_P); \
06a2c219
GM
4260 } \
4261 } \
4262 while (0)
4263
4264
4265/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4266 of AREA of glyph row ROW on window W between indices START and END.
4267 HL overrides the face for drawing glyph strings, e.g. it is
4268 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4269 x-positions of the drawing area.
4270
4271 This is an ugly monster macro construct because we must use alloca
4272 to allocate glyph strings (because x_draw_glyphs can be called
4273 asynchronously). */
4274
8abee2e1 4275#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4276 do \
4277 { \
4278 HEAD = TAIL = NULL; \
4279 while (START < END) \
4280 { \
4281 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4282 switch (first_glyph->type) \
4283 { \
4284 case CHAR_GLYPH: \
4285 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4286 TAIL, HL, X, LAST_X, \
4287 OVERLAPS_P); \
06a2c219
GM
4288 break; \
4289 \
4290 case STRETCH_GLYPH: \
4291 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
4292 HEAD, TAIL, HL, X, LAST_X); \
4293 break; \
4294 \
4295 case IMAGE_GLYPH: \
4296 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
4297 TAIL, HL, X, LAST_X); \
4298 break; \
4299 \
4300 default: \
4301 abort (); \
4302 } \
4303 \
4304 x_set_glyph_string_background_width (s, START, LAST_X); \
4305 (X) += s->width; \
4306 } \
4307 } \
4308 while (0)
4309
4310
4311/* Draw glyphs between START and END in AREA of ROW on window W,
4312 starting at x-position X. X is relative to AREA in W. HL is a
4313 face-override with the following meaning:
4314
4315 DRAW_NORMAL_TEXT draw normally
4316 DRAW_CURSOR draw in cursor face
4317 DRAW_MOUSE_FACE draw in mouse face.
4318 DRAW_INVERSE_VIDEO draw in mode line face
4319 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
4320 DRAW_IMAGE_RAISED draw an image with a raised relief around it
4321
4322 If REAL_START is non-null, return in *REAL_START the real starting
4323 position for display. This can be different from START in case
4324 overlapping glyphs must be displayed. If REAL_END is non-null,
4325 return in *REAL_END the real end position for display. This can be
4326 different from END in case overlapping glyphs must be displayed.
4327
66ac4b0e
GM
4328 If OVERLAPS_P is non-zero, draw only the foreground of characters
4329 and clip to the physical height of ROW.
4330
06a2c219
GM
4331 Value is the x-position reached, relative to AREA of W. */
4332
4333static int
66ac4b0e
GM
4334x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
4335 overlaps_p)
06a2c219
GM
4336 struct window *w;
4337 int x;
4338 struct glyph_row *row;
4339 enum glyph_row_area area;
4340 int start, end;
4341 enum draw_glyphs_face hl;
4342 int *real_start, *real_end;
66ac4b0e 4343 int overlaps_p;
dc6f92b8 4344{
06a2c219
GM
4345 struct glyph_string *head, *tail;
4346 struct glyph_string *s;
4347 int last_x, area_width;
4348 int x_reached;
4349 int i, j;
4350
4351 /* Let's rather be paranoid than getting a SEGV. */
4352 start = max (0, start);
4353 end = min (end, row->used[area]);
4354 if (real_start)
4355 *real_start = start;
4356 if (real_end)
4357 *real_end = end;
4358
4359 /* Translate X to frame coordinates. Set last_x to the right
4360 end of the drawing area. */
4361 if (row->full_width_p)
4362 {
4363 /* X is relative to the left edge of W, without scroll bars
4364 or flag areas. */
4365 struct frame *f = XFRAME (w->frame);
110859fc 4366 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 4367 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 4368
06a2c219
GM
4369 x += window_left_x;
4370 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
4371 last_x = window_left_x + area_width;
4372
4373 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4374 {
110859fc 4375 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
4376 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
4377 last_x += width;
4378 else
4379 x -= width;
4380 }
dc6f92b8 4381
b9432a85
GM
4382 x += FRAME_INTERNAL_BORDER_WIDTH (f);
4383 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
4384 }
4385 else
dc6f92b8 4386 {
06a2c219
GM
4387 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
4388 area_width = window_box_width (w, area);
4389 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
4390 }
4391
06a2c219
GM
4392 /* Build a doubly-linked list of glyph_string structures between
4393 head and tail from what we have to draw. Note that the macro
4394 BUILD_GLYPH_STRINGS will modify its start parameter. That's
4395 the reason we use a separate variable `i'. */
4396 i = start;
66ac4b0e
GM
4397 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
4398 overlaps_p);
06a2c219
GM
4399 if (tail)
4400 x_reached = tail->x + tail->background_width;
4401 else
4402 x_reached = x;
90e65f07 4403
06a2c219
GM
4404 /* If there are any glyphs with lbearing < 0 or rbearing > width in
4405 the row, redraw some glyphs in front or following the glyph
4406 strings built above. */
66ac4b0e 4407 if (!overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
4408 {
4409 int dummy_x = 0;
4410 struct glyph_string *h, *t;
4411
4412 /* Compute overhangs for all glyph strings. */
4413 for (s = head; s; s = s->next)
4414 x_compute_glyph_string_overhangs (s);
4415
4416 /* Prepend glyph strings for glyphs in front of the first glyph
4417 string that are overwritten because of the first glyph
4418 string's left overhang. The background of all strings
4419 prepended must be drawn because the first glyph string
4420 draws over it. */
4421 i = x_left_overwritten (head);
4422 if (i >= 0)
4423 {
4424 j = i;
4425 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
4426 DRAW_NORMAL_TEXT, dummy_x, last_x,
4427 overlaps_p);
06a2c219
GM
4428 start = i;
4429 if (real_start)
4430 *real_start = start;
4431 x_compute_overhangs_and_x (t, head->x, 1);
4432 x_prepend_glyph_string_lists (&head, &tail, h, t);
4433 }
58769bee 4434
06a2c219
GM
4435 /* Prepend glyph strings for glyphs in front of the first glyph
4436 string that overwrite that glyph string because of their
4437 right overhang. For these strings, only the foreground must
4438 be drawn, because it draws over the glyph string at `head'.
4439 The background must not be drawn because this would overwrite
4440 right overhangs of preceding glyphs for which no glyph
4441 strings exist. */
4442 i = x_left_overwriting (head);
4443 if (i >= 0)
4444 {
4445 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
4446 DRAW_NORMAL_TEXT, dummy_x, last_x,
4447 overlaps_p);
06a2c219
GM
4448 for (s = h; s; s = s->next)
4449 s->background_filled_p = 1;
4450 if (real_start)
4451 *real_start = i;
4452 x_compute_overhangs_and_x (t, head->x, 1);
4453 x_prepend_glyph_string_lists (&head, &tail, h, t);
4454 }
dbcb258a 4455
06a2c219
GM
4456 /* Append glyphs strings for glyphs following the last glyph
4457 string tail that are overwritten by tail. The background of
4458 these strings has to be drawn because tail's foreground draws
4459 over it. */
4460 i = x_right_overwritten (tail);
4461 if (i >= 0)
4462 {
4463 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4464 DRAW_NORMAL_TEXT, x, last_x,
4465 overlaps_p);
06a2c219
GM
4466 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4467 x_append_glyph_string_lists (&head, &tail, h, t);
4468 if (real_end)
4469 *real_end = i;
4470 }
dc6f92b8 4471
06a2c219
GM
4472 /* Append glyph strings for glyphs following the last glyph
4473 string tail that overwrite tail. The foreground of such
4474 glyphs has to be drawn because it writes into the background
4475 of tail. The background must not be drawn because it could
4476 paint over the foreground of following glyphs. */
4477 i = x_right_overwriting (tail);
4478 if (i >= 0)
4479 {
4480 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4481 DRAW_NORMAL_TEXT, x, last_x,
4482 overlaps_p);
06a2c219
GM
4483 for (s = h; s; s = s->next)
4484 s->background_filled_p = 1;
4485 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4486 x_append_glyph_string_lists (&head, &tail, h, t);
4487 if (real_end)
4488 *real_end = i;
4489 }
4490 }
58769bee 4491
06a2c219
GM
4492 /* Draw all strings. */
4493 for (s = head; s; s = s->next)
4494 x_draw_glyph_string (s);
dc6f92b8 4495
06a2c219
GM
4496 /* Value is the x-position up to which drawn, relative to AREA of W.
4497 This doesn't include parts drawn because of overhangs. */
4498 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
4499 if (!row->full_width_p)
4500 {
4501 if (area > LEFT_MARGIN_AREA)
4502 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
4503 if (area > TEXT_AREA)
4504 x_reached -= window_box_width (w, TEXT_AREA);
4505 }
4506 return x_reached;
4507}
dc6f92b8 4508
dc6f92b8 4509
66ac4b0e
GM
4510/* Fix the display of area AREA of overlapping row ROW in window W. */
4511
4512static void
4513x_fix_overlapping_area (w, row, area)
4514 struct window *w;
4515 struct glyph_row *row;
4516 enum glyph_row_area area;
4517{
4518 int i, x;
4519
4520 BLOCK_INPUT;
4521
4522 if (area == LEFT_MARGIN_AREA)
4523 x = 0;
4524 else if (area == TEXT_AREA)
4525 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
4526 else
4527 x = (window_box_width (w, LEFT_MARGIN_AREA)
4528 + window_box_width (w, TEXT_AREA));
4529
4530 for (i = 0; i < row->used[area];)
4531 {
4532 if (row->glyphs[area][i].overlaps_vertically_p)
4533 {
4534 int start = i, start_x = x;
4535
4536 do
4537 {
4538 x += row->glyphs[area][i].pixel_width;
4539 ++i;
4540 }
4541 while (i < row->used[area]
4542 && row->glyphs[area][i].overlaps_vertically_p);
4543
4544 x_draw_glyphs (w, start_x, row, area, start, i,
4545 (row->inverse_p
4546 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
4547 NULL, NULL, 1);
4548 }
4549 else
4550 {
4551 x += row->glyphs[area][i].pixel_width;
4552 ++i;
4553 }
4554 }
4555
4556 UNBLOCK_INPUT;
4557}
4558
4559
06a2c219
GM
4560/* Output LEN glyphs starting at START at the nominal cursor position.
4561 Advance the nominal cursor over the text. The global variable
4562 updated_window contains the window being updated, updated_row is
4563 the glyph row being updated, and updated_area is the area of that
4564 row being updated. */
dc6f92b8 4565
06a2c219
GM
4566static void
4567x_write_glyphs (start, len)
4568 struct glyph *start;
4569 int len;
4570{
4571 int x, hpos, real_start, real_end;
d9cdbb3d 4572
06a2c219 4573 xassert (updated_window && updated_row);
dc6f92b8 4574 BLOCK_INPUT;
06a2c219
GM
4575
4576 /* Write glyphs. */
dc6f92b8 4577
06a2c219
GM
4578 hpos = start - updated_row->glyphs[updated_area];
4579 x = x_draw_glyphs (updated_window, output_cursor.x,
4580 updated_row, updated_area,
4581 hpos, hpos + len,
4582 (updated_row->inverse_p
4583 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
66ac4b0e 4584 &real_start, &real_end, 0);
b30ec466 4585
06a2c219
GM
4586 /* If we drew over the cursor, note that it is not visible any more. */
4587 note_overwritten_text_cursor (updated_window, real_start,
4588 real_end - real_start);
dc6f92b8
JB
4589
4590 UNBLOCK_INPUT;
06a2c219
GM
4591
4592 /* Advance the output cursor. */
4593 output_cursor.hpos += len;
4594 output_cursor.x = x;
dc6f92b8
JB
4595}
4596
0cdd0c9f 4597
06a2c219 4598/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 4599
06a2c219
GM
4600static void
4601x_insert_glyphs (start, len)
4602 struct glyph *start;
4603 register int len;
4604{
4605 struct frame *f;
4606 struct window *w;
4607 int line_height, shift_by_width, shifted_region_width;
4608 struct glyph_row *row;
4609 struct glyph *glyph;
4610 int frame_x, frame_y, hpos, real_start, real_end;
58769bee 4611
06a2c219 4612 xassert (updated_window && updated_row);
0cdd0c9f 4613 BLOCK_INPUT;
06a2c219
GM
4614 w = updated_window;
4615 f = XFRAME (WINDOW_FRAME (w));
4616
4617 /* Get the height of the line we are in. */
4618 row = updated_row;
4619 line_height = row->height;
4620
4621 /* Get the width of the glyphs to insert. */
4622 shift_by_width = 0;
4623 for (glyph = start; glyph < start + len; ++glyph)
4624 shift_by_width += glyph->pixel_width;
4625
4626 /* Get the width of the region to shift right. */
4627 shifted_region_width = (window_box_width (w, updated_area)
4628 - output_cursor.x
4629 - shift_by_width);
4630
4631 /* Shift right. */
4632 frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x);
4633 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
4634 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
4635 f->output_data.x->normal_gc,
4636 frame_x, frame_y,
4637 shifted_region_width, line_height,
4638 frame_x + shift_by_width, frame_y);
4639
4640 /* Write the glyphs. */
4641 hpos = start - row->glyphs[updated_area];
4642 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
66ac4b0e 4643 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
06a2c219
GM
4644 note_overwritten_text_cursor (w, real_start, real_end - real_start);
4645
4646 /* Advance the output cursor. */
4647 output_cursor.hpos += len;
4648 output_cursor.x += shift_by_width;
0cdd0c9f
RS
4649 UNBLOCK_INPUT;
4650}
0cdd0c9f 4651
0cdd0c9f 4652
06a2c219
GM
4653/* Delete N glyphs at the nominal cursor position. Not implemented
4654 for X frames. */
c83febd7
RS
4655
4656static void
06a2c219
GM
4657x_delete_glyphs (n)
4658 register int n;
c83febd7 4659{
06a2c219 4660 abort ();
c83febd7
RS
4661}
4662
0cdd0c9f 4663
06a2c219
GM
4664/* Erase the current text line from the nominal cursor position
4665 (inclusive) to pixel column TO_X (exclusive). The idea is that
4666 everything from TO_X onward is already erased.
4667
4668 TO_X is a pixel position relative to updated_area of
4669 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 4670
06a2c219
GM
4671static void
4672x_clear_end_of_line (to_x)
4673 int to_x;
4674{
4675 struct frame *f;
4676 struct window *w = updated_window;
4677 int max_x, min_y, max_y;
4678 int from_x, from_y, to_y;
4679
4680 xassert (updated_window && updated_row);
4681 f = XFRAME (w->frame);
4682
4683 if (updated_row->full_width_p)
4684 {
4685 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
4686 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4687 && !w->pseudo_window_p)
4688 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 4689 }
06a2c219
GM
4690 else
4691 max_x = window_box_width (w, updated_area);
4692 max_y = window_text_bottom_y (w);
dc6f92b8 4693
06a2c219
GM
4694 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
4695 of window. For TO_X > 0, truncate to end of drawing area. */
4696 if (to_x == 0)
4697 return;
4698 else if (to_x < 0)
4699 to_x = max_x;
4700 else
4701 to_x = min (to_x, max_x);
dbc4e1c1 4702
06a2c219
GM
4703 to_y = min (max_y, output_cursor.y + updated_row->height);
4704
4705 /* Notice if the cursor will be cleared by this operation. */
4706 if (!updated_row->full_width_p)
4707 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
dbc4e1c1 4708
06a2c219
GM
4709 from_x = output_cursor.x;
4710
4711 /* Translate to frame coordinates. */
4712 if (updated_row->full_width_p)
4713 {
4714 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
4715 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
4716 }
0cdd0c9f
RS
4717 else
4718 {
06a2c219
GM
4719 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
4720 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
4721 }
4722
045dee35 4723 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
4724 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
4725 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
4726
4727 /* Prevent inadvertently clearing to end of the X window. */
4728 if (to_x > from_x && to_y > from_y)
4729 {
4730 BLOCK_INPUT;
4731 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4732 from_x, from_y, to_x - from_x, to_y - from_y,
4733 False);
4734 UNBLOCK_INPUT;
0cdd0c9f 4735 }
0cdd0c9f 4736}
dbc4e1c1 4737
0cdd0c9f 4738
06a2c219 4739/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 4740 frame. Otherwise clear the selected frame. */
06a2c219
GM
4741
4742static void
4743x_clear_frame ()
0cdd0c9f 4744{
06a2c219 4745 struct frame *f;
0cdd0c9f 4746
06a2c219
GM
4747 if (updating_frame)
4748 f = updating_frame;
0cdd0c9f 4749 else
b86bd3dd 4750 f = SELECTED_FRAME ();
58769bee 4751
06a2c219
GM
4752 /* Clearing the frame will erase any cursor, so mark them all as no
4753 longer visible. */
4754 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4755 output_cursor.hpos = output_cursor.vpos = 0;
4756 output_cursor.x = -1;
4757
4758 /* We don't set the output cursor here because there will always
4759 follow an explicit cursor_to. */
4760 BLOCK_INPUT;
4761 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
4762
4763 /* We have to clear the scroll bars, too. If we have changed
4764 colors or something like that, then they should be notified. */
4765 x_scroll_bar_clear (f);
0cdd0c9f 4766
06a2c219
GM
4767 XFlush (FRAME_X_DISPLAY (f));
4768 UNBLOCK_INPUT;
dc6f92b8 4769}
06a2c219
GM
4770
4771
dc6f92b8 4772\f
dbc4e1c1
JB
4773/* Invert the middle quarter of the frame for .15 sec. */
4774
06a2c219
GM
4775/* We use the select system call to do the waiting, so we have to make
4776 sure it's available. If it isn't, we just won't do visual bells. */
4777
dbc4e1c1
JB
4778#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4779
06a2c219
GM
4780
4781/* Subtract the `struct timeval' values X and Y, storing the result in
4782 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
4783
4784static int
4785timeval_subtract (result, x, y)
4786 struct timeval *result, x, y;
4787{
06a2c219
GM
4788 /* Perform the carry for the later subtraction by updating y. This
4789 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
4790 if (x.tv_usec < y.tv_usec)
4791 {
4792 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
4793 y.tv_usec -= 1000000 * nsec;
4794 y.tv_sec += nsec;
4795 }
06a2c219 4796
dbc4e1c1
JB
4797 if (x.tv_usec - y.tv_usec > 1000000)
4798 {
4799 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
4800 y.tv_usec += 1000000 * nsec;
4801 y.tv_sec -= nsec;
4802 }
4803
06a2c219
GM
4804 /* Compute the time remaining to wait. tv_usec is certainly
4805 positive. */
dbc4e1c1
JB
4806 result->tv_sec = x.tv_sec - y.tv_sec;
4807 result->tv_usec = x.tv_usec - y.tv_usec;
4808
06a2c219
GM
4809 /* Return indication of whether the result should be considered
4810 negative. */
dbc4e1c1
JB
4811 return x.tv_sec < y.tv_sec;
4812}
dc6f92b8 4813
dfcf069d 4814void
f676886a
JB
4815XTflash (f)
4816 struct frame *f;
dc6f92b8 4817{
dbc4e1c1 4818 BLOCK_INPUT;
dc6f92b8 4819
dbc4e1c1
JB
4820 {
4821 GC gc;
dc6f92b8 4822
06a2c219
GM
4823 /* Create a GC that will use the GXxor function to flip foreground
4824 pixels into background pixels. */
dbc4e1c1
JB
4825 {
4826 XGCValues values;
dc6f92b8 4827
dbc4e1c1 4828 values.function = GXxor;
7556890b
RS
4829 values.foreground = (f->output_data.x->foreground_pixel
4830 ^ f->output_data.x->background_pixel);
58769bee 4831
334208b7 4832 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
4833 GCFunction | GCForeground, &values);
4834 }
dc6f92b8 4835
dbc4e1c1 4836 {
e84e14c3
RS
4837 /* Get the height not including a menu bar widget. */
4838 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
4839 /* Height of each line to flash. */
4840 int flash_height = FRAME_LINE_HEIGHT (f);
4841 /* These will be the left and right margins of the rectangles. */
4842 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
4843 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
4844
4845 int width;
4846
4847 /* Don't flash the area between a scroll bar and the frame
4848 edge it is next to. */
4849 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
4850 {
4851 case vertical_scroll_bar_left:
4852 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4853 break;
4854
4855 case vertical_scroll_bar_right:
4856 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4857 break;
06a2c219
GM
4858
4859 default:
4860 break;
e84e14c3
RS
4861 }
4862
4863 width = flash_right - flash_left;
4864
4865 /* If window is tall, flash top and bottom line. */
4866 if (height > 3 * FRAME_LINE_HEIGHT (f))
4867 {
4868 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
4869 flash_left,
4870 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 4871 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
4872 width, flash_height);
4873 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4874 flash_left,
4875 (height - flash_height
4876 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4877 width, flash_height);
4878 }
4879 else
4880 /* If it is short, flash it all. */
4881 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4882 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4883 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 4884
06a2c219 4885 x_flush (f);
dc6f92b8 4886
dbc4e1c1 4887 {
06a2c219 4888 struct timeval wakeup;
dc6f92b8 4889
66c30ea1 4890 EMACS_GET_TIME (wakeup);
dc6f92b8 4891
dbc4e1c1
JB
4892 /* Compute time to wait until, propagating carry from usecs. */
4893 wakeup.tv_usec += 150000;
4894 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
4895 wakeup.tv_usec %= 1000000;
4896
4897 /* Keep waiting until past the time wakeup. */
4898 while (1)
4899 {
4900 struct timeval timeout;
4901
66c30ea1 4902 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
4903
4904 /* In effect, timeout = wakeup - timeout.
4905 Break if result would be negative. */
4906 if (timeval_subtract (&timeout, wakeup, timeout))
4907 break;
4908
4909 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 4910 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
4911 }
4912 }
58769bee 4913
e84e14c3
RS
4914 /* If window is tall, flash top and bottom line. */
4915 if (height > 3 * FRAME_LINE_HEIGHT (f))
4916 {
4917 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
4918 flash_left,
4919 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 4920 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
4921 width, flash_height);
4922 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4923 flash_left,
4924 (height - flash_height
4925 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4926 width, flash_height);
4927 }
4928 else
4929 /* If it is short, flash it all. */
4930 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4931 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4932 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4933
334208b7 4934 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 4935 x_flush (f);
dc6f92b8 4936 }
dbc4e1c1
JB
4937 }
4938
4939 UNBLOCK_INPUT;
dc6f92b8
JB
4940}
4941
06a2c219 4942#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
4943
4944
dc6f92b8
JB
4945/* Make audible bell. */
4946
dfcf069d 4947void
dc6f92b8
JB
4948XTring_bell ()
4949{
b86bd3dd
GM
4950 struct frame *f = SELECTED_FRAME ();
4951
4952 if (FRAME_X_DISPLAY (f))
4953 {
dbc4e1c1 4954#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
4955 if (visible_bell)
4956 XTflash (f);
4957 else
dbc4e1c1 4958#endif
b86bd3dd
GM
4959 {
4960 BLOCK_INPUT;
4961 XBell (FRAME_X_DISPLAY (f), 0);
4962 XFlush (FRAME_X_DISPLAY (f));
4963 UNBLOCK_INPUT;
4964 }
dc6f92b8
JB
4965 }
4966}
06a2c219 4967
dc6f92b8 4968\f
06a2c219
GM
4969/* Specify how many text lines, from the top of the window,
4970 should be affected by insert-lines and delete-lines operations.
4971 This, and those operations, are used only within an update
4972 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 4973
dfcf069d 4974static void
06a2c219
GM
4975XTset_terminal_window (n)
4976 register int n;
dc6f92b8 4977{
06a2c219 4978 /* This function intentionally left blank. */
dc6f92b8
JB
4979}
4980
06a2c219
GM
4981
4982\f
4983/***********************************************************************
4984 Line Dance
4985 ***********************************************************************/
4986
4987/* Perform an insert-lines or delete-lines operation, inserting N
4988 lines or deleting -N lines at vertical position VPOS. */
4989
dfcf069d 4990static void
06a2c219
GM
4991x_ins_del_lines (vpos, n)
4992 int vpos, n;
dc6f92b8
JB
4993{
4994 abort ();
4995}
06a2c219
GM
4996
4997
4998/* Scroll part of the display as described by RUN. */
dc6f92b8 4999
dfcf069d 5000static void
06a2c219
GM
5001x_scroll_run (w, run)
5002 struct window *w;
5003 struct run *run;
dc6f92b8 5004{
06a2c219
GM
5005 struct frame *f = XFRAME (w->frame);
5006 int x, y, width, height, from_y, to_y, bottom_y;
5007
5008 /* Get frame-relative bounding box of the text display area of W,
5009 without mode lines. Include in this box the flags areas to the
5010 left and right of W. */
5011 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5012 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5013 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5014
5015 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5016 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5017 bottom_y = y + height;
dc6f92b8 5018
06a2c219
GM
5019 if (to_y < from_y)
5020 {
5021 /* Scrolling up. Make sure we don't copy part of the mode
5022 line at the bottom. */
5023 if (from_y + run->height > bottom_y)
5024 height = bottom_y - from_y;
5025 else
5026 height = run->height;
5027 }
dc6f92b8 5028 else
06a2c219
GM
5029 {
5030 /* Scolling down. Make sure we don't copy over the mode line.
5031 at the bottom. */
5032 if (to_y + run->height > bottom_y)
5033 height = bottom_y - to_y;
5034 else
5035 height = run->height;
5036 }
7a13e894 5037
06a2c219
GM
5038 BLOCK_INPUT;
5039
5040 /* Cursor off. Will be switched on again in x_update_window_end. */
5041 updated_window = w;
5042 x_clear_cursor (w);
5043
5044 XCopyArea (FRAME_X_DISPLAY (f),
5045 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5046 f->output_data.x->normal_gc,
5047 x, from_y,
5048 width, height,
5049 x, to_y);
5050
5051 UNBLOCK_INPUT;
5052}
dc6f92b8 5053
dc6f92b8 5054
06a2c219
GM
5055\f
5056/***********************************************************************
5057 Exposure Events
5058 ***********************************************************************/
5059
5060/* Redisplay an exposed area of frame F. X and Y are the upper-left
5061 corner of the exposed rectangle. W and H are width and height of
5062 the exposed area. All are pixel values. W or H zero means redraw
5063 the entire frame. */
dc6f92b8 5064
06a2c219
GM
5065static void
5066expose_frame (f, x, y, w, h)
5067 struct frame *f;
5068 int x, y, w, h;
dc6f92b8 5069{
06a2c219 5070 XRectangle r;
dc6f92b8 5071
06a2c219 5072 TRACE ((stderr, "expose_frame "));
dc6f92b8 5073
06a2c219
GM
5074 /* No need to redraw if frame will be redrawn soon. */
5075 if (FRAME_GARBAGED_P (f))
dc6f92b8 5076 {
06a2c219
GM
5077 TRACE ((stderr, " garbaged\n"));
5078 return;
5079 }
5080
5081 /* If basic faces haven't been realized yet, there is no point in
5082 trying to redraw anything. This can happen when we get an expose
5083 event while Emacs is starting, e.g. by moving another window. */
5084 if (FRAME_FACE_CACHE (f) == NULL
5085 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5086 {
5087 TRACE ((stderr, " no faces\n"));
5088 return;
58769bee 5089 }
06a2c219
GM
5090
5091 if (w == 0 || h == 0)
58769bee 5092 {
06a2c219
GM
5093 r.x = r.y = 0;
5094 r.width = CANON_X_UNIT (f) * f->width;
5095 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5096 }
5097 else
5098 {
06a2c219
GM
5099 r.x = x;
5100 r.y = y;
5101 r.width = w;
5102 r.height = h;
5103 }
5104
5105 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
5106 expose_window_tree (XWINDOW (f->root_window), &r);
5107
9ea173e8 5108 if (WINDOWP (f->tool_bar_window))
06a2c219 5109 {
9ea173e8 5110 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
5111 XRectangle window_rect;
5112 XRectangle intersection_rect;
5113 int window_x, window_y, window_width, window_height;
5114
5115
5116 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5117 window_rect.x = window_x;
5118 window_rect.y = window_y;
5119 window_rect.width = window_width;
5120 window_rect.height = window_height;
5121
5122 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5123 expose_window (w, &intersection_rect);
5124 }
5125
5126#ifndef USE_X_TOOLKIT
5127 if (WINDOWP (f->menu_bar_window))
5128 {
5129 struct window *w = XWINDOW (f->menu_bar_window);
5130 XRectangle window_rect;
5131 XRectangle intersection_rect;
5132 int window_x, window_y, window_width, window_height;
5133
5134
5135 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5136 window_rect.x = window_x;
5137 window_rect.y = window_y;
5138 window_rect.width = window_width;
5139 window_rect.height = window_height;
5140
5141 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5142 expose_window (w, &intersection_rect);
dc6f92b8 5143 }
06a2c219 5144#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5145}
5146
06a2c219
GM
5147
5148/* Redraw (parts) of all windows in the window tree rooted at W that
5149 intersect R. R contains frame pixel coordinates. */
5150
58769bee 5151static void
06a2c219
GM
5152expose_window_tree (w, r)
5153 struct window *w;
5154 XRectangle *r;
dc6f92b8 5155{
06a2c219
GM
5156 while (w)
5157 {
5158 if (!NILP (w->hchild))
5159 expose_window_tree (XWINDOW (w->hchild), r);
5160 else if (!NILP (w->vchild))
5161 expose_window_tree (XWINDOW (w->vchild), r);
5162 else
5163 {
5164 XRectangle window_rect;
5165 XRectangle intersection_rect;
5166 struct frame *f = XFRAME (w->frame);
5167 int window_x, window_y, window_width, window_height;
5168
5169 /* Frame-relative pixel rectangle of W. */
5170 window_box (w, -1, &window_x, &window_y, &window_width,
5171 &window_height);
5172 window_rect.x
5173 = (window_x
110859fc 5174 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
714dc26c 5175 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
06a2c219
GM
5176 window_rect.y = window_y;
5177 window_rect.width
5178 = (window_width
110859fc 5179 + FRAME_X_FLAGS_AREA_WIDTH (f)
06a2c219
GM
5180 + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
5181 window_rect.height
5182 = window_height + CURRENT_MODE_LINE_HEIGHT (w);
5183
5184 if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
5185 expose_window (w, &intersection_rect);
5186 }
58769bee 5187
06a2c219
GM
5188 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5189 }
5190}
58769bee 5191
dc6f92b8 5192
06a2c219
GM
5193/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5194 which intersects rectangle R. R is in window-relative coordinates. */
5195
5196static void
5197expose_area (w, row, r, area)
5198 struct window *w;
5199 struct glyph_row *row;
5200 XRectangle *r;
5201 enum glyph_row_area area;
5202{
5203 int x;
5204 struct glyph *first = row->glyphs[area];
5205 struct glyph *end = row->glyphs[area] + row->used[area];
5206 struct glyph *last;
5207 int first_x;
5208
5209 /* Set x to the window-relative start position for drawing glyphs of
5210 AREA. The first glyph of the text area can be partially visible.
5211 The first glyphs of other areas cannot. */
5212 if (area == LEFT_MARGIN_AREA)
5213 x = 0;
5214 else if (area == TEXT_AREA)
5215 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5216 else
5217 x = (window_box_width (w, LEFT_MARGIN_AREA)
5218 + window_box_width (w, TEXT_AREA));
5219
6fb13182
GM
5220 if (area == TEXT_AREA && row->fill_line_p)
5221 /* If row extends face to end of line write the whole line. */
5222 x_draw_glyphs (w, x, row, area,
5223 0, row->used[area],
06a2c219 5224 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5225 NULL, NULL, 0);
6fb13182
GM
5226 else
5227 {
5228 /* Find the first glyph that must be redrawn. */
5229 while (first < end
5230 && x + first->pixel_width < r->x)
5231 {
5232 x += first->pixel_width;
5233 ++first;
5234 }
5235
5236 /* Find the last one. */
5237 last = first;
5238 first_x = x;
5239 while (last < end
5240 && x < r->x + r->width)
5241 {
5242 x += last->pixel_width;
5243 ++last;
5244 }
5245
5246 /* Repaint. */
5247 if (last > first)
5248 x_draw_glyphs (w, first_x, row, area,
5249 first - row->glyphs[area],
5250 last - row->glyphs[area],
5251 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5252 NULL, NULL, 0);
5253 }
06a2c219
GM
5254}
5255
58769bee 5256
06a2c219
GM
5257/* Redraw the parts of the glyph row ROW on window W intersecting
5258 rectangle R. R is in window-relative coordinates. */
dc6f92b8 5259
06a2c219
GM
5260static void
5261expose_line (w, row, r)
5262 struct window *w;
5263 struct glyph_row *row;
5264 XRectangle *r;
5265{
5266 xassert (row->enabled_p);
5267
5268 if (row->mode_line_p || w->pseudo_window_p)
5269 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5270 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5271 NULL, NULL, 0);
06a2c219
GM
5272 else
5273 {
5274 if (row->used[LEFT_MARGIN_AREA])
5275 expose_area (w, row, r, LEFT_MARGIN_AREA);
5276 if (row->used[TEXT_AREA])
5277 expose_area (w, row, r, TEXT_AREA);
5278 if (row->used[RIGHT_MARGIN_AREA])
5279 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5280 x_draw_row_bitmaps (w, row);
5281 }
5282}
dc6f92b8 5283
58769bee 5284
06a2c219
GM
5285/* Return non-zero if W's cursor intersects rectangle R. */
5286
5287static int
5288x_phys_cursor_in_rect_p (w, r)
5289 struct window *w;
5290 XRectangle *r;
5291{
5292 XRectangle cr, result;
5293 struct glyph *cursor_glyph;
5294
5295 cursor_glyph = get_phys_cursor_glyph (w);
5296 if (cursor_glyph)
5297 {
5298 cr.x = w->phys_cursor.x;
5299 cr.y = w->phys_cursor.y;
5300 cr.width = cursor_glyph->pixel_width;
5301 cr.height = w->phys_cursor_height;
5302 return x_intersect_rectangles (&cr, r, &result);
5303 }
5304 else
5305 return 0;
dc6f92b8 5306}
dc6f92b8 5307
06a2c219
GM
5308
5309/* Redraw a rectangle of window W. R is a rectangle in window
5310 relative coordinates. Call this function with input blocked. */
dc6f92b8
JB
5311
5312static void
06a2c219
GM
5313expose_window (w, r)
5314 struct window *w;
5315 XRectangle *r;
dc6f92b8 5316{
06a2c219
GM
5317 struct glyph_row *row;
5318 int y;
5319 int yb = window_text_bottom_y (w);
5320 int cursor_cleared_p;
dc6f92b8 5321
80c32bcc
GM
5322 /* If window is not yet fully initialized, do nothing. This can
5323 happen when toolkit scroll bars are used and a window is split.
5324 Reconfiguring the scroll bar will generate an expose for a newly
5325 created window. */
5326 if (w->current_matrix == NULL)
5327 return;
5328
06a2c219
GM
5329 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
5330 r->x, r->y, r->width, r->height));
dc6f92b8 5331
06a2c219
GM
5332 /* Convert to window coordinates. */
5333 r->x = FRAME_TO_WINDOW_PIXEL_X (w, r->x);
5334 r->y = FRAME_TO_WINDOW_PIXEL_Y (w, r->y);
dc6f92b8 5335
06a2c219
GM
5336 /* Turn off the cursor. */
5337 if (!w->pseudo_window_p
5338 && x_phys_cursor_in_rect_p (w, r))
5339 {
5340 x_clear_cursor (w);
5341 cursor_cleared_p = 1;
5342 }
5343 else
5344 cursor_cleared_p = 0;
5345
5346 /* Find the first row intersecting the rectangle R. */
5347 row = w->current_matrix->rows;
5348 y = 0;
5349 while (row->enabled_p
5350 && y < yb
5351 && y + row->height < r->y)
5352 {
5353 y += row->height;
5354 ++row;
5355 }
5356
dc6f92b8 5357 /* Display the text in the rectangle, one text line at a time. */
06a2c219
GM
5358 while (row->enabled_p
5359 && y < yb
5360 && y < r->y + r->height)
5361 {
5362 expose_line (w, row, r);
5363 y += row->height;
5364 ++row;
5365 }
5366
5367 /* Display the mode line if there is one. */
5368 if (WINDOW_WANTS_MODELINE_P (w)
5369 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
5370 row->enabled_p)
5371 && row->y < r->y + r->height)
5372 expose_line (w, row, r);
dc6f92b8 5373
06a2c219 5374 if (!w->pseudo_window_p)
dc6f92b8 5375 {
06a2c219
GM
5376 /* Draw border between windows. */
5377 x_draw_vertical_border (w);
5378
5379 /* Turn the cursor on again. */
5380 if (cursor_cleared_p)
5381 x_update_window_cursor (w, 1);
5382 }
5383}
dc6f92b8 5384
dc6f92b8 5385
06a2c219
GM
5386/* Determine the intersection of two rectangles R1 and R2. Return
5387 the intersection in *RESULT. Value is non-zero if RESULT is not
5388 empty. */
5389
5390static int
5391x_intersect_rectangles (r1, r2, result)
5392 XRectangle *r1, *r2, *result;
5393{
5394 XRectangle *left, *right;
5395 XRectangle *upper, *lower;
5396 int intersection_p = 0;
5397
5398 /* Rearrange so that R1 is the left-most rectangle. */
5399 if (r1->x < r2->x)
5400 left = r1, right = r2;
5401 else
5402 left = r2, right = r1;
5403
5404 /* X0 of the intersection is right.x0, if this is inside R1,
5405 otherwise there is no intersection. */
5406 if (right->x <= left->x + left->width)
5407 {
5408 result->x = right->x;
5409
5410 /* The right end of the intersection is the minimum of the
5411 the right ends of left and right. */
5412 result->width = (min (left->x + left->width, right->x + right->width)
5413 - result->x);
5414
5415 /* Same game for Y. */
5416 if (r1->y < r2->y)
5417 upper = r1, lower = r2;
5418 else
5419 upper = r2, lower = r1;
5420
5421 /* The upper end of the intersection is lower.y0, if this is inside
5422 of upper. Otherwise, there is no intersection. */
5423 if (lower->y <= upper->y + upper->height)
dc43ef94 5424 {
06a2c219
GM
5425 result->y = lower->y;
5426
5427 /* The lower end of the intersection is the minimum of the lower
5428 ends of upper and lower. */
5429 result->height = (min (lower->y + lower->height,
5430 upper->y + upper->height)
5431 - result->y);
5432 intersection_p = 1;
dc43ef94 5433 }
dc6f92b8
JB
5434 }
5435
06a2c219 5436 return intersection_p;
dc6f92b8 5437}
06a2c219
GM
5438
5439
5440
5441
dc6f92b8 5442\f
dc6f92b8 5443static void
334208b7
RS
5444frame_highlight (f)
5445 struct frame *f;
dc6f92b8 5446{
b3e1e05c
JB
5447 /* We used to only do this if Vx_no_window_manager was non-nil, but
5448 the ICCCM (section 4.1.6) says that the window's border pixmap
5449 and border pixel are window attributes which are "private to the
5450 client", so we can always change it to whatever we want. */
5451 BLOCK_INPUT;
334208b7 5452 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5453 f->output_data.x->border_pixel);
b3e1e05c 5454 UNBLOCK_INPUT;
5d46f928 5455 x_update_cursor (f, 1);
dc6f92b8
JB
5456}
5457
5458static void
334208b7
RS
5459frame_unhighlight (f)
5460 struct frame *f;
dc6f92b8 5461{
b3e1e05c
JB
5462 /* We used to only do this if Vx_no_window_manager was non-nil, but
5463 the ICCCM (section 4.1.6) says that the window's border pixmap
5464 and border pixel are window attributes which are "private to the
5465 client", so we can always change it to whatever we want. */
5466 BLOCK_INPUT;
334208b7 5467 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5468 f->output_data.x->border_tile);
b3e1e05c 5469 UNBLOCK_INPUT;
5d46f928 5470 x_update_cursor (f, 1);
dc6f92b8 5471}
dc6f92b8 5472
f676886a
JB
5473/* The focus has changed. Update the frames as necessary to reflect
5474 the new situation. Note that we can't change the selected frame
c5acd733 5475 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 5476 Each event gets marked with the frame in which it occurred, so the
c5acd733 5477 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 5478
6d4238f3 5479static void
0f941935
KH
5480x_new_focus_frame (dpyinfo, frame)
5481 struct x_display_info *dpyinfo;
f676886a 5482 struct frame *frame;
dc6f92b8 5483{
0f941935 5484 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 5485
0f941935 5486 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 5487 {
58769bee 5488 /* Set this before calling other routines, so that they see
f676886a 5489 the correct value of x_focus_frame. */
0f941935 5490 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
5491
5492 if (old_focus && old_focus->auto_lower)
f676886a 5493 x_lower_frame (old_focus);
dc6f92b8
JB
5494
5495#if 0
f676886a 5496 selected_frame = frame;
e0c1aef2
KH
5497 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
5498 selected_frame);
f676886a
JB
5499 Fselect_window (selected_frame->selected_window);
5500 choose_minibuf_frame ();
c118dd06 5501#endif /* ! 0 */
dc6f92b8 5502
0f941935
KH
5503 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
5504 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
5505 else
5506 pending_autoraise_frame = 0;
6d4238f3 5507 }
dc6f92b8 5508
0f941935 5509 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
5510}
5511
37c2c98b
RS
5512/* Handle an event saying the mouse has moved out of an Emacs frame. */
5513
5514void
0f941935
KH
5515x_mouse_leave (dpyinfo)
5516 struct x_display_info *dpyinfo;
37c2c98b 5517{
0f941935 5518 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 5519}
6d4238f3 5520
f451eb13
JB
5521/* The focus has changed, or we have redirected a frame's focus to
5522 another frame (this happens when a frame uses a surrogate
06a2c219 5523 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
5524
5525 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 5526 frame is being highlighted or un-highlighted; we only use it to find
0f941935 5527 the appropriate X display info. */
06a2c219 5528
6d4238f3 5529static void
0f941935
KH
5530XTframe_rehighlight (frame)
5531 struct frame *frame;
6d4238f3 5532{
0f941935
KH
5533 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
5534}
6d4238f3 5535
0f941935
KH
5536static void
5537x_frame_rehighlight (dpyinfo)
5538 struct x_display_info *dpyinfo;
5539{
5540 struct frame *old_highlight = dpyinfo->x_highlight_frame;
5541
5542 if (dpyinfo->x_focus_frame)
6d4238f3 5543 {
0f941935
KH
5544 dpyinfo->x_highlight_frame
5545 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
5546 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
5547 : dpyinfo->x_focus_frame);
5548 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 5549 {
0f941935
KH
5550 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
5551 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 5552 }
dc6f92b8 5553 }
6d4238f3 5554 else
0f941935 5555 dpyinfo->x_highlight_frame = 0;
dc6f92b8 5556
0f941935 5557 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
5558 {
5559 if (old_highlight)
f676886a 5560 frame_unhighlight (old_highlight);
0f941935
KH
5561 if (dpyinfo->x_highlight_frame)
5562 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 5563 }
dc6f92b8 5564}
06a2c219
GM
5565
5566
dc6f92b8 5567\f
06a2c219 5568/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 5569
28430d3c
JB
5570/* Initialize mode_switch_bit and modifier_meaning. */
5571static void
334208b7
RS
5572x_find_modifier_meanings (dpyinfo)
5573 struct x_display_info *dpyinfo;
28430d3c 5574{
f689eb05 5575 int min_code, max_code;
28430d3c
JB
5576 KeySym *syms;
5577 int syms_per_code;
5578 XModifierKeymap *mods;
5579
334208b7
RS
5580 dpyinfo->meta_mod_mask = 0;
5581 dpyinfo->shift_lock_mask = 0;
5582 dpyinfo->alt_mod_mask = 0;
5583 dpyinfo->super_mod_mask = 0;
5584 dpyinfo->hyper_mod_mask = 0;
58769bee 5585
9658a521 5586#ifdef HAVE_X11R4
334208b7 5587 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 5588#else
4a60f8c5
RS
5589 min_code = dpyinfo->display->min_keycode;
5590 max_code = dpyinfo->display->max_keycode;
9658a521
JB
5591#endif
5592
334208b7 5593 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
5594 min_code, max_code - min_code + 1,
5595 &syms_per_code);
334208b7 5596 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 5597
58769bee 5598 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 5599 Alt keysyms are on. */
28430d3c 5600 {
06a2c219 5601 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
5602
5603 for (row = 3; row < 8; row++)
5604 for (col = 0; col < mods->max_keypermod; col++)
5605 {
0299d313
RS
5606 KeyCode code
5607 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 5608
af92970c
KH
5609 /* Zeroes are used for filler. Skip them. */
5610 if (code == 0)
5611 continue;
5612
28430d3c
JB
5613 /* Are any of this keycode's keysyms a meta key? */
5614 {
5615 int code_col;
5616
5617 for (code_col = 0; code_col < syms_per_code; code_col++)
5618 {
f689eb05 5619 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 5620
f689eb05 5621 switch (sym)
28430d3c 5622 {
f689eb05
JB
5623 case XK_Meta_L:
5624 case XK_Meta_R:
334208b7 5625 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 5626 break;
f689eb05
JB
5627
5628 case XK_Alt_L:
5629 case XK_Alt_R:
334208b7 5630 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
5631 break;
5632
5633 case XK_Hyper_L:
5634 case XK_Hyper_R:
334208b7 5635 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
5636 break;
5637
5638 case XK_Super_L:
5639 case XK_Super_R:
334208b7 5640 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 5641 break;
11edeb03
JB
5642
5643 case XK_Shift_Lock:
5644 /* Ignore this if it's not on the lock modifier. */
5645 if ((1 << row) == LockMask)
334208b7 5646 dpyinfo->shift_lock_mask = LockMask;
11edeb03 5647 break;
28430d3c
JB
5648 }
5649 }
5650 }
5651 }
5652 }
5653
f689eb05 5654 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 5655 if (! dpyinfo->meta_mod_mask)
a3c44b14 5656 {
334208b7
RS
5657 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
5658 dpyinfo->alt_mod_mask = 0;
a3c44b14 5659 }
f689eb05 5660
148c4b70
RS
5661 /* If some keys are both alt and meta,
5662 make them just meta, not alt. */
334208b7 5663 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 5664 {
334208b7 5665 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 5666 }
58769bee 5667
28430d3c 5668 XFree ((char *) syms);
f689eb05 5669 XFreeModifiermap (mods);
28430d3c
JB
5670}
5671
dfeccd2d
JB
5672/* Convert between the modifier bits X uses and the modifier bits
5673 Emacs uses. */
06a2c219 5674
7c5283e4 5675static unsigned int
334208b7
RS
5676x_x_to_emacs_modifiers (dpyinfo, state)
5677 struct x_display_info *dpyinfo;
dc6f92b8
JB
5678 unsigned int state;
5679{
334208b7
RS
5680 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
5681 | ((state & ControlMask) ? ctrl_modifier : 0)
5682 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
5683 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
5684 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
5685 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
5686}
5687
dfeccd2d 5688static unsigned int
334208b7
RS
5689x_emacs_to_x_modifiers (dpyinfo, state)
5690 struct x_display_info *dpyinfo;
dfeccd2d
JB
5691 unsigned int state;
5692{
334208b7
RS
5693 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
5694 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
5695 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
5696 | ((state & shift_modifier) ? ShiftMask : 0)
5697 | ((state & ctrl_modifier) ? ControlMask : 0)
5698 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 5699}
d047c4eb
KH
5700
5701/* Convert a keysym to its name. */
5702
5703char *
5704x_get_keysym_name (keysym)
5705 KeySym keysym;
5706{
5707 char *value;
5708
5709 BLOCK_INPUT;
5710 value = XKeysymToString (keysym);
5711 UNBLOCK_INPUT;
5712
5713 return value;
5714}
06a2c219
GM
5715
5716
e4571a43
JB
5717\f
5718/* Mouse clicks and mouse movement. Rah. */
e4571a43 5719
06a2c219
GM
5720/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
5721 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
5722 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
5723 not force the value into range. */
69388238 5724
c8dba240 5725void
69388238 5726pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 5727 FRAME_PTR f;
69388238 5728 register int pix_x, pix_y;
e4571a43
JB
5729 register int *x, *y;
5730 XRectangle *bounds;
69388238 5731 int noclip;
e4571a43 5732{
06a2c219 5733 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
5734 even for negative values. */
5735 if (pix_x < 0)
7556890b 5736 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 5737 if (pix_y < 0)
7556890b 5738 pix_y -= (f)->output_data.x->line_height - 1;
69388238 5739
e4571a43
JB
5740 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
5741 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
5742
5743 if (bounds)
5744 {
7556890b
RS
5745 bounds->width = FONT_WIDTH (f->output_data.x->font);
5746 bounds->height = f->output_data.x->line_height;
e4571a43
JB
5747 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
5748 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
5749 }
5750
69388238
RS
5751 if (!noclip)
5752 {
5753 if (pix_x < 0)
5754 pix_x = 0;
3cbd2e0b
RS
5755 else if (pix_x > FRAME_WINDOW_WIDTH (f))
5756 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
5757
5758 if (pix_y < 0)
5759 pix_y = 0;
5760 else if (pix_y > f->height)
5761 pix_y = f->height;
5762 }
e4571a43
JB
5763
5764 *x = pix_x;
5765 *y = pix_y;
5766}
5767
06a2c219
GM
5768
5769/* Given HPOS/VPOS in the current matrix of W, return corresponding
5770 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
5771 can't tell the positions because W's display is not up to date,
5772 return 0. */
5773
5774int
5775glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
5776 struct window *w;
5777 int hpos, vpos;
5778 int *frame_x, *frame_y;
2b5c9e71 5779{
06a2c219
GM
5780 int success_p;
5781
5782 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
5783 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
5784
5785 if (display_completed)
5786 {
5787 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
5788 struct glyph *glyph = row->glyphs[TEXT_AREA];
5789 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
5790
5791 *frame_y = row->y;
5792 *frame_x = row->x;
5793 while (glyph < end)
5794 {
5795 *frame_x += glyph->pixel_width;
5796 ++glyph;
5797 }
5798
5799 success_p = 1;
5800 }
5801 else
5802 {
5803 *frame_y = *frame_x = 0;
5804 success_p = 0;
5805 }
5806
5807 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
5808 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
5809 return success_p;
2b5c9e71
RS
5810}
5811
06a2c219 5812
dc6f92b8
JB
5813/* Prepare a mouse-event in *RESULT for placement in the input queue.
5814
5815 If the event is a button press, then note that we have grabbed
f451eb13 5816 the mouse. */
dc6f92b8
JB
5817
5818static Lisp_Object
f451eb13 5819construct_mouse_click (result, event, f)
dc6f92b8
JB
5820 struct input_event *result;
5821 XButtonEvent *event;
f676886a 5822 struct frame *f;
dc6f92b8 5823{
f451eb13 5824 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 5825 otherwise. */
f451eb13 5826 result->kind = mouse_click;
69388238 5827 result->code = event->button - Button1;
1113d9db 5828 result->timestamp = event->time;
334208b7
RS
5829 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
5830 event->state)
f689eb05 5831 | (event->type == ButtonRelease
58769bee 5832 ? up_modifier
f689eb05 5833 : down_modifier));
dc6f92b8 5834
06a2c219
GM
5835 XSETINT (result->x, event->x);
5836 XSETINT (result->y, event->y);
5837 XSETFRAME (result->frame_or_window, f);
5838 return Qnil;
dc6f92b8 5839}
b849c413 5840
06a2c219
GM
5841#if 0 /* This function isn't called. --gerd */
5842
b849c413
RS
5843/* Prepare a menu-event in *RESULT for placement in the input queue. */
5844
5845static Lisp_Object
5846construct_menu_click (result, event, f)
5847 struct input_event *result;
5848 XButtonEvent *event;
5849 struct frame *f;
5850{
5851 /* Make the event type no_event; we'll change that when we decide
5852 otherwise. */
5853 result->kind = mouse_click;
26459b28 5854 result->code = event->button - Button1;
b849c413 5855 result->timestamp = event->time;
334208b7
RS
5856 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
5857 event->state)
b849c413 5858 | (event->type == ButtonRelease
58769bee 5859 ? up_modifier
b849c413
RS
5860 : down_modifier));
5861
e0c1aef2
KH
5862 XSETINT (result->x, event->x);
5863 XSETINT (result->y, -1);
5864 XSETFRAME (result->frame_or_window, f);
b849c413 5865}
06a2c219
GM
5866
5867#endif /* 0 */
5868
69388238 5869\f
90e65f07
JB
5870/* Function to report a mouse movement to the mainstream Emacs code.
5871 The input handler calls this.
5872
5873 We have received a mouse movement event, which is given in *event.
5874 If the mouse is over a different glyph than it was last time, tell
5875 the mainstream emacs code by setting mouse_moved. If not, ask for
5876 another motion event, so we can check again the next time it moves. */
b8009dd1 5877
06a2c219
GM
5878static XMotionEvent last_mouse_motion_event;
5879static Lisp_Object last_mouse_motion_frame;
5880
90e65f07 5881static void
12ba150f 5882note_mouse_movement (frame, event)
f676886a 5883 FRAME_PTR frame;
90e65f07 5884 XMotionEvent *event;
90e65f07 5885{
e5d77022 5886 last_mouse_movement_time = event->time;
06a2c219
GM
5887 last_mouse_motion_event = *event;
5888 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 5889
27f338af
RS
5890 if (event->window != FRAME_X_WINDOW (frame))
5891 {
39d8bb4d 5892 frame->mouse_moved = 1;
27f338af 5893 last_mouse_scroll_bar = Qnil;
27f338af 5894 note_mouse_highlight (frame, -1, -1);
27f338af
RS
5895 }
5896
90e65f07 5897 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
5898 else if (event->x < last_mouse_glyph.x
5899 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
5900 || event->y < last_mouse_glyph.y
5901 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 5902 {
39d8bb4d 5903 frame->mouse_moved = 1;
ab648270 5904 last_mouse_scroll_bar = Qnil;
b8009dd1 5905 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
5906 }
5907}
5908
bf1c0ba1 5909/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 5910
06a2c219
GM
5911 int disable_mouse_highlight;
5912
5913
5914\f
5915/************************************************************************
5916 Mouse Face
5917 ************************************************************************/
5918
5919/* Find the glyph under window-relative coordinates X/Y in window W.
5920 Consider only glyphs from buffer text, i.e. no glyphs from overlay
5921 strings. Return in *HPOS and *VPOS the row and column number of
5922 the glyph found. Return in *AREA the glyph area containing X.
5923 Value is a pointer to the glyph found or null if X/Y is not on
5924 text, or we can't tell because W's current matrix is not up to
5925 date. */
5926
5927static struct glyph *
5928x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
5929 struct window *w;
5930 int x, y;
5931 int *hpos, *vpos, *area;
5932{
5933 struct glyph *glyph, *end;
5934 struct glyph_row *row;
5935 int x0, i, left_area_width;
5936
5937 /* Find row containing Y. Give up if some row is not enabled. */
5938 for (i = 0; i < w->current_matrix->nrows; ++i)
5939 {
5940 row = MATRIX_ROW (w->current_matrix, i);
5941 if (!row->enabled_p)
5942 return NULL;
5943 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
5944 break;
5945 }
5946
5947 *vpos = i;
5948 *hpos = 0;
5949
5950 /* Give up if Y is not in the window. */
5951 if (i == w->current_matrix->nrows)
5952 return NULL;
5953
5954 /* Get the glyph area containing X. */
5955 if (w->pseudo_window_p)
5956 {
5957 *area = TEXT_AREA;
5958 x0 = 0;
5959 }
5960 else
5961 {
5962 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
5963 if (x < left_area_width)
5964 {
5965 *area = LEFT_MARGIN_AREA;
5966 x0 = 0;
5967 }
5968 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
5969 {
5970 *area = TEXT_AREA;
5971 x0 = row->x + left_area_width;
5972 }
5973 else
5974 {
5975 *area = RIGHT_MARGIN_AREA;
5976 x0 = left_area_width + window_box_width (w, TEXT_AREA);
5977 }
5978 }
5979
5980 /* Find glyph containing X. */
5981 glyph = row->glyphs[*area];
5982 end = glyph + row->used[*area];
5983 while (glyph < end)
5984 {
5985 if (x < x0 + glyph->pixel_width)
5986 {
5987 if (w->pseudo_window_p)
5988 break;
5989 else if (BUFFERP (glyph->object))
5990 break;
5991 }
5992
5993 x0 += glyph->pixel_width;
5994 ++glyph;
5995 }
5996
5997 if (glyph == end)
5998 return NULL;
5999
6000 *hpos = glyph - row->glyphs[*area];
6001 return glyph;
6002}
6003
6004
6005/* Convert frame-relative x/y to coordinates relative to window W.
6006 Takes pseudo-windows into account. */
6007
6008static void
6009frame_to_window_pixel_xy (w, x, y)
6010 struct window *w;
6011 int *x, *y;
6012{
6013 if (w->pseudo_window_p)
6014 {
6015 /* A pseudo-window is always full-width, and starts at the
6016 left edge of the frame, plus a frame border. */
6017 struct frame *f = XFRAME (w->frame);
6018 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6019 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6020 }
6021 else
6022 {
6023 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6024 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6025 }
6026}
6027
6028
6029/* Take proper action when mouse has moved to the mode or top line of
6030 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6031 mode line. X is relative to the start of the text display area of
6032 W, so the width of bitmap areas and scroll bars must be subtracted
6033 to get a position relative to the start of the mode line. */
6034
6035static void
6036note_mode_line_highlight (w, x, mode_line_p)
6037 struct window *w;
6038 int x, mode_line_p;
6039{
6040 struct frame *f = XFRAME (w->frame);
6041 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6042 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6043 struct glyph_row *row;
6044
6045 if (mode_line_p)
6046 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6047 else
045dee35 6048 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
06a2c219
GM
6049
6050 if (row->enabled_p)
6051 {
6052 struct glyph *glyph, *end;
6053 Lisp_Object help, map;
6054 int x0;
6055
6056 /* Find the glyph under X. */
6057 glyph = row->glyphs[TEXT_AREA];
6058 end = glyph + row->used[TEXT_AREA];
6059 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6060 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
6061 while (glyph < end
6062 && x >= x0 + glyph->pixel_width)
6063 {
6064 x0 += glyph->pixel_width;
6065 ++glyph;
6066 }
6067
6068 if (glyph < end
6069 && STRINGP (glyph->object)
6070 && XSTRING (glyph->object)->intervals
6071 && glyph->charpos >= 0
6072 && glyph->charpos < XSTRING (glyph->object)->size)
6073 {
6074 /* If we're on a string with `help-echo' text property,
6075 arrange for the help to be displayed. This is done by
6076 setting the global variable help_echo to the help string. */
6077 help = Fget_text_property (make_number (glyph->charpos),
6078 Qhelp_echo, glyph->object);
6079 if (STRINGP (help))
6080 help_echo = help;
6081
6082 /* Change the mouse pointer according to what is under X/Y. */
6083 map = Fget_text_property (make_number (glyph->charpos),
6084 Qlocal_map, glyph->object);
6085 if (!NILP (Fkeymapp (map)))
6086 cursor = f->output_data.x->nontext_cursor;
6087 }
6088 }
6089
6090 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6091}
6092
6093
6094/* Take proper action when the mouse has moved to position X, Y on
6095 frame F as regards highlighting characters that have mouse-face
6096 properties. Also de-highlighting chars where the mouse was before.
27f338af 6097 X and Y can be negative or out of range. */
b8009dd1
RS
6098
6099static void
6100note_mouse_highlight (f, x, y)
06a2c219 6101 struct frame *f;
c32cdd9a 6102 int x, y;
b8009dd1 6103{
06a2c219
GM
6104 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6105 int portion;
b8009dd1
RS
6106 Lisp_Object window;
6107 struct window *w;
6108
06a2c219
GM
6109 /* When a menu is active, don't highlight because this looks odd. */
6110#ifdef USE_X_TOOLKIT
6111 if (popup_activated ())
6112 return;
6113#endif
6114
bf1c0ba1
RS
6115 if (disable_mouse_highlight)
6116 return;
6117
06a2c219
GM
6118 dpyinfo->mouse_face_mouse_x = x;
6119 dpyinfo->mouse_face_mouse_y = y;
6120 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6121
06a2c219 6122 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6123 return;
6124
514e4681
RS
6125 if (gc_in_progress)
6126 {
06a2c219 6127 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6128 return;
6129 }
6130
b8009dd1 6131 /* Which window is that in? */
06a2c219 6132 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6133
6134 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6135 if (! EQ (window, dpyinfo->mouse_face_window))
6136 clear_mouse_face (dpyinfo);
6137
6138 /* Not on a window -> return. */
6139 if (!WINDOWP (window))
6140 return;
6141
6142 /* Convert to window-relative pixel coordinates. */
6143 w = XWINDOW (window);
6144 frame_to_window_pixel_xy (w, &x, &y);
6145
9ea173e8 6146 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6147 buffer. */
9ea173e8 6148 if (EQ (window, f->tool_bar_window))
06a2c219 6149 {
9ea173e8 6150 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6151 return;
6152 }
6153
6154 if (portion == 1 || portion == 3)
6155 {
6156 /* Mouse is on the mode or top line. */
6157 note_mode_line_highlight (w, x, portion == 1);
6158 return;
6159 }
6160 else
6161 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6162 f->output_data.x->text_cursor);
b8009dd1 6163
0cdd0c9f
RS
6164 /* Are we in a window whose display is up to date?
6165 And verify the buffer's text has not changed. */
06a2c219
GM
6166 if (/* Within text portion of the window. */
6167 portion == 0
0cdd0c9f 6168 && EQ (w->window_end_valid, w->buffer)
26459b28
KH
6169 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
6170 && (XFASTINT (w->last_overlay_modified)
6171 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
b8009dd1 6172 {
06a2c219
GM
6173 int hpos, vpos, pos, i, area;
6174 struct glyph *glyph;
b8009dd1 6175
06a2c219
GM
6176 /* Find the glyph under X/Y. */
6177 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
6178
6179 /* Clear mouse face if X/Y not over text. */
6180 if (glyph == NULL
6181 || area != TEXT_AREA
6182 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6183 {
06a2c219
GM
6184 clear_mouse_face (dpyinfo);
6185 return;
6186 }
6187
6188 pos = glyph->charpos;
6189 xassert (w->pseudo_window_p || BUFFERP (glyph->object));
6190
6191 /* Check for mouse-face and help-echo. */
6192 {
6193 Lisp_Object mouse_face, overlay, position;
6194 Lisp_Object *overlay_vec;
6195 int len, noverlays;
6196 struct buffer *obuf;
6197 int obegv, ozv;
6198
6199 /* If we get an out-of-range value, return now; avoid an error. */
6200 if (pos > BUF_Z (XBUFFER (w->buffer)))
6201 return;
6202
6203 /* Make the window's buffer temporarily current for
6204 overlays_at and compute_char_face. */
6205 obuf = current_buffer;
6206 current_buffer = XBUFFER (w->buffer);
6207 obegv = BEGV;
6208 ozv = ZV;
6209 BEGV = BEG;
6210 ZV = Z;
6211
6212 /* Is this char mouse-active or does it have help-echo? */
6213 XSETINT (position, pos);
6214
6215 /* Put all the overlays we want in a vector in overlay_vec.
6216 Store the length in len. If there are more than 10, make
6217 enough space for all, and try again. */
6218 len = 10;
6219 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6220 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6221 if (noverlays > len)
6222 {
6223 len = noverlays;
6224 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6225 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6226 }
6227
6228 noverlays = sort_overlays (overlay_vec, noverlays, w);
6229
6230 /* Check mouse-face highlighting. */
6231 if (! (EQ (window, dpyinfo->mouse_face_window)
6232 && vpos >= dpyinfo->mouse_face_beg_row
6233 && vpos <= dpyinfo->mouse_face_end_row
6234 && (vpos > dpyinfo->mouse_face_beg_row
6235 || hpos >= dpyinfo->mouse_face_beg_col)
6236 && (vpos < dpyinfo->mouse_face_end_row
6237 || hpos < dpyinfo->mouse_face_end_col
6238 || dpyinfo->mouse_face_past_end)))
6239 {
6240 /* Clear the display of the old active region, if any. */
6241 clear_mouse_face (dpyinfo);
6242
6243 /* Find the highest priority overlay that has a mouse-face prop. */
6244 overlay = Qnil;
6245 for (i = 0; i < noverlays; i++)
6246 {
6247 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6248 if (!NILP (mouse_face))
6249 {
6250 overlay = overlay_vec[i];
6251 break;
6252 }
6253 }
6254
6255 /* If no overlay applies, get a text property. */
6256 if (NILP (overlay))
6257 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6258
6259 /* Handle the overlay case. */
6260 if (! NILP (overlay))
6261 {
6262 /* Find the range of text around this char that
6263 should be active. */
6264 Lisp_Object before, after;
6265 int ignore;
6266
6267 before = Foverlay_start (overlay);
6268 after = Foverlay_end (overlay);
6269 /* Record this as the current active region. */
6270 fast_find_position (w, XFASTINT (before),
6271 &dpyinfo->mouse_face_beg_col,
6272 &dpyinfo->mouse_face_beg_row,
6273 &dpyinfo->mouse_face_beg_x,
6274 &dpyinfo->mouse_face_beg_y);
6275 dpyinfo->mouse_face_past_end
6276 = !fast_find_position (w, XFASTINT (after),
6277 &dpyinfo->mouse_face_end_col,
6278 &dpyinfo->mouse_face_end_row,
6279 &dpyinfo->mouse_face_end_x,
6280 &dpyinfo->mouse_face_end_y);
6281 dpyinfo->mouse_face_window = window;
6282 dpyinfo->mouse_face_face_id
6283 = face_at_buffer_position (w, pos, 0, 0,
6284 &ignore, pos + 1, 1);
6285
6286 /* Display it as active. */
6287 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6288 }
6289 /* Handle the text property case. */
6290 else if (! NILP (mouse_face))
6291 {
6292 /* Find the range of text around this char that
6293 should be active. */
6294 Lisp_Object before, after, beginning, end;
6295 int ignore;
6296
6297 beginning = Fmarker_position (w->start);
6298 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
6299 - XFASTINT (w->window_end_pos)));
6300 before
6301 = Fprevious_single_property_change (make_number (pos + 1),
6302 Qmouse_face,
6303 w->buffer, beginning);
6304 after
6305 = Fnext_single_property_change (position, Qmouse_face,
6306 w->buffer, end);
6307 /* Record this as the current active region. */
6308 fast_find_position (w, XFASTINT (before),
6309 &dpyinfo->mouse_face_beg_col,
6310 &dpyinfo->mouse_face_beg_row,
6311 &dpyinfo->mouse_face_beg_x,
6312 &dpyinfo->mouse_face_beg_y);
6313 dpyinfo->mouse_face_past_end
6314 = !fast_find_position (w, XFASTINT (after),
6315 &dpyinfo->mouse_face_end_col,
6316 &dpyinfo->mouse_face_end_row,
6317 &dpyinfo->mouse_face_end_x,
6318 &dpyinfo->mouse_face_end_y);
6319 dpyinfo->mouse_face_window = window;
6320 dpyinfo->mouse_face_face_id
6321 = face_at_buffer_position (w, pos, 0, 0,
6322 &ignore, pos + 1, 1);
6323
6324 /* Display it as active. */
6325 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6326 }
6327 }
6328
6329 /* Look for a `help-echo' property. */
6330 {
6331 Lisp_Object help;
6332
6333 /* Check overlays first. */
6334 help = Qnil;
6335 for (i = 0; i < noverlays && !STRINGP (help); ++i)
6336 help = Foverlay_get (overlay_vec[i], Qhelp_echo);
6337
6338 /* Try text properties. */
6339 if (!STRINGP (help)
6340 && ((STRINGP (glyph->object)
6341 && glyph->charpos >= 0
6342 && glyph->charpos < XSTRING (glyph->object)->size)
6343 || (BUFFERP (glyph->object)
6344 && glyph->charpos >= BEGV
6345 && glyph->charpos < ZV)))
6346 help = Fget_text_property (make_number (glyph->charpos),
6347 Qhelp_echo, glyph->object);
6348
6349 if (STRINGP (help))
6350 help_echo = help;
6351 }
6352
6353 BEGV = obegv;
6354 ZV = ozv;
6355 current_buffer = obuf;
6356 }
6357 }
6358}
6359
6360static void
6361redo_mouse_highlight ()
6362{
6363 if (!NILP (last_mouse_motion_frame)
6364 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
6365 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
6366 last_mouse_motion_event.x,
6367 last_mouse_motion_event.y);
6368}
6369
6370
6371\f
6372/***********************************************************************
9ea173e8 6373 Tool-bars
06a2c219
GM
6374 ***********************************************************************/
6375
9ea173e8
GM
6376static int x_tool_bar_item P_ ((struct frame *, int, int,
6377 struct glyph **, int *, int *, int *));
06a2c219 6378
9ea173e8 6379/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
6380 or -1. */
6381
9ea173e8 6382static int last_tool_bar_item;
06a2c219
GM
6383
6384
9ea173e8
GM
6385/* Get information about the tool-bar item at position X/Y on frame F.
6386 Return in *GLYPH a pointer to the glyph of the tool-bar item in
6387 the current matrix of the tool-bar window of F, or NULL if not
6388 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
6389 item in F->current_tool_bar_items. Value is
06a2c219 6390
9ea173e8 6391 -1 if X/Y is not on a tool-bar item
06a2c219
GM
6392 0 if X/Y is on the same item that was highlighted before.
6393 1 otherwise. */
6394
6395static int
9ea173e8 6396x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
6397 struct frame *f;
6398 int x, y;
6399 struct glyph **glyph;
6400 int *hpos, *vpos, *prop_idx;
6401{
6402 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6403 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6404 int area;
6405
6406 /* Find the glyph under X/Y. */
6407 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
6408 if (*glyph == NULL)
6409 return -1;
6410
9ea173e8
GM
6411 /* Get the start of this tool-bar item's properties in
6412 f->current_tool_bar_items. */
6413 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
6414 return -1;
6415
6416 /* Is mouse on the highlighted item? */
9ea173e8 6417 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
6418 && *vpos >= dpyinfo->mouse_face_beg_row
6419 && *vpos <= dpyinfo->mouse_face_end_row
6420 && (*vpos > dpyinfo->mouse_face_beg_row
6421 || *hpos >= dpyinfo->mouse_face_beg_col)
6422 && (*vpos < dpyinfo->mouse_face_end_row
6423 || *hpos < dpyinfo->mouse_face_end_col
6424 || dpyinfo->mouse_face_past_end))
6425 return 0;
6426
6427 return 1;
6428}
6429
6430
9ea173e8 6431/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
6432 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
6433 or ButtonRelase. */
6434
6435static void
9ea173e8 6436x_handle_tool_bar_click (f, button_event)
06a2c219
GM
6437 struct frame *f;
6438 XButtonEvent *button_event;
6439{
6440 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6441 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6442 int hpos, vpos, prop_idx;
6443 struct glyph *glyph;
6444 Lisp_Object enabled_p;
6445 int x = button_event->x;
6446 int y = button_event->y;
6447
9ea173e8 6448 /* If not on the highlighted tool-bar item, return. */
06a2c219 6449 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 6450 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
6451 return;
6452
6453 /* If item is disabled, do nothing. */
9ea173e8
GM
6454 enabled_p = (XVECTOR (f->current_tool_bar_items)
6455 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6456 if (NILP (enabled_p))
6457 return;
6458
6459 if (button_event->type == ButtonPress)
6460 {
6461 /* Show item in pressed state. */
6462 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
6463 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 6464 last_tool_bar_item = prop_idx;
06a2c219
GM
6465 }
6466 else
6467 {
6468 Lisp_Object key, frame;
6469 struct input_event event;
6470
6471 /* Show item in released state. */
6472 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
6473 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
6474
9ea173e8
GM
6475 key = (XVECTOR (f->current_tool_bar_items)
6476 ->contents[prop_idx + TOOL_BAR_ITEM_KEY]);
06a2c219
GM
6477
6478 XSETFRAME (frame, f);
9ea173e8
GM
6479 event.kind = TOOL_BAR_EVENT;
6480 event.frame_or_window = Fcons (frame, Fcons (Qtool_bar, Qnil));
06a2c219
GM
6481 kbd_buffer_store_event (&event);
6482
9ea173e8 6483 event.kind = TOOL_BAR_EVENT;
06a2c219
GM
6484 event.frame_or_window = Fcons (frame, key);
6485 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6486 button_event->state);
6487 kbd_buffer_store_event (&event);
9ea173e8 6488 last_tool_bar_item = -1;
06a2c219
GM
6489 }
6490}
6491
6492
9ea173e8
GM
6493/* Possibly highlight a tool-bar item on frame F when mouse moves to
6494 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
6495 note_mouse_highlight. */
6496
6497static void
9ea173e8 6498note_tool_bar_highlight (f, x, y)
06a2c219
GM
6499 struct frame *f;
6500 int x, y;
6501{
9ea173e8 6502 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
6503 struct window *w = XWINDOW (window);
6504 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6505 int hpos, vpos;
6506 struct glyph *glyph;
6507 struct glyph_row *row;
6508 int i, j, area;
6509 Lisp_Object enabled_p;
6510 int prop_idx;
6511 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
6512 int on_highlight_p, mouse_down_p, rc;
6513
6514 /* Function note_mouse_highlight is called with negative x(y
6515 values when mouse moves outside of the frame. */
6516 if (x <= 0 || y <= 0)
6517 {
6518 clear_mouse_face (dpyinfo);
6519 return;
6520 }
6521
9ea173e8 6522 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
6523 if (rc < 0)
6524 {
9ea173e8 6525 /* Not on tool-bar item. */
06a2c219
GM
6526 clear_mouse_face (dpyinfo);
6527 return;
6528 }
6529 else if (rc == 0)
9ea173e8 6530 /* On same tool-bar item as before. */
06a2c219 6531 goto set_help_echo;
b8009dd1 6532
06a2c219
GM
6533 clear_mouse_face (dpyinfo);
6534
9ea173e8 6535 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
6536 mouse_down_p = (dpyinfo->grabbed
6537 && f == last_mouse_frame
6538 && FRAME_LIVE_P (f));
6539 if (mouse_down_p
9ea173e8 6540 && last_tool_bar_item != prop_idx)
06a2c219
GM
6541 return;
6542
6543 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
6544 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
6545
9ea173e8
GM
6546 /* If tool-bar item is not enabled, don't highlight it. */
6547 enabled_p = (XVECTOR (f->current_tool_bar_items)
6548 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6549 if (!NILP (enabled_p))
6550 {
6551 /* Compute the x-position of the glyph. In front and past the
6552 image is a space. We include this is the highlighted area. */
6553 row = MATRIX_ROW (w->current_matrix, vpos);
6554 for (i = x = 0; i < hpos; ++i)
6555 x += row->glyphs[TEXT_AREA][i].pixel_width;
6556
6557 /* Record this as the current active region. */
6558 dpyinfo->mouse_face_beg_col = hpos;
6559 dpyinfo->mouse_face_beg_row = vpos;
6560 dpyinfo->mouse_face_beg_x = x;
6561 dpyinfo->mouse_face_beg_y = row->y;
6562 dpyinfo->mouse_face_past_end = 0;
6563
6564 dpyinfo->mouse_face_end_col = hpos + 1;
6565 dpyinfo->mouse_face_end_row = vpos;
6566 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
6567 dpyinfo->mouse_face_end_y = row->y;
6568 dpyinfo->mouse_face_window = window;
9ea173e8 6569 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
6570
6571 /* Display it as active. */
6572 show_mouse_face (dpyinfo, draw);
6573 dpyinfo->mouse_face_image_state = draw;
b8009dd1 6574 }
06a2c219
GM
6575
6576 set_help_echo:
6577
9ea173e8 6578 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 6579 XTread_socket does the rest. */
9ea173e8
GM
6580 help_echo = (XVECTOR (f->current_tool_bar_items)
6581 ->contents[prop_idx + TOOL_BAR_ITEM_HELP]);
06a2c219 6582 if (!STRINGP (help_echo))
9ea173e8
GM
6583 help_echo = (XVECTOR (f->current_tool_bar_items)
6584 ->contents[prop_idx + TOOL_BAR_ITEM_CAPTION]);
b8009dd1 6585}
4d73d038 6586
06a2c219
GM
6587
6588\f
6589/* Find the glyph matrix position of buffer position POS in window W.
6590 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
6591 current glyphs must be up to date. If POS is above window start
6592 return (0, 0, 0, 0). If POS is after end of W, return end of
6593 last line in W. */
b8009dd1
RS
6594
6595static int
06a2c219
GM
6596fast_find_position (w, pos, hpos, vpos, x, y)
6597 struct window *w;
b8009dd1 6598 int pos;
06a2c219 6599 int *hpos, *vpos, *x, *y;
b8009dd1 6600{
b8009dd1 6601 int i;
bf1c0ba1 6602 int lastcol;
06a2c219
GM
6603 int maybe_next_line_p = 0;
6604 int line_start_position;
6605 int yb = window_text_bottom_y (w);
6606 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
6607 struct glyph_row *best_row = row;
6608 int row_vpos = 0, best_row_vpos = 0;
6609 int current_x;
6610
6611 while (row->y < yb)
b8009dd1 6612 {
06a2c219
GM
6613 if (row->used[TEXT_AREA])
6614 line_start_position = row->glyphs[TEXT_AREA]->charpos;
6615 else
6616 line_start_position = 0;
6617
6618 if (line_start_position > pos)
b8009dd1 6619 break;
77b68646
RS
6620 /* If the position sought is the end of the buffer,
6621 don't include the blank lines at the bottom of the window. */
06a2c219
GM
6622 else if (line_start_position == pos
6623 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 6624 {
06a2c219 6625 maybe_next_line_p = 1;
77b68646
RS
6626 break;
6627 }
06a2c219
GM
6628 else if (line_start_position > 0)
6629 {
6630 best_row = row;
6631 best_row_vpos = row_vpos;
6632 }
6633
6634 ++row;
6635 ++row_vpos;
b8009dd1 6636 }
06a2c219
GM
6637
6638 /* Find the right column within BEST_ROW. */
6639 lastcol = 0;
6640 current_x = best_row->x;
6641 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 6642 {
06a2c219
GM
6643 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
6644 int charpos;
6645
6646 charpos = glyph->charpos;
6647 if (charpos == pos)
bf1c0ba1 6648 {
06a2c219
GM
6649 *hpos = i;
6650 *vpos = best_row_vpos;
6651 *x = current_x;
6652 *y = best_row->y;
bf1c0ba1
RS
6653 return 1;
6654 }
06a2c219 6655 else if (charpos > pos)
4d73d038 6656 break;
06a2c219
GM
6657 else if (charpos > 0)
6658 lastcol = i;
6659
6660 current_x += glyph->pixel_width;
bf1c0ba1 6661 }
b8009dd1 6662
77b68646
RS
6663 /* If we're looking for the end of the buffer,
6664 and we didn't find it in the line we scanned,
6665 use the start of the following line. */
06a2c219 6666 if (maybe_next_line_p)
77b68646 6667 {
06a2c219
GM
6668 ++best_row;
6669 ++best_row_vpos;
6670 lastcol = 0;
6671 current_x = best_row->x;
77b68646
RS
6672 }
6673
06a2c219
GM
6674 *vpos = best_row_vpos;
6675 *hpos = lastcol + 1;
6676 *x = current_x;
6677 *y = best_row->y;
b8009dd1
RS
6678 return 0;
6679}
6680
06a2c219 6681
b8009dd1
RS
6682/* Display the active region described by mouse_face_*
6683 in its mouse-face if HL > 0, in its normal face if HL = 0. */
6684
6685static void
06a2c219 6686show_mouse_face (dpyinfo, draw)
7a13e894 6687 struct x_display_info *dpyinfo;
06a2c219 6688 enum draw_glyphs_face draw;
b8009dd1 6689{
7a13e894 6690 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 6691 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 6692 int i;
06a2c219
GM
6693 int cursor_off_p = 0;
6694 struct cursor_pos saved_cursor;
6695
6696 saved_cursor = output_cursor;
6697
6698 /* If window is in the process of being destroyed, don't bother
6699 to do anything. */
6700 if (w->current_matrix == NULL)
6701 goto set_x_cursor;
6702
6703 /* Recognize when we are called to operate on rows that don't exist
6704 anymore. This can happen when a window is split. */
6705 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
6706 goto set_x_cursor;
6707
6708 set_output_cursor (&w->phys_cursor);
6709
6710 /* Note that mouse_face_beg_row etc. are window relative. */
6711 for (i = dpyinfo->mouse_face_beg_row;
6712 i <= dpyinfo->mouse_face_end_row;
6713 i++)
6714 {
6715 int start_hpos, end_hpos, start_x;
6716 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
6717
6718 /* Don't do anything if row doesn't have valid contents. */
6719 if (!row->enabled_p)
6720 continue;
6721
6722 /* For all but the first row, the highlight starts at column 0. */
6723 if (i == dpyinfo->mouse_face_beg_row)
6724 {
6725 start_hpos = dpyinfo->mouse_face_beg_col;
6726 start_x = dpyinfo->mouse_face_beg_x;
6727 }
6728 else
6729 {
6730 start_hpos = 0;
6731 start_x = 0;
6732 }
6733
6734 if (i == dpyinfo->mouse_face_end_row)
6735 end_hpos = dpyinfo->mouse_face_end_col;
6736 else
6737 end_hpos = row->used[TEXT_AREA];
6738
6739 /* If the cursor's in the text we are about to rewrite, turn the
6740 cursor off. */
6741 if (!w->pseudo_window_p
6742 && i == output_cursor.vpos
6743 && output_cursor.hpos >= start_hpos - 1
6744 && output_cursor.hpos <= end_hpos)
514e4681 6745 {
06a2c219
GM
6746 x_update_window_cursor (w, 0);
6747 cursor_off_p = 1;
514e4681 6748 }
b8009dd1 6749
06a2c219
GM
6750 if (end_hpos > start_hpos)
6751 x_draw_glyphs (w, start_x, row, updated_area,
66ac4b0e 6752 start_hpos, end_hpos, draw, NULL, NULL, 0);
b8009dd1
RS
6753 }
6754
514e4681 6755 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
6756 if (cursor_off_p)
6757 x_display_cursor (w, 1,
6758 output_cursor.hpos, output_cursor.vpos,
6759 output_cursor.x, output_cursor.y);
2729a2b5 6760
06a2c219 6761 output_cursor = saved_cursor;
fb3b7de5 6762
06a2c219
GM
6763 set_x_cursor:
6764
6765 /* Change the mouse cursor. */
6766 if (draw == DRAW_NORMAL_TEXT)
6767 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6768 f->output_data.x->text_cursor);
6769 else if (draw == DRAW_MOUSE_FACE)
334208b7 6770 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6771 f->output_data.x->cross_cursor);
27ead1d5 6772 else
334208b7 6773 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 6774 f->output_data.x->nontext_cursor);
b8009dd1
RS
6775}
6776
6777/* Clear out the mouse-highlighted active region.
06a2c219 6778 Redraw it un-highlighted first. */
b8009dd1 6779
06a2c219 6780void
7a13e894
RS
6781clear_mouse_face (dpyinfo)
6782 struct x_display_info *dpyinfo;
b8009dd1 6783{
06a2c219
GM
6784 if (tip_frame)
6785 return;
6786
7a13e894 6787 if (! NILP (dpyinfo->mouse_face_window))
06a2c219 6788 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
b8009dd1 6789
7a13e894
RS
6790 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
6791 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
6792 dpyinfo->mouse_face_window = Qnil;
b8009dd1 6793}
e687d06e
RS
6794
6795/* Just discard the mouse face information for frame F, if any.
6796 This is used when the size of F is changed. */
6797
dfcf069d 6798void
e687d06e
RS
6799cancel_mouse_face (f)
6800 FRAME_PTR f;
6801{
6802 Lisp_Object window;
6803 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6804
6805 window = dpyinfo->mouse_face_window;
6806 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
6807 {
6808 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
6809 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
6810 dpyinfo->mouse_face_window = Qnil;
6811 }
6812}
b8009dd1 6813\f
ab648270
JB
6814static struct scroll_bar *x_window_to_scroll_bar ();
6815static void x_scroll_bar_report_motion ();
12ba150f 6816
90e65f07 6817/* Return the current position of the mouse.
2d7fc7e8 6818 *fp should be a frame which indicates which display to ask about.
90e65f07 6819
2d7fc7e8 6820 If the mouse movement started in a scroll bar, set *fp, *bar_window,
ab648270 6821 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 6822 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 6823 position on the scroll bar.
12ba150f 6824
2d7fc7e8 6825 If the mouse movement started elsewhere, set *fp to the frame the
12ba150f
JB
6826 mouse is on, *bar_window to nil, and *x and *y to the character cell
6827 the mouse is over.
6828
06a2c219 6829 Set *time to the server time-stamp for the time at which the mouse
12ba150f
JB
6830 was at this position.
6831
a135645a
RS
6832 Don't store anything if we don't have a valid set of values to report.
6833
90e65f07 6834 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 6835 movement. */
90e65f07
JB
6836
6837static void
1cf412ec 6838XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 6839 FRAME_PTR *fp;
1cf412ec 6840 int insist;
12ba150f 6841 Lisp_Object *bar_window;
ab648270 6842 enum scroll_bar_part *part;
90e65f07 6843 Lisp_Object *x, *y;
e5d77022 6844 unsigned long *time;
90e65f07 6845{
a135645a
RS
6846 FRAME_PTR f1;
6847
90e65f07
JB
6848 BLOCK_INPUT;
6849
8bcee03e 6850 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 6851 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
6852 else
6853 {
12ba150f
JB
6854 Window root;
6855 int root_x, root_y;
90e65f07 6856
12ba150f
JB
6857 Window dummy_window;
6858 int dummy;
6859
39d8bb4d
KH
6860 Lisp_Object frame, tail;
6861
6862 /* Clear the mouse-moved flag for every frame on this display. */
6863 FOR_EACH_FRAME (tail, frame)
6864 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
6865 XFRAME (frame)->mouse_moved = 0;
6866
ab648270 6867 last_mouse_scroll_bar = Qnil;
12ba150f
JB
6868
6869 /* Figure out which root window we're on. */
334208b7
RS
6870 XQueryPointer (FRAME_X_DISPLAY (*fp),
6871 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
6872
6873 /* The root window which contains the pointer. */
6874 &root,
6875
6876 /* Trash which we can't trust if the pointer is on
6877 a different screen. */
6878 &dummy_window,
6879
6880 /* The position on that root window. */
58769bee 6881 &root_x, &root_y,
12ba150f
JB
6882
6883 /* More trash we can't trust. */
6884 &dummy, &dummy,
6885
6886 /* Modifier keys and pointer buttons, about which
6887 we don't care. */
6888 (unsigned int *) &dummy);
6889
6890 /* Now we have a position on the root; find the innermost window
6891 containing the pointer. */
6892 {
6893 Window win, child;
6894 int win_x, win_y;
06a2c219 6895 int parent_x = 0, parent_y = 0;
e99db5a1 6896 int count;
12ba150f
JB
6897
6898 win = root;
69388238 6899
2d7fc7e8
RS
6900 /* XTranslateCoordinates can get errors if the window
6901 structure is changing at the same time this function
6902 is running. So at least we must not crash from them. */
6903
e99db5a1 6904 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 6905
334208b7 6906 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 6907 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 6908 {
69388238
RS
6909 /* If mouse was grabbed on a frame, give coords for that frame
6910 even if the mouse is now outside it. */
334208b7 6911 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 6912
12ba150f 6913 /* From-window, to-window. */
69388238 6914 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
6915
6916 /* From-position, to-position. */
6917 root_x, root_y, &win_x, &win_y,
6918
6919 /* Child of win. */
6920 &child);
69388238
RS
6921 f1 = last_mouse_frame;
6922 }
6923 else
6924 {
6925 while (1)
6926 {
334208b7 6927 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 6928
69388238
RS
6929 /* From-window, to-window. */
6930 root, win,
12ba150f 6931
69388238
RS
6932 /* From-position, to-position. */
6933 root_x, root_y, &win_x, &win_y,
6934
6935 /* Child of win. */
6936 &child);
6937
9af3143a 6938 if (child == None || child == win)
69388238
RS
6939 break;
6940
6941 win = child;
6942 parent_x = win_x;
6943 parent_y = win_y;
6944 }
12ba150f 6945
69388238
RS
6946 /* Now we know that:
6947 win is the innermost window containing the pointer
6948 (XTC says it has no child containing the pointer),
6949 win_x and win_y are the pointer's position in it
6950 (XTC did this the last time through), and
6951 parent_x and parent_y are the pointer's position in win's parent.
6952 (They are what win_x and win_y were when win was child.
6953 If win is the root window, it has no parent, and
6954 parent_{x,y} are invalid, but that's okay, because we'll
6955 never use them in that case.) */
6956
6957 /* Is win one of our frames? */
19126e11 6958 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
69388238 6959 }
58769bee 6960
2d7fc7e8
RS
6961 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
6962 f1 = 0;
6963
e99db5a1 6964 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 6965
ab648270 6966 /* If not, is it one of our scroll bars? */
a135645a 6967 if (! f1)
12ba150f 6968 {
ab648270 6969 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
6970
6971 if (bar)
6972 {
a135645a 6973 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
6974 win_x = parent_x;
6975 win_y = parent_y;
6976 }
6977 }
90e65f07 6978
8bcee03e 6979 if (f1 == 0 && insist > 0)
b86bd3dd 6980 f1 = SELECTED_FRAME ();
1cf412ec 6981
a135645a 6982 if (f1)
12ba150f 6983 {
06a2c219
GM
6984 /* Ok, we found a frame. Store all the values.
6985 last_mouse_glyph is a rectangle used to reduce the
6986 generation of mouse events. To not miss any motion
6987 events, we must divide the frame into rectangles of the
6988 size of the smallest character that could be displayed
6989 on it, i.e. into the same rectangles that matrices on
6990 the frame are divided into. */
6991
6992#if OLD_REDISPLAY_CODE
2b5c9e71 6993 int ignore1, ignore2;
2b5c9e71 6994 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
334208b7 6995 &last_mouse_glyph,
1cf412ec
RS
6996 FRAME_X_DISPLAY_INFO (f1)->grabbed
6997 || insist);
06a2c219
GM
6998#else
6999 {
7000 int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
7001 int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
7002 int x = win_x;
7003 int y = win_y;
7004
7005 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
7006 round down even for negative values. */
7007 if (x < 0)
7008 x -= width - 1;
7009 if (y < 0)
7010 y -= height - 1;
7011
7012 last_mouse_glyph.width = width;
7013 last_mouse_glyph.height = height;
7014 last_mouse_glyph.x = (x + width - 1) / width * width;
7015 last_mouse_glyph.y = (y + height - 1) / height * height;
7016 }
7017#endif
12ba150f
JB
7018
7019 *bar_window = Qnil;
7020 *part = 0;
334208b7 7021 *fp = f1;
e0c1aef2
KH
7022 XSETINT (*x, win_x);
7023 XSETINT (*y, win_y);
12ba150f
JB
7024 *time = last_mouse_movement_time;
7025 }
7026 }
7027 }
90e65f07
JB
7028
7029 UNBLOCK_INPUT;
7030}
f451eb13 7031
06a2c219
GM
7032
7033DEFUN ("xt-process-timeouts", Fxt_process_timeouts, Sxt_process_timeouts,
7034 0, 0, 0,
7035 "Arrange for Xt timeout callbacks to be called.")
7036 ()
7037{
7038#ifdef USE_X_TOOLKIT
7039 BLOCK_INPUT;
7040 while (XtAppPending (Xt_app_con) & XtIMTimer)
7041 XtAppProcessEvent (Xt_app_con, XtIMTimer);
7042 UNBLOCK_INPUT;
7043#endif /* USE_X_TOOLKIT */
7044
7045 return Qnil;
7046}
7047
7048
7049\f
7050/* Scroll bar support. */
7051
7052/* Given an X window ID, find the struct scroll_bar which manages it.
7053 This can be called in GC, so we have to make sure to strip off mark
7054 bits. */
7055static struct scroll_bar *
7056x_window_to_scroll_bar (window_id)
7057 Window window_id;
7058{
7059 Lisp_Object tail;
7060
7061 for (tail = Vframe_list;
7062 XGCTYPE (tail) == Lisp_Cons;
8e713be6 7063 tail = XCDR (tail))
06a2c219
GM
7064 {
7065 Lisp_Object frame, bar, condemned;
7066
8e713be6 7067 frame = XCAR (tail);
06a2c219
GM
7068 /* All elements of Vframe_list should be frames. */
7069 if (! GC_FRAMEP (frame))
7070 abort ();
7071
7072 /* Scan this frame's scroll bar list for a scroll bar with the
7073 right window ID. */
7074 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
7075 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
7076 /* This trick allows us to search both the ordinary and
7077 condemned scroll bar lists with one loop. */
7078 ! GC_NILP (bar) || (bar = condemned,
7079 condemned = Qnil,
7080 ! GC_NILP (bar));
7081 bar = XSCROLL_BAR (bar)->next)
7082 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
7083 return XSCROLL_BAR (bar);
7084 }
7085
7086 return 0;
7087}
7088
7089
7090\f
7091/************************************************************************
7092 Toolkit scroll bars
7093 ************************************************************************/
7094
7095#if USE_TOOLKIT_SCROLL_BARS
7096
7097static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
7098static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
7099static void x_create_toolkit_scroll_bar P_ ((struct frame *,
7100 struct scroll_bar *));
7101static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
7102 int, int, int));
7103
7104
7105/* Id of action hook installed for scroll bars. */
7106
7107static XtActionHookId action_hook_id;
7108
7109/* Lisp window being scrolled. Set when starting to interact with
7110 a toolkit scroll bar, reset to nil when ending the interaction. */
7111
7112static Lisp_Object window_being_scrolled;
7113
7114/* Last scroll bar part sent in xm_scroll_callback. */
7115
7116static int last_scroll_bar_part;
7117
7118
7119/* Action hook installed via XtAppAddActionHook when toolkit scroll
7120 bars are used.. The hoos is responsible for detecting when
7121 the user ends an interaction with the scroll bar, and generates
7122 a `end-scroll' scroll_bar_click' event if so. */
7123
7124static void
7125xt_action_hook (widget, client_data, action_name, event, params,
7126 num_params)
7127 Widget widget;
7128 XtPointer client_data;
7129 String action_name;
7130 XEvent *event;
7131 String *params;
7132 Cardinal *num_params;
7133{
7134 int scroll_bar_p;
7135 char *end_action;
7136
7137#ifdef USE_MOTIF
7138 scroll_bar_p = XmIsScrollBar (widget);
7139 end_action = "Release";
7140#elif defined HAVE_XAW3D
7141 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
7142 end_action = "EndScroll";
7143#else
8abee2e1 7144 #error unknown scroll bar toolkit
06a2c219
GM
7145#endif /* HAVE_XAW3D */
7146
7147 /* Although LessTif uses XtTimeouts like Xaw3d, the timer hack to
7148 let Xt timeouts be processed doesn't work. */
7149 if (scroll_bar_p
7150 && strcmp (action_name, end_action) == 0
7151 && WINDOWP (window_being_scrolled))
7152 {
7153 struct window *w;
7154
7155 x_send_scroll_bar_event (window_being_scrolled,
7156 scroll_bar_end_scroll, 0, 0);
7157 w = XWINDOW (window_being_scrolled);
7158 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
7159 window_being_scrolled = Qnil;
7160 last_scroll_bar_part = -1;
7161 }
7162}
7163
7164
7165/* Send a client message with message type Xatom_Scrollbar for a
7166 scroll action to the frame of WINDOW. PART is a value identifying
7167 the part of the scroll bar that was clicked on. PORTION is the
7168 amount to scroll of a whole of WHOLE. */
7169
7170static void
7171x_send_scroll_bar_event (window, part, portion, whole)
7172 Lisp_Object window;
7173 int part, portion, whole;
7174{
7175 XEvent event;
7176 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
7177 struct frame *f = XFRAME (XWINDOW (window)->frame);
7178
7179 /* Construct a ClientMessage event to send to the frame. */
7180 ev->type = ClientMessage;
7181 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
7182 ev->display = FRAME_X_DISPLAY (f);
7183 ev->window = FRAME_X_WINDOW (f);
7184 ev->format = 32;
7185 ev->data.l[0] = (long) window;
7186 ev->data.l[1] = (long) part;
7187 ev->data.l[2] = (long) 0;
7188 ev->data.l[3] = (long) portion;
7189 ev->data.l[4] = (long) whole;
7190
7191 /* Setting the event mask to zero means that the message will
7192 be sent to the client that created the window, and if that
7193 window no longer exists, no event will be sent. */
7194 BLOCK_INPUT;
7195 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
7196 UNBLOCK_INPUT;
7197}
7198
7199
7200/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
7201 in *IEVENT. */
7202
7203static void
7204x_scroll_bar_to_input_event (event, ievent)
7205 XEvent *event;
7206 struct input_event *ievent;
7207{
7208 XClientMessageEvent *ev = (XClientMessageEvent *) event;
7209 Lisp_Object window = (Lisp_Object) ev->data.l[0];
7210 struct frame *f = XFRAME (XWINDOW (window)->frame);
7211
7212 ievent->kind = scroll_bar_click;
7213 ievent->frame_or_window = window;
7214 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
7215 ievent->part = ev->data.l[1];
7216 ievent->code = ev->data.l[2];
7217 ievent->x = make_number ((int) ev->data.l[3]);
7218 ievent->y = make_number ((int) ev->data.l[4]);
7219 ievent->modifiers = 0;
7220}
7221
7222
7223#ifdef USE_MOTIF
7224
7225/* Minimum and maximum values used for Motif scroll bars. */
7226
7227#define XM_SB_MIN 1
7228#define XM_SB_MAX 10000000
7229#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
7230
7231
7232/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
7233 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
7234 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
7235
7236static void
7237xm_scroll_callback (widget, client_data, call_data)
7238 Widget widget;
7239 XtPointer client_data, call_data;
7240{
7241 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7242 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
7243 double percent;
7244 int part = -1, whole = 0, portion = 0;
7245
7246 switch (cs->reason)
7247 {
7248 case XmCR_DECREMENT:
7249 bar->dragging = Qnil;
7250 part = scroll_bar_up_arrow;
7251 break;
7252
7253 case XmCR_INCREMENT:
7254 bar->dragging = Qnil;
7255 part = scroll_bar_down_arrow;
7256 break;
7257
7258 case XmCR_PAGE_DECREMENT:
7259 bar->dragging = Qnil;
7260 part = scroll_bar_above_handle;
7261 break;
7262
7263 case XmCR_PAGE_INCREMENT:
7264 bar->dragging = Qnil;
7265 part = scroll_bar_below_handle;
7266 break;
7267
7268 case XmCR_TO_TOP:
7269 bar->dragging = Qnil;
7270 part = scroll_bar_to_top;
7271 break;
7272
7273 case XmCR_TO_BOTTOM:
7274 bar->dragging = Qnil;
7275 part = scroll_bar_to_bottom;
7276 break;
7277
7278 case XmCR_DRAG:
7279 {
7280 int slider_size;
7281 int dragging_down_p = (INTEGERP (bar->dragging)
7282 && XINT (bar->dragging) <= cs->value);
7283
7284 /* Get the slider size. */
7285 BLOCK_INPUT;
7286 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
7287 UNBLOCK_INPUT;
7288
7289 /* At the max position of the scroll bar, do a line-wise
7290 movement. Without doing anything, the LessTif scroll bar
7291 calls us with the same cs->value again and again. If we
7292 want to make sure that we can reach the end of the buffer,
7293 we have to do something.
7294
7295 Implementation note: setting bar->dragging always to
7296 cs->value gives a smoother movement at the max position.
7297 Setting it to nil when doing line-wise movement gives
7298 a better slider behavior. */
7299
7300 if (cs->value + slider_size == XM_SB_MAX
7301 || (dragging_down_p
7302 && last_scroll_bar_part == scroll_bar_down_arrow))
7303 {
7304 part = scroll_bar_down_arrow;
7305 bar->dragging = Qnil;
7306 }
7307 else
7308 {
7309 whole = XM_SB_RANGE;
7310 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
7311 part = scroll_bar_handle;
7312 bar->dragging = make_number (cs->value);
7313 }
7314 }
7315 break;
7316
7317 case XmCR_VALUE_CHANGED:
7318 break;
7319 };
7320
7321 if (part >= 0)
7322 {
7323 window_being_scrolled = bar->window;
7324 last_scroll_bar_part = part;
7325 x_send_scroll_bar_event (bar->window, part, portion, whole);
7326 }
7327}
7328
7329
7330#else /* not USE_MOTIF, i.e. XAW3D. */
7331
7332
7333/* Xaw3d scroll bar callback. Invoked when the thumb is dragged.
7334 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
7335 scroll bar struct. CALL_DATA is a pointer to a float saying where
7336 the thumb is. */
7337
7338static void
7339xaw3d_jump_callback (widget, client_data, call_data)
7340 Widget widget;
7341 XtPointer client_data, call_data;
7342{
7343 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7344 float top = *(float *) call_data;
7345 float shown;
7346 int whole, portion;
7347 int dragging_down_p, part;
7348 double epsilon = 0.01;
7349
7350 /* Get the size of the thumb, a value between 0 and 1. */
7351 BLOCK_INPUT;
7352 XtVaGetValues (widget, XtNshown, &shown, NULL);
7353 UNBLOCK_INPUT;
7354
7355 whole = 10000000;
7356 portion = shown < 1 ? top * whole : 0;
7357 dragging_down_p = (INTEGERP (bar->dragging)
7358 && XINT (bar->dragging) < portion);
7359
7360 if (shown < 1
7361 && (abs (top + shown - 1) < epsilon
7362 || (dragging_down_p
7363 && last_scroll_bar_part == scroll_bar_down_arrow)))
7364 part = scroll_bar_down_arrow;
7365 else
7366 part = scroll_bar_handle;
7367
7368 window_being_scrolled = bar->window;
7369 bar->dragging = make_number (portion);
7370 last_scroll_bar_part = part;
7371 x_send_scroll_bar_event (bar->window, part, portion, whole);
7372}
7373
7374
7375/* Xaw3d scroll bar callback. Invoked for incremental scrolling.,
7376 i.e. line or page up or down. WIDGET is the Xaw3d scroll bar
7377 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
7378 the scroll bar. CALL_DATA is an integer specifying the action that
7379 has taken place. It's magnitude is in the range 0..height of the
7380 scroll bar. Negative values mean scroll towards buffer start.
7381 Values < height of scroll bar mean line-wise movement. */
7382
7383static void
7384xaw3d_scroll_callback (widget, client_data, call_data)
7385 Widget widget;
7386 XtPointer client_data, call_data;
7387{
7388 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7389 int position = (int) call_data;
7390 Dimension height;
7391 int part;
7392
7393 /* Get the height of the scroll bar. */
7394 BLOCK_INPUT;
7395 XtVaGetValues (widget, XtNheight, &height, NULL);
7396 UNBLOCK_INPUT;
7397
7398 if (position < 0)
7399 {
7400 if (abs (position) < height)
7401 part = scroll_bar_up_arrow;
7402 else
7403 part = scroll_bar_above_handle;
7404 }
7405 else
7406 {
7407 if (abs (position) < height)
7408 part = scroll_bar_down_arrow;
7409 else
7410 part = scroll_bar_below_handle;
7411 }
7412
7413 window_being_scrolled = bar->window;
7414 bar->dragging = Qnil;
7415 last_scroll_bar_part = part;
7416 x_send_scroll_bar_event (bar->window, part, 0, 0);
7417}
7418
7419
7420#endif /* not USE_MOTIF */
7421
7422
7423/* Create the widget for scroll bar BAR on frame F. Record the widget
7424 and X window of the scroll bar in BAR. */
7425
7426static void
7427x_create_toolkit_scroll_bar (f, bar)
7428 struct frame *f;
7429 struct scroll_bar *bar;
7430{
7431 Window xwindow;
7432 Widget widget;
7433 Arg av[20];
7434 int ac = 0;
7435 char *scroll_bar_name = "verticalScrollBar";
7436 unsigned long pixel;
7437
7438 BLOCK_INPUT;
7439
7440#ifdef USE_MOTIF
7441 /* LessTif 0.85, problems:
7442
7443 1. When the mouse if over the scroll bar, the scroll bar will
7444 get keyboard events. I didn't find a way to turn this off.
7445
7446 2. Do we have to explicitly set the cursor to get an arrow
7447 cursor (see below)? */
7448
7449 /* Set resources. Create the widget. */
7450 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7451 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
7452 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
7453 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
7454 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
7455 XtSetArg (av[ac], XmNincrement, 1); ++ac;
7456 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
7457
7458 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7459 if (pixel != -1)
7460 {
7461 XtSetArg (av[ac], XmNforeground, pixel);
7462 ++ac;
7463 }
7464
7465 pixel = f->output_data.x->scroll_bar_background_pixel;
7466 if (pixel != -1)
7467 {
7468 XtSetArg (av[ac], XmNbackground, pixel);
7469 ++ac;
7470 }
7471
7472 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
7473 scroll_bar_name, av, ac);
7474
7475 /* Add one callback for everything that can happen. */
7476 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
7477 (XtPointer) bar);
7478 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
7479 (XtPointer) bar);
7480 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
7481 (XtPointer) bar);
7482 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
7483 (XtPointer) bar);
7484 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
7485 (XtPointer) bar);
7486 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
7487 (XtPointer) bar);
7488 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
7489 (XtPointer) bar);
7490
7491 /* Realize the widget. Only after that is the X window created. */
7492 XtRealizeWidget (widget);
7493
7494 /* Set the cursor to an arrow. I didn't find a resource to do that.
7495 And I'm wondering why it hasn't an arrow cursor by default. */
7496 XDefineCursor (XtDisplay (widget), XtWindow (widget),
7497 f->output_data.x->nontext_cursor);
7498
7499#elif defined HAVE_XAW3D
7500
7501 /* Set resources. Create the widget. The background of the
7502 Xaw3d scroll bar widget is a little bit light for my taste.
7503 We don't alter it here to let users change it according
7504 to their taste with `emacs*verticalScrollBar.background: xxx'. */
7505 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7506 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
7507 XtSetArg (av[ac], XtNcursorName, "left_ptr"); ++ac;
7508 XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac;
7509
7510 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7511 if (pixel != -1)
7512 {
7513 XtSetArg (av[ac], XtNforeground, pixel);
7514 ++ac;
7515 }
7516
7517 pixel = f->output_data.x->scroll_bar_background_pixel;
7518 if (pixel != -1)
7519 {
7520 XtSetArg (av[ac], XtNbackground, pixel);
7521 ++ac;
7522 }
7523
7524 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
7525 f->output_data.x->edit_widget, av, ac);
7526
7527 /* Define callbacks. */
7528 XtAddCallback (widget, XtNjumpProc, xaw3d_jump_callback, (XtPointer) bar);
7529 XtAddCallback (widget, XtNscrollProc, xaw3d_scroll_callback,
7530 (XtPointer) bar);
7531
7532 /* Realize the widget. Only after that is the X window created. */
7533 XtRealizeWidget (widget);
7534
7535#endif /* HAVE_XAW3D */
7536
7537 /* Install an action hook that let's us detect when the user
7538 finishes interacting with a scroll bar. */
7539 if (action_hook_id == 0)
7540 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
7541
7542 /* Remember X window and widget in the scroll bar vector. */
7543 SET_SCROLL_BAR_X_WIDGET (bar, widget);
7544 xwindow = XtWindow (widget);
7545 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
7546
7547 UNBLOCK_INPUT;
7548}
7549
7550
7551/* Set the thumb size and position of scroll bar BAR. We are currently
7552 displaying PORTION out of a whole WHOLE, and our position POSITION. */
7553
7554static void
7555x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
7556 struct scroll_bar *bar;
7557 int portion, position, whole;
f451eb13 7558{
06a2c219
GM
7559 float top, shown;
7560 Arg av[2];
7561 Widget widget = SCROLL_BAR_X_WIDGET (bar);
f451eb13 7562
06a2c219
GM
7563 if (whole == 0)
7564 top = 0, shown = 1;
7565 else
f451eb13 7566 {
06a2c219
GM
7567 top = (float) position / whole;
7568 shown = (float) portion / whole;
7569 }
f451eb13 7570
06a2c219 7571 BLOCK_INPUT;
f451eb13 7572
06a2c219
GM
7573#ifdef USE_MOTIF
7574 {
7575 int size, value;
7576 Boolean arrow1_selected, arrow2_selected;
7577 unsigned char flags;
7578 XmScrollBarWidget sb;
7579
7580 /* Slider size. Must be in the range [1 .. MAX - MIN] where NAX
7581 is the scroll bar's maximum and MIN is the scroll bar's minimum
7582 value. */
7583 size = shown * XM_SB_RANGE;
7584 size = min (size, XM_SB_RANGE);
7585 size = max (size, 1);
7586
7587 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
7588 value = top * XM_SB_RANGE;
7589 value = min (value, XM_SB_MAX - size);
7590 value = max (value, XM_SB_MIN);
7591
7592 /* LessTif: Calling XmScrollBarSetValues after an increment or
7593 decrement turns off auto-repeat LessTif-internally. This can
7594 be seen in ScrollBar.c which resets Arrow1Selected and
7595 Arrow2Selected. It also sets internal flags so that LessTif
7596 believes the mouse is in the slider. We either have to change
7597 our code, or work around that by accessing private data. */
7598
7599 sb = (XmScrollBarWidget) widget;
7600 arrow1_selected = sb->scrollBar.arrow1_selected;
7601 arrow2_selected = sb->scrollBar.arrow2_selected;
7602 flags = sb->scrollBar.flags;
7603
7604 if (NILP (bar->dragging))
7605 XmScrollBarSetValues (widget, value, size, 0, 0, False);
7606 else if (last_scroll_bar_part == scroll_bar_down_arrow)
7607 /* This has the negative side effect that the slider value is
7608 not would it would be if we scrolled here using line-wise or
7609 page-wise movement. */
7610 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
7611 else
7612 {
7613 /* If currently dragging, only update the slider size.
7614 This reduces flicker effects. */
7615 int old_value, old_size, increment, page_increment;
7616
7617 XmScrollBarGetValues (widget, &old_value, &old_size,
7618 &increment, &page_increment);
7619 XmScrollBarSetValues (widget, old_value,
7620 min (size, XM_SB_RANGE - old_value),
7621 0, 0, False);
7622 }
7623
7624 sb->scrollBar.arrow1_selected = arrow1_selected;
7625 sb->scrollBar.arrow2_selected = arrow2_selected;
7626 sb->scrollBar.flags = flags;
7627 }
7628#elif defined HAVE_XAW3D
7629 {
7630 /* Restrict to [0 1]. */
7631 top = max (0, min (1, top));
7632 shown = max (0, min (1, shown));
7633
7634 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
7635 check that your system's configuration file contains a define
7636 for `NARROWPROTO'. See s/freebsd.h for an example. */
7637 if (NILP (bar->dragging))
eb393530
GM
7638 {
7639 float old_top, old_shown;
7640 XtVaGetValues (widget, XtNtopOfThumb, &old_top, XtNshown, &old_shown,
7641 NULL);
7642 if (top != old_top || shown != old_shown)
7643 XawScrollbarSetThumb (widget, top, shown);
7644 }
06a2c219
GM
7645 else
7646 {
7647 ScrollbarWidget sb = (ScrollbarWidget) widget;
7648 int scroll_mode = sb->scrollbar.scroll_mode;
f451eb13 7649
06a2c219
GM
7650 sb->scrollbar.scroll_mode = 0;
7651
7652 if (last_scroll_bar_part == scroll_bar_down_arrow)
7653 XawScrollbarSetThumb (widget, top, 1 - top);
7654 else
7655 {
7656 float old_top;
7657 XtVaGetValues (widget, XtNtopOfThumb, &old_top, NULL);
7658 XawScrollbarSetThumb (widget, old_top, min (shown, 1 - old_top));
7659 }
7660
7661 sb->scrollbar.scroll_mode = scroll_mode;
7662 }
7663 }
7664#endif /* HAVE_XAW3D */
7665
7666 UNBLOCK_INPUT;
f451eb13
JB
7667}
7668
06a2c219
GM
7669#endif /* USE_TOOLKIT_SCROLL_BARS */
7670
7671
7672\f
7673/************************************************************************
7674 Scroll bars, general
7675 ************************************************************************/
7676
7677/* Create a scroll bar and return the scroll bar vector for it. W is
7678 the Emacs window on which to create the scroll bar. TOP, LEFT,
7679 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
7680 scroll bar. */
7681
ab648270 7682static struct scroll_bar *
06a2c219
GM
7683x_scroll_bar_create (w, top, left, width, height)
7684 struct window *w;
f451eb13
JB
7685 int top, left, width, height;
7686{
06a2c219
GM
7687 struct frame *f = XFRAME (w->frame);
7688#ifdef USE_X_TOOLKIT
7689 Arg av[10];
7690#endif
7691 int ac = 0;
7692 Window window;
334208b7
RS
7693 struct scroll_bar *bar
7694 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
7695
7696 BLOCK_INPUT;
7697
06a2c219
GM
7698#if USE_TOOLKIT_SCROLL_BARS
7699 x_create_toolkit_scroll_bar (f, bar);
7700#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
7701 {
7702 XSetWindowAttributes a;
7703 unsigned long mask;
06a2c219
GM
7704
7705 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
7706 if (a.background_pixel == -1)
7707 a.background_pixel = f->output_data.x->background_pixel;
7708
12ba150f 7709 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 7710 | ButtonMotionMask | PointerMotionHintMask
12ba150f 7711 | ExposureMask);
7a13e894 7712 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 7713
dbc4e1c1 7714 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 7715
06a2c219
GM
7716 /* Clear the area of W that will serve as a scroll bar. This is
7717 for the case that a window has been split horizontally. In
7718 this case, no clear_frame is generated to reduce flickering. */
7719 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7720 left, top, width,
7721 window_box_height (w), False);
7722
7723 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7724 /* Position and size of scroll bar. */
7725 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7726 top,
7727 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
7728 height,
7729 /* Border width, depth, class, and visual. */
7730 0,
7731 CopyFromParent,
7732 CopyFromParent,
7733 CopyFromParent,
7734 /* Attributes. */
7735 mask, &a);
7736 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 7737 }
06a2c219 7738#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 7739
06a2c219 7740 XSETWINDOW (bar->window, w);
e0c1aef2
KH
7741 XSETINT (bar->top, top);
7742 XSETINT (bar->left, left);
7743 XSETINT (bar->width, width);
7744 XSETINT (bar->height, height);
7745 XSETINT (bar->start, 0);
7746 XSETINT (bar->end, 0);
12ba150f 7747 bar->dragging = Qnil;
f451eb13
JB
7748
7749 /* Add bar to its frame's list of scroll bars. */
334208b7 7750 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 7751 bar->prev = Qnil;
334208b7 7752 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 7753 if (!NILP (bar->next))
e0c1aef2 7754 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 7755
06a2c219
GM
7756 /* Map the window/widget. */
7757#if USE_TOOLKIT_SCROLL_BARS
7758 XtMapWidget (SCROLL_BAR_X_WIDGET (bar));
7759 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
7760 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7761 top,
7762 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
7763 height, 0);
7764#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 7765 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 7766#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
7767
7768 UNBLOCK_INPUT;
12ba150f 7769 return bar;
f451eb13
JB
7770}
7771
06a2c219 7772
12ba150f 7773/* Draw BAR's handle in the proper position.
06a2c219 7774
12ba150f
JB
7775 If the handle is already drawn from START to END, don't bother
7776 redrawing it, unless REBUILD is non-zero; in that case, always
7777 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 7778 events.)
12ba150f
JB
7779
7780 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
7781 fit inside its rectangle, but if the user is dragging the scroll
7782 bar handle, we want to let them drag it down all the way, so that
7783 the bar's top is as far down as it goes; otherwise, there's no way
7784 to move to the very end of the buffer. */
7785
f451eb13 7786static void
ab648270
JB
7787x_scroll_bar_set_handle (bar, start, end, rebuild)
7788 struct scroll_bar *bar;
f451eb13 7789 int start, end;
12ba150f 7790 int rebuild;
f451eb13 7791{
06a2c219 7792#ifndef USE_TOOLKIT_SCROLL_BARS
12ba150f 7793 int dragging = ! NILP (bar->dragging);
ab648270 7794 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 7795 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 7796 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
7797
7798 /* If the display is already accurate, do nothing. */
7799 if (! rebuild
7800 && start == XINT (bar->start)
7801 && end == XINT (bar->end))
7802 return;
7803
f451eb13
JB
7804 BLOCK_INPUT;
7805
7806 {
d9cdbb3d
RS
7807 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
7808 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
7809 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
7810
7811 /* Make sure the values are reasonable, and try to preserve
7812 the distance between start and end. */
12ba150f
JB
7813 {
7814 int length = end - start;
7815
7816 if (start < 0)
7817 start = 0;
7818 else if (start > top_range)
7819 start = top_range;
7820 end = start + length;
7821
7822 if (end < start)
7823 end = start;
7824 else if (end > top_range && ! dragging)
7825 end = top_range;
7826 }
f451eb13 7827
ab648270 7828 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
7829 XSETINT (bar->start, start);
7830 XSETINT (bar->end, end);
f451eb13 7831
12ba150f
JB
7832 /* Clip the end position, just for display. */
7833 if (end > top_range)
7834 end = top_range;
f451eb13 7835
ab648270 7836 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
7837 below top positions, to make sure the handle is always at least
7838 that many pixels tall. */
ab648270 7839 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 7840
12ba150f
JB
7841 /* Draw the empty space above the handle. Note that we can't clear
7842 zero-height areas; that means "clear to end of window." */
7843 if (0 < start)
334208b7 7844 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 7845
12ba150f 7846 /* x, y, width, height, and exposures. */
ab648270
JB
7847 VERTICAL_SCROLL_BAR_LEFT_BORDER,
7848 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
7849 inside_width, start,
7850 False);
f451eb13 7851
06a2c219
GM
7852 /* Change to proper foreground color if one is specified. */
7853 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
7854 XSetForeground (FRAME_X_DISPLAY (f), gc,
7855 f->output_data.x->scroll_bar_foreground_pixel);
7856
12ba150f 7857 /* Draw the handle itself. */
334208b7 7858 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 7859
12ba150f 7860 /* x, y, width, height */
ab648270
JB
7861 VERTICAL_SCROLL_BAR_LEFT_BORDER,
7862 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 7863 inside_width, end - start);
f451eb13 7864
06a2c219
GM
7865 /* Restore the foreground color of the GC if we changed it above. */
7866 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
7867 XSetForeground (FRAME_X_DISPLAY (f), gc,
7868 f->output_data.x->foreground_pixel);
f451eb13 7869
12ba150f
JB
7870 /* Draw the empty space below the handle. Note that we can't
7871 clear zero-height areas; that means "clear to end of window." */
7872 if (end < inside_height)
334208b7 7873 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 7874
12ba150f 7875 /* x, y, width, height, and exposures. */
ab648270
JB
7876 VERTICAL_SCROLL_BAR_LEFT_BORDER,
7877 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
7878 inside_width, inside_height - end,
7879 False);
f451eb13 7880
f451eb13
JB
7881 }
7882
f451eb13 7883 UNBLOCK_INPUT;
06a2c219 7884#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
7885}
7886
f451eb13 7887
06a2c219
GM
7888/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
7889 nil. */
58769bee 7890
12ba150f 7891static void
ab648270
JB
7892x_scroll_bar_remove (bar)
7893 struct scroll_bar *bar;
12ba150f
JB
7894{
7895 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7896
7897 BLOCK_INPUT;
7898
06a2c219
GM
7899#if USE_TOOLKIT_SCROLL_BARS
7900 XtDestroyWidget (SCROLL_BAR_X_WIDGET (bar));
7901#else /* not USE_TOOLKIT_SCROLL_BARS */
334208b7 7902 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219
GM
7903#endif /* not USE_TOOLKIT_SCROLL_BARS */
7904
ab648270
JB
7905 /* Disassociate this scroll bar from its window. */
7906 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
7907
7908 UNBLOCK_INPUT;
7909}
7910
06a2c219 7911
12ba150f
JB
7912/* Set the handle of the vertical scroll bar for WINDOW to indicate
7913 that we are displaying PORTION characters out of a total of WHOLE
ab648270 7914 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 7915 create one. */
06a2c219 7916
12ba150f 7917static void
06a2c219
GM
7918XTset_vertical_scroll_bar (w, portion, whole, position)
7919 struct window *w;
f451eb13
JB
7920 int portion, whole, position;
7921{
06a2c219 7922 struct frame *f = XFRAME (w->frame);
ab648270 7923 struct scroll_bar *bar;
3c6ede7b 7924 int top, height, left, sb_left, width, sb_width;
06a2c219 7925 int window_x, window_y, window_width, window_height;
06a2c219 7926
3c6ede7b 7927 /* Get window dimensions. */
06a2c219 7928 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
7929 top = window_y;
7930 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
7931 height = window_height;
06a2c219 7932
3c6ede7b 7933 /* Compute the left edge of the scroll bar area. */
06a2c219 7934 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
7935 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
7936 else
7937 left = XFASTINT (w->left);
7938 left *= CANON_X_UNIT (f);
7939 left += FRAME_INTERNAL_BORDER_WIDTH (f);
7940
7941 /* Compute the width of the scroll bar which might be less than
7942 the width of the area reserved for the scroll bar. */
7943 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
7944 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 7945 else
3c6ede7b 7946 sb_width = width;
12ba150f 7947
3c6ede7b
GM
7948 /* Compute the left edge of the scroll bar. */
7949#ifdef USE_TOOLKIT_SCROLL_BARS
7950 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
7951 sb_left = left + width - sb_width - (width - sb_width) / 2;
7952 else
7953 sb_left = left + (width - sb_width) / 2;
7954#else
7955 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
7956 sb_left = left + width - sb_width;
7957 else
7958 sb_left = left;
7959#endif
7960
ab648270 7961 /* Does the scroll bar exist yet? */
06a2c219 7962 if (NILP (w->vertical_scroll_bar))
3c6ede7b 7963 {
80c32bcc 7964 BLOCK_INPUT;
3c6ede7b
GM
7965 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7966 left, top, width, height, False);
80c32bcc 7967 UNBLOCK_INPUT;
3c6ede7b
GM
7968 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
7969 }
f451eb13 7970 else
12ba150f
JB
7971 {
7972 /* It may just need to be moved and resized. */
06a2c219
GM
7973 unsigned int mask = 0;
7974
7975 bar = XSCROLL_BAR (w->vertical_scroll_bar);
7976
7977 BLOCK_INPUT;
7978
3c6ede7b 7979 if (sb_left != XINT (bar->left))
06a2c219 7980 mask |= CWX;
3c6ede7b 7981 if (top != XINT (bar->top))
06a2c219 7982 mask |= CWY;
3c6ede7b 7983 if (sb_width != XINT (bar->width))
06a2c219 7984 mask |= CWWidth;
3c6ede7b 7985 if (height != XINT (bar->height))
06a2c219
GM
7986 mask |= CWHeight;
7987
7988#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
7989
7990 /* Since toolkit scroll bars are smaller than the space reserved
7991 for them on the frame, we have to clear "under" them. */
7992 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3c6ede7b 7993 left, top, width, height, False);
06a2c219
GM
7994
7995 /* Move/size the scroll bar widget. */
7996 if (mask)
7997 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
3c6ede7b
GM
7998 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7999 top,
8000 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8001 height, 0);
06a2c219
GM
8002
8003#else /* not USE_TOOLKIT_SCROLL_BARS */
8004
e1f6572f
RS
8005 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
8006 {
8007 /* Clear areas not covered by the scroll bar. This makes sure a
8008 previous mode line display is cleared after C-x 2 C-x 1, for
8009 example. Non-toolkit scroll bars are as wide as the area
8010 reserved for scroll bars - trim at both sides. */
8011 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8012 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8013 height, False);
8014 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8015 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8016 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8017 height, False);
8018 }
06a2c219
GM
8019
8020 /* Move/size the scroll bar window. */
8021 if (mask)
8022 {
8023 XWindowChanges wc;
8024
3c6ede7b
GM
8025 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
8026 wc.y = top;
8027 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
8028 wc.height = height;
06a2c219
GM
8029 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
8030 mask, &wc);
8031 }
8032
8033#endif /* not USE_TOOLKIT_SCROLL_BARS */
8034
8035 /* Remember new settings. */
3c6ede7b
GM
8036 XSETINT (bar->left, sb_left);
8037 XSETINT (bar->top, top);
8038 XSETINT (bar->width, sb_width);
8039 XSETINT (bar->height, height);
06a2c219
GM
8040
8041 UNBLOCK_INPUT;
12ba150f 8042 }
f451eb13 8043
06a2c219
GM
8044#if USE_TOOLKIT_SCROLL_BARS
8045 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
8046#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 8047 /* Set the scroll bar's current state, unless we're currently being
f451eb13 8048 dragged. */
12ba150f 8049 if (NILP (bar->dragging))
f451eb13 8050 {
92857db0 8051 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 8052
12ba150f 8053 if (whole == 0)
ab648270 8054 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
8055 else
8056 {
43f868f5
JB
8057 int start = ((double) position * top_range) / whole;
8058 int end = ((double) (position + portion) * top_range) / whole;
ab648270 8059 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 8060 }
f451eb13 8061 }
06a2c219 8062#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8063
06a2c219 8064 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
8065}
8066
12ba150f 8067
f451eb13 8068/* The following three hooks are used when we're doing a thorough
ab648270 8069 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 8070 are going to be deleted, because keeping track of when windows go
12ba150f
JB
8071 away is a real pain - "Can you say set-window-configuration, boys
8072 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 8073 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 8074 from the fiery pit when we actually redisplay its window. */
f451eb13 8075
ab648270
JB
8076/* Arrange for all scroll bars on FRAME to be removed at the next call
8077 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
8078 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
8079
58769bee 8080static void
ab648270 8081XTcondemn_scroll_bars (frame)
f451eb13
JB
8082 FRAME_PTR frame;
8083{
f9e24cb9
RS
8084 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
8085 while (! NILP (FRAME_SCROLL_BARS (frame)))
8086 {
8087 Lisp_Object bar;
8088 bar = FRAME_SCROLL_BARS (frame);
8089 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
8090 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
8091 XSCROLL_BAR (bar)->prev = Qnil;
8092 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
8093 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
8094 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
8095 }
f451eb13
JB
8096}
8097
06a2c219 8098/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 8099 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 8100static void
ab648270 8101XTredeem_scroll_bar (window)
12ba150f 8102 struct window *window;
f451eb13 8103{
ab648270 8104 struct scroll_bar *bar;
12ba150f 8105
ab648270
JB
8106 /* We can't redeem this window's scroll bar if it doesn't have one. */
8107 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
8108 abort ();
8109
ab648270 8110 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
8111
8112 /* Unlink it from the condemned list. */
8113 {
8114 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
8115
8116 if (NILP (bar->prev))
8117 {
8118 /* If the prev pointer is nil, it must be the first in one of
8119 the lists. */
ab648270 8120 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
8121 /* It's not condemned. Everything's fine. */
8122 return;
ab648270
JB
8123 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
8124 window->vertical_scroll_bar))
8125 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
8126 else
8127 /* If its prev pointer is nil, it must be at the front of
8128 one or the other! */
8129 abort ();
8130 }
8131 else
ab648270 8132 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
8133
8134 if (! NILP (bar->next))
ab648270 8135 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 8136
ab648270 8137 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8138 bar->prev = Qnil;
e0c1aef2 8139 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 8140 if (! NILP (bar->next))
e0c1aef2 8141 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
12ba150f 8142 }
f451eb13
JB
8143}
8144
ab648270
JB
8145/* Remove all scroll bars on FRAME that haven't been saved since the
8146 last call to `*condemn_scroll_bars_hook'. */
06a2c219 8147
f451eb13 8148static void
ab648270 8149XTjudge_scroll_bars (f)
12ba150f 8150 FRAME_PTR f;
f451eb13 8151{
12ba150f 8152 Lisp_Object bar, next;
f451eb13 8153
ab648270 8154 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
8155
8156 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
8157 more events on the hapless scroll bars. */
8158 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
8159
8160 for (; ! NILP (bar); bar = next)
f451eb13 8161 {
ab648270 8162 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 8163
ab648270 8164 x_scroll_bar_remove (b);
12ba150f
JB
8165
8166 next = b->next;
8167 b->next = b->prev = Qnil;
f451eb13 8168 }
12ba150f 8169
ab648270 8170 /* Now there should be no references to the condemned scroll bars,
12ba150f 8171 and they should get garbage-collected. */
f451eb13
JB
8172}
8173
8174
06a2c219
GM
8175/* Handle an Expose or GraphicsExpose event on a scroll bar. This
8176 is a no-op when using toolkit scroll bars.
ab648270
JB
8177
8178 This may be called from a signal handler, so we have to ignore GC
8179 mark bits. */
06a2c219 8180
f451eb13 8181static void
ab648270
JB
8182x_scroll_bar_expose (bar, event)
8183 struct scroll_bar *bar;
f451eb13
JB
8184 XEvent *event;
8185{
06a2c219
GM
8186#ifndef USE_TOOLKIT_SCROLL_BARS
8187
ab648270 8188 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8189 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8190 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 8191 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 8192
f451eb13
JB
8193 BLOCK_INPUT;
8194
ab648270 8195 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 8196
06a2c219 8197 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 8198 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
8199
8200 /* x, y, width, height */
d9cdbb3d 8201 0, 0,
3cbd2e0b 8202 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
8203 XINT (bar->height) - 1);
8204
f451eb13 8205 UNBLOCK_INPUT;
06a2c219
GM
8206
8207#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8208}
8209
ab648270
JB
8210/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8211 is set to something other than no_event, it is enqueued.
8212
8213 This may be called from a signal handler, so we have to ignore GC
8214 mark bits. */
06a2c219 8215
f451eb13 8216static void
ab648270
JB
8217x_scroll_bar_handle_click (bar, event, emacs_event)
8218 struct scroll_bar *bar;
f451eb13
JB
8219 XEvent *event;
8220 struct input_event *emacs_event;
8221{
0299d313 8222 if (! GC_WINDOWP (bar->window))
12ba150f
JB
8223 abort ();
8224
ab648270 8225 emacs_event->kind = scroll_bar_click;
69388238 8226 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
8227 emacs_event->modifiers
8228 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
8229 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
8230 event->xbutton.state)
8231 | (event->type == ButtonRelease
8232 ? up_modifier
8233 : down_modifier));
12ba150f 8234 emacs_event->frame_or_window = bar->window;
f451eb13 8235 emacs_event->timestamp = event->xbutton.time;
12ba150f 8236 {
06a2c219 8237#if 0
d9cdbb3d 8238 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 8239 int internal_height
d9cdbb3d 8240 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8241#endif
0299d313 8242 int top_range
d9cdbb3d 8243 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 8244 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
8245
8246 if (y < 0) y = 0;
8247 if (y > top_range) y = top_range;
8248
8249 if (y < XINT (bar->start))
ab648270
JB
8250 emacs_event->part = scroll_bar_above_handle;
8251 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8252 emacs_event->part = scroll_bar_handle;
12ba150f 8253 else
ab648270 8254 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
8255
8256 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
8257 they want to drag it. Lisp code needs to be able to decide
8258 whether or not we're dragging. */
929787e1 8259#if 0
12ba150f
JB
8260 /* If the user has just clicked on the handle, record where they're
8261 holding it. */
8262 if (event->type == ButtonPress
ab648270 8263 && emacs_event->part == scroll_bar_handle)
e0c1aef2 8264 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 8265#endif
12ba150f
JB
8266
8267 /* If the user has released the handle, set it to its final position. */
8268 if (event->type == ButtonRelease
8269 && ! NILP (bar->dragging))
8270 {
8271 int new_start = y - XINT (bar->dragging);
8272 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 8273
ab648270 8274 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
8275 bar->dragging = Qnil;
8276 }
f451eb13 8277
5116f055
JB
8278 /* Same deal here as the other #if 0. */
8279#if 0
58769bee 8280 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 8281 the handle. */
ab648270 8282 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
8283 emacs_event->x = bar->start;
8284 else
e0c1aef2 8285 XSETINT (emacs_event->x, y);
5116f055 8286#else
e0c1aef2 8287 XSETINT (emacs_event->x, y);
5116f055 8288#endif
f451eb13 8289
e0c1aef2 8290 XSETINT (emacs_event->y, top_range);
12ba150f
JB
8291 }
8292}
f451eb13 8293
ab648270
JB
8294/* Handle some mouse motion while someone is dragging the scroll bar.
8295
8296 This may be called from a signal handler, so we have to ignore GC
8297 mark bits. */
06a2c219 8298
f451eb13 8299static void
ab648270
JB
8300x_scroll_bar_note_movement (bar, event)
8301 struct scroll_bar *bar;
f451eb13
JB
8302 XEvent *event;
8303{
39d8bb4d
KH
8304 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
8305
f451eb13
JB
8306 last_mouse_movement_time = event->xmotion.time;
8307
39d8bb4d 8308 f->mouse_moved = 1;
e0c1aef2 8309 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
8310
8311 /* If we're dragging the bar, display it. */
ab648270 8312 if (! GC_NILP (bar->dragging))
f451eb13
JB
8313 {
8314 /* Where should the handle be now? */
12ba150f 8315 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 8316
12ba150f 8317 if (new_start != XINT (bar->start))
f451eb13 8318 {
12ba150f 8319 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 8320
ab648270 8321 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
8322 }
8323 }
f451eb13
JB
8324}
8325
12ba150f 8326/* Return information to the user about the current position of the mouse
ab648270 8327 on the scroll bar. */
06a2c219 8328
12ba150f 8329static void
334208b7
RS
8330x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
8331 FRAME_PTR *fp;
12ba150f 8332 Lisp_Object *bar_window;
ab648270 8333 enum scroll_bar_part *part;
12ba150f
JB
8334 Lisp_Object *x, *y;
8335 unsigned long *time;
8336{
ab648270 8337 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
8338 Window w = SCROLL_BAR_X_WINDOW (bar);
8339 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 8340 int win_x, win_y;
559cb2fb
JB
8341 Window dummy_window;
8342 int dummy_coord;
8343 unsigned int dummy_mask;
12ba150f 8344
cf7cb199
JB
8345 BLOCK_INPUT;
8346
ab648270 8347 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 8348 report that. */
334208b7 8349 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 8350
559cb2fb
JB
8351 /* Root, child, root x and root y. */
8352 &dummy_window, &dummy_window,
8353 &dummy_coord, &dummy_coord,
12ba150f 8354
559cb2fb
JB
8355 /* Position relative to scroll bar. */
8356 &win_x, &win_y,
12ba150f 8357
559cb2fb
JB
8358 /* Mouse buttons and modifier keys. */
8359 &dummy_mask))
7a13e894 8360 ;
559cb2fb
JB
8361 else
8362 {
06a2c219 8363#if 0
559cb2fb 8364 int inside_height
d9cdbb3d 8365 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8366#endif
559cb2fb 8367 int top_range
d9cdbb3d 8368 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
8369
8370 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
8371
8372 if (! NILP (bar->dragging))
8373 win_y -= XINT (bar->dragging);
8374
8375 if (win_y < 0)
8376 win_y = 0;
8377 if (win_y > top_range)
8378 win_y = top_range;
8379
334208b7 8380 *fp = f;
7a13e894 8381 *bar_window = bar->window;
559cb2fb
JB
8382
8383 if (! NILP (bar->dragging))
8384 *part = scroll_bar_handle;
8385 else if (win_y < XINT (bar->start))
8386 *part = scroll_bar_above_handle;
8387 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8388 *part = scroll_bar_handle;
8389 else
8390 *part = scroll_bar_below_handle;
12ba150f 8391
e0c1aef2
KH
8392 XSETINT (*x, win_y);
8393 XSETINT (*y, top_range);
12ba150f 8394
39d8bb4d 8395 f->mouse_moved = 0;
559cb2fb
JB
8396 last_mouse_scroll_bar = Qnil;
8397 }
12ba150f 8398
559cb2fb 8399 *time = last_mouse_movement_time;
cf7cb199 8400
cf7cb199 8401 UNBLOCK_INPUT;
12ba150f
JB
8402}
8403
f451eb13 8404
dbc4e1c1 8405/* The screen has been cleared so we may have changed foreground or
ab648270
JB
8406 background colors, and the scroll bars may need to be redrawn.
8407 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
8408 redraw them. */
8409
dfcf069d 8410void
ab648270 8411x_scroll_bar_clear (f)
dbc4e1c1
JB
8412 FRAME_PTR f;
8413{
06a2c219 8414#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
8415 Lisp_Object bar;
8416
b80c363e
RS
8417 /* We can have scroll bars even if this is 0,
8418 if we just turned off scroll bar mode.
8419 But in that case we should not clear them. */
8420 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
8421 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
8422 bar = XSCROLL_BAR (bar)->next)
8423 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
8424 0, 0, 0, 0, True);
06a2c219 8425#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
8426}
8427
06a2c219 8428/* This processes Expose events from the menu-bar specific X event
19126e11 8429 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 8430 when handling menu-bar or pop-up items. */
3afe33e7 8431
06a2c219 8432int
3afe33e7
RS
8433process_expose_from_menu (event)
8434 XEvent event;
8435{
8436 FRAME_PTR f;
19126e11 8437 struct x_display_info *dpyinfo;
06a2c219 8438 int frame_exposed_p = 0;
3afe33e7 8439
f94397b5
KH
8440 BLOCK_INPUT;
8441
19126e11
KH
8442 dpyinfo = x_display_info_for_display (event.xexpose.display);
8443 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
8444 if (f)
8445 {
8446 if (f->async_visible == 0)
8447 {
8448 f->async_visible = 1;
8449 f->async_iconified = 0;
06c488fd 8450 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
8451 SET_FRAME_GARBAGED (f);
8452 }
8453 else
8454 {
06a2c219
GM
8455 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
8456 event.xexpose.x, event.xexpose.y,
8457 event.xexpose.width, event.xexpose.height);
8458 frame_exposed_p = 1;
3afe33e7
RS
8459 }
8460 }
8461 else
8462 {
8463 struct scroll_bar *bar
8464 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 8465
3afe33e7
RS
8466 if (bar)
8467 x_scroll_bar_expose (bar, &event);
8468 }
f94397b5
KH
8469
8470 UNBLOCK_INPUT;
06a2c219 8471 return frame_exposed_p;
3afe33e7 8472}
09756a85
RS
8473\f
8474/* Define a queue to save up SelectionRequest events for later handling. */
8475
8476struct selection_event_queue
8477 {
8478 XEvent event;
8479 struct selection_event_queue *next;
8480 };
8481
8482static struct selection_event_queue *queue;
8483
8484/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 8485
09756a85
RS
8486static int x_queue_selection_requests;
8487
8488/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 8489
09756a85 8490static void
334208b7
RS
8491x_queue_event (f, event)
8492 FRAME_PTR f;
09756a85
RS
8493 XEvent *event;
8494{
8495 struct selection_event_queue *queue_tmp
06a2c219 8496 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 8497
58769bee 8498 if (queue_tmp != NULL)
09756a85
RS
8499 {
8500 queue_tmp->event = *event;
8501 queue_tmp->next = queue;
8502 queue = queue_tmp;
8503 }
8504}
8505
8506/* Take all the queued events and put them back
8507 so that they get processed afresh. */
8508
8509static void
db3906fd
RS
8510x_unqueue_events (display)
8511 Display *display;
09756a85 8512{
58769bee 8513 while (queue != NULL)
09756a85
RS
8514 {
8515 struct selection_event_queue *queue_tmp = queue;
db3906fd 8516 XPutBackEvent (display, &queue_tmp->event);
09756a85 8517 queue = queue_tmp->next;
06a2c219 8518 xfree ((char *)queue_tmp);
09756a85
RS
8519 }
8520}
8521
8522/* Start queuing SelectionRequest events. */
8523
8524void
db3906fd
RS
8525x_start_queuing_selection_requests (display)
8526 Display *display;
09756a85
RS
8527{
8528 x_queue_selection_requests++;
8529}
8530
8531/* Stop queuing SelectionRequest events. */
8532
8533void
db3906fd
RS
8534x_stop_queuing_selection_requests (display)
8535 Display *display;
09756a85
RS
8536{
8537 x_queue_selection_requests--;
db3906fd 8538 x_unqueue_events (display);
09756a85 8539}
f451eb13
JB
8540\f
8541/* The main X event-reading loop - XTread_socket. */
dc6f92b8 8542
06a2c219 8543/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
8544 but we have to put it out here, since static variables within functions
8545 sometimes don't work. */
06a2c219 8546
dc6f92b8
JB
8547static Time enter_timestamp;
8548
11edeb03 8549/* This holds the state XLookupString needs to implement dead keys
58769bee 8550 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
8551 says that a portable program can't use this, but Stephen Gildea assures
8552 me that letting the compiler initialize it to zeros will work okay.
8553
8554 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
8555 given for enter_time stamp, above. */
8556
11edeb03
JB
8557static XComposeStatus compose_status;
8558
10e6549c
RS
8559/* Record the last 100 characters stored
8560 to help debug the loss-of-chars-during-GC problem. */
06a2c219 8561
2224b905
RS
8562static int temp_index;
8563static short temp_buffer[100];
10e6549c 8564
7a13e894
RS
8565/* Set this to nonzero to fake an "X I/O error"
8566 on a particular display. */
06a2c219 8567
7a13e894
RS
8568struct x_display_info *XTread_socket_fake_io_error;
8569
2224b905
RS
8570/* When we find no input here, we occasionally do a no-op command
8571 to verify that the X server is still running and we can still talk with it.
8572 We try all the open displays, one by one.
8573 This variable is used for cycling thru the displays. */
06a2c219 8574
2224b905
RS
8575static struct x_display_info *next_noop_dpyinfo;
8576
06a2c219
GM
8577#define SET_SAVED_MENU_EVENT(size) \
8578 do \
8579 { \
8580 if (f->output_data.x->saved_menu_event == 0) \
8581 f->output_data.x->saved_menu_event \
8582 = (XEvent *) xmalloc (sizeof (XEvent)); \
8583 bcopy (&event, f->output_data.x->saved_menu_event, size); \
8584 if (numchars >= 1) \
8585 { \
8586 bufp->kind = menu_bar_activate_event; \
8587 XSETFRAME (bufp->frame_or_window, f); \
8588 bufp++; \
8589 count++; \
8590 numchars--; \
8591 } \
8592 } \
8593 while (0)
8594
8805890a 8595#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 8596#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 8597
dc6f92b8
JB
8598/* Read events coming from the X server.
8599 This routine is called by the SIGIO handler.
8600 We return as soon as there are no more events to be read.
8601
8602 Events representing keys are stored in buffer BUFP,
8603 which can hold up to NUMCHARS characters.
8604 We return the number of characters stored into the buffer,
8605 thus pretending to be `read'.
8606
dc6f92b8
JB
8607 EXPECTED is nonzero if the caller knows input is available. */
8608
7c5283e4 8609int
f66868ba 8610XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 8611 register int sd;
8805890a
KH
8612 /* register */ struct input_event *bufp;
8613 /* register */ int numchars;
dc6f92b8
JB
8614 int expected;
8615{
8616 int count = 0;
8617 int nbytes = 0;
dc6f92b8 8618 XEvent event;
f676886a 8619 struct frame *f;
66f55a9d 8620 int event_found = 0;
334208b7 8621 struct x_display_info *dpyinfo;
6c183ba5
RS
8622#ifdef HAVE_X_I18N
8623 Status status_return;
8624#endif
dc6f92b8 8625
9ac0d9e0 8626 if (interrupt_input_blocked)
dc6f92b8 8627 {
9ac0d9e0 8628 interrupt_input_pending = 1;
dc6f92b8
JB
8629 return -1;
8630 }
8631
9ac0d9e0 8632 interrupt_input_pending = 0;
dc6f92b8 8633 BLOCK_INPUT;
c0a04927
RS
8634
8635 /* So people can tell when we have read the available input. */
8636 input_signal_count++;
8637
dc6f92b8 8638 if (numchars <= 0)
06a2c219 8639 abort (); /* Don't think this happens. */
dc6f92b8 8640
7a13e894
RS
8641 /* Find the display we are supposed to read input for.
8642 It's the one communicating on descriptor SD. */
8643 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
8644 {
8645#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 8646#ifdef FIOSNBIO
7a13e894
RS
8647 /* If available, Xlib uses FIOSNBIO to make the socket
8648 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 8649 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 8650 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 8651 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 8652#endif /* ! defined (FIOSNBIO) */
7a13e894 8653#endif
dc6f92b8 8654
7a13e894
RS
8655#if 0 /* This code can't be made to work, with multiple displays,
8656 and appears not to be used on any system any more.
8657 Also keyboard.c doesn't turn O_NDELAY on and off
8658 for X connections. */
dc6f92b8
JB
8659#ifndef SIGIO
8660#ifndef HAVE_SELECT
7a13e894
RS
8661 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
8662 {
8663 extern int read_alarm_should_throw;
8664 read_alarm_should_throw = 1;
8665 XPeekEvent (dpyinfo->display, &event);
8666 read_alarm_should_throw = 0;
8667 }
c118dd06
JB
8668#endif /* HAVE_SELECT */
8669#endif /* SIGIO */
7a13e894 8670#endif
dc6f92b8 8671
7a13e894
RS
8672 /* For debugging, this gives a way to fake an I/O error. */
8673 if (dpyinfo == XTread_socket_fake_io_error)
8674 {
8675 XTread_socket_fake_io_error = 0;
8676 x_io_error_quitter (dpyinfo->display);
8677 }
dc6f92b8 8678
06a2c219 8679 while (XPending (dpyinfo->display))
dc6f92b8 8680 {
7a13e894 8681 XNextEvent (dpyinfo->display, &event);
06a2c219
GM
8682
8683 if (display_busy_cursor_p)
8684 {
8685 /* Setting inhibit_busy_cursor to 2 inhibits busy-cursor
8686 display until the next X event is read and we come
8687 here again. Setting it to 1 inhibits busy-cursor
8688 display for direct commands. */
8689 if (event.type == MotionNotify
8690 || event.type == EnterNotify
8691 || (dpyinfo->grabbed
8692 && event.type != ButtonRelease))
8693 inhibit_busy_cursor = 2;
8694 else
8695 inhibit_busy_cursor = 1;
8696 }
8697
531483fb 8698#ifdef HAVE_X_I18N
d1bc4182
RS
8699 {
8700 struct frame *f1 = x_any_window_to_frame (dpyinfo,
c99babf2 8701 event.xclient.window);
d1bc4182
RS
8702 /* The necessity of the following line took me
8703 a full work-day to decipher from the docs!! */
8704 if (f1 != 0 && FRAME_XIC (f1) && XFilterEvent (&event, None))
8705 break;
8706 }
0cd6403b 8707#endif
7a13e894
RS
8708 event_found = 1;
8709
8710 switch (event.type)
8711 {
8712 case ClientMessage:
c047688c 8713 {
7a13e894
RS
8714 if (event.xclient.message_type
8715 == dpyinfo->Xatom_wm_protocols
8716 && event.xclient.format == 32)
c047688c 8717 {
7a13e894
RS
8718 if (event.xclient.data.l[0]
8719 == dpyinfo->Xatom_wm_take_focus)
c047688c 8720 {
8c1a6a84
RS
8721 /* Use x_any_window_to_frame because this
8722 could be the shell widget window
8723 if the frame has no title bar. */
8724 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
8725#ifdef HAVE_X_I18N
8726 /* Not quite sure this is needed -pd */
8c1a6a84 8727 if (f && FRAME_XIC (f))
6c183ba5
RS
8728 XSetICFocus (FRAME_XIC (f));
8729#endif
bf7253f4
RS
8730 /* Since we set WM_TAKE_FOCUS, we must call
8731 XSetInputFocus explicitly. But not if f is null,
8732 since that might be an event for a deleted frame. */
7a13e894 8733 if (f)
bf7253f4
RS
8734 {
8735 Display *d = event.xclient.display;
8736 /* Catch and ignore errors, in case window has been
8737 iconified by a window manager such as GWM. */
8738 int count = x_catch_errors (d);
8739 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
8740 /* The ICCCM says this is
8741 the only valid choice. */
8742 RevertToParent,
bf7253f4
RS
8743 event.xclient.data.l[1]);
8744 /* This is needed to detect the error
8745 if there is an error. */
8746 XSync (d, False);
8747 x_uncatch_errors (d, count);
8748 }
7a13e894 8749 /* Not certain about handling scroll bars here */
c047688c 8750 }
7a13e894
RS
8751 else if (event.xclient.data.l[0]
8752 == dpyinfo->Xatom_wm_save_yourself)
8753 {
8754 /* Save state modify the WM_COMMAND property to
06a2c219 8755 something which can reinstate us. This notifies
7a13e894
RS
8756 the session manager, who's looking for such a
8757 PropertyNotify. Can restart processing when
06a2c219 8758 a keyboard or mouse event arrives. */
7a13e894
RS
8759 if (numchars > 0)
8760 {
19126e11
KH
8761 f = x_top_window_to_frame (dpyinfo,
8762 event.xclient.window);
7a13e894
RS
8763
8764 /* This is just so we only give real data once
8765 for a single Emacs process. */
b86bd3dd 8766 if (f == SELECTED_FRAME ())
7a13e894
RS
8767 XSetCommand (FRAME_X_DISPLAY (f),
8768 event.xclient.window,
8769 initial_argv, initial_argc);
f000f5c5 8770 else if (f)
7a13e894
RS
8771 XSetCommand (FRAME_X_DISPLAY (f),
8772 event.xclient.window,
8773 0, 0);
8774 }
8775 }
8776 else if (event.xclient.data.l[0]
8777 == dpyinfo->Xatom_wm_delete_window)
1fb20991 8778 {
19126e11
KH
8779 struct frame *f
8780 = x_any_window_to_frame (dpyinfo,
8781 event.xclient.window);
1fb20991 8782
7a13e894
RS
8783 if (f)
8784 {
8785 if (numchars == 0)
8786 abort ();
1fb20991 8787
7a13e894
RS
8788 bufp->kind = delete_window_event;
8789 XSETFRAME (bufp->frame_or_window, f);
8790 bufp++;
8791
8792 count += 1;
8793 numchars -= 1;
8794 }
1fb20991 8795 }
c047688c 8796 }
7a13e894
RS
8797 else if (event.xclient.message_type
8798 == dpyinfo->Xatom_wm_configure_denied)
8799 {
8800 }
8801 else if (event.xclient.message_type
8802 == dpyinfo->Xatom_wm_window_moved)
8803 {
8804 int new_x, new_y;
19126e11
KH
8805 struct frame *f
8806 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 8807
7a13e894
RS
8808 new_x = event.xclient.data.s[0];
8809 new_y = event.xclient.data.s[1];
1fb20991 8810
7a13e894
RS
8811 if (f)
8812 {
7556890b
RS
8813 f->output_data.x->left_pos = new_x;
8814 f->output_data.x->top_pos = new_y;
7a13e894 8815 }
1fb20991 8816 }
0fdff6bb 8817#ifdef HACK_EDITRES
7a13e894
RS
8818 else if (event.xclient.message_type
8819 == dpyinfo->Xatom_editres)
8820 {
19126e11
KH
8821 struct frame *f
8822 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 8823 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 8824 &event, NULL);
7a13e894 8825 }
0fdff6bb 8826#endif /* HACK_EDITRES */
06a2c219
GM
8827 else if ((event.xclient.message_type
8828 == dpyinfo->Xatom_DONE)
8829 || (event.xclient.message_type
8830 == dpyinfo->Xatom_PAGE))
8831 {
8832 /* Ghostview job completed. Kill it. We could
8833 reply with "Next" if we received "Page", but we
8834 currently never do because we are interested in
8835 images, only, which should have 1 page. */
8836 Window gs_window = (Window) event.xclient.data.l[0];
8837 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
8838 struct frame *f
8839 = x_window_to_frame (dpyinfo, event.xclient.window);
8840 x_kill_gs_process (pixmap, f);
8841 expose_frame (f, 0, 0, 0, 0);
8842 }
8843#ifdef USE_TOOLKIT_SCROLL_BARS
8844 /* Scroll bar callbacks send a ClientMessage from which
8845 we construct an input_event. */
8846 else if (event.xclient.message_type
8847 == dpyinfo->Xatom_Scrollbar)
8848 {
8849 x_scroll_bar_to_input_event (&event, bufp);
8850 ++bufp, ++count, --numchars;
8851 goto out;
8852 }
8853#endif /* USE_TOOLKIT_SCROLL_BARS */
8854 else
8855 goto OTHER;
7a13e894
RS
8856 }
8857 break;
dc6f92b8 8858
7a13e894 8859 case SelectionNotify:
3afe33e7 8860#ifdef USE_X_TOOLKIT
19126e11 8861 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 8862 goto OTHER;
3afe33e7 8863#endif /* not USE_X_TOOLKIT */
dfcf069d 8864 x_handle_selection_notify (&event.xselection);
7a13e894 8865 break;
d56a553a 8866
06a2c219 8867 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 8868#ifdef USE_X_TOOLKIT
19126e11 8869 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 8870 goto OTHER;
3afe33e7 8871#endif /* USE_X_TOOLKIT */
7a13e894
RS
8872 {
8873 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 8874
7a13e894
RS
8875 if (numchars == 0)
8876 abort ();
d56a553a 8877
7a13e894
RS
8878 bufp->kind = selection_clear_event;
8879 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
8880 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
8881 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 8882 bufp->frame_or_window = Qnil;
7a13e894 8883 bufp++;
d56a553a 8884
7a13e894
RS
8885 count += 1;
8886 numchars -= 1;
8887 }
8888 break;
dc6f92b8 8889
06a2c219 8890 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 8891#ifdef USE_X_TOOLKIT
19126e11 8892 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 8893 goto OTHER;
3afe33e7 8894#endif /* USE_X_TOOLKIT */
7a13e894 8895 if (x_queue_selection_requests)
19126e11 8896 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
8897 &event);
8898 else
8899 {
8900 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 8901
7a13e894
RS
8902 if (numchars == 0)
8903 abort ();
8904
8905 bufp->kind = selection_request_event;
8906 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
8907 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
8908 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
8909 SELECTION_EVENT_TARGET (bufp) = eventp->target;
8910 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
8911 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 8912 bufp->frame_or_window = Qnil;
7a13e894
RS
8913 bufp++;
8914
8915 count += 1;
8916 numchars -= 1;
8917 }
8918 break;
8919
8920 case PropertyNotify:
3afe33e7 8921#ifdef USE_X_TOOLKIT
19126e11 8922 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 8923 goto OTHER;
3afe33e7 8924#endif /* not USE_X_TOOLKIT */
dfcf069d 8925 x_handle_property_notify (&event.xproperty);
7a13e894 8926 break;
dc6f92b8 8927
7a13e894 8928 case ReparentNotify:
19126e11 8929 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
8930 if (f)
8931 {
8932 int x, y;
7556890b 8933 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 8934 x_real_positions (f, &x, &y);
7556890b
RS
8935 f->output_data.x->left_pos = x;
8936 f->output_data.x->top_pos = y;
7a13e894
RS
8937 }
8938 break;
3bd330d4 8939
7a13e894 8940 case Expose:
19126e11 8941 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 8942 if (f)
dc6f92b8 8943 {
7a13e894
RS
8944 if (f->async_visible == 0)
8945 {
8946 f->async_visible = 1;
8947 f->async_iconified = 0;
06c488fd 8948 f->output_data.x->has_been_visible = 1;
7a13e894
RS
8949 SET_FRAME_GARBAGED (f);
8950 }
8951 else
06a2c219
GM
8952 expose_frame (x_window_to_frame (dpyinfo,
8953 event.xexpose.window),
8954 event.xexpose.x, event.xexpose.y,
8955 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
8956 }
8957 else
7a13e894 8958 {
06a2c219
GM
8959#ifdef USE_TOOLKIT_SCROLL_BARS
8960 /* Dispatch event to the widget. */
8961 goto OTHER;
8962#else /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
8963 struct scroll_bar *bar
8964 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 8965
7a13e894
RS
8966 if (bar)
8967 x_scroll_bar_expose (bar, &event);
3afe33e7 8968#ifdef USE_X_TOOLKIT
7a13e894
RS
8969 else
8970 goto OTHER;
3afe33e7 8971#endif /* USE_X_TOOLKIT */
06a2c219 8972#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
8973 }
8974 break;
dc6f92b8 8975
7a13e894
RS
8976 case GraphicsExpose: /* This occurs when an XCopyArea's
8977 source area was obscured or not
8978 available.*/
19126e11 8979 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
8980 if (f)
8981 {
06a2c219
GM
8982 expose_frame (f,
8983 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
8984 event.xgraphicsexpose.width,
8985 event.xgraphicsexpose.height);
7a13e894 8986 }
3afe33e7 8987#ifdef USE_X_TOOLKIT
7a13e894
RS
8988 else
8989 goto OTHER;
3afe33e7 8990#endif /* USE_X_TOOLKIT */
7a13e894 8991 break;
dc6f92b8 8992
7a13e894 8993 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
8994 source area was completely
8995 available */
7a13e894 8996 break;
dc6f92b8 8997
7a13e894 8998 case UnmapNotify:
06a2c219
GM
8999 /* Redo the mouse-highlight after the tooltip has gone. */
9000 if (event.xmap.window == tip_window)
9001 {
9002 tip_window = 0;
9003 redo_mouse_highlight ();
9004 }
9005
91ea2a7a 9006 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
9007 if (f) /* F may no longer exist if
9008 the frame was deleted. */
9009 {
9010 /* While a frame is unmapped, display generation is
9011 disabled; you don't want to spend time updating a
9012 display that won't ever be seen. */
9013 f->async_visible = 0;
9014 /* We can't distinguish, from the event, whether the window
9015 has become iconified or invisible. So assume, if it
9016 was previously visible, than now it is iconified.
1aa6072f
RS
9017 But x_make_frame_invisible clears both
9018 the visible flag and the iconified flag;
9019 and that way, we know the window is not iconified now. */
7a13e894 9020 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
9021 {
9022 f->async_iconified = 1;
bddd097c 9023
1aa6072f
RS
9024 bufp->kind = iconify_event;
9025 XSETFRAME (bufp->frame_or_window, f);
9026 bufp++;
9027 count++;
9028 numchars--;
9029 }
7a13e894 9030 }
7a13e894 9031 goto OTHER;
dc6f92b8 9032
7a13e894 9033 case MapNotify:
06a2c219
GM
9034 if (event.xmap.window == tip_window)
9035 /* The tooltip has been drawn already. Avoid
9036 the SET_FRAME_GARBAGED below. */
9037 goto OTHER;
9038
9039 /* We use x_top_window_to_frame because map events can
9040 come for sub-windows and they don't mean that the
9041 frame is visible. */
19126e11 9042 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
9043 if (f)
9044 {
9045 f->async_visible = 1;
9046 f->async_iconified = 0;
06c488fd 9047 f->output_data.x->has_been_visible = 1;
dc6f92b8 9048
7a13e894
RS
9049 /* wait_reading_process_input will notice this and update
9050 the frame's display structures. */
9051 SET_FRAME_GARBAGED (f);
bddd097c 9052
d806e720
RS
9053 if (f->iconified)
9054 {
9055 bufp->kind = deiconify_event;
9056 XSETFRAME (bufp->frame_or_window, f);
9057 bufp++;
9058 count++;
9059 numchars--;
9060 }
e73ec6fa 9061 else if (! NILP (Vframe_list)
8e713be6 9062 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
9063 /* Force a redisplay sooner or later
9064 to update the frame titles
9065 in case this is the second frame. */
9066 record_asynch_buffer_change ();
7a13e894 9067 }
7a13e894 9068 goto OTHER;
dc6f92b8 9069
7a13e894 9070 case KeyPress:
19126e11 9071 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 9072
06a2c219
GM
9073#ifdef USE_MOTIF
9074 /* I couldn't find a way to prevent LessTif scroll bars
9075 from consuming key events. */
9076 if (f == 0)
9077 {
9078 Widget widget = XtWindowToWidget (dpyinfo->display,
9079 event.xkey.window);
9080 if (widget && XmIsScrollBar (widget))
9081 {
9082 widget = XtParent (widget);
9083 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
9084 }
9085 }
9086#endif /* USE_MOTIF */
9087
7a13e894
RS
9088 if (f != 0)
9089 {
9090 KeySym keysym, orig_keysym;
9091 /* al%imercury@uunet.uu.net says that making this 81 instead of
9092 80 fixed a bug whereby meta chars made his Emacs hang. */
9093 unsigned char copy_buffer[81];
9094 int modifiers;
64bb1782 9095
7a13e894
RS
9096 event.xkey.state
9097 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
9098 extra_keyboard_modifiers);
9099 modifiers = event.xkey.state;
3a2712f9 9100
7a13e894 9101 /* This will have to go some day... */
752a043f 9102
7a13e894
RS
9103 /* make_lispy_event turns chars into control chars.
9104 Don't do it here because XLookupString is too eager. */
9105 event.xkey.state &= ~ControlMask;
5d46f928
RS
9106 event.xkey.state &= ~(dpyinfo->meta_mod_mask
9107 | dpyinfo->super_mod_mask
9108 | dpyinfo->hyper_mod_mask
9109 | dpyinfo->alt_mod_mask);
9110
1cf4a0d1
RS
9111 /* In case Meta is ComposeCharacter,
9112 clear its status. According to Markus Ehrnsperger
9113 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
9114 this enables ComposeCharacter to work whether or
9115 not it is combined with Meta. */
9116 if (modifiers & dpyinfo->meta_mod_mask)
9117 bzero (&compose_status, sizeof (compose_status));
9118
6c183ba5
RS
9119#ifdef HAVE_X_I18N
9120 if (FRAME_XIC (f))
9121 {
5d7cc324
RS
9122 /* The necessity of the following line took me
9123 a full work-day to decipher from the docs!! */
9124 if (XFilterEvent (&event, None))
9125 break;
6c183ba5
RS
9126 nbytes = XmbLookupString (FRAME_XIC (f),
9127 &event.xkey, copy_buffer,
9128 80, &keysym,
9129 &status_return);
1decb680
PE
9130 if (status_return == XLookupNone)
9131 break;
9132 else if (status_return == XLookupChars)
9133 keysym = NoSymbol;
9134 else if (status_return != XLookupKeySym
9135 && status_return != XLookupBoth)
9136 abort ();
6c183ba5
RS
9137 }
9138 else
9139 nbytes = XLookupString (&event.xkey, copy_buffer,
9140 80, &keysym, &compose_status);
9141#else
0299d313
RS
9142 nbytes = XLookupString (&event.xkey, copy_buffer,
9143 80, &keysym, &compose_status);
6c183ba5 9144#endif
dc6f92b8 9145
7a13e894 9146 orig_keysym = keysym;
55123275 9147
7a13e894
RS
9148 if (numchars > 1)
9149 {
9150 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
9151 || keysym == XK_Delete
1097aea0 9152#ifdef XK_ISO_Left_Tab
441affdb 9153 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 9154#endif
852bff8f 9155 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
9156 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
9157 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 9158#ifdef HPUX
7a13e894
RS
9159 /* This recognizes the "extended function keys".
9160 It seems there's no cleaner way.
9161 Test IsModifierKey to avoid handling mode_switch
9162 incorrectly. */
9163 || ((unsigned) (keysym) >= XK_Select
9164 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
9165#endif
9166#ifdef XK_dead_circumflex
7a13e894 9167 || orig_keysym == XK_dead_circumflex
69388238
RS
9168#endif
9169#ifdef XK_dead_grave
7a13e894 9170 || orig_keysym == XK_dead_grave
69388238
RS
9171#endif
9172#ifdef XK_dead_tilde
7a13e894 9173 || orig_keysym == XK_dead_tilde
69388238
RS
9174#endif
9175#ifdef XK_dead_diaeresis
7a13e894 9176 || orig_keysym == XK_dead_diaeresis
69388238
RS
9177#endif
9178#ifdef XK_dead_macron
7a13e894 9179 || orig_keysym == XK_dead_macron
69388238
RS
9180#endif
9181#ifdef XK_dead_degree
7a13e894 9182 || orig_keysym == XK_dead_degree
69388238
RS
9183#endif
9184#ifdef XK_dead_acute
7a13e894 9185 || orig_keysym == XK_dead_acute
69388238
RS
9186#endif
9187#ifdef XK_dead_cedilla
7a13e894 9188 || orig_keysym == XK_dead_cedilla
69388238
RS
9189#endif
9190#ifdef XK_dead_breve
7a13e894 9191 || orig_keysym == XK_dead_breve
69388238
RS
9192#endif
9193#ifdef XK_dead_ogonek
7a13e894 9194 || orig_keysym == XK_dead_ogonek
69388238
RS
9195#endif
9196#ifdef XK_dead_caron
7a13e894 9197 || orig_keysym == XK_dead_caron
69388238
RS
9198#endif
9199#ifdef XK_dead_doubleacute
7a13e894 9200 || orig_keysym == XK_dead_doubleacute
69388238
RS
9201#endif
9202#ifdef XK_dead_abovedot
7a13e894 9203 || orig_keysym == XK_dead_abovedot
c34790e0 9204#endif
7a13e894
RS
9205 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
9206 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
9207 /* Any "vendor-specific" key is ok. */
9208 || (orig_keysym & (1 << 28)))
9209 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
9210#ifndef HAVE_X11R5
9211#ifdef XK_Mode_switch
7a13e894 9212 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
9213#endif
9214#ifdef XK_Num_Lock
7a13e894 9215 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
9216#endif
9217#endif /* not HAVE_X11R5 */
7a13e894 9218 ))
dc6f92b8 9219 {
10e6549c
RS
9220 if (temp_index == sizeof temp_buffer / sizeof (short))
9221 temp_index = 0;
7a13e894
RS
9222 temp_buffer[temp_index++] = keysym;
9223 bufp->kind = non_ascii_keystroke;
9224 bufp->code = keysym;
e0c1aef2 9225 XSETFRAME (bufp->frame_or_window, f);
334208b7
RS
9226 bufp->modifiers
9227 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9228 modifiers);
1113d9db 9229 bufp->timestamp = event.xkey.time;
dc6f92b8 9230 bufp++;
7a13e894
RS
9231 count++;
9232 numchars--;
06a2c219
GM
9233
9234 if (display_busy_cursor_p)
9235 if (keysym != XK_Return || minibuf_level == 0)
9236 inhibit_busy_cursor = 2;
dc6f92b8 9237 }
7a13e894
RS
9238 else if (numchars > nbytes)
9239 {
9240 register int i;
9241
9242 for (i = 0; i < nbytes; i++)
9243 {
9244 if (temp_index == sizeof temp_buffer / sizeof (short))
9245 temp_index = 0;
9246 temp_buffer[temp_index++] = copy_buffer[i];
9247 bufp->kind = ascii_keystroke;
9248 bufp->code = copy_buffer[i];
9249 XSETFRAME (bufp->frame_or_window, f);
9250 bufp->modifiers
9251 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9252 modifiers);
9253 bufp->timestamp = event.xkey.time;
9254 bufp++;
9255 }
9256
9257 count += nbytes;
9258 numchars -= nbytes;
1decb680
PE
9259
9260 if (keysym == NoSymbol)
9261 break;
7a13e894
RS
9262 }
9263 else
9264 abort ();
dc6f92b8 9265 }
10e6549c
RS
9266 else
9267 abort ();
dc6f92b8 9268 }
717ca130 9269 goto OTHER;
f451eb13 9270
7a13e894 9271 /* Here's a possible interpretation of the whole
06a2c219
GM
9272 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
9273 you get a FocusIn event, you have to get a FocusOut
9274 event before you relinquish the focus. If you
9275 haven't received a FocusIn event, then a mere
9276 LeaveNotify is enough to free you. */
f451eb13 9277
7a13e894 9278 case EnterNotify:
06a2c219
GM
9279 {
9280 int from_menu_bar_p = 0;
9281
9282 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
9283
9284#ifdef LESSTIF_VERSION
9285 /* When clicking outside of a menu bar popup to close
9286 it, we get a FocusIn/ EnterNotify sequence of
9287 events. The flag event.xcrossing.focus is not set
9288 in the EnterNotify event of that sequence because
9289 the focus is in the menu bar,
9290 event.xcrossing.window is the frame's X window.
9291 Unconditionally setting the focus frame to null in
9292 this case is not the right thing, because no event
9293 follows that could set the focus frame to the right
9294 value.
9295
9296 This could be a LessTif bug, but I wasn't able to
9297 reproduce the behavior in a simple test program.
9298
9299 (gerd, LessTif 0.88.1). */
9300
9301 if (!event.xcrossing.focus
9302 && f
9303 && f->output_data.x->menubar_widget)
9304 {
9305 Window focus;
9306 int revert;
9307
9308 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9309 if (focus == XtWindow (f->output_data.x->menubar_widget))
9310 from_menu_bar_p = 1;
9311 }
9312#endif /* LESSTIF_VERSION */
6d4238f3 9313
06a2c219
GM
9314 if (event.xcrossing.focus || from_menu_bar_p)
9315 {
9316 /* Avoid nasty pop/raise loops. */
9317 if (f && (!(f->auto_raise)
9318 || !(f->auto_lower)
9319 || (event.xcrossing.time - enter_timestamp) > 500))
9320 {
9321 x_new_focus_frame (dpyinfo, f);
9322 enter_timestamp = event.xcrossing.time;
9323 }
9324 }
9325 else if (f == dpyinfo->x_focus_frame)
9326 x_new_focus_frame (dpyinfo, 0);
9327
9328 /* EnterNotify counts as mouse movement,
9329 so update things that depend on mouse position. */
9330 if (f && !f->output_data.x->busy_p)
9331 note_mouse_movement (f, &event.xmotion);
9332 goto OTHER;
9333 }
dc6f92b8 9334
7a13e894 9335 case FocusIn:
19126e11 9336 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9337 if (event.xfocus.detail != NotifyPointer)
0f941935 9338 dpyinfo->x_focus_event_frame = f;
7a13e894 9339 if (f)
0f941935 9340 x_new_focus_frame (dpyinfo, f);
f9e24cb9 9341
6c183ba5
RS
9342#ifdef HAVE_X_I18N
9343 if (f && FRAME_XIC (f))
9344 XSetICFocus (FRAME_XIC (f));
9345#endif
9346
7a13e894 9347 goto OTHER;
10c5e63d 9348
7a13e894 9349 case LeaveNotify:
19126e11 9350 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 9351 if (f)
10c5e63d 9352 {
06a2c219
GM
9353 Lisp_Object frame;
9354 int from_menu_bar_p = 0;
9355
7a13e894 9356 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
9357 {
9358 /* If we move outside the frame, then we're
9359 certainly no longer on any text in the frame. */
9360 clear_mouse_face (dpyinfo);
9361 dpyinfo->mouse_face_mouse_frame = 0;
9362 }
9363
9364 /* Generate a nil HELP_EVENT to cancel a help-echo.
9365 Do it only if there's something to cancel.
9366 Otherwise, the startup message is cleared when
9367 the mouse leaves the frame. */
9368 if (any_help_event_p)
9369 {
9370 XSETFRAME (frame, f);
9371 bufp->kind = HELP_EVENT;
9372 bufp->frame_or_window = Fcons (frame, Qnil);
9373 ++bufp, ++count, --numchars;
9374 }
7a13e894 9375
06a2c219
GM
9376#ifdef LESSTIF_VERSION
9377 /* Please see the comment at the start of the
9378 EnterNotify case. */
9379 if (!event.xcrossing.focus
9380 && f->output_data.x->menubar_widget)
9381 {
9382 Window focus;
9383 int revert;
9384 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9385 if (focus == XtWindow (f->output_data.x->menubar_widget))
9386 from_menu_bar_p = 1;
9387 }
9388#endif /* LESSTIF_VERSION */
9389
9390 if (event.xcrossing.focus || from_menu_bar_p)
0f941935 9391 x_mouse_leave (dpyinfo);
10c5e63d 9392 else
7a13e894 9393 {
0f941935
KH
9394 if (f == dpyinfo->x_focus_event_frame)
9395 dpyinfo->x_focus_event_frame = 0;
9396 if (f == dpyinfo->x_focus_frame)
9397 x_new_focus_frame (dpyinfo, 0);
7a13e894 9398 }
10c5e63d 9399 }
7a13e894 9400 goto OTHER;
dc6f92b8 9401
7a13e894 9402 case FocusOut:
19126e11 9403 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9404 if (event.xfocus.detail != NotifyPointer
0f941935
KH
9405 && f == dpyinfo->x_focus_event_frame)
9406 dpyinfo->x_focus_event_frame = 0;
9407 if (f && f == dpyinfo->x_focus_frame)
9408 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 9409
6c183ba5
RS
9410#ifdef HAVE_X_I18N
9411 if (f && FRAME_XIC (f))
9412 XUnsetICFocus (FRAME_XIC (f));
9413#endif
9414
7a13e894 9415 goto OTHER;
dc6f92b8 9416
7a13e894 9417 case MotionNotify:
dc6f92b8 9418 {
06a2c219
GM
9419 previous_help_echo = help_echo;
9420 help_echo = Qnil;
9421
7a13e894
RS
9422 if (dpyinfo->grabbed && last_mouse_frame
9423 && FRAME_LIVE_P (last_mouse_frame))
9424 f = last_mouse_frame;
9425 else
19126e11 9426 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 9427
7a13e894
RS
9428 if (f)
9429 note_mouse_movement (f, &event.xmotion);
9430 else
9431 {
06a2c219 9432#ifndef USE_X_TOOLKIT
7a13e894
RS
9433 struct scroll_bar *bar
9434 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 9435
7a13e894
RS
9436 if (bar)
9437 x_scroll_bar_note_movement (bar, &event);
06a2c219 9438#endif /* USE_X_TOOLKIT */
b8009dd1 9439
06a2c219
GM
9440 /* If we move outside the frame, then we're
9441 certainly no longer on any text in the frame. */
7a13e894
RS
9442 clear_mouse_face (dpyinfo);
9443 }
06a2c219
GM
9444
9445 /* If the contents of the global variable help_echo
9446 has changed, generate a HELP_EVENT. */
9447 if (STRINGP (help_echo)
9448 || STRINGP (previous_help_echo))
9449 {
9450 Lisp_Object frame;
9451
9452 if (f)
9453 XSETFRAME (frame, f);
9454 else
9455 frame = Qnil;
9456
9457 any_help_event_p = 1;
9458 bufp->kind = HELP_EVENT;
9459 bufp->frame_or_window = Fcons (frame, help_echo);
9460 ++bufp, ++count, --numchars;
9461 }
9462
9463 goto OTHER;
dc6f92b8 9464 }
dc6f92b8 9465
7a13e894 9466 case ConfigureNotify:
9829ddba
RS
9467 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
9468 if (f)
af395ec1 9469 {
bf1b7b30
KH
9470 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
9471 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
06a2c219 9472
2d7fc7e8
RS
9473#ifndef USE_X_TOOLKIT
9474 /* In the toolkit version, change_frame_size
9475 is called by the code that handles resizing
9476 of the EmacsFrame widget. */
7a13e894 9477
7a13e894
RS
9478 /* Even if the number of character rows and columns has
9479 not changed, the font size may have changed, so we need
9480 to check the pixel dimensions as well. */
9481 if (columns != f->width
9482 || rows != f->height
7556890b
RS
9483 || event.xconfigure.width != f->output_data.x->pixel_width
9484 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 9485 {
7d1e984f 9486 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 9487 SET_FRAME_GARBAGED (f);
e687d06e 9488 cancel_mouse_face (f);
7a13e894 9489 }
2d7fc7e8 9490#endif
af395ec1 9491
7556890b
RS
9492 f->output_data.x->pixel_width = event.xconfigure.width;
9493 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
9494
9495 /* What we have now is the position of Emacs's own window.
9496 Convert that to the position of the window manager window. */
dcb07ae9
RS
9497 x_real_positions (f, &f->output_data.x->left_pos,
9498 &f->output_data.x->top_pos);
9499
9500 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
9501 {
9502 /* Since the WM decorations come below top_pos now,
9503 we must put them below top_pos in the future. */
9504 f->output_data.x->win_gravity = NorthWestGravity;
9505 x_wm_set_size_hint (f, (long) 0, 0);
9506 }
8f08dc93
KH
9507#ifdef USE_MOTIF
9508 /* Some window managers pass (0,0) as the location of
9509 the window, and the Motif event handler stores it
9510 in the emacs widget, which messes up Motif menus. */
9511 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
9512 {
9513 event.xconfigure.x = f->output_data.x->widget->core.x;
9514 event.xconfigure.y = f->output_data.x->widget->core.y;
9515 }
06a2c219 9516#endif /* USE_MOTIF */
7a13e894 9517 }
2d7fc7e8 9518 goto OTHER;
dc6f92b8 9519
7a13e894
RS
9520 case ButtonPress:
9521 case ButtonRelease:
9522 {
9523 /* If we decide we want to generate an event to be seen
9524 by the rest of Emacs, we put it here. */
9525 struct input_event emacs_event;
9ea173e8 9526 int tool_bar_p = 0;
06a2c219 9527
7a13e894 9528 emacs_event.kind = no_event;
7a13e894 9529 bzero (&compose_status, sizeof (compose_status));
9b07615b 9530
06a2c219
GM
9531 if (dpyinfo->grabbed
9532 && last_mouse_frame
9f67f20b
RS
9533 && FRAME_LIVE_P (last_mouse_frame))
9534 f = last_mouse_frame;
9535 else
2224b905 9536 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 9537
06a2c219
GM
9538 if (f)
9539 {
9ea173e8
GM
9540 /* Is this in the tool-bar? */
9541 if (WINDOWP (f->tool_bar_window)
9542 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
9543 {
9544 Lisp_Object window;
9545 int p, x, y;
9546
9547 x = event.xbutton.x;
9548 y = event.xbutton.y;
9549
9550 /* Set x and y. */
9551 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 9552 if (EQ (window, f->tool_bar_window))
06a2c219 9553 {
9ea173e8
GM
9554 x_handle_tool_bar_click (f, &event.xbutton);
9555 tool_bar_p = 1;
06a2c219
GM
9556 }
9557 }
9558
9ea173e8 9559 if (!tool_bar_p)
06a2c219
GM
9560 if (!dpyinfo->x_focus_frame
9561 || f == dpyinfo->x_focus_frame)
9562 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
9563 }
9564 else
9565 {
06a2c219 9566#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
9567 struct scroll_bar *bar
9568 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 9569
7a13e894
RS
9570 if (bar)
9571 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 9572#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9573 }
9574
9575 if (event.type == ButtonPress)
9576 {
9577 dpyinfo->grabbed |= (1 << event.xbutton.button);
9578 last_mouse_frame = f;
edad46f6
KH
9579 /* Ignore any mouse motion that happened
9580 before this event; any subsequent mouse-movement
9581 Emacs events should reflect only motion after
9582 the ButtonPress. */
a00e91cd
KH
9583 if (f != 0)
9584 f->mouse_moved = 0;
06a2c219 9585
9ea173e8
GM
9586 if (!tool_bar_p)
9587 last_tool_bar_item = -1;
06a2c219
GM
9588 if (display_busy_cursor_p)
9589 inhibit_busy_cursor = 2;
7a13e894 9590 }
3afe33e7
RS
9591 else
9592 {
7a13e894 9593 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 9594 }
23faf38f 9595
7a13e894
RS
9596 if (numchars >= 1 && emacs_event.kind != no_event)
9597 {
9598 bcopy (&emacs_event, bufp, sizeof (struct input_event));
9599 bufp++;
9600 count++;
9601 numchars--;
9602 }
3afe33e7
RS
9603
9604#ifdef USE_X_TOOLKIT
2224b905
RS
9605 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
9606 /* For a down-event in the menu bar,
9607 don't pass it to Xt right now.
9608 Instead, save it away
9609 and we will pass it to Xt from kbd_buffer_get_event.
9610 That way, we can run some Lisp code first. */
91375f8f
RS
9611 if (f && event.type == ButtonPress
9612 /* Verify the event is really within the menu bar
9613 and not just sent to it due to grabbing. */
9614 && event.xbutton.x >= 0
9615 && event.xbutton.x < f->output_data.x->pixel_width
9616 && event.xbutton.y >= 0
9617 && event.xbutton.y < f->output_data.x->menubar_height
9618 && event.xbutton.same_screen)
2224b905 9619 {
8805890a 9620 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
9621 XSETFRAME (last_mouse_press_frame, f);
9622 }
9623 else if (event.type == ButtonPress)
9624 {
9625 last_mouse_press_frame = Qnil;
30e671c3 9626 goto OTHER;
ce89ef46 9627 }
06a2c219 9628
2237cac9
RS
9629#ifdef USE_MOTIF /* This should do not harm for Lucid,
9630 but I am trying to be cautious. */
ce89ef46
RS
9631 else if (event.type == ButtonRelease)
9632 {
2237cac9 9633 if (!NILP (last_mouse_press_frame))
f10ded1c 9634 {
2237cac9
RS
9635 f = XFRAME (last_mouse_press_frame);
9636 if (f->output_data.x)
06a2c219 9637 SET_SAVED_BUTTON_EVENT;
f10ded1c 9638 }
06a2c219 9639 else
30e671c3 9640 goto OTHER;
2224b905 9641 }
2237cac9 9642#endif /* USE_MOTIF */
2224b905
RS
9643 else
9644 goto OTHER;
3afe33e7 9645#endif /* USE_X_TOOLKIT */
7a13e894
RS
9646 }
9647 break;
dc6f92b8 9648
7a13e894 9649 case CirculateNotify:
06a2c219
GM
9650 goto OTHER;
9651
7a13e894 9652 case CirculateRequest:
06a2c219
GM
9653 goto OTHER;
9654
9655 case VisibilityNotify:
9656 goto OTHER;
dc6f92b8 9657
7a13e894
RS
9658 case MappingNotify:
9659 /* Someone has changed the keyboard mapping - update the
9660 local cache. */
9661 switch (event.xmapping.request)
9662 {
9663 case MappingModifier:
9664 x_find_modifier_meanings (dpyinfo);
9665 /* This is meant to fall through. */
9666 case MappingKeyboard:
9667 XRefreshKeyboardMapping (&event.xmapping);
9668 }
7a13e894 9669 goto OTHER;
dc6f92b8 9670
7a13e894 9671 default:
7a13e894 9672 OTHER:
717ca130 9673#ifdef USE_X_TOOLKIT
7a13e894
RS
9674 BLOCK_INPUT;
9675 XtDispatchEvent (&event);
9676 UNBLOCK_INPUT;
3afe33e7 9677#endif /* USE_X_TOOLKIT */
7a13e894
RS
9678 break;
9679 }
dc6f92b8
JB
9680 }
9681 }
9682
06a2c219
GM
9683 out:;
9684
9a5196d0
RS
9685 /* On some systems, an X bug causes Emacs to get no more events
9686 when the window is destroyed. Detect that. (1994.) */
58769bee 9687 if (! event_found)
ef2a22d0 9688 {
ef2a22d0
RS
9689 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
9690 One XNOOP in 100 loops will make Emacs terminate.
9691 B. Bretthauer, 1994 */
9692 x_noop_count++;
58769bee 9693 if (x_noop_count >= 100)
ef2a22d0
RS
9694 {
9695 x_noop_count=0;
2224b905
RS
9696
9697 if (next_noop_dpyinfo == 0)
9698 next_noop_dpyinfo = x_display_list;
9699
9700 XNoOp (next_noop_dpyinfo->display);
9701
9702 /* Each time we get here, cycle through the displays now open. */
9703 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
9704 }
9705 }
502add23 9706
06a2c219 9707 /* If the focus was just given to an auto-raising frame,
0134a210 9708 raise it now. */
7a13e894 9709 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
9710 if (pending_autoraise_frame)
9711 {
9712 x_raise_frame (pending_autoraise_frame);
9713 pending_autoraise_frame = 0;
9714 }
0134a210 9715
dc6f92b8
JB
9716 UNBLOCK_INPUT;
9717 return count;
9718}
06a2c219
GM
9719
9720
9721
dc6f92b8 9722\f
06a2c219
GM
9723/***********************************************************************
9724 Text Cursor
9725 ***********************************************************************/
9726
9727/* Note if the text cursor of window W has been overwritten by a
9728 drawing operation that outputs N glyphs starting at HPOS in the
9729 line given by output_cursor.vpos. N < 0 means all the rest of the
9730 line after HPOS has been written. */
9731
9732static void
9733note_overwritten_text_cursor (w, hpos, n)
9734 struct window *w;
9735 int hpos, n;
9736{
9737 if (updated_area == TEXT_AREA
9738 && output_cursor.vpos == w->phys_cursor.vpos
9739 && hpos <= w->phys_cursor.hpos
9740 && (n < 0
9741 || hpos + n > w->phys_cursor.hpos))
9742 w->phys_cursor_on_p = 0;
9743}
f451eb13
JB
9744
9745
06a2c219
GM
9746/* Set clipping for output in glyph row ROW. W is the window in which
9747 we operate. GC is the graphics context to set clipping in.
9748 WHOLE_LINE_P non-zero means include the areas used for truncation
9749 mark display and alike in the clipping rectangle.
9750
9751 ROW may be a text row or, e.g., a mode line. Text rows must be
9752 clipped to the interior of the window dedicated to text display,
9753 mode lines must be clipped to the whole window. */
dc6f92b8
JB
9754
9755static void
06a2c219
GM
9756x_clip_to_row (w, row, gc, whole_line_p)
9757 struct window *w;
9758 struct glyph_row *row;
9759 GC gc;
9760 int whole_line_p;
dc6f92b8 9761{
06a2c219
GM
9762 struct frame *f = XFRAME (WINDOW_FRAME (w));
9763 XRectangle clip_rect;
9764 int window_x, window_y, window_width, window_height;
dc6f92b8 9765
06a2c219 9766 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 9767
06a2c219
GM
9768 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
9769 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
9770 clip_rect.y = max (clip_rect.y, window_y);
9771 clip_rect.width = window_width;
9772 clip_rect.height = row->visible_height;
5c1aae96 9773
06a2c219
GM
9774 /* If clipping to the whole line, including trunc marks, extend
9775 the rectangle to the left and increase its width. */
9776 if (whole_line_p)
9777 {
110859fc
GM
9778 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
9779 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 9780 }
5c1aae96 9781
06a2c219 9782 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
9783}
9784
06a2c219
GM
9785
9786/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
9787
9788static void
06a2c219
GM
9789x_draw_hollow_cursor (w, row)
9790 struct window *w;
9791 struct glyph_row *row;
dc6f92b8 9792{
06a2c219
GM
9793 struct frame *f = XFRAME (WINDOW_FRAME (w));
9794 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9795 Display *dpy = FRAME_X_DISPLAY (f);
9796 int x, y, wd, h;
9797 XGCValues xgcv;
9798 struct glyph *cursor_glyph;
9799 GC gc;
9800
9801 /* Compute frame-relative coordinates from window-relative
9802 coordinates. */
9803 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
9804 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
9805 + row->ascent - w->phys_cursor_ascent);
9806 h = row->height - 1;
9807
9808 /* Get the glyph the cursor is on. If we can't tell because
9809 the current matrix is invalid or such, give up. */
9810 cursor_glyph = get_phys_cursor_glyph (w);
9811 if (cursor_glyph == NULL)
dc6f92b8
JB
9812 return;
9813
06a2c219
GM
9814 /* Compute the width of the rectangle to draw. If on a stretch
9815 glyph, and `x-stretch-block-cursor' is nil, don't draw a
9816 rectangle as wide as the glyph, but use a canonical character
9817 width instead. */
9818 wd = cursor_glyph->pixel_width - 1;
9819 if (cursor_glyph->type == STRETCH_GLYPH
9820 && !x_stretch_cursor_p)
9821 wd = min (CANON_X_UNIT (f), wd);
9822
9823 /* The foreground of cursor_gc is typically the same as the normal
9824 background color, which can cause the cursor box to be invisible. */
9825 xgcv.foreground = f->output_data.x->cursor_pixel;
9826 if (dpyinfo->scratch_cursor_gc)
9827 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
9828 else
9829 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
9830 GCForeground, &xgcv);
9831 gc = dpyinfo->scratch_cursor_gc;
9832
9833 /* Set clipping, draw the rectangle, and reset clipping again. */
9834 x_clip_to_row (w, row, gc, 0);
9835 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
9836 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
9837}
9838
06a2c219
GM
9839
9840/* Draw a bar cursor on window W in glyph row ROW.
9841
9842 Implementation note: One would like to draw a bar cursor with an
9843 angle equal to the one given by the font property XA_ITALIC_ANGLE.
9844 Unfortunately, I didn't find a font yet that has this property set.
9845 --gerd. */
dc6f92b8
JB
9846
9847static void
06a2c219
GM
9848x_draw_bar_cursor (w, row)
9849 struct window *w;
9850 struct glyph_row *row;
dc6f92b8 9851{
06a2c219
GM
9852 /* If cursor hpos is out of bounds, don't draw garbage. This can
9853 happen in mini-buffer windows when switching between echo area
9854 glyphs and mini-buffer. */
9855 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
9856 {
9857 struct frame *f = XFRAME (w->frame);
9858 struct glyph *cursor_glyph;
9859 GC gc;
9860 int x;
9861 unsigned long mask;
9862 XGCValues xgcv;
9863 Display *dpy;
9864 Window window;
9865
9866 cursor_glyph = get_phys_cursor_glyph (w);
9867 if (cursor_glyph == NULL)
9868 return;
9869
9870 xgcv.background = f->output_data.x->cursor_pixel;
9871 xgcv.foreground = f->output_data.x->cursor_pixel;
9872 xgcv.graphics_exposures = 0;
9873 mask = GCForeground | GCBackground | GCGraphicsExposures;
9874 dpy = FRAME_X_DISPLAY (f);
9875 window = FRAME_X_WINDOW (f);
9876 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
9877
9878 if (gc)
9879 XChangeGC (dpy, gc, mask, &xgcv);
9880 else
9881 {
9882 gc = XCreateGC (dpy, window, mask, &xgcv);
9883 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
9884 }
9885
9886 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
9887 x_clip_to_row (w, row, gc, 0);
9888 XFillRectangle (dpy, window, gc,
9889 x,
9890 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
9891 min (cursor_glyph->pixel_width,
9892 f->output_data.x->cursor_width),
9893 row->height);
9894 XSetClipMask (dpy, gc, None);
9895 }
dc6f92b8
JB
9896}
9897
06a2c219
GM
9898
9899/* Clear the cursor of window W to background color, and mark the
9900 cursor as not shown. This is used when the text where the cursor
9901 is is about to be rewritten. */
9902
dc6f92b8 9903static void
06a2c219
GM
9904x_clear_cursor (w)
9905 struct window *w;
dc6f92b8 9906{
06a2c219
GM
9907 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
9908 x_update_window_cursor (w, 0);
9909}
90e65f07 9910
dbc4e1c1 9911
06a2c219
GM
9912/* Draw the cursor glyph of window W in glyph row ROW. See the
9913 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 9914
06a2c219
GM
9915static void
9916x_draw_phys_cursor_glyph (w, row, hl)
9917 struct window *w;
9918 struct glyph_row *row;
9919 enum draw_glyphs_face hl;
9920{
9921 /* If cursor hpos is out of bounds, don't draw garbage. This can
9922 happen in mini-buffer windows when switching between echo area
9923 glyphs and mini-buffer. */
9924 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
9925 {
9926 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
9927 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
9928 hl, 0, 0, 0);
9929
9930 /* When we erase the cursor, and ROW is overlapped by other
9931 rows, make sure that these overlapping parts of other rows
9932 are redrawn. */
9933 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
9934 {
9935 if (row > w->current_matrix->rows
9936 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
9937 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
9938
9939 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
9940 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
9941 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
9942 }
9943 }
06a2c219 9944}
dbc4e1c1 9945
eea6af04 9946
06a2c219 9947/* Erase the image of a cursor of window W from the screen. */
eea6af04 9948
06a2c219
GM
9949static void
9950x_erase_phys_cursor (w)
9951 struct window *w;
9952{
9953 struct frame *f = XFRAME (w->frame);
9954 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9955 int hpos = w->phys_cursor.hpos;
9956 int vpos = w->phys_cursor.vpos;
9957 int mouse_face_here_p = 0;
9958 struct glyph_matrix *active_glyphs = w->current_matrix;
9959 struct glyph_row *cursor_row;
9960 struct glyph *cursor_glyph;
9961 enum draw_glyphs_face hl;
9962
9963 /* No cursor displayed or row invalidated => nothing to do on the
9964 screen. */
9965 if (w->phys_cursor_type == NO_CURSOR)
9966 goto mark_cursor_off;
9967
9968 /* VPOS >= active_glyphs->nrows means that window has been resized.
9969 Don't bother to erase the cursor. */
9970 if (vpos >= active_glyphs->nrows)
9971 goto mark_cursor_off;
9972
9973 /* If row containing cursor is marked invalid, there is nothing we
9974 can do. */
9975 cursor_row = MATRIX_ROW (active_glyphs, vpos);
9976 if (!cursor_row->enabled_p)
9977 goto mark_cursor_off;
9978
9979 /* This can happen when the new row is shorter than the old one.
9980 In this case, either x_draw_glyphs or clear_end_of_line
9981 should have cleared the cursor. Note that we wouldn't be
9982 able to erase the cursor in this case because we don't have a
9983 cursor glyph at hand. */
9984 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
9985 goto mark_cursor_off;
9986
9987 /* If the cursor is in the mouse face area, redisplay that when
9988 we clear the cursor. */
9989 if (w == XWINDOW (dpyinfo->mouse_face_window)
9990 && (vpos > dpyinfo->mouse_face_beg_row
9991 || (vpos == dpyinfo->mouse_face_beg_row
9992 && hpos >= dpyinfo->mouse_face_beg_col))
9993 && (vpos < dpyinfo->mouse_face_end_row
9994 || (vpos == dpyinfo->mouse_face_end_row
9995 && hpos < dpyinfo->mouse_face_end_col))
9996 /* Don't redraw the cursor's spot in mouse face if it is at the
9997 end of a line (on a newline). The cursor appears there, but
9998 mouse highlighting does not. */
9999 && cursor_row->used[TEXT_AREA] > hpos)
10000 mouse_face_here_p = 1;
10001
10002 /* Maybe clear the display under the cursor. */
10003 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
10004 {
10005 int x;
045dee35 10006 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 10007
06a2c219
GM
10008 cursor_glyph = get_phys_cursor_glyph (w);
10009 if (cursor_glyph == NULL)
10010 goto mark_cursor_off;
dbc4e1c1 10011
06a2c219
GM
10012 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
10013
10014 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10015 x,
045dee35 10016 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219
GM
10017 cursor_row->y)),
10018 cursor_glyph->pixel_width,
10019 cursor_row->visible_height,
10020 False);
dbc4e1c1 10021 }
06a2c219
GM
10022
10023 /* Erase the cursor by redrawing the character underneath it. */
10024 if (mouse_face_here_p)
10025 hl = DRAW_MOUSE_FACE;
10026 else if (cursor_row->inverse_p)
10027 hl = DRAW_INVERSE_VIDEO;
10028 else
10029 hl = DRAW_NORMAL_TEXT;
10030 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 10031
06a2c219
GM
10032 mark_cursor_off:
10033 w->phys_cursor_on_p = 0;
10034 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
10035}
10036
10037
06a2c219
GM
10038/* Display or clear cursor of window W. If ON is zero, clear the
10039 cursor. If it is non-zero, display the cursor. If ON is nonzero,
10040 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 10041
06a2c219
GM
10042void
10043x_display_and_set_cursor (w, on, hpos, vpos, x, y)
10044 struct window *w;
10045 int on, hpos, vpos, x, y;
dbc4e1c1 10046{
06a2c219
GM
10047 struct frame *f = XFRAME (w->frame);
10048 int new_cursor_type;
10049 struct glyph_matrix *current_glyphs;
10050 struct glyph_row *glyph_row;
10051 struct glyph *glyph;
dbc4e1c1 10052
49d838ea 10053 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
10054 windows and frames; in the latter case, the frame or window may
10055 be in the midst of changing its size, and x and y may be off the
10056 window. */
10057 if (! FRAME_VISIBLE_P (f)
10058 || FRAME_GARBAGED_P (f)
10059 || vpos >= w->current_matrix->nrows
10060 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
10061 return;
10062
10063 /* If cursor is off and we want it off, return quickly. */
06a2c219 10064 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
10065 return;
10066
06a2c219
GM
10067 current_glyphs = w->current_matrix;
10068 glyph_row = MATRIX_ROW (current_glyphs, vpos);
10069 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
10070
10071 /* If cursor row is not enabled, we don't really know where to
10072 display the cursor. */
10073 if (!glyph_row->enabled_p)
10074 {
10075 w->phys_cursor_on_p = 0;
10076 return;
10077 }
10078
10079 xassert (interrupt_input_blocked);
10080
10081 /* Set new_cursor_type to the cursor we want to be displayed. In a
10082 mini-buffer window, we want the cursor only to appear if we are
10083 reading input from this window. For the selected window, we want
10084 the cursor type given by the frame parameter. If explicitly
10085 marked off, draw no cursor. In all other cases, we want a hollow
10086 box cursor. */
9b4a7047
GM
10087 if (cursor_in_echo_area
10088 && FRAME_HAS_MINIBUF_P (f)
10089 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 10090 {
9b4a7047
GM
10091 if (w == XWINDOW (echo_area_window))
10092 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
10093 else
10094 new_cursor_type = HOLLOW_BOX_CURSOR;
10095 }
06a2c219 10096 else
9b4a7047
GM
10097 {
10098 if (w != XWINDOW (selected_window)
10099 || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
10100 {
10101 if (MINI_WINDOW_P (w))
10102 new_cursor_type = NO_CURSOR;
10103 else
10104 new_cursor_type = HOLLOW_BOX_CURSOR;
10105 }
10106 else if (w->cursor_off_p)
10107 new_cursor_type = NO_CURSOR;
10108 else
10109 new_cursor_type = FRAME_DESIRED_CURSOR (f);
10110 }
06a2c219
GM
10111
10112 /* If cursor is currently being shown and we don't want it to be or
10113 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 10114 erase it. */
06a2c219 10115 if (w->phys_cursor_on_p
dc6f92b8 10116 && (!on
06a2c219
GM
10117 || w->phys_cursor.x != x
10118 || w->phys_cursor.y != y
10119 || new_cursor_type != w->phys_cursor_type))
10120 x_erase_phys_cursor (w);
10121
10122 /* If the cursor is now invisible and we want it to be visible,
10123 display it. */
10124 if (on && !w->phys_cursor_on_p)
10125 {
10126 w->phys_cursor_ascent = glyph_row->ascent;
10127 w->phys_cursor_height = glyph_row->height;
10128
10129 /* Set phys_cursor_.* before x_draw_.* is called because some
10130 of them may need the information. */
10131 w->phys_cursor.x = x;
10132 w->phys_cursor.y = glyph_row->y;
10133 w->phys_cursor.hpos = hpos;
10134 w->phys_cursor.vpos = vpos;
10135 w->phys_cursor_type = new_cursor_type;
10136 w->phys_cursor_on_p = 1;
10137
10138 switch (new_cursor_type)
dc6f92b8 10139 {
06a2c219
GM
10140 case HOLLOW_BOX_CURSOR:
10141 x_draw_hollow_cursor (w, glyph_row);
10142 break;
10143
10144 case FILLED_BOX_CURSOR:
10145 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
10146 break;
10147
10148 case BAR_CURSOR:
10149 x_draw_bar_cursor (w, glyph_row);
10150 break;
10151
10152 case NO_CURSOR:
10153 break;
dc6f92b8 10154
06a2c219
GM
10155 default:
10156 abort ();
10157 }
dc6f92b8
JB
10158 }
10159
06a2c219 10160#ifndef XFlush
f676886a 10161 if (updating_frame != f)
334208b7 10162 XFlush (FRAME_X_DISPLAY (f));
06a2c219 10163#endif
dc6f92b8
JB
10164}
10165
06a2c219
GM
10166
10167/* Display the cursor on window W, or clear it. X and Y are window
10168 relative pixel coordinates. HPOS and VPOS are glyph matrix
10169 positions. If W is not the selected window, display a hollow
10170 cursor. ON non-zero means display the cursor at X, Y which
10171 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 10172
dfcf069d 10173void
06a2c219
GM
10174x_display_cursor (w, on, hpos, vpos, x, y)
10175 struct window *w;
10176 int on, hpos, vpos, x, y;
dc6f92b8 10177{
f94397b5 10178 BLOCK_INPUT;
06a2c219 10179 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
10180 UNBLOCK_INPUT;
10181}
10182
06a2c219
GM
10183
10184/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
10185 Don't change the cursor's position. */
10186
dfcf069d 10187void
06a2c219 10188x_update_cursor (f, on_p)
5d46f928 10189 struct frame *f;
5d46f928 10190{
06a2c219
GM
10191 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
10192}
10193
10194
10195/* Call x_update_window_cursor with parameter ON_P on all leaf windows
10196 in the window tree rooted at W. */
10197
10198static void
10199x_update_cursor_in_window_tree (w, on_p)
10200 struct window *w;
10201 int on_p;
10202{
10203 while (w)
10204 {
10205 if (!NILP (w->hchild))
10206 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
10207 else if (!NILP (w->vchild))
10208 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
10209 else
10210 x_update_window_cursor (w, on_p);
10211
10212 w = NILP (w->next) ? 0 : XWINDOW (w->next);
10213 }
10214}
5d46f928 10215
f94397b5 10216
06a2c219
GM
10217/* Switch the display of W's cursor on or off, according to the value
10218 of ON. */
10219
10220static void
10221x_update_window_cursor (w, on)
10222 struct window *w;
10223 int on;
10224{
10225 BLOCK_INPUT;
10226 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
10227 w->phys_cursor.x, w->phys_cursor.y);
f94397b5 10228 UNBLOCK_INPUT;
dc6f92b8 10229}
06a2c219
GM
10230
10231
10232
dc6f92b8
JB
10233\f
10234/* Icons. */
10235
f676886a 10236/* Refresh bitmap kitchen sink icon for frame F
06a2c219 10237 when we get an expose event for it. */
dc6f92b8 10238
dfcf069d 10239void
f676886a
JB
10240refreshicon (f)
10241 struct frame *f;
dc6f92b8 10242{
06a2c219 10243 /* Normally, the window manager handles this function. */
dc6f92b8
JB
10244}
10245
dbc4e1c1 10246/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
10247
10248int
990ba854 10249x_bitmap_icon (f, file)
f676886a 10250 struct frame *f;
990ba854 10251 Lisp_Object file;
dc6f92b8 10252{
06a2c219 10253 int bitmap_id;
dc6f92b8 10254
c118dd06 10255 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10256 return 1;
10257
990ba854 10258 /* Free up our existing icon bitmap if any. */
7556890b
RS
10259 if (f->output_data.x->icon_bitmap > 0)
10260 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10261 f->output_data.x->icon_bitmap = 0;
990ba854
RS
10262
10263 if (STRINGP (file))
7f2ae036
RS
10264 bitmap_id = x_create_bitmap_from_file (f, file);
10265 else
10266 {
990ba854 10267 /* Create the GNU bitmap if necessary. */
5bf01b68 10268 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
10269 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
10270 = x_create_bitmap_from_data (f, gnu_bits,
10271 gnu_width, gnu_height);
990ba854
RS
10272
10273 /* The first time we create the GNU bitmap,
06a2c219 10274 this increments the ref-count one extra time.
990ba854
RS
10275 As a result, the GNU bitmap is never freed.
10276 That way, we don't have to worry about allocating it again. */
334208b7 10277 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 10278
334208b7 10279 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
10280 }
10281
10282 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 10283 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
10284
10285 return 0;
10286}
10287
10288
1be2d067
KH
10289/* Make the x-window of frame F use a rectangle with text.
10290 Use ICON_NAME as the text. */
dc6f92b8
JB
10291
10292int
f676886a
JB
10293x_text_icon (f, icon_name)
10294 struct frame *f;
dc6f92b8
JB
10295 char *icon_name;
10296{
c118dd06 10297 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10298 return 1;
10299
1be2d067
KH
10300#ifdef HAVE_X11R4
10301 {
10302 XTextProperty text;
10303 text.value = (unsigned char *) icon_name;
10304 text.encoding = XA_STRING;
10305 text.format = 8;
10306 text.nitems = strlen (icon_name);
10307#ifdef USE_X_TOOLKIT
7556890b 10308 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
10309 &text);
10310#else /* not USE_X_TOOLKIT */
10311 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
10312#endif /* not USE_X_TOOLKIT */
10313 }
10314#else /* not HAVE_X11R4 */
10315 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
10316#endif /* not HAVE_X11R4 */
58769bee 10317
7556890b
RS
10318 if (f->output_data.x->icon_bitmap > 0)
10319 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10320 f->output_data.x->icon_bitmap = 0;
b1c884c3 10321 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
10322
10323 return 0;
10324}
10325\f
e99db5a1
RS
10326#define X_ERROR_MESSAGE_SIZE 200
10327
10328/* If non-nil, this should be a string.
10329 It means catch X errors and store the error message in this string. */
10330
10331static Lisp_Object x_error_message_string;
10332
10333/* An X error handler which stores the error message in
10334 x_error_message_string. This is called from x_error_handler if
10335 x_catch_errors is in effect. */
10336
06a2c219 10337static void
e99db5a1
RS
10338x_error_catcher (display, error)
10339 Display *display;
10340 XErrorEvent *error;
10341{
10342 XGetErrorText (display, error->error_code,
10343 XSTRING (x_error_message_string)->data,
10344 X_ERROR_MESSAGE_SIZE);
10345}
10346
10347/* Begin trapping X errors for display DPY. Actually we trap X errors
10348 for all displays, but DPY should be the display you are actually
10349 operating on.
10350
10351 After calling this function, X protocol errors no longer cause
10352 Emacs to exit; instead, they are recorded in the string
10353 stored in x_error_message_string.
10354
10355 Calling x_check_errors signals an Emacs error if an X error has
10356 occurred since the last call to x_catch_errors or x_check_errors.
10357
10358 Calling x_uncatch_errors resumes the normal error handling. */
10359
10360void x_check_errors ();
10361static Lisp_Object x_catch_errors_unwind ();
10362
10363int
10364x_catch_errors (dpy)
10365 Display *dpy;
10366{
10367 int count = specpdl_ptr - specpdl;
10368
10369 /* Make sure any errors from previous requests have been dealt with. */
10370 XSync (dpy, False);
10371
10372 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
10373
10374 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
10375 XSTRING (x_error_message_string)->data[0] = 0;
10376
10377 return count;
10378}
10379
10380/* Unbind the binding that we made to check for X errors. */
10381
10382static Lisp_Object
10383x_catch_errors_unwind (old_val)
10384 Lisp_Object old_val;
10385{
10386 x_error_message_string = old_val;
10387 return Qnil;
10388}
10389
10390/* If any X protocol errors have arrived since the last call to
10391 x_catch_errors or x_check_errors, signal an Emacs error using
10392 sprintf (a buffer, FORMAT, the x error message text) as the text. */
10393
10394void
10395x_check_errors (dpy, format)
10396 Display *dpy;
10397 char *format;
10398{
10399 /* Make sure to catch any errors incurred so far. */
10400 XSync (dpy, False);
10401
10402 if (XSTRING (x_error_message_string)->data[0])
10403 error (format, XSTRING (x_error_message_string)->data);
10404}
10405
9829ddba
RS
10406/* Nonzero if we had any X protocol errors
10407 since we did x_catch_errors on DPY. */
e99db5a1
RS
10408
10409int
10410x_had_errors_p (dpy)
10411 Display *dpy;
10412{
10413 /* Make sure to catch any errors incurred so far. */
10414 XSync (dpy, False);
10415
10416 return XSTRING (x_error_message_string)->data[0] != 0;
10417}
10418
9829ddba
RS
10419/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
10420
06a2c219 10421void
9829ddba
RS
10422x_clear_errors (dpy)
10423 Display *dpy;
10424{
10425 XSTRING (x_error_message_string)->data[0] = 0;
10426}
10427
e99db5a1
RS
10428/* Stop catching X protocol errors and let them make Emacs die.
10429 DPY should be the display that was passed to x_catch_errors.
10430 COUNT should be the value that was returned by
10431 the corresponding call to x_catch_errors. */
10432
10433void
10434x_uncatch_errors (dpy, count)
10435 Display *dpy;
10436 int count;
10437{
10438 unbind_to (count, Qnil);
10439}
10440
10441#if 0
10442static unsigned int x_wire_count;
10443x_trace_wire ()
10444{
10445 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
10446}
10447#endif /* ! 0 */
10448
10449\f
10450/* Handle SIGPIPE, which can happen when the connection to a server
10451 simply goes away. SIGPIPE is handled by x_connection_signal.
10452 Don't need to do anything, because the write which caused the
10453 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 10454 which will do the appropriate cleanup for us. */
e99db5a1
RS
10455
10456static SIGTYPE
10457x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 10458 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
10459{
10460#ifdef USG
10461 /* USG systems forget handlers when they are used;
10462 must reestablish each time */
10463 signal (signalnum, x_connection_signal);
10464#endif /* USG */
10465}
10466\f
4746118a
JB
10467/* Handling X errors. */
10468
7a13e894 10469/* Handle the loss of connection to display DISPLAY. */
16bd92ea 10470
4746118a 10471static SIGTYPE
7a13e894
RS
10472x_connection_closed (display, error_message)
10473 Display *display;
10474 char *error_message;
4746118a 10475{
7a13e894
RS
10476 struct x_display_info *dpyinfo = x_display_info_for_display (display);
10477 Lisp_Object frame, tail;
10478
6186a4a0
RS
10479 /* Indicate that this display is dead. */
10480
f613a4c8 10481#ifdef USE_X_TOOLKIT
adabc3a9 10482 XtCloseDisplay (display);
f613a4c8 10483#endif
adabc3a9 10484
6186a4a0
RS
10485 dpyinfo->display = 0;
10486
06a2c219 10487 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
10488 that are on the dead display. */
10489 FOR_EACH_FRAME (tail, frame)
10490 {
10491 Lisp_Object minibuf_frame;
10492 minibuf_frame
10493 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
10494 if (FRAME_X_P (XFRAME (frame))
10495 && FRAME_X_P (XFRAME (minibuf_frame))
10496 && ! EQ (frame, minibuf_frame)
10497 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
10498 Fdelete_frame (frame, Qt);
10499 }
10500
10501 /* Now delete all remaining frames on the dead display.
06a2c219 10502 We are now sure none of these is used as the mini-buffer
7a13e894
RS
10503 for another frame that we need to delete. */
10504 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
10505 if (FRAME_X_P (XFRAME (frame))
10506 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
10507 {
10508 /* Set this to t so that Fdelete_frame won't get confused
10509 trying to find a replacement. */
10510 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
10511 Fdelete_frame (frame, Qt);
10512 }
7a13e894 10513
482a1bd2
KH
10514 if (dpyinfo)
10515 x_delete_display (dpyinfo);
7a13e894
RS
10516
10517 if (x_display_list == 0)
10518 {
f8d07b62 10519 fprintf (stderr, "%s\n", error_message);
7a13e894
RS
10520 shut_down_emacs (0, 0, Qnil);
10521 exit (70);
10522 }
12ba150f 10523
7a13e894
RS
10524 /* Ordinary stack unwind doesn't deal with these. */
10525#ifdef SIGIO
10526 sigunblock (sigmask (SIGIO));
10527#endif
10528 sigunblock (sigmask (SIGALRM));
10529 TOTALLY_UNBLOCK_INPUT;
10530
aa4d9a9e 10531 clear_waiting_for_input ();
7a13e894 10532 error ("%s", error_message);
4746118a
JB
10533}
10534
7a13e894
RS
10535/* This is the usual handler for X protocol errors.
10536 It kills all frames on the display that we got the error for.
10537 If that was the only one, it prints an error message and kills Emacs. */
10538
06a2c219 10539static void
c118dd06
JB
10540x_error_quitter (display, error)
10541 Display *display;
10542 XErrorEvent *error;
10543{
7a13e894 10544 char buf[256], buf1[356];
dc6f92b8 10545
58769bee 10546 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 10547 original error handler. */
dc6f92b8 10548
c118dd06 10549 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 10550 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 10551 buf, error->request_code);
7a13e894 10552 x_connection_closed (display, buf1);
dc6f92b8
JB
10553}
10554
e99db5a1
RS
10555/* This is the first-level handler for X protocol errors.
10556 It calls x_error_quitter or x_error_catcher. */
7a13e894 10557
8922af5f 10558static int
e99db5a1 10559x_error_handler (display, error)
8922af5f 10560 Display *display;
e99db5a1 10561 XErrorEvent *error;
8922af5f 10562{
e99db5a1
RS
10563 if (! NILP (x_error_message_string))
10564 x_error_catcher (display, error);
10565 else
10566 x_error_quitter (display, error);
06a2c219 10567 return 0;
f9e24cb9 10568}
c118dd06 10569
e99db5a1
RS
10570/* This is the handler for X IO errors, always.
10571 It kills all frames on the display that we lost touch with.
10572 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 10573
c118dd06 10574static int
e99db5a1 10575x_io_error_quitter (display)
c118dd06 10576 Display *display;
c118dd06 10577{
e99db5a1 10578 char buf[256];
dc6f92b8 10579
e99db5a1
RS
10580 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
10581 x_connection_closed (display, buf);
06a2c219 10582 return 0;
dc6f92b8 10583}
dc6f92b8 10584\f
f451eb13
JB
10585/* Changing the font of the frame. */
10586
76bcdf39
RS
10587/* Give frame F the font named FONTNAME as its default font, and
10588 return the full name of that font. FONTNAME may be a wildcard
10589 pattern; in that case, we choose some font that fits the pattern.
10590 The return value shows which font we chose. */
10591
b5cf7a0e 10592Lisp_Object
f676886a
JB
10593x_new_font (f, fontname)
10594 struct frame *f;
dc6f92b8
JB
10595 register char *fontname;
10596{
dc43ef94
KH
10597 struct font_info *fontp
10598 = fs_load_font (f, FRAME_X_FONT_TABLE (f), CHARSET_ASCII, fontname, -1);
dc6f92b8 10599
dc43ef94
KH
10600 if (!fontp)
10601 return Qnil;
2224a5fc 10602
dc43ef94
KH
10603 f->output_data.x->font = (XFontStruct *) (fontp->font);
10604 f->output_data.x->font_baseline
10605 = (f->output_data.x->font->ascent + fontp->baseline_offset);
10606 f->output_data.x->fontset = -1;
10607
b2cad826
KH
10608 /* Compute the scroll bar width in character columns. */
10609 if (f->scroll_bar_pixel_width > 0)
10610 {
7556890b 10611 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
10612 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
10613 }
10614 else
4e61bddf
RS
10615 {
10616 int wid = FONT_WIDTH (f->output_data.x->font);
10617 f->scroll_bar_cols = (14 + wid - 1) / wid;
10618 }
b2cad826 10619
f676886a 10620 /* Now make the frame display the given font. */
c118dd06 10621 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 10622 {
7556890b
RS
10623 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
10624 f->output_data.x->font->fid);
10625 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
10626 f->output_data.x->font->fid);
10627 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
10628 f->output_data.x->font->fid);
f676886a 10629
a27f9f86 10630 frame_update_line_height (f);
0134a210 10631 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 10632 }
a27f9f86
RS
10633 else
10634 /* If we are setting a new frame's font for the first time,
10635 there are no faces yet, so this font's height is the line height. */
7556890b 10636 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 10637
dc43ef94
KH
10638 return build_string (fontp->full_name);
10639}
10640
10641/* Give frame F the fontset named FONTSETNAME as its default font, and
10642 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
10643 pattern; in that case, we choose some fontset that fits the pattern.
10644 The return value shows which fontset we chose. */
b5cf7a0e 10645
dc43ef94
KH
10646Lisp_Object
10647x_new_fontset (f, fontsetname)
10648 struct frame *f;
10649 char *fontsetname;
10650{
10651 int fontset = fs_query_fontset (f, fontsetname);
10652 struct fontset_info *fontsetp;
10653 Lisp_Object result;
b5cf7a0e 10654
dc43ef94
KH
10655 if (fontset < 0)
10656 return Qnil;
b5cf7a0e 10657
2da424f1
KH
10658 if (f->output_data.x->fontset == fontset)
10659 /* This fontset is already set in frame F. There's nothing more
10660 to do. */
10661 return build_string (fontsetname);
10662
dc43ef94
KH
10663 fontsetp = FRAME_FONTSET_DATA (f)->fontset_table[fontset];
10664
10665 if (!fontsetp->fontname[CHARSET_ASCII])
10666 /* This fontset doesn't contain ASCII font. */
10667 return Qnil;
10668
10669 result = x_new_font (f, fontsetp->fontname[CHARSET_ASCII]);
10670
10671 if (!STRINGP (result))
10672 /* Can't load ASCII font. */
10673 return Qnil;
10674
10675 /* Since x_new_font doesn't update any fontset information, do it now. */
10676 f->output_data.x->fontset = fontset;
2da424f1 10677 FS_LOAD_FONT (f, FRAME_X_FONT_TABLE (f),
715a159b 10678 CHARSET_ASCII, fontsetp->fontname[CHARSET_ASCII], fontset);
dc43ef94
KH
10679
10680 return build_string (fontsetname);
dc6f92b8 10681}
dc6f92b8 10682\f
2e365682
RS
10683/* Calculate the absolute position in frame F
10684 from its current recorded position values and gravity. */
10685
dfcf069d 10686void
43bca5d5 10687x_calc_absolute_position (f)
f676886a 10688 struct frame *f;
dc6f92b8 10689{
06a2c219 10690 Window child;
6dba1858 10691 int win_x = 0, win_y = 0;
7556890b 10692 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
10693 int this_window;
10694
9829ddba
RS
10695 /* We have nothing to do if the current position
10696 is already for the top-left corner. */
10697 if (! ((flags & XNegative) || (flags & YNegative)))
10698 return;
10699
c81412a0 10700#ifdef USE_X_TOOLKIT
7556890b 10701 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
10702#else
10703 this_window = FRAME_X_WINDOW (f);
10704#endif
6dba1858
RS
10705
10706 /* Find the position of the outside upper-left corner of
9829ddba
RS
10707 the inner window, with respect to the outer window.
10708 But do this only if we will need the results. */
7556890b 10709 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 10710 {
9829ddba
RS
10711 int count;
10712
6dba1858 10713 BLOCK_INPUT;
9829ddba
RS
10714 count = x_catch_errors (FRAME_X_DISPLAY (f));
10715 while (1)
10716 {
10717 x_clear_errors (FRAME_X_DISPLAY (f));
10718 XTranslateCoordinates (FRAME_X_DISPLAY (f),
10719
10720 /* From-window, to-window. */
10721 this_window,
10722 f->output_data.x->parent_desc,
10723
10724 /* From-position, to-position. */
10725 0, 0, &win_x, &win_y,
10726
10727 /* Child of win. */
10728 &child);
10729 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
10730 {
10731 Window newroot, newparent = 0xdeadbeef;
10732 Window *newchildren;
10733 int nchildren;
10734
10735 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
10736 &newparent, &newchildren, &nchildren))
10737 break;
58769bee 10738
7c3c78a3 10739 XFree ((char *) newchildren);
6dba1858 10740
9829ddba
RS
10741 f->output_data.x->parent_desc = newparent;
10742 }
10743 else
10744 break;
10745 }
6dba1858 10746
9829ddba 10747 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
10748 UNBLOCK_INPUT;
10749 }
10750
10751 /* Treat negative positions as relative to the leftmost bottommost
10752 position that fits on the screen. */
20f55f9a 10753 if (flags & XNegative)
7556890b 10754 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
10755 - 2 * f->output_data.x->border_width - win_x
10756 - PIXEL_WIDTH (f)
10757 + f->output_data.x->left_pos);
dc6f92b8 10758
20f55f9a 10759 if (flags & YNegative)
06a2c219
GM
10760 {
10761 int menubar_height = 0;
10762
10763#ifdef USE_X_TOOLKIT
10764 if (f->output_data.x->menubar_widget)
10765 menubar_height
10766 = (f->output_data.x->menubar_widget->core.height
10767 + f->output_data.x->menubar_widget->core.border_width);
10768#endif
10769
10770 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
10771 - 2 * f->output_data.x->border_width
10772 - win_y
10773 - PIXEL_HEIGHT (f)
10774 - menubar_height
10775 + f->output_data.x->top_pos);
10776 }
2e365682 10777
3a35ab44
RS
10778 /* The left_pos and top_pos
10779 are now relative to the top and left screen edges,
10780 so the flags should correspond. */
7556890b 10781 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
10782}
10783
3a35ab44
RS
10784/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
10785 to really change the position, and 0 when calling from
10786 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
10787 position values). It is -1 when calling from x_set_frame_parameters,
10788 which means, do adjust for borders but don't change the gravity. */
3a35ab44 10789
dfcf069d 10790void
dc05a16b 10791x_set_offset (f, xoff, yoff, change_gravity)
f676886a 10792 struct frame *f;
dc6f92b8 10793 register int xoff, yoff;
dc05a16b 10794 int change_gravity;
dc6f92b8 10795{
4a4cbdd5
KH
10796 int modified_top, modified_left;
10797
aa3ff7c9 10798 if (change_gravity > 0)
3a35ab44 10799 {
7556890b
RS
10800 f->output_data.x->top_pos = yoff;
10801 f->output_data.x->left_pos = xoff;
10802 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 10803 if (xoff < 0)
7556890b 10804 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 10805 if (yoff < 0)
7556890b
RS
10806 f->output_data.x->size_hint_flags |= YNegative;
10807 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 10808 }
43bca5d5 10809 x_calc_absolute_position (f);
dc6f92b8
JB
10810
10811 BLOCK_INPUT;
c32cdd9a 10812 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 10813
7556890b
RS
10814 modified_left = f->output_data.x->left_pos;
10815 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
10816#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
10817 this seems to be unnecessary and incorrect. rms, 4/17/97. */
10818 /* It is a mystery why we need to add the border_width here
10819 when the frame is already visible, but experiment says we do. */
aa3ff7c9 10820 if (change_gravity != 0)
4a4cbdd5 10821 {
7556890b
RS
10822 modified_left += f->output_data.x->border_width;
10823 modified_top += f->output_data.x->border_width;
4a4cbdd5 10824 }
e73ec6fa 10825#endif
4a4cbdd5 10826
3afe33e7 10827#ifdef USE_X_TOOLKIT
7556890b 10828 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 10829 modified_left, modified_top);
3afe33e7 10830#else /* not USE_X_TOOLKIT */
334208b7 10831 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 10832 modified_left, modified_top);
3afe33e7 10833#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
10834 UNBLOCK_INPUT;
10835}
10836
bc20ebbf
FP
10837/* Call this to change the size of frame F's x-window.
10838 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
10839 for this size change and subsequent size changes.
10840 Otherwise we leave the window gravity unchanged. */
dc6f92b8 10841
dfcf069d 10842void
bc20ebbf 10843x_set_window_size (f, change_gravity, cols, rows)
f676886a 10844 struct frame *f;
bc20ebbf 10845 int change_gravity;
b1c884c3 10846 int cols, rows;
dc6f92b8 10847{
06a2c219 10848#ifndef USE_X_TOOLKIT
dc6f92b8 10849 int pixelwidth, pixelheight;
06a2c219 10850#endif
dc6f92b8 10851
80fd1fe2 10852 BLOCK_INPUT;
aee9a898
RS
10853
10854#ifdef USE_X_TOOLKIT
3a20653d
RS
10855 {
10856 /* The x and y position of the widget is clobbered by the
10857 call to XtSetValues within EmacsFrameSetCharSize.
10858 This is a real kludge, but I don't understand Xt so I can't
10859 figure out a correct fix. Can anyone else tell me? -- rms. */
7556890b
RS
10860 int xpos = f->output_data.x->widget->core.x;
10861 int ypos = f->output_data.x->widget->core.y;
10862 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
10863 f->output_data.x->widget->core.x = xpos;
10864 f->output_data.x->widget->core.y = ypos;
3a20653d 10865 }
80fd1fe2
FP
10866
10867#else /* not USE_X_TOOLKIT */
10868
b1c884c3 10869 check_frame_size (f, &rows, &cols);
7556890b 10870 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
10871 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
10872 ? 0
10873 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 10874 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 10875 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 10876 f->output_data.x->flags_areas_extra
110859fc 10877 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
10878 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
10879 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 10880
7556890b 10881 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 10882 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 10883
334208b7
RS
10884 XSync (FRAME_X_DISPLAY (f), False);
10885 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10886 pixelwidth, pixelheight);
b1c884c3
JB
10887
10888 /* Now, strictly speaking, we can't be sure that this is accurate,
10889 but the window manager will get around to dealing with the size
10890 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
10891 ConfigureNotify event gets here.
10892
10893 We could just not bother storing any of this information here,
10894 and let the ConfigureNotify event set everything up, but that
fddd5ceb 10895 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 10896 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
10897 point in the future when the ConfigureNotify event arrives.
10898
10899 We pass 1 for DELAY since we can't run Lisp code inside of
10900 a BLOCK_INPUT. */
7d1e984f 10901 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
10902 PIXEL_WIDTH (f) = pixelwidth;
10903 PIXEL_HEIGHT (f) = pixelheight;
10904
aee9a898
RS
10905 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
10906 receive in the ConfigureNotify event; if we get what we asked
10907 for, then the event won't cause the screen to become garbaged, so
10908 we have to make sure to do it here. */
10909 SET_FRAME_GARBAGED (f);
10910
10911 XFlush (FRAME_X_DISPLAY (f));
10912
10913#endif /* not USE_X_TOOLKIT */
10914
4d73d038 10915 /* If cursor was outside the new size, mark it as off. */
06a2c219 10916 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 10917
aee9a898
RS
10918 /* Clear out any recollection of where the mouse highlighting was,
10919 since it might be in a place that's outside the new frame size.
10920 Actually checking whether it is outside is a pain in the neck,
10921 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 10922 cancel_mouse_face (f);
dbc4e1c1 10923
dc6f92b8
JB
10924 UNBLOCK_INPUT;
10925}
dc6f92b8 10926\f
d047c4eb 10927/* Mouse warping. */
dc6f92b8 10928
9b378208 10929void
f676886a
JB
10930x_set_mouse_position (f, x, y)
10931 struct frame *f;
dc6f92b8
JB
10932 int x, y;
10933{
10934 int pix_x, pix_y;
10935
7556890b
RS
10936 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
10937 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
10938
10939 if (pix_x < 0) pix_x = 0;
10940 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
10941
10942 if (pix_y < 0) pix_y = 0;
10943 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
10944
10945 BLOCK_INPUT;
dc6f92b8 10946
334208b7
RS
10947 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
10948 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
10949 UNBLOCK_INPUT;
10950}
10951
9b378208
RS
10952/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
10953
10954void
10955x_set_mouse_pixel_position (f, pix_x, pix_y)
10956 struct frame *f;
10957 int pix_x, pix_y;
10958{
10959 BLOCK_INPUT;
10960
334208b7
RS
10961 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
10962 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
10963 UNBLOCK_INPUT;
10964}
d047c4eb
KH
10965\f
10966/* focus shifting, raising and lowering. */
9b378208 10967
dfcf069d 10968void
f676886a
JB
10969x_focus_on_frame (f)
10970 struct frame *f;
dc6f92b8 10971{
1fb20991 10972#if 0 /* This proves to be unpleasant. */
f676886a 10973 x_raise_frame (f);
1fb20991 10974#endif
6d4238f3
JB
10975#if 0
10976 /* I don't think that the ICCCM allows programs to do things like this
10977 without the interaction of the window manager. Whatever you end up
f676886a 10978 doing with this code, do it to x_unfocus_frame too. */
334208b7 10979 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 10980 RevertToPointerRoot, CurrentTime);
c118dd06 10981#endif /* ! 0 */
dc6f92b8
JB
10982}
10983
dfcf069d 10984void
f676886a
JB
10985x_unfocus_frame (f)
10986 struct frame *f;
dc6f92b8 10987{
6d4238f3 10988#if 0
f676886a 10989 /* Look at the remarks in x_focus_on_frame. */
0f941935 10990 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 10991 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 10992 RevertToPointerRoot, CurrentTime);
c118dd06 10993#endif /* ! 0 */
dc6f92b8
JB
10994}
10995
f676886a 10996/* Raise frame F. */
dc6f92b8 10997
dfcf069d 10998void
f676886a
JB
10999x_raise_frame (f)
11000 struct frame *f;
dc6f92b8 11001{
3a88c238 11002 if (f->async_visible)
dc6f92b8
JB
11003 {
11004 BLOCK_INPUT;
3afe33e7 11005#ifdef USE_X_TOOLKIT
7556890b 11006 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11007#else /* not USE_X_TOOLKIT */
334208b7 11008 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11009#endif /* not USE_X_TOOLKIT */
334208b7 11010 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11011 UNBLOCK_INPUT;
11012 }
11013}
11014
f676886a 11015/* Lower frame F. */
dc6f92b8 11016
dfcf069d 11017void
f676886a
JB
11018x_lower_frame (f)
11019 struct frame *f;
dc6f92b8 11020{
3a88c238 11021 if (f->async_visible)
dc6f92b8
JB
11022 {
11023 BLOCK_INPUT;
3afe33e7 11024#ifdef USE_X_TOOLKIT
7556890b 11025 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11026#else /* not USE_X_TOOLKIT */
334208b7 11027 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11028#endif /* not USE_X_TOOLKIT */
334208b7 11029 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11030 UNBLOCK_INPUT;
11031 }
11032}
11033
dbc4e1c1 11034static void
6b0442dc 11035XTframe_raise_lower (f, raise_flag)
dbc4e1c1 11036 FRAME_PTR f;
6b0442dc 11037 int raise_flag;
dbc4e1c1 11038{
6b0442dc 11039 if (raise_flag)
dbc4e1c1
JB
11040 x_raise_frame (f);
11041 else
11042 x_lower_frame (f);
11043}
d047c4eb
KH
11044\f
11045/* Change of visibility. */
dc6f92b8 11046
9382638d
KH
11047/* This tries to wait until the frame is really visible.
11048 However, if the window manager asks the user where to position
11049 the frame, this will return before the user finishes doing that.
11050 The frame will not actually be visible at that time,
11051 but it will become visible later when the window manager
11052 finishes with it. */
11053
dfcf069d 11054void
f676886a
JB
11055x_make_frame_visible (f)
11056 struct frame *f;
dc6f92b8 11057{
990ba854 11058 Lisp_Object type;
1aa6072f 11059 int original_top, original_left;
dc6f92b8 11060
dc6f92b8 11061 BLOCK_INPUT;
dc6f92b8 11062
990ba854
RS
11063 type = x_icon_type (f);
11064 if (!NILP (type))
11065 x_bitmap_icon (f, type);
bdcd49ba 11066
f676886a 11067 if (! FRAME_VISIBLE_P (f))
90e65f07 11068 {
1aa6072f
RS
11069 /* We test FRAME_GARBAGED_P here to make sure we don't
11070 call x_set_offset a second time
11071 if we get to x_make_frame_visible a second time
11072 before the window gets really visible. */
11073 if (! FRAME_ICONIFIED_P (f)
11074 && ! f->output_data.x->asked_for_visible)
11075 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
11076
11077 f->output_data.x->asked_for_visible = 1;
11078
90e65f07 11079 if (! EQ (Vx_no_window_manager, Qt))
f676886a 11080 x_wm_set_window_state (f, NormalState);
3afe33e7 11081#ifdef USE_X_TOOLKIT
d7a38a2e 11082 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11083 XtMapWidget (f->output_data.x->widget);
3afe33e7 11084#else /* not USE_X_TOOLKIT */
7f9c7f94 11085 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11086#endif /* not USE_X_TOOLKIT */
0134a210
RS
11087#if 0 /* This seems to bring back scroll bars in the wrong places
11088 if the window configuration has changed. They seem
11089 to come back ok without this. */
ab648270 11090 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 11091 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 11092#endif
90e65f07 11093 }
dc6f92b8 11094
334208b7 11095 XFlush (FRAME_X_DISPLAY (f));
90e65f07 11096
0dacf791
RS
11097 /* Synchronize to ensure Emacs knows the frame is visible
11098 before we do anything else. We do this loop with input not blocked
11099 so that incoming events are handled. */
11100 {
11101 Lisp_Object frame;
c0a04927 11102 int count = input_signal_count;
28c01ffe
RS
11103 /* This must be before UNBLOCK_INPUT
11104 since events that arrive in response to the actions above
11105 will set it when they are handled. */
11106 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
11107
11108 original_left = f->output_data.x->left_pos;
11109 original_top = f->output_data.x->top_pos;
c0a04927
RS
11110
11111 /* This must come after we set COUNT. */
11112 UNBLOCK_INPUT;
11113
2745e6c4 11114 /* We unblock here so that arriving X events are processed. */
1aa6072f 11115
dcb07ae9
RS
11116 /* Now move the window back to where it was "supposed to be".
11117 But don't do it if the gravity is negative.
11118 When the gravity is negative, this uses a position
28c01ffe
RS
11119 that is 3 pixels too low. Perhaps that's really the border width.
11120
11121 Don't do this if the window has never been visible before,
11122 because the window manager may choose the position
11123 and we don't want to override it. */
1aa6072f 11124
4d3f5d9a 11125 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 11126 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 11127 && previously_visible)
1aa6072f 11128 {
2745e6c4
RS
11129 Drawable rootw;
11130 int x, y;
11131 unsigned int width, height, border, depth;
06a2c219 11132
1aa6072f 11133 BLOCK_INPUT;
9829ddba 11134
06a2c219
GM
11135 /* On some window managers (such as FVWM) moving an existing
11136 window, even to the same place, causes the window manager
11137 to introduce an offset. This can cause the window to move
11138 to an unexpected location. Check the geometry (a little
11139 slow here) and then verify that the window is in the right
11140 place. If the window is not in the right place, move it
11141 there, and take the potential window manager hit. */
2745e6c4
RS
11142 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11143 &rootw, &x, &y, &width, &height, &border, &depth);
11144
11145 if (original_left != x || original_top != y)
11146 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11147 original_left, original_top);
11148
1aa6072f
RS
11149 UNBLOCK_INPUT;
11150 }
9829ddba 11151
e0c1aef2 11152 XSETFRAME (frame, f);
c0a04927
RS
11153
11154 while (1)
2a6cf806 11155 {
334208b7 11156 x_sync (f);
c0a04927
RS
11157 /* Once we have handled input events,
11158 we should have received the MapNotify if one is coming.
11159 So if we have not got it yet, stop looping.
11160 Some window managers make their own decisions
11161 about visibility. */
11162 if (input_signal_count != count)
11163 break;
c12a7cbd 11164 /* Machines that do polling rather than SIGIO have been observed
23cf7c60
KH
11165 to go into a busy-wait here. So we'll fake an alarm signal
11166 to let the handler know that there's something to be read.
11167 We used to raise a real alarm, but it seems that the handler
11168 isn't always enabled here. This is probably a bug. */
8b2f8d4e 11169 if (input_polling_used ())
3b2fa4e6
RS
11170 {
11171 /* It could be confusing if a real alarm arrives while processing
11172 the fake one. Turn it off and let the handler reset it. */
11173 alarm (0);
5e8e68ce 11174 input_poll_signal (0);
3b2fa4e6 11175 }
c0a04927
RS
11176 /* Once we have handled input events,
11177 we should have received the MapNotify if one is coming.
11178 So if we have not got it yet, stop looping.
11179 Some window managers make their own decisions
11180 about visibility. */
11181 if (input_signal_count != count)
11182 break;
2a6cf806 11183 }
0dacf791
RS
11184 FRAME_SAMPLE_VISIBILITY (f);
11185 }
dc6f92b8
JB
11186}
11187
06a2c219 11188/* Change from mapped state to withdrawn state. */
dc6f92b8 11189
d047c4eb
KH
11190/* Make the frame visible (mapped and not iconified). */
11191
dfcf069d 11192void
f676886a
JB
11193x_make_frame_invisible (f)
11194 struct frame *f;
dc6f92b8 11195{
546e6d5b
RS
11196 Window window;
11197
11198#ifdef USE_X_TOOLKIT
11199 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 11200 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
11201#else /* not USE_X_TOOLKIT */
11202 window = FRAME_X_WINDOW (f);
11203#endif /* not USE_X_TOOLKIT */
dc6f92b8 11204
9319ae23 11205 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11206 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11207 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11208
5627c40e 11209#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 11210 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 11211 return;
5627c40e 11212#endif
dc6f92b8
JB
11213
11214 BLOCK_INPUT;
c118dd06 11215
af31d76f
RS
11216 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
11217 that the current position of the window is user-specified, rather than
11218 program-specified, so that when the window is mapped again, it will be
11219 placed at the same location, without forcing the user to position it
11220 by hand again (they have already done that once for this window.) */
c32cdd9a 11221 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 11222
c118dd06
JB
11223#ifdef HAVE_X11R4
11224
334208b7
RS
11225 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
11226 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
11227 {
11228 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11229 error ("Can't notify window manager of window withdrawal");
c118dd06 11230 }
c118dd06 11231#else /* ! defined (HAVE_X11R4) */
16bd92ea 11232
c118dd06 11233 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
11234 if (! EQ (Vx_no_window_manager, Qt))
11235 {
16bd92ea 11236 XEvent unmap;
dc6f92b8 11237
16bd92ea 11238 unmap.xunmap.type = UnmapNotify;
546e6d5b 11239 unmap.xunmap.window = window;
334208b7 11240 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 11241 unmap.xunmap.from_configure = False;
334208b7
RS
11242 if (! XSendEvent (FRAME_X_DISPLAY (f),
11243 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 11244 False,
06a2c219 11245 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
11246 &unmap))
11247 {
11248 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11249 error ("Can't notify window manager of withdrawal");
16bd92ea 11250 }
dc6f92b8
JB
11251 }
11252
16bd92ea 11253 /* Unmap the window ourselves. Cheeky! */
334208b7 11254 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 11255#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 11256
5627c40e
RS
11257 /* We can't distinguish this from iconification
11258 just by the event that we get from the server.
11259 So we can't win using the usual strategy of letting
11260 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
11261 and synchronize with the server to make sure we agree. */
11262 f->visible = 0;
11263 FRAME_ICONIFIED_P (f) = 0;
11264 f->async_visible = 0;
11265 f->async_iconified = 0;
11266
334208b7 11267 x_sync (f);
5627c40e 11268
dc6f92b8
JB
11269 UNBLOCK_INPUT;
11270}
11271
06a2c219 11272/* Change window state from mapped to iconified. */
dc6f92b8 11273
dfcf069d 11274void
f676886a
JB
11275x_iconify_frame (f)
11276 struct frame *f;
dc6f92b8 11277{
3afe33e7 11278 int result;
990ba854 11279 Lisp_Object type;
dc6f92b8 11280
9319ae23 11281 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11282 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11283 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11284
3a88c238 11285 if (f->async_iconified)
dc6f92b8
JB
11286 return;
11287
3afe33e7 11288 BLOCK_INPUT;
546e6d5b 11289
9af3143a
RS
11290 FRAME_SAMPLE_VISIBILITY (f);
11291
990ba854
RS
11292 type = x_icon_type (f);
11293 if (!NILP (type))
11294 x_bitmap_icon (f, type);
bdcd49ba
RS
11295
11296#ifdef USE_X_TOOLKIT
11297
546e6d5b
RS
11298 if (! FRAME_VISIBLE_P (f))
11299 {
11300 if (! EQ (Vx_no_window_manager, Qt))
11301 x_wm_set_window_state (f, IconicState);
11302 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11303 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
11304 /* The server won't give us any event to indicate
11305 that an invisible frame was changed to an icon,
11306 so we have to record it here. */
11307 f->iconified = 1;
1e6bc770 11308 f->visible = 1;
9cf30a30 11309 f->async_iconified = 1;
1e6bc770 11310 f->async_visible = 0;
546e6d5b
RS
11311 UNBLOCK_INPUT;
11312 return;
11313 }
11314
334208b7 11315 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 11316 XtWindow (f->output_data.x->widget),
334208b7 11317 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
11318 UNBLOCK_INPUT;
11319
11320 if (!result)
546e6d5b 11321 error ("Can't notify window manager of iconification");
3afe33e7
RS
11322
11323 f->async_iconified = 1;
1e6bc770
RS
11324 f->async_visible = 0;
11325
8c002a25
KH
11326
11327 BLOCK_INPUT;
334208b7 11328 XFlush (FRAME_X_DISPLAY (f));
8c002a25 11329 UNBLOCK_INPUT;
3afe33e7
RS
11330#else /* not USE_X_TOOLKIT */
11331
fd13dbb2
RS
11332 /* Make sure the X server knows where the window should be positioned,
11333 in case the user deiconifies with the window manager. */
11334 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 11335 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 11336
16bd92ea
JB
11337 /* Since we don't know which revision of X we're running, we'll use both
11338 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
11339
11340 /* X11R4: send a ClientMessage to the window manager using the
11341 WM_CHANGE_STATE type. */
11342 {
11343 XEvent message;
58769bee 11344
c118dd06 11345 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 11346 message.xclient.type = ClientMessage;
334208b7 11347 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
11348 message.xclient.format = 32;
11349 message.xclient.data.l[0] = IconicState;
11350
334208b7
RS
11351 if (! XSendEvent (FRAME_X_DISPLAY (f),
11352 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
11353 False,
11354 SubstructureRedirectMask | SubstructureNotifyMask,
11355 &message))
dc6f92b8
JB
11356 {
11357 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11358 error ("Can't notify window manager of iconification");
dc6f92b8 11359 }
16bd92ea 11360 }
dc6f92b8 11361
58769bee 11362 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
11363 IconicState. */
11364 x_wm_set_window_state (f, IconicState);
dc6f92b8 11365
a9c00105
RS
11366 if (!FRAME_VISIBLE_P (f))
11367 {
11368 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 11369 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
11370 }
11371
3a88c238 11372 f->async_iconified = 1;
1e6bc770 11373 f->async_visible = 0;
dc6f92b8 11374
334208b7 11375 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 11376 UNBLOCK_INPUT;
8c002a25 11377#endif /* not USE_X_TOOLKIT */
dc6f92b8 11378}
d047c4eb 11379\f
c0ff3fab 11380/* Destroy the X window of frame F. */
dc6f92b8 11381
dfcf069d 11382void
c0ff3fab 11383x_destroy_window (f)
f676886a 11384 struct frame *f;
dc6f92b8 11385{
7f9c7f94
RS
11386 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11387
dc6f92b8 11388 BLOCK_INPUT;
c0ff3fab 11389
6186a4a0
RS
11390 /* If a display connection is dead, don't try sending more
11391 commands to the X server. */
11392 if (dpyinfo->display != 0)
11393 {
11394 if (f->output_data.x->icon_desc != 0)
11395 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
31f41daf
RS
11396#ifdef HAVE_X_I18N
11397 if (FRAME_XIM (f))
11398 {
11399 XDestroyIC (FRAME_XIC (f));
408be661
RS
11400#if ! defined (SOLARIS2) || defined (HAVE_X11R6)
11401 /* This line causes crashes on Solaris with Openwin,
11402 due to an apparent bug in XCloseIM.
11403 X11R6 seems not to have the bug. */
31f41daf 11404 XCloseIM (FRAME_XIM (f));
a9978dd8 11405#endif
31f41daf
RS
11406 }
11407#endif
6186a4a0 11408 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->window_desc);
3afe33e7 11409#ifdef USE_X_TOOLKIT
06a2c219
GM
11410 if (f->output_data.x->widget)
11411 XtDestroyWidget (f->output_data.x->widget);
6186a4a0 11412 free_frame_menubar (f);
3afe33e7
RS
11413#endif /* USE_X_TOOLKIT */
11414
6186a4a0
RS
11415 free_frame_faces (f);
11416 XFlush (FRAME_X_DISPLAY (f));
11417 }
dc6f92b8 11418
df89d8a4 11419 if (f->output_data.x->saved_menu_event)
06a2c219 11420 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 11421
7556890b
RS
11422 xfree (f->output_data.x);
11423 f->output_data.x = 0;
0f941935
KH
11424 if (f == dpyinfo->x_focus_frame)
11425 dpyinfo->x_focus_frame = 0;
11426 if (f == dpyinfo->x_focus_event_frame)
11427 dpyinfo->x_focus_event_frame = 0;
11428 if (f == dpyinfo->x_highlight_frame)
11429 dpyinfo->x_highlight_frame = 0;
c0ff3fab 11430
7f9c7f94
RS
11431 dpyinfo->reference_count--;
11432
11433 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 11434 {
7f9c7f94
RS
11435 dpyinfo->mouse_face_beg_row
11436 = dpyinfo->mouse_face_beg_col = -1;
11437 dpyinfo->mouse_face_end_row
11438 = dpyinfo->mouse_face_end_col = -1;
11439 dpyinfo->mouse_face_window = Qnil;
21323706
RS
11440 dpyinfo->mouse_face_deferred_gc = 0;
11441 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 11442 }
0134a210 11443
c0ff3fab 11444 UNBLOCK_INPUT;
dc6f92b8
JB
11445}
11446\f
f451eb13
JB
11447/* Setting window manager hints. */
11448
af31d76f
RS
11449/* Set the normal size hints for the window manager, for frame F.
11450 FLAGS is the flags word to use--or 0 meaning preserve the flags
11451 that the window now has.
11452 If USER_POSITION is nonzero, we set the USPosition
11453 flag (this is useful when FLAGS is 0). */
6dba1858 11454
dfcf069d 11455void
af31d76f 11456x_wm_set_size_hint (f, flags, user_position)
f676886a 11457 struct frame *f;
af31d76f
RS
11458 long flags;
11459 int user_position;
dc6f92b8
JB
11460{
11461 XSizeHints size_hints;
3afe33e7
RS
11462
11463#ifdef USE_X_TOOLKIT
7e4f2521
FP
11464 Arg al[2];
11465 int ac = 0;
11466 Dimension widget_width, widget_height;
7556890b 11467 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 11468#else /* not USE_X_TOOLKIT */
c118dd06 11469 Window window = FRAME_X_WINDOW (f);
3afe33e7 11470#endif /* not USE_X_TOOLKIT */
dc6f92b8 11471
b72a58fd
RS
11472 /* Setting PMaxSize caused various problems. */
11473 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 11474
7556890b
RS
11475 size_hints.x = f->output_data.x->left_pos;
11476 size_hints.y = f->output_data.x->top_pos;
7553a6b7 11477
7e4f2521
FP
11478#ifdef USE_X_TOOLKIT
11479 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
11480 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 11481 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
11482 size_hints.height = widget_height;
11483 size_hints.width = widget_width;
11484#else /* not USE_X_TOOLKIT */
f676886a
JB
11485 size_hints.height = PIXEL_HEIGHT (f);
11486 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 11487#endif /* not USE_X_TOOLKIT */
7553a6b7 11488
7556890b
RS
11489 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
11490 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
11491 size_hints.max_width
11492 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
11493 size_hints.max_height
11494 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 11495
d067ea8b
KH
11496 /* Calculate the base and minimum sizes.
11497
11498 (When we use the X toolkit, we don't do it here.
11499 Instead we copy the values that the widgets are using, below.) */
11500#ifndef USE_X_TOOLKIT
b1c884c3 11501 {
b0342f17 11502 int base_width, base_height;
0134a210 11503 int min_rows = 0, min_cols = 0;
b0342f17 11504
f451eb13
JB
11505 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
11506 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 11507
0134a210 11508 check_frame_size (f, &min_rows, &min_cols);
b0342f17 11509
0134a210
RS
11510 /* The window manager uses the base width hints to calculate the
11511 current number of rows and columns in the frame while
11512 resizing; min_width and min_height aren't useful for this
11513 purpose, since they might not give the dimensions for a
11514 zero-row, zero-column frame.
58769bee 11515
0134a210
RS
11516 We use the base_width and base_height members if we have
11517 them; otherwise, we set the min_width and min_height members
11518 to the size for a zero x zero frame. */
b0342f17
JB
11519
11520#ifdef HAVE_X11R4
0134a210
RS
11521 size_hints.flags |= PBaseSize;
11522 size_hints.base_width = base_width;
11523 size_hints.base_height = base_height;
11524 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
11525 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 11526#else
0134a210
RS
11527 size_hints.min_width = base_width;
11528 size_hints.min_height = base_height;
b0342f17 11529#endif
b1c884c3 11530 }
dc6f92b8 11531
d067ea8b 11532 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 11533 if (flags)
dc6f92b8 11534 {
d067ea8b
KH
11535 size_hints.flags |= flags;
11536 goto no_read;
11537 }
11538#endif /* not USE_X_TOOLKIT */
11539
11540 {
11541 XSizeHints hints; /* Sometimes I hate X Windows... */
11542 long supplied_return;
11543 int value;
af31d76f
RS
11544
11545#ifdef HAVE_X11R4
d067ea8b
KH
11546 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
11547 &supplied_return);
af31d76f 11548#else
d067ea8b 11549 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 11550#endif
58769bee 11551
d067ea8b
KH
11552#ifdef USE_X_TOOLKIT
11553 size_hints.base_height = hints.base_height;
11554 size_hints.base_width = hints.base_width;
11555 size_hints.min_height = hints.min_height;
11556 size_hints.min_width = hints.min_width;
11557#endif
11558
11559 if (flags)
11560 size_hints.flags |= flags;
11561 else
11562 {
11563 if (value == 0)
11564 hints.flags = 0;
11565 if (hints.flags & PSize)
11566 size_hints.flags |= PSize;
11567 if (hints.flags & PPosition)
11568 size_hints.flags |= PPosition;
11569 if (hints.flags & USPosition)
11570 size_hints.flags |= USPosition;
11571 if (hints.flags & USSize)
11572 size_hints.flags |= USSize;
11573 }
11574 }
11575
06a2c219 11576#ifndef USE_X_TOOLKIT
d067ea8b 11577 no_read:
06a2c219 11578#endif
0134a210 11579
af31d76f 11580#ifdef PWinGravity
7556890b 11581 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 11582 size_hints.flags |= PWinGravity;
dc05a16b 11583
af31d76f 11584 if (user_position)
6dba1858 11585 {
af31d76f
RS
11586 size_hints.flags &= ~ PPosition;
11587 size_hints.flags |= USPosition;
6dba1858 11588 }
2554751d 11589#endif /* PWinGravity */
6dba1858 11590
b0342f17 11591#ifdef HAVE_X11R4
334208b7 11592 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 11593#else
334208b7 11594 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 11595#endif
dc6f92b8
JB
11596}
11597
11598/* Used for IconicState or NormalState */
06a2c219 11599
dfcf069d 11600void
f676886a
JB
11601x_wm_set_window_state (f, state)
11602 struct frame *f;
dc6f92b8
JB
11603 int state;
11604{
3afe33e7 11605#ifdef USE_X_TOOLKIT
546e6d5b
RS
11606 Arg al[1];
11607
11608 XtSetArg (al[0], XtNinitialState, state);
7556890b 11609 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 11610#else /* not USE_X_TOOLKIT */
c118dd06 11611 Window window = FRAME_X_WINDOW (f);
dc6f92b8 11612
7556890b
RS
11613 f->output_data.x->wm_hints.flags |= StateHint;
11614 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 11615
7556890b 11616 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 11617#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11618}
11619
dfcf069d 11620void
7f2ae036 11621x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 11622 struct frame *f;
7f2ae036 11623 int pixmap_id;
dc6f92b8 11624{
d2bd6bc4
RS
11625 Pixmap icon_pixmap;
11626
06a2c219 11627#ifndef USE_X_TOOLKIT
c118dd06 11628 Window window = FRAME_X_WINDOW (f);
75231bad 11629#endif
dc6f92b8 11630
7f2ae036 11631 if (pixmap_id > 0)
dbc4e1c1 11632 {
d2bd6bc4 11633 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 11634 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
11635 }
11636 else
68568555
RS
11637 {
11638 /* It seems there is no way to turn off use of an icon pixmap.
11639 The following line does it, only if no icon has yet been created,
11640 for some window managers. But with mwm it crashes.
11641 Some people say it should clear the IconPixmapHint bit in this case,
11642 but that doesn't work, and the X consortium said it isn't the
11643 right thing at all. Since there is no way to win,
11644 best to explicitly give up. */
11645#if 0
11646 f->output_data.x->wm_hints.icon_pixmap = None;
11647#else
11648 return;
11649#endif
11650 }
b1c884c3 11651
d2bd6bc4
RS
11652#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
11653
11654 {
11655 Arg al[1];
11656 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
11657 XtSetValues (f->output_data.x->widget, al, 1);
11658 }
11659
11660#else /* not USE_X_TOOLKIT */
11661
7556890b
RS
11662 f->output_data.x->wm_hints.flags |= IconPixmapHint;
11663 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
11664
11665#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11666}
11667
dfcf069d 11668void
f676886a
JB
11669x_wm_set_icon_position (f, icon_x, icon_y)
11670 struct frame *f;
dc6f92b8
JB
11671 int icon_x, icon_y;
11672{
75231bad 11673#ifdef USE_X_TOOLKIT
7556890b 11674 Window window = XtWindow (f->output_data.x->widget);
75231bad 11675#else
c118dd06 11676 Window window = FRAME_X_WINDOW (f);
75231bad 11677#endif
dc6f92b8 11678
7556890b
RS
11679 f->output_data.x->wm_hints.flags |= IconPositionHint;
11680 f->output_data.x->wm_hints.icon_x = icon_x;
11681 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 11682
7556890b 11683 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
11684}
11685
11686\f
06a2c219
GM
11687/***********************************************************************
11688 Fonts
11689 ***********************************************************************/
dc43ef94
KH
11690
11691/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 11692
dc43ef94
KH
11693struct font_info *
11694x_get_font_info (f, font_idx)
11695 FRAME_PTR f;
11696 int font_idx;
11697{
11698 return (FRAME_X_FONT_TABLE (f) + font_idx);
11699}
11700
11701
11702/* Return a list of names of available fonts matching PATTERN on frame
11703 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
11704 to be listed. Frame F NULL means we have not yet created any
11705 frame on X, and consult the first display in x_display_list.
11706 MAXNAMES sets a limit on how many fonts to match. */
11707
11708Lisp_Object
11709x_list_fonts (f, pattern, size, maxnames)
11710 FRAME_PTR f;
11711 Lisp_Object pattern;
11712 int size;
11713 int maxnames;
11714{
06a2c219
GM
11715 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
11716 Lisp_Object tem, second_best;
dc43ef94 11717 Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
09c6077f 11718 int try_XLoadQueryFont = 0;
53ca4657 11719 int count;
dc43ef94 11720
6b0efe73 11721 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
11722 if (NILP (patterns))
11723 patterns = Fcons (pattern, Qnil);
81ba44e5 11724
09c6077f
KH
11725 if (maxnames == 1 && !size)
11726 /* We can return any single font matching PATTERN. */
11727 try_XLoadQueryFont = 1;
9a32686f 11728
8e713be6 11729 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 11730 {
dc43ef94
KH
11731 int num_fonts;
11732 char **names;
11733
8e713be6 11734 pattern = XCAR (patterns);
536f4067
RS
11735 /* See if we cached the result for this particular query.
11736 The cache is an alist of the form:
11737 (((PATTERN . MAXNAMES) (FONTNAME . WIDTH) ...) ...)
11738 */
8e713be6 11739 if (f && (tem = XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element),
b5210ea7
KH
11740 key = Fcons (pattern, make_number (maxnames)),
11741 !NILP (list = Fassoc (key, tem))))
11742 {
11743 list = Fcdr_safe (list);
11744 /* We have a cashed list. Don't have to get the list again. */
11745 goto label_cached;
11746 }
11747
11748 /* At first, put PATTERN in the cache. */
09c6077f 11749
dc43ef94 11750 BLOCK_INPUT;
17d85edc
KH
11751 count = x_catch_errors (dpy);
11752
09c6077f
KH
11753 if (try_XLoadQueryFont)
11754 {
11755 XFontStruct *font;
11756 unsigned long value;
11757
11758 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
11759 if (x_had_errors_p (dpy))
11760 {
11761 /* This error is perhaps due to insufficient memory on X
11762 server. Let's just ignore it. */
11763 font = NULL;
11764 x_clear_errors (dpy);
11765 }
11766
09c6077f
KH
11767 if (font
11768 && XGetFontProperty (font, XA_FONT, &value))
11769 {
11770 char *name = (char *) XGetAtomName (dpy, (Atom) value);
11771 int len = strlen (name);
01c752b5 11772 char *tmp;
09c6077f 11773
6f6512e8
KH
11774 /* If DXPC (a Differential X Protocol Compressor)
11775 Ver.3.7 is running, XGetAtomName will return null
11776 string. We must avoid such a name. */
11777 if (len == 0)
11778 try_XLoadQueryFont = 0;
11779 else
11780 {
11781 num_fonts = 1;
11782 names = (char **) alloca (sizeof (char *));
11783 /* Some systems only allow alloca assigned to a
11784 simple var. */
11785 tmp = (char *) alloca (len + 1); names[0] = tmp;
11786 bcopy (name, names[0], len + 1);
11787 XFree (name);
11788 }
09c6077f
KH
11789 }
11790 else
11791 try_XLoadQueryFont = 0;
a083fd23
RS
11792
11793 if (font)
11794 XFreeFont (dpy, font);
09c6077f
KH
11795 }
11796
11797 if (!try_XLoadQueryFont)
17d85edc
KH
11798 {
11799 /* We try at least 10 fonts because XListFonts will return
11800 auto-scaled fonts at the head. */
11801 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
11802 &num_fonts);
11803 if (x_had_errors_p (dpy))
11804 {
11805 /* This error is perhaps due to insufficient memory on X
11806 server. Let's just ignore it. */
11807 names = NULL;
11808 x_clear_errors (dpy);
11809 }
11810 }
11811
11812 x_uncatch_errors (dpy, count);
dc43ef94
KH
11813 UNBLOCK_INPUT;
11814
11815 if (names)
11816 {
11817 int i;
dc43ef94
KH
11818
11819 /* Make a list of all the fonts we got back.
11820 Store that in the font cache for the display. */
11821 for (i = 0; i < num_fonts; i++)
11822 {
06a2c219 11823 int width = 0;
dc43ef94 11824 char *p = names[i];
06a2c219
GM
11825 int average_width = -1, dashes = 0;
11826
dc43ef94 11827 /* Count the number of dashes in NAMES[I]. If there are
b5210ea7
KH
11828 14 dashes, and the field value following 12th dash
11829 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
11830 is usually too ugly to be used for editing. Let's
11831 ignore it. */
dc43ef94
KH
11832 while (*p)
11833 if (*p++ == '-')
11834 {
11835 dashes++;
11836 if (dashes == 7) /* PIXEL_SIZE field */
11837 width = atoi (p);
11838 else if (dashes == 12) /* AVERAGE_WIDTH field */
11839 average_width = atoi (p);
11840 }
11841 if (dashes < 14 || average_width != 0)
11842 {
11843 tem = build_string (names[i]);
11844 if (NILP (Fassoc (tem, list)))
11845 {
11846 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
11847 && ((fast_c_string_match_ignore_case
11848 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
11849 >= 0))
11850 /* We can set the value of PIXEL_SIZE to the
b5210ea7 11851 width of this font. */
dc43ef94
KH
11852 list = Fcons (Fcons (tem, make_number (width)), list);
11853 else
11854 /* For the moment, width is not known. */
11855 list = Fcons (Fcons (tem, Qnil), list);
11856 }
11857 }
11858 }
09c6077f
KH
11859 if (!try_XLoadQueryFont)
11860 XFreeFontNames (names);
dc43ef94
KH
11861 }
11862
b5210ea7 11863 /* Now store the result in the cache. */
dc43ef94 11864 if (f != NULL)
8e713be6 11865 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element)
dc43ef94 11866 = Fcons (Fcons (key, list),
8e713be6 11867 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
dc43ef94 11868
b5210ea7
KH
11869 label_cached:
11870 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 11871
b5210ea7
KH
11872 newlist = second_best = Qnil;
11873 /* Make a list of the fonts that have the right width. */
8e713be6 11874 for (; CONSP (list); list = XCDR (list))
b5210ea7 11875 {
536f4067
RS
11876 int found_size;
11877
8e713be6 11878 tem = XCAR (list);
dc43ef94 11879
8e713be6 11880 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
11881 continue;
11882 if (!size)
11883 {
8e713be6 11884 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
11885 continue;
11886 }
dc43ef94 11887
8e713be6 11888 if (!INTEGERP (XCDR (tem)))
dc43ef94 11889 {
b5210ea7
KH
11890 /* Since we have not yet known the size of this font, we
11891 must try slow function call XLoadQueryFont. */
dc43ef94
KH
11892 XFontStruct *thisinfo;
11893
11894 BLOCK_INPUT;
17d85edc 11895 count = x_catch_errors (dpy);
dc43ef94 11896 thisinfo = XLoadQueryFont (dpy,
8e713be6 11897 XSTRING (XCAR (tem))->data);
17d85edc
KH
11898 if (x_had_errors_p (dpy))
11899 {
11900 /* This error is perhaps due to insufficient memory on X
11901 server. Let's just ignore it. */
11902 thisinfo = NULL;
11903 x_clear_errors (dpy);
11904 }
11905 x_uncatch_errors (dpy, count);
dc43ef94
KH
11906 UNBLOCK_INPUT;
11907
11908 if (thisinfo)
11909 {
8e713be6 11910 XCDR (tem)
536f4067
RS
11911 = (thisinfo->min_bounds.width == 0
11912 ? make_number (0)
11913 : make_number (thisinfo->max_bounds.width));
dc43ef94
KH
11914 XFreeFont (dpy, thisinfo);
11915 }
11916 else
b5210ea7 11917 /* For unknown reason, the previous call of XListFont had
06a2c219 11918 returned a font which can't be opened. Record the size
b5210ea7 11919 as 0 not to try to open it again. */
8e713be6 11920 XCDR (tem) = make_number (0);
dc43ef94 11921 }
536f4067 11922
8e713be6 11923 found_size = XINT (XCDR (tem));
536f4067 11924 if (found_size == size)
8e713be6 11925 newlist = Fcons (XCAR (tem), newlist);
536f4067 11926 else if (found_size > 0)
b5210ea7 11927 {
536f4067 11928 if (NILP (second_best))
b5210ea7 11929 second_best = tem;
536f4067
RS
11930 else if (found_size < size)
11931 {
8e713be6
KR
11932 if (XINT (XCDR (second_best)) > size
11933 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
11934 second_best = tem;
11935 }
11936 else
11937 {
8e713be6
KR
11938 if (XINT (XCDR (second_best)) > size
11939 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
11940 second_best = tem;
11941 }
b5210ea7
KH
11942 }
11943 }
11944 if (!NILP (newlist))
11945 break;
11946 else if (!NILP (second_best))
11947 {
8e713be6 11948 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 11949 break;
dc43ef94 11950 }
dc43ef94
KH
11951 }
11952
11953 return newlist;
11954}
11955
06a2c219
GM
11956
11957#if GLYPH_DEBUG
11958
11959/* Check that FONT is valid on frame F. It is if it can be found in F's
11960 font table. */
11961
11962static void
11963x_check_font (f, font)
11964 struct frame *f;
11965 XFontStruct *font;
11966{
11967 int i;
11968 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11969
11970 xassert (font != NULL);
11971
11972 for (i = 0; i < dpyinfo->n_fonts; i++)
11973 if (dpyinfo->font_table[i].name
11974 && font == dpyinfo->font_table[i].font)
11975 break;
11976
11977 xassert (i < dpyinfo->n_fonts);
11978}
11979
11980#endif /* GLYPH_DEBUG != 0 */
11981
11982/* Set *W to the minimum width, *H to the minimum font height of FONT.
11983 Note: There are (broken) X fonts out there with invalid XFontStruct
11984 min_bounds contents. For example, handa@etl.go.jp reports that
11985 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
11986 have font->min_bounds.width == 0. */
11987
11988static INLINE void
11989x_font_min_bounds (font, w, h)
11990 XFontStruct *font;
11991 int *w, *h;
11992{
11993 *h = FONT_HEIGHT (font);
11994 *w = font->min_bounds.width;
11995
11996 /* Try to handle the case where FONT->min_bounds has invalid
11997 contents. Since the only font known to have invalid min_bounds
11998 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
11999 if (*w <= 0)
12000 *w = font->max_bounds.width;
12001}
12002
12003
12004/* Compute the smallest character width and smallest font height over
12005 all fonts available on frame F. Set the members smallest_char_width
12006 and smallest_font_height in F's x_display_info structure to
12007 the values computed. Value is non-zero if smallest_font_height or
12008 smallest_char_width become smaller than they were before. */
12009
12010static int
12011x_compute_min_glyph_bounds (f)
12012 struct frame *f;
12013{
12014 int i;
12015 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12016 XFontStruct *font;
12017 int old_width = dpyinfo->smallest_char_width;
12018 int old_height = dpyinfo->smallest_font_height;
12019
12020 dpyinfo->smallest_font_height = 100000;
12021 dpyinfo->smallest_char_width = 100000;
12022
12023 for (i = 0; i < dpyinfo->n_fonts; ++i)
12024 if (dpyinfo->font_table[i].name)
12025 {
12026 struct font_info *fontp = dpyinfo->font_table + i;
12027 int w, h;
12028
12029 font = (XFontStruct *) fontp->font;
12030 xassert (font != (XFontStruct *) ~0);
12031 x_font_min_bounds (font, &w, &h);
12032
12033 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
12034 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
12035 }
12036
12037 xassert (dpyinfo->smallest_char_width > 0
12038 && dpyinfo->smallest_font_height > 0);
12039
12040 return (dpyinfo->n_fonts == 1
12041 || dpyinfo->smallest_char_width < old_width
12042 || dpyinfo->smallest_font_height < old_height);
12043}
12044
12045
dc43ef94
KH
12046/* Load font named FONTNAME of the size SIZE for frame F, and return a
12047 pointer to the structure font_info while allocating it dynamically.
12048 If SIZE is 0, load any size of font.
12049 If loading is failed, return NULL. */
12050
12051struct font_info *
12052x_load_font (f, fontname, size)
12053 struct frame *f;
12054 register char *fontname;
12055 int size;
12056{
12057 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12058 Lisp_Object font_names;
d645aaa4 12059 int count;
dc43ef94
KH
12060
12061 /* Get a list of all the fonts that match this name. Once we
12062 have a list of matching fonts, we compare them against the fonts
12063 we already have by comparing names. */
09c6077f 12064 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
12065
12066 if (!NILP (font_names))
12067 {
12068 Lisp_Object tail;
12069 int i;
12070
12071 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 12072 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
12073 if (dpyinfo->font_table[i].name
12074 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 12075 XSTRING (XCAR (tail))->data)
06a2c219 12076 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 12077 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
12078 return (dpyinfo->font_table + i);
12079 }
12080
12081 /* Load the font and add it to the table. */
12082 {
12083 char *full_name;
12084 XFontStruct *font;
12085 struct font_info *fontp;
12086 unsigned long value;
06a2c219 12087 int i;
dc43ef94 12088
2da424f1
KH
12089 /* If we have found fonts by x_list_font, load one of them. If
12090 not, we still try to load a font by the name given as FONTNAME
12091 because XListFonts (called in x_list_font) of some X server has
12092 a bug of not finding a font even if the font surely exists and
12093 is loadable by XLoadQueryFont. */
e1d6d5b9 12094 if (size > 0 && !NILP (font_names))
8e713be6 12095 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
12096
12097 BLOCK_INPUT;
d645aaa4 12098 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 12099 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
12100 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12101 {
12102 /* This error is perhaps due to insufficient memory on X
12103 server. Let's just ignore it. */
12104 font = NULL;
12105 x_clear_errors (FRAME_X_DISPLAY (f));
12106 }
12107 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 12108 UNBLOCK_INPUT;
b5210ea7 12109 if (!font)
dc43ef94
KH
12110 return NULL;
12111
06a2c219
GM
12112 /* Find a free slot in the font table. */
12113 for (i = 0; i < dpyinfo->n_fonts; ++i)
12114 if (dpyinfo->font_table[i].name == NULL)
12115 break;
12116
12117 /* If no free slot found, maybe enlarge the font table. */
12118 if (i == dpyinfo->n_fonts
12119 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 12120 {
06a2c219
GM
12121 int sz;
12122 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
12123 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 12124 dpyinfo->font_table
06a2c219 12125 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
12126 }
12127
06a2c219
GM
12128 fontp = dpyinfo->font_table + i;
12129 if (i == dpyinfo->n_fonts)
12130 ++dpyinfo->n_fonts;
dc43ef94
KH
12131
12132 /* Now fill in the slots of *FONTP. */
12133 BLOCK_INPUT;
12134 fontp->font = font;
06a2c219 12135 fontp->font_idx = i;
dc43ef94
KH
12136 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
12137 bcopy (fontname, fontp->name, strlen (fontname) + 1);
12138
12139 /* Try to get the full name of FONT. Put it in FULL_NAME. */
12140 full_name = 0;
12141 if (XGetFontProperty (font, XA_FONT, &value))
12142 {
12143 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
12144 char *p = name;
12145 int dashes = 0;
12146
12147 /* Count the number of dashes in the "full name".
12148 If it is too few, this isn't really the font's full name,
12149 so don't use it.
12150 In X11R4, the fonts did not come with their canonical names
12151 stored in them. */
12152 while (*p)
12153 {
12154 if (*p == '-')
12155 dashes++;
12156 p++;
12157 }
12158
12159 if (dashes >= 13)
12160 {
12161 full_name = (char *) xmalloc (p - name + 1);
12162 bcopy (name, full_name, p - name + 1);
12163 }
12164
12165 XFree (name);
12166 }
12167
12168 if (full_name != 0)
12169 fontp->full_name = full_name;
12170 else
12171 fontp->full_name = fontp->name;
12172
12173 fontp->size = font->max_bounds.width;
d5749adb
KH
12174 fontp->height = FONT_HEIGHT (font);
12175 {
12176 /* For some font, ascent and descent in max_bounds field is
12177 larger than the above value. */
12178 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
12179 if (max_height > fontp->height)
74848a96 12180 fontp->height = max_height;
d5749adb 12181 }
dc43ef94 12182
2da424f1
KH
12183 if (NILP (font_names))
12184 {
12185 /* We come here because of a bug of XListFonts mentioned at
12186 the head of this block. Let's store this information in
12187 the cache for x_list_fonts. */
12188 Lisp_Object lispy_name = build_string (fontname);
12189 Lisp_Object lispy_full_name = build_string (fontp->full_name);
12190
8e713be6 12191 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12192 = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
12193 Fcons (Fcons (lispy_full_name,
12194 make_number (fontp->size)),
12195 Qnil)),
8e713be6 12196 XCDR (dpyinfo->name_list_element));
2da424f1 12197 if (full_name)
8e713be6 12198 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12199 = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
12200 Fcons (Fcons (lispy_full_name,
12201 make_number (fontp->size)),
12202 Qnil)),
8e713be6 12203 XCDR (dpyinfo->name_list_element));
2da424f1
KH
12204 }
12205
dc43ef94
KH
12206 /* The slot `encoding' specifies how to map a character
12207 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ce667c3e 12208 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
8ff102bd
RS
12209 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
12210 0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
12211 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 12212 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
12213 which is never used by any charset. If mapping can't be
12214 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
12215 fontp->encoding[1]
12216 = (font->max_byte1 == 0
12217 /* 1-byte font */
12218 ? (font->min_char_or_byte2 < 0x80
12219 ? (font->max_char_or_byte2 < 0x80
12220 ? 0 /* 0x20..0x7F */
8ff102bd 12221 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
12222 : 1) /* 0xA0..0xFF */
12223 /* 2-byte font */
12224 : (font->min_byte1 < 0x80
12225 ? (font->max_byte1 < 0x80
12226 ? (font->min_char_or_byte2 < 0x80
12227 ? (font->max_char_or_byte2 < 0x80
12228 ? 0 /* 0x2020..0x7F7F */
8ff102bd 12229 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 12230 : 3) /* 0x20A0..0x7FFF */
8ff102bd 12231 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
12232 : (font->min_char_or_byte2 < 0x80
12233 ? (font->max_char_or_byte2 < 0x80
12234 ? 2 /* 0xA020..0xFF7F */
8ff102bd 12235 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
12236 : 1))); /* 0xA0A0..0xFFFF */
12237
12238 fontp->baseline_offset
12239 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
12240 ? (long) value : 0);
12241 fontp->relative_compose
12242 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
12243 ? (long) value : 0);
f78798df
KH
12244 fontp->default_ascent
12245 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
12246 ? (long) value : 0);
dc43ef94 12247
06a2c219
GM
12248 /* Set global flag fonts_changed_p to non-zero if the font loaded
12249 has a character with a smaller width than any other character
12250 before, or if the font loaded has a smalle>r height than any
12251 other font loaded before. If this happens, it will make a
12252 glyph matrix reallocation necessary. */
12253 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 12254 UNBLOCK_INPUT;
dc43ef94
KH
12255 return fontp;
12256 }
12257}
12258
06a2c219
GM
12259
12260/* Return a pointer to struct font_info of a font named FONTNAME for
12261 frame F. If no such font is loaded, return NULL. */
12262
dc43ef94
KH
12263struct font_info *
12264x_query_font (f, fontname)
12265 struct frame *f;
12266 register char *fontname;
12267{
12268 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12269 int i;
12270
12271 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
12272 if (dpyinfo->font_table[i].name
12273 && (!strcmp (dpyinfo->font_table[i].name, fontname)
12274 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
12275 return (dpyinfo->font_table + i);
12276 return NULL;
12277}
12278
06a2c219
GM
12279
12280/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
12281 `encoder' of the structure. */
12282
12283void
12284x_find_ccl_program (fontp)
12285 struct font_info *fontp;
12286{
a42f54e6 12287 Lisp_Object list, elt;
a6582676 12288
8e713be6 12289 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 12290 {
8e713be6 12291 elt = XCAR (list);
a6582676 12292 if (CONSP (elt)
8e713be6
KR
12293 && STRINGP (XCAR (elt))
12294 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
a6582676 12295 >= 0))
a42f54e6
KH
12296 break;
12297 }
12298 if (! NILP (list))
12299 {
d27f8ca7
KH
12300 struct ccl_program *ccl
12301 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 12302
8e713be6 12303 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
12304 xfree (ccl);
12305 else
12306 fontp->font_encoder = ccl;
a6582676
KH
12307 }
12308}
12309
06a2c219 12310
dc43ef94 12311\f
06a2c219
GM
12312/***********************************************************************
12313 Initialization
12314 ***********************************************************************/
f451eb13 12315
3afe33e7
RS
12316#ifdef USE_X_TOOLKIT
12317static XrmOptionDescRec emacs_options[] = {
12318 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
12319 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
12320
12321 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
12322 XrmoptionSepArg, NULL},
12323 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
12324
12325 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12326 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12327 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12328 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
12329 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
12330 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
12331 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
12332};
12333#endif /* USE_X_TOOLKIT */
12334
7a13e894
RS
12335static int x_initialized;
12336
29b38361
KH
12337#ifdef MULTI_KBOARD
12338/* Test whether two display-name strings agree up to the dot that separates
12339 the screen number from the server number. */
12340static int
12341same_x_server (name1, name2)
12342 char *name1, *name2;
12343{
12344 int seen_colon = 0;
cf591cc1
RS
12345 unsigned char *system_name = XSTRING (Vsystem_name)->data;
12346 int system_name_length = strlen (system_name);
12347 int length_until_period = 0;
12348
12349 while (system_name[length_until_period] != 0
12350 && system_name[length_until_period] != '.')
12351 length_until_period++;
12352
12353 /* Treat `unix' like an empty host name. */
12354 if (! strncmp (name1, "unix:", 5))
12355 name1 += 4;
12356 if (! strncmp (name2, "unix:", 5))
12357 name2 += 4;
12358 /* Treat this host's name like an empty host name. */
12359 if (! strncmp (name1, system_name, system_name_length)
12360 && name1[system_name_length] == ':')
12361 name1 += system_name_length;
12362 if (! strncmp (name2, system_name, system_name_length)
12363 && name2[system_name_length] == ':')
12364 name2 += system_name_length;
12365 /* Treat this host's domainless name like an empty host name. */
12366 if (! strncmp (name1, system_name, length_until_period)
12367 && name1[length_until_period] == ':')
12368 name1 += length_until_period;
12369 if (! strncmp (name2, system_name, length_until_period)
12370 && name2[length_until_period] == ':')
12371 name2 += length_until_period;
12372
29b38361
KH
12373 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
12374 {
12375 if (*name1 == ':')
12376 seen_colon++;
12377 if (seen_colon && *name1 == '.')
12378 return 1;
12379 }
12380 return (seen_colon
12381 && (*name1 == '.' || *name1 == '\0')
12382 && (*name2 == '.' || *name2 == '\0'));
12383}
12384#endif
12385
71f8198a
PE
12386#if defined (HAVE_X_I18N) || (defined (USE_X_TOOLKIT) && defined (HAVE_X11XTR6))
12387/* Recover from setlocale (LC_ALL, ""). */
12388static void
12389fixup_locale ()
12390{
12391 /* Currently we require strerror to use the "C" locale,
12392 since we don't yet support decoding its string result. */
12393#ifdef LC_MESSAGES
12394 setlocale (LC_MESSAGES, "C");
12395#endif
12396
12397 /* The Emacs Lisp reader needs LC_NUMERIC to be "C",
12398 so that numbers are read and printed properly for Emacs Lisp. */
12399 setlocale (LC_NUMERIC, "C");
12400
12401 /* Currently we require strftime to use the "C" locale,
12402 since we don't yet support encoding its format argument,
12403 or decoding its string result. */
12404 setlocale (LC_TIME, "C");
12405}
12406#endif
12407
334208b7 12408struct x_display_info *
1f8255f2 12409x_term_init (display_name, xrm_option, resource_name)
334208b7 12410 Lisp_Object display_name;
1f8255f2
RS
12411 char *xrm_option;
12412 char *resource_name;
dc6f92b8 12413{
334208b7 12414 int connection;
7a13e894 12415 Display *dpy;
334208b7
RS
12416 struct x_display_info *dpyinfo;
12417 XrmDatabase xrdb;
12418
60439948
KH
12419 BLOCK_INPUT;
12420
7a13e894
RS
12421 if (!x_initialized)
12422 {
12423 x_initialize ();
12424 x_initialized = 1;
12425 }
dc6f92b8 12426
6c183ba5 12427#ifdef HAVE_X_I18N
6186a4a0 12428 setlocale (LC_ALL, "");
71f8198a 12429 fixup_locale ();
6c183ba5
RS
12430#endif
12431
3afe33e7 12432#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
12433 /* weiner@footloose.sps.mot.com reports that this causes
12434 errors with X11R5:
12435 X protocol error: BadAtom (invalid Atom parameter)
12436 on protocol request 18skiloaf.
12437 So let's not use it until R6. */
12438#ifdef HAVE_X11XTR6
bdcd49ba
RS
12439 XtSetLanguageProc (NULL, NULL, NULL);
12440#endif
12441
7f9c7f94
RS
12442 {
12443 int argc = 0;
12444 char *argv[3];
12445
12446 argv[0] = "";
12447 argc = 1;
12448 if (xrm_option)
12449 {
12450 argv[argc++] = "-xrm";
12451 argv[argc++] = xrm_option;
12452 }
12453 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
12454 resource_name, EMACS_CLASS,
12455 emacs_options, XtNumber (emacs_options),
12456 &argc, argv);
39d8bb4d
KH
12457
12458#ifdef HAVE_X11XTR6
10537cb1 12459 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 12460 fixup_locale ();
39d8bb4d 12461#endif
7f9c7f94 12462 }
3afe33e7
RS
12463
12464#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
12465#ifdef HAVE_X11R5
12466 XSetLocaleModifiers ("");
12467#endif
7a13e894 12468 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 12469#endif /* not USE_X_TOOLKIT */
334208b7 12470
7a13e894
RS
12471 /* Detect failure. */
12472 if (dpy == 0)
60439948
KH
12473 {
12474 UNBLOCK_INPUT;
12475 return 0;
12476 }
7a13e894
RS
12477
12478 /* We have definitely succeeded. Record the new connection. */
12479
12480 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
12481
29b38361
KH
12482#ifdef MULTI_KBOARD
12483 {
12484 struct x_display_info *share;
12485 Lisp_Object tail;
12486
12487 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
12488 share = share->next, tail = XCDR (tail))
12489 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
12490 XSTRING (display_name)->data))
12491 break;
12492 if (share)
12493 dpyinfo->kboard = share->kboard;
12494 else
12495 {
12496 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
12497 init_kboard (dpyinfo->kboard);
59e755be
KH
12498 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
12499 {
12500 char *vendor = ServerVendor (dpy);
12501 dpyinfo->kboard->Vsystem_key_alist
12502 = call1 (Qvendor_specific_keysyms,
12503 build_string (vendor ? vendor : ""));
12504 }
12505
29b38361
KH
12506 dpyinfo->kboard->next_kboard = all_kboards;
12507 all_kboards = dpyinfo->kboard;
0ad5446c
KH
12508 /* Don't let the initial kboard remain current longer than necessary.
12509 That would cause problems if a file loaded on startup tries to
06a2c219 12510 prompt in the mini-buffer. */
0ad5446c
KH
12511 if (current_kboard == initial_kboard)
12512 current_kboard = dpyinfo->kboard;
29b38361
KH
12513 }
12514 dpyinfo->kboard->reference_count++;
12515 }
b9737ad3
KH
12516#endif
12517
7a13e894
RS
12518 /* Put this display on the chain. */
12519 dpyinfo->next = x_display_list;
12520 x_display_list = dpyinfo;
12521
12522 /* Put it on x_display_name_list as well, to keep them parallel. */
12523 x_display_name_list = Fcons (Fcons (display_name, Qnil),
12524 x_display_name_list);
8e713be6 12525 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
12526
12527 dpyinfo->display = dpy;
dc6f92b8 12528
dc6f92b8 12529#if 0
7a13e894 12530 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 12531#endif /* ! 0 */
7a13e894
RS
12532
12533 dpyinfo->x_id_name
fc932ac6
RS
12534 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
12535 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
12536 + 2);
12537 sprintf (dpyinfo->x_id_name, "%s@%s",
12538 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
12539
12540 /* Figure out which modifier bits mean what. */
334208b7 12541 x_find_modifier_meanings (dpyinfo);
f451eb13 12542
ab648270 12543 /* Get the scroll bar cursor. */
7a13e894 12544 dpyinfo->vertical_scroll_bar_cursor
334208b7 12545 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 12546
334208b7
RS
12547 xrdb = x_load_resources (dpyinfo->display, xrm_option,
12548 resource_name, EMACS_CLASS);
12549#ifdef HAVE_XRMSETDATABASE
12550 XrmSetDatabase (dpyinfo->display, xrdb);
12551#else
12552 dpyinfo->display->db = xrdb;
12553#endif
547d9db8 12554 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
12555 all versions. */
12556 dpyinfo->xrdb = xrdb;
334208b7
RS
12557
12558 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
12559 DefaultScreen (dpyinfo->display));
12560 dpyinfo->visual = select_visual (dpyinfo->display, dpyinfo->screen,
12561 &dpyinfo->n_planes);
12562 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
12563 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
12564 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
12565 dpyinfo->grabbed = 0;
12566 dpyinfo->reference_count = 0;
12567 dpyinfo->icon_bitmap_id = -1;
06a2c219 12568 dpyinfo->font_table = NULL;
7a13e894
RS
12569 dpyinfo->n_fonts = 0;
12570 dpyinfo->font_table_size = 0;
12571 dpyinfo->bitmaps = 0;
12572 dpyinfo->bitmaps_size = 0;
12573 dpyinfo->bitmaps_last = 0;
12574 dpyinfo->scratch_cursor_gc = 0;
12575 dpyinfo->mouse_face_mouse_frame = 0;
12576 dpyinfo->mouse_face_deferred_gc = 0;
12577 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12578 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 12579 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894
RS
12580 dpyinfo->mouse_face_window = Qnil;
12581 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
12582 dpyinfo->mouse_face_defer = 0;
0f941935
KH
12583 dpyinfo->x_focus_frame = 0;
12584 dpyinfo->x_focus_event_frame = 0;
12585 dpyinfo->x_highlight_frame = 0;
06a2c219 12586 dpyinfo->image_cache = make_image_cache ();
334208b7 12587
06a2c219
GM
12588 {
12589 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
12590 double pixels = DisplayHeight (dpyinfo->display, screen_number);
12591 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
12592 dpyinfo->resy = pixels * 25.4 / mm;
12593 pixels = DisplayWidth (dpyinfo->display, screen_number);
12594 mm = DisplayWidthMM (dpyinfo->display, screen_number);
12595 dpyinfo->resx = pixels * 25.4 / mm;
12596 }
12597
334208b7
RS
12598 dpyinfo->Xatom_wm_protocols
12599 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
12600 dpyinfo->Xatom_wm_take_focus
12601 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
12602 dpyinfo->Xatom_wm_save_yourself
12603 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
12604 dpyinfo->Xatom_wm_delete_window
12605 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
12606 dpyinfo->Xatom_wm_change_state
12607 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
12608 dpyinfo->Xatom_wm_configure_denied
12609 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
12610 dpyinfo->Xatom_wm_window_moved
12611 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
12612 dpyinfo->Xatom_editres
12613 = XInternAtom (dpyinfo->display, "Editres", False);
12614 dpyinfo->Xatom_CLIPBOARD
12615 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
12616 dpyinfo->Xatom_TIMESTAMP
12617 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
12618 dpyinfo->Xatom_TEXT
12619 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
12620 dpyinfo->Xatom_COMPOUND_TEXT
12621 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
12622 dpyinfo->Xatom_DELETE
12623 = XInternAtom (dpyinfo->display, "DELETE", False);
12624 dpyinfo->Xatom_MULTIPLE
12625 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
12626 dpyinfo->Xatom_INCR
12627 = XInternAtom (dpyinfo->display, "INCR", False);
12628 dpyinfo->Xatom_EMACS_TMP
12629 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
12630 dpyinfo->Xatom_TARGETS
12631 = XInternAtom (dpyinfo->display, "TARGETS", False);
12632 dpyinfo->Xatom_NULL
12633 = XInternAtom (dpyinfo->display, "NULL", False);
12634 dpyinfo->Xatom_ATOM_PAIR
12635 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
12636 /* For properties of font. */
12637 dpyinfo->Xatom_PIXEL_SIZE
12638 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
12639 dpyinfo->Xatom_MULE_BASELINE_OFFSET
12640 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
12641 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
12642 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
12643 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
12644 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 12645
06a2c219
GM
12646 /* Ghostscript support. */
12647 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
12648 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
12649
12650 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
12651 False);
12652
547d9db8
KH
12653 dpyinfo->cut_buffers_initialized = 0;
12654
334208b7
RS
12655 connection = ConnectionNumber (dpyinfo->display);
12656 dpyinfo->connection = connection;
12657
dc43ef94 12658 {
5d7cc324
RS
12659 char null_bits[1];
12660
12661 null_bits[0] = 0x00;
dc43ef94
KH
12662
12663 dpyinfo->null_pixel
12664 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
12665 null_bits, 1, 1, (long) 0, (long) 0,
12666 1);
12667 }
12668
06a2c219
GM
12669 {
12670 extern int gray_bitmap_width, gray_bitmap_height;
12671 extern unsigned char *gray_bitmap_bits;
12672 dpyinfo->gray
12673 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
12674 gray_bitmap_bits,
12675 gray_bitmap_width, gray_bitmap_height,
12676 (unsigned long) 1, (unsigned long) 0, 1);
12677 }
12678
87485d6f
MW
12679#ifdef subprocesses
12680 /* This is only needed for distinguishing keyboard and process input. */
334208b7 12681 if (connection != 0)
7a13e894 12682 add_keyboard_wait_descriptor (connection);
87485d6f 12683#endif
6d4238f3 12684
041b69ac 12685#ifndef F_SETOWN_BUG
dc6f92b8 12686#ifdef F_SETOWN
dc6f92b8 12687#ifdef F_SETOWN_SOCK_NEG
61c3ce62 12688 /* stdin is a socket here */
334208b7 12689 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 12690#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 12691 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
12692#endif /* ! defined (F_SETOWN_SOCK_NEG) */
12693#endif /* ! defined (F_SETOWN) */
041b69ac 12694#endif /* F_SETOWN_BUG */
dc6f92b8
JB
12695
12696#ifdef SIGIO
eee20f6a
KH
12697 if (interrupt_input)
12698 init_sigio (connection);
c118dd06 12699#endif /* ! defined (SIGIO) */
dc6f92b8 12700
51b592fb 12701#ifdef USE_LUCID
f8c39f51 12702#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
12703 /* Make sure that we have a valid font for dialog boxes
12704 so that Xt does not crash. */
12705 {
12706 Display *dpy = dpyinfo->display;
12707 XrmValue d, fr, to;
12708 Font font;
e99db5a1 12709 int count;
51b592fb
RS
12710
12711 d.addr = (XPointer)&dpy;
12712 d.size = sizeof (Display *);
12713 fr.addr = XtDefaultFont;
12714 fr.size = sizeof (XtDefaultFont);
12715 to.size = sizeof (Font *);
12716 to.addr = (XPointer)&font;
e99db5a1 12717 count = x_catch_errors (dpy);
51b592fb
RS
12718 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
12719 abort ();
12720 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
12721 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 12722 x_uncatch_errors (dpy, count);
51b592fb
RS
12723 }
12724#endif
f8c39f51 12725#endif
51b592fb 12726
60439948
KH
12727 UNBLOCK_INPUT;
12728
7a13e894
RS
12729 return dpyinfo;
12730}
12731\f
12732/* Get rid of display DPYINFO, assuming all frames are already gone,
12733 and without sending any more commands to the X server. */
dc6f92b8 12734
7a13e894
RS
12735void
12736x_delete_display (dpyinfo)
12737 struct x_display_info *dpyinfo;
12738{
12739 delete_keyboard_wait_descriptor (dpyinfo->connection);
12740
12741 /* Discard this display from x_display_name_list and x_display_list.
12742 We can't use Fdelq because that can quit. */
12743 if (! NILP (x_display_name_list)
8e713be6
KR
12744 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
12745 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
12746 else
12747 {
12748 Lisp_Object tail;
12749
12750 tail = x_display_name_list;
8e713be6 12751 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 12752 {
8e713be6 12753 if (EQ (XCAR (XCDR (tail)),
7a13e894
RS
12754 dpyinfo->name_list_element))
12755 {
8e713be6 12756 XCDR (tail) = XCDR (XCDR (tail));
7a13e894
RS
12757 break;
12758 }
8e713be6 12759 tail = XCDR (tail);
7a13e894
RS
12760 }
12761 }
12762
12763 if (x_display_list == dpyinfo)
12764 x_display_list = dpyinfo->next;
7f9c7f94
RS
12765 else
12766 {
12767 struct x_display_info *tail;
7a13e894 12768
7f9c7f94
RS
12769 for (tail = x_display_list; tail; tail = tail->next)
12770 if (tail->next == dpyinfo)
12771 tail->next = tail->next->next;
12772 }
7a13e894 12773
0d777288
RS
12774#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
12775#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
12776 XrmDestroyDatabase (dpyinfo->xrdb);
12777#endif
0d777288 12778#endif
29b38361
KH
12779#ifdef MULTI_KBOARD
12780 if (--dpyinfo->kboard->reference_count == 0)
39f79001 12781 delete_kboard (dpyinfo->kboard);
b9737ad3
KH
12782#endif
12783 xfree (dpyinfo->font_table);
12784 xfree (dpyinfo->x_id_name);
12785 xfree (dpyinfo);
7a13e894
RS
12786}
12787\f
12788/* Set up use of X before we make the first connection. */
12789
06a2c219
GM
12790static struct redisplay_interface x_redisplay_interface =
12791{
12792 x_produce_glyphs,
12793 x_write_glyphs,
12794 x_insert_glyphs,
12795 x_clear_end_of_line,
12796 x_scroll_run,
12797 x_after_update_window_line,
12798 x_update_window_begin,
12799 x_update_window_end,
12800 XTcursor_to,
12801 x_flush,
66ac4b0e
GM
12802 x_get_glyph_overhangs,
12803 x_fix_overlapping_area
06a2c219
GM
12804};
12805
dfcf069d 12806void
7a13e894
RS
12807x_initialize ()
12808{
06a2c219
GM
12809 rif = &x_redisplay_interface;
12810
12811 clear_frame_hook = x_clear_frame;
12812 ins_del_lines_hook = x_ins_del_lines;
12813 change_line_highlight_hook = x_change_line_highlight;
12814 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
12815 ring_bell_hook = XTring_bell;
12816 reset_terminal_modes_hook = XTreset_terminal_modes;
12817 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
12818 update_begin_hook = x_update_begin;
12819 update_end_hook = x_update_end;
dc6f92b8
JB
12820 set_terminal_window_hook = XTset_terminal_window;
12821 read_socket_hook = XTread_socket;
b8009dd1 12822 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 12823 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 12824 mouse_position_hook = XTmouse_position;
f451eb13 12825 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 12826 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
12827 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
12828 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
12829 redeem_scroll_bar_hook = XTredeem_scroll_bar;
12830 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 12831 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 12832
f676886a 12833 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
12834 char_ins_del_ok = 0; /* just as fast to write the line */
12835 line_ins_del_ok = 1; /* we'll just blt 'em */
12836 fast_clear_end_of_line = 1; /* X does this well */
58769bee 12837 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
12838 off the bottom */
12839 baud_rate = 19200;
12840
7a13e894 12841 x_noop_count = 0;
9ea173e8 12842 last_tool_bar_item = -1;
06a2c219
GM
12843 any_help_event_p = 0;
12844
b30b24cb
RS
12845 /* Try to use interrupt input; if we can't, then start polling. */
12846 Fset_input_mode (Qt, Qnil, Qt, Qnil);
12847
7f9c7f94
RS
12848#ifdef USE_X_TOOLKIT
12849 XtToolkitInitialize ();
12850 Xt_app_con = XtCreateApplicationContext ();
665881ad 12851 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
7f9c7f94
RS
12852#endif
12853
58769bee 12854 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 12855 original error handler. */
e99db5a1 12856 XSetErrorHandler (x_error_handler);
334208b7 12857 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 12858
06a2c219 12859 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
12860#ifdef SIGWINCH
12861 signal (SIGWINCH, SIG_DFL);
c118dd06 12862#endif /* ! defined (SIGWINCH) */
dc6f92b8 12863
92e2441b 12864 signal (SIGPIPE, x_connection_signal);
dc6f92b8 12865}
55123275 12866
06a2c219 12867
55123275
JB
12868void
12869syms_of_xterm ()
12870{
e99db5a1
RS
12871 staticpro (&x_error_message_string);
12872 x_error_message_string = Qnil;
12873
7a13e894
RS
12874 staticpro (&x_display_name_list);
12875 x_display_name_list = Qnil;
334208b7 12876
ab648270 12877 staticpro (&last_mouse_scroll_bar);
e53cb100 12878 last_mouse_scroll_bar = Qnil;
59e755be
KH
12879
12880 staticpro (&Qvendor_specific_keysyms);
12881 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
12882
12883 staticpro (&last_mouse_press_frame);
12884 last_mouse_press_frame = Qnil;
06a2c219
GM
12885
12886 staticpro (&help_echo);
12887 help_echo = Qnil;
12888 staticpro (&previous_help_echo);
12889 previous_help_echo = Qnil;
12890
12891 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
12892 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
12893For example, if a block cursor is over a tab, it will be drawn as\n\
12894wide as that tab on the display.");
12895 x_stretch_cursor_p = 0;
12896
12897 DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
12898 "If not nil, Emacs uses toolkit scroll bars.");
12899#if USE_TOOLKIT_SCROLL_BARS
12900 x_toolkit_scroll_bars_p = 1;
12901#else
12902 x_toolkit_scroll_bars_p = 0;
12903#endif
12904
12905 defsubr (&Sxt_process_timeouts);
12906 staticpro (&last_mouse_motion_frame);
12907 last_mouse_motion_frame = Qnil;
55123275 12908}
6cf0ae86
RS
12909
12910#endif /* not HAVE_X_WINDOWS */
06a2c219 12911