(other-frame): Call x-focus-frame only if
[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
68c45bf0
PE
25#include <config.h>
26
039440c4 27/* On 4.3 these lose if they come after xterm.h. */
039440c4 28/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
29#include <signal.h>
30
4846819e
RS
31#include <stdio.h>
32
dc6f92b8
JB
33#ifdef HAVE_X_WINDOWS
34
35#include "lisp.h"
9ac0d9e0 36#include "blockinput.h"
dc6f92b8 37
ae79c227
AS
38/* Need syssignal.h for various externs and definitions that may be required
39 by some configurations for calls to signal later in this source file. */
40#include "syssignal.h"
41
dc6f92b8
JB
42/* This may include sys/types.h, and that somehow loses
43 if this is not done before the other system files. */
44#include "xterm.h"
f451eb13 45#include <X11/cursorfont.h>
dc6f92b8 46
16bd92ea 47#ifndef USG
dc6f92b8
JB
48/* Load sys/types.h if not already loaded.
49 In some systems loading it twice is suicidal. */
50#ifndef makedev
51#include <sys/types.h>
c118dd06
JB
52#endif /* makedev */
53#endif /* USG */
dc6f92b8 54
6df54671 55#ifdef BSD_SYSTEM
dc6f92b8 56#include <sys/ioctl.h>
6df54671 57#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 58
2d368234 59#include "systty.h"
3a2712f9 60#include "systime.h"
dc6f92b8 61
b8009dd1 62#ifndef INCLUDED_FCNTL
dc6f92b8 63#include <fcntl.h>
b8009dd1 64#endif
dc6f92b8
JB
65#include <ctype.h>
66#include <errno.h>
67#include <setjmp.h>
68#include <sys/stat.h>
a0a7635f
RS
69/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
70/* #include <sys/param.h> */
dc6f92b8 71
dc43ef94
KH
72#include "charset.h"
73#include "ccl.h"
7a13e894 74#include "frame.h"
a1dfb88a 75#include "fontset.h"
dc6f92b8
JB
76#include "dispextern.h"
77#include "termhooks.h"
78#include "termopts.h"
79#include "termchar.h"
80#if 0
81#include "sink.h"
82#include "sinkmask.h"
c118dd06 83#endif /* ! 0 */
dc6f92b8 84#include "gnu.h"
dc6f92b8 85#include "disptab.h"
dc6f92b8 86#include "buffer.h"
f451eb13 87#include "window.h"
3b2fa4e6 88#include "keyboard.h"
bde7c500 89#include "intervals.h"
dfcf069d 90#include "process.h"
bffcfca9 91#include "atimer.h"
dc6f92b8 92
d2bd6bc4
RS
93#ifdef USE_X_TOOLKIT
94#include <X11/Shell.h>
95#endif
96
06a2c219
GM
97#include <sys/types.h>
98#ifdef HAVE_SYS_TIME_H
99#include <sys/time.h>
100#endif
101#ifdef HAVE_UNISTD_H
102#include <unistd.h>
103#endif
104
3afe33e7 105#ifdef USE_X_TOOLKIT
06a2c219 106
9d7e2e3e 107extern void free_frame_menubar ();
2224b905 108extern FRAME_PTR x_menubar_window_to_frame ();
06a2c219 109
0fdff6bb
RS
110#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
111#define HACK_EDITRES
112extern void _XEditResCheckMessages ();
113#endif /* not NO_EDITRES */
06a2c219
GM
114
115/* Include toolkit specific headers for the scroll bar widget. */
116
117#ifdef USE_TOOLKIT_SCROLL_BARS
118#if defined USE_MOTIF
119#include <Xm/Xm.h> /* for LESSTIF_VERSION */
120#include <Xm/ScrollBar.h>
121#include <Xm/ScrollBarP.h>
ec18280f
SM
122#else /* !USE_MOTIF i.e. use Xaw */
123
124#ifdef HAVE_XAW3D
06a2c219 125#include <X11/Xaw3d/Simple.h>
06a2c219
GM
126#include <X11/Xaw3d/Scrollbar.h>
127#define ARROW_SCROLLBAR
128#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
129#else /* !HAVE_XAW3D */
130#include <X11/Xaw/Simple.h>
131#include <X11/Xaw/Scrollbar.h>
132#endif /* !HAVE_XAW3D */
133#ifndef XtNpickTop
134#define XtNpickTop "pickTop"
135#endif /* !XtNpickTop */
136#endif /* !USE_MOTIF */
06a2c219
GM
137#endif /* USE_TOOLKIT_SCROLL_BARS */
138
3afe33e7
RS
139#endif /* USE_X_TOOLKIT */
140
b849c413
RS
141#ifndef USE_X_TOOLKIT
142#define x_any_window_to_frame x_window_to_frame
5627c40e 143#define x_top_window_to_frame x_window_to_frame
b849c413
RS
144#endif
145
546e6d5b 146#ifdef USE_X_TOOLKIT
d067ea8b 147#include "widget.h"
546e6d5b
RS
148#ifndef XtNinitialState
149#define XtNinitialState "initialState"
150#endif
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
bffcfca9
GM
302/* Non-zero means user is interacting with a toolkit scroll bar. */
303
304static int toolkit_scroll_bar_interaction;
dc6f92b8 305
69388238
RS
306/* Mouse movement.
307
06a2c219 308 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
309 so that we would have to call XQueryPointer after each MotionNotify
310 event to ask for another such event. However, this made mouse tracking
311 slow, and there was a bug that made it eventually stop.
312
313 Simply asking for MotionNotify all the time seems to work better.
314
69388238
RS
315 In order to avoid asking for motion events and then throwing most
316 of them away or busy-polling the server for mouse positions, we ask
317 the server for pointer motion hints. This means that we get only
318 one event per group of mouse movements. "Groups" are delimited by
319 other kinds of events (focus changes and button clicks, for
320 example), or by XQueryPointer calls; when one of these happens, we
321 get another MotionNotify event the next time the mouse moves. This
322 is at least as efficient as getting motion events when mouse
323 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 324 is off. */
69388238
RS
325
326/* Where the mouse was last time we reported a mouse event. */
69388238 327
06a2c219
GM
328FRAME_PTR last_mouse_frame;
329static XRectangle last_mouse_glyph;
2237cac9
RS
330static Lisp_Object last_mouse_press_frame;
331
69388238
RS
332/* The scroll bar in which the last X motion event occurred.
333
06a2c219
GM
334 If the last X motion event occurred in a scroll bar, we set this so
335 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
336 an ordinary motion.
337
06a2c219
GM
338 If the last X motion event didn't occur in a scroll bar, we set
339 this to Qnil, to tell XTmouse_position to return an ordinary motion
340 event. */
341
69388238
RS
342static Lisp_Object last_mouse_scroll_bar;
343
69388238
RS
344/* This is a hack. We would really prefer that XTmouse_position would
345 return the time associated with the position it returns, but there
06a2c219 346 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
347 along with the position query. So, we just keep track of the time
348 of the last movement we received, and return that in hopes that
349 it's somewhat accurate. */
06a2c219 350
69388238
RS
351static Time last_mouse_movement_time;
352
06a2c219
GM
353/* Incremented by XTread_socket whenever it really tries to read
354 events. */
355
c0a04927
RS
356#ifdef __STDC__
357static int volatile input_signal_count;
358#else
359static int input_signal_count;
360#endif
361
7a13e894 362/* Used locally within XTread_socket. */
06a2c219 363
7a13e894 364static int x_noop_count;
dc6f92b8 365
7a13e894 366/* Initial values of argv and argc. */
06a2c219 367
7a13e894
RS
368extern char **initial_argv;
369extern int initial_argc;
dc6f92b8 370
7a13e894 371extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 372
06a2c219 373/* Tells if a window manager is present or not. */
7a13e894
RS
374
375extern Lisp_Object Vx_no_window_manager;
dc6f92b8 376
c2df547c 377extern Lisp_Object Qface, Qmouse_face;
b8009dd1 378
dc6f92b8
JB
379extern int errno;
380
dfeccd2d 381/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 382
64bb1782
RS
383extern int extra_keyboard_modifiers;
384
59e755be
KH
385static Lisp_Object Qvendor_specific_keysyms;
386
334208b7 387extern XrmDatabase x_load_resources ();
c32cdd9a
KH
388extern Lisp_Object x_icon_type ();
389
7a13e894 390
06a2c219
GM
391/* Enumeration for overriding/changing the face to use for drawing
392 glyphs in x_draw_glyphs. */
393
394enum draw_glyphs_face
395{
396 DRAW_NORMAL_TEXT,
397 DRAW_INVERSE_VIDEO,
398 DRAW_CURSOR,
399 DRAW_MOUSE_FACE,
400 DRAW_IMAGE_RAISED,
401 DRAW_IMAGE_SUNKEN
402};
403
404static void x_update_window_end P_ ((struct window *, int));
405static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
406void x_delete_display P_ ((struct x_display_info *));
407static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
408 unsigned));
409static int fast_find_position P_ ((struct window *, int, int *, int *,
410 int *, int *));
411static void set_output_cursor P_ ((struct cursor_pos *));
412static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
413 int *, int *, int *));
414static void note_mode_line_highlight P_ ((struct window *, int, int));
415static void x_check_font P_ ((struct frame *, XFontStruct *));
416static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
417static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
418static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
419static void show_mouse_face P_ ((struct x_display_info *,
420 enum draw_glyphs_face));
421static int x_io_error_quitter P_ ((Display *));
422int x_catch_errors P_ ((Display *));
423void x_uncatch_errors P_ ((Display *, int));
424void x_lower_frame P_ ((struct frame *));
425void x_scroll_bar_clear P_ ((struct frame *));
426int x_had_errors_p P_ ((Display *));
427void x_wm_set_size_hint P_ ((struct frame *, long, int));
428void x_raise_frame P_ ((struct frame *));
429void x_set_window_size P_ ((struct frame *, int, int, int));
430void x_wm_set_window_state P_ ((struct frame *, int));
431void x_wm_set_icon_pixmap P_ ((struct frame *, int));
432void x_initialize P_ ((void));
433static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
434static int x_compute_min_glyph_bounds P_ ((struct frame *));
435static void x_draw_phys_cursor_glyph P_ ((struct window *,
436 struct glyph_row *,
437 enum draw_glyphs_face));
438static void x_update_end P_ ((struct frame *));
439static void XTframe_up_to_date P_ ((struct frame *));
440static void XTreassert_line_highlight P_ ((int, int));
441static void x_change_line_highlight P_ ((int, int, int, int));
442static void XTset_terminal_modes P_ ((void));
443static void XTreset_terminal_modes P_ ((void));
444static void XTcursor_to P_ ((int, int, int, int));
445static void x_write_glyphs P_ ((struct glyph *, int));
446static void x_clear_end_of_line P_ ((int));
447static void x_clear_frame P_ ((void));
448static void x_clear_cursor P_ ((struct window *));
449static void frame_highlight P_ ((struct frame *));
450static void frame_unhighlight P_ ((struct frame *));
451static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
452static void XTframe_rehighlight P_ ((struct frame *));
453static void x_frame_rehighlight P_ ((struct x_display_info *));
454static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
455static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *));
456static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
457 XRectangle *));
458static void expose_frame P_ ((struct frame *, int, int, int, int));
459static void expose_window_tree P_ ((struct window *, XRectangle *));
460static void expose_window P_ ((struct window *, XRectangle *));
461static void expose_area P_ ((struct window *, struct glyph_row *,
462 XRectangle *, enum glyph_row_area));
463static void expose_line P_ ((struct window *, struct glyph_row *,
464 XRectangle *));
465static void x_update_cursor_in_window_tree P_ ((struct window *, int));
466static void x_update_window_cursor P_ ((struct window *, int));
467static void x_erase_phys_cursor P_ ((struct window *));
468void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
469static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
470 enum bitmap_type));
471
472static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
473 GC, int));
474static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
475static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
476static void note_overwritten_text_cursor P_ ((struct window *, int, int));
477static void x_flush P_ ((struct frame *f));
478
479
480/* Flush display of frame F, or of all frames if F is null. */
481
482static void
483x_flush (f)
484 struct frame *f;
485{
486 BLOCK_INPUT;
487 if (f == NULL)
488 {
489 Lisp_Object rest, frame;
490 FOR_EACH_FRAME (rest, frame)
491 x_flush (XFRAME (frame));
492 }
493 else if (FRAME_X_P (f))
494 XFlush (FRAME_X_DISPLAY (f));
495 UNBLOCK_INPUT;
496}
497
dc6f92b8 498
06a2c219
GM
499/* Remove calls to XFlush by defining XFlush to an empty replacement.
500 Calls to XFlush should be unnecessary because the X output buffer
501 is flushed automatically as needed by calls to XPending,
502 XNextEvent, or XWindowEvent according to the XFlush man page.
503 XTread_socket calls XPending. Removing XFlush improves
504 performance. */
505
506#define XFlush(DISPLAY) (void) 0
b8009dd1 507
334208b7 508\f
06a2c219
GM
509/***********************************************************************
510 Debugging
511 ***********************************************************************/
512
9382638d 513#if 0
06a2c219
GM
514
515/* This is a function useful for recording debugging information about
516 the sequence of occurrences in this file. */
9382638d
KH
517
518struct record
519{
520 char *locus;
521 int type;
522};
523
524struct record event_record[100];
525
526int event_record_index;
527
528record_event (locus, type)
529 char *locus;
530 int type;
531{
532 if (event_record_index == sizeof (event_record) / sizeof (struct record))
533 event_record_index = 0;
534
535 event_record[event_record_index].locus = locus;
536 event_record[event_record_index].type = type;
537 event_record_index++;
538}
539
540#endif /* 0 */
06a2c219
GM
541
542
9382638d 543\f
334208b7
RS
544/* Return the struct x_display_info corresponding to DPY. */
545
546struct x_display_info *
547x_display_info_for_display (dpy)
548 Display *dpy;
549{
550 struct x_display_info *dpyinfo;
551
552 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
553 if (dpyinfo->display == dpy)
554 return dpyinfo;
16bd92ea 555
334208b7
RS
556 return 0;
557}
f451eb13 558
06a2c219
GM
559
560\f
561/***********************************************************************
562 Starting and ending an update
563 ***********************************************************************/
564
565/* Start an update of frame F. This function is installed as a hook
566 for update_begin, i.e. it is called when update_begin is called.
567 This function is called prior to calls to x_update_window_begin for
568 each window being updated. Currently, there is nothing to do here
569 because all interesting stuff is done on a window basis. */
dc6f92b8 570
dfcf069d 571static void
06a2c219 572x_update_begin (f)
f676886a 573 struct frame *f;
58769bee 574{
06a2c219
GM
575 /* Nothing to do. */
576}
dc6f92b8 577
dc6f92b8 578
06a2c219
GM
579/* Start update of window W. Set the global variable updated_window
580 to the window being updated and set output_cursor to the cursor
581 position of W. */
dc6f92b8 582
06a2c219
GM
583static void
584x_update_window_begin (w)
585 struct window *w;
586{
587 struct frame *f = XFRAME (WINDOW_FRAME (w));
588 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
589
590 updated_window = w;
591 set_output_cursor (&w->cursor);
b8009dd1 592
06a2c219 593 BLOCK_INPUT;
d1bc4182 594
06a2c219 595 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 596 {
514e4681 597 /* Don't do highlighting for mouse motion during the update. */
06a2c219 598 display_info->mouse_face_defer = 1;
37c2c98b 599
06a2c219
GM
600 /* If F needs to be redrawn, simply forget about any prior mouse
601 highlighting. */
9f67f20b 602 if (FRAME_GARBAGED_P (f))
06a2c219
GM
603 display_info->mouse_face_window = Qnil;
604
605 /* Can we tell that this update does not affect the window
606 where the mouse highlight is? If so, no need to turn off.
607 Likewise, don't do anything if the frame is garbaged;
608 in that case, the frame's current matrix that we would use
609 is all wrong, and we will redisplay that line anyway. */
610 if (!NILP (display_info->mouse_face_window)
611 && w == XWINDOW (display_info->mouse_face_window))
514e4681 612 {
06a2c219 613 int i;
514e4681 614
06a2c219
GM
615 for (i = 0; i < w->desired_matrix->nrows; ++i)
616 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
617 break;
618
06a2c219
GM
619 if (i < w->desired_matrix->nrows)
620 clear_mouse_face (display_info);
514e4681 621 }
b8009dd1 622 }
6ccf47d1 623
dc6f92b8
JB
624 UNBLOCK_INPUT;
625}
626
06a2c219
GM
627
628/* Draw a vertical window border to the right of window W if W doesn't
629 have vertical scroll bars. */
630
dfcf069d 631static void
06a2c219
GM
632x_draw_vertical_border (w)
633 struct window *w;
58769bee 634{
06a2c219
GM
635 struct frame *f = XFRAME (WINDOW_FRAME (w));
636
637 /* Redraw borders between horizontally adjacent windows. Don't
638 do it for frames with vertical scroll bars because either the
639 right scroll bar of a window, or the left scroll bar of its
640 neighbor will suffice as a border. */
641 if (!WINDOW_RIGHTMOST_P (w)
642 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
643 {
644 int x0, x1, y0, y1;
dc6f92b8 645
06a2c219 646 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 647 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
648 y1 -= 1;
649
650 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
651 f->output_data.x->normal_gc, x1, y0, x1, y1);
652 }
653}
654
655
656/* End update of window W (which is equal to updated_window). Draw
657 vertical borders between horizontally adjacent windows, and display
658 W's cursor if CURSOR_ON_P is non-zero. W may be a menu bar
659 pseudo-window in case we don't have X toolkit support. Such
660 windows don't have a cursor, so don't display it here. */
661
662static void
663x_update_window_end (w, cursor_on_p)
664 struct window *w;
665 int cursor_on_p;
666{
667 if (!w->pseudo_window_p)
668 {
669 BLOCK_INPUT;
670 if (cursor_on_p)
671 x_display_and_set_cursor (w, 1, output_cursor.hpos,
672 output_cursor.vpos,
673 output_cursor.x, output_cursor.y);
674 x_draw_vertical_border (w);
675 UNBLOCK_INPUT;
676 }
677
678 updated_window = NULL;
679}
dc6f92b8 680
dc6f92b8 681
06a2c219
GM
682/* End update of frame F. This function is installed as a hook in
683 update_end. */
684
685static void
686x_update_end (f)
687 struct frame *f;
688{
689 /* Mouse highlight may be displayed again. */
aa8bff2e 690 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 691
06a2c219 692 BLOCK_INPUT;
334208b7 693 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
694 UNBLOCK_INPUT;
695}
b8009dd1 696
06a2c219
GM
697
698/* This function is called from various places in xdisp.c whenever a
699 complete update has been performed. The global variable
700 updated_window is not available here. */
b8009dd1 701
dfcf069d 702static void
b8009dd1 703XTframe_up_to_date (f)
06a2c219 704 struct frame *f;
b8009dd1 705{
06a2c219 706 if (FRAME_X_P (f))
514e4681 707 {
06a2c219
GM
708 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
709 if (dpyinfo->mouse_face_deferred_gc
710 || f == dpyinfo->mouse_face_mouse_frame)
711 {
712 BLOCK_INPUT;
713 if (dpyinfo->mouse_face_mouse_frame)
714 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
715 dpyinfo->mouse_face_mouse_x,
716 dpyinfo->mouse_face_mouse_y);
717 dpyinfo->mouse_face_deferred_gc = 0;
718 UNBLOCK_INPUT;
719 }
514e4681 720 }
b8009dd1 721}
06a2c219
GM
722
723
724/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
725 arrow bitmaps, or clear the areas where they would be displayed
726 before DESIRED_ROW is made current. The window being updated is
727 found in updated_window. This function It is called from
728 update_window_line only if it is known that there are differences
729 between bitmaps to be drawn between current row and DESIRED_ROW. */
730
731static void
732x_after_update_window_line (desired_row)
733 struct glyph_row *desired_row;
734{
735 struct window *w = updated_window;
736
737 xassert (w);
738
739 if (!desired_row->mode_line_p && !w->pseudo_window_p)
740 {
741 BLOCK_INPUT;
742 x_draw_row_bitmaps (w, desired_row);
743
744 /* When a window has disappeared, make sure that no rest of
745 full-width rows stays visible in the internal border. */
746 if (windows_or_buffers_changed)
747 {
748 struct frame *f = XFRAME (w->frame);
749 int width = FRAME_INTERNAL_BORDER_WIDTH (f);
750 int height = desired_row->visible_height;
110859fc
GM
751 int x = (window_box_right (w, -1)
752 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
753 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
754
755 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
756 x, y, width, height, False);
757 }
758
759 UNBLOCK_INPUT;
760 }
761}
762
763
764/* Draw the bitmap WHICH in one of the areas to the left or right of
765 window W. ROW is the glyph row for which to display the bitmap; it
766 determines the vertical position at which the bitmap has to be
767 drawn. */
768
769static void
770x_draw_bitmap (w, row, which)
771 struct window *w;
772 struct glyph_row *row;
773 enum bitmap_type which;
774{
775 struct frame *f = XFRAME (WINDOW_FRAME (w));
776 Display *display = FRAME_X_DISPLAY (f);
777 Window window = FRAME_X_WINDOW (f);
778 int x, y, wd, h, dy;
779 unsigned char *bits;
780 Pixmap pixmap;
781 GC gc = f->output_data.x->normal_gc;
782 struct face *face;
783 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
784
785 /* Must clip because of partially visible lines. */
786 x_clip_to_row (w, row, gc, 1);
787
788 switch (which)
789 {
790 case LEFT_TRUNCATION_BITMAP:
791 wd = left_width;
792 h = left_height;
793 bits = left_bits;
794 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
795 - wd
110859fc 796 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
797 break;
798
799 case OVERLAY_ARROW_BITMAP:
800 wd = left_width;
801 h = left_height;
802 bits = ov_bits;
803 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
804 - wd
110859fc 805 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
806 break;
807
808 case RIGHT_TRUNCATION_BITMAP:
809 wd = right_width;
810 h = right_height;
811 bits = right_bits;
812 x = window_box_right (w, -1);
110859fc 813 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
814 break;
815
816 case CONTINUED_LINE_BITMAP:
817 wd = right_width;
818 h = right_height;
819 bits = continued_bits;
820 x = window_box_right (w, -1);
110859fc 821 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
822 break;
823
824 case CONTINUATION_LINE_BITMAP:
825 wd = continuation_width;
826 h = continuation_height;
827 bits = continuation_bits;
828 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
829 - wd
110859fc 830 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
831 break;
832
833 case ZV_LINE_BITMAP:
834 wd = zv_width;
835 h = zv_height;
836 bits = zv_bits;
837 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
838 - wd
110859fc 839 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
840 break;
841
842 default:
843 abort ();
844 }
845
846 /* Convert to frame coordinates. Set dy to the offset in the row to
847 start drawing the bitmap. */
848 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
849 dy = (row->height - h) / 2;
850
851 /* Draw the bitmap. I believe these small pixmaps can be cached
852 by the server. */
853 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
854 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
855 face->foreground,
856 face->background, depth);
857 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
858 XFreePixmap (display, pixmap);
859 XSetClipMask (display, gc, None);
860}
861
862
863/* Draw flags bitmaps for glyph row ROW on window W. Call this
864 function with input blocked. */
865
866static void
867x_draw_row_bitmaps (w, row)
868 struct window *w;
869 struct glyph_row *row;
870{
871 struct frame *f = XFRAME (w->frame);
872 enum bitmap_type bitmap;
873 struct face *face;
045dee35 874 int header_line_height = -1;
06a2c219
GM
875
876 xassert (interrupt_input_blocked);
877
878 /* If row is completely invisible, because of vscrolling, we
879 don't have to draw anything. */
880 if (row->visible_height <= 0)
881 return;
882
883 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
884 PREPARE_FACE_FOR_DISPLAY (f, face);
885
886 /* Decide which bitmap to draw at the left side. */
887 if (row->overlay_arrow_p)
888 bitmap = OVERLAY_ARROW_BITMAP;
889 else if (row->truncated_on_left_p)
890 bitmap = LEFT_TRUNCATION_BITMAP;
891 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
892 bitmap = CONTINUATION_LINE_BITMAP;
893 else if (row->indicate_empty_line_p)
894 bitmap = ZV_LINE_BITMAP;
895 else
896 bitmap = NO_BITMAP;
897
898 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
899 the flags area. */
900 if (bitmap == NO_BITMAP
110859fc 901 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
902 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
903 {
904 /* If W has a vertical border to its left, don't draw over it. */
905 int border = ((XFASTINT (w->left) > 0
906 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
907 ? 1 : 0);
908 int left = window_box_left (w, -1);
909
045dee35
GM
910 if (header_line_height < 0)
911 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
912
913 /* In case the same realized face is used for bitmap areas and
914 for something displayed in the text (e.g. face `region' on
915 mono-displays, the fill style may have been changed to
916 FillSolid in x_draw_glyph_string_background. */
917 if (face->stipple)
918 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
919 else
920 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
921
06a2c219
GM
922 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
923 face->gc,
924 (left
110859fc 925 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 926 + border),
045dee35 927 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 928 row->y)),
110859fc 929 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 930 row->visible_height);
dcd08bfb
GM
931 if (!face->stipple)
932 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
933 }
934
935 /* Draw the left bitmap. */
936 if (bitmap != NO_BITMAP)
937 x_draw_bitmap (w, row, bitmap);
938
939 /* Decide which bitmap to draw at the right side. */
940 if (row->truncated_on_right_p)
941 bitmap = RIGHT_TRUNCATION_BITMAP;
942 else if (row->continued_p)
943 bitmap = CONTINUED_LINE_BITMAP;
944 else
945 bitmap = NO_BITMAP;
946
947 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
948 the flags area. */
949 if (bitmap == NO_BITMAP
110859fc 950 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
951 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
952 {
953 int right = window_box_right (w, -1);
954
045dee35
GM
955 if (header_line_height < 0)
956 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
957
958 /* In case the same realized face is used for bitmap areas and
959 for something displayed in the text (e.g. face `region' on
960 mono-displays, the fill style may have been changed to
961 FillSolid in x_draw_glyph_string_background. */
962 if (face->stipple)
963 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
964 else
965 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
966 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
967 face->gc,
968 right,
045dee35 969 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 970 row->y)),
110859fc 971 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 972 row->visible_height);
dcd08bfb
GM
973 if (!face->stipple)
974 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
975 }
976
977 /* Draw the right bitmap. */
978 if (bitmap != NO_BITMAP)
979 x_draw_bitmap (w, row, bitmap);
980}
981
dc6f92b8 982\f
06a2c219
GM
983/***********************************************************************
984 Line Highlighting
985 ***********************************************************************/
dc6f92b8 986
06a2c219
GM
987/* External interface to control of standout mode. Not used for X
988 frames. Aborts when called. */
989
990static void
dc6f92b8
JB
991XTreassert_line_highlight (new, vpos)
992 int new, vpos;
993{
06a2c219 994 abort ();
dc6f92b8
JB
995}
996
06a2c219
GM
997
998/* Call this when about to modify line at position VPOS and change
999 whether it is highlighted. Not used for X frames. Aborts when
1000 called. */
dc6f92b8 1001
dfcf069d 1002static void
06a2c219
GM
1003x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1004 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1005{
06a2c219 1006 abort ();
dc6f92b8
JB
1007}
1008
06a2c219
GM
1009
1010/* This is called when starting Emacs and when restarting after
1011 suspend. When starting Emacs, no X window is mapped. And nothing
1012 must be done to Emacs's own window if it is suspended (though that
1013 rarely happens). */
dc6f92b8 1014
dfcf069d 1015static void
dc6f92b8
JB
1016XTset_terminal_modes ()
1017{
1018}
1019
06a2c219
GM
1020/* This is called when exiting or suspending Emacs. Exiting will make
1021 the X-windows go away, and suspending requires no action. */
dc6f92b8 1022
dfcf069d 1023static void
dc6f92b8
JB
1024XTreset_terminal_modes ()
1025{
dc6f92b8 1026}
06a2c219
GM
1027
1028
dc6f92b8 1029\f
06a2c219
GM
1030/***********************************************************************
1031 Output Cursor
1032 ***********************************************************************/
1033
1034/* Set the global variable output_cursor to CURSOR. All cursor
1035 positions are relative to updated_window. */
dc6f92b8 1036
dfcf069d 1037static void
06a2c219
GM
1038set_output_cursor (cursor)
1039 struct cursor_pos *cursor;
dc6f92b8 1040{
06a2c219
GM
1041 output_cursor.hpos = cursor->hpos;
1042 output_cursor.vpos = cursor->vpos;
1043 output_cursor.x = cursor->x;
1044 output_cursor.y = cursor->y;
1045}
1046
1047
1048/* Set a nominal cursor position.
dc6f92b8 1049
06a2c219
GM
1050 HPOS and VPOS are column/row positions in a window glyph matrix. X
1051 and Y are window text area relative pixel positions.
1052
1053 If this is done during an update, updated_window will contain the
1054 window that is being updated and the position is the future output
1055 cursor position for that window. If updated_window is null, use
1056 selected_window and display the cursor at the given position. */
1057
1058static void
1059XTcursor_to (vpos, hpos, y, x)
1060 int vpos, hpos, y, x;
1061{
1062 struct window *w;
1063
1064 /* If updated_window is not set, work on selected_window. */
1065 if (updated_window)
1066 w = updated_window;
1067 else
1068 w = XWINDOW (selected_window);
dbcb258a 1069
06a2c219
GM
1070 /* Set the output cursor. */
1071 output_cursor.hpos = hpos;
1072 output_cursor.vpos = vpos;
1073 output_cursor.x = x;
1074 output_cursor.y = y;
dc6f92b8 1075
06a2c219
GM
1076 /* If not called as part of an update, really display the cursor.
1077 This will also set the cursor position of W. */
1078 if (updated_window == NULL)
dc6f92b8
JB
1079 {
1080 BLOCK_INPUT;
06a2c219 1081 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1082 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1083 UNBLOCK_INPUT;
1084 }
1085}
dc43ef94 1086
06a2c219
GM
1087
1088\f
1089/***********************************************************************
1090 Display Iterator
1091 ***********************************************************************/
1092
1093/* Function prototypes of this page. */
1094
1095static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1096 struct glyph *,
1097 XChar2b *));
1098static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1099 int, XChar2b *, int));
e2ef8ee6 1100static XCharStruct *x_per_char_metric_1 P_ ((XFontStruct *, XChar2b *));
06a2c219
GM
1101static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1102static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1103static void x_append_glyph P_ ((struct it *));
b4192550 1104static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1105static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1106 int, int, double));
1107static void x_produce_glyphs P_ ((struct it *));
06a2c219 1108static void x_produce_image_glyph P_ ((struct it *it));
e2ef8ee6 1109static XCharStruct *x_default_char P_ ((XFontStruct *, XChar2b *));
dc43ef94 1110
dc6f92b8 1111
e2ef8ee6
GM
1112/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1113 is not contained in the font. */
dc43ef94 1114
06a2c219 1115static INLINE XCharStruct *
e2ef8ee6 1116x_per_char_metric_1 (font, char2b)
06a2c219
GM
1117 XFontStruct *font;
1118 XChar2b *char2b;
1119{
1120 /* The result metric information. */
1121 XCharStruct *pcm = NULL;
dc6f92b8 1122
06a2c219 1123 xassert (font && char2b);
dc6f92b8 1124
06a2c219 1125 if (font->per_char != NULL)
dc6f92b8 1126 {
06a2c219 1127 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1128 {
06a2c219
GM
1129 /* min_char_or_byte2 specifies the linear character index
1130 corresponding to the first element of the per_char array,
1131 max_char_or_byte2 is the index of the last character. A
1132 character with non-zero CHAR2B->byte1 is not in the font.
1133 A character with byte2 less than min_char_or_byte2 or
1134 greater max_char_or_byte2 is not in the font. */
1135 if (char2b->byte1 == 0
1136 && char2b->byte2 >= font->min_char_or_byte2
1137 && char2b->byte2 <= font->max_char_or_byte2)
1138 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1139 }
06a2c219 1140 else
dc6f92b8 1141 {
06a2c219
GM
1142 /* If either min_byte1 or max_byte1 are nonzero, both
1143 min_char_or_byte2 and max_char_or_byte2 are less than
1144 256, and the 2-byte character index values corresponding
1145 to the per_char array element N (counting from 0) are:
1146
1147 byte1 = N/D + min_byte1
1148 byte2 = N\D + min_char_or_byte2
1149
1150 where:
1151
1152 D = max_char_or_byte2 - min_char_or_byte2 + 1
1153 / = integer division
1154 \ = integer modulus */
1155 if (char2b->byte1 >= font->min_byte1
1156 && char2b->byte1 <= font->max_byte1
1157 && char2b->byte2 >= font->min_char_or_byte2
1158 && char2b->byte2 <= font->max_char_or_byte2)
1159 {
1160 pcm = (font->per_char
1161 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1162 * (char2b->byte1 - font->min_byte1))
1163 + (char2b->byte2 - font->min_char_or_byte2));
1164 }
dc6f92b8 1165 }
06a2c219
GM
1166 }
1167 else
1168 {
1169 /* If the per_char pointer is null, all glyphs between the first
1170 and last character indexes inclusive have the same
1171 information, as given by both min_bounds and max_bounds. */
1172 if (char2b->byte2 >= font->min_char_or_byte2
1173 && char2b->byte2 <= font->max_char_or_byte2)
1174 pcm = &font->max_bounds;
1175 }
dc6f92b8 1176
e2ef8ee6
GM
1177 if (pcm && pcm->width == 0)
1178 pcm = NULL;
1179
1180 return pcm;
1181}
1182
1183
1184/* Return in *DEFAULT_CHAR the default char to use for characters not
1185 contained in FONT. This is either FONT->default_char if that is
1186 valid, or some suitable other character if FONT->default_char is
1187 invalid. Value is a pointer to the XCharStruct of
1188 FONT->default_char or null if FONT->default_char is invalid. */
1189
1190static INLINE XCharStruct *
1191x_default_char (font, default_char)
1192 XFontStruct *font;
1193 XChar2b *default_char;
1194{
1195 XCharStruct *pcm;
1196
1197 /* FONT->default_char is a 16-bit character code with byte1 in the
1198 most significant byte and byte2 in the least significant
1199 byte. */
1200 default_char->byte1 = (font->default_char >> BITS_PER_CHAR) & 0xff;
1201 default_char->byte2 = font->default_char & 0xff;
1202 pcm = x_per_char_metric_1 (font, default_char);
1203
1204 /* If FONT->default_char is invalid, choose a better one. */
1205 if (pcm == NULL)
1206 {
1207 if (font->per_char)
1208 {
1209 if (font->min_byte1 == 0 && font->max_byte1 == 0)
1210 {
1211 default_char->byte1 = 0;
1212 default_char->byte2 = font->min_char_or_byte2;
1213 }
1214 else
1215 {
1216 default_char->byte1 = font->min_byte1;
1217 default_char->byte2 = font->min_char_or_byte2;
1218 }
1219 }
1220 else
1221 default_char->byte2 = font->min_char_or_byte2;
1222 }
1223
1224 return pcm;
1225}
4a4dc352 1226
e2ef8ee6
GM
1227
1228/* Get metrics of character CHAR2B in FONT. Value is always non-null.
1229 If CHAR2B is not contained in FONT, a default character metric is
1230 returned. */
1231
1232static INLINE XCharStruct *
1233x_per_char_metric (font, char2b)
1234 XFontStruct *font;
1235 XChar2b *char2b;
1236{
1237 XCharStruct *pcm = x_per_char_metric_1 (font, char2b);
1238
1239 if (pcm == NULL)
06a2c219
GM
1240 {
1241 /* Character not contained in the font. FONT->default_char
1242 gives the character that will be printed. FONT->default_char
1243 is a 16-bit character code with byte1 in the most significant
1244 byte and byte2 in the least significant byte. */
1245 XChar2b default_char;
e2ef8ee6
GM
1246
1247 pcm = x_default_char (font, &default_char);
1248 if (pcm == NULL)
1249 pcm = x_per_char_metric_1 (font, &default_char);
06a2c219
GM
1250 }
1251
e2ef8ee6 1252 xassert (pcm != NULL);
06a2c219
GM
1253 return pcm;
1254}
b73b6aaf 1255
57b03282 1256
06a2c219
GM
1257/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1258 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1259
06a2c219
GM
1260static INLINE void
1261x_encode_char (c, char2b, font_info)
1262 int c;
1263 XChar2b *char2b;
1264 struct font_info *font_info;
1265{
1266 int charset = CHAR_CHARSET (c);
1267 XFontStruct *font = font_info->font;
1268
1269 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1270 This may be either a program in a special encoder language or a
1271 fixed encoding. */
1272 if (font_info->font_encoder)
1273 {
1274 /* It's a program. */
1275 struct ccl_program *ccl = font_info->font_encoder;
1276
1277 if (CHARSET_DIMENSION (charset) == 1)
1278 {
1279 ccl->reg[0] = charset;
1280 ccl->reg[1] = char2b->byte2;
1281 }
1282 else
1283 {
1284 ccl->reg[0] = charset;
1285 ccl->reg[1] = char2b->byte1;
1286 ccl->reg[2] = char2b->byte2;
1287 }
1288
1289 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1290
1291 /* We assume that MSBs are appropriately set/reset by CCL
1292 program. */
1293 if (font->max_byte1 == 0) /* 1-byte font */
1294 char2b->byte2 = ccl->reg[1];
1295 else
1296 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1297 }
1298 else if (font_info->encoding[charset])
1299 {
1300 /* Fixed encoding scheme. See fontset.h for the meaning of the
1301 encoding numbers. */
1302 int enc = font_info->encoding[charset];
1303
1304 if ((enc == 1 || enc == 2)
1305 && CHARSET_DIMENSION (charset) == 2)
1306 char2b->byte1 |= 0x80;
1307
1308 if (enc == 1 || enc == 3)
1309 char2b->byte2 |= 0x80;
1310 }
1311}
1312
1313
1314/* Get face and two-byte form of character C in face FACE_ID on frame
1315 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1316 means we want to display multibyte text. Value is a pointer to a
1317 realized face that is ready for display. */
1318
1319static INLINE struct face *
1320x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1321 struct frame *f;
1322 int c, face_id;
1323 XChar2b *char2b;
1324 int multibyte_p;
1325{
1326 struct face *face = FACE_FROM_ID (f, face_id);
1327
1328 if (!multibyte_p)
1329 {
1330 /* Unibyte case. We don't have to encode, but we have to make
1331 sure to use a face suitable for unibyte. */
1332 char2b->byte1 = 0;
1333 char2b->byte2 = c;
1334
1335 if (!FACE_SUITABLE_FOR_CHARSET_P (face, -1))
1336 {
1337 face_id = FACE_FOR_CHARSET (f, face_id, -1);
1338 face = FACE_FROM_ID (f, face_id);
1339 }
1340 }
1341 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1342 {
1343 /* Case of ASCII in a face known to fit ASCII. */
1344 char2b->byte1 = 0;
1345 char2b->byte2 = c;
1346 }
1347 else
1348 {
1349 int c1, c2, charset;
1350
1351 /* Split characters into bytes. If c2 is -1 afterwards, C is
1352 really a one-byte character so that byte1 is zero. */
1353 SPLIT_CHAR (c, charset, c1, c2);
1354 if (c2 > 0)
1355 char2b->byte1 = c1, char2b->byte2 = c2;
1356 else
1357 char2b->byte1 = 0, char2b->byte2 = c1;
1358
1359 /* Get the face for displaying C. If `face' is not suitable for
1360 charset, get the one that fits. (This can happen for the
b4192550
KH
1361 translations of a composition where the glyph
1362 specifies a face for the first component, but the other
1363 components have a different charset.) */
06a2c219
GM
1364 if (!FACE_SUITABLE_FOR_CHARSET_P (face, charset))
1365 {
1366 face_id = FACE_FOR_CHARSET (f, face_id, charset);
1367 face = FACE_FROM_ID (f, face_id);
1368 }
1369
1370 /* Maybe encode the character in *CHAR2B. */
1371 if (charset != CHARSET_ASCII)
1372 {
1373 struct font_info *font_info
1374 = FONT_INFO_FROM_ID (f, face->font_info_id);
1375 if (font_info)
1376 {
1377 x_encode_char (c, char2b, font_info);
1378 if (charset == charset_latin_iso8859_1)
1379 {
1380 xassert (((XFontStruct *) font_info->font)->max_char_or_byte2
1381 >= 0x80);
1382 char2b->byte2 |= 0x80;
1383 }
1384 }
1385 }
1386 }
1387
1388 /* Make sure X resources of the face are allocated. */
1389 xassert (face != NULL);
1390 PREPARE_FACE_FOR_DISPLAY (f, face);
1391
1392 return face;
1393}
1394
1395
1396/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1397 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1398 a pointer to a realized face that is ready for display. */
1399
1400static INLINE struct face *
1401x_get_glyph_face_and_encoding (f, glyph, char2b)
1402 struct frame *f;
1403 struct glyph *glyph;
1404 XChar2b *char2b;
1405{
1406 struct face *face;
1407
1408 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1409 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219
GM
1410
1411 if (!glyph->multibyte_p)
1412 {
1413 /* Unibyte case. We don't have to encode, but we have to make
1414 sure to use a face suitable for unibyte. */
1415 char2b->byte1 = 0;
43d120d8 1416 char2b->byte2 = glyph->u.ch;
06a2c219 1417 }
43d120d8
KH
1418 else if (glyph->u.ch < 128
1419 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1420 {
1421 /* Case of ASCII in a face known to fit ASCII. */
1422 char2b->byte1 = 0;
43d120d8 1423 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1424 }
1425 else
1426 {
1427 int c1, c2, charset;
1428
1429 /* Split characters into bytes. If c2 is -1 afterwards, C is
1430 really a one-byte character so that byte1 is zero. */
43d120d8 1431 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1432 if (c2 > 0)
1433 char2b->byte1 = c1, char2b->byte2 = c2;
1434 else
1435 char2b->byte1 = 0, char2b->byte2 = c1;
1436
1437 /* Maybe encode the character in *CHAR2B. */
1438 if (charset != CHARSET_ASCII)
1439 {
1440 struct font_info *font_info
1441 = FONT_INFO_FROM_ID (f, face->font_info_id);
1442 if (font_info)
1443 {
43d120d8 1444 x_encode_char (glyph->u.ch, char2b, font_info);
06a2c219
GM
1445 if (charset == charset_latin_iso8859_1)
1446 char2b->byte2 |= 0x80;
1447 }
1448 }
1449 }
1450
1451 /* Make sure X resources of the face are allocated. */
1452 xassert (face != NULL);
1453 PREPARE_FACE_FOR_DISPLAY (f, face);
1454 return face;
1455}
1456
1457
1458/* Store one glyph for IT->char_to_display in IT->glyph_row.
1459 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1460
1461static INLINE void
1462x_append_glyph (it)
1463 struct it *it;
1464{
1465 struct glyph *glyph;
1466 enum glyph_row_area area = it->area;
1467
1468 xassert (it->glyph_row);
1469 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1470
1471 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1472 if (glyph < it->glyph_row->glyphs[area + 1])
1473 {
1474 /* Play it safe. If sub-structures of the glyph are not all the
1475 same size, it otherwise be that some bits stay set. This
1476 would prevent a comparison with GLYPH_EQUAL_P. */
1477 glyph->u.val = 0;
1478
1479 glyph->type = CHAR_GLYPH;
1480 glyph->pixel_width = it->pixel_width;
43d120d8
KH
1481 glyph->u.ch = it->char_to_display;
1482 glyph->face_id = it->face_id;
06a2c219
GM
1483 glyph->charpos = CHARPOS (it->position);
1484 glyph->object = it->object;
1485 glyph->left_box_line_p = it->start_of_box_run_p;
1486 glyph->right_box_line_p = it->end_of_box_run_p;
1487 glyph->voffset = it->voffset;
1488 glyph->multibyte_p = it->multibyte_p;
66ac4b0e
GM
1489 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1490 || it->phys_descent > it->descent);
06a2c219
GM
1491 ++it->glyph_row->used[area];
1492 }
1493}
1494
b4192550
KH
1495/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1496 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1497
1498static INLINE void
1499x_append_composite_glyph (it)
1500 struct it *it;
1501{
1502 struct glyph *glyph;
1503 enum glyph_row_area area = it->area;
1504
1505 xassert (it->glyph_row);
1506
1507 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1508 if (glyph < it->glyph_row->glyphs[area + 1])
1509 {
1510 /* Play it safe. If sub-structures of the glyph are not all the
1511 same size, it otherwise be that some bits stay set. This
1512 would prevent a comparison with GLYPH_EQUAL_P. */
1513 glyph->u.val = 0;
1514
1515 glyph->type = COMPOSITE_GLYPH;
1516 glyph->pixel_width = it->pixel_width;
43d120d8
KH
1517 glyph->u.cmp_id = it->cmp_id;
1518 glyph->face_id = it->face_id;
b4192550
KH
1519 glyph->charpos = CHARPOS (it->position);
1520 glyph->object = it->object;
1521 glyph->left_box_line_p = it->start_of_box_run_p;
1522 glyph->right_box_line_p = it->end_of_box_run_p;
1523 glyph->voffset = it->voffset;
1524 glyph->multibyte_p = it->multibyte_p;
1525 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1526 || it->phys_descent > it->descent);
1527 ++it->glyph_row->used[area];
1528 }
1529}
1530
06a2c219
GM
1531
1532/* Change IT->ascent and IT->height according to the setting of
1533 IT->voffset. */
1534
1535static INLINE void
1536take_vertical_position_into_account (it)
1537 struct it *it;
1538{
1539 if (it->voffset)
1540 {
1541 if (it->voffset < 0)
1542 /* Increase the ascent so that we can display the text higher
1543 in the line. */
1544 it->ascent += abs (it->voffset);
1545 else
1546 /* Increase the descent so that we can display the text lower
1547 in the line. */
1548 it->descent += it->voffset;
1549 }
1550}
1551
1552
1553/* Produce glyphs/get display metrics for the image IT is loaded with.
1554 See the description of struct display_iterator in dispextern.h for
1555 an overview of struct display_iterator. */
1556
1557static void
1558x_produce_image_glyph (it)
1559 struct it *it;
1560{
1561 struct image *img;
1562 struct face *face;
1563
1564 xassert (it->what == IT_IMAGE);
1565
1566 face = FACE_FROM_ID (it->f, it->face_id);
1567 img = IMAGE_FROM_ID (it->f, it->image_id);
1568 xassert (img);
1569
1570 /* Make sure X resources of the face and image are loaded. */
1571 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1572 prepare_image_for_display (it->f, img);
1573
66ac4b0e
GM
1574 it->ascent = it->phys_ascent = IMAGE_ASCENT (img);
1575 it->descent = it->phys_descent = img->height + 2 * img->margin - it->ascent;
06a2c219
GM
1576 it->pixel_width = img->width + 2 * img->margin;
1577
1578 it->nglyphs = 1;
1579
1580 if (face->box != FACE_NO_BOX)
1581 {
1582 it->ascent += face->box_line_width;
1583 it->descent += face->box_line_width;
1584
1585 if (it->start_of_box_run_p)
1586 it->pixel_width += face->box_line_width;
1587 if (it->end_of_box_run_p)
1588 it->pixel_width += face->box_line_width;
1589 }
1590
1591 take_vertical_position_into_account (it);
1592
1593 if (it->glyph_row)
1594 {
1595 struct glyph *glyph;
1596 enum glyph_row_area area = it->area;
1597
1598 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1599 if (glyph < it->glyph_row->glyphs[area + 1])
1600 {
1601 glyph->type = IMAGE_GLYPH;
43d120d8
KH
1602 glyph->u.img_id = img->id;
1603 glyph->face_id = it->face_id;
06a2c219
GM
1604 glyph->pixel_width = it->pixel_width;
1605 glyph->charpos = CHARPOS (it->position);
1606 glyph->object = it->object;
1607 glyph->left_box_line_p = it->start_of_box_run_p;
1608 glyph->right_box_line_p = it->end_of_box_run_p;
1609 glyph->voffset = it->voffset;
1610 glyph->multibyte_p = it->multibyte_p;
1611 ++it->glyph_row->used[area];
1612 }
1613 }
1614}
1615
1616
1617/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1618 of the glyph, WIDTH and HEIGHT are the width and height of the
1619 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1620 ascent of the glyph (0 <= ASCENT <= 1). */
1621
1622static void
1623x_append_stretch_glyph (it, object, width, height, ascent)
1624 struct it *it;
1625 Lisp_Object object;
1626 int width, height;
1627 double ascent;
1628{
1629 struct glyph *glyph;
1630 enum glyph_row_area area = it->area;
1631
1632 xassert (ascent >= 0 && ascent <= 1);
1633
1634 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1635 if (glyph < it->glyph_row->glyphs[area + 1])
1636 {
1637 glyph->type = STRETCH_GLYPH;
1638 glyph->u.stretch.ascent = height * ascent;
1639 glyph->u.stretch.height = height;
43d120d8 1640 glyph->face_id = it->face_id;
06a2c219
GM
1641 glyph->pixel_width = width;
1642 glyph->charpos = CHARPOS (it->position);
1643 glyph->object = object;
1644 glyph->left_box_line_p = it->start_of_box_run_p;
1645 glyph->right_box_line_p = it->end_of_box_run_p;
1646 glyph->voffset = it->voffset;
1647 glyph->multibyte_p = it->multibyte_p;
1648 ++it->glyph_row->used[area];
1649 }
1650}
1651
1652
1653/* Produce a stretch glyph for iterator IT. IT->object is the value
1654 of the glyph property displayed. The value must be a list
1655 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1656 being recognized:
1657
1658 1. `:width WIDTH' specifies that the space should be WIDTH *
1659 canonical char width wide. WIDTH may be an integer or floating
1660 point number.
1661
1662 2. `:relative-width FACTOR' specifies that the width of the stretch
1663 should be computed from the width of the first character having the
1664 `glyph' property, and should be FACTOR times that width.
1665
1666 3. `:align-to HPOS' specifies that the space should be wide enough
1667 to reach HPOS, a value in canonical character units.
1668
1669 Exactly one of the above pairs must be present.
1670
1671 4. `:height HEIGHT' specifies that the height of the stretch produced
1672 should be HEIGHT, measured in canonical character units.
1673
1674 5. `:relative-height FACTOR' specifies that the height of the the
1675 stretch should be FACTOR times the height of the characters having
1676 the glyph property.
1677
1678 Either none or exactly one of 4 or 5 must be present.
1679
1680 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1681 of the stretch should be used for the ascent of the stretch.
1682 ASCENT must be in the range 0 <= ASCENT <= 100. */
1683
1684#define NUMVAL(X) \
1685 ((INTEGERP (X) || FLOATP (X)) \
1686 ? XFLOATINT (X) \
1687 : - 1)
1688
1689
1690static void
1691x_produce_stretch_glyph (it)
1692 struct it *it;
1693{
1694 /* (space :width WIDTH :height HEIGHT. */
1695 extern Lisp_Object QCwidth, QCheight, QCascent, Qspace;
1696 extern Lisp_Object QCrelative_width, QCrelative_height;
1697 extern Lisp_Object QCalign_to;
1698 Lisp_Object prop, plist;
1699 double width = 0, height = 0, ascent = 0;
1700 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1701 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1702
1703 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1704
1705 /* List should start with `space'. */
1706 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1707 plist = XCDR (it->object);
1708
1709 /* Compute the width of the stretch. */
1710 if (prop = Fplist_get (plist, QCwidth),
1711 NUMVAL (prop) > 0)
1712 /* Absolute width `:width WIDTH' specified and valid. */
1713 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1714 else if (prop = Fplist_get (plist, QCrelative_width),
1715 NUMVAL (prop) > 0)
1716 {
1717 /* Relative width `:relative-width FACTOR' specified and valid.
1718 Compute the width of the characters having the `glyph'
1719 property. */
1720 struct it it2;
1721 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1722
1723 it2 = *it;
1724 if (it->multibyte_p)
1725 {
1726 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1727 - IT_BYTEPOS (*it));
1728 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1729 }
1730 else
1731 it2.c = *p, it2.len = 1;
1732
1733 it2.glyph_row = NULL;
1734 it2.what = IT_CHARACTER;
1735 x_produce_glyphs (&it2);
1736 width = NUMVAL (prop) * it2.pixel_width;
1737 }
1738 else if (prop = Fplist_get (plist, QCalign_to),
1739 NUMVAL (prop) > 0)
1740 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1741 else
1742 /* Nothing specified -> width defaults to canonical char width. */
1743 width = CANON_X_UNIT (it->f);
1744
1745 /* Compute height. */
1746 if (prop = Fplist_get (plist, QCheight),
1747 NUMVAL (prop) > 0)
1748 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1749 else if (prop = Fplist_get (plist, QCrelative_height),
1750 NUMVAL (prop) > 0)
1751 height = FONT_HEIGHT (font) * NUMVAL (prop);
1752 else
1753 height = FONT_HEIGHT (font);
1754
1755 /* Compute percentage of height used for ascent. If
1756 `:ascent ASCENT' is present and valid, use that. Otherwise,
1757 derive the ascent from the font in use. */
1758 if (prop = Fplist_get (plist, QCascent),
1759 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1760 ascent = NUMVAL (prop) / 100.0;
1761 else
1762 ascent = (double) font->ascent / FONT_HEIGHT (font);
1763
1764 if (width <= 0)
1765 width = 1;
1766 if (height <= 0)
1767 height = 1;
1768
1769 if (it->glyph_row)
1770 {
1771 Lisp_Object object = it->stack[it->sp - 1].string;
1772 if (!STRINGP (object))
1773 object = it->w->buffer;
1774 x_append_stretch_glyph (it, object, width, height, ascent);
1775 }
1776
1777 it->pixel_width = width;
66ac4b0e
GM
1778 it->ascent = it->phys_ascent = height * ascent;
1779 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1780 it->nglyphs = 1;
1781
1782 if (face->box != FACE_NO_BOX)
1783 {
1784 it->ascent += face->box_line_width;
1785 it->descent += face->box_line_width;
1786
1787 if (it->start_of_box_run_p)
1788 it->pixel_width += face->box_line_width;
1789 if (it->end_of_box_run_p)
1790 it->pixel_width += face->box_line_width;
1791 }
1792
1793 take_vertical_position_into_account (it);
1794}
1795
b4192550
KH
1796/* Return proper value to be used as baseline offset of font that has
1797 ASCENT and DESCENT to draw characters by the font at the vertical
1798 center of the line of frame F.
1799
1800 Here, out task is to find the value of BOFF in the following figure;
1801
1802 -------------------------+-----------+-
1803 -+-+---------+-+ | |
1804 | | | | | |
1805 | | | | F_ASCENT F_HEIGHT
1806 | | | ASCENT | |
1807 HEIGHT | | | | |
1808 | | |-|-+------+-----------|------- baseline
1809 | | | | BOFF | |
1810 | |---------|-+-+ | |
1811 | | | DESCENT | |
1812 -+-+---------+-+ F_DESCENT |
1813 -------------------------+-----------+-
1814
1815 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1816 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1817 DESCENT = FONT->descent
1818 HEIGHT = FONT_HEIGHT (FONT)
1819 F_DESCENT = (F->output_data.x->font->descent
1820 - F->output_data.x->baseline_offset)
1821 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1822*/
1823
1824#define VCENTER_BASELINE_OFFSET(FONT, F) \
1825 ((FONT)->descent \
1826 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT))) / 2 \
1827 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1828
1829/* Produce glyphs/get display metrics for the display element IT is
1830 loaded with. See the description of struct display_iterator in
1831 dispextern.h for an overview of struct display_iterator. */
1832
1833static void
1834x_produce_glyphs (it)
1835 struct it *it;
1836{
1837 if (it->what == IT_CHARACTER)
1838 {
1839 XChar2b char2b;
1840 XFontStruct *font;
1841 struct face *face;
1842 XCharStruct *pcm;
06a2c219 1843 int font_not_found_p;
b4192550
KH
1844 struct font_info *font_info;
1845 int boff; /* baseline offset */
06a2c219
GM
1846
1847 /* Maybe translate single-byte characters to multibyte. */
1848 it->char_to_display = it->c;
1849 if (unibyte_display_via_language_environment
1850 && SINGLE_BYTE_CHAR_P (it->c)
1851 && (it->c >= 0240
1852 || (it->c >= 0200
1853 && !NILP (Vnonascii_translation_table))))
1854 {
1855 it->char_to_display = unibyte_char_to_multibyte (it->c);
1856 it->charset = CHAR_CHARSET (it->char_to_display);
1857 }
1858
1859 /* Get face and font to use. Encode IT->char_to_display. */
1860 face = x_get_char_face_and_encoding (it->f, it->char_to_display,
1861 it->face_id, &char2b,
1862 it->multibyte_p);
1863 font = face->font;
1864
1865 /* When no suitable font found, use the default font. */
1866 font_not_found_p = font == NULL;
1867 if (font_not_found_p)
b4192550
KH
1868 {
1869 font = FRAME_FONT (it->f);
1870 boff = it->f->output_data.x->baseline_offset;
1871 font_info = NULL;
1872 }
1873 else
1874 {
1875 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1876 boff = font_info->baseline_offset;
1877 if (font_info->vertical_centering)
1878 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1879 }
06a2c219
GM
1880
1881 if (it->char_to_display >= ' '
1882 && (!it->multibyte_p || it->char_to_display < 128))
1883 {
1884 /* Either unibyte or ASCII. */
1885 int stretched_p;
1886
1887 it->nglyphs = 1;
06a2c219
GM
1888
1889 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1890 it->ascent = font->ascent + boff;
1891 it->descent = font->descent - boff;
1892 it->phys_ascent = pcm->ascent + boff;
1893 it->phys_descent = pcm->descent - boff;
06a2c219
GM
1894 it->pixel_width = pcm->width;
1895
1896 /* If this is a space inside a region of text with
1897 `space-width' property, change its width. */
1898 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1899 if (stretched_p)
1900 it->pixel_width *= XFLOATINT (it->space_width);
1901
1902 /* If face has a box, add the box thickness to the character
1903 height. If character has a box line to the left and/or
1904 right, add the box line width to the character's width. */
1905 if (face->box != FACE_NO_BOX)
1906 {
1907 int thick = face->box_line_width;
1908
1909 it->ascent += thick;
1910 it->descent += thick;
1911
1912 if (it->start_of_box_run_p)
1913 it->pixel_width += thick;
1914 if (it->end_of_box_run_p)
1915 it->pixel_width += thick;
1916 }
1917
1918 /* If face has an overline, add the height of the overline
1919 (1 pixel) and a 1 pixel margin to the character height. */
1920 if (face->overline_p)
1921 it->ascent += 2;
1922
1923 take_vertical_position_into_account (it);
1924
1925 /* If we have to actually produce glyphs, do it. */
1926 if (it->glyph_row)
1927 {
1928 if (stretched_p)
1929 {
1930 /* Translate a space with a `space-width' property
1931 into a stretch glyph. */
1932 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1933 x_append_stretch_glyph (it, it->object, it->pixel_width,
1934 it->ascent + it->descent, ascent);
1935 }
1936 else
1937 x_append_glyph (it);
1938
1939 /* If characters with lbearing or rbearing are displayed
1940 in this line, record that fact in a flag of the
1941 glyph row. This is used to optimize X output code. */
1942 if (pcm->lbearing < 0
1943 || pcm->rbearing > pcm->width)
1944 it->glyph_row->contains_overlapping_glyphs_p = 1;
1945 }
1946 }
1947 else if (it->char_to_display == '\n')
1948 {
1949 /* A newline has no width but we need the height of the line. */
1950 it->pixel_width = 0;
1951 it->nglyphs = 0;
b4192550
KH
1952 it->ascent = it->phys_ascent = font->ascent + boff;
1953 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1954
1955 if (face->box != FACE_NO_BOX)
1956 {
1957 int thick = face->box_line_width;
1958 it->ascent += thick;
1959 it->descent += thick;
1960 }
1961 }
1962 else if (it->char_to_display == '\t')
1963 {
1964 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
1965 int x = (it->current_x
1966 - it->prompt_width
1967 + it->continuation_lines_width);
1968 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
1969
1970 it->pixel_width = next_tab_x - x;
1971 it->nglyphs = 1;
b4192550
KH
1972 it->ascent = it->phys_ascent = font->ascent + boff;
1973 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1974
1975 if (it->glyph_row)
1976 {
1977 double ascent = (double) it->ascent / (it->ascent + it->descent);
1978 x_append_stretch_glyph (it, it->object, it->pixel_width,
1979 it->ascent + it->descent, ascent);
1980 }
1981 }
1982 else
1983 {
1984 /* A multi-byte character. Assume that the display width of the
1985 character is the width of the character multiplied by the
b4192550 1986 width of the font. */
06a2c219 1987
b4192550
KH
1988 /* If we found a font, this font should give us the right
1989 metrics. If we didn't find a font, use the frame's
1990 default font and calculate the width of the character
1991 from the charset width; this is what old redisplay code
1992 did. */
1993 pcm = x_per_char_metric (font, &char2b);
1994 it->pixel_width = pcm->width;
1995 if (font_not_found_p)
1996 it->pixel_width *= CHARSET_WIDTH (it->charset);
1997 it->nglyphs = 1;
1998 it->ascent = font->ascent + boff;
1999 it->descent = font->descent - boff;
2000 it->phys_ascent = pcm->ascent + boff;
2001 it->phys_descent = pcm->descent - boff;
2002 if (it->glyph_row
2003 && (pcm->lbearing < 0
2004 || pcm->rbearing > pcm->width))
2005 it->glyph_row->contains_overlapping_glyphs_p = 1;
06a2c219
GM
2006
2007 if (face->box != FACE_NO_BOX)
2008 {
2009 int thick = face->box_line_width;
2010 it->ascent += thick;
2011 it->descent += thick;
2012
2013 if (it->start_of_box_run_p)
2014 it->pixel_width += thick;
2015 if (it->end_of_box_run_p)
2016 it->pixel_width += thick;
2017 }
2018
2019 /* If face has an overline, add the height of the overline
2020 (1 pixel) and a 1 pixel margin to the character height. */
2021 if (face->overline_p)
2022 it->ascent += 2;
2023
2024 take_vertical_position_into_account (it);
2025
2026 if (it->glyph_row)
2027 x_append_glyph (it);
2028 }
2029 }
b4192550
KH
2030 else if (it->what == IT_COMPOSITION)
2031 {
2032 /* Note: A composition is represented as one glyph in the
2033 glyph matrix. There are no padding glyphs. */
2034 XChar2b char2b;
2035 XFontStruct *font;
2036 struct face *face;
2037 XCharStruct *pcm;
2038 int font_not_found_p;
2039 struct font_info *font_info;
2040 int boff; /* baseline offset */
2041 struct composition *cmp = composition_table[it->cmp_id];
2042
2043 /* Maybe translate single-byte characters to multibyte. */
2044 it->char_to_display = it->c;
2045 if (unibyte_display_via_language_environment
2046 && SINGLE_BYTE_CHAR_P (it->c)
2047 && (it->c >= 0240
2048 || (it->c >= 0200
2049 && !NILP (Vnonascii_translation_table))))
2050 {
2051 it->char_to_display = unibyte_char_to_multibyte (it->c);
2052 it->charset = CHAR_CHARSET (it->char_to_display);
2053 }
2054
2055 /* Get face and font to use. Encode IT->char_to_display. */
2056 face = x_get_char_face_and_encoding (it->f, it->char_to_display,
2057 it->face_id, &char2b,
2058 it->multibyte_p);
2059 font = face->font;
2060
2061 /* When no suitable font found, use the default font. */
2062 font_not_found_p = font == NULL;
2063 if (font_not_found_p)
2064 {
2065 font = FRAME_FONT (it->f);
2066 boff = it->f->output_data.x->baseline_offset;
2067 font_info = NULL;
2068 }
2069 else
2070 {
2071 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2072 boff = font_info->baseline_offset;
2073 if (font_info->vertical_centering)
2074 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2075 }
2076
2077 /* There are no padding glyphs, so there is only one glyph to
2078 produce for the composition. Important is that pixel_width,
2079 ascent and descent are the values of what is drawn by
2080 draw_glyphs (i.e. the values of the overall glyphs composed). */
2081 it->nglyphs = 1;
2082
2083 /* If we have not yet calculated pixel size data of glyphs of
2084 the composition for the current face font, calculate them
2085 now. Theoretically, we have to check all fonts for the
2086 glyphs, but that requires much time and memory space. So,
2087 here we check only the font of the first glyph. This leads
2088 to incorrect display very rarely, and C-l (recenter) can
2089 correct the display anyway. */
2090 if (cmp->font != (void *) font)
2091 {
2092 /* Ascent and descent of the font of the first character of
2093 this composition (adjusted by baseline offset). Ascent
2094 and descent of overall glyphs should not be less than
2095 them respectively. */
2096 int font_ascent = font->ascent + boff;
2097 int font_descent = font->descent - boff;
2098 /* Bounding box of the overall glyphs. */
2099 int leftmost, rightmost, lowest, highest;
2100 int i;
2101
2102 cmp->font = (void *) font;
2103
2104 /* Initialize the bounding box. */
2105 pcm = x_per_char_metric (font, &char2b);
2106 leftmost = 0;
2107 rightmost = pcm->width;
2108 lowest = - pcm->descent + boff;
2109 highest = pcm->ascent + boff;
2110 if (font_info
2111 && font_info->default_ascent
2112 && CHAR_TABLE_P (Vuse_default_ascent)
2113 && !NILP (Faref (Vuse_default_ascent,
2114 make_number (it->char_to_display))))
2115 highest = font_info->default_ascent + boff;
2116
2117 /* Draw the first glyph at the normal position. It may be
2118 shifted to right later if some other glyphs are drawn at
2119 the left. */
2120 cmp->offsets[0] = 0;
2121 cmp->offsets[1] = boff;
2122
2123 /* Set cmp->offsets for the remaining glyphs. */
2124 for (i = 1; i < cmp->glyph_len; i++)
2125 {
2126 int left, right, btm, top;
2127 int ch = COMPOSITION_GLYPH (cmp, i);
2128
2129 face = x_get_char_face_and_encoding (it->f, ch,
2130 it->face_id, &char2b,
2131 it->multibyte_p);
2132 font = face->font;
2133 if (font == NULL)
2134 {
2135 font = FRAME_FONT (it->f);
2136 boff = it->f->output_data.x->baseline_offset;
2137 font_info = NULL;
2138 }
2139 else
2140 {
2141 font_info
2142 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2143 boff = font_info->baseline_offset;
2144 if (font_info->vertical_centering)
2145 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2146 }
2147
2148 pcm = x_per_char_metric (font, &char2b);
2149
2150 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2151 {
2152 /* Relative composition with or without
2153 alternate chars. */
2154 left = (leftmost + rightmost - pcm->width) / 2;
2155 btm = - pcm->descent + boff;
2156 if (font_info && font_info->relative_compose
2157 && (! CHAR_TABLE_P (Vignore_relative_composition)
2158 || NILP (Faref (Vignore_relative_composition,
2159 make_number (ch)))))
2160 {
2161
2162 if (- pcm->descent
2163 >= font_info->relative_compose)
2164 /* One extra pixel between two glyphs. */
2165 btm = highest + 1;
2166 else if (pcm->ascent <= 0)
2167 /* One extra pixel between two glyphs. */
2168 btm = lowest - 1 - pcm->ascent - pcm->descent;
2169 }
2170 }
2171 else
2172 {
2173 /* A composition rule is specified by an integer
2174 value that encodes global and new reference
2175 points (GREF and NREF). GREF and NREF are
2176 specified by numbers as below:
2177
2178 0---1---2 -- ascent
2179 | |
2180 | |
2181 | |
2182 9--10--11 -- center
2183 | |
2184 ---3---4---5--- baseline
2185 | |
2186 6---7---8 -- descent
2187 */
2188 int rule = COMPOSITION_RULE (cmp, i);
2189 int gref, nref, grefx, grefy, nrefx, nrefy;
2190
2191 COMPOSITION_DECODE_RULE (rule, gref, nref);
2192 grefx = gref % 3, nrefx = nref % 3;
2193 grefy = gref / 3, nrefy = nref / 3;
2194
2195 left = (leftmost
2196 + grefx * (rightmost - leftmost) / 2
2197 - nrefx * pcm->width / 2);
2198 btm = ((grefy == 0 ? highest
2199 : grefy == 1 ? 0
2200 : grefy == 2 ? lowest
2201 : (highest + lowest) / 2)
2202 - (nrefy == 0 ? pcm->ascent + pcm->descent
2203 : nrefy == 1 ? pcm->descent - boff
2204 : nrefy == 2 ? 0
2205 : (pcm->ascent + pcm->descent) / 2));
2206 }
2207
2208 cmp->offsets[i * 2] = left;
2209 cmp->offsets[i * 2 + 1] = btm + pcm->descent;
2210
2211 /* Update the bounding box of the overall glyphs. */
2212 right = left + pcm->width;
2213 top = btm + pcm->descent + pcm->ascent;
2214 if (left < leftmost)
2215 leftmost = left;
2216 if (right > rightmost)
2217 rightmost = right;
2218 if (top > highest)
2219 highest = top;
2220 if (btm < lowest)
2221 lowest = btm;
2222 }
2223
2224 /* If there are glyphs whose x-offsets are negative,
2225 shift all glyphs to the right and make all x-offsets
2226 non-negative. */
2227 if (leftmost < 0)
2228 {
2229 for (i = 0; i < cmp->glyph_len; i++)
2230 cmp->offsets[i * 2] -= leftmost;
2231 rightmost -= leftmost;
2232 }
2233
2234 cmp->pixel_width = rightmost;
2235 cmp->ascent = highest;
2236 cmp->descent = - lowest;
2237 if (cmp->ascent < font_ascent)
2238 cmp->ascent = font_ascent;
2239 if (cmp->descent < font_descent)
2240 cmp->descent = font_descent;
2241 }
2242
2243 it->pixel_width = cmp->pixel_width;
2244 it->ascent = it->phys_ascent = cmp->ascent;
2245 it->descent = it->phys_descent = cmp->descent;
2246
2247 if (face->box != FACE_NO_BOX)
2248 {
2249 int thick = face->box_line_width;
2250 it->ascent += thick;
2251 it->descent += thick;
2252
2253 if (it->start_of_box_run_p)
2254 it->pixel_width += thick;
2255 if (it->end_of_box_run_p)
2256 it->pixel_width += thick;
2257 }
2258
2259 /* If face has an overline, add the height of the overline
2260 (1 pixel) and a 1 pixel margin to the character height. */
2261 if (face->overline_p)
2262 it->ascent += 2;
2263
2264 take_vertical_position_into_account (it);
2265
2266 if (it->glyph_row)
2267 x_append_composite_glyph (it);
2268 }
06a2c219
GM
2269 else if (it->what == IT_IMAGE)
2270 x_produce_image_glyph (it);
2271 else if (it->what == IT_STRETCH)
2272 x_produce_stretch_glyph (it);
2273
2274 /* Accumulate dimensions. */
2275 xassert (it->ascent >= 0 && it->descent > 0);
2276 if (it->area == TEXT_AREA)
2277 it->current_x += it->pixel_width;
66ac4b0e 2278
06a2c219
GM
2279 it->max_ascent = max (it->max_ascent, it->ascent);
2280 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2281 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2282 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2283}
2284
2285
2286/* Estimate the pixel height of the mode or top line on frame F.
2287 FACE_ID specifies what line's height to estimate. */
2288
2289int
2290x_estimate_mode_line_height (f, face_id)
2291 struct frame *f;
2292 enum face_id face_id;
2293{
2294 int height = 1;
2295
2296 /* This function is called so early when Emacs starts that the face
2297 cache and mode line face are not yet initialized. */
2298 if (FRAME_FACE_CACHE (f))
2299 {
2300 struct face *face = FACE_FROM_ID (f, face_id);
2301 if (face)
2302 height = FONT_HEIGHT (face->font) + 2 * face->box_line_width;
2303 }
2304
2305 return height;
2306}
2307
2308\f
2309/***********************************************************************
2310 Glyph display
2311 ***********************************************************************/
2312
2313/* A sequence of glyphs to be drawn in the same face.
2314
2315 This data structure is not really completely X specific, so it
2316 could possibly, at least partially, be useful for other systems. It
2317 is currently not part of the external redisplay interface because
2318 it's not clear what other systems will need. */
2319
2320struct glyph_string
2321{
2322 /* X-origin of the string. */
2323 int x;
2324
2325 /* Y-origin and y-position of the base line of this string. */
2326 int y, ybase;
2327
2328 /* The width of the string, not including a face extension. */
2329 int width;
2330
2331 /* The width of the string, including a face extension. */
2332 int background_width;
2333
2334 /* The height of this string. This is the height of the line this
2335 string is drawn in, and can be different from the height of the
2336 font the string is drawn in. */
2337 int height;
2338
2339 /* Number of pixels this string overwrites in front of its x-origin.
2340 This number is zero if the string has an lbearing >= 0; it is
2341 -lbearing, if the string has an lbearing < 0. */
2342 int left_overhang;
2343
2344 /* Number of pixels this string overwrites past its right-most
2345 nominal x-position, i.e. x + width. Zero if the string's
2346 rbearing is <= its nominal width, rbearing - width otherwise. */
2347 int right_overhang;
2348
2349 /* The frame on which the glyph string is drawn. */
2350 struct frame *f;
2351
2352 /* The window on which the glyph string is drawn. */
2353 struct window *w;
2354
2355 /* X display and window for convenience. */
2356 Display *display;
2357 Window window;
2358
2359 /* The glyph row for which this string was built. It determines the
2360 y-origin and height of the string. */
2361 struct glyph_row *row;
2362
2363 /* The area within row. */
2364 enum glyph_row_area area;
2365
2366 /* Characters to be drawn, and number of characters. */
2367 XChar2b *char2b;
2368 int nchars;
2369
2370 /* Character set of this glyph string. */
2371 int charset;
2372
2373 /* A face-override for drawing cursors, mouse face and similar. */
2374 enum draw_glyphs_face hl;
2375
2376 /* Face in which this string is to be drawn. */
2377 struct face *face;
2378
2379 /* Font in which this string is to be drawn. */
2380 XFontStruct *font;
2381
2382 /* Font info for this string. */
2383 struct font_info *font_info;
2384
b4192550
KH
2385 /* Non-null means this string describes (part of) a composition.
2386 All characters from char2b are drawn composed. */
2387 struct composition *cmp;
06a2c219
GM
2388
2389 /* Index of this glyph string's first character in the glyph
b4192550
KH
2390 definition of CMP. If this is zero, this glyph string describes
2391 the first character of a composition. */
06a2c219
GM
2392 int gidx;
2393
2394 /* 1 means this glyph strings face has to be drawn to the right end
2395 of the window's drawing area. */
2396 unsigned extends_to_end_of_line_p : 1;
2397
2398 /* 1 means the background of this string has been drawn. */
2399 unsigned background_filled_p : 1;
2400
2401 /* 1 means glyph string must be drawn with 16-bit functions. */
2402 unsigned two_byte_p : 1;
2403
2404 /* 1 means that the original font determined for drawing this glyph
2405 string could not be loaded. The member `font' has been set to
2406 the frame's default font in this case. */
2407 unsigned font_not_found_p : 1;
2408
2409 /* 1 means that the face in which this glyph string is drawn has a
2410 stipple pattern. */
2411 unsigned stippled_p : 1;
2412
66ac4b0e
GM
2413 /* 1 means only the foreground of this glyph string must be drawn,
2414 and we should use the physical height of the line this glyph
2415 string appears in as clip rect. */
2416 unsigned for_overlaps_p : 1;
2417
06a2c219
GM
2418 /* The GC to use for drawing this glyph string. */
2419 GC gc;
2420
2421 /* A pointer to the first glyph in the string. This glyph
2422 corresponds to char2b[0]. Needed to draw rectangles if
2423 font_not_found_p is 1. */
2424 struct glyph *first_glyph;
2425
2426 /* Image, if any. */
2427 struct image *img;
2428
2429 struct glyph_string *next, *prev;
2430};
2431
2432
5c187dee 2433#if 0
06a2c219
GM
2434
2435static void
2436x_dump_glyph_string (s)
2437 struct glyph_string *s;
2438{
2439 fprintf (stderr, "glyph string\n");
2440 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2441 s->x, s->y, s->width, s->height);
2442 fprintf (stderr, " ybase = %d\n", s->ybase);
2443 fprintf (stderr, " hl = %d\n", s->hl);
2444 fprintf (stderr, " left overhang = %d, right = %d\n",
2445 s->left_overhang, s->right_overhang);
2446 fprintf (stderr, " nchars = %d\n", s->nchars);
2447 fprintf (stderr, " extends to end of line = %d\n",
2448 s->extends_to_end_of_line_p);
2449 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2450 fprintf (stderr, " bg width = %d\n", s->background_width);
2451}
2452
2453#endif /* GLYPH_DEBUG */
2454
2455
2456
2457static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2458 struct glyph_string **,
2459 struct glyph_string *,
2460 struct glyph_string *));
2461static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2462 struct glyph_string **,
2463 struct glyph_string *,
2464 struct glyph_string *));
2465static void x_append_glyph_string P_ ((struct glyph_string **,
2466 struct glyph_string **,
2467 struct glyph_string *));
2468static int x_left_overwritten P_ ((struct glyph_string *));
2469static int x_left_overwriting P_ ((struct glyph_string *));
2470static int x_right_overwritten P_ ((struct glyph_string *));
2471static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2472static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2473 int));
06a2c219
GM
2474static void x_init_glyph_string P_ ((struct glyph_string *,
2475 XChar2b *, struct window *,
2476 struct glyph_row *,
2477 enum glyph_row_area, int,
2478 enum draw_glyphs_face));
2479static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2480 enum glyph_row_area, int, int,
66ac4b0e 2481 enum draw_glyphs_face, int *, int *, int));
06a2c219
GM
2482static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2483static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2484static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2485 int));
2486static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2487static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2488static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2489static void x_draw_glyph_string P_ ((struct glyph_string *));
2490static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2491static void x_set_cursor_gc P_ ((struct glyph_string *));
2492static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2493static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2494static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2495 int *, int *));
2496static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2497static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2498 unsigned long *, double, int));
06a2c219 2499static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2500 double, int, unsigned long));
06a2c219
GM
2501static void x_setup_relief_colors P_ ((struct glyph_string *));
2502static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2503static void x_draw_image_relief P_ ((struct glyph_string *));
2504static void x_draw_image_foreground P_ ((struct glyph_string *));
2505static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2506static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2507static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2508 int, int, int));
2509static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2510 int, int, int, int, XRectangle *));
2511static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2512 int, int, int, XRectangle *));
66ac4b0e
GM
2513static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2514 enum glyph_row_area));
06a2c219
GM
2515
2516
06a2c219
GM
2517/* Append the list of glyph strings with head H and tail T to the list
2518 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2519
2520static INLINE void
2521x_append_glyph_string_lists (head, tail, h, t)
2522 struct glyph_string **head, **tail;
2523 struct glyph_string *h, *t;
2524{
2525 if (h)
2526 {
2527 if (*head)
2528 (*tail)->next = h;
2529 else
2530 *head = h;
2531 h->prev = *tail;
2532 *tail = t;
2533 }
2534}
2535
2536
2537/* Prepend the list of glyph strings with head H and tail T to the
2538 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2539 result. */
2540
2541static INLINE void
2542x_prepend_glyph_string_lists (head, tail, h, t)
2543 struct glyph_string **head, **tail;
2544 struct glyph_string *h, *t;
2545{
2546 if (h)
2547 {
2548 if (*head)
2549 (*head)->prev = t;
2550 else
2551 *tail = t;
2552 t->next = *head;
2553 *head = h;
2554 }
2555}
2556
2557
2558/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2559 Set *HEAD and *TAIL to the resulting list. */
2560
2561static INLINE void
2562x_append_glyph_string (head, tail, s)
2563 struct glyph_string **head, **tail;
2564 struct glyph_string *s;
2565{
2566 s->next = s->prev = NULL;
2567 x_append_glyph_string_lists (head, tail, s, s);
2568}
2569
2570
2571/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2572 face. */
2573
2574static void
2575x_set_cursor_gc (s)
2576 struct glyph_string *s;
2577{
2578 if (s->font == FRAME_FONT (s->f)
2579 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2580 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2581 && !s->cmp)
06a2c219
GM
2582 s->gc = s->f->output_data.x->cursor_gc;
2583 else
2584 {
2585 /* Cursor on non-default face: must merge. */
2586 XGCValues xgcv;
2587 unsigned long mask;
2588
2589 xgcv.background = s->f->output_data.x->cursor_pixel;
2590 xgcv.foreground = s->face->background;
2591
2592 /* If the glyph would be invisible, try a different foreground. */
2593 if (xgcv.foreground == xgcv.background)
2594 xgcv.foreground = s->face->foreground;
2595 if (xgcv.foreground == xgcv.background)
2596 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2597 if (xgcv.foreground == xgcv.background)
2598 xgcv.foreground = s->face->foreground;
2599
2600 /* Make sure the cursor is distinct from text in this face. */
2601 if (xgcv.background == s->face->background
2602 && xgcv.foreground == s->face->foreground)
2603 {
2604 xgcv.background = s->face->foreground;
2605 xgcv.foreground = s->face->background;
2606 }
2607
2608 IF_DEBUG (x_check_font (s->f, s->font));
2609 xgcv.font = s->font->fid;
2610 xgcv.graphics_exposures = False;
2611 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2612
2613 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2614 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2615 mask, &xgcv);
2616 else
2617 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2618 = XCreateGC (s->display, s->window, mask, &xgcv);
2619
2620 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2621 }
2622}
2623
2624
2625/* Set up S->gc of glyph string S for drawing text in mouse face. */
2626
2627static void
2628x_set_mouse_face_gc (s)
2629 struct glyph_string *s;
2630{
2631 int face_id;
2632
2633 /* What face has to be used for the mouse face? */
2634 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
2635 face_id = FACE_FOR_CHARSET (s->f, face_id, s->charset);
2636 s->face = FACE_FROM_ID (s->f, face_id);
2637 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2638
2639 /* If font in this face is same as S->font, use it. */
2640 if (s->font == s->face->font)
2641 s->gc = s->face->gc;
2642 else
2643 {
2644 /* Otherwise construct scratch_cursor_gc with values from FACE
2645 but font FONT. */
2646 XGCValues xgcv;
2647 unsigned long mask;
2648
2649 xgcv.background = s->face->background;
2650 xgcv.foreground = s->face->foreground;
2651 IF_DEBUG (x_check_font (s->f, s->font));
2652 xgcv.font = s->font->fid;
2653 xgcv.graphics_exposures = False;
2654 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2655
2656 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2657 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2658 mask, &xgcv);
2659 else
2660 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2661 = XCreateGC (s->display, s->window, mask, &xgcv);
2662
2663 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2664 }
2665
2666 xassert (s->gc != 0);
2667}
2668
2669
2670/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2671 Faces to use in the mode line have already been computed when the
2672 matrix was built, so there isn't much to do, here. */
2673
2674static INLINE void
2675x_set_mode_line_face_gc (s)
2676 struct glyph_string *s;
2677{
2678 s->gc = s->face->gc;
2679 xassert (s->gc != 0);
2680}
2681
2682
2683/* Set S->gc of glyph string S for drawing that glyph string. Set
2684 S->stippled_p to a non-zero value if the face of S has a stipple
2685 pattern. */
2686
2687static INLINE void
2688x_set_glyph_string_gc (s)
2689 struct glyph_string *s;
2690{
2691 if (s->hl == DRAW_NORMAL_TEXT)
2692 {
2693 s->gc = s->face->gc;
2694 s->stippled_p = s->face->stipple != 0;
2695 }
2696 else if (s->hl == DRAW_INVERSE_VIDEO)
2697 {
2698 x_set_mode_line_face_gc (s);
2699 s->stippled_p = s->face->stipple != 0;
2700 }
2701 else if (s->hl == DRAW_CURSOR)
2702 {
2703 x_set_cursor_gc (s);
2704 s->stippled_p = 0;
2705 }
2706 else if (s->hl == DRAW_MOUSE_FACE)
2707 {
2708 x_set_mouse_face_gc (s);
2709 s->stippled_p = s->face->stipple != 0;
2710 }
2711 else if (s->hl == DRAW_IMAGE_RAISED
2712 || s->hl == DRAW_IMAGE_SUNKEN)
2713 {
2714 s->gc = s->face->gc;
2715 s->stippled_p = s->face->stipple != 0;
2716 }
2717 else
2718 {
2719 s->gc = s->face->gc;
2720 s->stippled_p = s->face->stipple != 0;
2721 }
2722
2723 /* GC must have been set. */
2724 xassert (s->gc != 0);
2725}
2726
2727
2728/* Return in *R the clipping rectangle for glyph string S. */
2729
2730static void
2731x_get_glyph_string_clip_rect (s, r)
2732 struct glyph_string *s;
2733 XRectangle *r;
2734{
2735 if (s->row->full_width_p)
2736 {
2737 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2738 int canon_x = CANON_X_UNIT (s->f);
2739
2740 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2741 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2742
2743 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2744 {
1da3fd71 2745 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2746 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2747 r->x -= width;
2748 }
2749
b9432a85 2750 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2751
06a2c219
GM
2752 /* Unless displaying a mode or menu bar line, which are always
2753 fully visible, clip to the visible part of the row. */
2754 if (s->w->pseudo_window_p)
2755 r->height = s->row->visible_height;
2756 else
2757 r->height = s->height;
2758 }
2759 else
2760 {
2761 /* This is a text line that may be partially visible. */
2762 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2763 r->width = window_box_width (s->w, s->area);
2764 r->height = s->row->visible_height;
2765 }
2766
2767 /* Don't use S->y for clipping because it doesn't take partially
2768 visible lines into account. For example, it can be negative for
2769 partially visible lines at the top of a window. */
2770 if (!s->row->full_width_p
2771 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
045dee35 2772 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
06a2c219
GM
2773 else
2774 r->y = max (0, s->row->y);
06a2c219 2775
9ea173e8 2776 /* If drawing a tool-bar window, draw it over the internal border
06a2c219 2777 at the top of the window. */
9ea173e8 2778 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219 2779 r->y -= s->f->output_data.x->internal_border_width;
66ac4b0e
GM
2780
2781 /* If S draws overlapping rows, it's sufficient to use the top and
2782 bottom of the window for clipping because this glyph string
2783 intentionally draws over other lines. */
2784 if (s->for_overlaps_p)
2785 {
045dee35 2786 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2787 r->height = window_text_bottom_y (s->w) - r->y;
2788 }
2789
2790 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2791}
2792
2793
2794/* Set clipping for output of glyph string S. S may be part of a mode
2795 line or menu if we don't have X toolkit support. */
2796
2797static INLINE void
2798x_set_glyph_string_clipping (s)
2799 struct glyph_string *s;
2800{
2801 XRectangle r;
2802 x_get_glyph_string_clip_rect (s, &r);
2803 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2804}
2805
2806
2807/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2808 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2809
2810static INLINE void
2811x_compute_glyph_string_overhangs (s)
2812 struct glyph_string *s;
2813{
b4192550 2814 if (s->cmp == NULL
06a2c219
GM
2815 && s->first_glyph->type == CHAR_GLYPH)
2816 {
2817 XCharStruct cs;
2818 int direction, font_ascent, font_descent;
2819 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2820 &font_ascent, &font_descent, &cs);
2821 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2822 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2823 }
2824}
2825
2826
2827/* Compute overhangs and x-positions for glyph string S and its
2828 predecessors, or successors. X is the starting x-position for S.
2829 BACKWARD_P non-zero means process predecessors. */
2830
2831static void
2832x_compute_overhangs_and_x (s, x, backward_p)
2833 struct glyph_string *s;
2834 int x;
2835 int backward_p;
2836{
2837 if (backward_p)
2838 {
2839 while (s)
2840 {
2841 x_compute_glyph_string_overhangs (s);
2842 x -= s->width;
2843 s->x = x;
2844 s = s->prev;
2845 }
2846 }
2847 else
2848 {
2849 while (s)
2850 {
2851 x_compute_glyph_string_overhangs (s);
2852 s->x = x;
2853 x += s->width;
2854 s = s->next;
2855 }
2856 }
2857}
2858
2859
2860/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2861 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2862 assumed to be zero. */
06a2c219
GM
2863
2864static void
2865x_get_glyph_overhangs (glyph, f, left, right)
2866 struct glyph *glyph;
2867 struct frame *f;
2868 int *left, *right;
2869{
2870 int c;
2871
2872 *left = *right = 0;
2873
b4192550 2874 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2875 {
2876 XFontStruct *font;
2877 struct face *face;
2878 struct font_info *font_info;
2879 XChar2b char2b;
2880
2881 face = x_get_glyph_face_and_encoding (f, glyph, &char2b);
2882 font = face->font;
2883 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
2884 if (font)
2885 {
2886 XCharStruct *pcm = x_per_char_metric (font, &char2b);
2887
2888 if (pcm->rbearing > pcm->width)
2889 *right = pcm->rbearing - pcm->width;
2890 if (pcm->lbearing < 0)
2891 *left = -pcm->lbearing;
2892 }
2893 }
2894}
2895
2896
2897/* Return the index of the first glyph preceding glyph string S that
2898 is overwritten by S because of S's left overhang. Value is -1
2899 if no glyphs are overwritten. */
2900
2901static int
2902x_left_overwritten (s)
2903 struct glyph_string *s;
2904{
2905 int k;
2906
2907 if (s->left_overhang)
2908 {
2909 int x = 0, i;
2910 struct glyph *glyphs = s->row->glyphs[s->area];
2911 int first = s->first_glyph - glyphs;
2912
2913 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2914 x -= glyphs[i].pixel_width;
2915
2916 k = i + 1;
2917 }
2918 else
2919 k = -1;
2920
2921 return k;
2922}
2923
2924
2925/* Return the index of the first glyph preceding glyph string S that
2926 is overwriting S because of its right overhang. Value is -1 if no
2927 glyph in front of S overwrites S. */
2928
2929static int
2930x_left_overwriting (s)
2931 struct glyph_string *s;
2932{
2933 int i, k, x;
2934 struct glyph *glyphs = s->row->glyphs[s->area];
2935 int first = s->first_glyph - glyphs;
2936
2937 k = -1;
2938 x = 0;
2939 for (i = first - 1; i >= 0; --i)
2940 {
2941 int left, right;
2942 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2943 if (x + right > 0)
2944 k = i;
2945 x -= glyphs[i].pixel_width;
2946 }
2947
2948 return k;
2949}
2950
2951
2952/* Return the index of the last glyph following glyph string S that is
2953 not overwritten by S because of S's right overhang. Value is -1 if
2954 no such glyph is found. */
2955
2956static int
2957x_right_overwritten (s)
2958 struct glyph_string *s;
2959{
2960 int k = -1;
2961
2962 if (s->right_overhang)
2963 {
2964 int x = 0, i;
2965 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 2966 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
2967 int end = s->row->used[s->area];
2968
2969 for (i = first; i < end && s->right_overhang > x; ++i)
2970 x += glyphs[i].pixel_width;
2971
2972 k = i;
2973 }
2974
2975 return k;
2976}
2977
2978
2979/* Return the index of the last glyph following glyph string S that
2980 overwrites S because of its left overhang. Value is negative
2981 if no such glyph is found. */
2982
2983static int
2984x_right_overwriting (s)
2985 struct glyph_string *s;
2986{
2987 int i, k, x;
2988 int end = s->row->used[s->area];
2989 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 2990 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
2991
2992 k = -1;
2993 x = 0;
2994 for (i = first; i < end; ++i)
2995 {
2996 int left, right;
2997 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2998 if (x - left < 0)
2999 k = i;
3000 x += glyphs[i].pixel_width;
3001 }
3002
3003 return k;
3004}
3005
3006
3007/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3008
3009static INLINE void
3010x_clear_glyph_string_rect (s, x, y, w, h)
3011 struct glyph_string *s;
3012 int x, y, w, h;
3013{
3014 XGCValues xgcv;
3015 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3016 XSetForeground (s->display, s->gc, xgcv.background);
3017 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3018 XSetForeground (s->display, s->gc, xgcv.foreground);
3019}
3020
3021
3022/* Draw the background of glyph_string S. If S->background_filled_p
3023 is non-zero don't draw it. FORCE_P non-zero means draw the
3024 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3025 when a string preceding S draws into the background of S, or S
3026 contains the first component of a composition. */
06a2c219
GM
3027
3028static void
3029x_draw_glyph_string_background (s, force_p)
3030 struct glyph_string *s;
3031 int force_p;
3032{
3033 /* Nothing to do if background has already been drawn or if it
3034 shouldn't be drawn in the first place. */
3035 if (!s->background_filled_p)
3036 {
b4192550 3037 if (s->stippled_p)
06a2c219
GM
3038 {
3039 /* Fill background with a stipple pattern. */
3040 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3041 XFillRectangle (s->display, s->window, s->gc, s->x,
3042 s->y + s->face->box_line_width,
3043 s->background_width,
3044 s->height - 2 * s->face->box_line_width);
3045 XSetFillStyle (s->display, s->gc, FillSolid);
3046 s->background_filled_p = 1;
3047 }
3048 else if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
3049 || s->font_not_found_p
3050 || s->extends_to_end_of_line_p
06a2c219
GM
3051 || force_p)
3052 {
3053 x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
3054 s->background_width,
3055 s->height - 2 * s->face->box_line_width);
3056 s->background_filled_p = 1;
3057 }
3058 }
3059}
3060
3061
3062/* Draw the foreground of glyph string S. */
3063
3064static void
3065x_draw_glyph_string_foreground (s)
3066 struct glyph_string *s;
3067{
3068 int i, x;
3069
3070 /* If first glyph of S has a left box line, start drawing the text
3071 of S to the right of that box line. */
3072 if (s->face->box != FACE_NO_BOX
3073 && s->first_glyph->left_box_line_p)
3074 x = s->x + s->face->box_line_width;
3075 else
3076 x = s->x;
3077
b4192550
KH
3078 /* Draw characters of S as rectangles if S's font could not be
3079 loaded. */
3080 if (s->font_not_found_p)
06a2c219 3081 {
b4192550 3082 for (i = 0; i < s->nchars; ++i)
06a2c219 3083 {
b4192550
KH
3084 struct glyph *g = s->first_glyph + i;
3085 XDrawRectangle (s->display, s->window,
3086 s->gc, x, s->y, g->pixel_width - 1,
3087 s->height - 1);
3088 x += g->pixel_width;
06a2c219
GM
3089 }
3090 }
3091 else
3092 {
b4192550
KH
3093 char *char1b = (char *) s->char2b;
3094 int boff = s->font_info->baseline_offset;
e2ef8ee6 3095 XChar2b default_char;
06a2c219 3096
b4192550
KH
3097 if (s->font_info->vertical_centering)
3098 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3099
e2ef8ee6
GM
3100 /* If S->font has an invalid default char, X might output some
3101 characters with zero width which is highly undesirable.
3102 Choose another default char in this case, and replace all
3103 occurrences of invalid characters in the string with that
3104 char. */
3105 if (!x_default_char (s->font, &default_char))
3106 for (i = 0; i < s->nchars; ++i)
3107 if (!x_per_char_metric_1 (s->font, s->char2b + i))
3108 s->char2b[i] = default_char;
3109
b4192550
KH
3110 /* If we can use 8-bit functions, condense S->char2b. */
3111 if (!s->two_byte_p)
3112 for (i = 0; i < s->nchars; ++i)
3113 char1b[i] = s->char2b[i].byte2;
3114
3115 /* Draw text with XDrawString if background has already been
3116 filled. Otherwise, use XDrawImageString. (Note that
3117 XDrawImageString is usually faster than XDrawString.) Always
3118 use XDrawImageString when drawing the cursor so that there is
3119 no chance that characters under a box cursor are invisible. */
3120 if (s->for_overlaps_p
3121 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3122 {
3123 /* Draw characters with 16-bit or 8-bit functions. */
3124 if (s->two_byte_p)
3125 XDrawString16 (s->display, s->window, s->gc, x,
3126 s->ybase - boff, s->char2b, s->nchars);
3127 else
3128 XDrawString (s->display, s->window, s->gc, x,
3129 s->ybase - boff, char1b, s->nchars);
3130 }
06a2c219
GM
3131 else
3132 {
b4192550
KH
3133 if (s->two_byte_p)
3134 XDrawImageString16 (s->display, s->window, s->gc, x,
3135 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3136 else
b4192550
KH
3137 XDrawImageString (s->display, s->window, s->gc, x,
3138 s->ybase - boff, char1b, s->nchars);
3139 }
3140 }
3141}
06a2c219 3142
b4192550 3143/* Draw the foreground of composite glyph string S. */
06a2c219 3144
b4192550
KH
3145static void
3146x_draw_composite_glyph_string_foreground (s)
3147 struct glyph_string *s;
3148{
3149 int i, x;
06a2c219 3150
b4192550
KH
3151 /* If first glyph of S has a left box line, start drawing the text
3152 of S to the right of that box line. */
3153 if (s->face->box != FACE_NO_BOX
3154 && s->first_glyph->left_box_line_p)
3155 x = s->x + s->face->box_line_width;
3156 else
3157 x = s->x;
06a2c219 3158
b4192550
KH
3159 /* S is a glyph string for a composition. S->gidx is the index of
3160 the first character drawn for glyphs of this composition.
3161 S->gidx == 0 means we are drawing the very first character of
3162 this composition. */
06a2c219 3163
b4192550
KH
3164 /* Draw a rectangle for the composition if the font for the very
3165 first character of the composition could not be loaded. */
3166 if (s->font_not_found_p)
3167 {
3168 if (s->gidx == 0)
3169 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3170 s->width - 1, s->height - 1);
3171 }
3172 else
3173 {
3174 for (i = 0; i < s->nchars; i++, ++s->gidx)
3175 XDrawString16 (s->display, s->window, s->gc,
3176 x + s->cmp->offsets[s->gidx * 2],
3177 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3178 s->char2b + i, 1);
06a2c219
GM
3179 }
3180}
3181
3182
80c32bcc
GM
3183#ifdef USE_X_TOOLKIT
3184
3185/* Allocate the color COLOR->pixel on the screen and display of
3186 widget WIDGET in colormap CMAP. If an exact match cannot be
3187 allocated, try the nearest color available. Value is non-zero
3188 if successful. This is called from lwlib. */
3189
3190int
3191x_alloc_nearest_color_for_widget (widget, cmap, color)
3192 Widget widget;
3193 Colormap cmap;
3194 XColor *color;
3195{
3196 struct frame *f;
3197 struct x_display_info *dpyinfo;
5c187dee 3198 Lisp_Object tail;
80c32bcc
GM
3199
3200 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3201
3202 /* Find the top-level shell of the widget. Note that this function
3203 can be called when the widget is not yet realized, so XtWindow
3204 (widget) == 0. That's the reason we can't simply use
3205 x_any_window_to_frame. */
3206 while (!XtIsTopLevelShell (widget))
3207 widget = XtParent (widget);
3208
3209 /* Look for a frame with that top-level widget. Allocate the color
3210 on that frame to get the right gamma correction value. */
3211 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3212 if (GC_FRAMEP (XCAR (tail))
3213 && (f = XFRAME (XCAR (tail)),
3214 (f->output_data.nothing != 1
3215 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3216 && f->output_data.x->widget == widget)
3217 return x_alloc_nearest_color (f, cmap, color);
3218
3219 abort ();
3220}
3221
3222#endif /* USE_X_TOOLKIT */
3223
3224
06a2c219
GM
3225/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3226 CMAP. If an exact match can't be allocated, try the nearest color
3227 available. Value is non-zero if successful. Set *COLOR to the
3228 color allocated. */
3229
3230int
80c32bcc
GM
3231x_alloc_nearest_color (f, cmap, color)
3232 struct frame *f;
06a2c219
GM
3233 Colormap cmap;
3234 XColor *color;
3235{
80c32bcc
GM
3236 Display *display = FRAME_X_DISPLAY (f);
3237 Screen *screen = FRAME_X_SCREEN (f);
3238 int rc;
3239
3240 gamma_correct (f, color);
3241 rc = XAllocColor (display, cmap, color);
06a2c219
GM
3242 if (rc == 0)
3243 {
3244 /* If we got to this point, the colormap is full, so we're going
3245 to try to get the next closest color. The algorithm used is
3246 a least-squares matching, which is what X uses for closest
3247 color matching with StaticColor visuals. */
3248 int nearest, i;
3249 unsigned long nearest_delta = ~0;
3250 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3251 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3252
3253 for (i = 0; i < ncells; ++i)
3254 cells[i].pixel = i;
3255 XQueryColors (display, cmap, cells, ncells);
3256
3257 for (nearest = i = 0; i < ncells; ++i)
3258 {
3259 long dred = (color->red >> 8) - (cells[i].red >> 8);
3260 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3261 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3262 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3263
3264 if (delta < nearest_delta)
3265 {
3266 nearest = i;
3267 nearest_delta = delta;
3268 }
3269 }
3270
3271 color->red = cells[nearest].red;
3272 color->green = cells[nearest].green;
3273 color->blue = cells[nearest].blue;
3274 rc = XAllocColor (display, cmap, color);
3275 }
3276
3277 return rc;
3278}
3279
3280
3281/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3282 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3283 If this produces the same color as PIXEL, try a color where all RGB
3284 values have DELTA added. Return the allocated color in *PIXEL.
3285 DISPLAY is the X display, CMAP is the colormap to operate on.
3286 Value is non-zero if successful. */
3287
3288static int
3289x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3290 struct frame *f;
3291 Display *display;
3292 Colormap cmap;
3293 unsigned long *pixel;
68c45bf0 3294 double factor;
06a2c219
GM
3295 int delta;
3296{
3297 XColor color, new;
3298 int success_p;
3299
3300 /* Get RGB color values. */
3301 color.pixel = *pixel;
3302 XQueryColor (display, cmap, &color);
3303
3304 /* Change RGB values by specified FACTOR. Avoid overflow! */
3305 xassert (factor >= 0);
3306 new.red = min (0xffff, factor * color.red);
3307 new.green = min (0xffff, factor * color.green);
3308 new.blue = min (0xffff, factor * color.blue);
3309
3310 /* Try to allocate the color. */
80c32bcc 3311 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3312 if (success_p)
3313 {
3314 if (new.pixel == *pixel)
3315 {
3316 /* If we end up with the same color as before, try adding
3317 delta to the RGB values. */
0d605c67 3318 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3319
3320 new.red = min (0xffff, delta + color.red);
3321 new.green = min (0xffff, delta + color.green);
3322 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3323 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3324 }
3325 else
3326 success_p = 1;
3327 *pixel = new.pixel;
3328 }
3329
3330 return success_p;
3331}
3332
3333
3334/* Set up the foreground color for drawing relief lines of glyph
3335 string S. RELIEF is a pointer to a struct relief containing the GC
3336 with which lines will be drawn. Use a color that is FACTOR or
3337 DELTA lighter or darker than the relief's background which is found
3338 in S->f->output_data.x->relief_background. If such a color cannot
3339 be allocated, use DEFAULT_PIXEL, instead. */
3340
3341static void
3342x_setup_relief_color (f, relief, factor, delta, default_pixel)
3343 struct frame *f;
3344 struct relief *relief;
68c45bf0 3345 double factor;
06a2c219
GM
3346 int delta;
3347 unsigned long default_pixel;
3348{
3349 XGCValues xgcv;
3350 struct x_output *di = f->output_data.x;
3351 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3352 unsigned long pixel;
3353 unsigned long background = di->relief_background;
43bd1b2b 3354 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3355 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3356 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3357
3358 xgcv.graphics_exposures = False;
3359 xgcv.line_width = 1;
3360
3361 /* Free previously allocated color. The color cell will be reused
3362 when it has been freed as many times as it was allocated, so this
3363 doesn't affect faces using the same colors. */
3364 if (relief->gc
3365 && relief->allocated_p)
3366 {
3367 /* If display has an immutable color map, freeing colors is not
3368 necessary and some servers don't allow it. So don't do it. */
0d605c67 3369 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3370 relief->allocated_p = 0;
3371 }
3372
3373 /* Allocate new color. */
3374 xgcv.foreground = default_pixel;
3375 pixel = background;
dcd08bfb
GM
3376 if (dpyinfo->n_planes != 1
3377 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3378 {
3379 relief->allocated_p = 1;
3380 xgcv.foreground = relief->pixel = pixel;
3381 }
3382
3383 if (relief->gc == 0)
3384 {
dcd08bfb 3385 xgcv.stipple = dpyinfo->gray;
06a2c219 3386 mask |= GCStipple;
dcd08bfb 3387 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3388 }
3389 else
dcd08bfb 3390 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3391}
3392
3393
3394/* Set up colors for the relief lines around glyph string S. */
3395
3396static void
3397x_setup_relief_colors (s)
3398 struct glyph_string *s;
3399{
3400 struct x_output *di = s->f->output_data.x;
3401 unsigned long color;
3402
3403 if (s->face->use_box_color_for_shadows_p)
3404 color = s->face->box_color;
3405 else
3406 {
3407 XGCValues xgcv;
3408
3409 /* Get the background color of the face. */
3410 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3411 color = xgcv.background;
3412 }
3413
3414 if (di->white_relief.gc == 0
3415 || color != di->relief_background)
3416 {
3417 di->relief_background = color;
3418 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3419 WHITE_PIX_DEFAULT (s->f));
3420 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3421 BLACK_PIX_DEFAULT (s->f));
3422 }
3423}
3424
3425
3426/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3427 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3428 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3429 relief. LEFT_P non-zero means draw a relief on the left side of
3430 the rectangle. RIGHT_P non-zero means draw a relief on the right
3431 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3432 when drawing. */
3433
3434static void
3435x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3436 raised_p, left_p, right_p, clip_rect)
3437 struct frame *f;
3438 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3439 XRectangle *clip_rect;
3440{
3441 int i;
3442 GC gc;
3443
3444 if (raised_p)
3445 gc = f->output_data.x->white_relief.gc;
3446 else
3447 gc = f->output_data.x->black_relief.gc;
3448 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3449
3450 /* Top. */
3451 for (i = 0; i < width; ++i)
3452 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3453 left_x + i * left_p, top_y + i,
3454 right_x + 1 - i * right_p, top_y + i);
3455
3456 /* Left. */
3457 if (left_p)
3458 for (i = 0; i < width; ++i)
3459 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3460 left_x + i, top_y + i, left_x + i, bottom_y - i);
3461
3462 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3463 if (raised_p)
3464 gc = f->output_data.x->black_relief.gc;
3465 else
3466 gc = f->output_data.x->white_relief.gc;
3467 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3468
3469 /* Bottom. */
3470 for (i = 0; i < width; ++i)
3471 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3472 left_x + i * left_p, bottom_y - i,
3473 right_x + 1 - i * right_p, bottom_y - i);
3474
3475 /* Right. */
3476 if (right_p)
3477 for (i = 0; i < width; ++i)
3478 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3479 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3480
3481 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3482}
3483
3484
3485/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3486 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3487 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3488 left side of the rectangle. RIGHT_P non-zero means draw a line
3489 on the right side of the rectangle. CLIP_RECT is the clipping
3490 rectangle to use when drawing. */
3491
3492static void
3493x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3494 left_p, right_p, clip_rect)
3495 struct glyph_string *s;
3496 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3497 XRectangle *clip_rect;
3498{
3499 XGCValues xgcv;
3500
3501 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3502 XSetForeground (s->display, s->gc, s->face->box_color);
3503 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3504
3505 /* Top. */
3506 XFillRectangle (s->display, s->window, s->gc,
3507 left_x, top_y, right_x - left_x, width);
3508
3509 /* Left. */
3510 if (left_p)
3511 XFillRectangle (s->display, s->window, s->gc,
3512 left_x, top_y, width, bottom_y - top_y);
3513
3514 /* Bottom. */
3515 XFillRectangle (s->display, s->window, s->gc,
3516 left_x, bottom_y - width, right_x - left_x, width);
3517
3518 /* Right. */
3519 if (right_p)
3520 XFillRectangle (s->display, s->window, s->gc,
3521 right_x - width, top_y, width, bottom_y - top_y);
3522
3523 XSetForeground (s->display, s->gc, xgcv.foreground);
3524 XSetClipMask (s->display, s->gc, None);
3525}
3526
3527
3528/* Draw a box around glyph string S. */
3529
3530static void
3531x_draw_glyph_string_box (s)
3532 struct glyph_string *s;
3533{
3534 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3535 int left_p, right_p;
3536 struct glyph *last_glyph;
3537 XRectangle clip_rect;
3538
3539 last_x = window_box_right (s->w, s->area);
3540 if (s->row->full_width_p
3541 && !s->w->pseudo_window_p)
3542 {
110859fc 3543 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3544 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3545 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3546 }
3547
3548 /* The glyph that may have a right box line. */
b4192550 3549 last_glyph = (s->cmp || s->img
06a2c219
GM
3550 ? s->first_glyph
3551 : s->first_glyph + s->nchars - 1);
3552
3553 width = s->face->box_line_width;
3554 raised_p = s->face->box == FACE_RAISED_BOX;
3555 left_x = s->x;
3556 right_x = ((s->row->full_width_p
1da3fd71 3557 ? last_x - 1
a7aeb2de 3558 : min (last_x, s->x + s->background_width) - 1));
06a2c219
GM
3559 top_y = s->y;
3560 bottom_y = top_y + s->height - 1;
3561
3562 left_p = (s->first_glyph->left_box_line_p
3563 || (s->hl == DRAW_MOUSE_FACE
3564 && (s->prev == NULL
3565 || s->prev->hl != s->hl)));
3566 right_p = (last_glyph->right_box_line_p
3567 || (s->hl == DRAW_MOUSE_FACE
3568 && (s->next == NULL
3569 || s->next->hl != s->hl)));
3570
3571 x_get_glyph_string_clip_rect (s, &clip_rect);
3572
3573 if (s->face->box == FACE_SIMPLE_BOX)
3574 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3575 left_p, right_p, &clip_rect);
3576 else
3577 {
3578 x_setup_relief_colors (s);
3579 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3580 width, raised_p, left_p, right_p, &clip_rect);
3581 }
3582}
3583
3584
3585/* Draw foreground of image glyph string S. */
3586
3587static void
3588x_draw_image_foreground (s)
3589 struct glyph_string *s;
3590{
3591 int x;
3592 int y = s->ybase - IMAGE_ASCENT (s->img);
3593
3594 /* If first glyph of S has a left box line, start drawing it to the
3595 right of that line. */
3596 if (s->face->box != FACE_NO_BOX
3597 && s->first_glyph->left_box_line_p)
3598 x = s->x + s->face->box_line_width;
3599 else
3600 x = s->x;
3601
3602 /* If there is a margin around the image, adjust x- and y-position
3603 by that margin. */
3604 if (s->img->margin)
3605 {
3606 x += s->img->margin;
3607 y += s->img->margin;
3608 }
3609
3610 if (s->img->pixmap)
3611 {
3612 if (s->img->mask)
3613 {
3614 /* We can't set both a clip mask and use XSetClipRectangles
3615 because the latter also sets a clip mask. We also can't
3616 trust on the shape extension to be available
3617 (XShapeCombineRegion). So, compute the rectangle to draw
3618 manually. */
3619 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3620 | GCFunction);
3621 XGCValues xgcv;
3622 XRectangle clip_rect, image_rect, r;
3623
3624 xgcv.clip_mask = s->img->mask;
3625 xgcv.clip_x_origin = x;
3626 xgcv.clip_y_origin = y;
3627 xgcv.function = GXcopy;
3628 XChangeGC (s->display, s->gc, mask, &xgcv);
3629
3630 x_get_glyph_string_clip_rect (s, &clip_rect);
3631 image_rect.x = x;
3632 image_rect.y = y;
3633 image_rect.width = s->img->width;
3634 image_rect.height = s->img->height;
3635 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
3636 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3637 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
3638 }
3639 else
3640 {
3641 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3642 0, 0, s->img->width, s->img->height, x, y);
3643
3644 /* When the image has a mask, we can expect that at
3645 least part of a mouse highlight or a block cursor will
3646 be visible. If the image doesn't have a mask, make
3647 a block cursor visible by drawing a rectangle around
3648 the image. I believe it's looking better if we do
3649 nothing here for mouse-face. */
3650 if (s->hl == DRAW_CURSOR)
3651 XDrawRectangle (s->display, s->window, s->gc, x, y,
3652 s->img->width - 1, s->img->height - 1);
3653 }
3654 }
3655 else
3656 /* Draw a rectangle if image could not be loaded. */
3657 XDrawRectangle (s->display, s->window, s->gc, x, y,
3658 s->img->width - 1, s->img->height - 1);
3659}
3660
3661
3662/* Draw a relief around the image glyph string S. */
3663
3664static void
3665x_draw_image_relief (s)
3666 struct glyph_string *s;
3667{
3668 int x0, y0, x1, y1, thick, raised_p;
3669 XRectangle r;
3670 int x;
3671 int y = s->ybase - IMAGE_ASCENT (s->img);
3672
3673 /* If first glyph of S has a left box line, start drawing it to the
3674 right of that line. */
3675 if (s->face->box != FACE_NO_BOX
3676 && s->first_glyph->left_box_line_p)
3677 x = s->x + s->face->box_line_width;
3678 else
3679 x = s->x;
3680
3681 /* If there is a margin around the image, adjust x- and y-position
3682 by that margin. */
3683 if (s->img->margin)
3684 {
3685 x += s->img->margin;
3686 y += s->img->margin;
3687 }
3688
3689 if (s->hl == DRAW_IMAGE_SUNKEN
3690 || s->hl == DRAW_IMAGE_RAISED)
3691 {
9ea173e8 3692 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
3693 raised_p = s->hl == DRAW_IMAGE_RAISED;
3694 }
3695 else
3696 {
3697 thick = abs (s->img->relief);
3698 raised_p = s->img->relief > 0;
3699 }
3700
3701 x0 = x - thick;
3702 y0 = y - thick;
3703 x1 = x + s->img->width + thick - 1;
3704 y1 = y + s->img->height + thick - 1;
3705
3706 x_setup_relief_colors (s);
3707 x_get_glyph_string_clip_rect (s, &r);
3708 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
3709}
3710
3711
3712/* Draw the foreground of image glyph string S to PIXMAP. */
3713
3714static void
3715x_draw_image_foreground_1 (s, pixmap)
3716 struct glyph_string *s;
3717 Pixmap pixmap;
3718{
3719 int x;
3720 int y = s->ybase - s->y - IMAGE_ASCENT (s->img);
3721
3722 /* If first glyph of S has a left box line, start drawing it to the
3723 right of that line. */
3724 if (s->face->box != FACE_NO_BOX
3725 && s->first_glyph->left_box_line_p)
3726 x = s->face->box_line_width;
3727 else
3728 x = 0;
3729
3730 /* If there is a margin around the image, adjust x- and y-position
3731 by that margin. */
3732 if (s->img->margin)
3733 {
3734 x += s->img->margin;
3735 y += s->img->margin;
3736 }
dc43ef94 3737
06a2c219
GM
3738 if (s->img->pixmap)
3739 {
3740 if (s->img->mask)
3741 {
3742 /* We can't set both a clip mask and use XSetClipRectangles
3743 because the latter also sets a clip mask. We also can't
3744 trust on the shape extension to be available
3745 (XShapeCombineRegion). So, compute the rectangle to draw
3746 manually. */
3747 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3748 | GCFunction);
3749 XGCValues xgcv;
3750
3751 xgcv.clip_mask = s->img->mask;
3752 xgcv.clip_x_origin = x;
3753 xgcv.clip_y_origin = y;
3754 xgcv.function = GXcopy;
3755 XChangeGC (s->display, s->gc, mask, &xgcv);
3756
3757 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3758 0, 0, s->img->width, s->img->height, x, y);
3759 XSetClipMask (s->display, s->gc, None);
3760 }
3761 else
3762 {
3763 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3764 0, 0, s->img->width, s->img->height, x, y);
3765
3766 /* When the image has a mask, we can expect that at
3767 least part of a mouse highlight or a block cursor will
3768 be visible. If the image doesn't have a mask, make
3769 a block cursor visible by drawing a rectangle around
3770 the image. I believe it's looking better if we do
3771 nothing here for mouse-face. */
3772 if (s->hl == DRAW_CURSOR)
3773 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3774 s->img->width - 1, s->img->height - 1);
3775 }
3776 }
3777 else
3778 /* Draw a rectangle if image could not be loaded. */
3779 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3780 s->img->width - 1, s->img->height - 1);
3781}
dc43ef94 3782
990ba854 3783
06a2c219
GM
3784/* Draw part of the background of glyph string S. X, Y, W, and H
3785 give the rectangle to draw. */
a9a5b0a5 3786
06a2c219
GM
3787static void
3788x_draw_glyph_string_bg_rect (s, x, y, w, h)
3789 struct glyph_string *s;
3790 int x, y, w, h;
3791{
3792 if (s->stippled_p)
3793 {
3794 /* Fill background with a stipple pattern. */
3795 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3796 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3797 XSetFillStyle (s->display, s->gc, FillSolid);
3798 }
3799 else
3800 x_clear_glyph_string_rect (s, x, y, w, h);
3801}
07e34cb0 3802
b5210ea7 3803
06a2c219 3804/* Draw image glyph string S.
dc43ef94 3805
06a2c219
GM
3806 s->y
3807 s->x +-------------------------
3808 | s->face->box
3809 |
3810 | +-------------------------
3811 | | s->img->margin
3812 | |
3813 | | +-------------------
3814 | | | the image
dc43ef94 3815
06a2c219 3816 */
dc43ef94 3817
06a2c219
GM
3818static void
3819x_draw_image_glyph_string (s)
3820 struct glyph_string *s;
3821{
3822 int x, y;
3823 int box_line_width = s->face->box_line_width;
3824 int margin = s->img->margin;
3825 int height;
3826 Pixmap pixmap = None;
3827
3828 height = s->height - 2 * box_line_width;
3829
3830 /* Fill background with face under the image. Do it only if row is
3831 taller than image or if image has a clip mask to reduce
3832 flickering. */
3833 s->stippled_p = s->face->stipple != 0;
3834 if (height > s->img->height
3835 || margin
3836 || s->img->mask
3837 || s->img->pixmap == 0
3838 || s->width != s->background_width)
3839 {
3840 if (box_line_width && s->first_glyph->left_box_line_p)
3841 x = s->x + box_line_width;
3842 else
3843 x = s->x;
3844
3845 y = s->y + box_line_width;
3846
3847 if (s->img->mask)
3848 {
3849 /* Create a pixmap as large as the glyph string Fill it with
3850 the background color. Copy the image to it, using its
3851 mask. Copy the temporary pixmap to the display. */
3852 Screen *screen = FRAME_X_SCREEN (s->f);
3853 int depth = DefaultDepthOfScreen (screen);
3854
3855 /* Create a pixmap as large as the glyph string. */
3856 pixmap = XCreatePixmap (s->display, s->window,
3857 s->background_width,
3858 s->height, depth);
3859
3860 /* Don't clip in the following because we're working on the
3861 pixmap. */
3862 XSetClipMask (s->display, s->gc, None);
3863
3864 /* Fill the pixmap with the background color/stipple. */
3865 if (s->stippled_p)
3866 {
3867 /* Fill background with a stipple pattern. */
3868 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3869 XFillRectangle (s->display, pixmap, s->gc,
3870 0, 0, s->background_width, s->height);
3871 XSetFillStyle (s->display, s->gc, FillSolid);
3872 }
3873 else
3874 {
3875 XGCValues xgcv;
3876 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
3877 &xgcv);
3878 XSetForeground (s->display, s->gc, xgcv.background);
3879 XFillRectangle (s->display, pixmap, s->gc,
3880 0, 0, s->background_width, s->height);
3881 XSetForeground (s->display, s->gc, xgcv.foreground);
3882 }
3883 }
3884 else
3885 /* Implementation idea: Is it possible to construct a mask?
3886 We could look at the color at the margins of the image, and
3887 say that this color is probably the background color of the
3888 image. */
3889 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3890
3891 s->background_filled_p = 1;
3892 }
dc43ef94 3893
06a2c219
GM
3894 /* Draw the foreground. */
3895 if (pixmap != None)
3896 {
3897 x_draw_image_foreground_1 (s, pixmap);
3898 x_set_glyph_string_clipping (s);
3899 XCopyArea (s->display, pixmap, s->window, s->gc,
3900 0, 0, s->background_width, s->height, s->x, s->y);
3901 XFreePixmap (s->display, pixmap);
3902 }
3903 else
3904 x_draw_image_foreground (s);
b5210ea7 3905
06a2c219
GM
3906 /* If we must draw a relief around the image, do it. */
3907 if (s->img->relief
3908 || s->hl == DRAW_IMAGE_RAISED
3909 || s->hl == DRAW_IMAGE_SUNKEN)
3910 x_draw_image_relief (s);
3911}
8c1a6a84 3912
990ba854 3913
06a2c219 3914/* Draw stretch glyph string S. */
dc43ef94 3915
06a2c219
GM
3916static void
3917x_draw_stretch_glyph_string (s)
3918 struct glyph_string *s;
3919{
3920 xassert (s->first_glyph->type == STRETCH_GLYPH);
3921 s->stippled_p = s->face->stipple != 0;
990ba854 3922
06a2c219
GM
3923 if (s->hl == DRAW_CURSOR
3924 && !x_stretch_cursor_p)
3925 {
3926 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3927 as wide as the stretch glyph. */
3928 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 3929
06a2c219
GM
3930 /* Draw cursor. */
3931 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 3932
06a2c219
GM
3933 /* Clear rest using the GC of the original non-cursor face. */
3934 if (width < s->background_width)
3935 {
3936 GC gc = s->face->gc;
3937 int x = s->x + width, y = s->y;
3938 int w = s->background_width - width, h = s->height;
3939 XRectangle r;
dc43ef94 3940
06a2c219
GM
3941 x_get_glyph_string_clip_rect (s, &r);
3942 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
97210f4e 3943
06a2c219
GM
3944 if (s->face->stipple)
3945 {
3946 /* Fill background with a stipple pattern. */
3947 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3948 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3949 XSetFillStyle (s->display, gc, FillSolid);
3950 }
3951 else
3952 {
3953 XGCValues xgcv;
3954 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
3955 XSetForeground (s->display, gc, xgcv.background);
3956 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3957 XSetForeground (s->display, gc, xgcv.foreground);
3958 }
3959 }
3960 }
3961 else
3962 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
3963 s->height);
3964
3965 s->background_filled_p = 1;
3966}
3967
3968
3969/* Draw glyph string S. */
3970
3971static void
3972x_draw_glyph_string (s)
3973 struct glyph_string *s;
3974{
3975 /* If S draws into the background of its successor, draw the
3976 background of the successor first so that S can draw into it.
3977 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 3978 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
3979 {
3980 xassert (s->next->img == NULL);
3981 x_set_glyph_string_gc (s->next);
3982 x_set_glyph_string_clipping (s->next);
3983 x_draw_glyph_string_background (s->next, 1);
3984 }
97210f4e 3985
06a2c219
GM
3986 /* Set up S->gc, set clipping and draw S. */
3987 x_set_glyph_string_gc (s);
3988 x_set_glyph_string_clipping (s);
3989
3990 switch (s->first_glyph->type)
3991 {
3992 case IMAGE_GLYPH:
3993 x_draw_image_glyph_string (s);
3994 break;
3995
3996 case STRETCH_GLYPH:
3997 x_draw_stretch_glyph_string (s);
3998 break;
3999
4000 case CHAR_GLYPH:
66ac4b0e
GM
4001 if (s->for_overlaps_p)
4002 s->background_filled_p = 1;
4003 else
4004 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4005 x_draw_glyph_string_foreground (s);
4006 break;
4007
b4192550
KH
4008 case COMPOSITE_GLYPH:
4009 if (s->for_overlaps_p || s->gidx > 0)
4010 s->background_filled_p = 1;
4011 else
4012 x_draw_glyph_string_background (s, 1);
4013 x_draw_composite_glyph_string_foreground (s);
4014 break;
4015
06a2c219
GM
4016 default:
4017 abort ();
4018 }
4019
66ac4b0e 4020 if (!s->for_overlaps_p)
06a2c219 4021 {
66ac4b0e
GM
4022 /* Draw underline. */
4023 if (s->face->underline_p)
4024 {
4025 unsigned long dy, h;
06a2c219 4026
66ac4b0e
GM
4027 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4028 h = 1;
4029 if (!XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &dy))
4030 dy = s->height - h;
06a2c219 4031
66ac4b0e
GM
4032 if (s->face->underline_defaulted_p)
4033 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4034 s->width, h);
4035 else
4036 {
4037 XGCValues xgcv;
4038 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4039 XSetForeground (s->display, s->gc, s->face->underline_color);
4040 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4041 s->width, h);
4042 XSetForeground (s->display, s->gc, xgcv.foreground);
4043 }
dc6f92b8 4044 }
07e34cb0 4045
66ac4b0e
GM
4046 /* Draw overline. */
4047 if (s->face->overline_p)
06a2c219 4048 {
66ac4b0e
GM
4049 unsigned long dy = 0, h = 1;
4050
4051 if (s->face->overline_color_defaulted_p)
4052 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4053 s->width, h);
4054 else
4055 {
4056 XGCValues xgcv;
4057 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4058 XSetForeground (s->display, s->gc, s->face->overline_color);
4059 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4060 s->width, h);
4061 XSetForeground (s->display, s->gc, xgcv.foreground);
4062 }
06a2c219 4063 }
06a2c219 4064
66ac4b0e
GM
4065 /* Draw strike-through. */
4066 if (s->face->strike_through_p)
06a2c219 4067 {
66ac4b0e
GM
4068 unsigned long h = 1;
4069 unsigned long dy = (s->height - h) / 2;
4070
4071 if (s->face->strike_through_color_defaulted_p)
4072 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4073 s->width, h);
4074 else
4075 {
4076 XGCValues xgcv;
4077 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4078 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4079 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4080 s->width, h);
4081 XSetForeground (s->display, s->gc, xgcv.foreground);
4082 }
06a2c219 4083 }
06a2c219 4084
66ac4b0e
GM
4085 /* Draw relief. */
4086 if (s->face->box != FACE_NO_BOX)
4087 x_draw_glyph_string_box (s);
4088 }
06a2c219
GM
4089
4090 /* Reset clipping. */
4091 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4092}
07e34cb0 4093
06a2c219 4094
b4192550
KH
4095static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4096 struct face **, int));
06a2c219 4097
06a2c219 4098
b4192550
KH
4099/* Load glyph string S with a composition components specified by S->cmp.
4100 FACES is an array of faces for all components of this composition.
4101 S->gidx is the index of the first component for S.
4102 OVERLAPS_P non-zero means S should draw the foreground only, and
4103 use its lines physical height for clipping.
06a2c219 4104
b4192550 4105 Value is the index of a component not in S. */
07e34cb0 4106
b4192550
KH
4107static int
4108x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4109 struct glyph_string *s;
b4192550 4110 struct face **faces;
66ac4b0e 4111 int overlaps_p;
07e34cb0 4112{
b4192550 4113 int i;
06a2c219 4114
b4192550 4115 xassert (s);
06a2c219 4116
b4192550 4117 s->for_overlaps_p = overlaps_p;
06a2c219 4118
b4192550
KH
4119 s->face = faces[s->gidx];
4120 s->font = s->face->font;
4121 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4122
b4192550
KH
4123 /* For all glyphs of this composition, starting at the offset
4124 S->gidx, until we reach the end of the definition or encounter a
4125 glyph that requires the different face, add it to S. */
4126 ++s->nchars;
4127 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4128 ++s->nchars;
06a2c219 4129
b4192550
KH
4130 /* All glyph strings for the same composition has the same width,
4131 i.e. the width set for the first component of the composition. */
06a2c219 4132
06a2c219
GM
4133 s->width = s->first_glyph->pixel_width;
4134
4135 /* If the specified font could not be loaded, use the frame's
4136 default font, but record the fact that we couldn't load it in
4137 the glyph string so that we can draw rectangles for the
4138 characters of the glyph string. */
4139 if (s->font == NULL)
4140 {
4141 s->font_not_found_p = 1;
4142 s->font = FRAME_FONT (s->f);
4143 }
4144
4145 /* Adjust base line for subscript/superscript text. */
4146 s->ybase += s->first_glyph->voffset;
4147
4148 xassert (s->face && s->face->gc);
4149
4150 /* This glyph string must always be drawn with 16-bit functions. */
4151 s->two_byte_p = 1;
b4192550
KH
4152
4153 return s->gidx + s->nchars;
06a2c219
GM
4154}
4155
4156
b4192550 4157/* Load glyph string S with a sequence characters.
06a2c219 4158 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4159 first glyph to consider, END is the index of the last + 1.
4160 OVERLAPS_P non-zero means S should draw the foreground only, and
4161 use its lines physical height for clipping.
4162
4163 Value is the index of the first glyph not in S. */
06a2c219
GM
4164
4165static int
66ac4b0e 4166x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4167 struct glyph_string *s;
4168 int face_id;
66ac4b0e 4169 int start, end, overlaps_p;
06a2c219
GM
4170{
4171 struct glyph *glyph, *last;
4172 int voffset;
4173
06a2c219
GM
4174 xassert (s->f == XFRAME (s->w->frame));
4175 xassert (s->nchars == 0);
4176 xassert (start >= 0 && end > start);
4177
66ac4b0e 4178 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4179 glyph = s->row->glyphs[s->area] + start;
4180 last = s->row->glyphs[s->area] + end;
4181 voffset = glyph->voffset;
4182
4183 while (glyph < last
4184 && glyph->type == CHAR_GLYPH
4185 && glyph->voffset == voffset
4186 /* Same face id implies same charset, nowadays. */
43d120d8 4187 && glyph->face_id == face_id)
06a2c219
GM
4188 {
4189 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
4190 s->char2b + s->nchars);
4191 if (s->char2b[s->nchars].byte2 != 0)
4192 s->two_byte_p = 1;
4193
4194 ++s->nchars;
4195 xassert (s->nchars <= end - start);
4196 s->width += glyph->pixel_width;
4197 ++glyph;
4198 }
4199
4200 s->font = s->face->font;
4201 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4202
4203 /* If the specified font could not be loaded, use the frame's font,
4204 but record the fact that we couldn't load it in
4205 S->font_not_found_p so that we can draw rectangles for the
4206 characters of the glyph string. */
4207 if (s->font == NULL)
4208 {
4209 s->font_not_found_p = 1;
4210 s->font = FRAME_FONT (s->f);
4211 }
4212
4213 /* Adjust base line for subscript/superscript text. */
4214 s->ybase += voffset;
66ac4b0e 4215
06a2c219
GM
4216 xassert (s->face && s->face->gc);
4217 return glyph - s->row->glyphs[s->area];
07e34cb0 4218}
dc6f92b8 4219
06a2c219
GM
4220
4221/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4222
dfcf069d 4223static void
06a2c219
GM
4224x_fill_image_glyph_string (s)
4225 struct glyph_string *s;
4226{
4227 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4228 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4229 xassert (s->img);
43d120d8 4230 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4231 s->font = s->face->font;
4232 s->width = s->first_glyph->pixel_width;
4233
4234 /* Adjust base line for subscript/superscript text. */
4235 s->ybase += s->first_glyph->voffset;
4236}
4237
4238
4239/* Fill glyph string S from stretch glyph S->first_glyph. */
4240
4241static void
4242x_fill_stretch_glyph_string (s)
4243 struct glyph_string *s;
4244{
4245 xassert (s->first_glyph->type == STRETCH_GLYPH);
43d120d8 4246 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4247 s->font = s->face->font;
4248 s->width = s->first_glyph->pixel_width;
4249
4250 /* Adjust base line for subscript/superscript text. */
4251 s->ybase += s->first_glyph->voffset;
4252}
4253
4254
4255/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4256 of XChar2b structures for S; it can't be allocated in
4257 x_init_glyph_string because it must be allocated via `alloca'. W
4258 is the window on which S is drawn. ROW and AREA are the glyph row
4259 and area within the row from which S is constructed. START is the
4260 index of the first glyph structure covered by S. HL is a
4261 face-override for drawing S. */
4262
4263static void
4264x_init_glyph_string (s, char2b, w, row, area, start, hl)
4265 struct glyph_string *s;
4266 XChar2b *char2b;
4267 struct window *w;
4268 struct glyph_row *row;
4269 enum glyph_row_area area;
4270 int start;
4271 enum draw_glyphs_face hl;
4272{
4273 bzero (s, sizeof *s);
4274 s->w = w;
4275 s->f = XFRAME (w->frame);
4276 s->display = FRAME_X_DISPLAY (s->f);
4277 s->window = FRAME_X_WINDOW (s->f);
4278 s->char2b = char2b;
4279 s->hl = hl;
4280 s->row = row;
4281 s->area = area;
4282 s->first_glyph = row->glyphs[area] + start;
4283 s->height = row->height;
4284 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4285
9ea173e8
GM
4286 /* Display the internal border below the tool-bar window. */
4287 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4288 s->y -= s->f->output_data.x->internal_border_width;
4289
4290 s->ybase = s->y + row->ascent;
4291}
4292
4293
4294/* Set background width of glyph string S. START is the index of the
4295 first glyph following S. LAST_X is the right-most x-position + 1
4296 in the drawing area. */
4297
4298static INLINE void
4299x_set_glyph_string_background_width (s, start, last_x)
4300 struct glyph_string *s;
4301 int start;
4302 int last_x;
4303{
4304 /* If the face of this glyph string has to be drawn to the end of
4305 the drawing area, set S->extends_to_end_of_line_p. */
4306 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4307
4308 if (start == s->row->used[s->area]
4309 && s->hl == DRAW_NORMAL_TEXT
4310 && ((s->area == TEXT_AREA && s->row->fill_line_p)
4311 || s->face->background != default_face->background
4312 || s->face->stipple != default_face->stipple))
4313 s->extends_to_end_of_line_p = 1;
4314
4315 /* If S extends its face to the end of the line, set its
4316 background_width to the distance to the right edge of the drawing
4317 area. */
4318 if (s->extends_to_end_of_line_p)
1da3fd71 4319 s->background_width = last_x - s->x + 1;
06a2c219
GM
4320 else
4321 s->background_width = s->width;
4322}
4323
4324
4325/* Add a glyph string for a stretch glyph to the list of strings
4326 between HEAD and TAIL. START is the index of the stretch glyph in
4327 row area AREA of glyph row ROW. END is the index of the last glyph
4328 in that glyph row area. X is the current output position assigned
4329 to the new glyph string constructed. HL overrides that face of the
4330 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4331 is the right-most x-position of the drawing area. */
4332
8abee2e1
DL
4333/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4334 and below -- keep them on one line. */
4335#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4336 do \
4337 { \
4338 s = (struct glyph_string *) alloca (sizeof *s); \
4339 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4340 x_fill_stretch_glyph_string (s); \
4341 x_append_glyph_string (&HEAD, &TAIL, s); \
4342 ++START; \
4343 s->x = (X); \
4344 } \
4345 while (0)
4346
4347
4348/* Add a glyph string for an image glyph to the list of strings
4349 between HEAD and TAIL. START is the index of the image glyph in
4350 row area AREA of glyph row ROW. END is the index of the last glyph
4351 in that glyph row area. X is the current output position assigned
4352 to the new glyph string constructed. HL overrides that face of the
4353 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4354 is the right-most x-position of the drawing area. */
4355
8abee2e1 4356#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4357 do \
4358 { \
4359 s = (struct glyph_string *) alloca (sizeof *s); \
4360 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4361 x_fill_image_glyph_string (s); \
4362 x_append_glyph_string (&HEAD, &TAIL, s); \
4363 ++START; \
4364 s->x = (X); \
4365 } \
4366 while (0)
4367
4368
4369/* Add a glyph string for a sequence of character glyphs to the list
4370 of strings between HEAD and TAIL. START is the index of the first
4371 glyph in row area AREA of glyph row ROW that is part of the new
4372 glyph string. END is the index of the last glyph in that glyph row
4373 area. X is the current output position assigned to the new glyph
4374 string constructed. HL overrides that face of the glyph; e.g. it
4375 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4376 right-most x-position of the drawing area. */
4377
8abee2e1 4378#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4379 do \
4380 { \
4381 int c, charset, face_id; \
4382 XChar2b *char2b; \
4383 \
43d120d8 4384 c = (ROW)->glyphs[AREA][START].u.ch; \
06a2c219 4385 charset = CHAR_CHARSET (c); \
43d120d8 4386 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4387 \
b4192550
KH
4388 s = (struct glyph_string *) alloca (sizeof *s); \
4389 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4390 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4391 x_append_glyph_string (&HEAD, &TAIL, s); \
4392 s->charset = charset; \
4393 s->x = (X); \
4394 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4395 OVERLAPS_P); \
06a2c219
GM
4396 } \
4397 while (0)
4398
4399
b4192550
KH
4400/* Add a glyph string for a composite sequence to the list of strings
4401 between HEAD and TAIL. START is the index of the first glyph in
4402 row area AREA of glyph row ROW that is part of the new glyph
4403 string. END is the index of the last glyph in that glyph row area.
4404 X is the current output position assigned to the new glyph string
4405 constructed. HL overrides that face of the glyph; e.g. it is
4406 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4407 x-position of the drawing area. */
4408
6c27ec25 4409#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4410 do { \
43d120d8
KH
4411 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4412 int face_id = (ROW)->glyphs[AREA][START].face_id; \
b4192550
KH
4413 struct composition *cmp = composition_table[cmp_id]; \
4414 int glyph_len = cmp->glyph_len; \
4415 XChar2b *char2b; \
4416 struct face **faces; \
4417 struct glyph_string *first_s = NULL; \
4418 int n; \
4419 \
4420 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4421 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4422 /* At first, fill in `char2b' and `faces'. */ \
4423 for (n = 0; n < glyph_len; n++) \
4424 { \
43d120d8 4425 int c = COMPOSITION_GLYPH (cmp, n); \
b4192550
KH
4426 faces[n] = x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4427 face_id, char2b + n, 1); \
4428 } \
4429 \
4430 /* Make glyph_strings for each glyph sequence that is drawable by \
4431 the same face, and append them to HEAD/TAIL. */ \
4432 for (n = 0; n < cmp->glyph_len;) \
4433 { \
4434 s = (struct glyph_string *) alloca (sizeof *s); \
4435 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4436 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4437 s->cmp = cmp; \
4438 s->gidx = n; \
4439 s->charset = 0; \
4440 s->x = (X); \
4441 \
4442 if (n == 0) \
4443 first_s = s; \
4444 \
4445 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4446 } \
4447 \
4448 ++START; \
4449 s = first_s; \
4450 } while (0)
4451
4452
06a2c219
GM
4453/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4454 of AREA of glyph row ROW on window W between indices START and END.
4455 HL overrides the face for drawing glyph strings, e.g. it is
4456 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4457 x-positions of the drawing area.
4458
4459 This is an ugly monster macro construct because we must use alloca
4460 to allocate glyph strings (because x_draw_glyphs can be called
4461 asynchronously). */
4462
8abee2e1 4463#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4464 do \
4465 { \
4466 HEAD = TAIL = NULL; \
4467 while (START < END) \
4468 { \
4469 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4470 switch (first_glyph->type) \
4471 { \
4472 case CHAR_GLYPH: \
4473 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4474 TAIL, HL, X, LAST_X, \
4475 OVERLAPS_P); \
06a2c219
GM
4476 break; \
4477 \
b4192550
KH
4478 case COMPOSITE_GLYPH: \
4479 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
4480 HEAD, TAIL, HL, X, LAST_X,\
4481 OVERLAPS_P); \
4482 break; \
4483 \
06a2c219
GM
4484 case STRETCH_GLYPH: \
4485 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
4486 HEAD, TAIL, HL, X, LAST_X); \
4487 break; \
4488 \
4489 case IMAGE_GLYPH: \
4490 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
4491 TAIL, HL, X, LAST_X); \
4492 break; \
4493 \
4494 default: \
4495 abort (); \
4496 } \
4497 \
4498 x_set_glyph_string_background_width (s, START, LAST_X); \
4499 (X) += s->width; \
4500 } \
4501 } \
4502 while (0)
4503
4504
4505/* Draw glyphs between START and END in AREA of ROW on window W,
4506 starting at x-position X. X is relative to AREA in W. HL is a
4507 face-override with the following meaning:
4508
4509 DRAW_NORMAL_TEXT draw normally
4510 DRAW_CURSOR draw in cursor face
4511 DRAW_MOUSE_FACE draw in mouse face.
4512 DRAW_INVERSE_VIDEO draw in mode line face
4513 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
4514 DRAW_IMAGE_RAISED draw an image with a raised relief around it
4515
4516 If REAL_START is non-null, return in *REAL_START the real starting
4517 position for display. This can be different from START in case
4518 overlapping glyphs must be displayed. If REAL_END is non-null,
4519 return in *REAL_END the real end position for display. This can be
4520 different from END in case overlapping glyphs must be displayed.
4521
66ac4b0e
GM
4522 If OVERLAPS_P is non-zero, draw only the foreground of characters
4523 and clip to the physical height of ROW.
4524
06a2c219
GM
4525 Value is the x-position reached, relative to AREA of W. */
4526
4527static int
66ac4b0e
GM
4528x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
4529 overlaps_p)
06a2c219
GM
4530 struct window *w;
4531 int x;
4532 struct glyph_row *row;
4533 enum glyph_row_area area;
4534 int start, end;
4535 enum draw_glyphs_face hl;
4536 int *real_start, *real_end;
66ac4b0e 4537 int overlaps_p;
dc6f92b8 4538{
06a2c219
GM
4539 struct glyph_string *head, *tail;
4540 struct glyph_string *s;
4541 int last_x, area_width;
4542 int x_reached;
4543 int i, j;
4544
4545 /* Let's rather be paranoid than getting a SEGV. */
4546 start = max (0, start);
4547 end = min (end, row->used[area]);
4548 if (real_start)
4549 *real_start = start;
4550 if (real_end)
4551 *real_end = end;
4552
4553 /* Translate X to frame coordinates. Set last_x to the right
4554 end of the drawing area. */
4555 if (row->full_width_p)
4556 {
4557 /* X is relative to the left edge of W, without scroll bars
4558 or flag areas. */
4559 struct frame *f = XFRAME (w->frame);
110859fc 4560 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 4561 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 4562
06a2c219
GM
4563 x += window_left_x;
4564 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
4565 last_x = window_left_x + area_width;
4566
4567 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4568 {
110859fc 4569 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
4570 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
4571 last_x += width;
4572 else
4573 x -= width;
4574 }
dc6f92b8 4575
b9432a85
GM
4576 x += FRAME_INTERNAL_BORDER_WIDTH (f);
4577 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
4578 }
4579 else
dc6f92b8 4580 {
06a2c219
GM
4581 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
4582 area_width = window_box_width (w, area);
4583 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
4584 }
4585
06a2c219
GM
4586 /* Build a doubly-linked list of glyph_string structures between
4587 head and tail from what we have to draw. Note that the macro
4588 BUILD_GLYPH_STRINGS will modify its start parameter. That's
4589 the reason we use a separate variable `i'. */
4590 i = start;
66ac4b0e
GM
4591 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
4592 overlaps_p);
06a2c219
GM
4593 if (tail)
4594 x_reached = tail->x + tail->background_width;
4595 else
4596 x_reached = x;
90e65f07 4597
06a2c219
GM
4598 /* If there are any glyphs with lbearing < 0 or rbearing > width in
4599 the row, redraw some glyphs in front or following the glyph
4600 strings built above. */
66ac4b0e 4601 if (!overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
4602 {
4603 int dummy_x = 0;
4604 struct glyph_string *h, *t;
4605
4606 /* Compute overhangs for all glyph strings. */
4607 for (s = head; s; s = s->next)
4608 x_compute_glyph_string_overhangs (s);
4609
4610 /* Prepend glyph strings for glyphs in front of the first glyph
4611 string that are overwritten because of the first glyph
4612 string's left overhang. The background of all strings
4613 prepended must be drawn because the first glyph string
4614 draws over it. */
4615 i = x_left_overwritten (head);
4616 if (i >= 0)
4617 {
4618 j = i;
4619 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
4620 DRAW_NORMAL_TEXT, dummy_x, last_x,
4621 overlaps_p);
06a2c219
GM
4622 start = i;
4623 if (real_start)
4624 *real_start = start;
4625 x_compute_overhangs_and_x (t, head->x, 1);
4626 x_prepend_glyph_string_lists (&head, &tail, h, t);
4627 }
58769bee 4628
06a2c219
GM
4629 /* Prepend glyph strings for glyphs in front of the first glyph
4630 string that overwrite that glyph string because of their
4631 right overhang. For these strings, only the foreground must
4632 be drawn, because it draws over the glyph string at `head'.
4633 The background must not be drawn because this would overwrite
4634 right overhangs of preceding glyphs for which no glyph
4635 strings exist. */
4636 i = x_left_overwriting (head);
4637 if (i >= 0)
4638 {
4639 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
4640 DRAW_NORMAL_TEXT, dummy_x, last_x,
4641 overlaps_p);
06a2c219
GM
4642 for (s = h; s; s = s->next)
4643 s->background_filled_p = 1;
4644 if (real_start)
4645 *real_start = i;
4646 x_compute_overhangs_and_x (t, head->x, 1);
4647 x_prepend_glyph_string_lists (&head, &tail, h, t);
4648 }
dbcb258a 4649
06a2c219
GM
4650 /* Append glyphs strings for glyphs following the last glyph
4651 string tail that are overwritten by tail. The background of
4652 these strings has to be drawn because tail's foreground draws
4653 over it. */
4654 i = x_right_overwritten (tail);
4655 if (i >= 0)
4656 {
4657 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4658 DRAW_NORMAL_TEXT, x, last_x,
4659 overlaps_p);
06a2c219
GM
4660 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4661 x_append_glyph_string_lists (&head, &tail, h, t);
4662 if (real_end)
4663 *real_end = i;
4664 }
dc6f92b8 4665
06a2c219
GM
4666 /* Append glyph strings for glyphs following the last glyph
4667 string tail that overwrite tail. The foreground of such
4668 glyphs has to be drawn because it writes into the background
4669 of tail. The background must not be drawn because it could
4670 paint over the foreground of following glyphs. */
4671 i = x_right_overwriting (tail);
4672 if (i >= 0)
4673 {
4674 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4675 DRAW_NORMAL_TEXT, x, last_x,
4676 overlaps_p);
06a2c219
GM
4677 for (s = h; s; s = s->next)
4678 s->background_filled_p = 1;
4679 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4680 x_append_glyph_string_lists (&head, &tail, h, t);
4681 if (real_end)
4682 *real_end = i;
4683 }
4684 }
58769bee 4685
06a2c219
GM
4686 /* Draw all strings. */
4687 for (s = head; s; s = s->next)
4688 x_draw_glyph_string (s);
dc6f92b8 4689
06a2c219
GM
4690 /* Value is the x-position up to which drawn, relative to AREA of W.
4691 This doesn't include parts drawn because of overhangs. */
4692 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
4693 if (!row->full_width_p)
4694 {
4695 if (area > LEFT_MARGIN_AREA)
4696 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
4697 if (area > TEXT_AREA)
4698 x_reached -= window_box_width (w, TEXT_AREA);
4699 }
4700 return x_reached;
4701}
dc6f92b8 4702
dc6f92b8 4703
66ac4b0e
GM
4704/* Fix the display of area AREA of overlapping row ROW in window W. */
4705
4706static void
4707x_fix_overlapping_area (w, row, area)
4708 struct window *w;
4709 struct glyph_row *row;
4710 enum glyph_row_area area;
4711{
4712 int i, x;
4713
4714 BLOCK_INPUT;
4715
4716 if (area == LEFT_MARGIN_AREA)
4717 x = 0;
4718 else if (area == TEXT_AREA)
4719 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
4720 else
4721 x = (window_box_width (w, LEFT_MARGIN_AREA)
4722 + window_box_width (w, TEXT_AREA));
4723
4724 for (i = 0; i < row->used[area];)
4725 {
4726 if (row->glyphs[area][i].overlaps_vertically_p)
4727 {
4728 int start = i, start_x = x;
4729
4730 do
4731 {
4732 x += row->glyphs[area][i].pixel_width;
4733 ++i;
4734 }
4735 while (i < row->used[area]
4736 && row->glyphs[area][i].overlaps_vertically_p);
4737
4738 x_draw_glyphs (w, start_x, row, area, start, i,
4739 (row->inverse_p
4740 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
4741 NULL, NULL, 1);
4742 }
4743 else
4744 {
4745 x += row->glyphs[area][i].pixel_width;
4746 ++i;
4747 }
4748 }
4749
4750 UNBLOCK_INPUT;
4751}
4752
4753
06a2c219
GM
4754/* Output LEN glyphs starting at START at the nominal cursor position.
4755 Advance the nominal cursor over the text. The global variable
4756 updated_window contains the window being updated, updated_row is
4757 the glyph row being updated, and updated_area is the area of that
4758 row being updated. */
dc6f92b8 4759
06a2c219
GM
4760static void
4761x_write_glyphs (start, len)
4762 struct glyph *start;
4763 int len;
4764{
4765 int x, hpos, real_start, real_end;
d9cdbb3d 4766
06a2c219 4767 xassert (updated_window && updated_row);
dc6f92b8 4768 BLOCK_INPUT;
06a2c219
GM
4769
4770 /* Write glyphs. */
dc6f92b8 4771
06a2c219
GM
4772 hpos = start - updated_row->glyphs[updated_area];
4773 x = x_draw_glyphs (updated_window, output_cursor.x,
4774 updated_row, updated_area,
4775 hpos, hpos + len,
4776 (updated_row->inverse_p
4777 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
66ac4b0e 4778 &real_start, &real_end, 0);
b30ec466 4779
06a2c219
GM
4780 /* If we drew over the cursor, note that it is not visible any more. */
4781 note_overwritten_text_cursor (updated_window, real_start,
4782 real_end - real_start);
dc6f92b8
JB
4783
4784 UNBLOCK_INPUT;
06a2c219
GM
4785
4786 /* Advance the output cursor. */
4787 output_cursor.hpos += len;
4788 output_cursor.x = x;
dc6f92b8
JB
4789}
4790
0cdd0c9f 4791
06a2c219 4792/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 4793
06a2c219
GM
4794static void
4795x_insert_glyphs (start, len)
4796 struct glyph *start;
4797 register int len;
4798{
4799 struct frame *f;
4800 struct window *w;
4801 int line_height, shift_by_width, shifted_region_width;
4802 struct glyph_row *row;
4803 struct glyph *glyph;
4804 int frame_x, frame_y, hpos, real_start, real_end;
58769bee 4805
06a2c219 4806 xassert (updated_window && updated_row);
0cdd0c9f 4807 BLOCK_INPUT;
06a2c219
GM
4808 w = updated_window;
4809 f = XFRAME (WINDOW_FRAME (w));
4810
4811 /* Get the height of the line we are in. */
4812 row = updated_row;
4813 line_height = row->height;
4814
4815 /* Get the width of the glyphs to insert. */
4816 shift_by_width = 0;
4817 for (glyph = start; glyph < start + len; ++glyph)
4818 shift_by_width += glyph->pixel_width;
4819
4820 /* Get the width of the region to shift right. */
4821 shifted_region_width = (window_box_width (w, updated_area)
4822 - output_cursor.x
4823 - shift_by_width);
4824
4825 /* Shift right. */
4826 frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x);
4827 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
4828 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
4829 f->output_data.x->normal_gc,
4830 frame_x, frame_y,
4831 shifted_region_width, line_height,
4832 frame_x + shift_by_width, frame_y);
4833
4834 /* Write the glyphs. */
4835 hpos = start - row->glyphs[updated_area];
4836 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
66ac4b0e 4837 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
06a2c219
GM
4838 note_overwritten_text_cursor (w, real_start, real_end - real_start);
4839
4840 /* Advance the output cursor. */
4841 output_cursor.hpos += len;
4842 output_cursor.x += shift_by_width;
0cdd0c9f
RS
4843 UNBLOCK_INPUT;
4844}
0cdd0c9f 4845
0cdd0c9f 4846
06a2c219
GM
4847/* Delete N glyphs at the nominal cursor position. Not implemented
4848 for X frames. */
c83febd7
RS
4849
4850static void
06a2c219
GM
4851x_delete_glyphs (n)
4852 register int n;
c83febd7 4853{
06a2c219 4854 abort ();
c83febd7
RS
4855}
4856
0cdd0c9f 4857
06a2c219
GM
4858/* Erase the current text line from the nominal cursor position
4859 (inclusive) to pixel column TO_X (exclusive). The idea is that
4860 everything from TO_X onward is already erased.
4861
4862 TO_X is a pixel position relative to updated_area of
4863 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 4864
06a2c219
GM
4865static void
4866x_clear_end_of_line (to_x)
4867 int to_x;
4868{
4869 struct frame *f;
4870 struct window *w = updated_window;
4871 int max_x, min_y, max_y;
4872 int from_x, from_y, to_y;
4873
4874 xassert (updated_window && updated_row);
4875 f = XFRAME (w->frame);
4876
4877 if (updated_row->full_width_p)
4878 {
4879 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
4880 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4881 && !w->pseudo_window_p)
4882 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 4883 }
06a2c219
GM
4884 else
4885 max_x = window_box_width (w, updated_area);
4886 max_y = window_text_bottom_y (w);
dc6f92b8 4887
06a2c219
GM
4888 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
4889 of window. For TO_X > 0, truncate to end of drawing area. */
4890 if (to_x == 0)
4891 return;
4892 else if (to_x < 0)
4893 to_x = max_x;
4894 else
4895 to_x = min (to_x, max_x);
dbc4e1c1 4896
06a2c219
GM
4897 to_y = min (max_y, output_cursor.y + updated_row->height);
4898
4899 /* Notice if the cursor will be cleared by this operation. */
4900 if (!updated_row->full_width_p)
4901 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
dbc4e1c1 4902
06a2c219
GM
4903 from_x = output_cursor.x;
4904
4905 /* Translate to frame coordinates. */
4906 if (updated_row->full_width_p)
4907 {
4908 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
4909 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
4910 }
0cdd0c9f
RS
4911 else
4912 {
06a2c219
GM
4913 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
4914 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
4915 }
4916
045dee35 4917 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
4918 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
4919 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
4920
4921 /* Prevent inadvertently clearing to end of the X window. */
4922 if (to_x > from_x && to_y > from_y)
4923 {
4924 BLOCK_INPUT;
4925 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4926 from_x, from_y, to_x - from_x, to_y - from_y,
4927 False);
4928 UNBLOCK_INPUT;
0cdd0c9f 4929 }
0cdd0c9f 4930}
dbc4e1c1 4931
0cdd0c9f 4932
06a2c219 4933/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 4934 frame. Otherwise clear the selected frame. */
06a2c219
GM
4935
4936static void
4937x_clear_frame ()
0cdd0c9f 4938{
06a2c219 4939 struct frame *f;
0cdd0c9f 4940
06a2c219
GM
4941 if (updating_frame)
4942 f = updating_frame;
0cdd0c9f 4943 else
b86bd3dd 4944 f = SELECTED_FRAME ();
58769bee 4945
06a2c219
GM
4946 /* Clearing the frame will erase any cursor, so mark them all as no
4947 longer visible. */
4948 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4949 output_cursor.hpos = output_cursor.vpos = 0;
4950 output_cursor.x = -1;
4951
4952 /* We don't set the output cursor here because there will always
4953 follow an explicit cursor_to. */
4954 BLOCK_INPUT;
4955 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
4956
4957 /* We have to clear the scroll bars, too. If we have changed
4958 colors or something like that, then they should be notified. */
4959 x_scroll_bar_clear (f);
0cdd0c9f 4960
06a2c219
GM
4961 XFlush (FRAME_X_DISPLAY (f));
4962 UNBLOCK_INPUT;
dc6f92b8 4963}
06a2c219
GM
4964
4965
dc6f92b8 4966\f
dbc4e1c1
JB
4967/* Invert the middle quarter of the frame for .15 sec. */
4968
06a2c219
GM
4969/* We use the select system call to do the waiting, so we have to make
4970 sure it's available. If it isn't, we just won't do visual bells. */
4971
dbc4e1c1
JB
4972#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4973
06a2c219
GM
4974
4975/* Subtract the `struct timeval' values X and Y, storing the result in
4976 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
4977
4978static int
4979timeval_subtract (result, x, y)
4980 struct timeval *result, x, y;
4981{
06a2c219
GM
4982 /* Perform the carry for the later subtraction by updating y. This
4983 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
4984 if (x.tv_usec < y.tv_usec)
4985 {
4986 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
4987 y.tv_usec -= 1000000 * nsec;
4988 y.tv_sec += nsec;
4989 }
06a2c219 4990
dbc4e1c1
JB
4991 if (x.tv_usec - y.tv_usec > 1000000)
4992 {
4993 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
4994 y.tv_usec += 1000000 * nsec;
4995 y.tv_sec -= nsec;
4996 }
4997
06a2c219
GM
4998 /* Compute the time remaining to wait. tv_usec is certainly
4999 positive. */
dbc4e1c1
JB
5000 result->tv_sec = x.tv_sec - y.tv_sec;
5001 result->tv_usec = x.tv_usec - y.tv_usec;
5002
06a2c219
GM
5003 /* Return indication of whether the result should be considered
5004 negative. */
dbc4e1c1
JB
5005 return x.tv_sec < y.tv_sec;
5006}
dc6f92b8 5007
dfcf069d 5008void
f676886a
JB
5009XTflash (f)
5010 struct frame *f;
dc6f92b8 5011{
dbc4e1c1 5012 BLOCK_INPUT;
dc6f92b8 5013
dbc4e1c1
JB
5014 {
5015 GC gc;
dc6f92b8 5016
06a2c219
GM
5017 /* Create a GC that will use the GXxor function to flip foreground
5018 pixels into background pixels. */
dbc4e1c1
JB
5019 {
5020 XGCValues values;
dc6f92b8 5021
dbc4e1c1 5022 values.function = GXxor;
7556890b
RS
5023 values.foreground = (f->output_data.x->foreground_pixel
5024 ^ f->output_data.x->background_pixel);
58769bee 5025
334208b7 5026 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5027 GCFunction | GCForeground, &values);
5028 }
dc6f92b8 5029
dbc4e1c1 5030 {
e84e14c3
RS
5031 /* Get the height not including a menu bar widget. */
5032 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5033 /* Height of each line to flash. */
5034 int flash_height = FRAME_LINE_HEIGHT (f);
5035 /* These will be the left and right margins of the rectangles. */
5036 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5037 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5038
5039 int width;
5040
5041 /* Don't flash the area between a scroll bar and the frame
5042 edge it is next to. */
5043 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5044 {
5045 case vertical_scroll_bar_left:
5046 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5047 break;
5048
5049 case vertical_scroll_bar_right:
5050 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5051 break;
06a2c219
GM
5052
5053 default:
5054 break;
e84e14c3
RS
5055 }
5056
5057 width = flash_right - flash_left;
5058
5059 /* If window is tall, flash top and bottom line. */
5060 if (height > 3 * FRAME_LINE_HEIGHT (f))
5061 {
5062 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5063 flash_left,
5064 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5065 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5066 width, flash_height);
5067 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5068 flash_left,
5069 (height - flash_height
5070 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5071 width, flash_height);
5072 }
5073 else
5074 /* If it is short, flash it all. */
5075 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5076 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5077 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5078
06a2c219 5079 x_flush (f);
dc6f92b8 5080
dbc4e1c1 5081 {
06a2c219 5082 struct timeval wakeup;
dc6f92b8 5083
66c30ea1 5084 EMACS_GET_TIME (wakeup);
dc6f92b8 5085
dbc4e1c1
JB
5086 /* Compute time to wait until, propagating carry from usecs. */
5087 wakeup.tv_usec += 150000;
5088 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5089 wakeup.tv_usec %= 1000000;
5090
5091 /* Keep waiting until past the time wakeup. */
5092 while (1)
5093 {
5094 struct timeval timeout;
5095
66c30ea1 5096 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
5097
5098 /* In effect, timeout = wakeup - timeout.
5099 Break if result would be negative. */
5100 if (timeval_subtract (&timeout, wakeup, timeout))
5101 break;
5102
5103 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5104 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5105 }
5106 }
58769bee 5107
e84e14c3
RS
5108 /* If window is tall, flash top and bottom line. */
5109 if (height > 3 * FRAME_LINE_HEIGHT (f))
5110 {
5111 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5112 flash_left,
5113 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5114 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5115 width, flash_height);
5116 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5117 flash_left,
5118 (height - flash_height
5119 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5120 width, flash_height);
5121 }
5122 else
5123 /* If it is short, flash it all. */
5124 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5125 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5126 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5127
334208b7 5128 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5129 x_flush (f);
dc6f92b8 5130 }
dbc4e1c1
JB
5131 }
5132
5133 UNBLOCK_INPUT;
dc6f92b8
JB
5134}
5135
06a2c219 5136#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5137
5138
dc6f92b8
JB
5139/* Make audible bell. */
5140
dfcf069d 5141void
dc6f92b8
JB
5142XTring_bell ()
5143{
b86bd3dd
GM
5144 struct frame *f = SELECTED_FRAME ();
5145
5146 if (FRAME_X_DISPLAY (f))
5147 {
dbc4e1c1 5148#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5149 if (visible_bell)
5150 XTflash (f);
5151 else
dbc4e1c1 5152#endif
b86bd3dd
GM
5153 {
5154 BLOCK_INPUT;
5155 XBell (FRAME_X_DISPLAY (f), 0);
5156 XFlush (FRAME_X_DISPLAY (f));
5157 UNBLOCK_INPUT;
5158 }
dc6f92b8
JB
5159 }
5160}
06a2c219 5161
dc6f92b8 5162\f
06a2c219
GM
5163/* Specify how many text lines, from the top of the window,
5164 should be affected by insert-lines and delete-lines operations.
5165 This, and those operations, are used only within an update
5166 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5167
dfcf069d 5168static void
06a2c219
GM
5169XTset_terminal_window (n)
5170 register int n;
dc6f92b8 5171{
06a2c219 5172 /* This function intentionally left blank. */
dc6f92b8
JB
5173}
5174
06a2c219
GM
5175
5176\f
5177/***********************************************************************
5178 Line Dance
5179 ***********************************************************************/
5180
5181/* Perform an insert-lines or delete-lines operation, inserting N
5182 lines or deleting -N lines at vertical position VPOS. */
5183
dfcf069d 5184static void
06a2c219
GM
5185x_ins_del_lines (vpos, n)
5186 int vpos, n;
dc6f92b8
JB
5187{
5188 abort ();
5189}
06a2c219
GM
5190
5191
5192/* Scroll part of the display as described by RUN. */
dc6f92b8 5193
dfcf069d 5194static void
06a2c219
GM
5195x_scroll_run (w, run)
5196 struct window *w;
5197 struct run *run;
dc6f92b8 5198{
06a2c219
GM
5199 struct frame *f = XFRAME (w->frame);
5200 int x, y, width, height, from_y, to_y, bottom_y;
5201
5202 /* Get frame-relative bounding box of the text display area of W,
5203 without mode lines. Include in this box the flags areas to the
5204 left and right of W. */
5205 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5206 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5207 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5208
5209 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5210 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5211 bottom_y = y + height;
dc6f92b8 5212
06a2c219
GM
5213 if (to_y < from_y)
5214 {
5215 /* Scrolling up. Make sure we don't copy part of the mode
5216 line at the bottom. */
5217 if (from_y + run->height > bottom_y)
5218 height = bottom_y - from_y;
5219 else
5220 height = run->height;
5221 }
dc6f92b8 5222 else
06a2c219
GM
5223 {
5224 /* Scolling down. Make sure we don't copy over the mode line.
5225 at the bottom. */
5226 if (to_y + run->height > bottom_y)
5227 height = bottom_y - to_y;
5228 else
5229 height = run->height;
5230 }
7a13e894 5231
06a2c219
GM
5232 BLOCK_INPUT;
5233
5234 /* Cursor off. Will be switched on again in x_update_window_end. */
5235 updated_window = w;
5236 x_clear_cursor (w);
5237
5238 XCopyArea (FRAME_X_DISPLAY (f),
5239 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5240 f->output_data.x->normal_gc,
5241 x, from_y,
5242 width, height,
5243 x, to_y);
5244
5245 UNBLOCK_INPUT;
5246}
dc6f92b8 5247
dc6f92b8 5248
06a2c219
GM
5249\f
5250/***********************************************************************
5251 Exposure Events
5252 ***********************************************************************/
5253
5254/* Redisplay an exposed area of frame F. X and Y are the upper-left
5255 corner of the exposed rectangle. W and H are width and height of
5256 the exposed area. All are pixel values. W or H zero means redraw
5257 the entire frame. */
dc6f92b8 5258
06a2c219
GM
5259static void
5260expose_frame (f, x, y, w, h)
5261 struct frame *f;
5262 int x, y, w, h;
dc6f92b8 5263{
06a2c219 5264 XRectangle r;
dc6f92b8 5265
06a2c219 5266 TRACE ((stderr, "expose_frame "));
dc6f92b8 5267
06a2c219
GM
5268 /* No need to redraw if frame will be redrawn soon. */
5269 if (FRAME_GARBAGED_P (f))
dc6f92b8 5270 {
06a2c219
GM
5271 TRACE ((stderr, " garbaged\n"));
5272 return;
5273 }
5274
5275 /* If basic faces haven't been realized yet, there is no point in
5276 trying to redraw anything. This can happen when we get an expose
5277 event while Emacs is starting, e.g. by moving another window. */
5278 if (FRAME_FACE_CACHE (f) == NULL
5279 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5280 {
5281 TRACE ((stderr, " no faces\n"));
5282 return;
58769bee 5283 }
06a2c219
GM
5284
5285 if (w == 0 || h == 0)
58769bee 5286 {
06a2c219
GM
5287 r.x = r.y = 0;
5288 r.width = CANON_X_UNIT (f) * f->width;
5289 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5290 }
5291 else
5292 {
06a2c219
GM
5293 r.x = x;
5294 r.y = y;
5295 r.width = w;
5296 r.height = h;
5297 }
5298
5299 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
5300 expose_window_tree (XWINDOW (f->root_window), &r);
5301
9ea173e8 5302 if (WINDOWP (f->tool_bar_window))
06a2c219 5303 {
9ea173e8 5304 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
5305 XRectangle window_rect;
5306 XRectangle intersection_rect;
5307 int window_x, window_y, window_width, window_height;
5308
5309
5310 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5311 window_rect.x = window_x;
5312 window_rect.y = window_y;
5313 window_rect.width = window_width;
5314 window_rect.height = window_height;
5315
5316 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5317 expose_window (w, &intersection_rect);
5318 }
5319
5320#ifndef USE_X_TOOLKIT
5321 if (WINDOWP (f->menu_bar_window))
5322 {
5323 struct window *w = XWINDOW (f->menu_bar_window);
5324 XRectangle window_rect;
5325 XRectangle intersection_rect;
5326 int window_x, window_y, window_width, window_height;
5327
5328
5329 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5330 window_rect.x = window_x;
5331 window_rect.y = window_y;
5332 window_rect.width = window_width;
5333 window_rect.height = window_height;
5334
5335 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5336 expose_window (w, &intersection_rect);
dc6f92b8 5337 }
06a2c219 5338#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5339}
5340
06a2c219
GM
5341
5342/* Redraw (parts) of all windows in the window tree rooted at W that
5343 intersect R. R contains frame pixel coordinates. */
5344
58769bee 5345static void
06a2c219
GM
5346expose_window_tree (w, r)
5347 struct window *w;
5348 XRectangle *r;
dc6f92b8 5349{
06a2c219
GM
5350 while (w)
5351 {
5352 if (!NILP (w->hchild))
5353 expose_window_tree (XWINDOW (w->hchild), r);
5354 else if (!NILP (w->vchild))
5355 expose_window_tree (XWINDOW (w->vchild), r);
5356 else
5357 {
5358 XRectangle window_rect;
5359 XRectangle intersection_rect;
5360 struct frame *f = XFRAME (w->frame);
5361 int window_x, window_y, window_width, window_height;
5362
5363 /* Frame-relative pixel rectangle of W. */
5364 window_box (w, -1, &window_x, &window_y, &window_width,
5365 &window_height);
5366 window_rect.x
5367 = (window_x
110859fc 5368 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
714dc26c 5369 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
06a2c219
GM
5370 window_rect.y = window_y;
5371 window_rect.width
5372 = (window_width
110859fc 5373 + FRAME_X_FLAGS_AREA_WIDTH (f)
06a2c219
GM
5374 + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
5375 window_rect.height
5376 = window_height + CURRENT_MODE_LINE_HEIGHT (w);
5377
5378 if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
5379 expose_window (w, &intersection_rect);
5380 }
58769bee 5381
06a2c219
GM
5382 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5383 }
5384}
58769bee 5385
dc6f92b8 5386
06a2c219
GM
5387/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5388 which intersects rectangle R. R is in window-relative coordinates. */
5389
5390static void
5391expose_area (w, row, r, area)
5392 struct window *w;
5393 struct glyph_row *row;
5394 XRectangle *r;
5395 enum glyph_row_area area;
5396{
5397 int x;
5398 struct glyph *first = row->glyphs[area];
5399 struct glyph *end = row->glyphs[area] + row->used[area];
5400 struct glyph *last;
5401 int first_x;
5402
5403 /* Set x to the window-relative start position for drawing glyphs of
5404 AREA. The first glyph of the text area can be partially visible.
5405 The first glyphs of other areas cannot. */
5406 if (area == LEFT_MARGIN_AREA)
5407 x = 0;
5408 else if (area == TEXT_AREA)
5409 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5410 else
5411 x = (window_box_width (w, LEFT_MARGIN_AREA)
5412 + window_box_width (w, TEXT_AREA));
5413
6fb13182
GM
5414 if (area == TEXT_AREA && row->fill_line_p)
5415 /* If row extends face to end of line write the whole line. */
5416 x_draw_glyphs (w, x, row, area,
5417 0, row->used[area],
06a2c219 5418 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5419 NULL, NULL, 0);
6fb13182
GM
5420 else
5421 {
5422 /* Find the first glyph that must be redrawn. */
5423 while (first < end
5424 && x + first->pixel_width < r->x)
5425 {
5426 x += first->pixel_width;
5427 ++first;
5428 }
5429
5430 /* Find the last one. */
5431 last = first;
5432 first_x = x;
5433 while (last < end
5434 && x < r->x + r->width)
5435 {
5436 x += last->pixel_width;
5437 ++last;
5438 }
5439
5440 /* Repaint. */
5441 if (last > first)
5442 x_draw_glyphs (w, first_x, row, area,
5443 first - row->glyphs[area],
5444 last - row->glyphs[area],
5445 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5446 NULL, NULL, 0);
5447 }
06a2c219
GM
5448}
5449
58769bee 5450
06a2c219
GM
5451/* Redraw the parts of the glyph row ROW on window W intersecting
5452 rectangle R. R is in window-relative coordinates. */
dc6f92b8 5453
06a2c219
GM
5454static void
5455expose_line (w, row, r)
5456 struct window *w;
5457 struct glyph_row *row;
5458 XRectangle *r;
5459{
5460 xassert (row->enabled_p);
5461
5462 if (row->mode_line_p || w->pseudo_window_p)
5463 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5464 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5465 NULL, NULL, 0);
06a2c219
GM
5466 else
5467 {
5468 if (row->used[LEFT_MARGIN_AREA])
5469 expose_area (w, row, r, LEFT_MARGIN_AREA);
5470 if (row->used[TEXT_AREA])
5471 expose_area (w, row, r, TEXT_AREA);
5472 if (row->used[RIGHT_MARGIN_AREA])
5473 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5474 x_draw_row_bitmaps (w, row);
5475 }
5476}
dc6f92b8 5477
58769bee 5478
06a2c219
GM
5479/* Return non-zero if W's cursor intersects rectangle R. */
5480
5481static int
5482x_phys_cursor_in_rect_p (w, r)
5483 struct window *w;
5484 XRectangle *r;
5485{
5486 XRectangle cr, result;
5487 struct glyph *cursor_glyph;
5488
5489 cursor_glyph = get_phys_cursor_glyph (w);
5490 if (cursor_glyph)
5491 {
5492 cr.x = w->phys_cursor.x;
5493 cr.y = w->phys_cursor.y;
5494 cr.width = cursor_glyph->pixel_width;
5495 cr.height = w->phys_cursor_height;
5496 return x_intersect_rectangles (&cr, r, &result);
5497 }
5498 else
5499 return 0;
dc6f92b8 5500}
dc6f92b8 5501
06a2c219
GM
5502
5503/* Redraw a rectangle of window W. R is a rectangle in window
5504 relative coordinates. Call this function with input blocked. */
dc6f92b8
JB
5505
5506static void
06a2c219
GM
5507expose_window (w, r)
5508 struct window *w;
5509 XRectangle *r;
dc6f92b8 5510{
06a2c219
GM
5511 struct glyph_row *row;
5512 int y;
5513 int yb = window_text_bottom_y (w);
5514 int cursor_cleared_p;
dc6f92b8 5515
80c32bcc
GM
5516 /* If window is not yet fully initialized, do nothing. This can
5517 happen when toolkit scroll bars are used and a window is split.
5518 Reconfiguring the scroll bar will generate an expose for a newly
5519 created window. */
5520 if (w->current_matrix == NULL)
5521 return;
5522
06a2c219
GM
5523 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
5524 r->x, r->y, r->width, r->height));
dc6f92b8 5525
06a2c219
GM
5526 /* Convert to window coordinates. */
5527 r->x = FRAME_TO_WINDOW_PIXEL_X (w, r->x);
5528 r->y = FRAME_TO_WINDOW_PIXEL_Y (w, r->y);
dc6f92b8 5529
06a2c219
GM
5530 /* Turn off the cursor. */
5531 if (!w->pseudo_window_p
5532 && x_phys_cursor_in_rect_p (w, r))
5533 {
5534 x_clear_cursor (w);
5535 cursor_cleared_p = 1;
5536 }
5537 else
5538 cursor_cleared_p = 0;
5539
5540 /* Find the first row intersecting the rectangle R. */
5541 row = w->current_matrix->rows;
5542 y = 0;
5543 while (row->enabled_p
5544 && y < yb
5545 && y + row->height < r->y)
5546 {
5547 y += row->height;
5548 ++row;
5549 }
5550
dc6f92b8 5551 /* Display the text in the rectangle, one text line at a time. */
06a2c219
GM
5552 while (row->enabled_p
5553 && y < yb
5554 && y < r->y + r->height)
5555 {
5556 expose_line (w, row, r);
5557 y += row->height;
5558 ++row;
5559 }
5560
5561 /* Display the mode line if there is one. */
5562 if (WINDOW_WANTS_MODELINE_P (w)
5563 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
5564 row->enabled_p)
5565 && row->y < r->y + r->height)
5566 expose_line (w, row, r);
dc6f92b8 5567
06a2c219 5568 if (!w->pseudo_window_p)
dc6f92b8 5569 {
06a2c219
GM
5570 /* Draw border between windows. */
5571 x_draw_vertical_border (w);
5572
5573 /* Turn the cursor on again. */
5574 if (cursor_cleared_p)
5575 x_update_window_cursor (w, 1);
5576 }
5577}
dc6f92b8 5578
dc6f92b8 5579
06a2c219
GM
5580/* Determine the intersection of two rectangles R1 and R2. Return
5581 the intersection in *RESULT. Value is non-zero if RESULT is not
5582 empty. */
5583
5584static int
5585x_intersect_rectangles (r1, r2, result)
5586 XRectangle *r1, *r2, *result;
5587{
5588 XRectangle *left, *right;
5589 XRectangle *upper, *lower;
5590 int intersection_p = 0;
5591
5592 /* Rearrange so that R1 is the left-most rectangle. */
5593 if (r1->x < r2->x)
5594 left = r1, right = r2;
5595 else
5596 left = r2, right = r1;
5597
5598 /* X0 of the intersection is right.x0, if this is inside R1,
5599 otherwise there is no intersection. */
5600 if (right->x <= left->x + left->width)
5601 {
5602 result->x = right->x;
5603
5604 /* The right end of the intersection is the minimum of the
5605 the right ends of left and right. */
5606 result->width = (min (left->x + left->width, right->x + right->width)
5607 - result->x);
5608
5609 /* Same game for Y. */
5610 if (r1->y < r2->y)
5611 upper = r1, lower = r2;
5612 else
5613 upper = r2, lower = r1;
5614
5615 /* The upper end of the intersection is lower.y0, if this is inside
5616 of upper. Otherwise, there is no intersection. */
5617 if (lower->y <= upper->y + upper->height)
dc43ef94 5618 {
06a2c219
GM
5619 result->y = lower->y;
5620
5621 /* The lower end of the intersection is the minimum of the lower
5622 ends of upper and lower. */
5623 result->height = (min (lower->y + lower->height,
5624 upper->y + upper->height)
5625 - result->y);
5626 intersection_p = 1;
dc43ef94 5627 }
dc6f92b8
JB
5628 }
5629
06a2c219 5630 return intersection_p;
dc6f92b8 5631}
06a2c219
GM
5632
5633
5634
5635
dc6f92b8 5636\f
dc6f92b8 5637static void
334208b7
RS
5638frame_highlight (f)
5639 struct frame *f;
dc6f92b8 5640{
b3e1e05c
JB
5641 /* We used to only do this if Vx_no_window_manager was non-nil, but
5642 the ICCCM (section 4.1.6) says that the window's border pixmap
5643 and border pixel are window attributes which are "private to the
5644 client", so we can always change it to whatever we want. */
5645 BLOCK_INPUT;
334208b7 5646 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5647 f->output_data.x->border_pixel);
b3e1e05c 5648 UNBLOCK_INPUT;
5d46f928 5649 x_update_cursor (f, 1);
dc6f92b8
JB
5650}
5651
5652static void
334208b7
RS
5653frame_unhighlight (f)
5654 struct frame *f;
dc6f92b8 5655{
b3e1e05c
JB
5656 /* We used to only do this if Vx_no_window_manager was non-nil, but
5657 the ICCCM (section 4.1.6) says that the window's border pixmap
5658 and border pixel are window attributes which are "private to the
5659 client", so we can always change it to whatever we want. */
5660 BLOCK_INPUT;
334208b7 5661 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5662 f->output_data.x->border_tile);
b3e1e05c 5663 UNBLOCK_INPUT;
5d46f928 5664 x_update_cursor (f, 1);
dc6f92b8 5665}
dc6f92b8 5666
f676886a
JB
5667/* The focus has changed. Update the frames as necessary to reflect
5668 the new situation. Note that we can't change the selected frame
c5acd733 5669 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 5670 Each event gets marked with the frame in which it occurred, so the
c5acd733 5671 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 5672
6d4238f3 5673static void
0f941935
KH
5674x_new_focus_frame (dpyinfo, frame)
5675 struct x_display_info *dpyinfo;
f676886a 5676 struct frame *frame;
dc6f92b8 5677{
0f941935 5678 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 5679
0f941935 5680 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 5681 {
58769bee 5682 /* Set this before calling other routines, so that they see
f676886a 5683 the correct value of x_focus_frame. */
0f941935 5684 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
5685
5686 if (old_focus && old_focus->auto_lower)
f676886a 5687 x_lower_frame (old_focus);
dc6f92b8
JB
5688
5689#if 0
f676886a 5690 selected_frame = frame;
e0c1aef2
KH
5691 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
5692 selected_frame);
f676886a
JB
5693 Fselect_window (selected_frame->selected_window);
5694 choose_minibuf_frame ();
c118dd06 5695#endif /* ! 0 */
dc6f92b8 5696
0f941935
KH
5697 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
5698 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
5699 else
5700 pending_autoraise_frame = 0;
6d4238f3 5701 }
dc6f92b8 5702
0f941935 5703 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
5704}
5705
37c2c98b
RS
5706/* Handle an event saying the mouse has moved out of an Emacs frame. */
5707
5708void
0f941935
KH
5709x_mouse_leave (dpyinfo)
5710 struct x_display_info *dpyinfo;
37c2c98b 5711{
0f941935 5712 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 5713}
6d4238f3 5714
f451eb13
JB
5715/* The focus has changed, or we have redirected a frame's focus to
5716 another frame (this happens when a frame uses a surrogate
06a2c219 5717 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
5718
5719 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 5720 frame is being highlighted or un-highlighted; we only use it to find
0f941935 5721 the appropriate X display info. */
06a2c219 5722
6d4238f3 5723static void
0f941935
KH
5724XTframe_rehighlight (frame)
5725 struct frame *frame;
6d4238f3 5726{
0f941935
KH
5727 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
5728}
6d4238f3 5729
0f941935
KH
5730static void
5731x_frame_rehighlight (dpyinfo)
5732 struct x_display_info *dpyinfo;
5733{
5734 struct frame *old_highlight = dpyinfo->x_highlight_frame;
5735
5736 if (dpyinfo->x_focus_frame)
6d4238f3 5737 {
0f941935
KH
5738 dpyinfo->x_highlight_frame
5739 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
5740 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
5741 : dpyinfo->x_focus_frame);
5742 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 5743 {
0f941935
KH
5744 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
5745 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 5746 }
dc6f92b8 5747 }
6d4238f3 5748 else
0f941935 5749 dpyinfo->x_highlight_frame = 0;
dc6f92b8 5750
0f941935 5751 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
5752 {
5753 if (old_highlight)
f676886a 5754 frame_unhighlight (old_highlight);
0f941935
KH
5755 if (dpyinfo->x_highlight_frame)
5756 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 5757 }
dc6f92b8 5758}
06a2c219
GM
5759
5760
dc6f92b8 5761\f
06a2c219 5762/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 5763
28430d3c
JB
5764/* Initialize mode_switch_bit and modifier_meaning. */
5765static void
334208b7
RS
5766x_find_modifier_meanings (dpyinfo)
5767 struct x_display_info *dpyinfo;
28430d3c 5768{
f689eb05 5769 int min_code, max_code;
28430d3c
JB
5770 KeySym *syms;
5771 int syms_per_code;
5772 XModifierKeymap *mods;
5773
334208b7
RS
5774 dpyinfo->meta_mod_mask = 0;
5775 dpyinfo->shift_lock_mask = 0;
5776 dpyinfo->alt_mod_mask = 0;
5777 dpyinfo->super_mod_mask = 0;
5778 dpyinfo->hyper_mod_mask = 0;
58769bee 5779
9658a521 5780#ifdef HAVE_X11R4
334208b7 5781 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 5782#else
4a60f8c5
RS
5783 min_code = dpyinfo->display->min_keycode;
5784 max_code = dpyinfo->display->max_keycode;
9658a521
JB
5785#endif
5786
334208b7 5787 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
5788 min_code, max_code - min_code + 1,
5789 &syms_per_code);
334208b7 5790 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 5791
58769bee 5792 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 5793 Alt keysyms are on. */
28430d3c 5794 {
06a2c219 5795 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
5796
5797 for (row = 3; row < 8; row++)
5798 for (col = 0; col < mods->max_keypermod; col++)
5799 {
0299d313
RS
5800 KeyCode code
5801 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 5802
af92970c
KH
5803 /* Zeroes are used for filler. Skip them. */
5804 if (code == 0)
5805 continue;
5806
28430d3c
JB
5807 /* Are any of this keycode's keysyms a meta key? */
5808 {
5809 int code_col;
5810
5811 for (code_col = 0; code_col < syms_per_code; code_col++)
5812 {
f689eb05 5813 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 5814
f689eb05 5815 switch (sym)
28430d3c 5816 {
f689eb05
JB
5817 case XK_Meta_L:
5818 case XK_Meta_R:
334208b7 5819 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 5820 break;
f689eb05
JB
5821
5822 case XK_Alt_L:
5823 case XK_Alt_R:
334208b7 5824 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
5825 break;
5826
5827 case XK_Hyper_L:
5828 case XK_Hyper_R:
334208b7 5829 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
5830 break;
5831
5832 case XK_Super_L:
5833 case XK_Super_R:
334208b7 5834 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 5835 break;
11edeb03
JB
5836
5837 case XK_Shift_Lock:
5838 /* Ignore this if it's not on the lock modifier. */
5839 if ((1 << row) == LockMask)
334208b7 5840 dpyinfo->shift_lock_mask = LockMask;
11edeb03 5841 break;
28430d3c
JB
5842 }
5843 }
5844 }
5845 }
5846 }
5847
f689eb05 5848 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 5849 if (! dpyinfo->meta_mod_mask)
a3c44b14 5850 {
334208b7
RS
5851 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
5852 dpyinfo->alt_mod_mask = 0;
a3c44b14 5853 }
f689eb05 5854
148c4b70
RS
5855 /* If some keys are both alt and meta,
5856 make them just meta, not alt. */
334208b7 5857 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 5858 {
334208b7 5859 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 5860 }
58769bee 5861
28430d3c 5862 XFree ((char *) syms);
f689eb05 5863 XFreeModifiermap (mods);
28430d3c
JB
5864}
5865
dfeccd2d
JB
5866/* Convert between the modifier bits X uses and the modifier bits
5867 Emacs uses. */
06a2c219 5868
7c5283e4 5869static unsigned int
334208b7
RS
5870x_x_to_emacs_modifiers (dpyinfo, state)
5871 struct x_display_info *dpyinfo;
dc6f92b8
JB
5872 unsigned int state;
5873{
334208b7
RS
5874 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
5875 | ((state & ControlMask) ? ctrl_modifier : 0)
5876 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
5877 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
5878 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
5879 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
5880}
5881
dfeccd2d 5882static unsigned int
334208b7
RS
5883x_emacs_to_x_modifiers (dpyinfo, state)
5884 struct x_display_info *dpyinfo;
dfeccd2d
JB
5885 unsigned int state;
5886{
334208b7
RS
5887 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
5888 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
5889 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
5890 | ((state & shift_modifier) ? ShiftMask : 0)
5891 | ((state & ctrl_modifier) ? ControlMask : 0)
5892 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 5893}
d047c4eb
KH
5894
5895/* Convert a keysym to its name. */
5896
5897char *
5898x_get_keysym_name (keysym)
5899 KeySym keysym;
5900{
5901 char *value;
5902
5903 BLOCK_INPUT;
5904 value = XKeysymToString (keysym);
5905 UNBLOCK_INPUT;
5906
5907 return value;
5908}
06a2c219
GM
5909
5910
e4571a43
JB
5911\f
5912/* Mouse clicks and mouse movement. Rah. */
e4571a43 5913
06a2c219
GM
5914/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
5915 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
5916 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
5917 not force the value into range. */
69388238 5918
c8dba240 5919void
69388238 5920pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 5921 FRAME_PTR f;
69388238 5922 register int pix_x, pix_y;
e4571a43
JB
5923 register int *x, *y;
5924 XRectangle *bounds;
69388238 5925 int noclip;
e4571a43 5926{
06a2c219 5927 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
5928 even for negative values. */
5929 if (pix_x < 0)
7556890b 5930 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 5931 if (pix_y < 0)
7556890b 5932 pix_y -= (f)->output_data.x->line_height - 1;
69388238 5933
e4571a43
JB
5934 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
5935 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
5936
5937 if (bounds)
5938 {
7556890b
RS
5939 bounds->width = FONT_WIDTH (f->output_data.x->font);
5940 bounds->height = f->output_data.x->line_height;
e4571a43
JB
5941 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
5942 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
5943 }
5944
69388238
RS
5945 if (!noclip)
5946 {
5947 if (pix_x < 0)
5948 pix_x = 0;
3cbd2e0b
RS
5949 else if (pix_x > FRAME_WINDOW_WIDTH (f))
5950 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
5951
5952 if (pix_y < 0)
5953 pix_y = 0;
5954 else if (pix_y > f->height)
5955 pix_y = f->height;
5956 }
e4571a43
JB
5957
5958 *x = pix_x;
5959 *y = pix_y;
5960}
5961
06a2c219
GM
5962
5963/* Given HPOS/VPOS in the current matrix of W, return corresponding
5964 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
5965 can't tell the positions because W's display is not up to date,
5966 return 0. */
5967
5968int
5969glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
5970 struct window *w;
5971 int hpos, vpos;
5972 int *frame_x, *frame_y;
2b5c9e71 5973{
06a2c219
GM
5974 int success_p;
5975
5976 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
5977 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
5978
5979 if (display_completed)
5980 {
5981 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
5982 struct glyph *glyph = row->glyphs[TEXT_AREA];
5983 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
5984
5985 *frame_y = row->y;
5986 *frame_x = row->x;
5987 while (glyph < end)
5988 {
5989 *frame_x += glyph->pixel_width;
5990 ++glyph;
5991 }
5992
5993 success_p = 1;
5994 }
5995 else
5996 {
5997 *frame_y = *frame_x = 0;
5998 success_p = 0;
5999 }
6000
6001 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6002 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6003 return success_p;
2b5c9e71
RS
6004}
6005
06a2c219 6006
dc6f92b8
JB
6007/* Prepare a mouse-event in *RESULT for placement in the input queue.
6008
6009 If the event is a button press, then note that we have grabbed
f451eb13 6010 the mouse. */
dc6f92b8
JB
6011
6012static Lisp_Object
f451eb13 6013construct_mouse_click (result, event, f)
dc6f92b8
JB
6014 struct input_event *result;
6015 XButtonEvent *event;
f676886a 6016 struct frame *f;
dc6f92b8 6017{
f451eb13 6018 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6019 otherwise. */
f451eb13 6020 result->kind = mouse_click;
69388238 6021 result->code = event->button - Button1;
1113d9db 6022 result->timestamp = event->time;
334208b7
RS
6023 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6024 event->state)
f689eb05 6025 | (event->type == ButtonRelease
58769bee 6026 ? up_modifier
f689eb05 6027 : down_modifier));
dc6f92b8 6028
06a2c219
GM
6029 XSETINT (result->x, event->x);
6030 XSETINT (result->y, event->y);
6031 XSETFRAME (result->frame_or_window, f);
6032 return Qnil;
dc6f92b8 6033}
b849c413 6034
06a2c219
GM
6035#if 0 /* This function isn't called. --gerd */
6036
b849c413
RS
6037/* Prepare a menu-event in *RESULT for placement in the input queue. */
6038
6039static Lisp_Object
6040construct_menu_click (result, event, f)
6041 struct input_event *result;
6042 XButtonEvent *event;
6043 struct frame *f;
6044{
6045 /* Make the event type no_event; we'll change that when we decide
6046 otherwise. */
6047 result->kind = mouse_click;
26459b28 6048 result->code = event->button - Button1;
b849c413 6049 result->timestamp = event->time;
334208b7
RS
6050 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6051 event->state)
b849c413 6052 | (event->type == ButtonRelease
58769bee 6053 ? up_modifier
b849c413
RS
6054 : down_modifier));
6055
e0c1aef2
KH
6056 XSETINT (result->x, event->x);
6057 XSETINT (result->y, -1);
6058 XSETFRAME (result->frame_or_window, f);
b849c413 6059}
06a2c219
GM
6060
6061#endif /* 0 */
6062
69388238 6063\f
90e65f07
JB
6064/* Function to report a mouse movement to the mainstream Emacs code.
6065 The input handler calls this.
6066
6067 We have received a mouse movement event, which is given in *event.
6068 If the mouse is over a different glyph than it was last time, tell
6069 the mainstream emacs code by setting mouse_moved. If not, ask for
6070 another motion event, so we can check again the next time it moves. */
b8009dd1 6071
06a2c219
GM
6072static XMotionEvent last_mouse_motion_event;
6073static Lisp_Object last_mouse_motion_frame;
6074
90e65f07 6075static void
12ba150f 6076note_mouse_movement (frame, event)
f676886a 6077 FRAME_PTR frame;
90e65f07 6078 XMotionEvent *event;
90e65f07 6079{
e5d77022 6080 last_mouse_movement_time = event->time;
06a2c219
GM
6081 last_mouse_motion_event = *event;
6082 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6083
27f338af
RS
6084 if (event->window != FRAME_X_WINDOW (frame))
6085 {
39d8bb4d 6086 frame->mouse_moved = 1;
27f338af 6087 last_mouse_scroll_bar = Qnil;
27f338af 6088 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6089 }
6090
90e65f07 6091 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6092 else if (event->x < last_mouse_glyph.x
6093 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6094 || event->y < last_mouse_glyph.y
6095 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6096 {
39d8bb4d 6097 frame->mouse_moved = 1;
ab648270 6098 last_mouse_scroll_bar = Qnil;
b8009dd1 6099 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6100 }
6101}
6102
bf1c0ba1 6103/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6104
06a2c219
GM
6105 int disable_mouse_highlight;
6106
6107
6108\f
6109/************************************************************************
6110 Mouse Face
6111 ************************************************************************/
6112
6113/* Find the glyph under window-relative coordinates X/Y in window W.
6114 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6115 strings. Return in *HPOS and *VPOS the row and column number of
6116 the glyph found. Return in *AREA the glyph area containing X.
6117 Value is a pointer to the glyph found or null if X/Y is not on
6118 text, or we can't tell because W's current matrix is not up to
6119 date. */
6120
6121static struct glyph *
6122x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
6123 struct window *w;
6124 int x, y;
6125 int *hpos, *vpos, *area;
6126{
6127 struct glyph *glyph, *end;
6128 struct glyph_row *row;
6129 int x0, i, left_area_width;
6130
6131 /* Find row containing Y. Give up if some row is not enabled. */
6132 for (i = 0; i < w->current_matrix->nrows; ++i)
6133 {
6134 row = MATRIX_ROW (w->current_matrix, i);
6135 if (!row->enabled_p)
6136 return NULL;
6137 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6138 break;
6139 }
6140
6141 *vpos = i;
6142 *hpos = 0;
6143
6144 /* Give up if Y is not in the window. */
6145 if (i == w->current_matrix->nrows)
6146 return NULL;
6147
6148 /* Get the glyph area containing X. */
6149 if (w->pseudo_window_p)
6150 {
6151 *area = TEXT_AREA;
6152 x0 = 0;
6153 }
6154 else
6155 {
6156 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6157 if (x < left_area_width)
6158 {
6159 *area = LEFT_MARGIN_AREA;
6160 x0 = 0;
6161 }
6162 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6163 {
6164 *area = TEXT_AREA;
6165 x0 = row->x + left_area_width;
6166 }
6167 else
6168 {
6169 *area = RIGHT_MARGIN_AREA;
6170 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6171 }
6172 }
6173
6174 /* Find glyph containing X. */
6175 glyph = row->glyphs[*area];
6176 end = glyph + row->used[*area];
6177 while (glyph < end)
6178 {
6179 if (x < x0 + glyph->pixel_width)
6180 {
6181 if (w->pseudo_window_p)
6182 break;
6183 else if (BUFFERP (glyph->object))
6184 break;
6185 }
6186
6187 x0 += glyph->pixel_width;
6188 ++glyph;
6189 }
6190
6191 if (glyph == end)
6192 return NULL;
6193
6194 *hpos = glyph - row->glyphs[*area];
6195 return glyph;
6196}
6197
6198
6199/* Convert frame-relative x/y to coordinates relative to window W.
6200 Takes pseudo-windows into account. */
6201
6202static void
6203frame_to_window_pixel_xy (w, x, y)
6204 struct window *w;
6205 int *x, *y;
6206{
6207 if (w->pseudo_window_p)
6208 {
6209 /* A pseudo-window is always full-width, and starts at the
6210 left edge of the frame, plus a frame border. */
6211 struct frame *f = XFRAME (w->frame);
6212 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6213 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6214 }
6215 else
6216 {
6217 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6218 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6219 }
6220}
6221
6222
6223/* Take proper action when mouse has moved to the mode or top line of
6224 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6225 mode line. X is relative to the start of the text display area of
6226 W, so the width of bitmap areas and scroll bars must be subtracted
6227 to get a position relative to the start of the mode line. */
6228
6229static void
6230note_mode_line_highlight (w, x, mode_line_p)
6231 struct window *w;
6232 int x, mode_line_p;
6233{
6234 struct frame *f = XFRAME (w->frame);
6235 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6236 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6237 struct glyph_row *row;
6238
6239 if (mode_line_p)
6240 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6241 else
045dee35 6242 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
06a2c219
GM
6243
6244 if (row->enabled_p)
6245 {
6246 struct glyph *glyph, *end;
6247 Lisp_Object help, map;
6248 int x0;
6249
6250 /* Find the glyph under X. */
6251 glyph = row->glyphs[TEXT_AREA];
6252 end = glyph + row->used[TEXT_AREA];
6253 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6254 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
6255 while (glyph < end
6256 && x >= x0 + glyph->pixel_width)
6257 {
6258 x0 += glyph->pixel_width;
6259 ++glyph;
6260 }
6261
6262 if (glyph < end
6263 && STRINGP (glyph->object)
6264 && XSTRING (glyph->object)->intervals
6265 && glyph->charpos >= 0
6266 && glyph->charpos < XSTRING (glyph->object)->size)
6267 {
6268 /* If we're on a string with `help-echo' text property,
6269 arrange for the help to be displayed. This is done by
6270 setting the global variable help_echo to the help string. */
6271 help = Fget_text_property (make_number (glyph->charpos),
6272 Qhelp_echo, glyph->object);
6273 if (STRINGP (help))
6274 help_echo = help;
6275
6276 /* Change the mouse pointer according to what is under X/Y. */
6277 map = Fget_text_property (make_number (glyph->charpos),
6278 Qlocal_map, glyph->object);
6279 if (!NILP (Fkeymapp (map)))
6280 cursor = f->output_data.x->nontext_cursor;
6281 }
6282 }
6283
6284 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6285}
6286
6287
6288/* Take proper action when the mouse has moved to position X, Y on
6289 frame F as regards highlighting characters that have mouse-face
6290 properties. Also de-highlighting chars where the mouse was before.
27f338af 6291 X and Y can be negative or out of range. */
b8009dd1
RS
6292
6293static void
6294note_mouse_highlight (f, x, y)
06a2c219 6295 struct frame *f;
c32cdd9a 6296 int x, y;
b8009dd1 6297{
06a2c219
GM
6298 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6299 int portion;
b8009dd1
RS
6300 Lisp_Object window;
6301 struct window *w;
6302
06a2c219
GM
6303 /* When a menu is active, don't highlight because this looks odd. */
6304#ifdef USE_X_TOOLKIT
6305 if (popup_activated ())
6306 return;
6307#endif
6308
04fff9c0
GM
6309 if (disable_mouse_highlight
6310 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6311 return;
6312
06a2c219
GM
6313 dpyinfo->mouse_face_mouse_x = x;
6314 dpyinfo->mouse_face_mouse_y = y;
6315 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6316
06a2c219 6317 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6318 return;
6319
514e4681
RS
6320 if (gc_in_progress)
6321 {
06a2c219 6322 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6323 return;
6324 }
6325
b8009dd1 6326 /* Which window is that in? */
06a2c219 6327 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6328
6329 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6330 if (! EQ (window, dpyinfo->mouse_face_window))
6331 clear_mouse_face (dpyinfo);
6332
6333 /* Not on a window -> return. */
6334 if (!WINDOWP (window))
6335 return;
6336
6337 /* Convert to window-relative pixel coordinates. */
6338 w = XWINDOW (window);
6339 frame_to_window_pixel_xy (w, &x, &y);
6340
9ea173e8 6341 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6342 buffer. */
9ea173e8 6343 if (EQ (window, f->tool_bar_window))
06a2c219 6344 {
9ea173e8 6345 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6346 return;
6347 }
6348
6349 if (portion == 1 || portion == 3)
6350 {
6351 /* Mouse is on the mode or top line. */
6352 note_mode_line_highlight (w, x, portion == 1);
6353 return;
6354 }
6355 else
6356 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6357 f->output_data.x->text_cursor);
b8009dd1 6358
0cdd0c9f
RS
6359 /* Are we in a window whose display is up to date?
6360 And verify the buffer's text has not changed. */
06a2c219
GM
6361 if (/* Within text portion of the window. */
6362 portion == 0
0cdd0c9f 6363 && EQ (w->window_end_valid, w->buffer)
26459b28
KH
6364 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
6365 && (XFASTINT (w->last_overlay_modified)
6366 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
b8009dd1 6367 {
06a2c219
GM
6368 int hpos, vpos, pos, i, area;
6369 struct glyph *glyph;
b8009dd1 6370
06a2c219
GM
6371 /* Find the glyph under X/Y. */
6372 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
6373
6374 /* Clear mouse face if X/Y not over text. */
6375 if (glyph == NULL
6376 || area != TEXT_AREA
6377 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6378 {
06a2c219
GM
6379 clear_mouse_face (dpyinfo);
6380 return;
6381 }
6382
6383 pos = glyph->charpos;
6384 xassert (w->pseudo_window_p || BUFFERP (glyph->object));
6385
6386 /* Check for mouse-face and help-echo. */
6387 {
6388 Lisp_Object mouse_face, overlay, position;
6389 Lisp_Object *overlay_vec;
6390 int len, noverlays;
6391 struct buffer *obuf;
6392 int obegv, ozv;
6393
6394 /* If we get an out-of-range value, return now; avoid an error. */
6395 if (pos > BUF_Z (XBUFFER (w->buffer)))
6396 return;
6397
6398 /* Make the window's buffer temporarily current for
6399 overlays_at and compute_char_face. */
6400 obuf = current_buffer;
6401 current_buffer = XBUFFER (w->buffer);
6402 obegv = BEGV;
6403 ozv = ZV;
6404 BEGV = BEG;
6405 ZV = Z;
6406
6407 /* Is this char mouse-active or does it have help-echo? */
6408 XSETINT (position, pos);
6409
6410 /* Put all the overlays we want in a vector in overlay_vec.
6411 Store the length in len. If there are more than 10, make
6412 enough space for all, and try again. */
6413 len = 10;
6414 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6415 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6416 if (noverlays > len)
6417 {
6418 len = noverlays;
6419 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6420 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6421 }
6422
6423 noverlays = sort_overlays (overlay_vec, noverlays, w);
6424
6425 /* Check mouse-face highlighting. */
6426 if (! (EQ (window, dpyinfo->mouse_face_window)
6427 && vpos >= dpyinfo->mouse_face_beg_row
6428 && vpos <= dpyinfo->mouse_face_end_row
6429 && (vpos > dpyinfo->mouse_face_beg_row
6430 || hpos >= dpyinfo->mouse_face_beg_col)
6431 && (vpos < dpyinfo->mouse_face_end_row
6432 || hpos < dpyinfo->mouse_face_end_col
6433 || dpyinfo->mouse_face_past_end)))
6434 {
6435 /* Clear the display of the old active region, if any. */
6436 clear_mouse_face (dpyinfo);
6437
6438 /* Find the highest priority overlay that has a mouse-face prop. */
6439 overlay = Qnil;
6440 for (i = 0; i < noverlays; i++)
6441 {
6442 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6443 if (!NILP (mouse_face))
6444 {
6445 overlay = overlay_vec[i];
6446 break;
6447 }
6448 }
6449
6450 /* If no overlay applies, get a text property. */
6451 if (NILP (overlay))
6452 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6453
6454 /* Handle the overlay case. */
6455 if (! NILP (overlay))
6456 {
6457 /* Find the range of text around this char that
6458 should be active. */
6459 Lisp_Object before, after;
6460 int ignore;
6461
6462 before = Foverlay_start (overlay);
6463 after = Foverlay_end (overlay);
6464 /* Record this as the current active region. */
6465 fast_find_position (w, XFASTINT (before),
6466 &dpyinfo->mouse_face_beg_col,
6467 &dpyinfo->mouse_face_beg_row,
6468 &dpyinfo->mouse_face_beg_x,
6469 &dpyinfo->mouse_face_beg_y);
6470 dpyinfo->mouse_face_past_end
6471 = !fast_find_position (w, XFASTINT (after),
6472 &dpyinfo->mouse_face_end_col,
6473 &dpyinfo->mouse_face_end_row,
6474 &dpyinfo->mouse_face_end_x,
6475 &dpyinfo->mouse_face_end_y);
6476 dpyinfo->mouse_face_window = window;
6477 dpyinfo->mouse_face_face_id
6478 = face_at_buffer_position (w, pos, 0, 0,
6479 &ignore, pos + 1, 1);
6480
6481 /* Display it as active. */
6482 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6483 }
6484 /* Handle the text property case. */
6485 else if (! NILP (mouse_face))
6486 {
6487 /* Find the range of text around this char that
6488 should be active. */
6489 Lisp_Object before, after, beginning, end;
6490 int ignore;
6491
6492 beginning = Fmarker_position (w->start);
6493 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
6494 - XFASTINT (w->window_end_pos)));
6495 before
6496 = Fprevious_single_property_change (make_number (pos + 1),
6497 Qmouse_face,
6498 w->buffer, beginning);
6499 after
6500 = Fnext_single_property_change (position, Qmouse_face,
6501 w->buffer, end);
6502 /* Record this as the current active region. */
6503 fast_find_position (w, XFASTINT (before),
6504 &dpyinfo->mouse_face_beg_col,
6505 &dpyinfo->mouse_face_beg_row,
6506 &dpyinfo->mouse_face_beg_x,
6507 &dpyinfo->mouse_face_beg_y);
6508 dpyinfo->mouse_face_past_end
6509 = !fast_find_position (w, XFASTINT (after),
6510 &dpyinfo->mouse_face_end_col,
6511 &dpyinfo->mouse_face_end_row,
6512 &dpyinfo->mouse_face_end_x,
6513 &dpyinfo->mouse_face_end_y);
6514 dpyinfo->mouse_face_window = window;
6515 dpyinfo->mouse_face_face_id
6516 = face_at_buffer_position (w, pos, 0, 0,
6517 &ignore, pos + 1, 1);
6518
6519 /* Display it as active. */
6520 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6521 }
6522 }
6523
6524 /* Look for a `help-echo' property. */
6525 {
6526 Lisp_Object help;
6527
6528 /* Check overlays first. */
6529 help = Qnil;
6530 for (i = 0; i < noverlays && !STRINGP (help); ++i)
6531 help = Foverlay_get (overlay_vec[i], Qhelp_echo);
6532
6533 /* Try text properties. */
6534 if (!STRINGP (help)
6535 && ((STRINGP (glyph->object)
6536 && glyph->charpos >= 0
6537 && glyph->charpos < XSTRING (glyph->object)->size)
6538 || (BUFFERP (glyph->object)
6539 && glyph->charpos >= BEGV
6540 && glyph->charpos < ZV)))
6541 help = Fget_text_property (make_number (glyph->charpos),
6542 Qhelp_echo, glyph->object);
6543
6544 if (STRINGP (help))
6545 help_echo = help;
6546 }
6547
6548 BEGV = obegv;
6549 ZV = ozv;
6550 current_buffer = obuf;
6551 }
6552 }
6553}
6554
6555static void
6556redo_mouse_highlight ()
6557{
6558 if (!NILP (last_mouse_motion_frame)
6559 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
6560 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
6561 last_mouse_motion_event.x,
6562 last_mouse_motion_event.y);
6563}
6564
6565
6566\f
6567/***********************************************************************
9ea173e8 6568 Tool-bars
06a2c219
GM
6569 ***********************************************************************/
6570
9ea173e8
GM
6571static int x_tool_bar_item P_ ((struct frame *, int, int,
6572 struct glyph **, int *, int *, int *));
06a2c219 6573
9ea173e8 6574/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
6575 or -1. */
6576
9ea173e8 6577static int last_tool_bar_item;
06a2c219
GM
6578
6579
9ea173e8
GM
6580/* Get information about the tool-bar item at position X/Y on frame F.
6581 Return in *GLYPH a pointer to the glyph of the tool-bar item in
6582 the current matrix of the tool-bar window of F, or NULL if not
6583 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
6584 item in F->current_tool_bar_items. Value is
06a2c219 6585
9ea173e8 6586 -1 if X/Y is not on a tool-bar item
06a2c219
GM
6587 0 if X/Y is on the same item that was highlighted before.
6588 1 otherwise. */
6589
6590static int
9ea173e8 6591x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
6592 struct frame *f;
6593 int x, y;
6594 struct glyph **glyph;
6595 int *hpos, *vpos, *prop_idx;
6596{
6597 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6598 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6599 int area;
6600
6601 /* Find the glyph under X/Y. */
6602 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
6603 if (*glyph == NULL)
6604 return -1;
6605
9ea173e8
GM
6606 /* Get the start of this tool-bar item's properties in
6607 f->current_tool_bar_items. */
6608 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
6609 return -1;
6610
6611 /* Is mouse on the highlighted item? */
9ea173e8 6612 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
6613 && *vpos >= dpyinfo->mouse_face_beg_row
6614 && *vpos <= dpyinfo->mouse_face_end_row
6615 && (*vpos > dpyinfo->mouse_face_beg_row
6616 || *hpos >= dpyinfo->mouse_face_beg_col)
6617 && (*vpos < dpyinfo->mouse_face_end_row
6618 || *hpos < dpyinfo->mouse_face_end_col
6619 || dpyinfo->mouse_face_past_end))
6620 return 0;
6621
6622 return 1;
6623}
6624
6625
9ea173e8 6626/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
6627 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
6628 or ButtonRelase. */
6629
6630static void
9ea173e8 6631x_handle_tool_bar_click (f, button_event)
06a2c219
GM
6632 struct frame *f;
6633 XButtonEvent *button_event;
6634{
6635 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6636 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6637 int hpos, vpos, prop_idx;
6638 struct glyph *glyph;
6639 Lisp_Object enabled_p;
6640 int x = button_event->x;
6641 int y = button_event->y;
6642
9ea173e8 6643 /* If not on the highlighted tool-bar item, return. */
06a2c219 6644 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 6645 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
6646 return;
6647
6648 /* If item is disabled, do nothing. */
9ea173e8
GM
6649 enabled_p = (XVECTOR (f->current_tool_bar_items)
6650 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6651 if (NILP (enabled_p))
6652 return;
6653
6654 if (button_event->type == ButtonPress)
6655 {
6656 /* Show item in pressed state. */
6657 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
6658 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 6659 last_tool_bar_item = prop_idx;
06a2c219
GM
6660 }
6661 else
6662 {
6663 Lisp_Object key, frame;
6664 struct input_event event;
6665
6666 /* Show item in released state. */
6667 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
6668 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
6669
9ea173e8
GM
6670 key = (XVECTOR (f->current_tool_bar_items)
6671 ->contents[prop_idx + TOOL_BAR_ITEM_KEY]);
06a2c219
GM
6672
6673 XSETFRAME (frame, f);
9ea173e8
GM
6674 event.kind = TOOL_BAR_EVENT;
6675 event.frame_or_window = Fcons (frame, Fcons (Qtool_bar, Qnil));
06a2c219
GM
6676 kbd_buffer_store_event (&event);
6677
9ea173e8 6678 event.kind = TOOL_BAR_EVENT;
06a2c219
GM
6679 event.frame_or_window = Fcons (frame, key);
6680 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6681 button_event->state);
6682 kbd_buffer_store_event (&event);
9ea173e8 6683 last_tool_bar_item = -1;
06a2c219
GM
6684 }
6685}
6686
6687
9ea173e8
GM
6688/* Possibly highlight a tool-bar item on frame F when mouse moves to
6689 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
6690 note_mouse_highlight. */
6691
6692static void
9ea173e8 6693note_tool_bar_highlight (f, x, y)
06a2c219
GM
6694 struct frame *f;
6695 int x, y;
6696{
9ea173e8 6697 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
6698 struct window *w = XWINDOW (window);
6699 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6700 int hpos, vpos;
6701 struct glyph *glyph;
6702 struct glyph_row *row;
5c187dee 6703 int i;
06a2c219
GM
6704 Lisp_Object enabled_p;
6705 int prop_idx;
6706 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
5c187dee 6707 int mouse_down_p, rc;
06a2c219
GM
6708
6709 /* Function note_mouse_highlight is called with negative x(y
6710 values when mouse moves outside of the frame. */
6711 if (x <= 0 || y <= 0)
6712 {
6713 clear_mouse_face (dpyinfo);
6714 return;
6715 }
6716
9ea173e8 6717 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
6718 if (rc < 0)
6719 {
9ea173e8 6720 /* Not on tool-bar item. */
06a2c219
GM
6721 clear_mouse_face (dpyinfo);
6722 return;
6723 }
6724 else if (rc == 0)
9ea173e8 6725 /* On same tool-bar item as before. */
06a2c219 6726 goto set_help_echo;
b8009dd1 6727
06a2c219
GM
6728 clear_mouse_face (dpyinfo);
6729
9ea173e8 6730 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
6731 mouse_down_p = (dpyinfo->grabbed
6732 && f == last_mouse_frame
6733 && FRAME_LIVE_P (f));
6734 if (mouse_down_p
9ea173e8 6735 && last_tool_bar_item != prop_idx)
06a2c219
GM
6736 return;
6737
6738 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
6739 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
6740
9ea173e8
GM
6741 /* If tool-bar item is not enabled, don't highlight it. */
6742 enabled_p = (XVECTOR (f->current_tool_bar_items)
6743 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6744 if (!NILP (enabled_p))
6745 {
6746 /* Compute the x-position of the glyph. In front and past the
6747 image is a space. We include this is the highlighted area. */
6748 row = MATRIX_ROW (w->current_matrix, vpos);
6749 for (i = x = 0; i < hpos; ++i)
6750 x += row->glyphs[TEXT_AREA][i].pixel_width;
6751
6752 /* Record this as the current active region. */
6753 dpyinfo->mouse_face_beg_col = hpos;
6754 dpyinfo->mouse_face_beg_row = vpos;
6755 dpyinfo->mouse_face_beg_x = x;
6756 dpyinfo->mouse_face_beg_y = row->y;
6757 dpyinfo->mouse_face_past_end = 0;
6758
6759 dpyinfo->mouse_face_end_col = hpos + 1;
6760 dpyinfo->mouse_face_end_row = vpos;
6761 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
6762 dpyinfo->mouse_face_end_y = row->y;
6763 dpyinfo->mouse_face_window = window;
9ea173e8 6764 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
6765
6766 /* Display it as active. */
6767 show_mouse_face (dpyinfo, draw);
6768 dpyinfo->mouse_face_image_state = draw;
b8009dd1 6769 }
06a2c219
GM
6770
6771 set_help_echo:
6772
9ea173e8 6773 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 6774 XTread_socket does the rest. */
9ea173e8
GM
6775 help_echo = (XVECTOR (f->current_tool_bar_items)
6776 ->contents[prop_idx + TOOL_BAR_ITEM_HELP]);
06a2c219 6777 if (!STRINGP (help_echo))
9ea173e8
GM
6778 help_echo = (XVECTOR (f->current_tool_bar_items)
6779 ->contents[prop_idx + TOOL_BAR_ITEM_CAPTION]);
b8009dd1 6780}
4d73d038 6781
06a2c219
GM
6782
6783\f
6784/* Find the glyph matrix position of buffer position POS in window W.
6785 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
6786 current glyphs must be up to date. If POS is above window start
6787 return (0, 0, 0, 0). If POS is after end of W, return end of
6788 last line in W. */
b8009dd1
RS
6789
6790static int
06a2c219
GM
6791fast_find_position (w, pos, hpos, vpos, x, y)
6792 struct window *w;
b8009dd1 6793 int pos;
06a2c219 6794 int *hpos, *vpos, *x, *y;
b8009dd1 6795{
b8009dd1 6796 int i;
bf1c0ba1 6797 int lastcol;
06a2c219
GM
6798 int maybe_next_line_p = 0;
6799 int line_start_position;
6800 int yb = window_text_bottom_y (w);
6801 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
6802 struct glyph_row *best_row = row;
6803 int row_vpos = 0, best_row_vpos = 0;
6804 int current_x;
6805
6806 while (row->y < yb)
b8009dd1 6807 {
06a2c219
GM
6808 if (row->used[TEXT_AREA])
6809 line_start_position = row->glyphs[TEXT_AREA]->charpos;
6810 else
6811 line_start_position = 0;
6812
6813 if (line_start_position > pos)
b8009dd1 6814 break;
77b68646
RS
6815 /* If the position sought is the end of the buffer,
6816 don't include the blank lines at the bottom of the window. */
06a2c219
GM
6817 else if (line_start_position == pos
6818 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 6819 {
06a2c219 6820 maybe_next_line_p = 1;
77b68646
RS
6821 break;
6822 }
06a2c219
GM
6823 else if (line_start_position > 0)
6824 {
6825 best_row = row;
6826 best_row_vpos = row_vpos;
6827 }
6828
6829 ++row;
6830 ++row_vpos;
b8009dd1 6831 }
06a2c219
GM
6832
6833 /* Find the right column within BEST_ROW. */
6834 lastcol = 0;
6835 current_x = best_row->x;
6836 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 6837 {
06a2c219
GM
6838 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
6839 int charpos;
6840
6841 charpos = glyph->charpos;
6842 if (charpos == pos)
bf1c0ba1 6843 {
06a2c219
GM
6844 *hpos = i;
6845 *vpos = best_row_vpos;
6846 *x = current_x;
6847 *y = best_row->y;
bf1c0ba1
RS
6848 return 1;
6849 }
06a2c219 6850 else if (charpos > pos)
4d73d038 6851 break;
06a2c219
GM
6852 else if (charpos > 0)
6853 lastcol = i;
6854
6855 current_x += glyph->pixel_width;
bf1c0ba1 6856 }
b8009dd1 6857
77b68646
RS
6858 /* If we're looking for the end of the buffer,
6859 and we didn't find it in the line we scanned,
6860 use the start of the following line. */
06a2c219 6861 if (maybe_next_line_p)
77b68646 6862 {
06a2c219
GM
6863 ++best_row;
6864 ++best_row_vpos;
6865 lastcol = 0;
6866 current_x = best_row->x;
77b68646
RS
6867 }
6868
06a2c219
GM
6869 *vpos = best_row_vpos;
6870 *hpos = lastcol + 1;
6871 *x = current_x;
6872 *y = best_row->y;
b8009dd1
RS
6873 return 0;
6874}
6875
06a2c219 6876
b8009dd1
RS
6877/* Display the active region described by mouse_face_*
6878 in its mouse-face if HL > 0, in its normal face if HL = 0. */
6879
6880static void
06a2c219 6881show_mouse_face (dpyinfo, draw)
7a13e894 6882 struct x_display_info *dpyinfo;
06a2c219 6883 enum draw_glyphs_face draw;
b8009dd1 6884{
7a13e894 6885 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 6886 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 6887 int i;
06a2c219
GM
6888 int cursor_off_p = 0;
6889 struct cursor_pos saved_cursor;
6890
6891 saved_cursor = output_cursor;
6892
6893 /* If window is in the process of being destroyed, don't bother
6894 to do anything. */
6895 if (w->current_matrix == NULL)
6896 goto set_x_cursor;
6897
6898 /* Recognize when we are called to operate on rows that don't exist
6899 anymore. This can happen when a window is split. */
6900 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
6901 goto set_x_cursor;
6902
6903 set_output_cursor (&w->phys_cursor);
6904
6905 /* Note that mouse_face_beg_row etc. are window relative. */
6906 for (i = dpyinfo->mouse_face_beg_row;
6907 i <= dpyinfo->mouse_face_end_row;
6908 i++)
6909 {
6910 int start_hpos, end_hpos, start_x;
6911 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
6912
6913 /* Don't do anything if row doesn't have valid contents. */
6914 if (!row->enabled_p)
6915 continue;
6916
6917 /* For all but the first row, the highlight starts at column 0. */
6918 if (i == dpyinfo->mouse_face_beg_row)
6919 {
6920 start_hpos = dpyinfo->mouse_face_beg_col;
6921 start_x = dpyinfo->mouse_face_beg_x;
6922 }
6923 else
6924 {
6925 start_hpos = 0;
6926 start_x = 0;
6927 }
6928
6929 if (i == dpyinfo->mouse_face_end_row)
6930 end_hpos = dpyinfo->mouse_face_end_col;
6931 else
6932 end_hpos = row->used[TEXT_AREA];
6933
6934 /* If the cursor's in the text we are about to rewrite, turn the
6935 cursor off. */
6936 if (!w->pseudo_window_p
6937 && i == output_cursor.vpos
6938 && output_cursor.hpos >= start_hpos - 1
6939 && output_cursor.hpos <= end_hpos)
514e4681 6940 {
06a2c219
GM
6941 x_update_window_cursor (w, 0);
6942 cursor_off_p = 1;
514e4681 6943 }
b8009dd1 6944
06a2c219 6945 if (end_hpos > start_hpos)
54a91a0f 6946 x_draw_glyphs (w, start_x, row, TEXT_AREA,
66ac4b0e 6947 start_hpos, end_hpos, draw, NULL, NULL, 0);
b8009dd1
RS
6948 }
6949
514e4681 6950 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
6951 if (cursor_off_p)
6952 x_display_cursor (w, 1,
6953 output_cursor.hpos, output_cursor.vpos,
6954 output_cursor.x, output_cursor.y);
2729a2b5 6955
06a2c219 6956 output_cursor = saved_cursor;
fb3b7de5 6957
06a2c219
GM
6958 set_x_cursor:
6959
6960 /* Change the mouse cursor. */
6961 if (draw == DRAW_NORMAL_TEXT)
6962 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6963 f->output_data.x->text_cursor);
6964 else if (draw == DRAW_MOUSE_FACE)
334208b7 6965 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6966 f->output_data.x->cross_cursor);
27ead1d5 6967 else
334208b7 6968 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 6969 f->output_data.x->nontext_cursor);
b8009dd1
RS
6970}
6971
6972/* Clear out the mouse-highlighted active region.
06a2c219 6973 Redraw it un-highlighted first. */
b8009dd1 6974
06a2c219 6975void
7a13e894
RS
6976clear_mouse_face (dpyinfo)
6977 struct x_display_info *dpyinfo;
b8009dd1 6978{
06a2c219
GM
6979 if (tip_frame)
6980 return;
6981
7a13e894 6982 if (! NILP (dpyinfo->mouse_face_window))
06a2c219 6983 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
b8009dd1 6984
7a13e894
RS
6985 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
6986 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
6987 dpyinfo->mouse_face_window = Qnil;
b8009dd1 6988}
e687d06e
RS
6989
6990/* Just discard the mouse face information for frame F, if any.
6991 This is used when the size of F is changed. */
6992
dfcf069d 6993void
e687d06e
RS
6994cancel_mouse_face (f)
6995 FRAME_PTR f;
6996{
6997 Lisp_Object window;
6998 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6999
7000 window = dpyinfo->mouse_face_window;
7001 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7002 {
7003 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7004 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7005 dpyinfo->mouse_face_window = Qnil;
7006 }
7007}
b8009dd1 7008\f
ab648270
JB
7009static struct scroll_bar *x_window_to_scroll_bar ();
7010static void x_scroll_bar_report_motion ();
12ba150f 7011
90e65f07 7012/* Return the current position of the mouse.
2d7fc7e8 7013 *fp should be a frame which indicates which display to ask about.
90e65f07 7014
2d7fc7e8 7015 If the mouse movement started in a scroll bar, set *fp, *bar_window,
ab648270 7016 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 7017 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 7018 position on the scroll bar.
12ba150f 7019
2d7fc7e8 7020 If the mouse movement started elsewhere, set *fp to the frame the
12ba150f
JB
7021 mouse is on, *bar_window to nil, and *x and *y to the character cell
7022 the mouse is over.
7023
06a2c219 7024 Set *time to the server time-stamp for the time at which the mouse
12ba150f
JB
7025 was at this position.
7026
a135645a
RS
7027 Don't store anything if we don't have a valid set of values to report.
7028
90e65f07 7029 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7030 movement. */
90e65f07
JB
7031
7032static void
1cf412ec 7033XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7034 FRAME_PTR *fp;
1cf412ec 7035 int insist;
12ba150f 7036 Lisp_Object *bar_window;
ab648270 7037 enum scroll_bar_part *part;
90e65f07 7038 Lisp_Object *x, *y;
e5d77022 7039 unsigned long *time;
90e65f07 7040{
a135645a
RS
7041 FRAME_PTR f1;
7042
90e65f07
JB
7043 BLOCK_INPUT;
7044
8bcee03e 7045 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7046 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7047 else
7048 {
12ba150f
JB
7049 Window root;
7050 int root_x, root_y;
90e65f07 7051
12ba150f
JB
7052 Window dummy_window;
7053 int dummy;
7054
39d8bb4d
KH
7055 Lisp_Object frame, tail;
7056
7057 /* Clear the mouse-moved flag for every frame on this display. */
7058 FOR_EACH_FRAME (tail, frame)
7059 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7060 XFRAME (frame)->mouse_moved = 0;
7061
ab648270 7062 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7063
7064 /* Figure out which root window we're on. */
334208b7
RS
7065 XQueryPointer (FRAME_X_DISPLAY (*fp),
7066 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7067
7068 /* The root window which contains the pointer. */
7069 &root,
7070
7071 /* Trash which we can't trust if the pointer is on
7072 a different screen. */
7073 &dummy_window,
7074
7075 /* The position on that root window. */
58769bee 7076 &root_x, &root_y,
12ba150f
JB
7077
7078 /* More trash we can't trust. */
7079 &dummy, &dummy,
7080
7081 /* Modifier keys and pointer buttons, about which
7082 we don't care. */
7083 (unsigned int *) &dummy);
7084
7085 /* Now we have a position on the root; find the innermost window
7086 containing the pointer. */
7087 {
7088 Window win, child;
7089 int win_x, win_y;
06a2c219 7090 int parent_x = 0, parent_y = 0;
e99db5a1 7091 int count;
12ba150f
JB
7092
7093 win = root;
69388238 7094
2d7fc7e8
RS
7095 /* XTranslateCoordinates can get errors if the window
7096 structure is changing at the same time this function
7097 is running. So at least we must not crash from them. */
7098
e99db5a1 7099 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 7100
334208b7 7101 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 7102 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 7103 {
69388238
RS
7104 /* If mouse was grabbed on a frame, give coords for that frame
7105 even if the mouse is now outside it. */
334208b7 7106 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 7107
12ba150f 7108 /* From-window, to-window. */
69388238 7109 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
7110
7111 /* From-position, to-position. */
7112 root_x, root_y, &win_x, &win_y,
7113
7114 /* Child of win. */
7115 &child);
69388238
RS
7116 f1 = last_mouse_frame;
7117 }
7118 else
7119 {
7120 while (1)
7121 {
334208b7 7122 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 7123
69388238
RS
7124 /* From-window, to-window. */
7125 root, win,
12ba150f 7126
69388238
RS
7127 /* From-position, to-position. */
7128 root_x, root_y, &win_x, &win_y,
7129
7130 /* Child of win. */
7131 &child);
7132
9af3143a 7133 if (child == None || child == win)
69388238
RS
7134 break;
7135
7136 win = child;
7137 parent_x = win_x;
7138 parent_y = win_y;
7139 }
12ba150f 7140
69388238
RS
7141 /* Now we know that:
7142 win is the innermost window containing the pointer
7143 (XTC says it has no child containing the pointer),
7144 win_x and win_y are the pointer's position in it
7145 (XTC did this the last time through), and
7146 parent_x and parent_y are the pointer's position in win's parent.
7147 (They are what win_x and win_y were when win was child.
7148 If win is the root window, it has no parent, and
7149 parent_{x,y} are invalid, but that's okay, because we'll
7150 never use them in that case.) */
7151
7152 /* Is win one of our frames? */
19126e11 7153 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
69388238 7154 }
58769bee 7155
2d7fc7e8
RS
7156 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
7157 f1 = 0;
7158
e99db5a1 7159 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 7160
ab648270 7161 /* If not, is it one of our scroll bars? */
a135645a 7162 if (! f1)
12ba150f 7163 {
ab648270 7164 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
7165
7166 if (bar)
7167 {
a135645a 7168 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
7169 win_x = parent_x;
7170 win_y = parent_y;
7171 }
7172 }
90e65f07 7173
8bcee03e 7174 if (f1 == 0 && insist > 0)
b86bd3dd 7175 f1 = SELECTED_FRAME ();
1cf412ec 7176
a135645a 7177 if (f1)
12ba150f 7178 {
06a2c219
GM
7179 /* Ok, we found a frame. Store all the values.
7180 last_mouse_glyph is a rectangle used to reduce the
7181 generation of mouse events. To not miss any motion
7182 events, we must divide the frame into rectangles of the
7183 size of the smallest character that could be displayed
7184 on it, i.e. into the same rectangles that matrices on
7185 the frame are divided into. */
7186
7187#if OLD_REDISPLAY_CODE
2b5c9e71 7188 int ignore1, ignore2;
2b5c9e71 7189 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
334208b7 7190 &last_mouse_glyph,
1cf412ec
RS
7191 FRAME_X_DISPLAY_INFO (f1)->grabbed
7192 || insist);
06a2c219
GM
7193#else
7194 {
7195 int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
7196 int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
7197 int x = win_x;
7198 int y = win_y;
7199
7200 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
7201 round down even for negative values. */
7202 if (x < 0)
7203 x -= width - 1;
7204 if (y < 0)
7205 y -= height - 1;
7206
7207 last_mouse_glyph.width = width;
7208 last_mouse_glyph.height = height;
7209 last_mouse_glyph.x = (x + width - 1) / width * width;
7210 last_mouse_glyph.y = (y + height - 1) / height * height;
7211 }
7212#endif
12ba150f
JB
7213
7214 *bar_window = Qnil;
7215 *part = 0;
334208b7 7216 *fp = f1;
e0c1aef2
KH
7217 XSETINT (*x, win_x);
7218 XSETINT (*y, win_y);
12ba150f
JB
7219 *time = last_mouse_movement_time;
7220 }
7221 }
7222 }
90e65f07
JB
7223
7224 UNBLOCK_INPUT;
7225}
f451eb13 7226
06a2c219 7227
06a2c219 7228#ifdef USE_X_TOOLKIT
bffcfca9
GM
7229
7230/* Atimer callback function for TIMER. Called every 0.1s to process
7231 Xt timeouts, if needed. We must avoid calling XtAppPending as
7232 much as possible because that function does an implicit XFlush
7233 that slows us down. */
7234
7235static void
7236x_process_timeouts (timer)
7237 struct atimer *timer;
7238{
7239 if (toolkit_scroll_bar_interaction || popup_activated_flag)
7240 {
7241 BLOCK_INPUT;
7242 while (XtAppPending (Xt_app_con) & XtIMTimer)
7243 XtAppProcessEvent (Xt_app_con, XtIMTimer);
7244 UNBLOCK_INPUT;
7245 }
06a2c219
GM
7246}
7247
bffcfca9 7248#endif /* USE_X_TOOLKIT */
06a2c219
GM
7249
7250\f
7251/* Scroll bar support. */
7252
7253/* Given an X window ID, find the struct scroll_bar which manages it.
7254 This can be called in GC, so we have to make sure to strip off mark
7255 bits. */
bffcfca9 7256
06a2c219
GM
7257static struct scroll_bar *
7258x_window_to_scroll_bar (window_id)
7259 Window window_id;
7260{
7261 Lisp_Object tail;
7262
7263 for (tail = Vframe_list;
7264 XGCTYPE (tail) == Lisp_Cons;
8e713be6 7265 tail = XCDR (tail))
06a2c219
GM
7266 {
7267 Lisp_Object frame, bar, condemned;
7268
8e713be6 7269 frame = XCAR (tail);
06a2c219
GM
7270 /* All elements of Vframe_list should be frames. */
7271 if (! GC_FRAMEP (frame))
7272 abort ();
7273
7274 /* Scan this frame's scroll bar list for a scroll bar with the
7275 right window ID. */
7276 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
7277 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
7278 /* This trick allows us to search both the ordinary and
7279 condemned scroll bar lists with one loop. */
7280 ! GC_NILP (bar) || (bar = condemned,
7281 condemned = Qnil,
7282 ! GC_NILP (bar));
7283 bar = XSCROLL_BAR (bar)->next)
7284 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
7285 return XSCROLL_BAR (bar);
7286 }
7287
7288 return 0;
7289}
7290
7291
7292\f
7293/************************************************************************
7294 Toolkit scroll bars
7295 ************************************************************************/
7296
7297#if USE_TOOLKIT_SCROLL_BARS
7298
7299static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
7300static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
7301static void x_create_toolkit_scroll_bar P_ ((struct frame *,
7302 struct scroll_bar *));
7303static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
7304 int, int, int));
7305
7306
7307/* Id of action hook installed for scroll bars. */
7308
7309static XtActionHookId action_hook_id;
7310
7311/* Lisp window being scrolled. Set when starting to interact with
7312 a toolkit scroll bar, reset to nil when ending the interaction. */
7313
7314static Lisp_Object window_being_scrolled;
7315
7316/* Last scroll bar part sent in xm_scroll_callback. */
7317
7318static int last_scroll_bar_part;
7319
ec18280f
SM
7320/* Whether this is an Xaw with arrow-scrollbars. This should imply
7321 that movements of 1/20 of the screen size are mapped to up/down. */
7322
7323static Boolean xaw3d_arrow_scroll;
7324
7325/* Whether the drag scrolling maintains the mouse at the top of the
7326 thumb. If not, resizing the thumb needs to be done more carefully
7327 to avoid jerkyness. */
7328
7329static Boolean xaw3d_pick_top;
7330
06a2c219
GM
7331
7332/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 7333 bars are used.. The hook is responsible for detecting when
06a2c219
GM
7334 the user ends an interaction with the scroll bar, and generates
7335 a `end-scroll' scroll_bar_click' event if so. */
7336
7337static void
7338xt_action_hook (widget, client_data, action_name, event, params,
7339 num_params)
7340 Widget widget;
7341 XtPointer client_data;
7342 String action_name;
7343 XEvent *event;
7344 String *params;
7345 Cardinal *num_params;
7346{
7347 int scroll_bar_p;
7348 char *end_action;
7349
7350#ifdef USE_MOTIF
7351 scroll_bar_p = XmIsScrollBar (widget);
7352 end_action = "Release";
ec18280f 7353#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7354 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
7355 end_action = "EndScroll";
ec18280f 7356#endif /* USE_MOTIF */
06a2c219 7357
06a2c219
GM
7358 if (scroll_bar_p
7359 && strcmp (action_name, end_action) == 0
7360 && WINDOWP (window_being_scrolled))
7361 {
7362 struct window *w;
7363
7364 x_send_scroll_bar_event (window_being_scrolled,
7365 scroll_bar_end_scroll, 0, 0);
7366 w = XWINDOW (window_being_scrolled);
7367 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
7368 window_being_scrolled = Qnil;
7369 last_scroll_bar_part = -1;
bffcfca9
GM
7370
7371 /* Xt timeouts no longer needed. */
7372 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
7373 }
7374}
7375
7376
7377/* Send a client message with message type Xatom_Scrollbar for a
7378 scroll action to the frame of WINDOW. PART is a value identifying
7379 the part of the scroll bar that was clicked on. PORTION is the
7380 amount to scroll of a whole of WHOLE. */
7381
7382static void
7383x_send_scroll_bar_event (window, part, portion, whole)
7384 Lisp_Object window;
7385 int part, portion, whole;
7386{
7387 XEvent event;
7388 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
7389 struct frame *f = XFRAME (XWINDOW (window)->frame);
7390
7391 /* Construct a ClientMessage event to send to the frame. */
7392 ev->type = ClientMessage;
7393 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
7394 ev->display = FRAME_X_DISPLAY (f);
7395 ev->window = FRAME_X_WINDOW (f);
7396 ev->format = 32;
7397 ev->data.l[0] = (long) window;
7398 ev->data.l[1] = (long) part;
7399 ev->data.l[2] = (long) 0;
7400 ev->data.l[3] = (long) portion;
7401 ev->data.l[4] = (long) whole;
7402
bffcfca9
GM
7403 /* Make Xt timeouts work while the scroll bar is active. */
7404 toolkit_scroll_bar_interaction = 1;
7405
06a2c219
GM
7406 /* Setting the event mask to zero means that the message will
7407 be sent to the client that created the window, and if that
7408 window no longer exists, no event will be sent. */
7409 BLOCK_INPUT;
7410 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
7411 UNBLOCK_INPUT;
7412}
7413
7414
7415/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
7416 in *IEVENT. */
7417
7418static void
7419x_scroll_bar_to_input_event (event, ievent)
7420 XEvent *event;
7421 struct input_event *ievent;
7422{
7423 XClientMessageEvent *ev = (XClientMessageEvent *) event;
7424 Lisp_Object window = (Lisp_Object) ev->data.l[0];
7425 struct frame *f = XFRAME (XWINDOW (window)->frame);
7426
7427 ievent->kind = scroll_bar_click;
7428 ievent->frame_or_window = window;
7429 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
7430 ievent->part = ev->data.l[1];
7431 ievent->code = ev->data.l[2];
7432 ievent->x = make_number ((int) ev->data.l[3]);
7433 ievent->y = make_number ((int) ev->data.l[4]);
7434 ievent->modifiers = 0;
7435}
7436
7437
7438#ifdef USE_MOTIF
7439
7440/* Minimum and maximum values used for Motif scroll bars. */
7441
7442#define XM_SB_MIN 1
7443#define XM_SB_MAX 10000000
7444#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
7445
7446
7447/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
7448 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
7449 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
7450
7451static void
7452xm_scroll_callback (widget, client_data, call_data)
7453 Widget widget;
7454 XtPointer client_data, call_data;
7455{
7456 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7457 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
7458 double percent;
7459 int part = -1, whole = 0, portion = 0;
7460
7461 switch (cs->reason)
7462 {
7463 case XmCR_DECREMENT:
7464 bar->dragging = Qnil;
7465 part = scroll_bar_up_arrow;
7466 break;
7467
7468 case XmCR_INCREMENT:
7469 bar->dragging = Qnil;
7470 part = scroll_bar_down_arrow;
7471 break;
7472
7473 case XmCR_PAGE_DECREMENT:
7474 bar->dragging = Qnil;
7475 part = scroll_bar_above_handle;
7476 break;
7477
7478 case XmCR_PAGE_INCREMENT:
7479 bar->dragging = Qnil;
7480 part = scroll_bar_below_handle;
7481 break;
7482
7483 case XmCR_TO_TOP:
7484 bar->dragging = Qnil;
7485 part = scroll_bar_to_top;
7486 break;
7487
7488 case XmCR_TO_BOTTOM:
7489 bar->dragging = Qnil;
7490 part = scroll_bar_to_bottom;
7491 break;
7492
7493 case XmCR_DRAG:
7494 {
7495 int slider_size;
7496 int dragging_down_p = (INTEGERP (bar->dragging)
7497 && XINT (bar->dragging) <= cs->value);
7498
7499 /* Get the slider size. */
7500 BLOCK_INPUT;
7501 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
7502 UNBLOCK_INPUT;
7503
7504 /* At the max position of the scroll bar, do a line-wise
7505 movement. Without doing anything, the LessTif scroll bar
7506 calls us with the same cs->value again and again. If we
7507 want to make sure that we can reach the end of the buffer,
7508 we have to do something.
7509
7510 Implementation note: setting bar->dragging always to
7511 cs->value gives a smoother movement at the max position.
7512 Setting it to nil when doing line-wise movement gives
7513 a better slider behavior. */
7514
7515 if (cs->value + slider_size == XM_SB_MAX
7516 || (dragging_down_p
7517 && last_scroll_bar_part == scroll_bar_down_arrow))
7518 {
7519 part = scroll_bar_down_arrow;
7520 bar->dragging = Qnil;
7521 }
7522 else
7523 {
7524 whole = XM_SB_RANGE;
7525 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
7526 part = scroll_bar_handle;
7527 bar->dragging = make_number (cs->value);
7528 }
7529 }
7530 break;
7531
7532 case XmCR_VALUE_CHANGED:
7533 break;
7534 };
7535
7536 if (part >= 0)
7537 {
7538 window_being_scrolled = bar->window;
7539 last_scroll_bar_part = part;
7540 x_send_scroll_bar_event (bar->window, part, portion, whole);
7541 }
7542}
7543
7544
ec18280f 7545#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
7546
7547
ec18280f 7548/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
7549 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
7550 scroll bar struct. CALL_DATA is a pointer to a float saying where
7551 the thumb is. */
7552
7553static void
ec18280f 7554xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
7555 Widget widget;
7556 XtPointer client_data, call_data;
7557{
7558 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7559 float top = *(float *) call_data;
7560 float shown;
ec18280f
SM
7561 int whole, portion, height;
7562 int part;
06a2c219
GM
7563
7564 /* Get the size of the thumb, a value between 0 and 1. */
7565 BLOCK_INPUT;
ec18280f 7566 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
7567 UNBLOCK_INPUT;
7568
7569 whole = 10000000;
7570 portion = shown < 1 ? top * whole : 0;
06a2c219 7571
ec18280f
SM
7572 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
7573 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
7574 the bottom, so we force the scrolling whenever we see that we're
7575 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
7576 we try to ensure that we always stay two pixels away from the
7577 bottom). */
06a2c219
GM
7578 part = scroll_bar_down_arrow;
7579 else
7580 part = scroll_bar_handle;
7581
7582 window_being_scrolled = bar->window;
7583 bar->dragging = make_number (portion);
7584 last_scroll_bar_part = part;
7585 x_send_scroll_bar_event (bar->window, part, portion, whole);
7586}
7587
7588
ec18280f
SM
7589/* Xaw scroll bar callback. Invoked for incremental scrolling.,
7590 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
7591 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
7592 the scroll bar. CALL_DATA is an integer specifying the action that
7593 has taken place. It's magnitude is in the range 0..height of the
7594 scroll bar. Negative values mean scroll towards buffer start.
7595 Values < height of scroll bar mean line-wise movement. */
7596
7597static void
ec18280f 7598xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
7599 Widget widget;
7600 XtPointer client_data, call_data;
7601{
7602 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7603 int position = (int) call_data;
7604 Dimension height;
7605 int part;
7606
7607 /* Get the height of the scroll bar. */
7608 BLOCK_INPUT;
7609 XtVaGetValues (widget, XtNheight, &height, NULL);
7610 UNBLOCK_INPUT;
7611
ec18280f
SM
7612 if (abs (position) >= height)
7613 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
7614
7615 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
7616 it maps line-movement to call_data = max(5, height/20). */
7617 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
7618 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 7619 else
ec18280f 7620 part = scroll_bar_move_ratio;
06a2c219
GM
7621
7622 window_being_scrolled = bar->window;
7623 bar->dragging = Qnil;
7624 last_scroll_bar_part = part;
ec18280f 7625 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
7626}
7627
7628
7629#endif /* not USE_MOTIF */
7630
7631
7632/* Create the widget for scroll bar BAR on frame F. Record the widget
7633 and X window of the scroll bar in BAR. */
7634
7635static void
7636x_create_toolkit_scroll_bar (f, bar)
7637 struct frame *f;
7638 struct scroll_bar *bar;
7639{
7640 Window xwindow;
7641 Widget widget;
7642 Arg av[20];
7643 int ac = 0;
7644 char *scroll_bar_name = "verticalScrollBar";
7645 unsigned long pixel;
7646
7647 BLOCK_INPUT;
7648
7649#ifdef USE_MOTIF
7650 /* LessTif 0.85, problems:
7651
7652 1. When the mouse if over the scroll bar, the scroll bar will
7653 get keyboard events. I didn't find a way to turn this off.
7654
7655 2. Do we have to explicitly set the cursor to get an arrow
7656 cursor (see below)? */
7657
7658 /* Set resources. Create the widget. */
7659 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7660 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
7661 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
7662 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
7663 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
7664 XtSetArg (av[ac], XmNincrement, 1); ++ac;
7665 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
7666
7667 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7668 if (pixel != -1)
7669 {
7670 XtSetArg (av[ac], XmNforeground, pixel);
7671 ++ac;
7672 }
7673
7674 pixel = f->output_data.x->scroll_bar_background_pixel;
7675 if (pixel != -1)
7676 {
7677 XtSetArg (av[ac], XmNbackground, pixel);
7678 ++ac;
7679 }
7680
7681 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
7682 scroll_bar_name, av, ac);
7683
7684 /* Add one callback for everything that can happen. */
7685 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
7686 (XtPointer) bar);
7687 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
7688 (XtPointer) bar);
7689 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
7690 (XtPointer) bar);
7691 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
7692 (XtPointer) bar);
7693 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
7694 (XtPointer) bar);
7695 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
7696 (XtPointer) bar);
7697 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
7698 (XtPointer) bar);
7699
7700 /* Realize the widget. Only after that is the X window created. */
7701 XtRealizeWidget (widget);
7702
7703 /* Set the cursor to an arrow. I didn't find a resource to do that.
7704 And I'm wondering why it hasn't an arrow cursor by default. */
7705 XDefineCursor (XtDisplay (widget), XtWindow (widget),
7706 f->output_data.x->nontext_cursor);
7707
ec18280f 7708#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7709
7710 /* Set resources. Create the widget. The background of the
7711 Xaw3d scroll bar widget is a little bit light for my taste.
7712 We don't alter it here to let users change it according
7713 to their taste with `emacs*verticalScrollBar.background: xxx'. */
7714 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7715 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
7716 /* For smoother scrolling with Xaw3d -sm */
7717 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
7718 /* XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac; */
06a2c219
GM
7719
7720 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7721 if (pixel != -1)
7722 {
7723 XtSetArg (av[ac], XtNforeground, pixel);
7724 ++ac;
7725 }
7726
7727 pixel = f->output_data.x->scroll_bar_background_pixel;
7728 if (pixel != -1)
7729 {
7730 XtSetArg (av[ac], XtNbackground, pixel);
7731 ++ac;
7732 }
7733
7734 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
7735 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
7736
7737 {
7738 char *initial = "";
7739 char *val = initial;
7740 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
7741 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
7742 if (val == initial)
7743 { /* ARROW_SCROLL */
7744 xaw3d_arrow_scroll = True;
7745 /* Isn't that just a personal preference ? -sm */
7746 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
7747 }
7748 }
06a2c219
GM
7749
7750 /* Define callbacks. */
ec18280f
SM
7751 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
7752 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
7753 (XtPointer) bar);
7754
7755 /* Realize the widget. Only after that is the X window created. */
7756 XtRealizeWidget (widget);
7757
ec18280f 7758#endif /* !USE_MOTIF */
06a2c219
GM
7759
7760 /* Install an action hook that let's us detect when the user
7761 finishes interacting with a scroll bar. */
7762 if (action_hook_id == 0)
7763 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
7764
7765 /* Remember X window and widget in the scroll bar vector. */
7766 SET_SCROLL_BAR_X_WIDGET (bar, widget);
7767 xwindow = XtWindow (widget);
7768 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
7769
7770 UNBLOCK_INPUT;
7771}
7772
7773
7774/* Set the thumb size and position of scroll bar BAR. We are currently
7775 displaying PORTION out of a whole WHOLE, and our position POSITION. */
7776
7777static void
7778x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
7779 struct scroll_bar *bar;
7780 int portion, position, whole;
f451eb13 7781{
06a2c219 7782 float top, shown;
06a2c219 7783 Widget widget = SCROLL_BAR_X_WIDGET (bar);
f451eb13 7784
06a2c219
GM
7785 if (whole == 0)
7786 top = 0, shown = 1;
7787 else
f451eb13 7788 {
06a2c219
GM
7789 top = (float) position / whole;
7790 shown = (float) portion / whole;
7791 }
f451eb13 7792
06a2c219 7793 BLOCK_INPUT;
f451eb13 7794
06a2c219
GM
7795#ifdef USE_MOTIF
7796 {
7797 int size, value;
7798 Boolean arrow1_selected, arrow2_selected;
7799 unsigned char flags;
7800 XmScrollBarWidget sb;
7801
ec18280f 7802 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
7803 is the scroll bar's maximum and MIN is the scroll bar's minimum
7804 value. */
7805 size = shown * XM_SB_RANGE;
7806 size = min (size, XM_SB_RANGE);
7807 size = max (size, 1);
7808
7809 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
7810 value = top * XM_SB_RANGE;
7811 value = min (value, XM_SB_MAX - size);
7812 value = max (value, XM_SB_MIN);
7813
7814 /* LessTif: Calling XmScrollBarSetValues after an increment or
7815 decrement turns off auto-repeat LessTif-internally. This can
7816 be seen in ScrollBar.c which resets Arrow1Selected and
7817 Arrow2Selected. It also sets internal flags so that LessTif
7818 believes the mouse is in the slider. We either have to change
7819 our code, or work around that by accessing private data. */
7820
7821 sb = (XmScrollBarWidget) widget;
7822 arrow1_selected = sb->scrollBar.arrow1_selected;
7823 arrow2_selected = sb->scrollBar.arrow2_selected;
7824 flags = sb->scrollBar.flags;
7825
7826 if (NILP (bar->dragging))
7827 XmScrollBarSetValues (widget, value, size, 0, 0, False);
7828 else if (last_scroll_bar_part == scroll_bar_down_arrow)
7829 /* This has the negative side effect that the slider value is
ec18280f 7830 not what it would be if we scrolled here using line-wise or
06a2c219
GM
7831 page-wise movement. */
7832 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
7833 else
7834 {
7835 /* If currently dragging, only update the slider size.
7836 This reduces flicker effects. */
7837 int old_value, old_size, increment, page_increment;
7838
7839 XmScrollBarGetValues (widget, &old_value, &old_size,
7840 &increment, &page_increment);
7841 XmScrollBarSetValues (widget, old_value,
7842 min (size, XM_SB_RANGE - old_value),
7843 0, 0, False);
7844 }
7845
7846 sb->scrollBar.arrow1_selected = arrow1_selected;
7847 sb->scrollBar.arrow2_selected = arrow2_selected;
7848 sb->scrollBar.flags = flags;
7849 }
ec18280f 7850#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 7851 {
ec18280f
SM
7852 float old_top, old_shown;
7853 Dimension height;
7854 XtVaGetValues (widget,
7855 XtNtopOfThumb, &old_top,
7856 XtNshown, &old_shown,
7857 XtNheight, &height,
7858 NULL);
7859
7860 /* Massage the top+shown values. */
7861 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
7862 top = max (0, min (1, top));
7863 else
7864 top = old_top;
7865 /* Keep two pixels available for moving the thumb down. */
7866 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
7867
7868 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
7869 check that your system's configuration file contains a define
7870 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 7871 if (top != old_top || shown != old_shown)
eb393530 7872 {
ec18280f 7873 if (NILP (bar->dragging))
eb393530 7874 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
7875 else
7876 {
ec18280f
SM
7877#ifdef HAVE_XAW3D
7878 ScrollbarWidget sb = (ScrollbarWidget) widget;
7879 int scroll_mode;
7880
7881 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
7882 if (xaw3d_arrow_scroll)
7883 {
7884 /* Xaw3d stupidly ignores resize requests while dragging
7885 so we have to make it believe it's not in dragging mode. */
7886 scroll_mode = sb->scrollbar.scroll_mode;
7887 if (scroll_mode == 2)
7888 sb->scrollbar.scroll_mode = 0;
7889 }
7890#endif
7891 /* Try to make the scrolling a tad smoother. */
7892 if (!xaw3d_pick_top)
7893 shown = min (shown, old_shown);
7894
7895 XawScrollbarSetThumb (widget, top, shown);
7896
7897#ifdef HAVE_XAW3D
7898 if (xaw3d_arrow_scroll && scroll_mode == 2)
7899 sb->scrollbar.scroll_mode = scroll_mode;
7900#endif
06a2c219 7901 }
06a2c219
GM
7902 }
7903 }
ec18280f 7904#endif /* !USE_MOTIF */
06a2c219
GM
7905
7906 UNBLOCK_INPUT;
f451eb13
JB
7907}
7908
06a2c219
GM
7909#endif /* USE_TOOLKIT_SCROLL_BARS */
7910
7911
7912\f
7913/************************************************************************
7914 Scroll bars, general
7915 ************************************************************************/
7916
7917/* Create a scroll bar and return the scroll bar vector for it. W is
7918 the Emacs window on which to create the scroll bar. TOP, LEFT,
7919 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
7920 scroll bar. */
7921
ab648270 7922static struct scroll_bar *
06a2c219
GM
7923x_scroll_bar_create (w, top, left, width, height)
7924 struct window *w;
f451eb13
JB
7925 int top, left, width, height;
7926{
06a2c219 7927 struct frame *f = XFRAME (w->frame);
334208b7
RS
7928 struct scroll_bar *bar
7929 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
7930
7931 BLOCK_INPUT;
7932
06a2c219
GM
7933#if USE_TOOLKIT_SCROLL_BARS
7934 x_create_toolkit_scroll_bar (f, bar);
7935#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
7936 {
7937 XSetWindowAttributes a;
7938 unsigned long mask;
5c187dee 7939 Window window;
06a2c219
GM
7940
7941 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
7942 if (a.background_pixel == -1)
7943 a.background_pixel = f->output_data.x->background_pixel;
7944
12ba150f 7945 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 7946 | ButtonMotionMask | PointerMotionHintMask
12ba150f 7947 | ExposureMask);
7a13e894 7948 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 7949
dbc4e1c1 7950 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 7951
06a2c219
GM
7952 /* Clear the area of W that will serve as a scroll bar. This is
7953 for the case that a window has been split horizontally. In
7954 this case, no clear_frame is generated to reduce flickering. */
7955 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7956 left, top, width,
7957 window_box_height (w), False);
7958
7959 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7960 /* Position and size of scroll bar. */
7961 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7962 top,
7963 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
7964 height,
7965 /* Border width, depth, class, and visual. */
7966 0,
7967 CopyFromParent,
7968 CopyFromParent,
7969 CopyFromParent,
7970 /* Attributes. */
7971 mask, &a);
7972 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 7973 }
06a2c219 7974#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 7975
06a2c219 7976 XSETWINDOW (bar->window, w);
e0c1aef2
KH
7977 XSETINT (bar->top, top);
7978 XSETINT (bar->left, left);
7979 XSETINT (bar->width, width);
7980 XSETINT (bar->height, height);
7981 XSETINT (bar->start, 0);
7982 XSETINT (bar->end, 0);
12ba150f 7983 bar->dragging = Qnil;
f451eb13
JB
7984
7985 /* Add bar to its frame's list of scroll bars. */
334208b7 7986 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 7987 bar->prev = Qnil;
334208b7 7988 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 7989 if (!NILP (bar->next))
e0c1aef2 7990 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 7991
06a2c219
GM
7992 /* Map the window/widget. */
7993#if USE_TOOLKIT_SCROLL_BARS
7994 XtMapWidget (SCROLL_BAR_X_WIDGET (bar));
7995 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
7996 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7997 top,
7998 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
7999 height, 0);
8000#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 8001 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 8002#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8003
8004 UNBLOCK_INPUT;
12ba150f 8005 return bar;
f451eb13
JB
8006}
8007
06a2c219 8008
12ba150f 8009/* Draw BAR's handle in the proper position.
06a2c219 8010
12ba150f
JB
8011 If the handle is already drawn from START to END, don't bother
8012 redrawing it, unless REBUILD is non-zero; in that case, always
8013 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 8014 events.)
12ba150f
JB
8015
8016 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
8017 fit inside its rectangle, but if the user is dragging the scroll
8018 bar handle, we want to let them drag it down all the way, so that
8019 the bar's top is as far down as it goes; otherwise, there's no way
8020 to move to the very end of the buffer. */
8021
5c187dee
GM
8022#ifndef USE_TOOLKIT_SCROLL_BARS
8023
f451eb13 8024static void
ab648270
JB
8025x_scroll_bar_set_handle (bar, start, end, rebuild)
8026 struct scroll_bar *bar;
f451eb13 8027 int start, end;
12ba150f 8028 int rebuild;
f451eb13 8029{
12ba150f 8030 int dragging = ! NILP (bar->dragging);
ab648270 8031 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8032 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8033 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
8034
8035 /* If the display is already accurate, do nothing. */
8036 if (! rebuild
8037 && start == XINT (bar->start)
8038 && end == XINT (bar->end))
8039 return;
8040
f451eb13
JB
8041 BLOCK_INPUT;
8042
8043 {
d9cdbb3d
RS
8044 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
8045 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
8046 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
8047
8048 /* Make sure the values are reasonable, and try to preserve
8049 the distance between start and end. */
12ba150f
JB
8050 {
8051 int length = end - start;
8052
8053 if (start < 0)
8054 start = 0;
8055 else if (start > top_range)
8056 start = top_range;
8057 end = start + length;
8058
8059 if (end < start)
8060 end = start;
8061 else if (end > top_range && ! dragging)
8062 end = top_range;
8063 }
f451eb13 8064
ab648270 8065 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
8066 XSETINT (bar->start, start);
8067 XSETINT (bar->end, end);
f451eb13 8068
12ba150f
JB
8069 /* Clip the end position, just for display. */
8070 if (end > top_range)
8071 end = top_range;
f451eb13 8072
ab648270 8073 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
8074 below top positions, to make sure the handle is always at least
8075 that many pixels tall. */
ab648270 8076 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 8077
12ba150f
JB
8078 /* Draw the empty space above the handle. Note that we can't clear
8079 zero-height areas; that means "clear to end of window." */
8080 if (0 < start)
334208b7 8081 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8082
12ba150f 8083 /* x, y, width, height, and exposures. */
ab648270
JB
8084 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8085 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
8086 inside_width, start,
8087 False);
f451eb13 8088
06a2c219
GM
8089 /* Change to proper foreground color if one is specified. */
8090 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8091 XSetForeground (FRAME_X_DISPLAY (f), gc,
8092 f->output_data.x->scroll_bar_foreground_pixel);
8093
12ba150f 8094 /* Draw the handle itself. */
334208b7 8095 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 8096
12ba150f 8097 /* x, y, width, height */
ab648270
JB
8098 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8099 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 8100 inside_width, end - start);
f451eb13 8101
06a2c219
GM
8102 /* Restore the foreground color of the GC if we changed it above. */
8103 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8104 XSetForeground (FRAME_X_DISPLAY (f), gc,
8105 f->output_data.x->foreground_pixel);
f451eb13 8106
12ba150f
JB
8107 /* Draw the empty space below the handle. Note that we can't
8108 clear zero-height areas; that means "clear to end of window." */
8109 if (end < inside_height)
334208b7 8110 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8111
12ba150f 8112 /* x, y, width, height, and exposures. */
ab648270
JB
8113 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8114 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
8115 inside_width, inside_height - end,
8116 False);
f451eb13 8117
f451eb13
JB
8118 }
8119
f451eb13
JB
8120 UNBLOCK_INPUT;
8121}
8122
5c187dee 8123#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 8124
06a2c219
GM
8125/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
8126 nil. */
58769bee 8127
12ba150f 8128static void
ab648270
JB
8129x_scroll_bar_remove (bar)
8130 struct scroll_bar *bar;
12ba150f 8131{
12ba150f
JB
8132 BLOCK_INPUT;
8133
06a2c219
GM
8134#if USE_TOOLKIT_SCROLL_BARS
8135 XtDestroyWidget (SCROLL_BAR_X_WIDGET (bar));
8136#else /* not USE_TOOLKIT_SCROLL_BARS */
5c187dee
GM
8137 {
8138 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8139 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
8140 }
06a2c219
GM
8141#endif /* not USE_TOOLKIT_SCROLL_BARS */
8142
ab648270
JB
8143 /* Disassociate this scroll bar from its window. */
8144 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
8145
8146 UNBLOCK_INPUT;
8147}
8148
06a2c219 8149
12ba150f
JB
8150/* Set the handle of the vertical scroll bar for WINDOW to indicate
8151 that we are displaying PORTION characters out of a total of WHOLE
ab648270 8152 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 8153 create one. */
06a2c219 8154
12ba150f 8155static void
06a2c219
GM
8156XTset_vertical_scroll_bar (w, portion, whole, position)
8157 struct window *w;
f451eb13
JB
8158 int portion, whole, position;
8159{
06a2c219 8160 struct frame *f = XFRAME (w->frame);
ab648270 8161 struct scroll_bar *bar;
3c6ede7b 8162 int top, height, left, sb_left, width, sb_width;
06a2c219 8163 int window_x, window_y, window_width, window_height;
06a2c219 8164
3c6ede7b 8165 /* Get window dimensions. */
06a2c219 8166 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
8167 top = window_y;
8168 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
8169 height = window_height;
06a2c219 8170
3c6ede7b 8171 /* Compute the left edge of the scroll bar area. */
06a2c219 8172 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
8173 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
8174 else
8175 left = XFASTINT (w->left);
8176 left *= CANON_X_UNIT (f);
8177 left += FRAME_INTERNAL_BORDER_WIDTH (f);
8178
8179 /* Compute the width of the scroll bar which might be less than
8180 the width of the area reserved for the scroll bar. */
8181 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
8182 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 8183 else
3c6ede7b 8184 sb_width = width;
12ba150f 8185
3c6ede7b
GM
8186 /* Compute the left edge of the scroll bar. */
8187#ifdef USE_TOOLKIT_SCROLL_BARS
8188 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8189 sb_left = left + width - sb_width - (width - sb_width) / 2;
8190 else
8191 sb_left = left + (width - sb_width) / 2;
8192#else
8193 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8194 sb_left = left + width - sb_width;
8195 else
8196 sb_left = left;
8197#endif
8198
ab648270 8199 /* Does the scroll bar exist yet? */
06a2c219 8200 if (NILP (w->vertical_scroll_bar))
3c6ede7b 8201 {
80c32bcc 8202 BLOCK_INPUT;
3c6ede7b
GM
8203 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8204 left, top, width, height, False);
80c32bcc 8205 UNBLOCK_INPUT;
3c6ede7b
GM
8206 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
8207 }
f451eb13 8208 else
12ba150f
JB
8209 {
8210 /* It may just need to be moved and resized. */
06a2c219
GM
8211 unsigned int mask = 0;
8212
8213 bar = XSCROLL_BAR (w->vertical_scroll_bar);
8214
8215 BLOCK_INPUT;
8216
3c6ede7b 8217 if (sb_left != XINT (bar->left))
06a2c219 8218 mask |= CWX;
3c6ede7b 8219 if (top != XINT (bar->top))
06a2c219 8220 mask |= CWY;
3c6ede7b 8221 if (sb_width != XINT (bar->width))
06a2c219 8222 mask |= CWWidth;
3c6ede7b 8223 if (height != XINT (bar->height))
06a2c219
GM
8224 mask |= CWHeight;
8225
8226#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
8227
8228 /* Since toolkit scroll bars are smaller than the space reserved
8229 for them on the frame, we have to clear "under" them. */
8230 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3c6ede7b 8231 left, top, width, height, False);
06a2c219
GM
8232
8233 /* Move/size the scroll bar widget. */
8234 if (mask)
8235 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
3c6ede7b
GM
8236 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8237 top,
8238 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8239 height, 0);
06a2c219
GM
8240
8241#else /* not USE_TOOLKIT_SCROLL_BARS */
8242
e1f6572f
RS
8243 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
8244 {
8245 /* Clear areas not covered by the scroll bar. This makes sure a
8246 previous mode line display is cleared after C-x 2 C-x 1, for
8247 example. Non-toolkit scroll bars are as wide as the area
8248 reserved for scroll bars - trim at both sides. */
8249 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8250 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8251 height, False);
8252 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8253 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8254 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8255 height, False);
8256 }
06a2c219
GM
8257
8258 /* Move/size the scroll bar window. */
8259 if (mask)
8260 {
8261 XWindowChanges wc;
8262
3c6ede7b
GM
8263 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
8264 wc.y = top;
8265 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
8266 wc.height = height;
06a2c219
GM
8267 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
8268 mask, &wc);
8269 }
8270
8271#endif /* not USE_TOOLKIT_SCROLL_BARS */
8272
8273 /* Remember new settings. */
3c6ede7b
GM
8274 XSETINT (bar->left, sb_left);
8275 XSETINT (bar->top, top);
8276 XSETINT (bar->width, sb_width);
8277 XSETINT (bar->height, height);
06a2c219
GM
8278
8279 UNBLOCK_INPUT;
12ba150f 8280 }
f451eb13 8281
06a2c219
GM
8282#if USE_TOOLKIT_SCROLL_BARS
8283 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
8284#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 8285 /* Set the scroll bar's current state, unless we're currently being
f451eb13 8286 dragged. */
12ba150f 8287 if (NILP (bar->dragging))
f451eb13 8288 {
92857db0 8289 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 8290
12ba150f 8291 if (whole == 0)
ab648270 8292 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
8293 else
8294 {
43f868f5
JB
8295 int start = ((double) position * top_range) / whole;
8296 int end = ((double) (position + portion) * top_range) / whole;
ab648270 8297 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 8298 }
f451eb13 8299 }
06a2c219 8300#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8301
06a2c219 8302 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
8303}
8304
12ba150f 8305
f451eb13 8306/* The following three hooks are used when we're doing a thorough
ab648270 8307 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 8308 are going to be deleted, because keeping track of when windows go
12ba150f
JB
8309 away is a real pain - "Can you say set-window-configuration, boys
8310 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 8311 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 8312 from the fiery pit when we actually redisplay its window. */
f451eb13 8313
ab648270
JB
8314/* Arrange for all scroll bars on FRAME to be removed at the next call
8315 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
8316 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
8317
58769bee 8318static void
ab648270 8319XTcondemn_scroll_bars (frame)
f451eb13
JB
8320 FRAME_PTR frame;
8321{
f9e24cb9
RS
8322 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
8323 while (! NILP (FRAME_SCROLL_BARS (frame)))
8324 {
8325 Lisp_Object bar;
8326 bar = FRAME_SCROLL_BARS (frame);
8327 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
8328 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
8329 XSCROLL_BAR (bar)->prev = Qnil;
8330 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
8331 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
8332 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
8333 }
f451eb13
JB
8334}
8335
06a2c219 8336/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 8337 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 8338static void
ab648270 8339XTredeem_scroll_bar (window)
12ba150f 8340 struct window *window;
f451eb13 8341{
ab648270 8342 struct scroll_bar *bar;
12ba150f 8343
ab648270
JB
8344 /* We can't redeem this window's scroll bar if it doesn't have one. */
8345 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
8346 abort ();
8347
ab648270 8348 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
8349
8350 /* Unlink it from the condemned list. */
8351 {
8352 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
8353
8354 if (NILP (bar->prev))
8355 {
8356 /* If the prev pointer is nil, it must be the first in one of
8357 the lists. */
ab648270 8358 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
8359 /* It's not condemned. Everything's fine. */
8360 return;
ab648270
JB
8361 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
8362 window->vertical_scroll_bar))
8363 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
8364 else
8365 /* If its prev pointer is nil, it must be at the front of
8366 one or the other! */
8367 abort ();
8368 }
8369 else
ab648270 8370 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
8371
8372 if (! NILP (bar->next))
ab648270 8373 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 8374
ab648270 8375 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8376 bar->prev = Qnil;
e0c1aef2 8377 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 8378 if (! NILP (bar->next))
e0c1aef2 8379 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
12ba150f 8380 }
f451eb13
JB
8381}
8382
ab648270
JB
8383/* Remove all scroll bars on FRAME that haven't been saved since the
8384 last call to `*condemn_scroll_bars_hook'. */
06a2c219 8385
f451eb13 8386static void
ab648270 8387XTjudge_scroll_bars (f)
12ba150f 8388 FRAME_PTR f;
f451eb13 8389{
12ba150f 8390 Lisp_Object bar, next;
f451eb13 8391
ab648270 8392 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
8393
8394 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
8395 more events on the hapless scroll bars. */
8396 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
8397
8398 for (; ! NILP (bar); bar = next)
f451eb13 8399 {
ab648270 8400 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 8401
ab648270 8402 x_scroll_bar_remove (b);
12ba150f
JB
8403
8404 next = b->next;
8405 b->next = b->prev = Qnil;
f451eb13 8406 }
12ba150f 8407
ab648270 8408 /* Now there should be no references to the condemned scroll bars,
12ba150f 8409 and they should get garbage-collected. */
f451eb13
JB
8410}
8411
8412
06a2c219
GM
8413/* Handle an Expose or GraphicsExpose event on a scroll bar. This
8414 is a no-op when using toolkit scroll bars.
ab648270
JB
8415
8416 This may be called from a signal handler, so we have to ignore GC
8417 mark bits. */
06a2c219 8418
f451eb13 8419static void
ab648270
JB
8420x_scroll_bar_expose (bar, event)
8421 struct scroll_bar *bar;
f451eb13
JB
8422 XEvent *event;
8423{
06a2c219
GM
8424#ifndef USE_TOOLKIT_SCROLL_BARS
8425
ab648270 8426 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8427 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8428 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 8429 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 8430
f451eb13
JB
8431 BLOCK_INPUT;
8432
ab648270 8433 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 8434
06a2c219 8435 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 8436 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
8437
8438 /* x, y, width, height */
d9cdbb3d 8439 0, 0,
3cbd2e0b 8440 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
8441 XINT (bar->height) - 1);
8442
f451eb13 8443 UNBLOCK_INPUT;
06a2c219
GM
8444
8445#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8446}
8447
ab648270
JB
8448/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8449 is set to something other than no_event, it is enqueued.
8450
8451 This may be called from a signal handler, so we have to ignore GC
8452 mark bits. */
06a2c219 8453
5c187dee
GM
8454#ifndef USE_TOOLKIT_SCROLL_BARS
8455
f451eb13 8456static void
ab648270
JB
8457x_scroll_bar_handle_click (bar, event, emacs_event)
8458 struct scroll_bar *bar;
f451eb13
JB
8459 XEvent *event;
8460 struct input_event *emacs_event;
8461{
0299d313 8462 if (! GC_WINDOWP (bar->window))
12ba150f
JB
8463 abort ();
8464
ab648270 8465 emacs_event->kind = scroll_bar_click;
69388238 8466 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
8467 emacs_event->modifiers
8468 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
8469 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
8470 event->xbutton.state)
8471 | (event->type == ButtonRelease
8472 ? up_modifier
8473 : down_modifier));
12ba150f 8474 emacs_event->frame_or_window = bar->window;
f451eb13 8475 emacs_event->timestamp = event->xbutton.time;
12ba150f 8476 {
06a2c219 8477#if 0
d9cdbb3d 8478 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 8479 int internal_height
d9cdbb3d 8480 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8481#endif
0299d313 8482 int top_range
d9cdbb3d 8483 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 8484 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
8485
8486 if (y < 0) y = 0;
8487 if (y > top_range) y = top_range;
8488
8489 if (y < XINT (bar->start))
ab648270
JB
8490 emacs_event->part = scroll_bar_above_handle;
8491 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8492 emacs_event->part = scroll_bar_handle;
12ba150f 8493 else
ab648270 8494 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
8495
8496 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
8497 they want to drag it. Lisp code needs to be able to decide
8498 whether or not we're dragging. */
929787e1 8499#if 0
12ba150f
JB
8500 /* If the user has just clicked on the handle, record where they're
8501 holding it. */
8502 if (event->type == ButtonPress
ab648270 8503 && emacs_event->part == scroll_bar_handle)
e0c1aef2 8504 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 8505#endif
12ba150f
JB
8506
8507 /* If the user has released the handle, set it to its final position. */
8508 if (event->type == ButtonRelease
8509 && ! NILP (bar->dragging))
8510 {
8511 int new_start = y - XINT (bar->dragging);
8512 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 8513
ab648270 8514 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
8515 bar->dragging = Qnil;
8516 }
f451eb13 8517
5116f055
JB
8518 /* Same deal here as the other #if 0. */
8519#if 0
58769bee 8520 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 8521 the handle. */
ab648270 8522 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
8523 emacs_event->x = bar->start;
8524 else
e0c1aef2 8525 XSETINT (emacs_event->x, y);
5116f055 8526#else
e0c1aef2 8527 XSETINT (emacs_event->x, y);
5116f055 8528#endif
f451eb13 8529
e0c1aef2 8530 XSETINT (emacs_event->y, top_range);
12ba150f
JB
8531 }
8532}
f451eb13 8533
ab648270
JB
8534/* Handle some mouse motion while someone is dragging the scroll bar.
8535
8536 This may be called from a signal handler, so we have to ignore GC
8537 mark bits. */
06a2c219 8538
f451eb13 8539static void
ab648270
JB
8540x_scroll_bar_note_movement (bar, event)
8541 struct scroll_bar *bar;
f451eb13
JB
8542 XEvent *event;
8543{
39d8bb4d
KH
8544 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
8545
f451eb13
JB
8546 last_mouse_movement_time = event->xmotion.time;
8547
39d8bb4d 8548 f->mouse_moved = 1;
e0c1aef2 8549 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
8550
8551 /* If we're dragging the bar, display it. */
ab648270 8552 if (! GC_NILP (bar->dragging))
f451eb13
JB
8553 {
8554 /* Where should the handle be now? */
12ba150f 8555 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 8556
12ba150f 8557 if (new_start != XINT (bar->start))
f451eb13 8558 {
12ba150f 8559 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 8560
ab648270 8561 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
8562 }
8563 }
f451eb13
JB
8564}
8565
5c187dee
GM
8566#endif /* !USE_TOOLKIT_SCROLL_BARS */
8567
12ba150f 8568/* Return information to the user about the current position of the mouse
ab648270 8569 on the scroll bar. */
06a2c219 8570
12ba150f 8571static void
334208b7
RS
8572x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
8573 FRAME_PTR *fp;
12ba150f 8574 Lisp_Object *bar_window;
ab648270 8575 enum scroll_bar_part *part;
12ba150f
JB
8576 Lisp_Object *x, *y;
8577 unsigned long *time;
8578{
ab648270 8579 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
8580 Window w = SCROLL_BAR_X_WINDOW (bar);
8581 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 8582 int win_x, win_y;
559cb2fb
JB
8583 Window dummy_window;
8584 int dummy_coord;
8585 unsigned int dummy_mask;
12ba150f 8586
cf7cb199
JB
8587 BLOCK_INPUT;
8588
ab648270 8589 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 8590 report that. */
334208b7 8591 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 8592
559cb2fb
JB
8593 /* Root, child, root x and root y. */
8594 &dummy_window, &dummy_window,
8595 &dummy_coord, &dummy_coord,
12ba150f 8596
559cb2fb
JB
8597 /* Position relative to scroll bar. */
8598 &win_x, &win_y,
12ba150f 8599
559cb2fb
JB
8600 /* Mouse buttons and modifier keys. */
8601 &dummy_mask))
7a13e894 8602 ;
559cb2fb
JB
8603 else
8604 {
06a2c219 8605#if 0
559cb2fb 8606 int inside_height
d9cdbb3d 8607 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8608#endif
559cb2fb 8609 int top_range
d9cdbb3d 8610 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
8611
8612 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
8613
8614 if (! NILP (bar->dragging))
8615 win_y -= XINT (bar->dragging);
8616
8617 if (win_y < 0)
8618 win_y = 0;
8619 if (win_y > top_range)
8620 win_y = top_range;
8621
334208b7 8622 *fp = f;
7a13e894 8623 *bar_window = bar->window;
559cb2fb
JB
8624
8625 if (! NILP (bar->dragging))
8626 *part = scroll_bar_handle;
8627 else if (win_y < XINT (bar->start))
8628 *part = scroll_bar_above_handle;
8629 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8630 *part = scroll_bar_handle;
8631 else
8632 *part = scroll_bar_below_handle;
12ba150f 8633
e0c1aef2
KH
8634 XSETINT (*x, win_y);
8635 XSETINT (*y, top_range);
12ba150f 8636
39d8bb4d 8637 f->mouse_moved = 0;
559cb2fb
JB
8638 last_mouse_scroll_bar = Qnil;
8639 }
12ba150f 8640
559cb2fb 8641 *time = last_mouse_movement_time;
cf7cb199 8642
cf7cb199 8643 UNBLOCK_INPUT;
12ba150f
JB
8644}
8645
f451eb13 8646
dbc4e1c1 8647/* The screen has been cleared so we may have changed foreground or
ab648270
JB
8648 background colors, and the scroll bars may need to be redrawn.
8649 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
8650 redraw them. */
8651
dfcf069d 8652void
ab648270 8653x_scroll_bar_clear (f)
dbc4e1c1
JB
8654 FRAME_PTR f;
8655{
06a2c219 8656#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
8657 Lisp_Object bar;
8658
b80c363e
RS
8659 /* We can have scroll bars even if this is 0,
8660 if we just turned off scroll bar mode.
8661 But in that case we should not clear them. */
8662 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
8663 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
8664 bar = XSCROLL_BAR (bar)->next)
8665 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
8666 0, 0, 0, 0, True);
06a2c219 8667#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
8668}
8669
06a2c219 8670/* This processes Expose events from the menu-bar specific X event
19126e11 8671 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 8672 when handling menu-bar or pop-up items. */
3afe33e7 8673
06a2c219 8674int
3afe33e7
RS
8675process_expose_from_menu (event)
8676 XEvent event;
8677{
8678 FRAME_PTR f;
19126e11 8679 struct x_display_info *dpyinfo;
06a2c219 8680 int frame_exposed_p = 0;
3afe33e7 8681
f94397b5
KH
8682 BLOCK_INPUT;
8683
19126e11
KH
8684 dpyinfo = x_display_info_for_display (event.xexpose.display);
8685 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
8686 if (f)
8687 {
8688 if (f->async_visible == 0)
8689 {
8690 f->async_visible = 1;
8691 f->async_iconified = 0;
06c488fd 8692 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
8693 SET_FRAME_GARBAGED (f);
8694 }
8695 else
8696 {
06a2c219
GM
8697 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
8698 event.xexpose.x, event.xexpose.y,
8699 event.xexpose.width, event.xexpose.height);
8700 frame_exposed_p = 1;
3afe33e7
RS
8701 }
8702 }
8703 else
8704 {
8705 struct scroll_bar *bar
8706 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 8707
3afe33e7
RS
8708 if (bar)
8709 x_scroll_bar_expose (bar, &event);
8710 }
f94397b5
KH
8711
8712 UNBLOCK_INPUT;
06a2c219 8713 return frame_exposed_p;
3afe33e7 8714}
09756a85
RS
8715\f
8716/* Define a queue to save up SelectionRequest events for later handling. */
8717
8718struct selection_event_queue
8719 {
8720 XEvent event;
8721 struct selection_event_queue *next;
8722 };
8723
8724static struct selection_event_queue *queue;
8725
8726/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 8727
09756a85
RS
8728static int x_queue_selection_requests;
8729
8730/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 8731
09756a85 8732static void
334208b7
RS
8733x_queue_event (f, event)
8734 FRAME_PTR f;
09756a85
RS
8735 XEvent *event;
8736{
8737 struct selection_event_queue *queue_tmp
06a2c219 8738 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 8739
58769bee 8740 if (queue_tmp != NULL)
09756a85
RS
8741 {
8742 queue_tmp->event = *event;
8743 queue_tmp->next = queue;
8744 queue = queue_tmp;
8745 }
8746}
8747
8748/* Take all the queued events and put them back
8749 so that they get processed afresh. */
8750
8751static void
db3906fd
RS
8752x_unqueue_events (display)
8753 Display *display;
09756a85 8754{
58769bee 8755 while (queue != NULL)
09756a85
RS
8756 {
8757 struct selection_event_queue *queue_tmp = queue;
db3906fd 8758 XPutBackEvent (display, &queue_tmp->event);
09756a85 8759 queue = queue_tmp->next;
06a2c219 8760 xfree ((char *)queue_tmp);
09756a85
RS
8761 }
8762}
8763
8764/* Start queuing SelectionRequest events. */
8765
8766void
db3906fd
RS
8767x_start_queuing_selection_requests (display)
8768 Display *display;
09756a85
RS
8769{
8770 x_queue_selection_requests++;
8771}
8772
8773/* Stop queuing SelectionRequest events. */
8774
8775void
db3906fd
RS
8776x_stop_queuing_selection_requests (display)
8777 Display *display;
09756a85
RS
8778{
8779 x_queue_selection_requests--;
db3906fd 8780 x_unqueue_events (display);
09756a85 8781}
f451eb13
JB
8782\f
8783/* The main X event-reading loop - XTread_socket. */
dc6f92b8 8784
06a2c219 8785/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
8786 but we have to put it out here, since static variables within functions
8787 sometimes don't work. */
06a2c219 8788
dc6f92b8
JB
8789static Time enter_timestamp;
8790
11edeb03 8791/* This holds the state XLookupString needs to implement dead keys
58769bee 8792 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
8793 says that a portable program can't use this, but Stephen Gildea assures
8794 me that letting the compiler initialize it to zeros will work okay.
8795
8796 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
8797 given for enter_time stamp, above. */
8798
11edeb03
JB
8799static XComposeStatus compose_status;
8800
10e6549c
RS
8801/* Record the last 100 characters stored
8802 to help debug the loss-of-chars-during-GC problem. */
06a2c219 8803
2224b905
RS
8804static int temp_index;
8805static short temp_buffer[100];
10e6549c 8806
7a13e894
RS
8807/* Set this to nonzero to fake an "X I/O error"
8808 on a particular display. */
06a2c219 8809
7a13e894
RS
8810struct x_display_info *XTread_socket_fake_io_error;
8811
2224b905
RS
8812/* When we find no input here, we occasionally do a no-op command
8813 to verify that the X server is still running and we can still talk with it.
8814 We try all the open displays, one by one.
8815 This variable is used for cycling thru the displays. */
06a2c219 8816
2224b905
RS
8817static struct x_display_info *next_noop_dpyinfo;
8818
06a2c219
GM
8819#define SET_SAVED_MENU_EVENT(size) \
8820 do \
8821 { \
8822 if (f->output_data.x->saved_menu_event == 0) \
8823 f->output_data.x->saved_menu_event \
8824 = (XEvent *) xmalloc (sizeof (XEvent)); \
8825 bcopy (&event, f->output_data.x->saved_menu_event, size); \
8826 if (numchars >= 1) \
8827 { \
8828 bufp->kind = menu_bar_activate_event; \
8829 XSETFRAME (bufp->frame_or_window, f); \
8830 bufp++; \
8831 count++; \
8832 numchars--; \
8833 } \
8834 } \
8835 while (0)
8836
8805890a 8837#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 8838#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 8839
dc6f92b8
JB
8840/* Read events coming from the X server.
8841 This routine is called by the SIGIO handler.
8842 We return as soon as there are no more events to be read.
8843
8844 Events representing keys are stored in buffer BUFP,
8845 which can hold up to NUMCHARS characters.
8846 We return the number of characters stored into the buffer,
8847 thus pretending to be `read'.
8848
dc6f92b8
JB
8849 EXPECTED is nonzero if the caller knows input is available. */
8850
7c5283e4 8851int
f66868ba 8852XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 8853 register int sd;
8805890a
KH
8854 /* register */ struct input_event *bufp;
8855 /* register */ int numchars;
dc6f92b8
JB
8856 int expected;
8857{
8858 int count = 0;
8859 int nbytes = 0;
dc6f92b8 8860 XEvent event;
f676886a 8861 struct frame *f;
66f55a9d 8862 int event_found = 0;
334208b7 8863 struct x_display_info *dpyinfo;
dc6f92b8 8864
9ac0d9e0 8865 if (interrupt_input_blocked)
dc6f92b8 8866 {
9ac0d9e0 8867 interrupt_input_pending = 1;
dc6f92b8
JB
8868 return -1;
8869 }
8870
9ac0d9e0 8871 interrupt_input_pending = 0;
dc6f92b8 8872 BLOCK_INPUT;
c0a04927
RS
8873
8874 /* So people can tell when we have read the available input. */
8875 input_signal_count++;
8876
dc6f92b8 8877 if (numchars <= 0)
06a2c219 8878 abort (); /* Don't think this happens. */
dc6f92b8 8879
7a13e894
RS
8880 /* Find the display we are supposed to read input for.
8881 It's the one communicating on descriptor SD. */
8882 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
8883 {
8884#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 8885#ifdef FIOSNBIO
7a13e894
RS
8886 /* If available, Xlib uses FIOSNBIO to make the socket
8887 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 8888 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 8889 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 8890 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 8891#endif /* ! defined (FIOSNBIO) */
7a13e894 8892#endif
dc6f92b8 8893
7a13e894
RS
8894#if 0 /* This code can't be made to work, with multiple displays,
8895 and appears not to be used on any system any more.
8896 Also keyboard.c doesn't turn O_NDELAY on and off
8897 for X connections. */
dc6f92b8
JB
8898#ifndef SIGIO
8899#ifndef HAVE_SELECT
7a13e894
RS
8900 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
8901 {
8902 extern int read_alarm_should_throw;
8903 read_alarm_should_throw = 1;
8904 XPeekEvent (dpyinfo->display, &event);
8905 read_alarm_should_throw = 0;
8906 }
c118dd06
JB
8907#endif /* HAVE_SELECT */
8908#endif /* SIGIO */
7a13e894 8909#endif
dc6f92b8 8910
7a13e894
RS
8911 /* For debugging, this gives a way to fake an I/O error. */
8912 if (dpyinfo == XTread_socket_fake_io_error)
8913 {
8914 XTread_socket_fake_io_error = 0;
8915 x_io_error_quitter (dpyinfo->display);
8916 }
dc6f92b8 8917
06a2c219 8918 while (XPending (dpyinfo->display))
dc6f92b8 8919 {
7a13e894 8920 XNextEvent (dpyinfo->display, &event);
06a2c219 8921
531483fb 8922#ifdef HAVE_X_I18N
d1bc4182 8923 {
f2be1146
GM
8924 /* Filter events for the current X input method.
8925 XFilterEvent returns non-zero if the input method has
8926 consumed the event. We pass the frame's X window to
8927 XFilterEvent because that's the one for which the IC
8928 was created. */
f5d11644
GM
8929 struct frame *f1 = x_any_window_to_frame (dpyinfo,
8930 event.xclient.window);
8931 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
8932 break;
8933 }
0cd6403b 8934#endif
7a13e894
RS
8935 event_found = 1;
8936
8937 switch (event.type)
8938 {
8939 case ClientMessage:
c047688c 8940 {
7a13e894
RS
8941 if (event.xclient.message_type
8942 == dpyinfo->Xatom_wm_protocols
8943 && event.xclient.format == 32)
c047688c 8944 {
7a13e894
RS
8945 if (event.xclient.data.l[0]
8946 == dpyinfo->Xatom_wm_take_focus)
c047688c 8947 {
8c1a6a84
RS
8948 /* Use x_any_window_to_frame because this
8949 could be the shell widget window
8950 if the frame has no title bar. */
8951 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
8952#ifdef HAVE_X_I18N
8953 /* Not quite sure this is needed -pd */
8c1a6a84 8954 if (f && FRAME_XIC (f))
6c183ba5
RS
8955 XSetICFocus (FRAME_XIC (f));
8956#endif
f1da8f06
GM
8957#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
8958 instructs the WM to set the input focus automatically for
8959 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
8960 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
8961 it has set the focus. So, XSetInputFocus below is not
8962 needed.
8963
8964 The call to XSetInputFocus below has also caused trouble. In
8965 cases where the XSetInputFocus done by the WM and the one
8966 below are temporally close (on a fast machine), the call
8967 below can generate additional FocusIn events which confuse
8968 Emacs. */
8969
bf7253f4
RS
8970 /* Since we set WM_TAKE_FOCUS, we must call
8971 XSetInputFocus explicitly. But not if f is null,
8972 since that might be an event for a deleted frame. */
7a13e894 8973 if (f)
bf7253f4
RS
8974 {
8975 Display *d = event.xclient.display;
8976 /* Catch and ignore errors, in case window has been
8977 iconified by a window manager such as GWM. */
8978 int count = x_catch_errors (d);
8979 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
8980 /* The ICCCM says this is
8981 the only valid choice. */
8982 RevertToParent,
bf7253f4
RS
8983 event.xclient.data.l[1]);
8984 /* This is needed to detect the error
8985 if there is an error. */
8986 XSync (d, False);
8987 x_uncatch_errors (d, count);
8988 }
7a13e894 8989 /* Not certain about handling scroll bars here */
f1da8f06 8990#endif /* 0 */
c047688c 8991 }
7a13e894
RS
8992 else if (event.xclient.data.l[0]
8993 == dpyinfo->Xatom_wm_save_yourself)
8994 {
8995 /* Save state modify the WM_COMMAND property to
06a2c219 8996 something which can reinstate us. This notifies
7a13e894
RS
8997 the session manager, who's looking for such a
8998 PropertyNotify. Can restart processing when
06a2c219 8999 a keyboard or mouse event arrives. */
7a13e894
RS
9000 if (numchars > 0)
9001 {
19126e11
KH
9002 f = x_top_window_to_frame (dpyinfo,
9003 event.xclient.window);
7a13e894
RS
9004
9005 /* This is just so we only give real data once
9006 for a single Emacs process. */
b86bd3dd 9007 if (f == SELECTED_FRAME ())
7a13e894
RS
9008 XSetCommand (FRAME_X_DISPLAY (f),
9009 event.xclient.window,
9010 initial_argv, initial_argc);
f000f5c5 9011 else if (f)
7a13e894
RS
9012 XSetCommand (FRAME_X_DISPLAY (f),
9013 event.xclient.window,
9014 0, 0);
9015 }
9016 }
9017 else if (event.xclient.data.l[0]
9018 == dpyinfo->Xatom_wm_delete_window)
1fb20991 9019 {
19126e11
KH
9020 struct frame *f
9021 = x_any_window_to_frame (dpyinfo,
9022 event.xclient.window);
1fb20991 9023
7a13e894
RS
9024 if (f)
9025 {
9026 if (numchars == 0)
9027 abort ();
1fb20991 9028
7a13e894
RS
9029 bufp->kind = delete_window_event;
9030 XSETFRAME (bufp->frame_or_window, f);
9031 bufp++;
9032
9033 count += 1;
9034 numchars -= 1;
9035 }
1fb20991 9036 }
c047688c 9037 }
7a13e894
RS
9038 else if (event.xclient.message_type
9039 == dpyinfo->Xatom_wm_configure_denied)
9040 {
9041 }
9042 else if (event.xclient.message_type
9043 == dpyinfo->Xatom_wm_window_moved)
9044 {
9045 int new_x, new_y;
19126e11
KH
9046 struct frame *f
9047 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 9048
7a13e894
RS
9049 new_x = event.xclient.data.s[0];
9050 new_y = event.xclient.data.s[1];
1fb20991 9051
7a13e894
RS
9052 if (f)
9053 {
7556890b
RS
9054 f->output_data.x->left_pos = new_x;
9055 f->output_data.x->top_pos = new_y;
7a13e894 9056 }
1fb20991 9057 }
0fdff6bb 9058#ifdef HACK_EDITRES
7a13e894
RS
9059 else if (event.xclient.message_type
9060 == dpyinfo->Xatom_editres)
9061 {
19126e11
KH
9062 struct frame *f
9063 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 9064 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 9065 &event, NULL);
7a13e894 9066 }
0fdff6bb 9067#endif /* HACK_EDITRES */
06a2c219
GM
9068 else if ((event.xclient.message_type
9069 == dpyinfo->Xatom_DONE)
9070 || (event.xclient.message_type
9071 == dpyinfo->Xatom_PAGE))
9072 {
9073 /* Ghostview job completed. Kill it. We could
9074 reply with "Next" if we received "Page", but we
9075 currently never do because we are interested in
9076 images, only, which should have 1 page. */
06a2c219
GM
9077 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
9078 struct frame *f
9079 = x_window_to_frame (dpyinfo, event.xclient.window);
9080 x_kill_gs_process (pixmap, f);
9081 expose_frame (f, 0, 0, 0, 0);
9082 }
9083#ifdef USE_TOOLKIT_SCROLL_BARS
9084 /* Scroll bar callbacks send a ClientMessage from which
9085 we construct an input_event. */
9086 else if (event.xclient.message_type
9087 == dpyinfo->Xatom_Scrollbar)
9088 {
9089 x_scroll_bar_to_input_event (&event, bufp);
9090 ++bufp, ++count, --numchars;
9091 goto out;
9092 }
9093#endif /* USE_TOOLKIT_SCROLL_BARS */
9094 else
9095 goto OTHER;
7a13e894
RS
9096 }
9097 break;
dc6f92b8 9098
7a13e894 9099 case SelectionNotify:
3afe33e7 9100#ifdef USE_X_TOOLKIT
19126e11 9101 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 9102 goto OTHER;
3afe33e7 9103#endif /* not USE_X_TOOLKIT */
dfcf069d 9104 x_handle_selection_notify (&event.xselection);
7a13e894 9105 break;
d56a553a 9106
06a2c219 9107 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 9108#ifdef USE_X_TOOLKIT
19126e11 9109 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 9110 goto OTHER;
3afe33e7 9111#endif /* USE_X_TOOLKIT */
7a13e894
RS
9112 {
9113 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 9114
7a13e894
RS
9115 if (numchars == 0)
9116 abort ();
d56a553a 9117
7a13e894
RS
9118 bufp->kind = selection_clear_event;
9119 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9120 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9121 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9122 bufp->frame_or_window = Qnil;
7a13e894 9123 bufp++;
d56a553a 9124
7a13e894
RS
9125 count += 1;
9126 numchars -= 1;
9127 }
9128 break;
dc6f92b8 9129
06a2c219 9130 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 9131#ifdef USE_X_TOOLKIT
19126e11 9132 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 9133 goto OTHER;
3afe33e7 9134#endif /* USE_X_TOOLKIT */
7a13e894 9135 if (x_queue_selection_requests)
19126e11 9136 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
9137 &event);
9138 else
9139 {
9140 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 9141
7a13e894
RS
9142 if (numchars == 0)
9143 abort ();
9144
9145 bufp->kind = selection_request_event;
9146 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9147 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
9148 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9149 SELECTION_EVENT_TARGET (bufp) = eventp->target;
9150 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
9151 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9152 bufp->frame_or_window = Qnil;
7a13e894
RS
9153 bufp++;
9154
9155 count += 1;
9156 numchars -= 1;
9157 }
9158 break;
9159
9160 case PropertyNotify:
3afe33e7 9161#ifdef USE_X_TOOLKIT
19126e11 9162 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 9163 goto OTHER;
3afe33e7 9164#endif /* not USE_X_TOOLKIT */
dfcf069d 9165 x_handle_property_notify (&event.xproperty);
7a13e894 9166 break;
dc6f92b8 9167
7a13e894 9168 case ReparentNotify:
19126e11 9169 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
9170 if (f)
9171 {
9172 int x, y;
7556890b 9173 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 9174 x_real_positions (f, &x, &y);
7556890b
RS
9175 f->output_data.x->left_pos = x;
9176 f->output_data.x->top_pos = y;
7a13e894
RS
9177 }
9178 break;
3bd330d4 9179
7a13e894 9180 case Expose:
19126e11 9181 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 9182 if (f)
dc6f92b8 9183 {
7a13e894
RS
9184 if (f->async_visible == 0)
9185 {
9186 f->async_visible = 1;
9187 f->async_iconified = 0;
06c488fd 9188 f->output_data.x->has_been_visible = 1;
7a13e894
RS
9189 SET_FRAME_GARBAGED (f);
9190 }
9191 else
06a2c219
GM
9192 expose_frame (x_window_to_frame (dpyinfo,
9193 event.xexpose.window),
9194 event.xexpose.x, event.xexpose.y,
9195 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
9196 }
9197 else
7a13e894 9198 {
06a2c219
GM
9199#ifdef USE_TOOLKIT_SCROLL_BARS
9200 /* Dispatch event to the widget. */
9201 goto OTHER;
9202#else /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9203 struct scroll_bar *bar
9204 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9205
7a13e894
RS
9206 if (bar)
9207 x_scroll_bar_expose (bar, &event);
3afe33e7 9208#ifdef USE_X_TOOLKIT
7a13e894
RS
9209 else
9210 goto OTHER;
3afe33e7 9211#endif /* USE_X_TOOLKIT */
06a2c219 9212#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9213 }
9214 break;
dc6f92b8 9215
7a13e894
RS
9216 case GraphicsExpose: /* This occurs when an XCopyArea's
9217 source area was obscured or not
9218 available.*/
19126e11 9219 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
9220 if (f)
9221 {
06a2c219
GM
9222 expose_frame (f,
9223 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
9224 event.xgraphicsexpose.width,
9225 event.xgraphicsexpose.height);
7a13e894 9226 }
3afe33e7 9227#ifdef USE_X_TOOLKIT
7a13e894
RS
9228 else
9229 goto OTHER;
3afe33e7 9230#endif /* USE_X_TOOLKIT */
7a13e894 9231 break;
dc6f92b8 9232
7a13e894 9233 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
9234 source area was completely
9235 available */
7a13e894 9236 break;
dc6f92b8 9237
7a13e894 9238 case UnmapNotify:
06a2c219
GM
9239 /* Redo the mouse-highlight after the tooltip has gone. */
9240 if (event.xmap.window == tip_window)
9241 {
9242 tip_window = 0;
9243 redo_mouse_highlight ();
9244 }
9245
91ea2a7a 9246 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
9247 if (f) /* F may no longer exist if
9248 the frame was deleted. */
9249 {
9250 /* While a frame is unmapped, display generation is
9251 disabled; you don't want to spend time updating a
9252 display that won't ever be seen. */
9253 f->async_visible = 0;
9254 /* We can't distinguish, from the event, whether the window
9255 has become iconified or invisible. So assume, if it
9256 was previously visible, than now it is iconified.
1aa6072f
RS
9257 But x_make_frame_invisible clears both
9258 the visible flag and the iconified flag;
9259 and that way, we know the window is not iconified now. */
7a13e894 9260 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
9261 {
9262 f->async_iconified = 1;
bddd097c 9263
1aa6072f
RS
9264 bufp->kind = iconify_event;
9265 XSETFRAME (bufp->frame_or_window, f);
9266 bufp++;
9267 count++;
9268 numchars--;
9269 }
7a13e894 9270 }
7a13e894 9271 goto OTHER;
dc6f92b8 9272
7a13e894 9273 case MapNotify:
06a2c219
GM
9274 if (event.xmap.window == tip_window)
9275 /* The tooltip has been drawn already. Avoid
9276 the SET_FRAME_GARBAGED below. */
9277 goto OTHER;
9278
9279 /* We use x_top_window_to_frame because map events can
9280 come for sub-windows and they don't mean that the
9281 frame is visible. */
19126e11 9282 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
9283 if (f)
9284 {
9285 f->async_visible = 1;
9286 f->async_iconified = 0;
06c488fd 9287 f->output_data.x->has_been_visible = 1;
dc6f92b8 9288
7a13e894
RS
9289 /* wait_reading_process_input will notice this and update
9290 the frame's display structures. */
9291 SET_FRAME_GARBAGED (f);
bddd097c 9292
d806e720
RS
9293 if (f->iconified)
9294 {
9295 bufp->kind = deiconify_event;
9296 XSETFRAME (bufp->frame_or_window, f);
9297 bufp++;
9298 count++;
9299 numchars--;
9300 }
e73ec6fa 9301 else if (! NILP (Vframe_list)
8e713be6 9302 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
9303 /* Force a redisplay sooner or later
9304 to update the frame titles
9305 in case this is the second frame. */
9306 record_asynch_buffer_change ();
7a13e894 9307 }
7a13e894 9308 goto OTHER;
dc6f92b8 9309
7a13e894 9310 case KeyPress:
19126e11 9311 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 9312
06a2c219
GM
9313#ifdef USE_MOTIF
9314 /* I couldn't find a way to prevent LessTif scroll bars
9315 from consuming key events. */
9316 if (f == 0)
9317 {
9318 Widget widget = XtWindowToWidget (dpyinfo->display,
9319 event.xkey.window);
9320 if (widget && XmIsScrollBar (widget))
9321 {
9322 widget = XtParent (widget);
9323 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
9324 }
9325 }
9326#endif /* USE_MOTIF */
9327
7a13e894
RS
9328 if (f != 0)
9329 {
9330 KeySym keysym, orig_keysym;
9331 /* al%imercury@uunet.uu.net says that making this 81 instead of
9332 80 fixed a bug whereby meta chars made his Emacs hang. */
9333 unsigned char copy_buffer[81];
9334 int modifiers;
64bb1782 9335
7a13e894
RS
9336 event.xkey.state
9337 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
9338 extra_keyboard_modifiers);
9339 modifiers = event.xkey.state;
3a2712f9 9340
7a13e894 9341 /* This will have to go some day... */
752a043f 9342
7a13e894
RS
9343 /* make_lispy_event turns chars into control chars.
9344 Don't do it here because XLookupString is too eager. */
9345 event.xkey.state &= ~ControlMask;
5d46f928
RS
9346 event.xkey.state &= ~(dpyinfo->meta_mod_mask
9347 | dpyinfo->super_mod_mask
9348 | dpyinfo->hyper_mod_mask
9349 | dpyinfo->alt_mod_mask);
9350
1cf4a0d1
RS
9351 /* In case Meta is ComposeCharacter,
9352 clear its status. According to Markus Ehrnsperger
9353 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
9354 this enables ComposeCharacter to work whether or
9355 not it is combined with Meta. */
9356 if (modifiers & dpyinfo->meta_mod_mask)
9357 bzero (&compose_status, sizeof (compose_status));
9358
6c183ba5
RS
9359#ifdef HAVE_X_I18N
9360 if (FRAME_XIC (f))
9361 {
f5d11644
GM
9362 unsigned char *copy_bufptr = copy_buffer;
9363 int copy_bufsiz = sizeof (copy_buffer);
9364 Status status_return;
9365
6c183ba5 9366 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
9367 &event.xkey, copy_bufptr,
9368 copy_bufsiz, &keysym,
6c183ba5 9369 &status_return);
f5d11644
GM
9370 if (status_return == XBufferOverflow)
9371 {
9372 copy_bufsiz = nbytes + 1;
9373 copy_bufptr = (char *) alloca (copy_bufsiz);
9374 nbytes = XmbLookupString (FRAME_XIC (f),
9375 &event.xkey, copy_bufptr,
9376 copy_bufsiz, &keysym,
9377 &status_return);
9378 }
9379
1decb680
PE
9380 if (status_return == XLookupNone)
9381 break;
9382 else if (status_return == XLookupChars)
9383 keysym = NoSymbol;
9384 else if (status_return != XLookupKeySym
9385 && status_return != XLookupBoth)
9386 abort ();
6c183ba5
RS
9387 }
9388 else
9389 nbytes = XLookupString (&event.xkey, copy_buffer,
9390 80, &keysym, &compose_status);
9391#else
0299d313
RS
9392 nbytes = XLookupString (&event.xkey, copy_buffer,
9393 80, &keysym, &compose_status);
6c183ba5 9394#endif
dc6f92b8 9395
7a13e894 9396 orig_keysym = keysym;
55123275 9397
7a13e894
RS
9398 if (numchars > 1)
9399 {
9400 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
9401 || keysym == XK_Delete
1097aea0 9402#ifdef XK_ISO_Left_Tab
441affdb 9403 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 9404#endif
852bff8f 9405 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
9406 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
9407 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 9408#ifdef HPUX
7a13e894
RS
9409 /* This recognizes the "extended function keys".
9410 It seems there's no cleaner way.
9411 Test IsModifierKey to avoid handling mode_switch
9412 incorrectly. */
9413 || ((unsigned) (keysym) >= XK_Select
9414 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
9415#endif
9416#ifdef XK_dead_circumflex
7a13e894 9417 || orig_keysym == XK_dead_circumflex
69388238
RS
9418#endif
9419#ifdef XK_dead_grave
7a13e894 9420 || orig_keysym == XK_dead_grave
69388238
RS
9421#endif
9422#ifdef XK_dead_tilde
7a13e894 9423 || orig_keysym == XK_dead_tilde
69388238
RS
9424#endif
9425#ifdef XK_dead_diaeresis
7a13e894 9426 || orig_keysym == XK_dead_diaeresis
69388238
RS
9427#endif
9428#ifdef XK_dead_macron
7a13e894 9429 || orig_keysym == XK_dead_macron
69388238
RS
9430#endif
9431#ifdef XK_dead_degree
7a13e894 9432 || orig_keysym == XK_dead_degree
69388238
RS
9433#endif
9434#ifdef XK_dead_acute
7a13e894 9435 || orig_keysym == XK_dead_acute
69388238
RS
9436#endif
9437#ifdef XK_dead_cedilla
7a13e894 9438 || orig_keysym == XK_dead_cedilla
69388238
RS
9439#endif
9440#ifdef XK_dead_breve
7a13e894 9441 || orig_keysym == XK_dead_breve
69388238
RS
9442#endif
9443#ifdef XK_dead_ogonek
7a13e894 9444 || orig_keysym == XK_dead_ogonek
69388238
RS
9445#endif
9446#ifdef XK_dead_caron
7a13e894 9447 || orig_keysym == XK_dead_caron
69388238
RS
9448#endif
9449#ifdef XK_dead_doubleacute
7a13e894 9450 || orig_keysym == XK_dead_doubleacute
69388238
RS
9451#endif
9452#ifdef XK_dead_abovedot
7a13e894 9453 || orig_keysym == XK_dead_abovedot
c34790e0 9454#endif
7a13e894
RS
9455 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
9456 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
9457 /* Any "vendor-specific" key is ok. */
9458 || (orig_keysym & (1 << 28)))
9459 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
9460#ifndef HAVE_X11R5
9461#ifdef XK_Mode_switch
7a13e894 9462 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
9463#endif
9464#ifdef XK_Num_Lock
7a13e894 9465 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
9466#endif
9467#endif /* not HAVE_X11R5 */
7a13e894 9468 ))
dc6f92b8 9469 {
10e6549c
RS
9470 if (temp_index == sizeof temp_buffer / sizeof (short))
9471 temp_index = 0;
7a13e894
RS
9472 temp_buffer[temp_index++] = keysym;
9473 bufp->kind = non_ascii_keystroke;
9474 bufp->code = keysym;
e0c1aef2 9475 XSETFRAME (bufp->frame_or_window, f);
334208b7
RS
9476 bufp->modifiers
9477 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9478 modifiers);
1113d9db 9479 bufp->timestamp = event.xkey.time;
dc6f92b8 9480 bufp++;
7a13e894
RS
9481 count++;
9482 numchars--;
dc6f92b8 9483 }
7a13e894
RS
9484 else if (numchars > nbytes)
9485 {
9486 register int i;
9487
9488 for (i = 0; i < nbytes; i++)
9489 {
9490 if (temp_index == sizeof temp_buffer / sizeof (short))
9491 temp_index = 0;
9492 temp_buffer[temp_index++] = copy_buffer[i];
9493 bufp->kind = ascii_keystroke;
9494 bufp->code = copy_buffer[i];
9495 XSETFRAME (bufp->frame_or_window, f);
9496 bufp->modifiers
9497 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9498 modifiers);
9499 bufp->timestamp = event.xkey.time;
9500 bufp++;
9501 }
9502
9503 count += nbytes;
9504 numchars -= nbytes;
1decb680
PE
9505
9506 if (keysym == NoSymbol)
9507 break;
7a13e894
RS
9508 }
9509 else
9510 abort ();
dc6f92b8 9511 }
10e6549c
RS
9512 else
9513 abort ();
dc6f92b8 9514 }
59ddecde
GM
9515#ifdef HAVE_X_I18N
9516 /* Don't dispatch this event since XtDispatchEvent calls
9517 XFilterEvent, and two calls in a row may freeze the
9518 client. */
9519 break;
9520#else
717ca130 9521 goto OTHER;
59ddecde 9522#endif
f451eb13 9523
f5d11644 9524 case KeyRelease:
59ddecde
GM
9525#ifdef HAVE_X_I18N
9526 /* Don't dispatch this event since XtDispatchEvent calls
9527 XFilterEvent, and two calls in a row may freeze the
9528 client. */
9529 break;
9530#else
f5d11644 9531 goto OTHER;
59ddecde 9532#endif
f5d11644 9533
7a13e894 9534 /* Here's a possible interpretation of the whole
06a2c219
GM
9535 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
9536 you get a FocusIn event, you have to get a FocusOut
9537 event before you relinquish the focus. If you
9538 haven't received a FocusIn event, then a mere
9539 LeaveNotify is enough to free you. */
f451eb13 9540
7a13e894 9541 case EnterNotify:
06a2c219
GM
9542 {
9543 int from_menu_bar_p = 0;
9544
9545 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
9546
9547#ifdef LESSTIF_VERSION
9548 /* When clicking outside of a menu bar popup to close
9549 it, we get a FocusIn/ EnterNotify sequence of
9550 events. The flag event.xcrossing.focus is not set
9551 in the EnterNotify event of that sequence because
9552 the focus is in the menu bar,
9553 event.xcrossing.window is the frame's X window.
9554 Unconditionally setting the focus frame to null in
9555 this case is not the right thing, because no event
9556 follows that could set the focus frame to the right
9557 value.
9558
9559 This could be a LessTif bug, but I wasn't able to
9560 reproduce the behavior in a simple test program.
9561
9562 (gerd, LessTif 0.88.1). */
9563
9564 if (!event.xcrossing.focus
9565 && f
9566 && f->output_data.x->menubar_widget)
9567 {
9568 Window focus;
9569 int revert;
9570
9571 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9572 if (focus == XtWindow (f->output_data.x->menubar_widget))
9573 from_menu_bar_p = 1;
9574 }
9575#endif /* LESSTIF_VERSION */
6d4238f3 9576
06a2c219
GM
9577 if (event.xcrossing.focus || from_menu_bar_p)
9578 {
9579 /* Avoid nasty pop/raise loops. */
9580 if (f && (!(f->auto_raise)
9581 || !(f->auto_lower)
9582 || (event.xcrossing.time - enter_timestamp) > 500))
9583 {
9584 x_new_focus_frame (dpyinfo, f);
9585 enter_timestamp = event.xcrossing.time;
9586 }
9587 }
9588 else if (f == dpyinfo->x_focus_frame)
9589 x_new_focus_frame (dpyinfo, 0);
9590
9591 /* EnterNotify counts as mouse movement,
9592 so update things that depend on mouse position. */
9593 if (f && !f->output_data.x->busy_p)
9594 note_mouse_movement (f, &event.xmotion);
9595 goto OTHER;
9596 }
dc6f92b8 9597
7a13e894 9598 case FocusIn:
19126e11 9599 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9600 if (event.xfocus.detail != NotifyPointer)
0f941935 9601 dpyinfo->x_focus_event_frame = f;
7a13e894 9602 if (f)
0f941935 9603 x_new_focus_frame (dpyinfo, f);
f9e24cb9 9604
6c183ba5
RS
9605#ifdef HAVE_X_I18N
9606 if (f && FRAME_XIC (f))
9607 XSetICFocus (FRAME_XIC (f));
9608#endif
9609
7a13e894 9610 goto OTHER;
10c5e63d 9611
7a13e894 9612 case LeaveNotify:
19126e11 9613 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 9614 if (f)
10c5e63d 9615 {
06a2c219
GM
9616 Lisp_Object frame;
9617 int from_menu_bar_p = 0;
9618
7a13e894 9619 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
9620 {
9621 /* If we move outside the frame, then we're
9622 certainly no longer on any text in the frame. */
9623 clear_mouse_face (dpyinfo);
9624 dpyinfo->mouse_face_mouse_frame = 0;
9625 }
9626
9627 /* Generate a nil HELP_EVENT to cancel a help-echo.
9628 Do it only if there's something to cancel.
9629 Otherwise, the startup message is cleared when
9630 the mouse leaves the frame. */
9631 if (any_help_event_p)
9632 {
9633 XSETFRAME (frame, f);
9634 bufp->kind = HELP_EVENT;
9635 bufp->frame_or_window = Fcons (frame, Qnil);
9636 ++bufp, ++count, --numchars;
9637 }
7a13e894 9638
06a2c219
GM
9639#ifdef LESSTIF_VERSION
9640 /* Please see the comment at the start of the
9641 EnterNotify case. */
9642 if (!event.xcrossing.focus
9643 && f->output_data.x->menubar_widget)
9644 {
9645 Window focus;
9646 int revert;
9647 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9648 if (focus == XtWindow (f->output_data.x->menubar_widget))
9649 from_menu_bar_p = 1;
9650 }
9651#endif /* LESSTIF_VERSION */
9652
9653 if (event.xcrossing.focus || from_menu_bar_p)
0f941935 9654 x_mouse_leave (dpyinfo);
10c5e63d 9655 else
7a13e894 9656 {
0f941935
KH
9657 if (f == dpyinfo->x_focus_event_frame)
9658 dpyinfo->x_focus_event_frame = 0;
9659 if (f == dpyinfo->x_focus_frame)
9660 x_new_focus_frame (dpyinfo, 0);
7a13e894 9661 }
10c5e63d 9662 }
7a13e894 9663 goto OTHER;
dc6f92b8 9664
7a13e894 9665 case FocusOut:
19126e11 9666 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9667 if (event.xfocus.detail != NotifyPointer
0f941935
KH
9668 && f == dpyinfo->x_focus_event_frame)
9669 dpyinfo->x_focus_event_frame = 0;
9670 if (f && f == dpyinfo->x_focus_frame)
9671 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 9672
6c183ba5
RS
9673#ifdef HAVE_X_I18N
9674 if (f && FRAME_XIC (f))
9675 XUnsetICFocus (FRAME_XIC (f));
9676#endif
9677
7a13e894 9678 goto OTHER;
dc6f92b8 9679
7a13e894 9680 case MotionNotify:
dc6f92b8 9681 {
06a2c219
GM
9682 previous_help_echo = help_echo;
9683 help_echo = Qnil;
9684
7a13e894
RS
9685 if (dpyinfo->grabbed && last_mouse_frame
9686 && FRAME_LIVE_P (last_mouse_frame))
9687 f = last_mouse_frame;
9688 else
19126e11 9689 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 9690
7a13e894
RS
9691 if (f)
9692 note_mouse_movement (f, &event.xmotion);
9693 else
9694 {
e88b3c50 9695#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
9696 struct scroll_bar *bar
9697 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 9698
7a13e894
RS
9699 if (bar)
9700 x_scroll_bar_note_movement (bar, &event);
e88b3c50 9701#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 9702
06a2c219
GM
9703 /* If we move outside the frame, then we're
9704 certainly no longer on any text in the frame. */
7a13e894
RS
9705 clear_mouse_face (dpyinfo);
9706 }
06a2c219
GM
9707
9708 /* If the contents of the global variable help_echo
9709 has changed, generate a HELP_EVENT. */
9710 if (STRINGP (help_echo)
9711 || STRINGP (previous_help_echo))
9712 {
9713 Lisp_Object frame;
9714
9715 if (f)
9716 XSETFRAME (frame, f);
9717 else
9718 frame = Qnil;
9719
9720 any_help_event_p = 1;
9721 bufp->kind = HELP_EVENT;
9722 bufp->frame_or_window = Fcons (frame, help_echo);
9723 ++bufp, ++count, --numchars;
9724 }
9725
9726 goto OTHER;
dc6f92b8 9727 }
dc6f92b8 9728
7a13e894 9729 case ConfigureNotify:
9829ddba
RS
9730 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
9731 if (f)
af395ec1 9732 {
5c187dee 9733#ifndef USE_X_TOOLKIT
bf1b7b30
KH
9734 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
9735 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 9736
2d7fc7e8
RS
9737 /* In the toolkit version, change_frame_size
9738 is called by the code that handles resizing
9739 of the EmacsFrame widget. */
7a13e894 9740
7a13e894
RS
9741 /* Even if the number of character rows and columns has
9742 not changed, the font size may have changed, so we need
9743 to check the pixel dimensions as well. */
9744 if (columns != f->width
9745 || rows != f->height
7556890b
RS
9746 || event.xconfigure.width != f->output_data.x->pixel_width
9747 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 9748 {
7d1e984f 9749 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 9750 SET_FRAME_GARBAGED (f);
e687d06e 9751 cancel_mouse_face (f);
7a13e894 9752 }
2d7fc7e8 9753#endif
af395ec1 9754
7556890b
RS
9755 f->output_data.x->pixel_width = event.xconfigure.width;
9756 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
9757
9758 /* What we have now is the position of Emacs's own window.
9759 Convert that to the position of the window manager window. */
dcb07ae9
RS
9760 x_real_positions (f, &f->output_data.x->left_pos,
9761 &f->output_data.x->top_pos);
9762
f5d11644
GM
9763#ifdef HAVE_X_I18N
9764 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
9765 xic_set_statusarea (f);
9766#endif
9767
dcb07ae9
RS
9768 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
9769 {
9770 /* Since the WM decorations come below top_pos now,
9771 we must put them below top_pos in the future. */
9772 f->output_data.x->win_gravity = NorthWestGravity;
9773 x_wm_set_size_hint (f, (long) 0, 0);
9774 }
8f08dc93
KH
9775#ifdef USE_MOTIF
9776 /* Some window managers pass (0,0) as the location of
9777 the window, and the Motif event handler stores it
9778 in the emacs widget, which messes up Motif menus. */
9779 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
9780 {
9781 event.xconfigure.x = f->output_data.x->widget->core.x;
9782 event.xconfigure.y = f->output_data.x->widget->core.y;
9783 }
06a2c219 9784#endif /* USE_MOTIF */
7a13e894 9785 }
2d7fc7e8 9786 goto OTHER;
dc6f92b8 9787
7a13e894
RS
9788 case ButtonPress:
9789 case ButtonRelease:
9790 {
9791 /* If we decide we want to generate an event to be seen
9792 by the rest of Emacs, we put it here. */
9793 struct input_event emacs_event;
9ea173e8 9794 int tool_bar_p = 0;
06a2c219 9795
7a13e894 9796 emacs_event.kind = no_event;
7a13e894 9797 bzero (&compose_status, sizeof (compose_status));
9b07615b 9798
06a2c219
GM
9799 if (dpyinfo->grabbed
9800 && last_mouse_frame
9f67f20b
RS
9801 && FRAME_LIVE_P (last_mouse_frame))
9802 f = last_mouse_frame;
9803 else
2224b905 9804 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 9805
06a2c219
GM
9806 if (f)
9807 {
9ea173e8
GM
9808 /* Is this in the tool-bar? */
9809 if (WINDOWP (f->tool_bar_window)
9810 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
9811 {
9812 Lisp_Object window;
9813 int p, x, y;
9814
9815 x = event.xbutton.x;
9816 y = event.xbutton.y;
9817
9818 /* Set x and y. */
9819 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 9820 if (EQ (window, f->tool_bar_window))
06a2c219 9821 {
9ea173e8
GM
9822 x_handle_tool_bar_click (f, &event.xbutton);
9823 tool_bar_p = 1;
06a2c219
GM
9824 }
9825 }
9826
9ea173e8 9827 if (!tool_bar_p)
06a2c219
GM
9828 if (!dpyinfo->x_focus_frame
9829 || f == dpyinfo->x_focus_frame)
9830 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
9831 }
9832 else
9833 {
06a2c219 9834#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
9835 struct scroll_bar *bar
9836 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 9837
7a13e894
RS
9838 if (bar)
9839 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 9840#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9841 }
9842
9843 if (event.type == ButtonPress)
9844 {
9845 dpyinfo->grabbed |= (1 << event.xbutton.button);
9846 last_mouse_frame = f;
edad46f6
KH
9847 /* Ignore any mouse motion that happened
9848 before this event; any subsequent mouse-movement
9849 Emacs events should reflect only motion after
9850 the ButtonPress. */
a00e91cd
KH
9851 if (f != 0)
9852 f->mouse_moved = 0;
06a2c219 9853
9ea173e8
GM
9854 if (!tool_bar_p)
9855 last_tool_bar_item = -1;
7a13e894 9856 }
3afe33e7
RS
9857 else
9858 {
7a13e894 9859 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 9860 }
23faf38f 9861
7a13e894
RS
9862 if (numchars >= 1 && emacs_event.kind != no_event)
9863 {
9864 bcopy (&emacs_event, bufp, sizeof (struct input_event));
9865 bufp++;
9866 count++;
9867 numchars--;
9868 }
3afe33e7
RS
9869
9870#ifdef USE_X_TOOLKIT
2224b905
RS
9871 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
9872 /* For a down-event in the menu bar,
9873 don't pass it to Xt right now.
9874 Instead, save it away
9875 and we will pass it to Xt from kbd_buffer_get_event.
9876 That way, we can run some Lisp code first. */
91375f8f
RS
9877 if (f && event.type == ButtonPress
9878 /* Verify the event is really within the menu bar
9879 and not just sent to it due to grabbing. */
9880 && event.xbutton.x >= 0
9881 && event.xbutton.x < f->output_data.x->pixel_width
9882 && event.xbutton.y >= 0
9883 && event.xbutton.y < f->output_data.x->menubar_height
9884 && event.xbutton.same_screen)
2224b905 9885 {
8805890a 9886 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
9887 XSETFRAME (last_mouse_press_frame, f);
9888 }
9889 else if (event.type == ButtonPress)
9890 {
9891 last_mouse_press_frame = Qnil;
30e671c3 9892 goto OTHER;
ce89ef46 9893 }
06a2c219 9894
2237cac9
RS
9895#ifdef USE_MOTIF /* This should do not harm for Lucid,
9896 but I am trying to be cautious. */
ce89ef46
RS
9897 else if (event.type == ButtonRelease)
9898 {
2237cac9 9899 if (!NILP (last_mouse_press_frame))
f10ded1c 9900 {
2237cac9
RS
9901 f = XFRAME (last_mouse_press_frame);
9902 if (f->output_data.x)
06a2c219 9903 SET_SAVED_BUTTON_EVENT;
f10ded1c 9904 }
06a2c219 9905 else
30e671c3 9906 goto OTHER;
2224b905 9907 }
2237cac9 9908#endif /* USE_MOTIF */
2224b905
RS
9909 else
9910 goto OTHER;
3afe33e7 9911#endif /* USE_X_TOOLKIT */
7a13e894
RS
9912 }
9913 break;
dc6f92b8 9914
7a13e894 9915 case CirculateNotify:
06a2c219
GM
9916 goto OTHER;
9917
7a13e894 9918 case CirculateRequest:
06a2c219
GM
9919 goto OTHER;
9920
9921 case VisibilityNotify:
9922 goto OTHER;
dc6f92b8 9923
7a13e894
RS
9924 case MappingNotify:
9925 /* Someone has changed the keyboard mapping - update the
9926 local cache. */
9927 switch (event.xmapping.request)
9928 {
9929 case MappingModifier:
9930 x_find_modifier_meanings (dpyinfo);
9931 /* This is meant to fall through. */
9932 case MappingKeyboard:
9933 XRefreshKeyboardMapping (&event.xmapping);
9934 }
7a13e894 9935 goto OTHER;
dc6f92b8 9936
7a13e894 9937 default:
7a13e894 9938 OTHER:
717ca130 9939#ifdef USE_X_TOOLKIT
7a13e894
RS
9940 BLOCK_INPUT;
9941 XtDispatchEvent (&event);
9942 UNBLOCK_INPUT;
3afe33e7 9943#endif /* USE_X_TOOLKIT */
7a13e894
RS
9944 break;
9945 }
dc6f92b8
JB
9946 }
9947 }
9948
06a2c219
GM
9949 out:;
9950
9a5196d0
RS
9951 /* On some systems, an X bug causes Emacs to get no more events
9952 when the window is destroyed. Detect that. (1994.) */
58769bee 9953 if (! event_found)
ef2a22d0 9954 {
ef2a22d0
RS
9955 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
9956 One XNOOP in 100 loops will make Emacs terminate.
9957 B. Bretthauer, 1994 */
9958 x_noop_count++;
58769bee 9959 if (x_noop_count >= 100)
ef2a22d0
RS
9960 {
9961 x_noop_count=0;
2224b905
RS
9962
9963 if (next_noop_dpyinfo == 0)
9964 next_noop_dpyinfo = x_display_list;
9965
9966 XNoOp (next_noop_dpyinfo->display);
9967
9968 /* Each time we get here, cycle through the displays now open. */
9969 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
9970 }
9971 }
502add23 9972
06a2c219 9973 /* If the focus was just given to an auto-raising frame,
0134a210 9974 raise it now. */
7a13e894 9975 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
9976 if (pending_autoraise_frame)
9977 {
9978 x_raise_frame (pending_autoraise_frame);
9979 pending_autoraise_frame = 0;
9980 }
0134a210 9981
dc6f92b8
JB
9982 UNBLOCK_INPUT;
9983 return count;
9984}
06a2c219
GM
9985
9986
9987
dc6f92b8 9988\f
06a2c219
GM
9989/***********************************************************************
9990 Text Cursor
9991 ***********************************************************************/
9992
9993/* Note if the text cursor of window W has been overwritten by a
9994 drawing operation that outputs N glyphs starting at HPOS in the
9995 line given by output_cursor.vpos. N < 0 means all the rest of the
9996 line after HPOS has been written. */
9997
9998static void
9999note_overwritten_text_cursor (w, hpos, n)
10000 struct window *w;
10001 int hpos, n;
10002{
10003 if (updated_area == TEXT_AREA
10004 && output_cursor.vpos == w->phys_cursor.vpos
10005 && hpos <= w->phys_cursor.hpos
10006 && (n < 0
10007 || hpos + n > w->phys_cursor.hpos))
10008 w->phys_cursor_on_p = 0;
10009}
f451eb13
JB
10010
10011
06a2c219
GM
10012/* Set clipping for output in glyph row ROW. W is the window in which
10013 we operate. GC is the graphics context to set clipping in.
10014 WHOLE_LINE_P non-zero means include the areas used for truncation
10015 mark display and alike in the clipping rectangle.
10016
10017 ROW may be a text row or, e.g., a mode line. Text rows must be
10018 clipped to the interior of the window dedicated to text display,
10019 mode lines must be clipped to the whole window. */
dc6f92b8
JB
10020
10021static void
06a2c219
GM
10022x_clip_to_row (w, row, gc, whole_line_p)
10023 struct window *w;
10024 struct glyph_row *row;
10025 GC gc;
10026 int whole_line_p;
dc6f92b8 10027{
06a2c219
GM
10028 struct frame *f = XFRAME (WINDOW_FRAME (w));
10029 XRectangle clip_rect;
10030 int window_x, window_y, window_width, window_height;
dc6f92b8 10031
06a2c219 10032 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 10033
06a2c219
GM
10034 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
10035 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
10036 clip_rect.y = max (clip_rect.y, window_y);
10037 clip_rect.width = window_width;
10038 clip_rect.height = row->visible_height;
5c1aae96 10039
06a2c219
GM
10040 /* If clipping to the whole line, including trunc marks, extend
10041 the rectangle to the left and increase its width. */
10042 if (whole_line_p)
10043 {
110859fc
GM
10044 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
10045 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 10046 }
5c1aae96 10047
06a2c219 10048 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
10049}
10050
06a2c219
GM
10051
10052/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
10053
10054static void
06a2c219
GM
10055x_draw_hollow_cursor (w, row)
10056 struct window *w;
10057 struct glyph_row *row;
dc6f92b8 10058{
06a2c219
GM
10059 struct frame *f = XFRAME (WINDOW_FRAME (w));
10060 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10061 Display *dpy = FRAME_X_DISPLAY (f);
10062 int x, y, wd, h;
10063 XGCValues xgcv;
10064 struct glyph *cursor_glyph;
10065 GC gc;
10066
10067 /* Compute frame-relative coordinates from window-relative
10068 coordinates. */
10069 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10070 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
10071 + row->ascent - w->phys_cursor_ascent);
10072 h = row->height - 1;
10073
10074 /* Get the glyph the cursor is on. If we can't tell because
10075 the current matrix is invalid or such, give up. */
10076 cursor_glyph = get_phys_cursor_glyph (w);
10077 if (cursor_glyph == NULL)
dc6f92b8
JB
10078 return;
10079
06a2c219
GM
10080 /* Compute the width of the rectangle to draw. If on a stretch
10081 glyph, and `x-stretch-block-cursor' is nil, don't draw a
10082 rectangle as wide as the glyph, but use a canonical character
10083 width instead. */
10084 wd = cursor_glyph->pixel_width - 1;
10085 if (cursor_glyph->type == STRETCH_GLYPH
10086 && !x_stretch_cursor_p)
10087 wd = min (CANON_X_UNIT (f), wd);
10088
10089 /* The foreground of cursor_gc is typically the same as the normal
10090 background color, which can cause the cursor box to be invisible. */
10091 xgcv.foreground = f->output_data.x->cursor_pixel;
10092 if (dpyinfo->scratch_cursor_gc)
10093 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
10094 else
10095 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
10096 GCForeground, &xgcv);
10097 gc = dpyinfo->scratch_cursor_gc;
10098
10099 /* Set clipping, draw the rectangle, and reset clipping again. */
10100 x_clip_to_row (w, row, gc, 0);
10101 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
10102 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
10103}
10104
06a2c219
GM
10105
10106/* Draw a bar cursor on window W in glyph row ROW.
10107
10108 Implementation note: One would like to draw a bar cursor with an
10109 angle equal to the one given by the font property XA_ITALIC_ANGLE.
10110 Unfortunately, I didn't find a font yet that has this property set.
10111 --gerd. */
dc6f92b8
JB
10112
10113static void
06a2c219
GM
10114x_draw_bar_cursor (w, row)
10115 struct window *w;
10116 struct glyph_row *row;
dc6f92b8 10117{
06a2c219
GM
10118 /* If cursor hpos is out of bounds, don't draw garbage. This can
10119 happen in mini-buffer windows when switching between echo area
10120 glyphs and mini-buffer. */
10121 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
10122 {
10123 struct frame *f = XFRAME (w->frame);
10124 struct glyph *cursor_glyph;
10125 GC gc;
10126 int x;
10127 unsigned long mask;
10128 XGCValues xgcv;
10129 Display *dpy;
10130 Window window;
10131
10132 cursor_glyph = get_phys_cursor_glyph (w);
10133 if (cursor_glyph == NULL)
10134 return;
10135
10136 xgcv.background = f->output_data.x->cursor_pixel;
10137 xgcv.foreground = f->output_data.x->cursor_pixel;
10138 xgcv.graphics_exposures = 0;
10139 mask = GCForeground | GCBackground | GCGraphicsExposures;
10140 dpy = FRAME_X_DISPLAY (f);
10141 window = FRAME_X_WINDOW (f);
10142 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
10143
10144 if (gc)
10145 XChangeGC (dpy, gc, mask, &xgcv);
10146 else
10147 {
10148 gc = XCreateGC (dpy, window, mask, &xgcv);
10149 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
10150 }
10151
10152 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10153 x_clip_to_row (w, row, gc, 0);
10154 XFillRectangle (dpy, window, gc,
10155 x,
10156 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
10157 min (cursor_glyph->pixel_width,
10158 f->output_data.x->cursor_width),
10159 row->height);
10160 XSetClipMask (dpy, gc, None);
10161 }
dc6f92b8
JB
10162}
10163
06a2c219
GM
10164
10165/* Clear the cursor of window W to background color, and mark the
10166 cursor as not shown. This is used when the text where the cursor
10167 is is about to be rewritten. */
10168
dc6f92b8 10169static void
06a2c219
GM
10170x_clear_cursor (w)
10171 struct window *w;
dc6f92b8 10172{
06a2c219
GM
10173 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
10174 x_update_window_cursor (w, 0);
10175}
90e65f07 10176
dbc4e1c1 10177
06a2c219
GM
10178/* Draw the cursor glyph of window W in glyph row ROW. See the
10179 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 10180
06a2c219
GM
10181static void
10182x_draw_phys_cursor_glyph (w, row, hl)
10183 struct window *w;
10184 struct glyph_row *row;
10185 enum draw_glyphs_face hl;
10186{
10187 /* If cursor hpos is out of bounds, don't draw garbage. This can
10188 happen in mini-buffer windows when switching between echo area
10189 glyphs and mini-buffer. */
10190 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
10191 {
10192 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
10193 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
10194 hl, 0, 0, 0);
10195
10196 /* When we erase the cursor, and ROW is overlapped by other
10197 rows, make sure that these overlapping parts of other rows
10198 are redrawn. */
10199 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
10200 {
10201 if (row > w->current_matrix->rows
10202 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
10203 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
10204
10205 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
10206 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
10207 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
10208 }
10209 }
06a2c219 10210}
dbc4e1c1 10211
eea6af04 10212
06a2c219 10213/* Erase the image of a cursor of window W from the screen. */
eea6af04 10214
06a2c219
GM
10215static void
10216x_erase_phys_cursor (w)
10217 struct window *w;
10218{
10219 struct frame *f = XFRAME (w->frame);
10220 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10221 int hpos = w->phys_cursor.hpos;
10222 int vpos = w->phys_cursor.vpos;
10223 int mouse_face_here_p = 0;
10224 struct glyph_matrix *active_glyphs = w->current_matrix;
10225 struct glyph_row *cursor_row;
10226 struct glyph *cursor_glyph;
10227 enum draw_glyphs_face hl;
10228
10229 /* No cursor displayed or row invalidated => nothing to do on the
10230 screen. */
10231 if (w->phys_cursor_type == NO_CURSOR)
10232 goto mark_cursor_off;
10233
10234 /* VPOS >= active_glyphs->nrows means that window has been resized.
10235 Don't bother to erase the cursor. */
10236 if (vpos >= active_glyphs->nrows)
10237 goto mark_cursor_off;
10238
10239 /* If row containing cursor is marked invalid, there is nothing we
10240 can do. */
10241 cursor_row = MATRIX_ROW (active_glyphs, vpos);
10242 if (!cursor_row->enabled_p)
10243 goto mark_cursor_off;
10244
10245 /* This can happen when the new row is shorter than the old one.
10246 In this case, either x_draw_glyphs or clear_end_of_line
10247 should have cleared the cursor. Note that we wouldn't be
10248 able to erase the cursor in this case because we don't have a
10249 cursor glyph at hand. */
10250 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
10251 goto mark_cursor_off;
10252
10253 /* If the cursor is in the mouse face area, redisplay that when
10254 we clear the cursor. */
10255 if (w == XWINDOW (dpyinfo->mouse_face_window)
10256 && (vpos > dpyinfo->mouse_face_beg_row
10257 || (vpos == dpyinfo->mouse_face_beg_row
10258 && hpos >= dpyinfo->mouse_face_beg_col))
10259 && (vpos < dpyinfo->mouse_face_end_row
10260 || (vpos == dpyinfo->mouse_face_end_row
10261 && hpos < dpyinfo->mouse_face_end_col))
10262 /* Don't redraw the cursor's spot in mouse face if it is at the
10263 end of a line (on a newline). The cursor appears there, but
10264 mouse highlighting does not. */
10265 && cursor_row->used[TEXT_AREA] > hpos)
10266 mouse_face_here_p = 1;
10267
10268 /* Maybe clear the display under the cursor. */
10269 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
10270 {
10271 int x;
045dee35 10272 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 10273
06a2c219
GM
10274 cursor_glyph = get_phys_cursor_glyph (w);
10275 if (cursor_glyph == NULL)
10276 goto mark_cursor_off;
dbc4e1c1 10277
06a2c219
GM
10278 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
10279
10280 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10281 x,
045dee35 10282 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219
GM
10283 cursor_row->y)),
10284 cursor_glyph->pixel_width,
10285 cursor_row->visible_height,
10286 False);
dbc4e1c1 10287 }
06a2c219
GM
10288
10289 /* Erase the cursor by redrawing the character underneath it. */
10290 if (mouse_face_here_p)
10291 hl = DRAW_MOUSE_FACE;
10292 else if (cursor_row->inverse_p)
10293 hl = DRAW_INVERSE_VIDEO;
10294 else
10295 hl = DRAW_NORMAL_TEXT;
10296 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 10297
06a2c219
GM
10298 mark_cursor_off:
10299 w->phys_cursor_on_p = 0;
10300 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
10301}
10302
10303
06a2c219
GM
10304/* Display or clear cursor of window W. If ON is zero, clear the
10305 cursor. If it is non-zero, display the cursor. If ON is nonzero,
10306 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 10307
06a2c219
GM
10308void
10309x_display_and_set_cursor (w, on, hpos, vpos, x, y)
10310 struct window *w;
10311 int on, hpos, vpos, x, y;
dbc4e1c1 10312{
06a2c219
GM
10313 struct frame *f = XFRAME (w->frame);
10314 int new_cursor_type;
10315 struct glyph_matrix *current_glyphs;
10316 struct glyph_row *glyph_row;
10317 struct glyph *glyph;
dbc4e1c1 10318
49d838ea 10319 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
10320 windows and frames; in the latter case, the frame or window may
10321 be in the midst of changing its size, and x and y may be off the
10322 window. */
10323 if (! FRAME_VISIBLE_P (f)
10324 || FRAME_GARBAGED_P (f)
10325 || vpos >= w->current_matrix->nrows
10326 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
10327 return;
10328
10329 /* If cursor is off and we want it off, return quickly. */
06a2c219 10330 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
10331 return;
10332
06a2c219
GM
10333 current_glyphs = w->current_matrix;
10334 glyph_row = MATRIX_ROW (current_glyphs, vpos);
10335 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
10336
10337 /* If cursor row is not enabled, we don't really know where to
10338 display the cursor. */
10339 if (!glyph_row->enabled_p)
10340 {
10341 w->phys_cursor_on_p = 0;
10342 return;
10343 }
10344
10345 xassert (interrupt_input_blocked);
10346
10347 /* Set new_cursor_type to the cursor we want to be displayed. In a
10348 mini-buffer window, we want the cursor only to appear if we are
10349 reading input from this window. For the selected window, we want
10350 the cursor type given by the frame parameter. If explicitly
10351 marked off, draw no cursor. In all other cases, we want a hollow
10352 box cursor. */
9b4a7047
GM
10353 if (cursor_in_echo_area
10354 && FRAME_HAS_MINIBUF_P (f)
10355 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 10356 {
9b4a7047
GM
10357 if (w == XWINDOW (echo_area_window))
10358 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
10359 else
10360 new_cursor_type = HOLLOW_BOX_CURSOR;
10361 }
06a2c219 10362 else
9b4a7047
GM
10363 {
10364 if (w != XWINDOW (selected_window)
10365 || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
10366 {
e55a0b79
GM
10367 extern int cursor_in_non_selected_windows;
10368
10369 if (MINI_WINDOW_P (w) || !cursor_in_non_selected_windows)
9b4a7047
GM
10370 new_cursor_type = NO_CURSOR;
10371 else
10372 new_cursor_type = HOLLOW_BOX_CURSOR;
10373 }
10374 else if (w->cursor_off_p)
10375 new_cursor_type = NO_CURSOR;
10376 else
10377 new_cursor_type = FRAME_DESIRED_CURSOR (f);
10378 }
06a2c219
GM
10379
10380 /* If cursor is currently being shown and we don't want it to be or
10381 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 10382 erase it. */
06a2c219 10383 if (w->phys_cursor_on_p
dc6f92b8 10384 && (!on
06a2c219
GM
10385 || w->phys_cursor.x != x
10386 || w->phys_cursor.y != y
10387 || new_cursor_type != w->phys_cursor_type))
10388 x_erase_phys_cursor (w);
10389
10390 /* If the cursor is now invisible and we want it to be visible,
10391 display it. */
10392 if (on && !w->phys_cursor_on_p)
10393 {
10394 w->phys_cursor_ascent = glyph_row->ascent;
10395 w->phys_cursor_height = glyph_row->height;
10396
10397 /* Set phys_cursor_.* before x_draw_.* is called because some
10398 of them may need the information. */
10399 w->phys_cursor.x = x;
10400 w->phys_cursor.y = glyph_row->y;
10401 w->phys_cursor.hpos = hpos;
10402 w->phys_cursor.vpos = vpos;
10403 w->phys_cursor_type = new_cursor_type;
10404 w->phys_cursor_on_p = 1;
10405
10406 switch (new_cursor_type)
dc6f92b8 10407 {
06a2c219
GM
10408 case HOLLOW_BOX_CURSOR:
10409 x_draw_hollow_cursor (w, glyph_row);
10410 break;
10411
10412 case FILLED_BOX_CURSOR:
10413 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
10414 break;
10415
10416 case BAR_CURSOR:
10417 x_draw_bar_cursor (w, glyph_row);
10418 break;
10419
10420 case NO_CURSOR:
10421 break;
dc6f92b8 10422
06a2c219
GM
10423 default:
10424 abort ();
10425 }
59ddecde
GM
10426
10427#ifdef HAVE_X_I18N
10428 if (w == XWINDOW (f->selected_window))
10429 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
10430 xic_set_preeditarea (w, x, y);
10431#endif
dc6f92b8
JB
10432 }
10433
06a2c219 10434#ifndef XFlush
f676886a 10435 if (updating_frame != f)
334208b7 10436 XFlush (FRAME_X_DISPLAY (f));
06a2c219 10437#endif
dc6f92b8
JB
10438}
10439
06a2c219
GM
10440
10441/* Display the cursor on window W, or clear it. X and Y are window
10442 relative pixel coordinates. HPOS and VPOS are glyph matrix
10443 positions. If W is not the selected window, display a hollow
10444 cursor. ON non-zero means display the cursor at X, Y which
10445 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 10446
dfcf069d 10447void
06a2c219
GM
10448x_display_cursor (w, on, hpos, vpos, x, y)
10449 struct window *w;
10450 int on, hpos, vpos, x, y;
dc6f92b8 10451{
f94397b5 10452 BLOCK_INPUT;
06a2c219 10453 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
10454 UNBLOCK_INPUT;
10455}
10456
06a2c219
GM
10457
10458/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
10459 Don't change the cursor's position. */
10460
dfcf069d 10461void
06a2c219 10462x_update_cursor (f, on_p)
5d46f928 10463 struct frame *f;
5d46f928 10464{
06a2c219
GM
10465 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
10466}
10467
10468
10469/* Call x_update_window_cursor with parameter ON_P on all leaf windows
10470 in the window tree rooted at W. */
10471
10472static void
10473x_update_cursor_in_window_tree (w, on_p)
10474 struct window *w;
10475 int on_p;
10476{
10477 while (w)
10478 {
10479 if (!NILP (w->hchild))
10480 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
10481 else if (!NILP (w->vchild))
10482 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
10483 else
10484 x_update_window_cursor (w, on_p);
10485
10486 w = NILP (w->next) ? 0 : XWINDOW (w->next);
10487 }
10488}
5d46f928 10489
f94397b5 10490
06a2c219
GM
10491/* Switch the display of W's cursor on or off, according to the value
10492 of ON. */
10493
10494static void
10495x_update_window_cursor (w, on)
10496 struct window *w;
10497 int on;
10498{
10499 BLOCK_INPUT;
10500 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
10501 w->phys_cursor.x, w->phys_cursor.y);
f94397b5 10502 UNBLOCK_INPUT;
dc6f92b8 10503}
06a2c219
GM
10504
10505
10506
dc6f92b8
JB
10507\f
10508/* Icons. */
10509
f676886a 10510/* Refresh bitmap kitchen sink icon for frame F
06a2c219 10511 when we get an expose event for it. */
dc6f92b8 10512
dfcf069d 10513void
f676886a
JB
10514refreshicon (f)
10515 struct frame *f;
dc6f92b8 10516{
06a2c219 10517 /* Normally, the window manager handles this function. */
dc6f92b8
JB
10518}
10519
dbc4e1c1 10520/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
10521
10522int
990ba854 10523x_bitmap_icon (f, file)
f676886a 10524 struct frame *f;
990ba854 10525 Lisp_Object file;
dc6f92b8 10526{
06a2c219 10527 int bitmap_id;
dc6f92b8 10528
c118dd06 10529 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10530 return 1;
10531
990ba854 10532 /* Free up our existing icon bitmap if any. */
7556890b
RS
10533 if (f->output_data.x->icon_bitmap > 0)
10534 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10535 f->output_data.x->icon_bitmap = 0;
990ba854
RS
10536
10537 if (STRINGP (file))
7f2ae036
RS
10538 bitmap_id = x_create_bitmap_from_file (f, file);
10539 else
10540 {
990ba854 10541 /* Create the GNU bitmap if necessary. */
5bf01b68 10542 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
10543 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
10544 = x_create_bitmap_from_data (f, gnu_bits,
10545 gnu_width, gnu_height);
990ba854
RS
10546
10547 /* The first time we create the GNU bitmap,
06a2c219 10548 this increments the ref-count one extra time.
990ba854
RS
10549 As a result, the GNU bitmap is never freed.
10550 That way, we don't have to worry about allocating it again. */
334208b7 10551 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 10552
334208b7 10553 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
10554 }
10555
10556 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 10557 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
10558
10559 return 0;
10560}
10561
10562
1be2d067
KH
10563/* Make the x-window of frame F use a rectangle with text.
10564 Use ICON_NAME as the text. */
dc6f92b8
JB
10565
10566int
f676886a
JB
10567x_text_icon (f, icon_name)
10568 struct frame *f;
dc6f92b8
JB
10569 char *icon_name;
10570{
c118dd06 10571 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10572 return 1;
10573
1be2d067
KH
10574#ifdef HAVE_X11R4
10575 {
10576 XTextProperty text;
10577 text.value = (unsigned char *) icon_name;
10578 text.encoding = XA_STRING;
10579 text.format = 8;
10580 text.nitems = strlen (icon_name);
10581#ifdef USE_X_TOOLKIT
7556890b 10582 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
10583 &text);
10584#else /* not USE_X_TOOLKIT */
10585 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
10586#endif /* not USE_X_TOOLKIT */
10587 }
10588#else /* not HAVE_X11R4 */
10589 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
10590#endif /* not HAVE_X11R4 */
58769bee 10591
7556890b
RS
10592 if (f->output_data.x->icon_bitmap > 0)
10593 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10594 f->output_data.x->icon_bitmap = 0;
b1c884c3 10595 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
10596
10597 return 0;
10598}
10599\f
e99db5a1
RS
10600#define X_ERROR_MESSAGE_SIZE 200
10601
10602/* If non-nil, this should be a string.
10603 It means catch X errors and store the error message in this string. */
10604
10605static Lisp_Object x_error_message_string;
10606
10607/* An X error handler which stores the error message in
10608 x_error_message_string. This is called from x_error_handler if
10609 x_catch_errors is in effect. */
10610
06a2c219 10611static void
e99db5a1
RS
10612x_error_catcher (display, error)
10613 Display *display;
10614 XErrorEvent *error;
10615{
10616 XGetErrorText (display, error->error_code,
10617 XSTRING (x_error_message_string)->data,
10618 X_ERROR_MESSAGE_SIZE);
10619}
10620
10621/* Begin trapping X errors for display DPY. Actually we trap X errors
10622 for all displays, but DPY should be the display you are actually
10623 operating on.
10624
10625 After calling this function, X protocol errors no longer cause
10626 Emacs to exit; instead, they are recorded in the string
10627 stored in x_error_message_string.
10628
10629 Calling x_check_errors signals an Emacs error if an X error has
10630 occurred since the last call to x_catch_errors or x_check_errors.
10631
10632 Calling x_uncatch_errors resumes the normal error handling. */
10633
10634void x_check_errors ();
10635static Lisp_Object x_catch_errors_unwind ();
10636
10637int
10638x_catch_errors (dpy)
10639 Display *dpy;
10640{
10641 int count = specpdl_ptr - specpdl;
10642
10643 /* Make sure any errors from previous requests have been dealt with. */
10644 XSync (dpy, False);
10645
10646 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
10647
10648 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
10649 XSTRING (x_error_message_string)->data[0] = 0;
10650
10651 return count;
10652}
10653
10654/* Unbind the binding that we made to check for X errors. */
10655
10656static Lisp_Object
10657x_catch_errors_unwind (old_val)
10658 Lisp_Object old_val;
10659{
10660 x_error_message_string = old_val;
10661 return Qnil;
10662}
10663
10664/* If any X protocol errors have arrived since the last call to
10665 x_catch_errors or x_check_errors, signal an Emacs error using
10666 sprintf (a buffer, FORMAT, the x error message text) as the text. */
10667
10668void
10669x_check_errors (dpy, format)
10670 Display *dpy;
10671 char *format;
10672{
10673 /* Make sure to catch any errors incurred so far. */
10674 XSync (dpy, False);
10675
10676 if (XSTRING (x_error_message_string)->data[0])
10677 error (format, XSTRING (x_error_message_string)->data);
10678}
10679
9829ddba
RS
10680/* Nonzero if we had any X protocol errors
10681 since we did x_catch_errors on DPY. */
e99db5a1
RS
10682
10683int
10684x_had_errors_p (dpy)
10685 Display *dpy;
10686{
10687 /* Make sure to catch any errors incurred so far. */
10688 XSync (dpy, False);
10689
10690 return XSTRING (x_error_message_string)->data[0] != 0;
10691}
10692
9829ddba
RS
10693/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
10694
06a2c219 10695void
9829ddba
RS
10696x_clear_errors (dpy)
10697 Display *dpy;
10698{
10699 XSTRING (x_error_message_string)->data[0] = 0;
10700}
10701
e99db5a1
RS
10702/* Stop catching X protocol errors and let them make Emacs die.
10703 DPY should be the display that was passed to x_catch_errors.
10704 COUNT should be the value that was returned by
10705 the corresponding call to x_catch_errors. */
10706
10707void
10708x_uncatch_errors (dpy, count)
10709 Display *dpy;
10710 int count;
10711{
10712 unbind_to (count, Qnil);
10713}
10714
10715#if 0
10716static unsigned int x_wire_count;
10717x_trace_wire ()
10718{
10719 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
10720}
10721#endif /* ! 0 */
10722
10723\f
10724/* Handle SIGPIPE, which can happen when the connection to a server
10725 simply goes away. SIGPIPE is handled by x_connection_signal.
10726 Don't need to do anything, because the write which caused the
10727 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 10728 which will do the appropriate cleanup for us. */
e99db5a1
RS
10729
10730static SIGTYPE
10731x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 10732 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
10733{
10734#ifdef USG
10735 /* USG systems forget handlers when they are used;
10736 must reestablish each time */
10737 signal (signalnum, x_connection_signal);
10738#endif /* USG */
10739}
10740\f
4746118a
JB
10741/* Handling X errors. */
10742
7a13e894 10743/* Handle the loss of connection to display DISPLAY. */
16bd92ea 10744
4746118a 10745static SIGTYPE
7a13e894
RS
10746x_connection_closed (display, error_message)
10747 Display *display;
10748 char *error_message;
4746118a 10749{
7a13e894
RS
10750 struct x_display_info *dpyinfo = x_display_info_for_display (display);
10751 Lisp_Object frame, tail;
10752
6186a4a0
RS
10753 /* Indicate that this display is dead. */
10754
2e465cdd 10755#if 0 /* Closing the display caused a bus error on OpenWindows. */
f613a4c8 10756#ifdef USE_X_TOOLKIT
adabc3a9 10757 XtCloseDisplay (display);
2e465cdd 10758#endif
f613a4c8 10759#endif
adabc3a9 10760
6186a4a0
RS
10761 dpyinfo->display = 0;
10762
06a2c219 10763 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
10764 that are on the dead display. */
10765 FOR_EACH_FRAME (tail, frame)
10766 {
10767 Lisp_Object minibuf_frame;
10768 minibuf_frame
10769 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
10770 if (FRAME_X_P (XFRAME (frame))
10771 && FRAME_X_P (XFRAME (minibuf_frame))
10772 && ! EQ (frame, minibuf_frame)
10773 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
10774 Fdelete_frame (frame, Qt);
10775 }
10776
10777 /* Now delete all remaining frames on the dead display.
06a2c219 10778 We are now sure none of these is used as the mini-buffer
7a13e894
RS
10779 for another frame that we need to delete. */
10780 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
10781 if (FRAME_X_P (XFRAME (frame))
10782 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
10783 {
10784 /* Set this to t so that Fdelete_frame won't get confused
10785 trying to find a replacement. */
10786 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
10787 Fdelete_frame (frame, Qt);
10788 }
7a13e894 10789
482a1bd2
KH
10790 if (dpyinfo)
10791 x_delete_display (dpyinfo);
7a13e894
RS
10792
10793 if (x_display_list == 0)
10794 {
f8d07b62 10795 fprintf (stderr, "%s\n", error_message);
7a13e894
RS
10796 shut_down_emacs (0, 0, Qnil);
10797 exit (70);
10798 }
12ba150f 10799
7a13e894
RS
10800 /* Ordinary stack unwind doesn't deal with these. */
10801#ifdef SIGIO
10802 sigunblock (sigmask (SIGIO));
10803#endif
10804 sigunblock (sigmask (SIGALRM));
10805 TOTALLY_UNBLOCK_INPUT;
10806
aa4d9a9e 10807 clear_waiting_for_input ();
7a13e894 10808 error ("%s", error_message);
4746118a
JB
10809}
10810
7a13e894
RS
10811/* This is the usual handler for X protocol errors.
10812 It kills all frames on the display that we got the error for.
10813 If that was the only one, it prints an error message and kills Emacs. */
10814
06a2c219 10815static void
c118dd06
JB
10816x_error_quitter (display, error)
10817 Display *display;
10818 XErrorEvent *error;
10819{
7a13e894 10820 char buf[256], buf1[356];
dc6f92b8 10821
58769bee 10822 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 10823 original error handler. */
dc6f92b8 10824
c118dd06 10825 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 10826 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 10827 buf, error->request_code);
7a13e894 10828 x_connection_closed (display, buf1);
dc6f92b8
JB
10829}
10830
e99db5a1
RS
10831/* This is the first-level handler for X protocol errors.
10832 It calls x_error_quitter or x_error_catcher. */
7a13e894 10833
8922af5f 10834static int
e99db5a1 10835x_error_handler (display, error)
8922af5f 10836 Display *display;
e99db5a1 10837 XErrorEvent *error;
8922af5f 10838{
e99db5a1
RS
10839 if (! NILP (x_error_message_string))
10840 x_error_catcher (display, error);
10841 else
10842 x_error_quitter (display, error);
06a2c219 10843 return 0;
f9e24cb9 10844}
c118dd06 10845
e99db5a1
RS
10846/* This is the handler for X IO errors, always.
10847 It kills all frames on the display that we lost touch with.
10848 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 10849
c118dd06 10850static int
e99db5a1 10851x_io_error_quitter (display)
c118dd06 10852 Display *display;
c118dd06 10853{
e99db5a1 10854 char buf[256];
dc6f92b8 10855
e99db5a1
RS
10856 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
10857 x_connection_closed (display, buf);
06a2c219 10858 return 0;
dc6f92b8 10859}
dc6f92b8 10860\f
f451eb13
JB
10861/* Changing the font of the frame. */
10862
76bcdf39
RS
10863/* Give frame F the font named FONTNAME as its default font, and
10864 return the full name of that font. FONTNAME may be a wildcard
10865 pattern; in that case, we choose some font that fits the pattern.
10866 The return value shows which font we chose. */
10867
b5cf7a0e 10868Lisp_Object
f676886a
JB
10869x_new_font (f, fontname)
10870 struct frame *f;
dc6f92b8
JB
10871 register char *fontname;
10872{
dc43ef94
KH
10873 struct font_info *fontp
10874 = fs_load_font (f, FRAME_X_FONT_TABLE (f), CHARSET_ASCII, fontname, -1);
dc6f92b8 10875
dc43ef94
KH
10876 if (!fontp)
10877 return Qnil;
2224a5fc 10878
dc43ef94 10879 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 10880 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
10881 f->output_data.x->fontset = -1;
10882
b2cad826
KH
10883 /* Compute the scroll bar width in character columns. */
10884 if (f->scroll_bar_pixel_width > 0)
10885 {
7556890b 10886 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
10887 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
10888 }
10889 else
4e61bddf
RS
10890 {
10891 int wid = FONT_WIDTH (f->output_data.x->font);
10892 f->scroll_bar_cols = (14 + wid - 1) / wid;
10893 }
b2cad826 10894
f676886a 10895 /* Now make the frame display the given font. */
c118dd06 10896 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 10897 {
7556890b
RS
10898 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
10899 f->output_data.x->font->fid);
10900 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
10901 f->output_data.x->font->fid);
10902 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
10903 f->output_data.x->font->fid);
f676886a 10904
a27f9f86 10905 frame_update_line_height (f);
0134a210 10906 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 10907 }
a27f9f86
RS
10908 else
10909 /* If we are setting a new frame's font for the first time,
10910 there are no faces yet, so this font's height is the line height. */
7556890b 10911 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 10912
dc43ef94
KH
10913 return build_string (fontp->full_name);
10914}
10915
10916/* Give frame F the fontset named FONTSETNAME as its default font, and
10917 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
10918 pattern; in that case, we choose some fontset that fits the pattern.
10919 The return value shows which fontset we chose. */
b5cf7a0e 10920
dc43ef94
KH
10921Lisp_Object
10922x_new_fontset (f, fontsetname)
10923 struct frame *f;
10924 char *fontsetname;
10925{
10926 int fontset = fs_query_fontset (f, fontsetname);
10927 struct fontset_info *fontsetp;
10928 Lisp_Object result;
b5cf7a0e 10929
dc43ef94
KH
10930 if (fontset < 0)
10931 return Qnil;
b5cf7a0e 10932
2da424f1
KH
10933 if (f->output_data.x->fontset == fontset)
10934 /* This fontset is already set in frame F. There's nothing more
10935 to do. */
10936 return build_string (fontsetname);
10937
dc43ef94
KH
10938 fontsetp = FRAME_FONTSET_DATA (f)->fontset_table[fontset];
10939
10940 if (!fontsetp->fontname[CHARSET_ASCII])
10941 /* This fontset doesn't contain ASCII font. */
10942 return Qnil;
10943
10944 result = x_new_font (f, fontsetp->fontname[CHARSET_ASCII]);
10945
10946 if (!STRINGP (result))
10947 /* Can't load ASCII font. */
10948 return Qnil;
10949
10950 /* Since x_new_font doesn't update any fontset information, do it now. */
10951 f->output_data.x->fontset = fontset;
2da424f1 10952 FS_LOAD_FONT (f, FRAME_X_FONT_TABLE (f),
715a159b 10953 CHARSET_ASCII, fontsetp->fontname[CHARSET_ASCII], fontset);
dc43ef94 10954
f5d11644
GM
10955#ifdef HAVE_X_I18N
10956 if (FRAME_XIC (f)
10957 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
10958 xic_set_xfontset (f, fontsetp->fontname[CHARSET_ASCII]);
10959#endif
10960
dc43ef94 10961 return build_string (fontsetname);
dc6f92b8 10962}
f5d11644
GM
10963
10964\f
10965/***********************************************************************
10966 X Input Methods
10967 ***********************************************************************/
10968
10969#ifdef HAVE_X_I18N
10970
10971#ifdef HAVE_X11R6
10972
10973/* XIM destroy callback function, which is called whenever the
10974 connection to input method XIM dies. CLIENT_DATA contains a
10975 pointer to the x_display_info structure corresponding to XIM. */
10976
10977static void
10978xim_destroy_callback (xim, client_data, call_data)
10979 XIM xim;
10980 XPointer client_data;
10981 XPointer call_data;
10982{
10983 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
10984 Lisp_Object frame, tail;
10985
10986 BLOCK_INPUT;
10987
10988 /* No need to call XDestroyIC.. */
10989 FOR_EACH_FRAME (tail, frame)
10990 {
10991 struct frame *f = XFRAME (frame);
10992 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
10993 {
10994 FRAME_XIC (f) = NULL;
10995 if (FRAME_XIC_FONTSET (f))
10996 {
10997 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
10998 FRAME_XIC_FONTSET (f) = NULL;
10999 }
11000 }
11001 }
11002
11003 /* No need to call XCloseIM. */
11004 dpyinfo->xim = NULL;
11005 XFree (dpyinfo->xim_styles);
11006 UNBLOCK_INPUT;
11007}
11008
11009#endif /* HAVE_X11R6 */
11010
11011/* Open the connection to the XIM server on display DPYINFO.
11012 RESOURCE_NAME is the resource name Emacs uses. */
11013
11014static void
11015xim_open_dpy (dpyinfo, resource_name)
11016 struct x_display_info *dpyinfo;
11017 char *resource_name;
11018{
11019 XIM xim;
11020
11021 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
11022 dpyinfo->xim = xim;
11023
11024 if (xim)
11025 {
f5d11644
GM
11026#ifdef HAVE_X11R6
11027 XIMCallback destroy;
11028#endif
11029
11030 /* Get supported styles and XIM values. */
11031 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
11032
11033#ifdef HAVE_X11R6
11034 destroy.callback = xim_destroy_callback;
11035 destroy.client_data = (XPointer)dpyinfo;
11036 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
11037#endif
11038 }
11039}
11040
11041
b9de836c 11042#ifdef HAVE_X11R6_XIM
f5d11644
GM
11043
11044struct xim_inst_t
11045{
11046 struct x_display_info *dpyinfo;
11047 char *resource_name;
11048};
11049
11050/* XIM instantiate callback function, which is called whenever an XIM
11051 server is available. DISPLAY is teh display of the XIM.
11052 CLIENT_DATA contains a pointer to an xim_inst_t structure created
11053 when the callback was registered. */
11054
11055static void
11056xim_instantiate_callback (display, client_data, call_data)
11057 Display *display;
11058 XPointer client_data;
11059 XPointer call_data;
11060{
11061 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
11062 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
11063
11064 /* We don't support multiple XIM connections. */
11065 if (dpyinfo->xim)
11066 return;
11067
11068 xim_open_dpy (dpyinfo, xim_inst->resource_name);
11069
11070 /* Create XIC for the existing frames on the same display, as long
11071 as they have no XIC. */
11072 if (dpyinfo->xim && dpyinfo->reference_count > 0)
11073 {
11074 Lisp_Object tail, frame;
11075
11076 BLOCK_INPUT;
11077 FOR_EACH_FRAME (tail, frame)
11078 {
11079 struct frame *f = XFRAME (frame);
11080
11081 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
11082 if (FRAME_XIC (f) == NULL)
11083 {
11084 create_frame_xic (f);
11085 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
11086 xic_set_statusarea (f);
11087 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
11088 {
11089 struct window *w = XWINDOW (f->selected_window);
11090 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
11091 }
11092 }
11093 }
11094
11095 UNBLOCK_INPUT;
11096 }
11097}
11098
b9de836c 11099#endif /* HAVE_X11R6_XIM */
f5d11644
GM
11100
11101
11102/* Open a connection to the XIM server on display DPYINFO.
11103 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
11104 connection only at the first time. On X11R6, open the connection
11105 in the XIM instantiate callback function. */
11106
11107static void
11108xim_initialize (dpyinfo, resource_name)
11109 struct x_display_info *dpyinfo;
11110 char *resource_name;
11111{
b9de836c 11112#ifdef HAVE_X11R6_XIM
f5d11644
GM
11113 struct xim_inst_t *xim_inst;
11114 int len;
11115
11116 dpyinfo->xim = NULL;
11117 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
11118 xim_inst->dpyinfo = dpyinfo;
11119 len = strlen (resource_name);
11120 xim_inst->resource_name = (char *) xmalloc (len + 1);
11121 bcopy (resource_name, xim_inst->resource_name, len + 1);
11122 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11123 resource_name, EMACS_CLASS,
11124 xim_instantiate_callback,
11125 (XPointer)xim_inst);
b9de836c 11126#else /* not HAVE_X11R6_XIM */
f5d11644
GM
11127 dpyinfo->xim = NULL;
11128 xim_open_dpy (dpyinfo, resource_name);
b9de836c 11129#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11130}
11131
11132
11133/* Close the connection to the XIM server on display DPYINFO. */
11134
11135static void
11136xim_close_dpy (dpyinfo)
11137 struct x_display_info *dpyinfo;
11138{
b9de836c 11139#ifdef HAVE_X11R6_XIM
f5d11644
GM
11140 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11141 NULL, EMACS_CLASS,
11142 xim_instantiate_callback, NULL);
b9de836c 11143#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11144 XCloseIM (dpyinfo->xim);
11145 dpyinfo->xim = NULL;
11146 XFree (dpyinfo->xim_styles);
11147}
11148
b9de836c 11149#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11150
11151
dc6f92b8 11152\f
2e365682
RS
11153/* Calculate the absolute position in frame F
11154 from its current recorded position values and gravity. */
11155
dfcf069d 11156void
43bca5d5 11157x_calc_absolute_position (f)
f676886a 11158 struct frame *f;
dc6f92b8 11159{
06a2c219 11160 Window child;
6dba1858 11161 int win_x = 0, win_y = 0;
7556890b 11162 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
11163 int this_window;
11164
9829ddba
RS
11165 /* We have nothing to do if the current position
11166 is already for the top-left corner. */
11167 if (! ((flags & XNegative) || (flags & YNegative)))
11168 return;
11169
c81412a0 11170#ifdef USE_X_TOOLKIT
7556890b 11171 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
11172#else
11173 this_window = FRAME_X_WINDOW (f);
11174#endif
6dba1858
RS
11175
11176 /* Find the position of the outside upper-left corner of
9829ddba
RS
11177 the inner window, with respect to the outer window.
11178 But do this only if we will need the results. */
7556890b 11179 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 11180 {
9829ddba
RS
11181 int count;
11182
6dba1858 11183 BLOCK_INPUT;
9829ddba
RS
11184 count = x_catch_errors (FRAME_X_DISPLAY (f));
11185 while (1)
11186 {
11187 x_clear_errors (FRAME_X_DISPLAY (f));
11188 XTranslateCoordinates (FRAME_X_DISPLAY (f),
11189
11190 /* From-window, to-window. */
11191 this_window,
11192 f->output_data.x->parent_desc,
11193
11194 /* From-position, to-position. */
11195 0, 0, &win_x, &win_y,
11196
11197 /* Child of win. */
11198 &child);
11199 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
11200 {
11201 Window newroot, newparent = 0xdeadbeef;
11202 Window *newchildren;
11203 int nchildren;
11204
11205 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
11206 &newparent, &newchildren, &nchildren))
11207 break;
58769bee 11208
7c3c78a3 11209 XFree ((char *) newchildren);
6dba1858 11210
9829ddba
RS
11211 f->output_data.x->parent_desc = newparent;
11212 }
11213 else
11214 break;
11215 }
6dba1858 11216
9829ddba 11217 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
11218 UNBLOCK_INPUT;
11219 }
11220
11221 /* Treat negative positions as relative to the leftmost bottommost
11222 position that fits on the screen. */
20f55f9a 11223 if (flags & XNegative)
7556890b 11224 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
11225 - 2 * f->output_data.x->border_width - win_x
11226 - PIXEL_WIDTH (f)
11227 + f->output_data.x->left_pos);
dc6f92b8 11228
20f55f9a 11229 if (flags & YNegative)
06a2c219
GM
11230 {
11231 int menubar_height = 0;
11232
11233#ifdef USE_X_TOOLKIT
11234 if (f->output_data.x->menubar_widget)
11235 menubar_height
11236 = (f->output_data.x->menubar_widget->core.height
11237 + f->output_data.x->menubar_widget->core.border_width);
11238#endif
11239
11240 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
11241 - 2 * f->output_data.x->border_width
11242 - win_y
11243 - PIXEL_HEIGHT (f)
11244 - menubar_height
11245 + f->output_data.x->top_pos);
11246 }
2e365682 11247
3a35ab44
RS
11248 /* The left_pos and top_pos
11249 are now relative to the top and left screen edges,
11250 so the flags should correspond. */
7556890b 11251 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
11252}
11253
3a35ab44
RS
11254/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
11255 to really change the position, and 0 when calling from
11256 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
11257 position values). It is -1 when calling from x_set_frame_parameters,
11258 which means, do adjust for borders but don't change the gravity. */
3a35ab44 11259
dfcf069d 11260void
dc05a16b 11261x_set_offset (f, xoff, yoff, change_gravity)
f676886a 11262 struct frame *f;
dc6f92b8 11263 register int xoff, yoff;
dc05a16b 11264 int change_gravity;
dc6f92b8 11265{
4a4cbdd5
KH
11266 int modified_top, modified_left;
11267
aa3ff7c9 11268 if (change_gravity > 0)
3a35ab44 11269 {
7556890b
RS
11270 f->output_data.x->top_pos = yoff;
11271 f->output_data.x->left_pos = xoff;
11272 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 11273 if (xoff < 0)
7556890b 11274 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 11275 if (yoff < 0)
7556890b
RS
11276 f->output_data.x->size_hint_flags |= YNegative;
11277 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 11278 }
43bca5d5 11279 x_calc_absolute_position (f);
dc6f92b8
JB
11280
11281 BLOCK_INPUT;
c32cdd9a 11282 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 11283
7556890b
RS
11284 modified_left = f->output_data.x->left_pos;
11285 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
11286#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
11287 this seems to be unnecessary and incorrect. rms, 4/17/97. */
11288 /* It is a mystery why we need to add the border_width here
11289 when the frame is already visible, but experiment says we do. */
aa3ff7c9 11290 if (change_gravity != 0)
4a4cbdd5 11291 {
7556890b
RS
11292 modified_left += f->output_data.x->border_width;
11293 modified_top += f->output_data.x->border_width;
4a4cbdd5 11294 }
e73ec6fa 11295#endif
4a4cbdd5 11296
3afe33e7 11297#ifdef USE_X_TOOLKIT
7556890b 11298 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 11299 modified_left, modified_top);
3afe33e7 11300#else /* not USE_X_TOOLKIT */
334208b7 11301 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 11302 modified_left, modified_top);
3afe33e7 11303#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11304 UNBLOCK_INPUT;
11305}
11306
bc20ebbf
FP
11307/* Call this to change the size of frame F's x-window.
11308 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
11309 for this size change and subsequent size changes.
11310 Otherwise we leave the window gravity unchanged. */
dc6f92b8 11311
dfcf069d 11312void
bc20ebbf 11313x_set_window_size (f, change_gravity, cols, rows)
f676886a 11314 struct frame *f;
bc20ebbf 11315 int change_gravity;
b1c884c3 11316 int cols, rows;
dc6f92b8 11317{
06a2c219 11318#ifndef USE_X_TOOLKIT
dc6f92b8 11319 int pixelwidth, pixelheight;
06a2c219 11320#endif
dc6f92b8 11321
80fd1fe2 11322 BLOCK_INPUT;
aee9a898
RS
11323
11324#ifdef USE_X_TOOLKIT
3a20653d
RS
11325 {
11326 /* The x and y position of the widget is clobbered by the
11327 call to XtSetValues within EmacsFrameSetCharSize.
11328 This is a real kludge, but I don't understand Xt so I can't
11329 figure out a correct fix. Can anyone else tell me? -- rms. */
7556890b
RS
11330 int xpos = f->output_data.x->widget->core.x;
11331 int ypos = f->output_data.x->widget->core.y;
11332 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
11333 f->output_data.x->widget->core.x = xpos;
11334 f->output_data.x->widget->core.y = ypos;
3a20653d 11335 }
80fd1fe2
FP
11336
11337#else /* not USE_X_TOOLKIT */
11338
b1c884c3 11339 check_frame_size (f, &rows, &cols);
7556890b 11340 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
11341 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
11342 ? 0
11343 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 11344 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 11345 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 11346 f->output_data.x->flags_areas_extra
110859fc 11347 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
11348 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
11349 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 11350
7556890b 11351 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 11352 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 11353
334208b7
RS
11354 XSync (FRAME_X_DISPLAY (f), False);
11355 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11356 pixelwidth, pixelheight);
b1c884c3
JB
11357
11358 /* Now, strictly speaking, we can't be sure that this is accurate,
11359 but the window manager will get around to dealing with the size
11360 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
11361 ConfigureNotify event gets here.
11362
11363 We could just not bother storing any of this information here,
11364 and let the ConfigureNotify event set everything up, but that
fddd5ceb 11365 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 11366 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
11367 point in the future when the ConfigureNotify event arrives.
11368
11369 We pass 1 for DELAY since we can't run Lisp code inside of
11370 a BLOCK_INPUT. */
7d1e984f 11371 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
11372 PIXEL_WIDTH (f) = pixelwidth;
11373 PIXEL_HEIGHT (f) = pixelheight;
11374
aee9a898
RS
11375 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
11376 receive in the ConfigureNotify event; if we get what we asked
11377 for, then the event won't cause the screen to become garbaged, so
11378 we have to make sure to do it here. */
11379 SET_FRAME_GARBAGED (f);
11380
11381 XFlush (FRAME_X_DISPLAY (f));
11382
11383#endif /* not USE_X_TOOLKIT */
11384
4d73d038 11385 /* If cursor was outside the new size, mark it as off. */
06a2c219 11386 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 11387
aee9a898
RS
11388 /* Clear out any recollection of where the mouse highlighting was,
11389 since it might be in a place that's outside the new frame size.
11390 Actually checking whether it is outside is a pain in the neck,
11391 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 11392 cancel_mouse_face (f);
dbc4e1c1 11393
dc6f92b8
JB
11394 UNBLOCK_INPUT;
11395}
dc6f92b8 11396\f
d047c4eb 11397/* Mouse warping. */
dc6f92b8 11398
9b378208 11399void
f676886a
JB
11400x_set_mouse_position (f, x, y)
11401 struct frame *f;
dc6f92b8
JB
11402 int x, y;
11403{
11404 int pix_x, pix_y;
11405
7556890b
RS
11406 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
11407 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
11408
11409 if (pix_x < 0) pix_x = 0;
11410 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
11411
11412 if (pix_y < 0) pix_y = 0;
11413 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
11414
11415 BLOCK_INPUT;
dc6f92b8 11416
334208b7
RS
11417 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11418 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
11419 UNBLOCK_INPUT;
11420}
11421
9b378208
RS
11422/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
11423
11424void
11425x_set_mouse_pixel_position (f, pix_x, pix_y)
11426 struct frame *f;
11427 int pix_x, pix_y;
11428{
11429 BLOCK_INPUT;
11430
334208b7
RS
11431 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11432 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
11433 UNBLOCK_INPUT;
11434}
d047c4eb
KH
11435\f
11436/* focus shifting, raising and lowering. */
9b378208 11437
dfcf069d 11438void
f676886a
JB
11439x_focus_on_frame (f)
11440 struct frame *f;
dc6f92b8 11441{
1fb20991 11442#if 0 /* This proves to be unpleasant. */
f676886a 11443 x_raise_frame (f);
1fb20991 11444#endif
6d4238f3
JB
11445#if 0
11446 /* I don't think that the ICCCM allows programs to do things like this
11447 without the interaction of the window manager. Whatever you end up
f676886a 11448 doing with this code, do it to x_unfocus_frame too. */
334208b7 11449 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 11450 RevertToPointerRoot, CurrentTime);
c118dd06 11451#endif /* ! 0 */
dc6f92b8
JB
11452}
11453
dfcf069d 11454void
f676886a
JB
11455x_unfocus_frame (f)
11456 struct frame *f;
dc6f92b8 11457{
6d4238f3 11458#if 0
f676886a 11459 /* Look at the remarks in x_focus_on_frame. */
0f941935 11460 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 11461 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 11462 RevertToPointerRoot, CurrentTime);
c118dd06 11463#endif /* ! 0 */
dc6f92b8
JB
11464}
11465
f676886a 11466/* Raise frame F. */
dc6f92b8 11467
dfcf069d 11468void
f676886a
JB
11469x_raise_frame (f)
11470 struct frame *f;
dc6f92b8 11471{
3a88c238 11472 if (f->async_visible)
dc6f92b8
JB
11473 {
11474 BLOCK_INPUT;
3afe33e7 11475#ifdef USE_X_TOOLKIT
7556890b 11476 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11477#else /* not USE_X_TOOLKIT */
334208b7 11478 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11479#endif /* not USE_X_TOOLKIT */
334208b7 11480 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11481 UNBLOCK_INPUT;
11482 }
11483}
11484
f676886a 11485/* Lower frame F. */
dc6f92b8 11486
dfcf069d 11487void
f676886a
JB
11488x_lower_frame (f)
11489 struct frame *f;
dc6f92b8 11490{
3a88c238 11491 if (f->async_visible)
dc6f92b8
JB
11492 {
11493 BLOCK_INPUT;
3afe33e7 11494#ifdef USE_X_TOOLKIT
7556890b 11495 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11496#else /* not USE_X_TOOLKIT */
334208b7 11497 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11498#endif /* not USE_X_TOOLKIT */
334208b7 11499 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11500 UNBLOCK_INPUT;
11501 }
11502}
11503
dbc4e1c1 11504static void
6b0442dc 11505XTframe_raise_lower (f, raise_flag)
dbc4e1c1 11506 FRAME_PTR f;
6b0442dc 11507 int raise_flag;
dbc4e1c1 11508{
6b0442dc 11509 if (raise_flag)
dbc4e1c1
JB
11510 x_raise_frame (f);
11511 else
11512 x_lower_frame (f);
11513}
d047c4eb
KH
11514\f
11515/* Change of visibility. */
dc6f92b8 11516
9382638d
KH
11517/* This tries to wait until the frame is really visible.
11518 However, if the window manager asks the user where to position
11519 the frame, this will return before the user finishes doing that.
11520 The frame will not actually be visible at that time,
11521 but it will become visible later when the window manager
11522 finishes with it. */
11523
dfcf069d 11524void
f676886a
JB
11525x_make_frame_visible (f)
11526 struct frame *f;
dc6f92b8 11527{
990ba854 11528 Lisp_Object type;
1aa6072f 11529 int original_top, original_left;
dc6f92b8 11530
dc6f92b8 11531 BLOCK_INPUT;
dc6f92b8 11532
990ba854
RS
11533 type = x_icon_type (f);
11534 if (!NILP (type))
11535 x_bitmap_icon (f, type);
bdcd49ba 11536
f676886a 11537 if (! FRAME_VISIBLE_P (f))
90e65f07 11538 {
1aa6072f
RS
11539 /* We test FRAME_GARBAGED_P here to make sure we don't
11540 call x_set_offset a second time
11541 if we get to x_make_frame_visible a second time
11542 before the window gets really visible. */
11543 if (! FRAME_ICONIFIED_P (f)
11544 && ! f->output_data.x->asked_for_visible)
11545 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
11546
11547 f->output_data.x->asked_for_visible = 1;
11548
90e65f07 11549 if (! EQ (Vx_no_window_manager, Qt))
f676886a 11550 x_wm_set_window_state (f, NormalState);
3afe33e7 11551#ifdef USE_X_TOOLKIT
d7a38a2e 11552 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11553 XtMapWidget (f->output_data.x->widget);
3afe33e7 11554#else /* not USE_X_TOOLKIT */
7f9c7f94 11555 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11556#endif /* not USE_X_TOOLKIT */
0134a210
RS
11557#if 0 /* This seems to bring back scroll bars in the wrong places
11558 if the window configuration has changed. They seem
11559 to come back ok without this. */
ab648270 11560 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 11561 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 11562#endif
90e65f07 11563 }
dc6f92b8 11564
334208b7 11565 XFlush (FRAME_X_DISPLAY (f));
90e65f07 11566
0dacf791
RS
11567 /* Synchronize to ensure Emacs knows the frame is visible
11568 before we do anything else. We do this loop with input not blocked
11569 so that incoming events are handled. */
11570 {
11571 Lisp_Object frame;
12ce2351 11572 int count;
28c01ffe
RS
11573 /* This must be before UNBLOCK_INPUT
11574 since events that arrive in response to the actions above
11575 will set it when they are handled. */
11576 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
11577
11578 original_left = f->output_data.x->left_pos;
11579 original_top = f->output_data.x->top_pos;
c0a04927
RS
11580
11581 /* This must come after we set COUNT. */
11582 UNBLOCK_INPUT;
11583
2745e6c4 11584 /* We unblock here so that arriving X events are processed. */
1aa6072f 11585
dcb07ae9
RS
11586 /* Now move the window back to where it was "supposed to be".
11587 But don't do it if the gravity is negative.
11588 When the gravity is negative, this uses a position
28c01ffe
RS
11589 that is 3 pixels too low. Perhaps that's really the border width.
11590
11591 Don't do this if the window has never been visible before,
11592 because the window manager may choose the position
11593 and we don't want to override it. */
1aa6072f 11594
4d3f5d9a 11595 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 11596 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 11597 && previously_visible)
1aa6072f 11598 {
2745e6c4
RS
11599 Drawable rootw;
11600 int x, y;
11601 unsigned int width, height, border, depth;
06a2c219 11602
1aa6072f 11603 BLOCK_INPUT;
9829ddba 11604
06a2c219
GM
11605 /* On some window managers (such as FVWM) moving an existing
11606 window, even to the same place, causes the window manager
11607 to introduce an offset. This can cause the window to move
11608 to an unexpected location. Check the geometry (a little
11609 slow here) and then verify that the window is in the right
11610 place. If the window is not in the right place, move it
11611 there, and take the potential window manager hit. */
2745e6c4
RS
11612 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11613 &rootw, &x, &y, &width, &height, &border, &depth);
11614
11615 if (original_left != x || original_top != y)
11616 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11617 original_left, original_top);
11618
1aa6072f
RS
11619 UNBLOCK_INPUT;
11620 }
9829ddba 11621
e0c1aef2 11622 XSETFRAME (frame, f);
c0a04927 11623
12ce2351
GM
11624 /* Wait until the frame is visible. Process X events until a
11625 MapNotify event has been seen, or until we think we won't get a
11626 MapNotify at all.. */
11627 for (count = input_signal_count + 10;
11628 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 11629 {
12ce2351 11630 /* Force processing of queued events. */
334208b7 11631 x_sync (f);
12ce2351
GM
11632
11633 /* Machines that do polling rather than SIGIO have been
11634 observed to go into a busy-wait here. So we'll fake an
11635 alarm signal to let the handler know that there's something
11636 to be read. We used to raise a real alarm, but it seems
11637 that the handler isn't always enabled here. This is
11638 probably a bug. */
8b2f8d4e 11639 if (input_polling_used ())
3b2fa4e6 11640 {
12ce2351
GM
11641 /* It could be confusing if a real alarm arrives while
11642 processing the fake one. Turn it off and let the
11643 handler reset it. */
bffcfca9
GM
11644 int old_poll_suppress_count = poll_suppress_count;
11645 poll_suppress_count = 1;
11646 poll_for_input_1 ();
11647 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 11648 }
12ce2351
GM
11649
11650 /* See if a MapNotify event has been processed. */
11651 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 11652 }
0dacf791 11653 }
dc6f92b8
JB
11654}
11655
06a2c219 11656/* Change from mapped state to withdrawn state. */
dc6f92b8 11657
d047c4eb
KH
11658/* Make the frame visible (mapped and not iconified). */
11659
dfcf069d 11660void
f676886a
JB
11661x_make_frame_invisible (f)
11662 struct frame *f;
dc6f92b8 11663{
546e6d5b
RS
11664 Window window;
11665
11666#ifdef USE_X_TOOLKIT
11667 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 11668 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
11669#else /* not USE_X_TOOLKIT */
11670 window = FRAME_X_WINDOW (f);
11671#endif /* not USE_X_TOOLKIT */
dc6f92b8 11672
9319ae23 11673 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11674 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11675 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11676
5627c40e 11677#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 11678 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 11679 return;
5627c40e 11680#endif
dc6f92b8
JB
11681
11682 BLOCK_INPUT;
c118dd06 11683
af31d76f
RS
11684 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
11685 that the current position of the window is user-specified, rather than
11686 program-specified, so that when the window is mapped again, it will be
11687 placed at the same location, without forcing the user to position it
11688 by hand again (they have already done that once for this window.) */
c32cdd9a 11689 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 11690
c118dd06
JB
11691#ifdef HAVE_X11R4
11692
334208b7
RS
11693 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
11694 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
11695 {
11696 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11697 error ("Can't notify window manager of window withdrawal");
c118dd06 11698 }
c118dd06 11699#else /* ! defined (HAVE_X11R4) */
16bd92ea 11700
c118dd06 11701 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
11702 if (! EQ (Vx_no_window_manager, Qt))
11703 {
16bd92ea 11704 XEvent unmap;
dc6f92b8 11705
16bd92ea 11706 unmap.xunmap.type = UnmapNotify;
546e6d5b 11707 unmap.xunmap.window = window;
334208b7 11708 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 11709 unmap.xunmap.from_configure = False;
334208b7
RS
11710 if (! XSendEvent (FRAME_X_DISPLAY (f),
11711 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 11712 False,
06a2c219 11713 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
11714 &unmap))
11715 {
11716 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11717 error ("Can't notify window manager of withdrawal");
16bd92ea 11718 }
dc6f92b8
JB
11719 }
11720
16bd92ea 11721 /* Unmap the window ourselves. Cheeky! */
334208b7 11722 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 11723#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 11724
5627c40e
RS
11725 /* We can't distinguish this from iconification
11726 just by the event that we get from the server.
11727 So we can't win using the usual strategy of letting
11728 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
11729 and synchronize with the server to make sure we agree. */
11730 f->visible = 0;
11731 FRAME_ICONIFIED_P (f) = 0;
11732 f->async_visible = 0;
11733 f->async_iconified = 0;
11734
334208b7 11735 x_sync (f);
5627c40e 11736
dc6f92b8
JB
11737 UNBLOCK_INPUT;
11738}
11739
06a2c219 11740/* Change window state from mapped to iconified. */
dc6f92b8 11741
dfcf069d 11742void
f676886a
JB
11743x_iconify_frame (f)
11744 struct frame *f;
dc6f92b8 11745{
3afe33e7 11746 int result;
990ba854 11747 Lisp_Object type;
dc6f92b8 11748
9319ae23 11749 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11750 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11751 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11752
3a88c238 11753 if (f->async_iconified)
dc6f92b8
JB
11754 return;
11755
3afe33e7 11756 BLOCK_INPUT;
546e6d5b 11757
9af3143a
RS
11758 FRAME_SAMPLE_VISIBILITY (f);
11759
990ba854
RS
11760 type = x_icon_type (f);
11761 if (!NILP (type))
11762 x_bitmap_icon (f, type);
bdcd49ba
RS
11763
11764#ifdef USE_X_TOOLKIT
11765
546e6d5b
RS
11766 if (! FRAME_VISIBLE_P (f))
11767 {
11768 if (! EQ (Vx_no_window_manager, Qt))
11769 x_wm_set_window_state (f, IconicState);
11770 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11771 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
11772 /* The server won't give us any event to indicate
11773 that an invisible frame was changed to an icon,
11774 so we have to record it here. */
11775 f->iconified = 1;
1e6bc770 11776 f->visible = 1;
9cf30a30 11777 f->async_iconified = 1;
1e6bc770 11778 f->async_visible = 0;
546e6d5b
RS
11779 UNBLOCK_INPUT;
11780 return;
11781 }
11782
334208b7 11783 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 11784 XtWindow (f->output_data.x->widget),
334208b7 11785 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
11786 UNBLOCK_INPUT;
11787
11788 if (!result)
546e6d5b 11789 error ("Can't notify window manager of iconification");
3afe33e7
RS
11790
11791 f->async_iconified = 1;
1e6bc770
RS
11792 f->async_visible = 0;
11793
8c002a25
KH
11794
11795 BLOCK_INPUT;
334208b7 11796 XFlush (FRAME_X_DISPLAY (f));
8c002a25 11797 UNBLOCK_INPUT;
3afe33e7
RS
11798#else /* not USE_X_TOOLKIT */
11799
fd13dbb2
RS
11800 /* Make sure the X server knows where the window should be positioned,
11801 in case the user deiconifies with the window manager. */
11802 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 11803 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 11804
16bd92ea
JB
11805 /* Since we don't know which revision of X we're running, we'll use both
11806 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
11807
11808 /* X11R4: send a ClientMessage to the window manager using the
11809 WM_CHANGE_STATE type. */
11810 {
11811 XEvent message;
58769bee 11812
c118dd06 11813 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 11814 message.xclient.type = ClientMessage;
334208b7 11815 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
11816 message.xclient.format = 32;
11817 message.xclient.data.l[0] = IconicState;
11818
334208b7
RS
11819 if (! XSendEvent (FRAME_X_DISPLAY (f),
11820 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
11821 False,
11822 SubstructureRedirectMask | SubstructureNotifyMask,
11823 &message))
dc6f92b8
JB
11824 {
11825 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11826 error ("Can't notify window manager of iconification");
dc6f92b8 11827 }
16bd92ea 11828 }
dc6f92b8 11829
58769bee 11830 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
11831 IconicState. */
11832 x_wm_set_window_state (f, IconicState);
dc6f92b8 11833
a9c00105
RS
11834 if (!FRAME_VISIBLE_P (f))
11835 {
11836 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 11837 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
11838 }
11839
3a88c238 11840 f->async_iconified = 1;
1e6bc770 11841 f->async_visible = 0;
dc6f92b8 11842
334208b7 11843 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 11844 UNBLOCK_INPUT;
8c002a25 11845#endif /* not USE_X_TOOLKIT */
dc6f92b8 11846}
d047c4eb 11847\f
c0ff3fab 11848/* Destroy the X window of frame F. */
dc6f92b8 11849
dfcf069d 11850void
c0ff3fab 11851x_destroy_window (f)
f676886a 11852 struct frame *f;
dc6f92b8 11853{
7f9c7f94
RS
11854 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11855
dc6f92b8 11856 BLOCK_INPUT;
c0ff3fab 11857
6186a4a0
RS
11858 /* If a display connection is dead, don't try sending more
11859 commands to the X server. */
11860 if (dpyinfo->display != 0)
11861 {
11862 if (f->output_data.x->icon_desc != 0)
11863 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
31f41daf 11864#ifdef HAVE_X_I18N
f5d11644
GM
11865 if (FRAME_XIC (f))
11866 free_frame_xic (f);
31f41daf 11867#endif
6186a4a0 11868 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->window_desc);
3afe33e7 11869#ifdef USE_X_TOOLKIT
06a2c219
GM
11870 if (f->output_data.x->widget)
11871 XtDestroyWidget (f->output_data.x->widget);
6186a4a0 11872 free_frame_menubar (f);
3afe33e7
RS
11873#endif /* USE_X_TOOLKIT */
11874
6186a4a0
RS
11875 free_frame_faces (f);
11876 XFlush (FRAME_X_DISPLAY (f));
11877 }
dc6f92b8 11878
df89d8a4 11879 if (f->output_data.x->saved_menu_event)
06a2c219 11880 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 11881
7556890b
RS
11882 xfree (f->output_data.x);
11883 f->output_data.x = 0;
0f941935
KH
11884 if (f == dpyinfo->x_focus_frame)
11885 dpyinfo->x_focus_frame = 0;
11886 if (f == dpyinfo->x_focus_event_frame)
11887 dpyinfo->x_focus_event_frame = 0;
11888 if (f == dpyinfo->x_highlight_frame)
11889 dpyinfo->x_highlight_frame = 0;
c0ff3fab 11890
7f9c7f94
RS
11891 dpyinfo->reference_count--;
11892
11893 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 11894 {
7f9c7f94
RS
11895 dpyinfo->mouse_face_beg_row
11896 = dpyinfo->mouse_face_beg_col = -1;
11897 dpyinfo->mouse_face_end_row
11898 = dpyinfo->mouse_face_end_col = -1;
11899 dpyinfo->mouse_face_window = Qnil;
21323706
RS
11900 dpyinfo->mouse_face_deferred_gc = 0;
11901 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 11902 }
0134a210 11903
c0ff3fab 11904 UNBLOCK_INPUT;
dc6f92b8
JB
11905}
11906\f
f451eb13
JB
11907/* Setting window manager hints. */
11908
af31d76f
RS
11909/* Set the normal size hints for the window manager, for frame F.
11910 FLAGS is the flags word to use--or 0 meaning preserve the flags
11911 that the window now has.
11912 If USER_POSITION is nonzero, we set the USPosition
11913 flag (this is useful when FLAGS is 0). */
6dba1858 11914
dfcf069d 11915void
af31d76f 11916x_wm_set_size_hint (f, flags, user_position)
f676886a 11917 struct frame *f;
af31d76f
RS
11918 long flags;
11919 int user_position;
dc6f92b8
JB
11920{
11921 XSizeHints size_hints;
3afe33e7
RS
11922
11923#ifdef USE_X_TOOLKIT
7e4f2521
FP
11924 Arg al[2];
11925 int ac = 0;
11926 Dimension widget_width, widget_height;
7556890b 11927 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 11928#else /* not USE_X_TOOLKIT */
c118dd06 11929 Window window = FRAME_X_WINDOW (f);
3afe33e7 11930#endif /* not USE_X_TOOLKIT */
dc6f92b8 11931
b72a58fd
RS
11932 /* Setting PMaxSize caused various problems. */
11933 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 11934
7556890b
RS
11935 size_hints.x = f->output_data.x->left_pos;
11936 size_hints.y = f->output_data.x->top_pos;
7553a6b7 11937
7e4f2521
FP
11938#ifdef USE_X_TOOLKIT
11939 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
11940 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 11941 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
11942 size_hints.height = widget_height;
11943 size_hints.width = widget_width;
11944#else /* not USE_X_TOOLKIT */
f676886a
JB
11945 size_hints.height = PIXEL_HEIGHT (f);
11946 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 11947#endif /* not USE_X_TOOLKIT */
7553a6b7 11948
7556890b
RS
11949 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
11950 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
11951 size_hints.max_width
11952 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
11953 size_hints.max_height
11954 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 11955
d067ea8b
KH
11956 /* Calculate the base and minimum sizes.
11957
11958 (When we use the X toolkit, we don't do it here.
11959 Instead we copy the values that the widgets are using, below.) */
11960#ifndef USE_X_TOOLKIT
b1c884c3 11961 {
b0342f17 11962 int base_width, base_height;
0134a210 11963 int min_rows = 0, min_cols = 0;
b0342f17 11964
f451eb13
JB
11965 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
11966 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 11967
0134a210 11968 check_frame_size (f, &min_rows, &min_cols);
b0342f17 11969
0134a210
RS
11970 /* The window manager uses the base width hints to calculate the
11971 current number of rows and columns in the frame while
11972 resizing; min_width and min_height aren't useful for this
11973 purpose, since they might not give the dimensions for a
11974 zero-row, zero-column frame.
58769bee 11975
0134a210
RS
11976 We use the base_width and base_height members if we have
11977 them; otherwise, we set the min_width and min_height members
11978 to the size for a zero x zero frame. */
b0342f17
JB
11979
11980#ifdef HAVE_X11R4
0134a210
RS
11981 size_hints.flags |= PBaseSize;
11982 size_hints.base_width = base_width;
11983 size_hints.base_height = base_height;
11984 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
11985 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 11986#else
0134a210
RS
11987 size_hints.min_width = base_width;
11988 size_hints.min_height = base_height;
b0342f17 11989#endif
b1c884c3 11990 }
dc6f92b8 11991
d067ea8b 11992 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 11993 if (flags)
dc6f92b8 11994 {
d067ea8b
KH
11995 size_hints.flags |= flags;
11996 goto no_read;
11997 }
11998#endif /* not USE_X_TOOLKIT */
11999
12000 {
12001 XSizeHints hints; /* Sometimes I hate X Windows... */
12002 long supplied_return;
12003 int value;
af31d76f
RS
12004
12005#ifdef HAVE_X11R4
d067ea8b
KH
12006 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
12007 &supplied_return);
af31d76f 12008#else
d067ea8b 12009 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 12010#endif
58769bee 12011
d067ea8b
KH
12012#ifdef USE_X_TOOLKIT
12013 size_hints.base_height = hints.base_height;
12014 size_hints.base_width = hints.base_width;
12015 size_hints.min_height = hints.min_height;
12016 size_hints.min_width = hints.min_width;
12017#endif
12018
12019 if (flags)
12020 size_hints.flags |= flags;
12021 else
12022 {
12023 if (value == 0)
12024 hints.flags = 0;
12025 if (hints.flags & PSize)
12026 size_hints.flags |= PSize;
12027 if (hints.flags & PPosition)
12028 size_hints.flags |= PPosition;
12029 if (hints.flags & USPosition)
12030 size_hints.flags |= USPosition;
12031 if (hints.flags & USSize)
12032 size_hints.flags |= USSize;
12033 }
12034 }
12035
06a2c219 12036#ifndef USE_X_TOOLKIT
d067ea8b 12037 no_read:
06a2c219 12038#endif
0134a210 12039
af31d76f 12040#ifdef PWinGravity
7556890b 12041 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 12042 size_hints.flags |= PWinGravity;
dc05a16b 12043
af31d76f 12044 if (user_position)
6dba1858 12045 {
af31d76f
RS
12046 size_hints.flags &= ~ PPosition;
12047 size_hints.flags |= USPosition;
6dba1858 12048 }
2554751d 12049#endif /* PWinGravity */
6dba1858 12050
b0342f17 12051#ifdef HAVE_X11R4
334208b7 12052 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12053#else
334208b7 12054 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12055#endif
dc6f92b8
JB
12056}
12057
12058/* Used for IconicState or NormalState */
06a2c219 12059
dfcf069d 12060void
f676886a
JB
12061x_wm_set_window_state (f, state)
12062 struct frame *f;
dc6f92b8
JB
12063 int state;
12064{
3afe33e7 12065#ifdef USE_X_TOOLKIT
546e6d5b
RS
12066 Arg al[1];
12067
12068 XtSetArg (al[0], XtNinitialState, state);
7556890b 12069 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 12070#else /* not USE_X_TOOLKIT */
c118dd06 12071 Window window = FRAME_X_WINDOW (f);
dc6f92b8 12072
7556890b
RS
12073 f->output_data.x->wm_hints.flags |= StateHint;
12074 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 12075
7556890b 12076 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 12077#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12078}
12079
dfcf069d 12080void
7f2ae036 12081x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 12082 struct frame *f;
7f2ae036 12083 int pixmap_id;
dc6f92b8 12084{
d2bd6bc4
RS
12085 Pixmap icon_pixmap;
12086
06a2c219 12087#ifndef USE_X_TOOLKIT
c118dd06 12088 Window window = FRAME_X_WINDOW (f);
75231bad 12089#endif
dc6f92b8 12090
7f2ae036 12091 if (pixmap_id > 0)
dbc4e1c1 12092 {
d2bd6bc4 12093 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 12094 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
12095 }
12096 else
68568555
RS
12097 {
12098 /* It seems there is no way to turn off use of an icon pixmap.
12099 The following line does it, only if no icon has yet been created,
12100 for some window managers. But with mwm it crashes.
12101 Some people say it should clear the IconPixmapHint bit in this case,
12102 but that doesn't work, and the X consortium said it isn't the
12103 right thing at all. Since there is no way to win,
12104 best to explicitly give up. */
12105#if 0
12106 f->output_data.x->wm_hints.icon_pixmap = None;
12107#else
12108 return;
12109#endif
12110 }
b1c884c3 12111
d2bd6bc4
RS
12112#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
12113
12114 {
12115 Arg al[1];
12116 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
12117 XtSetValues (f->output_data.x->widget, al, 1);
12118 }
12119
12120#else /* not USE_X_TOOLKIT */
12121
7556890b
RS
12122 f->output_data.x->wm_hints.flags |= IconPixmapHint;
12123 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
12124
12125#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12126}
12127
dfcf069d 12128void
f676886a
JB
12129x_wm_set_icon_position (f, icon_x, icon_y)
12130 struct frame *f;
dc6f92b8
JB
12131 int icon_x, icon_y;
12132{
75231bad 12133#ifdef USE_X_TOOLKIT
7556890b 12134 Window window = XtWindow (f->output_data.x->widget);
75231bad 12135#else
c118dd06 12136 Window window = FRAME_X_WINDOW (f);
75231bad 12137#endif
dc6f92b8 12138
7556890b
RS
12139 f->output_data.x->wm_hints.flags |= IconPositionHint;
12140 f->output_data.x->wm_hints.icon_x = icon_x;
12141 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 12142
7556890b 12143 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
12144}
12145
12146\f
06a2c219
GM
12147/***********************************************************************
12148 Fonts
12149 ***********************************************************************/
dc43ef94
KH
12150
12151/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 12152
dc43ef94
KH
12153struct font_info *
12154x_get_font_info (f, font_idx)
12155 FRAME_PTR f;
12156 int font_idx;
12157{
12158 return (FRAME_X_FONT_TABLE (f) + font_idx);
12159}
12160
12161
12162/* Return a list of names of available fonts matching PATTERN on frame
12163 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
12164 to be listed. Frame F NULL means we have not yet created any
12165 frame on X, and consult the first display in x_display_list.
12166 MAXNAMES sets a limit on how many fonts to match. */
12167
12168Lisp_Object
12169x_list_fonts (f, pattern, size, maxnames)
12170 FRAME_PTR f;
12171 Lisp_Object pattern;
12172 int size;
12173 int maxnames;
12174{
06a2c219
GM
12175 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
12176 Lisp_Object tem, second_best;
dc43ef94 12177 Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
09c6077f 12178 int try_XLoadQueryFont = 0;
53ca4657 12179 int count;
dc43ef94 12180
6b0efe73 12181 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
12182 if (NILP (patterns))
12183 patterns = Fcons (pattern, Qnil);
81ba44e5 12184
09c6077f
KH
12185 if (maxnames == 1 && !size)
12186 /* We can return any single font matching PATTERN. */
12187 try_XLoadQueryFont = 1;
9a32686f 12188
8e713be6 12189 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 12190 {
dc43ef94
KH
12191 int num_fonts;
12192 char **names;
12193
8e713be6 12194 pattern = XCAR (patterns);
536f4067
RS
12195 /* See if we cached the result for this particular query.
12196 The cache is an alist of the form:
12197 (((PATTERN . MAXNAMES) (FONTNAME . WIDTH) ...) ...)
12198 */
8e713be6 12199 if (f && (tem = XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element),
b5210ea7
KH
12200 key = Fcons (pattern, make_number (maxnames)),
12201 !NILP (list = Fassoc (key, tem))))
12202 {
12203 list = Fcdr_safe (list);
12204 /* We have a cashed list. Don't have to get the list again. */
12205 goto label_cached;
12206 }
12207
12208 /* At first, put PATTERN in the cache. */
09c6077f 12209
dc43ef94 12210 BLOCK_INPUT;
17d85edc
KH
12211 count = x_catch_errors (dpy);
12212
09c6077f
KH
12213 if (try_XLoadQueryFont)
12214 {
12215 XFontStruct *font;
12216 unsigned long value;
12217
12218 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
12219 if (x_had_errors_p (dpy))
12220 {
12221 /* This error is perhaps due to insufficient memory on X
12222 server. Let's just ignore it. */
12223 font = NULL;
12224 x_clear_errors (dpy);
12225 }
12226
09c6077f
KH
12227 if (font
12228 && XGetFontProperty (font, XA_FONT, &value))
12229 {
12230 char *name = (char *) XGetAtomName (dpy, (Atom) value);
12231 int len = strlen (name);
01c752b5 12232 char *tmp;
09c6077f 12233
6f6512e8
KH
12234 /* If DXPC (a Differential X Protocol Compressor)
12235 Ver.3.7 is running, XGetAtomName will return null
12236 string. We must avoid such a name. */
12237 if (len == 0)
12238 try_XLoadQueryFont = 0;
12239 else
12240 {
12241 num_fonts = 1;
12242 names = (char **) alloca (sizeof (char *));
12243 /* Some systems only allow alloca assigned to a
12244 simple var. */
12245 tmp = (char *) alloca (len + 1); names[0] = tmp;
12246 bcopy (name, names[0], len + 1);
12247 XFree (name);
12248 }
09c6077f
KH
12249 }
12250 else
12251 try_XLoadQueryFont = 0;
a083fd23
RS
12252
12253 if (font)
12254 XFreeFont (dpy, font);
09c6077f
KH
12255 }
12256
12257 if (!try_XLoadQueryFont)
17d85edc
KH
12258 {
12259 /* We try at least 10 fonts because XListFonts will return
12260 auto-scaled fonts at the head. */
12261 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
12262 &num_fonts);
12263 if (x_had_errors_p (dpy))
12264 {
12265 /* This error is perhaps due to insufficient memory on X
12266 server. Let's just ignore it. */
12267 names = NULL;
12268 x_clear_errors (dpy);
12269 }
12270 }
12271
12272 x_uncatch_errors (dpy, count);
dc43ef94
KH
12273 UNBLOCK_INPUT;
12274
12275 if (names)
12276 {
12277 int i;
dc43ef94
KH
12278
12279 /* Make a list of all the fonts we got back.
12280 Store that in the font cache for the display. */
12281 for (i = 0; i < num_fonts; i++)
12282 {
06a2c219 12283 int width = 0;
dc43ef94 12284 char *p = names[i];
06a2c219
GM
12285 int average_width = -1, dashes = 0;
12286
dc43ef94 12287 /* Count the number of dashes in NAMES[I]. If there are
b5210ea7
KH
12288 14 dashes, and the field value following 12th dash
12289 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
12290 is usually too ugly to be used for editing. Let's
12291 ignore it. */
dc43ef94
KH
12292 while (*p)
12293 if (*p++ == '-')
12294 {
12295 dashes++;
12296 if (dashes == 7) /* PIXEL_SIZE field */
12297 width = atoi (p);
12298 else if (dashes == 12) /* AVERAGE_WIDTH field */
12299 average_width = atoi (p);
12300 }
12301 if (dashes < 14 || average_width != 0)
12302 {
12303 tem = build_string (names[i]);
12304 if (NILP (Fassoc (tem, list)))
12305 {
12306 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
12307 && ((fast_c_string_match_ignore_case
12308 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
12309 >= 0))
12310 /* We can set the value of PIXEL_SIZE to the
b5210ea7 12311 width of this font. */
dc43ef94
KH
12312 list = Fcons (Fcons (tem, make_number (width)), list);
12313 else
12314 /* For the moment, width is not known. */
12315 list = Fcons (Fcons (tem, Qnil), list);
12316 }
12317 }
12318 }
09c6077f
KH
12319 if (!try_XLoadQueryFont)
12320 XFreeFontNames (names);
dc43ef94
KH
12321 }
12322
b5210ea7 12323 /* Now store the result in the cache. */
dc43ef94 12324 if (f != NULL)
8e713be6 12325 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element)
dc43ef94 12326 = Fcons (Fcons (key, list),
8e713be6 12327 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
dc43ef94 12328
b5210ea7
KH
12329 label_cached:
12330 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 12331
b5210ea7
KH
12332 newlist = second_best = Qnil;
12333 /* Make a list of the fonts that have the right width. */
8e713be6 12334 for (; CONSP (list); list = XCDR (list))
b5210ea7 12335 {
536f4067
RS
12336 int found_size;
12337
8e713be6 12338 tem = XCAR (list);
dc43ef94 12339
8e713be6 12340 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
12341 continue;
12342 if (!size)
12343 {
8e713be6 12344 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
12345 continue;
12346 }
dc43ef94 12347
8e713be6 12348 if (!INTEGERP (XCDR (tem)))
dc43ef94 12349 {
b5210ea7
KH
12350 /* Since we have not yet known the size of this font, we
12351 must try slow function call XLoadQueryFont. */
dc43ef94
KH
12352 XFontStruct *thisinfo;
12353
12354 BLOCK_INPUT;
17d85edc 12355 count = x_catch_errors (dpy);
dc43ef94 12356 thisinfo = XLoadQueryFont (dpy,
8e713be6 12357 XSTRING (XCAR (tem))->data);
17d85edc
KH
12358 if (x_had_errors_p (dpy))
12359 {
12360 /* This error is perhaps due to insufficient memory on X
12361 server. Let's just ignore it. */
12362 thisinfo = NULL;
12363 x_clear_errors (dpy);
12364 }
12365 x_uncatch_errors (dpy, count);
dc43ef94
KH
12366 UNBLOCK_INPUT;
12367
12368 if (thisinfo)
12369 {
8e713be6 12370 XCDR (tem)
536f4067
RS
12371 = (thisinfo->min_bounds.width == 0
12372 ? make_number (0)
12373 : make_number (thisinfo->max_bounds.width));
dc43ef94
KH
12374 XFreeFont (dpy, thisinfo);
12375 }
12376 else
b5210ea7 12377 /* For unknown reason, the previous call of XListFont had
06a2c219 12378 returned a font which can't be opened. Record the size
b5210ea7 12379 as 0 not to try to open it again. */
8e713be6 12380 XCDR (tem) = make_number (0);
dc43ef94 12381 }
536f4067 12382
8e713be6 12383 found_size = XINT (XCDR (tem));
536f4067 12384 if (found_size == size)
8e713be6 12385 newlist = Fcons (XCAR (tem), newlist);
536f4067 12386 else if (found_size > 0)
b5210ea7 12387 {
536f4067 12388 if (NILP (second_best))
b5210ea7 12389 second_best = tem;
536f4067
RS
12390 else if (found_size < size)
12391 {
8e713be6
KR
12392 if (XINT (XCDR (second_best)) > size
12393 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
12394 second_best = tem;
12395 }
12396 else
12397 {
8e713be6
KR
12398 if (XINT (XCDR (second_best)) > size
12399 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
12400 second_best = tem;
12401 }
b5210ea7
KH
12402 }
12403 }
12404 if (!NILP (newlist))
12405 break;
12406 else if (!NILP (second_best))
12407 {
8e713be6 12408 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 12409 break;
dc43ef94 12410 }
dc43ef94
KH
12411 }
12412
12413 return newlist;
12414}
12415
06a2c219
GM
12416
12417#if GLYPH_DEBUG
12418
12419/* Check that FONT is valid on frame F. It is if it can be found in F's
12420 font table. */
12421
12422static void
12423x_check_font (f, font)
12424 struct frame *f;
12425 XFontStruct *font;
12426{
12427 int i;
12428 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12429
12430 xassert (font != NULL);
12431
12432 for (i = 0; i < dpyinfo->n_fonts; i++)
12433 if (dpyinfo->font_table[i].name
12434 && font == dpyinfo->font_table[i].font)
12435 break;
12436
12437 xassert (i < dpyinfo->n_fonts);
12438}
12439
12440#endif /* GLYPH_DEBUG != 0 */
12441
12442/* Set *W to the minimum width, *H to the minimum font height of FONT.
12443 Note: There are (broken) X fonts out there with invalid XFontStruct
12444 min_bounds contents. For example, handa@etl.go.jp reports that
12445 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
12446 have font->min_bounds.width == 0. */
12447
12448static INLINE void
12449x_font_min_bounds (font, w, h)
12450 XFontStruct *font;
12451 int *w, *h;
12452{
12453 *h = FONT_HEIGHT (font);
12454 *w = font->min_bounds.width;
12455
12456 /* Try to handle the case where FONT->min_bounds has invalid
12457 contents. Since the only font known to have invalid min_bounds
12458 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
12459 if (*w <= 0)
12460 *w = font->max_bounds.width;
12461}
12462
12463
12464/* Compute the smallest character width and smallest font height over
12465 all fonts available on frame F. Set the members smallest_char_width
12466 and smallest_font_height in F's x_display_info structure to
12467 the values computed. Value is non-zero if smallest_font_height or
12468 smallest_char_width become smaller than they were before. */
12469
12470static int
12471x_compute_min_glyph_bounds (f)
12472 struct frame *f;
12473{
12474 int i;
12475 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12476 XFontStruct *font;
12477 int old_width = dpyinfo->smallest_char_width;
12478 int old_height = dpyinfo->smallest_font_height;
12479
12480 dpyinfo->smallest_font_height = 100000;
12481 dpyinfo->smallest_char_width = 100000;
12482
12483 for (i = 0; i < dpyinfo->n_fonts; ++i)
12484 if (dpyinfo->font_table[i].name)
12485 {
12486 struct font_info *fontp = dpyinfo->font_table + i;
12487 int w, h;
12488
12489 font = (XFontStruct *) fontp->font;
12490 xassert (font != (XFontStruct *) ~0);
12491 x_font_min_bounds (font, &w, &h);
12492
12493 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
12494 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
12495 }
12496
12497 xassert (dpyinfo->smallest_char_width > 0
12498 && dpyinfo->smallest_font_height > 0);
12499
12500 return (dpyinfo->n_fonts == 1
12501 || dpyinfo->smallest_char_width < old_width
12502 || dpyinfo->smallest_font_height < old_height);
12503}
12504
12505
dc43ef94
KH
12506/* Load font named FONTNAME of the size SIZE for frame F, and return a
12507 pointer to the structure font_info while allocating it dynamically.
12508 If SIZE is 0, load any size of font.
12509 If loading is failed, return NULL. */
12510
12511struct font_info *
12512x_load_font (f, fontname, size)
12513 struct frame *f;
12514 register char *fontname;
12515 int size;
12516{
12517 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12518 Lisp_Object font_names;
d645aaa4 12519 int count;
dc43ef94
KH
12520
12521 /* Get a list of all the fonts that match this name. Once we
12522 have a list of matching fonts, we compare them against the fonts
12523 we already have by comparing names. */
09c6077f 12524 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
12525
12526 if (!NILP (font_names))
12527 {
12528 Lisp_Object tail;
12529 int i;
12530
12531 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 12532 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
12533 if (dpyinfo->font_table[i].name
12534 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 12535 XSTRING (XCAR (tail))->data)
06a2c219 12536 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 12537 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
12538 return (dpyinfo->font_table + i);
12539 }
12540
12541 /* Load the font and add it to the table. */
12542 {
12543 char *full_name;
12544 XFontStruct *font;
12545 struct font_info *fontp;
12546 unsigned long value;
06a2c219 12547 int i;
dc43ef94 12548
2da424f1
KH
12549 /* If we have found fonts by x_list_font, load one of them. If
12550 not, we still try to load a font by the name given as FONTNAME
12551 because XListFonts (called in x_list_font) of some X server has
12552 a bug of not finding a font even if the font surely exists and
12553 is loadable by XLoadQueryFont. */
e1d6d5b9 12554 if (size > 0 && !NILP (font_names))
8e713be6 12555 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
12556
12557 BLOCK_INPUT;
d645aaa4 12558 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 12559 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
12560 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12561 {
12562 /* This error is perhaps due to insufficient memory on X
12563 server. Let's just ignore it. */
12564 font = NULL;
12565 x_clear_errors (FRAME_X_DISPLAY (f));
12566 }
12567 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 12568 UNBLOCK_INPUT;
b5210ea7 12569 if (!font)
dc43ef94
KH
12570 return NULL;
12571
06a2c219
GM
12572 /* Find a free slot in the font table. */
12573 for (i = 0; i < dpyinfo->n_fonts; ++i)
12574 if (dpyinfo->font_table[i].name == NULL)
12575 break;
12576
12577 /* If no free slot found, maybe enlarge the font table. */
12578 if (i == dpyinfo->n_fonts
12579 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 12580 {
06a2c219
GM
12581 int sz;
12582 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
12583 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 12584 dpyinfo->font_table
06a2c219 12585 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
12586 }
12587
06a2c219
GM
12588 fontp = dpyinfo->font_table + i;
12589 if (i == dpyinfo->n_fonts)
12590 ++dpyinfo->n_fonts;
dc43ef94
KH
12591
12592 /* Now fill in the slots of *FONTP. */
12593 BLOCK_INPUT;
12594 fontp->font = font;
06a2c219 12595 fontp->font_idx = i;
dc43ef94
KH
12596 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
12597 bcopy (fontname, fontp->name, strlen (fontname) + 1);
12598
12599 /* Try to get the full name of FONT. Put it in FULL_NAME. */
12600 full_name = 0;
12601 if (XGetFontProperty (font, XA_FONT, &value))
12602 {
12603 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
12604 char *p = name;
12605 int dashes = 0;
12606
12607 /* Count the number of dashes in the "full name".
12608 If it is too few, this isn't really the font's full name,
12609 so don't use it.
12610 In X11R4, the fonts did not come with their canonical names
12611 stored in them. */
12612 while (*p)
12613 {
12614 if (*p == '-')
12615 dashes++;
12616 p++;
12617 }
12618
12619 if (dashes >= 13)
12620 {
12621 full_name = (char *) xmalloc (p - name + 1);
12622 bcopy (name, full_name, p - name + 1);
12623 }
12624
12625 XFree (name);
12626 }
12627
12628 if (full_name != 0)
12629 fontp->full_name = full_name;
12630 else
12631 fontp->full_name = fontp->name;
12632
12633 fontp->size = font->max_bounds.width;
d5749adb
KH
12634 fontp->height = FONT_HEIGHT (font);
12635 {
12636 /* For some font, ascent and descent in max_bounds field is
12637 larger than the above value. */
12638 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
12639 if (max_height > fontp->height)
74848a96 12640 fontp->height = max_height;
d5749adb 12641 }
dc43ef94 12642
2da424f1
KH
12643 if (NILP (font_names))
12644 {
12645 /* We come here because of a bug of XListFonts mentioned at
12646 the head of this block. Let's store this information in
12647 the cache for x_list_fonts. */
12648 Lisp_Object lispy_name = build_string (fontname);
12649 Lisp_Object lispy_full_name = build_string (fontp->full_name);
12650
8e713be6 12651 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12652 = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
12653 Fcons (Fcons (lispy_full_name,
12654 make_number (fontp->size)),
12655 Qnil)),
8e713be6 12656 XCDR (dpyinfo->name_list_element));
2da424f1 12657 if (full_name)
8e713be6 12658 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12659 = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
12660 Fcons (Fcons (lispy_full_name,
12661 make_number (fontp->size)),
12662 Qnil)),
8e713be6 12663 XCDR (dpyinfo->name_list_element));
2da424f1
KH
12664 }
12665
dc43ef94
KH
12666 /* The slot `encoding' specifies how to map a character
12667 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ce667c3e 12668 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
8ff102bd
RS
12669 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
12670 0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
12671 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 12672 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
12673 which is never used by any charset. If mapping can't be
12674 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
12675 fontp->encoding[1]
12676 = (font->max_byte1 == 0
12677 /* 1-byte font */
12678 ? (font->min_char_or_byte2 < 0x80
12679 ? (font->max_char_or_byte2 < 0x80
12680 ? 0 /* 0x20..0x7F */
8ff102bd 12681 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
12682 : 1) /* 0xA0..0xFF */
12683 /* 2-byte font */
12684 : (font->min_byte1 < 0x80
12685 ? (font->max_byte1 < 0x80
12686 ? (font->min_char_or_byte2 < 0x80
12687 ? (font->max_char_or_byte2 < 0x80
12688 ? 0 /* 0x2020..0x7F7F */
8ff102bd 12689 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 12690 : 3) /* 0x20A0..0x7FFF */
8ff102bd 12691 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
12692 : (font->min_char_or_byte2 < 0x80
12693 ? (font->max_char_or_byte2 < 0x80
12694 ? 2 /* 0xA020..0xFF7F */
8ff102bd 12695 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
12696 : 1))); /* 0xA0A0..0xFFFF */
12697
12698 fontp->baseline_offset
12699 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
12700 ? (long) value : 0);
12701 fontp->relative_compose
12702 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
12703 ? (long) value : 0);
f78798df
KH
12704 fontp->default_ascent
12705 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
12706 ? (long) value : 0);
dc43ef94 12707
06a2c219
GM
12708 /* Set global flag fonts_changed_p to non-zero if the font loaded
12709 has a character with a smaller width than any other character
12710 before, or if the font loaded has a smalle>r height than any
12711 other font loaded before. If this happens, it will make a
12712 glyph matrix reallocation necessary. */
12713 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 12714 UNBLOCK_INPUT;
dc43ef94
KH
12715 return fontp;
12716 }
12717}
12718
06a2c219
GM
12719
12720/* Return a pointer to struct font_info of a font named FONTNAME for
12721 frame F. If no such font is loaded, return NULL. */
12722
dc43ef94
KH
12723struct font_info *
12724x_query_font (f, fontname)
12725 struct frame *f;
12726 register char *fontname;
12727{
12728 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12729 int i;
12730
12731 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
12732 if (dpyinfo->font_table[i].name
12733 && (!strcmp (dpyinfo->font_table[i].name, fontname)
12734 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
12735 return (dpyinfo->font_table + i);
12736 return NULL;
12737}
12738
06a2c219
GM
12739
12740/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
12741 `encoder' of the structure. */
12742
12743void
12744x_find_ccl_program (fontp)
12745 struct font_info *fontp;
12746{
a42f54e6 12747 Lisp_Object list, elt;
a6582676 12748
8e713be6 12749 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 12750 {
8e713be6 12751 elt = XCAR (list);
a6582676 12752 if (CONSP (elt)
8e713be6
KR
12753 && STRINGP (XCAR (elt))
12754 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
a6582676 12755 >= 0))
a42f54e6
KH
12756 break;
12757 }
12758 if (! NILP (list))
12759 {
d27f8ca7
KH
12760 struct ccl_program *ccl
12761 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 12762
8e713be6 12763 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
12764 xfree (ccl);
12765 else
12766 fontp->font_encoder = ccl;
a6582676
KH
12767 }
12768}
12769
06a2c219 12770
dc43ef94 12771\f
06a2c219
GM
12772/***********************************************************************
12773 Initialization
12774 ***********************************************************************/
f451eb13 12775
3afe33e7
RS
12776#ifdef USE_X_TOOLKIT
12777static XrmOptionDescRec emacs_options[] = {
12778 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
12779 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
12780
12781 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
12782 XrmoptionSepArg, NULL},
12783 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
12784
12785 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12786 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12787 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12788 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
12789 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
12790 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
12791 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
12792};
12793#endif /* USE_X_TOOLKIT */
12794
7a13e894
RS
12795static int x_initialized;
12796
29b38361
KH
12797#ifdef MULTI_KBOARD
12798/* Test whether two display-name strings agree up to the dot that separates
12799 the screen number from the server number. */
12800static int
12801same_x_server (name1, name2)
12802 char *name1, *name2;
12803{
12804 int seen_colon = 0;
cf591cc1
RS
12805 unsigned char *system_name = XSTRING (Vsystem_name)->data;
12806 int system_name_length = strlen (system_name);
12807 int length_until_period = 0;
12808
12809 while (system_name[length_until_period] != 0
12810 && system_name[length_until_period] != '.')
12811 length_until_period++;
12812
12813 /* Treat `unix' like an empty host name. */
12814 if (! strncmp (name1, "unix:", 5))
12815 name1 += 4;
12816 if (! strncmp (name2, "unix:", 5))
12817 name2 += 4;
12818 /* Treat this host's name like an empty host name. */
12819 if (! strncmp (name1, system_name, system_name_length)
12820 && name1[system_name_length] == ':')
12821 name1 += system_name_length;
12822 if (! strncmp (name2, system_name, system_name_length)
12823 && name2[system_name_length] == ':')
12824 name2 += system_name_length;
12825 /* Treat this host's domainless name like an empty host name. */
12826 if (! strncmp (name1, system_name, length_until_period)
12827 && name1[length_until_period] == ':')
12828 name1 += length_until_period;
12829 if (! strncmp (name2, system_name, length_until_period)
12830 && name2[length_until_period] == ':')
12831 name2 += length_until_period;
12832
29b38361
KH
12833 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
12834 {
12835 if (*name1 == ':')
12836 seen_colon++;
12837 if (seen_colon && *name1 == '.')
12838 return 1;
12839 }
12840 return (seen_colon
12841 && (*name1 == '.' || *name1 == '\0')
12842 && (*name2 == '.' || *name2 == '\0'));
12843}
12844#endif
12845
334208b7 12846struct x_display_info *
1f8255f2 12847x_term_init (display_name, xrm_option, resource_name)
334208b7 12848 Lisp_Object display_name;
1f8255f2
RS
12849 char *xrm_option;
12850 char *resource_name;
dc6f92b8 12851{
334208b7 12852 int connection;
7a13e894 12853 Display *dpy;
334208b7
RS
12854 struct x_display_info *dpyinfo;
12855 XrmDatabase xrdb;
12856
60439948
KH
12857 BLOCK_INPUT;
12858
7a13e894
RS
12859 if (!x_initialized)
12860 {
12861 x_initialize ();
12862 x_initialized = 1;
12863 }
dc6f92b8 12864
3afe33e7 12865#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
12866 /* weiner@footloose.sps.mot.com reports that this causes
12867 errors with X11R5:
12868 X protocol error: BadAtom (invalid Atom parameter)
12869 on protocol request 18skiloaf.
12870 So let's not use it until R6. */
12871#ifdef HAVE_X11XTR6
bdcd49ba
RS
12872 XtSetLanguageProc (NULL, NULL, NULL);
12873#endif
12874
7f9c7f94
RS
12875 {
12876 int argc = 0;
12877 char *argv[3];
12878
12879 argv[0] = "";
12880 argc = 1;
12881 if (xrm_option)
12882 {
12883 argv[argc++] = "-xrm";
12884 argv[argc++] = xrm_option;
12885 }
12886 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
12887 resource_name, EMACS_CLASS,
12888 emacs_options, XtNumber (emacs_options),
12889 &argc, argv);
39d8bb4d
KH
12890
12891#ifdef HAVE_X11XTR6
10537cb1 12892 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 12893 fixup_locale ();
39d8bb4d 12894#endif
7f9c7f94 12895 }
3afe33e7
RS
12896
12897#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
12898#ifdef HAVE_X11R5
12899 XSetLocaleModifiers ("");
12900#endif
7a13e894 12901 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 12902#endif /* not USE_X_TOOLKIT */
334208b7 12903
7a13e894
RS
12904 /* Detect failure. */
12905 if (dpy == 0)
60439948
KH
12906 {
12907 UNBLOCK_INPUT;
12908 return 0;
12909 }
7a13e894
RS
12910
12911 /* We have definitely succeeded. Record the new connection. */
12912
12913 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
12914
29b38361
KH
12915#ifdef MULTI_KBOARD
12916 {
12917 struct x_display_info *share;
12918 Lisp_Object tail;
12919
12920 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
12921 share = share->next, tail = XCDR (tail))
12922 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
12923 XSTRING (display_name)->data))
12924 break;
12925 if (share)
12926 dpyinfo->kboard = share->kboard;
12927 else
12928 {
12929 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
12930 init_kboard (dpyinfo->kboard);
59e755be
KH
12931 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
12932 {
12933 char *vendor = ServerVendor (dpy);
12934 dpyinfo->kboard->Vsystem_key_alist
12935 = call1 (Qvendor_specific_keysyms,
12936 build_string (vendor ? vendor : ""));
12937 }
12938
29b38361
KH
12939 dpyinfo->kboard->next_kboard = all_kboards;
12940 all_kboards = dpyinfo->kboard;
0ad5446c
KH
12941 /* Don't let the initial kboard remain current longer than necessary.
12942 That would cause problems if a file loaded on startup tries to
06a2c219 12943 prompt in the mini-buffer. */
0ad5446c
KH
12944 if (current_kboard == initial_kboard)
12945 current_kboard = dpyinfo->kboard;
29b38361
KH
12946 }
12947 dpyinfo->kboard->reference_count++;
12948 }
b9737ad3
KH
12949#endif
12950
7a13e894
RS
12951 /* Put this display on the chain. */
12952 dpyinfo->next = x_display_list;
12953 x_display_list = dpyinfo;
12954
12955 /* Put it on x_display_name_list as well, to keep them parallel. */
12956 x_display_name_list = Fcons (Fcons (display_name, Qnil),
12957 x_display_name_list);
8e713be6 12958 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
12959
12960 dpyinfo->display = dpy;
dc6f92b8 12961
dc6f92b8 12962#if 0
7a13e894 12963 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 12964#endif /* ! 0 */
7a13e894
RS
12965
12966 dpyinfo->x_id_name
fc932ac6
RS
12967 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
12968 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
12969 + 2);
12970 sprintf (dpyinfo->x_id_name, "%s@%s",
12971 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
12972
12973 /* Figure out which modifier bits mean what. */
334208b7 12974 x_find_modifier_meanings (dpyinfo);
f451eb13 12975
ab648270 12976 /* Get the scroll bar cursor. */
7a13e894 12977 dpyinfo->vertical_scroll_bar_cursor
334208b7 12978 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 12979
334208b7
RS
12980 xrdb = x_load_resources (dpyinfo->display, xrm_option,
12981 resource_name, EMACS_CLASS);
12982#ifdef HAVE_XRMSETDATABASE
12983 XrmSetDatabase (dpyinfo->display, xrdb);
12984#else
12985 dpyinfo->display->db = xrdb;
12986#endif
547d9db8 12987 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
12988 all versions. */
12989 dpyinfo->xrdb = xrdb;
334208b7
RS
12990
12991 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
12992 DefaultScreen (dpyinfo->display));
5ff67d81 12993 select_visual (dpyinfo);
43bd1b2b 12994 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
12995 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
12996 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
12997 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
12998 dpyinfo->grabbed = 0;
12999 dpyinfo->reference_count = 0;
13000 dpyinfo->icon_bitmap_id = -1;
06a2c219 13001 dpyinfo->font_table = NULL;
7a13e894
RS
13002 dpyinfo->n_fonts = 0;
13003 dpyinfo->font_table_size = 0;
13004 dpyinfo->bitmaps = 0;
13005 dpyinfo->bitmaps_size = 0;
13006 dpyinfo->bitmaps_last = 0;
13007 dpyinfo->scratch_cursor_gc = 0;
13008 dpyinfo->mouse_face_mouse_frame = 0;
13009 dpyinfo->mouse_face_deferred_gc = 0;
13010 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
13011 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 13012 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894
RS
13013 dpyinfo->mouse_face_window = Qnil;
13014 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
13015 dpyinfo->mouse_face_defer = 0;
0f941935
KH
13016 dpyinfo->x_focus_frame = 0;
13017 dpyinfo->x_focus_event_frame = 0;
13018 dpyinfo->x_highlight_frame = 0;
06a2c219 13019 dpyinfo->image_cache = make_image_cache ();
334208b7 13020
43bd1b2b 13021 /* See if a private colormap is requested. */
5ff67d81
GM
13022 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
13023 {
13024 if (dpyinfo->visual->class == PseudoColor)
13025 {
13026 Lisp_Object value;
13027 value = display_x_get_resource (dpyinfo,
13028 build_string ("privateColormap"),
13029 build_string ("PrivateColormap"),
13030 Qnil, Qnil);
13031 if (STRINGP (value)
13032 && (!strcmp (XSTRING (value)->data, "true")
13033 || !strcmp (XSTRING (value)->data, "on")))
13034 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
13035 }
43bd1b2b 13036 }
5ff67d81
GM
13037 else
13038 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
13039 dpyinfo->visual, AllocNone);
43bd1b2b 13040
06a2c219
GM
13041 {
13042 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
13043 double pixels = DisplayHeight (dpyinfo->display, screen_number);
13044 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
13045 dpyinfo->resy = pixels * 25.4 / mm;
13046 pixels = DisplayWidth (dpyinfo->display, screen_number);
13047 mm = DisplayWidthMM (dpyinfo->display, screen_number);
13048 dpyinfo->resx = pixels * 25.4 / mm;
13049 }
13050
334208b7
RS
13051 dpyinfo->Xatom_wm_protocols
13052 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
13053 dpyinfo->Xatom_wm_take_focus
13054 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
13055 dpyinfo->Xatom_wm_save_yourself
13056 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
13057 dpyinfo->Xatom_wm_delete_window
13058 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
13059 dpyinfo->Xatom_wm_change_state
13060 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
13061 dpyinfo->Xatom_wm_configure_denied
13062 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
13063 dpyinfo->Xatom_wm_window_moved
13064 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
13065 dpyinfo->Xatom_editres
13066 = XInternAtom (dpyinfo->display, "Editres", False);
13067 dpyinfo->Xatom_CLIPBOARD
13068 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
13069 dpyinfo->Xatom_TIMESTAMP
13070 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
13071 dpyinfo->Xatom_TEXT
13072 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
13073 dpyinfo->Xatom_COMPOUND_TEXT
13074 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
13075 dpyinfo->Xatom_DELETE
13076 = XInternAtom (dpyinfo->display, "DELETE", False);
13077 dpyinfo->Xatom_MULTIPLE
13078 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
13079 dpyinfo->Xatom_INCR
13080 = XInternAtom (dpyinfo->display, "INCR", False);
13081 dpyinfo->Xatom_EMACS_TMP
13082 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
13083 dpyinfo->Xatom_TARGETS
13084 = XInternAtom (dpyinfo->display, "TARGETS", False);
13085 dpyinfo->Xatom_NULL
13086 = XInternAtom (dpyinfo->display, "NULL", False);
13087 dpyinfo->Xatom_ATOM_PAIR
13088 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
13089 /* For properties of font. */
13090 dpyinfo->Xatom_PIXEL_SIZE
13091 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
13092 dpyinfo->Xatom_MULE_BASELINE_OFFSET
13093 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
13094 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
13095 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
13096 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
13097 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 13098
06a2c219
GM
13099 /* Ghostscript support. */
13100 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
13101 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
13102
13103 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
13104 False);
13105
547d9db8
KH
13106 dpyinfo->cut_buffers_initialized = 0;
13107
334208b7
RS
13108 connection = ConnectionNumber (dpyinfo->display);
13109 dpyinfo->connection = connection;
13110
dc43ef94 13111 {
5d7cc324
RS
13112 char null_bits[1];
13113
13114 null_bits[0] = 0x00;
dc43ef94
KH
13115
13116 dpyinfo->null_pixel
13117 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13118 null_bits, 1, 1, (long) 0, (long) 0,
13119 1);
13120 }
13121
06a2c219
GM
13122 {
13123 extern int gray_bitmap_width, gray_bitmap_height;
13124 extern unsigned char *gray_bitmap_bits;
13125 dpyinfo->gray
13126 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13127 gray_bitmap_bits,
13128 gray_bitmap_width, gray_bitmap_height,
13129 (unsigned long) 1, (unsigned long) 0, 1);
13130 }
13131
f5d11644
GM
13132#ifdef HAVE_X_I18N
13133 xim_initialize (dpyinfo, resource_name);
13134#endif
13135
87485d6f
MW
13136#ifdef subprocesses
13137 /* This is only needed for distinguishing keyboard and process input. */
334208b7 13138 if (connection != 0)
7a13e894 13139 add_keyboard_wait_descriptor (connection);
87485d6f 13140#endif
6d4238f3 13141
041b69ac 13142#ifndef F_SETOWN_BUG
dc6f92b8 13143#ifdef F_SETOWN
dc6f92b8 13144#ifdef F_SETOWN_SOCK_NEG
61c3ce62 13145 /* stdin is a socket here */
334208b7 13146 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 13147#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 13148 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
13149#endif /* ! defined (F_SETOWN_SOCK_NEG) */
13150#endif /* ! defined (F_SETOWN) */
041b69ac 13151#endif /* F_SETOWN_BUG */
dc6f92b8
JB
13152
13153#ifdef SIGIO
eee20f6a
KH
13154 if (interrupt_input)
13155 init_sigio (connection);
c118dd06 13156#endif /* ! defined (SIGIO) */
dc6f92b8 13157
51b592fb 13158#ifdef USE_LUCID
f8c39f51 13159#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
13160 /* Make sure that we have a valid font for dialog boxes
13161 so that Xt does not crash. */
13162 {
13163 Display *dpy = dpyinfo->display;
13164 XrmValue d, fr, to;
13165 Font font;
e99db5a1 13166 int count;
51b592fb
RS
13167
13168 d.addr = (XPointer)&dpy;
13169 d.size = sizeof (Display *);
13170 fr.addr = XtDefaultFont;
13171 fr.size = sizeof (XtDefaultFont);
13172 to.size = sizeof (Font *);
13173 to.addr = (XPointer)&font;
e99db5a1 13174 count = x_catch_errors (dpy);
51b592fb
RS
13175 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
13176 abort ();
13177 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
13178 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 13179 x_uncatch_errors (dpy, count);
51b592fb
RS
13180 }
13181#endif
f8c39f51 13182#endif
51b592fb 13183
34e23e5a
GM
13184 /* See if we should run in synchronous mode. This is useful
13185 for debugging X code. */
13186 {
13187 Lisp_Object value;
13188 value = display_x_get_resource (dpyinfo,
13189 build_string ("synchronous"),
13190 build_string ("Synchronous"),
13191 Qnil, Qnil);
13192 if (STRINGP (value)
13193 && (!strcmp (XSTRING (value)->data, "true")
13194 || !strcmp (XSTRING (value)->data, "on")))
13195 XSynchronize (dpyinfo->display, True);
13196 }
13197
60439948
KH
13198 UNBLOCK_INPUT;
13199
7a13e894
RS
13200 return dpyinfo;
13201}
13202\f
13203/* Get rid of display DPYINFO, assuming all frames are already gone,
13204 and without sending any more commands to the X server. */
dc6f92b8 13205
7a13e894
RS
13206void
13207x_delete_display (dpyinfo)
13208 struct x_display_info *dpyinfo;
13209{
13210 delete_keyboard_wait_descriptor (dpyinfo->connection);
13211
13212 /* Discard this display from x_display_name_list and x_display_list.
13213 We can't use Fdelq because that can quit. */
13214 if (! NILP (x_display_name_list)
8e713be6
KR
13215 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
13216 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
13217 else
13218 {
13219 Lisp_Object tail;
13220
13221 tail = x_display_name_list;
8e713be6 13222 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 13223 {
bffcfca9 13224 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 13225 {
8e713be6 13226 XCDR (tail) = XCDR (XCDR (tail));
7a13e894
RS
13227 break;
13228 }
8e713be6 13229 tail = XCDR (tail);
7a13e894
RS
13230 }
13231 }
13232
9bda743f
GM
13233 if (next_noop_dpyinfo == dpyinfo)
13234 next_noop_dpyinfo = dpyinfo->next;
13235
7a13e894
RS
13236 if (x_display_list == dpyinfo)
13237 x_display_list = dpyinfo->next;
7f9c7f94
RS
13238 else
13239 {
13240 struct x_display_info *tail;
7a13e894 13241
7f9c7f94
RS
13242 for (tail = x_display_list; tail; tail = tail->next)
13243 if (tail->next == dpyinfo)
13244 tail->next = tail->next->next;
13245 }
7a13e894 13246
0d777288
RS
13247#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
13248#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
13249 XrmDestroyDatabase (dpyinfo->xrdb);
13250#endif
0d777288 13251#endif
29b38361
KH
13252#ifdef MULTI_KBOARD
13253 if (--dpyinfo->kboard->reference_count == 0)
39f79001 13254 delete_kboard (dpyinfo->kboard);
b9737ad3 13255#endif
f5d11644
GM
13256#ifdef HAVE_X_I18N
13257 if (dpyinfo->xim)
13258 xim_close_dpy (dpyinfo);
13259#endif
13260
b9737ad3
KH
13261 xfree (dpyinfo->font_table);
13262 xfree (dpyinfo->x_id_name);
13263 xfree (dpyinfo);
7a13e894
RS
13264}
13265\f
13266/* Set up use of X before we make the first connection. */
13267
06a2c219
GM
13268static struct redisplay_interface x_redisplay_interface =
13269{
13270 x_produce_glyphs,
13271 x_write_glyphs,
13272 x_insert_glyphs,
13273 x_clear_end_of_line,
13274 x_scroll_run,
13275 x_after_update_window_line,
13276 x_update_window_begin,
13277 x_update_window_end,
13278 XTcursor_to,
13279 x_flush,
66ac4b0e
GM
13280 x_get_glyph_overhangs,
13281 x_fix_overlapping_area
06a2c219
GM
13282};
13283
dfcf069d 13284void
7a13e894
RS
13285x_initialize ()
13286{
06a2c219
GM
13287 rif = &x_redisplay_interface;
13288
13289 clear_frame_hook = x_clear_frame;
13290 ins_del_lines_hook = x_ins_del_lines;
13291 change_line_highlight_hook = x_change_line_highlight;
13292 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
13293 ring_bell_hook = XTring_bell;
13294 reset_terminal_modes_hook = XTreset_terminal_modes;
13295 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
13296 update_begin_hook = x_update_begin;
13297 update_end_hook = x_update_end;
dc6f92b8
JB
13298 set_terminal_window_hook = XTset_terminal_window;
13299 read_socket_hook = XTread_socket;
b8009dd1 13300 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 13301 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 13302 mouse_position_hook = XTmouse_position;
f451eb13 13303 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 13304 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
13305 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13306 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13307 redeem_scroll_bar_hook = XTredeem_scroll_bar;
13308 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 13309 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 13310
f676886a 13311 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
13312 char_ins_del_ok = 0; /* just as fast to write the line */
13313 line_ins_del_ok = 1; /* we'll just blt 'em */
13314 fast_clear_end_of_line = 1; /* X does this well */
58769bee 13315 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
13316 off the bottom */
13317 baud_rate = 19200;
13318
7a13e894 13319 x_noop_count = 0;
9ea173e8 13320 last_tool_bar_item = -1;
06a2c219
GM
13321 any_help_event_p = 0;
13322
b30b24cb
RS
13323 /* Try to use interrupt input; if we can't, then start polling. */
13324 Fset_input_mode (Qt, Qnil, Qt, Qnil);
13325
7f9c7f94
RS
13326#ifdef USE_X_TOOLKIT
13327 XtToolkitInitialize ();
13328 Xt_app_con = XtCreateApplicationContext ();
665881ad 13329 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
13330
13331 /* Install an asynchronous timer that processes Xt timeout events
13332 every 0.1s. This is necessary because some widget sets use
13333 timeouts internally, for example the LessTif menu bar, or the
13334 Xaw3d scroll bar. When Xt timouts aren't processed, these
13335 widgets don't behave normally. */
13336 {
13337 EMACS_TIME interval;
13338 EMACS_SET_SECS_USECS (interval, 0, 100000);
13339 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
13340 }
db74249b 13341#endif
bffcfca9 13342
db74249b 13343#if USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
13344 xaw3d_arrow_scroll = False;
13345 xaw3d_pick_top = True;
7f9c7f94
RS
13346#endif
13347
58769bee 13348 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 13349 original error handler. */
e99db5a1 13350 XSetErrorHandler (x_error_handler);
334208b7 13351 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 13352
06a2c219 13353 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
13354#ifdef SIGWINCH
13355 signal (SIGWINCH, SIG_DFL);
c118dd06 13356#endif /* ! defined (SIGWINCH) */
dc6f92b8 13357
92e2441b 13358 signal (SIGPIPE, x_connection_signal);
dc6f92b8 13359}
55123275 13360
06a2c219 13361
55123275
JB
13362void
13363syms_of_xterm ()
13364{
e99db5a1
RS
13365 staticpro (&x_error_message_string);
13366 x_error_message_string = Qnil;
13367
7a13e894
RS
13368 staticpro (&x_display_name_list);
13369 x_display_name_list = Qnil;
334208b7 13370
ab648270 13371 staticpro (&last_mouse_scroll_bar);
e53cb100 13372 last_mouse_scroll_bar = Qnil;
59e755be
KH
13373
13374 staticpro (&Qvendor_specific_keysyms);
13375 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
13376
13377 staticpro (&last_mouse_press_frame);
13378 last_mouse_press_frame = Qnil;
06a2c219
GM
13379
13380 staticpro (&help_echo);
13381 help_echo = Qnil;
13382 staticpro (&previous_help_echo);
13383 previous_help_echo = Qnil;
13384
13385 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
13386 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
13387For example, if a block cursor is over a tab, it will be drawn as\n\
13388wide as that tab on the display.");
13389 x_stretch_cursor_p = 0;
13390
13391 DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
13392 "If not nil, Emacs uses toolkit scroll bars.");
13393#if USE_TOOLKIT_SCROLL_BARS
13394 x_toolkit_scroll_bars_p = 1;
13395#else
13396 x_toolkit_scroll_bars_p = 0;
13397#endif
13398
06a2c219
GM
13399 staticpro (&last_mouse_motion_frame);
13400 last_mouse_motion_frame = Qnil;
55123275 13401}
6cf0ae86
RS
13402
13403#endif /* not HAVE_X_WINDOWS */
06a2c219 13404