(sweep_weak_table): Fix survival conditions for
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
1c7e22fd 2 Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000
06a2c219 3 Free Software Foundation, Inc.
dc6f92b8
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4746118a 9the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
dc6f92b8 21
06a2c219 22/* New display code by Gerd Moellmann <gerd@gnu.org>. */
3afe33e7
RS
23/* Xt features made by Fred Pierresteguy. */
24
68c45bf0
PE
25#include <config.h>
26
039440c4 27/* On 4.3 these lose if they come after xterm.h. */
039440c4 28/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
29#include <signal.h>
30
4846819e
RS
31#include <stdio.h>
32
dc6f92b8
JB
33#ifdef HAVE_X_WINDOWS
34
35#include "lisp.h"
9ac0d9e0 36#include "blockinput.h"
dc6f92b8 37
ae79c227
AS
38/* Need syssignal.h for various externs and definitions that may be required
39 by some configurations for calls to signal later in this source file. */
40#include "syssignal.h"
41
dc6f92b8
JB
42/* This may include sys/types.h, and that somehow loses
43 if this is not done before the other system files. */
44#include "xterm.h"
f451eb13 45#include <X11/cursorfont.h>
dc6f92b8
JB
46
47/* Load sys/types.h if not already loaded.
48 In some systems loading it twice is suicidal. */
49#ifndef makedev
50#include <sys/types.h>
c118dd06 51#endif /* makedev */
dc6f92b8 52
6df54671 53#ifdef BSD_SYSTEM
dc6f92b8 54#include <sys/ioctl.h>
6df54671 55#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 56
2d368234 57#include "systty.h"
3a2712f9 58#include "systime.h"
dc6f92b8 59
b8009dd1 60#ifndef INCLUDED_FCNTL
dc6f92b8 61#include <fcntl.h>
b8009dd1 62#endif
dc6f92b8
JB
63#include <ctype.h>
64#include <errno.h>
65#include <setjmp.h>
66#include <sys/stat.h>
a0a7635f
RS
67/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
68/* #include <sys/param.h> */
dc6f92b8 69
dc43ef94
KH
70#include "charset.h"
71#include "ccl.h"
7a13e894 72#include "frame.h"
dc6f92b8 73#include "dispextern.h"
ee569018 74#include "fontset.h"
dc6f92b8
JB
75#include "termhooks.h"
76#include "termopts.h"
77#include "termchar.h"
78#if 0
79#include "sink.h"
80#include "sinkmask.h"
c118dd06 81#endif /* ! 0 */
dc6f92b8 82#include "gnu.h"
dc6f92b8 83#include "disptab.h"
dc6f92b8 84#include "buffer.h"
f451eb13 85#include "window.h"
3b2fa4e6 86#include "keyboard.h"
bde7c500 87#include "intervals.h"
dfcf069d 88#include "process.h"
bffcfca9 89#include "atimer.h"
dc6f92b8 90
d2bd6bc4
RS
91#ifdef USE_X_TOOLKIT
92#include <X11/Shell.h>
93#endif
94
06a2c219
GM
95#ifdef HAVE_SYS_TIME_H
96#include <sys/time.h>
97#endif
98#ifdef HAVE_UNISTD_H
99#include <unistd.h>
100#endif
101
3afe33e7 102#ifdef USE_X_TOOLKIT
06a2c219 103
952291d9
GM
104extern void free_frame_menubar P_ ((struct frame *));
105extern struct frame *x_menubar_window_to_frame P_ ((struct x_display_info *,
106 int));
06a2c219 107
0fdff6bb
RS
108#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
109#define HACK_EDITRES
110extern void _XEditResCheckMessages ();
111#endif /* not NO_EDITRES */
06a2c219
GM
112
113/* Include toolkit specific headers for the scroll bar widget. */
114
115#ifdef USE_TOOLKIT_SCROLL_BARS
116#if defined USE_MOTIF
117#include <Xm/Xm.h> /* for LESSTIF_VERSION */
118#include <Xm/ScrollBar.h>
119#include <Xm/ScrollBarP.h>
ec18280f
SM
120#else /* !USE_MOTIF i.e. use Xaw */
121
122#ifdef HAVE_XAW3D
06a2c219 123#include <X11/Xaw3d/Simple.h>
06a2c219
GM
124#include <X11/Xaw3d/Scrollbar.h>
125#define ARROW_SCROLLBAR
126#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
127#else /* !HAVE_XAW3D */
128#include <X11/Xaw/Simple.h>
129#include <X11/Xaw/Scrollbar.h>
130#endif /* !HAVE_XAW3D */
131#ifndef XtNpickTop
132#define XtNpickTop "pickTop"
133#endif /* !XtNpickTop */
134#endif /* !USE_MOTIF */
06a2c219
GM
135#endif /* USE_TOOLKIT_SCROLL_BARS */
136
3afe33e7
RS
137#endif /* USE_X_TOOLKIT */
138
b849c413
RS
139#ifndef USE_X_TOOLKIT
140#define x_any_window_to_frame x_window_to_frame
5627c40e 141#define x_top_window_to_frame x_window_to_frame
b849c413
RS
142#endif
143
546e6d5b 144#ifdef USE_X_TOOLKIT
d067ea8b 145#include "widget.h"
546e6d5b
RS
146#ifndef XtNinitialState
147#define XtNinitialState "initialState"
148#endif
149#endif
150
80528801
KH
151#ifdef SOLARIS2
152/* memmove will be defined as a macro in Xfuncs.h unless
153 <string.h> is included beforehand. The declaration for memmove in
154 <string.h> will cause a syntax error when Xfuncs.h later includes it. */
155#include <string.h>
156#endif
157
e4b68333 158#ifndef min
06a2c219 159#define min(a,b) ((a) < (b) ? (a) : (b))
e4b68333
RS
160#endif
161#ifndef max
06a2c219
GM
162#define max(a,b) ((a) > (b) ? (a) : (b))
163#endif
164
165#define abs(x) ((x) < 0 ? -(x) : (x))
166
167#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
168
169\f
170/* Bitmaps for truncated lines. */
171
172enum bitmap_type
173{
174 NO_BITMAP,
175 LEFT_TRUNCATION_BITMAP,
176 RIGHT_TRUNCATION_BITMAP,
177 OVERLAY_ARROW_BITMAP,
178 CONTINUED_LINE_BITMAP,
179 CONTINUATION_LINE_BITMAP,
180 ZV_LINE_BITMAP
181};
182
183/* Bitmap drawn to indicate lines not displaying text if
184 `indicate-empty-lines' is non-nil. */
185
186#define zv_width 8
187#define zv_height 8
188static unsigned char zv_bits[] = {
189 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
190
191/* An arrow like this: `<-'. */
192
193#define left_width 8
194#define left_height 8
195static unsigned char left_bits[] = {
196 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
197
110859fc
GM
198/* Right truncation arrow bitmap `->'. */
199
200#define right_width 8
201#define right_height 8
202static unsigned char right_bits[] = {
203 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
204
06a2c219
GM
205/* Marker for continued lines. */
206
207#define continued_width 8
208#define continued_height 8
209static unsigned char continued_bits[] = {
110859fc
GM
210 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
211
212/* Marker for continuation lines. */
06a2c219
GM
213
214#define continuation_width 8
215#define continuation_height 8
216static unsigned char continuation_bits[] = {
110859fc 217 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 218
110859fc 219/* Overlay arrow bitmap. */
06a2c219 220
110859fc
GM
221#if 0
222/* A bomb. */
06a2c219
GM
223#define ov_width 8
224#define ov_height 8
225static unsigned char ov_bits[] = {
226 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 227#else
110859fc 228/* A triangular arrow. */
06a2c219
GM
229#define ov_width 8
230#define ov_height 8
231static unsigned char ov_bits[] = {
110859fc
GM
232 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
233
e4b68333 234#endif
06a2c219
GM
235
236extern Lisp_Object Qhelp_echo;
237
69388238 238\f
06a2c219
GM
239/* Non-zero means Emacs uses toolkit scroll bars. */
240
241int x_toolkit_scroll_bars_p;
242
243/* If a string, XTread_socket generates an event to display that string.
244 (The display is done in read_char.) */
245
246static Lisp_Object help_echo;
7cea38bc 247static Lisp_Object help_echo_window;
be010514
GM
248static Lisp_Object help_echo_object;
249static int help_echo_pos;
06a2c219
GM
250
251/* Temporary variable for XTread_socket. */
252
253static Lisp_Object previous_help_echo;
254
255/* Non-zero means that a HELP_EVENT has been generated since Emacs
256 start. */
257
258static int any_help_event_p;
259
260/* Non-zero means draw block and hollow cursor as wide as the glyph
261 under it. For example, if a block cursor is over a tab, it will be
262 drawn as wide as that tab on the display. */
263
264int x_stretch_cursor_p;
265
266/* This is a chain of structures for all the X displays currently in
267 use. */
268
334208b7 269struct x_display_info *x_display_list;
dc6f92b8 270
06a2c219
GM
271/* This is a list of cons cells, each of the form (NAME
272 . FONT-LIST-CACHE), one for each element of x_display_list and in
273 the same order. NAME is the name of the frame. FONT-LIST-CACHE
274 records previous values returned by x-list-fonts. */
275
7a13e894 276Lisp_Object x_display_name_list;
f451eb13 277
987d2ad1 278/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
279 This is set by update_begin and looked at by all the XT functions.
280 It is zero while not inside an update. In that case, the XT
281 functions assume that `selected_frame' is the frame to apply to. */
282
d0386f2a 283extern struct frame *updating_frame;
dc6f92b8 284
dfcf069d 285extern int waiting_for_input;
0e81d8cd 286
06a2c219
GM
287/* This is a frame waiting to be auto-raised, within XTread_socket. */
288
0134a210
RS
289struct frame *pending_autoraise_frame;
290
7f9c7f94
RS
291#ifdef USE_X_TOOLKIT
292/* The application context for Xt use. */
293XtAppContext Xt_app_con;
06a2c219
GM
294static String Xt_default_resources[] = {0};
295#endif /* USE_X_TOOLKIT */
665881ad 296
06a2c219
GM
297/* Nominal cursor position -- where to draw output.
298 HPOS and VPOS are window relative glyph matrix coordinates.
299 X and Y are window relative pixel coordinates. */
dc6f92b8 300
06a2c219 301struct cursor_pos output_cursor;
dc6f92b8 302
bffcfca9
GM
303/* Non-zero means user is interacting with a toolkit scroll bar. */
304
305static int toolkit_scroll_bar_interaction;
dc6f92b8 306
69388238
RS
307/* Mouse movement.
308
06a2c219 309 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
310 so that we would have to call XQueryPointer after each MotionNotify
311 event to ask for another such event. However, this made mouse tracking
312 slow, and there was a bug that made it eventually stop.
313
314 Simply asking for MotionNotify all the time seems to work better.
315
69388238
RS
316 In order to avoid asking for motion events and then throwing most
317 of them away or busy-polling the server for mouse positions, we ask
318 the server for pointer motion hints. This means that we get only
319 one event per group of mouse movements. "Groups" are delimited by
320 other kinds of events (focus changes and button clicks, for
321 example), or by XQueryPointer calls; when one of these happens, we
322 get another MotionNotify event the next time the mouse moves. This
323 is at least as efficient as getting motion events when mouse
324 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 325 is off. */
69388238
RS
326
327/* Where the mouse was last time we reported a mouse event. */
69388238 328
06a2c219
GM
329FRAME_PTR last_mouse_frame;
330static XRectangle last_mouse_glyph;
2237cac9
RS
331static Lisp_Object last_mouse_press_frame;
332
69388238
RS
333/* The scroll bar in which the last X motion event occurred.
334
06a2c219
GM
335 If the last X motion event occurred in a scroll bar, we set this so
336 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
337 an ordinary motion.
338
06a2c219
GM
339 If the last X motion event didn't occur in a scroll bar, we set
340 this to Qnil, to tell XTmouse_position to return an ordinary motion
341 event. */
342
69388238
RS
343static Lisp_Object last_mouse_scroll_bar;
344
69388238
RS
345/* This is a hack. We would really prefer that XTmouse_position would
346 return the time associated with the position it returns, but there
06a2c219 347 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
348 along with the position query. So, we just keep track of the time
349 of the last movement we received, and return that in hopes that
350 it's somewhat accurate. */
06a2c219 351
69388238
RS
352static Time last_mouse_movement_time;
353
06a2c219
GM
354/* Incremented by XTread_socket whenever it really tries to read
355 events. */
356
c0a04927
RS
357#ifdef __STDC__
358static int volatile input_signal_count;
359#else
360static int input_signal_count;
361#endif
362
7a13e894 363/* Used locally within XTread_socket. */
06a2c219 364
7a13e894 365static int x_noop_count;
dc6f92b8 366
7a13e894 367/* Initial values of argv and argc. */
06a2c219 368
7a13e894
RS
369extern char **initial_argv;
370extern int initial_argc;
dc6f92b8 371
7a13e894 372extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 373
06a2c219 374/* Tells if a window manager is present or not. */
7a13e894
RS
375
376extern Lisp_Object Vx_no_window_manager;
dc6f92b8 377
c2df547c 378extern Lisp_Object Qface, Qmouse_face;
b8009dd1 379
dc6f92b8
JB
380extern int errno;
381
dfeccd2d 382/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 383
64bb1782
RS
384extern int extra_keyboard_modifiers;
385
59e755be
KH
386static Lisp_Object Qvendor_specific_keysyms;
387
952291d9
GM
388extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
389extern Lisp_Object x_icon_type P_ ((struct frame *));
c32cdd9a 390
7a13e894 391
06a2c219
GM
392/* Enumeration for overriding/changing the face to use for drawing
393 glyphs in x_draw_glyphs. */
394
395enum draw_glyphs_face
396{
397 DRAW_NORMAL_TEXT,
398 DRAW_INVERSE_VIDEO,
399 DRAW_CURSOR,
400 DRAW_MOUSE_FACE,
401 DRAW_IMAGE_RAISED,
402 DRAW_IMAGE_SUNKEN
403};
404
71b8321e 405static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
406static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
407void x_delete_display P_ ((struct x_display_info *));
408static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
409 unsigned));
410static int fast_find_position P_ ((struct window *, int, int *, int *,
411 int *, int *));
412static void set_output_cursor P_ ((struct cursor_pos *));
413static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
414 int *, int *, int *));
415static void note_mode_line_highlight P_ ((struct window *, int, int));
06a2c219 416static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
417static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
418static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
419static void show_mouse_face P_ ((struct x_display_info *,
420 enum draw_glyphs_face));
421static int x_io_error_quitter P_ ((Display *));
422int x_catch_errors P_ ((Display *));
423void x_uncatch_errors P_ ((Display *, int));
424void x_lower_frame P_ ((struct frame *));
425void x_scroll_bar_clear P_ ((struct frame *));
426int x_had_errors_p P_ ((Display *));
427void x_wm_set_size_hint P_ ((struct frame *, long, int));
428void x_raise_frame P_ ((struct frame *));
429void x_set_window_size P_ ((struct frame *, int, int, int));
430void x_wm_set_window_state P_ ((struct frame *, int));
431void x_wm_set_icon_pixmap P_ ((struct frame *, int));
432void x_initialize P_ ((void));
433static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
434static int x_compute_min_glyph_bounds P_ ((struct frame *));
435static void x_draw_phys_cursor_glyph P_ ((struct window *,
436 struct glyph_row *,
437 enum draw_glyphs_face));
438static void x_update_end P_ ((struct frame *));
439static void XTframe_up_to_date P_ ((struct frame *));
440static void XTreassert_line_highlight P_ ((int, int));
441static void x_change_line_highlight P_ ((int, int, int, int));
442static void XTset_terminal_modes P_ ((void));
443static void XTreset_terminal_modes P_ ((void));
444static void XTcursor_to P_ ((int, int, int, int));
445static void x_write_glyphs P_ ((struct glyph *, int));
446static void x_clear_end_of_line P_ ((int));
447static void x_clear_frame P_ ((void));
448static void x_clear_cursor P_ ((struct window *));
449static void frame_highlight P_ ((struct frame *));
450static void frame_unhighlight P_ ((struct frame *));
451static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
452static void XTframe_rehighlight P_ ((struct frame *));
453static void x_frame_rehighlight P_ ((struct x_display_info *));
454static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 455static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
456static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
457 XRectangle *));
458static void expose_frame P_ ((struct frame *, int, int, int, int));
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));
952291d9
GM
478static void x_update_begin P_ ((struct frame *));
479static void x_update_window_begin P_ ((struct window *));
480static void x_draw_vertical_border P_ ((struct window *));
481static void x_after_update_window_line P_ ((struct glyph_row *));
482static INLINE void take_vertical_position_into_account P_ ((struct it *));
483static void x_produce_stretch_glyph P_ ((struct it *));
484
06a2c219
GM
485
486/* Flush display of frame F, or of all frames if F is null. */
487
488static void
489x_flush (f)
490 struct frame *f;
491{
492 BLOCK_INPUT;
493 if (f == NULL)
494 {
495 Lisp_Object rest, frame;
496 FOR_EACH_FRAME (rest, frame)
497 x_flush (XFRAME (frame));
498 }
499 else if (FRAME_X_P (f))
500 XFlush (FRAME_X_DISPLAY (f));
501 UNBLOCK_INPUT;
502}
503
dc6f92b8 504
06a2c219
GM
505/* Remove calls to XFlush by defining XFlush to an empty replacement.
506 Calls to XFlush should be unnecessary because the X output buffer
507 is flushed automatically as needed by calls to XPending,
508 XNextEvent, or XWindowEvent according to the XFlush man page.
509 XTread_socket calls XPending. Removing XFlush improves
510 performance. */
511
512#define XFlush(DISPLAY) (void) 0
b8009dd1 513
334208b7 514\f
06a2c219
GM
515/***********************************************************************
516 Debugging
517 ***********************************************************************/
518
9382638d 519#if 0
06a2c219
GM
520
521/* This is a function useful for recording debugging information about
522 the sequence of occurrences in this file. */
9382638d
KH
523
524struct record
525{
526 char *locus;
527 int type;
528};
529
530struct record event_record[100];
531
532int event_record_index;
533
534record_event (locus, type)
535 char *locus;
536 int type;
537{
538 if (event_record_index == sizeof (event_record) / sizeof (struct record))
539 event_record_index = 0;
540
541 event_record[event_record_index].locus = locus;
542 event_record[event_record_index].type = type;
543 event_record_index++;
544}
545
546#endif /* 0 */
06a2c219
GM
547
548
9382638d 549\f
334208b7
RS
550/* Return the struct x_display_info corresponding to DPY. */
551
552struct x_display_info *
553x_display_info_for_display (dpy)
554 Display *dpy;
555{
556 struct x_display_info *dpyinfo;
557
558 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
559 if (dpyinfo->display == dpy)
560 return dpyinfo;
16bd92ea 561
334208b7
RS
562 return 0;
563}
f451eb13 564
06a2c219
GM
565
566\f
567/***********************************************************************
568 Starting and ending an update
569 ***********************************************************************/
570
571/* Start an update of frame F. This function is installed as a hook
572 for update_begin, i.e. it is called when update_begin is called.
573 This function is called prior to calls to x_update_window_begin for
574 each window being updated. Currently, there is nothing to do here
575 because all interesting stuff is done on a window basis. */
dc6f92b8 576
dfcf069d 577static void
06a2c219 578x_update_begin (f)
f676886a 579 struct frame *f;
58769bee 580{
06a2c219
GM
581 /* Nothing to do. */
582}
dc6f92b8 583
dc6f92b8 584
06a2c219
GM
585/* Start update of window W. Set the global variable updated_window
586 to the window being updated and set output_cursor to the cursor
587 position of W. */
dc6f92b8 588
06a2c219
GM
589static void
590x_update_window_begin (w)
591 struct window *w;
592{
593 struct frame *f = XFRAME (WINDOW_FRAME (w));
594 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
595
596 updated_window = w;
597 set_output_cursor (&w->cursor);
b8009dd1 598
06a2c219 599 BLOCK_INPUT;
d1bc4182 600
06a2c219 601 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 602 {
514e4681 603 /* Don't do highlighting for mouse motion during the update. */
06a2c219 604 display_info->mouse_face_defer = 1;
37c2c98b 605
06a2c219
GM
606 /* If F needs to be redrawn, simply forget about any prior mouse
607 highlighting. */
9f67f20b 608 if (FRAME_GARBAGED_P (f))
06a2c219
GM
609 display_info->mouse_face_window = Qnil;
610
64f26cf5
GM
611#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
612 their mouse_face_p flag set, which means that they are always
613 unequal to rows in a desired matrix which never have that
614 flag set. So, rows containing mouse-face glyphs are never
615 scrolled, and we don't have to switch the mouse highlight off
616 here to prevent it from being scrolled. */
617
06a2c219
GM
618 /* Can we tell that this update does not affect the window
619 where the mouse highlight is? If so, no need to turn off.
620 Likewise, don't do anything if the frame is garbaged;
621 in that case, the frame's current matrix that we would use
622 is all wrong, and we will redisplay that line anyway. */
623 if (!NILP (display_info->mouse_face_window)
624 && w == XWINDOW (display_info->mouse_face_window))
514e4681 625 {
06a2c219 626 int i;
514e4681 627
06a2c219
GM
628 for (i = 0; i < w->desired_matrix->nrows; ++i)
629 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
630 break;
631
06a2c219
GM
632 if (i < w->desired_matrix->nrows)
633 clear_mouse_face (display_info);
514e4681 634 }
64f26cf5 635#endif /* 0 */
b8009dd1 636 }
6ccf47d1 637
dc6f92b8
JB
638 UNBLOCK_INPUT;
639}
640
06a2c219
GM
641
642/* Draw a vertical window border to the right of window W if W doesn't
643 have vertical scroll bars. */
644
dfcf069d 645static void
06a2c219
GM
646x_draw_vertical_border (w)
647 struct window *w;
58769bee 648{
06a2c219
GM
649 struct frame *f = XFRAME (WINDOW_FRAME (w));
650
651 /* Redraw borders between horizontally adjacent windows. Don't
652 do it for frames with vertical scroll bars because either the
653 right scroll bar of a window, or the left scroll bar of its
654 neighbor will suffice as a border. */
655 if (!WINDOW_RIGHTMOST_P (w)
656 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
657 {
658 int x0, x1, y0, y1;
dc6f92b8 659
06a2c219 660 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 661 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
662 y1 -= 1;
663
664 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
665 f->output_data.x->normal_gc, x1, y0, x1, y1);
666 }
667}
668
669
71b8321e
GM
670/* End update of window W (which is equal to updated_window).
671
672 Draw vertical borders between horizontally adjacent windows, and
673 display W's cursor if CURSOR_ON_P is non-zero.
674
675 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
676 glyphs in mouse-face were overwritten. In that case we have to
677 make sure that the mouse-highlight is properly redrawn.
678
679 W may be a menu bar pseudo-window in case we don't have X toolkit
680 support. Such windows don't have a cursor, so don't display it
681 here. */
06a2c219
GM
682
683static void
71b8321e 684x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 685 struct window *w;
71b8321e 686 int cursor_on_p, mouse_face_overwritten_p;
06a2c219
GM
687{
688 if (!w->pseudo_window_p)
689 {
71b8321e
GM
690 struct x_display_info *dpyinfo
691 = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
692
06a2c219 693 BLOCK_INPUT;
71b8321e
GM
694
695 /* If a row with mouse-face was overwritten, arrange for
696 XTframe_up_to_date to redisplay the mouse highlight. */
697 if (mouse_face_overwritten_p)
698 {
699 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
700 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
701 dpyinfo->mouse_face_window = Qnil;
702 }
703
06a2c219
GM
704 if (cursor_on_p)
705 x_display_and_set_cursor (w, 1, output_cursor.hpos,
706 output_cursor.vpos,
707 output_cursor.x, output_cursor.y);
71b8321e 708
06a2c219
GM
709 x_draw_vertical_border (w);
710 UNBLOCK_INPUT;
711 }
712
713 updated_window = NULL;
714}
dc6f92b8 715
dc6f92b8 716
06a2c219
GM
717/* End update of frame F. This function is installed as a hook in
718 update_end. */
719
720static void
721x_update_end (f)
722 struct frame *f;
723{
724 /* Mouse highlight may be displayed again. */
aa8bff2e 725 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 726
06a2c219 727 BLOCK_INPUT;
334208b7 728 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
729 UNBLOCK_INPUT;
730}
b8009dd1 731
06a2c219
GM
732
733/* This function is called from various places in xdisp.c whenever a
734 complete update has been performed. The global variable
735 updated_window is not available here. */
b8009dd1 736
dfcf069d 737static void
b8009dd1 738XTframe_up_to_date (f)
06a2c219 739 struct frame *f;
b8009dd1 740{
06a2c219 741 if (FRAME_X_P (f))
514e4681 742 {
06a2c219 743 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 744
06a2c219
GM
745 if (dpyinfo->mouse_face_deferred_gc
746 || f == dpyinfo->mouse_face_mouse_frame)
747 {
748 BLOCK_INPUT;
749 if (dpyinfo->mouse_face_mouse_frame)
750 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
751 dpyinfo->mouse_face_mouse_x,
752 dpyinfo->mouse_face_mouse_y);
753 dpyinfo->mouse_face_deferred_gc = 0;
754 UNBLOCK_INPUT;
755 }
514e4681 756 }
b8009dd1 757}
06a2c219
GM
758
759
760/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
761 arrow bitmaps, or clear the areas where they would be displayed
762 before DESIRED_ROW is made current. The window being updated is
763 found in updated_window. This function It is called from
764 update_window_line only if it is known that there are differences
765 between bitmaps to be drawn between current row and DESIRED_ROW. */
766
767static void
768x_after_update_window_line (desired_row)
769 struct glyph_row *desired_row;
770{
771 struct window *w = updated_window;
772
773 xassert (w);
774
775 if (!desired_row->mode_line_p && !w->pseudo_window_p)
776 {
777 BLOCK_INPUT;
778 x_draw_row_bitmaps (w, desired_row);
779
780 /* When a window has disappeared, make sure that no rest of
781 full-width rows stays visible in the internal border. */
782 if (windows_or_buffers_changed)
783 {
784 struct frame *f = XFRAME (w->frame);
785 int width = FRAME_INTERNAL_BORDER_WIDTH (f);
786 int height = desired_row->visible_height;
110859fc
GM
787 int x = (window_box_right (w, -1)
788 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
789 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
790
791 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
792 x, y, width, height, False);
793 }
794
795 UNBLOCK_INPUT;
796 }
797}
798
799
800/* Draw the bitmap WHICH in one of the areas to the left or right of
801 window W. ROW is the glyph row for which to display the bitmap; it
802 determines the vertical position at which the bitmap has to be
803 drawn. */
804
805static void
806x_draw_bitmap (w, row, which)
807 struct window *w;
808 struct glyph_row *row;
809 enum bitmap_type which;
810{
811 struct frame *f = XFRAME (WINDOW_FRAME (w));
812 Display *display = FRAME_X_DISPLAY (f);
813 Window window = FRAME_X_WINDOW (f);
814 int x, y, wd, h, dy;
815 unsigned char *bits;
816 Pixmap pixmap;
817 GC gc = f->output_data.x->normal_gc;
818 struct face *face;
819 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
820
821 /* Must clip because of partially visible lines. */
822 x_clip_to_row (w, row, gc, 1);
823
824 switch (which)
825 {
826 case LEFT_TRUNCATION_BITMAP:
827 wd = left_width;
828 h = left_height;
829 bits = left_bits;
830 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
831 - wd
110859fc 832 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
833 break;
834
835 case OVERLAY_ARROW_BITMAP:
836 wd = left_width;
837 h = left_height;
838 bits = ov_bits;
839 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
840 - wd
110859fc 841 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
842 break;
843
844 case RIGHT_TRUNCATION_BITMAP:
845 wd = right_width;
846 h = right_height;
847 bits = right_bits;
848 x = window_box_right (w, -1);
110859fc 849 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
850 break;
851
852 case CONTINUED_LINE_BITMAP:
853 wd = right_width;
854 h = right_height;
855 bits = continued_bits;
856 x = window_box_right (w, -1);
110859fc 857 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
858 break;
859
860 case CONTINUATION_LINE_BITMAP:
861 wd = continuation_width;
862 h = continuation_height;
863 bits = continuation_bits;
864 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
865 - wd
110859fc 866 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
867 break;
868
869 case ZV_LINE_BITMAP:
870 wd = zv_width;
871 h = zv_height;
872 bits = zv_bits;
873 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
874 - wd
110859fc 875 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
876 break;
877
878 default:
879 abort ();
880 }
881
882 /* Convert to frame coordinates. Set dy to the offset in the row to
883 start drawing the bitmap. */
884 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
885 dy = (row->height - h) / 2;
886
887 /* Draw the bitmap. I believe these small pixmaps can be cached
888 by the server. */
889 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
890 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
891 face->foreground,
892 face->background, depth);
893 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
894 XFreePixmap (display, pixmap);
895 XSetClipMask (display, gc, None);
896}
897
898
899/* Draw flags bitmaps for glyph row ROW on window W. Call this
900 function with input blocked. */
901
902static void
903x_draw_row_bitmaps (w, row)
904 struct window *w;
905 struct glyph_row *row;
906{
907 struct frame *f = XFRAME (w->frame);
908 enum bitmap_type bitmap;
909 struct face *face;
045dee35 910 int header_line_height = -1;
06a2c219
GM
911
912 xassert (interrupt_input_blocked);
913
914 /* If row is completely invisible, because of vscrolling, we
915 don't have to draw anything. */
916 if (row->visible_height <= 0)
917 return;
918
919 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
920 PREPARE_FACE_FOR_DISPLAY (f, face);
921
922 /* Decide which bitmap to draw at the left side. */
923 if (row->overlay_arrow_p)
924 bitmap = OVERLAY_ARROW_BITMAP;
925 else if (row->truncated_on_left_p)
926 bitmap = LEFT_TRUNCATION_BITMAP;
927 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
928 bitmap = CONTINUATION_LINE_BITMAP;
929 else if (row->indicate_empty_line_p)
930 bitmap = ZV_LINE_BITMAP;
931 else
932 bitmap = NO_BITMAP;
933
934 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
935 the flags area. */
936 if (bitmap == NO_BITMAP
110859fc 937 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
938 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
939 {
940 /* If W has a vertical border to its left, don't draw over it. */
941 int border = ((XFASTINT (w->left) > 0
942 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
943 ? 1 : 0);
944 int left = window_box_left (w, -1);
945
045dee35
GM
946 if (header_line_height < 0)
947 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
948
949 /* In case the same realized face is used for bitmap areas and
950 for something displayed in the text (e.g. face `region' on
951 mono-displays, the fill style may have been changed to
952 FillSolid in x_draw_glyph_string_background. */
953 if (face->stipple)
954 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
955 else
956 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
957
06a2c219
GM
958 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
959 face->gc,
960 (left
110859fc 961 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 962 + border),
045dee35 963 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 964 row->y)),
110859fc 965 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 966 row->visible_height);
dcd08bfb
GM
967 if (!face->stipple)
968 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
969 }
970
971 /* Draw the left bitmap. */
972 if (bitmap != NO_BITMAP)
973 x_draw_bitmap (w, row, bitmap);
974
975 /* Decide which bitmap to draw at the right side. */
976 if (row->truncated_on_right_p)
977 bitmap = RIGHT_TRUNCATION_BITMAP;
978 else if (row->continued_p)
979 bitmap = CONTINUED_LINE_BITMAP;
980 else
981 bitmap = NO_BITMAP;
982
983 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
984 the flags area. */
985 if (bitmap == NO_BITMAP
110859fc 986 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
987 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
988 {
989 int right = window_box_right (w, -1);
990
045dee35
GM
991 if (header_line_height < 0)
992 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
993
994 /* In case the same realized face is used for bitmap areas and
995 for something displayed in the text (e.g. face `region' on
996 mono-displays, the fill style may have been changed to
997 FillSolid in x_draw_glyph_string_background. */
998 if (face->stipple)
999 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1000 else
1001 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
1002 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1003 face->gc,
1004 right,
045dee35 1005 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 1006 row->y)),
110859fc 1007 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 1008 row->visible_height);
dcd08bfb
GM
1009 if (!face->stipple)
1010 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
1011 }
1012
1013 /* Draw the right bitmap. */
1014 if (bitmap != NO_BITMAP)
1015 x_draw_bitmap (w, row, bitmap);
1016}
1017
dc6f92b8 1018\f
06a2c219
GM
1019/***********************************************************************
1020 Line Highlighting
1021 ***********************************************************************/
dc6f92b8 1022
06a2c219
GM
1023/* External interface to control of standout mode. Not used for X
1024 frames. Aborts when called. */
1025
1026static void
dc6f92b8
JB
1027XTreassert_line_highlight (new, vpos)
1028 int new, vpos;
1029{
06a2c219 1030 abort ();
dc6f92b8
JB
1031}
1032
06a2c219
GM
1033
1034/* Call this when about to modify line at position VPOS and change
1035 whether it is highlighted. Not used for X frames. Aborts when
1036 called. */
dc6f92b8 1037
dfcf069d 1038static void
06a2c219
GM
1039x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1040 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1041{
06a2c219 1042 abort ();
dc6f92b8
JB
1043}
1044
06a2c219
GM
1045
1046/* This is called when starting Emacs and when restarting after
1047 suspend. When starting Emacs, no X window is mapped. And nothing
1048 must be done to Emacs's own window if it is suspended (though that
1049 rarely happens). */
dc6f92b8 1050
dfcf069d 1051static void
dc6f92b8
JB
1052XTset_terminal_modes ()
1053{
1054}
1055
06a2c219
GM
1056/* This is called when exiting or suspending Emacs. Exiting will make
1057 the X-windows go away, and suspending requires no action. */
dc6f92b8 1058
dfcf069d 1059static void
dc6f92b8
JB
1060XTreset_terminal_modes ()
1061{
dc6f92b8 1062}
06a2c219
GM
1063
1064
dc6f92b8 1065\f
06a2c219
GM
1066/***********************************************************************
1067 Output Cursor
1068 ***********************************************************************/
1069
1070/* Set the global variable output_cursor to CURSOR. All cursor
1071 positions are relative to updated_window. */
dc6f92b8 1072
dfcf069d 1073static void
06a2c219
GM
1074set_output_cursor (cursor)
1075 struct cursor_pos *cursor;
dc6f92b8 1076{
06a2c219
GM
1077 output_cursor.hpos = cursor->hpos;
1078 output_cursor.vpos = cursor->vpos;
1079 output_cursor.x = cursor->x;
1080 output_cursor.y = cursor->y;
1081}
1082
1083
1084/* Set a nominal cursor position.
dc6f92b8 1085
06a2c219
GM
1086 HPOS and VPOS are column/row positions in a window glyph matrix. X
1087 and Y are window text area relative pixel positions.
1088
1089 If this is done during an update, updated_window will contain the
1090 window that is being updated and the position is the future output
1091 cursor position for that window. If updated_window is null, use
1092 selected_window and display the cursor at the given position. */
1093
1094static void
1095XTcursor_to (vpos, hpos, y, x)
1096 int vpos, hpos, y, x;
1097{
1098 struct window *w;
1099
1100 /* If updated_window is not set, work on selected_window. */
1101 if (updated_window)
1102 w = updated_window;
1103 else
1104 w = XWINDOW (selected_window);
dbcb258a 1105
06a2c219
GM
1106 /* Set the output cursor. */
1107 output_cursor.hpos = hpos;
1108 output_cursor.vpos = vpos;
1109 output_cursor.x = x;
1110 output_cursor.y = y;
dc6f92b8 1111
06a2c219
GM
1112 /* If not called as part of an update, really display the cursor.
1113 This will also set the cursor position of W. */
1114 if (updated_window == NULL)
dc6f92b8
JB
1115 {
1116 BLOCK_INPUT;
06a2c219 1117 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1118 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1119 UNBLOCK_INPUT;
1120 }
1121}
dc43ef94 1122
06a2c219
GM
1123
1124\f
1125/***********************************************************************
1126 Display Iterator
1127 ***********************************************************************/
1128
1129/* Function prototypes of this page. */
1130
1131static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1132 struct glyph *,
ee569018
KH
1133 XChar2b *,
1134 int *));
06a2c219
GM
1135static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1136 int, XChar2b *, int));
1137static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1138static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1139static void x_append_glyph P_ ((struct it *));
b4192550 1140static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1141static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1142 int, int, double));
1143static void x_produce_glyphs P_ ((struct it *));
06a2c219 1144static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1145
1146
1147/* Return a pointer to per-char metric information in FONT of a
1148 character pointed by B which is a pointer to an XChar2b. */
1149
1150#define PER_CHAR_METRIC(font, b) \
1151 ((font)->per_char \
1152 ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
1153 + (((font)->min_byte1 || (font)->max_byte1) \
1154 ? (((b)->byte1 - (font)->min_byte1) \
1155 * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
1156 : 0)) \
1157 : &((font)->max_bounds))
dc43ef94 1158
dc6f92b8 1159
e2ef8ee6
GM
1160/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1161 is not contained in the font. */
dc43ef94 1162
06a2c219 1163static INLINE XCharStruct *
ee569018 1164x_per_char_metric (font, char2b)
06a2c219
GM
1165 XFontStruct *font;
1166 XChar2b *char2b;
1167{
1168 /* The result metric information. */
1169 XCharStruct *pcm = NULL;
dc6f92b8 1170
06a2c219 1171 xassert (font && char2b);
dc6f92b8 1172
06a2c219 1173 if (font->per_char != NULL)
dc6f92b8 1174 {
06a2c219 1175 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1176 {
06a2c219
GM
1177 /* min_char_or_byte2 specifies the linear character index
1178 corresponding to the first element of the per_char array,
1179 max_char_or_byte2 is the index of the last character. A
1180 character with non-zero CHAR2B->byte1 is not in the font.
1181 A character with byte2 less than min_char_or_byte2 or
1182 greater max_char_or_byte2 is not in the font. */
1183 if (char2b->byte1 == 0
1184 && char2b->byte2 >= font->min_char_or_byte2
1185 && char2b->byte2 <= font->max_char_or_byte2)
1186 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1187 }
06a2c219 1188 else
dc6f92b8 1189 {
06a2c219
GM
1190 /* If either min_byte1 or max_byte1 are nonzero, both
1191 min_char_or_byte2 and max_char_or_byte2 are less than
1192 256, and the 2-byte character index values corresponding
1193 to the per_char array element N (counting from 0) are:
1194
1195 byte1 = N/D + min_byte1
1196 byte2 = N\D + min_char_or_byte2
1197
1198 where:
1199
1200 D = max_char_or_byte2 - min_char_or_byte2 + 1
1201 / = integer division
1202 \ = integer modulus */
1203 if (char2b->byte1 >= font->min_byte1
1204 && char2b->byte1 <= font->max_byte1
1205 && char2b->byte2 >= font->min_char_or_byte2
1206 && char2b->byte2 <= font->max_char_or_byte2)
1207 {
1208 pcm = (font->per_char
1209 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1210 * (char2b->byte1 - font->min_byte1))
1211 + (char2b->byte2 - font->min_char_or_byte2));
1212 }
dc6f92b8 1213 }
06a2c219
GM
1214 }
1215 else
1216 {
1217 /* If the per_char pointer is null, all glyphs between the first
1218 and last character indexes inclusive have the same
1219 information, as given by both min_bounds and max_bounds. */
1220 if (char2b->byte2 >= font->min_char_or_byte2
1221 && char2b->byte2 <= font->max_char_or_byte2)
1222 pcm = &font->max_bounds;
1223 }
dc6f92b8 1224
ee569018 1225 return ((pcm == NULL
3e71d8f2 1226 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1227 ? NULL : pcm);
06a2c219 1228}
b73b6aaf 1229
57b03282 1230
06a2c219
GM
1231/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1232 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1233
06a2c219
GM
1234static INLINE void
1235x_encode_char (c, char2b, font_info)
1236 int c;
1237 XChar2b *char2b;
1238 struct font_info *font_info;
1239{
1240 int charset = CHAR_CHARSET (c);
1241 XFontStruct *font = font_info->font;
1242
1243 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1244 This may be either a program in a special encoder language or a
1245 fixed encoding. */
1246 if (font_info->font_encoder)
1247 {
1248 /* It's a program. */
1249 struct ccl_program *ccl = font_info->font_encoder;
1250
1251 if (CHARSET_DIMENSION (charset) == 1)
1252 {
1253 ccl->reg[0] = charset;
1254 ccl->reg[1] = char2b->byte2;
1255 }
1256 else
1257 {
1258 ccl->reg[0] = charset;
1259 ccl->reg[1] = char2b->byte1;
1260 ccl->reg[2] = char2b->byte2;
1261 }
1262
1263 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1264
1265 /* We assume that MSBs are appropriately set/reset by CCL
1266 program. */
1267 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1268 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1269 else
1270 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1271 }
1272 else if (font_info->encoding[charset])
1273 {
1274 /* Fixed encoding scheme. See fontset.h for the meaning of the
1275 encoding numbers. */
1276 int enc = font_info->encoding[charset];
1277
1278 if ((enc == 1 || enc == 2)
1279 && CHARSET_DIMENSION (charset) == 2)
1280 char2b->byte1 |= 0x80;
1281
1282 if (enc == 1 || enc == 3)
1283 char2b->byte2 |= 0x80;
1284 }
1285}
1286
1287
1288/* Get face and two-byte form of character C in face FACE_ID on frame
1289 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1290 means we want to display multibyte text. Value is a pointer to a
1291 realized face that is ready for display. */
1292
1293static INLINE struct face *
1294x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1295 struct frame *f;
1296 int c, face_id;
1297 XChar2b *char2b;
1298 int multibyte_p;
1299{
1300 struct face *face = FACE_FROM_ID (f, face_id);
1301
1302 if (!multibyte_p)
1303 {
1304 /* Unibyte case. We don't have to encode, but we have to make
1305 sure to use a face suitable for unibyte. */
1306 char2b->byte1 = 0;
1307 char2b->byte2 = c;
ee569018
KH
1308 face_id = FACE_FOR_CHAR (f, face, c);
1309 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1310 }
1311 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1312 {
1313 /* Case of ASCII in a face known to fit ASCII. */
1314 char2b->byte1 = 0;
1315 char2b->byte2 = c;
1316 }
1317 else
1318 {
1319 int c1, c2, charset;
1320
1321 /* Split characters into bytes. If c2 is -1 afterwards, C is
1322 really a one-byte character so that byte1 is zero. */
1323 SPLIT_CHAR (c, charset, c1, c2);
1324 if (c2 > 0)
1325 char2b->byte1 = c1, char2b->byte2 = c2;
1326 else
1327 char2b->byte1 = 0, char2b->byte2 = c1;
1328
06a2c219 1329 /* Maybe encode the character in *CHAR2B. */
ee569018 1330 if (face->font != NULL)
06a2c219
GM
1331 {
1332 struct font_info *font_info
1333 = FONT_INFO_FROM_ID (f, face->font_info_id);
1334 if (font_info)
ee569018 1335 x_encode_char (c, char2b, font_info);
06a2c219
GM
1336 }
1337 }
1338
1339 /* Make sure X resources of the face are allocated. */
1340 xassert (face != NULL);
1341 PREPARE_FACE_FOR_DISPLAY (f, face);
1342
1343 return face;
1344}
1345
1346
1347/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1348 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1349 a pointer to a realized face that is ready for display. */
1350
1351static INLINE struct face *
ee569018 1352x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1353 struct frame *f;
1354 struct glyph *glyph;
1355 XChar2b *char2b;
ee569018 1356 int *two_byte_p;
06a2c219
GM
1357{
1358 struct face *face;
1359
1360 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1361 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1362
ee569018
KH
1363 if (two_byte_p)
1364 *two_byte_p = 0;
1365
06a2c219
GM
1366 if (!glyph->multibyte_p)
1367 {
1368 /* Unibyte case. We don't have to encode, but we have to make
1369 sure to use a face suitable for unibyte. */
1370 char2b->byte1 = 0;
43d120d8 1371 char2b->byte2 = glyph->u.ch;
06a2c219 1372 }
43d120d8
KH
1373 else if (glyph->u.ch < 128
1374 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1375 {
1376 /* Case of ASCII in a face known to fit ASCII. */
1377 char2b->byte1 = 0;
43d120d8 1378 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1379 }
1380 else
1381 {
1382 int c1, c2, charset;
1383
1384 /* Split characters into bytes. If c2 is -1 afterwards, C is
1385 really a one-byte character so that byte1 is zero. */
43d120d8 1386 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1387 if (c2 > 0)
1388 char2b->byte1 = c1, char2b->byte2 = c2;
1389 else
1390 char2b->byte1 = 0, char2b->byte2 = c1;
1391
1392 /* Maybe encode the character in *CHAR2B. */
1393 if (charset != CHARSET_ASCII)
1394 {
1395 struct font_info *font_info
1396 = FONT_INFO_FROM_ID (f, face->font_info_id);
1397 if (font_info)
1398 {
43d120d8 1399 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1400 if (two_byte_p)
1401 *two_byte_p
1402 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1403 }
1404 }
1405 }
1406
1407 /* Make sure X resources of the face are allocated. */
1408 xassert (face != NULL);
1409 PREPARE_FACE_FOR_DISPLAY (f, face);
1410 return face;
1411}
1412
1413
1414/* Store one glyph for IT->char_to_display in IT->glyph_row.
1415 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1416
1417static INLINE void
1418x_append_glyph (it)
1419 struct it *it;
1420{
1421 struct glyph *glyph;
1422 enum glyph_row_area area = it->area;
1423
1424 xassert (it->glyph_row);
1425 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1426
1427 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1428 if (glyph < it->glyph_row->glyphs[area + 1])
1429 {
06a2c219
GM
1430 glyph->charpos = CHARPOS (it->position);
1431 glyph->object = it->object;
88d75730 1432 glyph->pixel_width = it->pixel_width;
06a2c219 1433 glyph->voffset = it->voffset;
88d75730 1434 glyph->type = CHAR_GLYPH;
06a2c219 1435 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1436 glyph->left_box_line_p = it->start_of_box_run_p;
1437 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1438 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1439 || it->phys_descent > it->descent);
88d75730 1440 glyph->padding_p = 0;
ee569018 1441 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1442 glyph->face_id = it->face_id;
1443 glyph->u.ch = it->char_to_display;
06a2c219
GM
1444 ++it->glyph_row->used[area];
1445 }
1446}
1447
b4192550
KH
1448/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1449 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1450
1451static INLINE void
1452x_append_composite_glyph (it)
1453 struct it *it;
1454{
1455 struct glyph *glyph;
1456 enum glyph_row_area area = it->area;
1457
1458 xassert (it->glyph_row);
1459
1460 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1461 if (glyph < it->glyph_row->glyphs[area + 1])
1462 {
b4192550
KH
1463 glyph->charpos = CHARPOS (it->position);
1464 glyph->object = it->object;
88d75730 1465 glyph->pixel_width = it->pixel_width;
b4192550 1466 glyph->voffset = it->voffset;
88d75730 1467 glyph->type = COMPOSITE_GLYPH;
b4192550 1468 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1469 glyph->left_box_line_p = it->start_of_box_run_p;
1470 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1471 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1472 || it->phys_descent > it->descent);
88d75730
GM
1473 glyph->padding_p = 0;
1474 glyph->glyph_not_available_p = 0;
1475 glyph->face_id = it->face_id;
1476 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1477 ++it->glyph_row->used[area];
1478 }
1479}
1480
06a2c219
GM
1481
1482/* Change IT->ascent and IT->height according to the setting of
1483 IT->voffset. */
1484
1485static INLINE void
1486take_vertical_position_into_account (it)
1487 struct it *it;
1488{
1489 if (it->voffset)
1490 {
1491 if (it->voffset < 0)
1492 /* Increase the ascent so that we can display the text higher
1493 in the line. */
1494 it->ascent += abs (it->voffset);
1495 else
1496 /* Increase the descent so that we can display the text lower
1497 in the line. */
1498 it->descent += it->voffset;
1499 }
1500}
1501
1502
1503/* Produce glyphs/get display metrics for the image IT is loaded with.
1504 See the description of struct display_iterator in dispextern.h for
1505 an overview of struct display_iterator. */
1506
1507static void
1508x_produce_image_glyph (it)
1509 struct it *it;
1510{
1511 struct image *img;
1512 struct face *face;
1513
1514 xassert (it->what == IT_IMAGE);
1515
1516 face = FACE_FROM_ID (it->f, it->face_id);
1517 img = IMAGE_FROM_ID (it->f, it->image_id);
1518 xassert (img);
1519
1520 /* Make sure X resources of the face and image are loaded. */
1521 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1522 prepare_image_for_display (it->f, img);
1523
95af8492 1524 it->ascent = it->phys_ascent = image_ascent (img, face);
66ac4b0e 1525 it->descent = it->phys_descent = img->height + 2 * img->margin - it->ascent;
06a2c219
GM
1526 it->pixel_width = img->width + 2 * img->margin;
1527
1528 it->nglyphs = 1;
1529
1530 if (face->box != FACE_NO_BOX)
1531 {
1532 it->ascent += face->box_line_width;
1533 it->descent += face->box_line_width;
1534
1535 if (it->start_of_box_run_p)
1536 it->pixel_width += face->box_line_width;
1537 if (it->end_of_box_run_p)
1538 it->pixel_width += face->box_line_width;
1539 }
1540
1541 take_vertical_position_into_account (it);
1542
1543 if (it->glyph_row)
1544 {
1545 struct glyph *glyph;
1546 enum glyph_row_area area = it->area;
1547
1548 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1549 if (glyph < it->glyph_row->glyphs[area + 1])
1550 {
06a2c219
GM
1551 glyph->charpos = CHARPOS (it->position);
1552 glyph->object = it->object;
88d75730 1553 glyph->pixel_width = it->pixel_width;
06a2c219 1554 glyph->voffset = it->voffset;
88d75730 1555 glyph->type = IMAGE_GLYPH;
06a2c219 1556 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1557 glyph->left_box_line_p = it->start_of_box_run_p;
1558 glyph->right_box_line_p = it->end_of_box_run_p;
1559 glyph->overlaps_vertically_p = 0;
1560 glyph->padding_p = 0;
1561 glyph->glyph_not_available_p = 0;
1562 glyph->face_id = it->face_id;
1563 glyph->u.img_id = img->id;
06a2c219
GM
1564 ++it->glyph_row->used[area];
1565 }
1566 }
1567}
1568
1569
1570/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1571 of the glyph, WIDTH and HEIGHT are the width and height of the
1572 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1573 ascent of the glyph (0 <= ASCENT <= 1). */
1574
1575static void
1576x_append_stretch_glyph (it, object, width, height, ascent)
1577 struct it *it;
1578 Lisp_Object object;
1579 int width, height;
1580 double ascent;
1581{
1582 struct glyph *glyph;
1583 enum glyph_row_area area = it->area;
1584
1585 xassert (ascent >= 0 && ascent <= 1);
1586
1587 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1588 if (glyph < it->glyph_row->glyphs[area + 1])
1589 {
06a2c219
GM
1590 glyph->charpos = CHARPOS (it->position);
1591 glyph->object = object;
88d75730 1592 glyph->pixel_width = width;
06a2c219 1593 glyph->voffset = it->voffset;
88d75730 1594 glyph->type = STRETCH_GLYPH;
06a2c219 1595 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1596 glyph->left_box_line_p = it->start_of_box_run_p;
1597 glyph->right_box_line_p = it->end_of_box_run_p;
1598 glyph->overlaps_vertically_p = 0;
1599 glyph->padding_p = 0;
1600 glyph->glyph_not_available_p = 0;
1601 glyph->face_id = it->face_id;
1602 glyph->u.stretch.ascent = height * ascent;
1603 glyph->u.stretch.height = height;
06a2c219
GM
1604 ++it->glyph_row->used[area];
1605 }
1606}
1607
1608
1609/* Produce a stretch glyph for iterator IT. IT->object is the value
1610 of the glyph property displayed. The value must be a list
1611 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1612 being recognized:
1613
1614 1. `:width WIDTH' specifies that the space should be WIDTH *
1615 canonical char width wide. WIDTH may be an integer or floating
1616 point number.
1617
1618 2. `:relative-width FACTOR' specifies that the width of the stretch
1619 should be computed from the width of the first character having the
1620 `glyph' property, and should be FACTOR times that width.
1621
1622 3. `:align-to HPOS' specifies that the space should be wide enough
1623 to reach HPOS, a value in canonical character units.
1624
1625 Exactly one of the above pairs must be present.
1626
1627 4. `:height HEIGHT' specifies that the height of the stretch produced
1628 should be HEIGHT, measured in canonical character units.
1629
1630 5. `:relative-height FACTOR' specifies that the height of the the
1631 stretch should be FACTOR times the height of the characters having
1632 the glyph property.
1633
1634 Either none or exactly one of 4 or 5 must be present.
1635
1636 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1637 of the stretch should be used for the ascent of the stretch.
1638 ASCENT must be in the range 0 <= ASCENT <= 100. */
1639
1640#define NUMVAL(X) \
1641 ((INTEGERP (X) || FLOATP (X)) \
1642 ? XFLOATINT (X) \
1643 : - 1)
1644
1645
1646static void
1647x_produce_stretch_glyph (it)
1648 struct it *it;
1649{
1650 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1651#if GLYPH_DEBUG
1652 extern Lisp_Object Qspace;
1653#endif
1654 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1655 extern Lisp_Object QCrelative_width, QCrelative_height;
1656 extern Lisp_Object QCalign_to;
1657 Lisp_Object prop, plist;
1658 double width = 0, height = 0, ascent = 0;
1659 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1660 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1661
1662 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1663
1664 /* List should start with `space'. */
1665 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1666 plist = XCDR (it->object);
1667
1668 /* Compute the width of the stretch. */
1669 if (prop = Fplist_get (plist, QCwidth),
1670 NUMVAL (prop) > 0)
1671 /* Absolute width `:width WIDTH' specified and valid. */
1672 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1673 else if (prop = Fplist_get (plist, QCrelative_width),
1674 NUMVAL (prop) > 0)
1675 {
1676 /* Relative width `:relative-width FACTOR' specified and valid.
1677 Compute the width of the characters having the `glyph'
1678 property. */
1679 struct it it2;
1680 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1681
1682 it2 = *it;
1683 if (it->multibyte_p)
1684 {
1685 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1686 - IT_BYTEPOS (*it));
1687 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1688 }
1689 else
1690 it2.c = *p, it2.len = 1;
1691
1692 it2.glyph_row = NULL;
1693 it2.what = IT_CHARACTER;
1694 x_produce_glyphs (&it2);
1695 width = NUMVAL (prop) * it2.pixel_width;
1696 }
1697 else if (prop = Fplist_get (plist, QCalign_to),
1698 NUMVAL (prop) > 0)
1699 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1700 else
1701 /* Nothing specified -> width defaults to canonical char width. */
1702 width = CANON_X_UNIT (it->f);
1703
1704 /* Compute height. */
1705 if (prop = Fplist_get (plist, QCheight),
1706 NUMVAL (prop) > 0)
1707 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1708 else if (prop = Fplist_get (plist, QCrelative_height),
1709 NUMVAL (prop) > 0)
1710 height = FONT_HEIGHT (font) * NUMVAL (prop);
1711 else
1712 height = FONT_HEIGHT (font);
1713
1714 /* Compute percentage of height used for ascent. If
1715 `:ascent ASCENT' is present and valid, use that. Otherwise,
1716 derive the ascent from the font in use. */
1717 if (prop = Fplist_get (plist, QCascent),
1718 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1719 ascent = NUMVAL (prop) / 100.0;
1720 else
1721 ascent = (double) font->ascent / FONT_HEIGHT (font);
1722
1723 if (width <= 0)
1724 width = 1;
1725 if (height <= 0)
1726 height = 1;
1727
1728 if (it->glyph_row)
1729 {
1730 Lisp_Object object = it->stack[it->sp - 1].string;
1731 if (!STRINGP (object))
1732 object = it->w->buffer;
1733 x_append_stretch_glyph (it, object, width, height, ascent);
1734 }
1735
1736 it->pixel_width = width;
66ac4b0e
GM
1737 it->ascent = it->phys_ascent = height * ascent;
1738 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1739 it->nglyphs = 1;
1740
1741 if (face->box != FACE_NO_BOX)
1742 {
1743 it->ascent += face->box_line_width;
1744 it->descent += face->box_line_width;
1745
1746 if (it->start_of_box_run_p)
1747 it->pixel_width += face->box_line_width;
1748 if (it->end_of_box_run_p)
1749 it->pixel_width += face->box_line_width;
1750 }
1751
1752 take_vertical_position_into_account (it);
1753}
1754
b4192550
KH
1755/* Return proper value to be used as baseline offset of font that has
1756 ASCENT and DESCENT to draw characters by the font at the vertical
1757 center of the line of frame F.
1758
1759 Here, out task is to find the value of BOFF in the following figure;
1760
1761 -------------------------+-----------+-
1762 -+-+---------+-+ | |
1763 | | | | | |
1764 | | | | F_ASCENT F_HEIGHT
1765 | | | ASCENT | |
1766 HEIGHT | | | | |
1767 | | |-|-+------+-----------|------- baseline
1768 | | | | BOFF | |
1769 | |---------|-+-+ | |
1770 | | | DESCENT | |
1771 -+-+---------+-+ F_DESCENT |
1772 -------------------------+-----------+-
1773
1774 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1775 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1776 DESCENT = FONT->descent
1777 HEIGHT = FONT_HEIGHT (FONT)
1778 F_DESCENT = (F->output_data.x->font->descent
1779 - F->output_data.x->baseline_offset)
1780 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1781*/
1782
1783#define VCENTER_BASELINE_OFFSET(FONT, F) \
1784 ((FONT)->descent \
1785 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT))) / 2 \
1786 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1787
1788/* Produce glyphs/get display metrics for the display element IT is
1789 loaded with. See the description of struct display_iterator in
1790 dispextern.h for an overview of struct display_iterator. */
1791
1792static void
1793x_produce_glyphs (it)
1794 struct it *it;
1795{
ee569018
KH
1796 it->glyph_not_available_p = 0;
1797
06a2c219
GM
1798 if (it->what == IT_CHARACTER)
1799 {
1800 XChar2b char2b;
1801 XFontStruct *font;
ee569018 1802 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1803 XCharStruct *pcm;
06a2c219 1804 int font_not_found_p;
b4192550
KH
1805 struct font_info *font_info;
1806 int boff; /* baseline offset */
06a2c219 1807
ee569018
KH
1808 /* Maybe translate single-byte characters to multibyte, or the
1809 other way. */
06a2c219 1810 it->char_to_display = it->c;
ee569018 1811 if (!ASCII_BYTE_P (it->c))
06a2c219 1812 {
ee569018
KH
1813 if (unibyte_display_via_language_environment
1814 && SINGLE_BYTE_CHAR_P (it->c)
1815 && (it->c >= 0240
1816 || !NILP (Vnonascii_translation_table)))
1817 {
1818 it->char_to_display = unibyte_char_to_multibyte (it->c);
1819 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1820 face = FACE_FROM_ID (it->f, it->face_id);
1821 }
1822 else if (!SINGLE_BYTE_CHAR_P (it->c)
1823 && !it->multibyte_p)
1824 {
1825 it->char_to_display = multibyte_char_to_unibyte (it->c, Qnil);
1826 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1827 face = FACE_FROM_ID (it->f, it->face_id);
1828 }
06a2c219
GM
1829 }
1830
ee569018
KH
1831 /* Get font to use. Encode IT->char_to_display. */
1832 x_get_char_face_and_encoding (it->f, it->char_to_display,
1833 it->face_id, &char2b,
1834 it->multibyte_p);
06a2c219
GM
1835 font = face->font;
1836
1837 /* When no suitable font found, use the default font. */
1838 font_not_found_p = font == NULL;
1839 if (font_not_found_p)
b4192550
KH
1840 {
1841 font = FRAME_FONT (it->f);
1842 boff = it->f->output_data.x->baseline_offset;
1843 font_info = NULL;
1844 }
1845 else
1846 {
1847 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1848 boff = font_info->baseline_offset;
1849 if (font_info->vertical_centering)
1850 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1851 }
06a2c219
GM
1852
1853 if (it->char_to_display >= ' '
1854 && (!it->multibyte_p || it->char_to_display < 128))
1855 {
1856 /* Either unibyte or ASCII. */
1857 int stretched_p;
1858
1859 it->nglyphs = 1;
06a2c219
GM
1860
1861 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1862 it->ascent = font->ascent + boff;
1863 it->descent = font->descent - boff;
474848ac
GM
1864
1865 if (pcm)
1866 {
1867 it->phys_ascent = pcm->ascent + boff;
1868 it->phys_descent = pcm->descent - boff;
1869 it->pixel_width = pcm->width;
1870 }
1871 else
1872 {
1873 it->glyph_not_available_p = 1;
1874 it->phys_ascent = font->ascent + boff;
1875 it->phys_descent = font->descent - boff;
1876 it->pixel_width = FONT_WIDTH (font);
1877 }
06a2c219
GM
1878
1879 /* If this is a space inside a region of text with
1880 `space-width' property, change its width. */
1881 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1882 if (stretched_p)
1883 it->pixel_width *= XFLOATINT (it->space_width);
1884
1885 /* If face has a box, add the box thickness to the character
1886 height. If character has a box line to the left and/or
1887 right, add the box line width to the character's width. */
1888 if (face->box != FACE_NO_BOX)
1889 {
1890 int thick = face->box_line_width;
1891
1892 it->ascent += thick;
1893 it->descent += thick;
1894
1895 if (it->start_of_box_run_p)
1896 it->pixel_width += thick;
1897 if (it->end_of_box_run_p)
1898 it->pixel_width += thick;
1899 }
1900
1901 /* If face has an overline, add the height of the overline
1902 (1 pixel) and a 1 pixel margin to the character height. */
1903 if (face->overline_p)
1904 it->ascent += 2;
1905
1906 take_vertical_position_into_account (it);
1907
1908 /* If we have to actually produce glyphs, do it. */
1909 if (it->glyph_row)
1910 {
1911 if (stretched_p)
1912 {
1913 /* Translate a space with a `space-width' property
1914 into a stretch glyph. */
1915 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1916 x_append_stretch_glyph (it, it->object, it->pixel_width,
1917 it->ascent + it->descent, ascent);
1918 }
1919 else
1920 x_append_glyph (it);
1921
1922 /* If characters with lbearing or rbearing are displayed
1923 in this line, record that fact in a flag of the
1924 glyph row. This is used to optimize X output code. */
1c7e22fd 1925 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1926 it->glyph_row->contains_overlapping_glyphs_p = 1;
1927 }
1928 }
1929 else if (it->char_to_display == '\n')
1930 {
1931 /* A newline has no width but we need the height of the line. */
1932 it->pixel_width = 0;
1933 it->nglyphs = 0;
b4192550
KH
1934 it->ascent = it->phys_ascent = font->ascent + boff;
1935 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1936
1937 if (face->box != FACE_NO_BOX)
1938 {
1939 int thick = face->box_line_width;
1940 it->ascent += thick;
1941 it->descent += thick;
1942 }
1943 }
1944 else if (it->char_to_display == '\t')
1945 {
1946 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1947 int x = it->current_x + it->continuation_lines_width;
06a2c219
GM
1948 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
1949
1950 it->pixel_width = next_tab_x - x;
1951 it->nglyphs = 1;
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 (it->glyph_row)
1956 {
1957 double ascent = (double) it->ascent / (it->ascent + it->descent);
1958 x_append_stretch_glyph (it, it->object, it->pixel_width,
1959 it->ascent + it->descent, ascent);
1960 }
1961 }
1962 else
1963 {
1964 /* A multi-byte character. Assume that the display width of the
1965 character is the width of the character multiplied by the
b4192550 1966 width of the font. */
06a2c219 1967
b4192550
KH
1968 /* If we found a font, this font should give us the right
1969 metrics. If we didn't find a font, use the frame's
1970 default font and calculate the width of the character
1971 from the charset width; this is what old redisplay code
1972 did. */
1973 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1974 if (font_not_found_p || !pcm)
1975 {
1976 int charset = CHAR_CHARSET (it->char_to_display);
1977
1978 it->glyph_not_available_p = 1;
1979 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
1980 * CHARSET_WIDTH (charset));
1981 it->phys_ascent = font->ascent + boff;
1982 it->phys_descent = font->descent - boff;
1983 }
1984 else
1985 {
1986 it->pixel_width = pcm->width;
1987 it->phys_ascent = pcm->ascent + boff;
1988 it->phys_descent = pcm->descent - boff;
1989 if (it->glyph_row
1990 && (pcm->lbearing < 0
1991 || pcm->rbearing > pcm->width))
1992 it->glyph_row->contains_overlapping_glyphs_p = 1;
1993 }
b4192550
KH
1994 it->nglyphs = 1;
1995 it->ascent = font->ascent + boff;
1996 it->descent = font->descent - boff;
06a2c219
GM
1997 if (face->box != FACE_NO_BOX)
1998 {
1999 int thick = face->box_line_width;
2000 it->ascent += thick;
2001 it->descent += thick;
2002
2003 if (it->start_of_box_run_p)
2004 it->pixel_width += thick;
2005 if (it->end_of_box_run_p)
2006 it->pixel_width += thick;
2007 }
2008
2009 /* If face has an overline, add the height of the overline
2010 (1 pixel) and a 1 pixel margin to the character height. */
2011 if (face->overline_p)
2012 it->ascent += 2;
2013
2014 take_vertical_position_into_account (it);
2015
2016 if (it->glyph_row)
2017 x_append_glyph (it);
2018 }
2019 }
b4192550
KH
2020 else if (it->what == IT_COMPOSITION)
2021 {
2022 /* Note: A composition is represented as one glyph in the
2023 glyph matrix. There are no padding glyphs. */
2024 XChar2b char2b;
2025 XFontStruct *font;
ee569018 2026 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2027 XCharStruct *pcm;
2028 int font_not_found_p;
2029 struct font_info *font_info;
2030 int boff; /* baseline offset */
2031 struct composition *cmp = composition_table[it->cmp_id];
2032
2033 /* Maybe translate single-byte characters to multibyte. */
2034 it->char_to_display = it->c;
2035 if (unibyte_display_via_language_environment
2036 && SINGLE_BYTE_CHAR_P (it->c)
2037 && (it->c >= 0240
2038 || (it->c >= 0200
2039 && !NILP (Vnonascii_translation_table))))
2040 {
2041 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2042 }
2043
2044 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2045 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2046 face = FACE_FROM_ID (it->f, it->face_id);
2047 x_get_char_face_and_encoding (it->f, it->char_to_display,
2048 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2049 font = face->font;
2050
2051 /* When no suitable font found, use the default font. */
2052 font_not_found_p = font == NULL;
2053 if (font_not_found_p)
2054 {
2055 font = FRAME_FONT (it->f);
2056 boff = it->f->output_data.x->baseline_offset;
2057 font_info = NULL;
2058 }
2059 else
2060 {
2061 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2062 boff = font_info->baseline_offset;
2063 if (font_info->vertical_centering)
2064 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2065 }
2066
2067 /* There are no padding glyphs, so there is only one glyph to
2068 produce for the composition. Important is that pixel_width,
2069 ascent and descent are the values of what is drawn by
2070 draw_glyphs (i.e. the values of the overall glyphs composed). */
2071 it->nglyphs = 1;
2072
2073 /* If we have not yet calculated pixel size data of glyphs of
2074 the composition for the current face font, calculate them
2075 now. Theoretically, we have to check all fonts for the
2076 glyphs, but that requires much time and memory space. So,
2077 here we check only the font of the first glyph. This leads
2078 to incorrect display very rarely, and C-l (recenter) can
2079 correct the display anyway. */
2080 if (cmp->font != (void *) font)
2081 {
2082 /* Ascent and descent of the font of the first character of
2083 this composition (adjusted by baseline offset). Ascent
2084 and descent of overall glyphs should not be less than
2085 them respectively. */
2086 int font_ascent = font->ascent + boff;
2087 int font_descent = font->descent - boff;
2088 /* Bounding box of the overall glyphs. */
2089 int leftmost, rightmost, lowest, highest;
329bed06 2090 int i, width, ascent, descent;
b4192550
KH
2091
2092 cmp->font = (void *) font;
2093
2094 /* Initialize the bounding box. */
2095 pcm = x_per_char_metric (font, &char2b);
329bed06
GM
2096 if (pcm)
2097 {
2098 width = pcm->width;
2099 ascent = pcm->ascent;
2100 descent = pcm->descent;
2101 }
2102 else
2103 {
2104 width = FONT_WIDTH (font);
2105 ascent = font->ascent;
2106 descent = font->descent;
2107 }
2108
2109 rightmost = width;
2110 lowest = - descent + boff;
2111 highest = ascent + boff;
b4192550 2112 leftmost = 0;
329bed06 2113
b4192550
KH
2114 if (font_info
2115 && font_info->default_ascent
2116 && CHAR_TABLE_P (Vuse_default_ascent)
2117 && !NILP (Faref (Vuse_default_ascent,
2118 make_number (it->char_to_display))))
2119 highest = font_info->default_ascent + boff;
2120
2121 /* Draw the first glyph at the normal position. It may be
2122 shifted to right later if some other glyphs are drawn at
2123 the left. */
2124 cmp->offsets[0] = 0;
2125 cmp->offsets[1] = boff;
2126
2127 /* Set cmp->offsets for the remaining glyphs. */
2128 for (i = 1; i < cmp->glyph_len; i++)
2129 {
2130 int left, right, btm, top;
2131 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2132 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2133
2134 face = FACE_FROM_ID (it->f, face_id);
2135 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2136 it->multibyte_p);
b4192550
KH
2137 font = face->font;
2138 if (font == NULL)
2139 {
2140 font = FRAME_FONT (it->f);
2141 boff = it->f->output_data.x->baseline_offset;
2142 font_info = NULL;
2143 }
2144 else
2145 {
2146 font_info
2147 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2148 boff = font_info->baseline_offset;
2149 if (font_info->vertical_centering)
2150 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2151 }
2152
2153 pcm = x_per_char_metric (font, &char2b);
329bed06
GM
2154 if (pcm)
2155 {
2156 width = pcm->width;
2157 ascent = pcm->ascent;
2158 descent = pcm->descent;
2159 }
2160 else
2161 {
2162 width = FONT_WIDTH (font);
2163 ascent = font->ascent;
2164 descent = font->descent;
2165 }
b4192550
KH
2166
2167 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2168 {
2169 /* Relative composition with or without
2170 alternate chars. */
329bed06
GM
2171 left = (leftmost + rightmost - width) / 2;
2172 btm = - descent + boff;
b4192550
KH
2173 if (font_info && font_info->relative_compose
2174 && (! CHAR_TABLE_P (Vignore_relative_composition)
2175 || NILP (Faref (Vignore_relative_composition,
2176 make_number (ch)))))
2177 {
2178
329bed06 2179 if (- descent >= font_info->relative_compose)
b4192550
KH
2180 /* One extra pixel between two glyphs. */
2181 btm = highest + 1;
329bed06 2182 else if (ascent <= 0)
b4192550 2183 /* One extra pixel between two glyphs. */
329bed06 2184 btm = lowest - 1 - ascent - descent;
b4192550
KH
2185 }
2186 }
2187 else
2188 {
2189 /* A composition rule is specified by an integer
2190 value that encodes global and new reference
2191 points (GREF and NREF). GREF and NREF are
2192 specified by numbers as below:
2193
2194 0---1---2 -- ascent
2195 | |
2196 | |
2197 | |
2198 9--10--11 -- center
2199 | |
2200 ---3---4---5--- baseline
2201 | |
2202 6---7---8 -- descent
2203 */
2204 int rule = COMPOSITION_RULE (cmp, i);
2205 int gref, nref, grefx, grefy, nrefx, nrefy;
2206
2207 COMPOSITION_DECODE_RULE (rule, gref, nref);
2208 grefx = gref % 3, nrefx = nref % 3;
2209 grefy = gref / 3, nrefy = nref / 3;
2210
2211 left = (leftmost
2212 + grefx * (rightmost - leftmost) / 2
329bed06 2213 - nrefx * width / 2);
b4192550
KH
2214 btm = ((grefy == 0 ? highest
2215 : grefy == 1 ? 0
2216 : grefy == 2 ? lowest
2217 : (highest + lowest) / 2)
329bed06
GM
2218 - (nrefy == 0 ? ascent + descent
2219 : nrefy == 1 ? descent - boff
b4192550 2220 : nrefy == 2 ? 0
329bed06 2221 : (ascent + descent) / 2));
b4192550
KH
2222 }
2223
2224 cmp->offsets[i * 2] = left;
329bed06 2225 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2226
2227 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2228 right = left + width;
2229 top = btm + descent + ascent;
b4192550
KH
2230 if (left < leftmost)
2231 leftmost = left;
2232 if (right > rightmost)
2233 rightmost = right;
2234 if (top > highest)
2235 highest = top;
2236 if (btm < lowest)
2237 lowest = btm;
2238 }
2239
2240 /* If there are glyphs whose x-offsets are negative,
2241 shift all glyphs to the right and make all x-offsets
2242 non-negative. */
2243 if (leftmost < 0)
2244 {
2245 for (i = 0; i < cmp->glyph_len; i++)
2246 cmp->offsets[i * 2] -= leftmost;
2247 rightmost -= leftmost;
2248 }
2249
2250 cmp->pixel_width = rightmost;
2251 cmp->ascent = highest;
2252 cmp->descent = - lowest;
2253 if (cmp->ascent < font_ascent)
2254 cmp->ascent = font_ascent;
2255 if (cmp->descent < font_descent)
2256 cmp->descent = font_descent;
2257 }
2258
2259 it->pixel_width = cmp->pixel_width;
2260 it->ascent = it->phys_ascent = cmp->ascent;
2261 it->descent = it->phys_descent = cmp->descent;
2262
2263 if (face->box != FACE_NO_BOX)
2264 {
2265 int thick = face->box_line_width;
2266 it->ascent += thick;
2267 it->descent += thick;
2268
2269 if (it->start_of_box_run_p)
2270 it->pixel_width += thick;
2271 if (it->end_of_box_run_p)
2272 it->pixel_width += thick;
2273 }
2274
2275 /* If face has an overline, add the height of the overline
2276 (1 pixel) and a 1 pixel margin to the character height. */
2277 if (face->overline_p)
2278 it->ascent += 2;
2279
2280 take_vertical_position_into_account (it);
2281
2282 if (it->glyph_row)
2283 x_append_composite_glyph (it);
2284 }
06a2c219
GM
2285 else if (it->what == IT_IMAGE)
2286 x_produce_image_glyph (it);
2287 else if (it->what == IT_STRETCH)
2288 x_produce_stretch_glyph (it);
2289
3017fdd1
GM
2290 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2291 because this isn't true for images with `:ascent 100'. */
2292 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2293 if (it->area == TEXT_AREA)
2294 it->current_x += it->pixel_width;
66ac4b0e 2295
d365f5bb
GM
2296 it->descent += it->extra_line_spacing;
2297
06a2c219
GM
2298 it->max_ascent = max (it->max_ascent, it->ascent);
2299 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2300 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2301 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2302}
2303
2304
2305/* Estimate the pixel height of the mode or top line on frame F.
2306 FACE_ID specifies what line's height to estimate. */
2307
2308int
2309x_estimate_mode_line_height (f, face_id)
2310 struct frame *f;
2311 enum face_id face_id;
2312{
2313 int height = 1;
2314
2315 /* This function is called so early when Emacs starts that the face
2316 cache and mode line face are not yet initialized. */
2317 if (FRAME_FACE_CACHE (f))
2318 {
2319 struct face *face = FACE_FROM_ID (f, face_id);
2320 if (face)
2321 height = FONT_HEIGHT (face->font) + 2 * face->box_line_width;
2322 }
2323
2324 return height;
2325}
2326
2327\f
2328/***********************************************************************
2329 Glyph display
2330 ***********************************************************************/
2331
2332/* A sequence of glyphs to be drawn in the same face.
2333
2334 This data structure is not really completely X specific, so it
2335 could possibly, at least partially, be useful for other systems. It
2336 is currently not part of the external redisplay interface because
2337 it's not clear what other systems will need. */
2338
2339struct glyph_string
2340{
2341 /* X-origin of the string. */
2342 int x;
2343
2344 /* Y-origin and y-position of the base line of this string. */
2345 int y, ybase;
2346
2347 /* The width of the string, not including a face extension. */
2348 int width;
2349
2350 /* The width of the string, including a face extension. */
2351 int background_width;
2352
2353 /* The height of this string. This is the height of the line this
2354 string is drawn in, and can be different from the height of the
2355 font the string is drawn in. */
2356 int height;
2357
2358 /* Number of pixels this string overwrites in front of its x-origin.
2359 This number is zero if the string has an lbearing >= 0; it is
2360 -lbearing, if the string has an lbearing < 0. */
2361 int left_overhang;
2362
2363 /* Number of pixels this string overwrites past its right-most
2364 nominal x-position, i.e. x + width. Zero if the string's
2365 rbearing is <= its nominal width, rbearing - width otherwise. */
2366 int right_overhang;
2367
2368 /* The frame on which the glyph string is drawn. */
2369 struct frame *f;
2370
2371 /* The window on which the glyph string is drawn. */
2372 struct window *w;
2373
2374 /* X display and window for convenience. */
2375 Display *display;
2376 Window window;
2377
2378 /* The glyph row for which this string was built. It determines the
2379 y-origin and height of the string. */
2380 struct glyph_row *row;
2381
2382 /* The area within row. */
2383 enum glyph_row_area area;
2384
2385 /* Characters to be drawn, and number of characters. */
2386 XChar2b *char2b;
2387 int nchars;
2388
06a2c219
GM
2389 /* A face-override for drawing cursors, mouse face and similar. */
2390 enum draw_glyphs_face hl;
2391
2392 /* Face in which this string is to be drawn. */
2393 struct face *face;
2394
2395 /* Font in which this string is to be drawn. */
2396 XFontStruct *font;
2397
2398 /* Font info for this string. */
2399 struct font_info *font_info;
2400
b4192550
KH
2401 /* Non-null means this string describes (part of) a composition.
2402 All characters from char2b are drawn composed. */
2403 struct composition *cmp;
06a2c219
GM
2404
2405 /* Index of this glyph string's first character in the glyph
b4192550
KH
2406 definition of CMP. If this is zero, this glyph string describes
2407 the first character of a composition. */
06a2c219
GM
2408 int gidx;
2409
2410 /* 1 means this glyph strings face has to be drawn to the right end
2411 of the window's drawing area. */
2412 unsigned extends_to_end_of_line_p : 1;
2413
2414 /* 1 means the background of this string has been drawn. */
2415 unsigned background_filled_p : 1;
2416
2417 /* 1 means glyph string must be drawn with 16-bit functions. */
2418 unsigned two_byte_p : 1;
2419
2420 /* 1 means that the original font determined for drawing this glyph
2421 string could not be loaded. The member `font' has been set to
2422 the frame's default font in this case. */
2423 unsigned font_not_found_p : 1;
2424
2425 /* 1 means that the face in which this glyph string is drawn has a
2426 stipple pattern. */
2427 unsigned stippled_p : 1;
2428
66ac4b0e
GM
2429 /* 1 means only the foreground of this glyph string must be drawn,
2430 and we should use the physical height of the line this glyph
2431 string appears in as clip rect. */
2432 unsigned for_overlaps_p : 1;
2433
06a2c219
GM
2434 /* The GC to use for drawing this glyph string. */
2435 GC gc;
2436
2437 /* A pointer to the first glyph in the string. This glyph
2438 corresponds to char2b[0]. Needed to draw rectangles if
2439 font_not_found_p is 1. */
2440 struct glyph *first_glyph;
2441
2442 /* Image, if any. */
2443 struct image *img;
2444
2445 struct glyph_string *next, *prev;
2446};
2447
2448
5c187dee 2449#if 0
06a2c219
GM
2450
2451static void
2452x_dump_glyph_string (s)
2453 struct glyph_string *s;
2454{
2455 fprintf (stderr, "glyph string\n");
2456 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2457 s->x, s->y, s->width, s->height);
2458 fprintf (stderr, " ybase = %d\n", s->ybase);
2459 fprintf (stderr, " hl = %d\n", s->hl);
2460 fprintf (stderr, " left overhang = %d, right = %d\n",
2461 s->left_overhang, s->right_overhang);
2462 fprintf (stderr, " nchars = %d\n", s->nchars);
2463 fprintf (stderr, " extends to end of line = %d\n",
2464 s->extends_to_end_of_line_p);
2465 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2466 fprintf (stderr, " bg width = %d\n", s->background_width);
2467}
2468
2469#endif /* GLYPH_DEBUG */
2470
2471
2472
2473static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2474 struct glyph_string **,
2475 struct glyph_string *,
2476 struct glyph_string *));
2477static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2478 struct glyph_string **,
2479 struct glyph_string *,
2480 struct glyph_string *));
2481static void x_append_glyph_string P_ ((struct glyph_string **,
2482 struct glyph_string **,
2483 struct glyph_string *));
2484static int x_left_overwritten P_ ((struct glyph_string *));
2485static int x_left_overwriting P_ ((struct glyph_string *));
2486static int x_right_overwritten P_ ((struct glyph_string *));
2487static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2488static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2489 int));
06a2c219
GM
2490static void x_init_glyph_string P_ ((struct glyph_string *,
2491 XChar2b *, struct window *,
2492 struct glyph_row *,
2493 enum glyph_row_area, int,
2494 enum draw_glyphs_face));
2495static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2496 enum glyph_row_area, int, int,
66ac4b0e 2497 enum draw_glyphs_face, int *, int *, int));
06a2c219
GM
2498static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2499static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2500static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2501 int));
2502static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2503static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2504static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2505static void x_draw_glyph_string P_ ((struct glyph_string *));
2506static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2507static void x_set_cursor_gc P_ ((struct glyph_string *));
2508static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2509static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2510static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2511 int *, int *));
2512static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2513static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2514 unsigned long *, double, int));
06a2c219 2515static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2516 double, int, unsigned long));
06a2c219
GM
2517static void x_setup_relief_colors P_ ((struct glyph_string *));
2518static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2519static void x_draw_image_relief P_ ((struct glyph_string *));
2520static void x_draw_image_foreground P_ ((struct glyph_string *));
2521static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2522static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2523static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2524 int, int, int));
2525static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2526 int, int, int, int, XRectangle *));
2527static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2528 int, int, int, XRectangle *));
66ac4b0e
GM
2529static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2530 enum glyph_row_area));
209f68d9
GM
2531static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2532 struct glyph_row *,
2533 enum glyph_row_area, int, int));
06a2c219 2534
163dcff3
GM
2535#if GLYPH_DEBUG
2536static void x_check_font P_ ((struct frame *, XFontStruct *));
2537#endif
2538
06a2c219 2539
06a2c219
GM
2540/* Append the list of glyph strings with head H and tail T to the list
2541 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2542
2543static INLINE void
2544x_append_glyph_string_lists (head, tail, h, t)
2545 struct glyph_string **head, **tail;
2546 struct glyph_string *h, *t;
2547{
2548 if (h)
2549 {
2550 if (*head)
2551 (*tail)->next = h;
2552 else
2553 *head = h;
2554 h->prev = *tail;
2555 *tail = t;
2556 }
2557}
2558
2559
2560/* Prepend the list of glyph strings with head H and tail T to the
2561 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2562 result. */
2563
2564static INLINE void
2565x_prepend_glyph_string_lists (head, tail, h, t)
2566 struct glyph_string **head, **tail;
2567 struct glyph_string *h, *t;
2568{
2569 if (h)
2570 {
2571 if (*head)
2572 (*head)->prev = t;
2573 else
2574 *tail = t;
2575 t->next = *head;
2576 *head = h;
2577 }
2578}
2579
2580
2581/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2582 Set *HEAD and *TAIL to the resulting list. */
2583
2584static INLINE void
2585x_append_glyph_string (head, tail, s)
2586 struct glyph_string **head, **tail;
2587 struct glyph_string *s;
2588{
2589 s->next = s->prev = NULL;
2590 x_append_glyph_string_lists (head, tail, s, s);
2591}
2592
2593
2594/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2595 face. */
2596
2597static void
2598x_set_cursor_gc (s)
2599 struct glyph_string *s;
2600{
2601 if (s->font == FRAME_FONT (s->f)
2602 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2603 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2604 && !s->cmp)
06a2c219
GM
2605 s->gc = s->f->output_data.x->cursor_gc;
2606 else
2607 {
2608 /* Cursor on non-default face: must merge. */
2609 XGCValues xgcv;
2610 unsigned long mask;
2611
2612 xgcv.background = s->f->output_data.x->cursor_pixel;
2613 xgcv.foreground = s->face->background;
2614
2615 /* If the glyph would be invisible, try a different foreground. */
2616 if (xgcv.foreground == xgcv.background)
2617 xgcv.foreground = s->face->foreground;
2618 if (xgcv.foreground == xgcv.background)
2619 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2620 if (xgcv.foreground == xgcv.background)
2621 xgcv.foreground = s->face->foreground;
2622
2623 /* Make sure the cursor is distinct from text in this face. */
2624 if (xgcv.background == s->face->background
2625 && xgcv.foreground == s->face->foreground)
2626 {
2627 xgcv.background = s->face->foreground;
2628 xgcv.foreground = s->face->background;
2629 }
2630
2631 IF_DEBUG (x_check_font (s->f, s->font));
2632 xgcv.font = s->font->fid;
2633 xgcv.graphics_exposures = False;
2634 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2635
2636 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2637 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2638 mask, &xgcv);
2639 else
2640 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2641 = XCreateGC (s->display, s->window, mask, &xgcv);
2642
2643 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2644 }
2645}
2646
2647
2648/* Set up S->gc of glyph string S for drawing text in mouse face. */
2649
2650static void
2651x_set_mouse_face_gc (s)
2652 struct glyph_string *s;
2653{
2654 int face_id;
ee569018 2655 struct face *face;
06a2c219
GM
2656
2657 /* What face has to be used for the mouse face? */
2658 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2659 face = FACE_FROM_ID (s->f, face_id);
033e3e18
GM
2660 if (s->first_glyph->type == CHAR_GLYPH)
2661 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2662 else
2663 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2664 s->face = FACE_FROM_ID (s->f, face_id);
2665 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2666
2667 /* If font in this face is same as S->font, use it. */
2668 if (s->font == s->face->font)
2669 s->gc = s->face->gc;
2670 else
2671 {
2672 /* Otherwise construct scratch_cursor_gc with values from FACE
2673 but font FONT. */
2674 XGCValues xgcv;
2675 unsigned long mask;
2676
2677 xgcv.background = s->face->background;
2678 xgcv.foreground = s->face->foreground;
2679 IF_DEBUG (x_check_font (s->f, s->font));
2680 xgcv.font = s->font->fid;
2681 xgcv.graphics_exposures = False;
2682 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2683
2684 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2685 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2686 mask, &xgcv);
2687 else
2688 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2689 = XCreateGC (s->display, s->window, mask, &xgcv);
2690
2691 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2692 }
2693
2694 xassert (s->gc != 0);
2695}
2696
2697
2698/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2699 Faces to use in the mode line have already been computed when the
2700 matrix was built, so there isn't much to do, here. */
2701
2702static INLINE void
2703x_set_mode_line_face_gc (s)
2704 struct glyph_string *s;
2705{
2706 s->gc = s->face->gc;
06a2c219
GM
2707}
2708
2709
2710/* Set S->gc of glyph string S for drawing that glyph string. Set
2711 S->stippled_p to a non-zero value if the face of S has a stipple
2712 pattern. */
2713
2714static INLINE void
2715x_set_glyph_string_gc (s)
2716 struct glyph_string *s;
2717{
209f68d9
GM
2718 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2719
06a2c219
GM
2720 if (s->hl == DRAW_NORMAL_TEXT)
2721 {
2722 s->gc = s->face->gc;
2723 s->stippled_p = s->face->stipple != 0;
2724 }
2725 else if (s->hl == DRAW_INVERSE_VIDEO)
2726 {
2727 x_set_mode_line_face_gc (s);
2728 s->stippled_p = s->face->stipple != 0;
2729 }
2730 else if (s->hl == DRAW_CURSOR)
2731 {
2732 x_set_cursor_gc (s);
2733 s->stippled_p = 0;
2734 }
2735 else if (s->hl == DRAW_MOUSE_FACE)
2736 {
2737 x_set_mouse_face_gc (s);
2738 s->stippled_p = s->face->stipple != 0;
2739 }
2740 else if (s->hl == DRAW_IMAGE_RAISED
2741 || s->hl == DRAW_IMAGE_SUNKEN)
2742 {
2743 s->gc = s->face->gc;
2744 s->stippled_p = s->face->stipple != 0;
2745 }
2746 else
2747 {
2748 s->gc = s->face->gc;
2749 s->stippled_p = s->face->stipple != 0;
2750 }
2751
2752 /* GC must have been set. */
2753 xassert (s->gc != 0);
2754}
2755
2756
2757/* Return in *R the clipping rectangle for glyph string S. */
2758
2759static void
2760x_get_glyph_string_clip_rect (s, r)
2761 struct glyph_string *s;
2762 XRectangle *r;
2763{
2764 if (s->row->full_width_p)
2765 {
2766 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2767 int canon_x = CANON_X_UNIT (s->f);
2768
2769 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2770 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2771
2772 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2773 {
1da3fd71 2774 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2775 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2776 r->x -= width;
2777 }
2778
b9432a85 2779 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2780
06a2c219
GM
2781 /* Unless displaying a mode or menu bar line, which are always
2782 fully visible, clip to the visible part of the row. */
2783 if (s->w->pseudo_window_p)
2784 r->height = s->row->visible_height;
2785 else
2786 r->height = s->height;
2787 }
2788 else
2789 {
2790 /* This is a text line that may be partially visible. */
2791 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2792 r->width = window_box_width (s->w, s->area);
2793 r->height = s->row->visible_height;
2794 }
2795
2796 /* Don't use S->y for clipping because it doesn't take partially
2797 visible lines into account. For example, it can be negative for
2798 partially visible lines at the top of a window. */
2799 if (!s->row->full_width_p
2800 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
045dee35 2801 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
06a2c219
GM
2802 else
2803 r->y = max (0, s->row->y);
06a2c219 2804
9ea173e8 2805 /* If drawing a tool-bar window, draw it over the internal border
06a2c219 2806 at the top of the window. */
9ea173e8 2807 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219 2808 r->y -= s->f->output_data.x->internal_border_width;
66ac4b0e
GM
2809
2810 /* If S draws overlapping rows, it's sufficient to use the top and
2811 bottom of the window for clipping because this glyph string
2812 intentionally draws over other lines. */
2813 if (s->for_overlaps_p)
2814 {
045dee35 2815 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2816 r->height = window_text_bottom_y (s->w) - r->y;
2817 }
2818
2819 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2820}
2821
2822
2823/* Set clipping for output of glyph string S. S may be part of a mode
2824 line or menu if we don't have X toolkit support. */
2825
2826static INLINE void
2827x_set_glyph_string_clipping (s)
2828 struct glyph_string *s;
2829{
2830 XRectangle r;
2831 x_get_glyph_string_clip_rect (s, &r);
2832 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2833}
2834
2835
2836/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2837 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2838
2839static INLINE void
2840x_compute_glyph_string_overhangs (s)
2841 struct glyph_string *s;
2842{
b4192550 2843 if (s->cmp == NULL
06a2c219
GM
2844 && s->first_glyph->type == CHAR_GLYPH)
2845 {
2846 XCharStruct cs;
2847 int direction, font_ascent, font_descent;
2848 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2849 &font_ascent, &font_descent, &cs);
2850 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2851 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2852 }
2853}
2854
2855
2856/* Compute overhangs and x-positions for glyph string S and its
2857 predecessors, or successors. X is the starting x-position for S.
2858 BACKWARD_P non-zero means process predecessors. */
2859
2860static void
2861x_compute_overhangs_and_x (s, x, backward_p)
2862 struct glyph_string *s;
2863 int x;
2864 int backward_p;
2865{
2866 if (backward_p)
2867 {
2868 while (s)
2869 {
2870 x_compute_glyph_string_overhangs (s);
2871 x -= s->width;
2872 s->x = x;
2873 s = s->prev;
2874 }
2875 }
2876 else
2877 {
2878 while (s)
2879 {
2880 x_compute_glyph_string_overhangs (s);
2881 s->x = x;
2882 x += s->width;
2883 s = s->next;
2884 }
2885 }
2886}
2887
2888
2889/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2890 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2891 assumed to be zero. */
06a2c219
GM
2892
2893static void
2894x_get_glyph_overhangs (glyph, f, left, right)
2895 struct glyph *glyph;
2896 struct frame *f;
2897 int *left, *right;
2898{
06a2c219
GM
2899 *left = *right = 0;
2900
b4192550 2901 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2902 {
2903 XFontStruct *font;
2904 struct face *face;
2905 struct font_info *font_info;
2906 XChar2b char2b;
ee569018
KH
2907 XCharStruct *pcm;
2908
2909 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2910 font = face->font;
2911 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2912 if (font
2913 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2914 {
06a2c219
GM
2915 if (pcm->rbearing > pcm->width)
2916 *right = pcm->rbearing - pcm->width;
2917 if (pcm->lbearing < 0)
2918 *left = -pcm->lbearing;
2919 }
2920 }
2921}
2922
2923
2924/* Return the index of the first glyph preceding glyph string S that
2925 is overwritten by S because of S's left overhang. Value is -1
2926 if no glyphs are overwritten. */
2927
2928static int
2929x_left_overwritten (s)
2930 struct glyph_string *s;
2931{
2932 int k;
2933
2934 if (s->left_overhang)
2935 {
2936 int x = 0, i;
2937 struct glyph *glyphs = s->row->glyphs[s->area];
2938 int first = s->first_glyph - glyphs;
2939
2940 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2941 x -= glyphs[i].pixel_width;
2942
2943 k = i + 1;
2944 }
2945 else
2946 k = -1;
2947
2948 return k;
2949}
2950
2951
2952/* Return the index of the first glyph preceding glyph string S that
2953 is overwriting S because of its right overhang. Value is -1 if no
2954 glyph in front of S overwrites S. */
2955
2956static int
2957x_left_overwriting (s)
2958 struct glyph_string *s;
2959{
2960 int i, k, x;
2961 struct glyph *glyphs = s->row->glyphs[s->area];
2962 int first = s->first_glyph - glyphs;
2963
2964 k = -1;
2965 x = 0;
2966 for (i = first - 1; i >= 0; --i)
2967 {
2968 int left, right;
2969 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2970 if (x + right > 0)
2971 k = i;
2972 x -= glyphs[i].pixel_width;
2973 }
2974
2975 return k;
2976}
2977
2978
2979/* Return the index of the last glyph following glyph string S that is
2980 not overwritten by S because of S's right overhang. Value is -1 if
2981 no such glyph is found. */
2982
2983static int
2984x_right_overwritten (s)
2985 struct glyph_string *s;
2986{
2987 int k = -1;
2988
2989 if (s->right_overhang)
2990 {
2991 int x = 0, i;
2992 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 2993 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
2994 int end = s->row->used[s->area];
2995
2996 for (i = first; i < end && s->right_overhang > x; ++i)
2997 x += glyphs[i].pixel_width;
2998
2999 k = i;
3000 }
3001
3002 return k;
3003}
3004
3005
3006/* Return the index of the last glyph following glyph string S that
3007 overwrites S because of its left overhang. Value is negative
3008 if no such glyph is found. */
3009
3010static int
3011x_right_overwriting (s)
3012 struct glyph_string *s;
3013{
3014 int i, k, x;
3015 int end = s->row->used[s->area];
3016 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3017 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3018
3019 k = -1;
3020 x = 0;
3021 for (i = first; i < end; ++i)
3022 {
3023 int left, right;
3024 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3025 if (x - left < 0)
3026 k = i;
3027 x += glyphs[i].pixel_width;
3028 }
3029
3030 return k;
3031}
3032
3033
3034/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3035
3036static INLINE void
3037x_clear_glyph_string_rect (s, x, y, w, h)
3038 struct glyph_string *s;
3039 int x, y, w, h;
3040{
3041 XGCValues xgcv;
3042 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3043 XSetForeground (s->display, s->gc, xgcv.background);
3044 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3045 XSetForeground (s->display, s->gc, xgcv.foreground);
3046}
3047
3048
3049/* Draw the background of glyph_string S. If S->background_filled_p
3050 is non-zero don't draw it. FORCE_P non-zero means draw the
3051 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3052 when a string preceding S draws into the background of S, or S
3053 contains the first component of a composition. */
06a2c219
GM
3054
3055static void
3056x_draw_glyph_string_background (s, force_p)
3057 struct glyph_string *s;
3058 int force_p;
3059{
3060 /* Nothing to do if background has already been drawn or if it
3061 shouldn't be drawn in the first place. */
3062 if (!s->background_filled_p)
3063 {
b4192550 3064 if (s->stippled_p)
06a2c219
GM
3065 {
3066 /* Fill background with a stipple pattern. */
3067 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3068 XFillRectangle (s->display, s->window, s->gc, s->x,
3069 s->y + s->face->box_line_width,
3070 s->background_width,
3071 s->height - 2 * s->face->box_line_width);
3072 XSetFillStyle (s->display, s->gc, FillSolid);
3073 s->background_filled_p = 1;
3074 }
3075 else if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
3076 || s->font_not_found_p
3077 || s->extends_to_end_of_line_p
06a2c219
GM
3078 || force_p)
3079 {
3080 x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
3081 s->background_width,
3082 s->height - 2 * s->face->box_line_width);
3083 s->background_filled_p = 1;
3084 }
3085 }
3086}
3087
3088
3089/* Draw the foreground of glyph string S. */
3090
3091static void
3092x_draw_glyph_string_foreground (s)
3093 struct glyph_string *s;
3094{
3095 int i, x;
3096
3097 /* If first glyph of S has a left box line, start drawing the text
3098 of S to the right of that box line. */
3099 if (s->face->box != FACE_NO_BOX
3100 && s->first_glyph->left_box_line_p)
3101 x = s->x + s->face->box_line_width;
3102 else
3103 x = s->x;
3104
b4192550
KH
3105 /* Draw characters of S as rectangles if S's font could not be
3106 loaded. */
3107 if (s->font_not_found_p)
06a2c219 3108 {
b4192550 3109 for (i = 0; i < s->nchars; ++i)
06a2c219 3110 {
b4192550
KH
3111 struct glyph *g = s->first_glyph + i;
3112 XDrawRectangle (s->display, s->window,
3113 s->gc, x, s->y, g->pixel_width - 1,
3114 s->height - 1);
3115 x += g->pixel_width;
06a2c219
GM
3116 }
3117 }
3118 else
3119 {
b4192550
KH
3120 char *char1b = (char *) s->char2b;
3121 int boff = s->font_info->baseline_offset;
06a2c219 3122
b4192550
KH
3123 if (s->font_info->vertical_centering)
3124 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3125
3126 /* If we can use 8-bit functions, condense S->char2b. */
3127 if (!s->two_byte_p)
3128 for (i = 0; i < s->nchars; ++i)
3129 char1b[i] = s->char2b[i].byte2;
3130
3131 /* Draw text with XDrawString if background has already been
3132 filled. Otherwise, use XDrawImageString. (Note that
3133 XDrawImageString is usually faster than XDrawString.) Always
3134 use XDrawImageString when drawing the cursor so that there is
3135 no chance that characters under a box cursor are invisible. */
3136 if (s->for_overlaps_p
3137 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3138 {
3139 /* Draw characters with 16-bit or 8-bit functions. */
3140 if (s->two_byte_p)
3141 XDrawString16 (s->display, s->window, s->gc, x,
3142 s->ybase - boff, s->char2b, s->nchars);
3143 else
3144 XDrawString (s->display, s->window, s->gc, x,
3145 s->ybase - boff, char1b, s->nchars);
3146 }
06a2c219
GM
3147 else
3148 {
b4192550
KH
3149 if (s->two_byte_p)
3150 XDrawImageString16 (s->display, s->window, s->gc, x,
3151 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3152 else
b4192550
KH
3153 XDrawImageString (s->display, s->window, s->gc, x,
3154 s->ybase - boff, char1b, s->nchars);
3155 }
3156 }
3157}
06a2c219 3158
b4192550 3159/* Draw the foreground of composite glyph string S. */
06a2c219 3160
b4192550
KH
3161static void
3162x_draw_composite_glyph_string_foreground (s)
3163 struct glyph_string *s;
3164{
3165 int i, x;
06a2c219 3166
b4192550
KH
3167 /* If first glyph of S has a left box line, start drawing the text
3168 of S to the right of that box line. */
3169 if (s->face->box != FACE_NO_BOX
3170 && s->first_glyph->left_box_line_p)
3171 x = s->x + s->face->box_line_width;
3172 else
3173 x = s->x;
06a2c219 3174
b4192550
KH
3175 /* S is a glyph string for a composition. S->gidx is the index of
3176 the first character drawn for glyphs of this composition.
3177 S->gidx == 0 means we are drawing the very first character of
3178 this composition. */
06a2c219 3179
b4192550
KH
3180 /* Draw a rectangle for the composition if the font for the very
3181 first character of the composition could not be loaded. */
3182 if (s->font_not_found_p)
3183 {
3184 if (s->gidx == 0)
3185 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3186 s->width - 1, s->height - 1);
3187 }
3188 else
3189 {
3190 for (i = 0; i < s->nchars; i++, ++s->gidx)
3191 XDrawString16 (s->display, s->window, s->gc,
3192 x + s->cmp->offsets[s->gidx * 2],
3193 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3194 s->char2b + i, 1);
06a2c219
GM
3195 }
3196}
3197
3198
80c32bcc
GM
3199#ifdef USE_X_TOOLKIT
3200
3e71d8f2 3201static struct frame *x_frame_of_widget P_ ((Widget));
80c32bcc 3202
3e71d8f2
GM
3203
3204/* Return the frame on which widget WIDGET is used.. Abort if frame
3205 cannot be determined. */
3206
e851c833 3207static struct frame *
3e71d8f2 3208x_frame_of_widget (widget)
80c32bcc 3209 Widget widget;
80c32bcc 3210{
80c32bcc 3211 struct x_display_info *dpyinfo;
5c187dee 3212 Lisp_Object tail;
3e71d8f2
GM
3213 struct frame *f;
3214
80c32bcc
GM
3215 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3216
3217 /* Find the top-level shell of the widget. Note that this function
3218 can be called when the widget is not yet realized, so XtWindow
3219 (widget) == 0. That's the reason we can't simply use
3220 x_any_window_to_frame. */
3221 while (!XtIsTopLevelShell (widget))
3222 widget = XtParent (widget);
3223
3224 /* Look for a frame with that top-level widget. Allocate the color
3225 on that frame to get the right gamma correction value. */
3226 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3227 if (GC_FRAMEP (XCAR (tail))
3228 && (f = XFRAME (XCAR (tail)),
3229 (f->output_data.nothing != 1
3230 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3231 && f->output_data.x->widget == widget)
3e71d8f2 3232 return f;
80c32bcc
GM
3233
3234 abort ();
3235}
3236
3e71d8f2
GM
3237
3238/* Allocate the color COLOR->pixel on the screen and display of
3239 widget WIDGET in colormap CMAP. If an exact match cannot be
3240 allocated, try the nearest color available. Value is non-zero
3241 if successful. This is called from lwlib. */
3242
3243int
3244x_alloc_nearest_color_for_widget (widget, cmap, color)
3245 Widget widget;
3246 Colormap cmap;
3247 XColor *color;
3248{
3249 struct frame *f = x_frame_of_widget (widget);
3250 return x_alloc_nearest_color (f, cmap, color);
3251}
3252
3253
80c32bcc
GM
3254#endif /* USE_X_TOOLKIT */
3255
3256
06a2c219
GM
3257/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3258 CMAP. If an exact match can't be allocated, try the nearest color
3259 available. Value is non-zero if successful. Set *COLOR to the
3260 color allocated. */
3261
3262int
80c32bcc
GM
3263x_alloc_nearest_color (f, cmap, color)
3264 struct frame *f;
06a2c219
GM
3265 Colormap cmap;
3266 XColor *color;
3267{
80c32bcc
GM
3268 Display *display = FRAME_X_DISPLAY (f);
3269 Screen *screen = FRAME_X_SCREEN (f);
3270 int rc;
3271
3272 gamma_correct (f, color);
3273 rc = XAllocColor (display, cmap, color);
06a2c219
GM
3274 if (rc == 0)
3275 {
3276 /* If we got to this point, the colormap is full, so we're going
3277 to try to get the next closest color. The algorithm used is
3278 a least-squares matching, which is what X uses for closest
3279 color matching with StaticColor visuals. */
3280 int nearest, i;
3281 unsigned long nearest_delta = ~0;
3282 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3283 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3284
3285 for (i = 0; i < ncells; ++i)
3286 cells[i].pixel = i;
3287 XQueryColors (display, cmap, cells, ncells);
3288
3289 for (nearest = i = 0; i < ncells; ++i)
3290 {
3291 long dred = (color->red >> 8) - (cells[i].red >> 8);
3292 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3293 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3294 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3295
3296 if (delta < nearest_delta)
3297 {
3298 nearest = i;
3299 nearest_delta = delta;
3300 }
3301 }
3302
3303 color->red = cells[nearest].red;
3304 color->green = cells[nearest].green;
3305 color->blue = cells[nearest].blue;
3306 rc = XAllocColor (display, cmap, color);
3307 }
3308
d9c545da
GM
3309#ifdef DEBUG_X_COLORS
3310 if (rc)
3311 register_color (color->pixel);
3312#endif /* DEBUG_X_COLORS */
3313
06a2c219
GM
3314 return rc;
3315}
3316
3317
d9c545da
GM
3318/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3319 It's necessary to do this instead of just using PIXEL directly to
3320 get color reference counts right. */
3321
3322unsigned long
3323x_copy_color (f, pixel)
3324 struct frame *f;
3325 unsigned long pixel;
3326{
3327 XColor color;
3328
3329 color.pixel = pixel;
3330 BLOCK_INPUT;
3331 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3332 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3333 UNBLOCK_INPUT;
3334#ifdef DEBUG_X_COLORS
3335 register_color (pixel);
3336#endif
3337 return color.pixel;
3338}
3339
3340
3e71d8f2
GM
3341/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3342 It's necessary to do this instead of just using PIXEL directly to
3343 get color reference counts right. */
3344
3345unsigned long
3346x_copy_dpy_color (dpy, cmap, pixel)
3347 Display *dpy;
3348 Colormap cmap;
3349 unsigned long pixel;
3350{
3351 XColor color;
3352
3353 color.pixel = pixel;
3354 BLOCK_INPUT;
3355 XQueryColor (dpy, cmap, &color);
3356 XAllocColor (dpy, cmap, &color);
3357 UNBLOCK_INPUT;
3358#ifdef DEBUG_X_COLORS
3359 register_color (pixel);
3360#endif
3361 return color.pixel;
3362}
3363
3364
06a2c219
GM
3365/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3366 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3367 If this produces the same color as PIXEL, try a color where all RGB
3368 values have DELTA added. Return the allocated color in *PIXEL.
3369 DISPLAY is the X display, CMAP is the colormap to operate on.
3370 Value is non-zero if successful. */
3371
3372static int
3373x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3374 struct frame *f;
3375 Display *display;
3376 Colormap cmap;
3377 unsigned long *pixel;
68c45bf0 3378 double factor;
06a2c219
GM
3379 int delta;
3380{
3381 XColor color, new;
3382 int success_p;
3383
3384 /* Get RGB color values. */
3385 color.pixel = *pixel;
3386 XQueryColor (display, cmap, &color);
3387
3388 /* Change RGB values by specified FACTOR. Avoid overflow! */
3389 xassert (factor >= 0);
3390 new.red = min (0xffff, factor * color.red);
3391 new.green = min (0xffff, factor * color.green);
3392 new.blue = min (0xffff, factor * color.blue);
3393
3394 /* Try to allocate the color. */
80c32bcc 3395 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3396 if (success_p)
3397 {
3398 if (new.pixel == *pixel)
3399 {
3400 /* If we end up with the same color as before, try adding
3401 delta to the RGB values. */
0d605c67 3402 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3403
3404 new.red = min (0xffff, delta + color.red);
3405 new.green = min (0xffff, delta + color.green);
3406 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3407 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3408 }
3409 else
3410 success_p = 1;
3411 *pixel = new.pixel;
3412 }
3413
3414 return success_p;
3415}
3416
3417
3418/* Set up the foreground color for drawing relief lines of glyph
3419 string S. RELIEF is a pointer to a struct relief containing the GC
3420 with which lines will be drawn. Use a color that is FACTOR or
3421 DELTA lighter or darker than the relief's background which is found
3422 in S->f->output_data.x->relief_background. If such a color cannot
3423 be allocated, use DEFAULT_PIXEL, instead. */
3424
3425static void
3426x_setup_relief_color (f, relief, factor, delta, default_pixel)
3427 struct frame *f;
3428 struct relief *relief;
68c45bf0 3429 double factor;
06a2c219
GM
3430 int delta;
3431 unsigned long default_pixel;
3432{
3433 XGCValues xgcv;
3434 struct x_output *di = f->output_data.x;
3435 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3436 unsigned long pixel;
3437 unsigned long background = di->relief_background;
43bd1b2b 3438 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3439 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3440 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3441
3442 xgcv.graphics_exposures = False;
3443 xgcv.line_width = 1;
3444
3445 /* Free previously allocated color. The color cell will be reused
3446 when it has been freed as many times as it was allocated, so this
3447 doesn't affect faces using the same colors. */
3448 if (relief->gc
3449 && relief->allocated_p)
3450 {
0d605c67 3451 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3452 relief->allocated_p = 0;
3453 }
3454
3455 /* Allocate new color. */
3456 xgcv.foreground = default_pixel;
3457 pixel = background;
dcd08bfb
GM
3458 if (dpyinfo->n_planes != 1
3459 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3460 {
3461 relief->allocated_p = 1;
3462 xgcv.foreground = relief->pixel = pixel;
3463 }
3464
3465 if (relief->gc == 0)
3466 {
dcd08bfb 3467 xgcv.stipple = dpyinfo->gray;
06a2c219 3468 mask |= GCStipple;
dcd08bfb 3469 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3470 }
3471 else
dcd08bfb 3472 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3473}
3474
3475
3476/* Set up colors for the relief lines around glyph string S. */
3477
3478static void
3479x_setup_relief_colors (s)
3480 struct glyph_string *s;
3481{
3482 struct x_output *di = s->f->output_data.x;
3483 unsigned long color;
3484
3485 if (s->face->use_box_color_for_shadows_p)
3486 color = s->face->box_color;
3487 else
3488 {
3489 XGCValues xgcv;
3490
3491 /* Get the background color of the face. */
3492 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3493 color = xgcv.background;
3494 }
3495
3496 if (di->white_relief.gc == 0
3497 || color != di->relief_background)
3498 {
3499 di->relief_background = color;
3500 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3501 WHITE_PIX_DEFAULT (s->f));
3502 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3503 BLACK_PIX_DEFAULT (s->f));
3504 }
3505}
3506
3507
3508/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3509 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3510 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3511 relief. LEFT_P non-zero means draw a relief on the left side of
3512 the rectangle. RIGHT_P non-zero means draw a relief on the right
3513 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3514 when drawing. */
3515
3516static void
3517x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3518 raised_p, left_p, right_p, clip_rect)
3519 struct frame *f;
3520 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3521 XRectangle *clip_rect;
3522{
3523 int i;
3524 GC gc;
3525
3526 if (raised_p)
3527 gc = f->output_data.x->white_relief.gc;
3528 else
3529 gc = f->output_data.x->black_relief.gc;
3530 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3531
3532 /* Top. */
3533 for (i = 0; i < width; ++i)
3534 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3535 left_x + i * left_p, top_y + i,
3536 right_x + 1 - i * right_p, top_y + i);
3537
3538 /* Left. */
3539 if (left_p)
3540 for (i = 0; i < width; ++i)
3541 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3542 left_x + i, top_y + i, left_x + i, bottom_y - i);
3543
3544 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3545 if (raised_p)
3546 gc = f->output_data.x->black_relief.gc;
3547 else
3548 gc = f->output_data.x->white_relief.gc;
3549 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3550
3551 /* Bottom. */
3552 for (i = 0; i < width; ++i)
3553 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3554 left_x + i * left_p, bottom_y - i,
3555 right_x + 1 - i * right_p, bottom_y - i);
3556
3557 /* Right. */
3558 if (right_p)
3559 for (i = 0; i < width; ++i)
3560 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3561 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3562
3563 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3564}
3565
3566
3567/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3568 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3569 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3570 left side of the rectangle. RIGHT_P non-zero means draw a line
3571 on the right side of the rectangle. CLIP_RECT is the clipping
3572 rectangle to use when drawing. */
3573
3574static void
3575x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3576 left_p, right_p, clip_rect)
3577 struct glyph_string *s;
3578 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3579 XRectangle *clip_rect;
3580{
3581 XGCValues xgcv;
3582
3583 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3584 XSetForeground (s->display, s->gc, s->face->box_color);
3585 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3586
3587 /* Top. */
3588 XFillRectangle (s->display, s->window, s->gc,
3589 left_x, top_y, right_x - left_x, width);
3590
3591 /* Left. */
3592 if (left_p)
3593 XFillRectangle (s->display, s->window, s->gc,
3594 left_x, top_y, width, bottom_y - top_y);
3595
3596 /* Bottom. */
3597 XFillRectangle (s->display, s->window, s->gc,
3598 left_x, bottom_y - width, right_x - left_x, width);
3599
3600 /* Right. */
3601 if (right_p)
3602 XFillRectangle (s->display, s->window, s->gc,
3603 right_x - width, top_y, width, bottom_y - top_y);
3604
3605 XSetForeground (s->display, s->gc, xgcv.foreground);
3606 XSetClipMask (s->display, s->gc, None);
3607}
3608
3609
3610/* Draw a box around glyph string S. */
3611
3612static void
3613x_draw_glyph_string_box (s)
3614 struct glyph_string *s;
3615{
3616 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3617 int left_p, right_p;
3618 struct glyph *last_glyph;
3619 XRectangle clip_rect;
3620
3621 last_x = window_box_right (s->w, s->area);
3622 if (s->row->full_width_p
3623 && !s->w->pseudo_window_p)
3624 {
110859fc 3625 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3626 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3627 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3628 }
3629
3630 /* The glyph that may have a right box line. */
b4192550 3631 last_glyph = (s->cmp || s->img
06a2c219
GM
3632 ? s->first_glyph
3633 : s->first_glyph + s->nchars - 1);
3634
3635 width = s->face->box_line_width;
3636 raised_p = s->face->box == FACE_RAISED_BOX;
3637 left_x = s->x;
3638 right_x = ((s->row->full_width_p
1da3fd71 3639 ? last_x - 1
a7aeb2de 3640 : min (last_x, s->x + s->background_width) - 1));
06a2c219
GM
3641 top_y = s->y;
3642 bottom_y = top_y + s->height - 1;
3643
3644 left_p = (s->first_glyph->left_box_line_p
3645 || (s->hl == DRAW_MOUSE_FACE
3646 && (s->prev == NULL
3647 || s->prev->hl != s->hl)));
3648 right_p = (last_glyph->right_box_line_p
3649 || (s->hl == DRAW_MOUSE_FACE
3650 && (s->next == NULL
3651 || s->next->hl != s->hl)));
3652
3653 x_get_glyph_string_clip_rect (s, &clip_rect);
3654
3655 if (s->face->box == FACE_SIMPLE_BOX)
3656 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3657 left_p, right_p, &clip_rect);
3658 else
3659 {
3660 x_setup_relief_colors (s);
3661 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3662 width, raised_p, left_p, right_p, &clip_rect);
3663 }
3664}
3665
3666
3667/* Draw foreground of image glyph string S. */
3668
3669static void
3670x_draw_image_foreground (s)
3671 struct glyph_string *s;
3672{
3673 int x;
95af8492 3674 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3675
3676 /* If first glyph of S has a left box line, start drawing it to the
3677 right of that line. */
3678 if (s->face->box != FACE_NO_BOX
3679 && s->first_glyph->left_box_line_p)
3680 x = s->x + s->face->box_line_width;
3681 else
3682 x = s->x;
3683
3684 /* If there is a margin around the image, adjust x- and y-position
3685 by that margin. */
3686 if (s->img->margin)
3687 {
3688 x += s->img->margin;
3689 y += s->img->margin;
3690 }
3691
3692 if (s->img->pixmap)
3693 {
3694 if (s->img->mask)
3695 {
3696 /* We can't set both a clip mask and use XSetClipRectangles
3697 because the latter also sets a clip mask. We also can't
3698 trust on the shape extension to be available
3699 (XShapeCombineRegion). So, compute the rectangle to draw
3700 manually. */
3701 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3702 | GCFunction);
3703 XGCValues xgcv;
3704 XRectangle clip_rect, image_rect, r;
3705
3706 xgcv.clip_mask = s->img->mask;
3707 xgcv.clip_x_origin = x;
3708 xgcv.clip_y_origin = y;
3709 xgcv.function = GXcopy;
3710 XChangeGC (s->display, s->gc, mask, &xgcv);
3711
3712 x_get_glyph_string_clip_rect (s, &clip_rect);
3713 image_rect.x = x;
3714 image_rect.y = y;
3715 image_rect.width = s->img->width;
3716 image_rect.height = s->img->height;
3717 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
3718 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3719 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
3720 }
3721 else
3722 {
3723 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3724 0, 0, s->img->width, s->img->height, x, y);
3725
3726 /* When the image has a mask, we can expect that at
3727 least part of a mouse highlight or a block cursor will
3728 be visible. If the image doesn't have a mask, make
3729 a block cursor visible by drawing a rectangle around
3730 the image. I believe it's looking better if we do
3731 nothing here for mouse-face. */
3732 if (s->hl == DRAW_CURSOR)
3733 XDrawRectangle (s->display, s->window, s->gc, x, y,
3734 s->img->width - 1, s->img->height - 1);
3735 }
3736 }
3737 else
3738 /* Draw a rectangle if image could not be loaded. */
3739 XDrawRectangle (s->display, s->window, s->gc, x, y,
3740 s->img->width - 1, s->img->height - 1);
3741}
3742
3743
3744/* Draw a relief around the image glyph string S. */
3745
3746static void
3747x_draw_image_relief (s)
3748 struct glyph_string *s;
3749{
3750 int x0, y0, x1, y1, thick, raised_p;
3751 XRectangle r;
3752 int x;
95af8492 3753 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3754
3755 /* If first glyph of S has a left box line, start drawing it to the
3756 right of that line. */
3757 if (s->face->box != FACE_NO_BOX
3758 && s->first_glyph->left_box_line_p)
3759 x = s->x + s->face->box_line_width;
3760 else
3761 x = s->x;
3762
3763 /* If there is a margin around the image, adjust x- and y-position
3764 by that margin. */
3765 if (s->img->margin)
3766 {
3767 x += s->img->margin;
3768 y += s->img->margin;
3769 }
3770
3771 if (s->hl == DRAW_IMAGE_SUNKEN
3772 || s->hl == DRAW_IMAGE_RAISED)
3773 {
9ea173e8 3774 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
3775 raised_p = s->hl == DRAW_IMAGE_RAISED;
3776 }
3777 else
3778 {
3779 thick = abs (s->img->relief);
3780 raised_p = s->img->relief > 0;
3781 }
3782
3783 x0 = x - thick;
3784 y0 = y - thick;
3785 x1 = x + s->img->width + thick - 1;
3786 y1 = y + s->img->height + thick - 1;
3787
3788 x_setup_relief_colors (s);
3789 x_get_glyph_string_clip_rect (s, &r);
3790 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
3791}
3792
3793
3794/* Draw the foreground of image glyph string S to PIXMAP. */
3795
3796static void
3797x_draw_image_foreground_1 (s, pixmap)
3798 struct glyph_string *s;
3799 Pixmap pixmap;
3800{
3801 int x;
95af8492 3802 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
3803
3804 /* If first glyph of S has a left box line, start drawing it to the
3805 right of that line. */
3806 if (s->face->box != FACE_NO_BOX
3807 && s->first_glyph->left_box_line_p)
3808 x = s->face->box_line_width;
3809 else
3810 x = 0;
3811
3812 /* If there is a margin around the image, adjust x- and y-position
3813 by that margin. */
3814 if (s->img->margin)
3815 {
3816 x += s->img->margin;
3817 y += s->img->margin;
3818 }
dc43ef94 3819
06a2c219
GM
3820 if (s->img->pixmap)
3821 {
3822 if (s->img->mask)
3823 {
3824 /* We can't set both a clip mask and use XSetClipRectangles
3825 because the latter also sets a clip mask. We also can't
3826 trust on the shape extension to be available
3827 (XShapeCombineRegion). So, compute the rectangle to draw
3828 manually. */
3829 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3830 | GCFunction);
3831 XGCValues xgcv;
3832
3833 xgcv.clip_mask = s->img->mask;
3834 xgcv.clip_x_origin = x;
3835 xgcv.clip_y_origin = y;
3836 xgcv.function = GXcopy;
3837 XChangeGC (s->display, s->gc, mask, &xgcv);
3838
3839 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3840 0, 0, s->img->width, s->img->height, x, y);
3841 XSetClipMask (s->display, s->gc, None);
3842 }
3843 else
3844 {
3845 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3846 0, 0, s->img->width, s->img->height, x, y);
3847
3848 /* When the image has a mask, we can expect that at
3849 least part of a mouse highlight or a block cursor will
3850 be visible. If the image doesn't have a mask, make
3851 a block cursor visible by drawing a rectangle around
3852 the image. I believe it's looking better if we do
3853 nothing here for mouse-face. */
3854 if (s->hl == DRAW_CURSOR)
3855 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3856 s->img->width - 1, s->img->height - 1);
3857 }
3858 }
3859 else
3860 /* Draw a rectangle if image could not be loaded. */
3861 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3862 s->img->width - 1, s->img->height - 1);
3863}
dc43ef94 3864
990ba854 3865
06a2c219
GM
3866/* Draw part of the background of glyph string S. X, Y, W, and H
3867 give the rectangle to draw. */
a9a5b0a5 3868
06a2c219
GM
3869static void
3870x_draw_glyph_string_bg_rect (s, x, y, w, h)
3871 struct glyph_string *s;
3872 int x, y, w, h;
3873{
3874 if (s->stippled_p)
3875 {
3876 /* Fill background with a stipple pattern. */
3877 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3878 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3879 XSetFillStyle (s->display, s->gc, FillSolid);
3880 }
3881 else
3882 x_clear_glyph_string_rect (s, x, y, w, h);
3883}
07e34cb0 3884
b5210ea7 3885
06a2c219 3886/* Draw image glyph string S.
dc43ef94 3887
06a2c219
GM
3888 s->y
3889 s->x +-------------------------
3890 | s->face->box
3891 |
3892 | +-------------------------
3893 | | s->img->margin
3894 | |
3895 | | +-------------------
3896 | | | the image
dc43ef94 3897
06a2c219 3898 */
dc43ef94 3899
06a2c219
GM
3900static void
3901x_draw_image_glyph_string (s)
3902 struct glyph_string *s;
3903{
3904 int x, y;
3905 int box_line_width = s->face->box_line_width;
3906 int margin = s->img->margin;
3907 int height;
3908 Pixmap pixmap = None;
3909
3910 height = s->height - 2 * box_line_width;
3911
3912 /* Fill background with face under the image. Do it only if row is
3913 taller than image or if image has a clip mask to reduce
3914 flickering. */
3915 s->stippled_p = s->face->stipple != 0;
3916 if (height > s->img->height
3917 || margin
3918 || s->img->mask
3919 || s->img->pixmap == 0
3920 || s->width != s->background_width)
3921 {
3922 if (box_line_width && s->first_glyph->left_box_line_p)
3923 x = s->x + box_line_width;
3924 else
3925 x = s->x;
3926
3927 y = s->y + box_line_width;
3928
3929 if (s->img->mask)
3930 {
3931 /* Create a pixmap as large as the glyph string Fill it with
3932 the background color. Copy the image to it, using its
3933 mask. Copy the temporary pixmap to the display. */
3934 Screen *screen = FRAME_X_SCREEN (s->f);
3935 int depth = DefaultDepthOfScreen (screen);
3936
3937 /* Create a pixmap as large as the glyph string. */
3938 pixmap = XCreatePixmap (s->display, s->window,
3939 s->background_width,
3940 s->height, depth);
3941
3942 /* Don't clip in the following because we're working on the
3943 pixmap. */
3944 XSetClipMask (s->display, s->gc, None);
3945
3946 /* Fill the pixmap with the background color/stipple. */
3947 if (s->stippled_p)
3948 {
3949 /* Fill background with a stipple pattern. */
3950 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3951 XFillRectangle (s->display, pixmap, s->gc,
3952 0, 0, s->background_width, s->height);
3953 XSetFillStyle (s->display, s->gc, FillSolid);
3954 }
3955 else
3956 {
3957 XGCValues xgcv;
3958 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
3959 &xgcv);
3960 XSetForeground (s->display, s->gc, xgcv.background);
3961 XFillRectangle (s->display, pixmap, s->gc,
3962 0, 0, s->background_width, s->height);
3963 XSetForeground (s->display, s->gc, xgcv.foreground);
3964 }
3965 }
3966 else
3967 /* Implementation idea: Is it possible to construct a mask?
3968 We could look at the color at the margins of the image, and
3969 say that this color is probably the background color of the
3970 image. */
3971 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3972
3973 s->background_filled_p = 1;
3974 }
dc43ef94 3975
06a2c219
GM
3976 /* Draw the foreground. */
3977 if (pixmap != None)
3978 {
3979 x_draw_image_foreground_1 (s, pixmap);
3980 x_set_glyph_string_clipping (s);
3981 XCopyArea (s->display, pixmap, s->window, s->gc,
3982 0, 0, s->background_width, s->height, s->x, s->y);
3983 XFreePixmap (s->display, pixmap);
3984 }
3985 else
3986 x_draw_image_foreground (s);
b5210ea7 3987
06a2c219
GM
3988 /* If we must draw a relief around the image, do it. */
3989 if (s->img->relief
3990 || s->hl == DRAW_IMAGE_RAISED
3991 || s->hl == DRAW_IMAGE_SUNKEN)
3992 x_draw_image_relief (s);
3993}
8c1a6a84 3994
990ba854 3995
06a2c219 3996/* Draw stretch glyph string S. */
dc43ef94 3997
06a2c219
GM
3998static void
3999x_draw_stretch_glyph_string (s)
4000 struct glyph_string *s;
4001{
4002 xassert (s->first_glyph->type == STRETCH_GLYPH);
4003 s->stippled_p = s->face->stipple != 0;
990ba854 4004
06a2c219
GM
4005 if (s->hl == DRAW_CURSOR
4006 && !x_stretch_cursor_p)
4007 {
4008 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4009 as wide as the stretch glyph. */
4010 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4011
06a2c219
GM
4012 /* Draw cursor. */
4013 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4014
06a2c219
GM
4015 /* Clear rest using the GC of the original non-cursor face. */
4016 if (width < s->background_width)
4017 {
4018 GC gc = s->face->gc;
4019 int x = s->x + width, y = s->y;
4020 int w = s->background_width - width, h = s->height;
4021 XRectangle r;
dc43ef94 4022
06a2c219
GM
4023 x_get_glyph_string_clip_rect (s, &r);
4024 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
97210f4e 4025
06a2c219
GM
4026 if (s->face->stipple)
4027 {
4028 /* Fill background with a stipple pattern. */
4029 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4030 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4031 XSetFillStyle (s->display, gc, FillSolid);
4032 }
4033 else
4034 {
4035 XGCValues xgcv;
4036 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4037 XSetForeground (s->display, gc, xgcv.background);
4038 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4039 XSetForeground (s->display, gc, xgcv.foreground);
4040 }
4041 }
4042 }
4043 else
4044 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4045 s->height);
4046
4047 s->background_filled_p = 1;
4048}
4049
4050
4051/* Draw glyph string S. */
4052
4053static void
4054x_draw_glyph_string (s)
4055 struct glyph_string *s;
4056{
4057 /* If S draws into the background of its successor, draw the
4058 background of the successor first so that S can draw into it.
4059 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4060 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4061 {
4062 xassert (s->next->img == NULL);
4063 x_set_glyph_string_gc (s->next);
4064 x_set_glyph_string_clipping (s->next);
4065 x_draw_glyph_string_background (s->next, 1);
4066 }
97210f4e 4067
06a2c219
GM
4068 /* Set up S->gc, set clipping and draw S. */
4069 x_set_glyph_string_gc (s);
4070 x_set_glyph_string_clipping (s);
4071
4072 switch (s->first_glyph->type)
4073 {
4074 case IMAGE_GLYPH:
4075 x_draw_image_glyph_string (s);
4076 break;
4077
4078 case STRETCH_GLYPH:
4079 x_draw_stretch_glyph_string (s);
4080 break;
4081
4082 case CHAR_GLYPH:
66ac4b0e
GM
4083 if (s->for_overlaps_p)
4084 s->background_filled_p = 1;
4085 else
4086 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4087 x_draw_glyph_string_foreground (s);
4088 break;
4089
b4192550
KH
4090 case COMPOSITE_GLYPH:
4091 if (s->for_overlaps_p || s->gidx > 0)
4092 s->background_filled_p = 1;
4093 else
4094 x_draw_glyph_string_background (s, 1);
4095 x_draw_composite_glyph_string_foreground (s);
4096 break;
4097
06a2c219
GM
4098 default:
4099 abort ();
4100 }
4101
66ac4b0e 4102 if (!s->for_overlaps_p)
06a2c219 4103 {
66ac4b0e
GM
4104 /* Draw underline. */
4105 if (s->face->underline_p)
4106 {
4107 unsigned long dy, h;
06a2c219 4108
66ac4b0e
GM
4109 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4110 h = 1;
4111 if (!XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &dy))
4112 dy = s->height - h;
06a2c219 4113
66ac4b0e
GM
4114 if (s->face->underline_defaulted_p)
4115 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4116 s->width, h);
4117 else
4118 {
4119 XGCValues xgcv;
4120 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4121 XSetForeground (s->display, s->gc, s->face->underline_color);
4122 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4123 s->width, h);
4124 XSetForeground (s->display, s->gc, xgcv.foreground);
4125 }
dc6f92b8 4126 }
07e34cb0 4127
66ac4b0e
GM
4128 /* Draw overline. */
4129 if (s->face->overline_p)
06a2c219 4130 {
66ac4b0e
GM
4131 unsigned long dy = 0, h = 1;
4132
4133 if (s->face->overline_color_defaulted_p)
4134 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4135 s->width, h);
4136 else
4137 {
4138 XGCValues xgcv;
4139 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4140 XSetForeground (s->display, s->gc, s->face->overline_color);
4141 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4142 s->width, h);
4143 XSetForeground (s->display, s->gc, xgcv.foreground);
4144 }
06a2c219 4145 }
06a2c219 4146
66ac4b0e
GM
4147 /* Draw strike-through. */
4148 if (s->face->strike_through_p)
06a2c219 4149 {
66ac4b0e
GM
4150 unsigned long h = 1;
4151 unsigned long dy = (s->height - h) / 2;
4152
4153 if (s->face->strike_through_color_defaulted_p)
4154 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4155 s->width, h);
4156 else
4157 {
4158 XGCValues xgcv;
4159 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4160 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4161 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4162 s->width, h);
4163 XSetForeground (s->display, s->gc, xgcv.foreground);
4164 }
06a2c219 4165 }
06a2c219 4166
66ac4b0e
GM
4167 /* Draw relief. */
4168 if (s->face->box != FACE_NO_BOX)
4169 x_draw_glyph_string_box (s);
4170 }
06a2c219
GM
4171
4172 /* Reset clipping. */
4173 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4174}
07e34cb0 4175
06a2c219 4176
b4192550
KH
4177static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4178 struct face **, int));
06a2c219 4179
06a2c219 4180
209f68d9
GM
4181/* Fill glyph string S with composition components specified by S->cmp.
4182
b4192550
KH
4183 FACES is an array of faces for all components of this composition.
4184 S->gidx is the index of the first component for S.
4185 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4186 use its physical height for clipping.
06a2c219 4187
b4192550 4188 Value is the index of a component not in S. */
07e34cb0 4189
b4192550
KH
4190static int
4191x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4192 struct glyph_string *s;
b4192550 4193 struct face **faces;
66ac4b0e 4194 int overlaps_p;
07e34cb0 4195{
b4192550 4196 int i;
06a2c219 4197
b4192550 4198 xassert (s);
06a2c219 4199
b4192550 4200 s->for_overlaps_p = overlaps_p;
06a2c219 4201
b4192550
KH
4202 s->face = faces[s->gidx];
4203 s->font = s->face->font;
4204 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4205
b4192550
KH
4206 /* For all glyphs of this composition, starting at the offset
4207 S->gidx, until we reach the end of the definition or encounter a
4208 glyph that requires the different face, add it to S. */
4209 ++s->nchars;
4210 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4211 ++s->nchars;
06a2c219 4212
b4192550
KH
4213 /* All glyph strings for the same composition has the same width,
4214 i.e. the width set for the first component of the composition. */
06a2c219 4215
06a2c219
GM
4216 s->width = s->first_glyph->pixel_width;
4217
4218 /* If the specified font could not be loaded, use the frame's
4219 default font, but record the fact that we couldn't load it in
4220 the glyph string so that we can draw rectangles for the
4221 characters of the glyph string. */
4222 if (s->font == NULL)
4223 {
4224 s->font_not_found_p = 1;
4225 s->font = FRAME_FONT (s->f);
4226 }
4227
4228 /* Adjust base line for subscript/superscript text. */
4229 s->ybase += s->first_glyph->voffset;
4230
4231 xassert (s->face && s->face->gc);
4232
4233 /* This glyph string must always be drawn with 16-bit functions. */
4234 s->two_byte_p = 1;
b4192550
KH
4235
4236 return s->gidx + s->nchars;
06a2c219
GM
4237}
4238
4239
209f68d9
GM
4240/* Fill glyph string S from a sequence of character glyphs.
4241
06a2c219 4242 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4243 first glyph to consider, END is the index of the last + 1.
4244 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4245 use its physical height for clipping.
66ac4b0e
GM
4246
4247 Value is the index of the first glyph not in S. */
06a2c219
GM
4248
4249static int
66ac4b0e 4250x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4251 struct glyph_string *s;
4252 int face_id;
66ac4b0e 4253 int start, end, overlaps_p;
06a2c219
GM
4254{
4255 struct glyph *glyph, *last;
4256 int voffset;
ee569018 4257 int glyph_not_available_p;
06a2c219 4258
06a2c219
GM
4259 xassert (s->f == XFRAME (s->w->frame));
4260 xassert (s->nchars == 0);
4261 xassert (start >= 0 && end > start);
4262
66ac4b0e 4263 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4264 glyph = s->row->glyphs[s->area] + start;
4265 last = s->row->glyphs[s->area] + end;
4266 voffset = glyph->voffset;
4267
ee569018
KH
4268 glyph_not_available_p = glyph->glyph_not_available_p;
4269
06a2c219
GM
4270 while (glyph < last
4271 && glyph->type == CHAR_GLYPH
4272 && glyph->voffset == voffset
ee569018
KH
4273 /* Same face id implies same font, nowadays. */
4274 && glyph->face_id == face_id
4275 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4276 {
ee569018
KH
4277 int two_byte_p;
4278
06a2c219 4279 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4280 s->char2b + s->nchars,
4281 &two_byte_p);
4282 s->two_byte_p = two_byte_p;
06a2c219
GM
4283 ++s->nchars;
4284 xassert (s->nchars <= end - start);
4285 s->width += glyph->pixel_width;
4286 ++glyph;
4287 }
4288
4289 s->font = s->face->font;
4290 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4291
4292 /* If the specified font could not be loaded, use the frame's font,
4293 but record the fact that we couldn't load it in
4294 S->font_not_found_p so that we can draw rectangles for the
4295 characters of the glyph string. */
ee569018 4296 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4297 {
4298 s->font_not_found_p = 1;
4299 s->font = FRAME_FONT (s->f);
4300 }
4301
4302 /* Adjust base line for subscript/superscript text. */
4303 s->ybase += voffset;
66ac4b0e 4304
06a2c219
GM
4305 xassert (s->face && s->face->gc);
4306 return glyph - s->row->glyphs[s->area];
07e34cb0 4307}
dc6f92b8 4308
06a2c219
GM
4309
4310/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4311
dfcf069d 4312static void
06a2c219
GM
4313x_fill_image_glyph_string (s)
4314 struct glyph_string *s;
4315{
4316 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4317 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4318 xassert (s->img);
43d120d8 4319 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4320 s->font = s->face->font;
4321 s->width = s->first_glyph->pixel_width;
4322
4323 /* Adjust base line for subscript/superscript text. */
4324 s->ybase += s->first_glyph->voffset;
4325}
4326
4327
209f68d9 4328/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4329
209f68d9
GM
4330 ROW is the glyph row in which the glyphs are found, AREA is the
4331 area within the row. START is the index of the first glyph to
4332 consider, END is the index of the last + 1.
4333
4334 Value is the index of the first glyph not in S. */
4335
4336static int
4337x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4338 struct glyph_string *s;
209f68d9
GM
4339 struct glyph_row *row;
4340 enum glyph_row_area area;
4341 int start, end;
06a2c219 4342{
209f68d9
GM
4343 struct glyph *glyph, *last;
4344 int voffset, face_id;
4345
06a2c219 4346 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4347
4348 glyph = s->row->glyphs[s->area] + start;
4349 last = s->row->glyphs[s->area] + end;
4350 face_id = glyph->face_id;
4351 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4352 s->font = s->face->font;
209f68d9
GM
4353 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4354 s->width = glyph->pixel_width;
4355 voffset = glyph->voffset;
4356
4357 for (++glyph;
4358 (glyph < last
4359 && glyph->type == STRETCH_GLYPH
4360 && glyph->voffset == voffset
4361 && glyph->face_id == face_id);
4362 ++glyph)
4363 s->width += glyph->pixel_width;
06a2c219
GM
4364
4365 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4366 s->ybase += voffset;
4367
4368 xassert (s->face && s->face->gc);
4369 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4370}
4371
4372
4373/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4374 of XChar2b structures for S; it can't be allocated in
4375 x_init_glyph_string because it must be allocated via `alloca'. W
4376 is the window on which S is drawn. ROW and AREA are the glyph row
4377 and area within the row from which S is constructed. START is the
4378 index of the first glyph structure covered by S. HL is a
4379 face-override for drawing S. */
4380
4381static void
4382x_init_glyph_string (s, char2b, w, row, area, start, hl)
4383 struct glyph_string *s;
4384 XChar2b *char2b;
4385 struct window *w;
4386 struct glyph_row *row;
4387 enum glyph_row_area area;
4388 int start;
4389 enum draw_glyphs_face hl;
4390{
4391 bzero (s, sizeof *s);
4392 s->w = w;
4393 s->f = XFRAME (w->frame);
4394 s->display = FRAME_X_DISPLAY (s->f);
4395 s->window = FRAME_X_WINDOW (s->f);
4396 s->char2b = char2b;
4397 s->hl = hl;
4398 s->row = row;
4399 s->area = area;
4400 s->first_glyph = row->glyphs[area] + start;
4401 s->height = row->height;
4402 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4403
9ea173e8
GM
4404 /* Display the internal border below the tool-bar window. */
4405 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4406 s->y -= s->f->output_data.x->internal_border_width;
4407
4408 s->ybase = s->y + row->ascent;
4409}
4410
4411
4412/* Set background width of glyph string S. START is the index of the
4413 first glyph following S. LAST_X is the right-most x-position + 1
4414 in the drawing area. */
4415
4416static INLINE void
4417x_set_glyph_string_background_width (s, start, last_x)
4418 struct glyph_string *s;
4419 int start;
4420 int last_x;
4421{
4422 /* If the face of this glyph string has to be drawn to the end of
4423 the drawing area, set S->extends_to_end_of_line_p. */
4424 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4425
4426 if (start == s->row->used[s->area]
4427 && s->hl == DRAW_NORMAL_TEXT
4428 && ((s->area == TEXT_AREA && s->row->fill_line_p)
4429 || s->face->background != default_face->background
4430 || s->face->stipple != default_face->stipple))
4431 s->extends_to_end_of_line_p = 1;
4432
4433 /* If S extends its face to the end of the line, set its
4434 background_width to the distance to the right edge of the drawing
4435 area. */
4436 if (s->extends_to_end_of_line_p)
1da3fd71 4437 s->background_width = last_x - s->x + 1;
06a2c219
GM
4438 else
4439 s->background_width = s->width;
4440}
4441
4442
4443/* Add a glyph string for a stretch glyph to the list of strings
4444 between HEAD and TAIL. START is the index of the stretch glyph in
4445 row area AREA of glyph row ROW. END is the index of the last glyph
4446 in that glyph row area. X is the current output position assigned
4447 to the new glyph string constructed. HL overrides that face of the
4448 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4449 is the right-most x-position of the drawing area. */
4450
8abee2e1
DL
4451/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4452 and below -- keep them on one line. */
4453#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4454 do \
4455 { \
4456 s = (struct glyph_string *) alloca (sizeof *s); \
4457 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4458 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4459 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4460 s->x = (X); \
4461 } \
4462 while (0)
4463
4464
4465/* Add a glyph string for an image glyph to the list of strings
4466 between HEAD and TAIL. START is the index of the image glyph in
4467 row area AREA of glyph row ROW. END is the index of the last glyph
4468 in that glyph row area. X is the current output position assigned
4469 to the new glyph string constructed. HL overrides that face of the
4470 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4471 is the right-most x-position of the drawing area. */
4472
8abee2e1 4473#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4474 do \
4475 { \
4476 s = (struct glyph_string *) alloca (sizeof *s); \
4477 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4478 x_fill_image_glyph_string (s); \
4479 x_append_glyph_string (&HEAD, &TAIL, s); \
4480 ++START; \
4481 s->x = (X); \
4482 } \
4483 while (0)
4484
4485
4486/* Add a glyph string for a sequence of character glyphs to the list
4487 of strings between HEAD and TAIL. START is the index of the first
4488 glyph in row area AREA of glyph row ROW that is part of the new
4489 glyph string. END is the index of the last glyph in that glyph row
4490 area. X is the current output position assigned to the new glyph
4491 string constructed. HL overrides that face of the glyph; e.g. it
4492 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4493 right-most x-position of the drawing area. */
4494
8abee2e1 4495#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4496 do \
4497 { \
3e71d8f2 4498 int c, face_id; \
06a2c219
GM
4499 XChar2b *char2b; \
4500 \
43d120d8 4501 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4502 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4503 \
b4192550
KH
4504 s = (struct glyph_string *) alloca (sizeof *s); \
4505 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4506 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4507 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4508 s->x = (X); \
4509 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4510 OVERLAPS_P); \
06a2c219
GM
4511 } \
4512 while (0)
4513
4514
b4192550
KH
4515/* Add a glyph string for a composite sequence to the list of strings
4516 between HEAD and TAIL. START is the index of the first glyph in
4517 row area AREA of glyph row ROW that is part of the new glyph
4518 string. END is the index of the last glyph in that glyph row area.
4519 X is the current output position assigned to the new glyph string
4520 constructed. HL overrides that face of the glyph; e.g. it is
4521 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4522 x-position of the drawing area. */
4523
6c27ec25 4524#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4525 do { \
43d120d8
KH
4526 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4527 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4528 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4529 struct composition *cmp = composition_table[cmp_id]; \
4530 int glyph_len = cmp->glyph_len; \
4531 XChar2b *char2b; \
4532 struct face **faces; \
4533 struct glyph_string *first_s = NULL; \
4534 int n; \
4535 \
ee569018 4536 base_face = base_face->ascii_face; \
b4192550
KH
4537 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4538 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4539 /* At first, fill in `char2b' and `faces'. */ \
4540 for (n = 0; n < glyph_len; n++) \
4541 { \
43d120d8 4542 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4543 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4544 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4545 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4546 this_face_id, char2b + n, 1); \
b4192550
KH
4547 } \
4548 \
4549 /* Make glyph_strings for each glyph sequence that is drawable by \
4550 the same face, and append them to HEAD/TAIL. */ \
4551 for (n = 0; n < cmp->glyph_len;) \
4552 { \
4553 s = (struct glyph_string *) alloca (sizeof *s); \
4554 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4555 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4556 s->cmp = cmp; \
4557 s->gidx = n; \
b4192550
KH
4558 s->x = (X); \
4559 \
4560 if (n == 0) \
4561 first_s = s; \
4562 \
4563 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4564 } \
4565 \
4566 ++START; \
4567 s = first_s; \
4568 } while (0)
4569
4570
06a2c219
GM
4571/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4572 of AREA of glyph row ROW on window W between indices START and END.
4573 HL overrides the face for drawing glyph strings, e.g. it is
4574 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4575 x-positions of the drawing area.
4576
4577 This is an ugly monster macro construct because we must use alloca
4578 to allocate glyph strings (because x_draw_glyphs can be called
4579 asynchronously). */
4580
8abee2e1 4581#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4582 do \
4583 { \
4584 HEAD = TAIL = NULL; \
4585 while (START < END) \
4586 { \
4587 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4588 switch (first_glyph->type) \
4589 { \
4590 case CHAR_GLYPH: \
4591 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4592 TAIL, HL, X, LAST_X, \
4593 OVERLAPS_P); \
06a2c219
GM
4594 break; \
4595 \
b4192550
KH
4596 case COMPOSITE_GLYPH: \
4597 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
4598 HEAD, TAIL, HL, X, LAST_X,\
4599 OVERLAPS_P); \
4600 break; \
4601 \
06a2c219
GM
4602 case STRETCH_GLYPH: \
4603 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
4604 HEAD, TAIL, HL, X, LAST_X); \
4605 break; \
4606 \
4607 case IMAGE_GLYPH: \
4608 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
4609 TAIL, HL, X, LAST_X); \
4610 break; \
4611 \
4612 default: \
4613 abort (); \
4614 } \
4615 \
4616 x_set_glyph_string_background_width (s, START, LAST_X); \
4617 (X) += s->width; \
4618 } \
4619 } \
4620 while (0)
4621
4622
4623/* Draw glyphs between START and END in AREA of ROW on window W,
4624 starting at x-position X. X is relative to AREA in W. HL is a
4625 face-override with the following meaning:
4626
4627 DRAW_NORMAL_TEXT draw normally
4628 DRAW_CURSOR draw in cursor face
4629 DRAW_MOUSE_FACE draw in mouse face.
4630 DRAW_INVERSE_VIDEO draw in mode line face
4631 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
4632 DRAW_IMAGE_RAISED draw an image with a raised relief around it
4633
4634 If REAL_START is non-null, return in *REAL_START the real starting
4635 position for display. This can be different from START in case
4636 overlapping glyphs must be displayed. If REAL_END is non-null,
4637 return in *REAL_END the real end position for display. This can be
4638 different from END in case overlapping glyphs must be displayed.
4639
66ac4b0e
GM
4640 If OVERLAPS_P is non-zero, draw only the foreground of characters
4641 and clip to the physical height of ROW.
4642
06a2c219
GM
4643 Value is the x-position reached, relative to AREA of W. */
4644
4645static int
66ac4b0e
GM
4646x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
4647 overlaps_p)
06a2c219
GM
4648 struct window *w;
4649 int x;
4650 struct glyph_row *row;
4651 enum glyph_row_area area;
4652 int start, end;
4653 enum draw_glyphs_face hl;
4654 int *real_start, *real_end;
66ac4b0e 4655 int overlaps_p;
dc6f92b8 4656{
06a2c219
GM
4657 struct glyph_string *head, *tail;
4658 struct glyph_string *s;
4659 int last_x, area_width;
4660 int x_reached;
4661 int i, j;
4662
4663 /* Let's rather be paranoid than getting a SEGV. */
4664 start = max (0, start);
4665 end = min (end, row->used[area]);
4666 if (real_start)
4667 *real_start = start;
4668 if (real_end)
4669 *real_end = end;
4670
4671 /* Translate X to frame coordinates. Set last_x to the right
4672 end of the drawing area. */
4673 if (row->full_width_p)
4674 {
4675 /* X is relative to the left edge of W, without scroll bars
4676 or flag areas. */
4677 struct frame *f = XFRAME (w->frame);
110859fc 4678 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 4679 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 4680
06a2c219
GM
4681 x += window_left_x;
4682 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
4683 last_x = window_left_x + area_width;
4684
4685 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4686 {
110859fc 4687 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
4688 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
4689 last_x += width;
4690 else
4691 x -= width;
4692 }
dc6f92b8 4693
b9432a85
GM
4694 x += FRAME_INTERNAL_BORDER_WIDTH (f);
4695 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
4696 }
4697 else
dc6f92b8 4698 {
06a2c219
GM
4699 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
4700 area_width = window_box_width (w, area);
4701 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
4702 }
4703
06a2c219
GM
4704 /* Build a doubly-linked list of glyph_string structures between
4705 head and tail from what we have to draw. Note that the macro
4706 BUILD_GLYPH_STRINGS will modify its start parameter. That's
4707 the reason we use a separate variable `i'. */
4708 i = start;
66ac4b0e
GM
4709 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
4710 overlaps_p);
06a2c219
GM
4711 if (tail)
4712 x_reached = tail->x + tail->background_width;
4713 else
4714 x_reached = x;
90e65f07 4715
06a2c219
GM
4716 /* If there are any glyphs with lbearing < 0 or rbearing > width in
4717 the row, redraw some glyphs in front or following the glyph
4718 strings built above. */
66ac4b0e 4719 if (!overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
4720 {
4721 int dummy_x = 0;
4722 struct glyph_string *h, *t;
4723
4724 /* Compute overhangs for all glyph strings. */
4725 for (s = head; s; s = s->next)
4726 x_compute_glyph_string_overhangs (s);
4727
4728 /* Prepend glyph strings for glyphs in front of the first glyph
4729 string that are overwritten because of the first glyph
4730 string's left overhang. The background of all strings
4731 prepended must be drawn because the first glyph string
4732 draws over it. */
4733 i = x_left_overwritten (head);
4734 if (i >= 0)
4735 {
4736 j = i;
4737 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
4738 DRAW_NORMAL_TEXT, dummy_x, last_x,
4739 overlaps_p);
06a2c219
GM
4740 start = i;
4741 if (real_start)
4742 *real_start = start;
4743 x_compute_overhangs_and_x (t, head->x, 1);
4744 x_prepend_glyph_string_lists (&head, &tail, h, t);
4745 }
58769bee 4746
06a2c219
GM
4747 /* Prepend glyph strings for glyphs in front of the first glyph
4748 string that overwrite that glyph string because of their
4749 right overhang. For these strings, only the foreground must
4750 be drawn, because it draws over the glyph string at `head'.
4751 The background must not be drawn because this would overwrite
4752 right overhangs of preceding glyphs for which no glyph
4753 strings exist. */
4754 i = x_left_overwriting (head);
4755 if (i >= 0)
4756 {
4757 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
4758 DRAW_NORMAL_TEXT, dummy_x, last_x,
4759 overlaps_p);
06a2c219
GM
4760 for (s = h; s; s = s->next)
4761 s->background_filled_p = 1;
4762 if (real_start)
4763 *real_start = i;
4764 x_compute_overhangs_and_x (t, head->x, 1);
4765 x_prepend_glyph_string_lists (&head, &tail, h, t);
4766 }
dbcb258a 4767
06a2c219
GM
4768 /* Append glyphs strings for glyphs following the last glyph
4769 string tail that are overwritten by tail. The background of
4770 these strings has to be drawn because tail's foreground draws
4771 over it. */
4772 i = x_right_overwritten (tail);
4773 if (i >= 0)
4774 {
4775 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4776 DRAW_NORMAL_TEXT, x, last_x,
4777 overlaps_p);
06a2c219
GM
4778 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4779 x_append_glyph_string_lists (&head, &tail, h, t);
4780 if (real_end)
4781 *real_end = i;
4782 }
dc6f92b8 4783
06a2c219
GM
4784 /* Append glyph strings for glyphs following the last glyph
4785 string tail that overwrite tail. The foreground of such
4786 glyphs has to be drawn because it writes into the background
4787 of tail. The background must not be drawn because it could
4788 paint over the foreground of following glyphs. */
4789 i = x_right_overwriting (tail);
4790 if (i >= 0)
4791 {
4792 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4793 DRAW_NORMAL_TEXT, x, last_x,
4794 overlaps_p);
06a2c219
GM
4795 for (s = h; s; s = s->next)
4796 s->background_filled_p = 1;
4797 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4798 x_append_glyph_string_lists (&head, &tail, h, t);
4799 if (real_end)
4800 *real_end = i;
4801 }
4802 }
58769bee 4803
06a2c219
GM
4804 /* Draw all strings. */
4805 for (s = head; s; s = s->next)
4806 x_draw_glyph_string (s);
dc6f92b8 4807
06a2c219
GM
4808 /* Value is the x-position up to which drawn, relative to AREA of W.
4809 This doesn't include parts drawn because of overhangs. */
4810 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
4811 if (!row->full_width_p)
4812 {
4813 if (area > LEFT_MARGIN_AREA)
4814 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
4815 if (area > TEXT_AREA)
4816 x_reached -= window_box_width (w, TEXT_AREA);
4817 }
4818 return x_reached;
4819}
dc6f92b8 4820
dc6f92b8 4821
66ac4b0e
GM
4822/* Fix the display of area AREA of overlapping row ROW in window W. */
4823
4824static void
4825x_fix_overlapping_area (w, row, area)
4826 struct window *w;
4827 struct glyph_row *row;
4828 enum glyph_row_area area;
4829{
4830 int i, x;
4831
4832 BLOCK_INPUT;
4833
4834 if (area == LEFT_MARGIN_AREA)
4835 x = 0;
4836 else if (area == TEXT_AREA)
4837 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
4838 else
4839 x = (window_box_width (w, LEFT_MARGIN_AREA)
4840 + window_box_width (w, TEXT_AREA));
4841
4842 for (i = 0; i < row->used[area];)
4843 {
4844 if (row->glyphs[area][i].overlaps_vertically_p)
4845 {
4846 int start = i, start_x = x;
4847
4848 do
4849 {
4850 x += row->glyphs[area][i].pixel_width;
4851 ++i;
4852 }
4853 while (i < row->used[area]
4854 && row->glyphs[area][i].overlaps_vertically_p);
4855
4856 x_draw_glyphs (w, start_x, row, area, start, i,
4857 (row->inverse_p
4858 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
4859 NULL, NULL, 1);
4860 }
4861 else
4862 {
4863 x += row->glyphs[area][i].pixel_width;
4864 ++i;
4865 }
4866 }
4867
4868 UNBLOCK_INPUT;
4869}
4870
4871
06a2c219
GM
4872/* Output LEN glyphs starting at START at the nominal cursor position.
4873 Advance the nominal cursor over the text. The global variable
4874 updated_window contains the window being updated, updated_row is
4875 the glyph row being updated, and updated_area is the area of that
4876 row being updated. */
dc6f92b8 4877
06a2c219
GM
4878static void
4879x_write_glyphs (start, len)
4880 struct glyph *start;
4881 int len;
4882{
4883 int x, hpos, real_start, real_end;
d9cdbb3d 4884
06a2c219 4885 xassert (updated_window && updated_row);
dc6f92b8 4886 BLOCK_INPUT;
06a2c219
GM
4887
4888 /* Write glyphs. */
dc6f92b8 4889
06a2c219
GM
4890 hpos = start - updated_row->glyphs[updated_area];
4891 x = x_draw_glyphs (updated_window, output_cursor.x,
4892 updated_row, updated_area,
4893 hpos, hpos + len,
4894 (updated_row->inverse_p
4895 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
66ac4b0e 4896 &real_start, &real_end, 0);
b30ec466 4897
06a2c219
GM
4898 /* If we drew over the cursor, note that it is not visible any more. */
4899 note_overwritten_text_cursor (updated_window, real_start,
4900 real_end - real_start);
dc6f92b8
JB
4901
4902 UNBLOCK_INPUT;
06a2c219
GM
4903
4904 /* Advance the output cursor. */
4905 output_cursor.hpos += len;
4906 output_cursor.x = x;
dc6f92b8
JB
4907}
4908
0cdd0c9f 4909
06a2c219 4910/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 4911
06a2c219
GM
4912static void
4913x_insert_glyphs (start, len)
4914 struct glyph *start;
4915 register int len;
4916{
4917 struct frame *f;
4918 struct window *w;
4919 int line_height, shift_by_width, shifted_region_width;
4920 struct glyph_row *row;
4921 struct glyph *glyph;
4922 int frame_x, frame_y, hpos, real_start, real_end;
58769bee 4923
06a2c219 4924 xassert (updated_window && updated_row);
0cdd0c9f 4925 BLOCK_INPUT;
06a2c219
GM
4926 w = updated_window;
4927 f = XFRAME (WINDOW_FRAME (w));
4928
4929 /* Get the height of the line we are in. */
4930 row = updated_row;
4931 line_height = row->height;
4932
4933 /* Get the width of the glyphs to insert. */
4934 shift_by_width = 0;
4935 for (glyph = start; glyph < start + len; ++glyph)
4936 shift_by_width += glyph->pixel_width;
4937
4938 /* Get the width of the region to shift right. */
4939 shifted_region_width = (window_box_width (w, updated_area)
4940 - output_cursor.x
4941 - shift_by_width);
4942
4943 /* Shift right. */
4944 frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x);
4945 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
4946 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
4947 f->output_data.x->normal_gc,
4948 frame_x, frame_y,
4949 shifted_region_width, line_height,
4950 frame_x + shift_by_width, frame_y);
4951
4952 /* Write the glyphs. */
4953 hpos = start - row->glyphs[updated_area];
4954 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
66ac4b0e 4955 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
06a2c219
GM
4956 note_overwritten_text_cursor (w, real_start, real_end - real_start);
4957
4958 /* Advance the output cursor. */
4959 output_cursor.hpos += len;
4960 output_cursor.x += shift_by_width;
0cdd0c9f
RS
4961 UNBLOCK_INPUT;
4962}
0cdd0c9f 4963
0cdd0c9f 4964
06a2c219
GM
4965/* Delete N glyphs at the nominal cursor position. Not implemented
4966 for X frames. */
c83febd7
RS
4967
4968static void
06a2c219
GM
4969x_delete_glyphs (n)
4970 register int n;
c83febd7 4971{
06a2c219 4972 abort ();
c83febd7
RS
4973}
4974
0cdd0c9f 4975
06a2c219
GM
4976/* Erase the current text line from the nominal cursor position
4977 (inclusive) to pixel column TO_X (exclusive). The idea is that
4978 everything from TO_X onward is already erased.
4979
4980 TO_X is a pixel position relative to updated_area of
4981 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 4982
06a2c219
GM
4983static void
4984x_clear_end_of_line (to_x)
4985 int to_x;
4986{
4987 struct frame *f;
4988 struct window *w = updated_window;
4989 int max_x, min_y, max_y;
4990 int from_x, from_y, to_y;
4991
4992 xassert (updated_window && updated_row);
4993 f = XFRAME (w->frame);
4994
4995 if (updated_row->full_width_p)
4996 {
4997 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
4998 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4999 && !w->pseudo_window_p)
5000 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5001 }
06a2c219
GM
5002 else
5003 max_x = window_box_width (w, updated_area);
5004 max_y = window_text_bottom_y (w);
dc6f92b8 5005
06a2c219
GM
5006 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5007 of window. For TO_X > 0, truncate to end of drawing area. */
5008 if (to_x == 0)
5009 return;
5010 else if (to_x < 0)
5011 to_x = max_x;
5012 else
5013 to_x = min (to_x, max_x);
dbc4e1c1 5014
06a2c219
GM
5015 to_y = min (max_y, output_cursor.y + updated_row->height);
5016
5017 /* Notice if the cursor will be cleared by this operation. */
5018 if (!updated_row->full_width_p)
5019 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
dbc4e1c1 5020
06a2c219
GM
5021 from_x = output_cursor.x;
5022
5023 /* Translate to frame coordinates. */
5024 if (updated_row->full_width_p)
5025 {
5026 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5027 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5028 }
0cdd0c9f
RS
5029 else
5030 {
06a2c219
GM
5031 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5032 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5033 }
5034
045dee35 5035 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5036 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5037 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5038
5039 /* Prevent inadvertently clearing to end of the X window. */
5040 if (to_x > from_x && to_y > from_y)
5041 {
5042 BLOCK_INPUT;
5043 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5044 from_x, from_y, to_x - from_x, to_y - from_y,
5045 False);
5046 UNBLOCK_INPUT;
0cdd0c9f 5047 }
0cdd0c9f 5048}
dbc4e1c1 5049
0cdd0c9f 5050
06a2c219 5051/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5052 frame. Otherwise clear the selected frame. */
06a2c219
GM
5053
5054static void
5055x_clear_frame ()
0cdd0c9f 5056{
06a2c219 5057 struct frame *f;
0cdd0c9f 5058
06a2c219
GM
5059 if (updating_frame)
5060 f = updating_frame;
0cdd0c9f 5061 else
b86bd3dd 5062 f = SELECTED_FRAME ();
58769bee 5063
06a2c219
GM
5064 /* Clearing the frame will erase any cursor, so mark them all as no
5065 longer visible. */
5066 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5067 output_cursor.hpos = output_cursor.vpos = 0;
5068 output_cursor.x = -1;
5069
5070 /* We don't set the output cursor here because there will always
5071 follow an explicit cursor_to. */
5072 BLOCK_INPUT;
5073 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5074
5075 /* We have to clear the scroll bars, too. If we have changed
5076 colors or something like that, then they should be notified. */
5077 x_scroll_bar_clear (f);
0cdd0c9f 5078
06a2c219
GM
5079 XFlush (FRAME_X_DISPLAY (f));
5080 UNBLOCK_INPUT;
dc6f92b8 5081}
06a2c219
GM
5082
5083
dc6f92b8 5084\f
dbc4e1c1
JB
5085/* Invert the middle quarter of the frame for .15 sec. */
5086
06a2c219
GM
5087/* We use the select system call to do the waiting, so we have to make
5088 sure it's available. If it isn't, we just won't do visual bells. */
5089
dbc4e1c1
JB
5090#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5091
06a2c219
GM
5092
5093/* Subtract the `struct timeval' values X and Y, storing the result in
5094 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5095
5096static int
5097timeval_subtract (result, x, y)
5098 struct timeval *result, x, y;
5099{
06a2c219
GM
5100 /* Perform the carry for the later subtraction by updating y. This
5101 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5102 if (x.tv_usec < y.tv_usec)
5103 {
5104 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5105 y.tv_usec -= 1000000 * nsec;
5106 y.tv_sec += nsec;
5107 }
06a2c219 5108
dbc4e1c1
JB
5109 if (x.tv_usec - y.tv_usec > 1000000)
5110 {
5111 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5112 y.tv_usec += 1000000 * nsec;
5113 y.tv_sec -= nsec;
5114 }
5115
06a2c219
GM
5116 /* Compute the time remaining to wait. tv_usec is certainly
5117 positive. */
dbc4e1c1
JB
5118 result->tv_sec = x.tv_sec - y.tv_sec;
5119 result->tv_usec = x.tv_usec - y.tv_usec;
5120
06a2c219
GM
5121 /* Return indication of whether the result should be considered
5122 negative. */
dbc4e1c1
JB
5123 return x.tv_sec < y.tv_sec;
5124}
dc6f92b8 5125
dfcf069d 5126void
f676886a
JB
5127XTflash (f)
5128 struct frame *f;
dc6f92b8 5129{
dbc4e1c1 5130 BLOCK_INPUT;
dc6f92b8 5131
dbc4e1c1
JB
5132 {
5133 GC gc;
dc6f92b8 5134
06a2c219
GM
5135 /* Create a GC that will use the GXxor function to flip foreground
5136 pixels into background pixels. */
dbc4e1c1
JB
5137 {
5138 XGCValues values;
dc6f92b8 5139
dbc4e1c1 5140 values.function = GXxor;
7556890b
RS
5141 values.foreground = (f->output_data.x->foreground_pixel
5142 ^ f->output_data.x->background_pixel);
58769bee 5143
334208b7 5144 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5145 GCFunction | GCForeground, &values);
5146 }
dc6f92b8 5147
dbc4e1c1 5148 {
e84e14c3
RS
5149 /* Get the height not including a menu bar widget. */
5150 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5151 /* Height of each line to flash. */
5152 int flash_height = FRAME_LINE_HEIGHT (f);
5153 /* These will be the left and right margins of the rectangles. */
5154 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5155 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5156
5157 int width;
5158
5159 /* Don't flash the area between a scroll bar and the frame
5160 edge it is next to. */
5161 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5162 {
5163 case vertical_scroll_bar_left:
5164 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5165 break;
5166
5167 case vertical_scroll_bar_right:
5168 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5169 break;
06a2c219
GM
5170
5171 default:
5172 break;
e84e14c3
RS
5173 }
5174
5175 width = flash_right - flash_left;
5176
5177 /* If window is tall, flash top and bottom line. */
5178 if (height > 3 * FRAME_LINE_HEIGHT (f))
5179 {
5180 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5181 flash_left,
5182 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5183 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5184 width, flash_height);
5185 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5186 flash_left,
5187 (height - flash_height
5188 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5189 width, flash_height);
5190 }
5191 else
5192 /* If it is short, flash it all. */
5193 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5194 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5195 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5196
06a2c219 5197 x_flush (f);
dc6f92b8 5198
dbc4e1c1 5199 {
06a2c219 5200 struct timeval wakeup;
dc6f92b8 5201
66c30ea1 5202 EMACS_GET_TIME (wakeup);
dc6f92b8 5203
dbc4e1c1
JB
5204 /* Compute time to wait until, propagating carry from usecs. */
5205 wakeup.tv_usec += 150000;
5206 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5207 wakeup.tv_usec %= 1000000;
5208
5209 /* Keep waiting until past the time wakeup. */
5210 while (1)
5211 {
5212 struct timeval timeout;
5213
66c30ea1 5214 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
5215
5216 /* In effect, timeout = wakeup - timeout.
5217 Break if result would be negative. */
5218 if (timeval_subtract (&timeout, wakeup, timeout))
5219 break;
5220
5221 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5222 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5223 }
5224 }
58769bee 5225
e84e14c3
RS
5226 /* If window is tall, flash top and bottom line. */
5227 if (height > 3 * FRAME_LINE_HEIGHT (f))
5228 {
5229 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5230 flash_left,
5231 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5232 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5233 width, flash_height);
5234 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5235 flash_left,
5236 (height - flash_height
5237 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5238 width, flash_height);
5239 }
5240 else
5241 /* If it is short, flash it all. */
5242 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5243 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5244 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5245
334208b7 5246 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5247 x_flush (f);
dc6f92b8 5248 }
dbc4e1c1
JB
5249 }
5250
5251 UNBLOCK_INPUT;
dc6f92b8
JB
5252}
5253
06a2c219 5254#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5255
5256
dc6f92b8
JB
5257/* Make audible bell. */
5258
dfcf069d 5259void
dc6f92b8
JB
5260XTring_bell ()
5261{
b86bd3dd
GM
5262 struct frame *f = SELECTED_FRAME ();
5263
5264 if (FRAME_X_DISPLAY (f))
5265 {
dbc4e1c1 5266#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5267 if (visible_bell)
5268 XTflash (f);
5269 else
dbc4e1c1 5270#endif
b86bd3dd
GM
5271 {
5272 BLOCK_INPUT;
5273 XBell (FRAME_X_DISPLAY (f), 0);
5274 XFlush (FRAME_X_DISPLAY (f));
5275 UNBLOCK_INPUT;
5276 }
dc6f92b8
JB
5277 }
5278}
06a2c219 5279
dc6f92b8 5280\f
06a2c219
GM
5281/* Specify how many text lines, from the top of the window,
5282 should be affected by insert-lines and delete-lines operations.
5283 This, and those operations, are used only within an update
5284 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5285
dfcf069d 5286static void
06a2c219
GM
5287XTset_terminal_window (n)
5288 register int n;
dc6f92b8 5289{
06a2c219 5290 /* This function intentionally left blank. */
dc6f92b8
JB
5291}
5292
06a2c219
GM
5293
5294\f
5295/***********************************************************************
5296 Line Dance
5297 ***********************************************************************/
5298
5299/* Perform an insert-lines or delete-lines operation, inserting N
5300 lines or deleting -N lines at vertical position VPOS. */
5301
dfcf069d 5302static void
06a2c219
GM
5303x_ins_del_lines (vpos, n)
5304 int vpos, n;
dc6f92b8
JB
5305{
5306 abort ();
5307}
06a2c219
GM
5308
5309
5310/* Scroll part of the display as described by RUN. */
dc6f92b8 5311
dfcf069d 5312static void
06a2c219
GM
5313x_scroll_run (w, run)
5314 struct window *w;
5315 struct run *run;
dc6f92b8 5316{
06a2c219
GM
5317 struct frame *f = XFRAME (w->frame);
5318 int x, y, width, height, from_y, to_y, bottom_y;
5319
5320 /* Get frame-relative bounding box of the text display area of W,
5321 without mode lines. Include in this box the flags areas to the
5322 left and right of W. */
5323 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5324 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5325 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5326
5327 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5328 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5329 bottom_y = y + height;
dc6f92b8 5330
06a2c219
GM
5331 if (to_y < from_y)
5332 {
5333 /* Scrolling up. Make sure we don't copy part of the mode
5334 line at the bottom. */
5335 if (from_y + run->height > bottom_y)
5336 height = bottom_y - from_y;
5337 else
5338 height = run->height;
5339 }
dc6f92b8 5340 else
06a2c219
GM
5341 {
5342 /* Scolling down. Make sure we don't copy over the mode line.
5343 at the bottom. */
5344 if (to_y + run->height > bottom_y)
5345 height = bottom_y - to_y;
5346 else
5347 height = run->height;
5348 }
7a13e894 5349
06a2c219
GM
5350 BLOCK_INPUT;
5351
5352 /* Cursor off. Will be switched on again in x_update_window_end. */
5353 updated_window = w;
5354 x_clear_cursor (w);
5355
5356 XCopyArea (FRAME_X_DISPLAY (f),
5357 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5358 f->output_data.x->normal_gc,
5359 x, from_y,
5360 width, height,
5361 x, to_y);
5362
5363 UNBLOCK_INPUT;
5364}
dc6f92b8 5365
dc6f92b8 5366
06a2c219
GM
5367\f
5368/***********************************************************************
5369 Exposure Events
5370 ***********************************************************************/
5371
5372/* Redisplay an exposed area of frame F. X and Y are the upper-left
5373 corner of the exposed rectangle. W and H are width and height of
5374 the exposed area. All are pixel values. W or H zero means redraw
5375 the entire frame. */
dc6f92b8 5376
06a2c219
GM
5377static void
5378expose_frame (f, x, y, w, h)
5379 struct frame *f;
5380 int x, y, w, h;
dc6f92b8 5381{
06a2c219 5382 XRectangle r;
dc6f92b8 5383
06a2c219 5384 TRACE ((stderr, "expose_frame "));
dc6f92b8 5385
06a2c219
GM
5386 /* No need to redraw if frame will be redrawn soon. */
5387 if (FRAME_GARBAGED_P (f))
dc6f92b8 5388 {
06a2c219
GM
5389 TRACE ((stderr, " garbaged\n"));
5390 return;
5391 }
5392
5393 /* If basic faces haven't been realized yet, there is no point in
5394 trying to redraw anything. This can happen when we get an expose
5395 event while Emacs is starting, e.g. by moving another window. */
5396 if (FRAME_FACE_CACHE (f) == NULL
5397 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5398 {
5399 TRACE ((stderr, " no faces\n"));
5400 return;
58769bee 5401 }
06a2c219
GM
5402
5403 if (w == 0 || h == 0)
58769bee 5404 {
06a2c219
GM
5405 r.x = r.y = 0;
5406 r.width = CANON_X_UNIT (f) * f->width;
5407 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5408 }
5409 else
5410 {
06a2c219
GM
5411 r.x = x;
5412 r.y = y;
5413 r.width = w;
5414 r.height = h;
5415 }
5416
5417 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
5418 expose_window_tree (XWINDOW (f->root_window), &r);
5419
9ea173e8 5420 if (WINDOWP (f->tool_bar_window))
06a2c219 5421 {
9ea173e8 5422 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
5423 XRectangle window_rect;
5424 XRectangle intersection_rect;
5425 int window_x, window_y, window_width, window_height;
5426
5427
5428 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5429 window_rect.x = window_x;
5430 window_rect.y = window_y;
5431 window_rect.width = window_width;
5432 window_rect.height = window_height;
5433
5434 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5435 expose_window (w, &intersection_rect);
5436 }
5437
5438#ifndef USE_X_TOOLKIT
5439 if (WINDOWP (f->menu_bar_window))
5440 {
5441 struct window *w = XWINDOW (f->menu_bar_window);
5442 XRectangle window_rect;
5443 XRectangle intersection_rect;
5444 int window_x, window_y, window_width, window_height;
5445
5446
5447 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5448 window_rect.x = window_x;
5449 window_rect.y = window_y;
5450 window_rect.width = window_width;
5451 window_rect.height = window_height;
5452
5453 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5454 expose_window (w, &intersection_rect);
dc6f92b8 5455 }
06a2c219 5456#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5457}
5458
06a2c219
GM
5459
5460/* Redraw (parts) of all windows in the window tree rooted at W that
5461 intersect R. R contains frame pixel coordinates. */
5462
58769bee 5463static void
06a2c219
GM
5464expose_window_tree (w, r)
5465 struct window *w;
5466 XRectangle *r;
dc6f92b8 5467{
06a2c219
GM
5468 while (w)
5469 {
5470 if (!NILP (w->hchild))
5471 expose_window_tree (XWINDOW (w->hchild), r);
5472 else if (!NILP (w->vchild))
5473 expose_window_tree (XWINDOW (w->vchild), r);
5474 else
5475 {
5476 XRectangle window_rect;
5477 XRectangle intersection_rect;
5478 struct frame *f = XFRAME (w->frame);
5479 int window_x, window_y, window_width, window_height;
5480
5481 /* Frame-relative pixel rectangle of W. */
5482 window_box (w, -1, &window_x, &window_y, &window_width,
5483 &window_height);
5484 window_rect.x
5485 = (window_x
110859fc 5486 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
714dc26c 5487 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
06a2c219
GM
5488 window_rect.y = window_y;
5489 window_rect.width
5490 = (window_width
110859fc 5491 + FRAME_X_FLAGS_AREA_WIDTH (f)
06a2c219
GM
5492 + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
5493 window_rect.height
5494 = window_height + CURRENT_MODE_LINE_HEIGHT (w);
5495
5496 if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
5497 expose_window (w, &intersection_rect);
5498 }
58769bee 5499
06a2c219
GM
5500 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5501 }
5502}
58769bee 5503
dc6f92b8 5504
06a2c219
GM
5505/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5506 which intersects rectangle R. R is in window-relative coordinates. */
5507
5508static void
5509expose_area (w, row, r, area)
5510 struct window *w;
5511 struct glyph_row *row;
5512 XRectangle *r;
5513 enum glyph_row_area area;
5514{
5515 int x;
5516 struct glyph *first = row->glyphs[area];
5517 struct glyph *end = row->glyphs[area] + row->used[area];
5518 struct glyph *last;
5519 int first_x;
5520
5521 /* Set x to the window-relative start position for drawing glyphs of
5522 AREA. The first glyph of the text area can be partially visible.
5523 The first glyphs of other areas cannot. */
5524 if (area == LEFT_MARGIN_AREA)
5525 x = 0;
5526 else if (area == TEXT_AREA)
5527 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5528 else
5529 x = (window_box_width (w, LEFT_MARGIN_AREA)
5530 + window_box_width (w, TEXT_AREA));
5531
6fb13182
GM
5532 if (area == TEXT_AREA && row->fill_line_p)
5533 /* If row extends face to end of line write the whole line. */
5534 x_draw_glyphs (w, x, row, area,
5535 0, row->used[area],
06a2c219 5536 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5537 NULL, NULL, 0);
6fb13182
GM
5538 else
5539 {
5540 /* Find the first glyph that must be redrawn. */
5541 while (first < end
5542 && x + first->pixel_width < r->x)
5543 {
5544 x += first->pixel_width;
5545 ++first;
5546 }
5547
5548 /* Find the last one. */
5549 last = first;
5550 first_x = x;
5551 while (last < end
5552 && x < r->x + r->width)
5553 {
5554 x += last->pixel_width;
5555 ++last;
5556 }
5557
5558 /* Repaint. */
5559 if (last > first)
5560 x_draw_glyphs (w, first_x, row, area,
5561 first - row->glyphs[area],
5562 last - row->glyphs[area],
5563 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5564 NULL, NULL, 0);
5565 }
06a2c219
GM
5566}
5567
58769bee 5568
06a2c219
GM
5569/* Redraw the parts of the glyph row ROW on window W intersecting
5570 rectangle R. R is in window-relative coordinates. */
dc6f92b8 5571
06a2c219
GM
5572static void
5573expose_line (w, row, r)
5574 struct window *w;
5575 struct glyph_row *row;
5576 XRectangle *r;
5577{
5578 xassert (row->enabled_p);
5579
5580 if (row->mode_line_p || w->pseudo_window_p)
5581 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5582 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5583 NULL, NULL, 0);
06a2c219
GM
5584 else
5585 {
5586 if (row->used[LEFT_MARGIN_AREA])
5587 expose_area (w, row, r, LEFT_MARGIN_AREA);
5588 if (row->used[TEXT_AREA])
5589 expose_area (w, row, r, TEXT_AREA);
5590 if (row->used[RIGHT_MARGIN_AREA])
5591 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5592 x_draw_row_bitmaps (w, row);
5593 }
5594}
dc6f92b8 5595
58769bee 5596
06a2c219
GM
5597/* Return non-zero if W's cursor intersects rectangle R. */
5598
5599static int
5600x_phys_cursor_in_rect_p (w, r)
5601 struct window *w;
5602 XRectangle *r;
5603{
5604 XRectangle cr, result;
5605 struct glyph *cursor_glyph;
5606
5607 cursor_glyph = get_phys_cursor_glyph (w);
5608 if (cursor_glyph)
5609 {
5610 cr.x = w->phys_cursor.x;
5611 cr.y = w->phys_cursor.y;
5612 cr.width = cursor_glyph->pixel_width;
5613 cr.height = w->phys_cursor_height;
5614 return x_intersect_rectangles (&cr, r, &result);
5615 }
5616 else
5617 return 0;
dc6f92b8 5618}
dc6f92b8 5619
06a2c219
GM
5620
5621/* Redraw a rectangle of window W. R is a rectangle in window
5622 relative coordinates. Call this function with input blocked. */
dc6f92b8
JB
5623
5624static void
06a2c219
GM
5625expose_window (w, r)
5626 struct window *w;
5627 XRectangle *r;
dc6f92b8 5628{
06a2c219
GM
5629 struct glyph_row *row;
5630 int y;
5631 int yb = window_text_bottom_y (w);
5632 int cursor_cleared_p;
dc6f92b8 5633
80c32bcc
GM
5634 /* If window is not yet fully initialized, do nothing. This can
5635 happen when toolkit scroll bars are used and a window is split.
5636 Reconfiguring the scroll bar will generate an expose for a newly
5637 created window. */
5638 if (w->current_matrix == NULL)
5639 return;
5640
06a2c219
GM
5641 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
5642 r->x, r->y, r->width, r->height));
dc6f92b8 5643
06a2c219
GM
5644 /* Convert to window coordinates. */
5645 r->x = FRAME_TO_WINDOW_PIXEL_X (w, r->x);
5646 r->y = FRAME_TO_WINDOW_PIXEL_Y (w, r->y);
dc6f92b8 5647
06a2c219
GM
5648 /* Turn off the cursor. */
5649 if (!w->pseudo_window_p
5650 && x_phys_cursor_in_rect_p (w, r))
5651 {
5652 x_clear_cursor (w);
5653 cursor_cleared_p = 1;
5654 }
5655 else
5656 cursor_cleared_p = 0;
5657
5658 /* Find the first row intersecting the rectangle R. */
5659 row = w->current_matrix->rows;
5660 y = 0;
5661 while (row->enabled_p
5662 && y < yb
5663 && y + row->height < r->y)
5664 {
5665 y += row->height;
5666 ++row;
5667 }
5668
dc6f92b8 5669 /* Display the text in the rectangle, one text line at a time. */
06a2c219
GM
5670 while (row->enabled_p
5671 && y < yb
5672 && y < r->y + r->height)
5673 {
5674 expose_line (w, row, r);
5675 y += row->height;
5676 ++row;
5677 }
5678
5679 /* Display the mode line if there is one. */
5680 if (WINDOW_WANTS_MODELINE_P (w)
5681 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
5682 row->enabled_p)
5683 && row->y < r->y + r->height)
5684 expose_line (w, row, r);
dc6f92b8 5685
06a2c219 5686 if (!w->pseudo_window_p)
dc6f92b8 5687 {
06a2c219
GM
5688 /* Draw border between windows. */
5689 x_draw_vertical_border (w);
5690
5691 /* Turn the cursor on again. */
5692 if (cursor_cleared_p)
5693 x_update_window_cursor (w, 1);
5694 }
5695}
dc6f92b8 5696
dc6f92b8 5697
06a2c219
GM
5698/* Determine the intersection of two rectangles R1 and R2. Return
5699 the intersection in *RESULT. Value is non-zero if RESULT is not
5700 empty. */
5701
5702static int
5703x_intersect_rectangles (r1, r2, result)
5704 XRectangle *r1, *r2, *result;
5705{
5706 XRectangle *left, *right;
5707 XRectangle *upper, *lower;
5708 int intersection_p = 0;
5709
5710 /* Rearrange so that R1 is the left-most rectangle. */
5711 if (r1->x < r2->x)
5712 left = r1, right = r2;
5713 else
5714 left = r2, right = r1;
5715
5716 /* X0 of the intersection is right.x0, if this is inside R1,
5717 otherwise there is no intersection. */
5718 if (right->x <= left->x + left->width)
5719 {
5720 result->x = right->x;
5721
5722 /* The right end of the intersection is the minimum of the
5723 the right ends of left and right. */
5724 result->width = (min (left->x + left->width, right->x + right->width)
5725 - result->x);
5726
5727 /* Same game for Y. */
5728 if (r1->y < r2->y)
5729 upper = r1, lower = r2;
5730 else
5731 upper = r2, lower = r1;
5732
5733 /* The upper end of the intersection is lower.y0, if this is inside
5734 of upper. Otherwise, there is no intersection. */
5735 if (lower->y <= upper->y + upper->height)
dc43ef94 5736 {
06a2c219
GM
5737 result->y = lower->y;
5738
5739 /* The lower end of the intersection is the minimum of the lower
5740 ends of upper and lower. */
5741 result->height = (min (lower->y + lower->height,
5742 upper->y + upper->height)
5743 - result->y);
5744 intersection_p = 1;
dc43ef94 5745 }
dc6f92b8
JB
5746 }
5747
06a2c219 5748 return intersection_p;
dc6f92b8 5749}
06a2c219
GM
5750
5751
5752
5753
dc6f92b8 5754\f
dc6f92b8 5755static void
334208b7
RS
5756frame_highlight (f)
5757 struct frame *f;
dc6f92b8 5758{
b3e1e05c
JB
5759 /* We used to only do this if Vx_no_window_manager was non-nil, but
5760 the ICCCM (section 4.1.6) says that the window's border pixmap
5761 and border pixel are window attributes which are "private to the
5762 client", so we can always change it to whatever we want. */
5763 BLOCK_INPUT;
334208b7 5764 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5765 f->output_data.x->border_pixel);
b3e1e05c 5766 UNBLOCK_INPUT;
5d46f928 5767 x_update_cursor (f, 1);
dc6f92b8
JB
5768}
5769
5770static void
334208b7
RS
5771frame_unhighlight (f)
5772 struct frame *f;
dc6f92b8 5773{
b3e1e05c
JB
5774 /* We used to only do this if Vx_no_window_manager was non-nil, but
5775 the ICCCM (section 4.1.6) says that the window's border pixmap
5776 and border pixel are window attributes which are "private to the
5777 client", so we can always change it to whatever we want. */
5778 BLOCK_INPUT;
334208b7 5779 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5780 f->output_data.x->border_tile);
b3e1e05c 5781 UNBLOCK_INPUT;
5d46f928 5782 x_update_cursor (f, 1);
dc6f92b8 5783}
dc6f92b8 5784
f676886a
JB
5785/* The focus has changed. Update the frames as necessary to reflect
5786 the new situation. Note that we can't change the selected frame
c5acd733 5787 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 5788 Each event gets marked with the frame in which it occurred, so the
c5acd733 5789 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 5790
6d4238f3 5791static void
0f941935
KH
5792x_new_focus_frame (dpyinfo, frame)
5793 struct x_display_info *dpyinfo;
f676886a 5794 struct frame *frame;
dc6f92b8 5795{
0f941935 5796 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 5797
0f941935 5798 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 5799 {
58769bee 5800 /* Set this before calling other routines, so that they see
f676886a 5801 the correct value of x_focus_frame. */
0f941935 5802 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
5803
5804 if (old_focus && old_focus->auto_lower)
f676886a 5805 x_lower_frame (old_focus);
dc6f92b8
JB
5806
5807#if 0
f676886a 5808 selected_frame = frame;
e0c1aef2
KH
5809 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
5810 selected_frame);
f676886a
JB
5811 Fselect_window (selected_frame->selected_window);
5812 choose_minibuf_frame ();
c118dd06 5813#endif /* ! 0 */
dc6f92b8 5814
0f941935
KH
5815 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
5816 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
5817 else
5818 pending_autoraise_frame = 0;
6d4238f3 5819 }
dc6f92b8 5820
0f941935 5821 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
5822}
5823
37c2c98b
RS
5824/* Handle an event saying the mouse has moved out of an Emacs frame. */
5825
5826void
0f941935
KH
5827x_mouse_leave (dpyinfo)
5828 struct x_display_info *dpyinfo;
37c2c98b 5829{
0f941935 5830 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 5831}
6d4238f3 5832
f451eb13
JB
5833/* The focus has changed, or we have redirected a frame's focus to
5834 another frame (this happens when a frame uses a surrogate
06a2c219 5835 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
5836
5837 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 5838 frame is being highlighted or un-highlighted; we only use it to find
0f941935 5839 the appropriate X display info. */
06a2c219 5840
6d4238f3 5841static void
0f941935
KH
5842XTframe_rehighlight (frame)
5843 struct frame *frame;
6d4238f3 5844{
0f941935
KH
5845 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
5846}
6d4238f3 5847
0f941935
KH
5848static void
5849x_frame_rehighlight (dpyinfo)
5850 struct x_display_info *dpyinfo;
5851{
5852 struct frame *old_highlight = dpyinfo->x_highlight_frame;
5853
5854 if (dpyinfo->x_focus_frame)
6d4238f3 5855 {
0f941935
KH
5856 dpyinfo->x_highlight_frame
5857 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
5858 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
5859 : dpyinfo->x_focus_frame);
5860 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 5861 {
0f941935
KH
5862 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
5863 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 5864 }
dc6f92b8 5865 }
6d4238f3 5866 else
0f941935 5867 dpyinfo->x_highlight_frame = 0;
dc6f92b8 5868
0f941935 5869 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
5870 {
5871 if (old_highlight)
f676886a 5872 frame_unhighlight (old_highlight);
0f941935
KH
5873 if (dpyinfo->x_highlight_frame)
5874 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 5875 }
dc6f92b8 5876}
06a2c219
GM
5877
5878
dc6f92b8 5879\f
06a2c219 5880/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 5881
28430d3c
JB
5882/* Initialize mode_switch_bit and modifier_meaning. */
5883static void
334208b7
RS
5884x_find_modifier_meanings (dpyinfo)
5885 struct x_display_info *dpyinfo;
28430d3c 5886{
f689eb05 5887 int min_code, max_code;
28430d3c
JB
5888 KeySym *syms;
5889 int syms_per_code;
5890 XModifierKeymap *mods;
5891
334208b7
RS
5892 dpyinfo->meta_mod_mask = 0;
5893 dpyinfo->shift_lock_mask = 0;
5894 dpyinfo->alt_mod_mask = 0;
5895 dpyinfo->super_mod_mask = 0;
5896 dpyinfo->hyper_mod_mask = 0;
58769bee 5897
9658a521 5898#ifdef HAVE_X11R4
334208b7 5899 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 5900#else
4a60f8c5
RS
5901 min_code = dpyinfo->display->min_keycode;
5902 max_code = dpyinfo->display->max_keycode;
9658a521
JB
5903#endif
5904
334208b7 5905 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
5906 min_code, max_code - min_code + 1,
5907 &syms_per_code);
334208b7 5908 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 5909
58769bee 5910 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 5911 Alt keysyms are on. */
28430d3c 5912 {
06a2c219 5913 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
5914
5915 for (row = 3; row < 8; row++)
5916 for (col = 0; col < mods->max_keypermod; col++)
5917 {
0299d313
RS
5918 KeyCode code
5919 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 5920
af92970c
KH
5921 /* Zeroes are used for filler. Skip them. */
5922 if (code == 0)
5923 continue;
5924
28430d3c
JB
5925 /* Are any of this keycode's keysyms a meta key? */
5926 {
5927 int code_col;
5928
5929 for (code_col = 0; code_col < syms_per_code; code_col++)
5930 {
f689eb05 5931 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 5932
f689eb05 5933 switch (sym)
28430d3c 5934 {
f689eb05
JB
5935 case XK_Meta_L:
5936 case XK_Meta_R:
334208b7 5937 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 5938 break;
f689eb05
JB
5939
5940 case XK_Alt_L:
5941 case XK_Alt_R:
334208b7 5942 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
5943 break;
5944
5945 case XK_Hyper_L:
5946 case XK_Hyper_R:
334208b7 5947 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
5948 break;
5949
5950 case XK_Super_L:
5951 case XK_Super_R:
334208b7 5952 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 5953 break;
11edeb03
JB
5954
5955 case XK_Shift_Lock:
5956 /* Ignore this if it's not on the lock modifier. */
5957 if ((1 << row) == LockMask)
334208b7 5958 dpyinfo->shift_lock_mask = LockMask;
11edeb03 5959 break;
28430d3c
JB
5960 }
5961 }
5962 }
5963 }
5964 }
5965
f689eb05 5966 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 5967 if (! dpyinfo->meta_mod_mask)
a3c44b14 5968 {
334208b7
RS
5969 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
5970 dpyinfo->alt_mod_mask = 0;
a3c44b14 5971 }
f689eb05 5972
148c4b70
RS
5973 /* If some keys are both alt and meta,
5974 make them just meta, not alt. */
334208b7 5975 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 5976 {
334208b7 5977 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 5978 }
58769bee 5979
28430d3c 5980 XFree ((char *) syms);
f689eb05 5981 XFreeModifiermap (mods);
28430d3c
JB
5982}
5983
dfeccd2d
JB
5984/* Convert between the modifier bits X uses and the modifier bits
5985 Emacs uses. */
06a2c219 5986
7c5283e4 5987static unsigned int
334208b7
RS
5988x_x_to_emacs_modifiers (dpyinfo, state)
5989 struct x_display_info *dpyinfo;
dc6f92b8
JB
5990 unsigned int state;
5991{
334208b7
RS
5992 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
5993 | ((state & ControlMask) ? ctrl_modifier : 0)
5994 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
5995 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
5996 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
5997 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
5998}
5999
dfeccd2d 6000static unsigned int
334208b7
RS
6001x_emacs_to_x_modifiers (dpyinfo, state)
6002 struct x_display_info *dpyinfo;
dfeccd2d
JB
6003 unsigned int state;
6004{
334208b7
RS
6005 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6006 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6007 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6008 | ((state & shift_modifier) ? ShiftMask : 0)
6009 | ((state & ctrl_modifier) ? ControlMask : 0)
6010 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6011}
d047c4eb
KH
6012
6013/* Convert a keysym to its name. */
6014
6015char *
6016x_get_keysym_name (keysym)
6017 KeySym keysym;
6018{
6019 char *value;
6020
6021 BLOCK_INPUT;
6022 value = XKeysymToString (keysym);
6023 UNBLOCK_INPUT;
6024
6025 return value;
6026}
06a2c219
GM
6027
6028
e4571a43
JB
6029\f
6030/* Mouse clicks and mouse movement. Rah. */
e4571a43 6031
06a2c219
GM
6032/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6033 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6034 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6035 not force the value into range. */
69388238 6036
c8dba240 6037void
69388238 6038pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6039 FRAME_PTR f;
69388238 6040 register int pix_x, pix_y;
e4571a43
JB
6041 register int *x, *y;
6042 XRectangle *bounds;
69388238 6043 int noclip;
e4571a43 6044{
06a2c219 6045 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6046 even for negative values. */
6047 if (pix_x < 0)
7556890b 6048 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6049 if (pix_y < 0)
7556890b 6050 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6051
e4571a43
JB
6052 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6053 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6054
6055 if (bounds)
6056 {
7556890b
RS
6057 bounds->width = FONT_WIDTH (f->output_data.x->font);
6058 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6059 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6060 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6061 }
6062
69388238
RS
6063 if (!noclip)
6064 {
6065 if (pix_x < 0)
6066 pix_x = 0;
3cbd2e0b
RS
6067 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6068 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6069
6070 if (pix_y < 0)
6071 pix_y = 0;
6072 else if (pix_y > f->height)
6073 pix_y = f->height;
6074 }
e4571a43
JB
6075
6076 *x = pix_x;
6077 *y = pix_y;
6078}
6079
06a2c219
GM
6080
6081/* Given HPOS/VPOS in the current matrix of W, return corresponding
6082 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6083 can't tell the positions because W's display is not up to date,
6084 return 0. */
6085
6086int
6087glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6088 struct window *w;
6089 int hpos, vpos;
6090 int *frame_x, *frame_y;
2b5c9e71 6091{
06a2c219
GM
6092 int success_p;
6093
6094 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6095 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6096
6097 if (display_completed)
6098 {
6099 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6100 struct glyph *glyph = row->glyphs[TEXT_AREA];
6101 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6102
6103 *frame_y = row->y;
6104 *frame_x = row->x;
6105 while (glyph < end)
6106 {
6107 *frame_x += glyph->pixel_width;
6108 ++glyph;
6109 }
6110
6111 success_p = 1;
6112 }
6113 else
6114 {
6115 *frame_y = *frame_x = 0;
6116 success_p = 0;
6117 }
6118
6119 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6120 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6121 return success_p;
2b5c9e71
RS
6122}
6123
06a2c219 6124
dc6f92b8
JB
6125/* Prepare a mouse-event in *RESULT for placement in the input queue.
6126
6127 If the event is a button press, then note that we have grabbed
f451eb13 6128 the mouse. */
dc6f92b8
JB
6129
6130static Lisp_Object
f451eb13 6131construct_mouse_click (result, event, f)
dc6f92b8
JB
6132 struct input_event *result;
6133 XButtonEvent *event;
f676886a 6134 struct frame *f;
dc6f92b8 6135{
f451eb13 6136 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6137 otherwise. */
f451eb13 6138 result->kind = mouse_click;
69388238 6139 result->code = event->button - Button1;
1113d9db 6140 result->timestamp = event->time;
334208b7
RS
6141 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6142 event->state)
f689eb05 6143 | (event->type == ButtonRelease
58769bee 6144 ? up_modifier
f689eb05 6145 : down_modifier));
dc6f92b8 6146
06a2c219
GM
6147 XSETINT (result->x, event->x);
6148 XSETINT (result->y, event->y);
6149 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6150 result->arg = Qnil;
06a2c219 6151 return Qnil;
dc6f92b8 6152}
b849c413 6153
69388238 6154\f
90e65f07
JB
6155/* Function to report a mouse movement to the mainstream Emacs code.
6156 The input handler calls this.
6157
6158 We have received a mouse movement event, which is given in *event.
6159 If the mouse is over a different glyph than it was last time, tell
6160 the mainstream emacs code by setting mouse_moved. If not, ask for
6161 another motion event, so we can check again the next time it moves. */
b8009dd1 6162
06a2c219
GM
6163static XMotionEvent last_mouse_motion_event;
6164static Lisp_Object last_mouse_motion_frame;
6165
90e65f07 6166static void
12ba150f 6167note_mouse_movement (frame, event)
f676886a 6168 FRAME_PTR frame;
90e65f07 6169 XMotionEvent *event;
90e65f07 6170{
e5d77022 6171 last_mouse_movement_time = event->time;
06a2c219
GM
6172 last_mouse_motion_event = *event;
6173 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6174
27f338af
RS
6175 if (event->window != FRAME_X_WINDOW (frame))
6176 {
39d8bb4d 6177 frame->mouse_moved = 1;
27f338af 6178 last_mouse_scroll_bar = Qnil;
27f338af 6179 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6180 }
6181
90e65f07 6182 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6183 else if (event->x < last_mouse_glyph.x
6184 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6185 || event->y < last_mouse_glyph.y
6186 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6187 {
39d8bb4d 6188 frame->mouse_moved = 1;
ab648270 6189 last_mouse_scroll_bar = Qnil;
b8009dd1 6190 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6191 }
6192}
6193
bf1c0ba1 6194/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6195
06a2c219
GM
6196 int disable_mouse_highlight;
6197
6198
6199\f
6200/************************************************************************
6201 Mouse Face
6202 ************************************************************************/
6203
6204/* Find the glyph under window-relative coordinates X/Y in window W.
6205 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6206 strings. Return in *HPOS and *VPOS the row and column number of
6207 the glyph found. Return in *AREA the glyph area containing X.
6208 Value is a pointer to the glyph found or null if X/Y is not on
6209 text, or we can't tell because W's current matrix is not up to
6210 date. */
6211
6212static struct glyph *
6213x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
6214 struct window *w;
6215 int x, y;
6216 int *hpos, *vpos, *area;
6217{
6218 struct glyph *glyph, *end;
3e71d8f2 6219 struct glyph_row *row = NULL;
06a2c219
GM
6220 int x0, i, left_area_width;
6221
6222 /* Find row containing Y. Give up if some row is not enabled. */
6223 for (i = 0; i < w->current_matrix->nrows; ++i)
6224 {
6225 row = MATRIX_ROW (w->current_matrix, i);
6226 if (!row->enabled_p)
6227 return NULL;
6228 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6229 break;
6230 }
6231
6232 *vpos = i;
6233 *hpos = 0;
6234
6235 /* Give up if Y is not in the window. */
6236 if (i == w->current_matrix->nrows)
6237 return NULL;
6238
6239 /* Get the glyph area containing X. */
6240 if (w->pseudo_window_p)
6241 {
6242 *area = TEXT_AREA;
6243 x0 = 0;
6244 }
6245 else
6246 {
6247 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6248 if (x < left_area_width)
6249 {
6250 *area = LEFT_MARGIN_AREA;
6251 x0 = 0;
6252 }
6253 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6254 {
6255 *area = TEXT_AREA;
6256 x0 = row->x + left_area_width;
6257 }
6258 else
6259 {
6260 *area = RIGHT_MARGIN_AREA;
6261 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6262 }
6263 }
6264
6265 /* Find glyph containing X. */
6266 glyph = row->glyphs[*area];
6267 end = glyph + row->used[*area];
6268 while (glyph < end)
6269 {
6270 if (x < x0 + glyph->pixel_width)
6271 {
6272 if (w->pseudo_window_p)
6273 break;
6274 else if (BUFFERP (glyph->object))
6275 break;
6276 }
6277
6278 x0 += glyph->pixel_width;
6279 ++glyph;
6280 }
6281
6282 if (glyph == end)
6283 return NULL;
6284
6285 *hpos = glyph - row->glyphs[*area];
6286 return glyph;
6287}
6288
6289
6290/* Convert frame-relative x/y to coordinates relative to window W.
6291 Takes pseudo-windows into account. */
6292
6293static void
6294frame_to_window_pixel_xy (w, x, y)
6295 struct window *w;
6296 int *x, *y;
6297{
6298 if (w->pseudo_window_p)
6299 {
6300 /* A pseudo-window is always full-width, and starts at the
6301 left edge of the frame, plus a frame border. */
6302 struct frame *f = XFRAME (w->frame);
6303 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6304 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6305 }
6306 else
6307 {
6308 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6309 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6310 }
6311}
6312
6313
6314/* Take proper action when mouse has moved to the mode or top line of
6315 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6316 mode line. X is relative to the start of the text display area of
6317 W, so the width of bitmap areas and scroll bars must be subtracted
6318 to get a position relative to the start of the mode line. */
6319
6320static void
6321note_mode_line_highlight (w, x, mode_line_p)
6322 struct window *w;
6323 int x, mode_line_p;
6324{
6325 struct frame *f = XFRAME (w->frame);
6326 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6327 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6328 struct glyph_row *row;
6329
6330 if (mode_line_p)
6331 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6332 else
045dee35 6333 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
06a2c219
GM
6334
6335 if (row->enabled_p)
6336 {
6337 struct glyph *glyph, *end;
6338 Lisp_Object help, map;
6339 int x0;
6340
6341 /* Find the glyph under X. */
6342 glyph = row->glyphs[TEXT_AREA];
6343 end = glyph + row->used[TEXT_AREA];
6344 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6345 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
6346 while (glyph < end
6347 && x >= x0 + glyph->pixel_width)
6348 {
6349 x0 += glyph->pixel_width;
6350 ++glyph;
6351 }
6352
6353 if (glyph < end
6354 && STRINGP (glyph->object)
6355 && XSTRING (glyph->object)->intervals
6356 && glyph->charpos >= 0
6357 && glyph->charpos < XSTRING (glyph->object)->size)
6358 {
6359 /* If we're on a string with `help-echo' text property,
6360 arrange for the help to be displayed. This is done by
6361 setting the global variable help_echo to the help string. */
6362 help = Fget_text_property (make_number (glyph->charpos),
6363 Qhelp_echo, glyph->object);
b7e80413 6364 if (!NILP (help))
be010514
GM
6365 {
6366 help_echo = help;
7cea38bc 6367 XSETWINDOW (help_echo_window, w);
be010514
GM
6368 help_echo_object = glyph->object;
6369 help_echo_pos = glyph->charpos;
6370 }
06a2c219
GM
6371
6372 /* Change the mouse pointer according to what is under X/Y. */
6373 map = Fget_text_property (make_number (glyph->charpos),
6374 Qlocal_map, glyph->object);
6375 if (!NILP (Fkeymapp (map)))
6376 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6377 else
6378 {
6379 map = Fget_text_property (make_number (glyph->charpos),
6380 Qkeymap, glyph->object);
6381 if (!NILP (Fkeymapp (map)))
6382 cursor = f->output_data.x->nontext_cursor;
6383 }
06a2c219
GM
6384 }
6385 }
6386
6387 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6388}
6389
6390
6391/* Take proper action when the mouse has moved to position X, Y on
6392 frame F as regards highlighting characters that have mouse-face
6393 properties. Also de-highlighting chars where the mouse was before.
27f338af 6394 X and Y can be negative or out of range. */
b8009dd1
RS
6395
6396static void
6397note_mouse_highlight (f, x, y)
06a2c219 6398 struct frame *f;
c32cdd9a 6399 int x, y;
b8009dd1 6400{
06a2c219
GM
6401 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6402 int portion;
b8009dd1
RS
6403 Lisp_Object window;
6404 struct window *w;
6405
06a2c219
GM
6406 /* When a menu is active, don't highlight because this looks odd. */
6407#ifdef USE_X_TOOLKIT
6408 if (popup_activated ())
6409 return;
6410#endif
6411
04fff9c0
GM
6412 if (disable_mouse_highlight
6413 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6414 return;
6415
06a2c219
GM
6416 dpyinfo->mouse_face_mouse_x = x;
6417 dpyinfo->mouse_face_mouse_y = y;
6418 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6419
06a2c219 6420 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6421 return;
6422
514e4681
RS
6423 if (gc_in_progress)
6424 {
06a2c219 6425 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6426 return;
6427 }
6428
b8009dd1 6429 /* Which window is that in? */
06a2c219 6430 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6431
6432 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6433 if (! EQ (window, dpyinfo->mouse_face_window))
6434 clear_mouse_face (dpyinfo);
6435
6436 /* Not on a window -> return. */
6437 if (!WINDOWP (window))
6438 return;
6439
6440 /* Convert to window-relative pixel coordinates. */
6441 w = XWINDOW (window);
6442 frame_to_window_pixel_xy (w, &x, &y);
6443
9ea173e8 6444 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6445 buffer. */
9ea173e8 6446 if (EQ (window, f->tool_bar_window))
06a2c219 6447 {
9ea173e8 6448 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6449 return;
6450 }
6451
6452 if (portion == 1 || portion == 3)
6453 {
6454 /* Mouse is on the mode or top line. */
6455 note_mode_line_highlight (w, x, portion == 1);
6456 return;
6457 }
6458 else
6459 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6460 f->output_data.x->text_cursor);
b8009dd1 6461
0cdd0c9f
RS
6462 /* Are we in a window whose display is up to date?
6463 And verify the buffer's text has not changed. */
06a2c219
GM
6464 if (/* Within text portion of the window. */
6465 portion == 0
0cdd0c9f 6466 && EQ (w->window_end_valid, w->buffer)
26459b28
KH
6467 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
6468 && (XFASTINT (w->last_overlay_modified)
6469 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
b8009dd1 6470 {
06a2c219
GM
6471 int hpos, vpos, pos, i, area;
6472 struct glyph *glyph;
b8009dd1 6473
06a2c219
GM
6474 /* Find the glyph under X/Y. */
6475 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
6476
6477 /* Clear mouse face if X/Y not over text. */
6478 if (glyph == NULL
6479 || area != TEXT_AREA
6480 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6481 {
06a2c219
GM
6482 clear_mouse_face (dpyinfo);
6483 return;
6484 }
6485
6486 pos = glyph->charpos;
6487 xassert (w->pseudo_window_p || BUFFERP (glyph->object));
6488
6489 /* Check for mouse-face and help-echo. */
6490 {
6491 Lisp_Object mouse_face, overlay, position;
6492 Lisp_Object *overlay_vec;
6493 int len, noverlays;
6494 struct buffer *obuf;
6495 int obegv, ozv;
6496
6497 /* If we get an out-of-range value, return now; avoid an error. */
6498 if (pos > BUF_Z (XBUFFER (w->buffer)))
6499 return;
6500
6501 /* Make the window's buffer temporarily current for
6502 overlays_at and compute_char_face. */
6503 obuf = current_buffer;
6504 current_buffer = XBUFFER (w->buffer);
6505 obegv = BEGV;
6506 ozv = ZV;
6507 BEGV = BEG;
6508 ZV = Z;
6509
6510 /* Is this char mouse-active or does it have help-echo? */
6511 XSETINT (position, pos);
6512
6513 /* Put all the overlays we want in a vector in overlay_vec.
6514 Store the length in len. If there are more than 10, make
6515 enough space for all, and try again. */
6516 len = 10;
6517 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6518 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6519 if (noverlays > len)
6520 {
6521 len = noverlays;
6522 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6523 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6524 }
f8349001
GM
6525
6526 /* Sort overlays into increasing priority order. */
06a2c219
GM
6527 noverlays = sort_overlays (overlay_vec, noverlays, w);
6528
6529 /* Check mouse-face highlighting. */
6530 if (! (EQ (window, dpyinfo->mouse_face_window)
6531 && vpos >= dpyinfo->mouse_face_beg_row
6532 && vpos <= dpyinfo->mouse_face_end_row
6533 && (vpos > dpyinfo->mouse_face_beg_row
6534 || hpos >= dpyinfo->mouse_face_beg_col)
6535 && (vpos < dpyinfo->mouse_face_end_row
6536 || hpos < dpyinfo->mouse_face_end_col
6537 || dpyinfo->mouse_face_past_end)))
6538 {
6539 /* Clear the display of the old active region, if any. */
6540 clear_mouse_face (dpyinfo);
6541
6542 /* Find the highest priority overlay that has a mouse-face prop. */
6543 overlay = Qnil;
f8349001 6544 for (i = noverlays - 1; i >= 0; --i)
06a2c219
GM
6545 {
6546 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6547 if (!NILP (mouse_face))
6548 {
6549 overlay = overlay_vec[i];
6550 break;
6551 }
6552 }
6553
6554 /* If no overlay applies, get a text property. */
6555 if (NILP (overlay))
6556 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6557
6558 /* Handle the overlay case. */
6559 if (! NILP (overlay))
6560 {
6561 /* Find the range of text around this char that
6562 should be active. */
6563 Lisp_Object before, after;
6564 int ignore;
6565
6566 before = Foverlay_start (overlay);
6567 after = Foverlay_end (overlay);
6568 /* Record this as the current active region. */
6569 fast_find_position (w, XFASTINT (before),
6570 &dpyinfo->mouse_face_beg_col,
6571 &dpyinfo->mouse_face_beg_row,
6572 &dpyinfo->mouse_face_beg_x,
6573 &dpyinfo->mouse_face_beg_y);
6574 dpyinfo->mouse_face_past_end
6575 = !fast_find_position (w, XFASTINT (after),
6576 &dpyinfo->mouse_face_end_col,
6577 &dpyinfo->mouse_face_end_row,
6578 &dpyinfo->mouse_face_end_x,
6579 &dpyinfo->mouse_face_end_y);
6580 dpyinfo->mouse_face_window = window;
6581 dpyinfo->mouse_face_face_id
6582 = face_at_buffer_position (w, pos, 0, 0,
6583 &ignore, pos + 1, 1);
6584
6585 /* Display it as active. */
6586 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6587 }
6588 /* Handle the text property case. */
6589 else if (! NILP (mouse_face))
6590 {
6591 /* Find the range of text around this char that
6592 should be active. */
6593 Lisp_Object before, after, beginning, end;
6594 int ignore;
6595
6596 beginning = Fmarker_position (w->start);
6597 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
6598 - XFASTINT (w->window_end_pos)));
6599 before
6600 = Fprevious_single_property_change (make_number (pos + 1),
6601 Qmouse_face,
6602 w->buffer, beginning);
6603 after
6604 = Fnext_single_property_change (position, Qmouse_face,
6605 w->buffer, end);
6606 /* Record this as the current active region. */
6607 fast_find_position (w, XFASTINT (before),
6608 &dpyinfo->mouse_face_beg_col,
6609 &dpyinfo->mouse_face_beg_row,
6610 &dpyinfo->mouse_face_beg_x,
6611 &dpyinfo->mouse_face_beg_y);
6612 dpyinfo->mouse_face_past_end
6613 = !fast_find_position (w, XFASTINT (after),
6614 &dpyinfo->mouse_face_end_col,
6615 &dpyinfo->mouse_face_end_row,
6616 &dpyinfo->mouse_face_end_x,
6617 &dpyinfo->mouse_face_end_y);
6618 dpyinfo->mouse_face_window = window;
6619 dpyinfo->mouse_face_face_id
6620 = face_at_buffer_position (w, pos, 0, 0,
6621 &ignore, pos + 1, 1);
6622
6623 /* Display it as active. */
6624 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6625 }
6626 }
6627
6628 /* Look for a `help-echo' property. */
6629 {
743934db 6630 Lisp_Object help, overlay;
06a2c219
GM
6631
6632 /* Check overlays first. */
6633 help = Qnil;
f8349001 6634 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
743934db
GM
6635 {
6636 overlay = overlay_vec[i];
6637 help = Foverlay_get (overlay, Qhelp_echo);
6638 }
be010514
GM
6639
6640 if (!NILP (help))
6641 {
6642 help_echo = help;
7cea38bc 6643 help_echo_window = window;
743934db 6644 help_echo_object = overlay;
be010514
GM
6645 help_echo_pos = pos;
6646 }
6647 else
6648 {
6649 /* Try text properties. */
6650 if ((STRINGP (glyph->object)
06a2c219
GM
6651 && glyph->charpos >= 0
6652 && glyph->charpos < XSTRING (glyph->object)->size)
6653 || (BUFFERP (glyph->object)
6654 && glyph->charpos >= BEGV
be010514
GM
6655 && glyph->charpos < ZV))
6656 help = Fget_text_property (make_number (glyph->charpos),
6657 Qhelp_echo, glyph->object);
06a2c219 6658
be010514
GM
6659 if (!NILP (help))
6660 {
6661 help_echo = help;
7cea38bc 6662 help_echo_window = window;
be010514
GM
6663 help_echo_object = glyph->object;
6664 help_echo_pos = glyph->charpos;
6665 }
6666 }
06a2c219
GM
6667 }
6668
6669 BEGV = obegv;
6670 ZV = ozv;
6671 current_buffer = obuf;
6672 }
6673 }
6674}
6675
6676static void
6677redo_mouse_highlight ()
6678{
6679 if (!NILP (last_mouse_motion_frame)
6680 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
6681 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
6682 last_mouse_motion_event.x,
6683 last_mouse_motion_event.y);
6684}
6685
6686
6687\f
6688/***********************************************************************
9ea173e8 6689 Tool-bars
06a2c219
GM
6690 ***********************************************************************/
6691
9ea173e8
GM
6692static int x_tool_bar_item P_ ((struct frame *, int, int,
6693 struct glyph **, int *, int *, int *));
06a2c219 6694
9ea173e8 6695/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
6696 or -1. */
6697
9ea173e8 6698static int last_tool_bar_item;
06a2c219
GM
6699
6700
9ea173e8
GM
6701/* Get information about the tool-bar item at position X/Y on frame F.
6702 Return in *GLYPH a pointer to the glyph of the tool-bar item in
6703 the current matrix of the tool-bar window of F, or NULL if not
6704 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
6705 item in F->current_tool_bar_items. Value is
06a2c219 6706
9ea173e8 6707 -1 if X/Y is not on a tool-bar item
06a2c219
GM
6708 0 if X/Y is on the same item that was highlighted before.
6709 1 otherwise. */
6710
6711static int
9ea173e8 6712x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
6713 struct frame *f;
6714 int x, y;
6715 struct glyph **glyph;
6716 int *hpos, *vpos, *prop_idx;
6717{
6718 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6719 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6720 int area;
6721
6722 /* Find the glyph under X/Y. */
6723 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
6724 if (*glyph == NULL)
6725 return -1;
6726
9ea173e8
GM
6727 /* Get the start of this tool-bar item's properties in
6728 f->current_tool_bar_items. */
6729 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
6730 return -1;
6731
6732 /* Is mouse on the highlighted item? */
9ea173e8 6733 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
6734 && *vpos >= dpyinfo->mouse_face_beg_row
6735 && *vpos <= dpyinfo->mouse_face_end_row
6736 && (*vpos > dpyinfo->mouse_face_beg_row
6737 || *hpos >= dpyinfo->mouse_face_beg_col)
6738 && (*vpos < dpyinfo->mouse_face_end_row
6739 || *hpos < dpyinfo->mouse_face_end_col
6740 || dpyinfo->mouse_face_past_end))
6741 return 0;
6742
6743 return 1;
6744}
6745
6746
9ea173e8 6747/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
6748 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
6749 or ButtonRelase. */
6750
6751static void
9ea173e8 6752x_handle_tool_bar_click (f, button_event)
06a2c219
GM
6753 struct frame *f;
6754 XButtonEvent *button_event;
6755{
6756 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6757 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6758 int hpos, vpos, prop_idx;
6759 struct glyph *glyph;
6760 Lisp_Object enabled_p;
6761 int x = button_event->x;
6762 int y = button_event->y;
6763
9ea173e8 6764 /* If not on the highlighted tool-bar item, return. */
06a2c219 6765 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 6766 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
6767 return;
6768
6769 /* If item is disabled, do nothing. */
9ea173e8
GM
6770 enabled_p = (XVECTOR (f->current_tool_bar_items)
6771 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6772 if (NILP (enabled_p))
6773 return;
6774
6775 if (button_event->type == ButtonPress)
6776 {
6777 /* Show item in pressed state. */
6778 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
6779 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 6780 last_tool_bar_item = prop_idx;
06a2c219
GM
6781 }
6782 else
6783 {
6784 Lisp_Object key, frame;
6785 struct input_event event;
6786
6787 /* Show item in released state. */
6788 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
6789 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
6790
9ea173e8
GM
6791 key = (XVECTOR (f->current_tool_bar_items)
6792 ->contents[prop_idx + TOOL_BAR_ITEM_KEY]);
06a2c219
GM
6793
6794 XSETFRAME (frame, f);
9ea173e8 6795 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
6796 event.frame_or_window = frame;
6797 event.arg = frame;
06a2c219
GM
6798 kbd_buffer_store_event (&event);
6799
9ea173e8 6800 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
6801 event.frame_or_window = frame;
6802 event.arg = key;
06a2c219
GM
6803 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6804 button_event->state);
6805 kbd_buffer_store_event (&event);
9ea173e8 6806 last_tool_bar_item = -1;
06a2c219
GM
6807 }
6808}
6809
6810
9ea173e8
GM
6811/* Possibly highlight a tool-bar item on frame F when mouse moves to
6812 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
6813 note_mouse_highlight. */
6814
6815static void
9ea173e8 6816note_tool_bar_highlight (f, x, y)
06a2c219
GM
6817 struct frame *f;
6818 int x, y;
6819{
9ea173e8 6820 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
6821 struct window *w = XWINDOW (window);
6822 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6823 int hpos, vpos;
6824 struct glyph *glyph;
6825 struct glyph_row *row;
5c187dee 6826 int i;
06a2c219
GM
6827 Lisp_Object enabled_p;
6828 int prop_idx;
6829 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
5c187dee 6830 int mouse_down_p, rc;
06a2c219
GM
6831
6832 /* Function note_mouse_highlight is called with negative x(y
6833 values when mouse moves outside of the frame. */
6834 if (x <= 0 || y <= 0)
6835 {
6836 clear_mouse_face (dpyinfo);
6837 return;
6838 }
6839
9ea173e8 6840 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
6841 if (rc < 0)
6842 {
9ea173e8 6843 /* Not on tool-bar item. */
06a2c219
GM
6844 clear_mouse_face (dpyinfo);
6845 return;
6846 }
6847 else if (rc == 0)
9ea173e8 6848 /* On same tool-bar item as before. */
06a2c219 6849 goto set_help_echo;
b8009dd1 6850
06a2c219
GM
6851 clear_mouse_face (dpyinfo);
6852
9ea173e8 6853 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
6854 mouse_down_p = (dpyinfo->grabbed
6855 && f == last_mouse_frame
6856 && FRAME_LIVE_P (f));
6857 if (mouse_down_p
9ea173e8 6858 && last_tool_bar_item != prop_idx)
06a2c219
GM
6859 return;
6860
6861 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
6862 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
6863
9ea173e8
GM
6864 /* If tool-bar item is not enabled, don't highlight it. */
6865 enabled_p = (XVECTOR (f->current_tool_bar_items)
6866 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6867 if (!NILP (enabled_p))
6868 {
6869 /* Compute the x-position of the glyph. In front and past the
6870 image is a space. We include this is the highlighted area. */
6871 row = MATRIX_ROW (w->current_matrix, vpos);
6872 for (i = x = 0; i < hpos; ++i)
6873 x += row->glyphs[TEXT_AREA][i].pixel_width;
6874
6875 /* Record this as the current active region. */
6876 dpyinfo->mouse_face_beg_col = hpos;
6877 dpyinfo->mouse_face_beg_row = vpos;
6878 dpyinfo->mouse_face_beg_x = x;
6879 dpyinfo->mouse_face_beg_y = row->y;
6880 dpyinfo->mouse_face_past_end = 0;
6881
6882 dpyinfo->mouse_face_end_col = hpos + 1;
6883 dpyinfo->mouse_face_end_row = vpos;
6884 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
6885 dpyinfo->mouse_face_end_y = row->y;
6886 dpyinfo->mouse_face_window = window;
9ea173e8 6887 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
6888
6889 /* Display it as active. */
6890 show_mouse_face (dpyinfo, draw);
6891 dpyinfo->mouse_face_image_state = draw;
b8009dd1 6892 }
06a2c219
GM
6893
6894 set_help_echo:
6895
9ea173e8 6896 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 6897 XTread_socket does the rest. */
7cea38bc 6898 help_echo_object = help_echo_window = Qnil;
be010514 6899 help_echo_pos = -1;
9ea173e8
GM
6900 help_echo = (XVECTOR (f->current_tool_bar_items)
6901 ->contents[prop_idx + TOOL_BAR_ITEM_HELP]);
b7e80413 6902 if (NILP (help_echo))
9ea173e8
GM
6903 help_echo = (XVECTOR (f->current_tool_bar_items)
6904 ->contents[prop_idx + TOOL_BAR_ITEM_CAPTION]);
b8009dd1 6905}
4d73d038 6906
06a2c219
GM
6907
6908\f
6909/* Find the glyph matrix position of buffer position POS in window W.
6910 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
6911 current glyphs must be up to date. If POS is above window start
6912 return (0, 0, 0, 0). If POS is after end of W, return end of
6913 last line in W. */
b8009dd1
RS
6914
6915static int
06a2c219
GM
6916fast_find_position (w, pos, hpos, vpos, x, y)
6917 struct window *w;
b8009dd1 6918 int pos;
06a2c219 6919 int *hpos, *vpos, *x, *y;
b8009dd1 6920{
b8009dd1 6921 int i;
bf1c0ba1 6922 int lastcol;
06a2c219
GM
6923 int maybe_next_line_p = 0;
6924 int line_start_position;
6925 int yb = window_text_bottom_y (w);
6926 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
6927 struct glyph_row *best_row = row;
6928 int row_vpos = 0, best_row_vpos = 0;
6929 int current_x;
6930
6931 while (row->y < yb)
b8009dd1 6932 {
06a2c219
GM
6933 if (row->used[TEXT_AREA])
6934 line_start_position = row->glyphs[TEXT_AREA]->charpos;
6935 else
6936 line_start_position = 0;
6937
6938 if (line_start_position > pos)
b8009dd1 6939 break;
77b68646
RS
6940 /* If the position sought is the end of the buffer,
6941 don't include the blank lines at the bottom of the window. */
06a2c219
GM
6942 else if (line_start_position == pos
6943 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 6944 {
06a2c219 6945 maybe_next_line_p = 1;
77b68646
RS
6946 break;
6947 }
06a2c219
GM
6948 else if (line_start_position > 0)
6949 {
6950 best_row = row;
6951 best_row_vpos = row_vpos;
6952 }
4b0bb6f3
GM
6953
6954 if (row->y + row->height >= yb)
6955 break;
06a2c219
GM
6956
6957 ++row;
6958 ++row_vpos;
b8009dd1 6959 }
06a2c219
GM
6960
6961 /* Find the right column within BEST_ROW. */
6962 lastcol = 0;
6963 current_x = best_row->x;
6964 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 6965 {
06a2c219
GM
6966 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
6967 int charpos;
6968
6969 charpos = glyph->charpos;
6970 if (charpos == pos)
bf1c0ba1 6971 {
06a2c219
GM
6972 *hpos = i;
6973 *vpos = best_row_vpos;
6974 *x = current_x;
6975 *y = best_row->y;
bf1c0ba1
RS
6976 return 1;
6977 }
06a2c219 6978 else if (charpos > pos)
4d73d038 6979 break;
06a2c219
GM
6980 else if (charpos > 0)
6981 lastcol = i;
6982
6983 current_x += glyph->pixel_width;
bf1c0ba1 6984 }
b8009dd1 6985
77b68646
RS
6986 /* If we're looking for the end of the buffer,
6987 and we didn't find it in the line we scanned,
6988 use the start of the following line. */
06a2c219 6989 if (maybe_next_line_p)
77b68646 6990 {
06a2c219
GM
6991 ++best_row;
6992 ++best_row_vpos;
6993 lastcol = 0;
6994 current_x = best_row->x;
77b68646
RS
6995 }
6996
06a2c219
GM
6997 *vpos = best_row_vpos;
6998 *hpos = lastcol + 1;
6999 *x = current_x;
7000 *y = best_row->y;
b8009dd1
RS
7001 return 0;
7002}
7003
06a2c219 7004
b8009dd1
RS
7005/* Display the active region described by mouse_face_*
7006 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7007
7008static void
06a2c219 7009show_mouse_face (dpyinfo, draw)
7a13e894 7010 struct x_display_info *dpyinfo;
06a2c219 7011 enum draw_glyphs_face draw;
b8009dd1 7012{
7a13e894 7013 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7014 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 7015 int i;
06a2c219
GM
7016 int cursor_off_p = 0;
7017 struct cursor_pos saved_cursor;
7018
7019 saved_cursor = output_cursor;
7020
7021 /* If window is in the process of being destroyed, don't bother
7022 to do anything. */
7023 if (w->current_matrix == NULL)
7024 goto set_x_cursor;
7025
7026 /* Recognize when we are called to operate on rows that don't exist
7027 anymore. This can happen when a window is split. */
7028 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
7029 goto set_x_cursor;
7030
7031 set_output_cursor (&w->phys_cursor);
7032
7033 /* Note that mouse_face_beg_row etc. are window relative. */
7034 for (i = dpyinfo->mouse_face_beg_row;
7035 i <= dpyinfo->mouse_face_end_row;
7036 i++)
7037 {
7038 int start_hpos, end_hpos, start_x;
7039 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
7040
7041 /* Don't do anything if row doesn't have valid contents. */
7042 if (!row->enabled_p)
7043 continue;
7044
7045 /* For all but the first row, the highlight starts at column 0. */
7046 if (i == dpyinfo->mouse_face_beg_row)
7047 {
7048 start_hpos = dpyinfo->mouse_face_beg_col;
7049 start_x = dpyinfo->mouse_face_beg_x;
7050 }
7051 else
7052 {
7053 start_hpos = 0;
7054 start_x = 0;
7055 }
7056
7057 if (i == dpyinfo->mouse_face_end_row)
7058 end_hpos = dpyinfo->mouse_face_end_col;
7059 else
7060 end_hpos = row->used[TEXT_AREA];
7061
7062 /* If the cursor's in the text we are about to rewrite, turn the
7063 cursor off. */
7064 if (!w->pseudo_window_p
7065 && i == output_cursor.vpos
7066 && output_cursor.hpos >= start_hpos - 1
7067 && output_cursor.hpos <= end_hpos)
514e4681 7068 {
06a2c219
GM
7069 x_update_window_cursor (w, 0);
7070 cursor_off_p = 1;
514e4681 7071 }
b8009dd1 7072
06a2c219 7073 if (end_hpos > start_hpos)
64f26cf5
GM
7074 {
7075 row->mouse_face_p = draw == DRAW_MOUSE_FACE;
7076 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7077 start_hpos, end_hpos, draw, NULL, NULL, 0);
7078 }
b8009dd1
RS
7079 }
7080
514e4681 7081 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
7082 if (cursor_off_p)
7083 x_display_cursor (w, 1,
7084 output_cursor.hpos, output_cursor.vpos,
7085 output_cursor.x, output_cursor.y);
2729a2b5 7086
06a2c219 7087 output_cursor = saved_cursor;
fb3b7de5 7088
06a2c219
GM
7089 set_x_cursor:
7090
7091 /* Change the mouse cursor. */
7092 if (draw == DRAW_NORMAL_TEXT)
7093 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7094 f->output_data.x->text_cursor);
7095 else if (draw == DRAW_MOUSE_FACE)
334208b7 7096 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7097 f->output_data.x->cross_cursor);
27ead1d5 7098 else
334208b7 7099 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7100 f->output_data.x->nontext_cursor);
b8009dd1
RS
7101}
7102
7103/* Clear out the mouse-highlighted active region.
06a2c219 7104 Redraw it un-highlighted first. */
b8009dd1 7105
06a2c219 7106void
7a13e894
RS
7107clear_mouse_face (dpyinfo)
7108 struct x_display_info *dpyinfo;
b8009dd1 7109{
06a2c219
GM
7110 if (tip_frame)
7111 return;
7112
7a13e894 7113 if (! NILP (dpyinfo->mouse_face_window))
06a2c219 7114 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
b8009dd1 7115
7a13e894
RS
7116 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7117 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7118 dpyinfo->mouse_face_window = Qnil;
b8009dd1 7119}
e687d06e 7120
71b8321e
GM
7121
7122/* Clear any mouse-face on window W. This function is part of the
7123 redisplay interface, and is called from try_window_id and similar
7124 functions to ensure the mouse-highlight is off. */
7125
7126static void
7127x_clear_mouse_face (w)
7128 struct window *w;
7129{
7130 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7131 Lisp_Object window;
7132
7133 XSETWINDOW (window, w);
7134 if (EQ (window, dpyinfo->mouse_face_window))
7135 clear_mouse_face (dpyinfo);
7136}
7137
7138
e687d06e
RS
7139/* Just discard the mouse face information for frame F, if any.
7140 This is used when the size of F is changed. */
7141
dfcf069d 7142void
e687d06e
RS
7143cancel_mouse_face (f)
7144 FRAME_PTR f;
7145{
7146 Lisp_Object window;
7147 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7148
7149 window = dpyinfo->mouse_face_window;
7150 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7151 {
7152 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7153 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7154 dpyinfo->mouse_face_window = Qnil;
7155 }
7156}
b8009dd1 7157\f
ab648270
JB
7158static struct scroll_bar *x_window_to_scroll_bar ();
7159static void x_scroll_bar_report_motion ();
12ba150f 7160
90e65f07 7161/* Return the current position of the mouse.
2d7fc7e8 7162 *fp should be a frame which indicates which display to ask about.
90e65f07 7163
2d7fc7e8 7164 If the mouse movement started in a scroll bar, set *fp, *bar_window,
ab648270 7165 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 7166 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 7167 position on the scroll bar.
12ba150f 7168
2d7fc7e8 7169 If the mouse movement started elsewhere, set *fp to the frame the
12ba150f
JB
7170 mouse is on, *bar_window to nil, and *x and *y to the character cell
7171 the mouse is over.
7172
06a2c219 7173 Set *time to the server time-stamp for the time at which the mouse
12ba150f
JB
7174 was at this position.
7175
a135645a
RS
7176 Don't store anything if we don't have a valid set of values to report.
7177
90e65f07 7178 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7179 movement. */
90e65f07
JB
7180
7181static void
1cf412ec 7182XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7183 FRAME_PTR *fp;
1cf412ec 7184 int insist;
12ba150f 7185 Lisp_Object *bar_window;
ab648270 7186 enum scroll_bar_part *part;
90e65f07 7187 Lisp_Object *x, *y;
e5d77022 7188 unsigned long *time;
90e65f07 7189{
a135645a
RS
7190 FRAME_PTR f1;
7191
90e65f07
JB
7192 BLOCK_INPUT;
7193
8bcee03e 7194 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7195 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7196 else
7197 {
12ba150f
JB
7198 Window root;
7199 int root_x, root_y;
90e65f07 7200
12ba150f
JB
7201 Window dummy_window;
7202 int dummy;
7203
39d8bb4d
KH
7204 Lisp_Object frame, tail;
7205
7206 /* Clear the mouse-moved flag for every frame on this display. */
7207 FOR_EACH_FRAME (tail, frame)
7208 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7209 XFRAME (frame)->mouse_moved = 0;
7210
ab648270 7211 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7212
7213 /* Figure out which root window we're on. */
334208b7
RS
7214 XQueryPointer (FRAME_X_DISPLAY (*fp),
7215 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7216
7217 /* The root window which contains the pointer. */
7218 &root,
7219
7220 /* Trash which we can't trust if the pointer is on
7221 a different screen. */
7222 &dummy_window,
7223
7224 /* The position on that root window. */
58769bee 7225 &root_x, &root_y,
12ba150f
JB
7226
7227 /* More trash we can't trust. */
7228 &dummy, &dummy,
7229
7230 /* Modifier keys and pointer buttons, about which
7231 we don't care. */
7232 (unsigned int *) &dummy);
7233
7234 /* Now we have a position on the root; find the innermost window
7235 containing the pointer. */
7236 {
7237 Window win, child;
7238 int win_x, win_y;
06a2c219 7239 int parent_x = 0, parent_y = 0;
e99db5a1 7240 int count;
12ba150f
JB
7241
7242 win = root;
69388238 7243
2d7fc7e8
RS
7244 /* XTranslateCoordinates can get errors if the window
7245 structure is changing at the same time this function
7246 is running. So at least we must not crash from them. */
7247
e99db5a1 7248 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 7249
334208b7 7250 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 7251 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 7252 {
69388238
RS
7253 /* If mouse was grabbed on a frame, give coords for that frame
7254 even if the mouse is now outside it. */
334208b7 7255 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 7256
12ba150f 7257 /* From-window, to-window. */
69388238 7258 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
7259
7260 /* From-position, to-position. */
7261 root_x, root_y, &win_x, &win_y,
7262
7263 /* Child of win. */
7264 &child);
69388238
RS
7265 f1 = last_mouse_frame;
7266 }
7267 else
7268 {
7269 while (1)
7270 {
334208b7 7271 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 7272
69388238
RS
7273 /* From-window, to-window. */
7274 root, win,
12ba150f 7275
69388238
RS
7276 /* From-position, to-position. */
7277 root_x, root_y, &win_x, &win_y,
7278
7279 /* Child of win. */
7280 &child);
7281
9af3143a 7282 if (child == None || child == win)
69388238
RS
7283 break;
7284
7285 win = child;
7286 parent_x = win_x;
7287 parent_y = win_y;
7288 }
12ba150f 7289
69388238
RS
7290 /* Now we know that:
7291 win is the innermost window containing the pointer
7292 (XTC says it has no child containing the pointer),
7293 win_x and win_y are the pointer's position in it
7294 (XTC did this the last time through), and
7295 parent_x and parent_y are the pointer's position in win's parent.
7296 (They are what win_x and win_y were when win was child.
7297 If win is the root window, it has no parent, and
7298 parent_{x,y} are invalid, but that's okay, because we'll
7299 never use them in that case.) */
7300
7301 /* Is win one of our frames? */
19126e11 7302 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
69388238 7303 }
58769bee 7304
2d7fc7e8
RS
7305 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
7306 f1 = 0;
7307
e99db5a1 7308 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 7309
ab648270 7310 /* If not, is it one of our scroll bars? */
a135645a 7311 if (! f1)
12ba150f 7312 {
ab648270 7313 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
7314
7315 if (bar)
7316 {
a135645a 7317 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
7318 win_x = parent_x;
7319 win_y = parent_y;
7320 }
7321 }
90e65f07 7322
8bcee03e 7323 if (f1 == 0 && insist > 0)
b86bd3dd 7324 f1 = SELECTED_FRAME ();
1cf412ec 7325
a135645a 7326 if (f1)
12ba150f 7327 {
06a2c219
GM
7328 /* Ok, we found a frame. Store all the values.
7329 last_mouse_glyph is a rectangle used to reduce the
7330 generation of mouse events. To not miss any motion
7331 events, we must divide the frame into rectangles of the
7332 size of the smallest character that could be displayed
7333 on it, i.e. into the same rectangles that matrices on
7334 the frame are divided into. */
7335
7336#if OLD_REDISPLAY_CODE
2b5c9e71 7337 int ignore1, ignore2;
2b5c9e71 7338 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
334208b7 7339 &last_mouse_glyph,
1cf412ec
RS
7340 FRAME_X_DISPLAY_INFO (f1)->grabbed
7341 || insist);
06a2c219
GM
7342#else
7343 {
7344 int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
7345 int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
7346 int x = win_x;
7347 int y = win_y;
7348
7349 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
7350 round down even for negative values. */
7351 if (x < 0)
7352 x -= width - 1;
7353 if (y < 0)
7354 y -= height - 1;
7355
7356 last_mouse_glyph.width = width;
7357 last_mouse_glyph.height = height;
7358 last_mouse_glyph.x = (x + width - 1) / width * width;
7359 last_mouse_glyph.y = (y + height - 1) / height * height;
7360 }
7361#endif
12ba150f
JB
7362
7363 *bar_window = Qnil;
7364 *part = 0;
334208b7 7365 *fp = f1;
e0c1aef2
KH
7366 XSETINT (*x, win_x);
7367 XSETINT (*y, win_y);
12ba150f
JB
7368 *time = last_mouse_movement_time;
7369 }
7370 }
7371 }
90e65f07
JB
7372
7373 UNBLOCK_INPUT;
7374}
f451eb13 7375
06a2c219 7376
06a2c219 7377#ifdef USE_X_TOOLKIT
bffcfca9
GM
7378
7379/* Atimer callback function for TIMER. Called every 0.1s to process
7380 Xt timeouts, if needed. We must avoid calling XtAppPending as
7381 much as possible because that function does an implicit XFlush
7382 that slows us down. */
7383
7384static void
7385x_process_timeouts (timer)
7386 struct atimer *timer;
7387{
7388 if (toolkit_scroll_bar_interaction || popup_activated_flag)
7389 {
7390 BLOCK_INPUT;
7391 while (XtAppPending (Xt_app_con) & XtIMTimer)
7392 XtAppProcessEvent (Xt_app_con, XtIMTimer);
7393 UNBLOCK_INPUT;
7394 }
06a2c219
GM
7395}
7396
bffcfca9 7397#endif /* USE_X_TOOLKIT */
06a2c219
GM
7398
7399\f
7400/* Scroll bar support. */
7401
7402/* Given an X window ID, find the struct scroll_bar which manages it.
7403 This can be called in GC, so we have to make sure to strip off mark
7404 bits. */
bffcfca9 7405
06a2c219
GM
7406static struct scroll_bar *
7407x_window_to_scroll_bar (window_id)
7408 Window window_id;
7409{
7410 Lisp_Object tail;
7411
7412 for (tail = Vframe_list;
7413 XGCTYPE (tail) == Lisp_Cons;
8e713be6 7414 tail = XCDR (tail))
06a2c219
GM
7415 {
7416 Lisp_Object frame, bar, condemned;
7417
8e713be6 7418 frame = XCAR (tail);
06a2c219
GM
7419 /* All elements of Vframe_list should be frames. */
7420 if (! GC_FRAMEP (frame))
7421 abort ();
7422
7423 /* Scan this frame's scroll bar list for a scroll bar with the
7424 right window ID. */
7425 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
7426 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
7427 /* This trick allows us to search both the ordinary and
7428 condemned scroll bar lists with one loop. */
7429 ! GC_NILP (bar) || (bar = condemned,
7430 condemned = Qnil,
7431 ! GC_NILP (bar));
7432 bar = XSCROLL_BAR (bar)->next)
7433 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
7434 return XSCROLL_BAR (bar);
7435 }
7436
7437 return 0;
7438}
7439
7440
7441\f
7442/************************************************************************
7443 Toolkit scroll bars
7444 ************************************************************************/
7445
7446#if USE_TOOLKIT_SCROLL_BARS
7447
7448static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
7449static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
7450static void x_create_toolkit_scroll_bar P_ ((struct frame *,
7451 struct scroll_bar *));
7452static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
7453 int, int, int));
7454
7455
7456/* Id of action hook installed for scroll bars. */
7457
7458static XtActionHookId action_hook_id;
7459
7460/* Lisp window being scrolled. Set when starting to interact with
7461 a toolkit scroll bar, reset to nil when ending the interaction. */
7462
7463static Lisp_Object window_being_scrolled;
7464
7465/* Last scroll bar part sent in xm_scroll_callback. */
7466
7467static int last_scroll_bar_part;
7468
ec18280f
SM
7469/* Whether this is an Xaw with arrow-scrollbars. This should imply
7470 that movements of 1/20 of the screen size are mapped to up/down. */
7471
7472static Boolean xaw3d_arrow_scroll;
7473
7474/* Whether the drag scrolling maintains the mouse at the top of the
7475 thumb. If not, resizing the thumb needs to be done more carefully
7476 to avoid jerkyness. */
7477
7478static Boolean xaw3d_pick_top;
7479
06a2c219
GM
7480
7481/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 7482 bars are used.. The hook is responsible for detecting when
06a2c219
GM
7483 the user ends an interaction with the scroll bar, and generates
7484 a `end-scroll' scroll_bar_click' event if so. */
7485
7486static void
7487xt_action_hook (widget, client_data, action_name, event, params,
7488 num_params)
7489 Widget widget;
7490 XtPointer client_data;
7491 String action_name;
7492 XEvent *event;
7493 String *params;
7494 Cardinal *num_params;
7495{
7496 int scroll_bar_p;
7497 char *end_action;
7498
7499#ifdef USE_MOTIF
7500 scroll_bar_p = XmIsScrollBar (widget);
7501 end_action = "Release";
ec18280f 7502#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7503 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
7504 end_action = "EndScroll";
ec18280f 7505#endif /* USE_MOTIF */
06a2c219 7506
06a2c219
GM
7507 if (scroll_bar_p
7508 && strcmp (action_name, end_action) == 0
7509 && WINDOWP (window_being_scrolled))
7510 {
7511 struct window *w;
7512
7513 x_send_scroll_bar_event (window_being_scrolled,
7514 scroll_bar_end_scroll, 0, 0);
7515 w = XWINDOW (window_being_scrolled);
7516 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
7517 window_being_scrolled = Qnil;
7518 last_scroll_bar_part = -1;
bffcfca9
GM
7519
7520 /* Xt timeouts no longer needed. */
7521 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
7522 }
7523}
7524
7525
7526/* Send a client message with message type Xatom_Scrollbar for a
7527 scroll action to the frame of WINDOW. PART is a value identifying
7528 the part of the scroll bar that was clicked on. PORTION is the
7529 amount to scroll of a whole of WHOLE. */
7530
7531static void
7532x_send_scroll_bar_event (window, part, portion, whole)
7533 Lisp_Object window;
7534 int part, portion, whole;
7535{
7536 XEvent event;
7537 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
7538 struct frame *f = XFRAME (XWINDOW (window)->frame);
7539
7540 /* Construct a ClientMessage event to send to the frame. */
7541 ev->type = ClientMessage;
7542 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
7543 ev->display = FRAME_X_DISPLAY (f);
7544 ev->window = FRAME_X_WINDOW (f);
7545 ev->format = 32;
52e386c2 7546 ev->data.l[0] = (long) XFASTINT (window);
06a2c219
GM
7547 ev->data.l[1] = (long) part;
7548 ev->data.l[2] = (long) 0;
7549 ev->data.l[3] = (long) portion;
7550 ev->data.l[4] = (long) whole;
7551
bffcfca9
GM
7552 /* Make Xt timeouts work while the scroll bar is active. */
7553 toolkit_scroll_bar_interaction = 1;
7554
06a2c219
GM
7555 /* Setting the event mask to zero means that the message will
7556 be sent to the client that created the window, and if that
7557 window no longer exists, no event will be sent. */
7558 BLOCK_INPUT;
7559 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
7560 UNBLOCK_INPUT;
7561}
7562
7563
7564/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
7565 in *IEVENT. */
7566
7567static void
7568x_scroll_bar_to_input_event (event, ievent)
7569 XEvent *event;
7570 struct input_event *ievent;
7571{
7572 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
7573 Lisp_Object window;
7574 struct frame *f;
7575
7576 XSETFASTINT (window, ev->data.l[0]);
7577 f = XFRAME (XWINDOW (window)->frame);
06a2c219
GM
7578
7579 ievent->kind = scroll_bar_click;
7580 ievent->frame_or_window = window;
0f8aabe9 7581 ievent->arg = Qnil;
06a2c219
GM
7582 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
7583 ievent->part = ev->data.l[1];
7584 ievent->code = ev->data.l[2];
7585 ievent->x = make_number ((int) ev->data.l[3]);
7586 ievent->y = make_number ((int) ev->data.l[4]);
7587 ievent->modifiers = 0;
7588}
7589
7590
7591#ifdef USE_MOTIF
7592
7593/* Minimum and maximum values used for Motif scroll bars. */
7594
7595#define XM_SB_MIN 1
7596#define XM_SB_MAX 10000000
7597#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
7598
7599
7600/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
7601 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
7602 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
7603
7604static void
7605xm_scroll_callback (widget, client_data, call_data)
7606 Widget widget;
7607 XtPointer client_data, call_data;
7608{
7609 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7610 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
7611 double percent;
7612 int part = -1, whole = 0, portion = 0;
7613
7614 switch (cs->reason)
7615 {
7616 case XmCR_DECREMENT:
7617 bar->dragging = Qnil;
7618 part = scroll_bar_up_arrow;
7619 break;
7620
7621 case XmCR_INCREMENT:
7622 bar->dragging = Qnil;
7623 part = scroll_bar_down_arrow;
7624 break;
7625
7626 case XmCR_PAGE_DECREMENT:
7627 bar->dragging = Qnil;
7628 part = scroll_bar_above_handle;
7629 break;
7630
7631 case XmCR_PAGE_INCREMENT:
7632 bar->dragging = Qnil;
7633 part = scroll_bar_below_handle;
7634 break;
7635
7636 case XmCR_TO_TOP:
7637 bar->dragging = Qnil;
7638 part = scroll_bar_to_top;
7639 break;
7640
7641 case XmCR_TO_BOTTOM:
7642 bar->dragging = Qnil;
7643 part = scroll_bar_to_bottom;
7644 break;
7645
7646 case XmCR_DRAG:
7647 {
7648 int slider_size;
7649 int dragging_down_p = (INTEGERP (bar->dragging)
7650 && XINT (bar->dragging) <= cs->value);
7651
7652 /* Get the slider size. */
7653 BLOCK_INPUT;
7654 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
7655 UNBLOCK_INPUT;
7656
7657 /* At the max position of the scroll bar, do a line-wise
7658 movement. Without doing anything, the LessTif scroll bar
7659 calls us with the same cs->value again and again. If we
7660 want to make sure that we can reach the end of the buffer,
7661 we have to do something.
7662
7663 Implementation note: setting bar->dragging always to
7664 cs->value gives a smoother movement at the max position.
7665 Setting it to nil when doing line-wise movement gives
7666 a better slider behavior. */
7667
7668 if (cs->value + slider_size == XM_SB_MAX
7669 || (dragging_down_p
7670 && last_scroll_bar_part == scroll_bar_down_arrow))
7671 {
7672 part = scroll_bar_down_arrow;
7673 bar->dragging = Qnil;
7674 }
7675 else
7676 {
7677 whole = XM_SB_RANGE;
7678 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
7679 part = scroll_bar_handle;
7680 bar->dragging = make_number (cs->value);
7681 }
7682 }
7683 break;
7684
7685 case XmCR_VALUE_CHANGED:
7686 break;
7687 };
7688
7689 if (part >= 0)
7690 {
7691 window_being_scrolled = bar->window;
7692 last_scroll_bar_part = part;
7693 x_send_scroll_bar_event (bar->window, part, portion, whole);
7694 }
7695}
7696
7697
ec18280f 7698#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
7699
7700
ec18280f 7701/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
7702 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
7703 scroll bar struct. CALL_DATA is a pointer to a float saying where
7704 the thumb is. */
7705
7706static void
ec18280f 7707xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
7708 Widget widget;
7709 XtPointer client_data, call_data;
7710{
7711 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7712 float top = *(float *) call_data;
7713 float shown;
ec18280f
SM
7714 int whole, portion, height;
7715 int part;
06a2c219
GM
7716
7717 /* Get the size of the thumb, a value between 0 and 1. */
7718 BLOCK_INPUT;
ec18280f 7719 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
7720 UNBLOCK_INPUT;
7721
7722 whole = 10000000;
7723 portion = shown < 1 ? top * whole : 0;
06a2c219 7724
ec18280f
SM
7725 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
7726 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
7727 the bottom, so we force the scrolling whenever we see that we're
7728 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
7729 we try to ensure that we always stay two pixels away from the
7730 bottom). */
06a2c219
GM
7731 part = scroll_bar_down_arrow;
7732 else
7733 part = scroll_bar_handle;
7734
7735 window_being_scrolled = bar->window;
7736 bar->dragging = make_number (portion);
7737 last_scroll_bar_part = part;
7738 x_send_scroll_bar_event (bar->window, part, portion, whole);
7739}
7740
7741
ec18280f
SM
7742/* Xaw scroll bar callback. Invoked for incremental scrolling.,
7743 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
7744 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
7745 the scroll bar. CALL_DATA is an integer specifying the action that
7746 has taken place. It's magnitude is in the range 0..height of the
7747 scroll bar. Negative values mean scroll towards buffer start.
7748 Values < height of scroll bar mean line-wise movement. */
7749
7750static void
ec18280f 7751xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
7752 Widget widget;
7753 XtPointer client_data, call_data;
7754{
7755 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7756 int position = (int) call_data;
7757 Dimension height;
7758 int part;
7759
7760 /* Get the height of the scroll bar. */
7761 BLOCK_INPUT;
7762 XtVaGetValues (widget, XtNheight, &height, NULL);
7763 UNBLOCK_INPUT;
7764
ec18280f
SM
7765 if (abs (position) >= height)
7766 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
7767
7768 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
7769 it maps line-movement to call_data = max(5, height/20). */
7770 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
7771 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 7772 else
ec18280f 7773 part = scroll_bar_move_ratio;
06a2c219
GM
7774
7775 window_being_scrolled = bar->window;
7776 bar->dragging = Qnil;
7777 last_scroll_bar_part = part;
ec18280f 7778 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
7779}
7780
7781
7782#endif /* not USE_MOTIF */
7783
7784
7785/* Create the widget for scroll bar BAR on frame F. Record the widget
7786 and X window of the scroll bar in BAR. */
7787
7788static void
7789x_create_toolkit_scroll_bar (f, bar)
7790 struct frame *f;
7791 struct scroll_bar *bar;
7792{
7793 Window xwindow;
7794 Widget widget;
7795 Arg av[20];
7796 int ac = 0;
7797 char *scroll_bar_name = "verticalScrollBar";
7798 unsigned long pixel;
7799
7800 BLOCK_INPUT;
7801
7802#ifdef USE_MOTIF
7803 /* LessTif 0.85, problems:
7804
7805 1. When the mouse if over the scroll bar, the scroll bar will
7806 get keyboard events. I didn't find a way to turn this off.
7807
7808 2. Do we have to explicitly set the cursor to get an arrow
7809 cursor (see below)? */
7810
7811 /* Set resources. Create the widget. */
7812 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7813 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
7814 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
7815 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
7816 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
7817 XtSetArg (av[ac], XmNincrement, 1); ++ac;
7818 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
7819
7820 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7821 if (pixel != -1)
7822 {
7823 XtSetArg (av[ac], XmNforeground, pixel);
7824 ++ac;
7825 }
7826
7827 pixel = f->output_data.x->scroll_bar_background_pixel;
7828 if (pixel != -1)
7829 {
7830 XtSetArg (av[ac], XmNbackground, pixel);
7831 ++ac;
7832 }
7833
7834 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
7835 scroll_bar_name, av, ac);
7836
7837 /* Add one callback for everything that can happen. */
7838 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
7839 (XtPointer) bar);
7840 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
7841 (XtPointer) bar);
7842 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
7843 (XtPointer) bar);
7844 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
7845 (XtPointer) bar);
7846 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
7847 (XtPointer) bar);
7848 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
7849 (XtPointer) bar);
7850 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
7851 (XtPointer) bar);
7852
7853 /* Realize the widget. Only after that is the X window created. */
7854 XtRealizeWidget (widget);
7855
7856 /* Set the cursor to an arrow. I didn't find a resource to do that.
7857 And I'm wondering why it hasn't an arrow cursor by default. */
7858 XDefineCursor (XtDisplay (widget), XtWindow (widget),
7859 f->output_data.x->nontext_cursor);
7860
ec18280f 7861#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7862
7863 /* Set resources. Create the widget. The background of the
7864 Xaw3d scroll bar widget is a little bit light for my taste.
7865 We don't alter it here to let users change it according
7866 to their taste with `emacs*verticalScrollBar.background: xxx'. */
7867 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7868 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
7869 /* For smoother scrolling with Xaw3d -sm */
7870 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
7871 /* XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac; */
06a2c219
GM
7872
7873 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7874 if (pixel != -1)
7875 {
7876 XtSetArg (av[ac], XtNforeground, pixel);
7877 ++ac;
7878 }
7879
7880 pixel = f->output_data.x->scroll_bar_background_pixel;
7881 if (pixel != -1)
7882 {
7883 XtSetArg (av[ac], XtNbackground, pixel);
7884 ++ac;
7885 }
7886
7887 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
7888 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
7889
7890 {
7891 char *initial = "";
7892 char *val = initial;
7893 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
7894 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
7895 if (val == initial)
7896 { /* ARROW_SCROLL */
7897 xaw3d_arrow_scroll = True;
7898 /* Isn't that just a personal preference ? -sm */
7899 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
7900 }
7901 }
06a2c219
GM
7902
7903 /* Define callbacks. */
ec18280f
SM
7904 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
7905 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
7906 (XtPointer) bar);
7907
7908 /* Realize the widget. Only after that is the X window created. */
7909 XtRealizeWidget (widget);
7910
ec18280f 7911#endif /* !USE_MOTIF */
06a2c219
GM
7912
7913 /* Install an action hook that let's us detect when the user
7914 finishes interacting with a scroll bar. */
7915 if (action_hook_id == 0)
7916 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
7917
7918 /* Remember X window and widget in the scroll bar vector. */
7919 SET_SCROLL_BAR_X_WIDGET (bar, widget);
7920 xwindow = XtWindow (widget);
7921 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
7922
7923 UNBLOCK_INPUT;
7924}
7925
7926
7927/* Set the thumb size and position of scroll bar BAR. We are currently
7928 displaying PORTION out of a whole WHOLE, and our position POSITION. */
7929
7930static void
7931x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
7932 struct scroll_bar *bar;
7933 int portion, position, whole;
f451eb13 7934{
06a2c219 7935 float top, shown;
06a2c219 7936 Widget widget = SCROLL_BAR_X_WIDGET (bar);
f451eb13 7937
06a2c219
GM
7938 if (whole == 0)
7939 top = 0, shown = 1;
7940 else
f451eb13 7941 {
06a2c219
GM
7942 top = (float) position / whole;
7943 shown = (float) portion / whole;
7944 }
f451eb13 7945
06a2c219 7946 BLOCK_INPUT;
f451eb13 7947
06a2c219
GM
7948#ifdef USE_MOTIF
7949 {
7950 int size, value;
7951 Boolean arrow1_selected, arrow2_selected;
7952 unsigned char flags;
7953 XmScrollBarWidget sb;
7954
ec18280f 7955 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
7956 is the scroll bar's maximum and MIN is the scroll bar's minimum
7957 value. */
7958 size = shown * XM_SB_RANGE;
7959 size = min (size, XM_SB_RANGE);
7960 size = max (size, 1);
7961
7962 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
7963 value = top * XM_SB_RANGE;
7964 value = min (value, XM_SB_MAX - size);
7965 value = max (value, XM_SB_MIN);
7966
7967 /* LessTif: Calling XmScrollBarSetValues after an increment or
7968 decrement turns off auto-repeat LessTif-internally. This can
7969 be seen in ScrollBar.c which resets Arrow1Selected and
7970 Arrow2Selected. It also sets internal flags so that LessTif
7971 believes the mouse is in the slider. We either have to change
7972 our code, or work around that by accessing private data. */
7973
7974 sb = (XmScrollBarWidget) widget;
7975 arrow1_selected = sb->scrollBar.arrow1_selected;
7976 arrow2_selected = sb->scrollBar.arrow2_selected;
7977 flags = sb->scrollBar.flags;
7978
7979 if (NILP (bar->dragging))
7980 XmScrollBarSetValues (widget, value, size, 0, 0, False);
7981 else if (last_scroll_bar_part == scroll_bar_down_arrow)
7982 /* This has the negative side effect that the slider value is
ec18280f 7983 not what it would be if we scrolled here using line-wise or
06a2c219
GM
7984 page-wise movement. */
7985 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
7986 else
7987 {
7988 /* If currently dragging, only update the slider size.
7989 This reduces flicker effects. */
7990 int old_value, old_size, increment, page_increment;
7991
7992 XmScrollBarGetValues (widget, &old_value, &old_size,
7993 &increment, &page_increment);
7994 XmScrollBarSetValues (widget, old_value,
7995 min (size, XM_SB_RANGE - old_value),
7996 0, 0, False);
7997 }
7998
7999 sb->scrollBar.arrow1_selected = arrow1_selected;
8000 sb->scrollBar.arrow2_selected = arrow2_selected;
8001 sb->scrollBar.flags = flags;
8002 }
ec18280f 8003#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8004 {
ec18280f
SM
8005 float old_top, old_shown;
8006 Dimension height;
8007 XtVaGetValues (widget,
8008 XtNtopOfThumb, &old_top,
8009 XtNshown, &old_shown,
8010 XtNheight, &height,
8011 NULL);
8012
8013 /* Massage the top+shown values. */
8014 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8015 top = max (0, min (1, top));
8016 else
8017 top = old_top;
8018 /* Keep two pixels available for moving the thumb down. */
8019 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8020
8021 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8022 check that your system's configuration file contains a define
8023 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8024 if (top != old_top || shown != old_shown)
eb393530 8025 {
ec18280f 8026 if (NILP (bar->dragging))
eb393530 8027 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8028 else
8029 {
ec18280f
SM
8030#ifdef HAVE_XAW3D
8031 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8032 int scroll_mode = 0;
ec18280f
SM
8033
8034 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8035 if (xaw3d_arrow_scroll)
8036 {
8037 /* Xaw3d stupidly ignores resize requests while dragging
8038 so we have to make it believe it's not in dragging mode. */
8039 scroll_mode = sb->scrollbar.scroll_mode;
8040 if (scroll_mode == 2)
8041 sb->scrollbar.scroll_mode = 0;
8042 }
8043#endif
8044 /* Try to make the scrolling a tad smoother. */
8045 if (!xaw3d_pick_top)
8046 shown = min (shown, old_shown);
8047
8048 XawScrollbarSetThumb (widget, top, shown);
8049
8050#ifdef HAVE_XAW3D
8051 if (xaw3d_arrow_scroll && scroll_mode == 2)
8052 sb->scrollbar.scroll_mode = scroll_mode;
8053#endif
06a2c219 8054 }
06a2c219
GM
8055 }
8056 }
ec18280f 8057#endif /* !USE_MOTIF */
06a2c219
GM
8058
8059 UNBLOCK_INPUT;
f451eb13
JB
8060}
8061
06a2c219
GM
8062#endif /* USE_TOOLKIT_SCROLL_BARS */
8063
8064
8065\f
8066/************************************************************************
8067 Scroll bars, general
8068 ************************************************************************/
8069
8070/* Create a scroll bar and return the scroll bar vector for it. W is
8071 the Emacs window on which to create the scroll bar. TOP, LEFT,
8072 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8073 scroll bar. */
8074
ab648270 8075static struct scroll_bar *
06a2c219
GM
8076x_scroll_bar_create (w, top, left, width, height)
8077 struct window *w;
f451eb13
JB
8078 int top, left, width, height;
8079{
06a2c219 8080 struct frame *f = XFRAME (w->frame);
334208b7
RS
8081 struct scroll_bar *bar
8082 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8083
8084 BLOCK_INPUT;
8085
06a2c219
GM
8086#if USE_TOOLKIT_SCROLL_BARS
8087 x_create_toolkit_scroll_bar (f, bar);
8088#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8089 {
8090 XSetWindowAttributes a;
8091 unsigned long mask;
5c187dee 8092 Window window;
06a2c219
GM
8093
8094 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8095 if (a.background_pixel == -1)
8096 a.background_pixel = f->output_data.x->background_pixel;
8097
12ba150f 8098 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8099 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8100 | ExposureMask);
7a13e894 8101 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8102
dbc4e1c1 8103 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8104
06a2c219
GM
8105 /* Clear the area of W that will serve as a scroll bar. This is
8106 for the case that a window has been split horizontally. In
8107 this case, no clear_frame is generated to reduce flickering. */
8108 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8109 left, top, width,
8110 window_box_height (w), False);
8111
8112 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8113 /* Position and size of scroll bar. */
8114 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8115 top,
8116 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8117 height,
8118 /* Border width, depth, class, and visual. */
8119 0,
8120 CopyFromParent,
8121 CopyFromParent,
8122 CopyFromParent,
8123 /* Attributes. */
8124 mask, &a);
8125 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8126 }
06a2c219 8127#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8128
06a2c219 8129 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8130 XSETINT (bar->top, top);
8131 XSETINT (bar->left, left);
8132 XSETINT (bar->width, width);
8133 XSETINT (bar->height, height);
8134 XSETINT (bar->start, 0);
8135 XSETINT (bar->end, 0);
12ba150f 8136 bar->dragging = Qnil;
f451eb13
JB
8137
8138 /* Add bar to its frame's list of scroll bars. */
334208b7 8139 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8140 bar->prev = Qnil;
334208b7 8141 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 8142 if (!NILP (bar->next))
e0c1aef2 8143 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 8144
06a2c219
GM
8145 /* Map the window/widget. */
8146#if USE_TOOLKIT_SCROLL_BARS
8147 XtMapWidget (SCROLL_BAR_X_WIDGET (bar));
8148 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
8149 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8150 top,
8151 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8152 height, 0);
8153#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 8154 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 8155#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8156
8157 UNBLOCK_INPUT;
12ba150f 8158 return bar;
f451eb13
JB
8159}
8160
06a2c219 8161
12ba150f 8162/* Draw BAR's handle in the proper position.
06a2c219 8163
12ba150f
JB
8164 If the handle is already drawn from START to END, don't bother
8165 redrawing it, unless REBUILD is non-zero; in that case, always
8166 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 8167 events.)
12ba150f
JB
8168
8169 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
8170 fit inside its rectangle, but if the user is dragging the scroll
8171 bar handle, we want to let them drag it down all the way, so that
8172 the bar's top is as far down as it goes; otherwise, there's no way
8173 to move to the very end of the buffer. */
8174
5c187dee
GM
8175#ifndef USE_TOOLKIT_SCROLL_BARS
8176
f451eb13 8177static void
ab648270
JB
8178x_scroll_bar_set_handle (bar, start, end, rebuild)
8179 struct scroll_bar *bar;
f451eb13 8180 int start, end;
12ba150f 8181 int rebuild;
f451eb13 8182{
12ba150f 8183 int dragging = ! NILP (bar->dragging);
ab648270 8184 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8185 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8186 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
8187
8188 /* If the display is already accurate, do nothing. */
8189 if (! rebuild
8190 && start == XINT (bar->start)
8191 && end == XINT (bar->end))
8192 return;
8193
f451eb13
JB
8194 BLOCK_INPUT;
8195
8196 {
d9cdbb3d
RS
8197 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
8198 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
8199 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
8200
8201 /* Make sure the values are reasonable, and try to preserve
8202 the distance between start and end. */
12ba150f
JB
8203 {
8204 int length = end - start;
8205
8206 if (start < 0)
8207 start = 0;
8208 else if (start > top_range)
8209 start = top_range;
8210 end = start + length;
8211
8212 if (end < start)
8213 end = start;
8214 else if (end > top_range && ! dragging)
8215 end = top_range;
8216 }
f451eb13 8217
ab648270 8218 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
8219 XSETINT (bar->start, start);
8220 XSETINT (bar->end, end);
f451eb13 8221
12ba150f
JB
8222 /* Clip the end position, just for display. */
8223 if (end > top_range)
8224 end = top_range;
f451eb13 8225
ab648270 8226 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
8227 below top positions, to make sure the handle is always at least
8228 that many pixels tall. */
ab648270 8229 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 8230
12ba150f
JB
8231 /* Draw the empty space above the handle. Note that we can't clear
8232 zero-height areas; that means "clear to end of window." */
8233 if (0 < start)
334208b7 8234 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8235
12ba150f 8236 /* x, y, width, height, and exposures. */
ab648270
JB
8237 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8238 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
8239 inside_width, start,
8240 False);
f451eb13 8241
06a2c219
GM
8242 /* Change to proper foreground color if one is specified. */
8243 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8244 XSetForeground (FRAME_X_DISPLAY (f), gc,
8245 f->output_data.x->scroll_bar_foreground_pixel);
8246
12ba150f 8247 /* Draw the handle itself. */
334208b7 8248 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 8249
12ba150f 8250 /* x, y, width, height */
ab648270
JB
8251 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8252 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 8253 inside_width, end - start);
f451eb13 8254
06a2c219
GM
8255 /* Restore the foreground color of the GC if we changed it above. */
8256 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8257 XSetForeground (FRAME_X_DISPLAY (f), gc,
8258 f->output_data.x->foreground_pixel);
f451eb13 8259
12ba150f
JB
8260 /* Draw the empty space below the handle. Note that we can't
8261 clear zero-height areas; that means "clear to end of window." */
8262 if (end < inside_height)
334208b7 8263 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8264
12ba150f 8265 /* x, y, width, height, and exposures. */
ab648270
JB
8266 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8267 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
8268 inside_width, inside_height - end,
8269 False);
f451eb13 8270
f451eb13
JB
8271 }
8272
f451eb13
JB
8273 UNBLOCK_INPUT;
8274}
8275
5c187dee 8276#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 8277
06a2c219
GM
8278/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
8279 nil. */
58769bee 8280
12ba150f 8281static void
ab648270
JB
8282x_scroll_bar_remove (bar)
8283 struct scroll_bar *bar;
12ba150f 8284{
12ba150f
JB
8285 BLOCK_INPUT;
8286
06a2c219
GM
8287#if USE_TOOLKIT_SCROLL_BARS
8288 XtDestroyWidget (SCROLL_BAR_X_WIDGET (bar));
8289#else /* not USE_TOOLKIT_SCROLL_BARS */
5c187dee
GM
8290 {
8291 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8292 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
8293 }
06a2c219
GM
8294#endif /* not USE_TOOLKIT_SCROLL_BARS */
8295
ab648270
JB
8296 /* Disassociate this scroll bar from its window. */
8297 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
8298
8299 UNBLOCK_INPUT;
8300}
8301
06a2c219 8302
12ba150f
JB
8303/* Set the handle of the vertical scroll bar for WINDOW to indicate
8304 that we are displaying PORTION characters out of a total of WHOLE
ab648270 8305 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 8306 create one. */
06a2c219 8307
12ba150f 8308static void
06a2c219
GM
8309XTset_vertical_scroll_bar (w, portion, whole, position)
8310 struct window *w;
f451eb13
JB
8311 int portion, whole, position;
8312{
06a2c219 8313 struct frame *f = XFRAME (w->frame);
ab648270 8314 struct scroll_bar *bar;
3c6ede7b 8315 int top, height, left, sb_left, width, sb_width;
06a2c219 8316 int window_x, window_y, window_width, window_height;
06a2c219 8317
3c6ede7b 8318 /* Get window dimensions. */
06a2c219 8319 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
8320 top = window_y;
8321 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
8322 height = window_height;
06a2c219 8323
3c6ede7b 8324 /* Compute the left edge of the scroll bar area. */
06a2c219 8325 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
8326 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
8327 else
8328 left = XFASTINT (w->left);
8329 left *= CANON_X_UNIT (f);
8330 left += FRAME_INTERNAL_BORDER_WIDTH (f);
8331
8332 /* Compute the width of the scroll bar which might be less than
8333 the width of the area reserved for the scroll bar. */
8334 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
8335 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 8336 else
3c6ede7b 8337 sb_width = width;
12ba150f 8338
3c6ede7b
GM
8339 /* Compute the left edge of the scroll bar. */
8340#ifdef USE_TOOLKIT_SCROLL_BARS
8341 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8342 sb_left = left + width - sb_width - (width - sb_width) / 2;
8343 else
8344 sb_left = left + (width - sb_width) / 2;
8345#else
8346 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8347 sb_left = left + width - sb_width;
8348 else
8349 sb_left = left;
8350#endif
8351
ab648270 8352 /* Does the scroll bar exist yet? */
06a2c219 8353 if (NILP (w->vertical_scroll_bar))
3c6ede7b 8354 {
80c32bcc 8355 BLOCK_INPUT;
3c6ede7b
GM
8356 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8357 left, top, width, height, False);
80c32bcc 8358 UNBLOCK_INPUT;
3c6ede7b
GM
8359 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
8360 }
f451eb13 8361 else
12ba150f
JB
8362 {
8363 /* It may just need to be moved and resized. */
06a2c219
GM
8364 unsigned int mask = 0;
8365
8366 bar = XSCROLL_BAR (w->vertical_scroll_bar);
8367
8368 BLOCK_INPUT;
8369
3c6ede7b 8370 if (sb_left != XINT (bar->left))
06a2c219 8371 mask |= CWX;
3c6ede7b 8372 if (top != XINT (bar->top))
06a2c219 8373 mask |= CWY;
3c6ede7b 8374 if (sb_width != XINT (bar->width))
06a2c219 8375 mask |= CWWidth;
3c6ede7b 8376 if (height != XINT (bar->height))
06a2c219
GM
8377 mask |= CWHeight;
8378
8379#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
8380
8381 /* Since toolkit scroll bars are smaller than the space reserved
8382 for them on the frame, we have to clear "under" them. */
8383 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3c6ede7b 8384 left, top, width, height, False);
06a2c219
GM
8385
8386 /* Move/size the scroll bar widget. */
8387 if (mask)
8388 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
3c6ede7b
GM
8389 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8390 top,
8391 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8392 height, 0);
06a2c219
GM
8393
8394#else /* not USE_TOOLKIT_SCROLL_BARS */
8395
e1f6572f
RS
8396 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
8397 {
8398 /* Clear areas not covered by the scroll bar. This makes sure a
8399 previous mode line display is cleared after C-x 2 C-x 1, for
8400 example. Non-toolkit scroll bars are as wide as the area
8401 reserved for scroll bars - trim at both sides. */
8402 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8403 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8404 height, False);
8405 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8406 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8407 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8408 height, False);
8409 }
06a2c219
GM
8410
8411 /* Move/size the scroll bar window. */
8412 if (mask)
8413 {
8414 XWindowChanges wc;
8415
3c6ede7b
GM
8416 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
8417 wc.y = top;
8418 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
8419 wc.height = height;
06a2c219
GM
8420 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
8421 mask, &wc);
8422 }
8423
8424#endif /* not USE_TOOLKIT_SCROLL_BARS */
8425
8426 /* Remember new settings. */
3c6ede7b
GM
8427 XSETINT (bar->left, sb_left);
8428 XSETINT (bar->top, top);
8429 XSETINT (bar->width, sb_width);
8430 XSETINT (bar->height, height);
06a2c219
GM
8431
8432 UNBLOCK_INPUT;
12ba150f 8433 }
f451eb13 8434
06a2c219
GM
8435#if USE_TOOLKIT_SCROLL_BARS
8436 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
8437#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 8438 /* Set the scroll bar's current state, unless we're currently being
f451eb13 8439 dragged. */
12ba150f 8440 if (NILP (bar->dragging))
f451eb13 8441 {
92857db0 8442 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 8443
12ba150f 8444 if (whole == 0)
ab648270 8445 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
8446 else
8447 {
43f868f5
JB
8448 int start = ((double) position * top_range) / whole;
8449 int end = ((double) (position + portion) * top_range) / whole;
ab648270 8450 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 8451 }
f451eb13 8452 }
06a2c219 8453#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8454
06a2c219 8455 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
8456}
8457
12ba150f 8458
f451eb13 8459/* The following three hooks are used when we're doing a thorough
ab648270 8460 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 8461 are going to be deleted, because keeping track of when windows go
12ba150f
JB
8462 away is a real pain - "Can you say set-window-configuration, boys
8463 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 8464 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 8465 from the fiery pit when we actually redisplay its window. */
f451eb13 8466
ab648270
JB
8467/* Arrange for all scroll bars on FRAME to be removed at the next call
8468 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
8469 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
8470
58769bee 8471static void
ab648270 8472XTcondemn_scroll_bars (frame)
f451eb13
JB
8473 FRAME_PTR frame;
8474{
f9e24cb9
RS
8475 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
8476 while (! NILP (FRAME_SCROLL_BARS (frame)))
8477 {
8478 Lisp_Object bar;
8479 bar = FRAME_SCROLL_BARS (frame);
8480 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
8481 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
8482 XSCROLL_BAR (bar)->prev = Qnil;
8483 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
8484 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
8485 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
8486 }
f451eb13
JB
8487}
8488
06a2c219 8489/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 8490 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 8491static void
ab648270 8492XTredeem_scroll_bar (window)
12ba150f 8493 struct window *window;
f451eb13 8494{
ab648270 8495 struct scroll_bar *bar;
12ba150f 8496
ab648270
JB
8497 /* We can't redeem this window's scroll bar if it doesn't have one. */
8498 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
8499 abort ();
8500
ab648270 8501 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
8502
8503 /* Unlink it from the condemned list. */
8504 {
8505 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
8506
8507 if (NILP (bar->prev))
8508 {
8509 /* If the prev pointer is nil, it must be the first in one of
8510 the lists. */
ab648270 8511 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
8512 /* It's not condemned. Everything's fine. */
8513 return;
ab648270
JB
8514 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
8515 window->vertical_scroll_bar))
8516 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
8517 else
8518 /* If its prev pointer is nil, it must be at the front of
8519 one or the other! */
8520 abort ();
8521 }
8522 else
ab648270 8523 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
8524
8525 if (! NILP (bar->next))
ab648270 8526 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 8527
ab648270 8528 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8529 bar->prev = Qnil;
e0c1aef2 8530 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 8531 if (! NILP (bar->next))
e0c1aef2 8532 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
12ba150f 8533 }
f451eb13
JB
8534}
8535
ab648270
JB
8536/* Remove all scroll bars on FRAME that haven't been saved since the
8537 last call to `*condemn_scroll_bars_hook'. */
06a2c219 8538
f451eb13 8539static void
ab648270 8540XTjudge_scroll_bars (f)
12ba150f 8541 FRAME_PTR f;
f451eb13 8542{
12ba150f 8543 Lisp_Object bar, next;
f451eb13 8544
ab648270 8545 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
8546
8547 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
8548 more events on the hapless scroll bars. */
8549 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
8550
8551 for (; ! NILP (bar); bar = next)
f451eb13 8552 {
ab648270 8553 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 8554
ab648270 8555 x_scroll_bar_remove (b);
12ba150f
JB
8556
8557 next = b->next;
8558 b->next = b->prev = Qnil;
f451eb13 8559 }
12ba150f 8560
ab648270 8561 /* Now there should be no references to the condemned scroll bars,
12ba150f 8562 and they should get garbage-collected. */
f451eb13
JB
8563}
8564
8565
06a2c219
GM
8566/* Handle an Expose or GraphicsExpose event on a scroll bar. This
8567 is a no-op when using toolkit scroll bars.
ab648270
JB
8568
8569 This may be called from a signal handler, so we have to ignore GC
8570 mark bits. */
06a2c219 8571
f451eb13 8572static void
ab648270
JB
8573x_scroll_bar_expose (bar, event)
8574 struct scroll_bar *bar;
f451eb13
JB
8575 XEvent *event;
8576{
06a2c219
GM
8577#ifndef USE_TOOLKIT_SCROLL_BARS
8578
ab648270 8579 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8580 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8581 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 8582 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 8583
f451eb13
JB
8584 BLOCK_INPUT;
8585
ab648270 8586 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 8587
06a2c219 8588 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 8589 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
8590
8591 /* x, y, width, height */
d9cdbb3d 8592 0, 0,
3cbd2e0b 8593 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
8594 XINT (bar->height) - 1);
8595
f451eb13 8596 UNBLOCK_INPUT;
06a2c219
GM
8597
8598#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8599}
8600
ab648270
JB
8601/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8602 is set to something other than no_event, it is enqueued.
8603
8604 This may be called from a signal handler, so we have to ignore GC
8605 mark bits. */
06a2c219 8606
5c187dee
GM
8607#ifndef USE_TOOLKIT_SCROLL_BARS
8608
f451eb13 8609static void
ab648270
JB
8610x_scroll_bar_handle_click (bar, event, emacs_event)
8611 struct scroll_bar *bar;
f451eb13
JB
8612 XEvent *event;
8613 struct input_event *emacs_event;
8614{
0299d313 8615 if (! GC_WINDOWP (bar->window))
12ba150f
JB
8616 abort ();
8617
ab648270 8618 emacs_event->kind = scroll_bar_click;
69388238 8619 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
8620 emacs_event->modifiers
8621 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
8622 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
8623 event->xbutton.state)
8624 | (event->type == ButtonRelease
8625 ? up_modifier
8626 : down_modifier));
12ba150f 8627 emacs_event->frame_or_window = bar->window;
0f8aabe9 8628 emacs_event->arg = Qnil;
f451eb13 8629 emacs_event->timestamp = event->xbutton.time;
12ba150f 8630 {
06a2c219 8631#if 0
d9cdbb3d 8632 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 8633 int internal_height
d9cdbb3d 8634 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8635#endif
0299d313 8636 int top_range
d9cdbb3d 8637 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 8638 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
8639
8640 if (y < 0) y = 0;
8641 if (y > top_range) y = top_range;
8642
8643 if (y < XINT (bar->start))
ab648270
JB
8644 emacs_event->part = scroll_bar_above_handle;
8645 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8646 emacs_event->part = scroll_bar_handle;
12ba150f 8647 else
ab648270 8648 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
8649
8650 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
8651 they want to drag it. Lisp code needs to be able to decide
8652 whether or not we're dragging. */
929787e1 8653#if 0
12ba150f
JB
8654 /* If the user has just clicked on the handle, record where they're
8655 holding it. */
8656 if (event->type == ButtonPress
ab648270 8657 && emacs_event->part == scroll_bar_handle)
e0c1aef2 8658 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 8659#endif
12ba150f
JB
8660
8661 /* If the user has released the handle, set it to its final position. */
8662 if (event->type == ButtonRelease
8663 && ! NILP (bar->dragging))
8664 {
8665 int new_start = y - XINT (bar->dragging);
8666 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 8667
ab648270 8668 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
8669 bar->dragging = Qnil;
8670 }
f451eb13 8671
5116f055
JB
8672 /* Same deal here as the other #if 0. */
8673#if 0
58769bee 8674 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 8675 the handle. */
ab648270 8676 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
8677 emacs_event->x = bar->start;
8678 else
e0c1aef2 8679 XSETINT (emacs_event->x, y);
5116f055 8680#else
e0c1aef2 8681 XSETINT (emacs_event->x, y);
5116f055 8682#endif
f451eb13 8683
e0c1aef2 8684 XSETINT (emacs_event->y, top_range);
12ba150f
JB
8685 }
8686}
f451eb13 8687
ab648270
JB
8688/* Handle some mouse motion while someone is dragging the scroll bar.
8689
8690 This may be called from a signal handler, so we have to ignore GC
8691 mark bits. */
06a2c219 8692
f451eb13 8693static void
ab648270
JB
8694x_scroll_bar_note_movement (bar, event)
8695 struct scroll_bar *bar;
f451eb13
JB
8696 XEvent *event;
8697{
39d8bb4d
KH
8698 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
8699
f451eb13
JB
8700 last_mouse_movement_time = event->xmotion.time;
8701
39d8bb4d 8702 f->mouse_moved = 1;
e0c1aef2 8703 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
8704
8705 /* If we're dragging the bar, display it. */
ab648270 8706 if (! GC_NILP (bar->dragging))
f451eb13
JB
8707 {
8708 /* Where should the handle be now? */
12ba150f 8709 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 8710
12ba150f 8711 if (new_start != XINT (bar->start))
f451eb13 8712 {
12ba150f 8713 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 8714
ab648270 8715 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
8716 }
8717 }
f451eb13
JB
8718}
8719
5c187dee
GM
8720#endif /* !USE_TOOLKIT_SCROLL_BARS */
8721
12ba150f 8722/* Return information to the user about the current position of the mouse
ab648270 8723 on the scroll bar. */
06a2c219 8724
12ba150f 8725static void
334208b7
RS
8726x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
8727 FRAME_PTR *fp;
12ba150f 8728 Lisp_Object *bar_window;
ab648270 8729 enum scroll_bar_part *part;
12ba150f
JB
8730 Lisp_Object *x, *y;
8731 unsigned long *time;
8732{
ab648270 8733 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
8734 Window w = SCROLL_BAR_X_WINDOW (bar);
8735 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 8736 int win_x, win_y;
559cb2fb
JB
8737 Window dummy_window;
8738 int dummy_coord;
8739 unsigned int dummy_mask;
12ba150f 8740
cf7cb199
JB
8741 BLOCK_INPUT;
8742
ab648270 8743 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 8744 report that. */
334208b7 8745 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 8746
559cb2fb
JB
8747 /* Root, child, root x and root y. */
8748 &dummy_window, &dummy_window,
8749 &dummy_coord, &dummy_coord,
12ba150f 8750
559cb2fb
JB
8751 /* Position relative to scroll bar. */
8752 &win_x, &win_y,
12ba150f 8753
559cb2fb
JB
8754 /* Mouse buttons and modifier keys. */
8755 &dummy_mask))
7a13e894 8756 ;
559cb2fb
JB
8757 else
8758 {
06a2c219 8759#if 0
559cb2fb 8760 int inside_height
d9cdbb3d 8761 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8762#endif
559cb2fb 8763 int top_range
d9cdbb3d 8764 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
8765
8766 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
8767
8768 if (! NILP (bar->dragging))
8769 win_y -= XINT (bar->dragging);
8770
8771 if (win_y < 0)
8772 win_y = 0;
8773 if (win_y > top_range)
8774 win_y = top_range;
8775
334208b7 8776 *fp = f;
7a13e894 8777 *bar_window = bar->window;
559cb2fb
JB
8778
8779 if (! NILP (bar->dragging))
8780 *part = scroll_bar_handle;
8781 else if (win_y < XINT (bar->start))
8782 *part = scroll_bar_above_handle;
8783 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8784 *part = scroll_bar_handle;
8785 else
8786 *part = scroll_bar_below_handle;
12ba150f 8787
e0c1aef2
KH
8788 XSETINT (*x, win_y);
8789 XSETINT (*y, top_range);
12ba150f 8790
39d8bb4d 8791 f->mouse_moved = 0;
559cb2fb
JB
8792 last_mouse_scroll_bar = Qnil;
8793 }
12ba150f 8794
559cb2fb 8795 *time = last_mouse_movement_time;
cf7cb199 8796
cf7cb199 8797 UNBLOCK_INPUT;
12ba150f
JB
8798}
8799
f451eb13 8800
dbc4e1c1 8801/* The screen has been cleared so we may have changed foreground or
ab648270
JB
8802 background colors, and the scroll bars may need to be redrawn.
8803 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
8804 redraw them. */
8805
dfcf069d 8806void
ab648270 8807x_scroll_bar_clear (f)
dbc4e1c1
JB
8808 FRAME_PTR f;
8809{
06a2c219 8810#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
8811 Lisp_Object bar;
8812
b80c363e
RS
8813 /* We can have scroll bars even if this is 0,
8814 if we just turned off scroll bar mode.
8815 But in that case we should not clear them. */
8816 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
8817 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
8818 bar = XSCROLL_BAR (bar)->next)
8819 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
8820 0, 0, 0, 0, True);
06a2c219 8821#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
8822}
8823
06a2c219 8824/* This processes Expose events from the menu-bar specific X event
19126e11 8825 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 8826 when handling menu-bar or pop-up items. */
3afe33e7 8827
06a2c219 8828int
3afe33e7
RS
8829process_expose_from_menu (event)
8830 XEvent event;
8831{
8832 FRAME_PTR f;
19126e11 8833 struct x_display_info *dpyinfo;
06a2c219 8834 int frame_exposed_p = 0;
3afe33e7 8835
f94397b5
KH
8836 BLOCK_INPUT;
8837
19126e11
KH
8838 dpyinfo = x_display_info_for_display (event.xexpose.display);
8839 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
8840 if (f)
8841 {
8842 if (f->async_visible == 0)
8843 {
8844 f->async_visible = 1;
8845 f->async_iconified = 0;
06c488fd 8846 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
8847 SET_FRAME_GARBAGED (f);
8848 }
8849 else
8850 {
06a2c219
GM
8851 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
8852 event.xexpose.x, event.xexpose.y,
8853 event.xexpose.width, event.xexpose.height);
8854 frame_exposed_p = 1;
3afe33e7
RS
8855 }
8856 }
8857 else
8858 {
8859 struct scroll_bar *bar
8860 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 8861
3afe33e7
RS
8862 if (bar)
8863 x_scroll_bar_expose (bar, &event);
8864 }
f94397b5
KH
8865
8866 UNBLOCK_INPUT;
06a2c219 8867 return frame_exposed_p;
3afe33e7 8868}
09756a85
RS
8869\f
8870/* Define a queue to save up SelectionRequest events for later handling. */
8871
8872struct selection_event_queue
8873 {
8874 XEvent event;
8875 struct selection_event_queue *next;
8876 };
8877
8878static struct selection_event_queue *queue;
8879
8880/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 8881
09756a85
RS
8882static int x_queue_selection_requests;
8883
8884/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 8885
09756a85 8886static void
334208b7
RS
8887x_queue_event (f, event)
8888 FRAME_PTR f;
09756a85
RS
8889 XEvent *event;
8890{
8891 struct selection_event_queue *queue_tmp
06a2c219 8892 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 8893
58769bee 8894 if (queue_tmp != NULL)
09756a85
RS
8895 {
8896 queue_tmp->event = *event;
8897 queue_tmp->next = queue;
8898 queue = queue_tmp;
8899 }
8900}
8901
8902/* Take all the queued events and put them back
8903 so that they get processed afresh. */
8904
8905static void
db3906fd
RS
8906x_unqueue_events (display)
8907 Display *display;
09756a85 8908{
58769bee 8909 while (queue != NULL)
09756a85
RS
8910 {
8911 struct selection_event_queue *queue_tmp = queue;
db3906fd 8912 XPutBackEvent (display, &queue_tmp->event);
09756a85 8913 queue = queue_tmp->next;
06a2c219 8914 xfree ((char *)queue_tmp);
09756a85
RS
8915 }
8916}
8917
8918/* Start queuing SelectionRequest events. */
8919
8920void
db3906fd
RS
8921x_start_queuing_selection_requests (display)
8922 Display *display;
09756a85
RS
8923{
8924 x_queue_selection_requests++;
8925}
8926
8927/* Stop queuing SelectionRequest events. */
8928
8929void
db3906fd
RS
8930x_stop_queuing_selection_requests (display)
8931 Display *display;
09756a85
RS
8932{
8933 x_queue_selection_requests--;
db3906fd 8934 x_unqueue_events (display);
09756a85 8935}
f451eb13
JB
8936\f
8937/* The main X event-reading loop - XTread_socket. */
dc6f92b8 8938
06a2c219 8939/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
8940 but we have to put it out here, since static variables within functions
8941 sometimes don't work. */
06a2c219 8942
dc6f92b8
JB
8943static Time enter_timestamp;
8944
11edeb03 8945/* This holds the state XLookupString needs to implement dead keys
58769bee 8946 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
8947 says that a portable program can't use this, but Stephen Gildea assures
8948 me that letting the compiler initialize it to zeros will work okay.
8949
8950 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
8951 given for enter_time stamp, above. */
8952
11edeb03
JB
8953static XComposeStatus compose_status;
8954
10e6549c
RS
8955/* Record the last 100 characters stored
8956 to help debug the loss-of-chars-during-GC problem. */
06a2c219 8957
2224b905
RS
8958static int temp_index;
8959static short temp_buffer[100];
10e6549c 8960
7a13e894
RS
8961/* Set this to nonzero to fake an "X I/O error"
8962 on a particular display. */
06a2c219 8963
7a13e894
RS
8964struct x_display_info *XTread_socket_fake_io_error;
8965
2224b905
RS
8966/* When we find no input here, we occasionally do a no-op command
8967 to verify that the X server is still running and we can still talk with it.
8968 We try all the open displays, one by one.
8969 This variable is used for cycling thru the displays. */
06a2c219 8970
2224b905
RS
8971static struct x_display_info *next_noop_dpyinfo;
8972
06a2c219
GM
8973#define SET_SAVED_MENU_EVENT(size) \
8974 do \
8975 { \
8976 if (f->output_data.x->saved_menu_event == 0) \
8977 f->output_data.x->saved_menu_event \
8978 = (XEvent *) xmalloc (sizeof (XEvent)); \
8979 bcopy (&event, f->output_data.x->saved_menu_event, size); \
8980 if (numchars >= 1) \
8981 { \
8982 bufp->kind = menu_bar_activate_event; \
8983 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 8984 bufp->arg = Qnil; \
06a2c219
GM
8985 bufp++; \
8986 count++; \
8987 numchars--; \
8988 } \
8989 } \
8990 while (0)
8991
8805890a 8992#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 8993#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 8994
dc6f92b8
JB
8995/* Read events coming from the X server.
8996 This routine is called by the SIGIO handler.
8997 We return as soon as there are no more events to be read.
8998
8999 Events representing keys are stored in buffer BUFP,
9000 which can hold up to NUMCHARS characters.
9001 We return the number of characters stored into the buffer,
9002 thus pretending to be `read'.
9003
dc6f92b8
JB
9004 EXPECTED is nonzero if the caller knows input is available. */
9005
7c5283e4 9006int
f66868ba 9007XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9008 register int sd;
8805890a
KH
9009 /* register */ struct input_event *bufp;
9010 /* register */ int numchars;
dc6f92b8
JB
9011 int expected;
9012{
9013 int count = 0;
9014 int nbytes = 0;
dc6f92b8 9015 XEvent event;
f676886a 9016 struct frame *f;
66f55a9d 9017 int event_found = 0;
334208b7 9018 struct x_display_info *dpyinfo;
dc6f92b8 9019
9ac0d9e0 9020 if (interrupt_input_blocked)
dc6f92b8 9021 {
9ac0d9e0 9022 interrupt_input_pending = 1;
dc6f92b8
JB
9023 return -1;
9024 }
9025
9ac0d9e0 9026 interrupt_input_pending = 0;
dc6f92b8 9027 BLOCK_INPUT;
c0a04927
RS
9028
9029 /* So people can tell when we have read the available input. */
9030 input_signal_count++;
9031
dc6f92b8 9032 if (numchars <= 0)
06a2c219 9033 abort (); /* Don't think this happens. */
dc6f92b8 9034
bde5503b
GM
9035 ++handling_signal;
9036
7a13e894
RS
9037 /* Find the display we are supposed to read input for.
9038 It's the one communicating on descriptor SD. */
9039 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9040 {
9041#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9042#ifdef FIOSNBIO
7a13e894
RS
9043 /* If available, Xlib uses FIOSNBIO to make the socket
9044 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9045 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9046 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9047 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9048#endif /* ! defined (FIOSNBIO) */
7a13e894 9049#endif
dc6f92b8 9050
7a13e894
RS
9051#if 0 /* This code can't be made to work, with multiple displays,
9052 and appears not to be used on any system any more.
9053 Also keyboard.c doesn't turn O_NDELAY on and off
9054 for X connections. */
dc6f92b8
JB
9055#ifndef SIGIO
9056#ifndef HAVE_SELECT
7a13e894
RS
9057 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9058 {
9059 extern int read_alarm_should_throw;
9060 read_alarm_should_throw = 1;
9061 XPeekEvent (dpyinfo->display, &event);
9062 read_alarm_should_throw = 0;
9063 }
c118dd06
JB
9064#endif /* HAVE_SELECT */
9065#endif /* SIGIO */
7a13e894 9066#endif
dc6f92b8 9067
7a13e894
RS
9068 /* For debugging, this gives a way to fake an I/O error. */
9069 if (dpyinfo == XTread_socket_fake_io_error)
9070 {
9071 XTread_socket_fake_io_error = 0;
9072 x_io_error_quitter (dpyinfo->display);
9073 }
dc6f92b8 9074
06a2c219 9075 while (XPending (dpyinfo->display))
dc6f92b8 9076 {
7a13e894 9077 XNextEvent (dpyinfo->display, &event);
06a2c219 9078
531483fb 9079#ifdef HAVE_X_I18N
d1bc4182 9080 {
f2be1146
GM
9081 /* Filter events for the current X input method.
9082 XFilterEvent returns non-zero if the input method has
9083 consumed the event. We pass the frame's X window to
9084 XFilterEvent because that's the one for which the IC
9085 was created. */
f5d11644
GM
9086 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9087 event.xclient.window);
9088 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9089 break;
9090 }
0cd6403b 9091#endif
7a13e894
RS
9092 event_found = 1;
9093
9094 switch (event.type)
9095 {
9096 case ClientMessage:
c047688c 9097 {
7a13e894
RS
9098 if (event.xclient.message_type
9099 == dpyinfo->Xatom_wm_protocols
9100 && event.xclient.format == 32)
c047688c 9101 {
7a13e894
RS
9102 if (event.xclient.data.l[0]
9103 == dpyinfo->Xatom_wm_take_focus)
c047688c 9104 {
8c1a6a84
RS
9105 /* Use x_any_window_to_frame because this
9106 could be the shell widget window
9107 if the frame has no title bar. */
9108 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
9109#ifdef HAVE_X_I18N
9110 /* Not quite sure this is needed -pd */
8c1a6a84 9111 if (f && FRAME_XIC (f))
6c183ba5
RS
9112 XSetICFocus (FRAME_XIC (f));
9113#endif
f1da8f06
GM
9114#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
9115 instructs the WM to set the input focus automatically for
9116 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
9117 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
9118 it has set the focus. So, XSetInputFocus below is not
9119 needed.
9120
9121 The call to XSetInputFocus below has also caused trouble. In
9122 cases where the XSetInputFocus done by the WM and the one
9123 below are temporally close (on a fast machine), the call
9124 below can generate additional FocusIn events which confuse
9125 Emacs. */
9126
bf7253f4
RS
9127 /* Since we set WM_TAKE_FOCUS, we must call
9128 XSetInputFocus explicitly. But not if f is null,
9129 since that might be an event for a deleted frame. */
7a13e894 9130 if (f)
bf7253f4
RS
9131 {
9132 Display *d = event.xclient.display;
9133 /* Catch and ignore errors, in case window has been
9134 iconified by a window manager such as GWM. */
9135 int count = x_catch_errors (d);
9136 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
9137 /* The ICCCM says this is
9138 the only valid choice. */
9139 RevertToParent,
bf7253f4
RS
9140 event.xclient.data.l[1]);
9141 /* This is needed to detect the error
9142 if there is an error. */
9143 XSync (d, False);
9144 x_uncatch_errors (d, count);
9145 }
7a13e894 9146 /* Not certain about handling scroll bars here */
f1da8f06 9147#endif /* 0 */
c047688c 9148 }
7a13e894
RS
9149 else if (event.xclient.data.l[0]
9150 == dpyinfo->Xatom_wm_save_yourself)
9151 {
9152 /* Save state modify the WM_COMMAND property to
06a2c219 9153 something which can reinstate us. This notifies
7a13e894
RS
9154 the session manager, who's looking for such a
9155 PropertyNotify. Can restart processing when
06a2c219 9156 a keyboard or mouse event arrives. */
7a13e894
RS
9157 if (numchars > 0)
9158 {
19126e11
KH
9159 f = x_top_window_to_frame (dpyinfo,
9160 event.xclient.window);
7a13e894
RS
9161
9162 /* This is just so we only give real data once
9163 for a single Emacs process. */
b86bd3dd 9164 if (f == SELECTED_FRAME ())
7a13e894
RS
9165 XSetCommand (FRAME_X_DISPLAY (f),
9166 event.xclient.window,
9167 initial_argv, initial_argc);
f000f5c5 9168 else if (f)
7a13e894
RS
9169 XSetCommand (FRAME_X_DISPLAY (f),
9170 event.xclient.window,
9171 0, 0);
9172 }
9173 }
9174 else if (event.xclient.data.l[0]
9175 == dpyinfo->Xatom_wm_delete_window)
1fb20991 9176 {
19126e11
KH
9177 struct frame *f
9178 = x_any_window_to_frame (dpyinfo,
9179 event.xclient.window);
1fb20991 9180
7a13e894
RS
9181 if (f)
9182 {
9183 if (numchars == 0)
9184 abort ();
1fb20991 9185
7a13e894
RS
9186 bufp->kind = delete_window_event;
9187 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9188 bufp->arg = Qnil;
7a13e894
RS
9189 bufp++;
9190
9191 count += 1;
9192 numchars -= 1;
9193 }
1fb20991 9194 }
c047688c 9195 }
7a13e894
RS
9196 else if (event.xclient.message_type
9197 == dpyinfo->Xatom_wm_configure_denied)
9198 {
9199 }
9200 else if (event.xclient.message_type
9201 == dpyinfo->Xatom_wm_window_moved)
9202 {
9203 int new_x, new_y;
19126e11
KH
9204 struct frame *f
9205 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 9206
7a13e894
RS
9207 new_x = event.xclient.data.s[0];
9208 new_y = event.xclient.data.s[1];
1fb20991 9209
7a13e894
RS
9210 if (f)
9211 {
7556890b
RS
9212 f->output_data.x->left_pos = new_x;
9213 f->output_data.x->top_pos = new_y;
7a13e894 9214 }
1fb20991 9215 }
0fdff6bb 9216#ifdef HACK_EDITRES
7a13e894
RS
9217 else if (event.xclient.message_type
9218 == dpyinfo->Xatom_editres)
9219 {
19126e11
KH
9220 struct frame *f
9221 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 9222 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 9223 &event, NULL);
7a13e894 9224 }
0fdff6bb 9225#endif /* HACK_EDITRES */
06a2c219
GM
9226 else if ((event.xclient.message_type
9227 == dpyinfo->Xatom_DONE)
9228 || (event.xclient.message_type
9229 == dpyinfo->Xatom_PAGE))
9230 {
9231 /* Ghostview job completed. Kill it. We could
9232 reply with "Next" if we received "Page", but we
9233 currently never do because we are interested in
9234 images, only, which should have 1 page. */
06a2c219
GM
9235 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
9236 struct frame *f
9237 = x_window_to_frame (dpyinfo, event.xclient.window);
9238 x_kill_gs_process (pixmap, f);
9239 expose_frame (f, 0, 0, 0, 0);
9240 }
9241#ifdef USE_TOOLKIT_SCROLL_BARS
9242 /* Scroll bar callbacks send a ClientMessage from which
9243 we construct an input_event. */
9244 else if (event.xclient.message_type
9245 == dpyinfo->Xatom_Scrollbar)
9246 {
9247 x_scroll_bar_to_input_event (&event, bufp);
9248 ++bufp, ++count, --numchars;
9249 goto out;
9250 }
9251#endif /* USE_TOOLKIT_SCROLL_BARS */
9252 else
9253 goto OTHER;
7a13e894
RS
9254 }
9255 break;
dc6f92b8 9256
7a13e894 9257 case SelectionNotify:
3afe33e7 9258#ifdef USE_X_TOOLKIT
19126e11 9259 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 9260 goto OTHER;
3afe33e7 9261#endif /* not USE_X_TOOLKIT */
dfcf069d 9262 x_handle_selection_notify (&event.xselection);
7a13e894 9263 break;
d56a553a 9264
06a2c219 9265 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 9266#ifdef USE_X_TOOLKIT
19126e11 9267 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 9268 goto OTHER;
3afe33e7 9269#endif /* USE_X_TOOLKIT */
7a13e894
RS
9270 {
9271 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 9272
7a13e894
RS
9273 if (numchars == 0)
9274 abort ();
d56a553a 9275
7a13e894
RS
9276 bufp->kind = selection_clear_event;
9277 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9278 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9279 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9280 bufp->frame_or_window = Qnil;
0f8aabe9 9281 bufp->arg = Qnil;
7a13e894 9282 bufp++;
d56a553a 9283
7a13e894
RS
9284 count += 1;
9285 numchars -= 1;
9286 }
9287 break;
dc6f92b8 9288
06a2c219 9289 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 9290#ifdef USE_X_TOOLKIT
19126e11 9291 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 9292 goto OTHER;
3afe33e7 9293#endif /* USE_X_TOOLKIT */
7a13e894 9294 if (x_queue_selection_requests)
19126e11 9295 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
9296 &event);
9297 else
9298 {
9299 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 9300
7a13e894
RS
9301 if (numchars == 0)
9302 abort ();
9303
9304 bufp->kind = selection_request_event;
9305 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9306 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
9307 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9308 SELECTION_EVENT_TARGET (bufp) = eventp->target;
9309 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
9310 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9311 bufp->frame_or_window = Qnil;
0f8aabe9 9312 bufp->arg = Qnil;
7a13e894
RS
9313 bufp++;
9314
9315 count += 1;
9316 numchars -= 1;
9317 }
9318 break;
9319
9320 case PropertyNotify:
3afe33e7 9321#ifdef USE_X_TOOLKIT
19126e11 9322 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 9323 goto OTHER;
3afe33e7 9324#endif /* not USE_X_TOOLKIT */
dfcf069d 9325 x_handle_property_notify (&event.xproperty);
7a13e894 9326 break;
dc6f92b8 9327
7a13e894 9328 case ReparentNotify:
19126e11 9329 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
9330 if (f)
9331 {
9332 int x, y;
7556890b 9333 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 9334 x_real_positions (f, &x, &y);
7556890b
RS
9335 f->output_data.x->left_pos = x;
9336 f->output_data.x->top_pos = y;
7a13e894
RS
9337 }
9338 break;
3bd330d4 9339
7a13e894 9340 case Expose:
19126e11 9341 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 9342 if (f)
dc6f92b8 9343 {
7a13e894
RS
9344 if (f->async_visible == 0)
9345 {
9346 f->async_visible = 1;
9347 f->async_iconified = 0;
06c488fd 9348 f->output_data.x->has_been_visible = 1;
7a13e894
RS
9349 SET_FRAME_GARBAGED (f);
9350 }
9351 else
06a2c219
GM
9352 expose_frame (x_window_to_frame (dpyinfo,
9353 event.xexpose.window),
9354 event.xexpose.x, event.xexpose.y,
9355 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
9356 }
9357 else
7a13e894 9358 {
06a2c219
GM
9359#ifdef USE_TOOLKIT_SCROLL_BARS
9360 /* Dispatch event to the widget. */
9361 goto OTHER;
9362#else /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9363 struct scroll_bar *bar
9364 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9365
7a13e894
RS
9366 if (bar)
9367 x_scroll_bar_expose (bar, &event);
3afe33e7 9368#ifdef USE_X_TOOLKIT
7a13e894
RS
9369 else
9370 goto OTHER;
3afe33e7 9371#endif /* USE_X_TOOLKIT */
06a2c219 9372#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9373 }
9374 break;
dc6f92b8 9375
7a13e894
RS
9376 case GraphicsExpose: /* This occurs when an XCopyArea's
9377 source area was obscured or not
9378 available.*/
19126e11 9379 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
9380 if (f)
9381 {
06a2c219
GM
9382 expose_frame (f,
9383 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
9384 event.xgraphicsexpose.width,
9385 event.xgraphicsexpose.height);
7a13e894 9386 }
3afe33e7 9387#ifdef USE_X_TOOLKIT
7a13e894
RS
9388 else
9389 goto OTHER;
3afe33e7 9390#endif /* USE_X_TOOLKIT */
7a13e894 9391 break;
dc6f92b8 9392
7a13e894 9393 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
9394 source area was completely
9395 available */
7a13e894 9396 break;
dc6f92b8 9397
7a13e894 9398 case UnmapNotify:
06a2c219
GM
9399 /* Redo the mouse-highlight after the tooltip has gone. */
9400 if (event.xmap.window == tip_window)
9401 {
9402 tip_window = 0;
9403 redo_mouse_highlight ();
9404 }
9405
91ea2a7a 9406 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
9407 if (f) /* F may no longer exist if
9408 the frame was deleted. */
9409 {
9410 /* While a frame is unmapped, display generation is
9411 disabled; you don't want to spend time updating a
9412 display that won't ever be seen. */
9413 f->async_visible = 0;
9414 /* We can't distinguish, from the event, whether the window
9415 has become iconified or invisible. So assume, if it
9416 was previously visible, than now it is iconified.
1aa6072f
RS
9417 But x_make_frame_invisible clears both
9418 the visible flag and the iconified flag;
9419 and that way, we know the window is not iconified now. */
7a13e894 9420 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
9421 {
9422 f->async_iconified = 1;
bddd097c 9423
1aa6072f
RS
9424 bufp->kind = iconify_event;
9425 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9426 bufp->arg = Qnil;
1aa6072f
RS
9427 bufp++;
9428 count++;
9429 numchars--;
9430 }
7a13e894 9431 }
7a13e894 9432 goto OTHER;
dc6f92b8 9433
7a13e894 9434 case MapNotify:
06a2c219
GM
9435 if (event.xmap.window == tip_window)
9436 /* The tooltip has been drawn already. Avoid
9437 the SET_FRAME_GARBAGED below. */
9438 goto OTHER;
9439
9440 /* We use x_top_window_to_frame because map events can
9441 come for sub-windows and they don't mean that the
9442 frame is visible. */
19126e11 9443 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
9444 if (f)
9445 {
9446 f->async_visible = 1;
9447 f->async_iconified = 0;
06c488fd 9448 f->output_data.x->has_been_visible = 1;
dc6f92b8 9449
7a13e894
RS
9450 /* wait_reading_process_input will notice this and update
9451 the frame's display structures. */
9452 SET_FRAME_GARBAGED (f);
bddd097c 9453
d806e720
RS
9454 if (f->iconified)
9455 {
9456 bufp->kind = deiconify_event;
9457 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9458 bufp->arg = Qnil;
d806e720
RS
9459 bufp++;
9460 count++;
9461 numchars--;
9462 }
e73ec6fa 9463 else if (! NILP (Vframe_list)
8e713be6 9464 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
9465 /* Force a redisplay sooner or later
9466 to update the frame titles
9467 in case this is the second frame. */
9468 record_asynch_buffer_change ();
7a13e894 9469 }
7a13e894 9470 goto OTHER;
dc6f92b8 9471
7a13e894 9472 case KeyPress:
19126e11 9473 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 9474
06a2c219
GM
9475#ifdef USE_MOTIF
9476 /* I couldn't find a way to prevent LessTif scroll bars
9477 from consuming key events. */
9478 if (f == 0)
9479 {
9480 Widget widget = XtWindowToWidget (dpyinfo->display,
9481 event.xkey.window);
9482 if (widget && XmIsScrollBar (widget))
9483 {
9484 widget = XtParent (widget);
9485 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
9486 }
9487 }
9488#endif /* USE_MOTIF */
9489
7a13e894
RS
9490 if (f != 0)
9491 {
9492 KeySym keysym, orig_keysym;
9493 /* al%imercury@uunet.uu.net says that making this 81 instead of
9494 80 fixed a bug whereby meta chars made his Emacs hang. */
9495 unsigned char copy_buffer[81];
9496 int modifiers;
64bb1782 9497
7a13e894
RS
9498 event.xkey.state
9499 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
9500 extra_keyboard_modifiers);
9501 modifiers = event.xkey.state;
3a2712f9 9502
7a13e894 9503 /* This will have to go some day... */
752a043f 9504
7a13e894
RS
9505 /* make_lispy_event turns chars into control chars.
9506 Don't do it here because XLookupString is too eager. */
9507 event.xkey.state &= ~ControlMask;
5d46f928
RS
9508 event.xkey.state &= ~(dpyinfo->meta_mod_mask
9509 | dpyinfo->super_mod_mask
9510 | dpyinfo->hyper_mod_mask
9511 | dpyinfo->alt_mod_mask);
9512
1cf4a0d1
RS
9513 /* In case Meta is ComposeCharacter,
9514 clear its status. According to Markus Ehrnsperger
9515 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
9516 this enables ComposeCharacter to work whether or
9517 not it is combined with Meta. */
9518 if (modifiers & dpyinfo->meta_mod_mask)
9519 bzero (&compose_status, sizeof (compose_status));
9520
6c183ba5
RS
9521#ifdef HAVE_X_I18N
9522 if (FRAME_XIC (f))
9523 {
f5d11644
GM
9524 unsigned char *copy_bufptr = copy_buffer;
9525 int copy_bufsiz = sizeof (copy_buffer);
9526 Status status_return;
9527
6c183ba5 9528 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
9529 &event.xkey, copy_bufptr,
9530 copy_bufsiz, &keysym,
6c183ba5 9531 &status_return);
f5d11644
GM
9532 if (status_return == XBufferOverflow)
9533 {
9534 copy_bufsiz = nbytes + 1;
9535 copy_bufptr = (char *) alloca (copy_bufsiz);
9536 nbytes = XmbLookupString (FRAME_XIC (f),
9537 &event.xkey, copy_bufptr,
9538 copy_bufsiz, &keysym,
9539 &status_return);
9540 }
9541
1decb680
PE
9542 if (status_return == XLookupNone)
9543 break;
9544 else if (status_return == XLookupChars)
fdd9d55e
GM
9545 {
9546 keysym = NoSymbol;
9547 modifiers = 0;
9548 }
1decb680
PE
9549 else if (status_return != XLookupKeySym
9550 && status_return != XLookupBoth)
9551 abort ();
6c183ba5
RS
9552 }
9553 else
9554 nbytes = XLookupString (&event.xkey, copy_buffer,
9555 80, &keysym, &compose_status);
9556#else
0299d313
RS
9557 nbytes = XLookupString (&event.xkey, copy_buffer,
9558 80, &keysym, &compose_status);
6c183ba5 9559#endif
dc6f92b8 9560
7a13e894 9561 orig_keysym = keysym;
55123275 9562
7a13e894
RS
9563 if (numchars > 1)
9564 {
9565 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
9566 || keysym == XK_Delete
1097aea0 9567#ifdef XK_ISO_Left_Tab
441affdb 9568 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 9569#endif
852bff8f 9570 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
9571 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
9572 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 9573#ifdef HPUX
7a13e894
RS
9574 /* This recognizes the "extended function keys".
9575 It seems there's no cleaner way.
9576 Test IsModifierKey to avoid handling mode_switch
9577 incorrectly. */
9578 || ((unsigned) (keysym) >= XK_Select
9579 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
9580#endif
9581#ifdef XK_dead_circumflex
7a13e894 9582 || orig_keysym == XK_dead_circumflex
69388238
RS
9583#endif
9584#ifdef XK_dead_grave
7a13e894 9585 || orig_keysym == XK_dead_grave
69388238
RS
9586#endif
9587#ifdef XK_dead_tilde
7a13e894 9588 || orig_keysym == XK_dead_tilde
69388238
RS
9589#endif
9590#ifdef XK_dead_diaeresis
7a13e894 9591 || orig_keysym == XK_dead_diaeresis
69388238
RS
9592#endif
9593#ifdef XK_dead_macron
7a13e894 9594 || orig_keysym == XK_dead_macron
69388238
RS
9595#endif
9596#ifdef XK_dead_degree
7a13e894 9597 || orig_keysym == XK_dead_degree
69388238
RS
9598#endif
9599#ifdef XK_dead_acute
7a13e894 9600 || orig_keysym == XK_dead_acute
69388238
RS
9601#endif
9602#ifdef XK_dead_cedilla
7a13e894 9603 || orig_keysym == XK_dead_cedilla
69388238
RS
9604#endif
9605#ifdef XK_dead_breve
7a13e894 9606 || orig_keysym == XK_dead_breve
69388238
RS
9607#endif
9608#ifdef XK_dead_ogonek
7a13e894 9609 || orig_keysym == XK_dead_ogonek
69388238
RS
9610#endif
9611#ifdef XK_dead_caron
7a13e894 9612 || orig_keysym == XK_dead_caron
69388238
RS
9613#endif
9614#ifdef XK_dead_doubleacute
7a13e894 9615 || orig_keysym == XK_dead_doubleacute
69388238
RS
9616#endif
9617#ifdef XK_dead_abovedot
7a13e894 9618 || orig_keysym == XK_dead_abovedot
c34790e0 9619#endif
7a13e894
RS
9620 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
9621 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
9622 /* Any "vendor-specific" key is ok. */
9623 || (orig_keysym & (1 << 28)))
9624 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
9625#ifndef HAVE_X11R5
9626#ifdef XK_Mode_switch
7a13e894 9627 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
9628#endif
9629#ifdef XK_Num_Lock
7a13e894 9630 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
9631#endif
9632#endif /* not HAVE_X11R5 */
7a13e894 9633 ))
dc6f92b8 9634 {
10e6549c
RS
9635 if (temp_index == sizeof temp_buffer / sizeof (short))
9636 temp_index = 0;
7a13e894
RS
9637 temp_buffer[temp_index++] = keysym;
9638 bufp->kind = non_ascii_keystroke;
9639 bufp->code = keysym;
e0c1aef2 9640 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9641 bufp->arg = Qnil;
334208b7
RS
9642 bufp->modifiers
9643 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9644 modifiers);
1113d9db 9645 bufp->timestamp = event.xkey.time;
dc6f92b8 9646 bufp++;
7a13e894
RS
9647 count++;
9648 numchars--;
dc6f92b8 9649 }
7a13e894
RS
9650 else if (numchars > nbytes)
9651 {
9652 register int i;
9653
9654 for (i = 0; i < nbytes; i++)
9655 {
9656 if (temp_index == sizeof temp_buffer / sizeof (short))
9657 temp_index = 0;
9658 temp_buffer[temp_index++] = copy_buffer[i];
9659 bufp->kind = ascii_keystroke;
9660 bufp->code = copy_buffer[i];
9661 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9662 bufp->arg = Qnil;
7a13e894
RS
9663 bufp->modifiers
9664 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9665 modifiers);
9666 bufp->timestamp = event.xkey.time;
9667 bufp++;
9668 }
9669
9670 count += nbytes;
9671 numchars -= nbytes;
1decb680
PE
9672
9673 if (keysym == NoSymbol)
9674 break;
7a13e894
RS
9675 }
9676 else
9677 abort ();
dc6f92b8 9678 }
10e6549c
RS
9679 else
9680 abort ();
dc6f92b8 9681 }
59ddecde
GM
9682#ifdef HAVE_X_I18N
9683 /* Don't dispatch this event since XtDispatchEvent calls
9684 XFilterEvent, and two calls in a row may freeze the
9685 client. */
9686 break;
9687#else
717ca130 9688 goto OTHER;
59ddecde 9689#endif
f451eb13 9690
f5d11644 9691 case KeyRelease:
59ddecde
GM
9692#ifdef HAVE_X_I18N
9693 /* Don't dispatch this event since XtDispatchEvent calls
9694 XFilterEvent, and two calls in a row may freeze the
9695 client. */
9696 break;
9697#else
f5d11644 9698 goto OTHER;
59ddecde 9699#endif
f5d11644 9700
7a13e894 9701 /* Here's a possible interpretation of the whole
06a2c219
GM
9702 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
9703 you get a FocusIn event, you have to get a FocusOut
9704 event before you relinquish the focus. If you
9705 haven't received a FocusIn event, then a mere
9706 LeaveNotify is enough to free you. */
f451eb13 9707
7a13e894 9708 case EnterNotify:
06a2c219
GM
9709 {
9710 int from_menu_bar_p = 0;
9711
9712 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
9713
9714#ifdef LESSTIF_VERSION
9715 /* When clicking outside of a menu bar popup to close
9716 it, we get a FocusIn/ EnterNotify sequence of
9717 events. The flag event.xcrossing.focus is not set
9718 in the EnterNotify event of that sequence because
9719 the focus is in the menu bar,
9720 event.xcrossing.window is the frame's X window.
9721 Unconditionally setting the focus frame to null in
9722 this case is not the right thing, because no event
9723 follows that could set the focus frame to the right
9724 value.
9725
9726 This could be a LessTif bug, but I wasn't able to
9727 reproduce the behavior in a simple test program.
9728
9729 (gerd, LessTif 0.88.1). */
9730
9731 if (!event.xcrossing.focus
9732 && f
9733 && f->output_data.x->menubar_widget)
9734 {
9735 Window focus;
9736 int revert;
9737
9738 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9739 if (focus == XtWindow (f->output_data.x->menubar_widget))
9740 from_menu_bar_p = 1;
9741 }
9742#endif /* LESSTIF_VERSION */
6d4238f3 9743
06a2c219
GM
9744 if (event.xcrossing.focus || from_menu_bar_p)
9745 {
9746 /* Avoid nasty pop/raise loops. */
9747 if (f && (!(f->auto_raise)
9748 || !(f->auto_lower)
9749 || (event.xcrossing.time - enter_timestamp) > 500))
9750 {
9751 x_new_focus_frame (dpyinfo, f);
9752 enter_timestamp = event.xcrossing.time;
9753 }
9754 }
9755 else if (f == dpyinfo->x_focus_frame)
9756 x_new_focus_frame (dpyinfo, 0);
9757
9758 /* EnterNotify counts as mouse movement,
9759 so update things that depend on mouse position. */
9760 if (f && !f->output_data.x->busy_p)
9761 note_mouse_movement (f, &event.xmotion);
9762 goto OTHER;
9763 }
dc6f92b8 9764
7a13e894 9765 case FocusIn:
19126e11 9766 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9767 if (event.xfocus.detail != NotifyPointer)
0f941935 9768 dpyinfo->x_focus_event_frame = f;
7a13e894 9769 if (f)
eb72635f
GM
9770 {
9771 x_new_focus_frame (dpyinfo, f);
9772
9773 /* Don't stop displaying the initial startup message
9774 for a switch-frame event we don't need. */
9775 if (GC_NILP (Vterminal_frame)
9776 && GC_CONSP (Vframe_list)
9777 && !GC_NILP (XCDR (Vframe_list)))
9778 {
9779 bufp->kind = FOCUS_IN_EVENT;
9780 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9781 bufp->arg = Qnil;
eb72635f
GM
9782 ++bufp, ++count, --numchars;
9783 }
9784 }
f9e24cb9 9785
6c183ba5
RS
9786#ifdef HAVE_X_I18N
9787 if (f && FRAME_XIC (f))
9788 XSetICFocus (FRAME_XIC (f));
9789#endif
9790
7a13e894 9791 goto OTHER;
10c5e63d 9792
7a13e894 9793 case LeaveNotify:
19126e11 9794 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 9795 if (f)
10c5e63d 9796 {
06a2c219
GM
9797 Lisp_Object frame;
9798 int from_menu_bar_p = 0;
9799
7a13e894 9800 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
9801 {
9802 /* If we move outside the frame, then we're
9803 certainly no longer on any text in the frame. */
9804 clear_mouse_face (dpyinfo);
9805 dpyinfo->mouse_face_mouse_frame = 0;
9806 }
9807
9808 /* Generate a nil HELP_EVENT to cancel a help-echo.
9809 Do it only if there's something to cancel.
9810 Otherwise, the startup message is cleared when
9811 the mouse leaves the frame. */
9812 if (any_help_event_p)
9813 {
be010514
GM
9814 Lisp_Object frame;
9815 int n;
9816
06a2c219 9817 XSETFRAME (frame, f);
7cea38bc 9818 n = gen_help_event (bufp, Qnil, frame, Qnil, Qnil, 0);
be010514 9819 bufp += n, count += n, numchars -= n;
06a2c219 9820 }
7a13e894 9821
06a2c219
GM
9822#ifdef LESSTIF_VERSION
9823 /* Please see the comment at the start of the
9824 EnterNotify case. */
9825 if (!event.xcrossing.focus
9826 && f->output_data.x->menubar_widget)
9827 {
9828 Window focus;
9829 int revert;
9830 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9831 if (focus == XtWindow (f->output_data.x->menubar_widget))
9832 from_menu_bar_p = 1;
9833 }
9834#endif /* LESSTIF_VERSION */
9835
9836 if (event.xcrossing.focus || from_menu_bar_p)
0f941935 9837 x_mouse_leave (dpyinfo);
10c5e63d 9838 else
7a13e894 9839 {
0f941935
KH
9840 if (f == dpyinfo->x_focus_event_frame)
9841 dpyinfo->x_focus_event_frame = 0;
9842 if (f == dpyinfo->x_focus_frame)
9843 x_new_focus_frame (dpyinfo, 0);
7a13e894 9844 }
10c5e63d 9845 }
7a13e894 9846 goto OTHER;
dc6f92b8 9847
7a13e894 9848 case FocusOut:
19126e11 9849 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9850 if (event.xfocus.detail != NotifyPointer
0f941935
KH
9851 && f == dpyinfo->x_focus_event_frame)
9852 dpyinfo->x_focus_event_frame = 0;
9853 if (f && f == dpyinfo->x_focus_frame)
9854 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 9855
6c183ba5
RS
9856#ifdef HAVE_X_I18N
9857 if (f && FRAME_XIC (f))
9858 XUnsetICFocus (FRAME_XIC (f));
9859#endif
9860
7a13e894 9861 goto OTHER;
dc6f92b8 9862
7a13e894 9863 case MotionNotify:
dc6f92b8 9864 {
06a2c219 9865 previous_help_echo = help_echo;
7cea38bc 9866 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 9867 help_echo_pos = -1;
06a2c219 9868
7a13e894
RS
9869 if (dpyinfo->grabbed && last_mouse_frame
9870 && FRAME_LIVE_P (last_mouse_frame))
9871 f = last_mouse_frame;
9872 else
19126e11 9873 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 9874
7a13e894
RS
9875 if (f)
9876 note_mouse_movement (f, &event.xmotion);
9877 else
9878 {
e88b3c50 9879#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
9880 struct scroll_bar *bar
9881 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 9882
7a13e894
RS
9883 if (bar)
9884 x_scroll_bar_note_movement (bar, &event);
e88b3c50 9885#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 9886
06a2c219
GM
9887 /* If we move outside the frame, then we're
9888 certainly no longer on any text in the frame. */
7a13e894
RS
9889 clear_mouse_face (dpyinfo);
9890 }
06a2c219
GM
9891
9892 /* If the contents of the global variable help_echo
9893 has changed, generate a HELP_EVENT. */
b7e80413
SM
9894 if (!NILP (help_echo)
9895 || !NILP (previous_help_echo))
06a2c219
GM
9896 {
9897 Lisp_Object frame;
be010514 9898 int n;
06a2c219
GM
9899
9900 if (f)
9901 XSETFRAME (frame, f);
9902 else
9903 frame = Qnil;
9904
9905 any_help_event_p = 1;
be010514 9906 n = gen_help_event (bufp, help_echo, frame,
7cea38bc
GM
9907 help_echo_window, help_echo_object,
9908 help_echo_pos);
be010514 9909 bufp += n, count += n, numchars -= n;
06a2c219
GM
9910 }
9911
9912 goto OTHER;
dc6f92b8 9913 }
dc6f92b8 9914
7a13e894 9915 case ConfigureNotify:
9829ddba
RS
9916 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
9917 if (f)
af395ec1 9918 {
5c187dee 9919#ifndef USE_X_TOOLKIT
bf1b7b30
KH
9920 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
9921 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 9922
2d7fc7e8
RS
9923 /* In the toolkit version, change_frame_size
9924 is called by the code that handles resizing
9925 of the EmacsFrame widget. */
7a13e894 9926
7a13e894
RS
9927 /* Even if the number of character rows and columns has
9928 not changed, the font size may have changed, so we need
9929 to check the pixel dimensions as well. */
9930 if (columns != f->width
9931 || rows != f->height
7556890b
RS
9932 || event.xconfigure.width != f->output_data.x->pixel_width
9933 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 9934 {
7d1e984f 9935 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 9936 SET_FRAME_GARBAGED (f);
e687d06e 9937 cancel_mouse_face (f);
7a13e894 9938 }
2d7fc7e8 9939#endif
af395ec1 9940
7556890b
RS
9941 f->output_data.x->pixel_width = event.xconfigure.width;
9942 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
9943
9944 /* What we have now is the position of Emacs's own window.
9945 Convert that to the position of the window manager window. */
dcb07ae9
RS
9946 x_real_positions (f, &f->output_data.x->left_pos,
9947 &f->output_data.x->top_pos);
9948
f5d11644
GM
9949#ifdef HAVE_X_I18N
9950 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
9951 xic_set_statusarea (f);
9952#endif
9953
dcb07ae9
RS
9954 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
9955 {
9956 /* Since the WM decorations come below top_pos now,
9957 we must put them below top_pos in the future. */
9958 f->output_data.x->win_gravity = NorthWestGravity;
9959 x_wm_set_size_hint (f, (long) 0, 0);
9960 }
8f08dc93
KH
9961#ifdef USE_MOTIF
9962 /* Some window managers pass (0,0) as the location of
9963 the window, and the Motif event handler stores it
9964 in the emacs widget, which messes up Motif menus. */
9965 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
9966 {
9967 event.xconfigure.x = f->output_data.x->widget->core.x;
9968 event.xconfigure.y = f->output_data.x->widget->core.y;
9969 }
06a2c219 9970#endif /* USE_MOTIF */
7a13e894 9971 }
2d7fc7e8 9972 goto OTHER;
dc6f92b8 9973
7a13e894
RS
9974 case ButtonPress:
9975 case ButtonRelease:
9976 {
9977 /* If we decide we want to generate an event to be seen
9978 by the rest of Emacs, we put it here. */
9979 struct input_event emacs_event;
9ea173e8 9980 int tool_bar_p = 0;
06a2c219 9981
7a13e894 9982 emacs_event.kind = no_event;
7a13e894 9983 bzero (&compose_status, sizeof (compose_status));
9b07615b 9984
06a2c219
GM
9985 if (dpyinfo->grabbed
9986 && last_mouse_frame
9f67f20b
RS
9987 && FRAME_LIVE_P (last_mouse_frame))
9988 f = last_mouse_frame;
9989 else
2224b905 9990 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 9991
06a2c219
GM
9992 if (f)
9993 {
9ea173e8
GM
9994 /* Is this in the tool-bar? */
9995 if (WINDOWP (f->tool_bar_window)
9996 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
9997 {
9998 Lisp_Object window;
9999 int p, x, y;
10000
10001 x = event.xbutton.x;
10002 y = event.xbutton.y;
10003
10004 /* Set x and y. */
10005 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10006 if (EQ (window, f->tool_bar_window))
06a2c219 10007 {
9ea173e8
GM
10008 x_handle_tool_bar_click (f, &event.xbutton);
10009 tool_bar_p = 1;
06a2c219
GM
10010 }
10011 }
10012
9ea173e8 10013 if (!tool_bar_p)
06a2c219
GM
10014 if (!dpyinfo->x_focus_frame
10015 || f == dpyinfo->x_focus_frame)
10016 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10017 }
10018 else
10019 {
06a2c219 10020#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10021 struct scroll_bar *bar
10022 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10023
7a13e894
RS
10024 if (bar)
10025 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10026#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10027 }
10028
10029 if (event.type == ButtonPress)
10030 {
10031 dpyinfo->grabbed |= (1 << event.xbutton.button);
10032 last_mouse_frame = f;
edad46f6
KH
10033 /* Ignore any mouse motion that happened
10034 before this event; any subsequent mouse-movement
10035 Emacs events should reflect only motion after
10036 the ButtonPress. */
a00e91cd
KH
10037 if (f != 0)
10038 f->mouse_moved = 0;
06a2c219 10039
9ea173e8
GM
10040 if (!tool_bar_p)
10041 last_tool_bar_item = -1;
7a13e894 10042 }
3afe33e7
RS
10043 else
10044 {
7a13e894 10045 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10046 }
23faf38f 10047
7a13e894
RS
10048 if (numchars >= 1 && emacs_event.kind != no_event)
10049 {
10050 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10051 bufp++;
10052 count++;
10053 numchars--;
10054 }
3afe33e7
RS
10055
10056#ifdef USE_X_TOOLKIT
2224b905
RS
10057 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10058 /* For a down-event in the menu bar,
10059 don't pass it to Xt right now.
10060 Instead, save it away
10061 and we will pass it to Xt from kbd_buffer_get_event.
10062 That way, we can run some Lisp code first. */
91375f8f
RS
10063 if (f && event.type == ButtonPress
10064 /* Verify the event is really within the menu bar
10065 and not just sent to it due to grabbing. */
10066 && event.xbutton.x >= 0
10067 && event.xbutton.x < f->output_data.x->pixel_width
10068 && event.xbutton.y >= 0
10069 && event.xbutton.y < f->output_data.x->menubar_height
10070 && event.xbutton.same_screen)
2224b905 10071 {
8805890a 10072 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
10073 XSETFRAME (last_mouse_press_frame, f);
10074 }
10075 else if (event.type == ButtonPress)
10076 {
10077 last_mouse_press_frame = Qnil;
30e671c3 10078 goto OTHER;
ce89ef46 10079 }
06a2c219 10080
2237cac9
RS
10081#ifdef USE_MOTIF /* This should do not harm for Lucid,
10082 but I am trying to be cautious. */
ce89ef46
RS
10083 else if (event.type == ButtonRelease)
10084 {
2237cac9 10085 if (!NILP (last_mouse_press_frame))
f10ded1c 10086 {
2237cac9
RS
10087 f = XFRAME (last_mouse_press_frame);
10088 if (f->output_data.x)
06a2c219 10089 SET_SAVED_BUTTON_EVENT;
f10ded1c 10090 }
06a2c219 10091 else
30e671c3 10092 goto OTHER;
2224b905 10093 }
2237cac9 10094#endif /* USE_MOTIF */
2224b905
RS
10095 else
10096 goto OTHER;
3afe33e7 10097#endif /* USE_X_TOOLKIT */
7a13e894
RS
10098 }
10099 break;
dc6f92b8 10100
7a13e894 10101 case CirculateNotify:
06a2c219
GM
10102 goto OTHER;
10103
7a13e894 10104 case CirculateRequest:
06a2c219
GM
10105 goto OTHER;
10106
10107 case VisibilityNotify:
10108 goto OTHER;
dc6f92b8 10109
7a13e894
RS
10110 case MappingNotify:
10111 /* Someone has changed the keyboard mapping - update the
10112 local cache. */
10113 switch (event.xmapping.request)
10114 {
10115 case MappingModifier:
10116 x_find_modifier_meanings (dpyinfo);
10117 /* This is meant to fall through. */
10118 case MappingKeyboard:
10119 XRefreshKeyboardMapping (&event.xmapping);
10120 }
7a13e894 10121 goto OTHER;
dc6f92b8 10122
7a13e894 10123 default:
7a13e894 10124 OTHER:
717ca130 10125#ifdef USE_X_TOOLKIT
7a13e894
RS
10126 BLOCK_INPUT;
10127 XtDispatchEvent (&event);
10128 UNBLOCK_INPUT;
3afe33e7 10129#endif /* USE_X_TOOLKIT */
7a13e894
RS
10130 break;
10131 }
dc6f92b8
JB
10132 }
10133 }
10134
06a2c219
GM
10135 out:;
10136
9a5196d0
RS
10137 /* On some systems, an X bug causes Emacs to get no more events
10138 when the window is destroyed. Detect that. (1994.) */
58769bee 10139 if (! event_found)
ef2a22d0 10140 {
ef2a22d0
RS
10141 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
10142 One XNOOP in 100 loops will make Emacs terminate.
10143 B. Bretthauer, 1994 */
10144 x_noop_count++;
58769bee 10145 if (x_noop_count >= 100)
ef2a22d0
RS
10146 {
10147 x_noop_count=0;
2224b905
RS
10148
10149 if (next_noop_dpyinfo == 0)
10150 next_noop_dpyinfo = x_display_list;
10151
10152 XNoOp (next_noop_dpyinfo->display);
10153
10154 /* Each time we get here, cycle through the displays now open. */
10155 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
10156 }
10157 }
502add23 10158
06a2c219 10159 /* If the focus was just given to an auto-raising frame,
0134a210 10160 raise it now. */
7a13e894 10161 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
10162 if (pending_autoraise_frame)
10163 {
10164 x_raise_frame (pending_autoraise_frame);
10165 pending_autoraise_frame = 0;
10166 }
0134a210 10167
dc6f92b8 10168 UNBLOCK_INPUT;
bde5503b 10169 --handling_signal;
dc6f92b8
JB
10170 return count;
10171}
06a2c219
GM
10172
10173
10174
dc6f92b8 10175\f
06a2c219
GM
10176/***********************************************************************
10177 Text Cursor
10178 ***********************************************************************/
10179
10180/* Note if the text cursor of window W has been overwritten by a
10181 drawing operation that outputs N glyphs starting at HPOS in the
10182 line given by output_cursor.vpos. N < 0 means all the rest of the
10183 line after HPOS has been written. */
10184
10185static void
10186note_overwritten_text_cursor (w, hpos, n)
10187 struct window *w;
10188 int hpos, n;
10189{
10190 if (updated_area == TEXT_AREA
10191 && output_cursor.vpos == w->phys_cursor.vpos
10192 && hpos <= w->phys_cursor.hpos
10193 && (n < 0
10194 || hpos + n > w->phys_cursor.hpos))
10195 w->phys_cursor_on_p = 0;
10196}
f451eb13
JB
10197
10198
06a2c219
GM
10199/* Set clipping for output in glyph row ROW. W is the window in which
10200 we operate. GC is the graphics context to set clipping in.
10201 WHOLE_LINE_P non-zero means include the areas used for truncation
10202 mark display and alike in the clipping rectangle.
10203
10204 ROW may be a text row or, e.g., a mode line. Text rows must be
10205 clipped to the interior of the window dedicated to text display,
10206 mode lines must be clipped to the whole window. */
dc6f92b8
JB
10207
10208static void
06a2c219
GM
10209x_clip_to_row (w, row, gc, whole_line_p)
10210 struct window *w;
10211 struct glyph_row *row;
10212 GC gc;
10213 int whole_line_p;
dc6f92b8 10214{
06a2c219
GM
10215 struct frame *f = XFRAME (WINDOW_FRAME (w));
10216 XRectangle clip_rect;
10217 int window_x, window_y, window_width, window_height;
dc6f92b8 10218
06a2c219 10219 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 10220
06a2c219
GM
10221 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
10222 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
10223 clip_rect.y = max (clip_rect.y, window_y);
10224 clip_rect.width = window_width;
10225 clip_rect.height = row->visible_height;
5c1aae96 10226
06a2c219
GM
10227 /* If clipping to the whole line, including trunc marks, extend
10228 the rectangle to the left and increase its width. */
10229 if (whole_line_p)
10230 {
110859fc
GM
10231 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
10232 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 10233 }
5c1aae96 10234
06a2c219 10235 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
10236}
10237
06a2c219
GM
10238
10239/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
10240
10241static void
06a2c219
GM
10242x_draw_hollow_cursor (w, row)
10243 struct window *w;
10244 struct glyph_row *row;
dc6f92b8 10245{
06a2c219
GM
10246 struct frame *f = XFRAME (WINDOW_FRAME (w));
10247 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10248 Display *dpy = FRAME_X_DISPLAY (f);
10249 int x, y, wd, h;
10250 XGCValues xgcv;
10251 struct glyph *cursor_glyph;
10252 GC gc;
10253
10254 /* Compute frame-relative coordinates from window-relative
10255 coordinates. */
10256 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10257 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
10258 + row->ascent - w->phys_cursor_ascent);
10259 h = row->height - 1;
10260
10261 /* Get the glyph the cursor is on. If we can't tell because
10262 the current matrix is invalid or such, give up. */
10263 cursor_glyph = get_phys_cursor_glyph (w);
10264 if (cursor_glyph == NULL)
dc6f92b8
JB
10265 return;
10266
06a2c219
GM
10267 /* Compute the width of the rectangle to draw. If on a stretch
10268 glyph, and `x-stretch-block-cursor' is nil, don't draw a
10269 rectangle as wide as the glyph, but use a canonical character
10270 width instead. */
10271 wd = cursor_glyph->pixel_width - 1;
10272 if (cursor_glyph->type == STRETCH_GLYPH
10273 && !x_stretch_cursor_p)
10274 wd = min (CANON_X_UNIT (f), wd);
10275
10276 /* The foreground of cursor_gc is typically the same as the normal
10277 background color, which can cause the cursor box to be invisible. */
10278 xgcv.foreground = f->output_data.x->cursor_pixel;
10279 if (dpyinfo->scratch_cursor_gc)
10280 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
10281 else
10282 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
10283 GCForeground, &xgcv);
10284 gc = dpyinfo->scratch_cursor_gc;
10285
10286 /* Set clipping, draw the rectangle, and reset clipping again. */
10287 x_clip_to_row (w, row, gc, 0);
10288 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
10289 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
10290}
10291
06a2c219
GM
10292
10293/* Draw a bar cursor on window W in glyph row ROW.
10294
10295 Implementation note: One would like to draw a bar cursor with an
10296 angle equal to the one given by the font property XA_ITALIC_ANGLE.
10297 Unfortunately, I didn't find a font yet that has this property set.
10298 --gerd. */
dc6f92b8
JB
10299
10300static void
f02d8aa0 10301x_draw_bar_cursor (w, row, width)
06a2c219
GM
10302 struct window *w;
10303 struct glyph_row *row;
f02d8aa0 10304 int width;
dc6f92b8 10305{
06a2c219
GM
10306 /* If cursor hpos is out of bounds, don't draw garbage. This can
10307 happen in mini-buffer windows when switching between echo area
10308 glyphs and mini-buffer. */
10309 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
10310 {
10311 struct frame *f = XFRAME (w->frame);
10312 struct glyph *cursor_glyph;
10313 GC gc;
10314 int x;
10315 unsigned long mask;
10316 XGCValues xgcv;
10317 Display *dpy;
10318 Window window;
10319
10320 cursor_glyph = get_phys_cursor_glyph (w);
10321 if (cursor_glyph == NULL)
10322 return;
10323
10324 xgcv.background = f->output_data.x->cursor_pixel;
10325 xgcv.foreground = f->output_data.x->cursor_pixel;
10326 xgcv.graphics_exposures = 0;
10327 mask = GCForeground | GCBackground | GCGraphicsExposures;
10328 dpy = FRAME_X_DISPLAY (f);
10329 window = FRAME_X_WINDOW (f);
10330 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
10331
10332 if (gc)
10333 XChangeGC (dpy, gc, mask, &xgcv);
10334 else
10335 {
10336 gc = XCreateGC (dpy, window, mask, &xgcv);
10337 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
10338 }
10339
f02d8aa0
GM
10340 if (width < 0)
10341 width = f->output_data.x->cursor_width;
10342
06a2c219
GM
10343 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10344 x_clip_to_row (w, row, gc, 0);
10345 XFillRectangle (dpy, window, gc,
10346 x,
10347 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 10348 min (cursor_glyph->pixel_width, width),
06a2c219
GM
10349 row->height);
10350 XSetClipMask (dpy, gc, None);
10351 }
dc6f92b8
JB
10352}
10353
06a2c219
GM
10354
10355/* Clear the cursor of window W to background color, and mark the
10356 cursor as not shown. This is used when the text where the cursor
10357 is is about to be rewritten. */
10358
dc6f92b8 10359static void
06a2c219
GM
10360x_clear_cursor (w)
10361 struct window *w;
dc6f92b8 10362{
06a2c219
GM
10363 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
10364 x_update_window_cursor (w, 0);
10365}
90e65f07 10366
dbc4e1c1 10367
06a2c219
GM
10368/* Draw the cursor glyph of window W in glyph row ROW. See the
10369 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 10370
06a2c219
GM
10371static void
10372x_draw_phys_cursor_glyph (w, row, hl)
10373 struct window *w;
10374 struct glyph_row *row;
10375 enum draw_glyphs_face hl;
10376{
10377 /* If cursor hpos is out of bounds, don't draw garbage. This can
10378 happen in mini-buffer windows when switching between echo area
10379 glyphs and mini-buffer. */
10380 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
10381 {
10382 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
10383 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
10384 hl, 0, 0, 0);
10385
10386 /* When we erase the cursor, and ROW is overlapped by other
10387 rows, make sure that these overlapping parts of other rows
10388 are redrawn. */
10389 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
10390 {
10391 if (row > w->current_matrix->rows
10392 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
10393 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
10394
10395 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
10396 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
10397 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
10398 }
10399 }
06a2c219 10400}
dbc4e1c1 10401
eea6af04 10402
06a2c219 10403/* Erase the image of a cursor of window W from the screen. */
eea6af04 10404
06a2c219
GM
10405static void
10406x_erase_phys_cursor (w)
10407 struct window *w;
10408{
10409 struct frame *f = XFRAME (w->frame);
10410 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10411 int hpos = w->phys_cursor.hpos;
10412 int vpos = w->phys_cursor.vpos;
10413 int mouse_face_here_p = 0;
10414 struct glyph_matrix *active_glyphs = w->current_matrix;
10415 struct glyph_row *cursor_row;
10416 struct glyph *cursor_glyph;
10417 enum draw_glyphs_face hl;
10418
10419 /* No cursor displayed or row invalidated => nothing to do on the
10420 screen. */
10421 if (w->phys_cursor_type == NO_CURSOR)
10422 goto mark_cursor_off;
10423
10424 /* VPOS >= active_glyphs->nrows means that window has been resized.
10425 Don't bother to erase the cursor. */
10426 if (vpos >= active_glyphs->nrows)
10427 goto mark_cursor_off;
10428
10429 /* If row containing cursor is marked invalid, there is nothing we
10430 can do. */
10431 cursor_row = MATRIX_ROW (active_glyphs, vpos);
10432 if (!cursor_row->enabled_p)
10433 goto mark_cursor_off;
10434
10435 /* This can happen when the new row is shorter than the old one.
10436 In this case, either x_draw_glyphs or clear_end_of_line
10437 should have cleared the cursor. Note that we wouldn't be
10438 able to erase the cursor in this case because we don't have a
10439 cursor glyph at hand. */
10440 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
10441 goto mark_cursor_off;
10442
10443 /* If the cursor is in the mouse face area, redisplay that when
10444 we clear the cursor. */
8801a864
KR
10445 if (! NILP (dpyinfo->mouse_face_window)
10446 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
10447 && (vpos > dpyinfo->mouse_face_beg_row
10448 || (vpos == dpyinfo->mouse_face_beg_row
10449 && hpos >= dpyinfo->mouse_face_beg_col))
10450 && (vpos < dpyinfo->mouse_face_end_row
10451 || (vpos == dpyinfo->mouse_face_end_row
10452 && hpos < dpyinfo->mouse_face_end_col))
10453 /* Don't redraw the cursor's spot in mouse face if it is at the
10454 end of a line (on a newline). The cursor appears there, but
10455 mouse highlighting does not. */
10456 && cursor_row->used[TEXT_AREA] > hpos)
10457 mouse_face_here_p = 1;
10458
10459 /* Maybe clear the display under the cursor. */
10460 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
10461 {
10462 int x;
045dee35 10463 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 10464
06a2c219
GM
10465 cursor_glyph = get_phys_cursor_glyph (w);
10466 if (cursor_glyph == NULL)
10467 goto mark_cursor_off;
dbc4e1c1 10468
06a2c219
GM
10469 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
10470
10471 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10472 x,
045dee35 10473 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219
GM
10474 cursor_row->y)),
10475 cursor_glyph->pixel_width,
10476 cursor_row->visible_height,
10477 False);
dbc4e1c1 10478 }
06a2c219
GM
10479
10480 /* Erase the cursor by redrawing the character underneath it. */
10481 if (mouse_face_here_p)
10482 hl = DRAW_MOUSE_FACE;
10483 else if (cursor_row->inverse_p)
10484 hl = DRAW_INVERSE_VIDEO;
10485 else
10486 hl = DRAW_NORMAL_TEXT;
10487 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 10488
06a2c219
GM
10489 mark_cursor_off:
10490 w->phys_cursor_on_p = 0;
10491 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
10492}
10493
10494
06a2c219
GM
10495/* Display or clear cursor of window W. If ON is zero, clear the
10496 cursor. If it is non-zero, display the cursor. If ON is nonzero,
10497 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 10498
06a2c219
GM
10499void
10500x_display_and_set_cursor (w, on, hpos, vpos, x, y)
10501 struct window *w;
10502 int on, hpos, vpos, x, y;
dbc4e1c1 10503{
06a2c219
GM
10504 struct frame *f = XFRAME (w->frame);
10505 int new_cursor_type;
f02d8aa0 10506 int new_cursor_width;
06a2c219
GM
10507 struct glyph_matrix *current_glyphs;
10508 struct glyph_row *glyph_row;
10509 struct glyph *glyph;
dbc4e1c1 10510
49d838ea 10511 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
10512 windows and frames; in the latter case, the frame or window may
10513 be in the midst of changing its size, and x and y may be off the
10514 window. */
10515 if (! FRAME_VISIBLE_P (f)
10516 || FRAME_GARBAGED_P (f)
10517 || vpos >= w->current_matrix->nrows
10518 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
10519 return;
10520
10521 /* If cursor is off and we want it off, return quickly. */
06a2c219 10522 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
10523 return;
10524
06a2c219
GM
10525 current_glyphs = w->current_matrix;
10526 glyph_row = MATRIX_ROW (current_glyphs, vpos);
10527 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
10528
10529 /* If cursor row is not enabled, we don't really know where to
10530 display the cursor. */
10531 if (!glyph_row->enabled_p)
10532 {
10533 w->phys_cursor_on_p = 0;
10534 return;
10535 }
10536
10537 xassert (interrupt_input_blocked);
10538
10539 /* Set new_cursor_type to the cursor we want to be displayed. In a
10540 mini-buffer window, we want the cursor only to appear if we are
10541 reading input from this window. For the selected window, we want
10542 the cursor type given by the frame parameter. If explicitly
10543 marked off, draw no cursor. In all other cases, we want a hollow
10544 box cursor. */
f02d8aa0 10545 new_cursor_width = -1;
9b4a7047
GM
10546 if (cursor_in_echo_area
10547 && FRAME_HAS_MINIBUF_P (f)
10548 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 10549 {
9b4a7047
GM
10550 if (w == XWINDOW (echo_area_window))
10551 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
10552 else
10553 new_cursor_type = HOLLOW_BOX_CURSOR;
10554 }
06a2c219 10555 else
9b4a7047
GM
10556 {
10557 if (w != XWINDOW (selected_window)
10558 || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
10559 {
e55a0b79
GM
10560 extern int cursor_in_non_selected_windows;
10561
10562 if (MINI_WINDOW_P (w) || !cursor_in_non_selected_windows)
9b4a7047
GM
10563 new_cursor_type = NO_CURSOR;
10564 else
10565 new_cursor_type = HOLLOW_BOX_CURSOR;
10566 }
10567 else if (w->cursor_off_p)
10568 new_cursor_type = NO_CURSOR;
10569 else
f02d8aa0
GM
10570 {
10571 struct buffer *b = XBUFFER (w->buffer);
10572
10573 if (EQ (b->cursor_type, Qt))
10574 new_cursor_type = FRAME_DESIRED_CURSOR (f);
10575 else
10576 new_cursor_type = x_specified_cursor_type (b->cursor_type,
10577 &new_cursor_width);
10578 }
9b4a7047 10579 }
06a2c219
GM
10580
10581 /* If cursor is currently being shown and we don't want it to be or
10582 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 10583 erase it. */
06a2c219 10584 if (w->phys_cursor_on_p
dc6f92b8 10585 && (!on
06a2c219
GM
10586 || w->phys_cursor.x != x
10587 || w->phys_cursor.y != y
10588 || new_cursor_type != w->phys_cursor_type))
10589 x_erase_phys_cursor (w);
10590
10591 /* If the cursor is now invisible and we want it to be visible,
10592 display it. */
10593 if (on && !w->phys_cursor_on_p)
10594 {
10595 w->phys_cursor_ascent = glyph_row->ascent;
10596 w->phys_cursor_height = glyph_row->height;
10597
10598 /* Set phys_cursor_.* before x_draw_.* is called because some
10599 of them may need the information. */
10600 w->phys_cursor.x = x;
10601 w->phys_cursor.y = glyph_row->y;
10602 w->phys_cursor.hpos = hpos;
10603 w->phys_cursor.vpos = vpos;
10604 w->phys_cursor_type = new_cursor_type;
10605 w->phys_cursor_on_p = 1;
10606
10607 switch (new_cursor_type)
dc6f92b8 10608 {
06a2c219
GM
10609 case HOLLOW_BOX_CURSOR:
10610 x_draw_hollow_cursor (w, glyph_row);
10611 break;
10612
10613 case FILLED_BOX_CURSOR:
10614 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
10615 break;
10616
10617 case BAR_CURSOR:
f02d8aa0 10618 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
10619 break;
10620
10621 case NO_CURSOR:
10622 break;
dc6f92b8 10623
06a2c219
GM
10624 default:
10625 abort ();
10626 }
59ddecde
GM
10627
10628#ifdef HAVE_X_I18N
10629 if (w == XWINDOW (f->selected_window))
10630 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
10631 xic_set_preeditarea (w, x, y);
10632#endif
dc6f92b8
JB
10633 }
10634
06a2c219 10635#ifndef XFlush
f676886a 10636 if (updating_frame != f)
334208b7 10637 XFlush (FRAME_X_DISPLAY (f));
06a2c219 10638#endif
dc6f92b8
JB
10639}
10640
06a2c219
GM
10641
10642/* Display the cursor on window W, or clear it. X and Y are window
10643 relative pixel coordinates. HPOS and VPOS are glyph matrix
10644 positions. If W is not the selected window, display a hollow
10645 cursor. ON non-zero means display the cursor at X, Y which
10646 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 10647
dfcf069d 10648void
06a2c219
GM
10649x_display_cursor (w, on, hpos, vpos, x, y)
10650 struct window *w;
10651 int on, hpos, vpos, x, y;
dc6f92b8 10652{
f94397b5 10653 BLOCK_INPUT;
06a2c219 10654 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
10655 UNBLOCK_INPUT;
10656}
10657
06a2c219
GM
10658
10659/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
10660 Don't change the cursor's position. */
10661
dfcf069d 10662void
06a2c219 10663x_update_cursor (f, on_p)
5d46f928 10664 struct frame *f;
5d46f928 10665{
06a2c219
GM
10666 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
10667}
10668
10669
10670/* Call x_update_window_cursor with parameter ON_P on all leaf windows
10671 in the window tree rooted at W. */
10672
10673static void
10674x_update_cursor_in_window_tree (w, on_p)
10675 struct window *w;
10676 int on_p;
10677{
10678 while (w)
10679 {
10680 if (!NILP (w->hchild))
10681 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
10682 else if (!NILP (w->vchild))
10683 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
10684 else
10685 x_update_window_cursor (w, on_p);
10686
10687 w = NILP (w->next) ? 0 : XWINDOW (w->next);
10688 }
10689}
5d46f928 10690
f94397b5 10691
06a2c219
GM
10692/* Switch the display of W's cursor on or off, according to the value
10693 of ON. */
10694
10695static void
10696x_update_window_cursor (w, on)
10697 struct window *w;
10698 int on;
10699{
16b5d424
GM
10700 /* Don't update cursor in windows whose frame is in the process
10701 of being deleted. */
10702 if (w->current_matrix)
10703 {
10704 BLOCK_INPUT;
10705 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
10706 w->phys_cursor.x, w->phys_cursor.y);
10707 UNBLOCK_INPUT;
10708 }
dc6f92b8 10709}
06a2c219
GM
10710
10711
10712
dc6f92b8
JB
10713\f
10714/* Icons. */
10715
f676886a 10716/* Refresh bitmap kitchen sink icon for frame F
06a2c219 10717 when we get an expose event for it. */
dc6f92b8 10718
dfcf069d 10719void
f676886a
JB
10720refreshicon (f)
10721 struct frame *f;
dc6f92b8 10722{
06a2c219 10723 /* Normally, the window manager handles this function. */
dc6f92b8
JB
10724}
10725
dbc4e1c1 10726/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
10727
10728int
990ba854 10729x_bitmap_icon (f, file)
f676886a 10730 struct frame *f;
990ba854 10731 Lisp_Object file;
dc6f92b8 10732{
06a2c219 10733 int bitmap_id;
dc6f92b8 10734
c118dd06 10735 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10736 return 1;
10737
990ba854 10738 /* Free up our existing icon bitmap if any. */
7556890b
RS
10739 if (f->output_data.x->icon_bitmap > 0)
10740 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10741 f->output_data.x->icon_bitmap = 0;
990ba854
RS
10742
10743 if (STRINGP (file))
7f2ae036
RS
10744 bitmap_id = x_create_bitmap_from_file (f, file);
10745 else
10746 {
990ba854 10747 /* Create the GNU bitmap if necessary. */
5bf01b68 10748 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
10749 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
10750 = x_create_bitmap_from_data (f, gnu_bits,
10751 gnu_width, gnu_height);
990ba854
RS
10752
10753 /* The first time we create the GNU bitmap,
06a2c219 10754 this increments the ref-count one extra time.
990ba854
RS
10755 As a result, the GNU bitmap is never freed.
10756 That way, we don't have to worry about allocating it again. */
334208b7 10757 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 10758
334208b7 10759 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
10760 }
10761
10762 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 10763 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
10764
10765 return 0;
10766}
10767
10768
1be2d067
KH
10769/* Make the x-window of frame F use a rectangle with text.
10770 Use ICON_NAME as the text. */
dc6f92b8
JB
10771
10772int
f676886a
JB
10773x_text_icon (f, icon_name)
10774 struct frame *f;
dc6f92b8
JB
10775 char *icon_name;
10776{
c118dd06 10777 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10778 return 1;
10779
1be2d067
KH
10780#ifdef HAVE_X11R4
10781 {
10782 XTextProperty text;
10783 text.value = (unsigned char *) icon_name;
10784 text.encoding = XA_STRING;
10785 text.format = 8;
10786 text.nitems = strlen (icon_name);
10787#ifdef USE_X_TOOLKIT
7556890b 10788 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
10789 &text);
10790#else /* not USE_X_TOOLKIT */
10791 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
10792#endif /* not USE_X_TOOLKIT */
10793 }
10794#else /* not HAVE_X11R4 */
10795 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
10796#endif /* not HAVE_X11R4 */
58769bee 10797
7556890b
RS
10798 if (f->output_data.x->icon_bitmap > 0)
10799 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10800 f->output_data.x->icon_bitmap = 0;
b1c884c3 10801 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
10802
10803 return 0;
10804}
10805\f
e99db5a1
RS
10806#define X_ERROR_MESSAGE_SIZE 200
10807
10808/* If non-nil, this should be a string.
10809 It means catch X errors and store the error message in this string. */
10810
10811static Lisp_Object x_error_message_string;
10812
10813/* An X error handler which stores the error message in
10814 x_error_message_string. This is called from x_error_handler if
10815 x_catch_errors is in effect. */
10816
06a2c219 10817static void
e99db5a1
RS
10818x_error_catcher (display, error)
10819 Display *display;
10820 XErrorEvent *error;
10821{
10822 XGetErrorText (display, error->error_code,
10823 XSTRING (x_error_message_string)->data,
10824 X_ERROR_MESSAGE_SIZE);
10825}
10826
10827/* Begin trapping X errors for display DPY. Actually we trap X errors
10828 for all displays, but DPY should be the display you are actually
10829 operating on.
10830
10831 After calling this function, X protocol errors no longer cause
10832 Emacs to exit; instead, they are recorded in the string
10833 stored in x_error_message_string.
10834
10835 Calling x_check_errors signals an Emacs error if an X error has
10836 occurred since the last call to x_catch_errors or x_check_errors.
10837
10838 Calling x_uncatch_errors resumes the normal error handling. */
10839
10840void x_check_errors ();
10841static Lisp_Object x_catch_errors_unwind ();
10842
10843int
10844x_catch_errors (dpy)
10845 Display *dpy;
10846{
10847 int count = specpdl_ptr - specpdl;
10848
10849 /* Make sure any errors from previous requests have been dealt with. */
10850 XSync (dpy, False);
10851
10852 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
10853
10854 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
10855 XSTRING (x_error_message_string)->data[0] = 0;
10856
10857 return count;
10858}
10859
10860/* Unbind the binding that we made to check for X errors. */
10861
10862static Lisp_Object
10863x_catch_errors_unwind (old_val)
10864 Lisp_Object old_val;
10865{
10866 x_error_message_string = old_val;
10867 return Qnil;
10868}
10869
10870/* If any X protocol errors have arrived since the last call to
10871 x_catch_errors or x_check_errors, signal an Emacs error using
10872 sprintf (a buffer, FORMAT, the x error message text) as the text. */
10873
10874void
10875x_check_errors (dpy, format)
10876 Display *dpy;
10877 char *format;
10878{
10879 /* Make sure to catch any errors incurred so far. */
10880 XSync (dpy, False);
10881
10882 if (XSTRING (x_error_message_string)->data[0])
10883 error (format, XSTRING (x_error_message_string)->data);
10884}
10885
9829ddba
RS
10886/* Nonzero if we had any X protocol errors
10887 since we did x_catch_errors on DPY. */
e99db5a1
RS
10888
10889int
10890x_had_errors_p (dpy)
10891 Display *dpy;
10892{
10893 /* Make sure to catch any errors incurred so far. */
10894 XSync (dpy, False);
10895
10896 return XSTRING (x_error_message_string)->data[0] != 0;
10897}
10898
9829ddba
RS
10899/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
10900
06a2c219 10901void
9829ddba
RS
10902x_clear_errors (dpy)
10903 Display *dpy;
10904{
10905 XSTRING (x_error_message_string)->data[0] = 0;
10906}
10907
e99db5a1
RS
10908/* Stop catching X protocol errors and let them make Emacs die.
10909 DPY should be the display that was passed to x_catch_errors.
10910 COUNT should be the value that was returned by
10911 the corresponding call to x_catch_errors. */
10912
10913void
10914x_uncatch_errors (dpy, count)
10915 Display *dpy;
10916 int count;
10917{
10918 unbind_to (count, Qnil);
10919}
10920
10921#if 0
10922static unsigned int x_wire_count;
10923x_trace_wire ()
10924{
10925 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
10926}
10927#endif /* ! 0 */
10928
10929\f
10930/* Handle SIGPIPE, which can happen when the connection to a server
10931 simply goes away. SIGPIPE is handled by x_connection_signal.
10932 Don't need to do anything, because the write which caused the
10933 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 10934 which will do the appropriate cleanup for us. */
e99db5a1
RS
10935
10936static SIGTYPE
10937x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 10938 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
10939{
10940#ifdef USG
10941 /* USG systems forget handlers when they are used;
10942 must reestablish each time */
10943 signal (signalnum, x_connection_signal);
10944#endif /* USG */
10945}
10946\f
4746118a
JB
10947/* Handling X errors. */
10948
7a13e894 10949/* Handle the loss of connection to display DISPLAY. */
16bd92ea 10950
4746118a 10951static SIGTYPE
7a13e894
RS
10952x_connection_closed (display, error_message)
10953 Display *display;
10954 char *error_message;
4746118a 10955{
7a13e894
RS
10956 struct x_display_info *dpyinfo = x_display_info_for_display (display);
10957 Lisp_Object frame, tail;
10958
6186a4a0
RS
10959 /* Indicate that this display is dead. */
10960
2e465cdd 10961#if 0 /* Closing the display caused a bus error on OpenWindows. */
f613a4c8 10962#ifdef USE_X_TOOLKIT
adabc3a9 10963 XtCloseDisplay (display);
2e465cdd 10964#endif
f613a4c8 10965#endif
adabc3a9 10966
9e80b57d
KR
10967 if (dpyinfo)
10968 dpyinfo->display = 0;
6186a4a0 10969
06a2c219 10970 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
10971 that are on the dead display. */
10972 FOR_EACH_FRAME (tail, frame)
10973 {
10974 Lisp_Object minibuf_frame;
10975 minibuf_frame
10976 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
10977 if (FRAME_X_P (XFRAME (frame))
10978 && FRAME_X_P (XFRAME (minibuf_frame))
10979 && ! EQ (frame, minibuf_frame)
10980 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
10981 Fdelete_frame (frame, Qt);
10982 }
10983
10984 /* Now delete all remaining frames on the dead display.
06a2c219 10985 We are now sure none of these is used as the mini-buffer
7a13e894
RS
10986 for another frame that we need to delete. */
10987 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
10988 if (FRAME_X_P (XFRAME (frame))
10989 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
10990 {
10991 /* Set this to t so that Fdelete_frame won't get confused
10992 trying to find a replacement. */
10993 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
10994 Fdelete_frame (frame, Qt);
10995 }
7a13e894 10996
482a1bd2
KH
10997 if (dpyinfo)
10998 x_delete_display (dpyinfo);
7a13e894
RS
10999
11000 if (x_display_list == 0)
11001 {
f8d07b62 11002 fprintf (stderr, "%s\n", error_message);
7a13e894
RS
11003 shut_down_emacs (0, 0, Qnil);
11004 exit (70);
11005 }
12ba150f 11006
7a13e894
RS
11007 /* Ordinary stack unwind doesn't deal with these. */
11008#ifdef SIGIO
11009 sigunblock (sigmask (SIGIO));
11010#endif
11011 sigunblock (sigmask (SIGALRM));
11012 TOTALLY_UNBLOCK_INPUT;
11013
aa4d9a9e 11014 clear_waiting_for_input ();
7a13e894 11015 error ("%s", error_message);
4746118a
JB
11016}
11017
7a13e894
RS
11018/* This is the usual handler for X protocol errors.
11019 It kills all frames on the display that we got the error for.
11020 If that was the only one, it prints an error message and kills Emacs. */
11021
06a2c219 11022static void
c118dd06
JB
11023x_error_quitter (display, error)
11024 Display *display;
11025 XErrorEvent *error;
11026{
7a13e894 11027 char buf[256], buf1[356];
dc6f92b8 11028
58769bee 11029 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 11030 original error handler. */
dc6f92b8 11031
c118dd06 11032 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 11033 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 11034 buf, error->request_code);
7a13e894 11035 x_connection_closed (display, buf1);
dc6f92b8
JB
11036}
11037
e99db5a1
RS
11038/* This is the first-level handler for X protocol errors.
11039 It calls x_error_quitter or x_error_catcher. */
7a13e894 11040
8922af5f 11041static int
e99db5a1 11042x_error_handler (display, error)
8922af5f 11043 Display *display;
e99db5a1 11044 XErrorEvent *error;
8922af5f 11045{
e99db5a1
RS
11046 if (! NILP (x_error_message_string))
11047 x_error_catcher (display, error);
11048 else
11049 x_error_quitter (display, error);
06a2c219 11050 return 0;
f9e24cb9 11051}
c118dd06 11052
e99db5a1
RS
11053/* This is the handler for X IO errors, always.
11054 It kills all frames on the display that we lost touch with.
11055 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 11056
c118dd06 11057static int
e99db5a1 11058x_io_error_quitter (display)
c118dd06 11059 Display *display;
c118dd06 11060{
e99db5a1 11061 char buf[256];
dc6f92b8 11062
e99db5a1
RS
11063 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
11064 x_connection_closed (display, buf);
06a2c219 11065 return 0;
dc6f92b8 11066}
dc6f92b8 11067\f
f451eb13
JB
11068/* Changing the font of the frame. */
11069
76bcdf39
RS
11070/* Give frame F the font named FONTNAME as its default font, and
11071 return the full name of that font. FONTNAME may be a wildcard
11072 pattern; in that case, we choose some font that fits the pattern.
11073 The return value shows which font we chose. */
11074
b5cf7a0e 11075Lisp_Object
f676886a
JB
11076x_new_font (f, fontname)
11077 struct frame *f;
dc6f92b8
JB
11078 register char *fontname;
11079{
dc43ef94 11080 struct font_info *fontp
ee569018 11081 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 11082
dc43ef94
KH
11083 if (!fontp)
11084 return Qnil;
2224a5fc 11085
dc43ef94 11086 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 11087 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
11088 f->output_data.x->fontset = -1;
11089
b2cad826
KH
11090 /* Compute the scroll bar width in character columns. */
11091 if (f->scroll_bar_pixel_width > 0)
11092 {
7556890b 11093 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
11094 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
11095 }
11096 else
4e61bddf
RS
11097 {
11098 int wid = FONT_WIDTH (f->output_data.x->font);
11099 f->scroll_bar_cols = (14 + wid - 1) / wid;
11100 }
b2cad826 11101
f676886a 11102 /* Now make the frame display the given font. */
c118dd06 11103 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 11104 {
7556890b
RS
11105 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
11106 f->output_data.x->font->fid);
11107 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
11108 f->output_data.x->font->fid);
11109 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
11110 f->output_data.x->font->fid);
f676886a 11111
a27f9f86 11112 frame_update_line_height (f);
0134a210 11113 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 11114 }
a27f9f86
RS
11115 else
11116 /* If we are setting a new frame's font for the first time,
11117 there are no faces yet, so this font's height is the line height. */
7556890b 11118 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 11119
dc43ef94
KH
11120 return build_string (fontp->full_name);
11121}
11122
11123/* Give frame F the fontset named FONTSETNAME as its default font, and
11124 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
11125 pattern; in that case, we choose some fontset that fits the pattern.
11126 The return value shows which fontset we chose. */
b5cf7a0e 11127
dc43ef94
KH
11128Lisp_Object
11129x_new_fontset (f, fontsetname)
11130 struct frame *f;
11131 char *fontsetname;
11132{
ee569018 11133 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 11134 Lisp_Object result;
b5cf7a0e 11135
dc43ef94
KH
11136 if (fontset < 0)
11137 return Qnil;
b5cf7a0e 11138
2da424f1
KH
11139 if (f->output_data.x->fontset == fontset)
11140 /* This fontset is already set in frame F. There's nothing more
11141 to do. */
ee569018 11142 return fontset_name (fontset);
dc43ef94 11143
ee569018 11144 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
11145
11146 if (!STRINGP (result))
11147 /* Can't load ASCII font. */
11148 return Qnil;
11149
11150 /* Since x_new_font doesn't update any fontset information, do it now. */
11151 f->output_data.x->fontset = fontset;
dc43ef94 11152
f5d11644
GM
11153#ifdef HAVE_X_I18N
11154 if (FRAME_XIC (f)
11155 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 11156 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
11157#endif
11158
dc43ef94 11159 return build_string (fontsetname);
dc6f92b8 11160}
f5d11644
GM
11161
11162\f
11163/***********************************************************************
11164 X Input Methods
11165 ***********************************************************************/
11166
11167#ifdef HAVE_X_I18N
11168
11169#ifdef HAVE_X11R6
11170
11171/* XIM destroy callback function, which is called whenever the
11172 connection to input method XIM dies. CLIENT_DATA contains a
11173 pointer to the x_display_info structure corresponding to XIM. */
11174
11175static void
11176xim_destroy_callback (xim, client_data, call_data)
11177 XIM xim;
11178 XPointer client_data;
11179 XPointer call_data;
11180{
11181 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
11182 Lisp_Object frame, tail;
11183
11184 BLOCK_INPUT;
11185
11186 /* No need to call XDestroyIC.. */
11187 FOR_EACH_FRAME (tail, frame)
11188 {
11189 struct frame *f = XFRAME (frame);
11190 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
11191 {
11192 FRAME_XIC (f) = NULL;
11193 if (FRAME_XIC_FONTSET (f))
11194 {
11195 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
11196 FRAME_XIC_FONTSET (f) = NULL;
11197 }
11198 }
11199 }
11200
11201 /* No need to call XCloseIM. */
11202 dpyinfo->xim = NULL;
11203 XFree (dpyinfo->xim_styles);
11204 UNBLOCK_INPUT;
11205}
11206
11207#endif /* HAVE_X11R6 */
11208
11209/* Open the connection to the XIM server on display DPYINFO.
11210 RESOURCE_NAME is the resource name Emacs uses. */
11211
11212static void
11213xim_open_dpy (dpyinfo, resource_name)
11214 struct x_display_info *dpyinfo;
11215 char *resource_name;
11216{
287f7dd6 11217#ifdef USE_XIM
f5d11644
GM
11218 XIM xim;
11219
11220 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
11221 dpyinfo->xim = xim;
11222
11223 if (xim)
11224 {
f5d11644
GM
11225#ifdef HAVE_X11R6
11226 XIMCallback destroy;
11227#endif
11228
11229 /* Get supported styles and XIM values. */
11230 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
11231
11232#ifdef HAVE_X11R6
11233 destroy.callback = xim_destroy_callback;
11234 destroy.client_data = (XPointer)dpyinfo;
68642df6 11235 /* This isn't prptotyped in OSF 5.0. */
f5d11644
GM
11236 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
11237#endif
11238 }
287f7dd6
GM
11239
11240#else /* not USE_XIM */
11241 dpyinfo->xim = NULL;
11242#endif /* not USE_XIM */
f5d11644
GM
11243}
11244
11245
b9de836c 11246#ifdef HAVE_X11R6_XIM
f5d11644
GM
11247
11248struct xim_inst_t
11249{
11250 struct x_display_info *dpyinfo;
11251 char *resource_name;
11252};
11253
11254/* XIM instantiate callback function, which is called whenever an XIM
11255 server is available. DISPLAY is teh display of the XIM.
11256 CLIENT_DATA contains a pointer to an xim_inst_t structure created
11257 when the callback was registered. */
11258
11259static void
11260xim_instantiate_callback (display, client_data, call_data)
11261 Display *display;
11262 XPointer client_data;
11263 XPointer call_data;
11264{
11265 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
11266 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
11267
11268 /* We don't support multiple XIM connections. */
11269 if (dpyinfo->xim)
11270 return;
11271
11272 xim_open_dpy (dpyinfo, xim_inst->resource_name);
11273
11274 /* Create XIC for the existing frames on the same display, as long
11275 as they have no XIC. */
11276 if (dpyinfo->xim && dpyinfo->reference_count > 0)
11277 {
11278 Lisp_Object tail, frame;
11279
11280 BLOCK_INPUT;
11281 FOR_EACH_FRAME (tail, frame)
11282 {
11283 struct frame *f = XFRAME (frame);
11284
11285 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
11286 if (FRAME_XIC (f) == NULL)
11287 {
11288 create_frame_xic (f);
11289 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
11290 xic_set_statusarea (f);
11291 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
11292 {
11293 struct window *w = XWINDOW (f->selected_window);
11294 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
11295 }
11296 }
11297 }
11298
11299 UNBLOCK_INPUT;
11300 }
11301}
11302
b9de836c 11303#endif /* HAVE_X11R6_XIM */
f5d11644
GM
11304
11305
11306/* Open a connection to the XIM server on display DPYINFO.
11307 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
11308 connection only at the first time. On X11R6, open the connection
11309 in the XIM instantiate callback function. */
11310
11311static void
11312xim_initialize (dpyinfo, resource_name)
11313 struct x_display_info *dpyinfo;
11314 char *resource_name;
11315{
287f7dd6 11316#ifdef USE_XIM
b9de836c 11317#ifdef HAVE_X11R6_XIM
f5d11644
GM
11318 struct xim_inst_t *xim_inst;
11319 int len;
11320
11321 dpyinfo->xim = NULL;
11322 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
11323 xim_inst->dpyinfo = dpyinfo;
11324 len = strlen (resource_name);
11325 xim_inst->resource_name = (char *) xmalloc (len + 1);
11326 bcopy (resource_name, xim_inst->resource_name, len + 1);
11327 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11328 resource_name, EMACS_CLASS,
11329 xim_instantiate_callback,
2ebb2f8b
DL
11330 /* Fixme: This is XPointer in
11331 XFree86 but (XPointer *) on
11332 Tru64, at least. */
11333 (XPointer) xim_inst);
b9de836c 11334#else /* not HAVE_X11R6_XIM */
f5d11644
GM
11335 dpyinfo->xim = NULL;
11336 xim_open_dpy (dpyinfo, resource_name);
b9de836c 11337#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
11338
11339#else /* not USE_XIM */
11340 dpyinfo->xim = NULL;
11341#endif /* not USE_XIM */
f5d11644
GM
11342}
11343
11344
11345/* Close the connection to the XIM server on display DPYINFO. */
11346
11347static void
11348xim_close_dpy (dpyinfo)
11349 struct x_display_info *dpyinfo;
11350{
287f7dd6 11351#ifdef USE_XIM
b9de836c 11352#ifdef HAVE_X11R6_XIM
f5d11644
GM
11353 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11354 NULL, EMACS_CLASS,
11355 xim_instantiate_callback, NULL);
b9de836c 11356#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11357 XCloseIM (dpyinfo->xim);
11358 dpyinfo->xim = NULL;
11359 XFree (dpyinfo->xim_styles);
287f7dd6 11360#endif /* USE_XIM */
f5d11644
GM
11361}
11362
b9de836c 11363#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11364
11365
dc6f92b8 11366\f
2e365682
RS
11367/* Calculate the absolute position in frame F
11368 from its current recorded position values and gravity. */
11369
dfcf069d 11370void
43bca5d5 11371x_calc_absolute_position (f)
f676886a 11372 struct frame *f;
dc6f92b8 11373{
06a2c219 11374 Window child;
6dba1858 11375 int win_x = 0, win_y = 0;
7556890b 11376 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
11377 int this_window;
11378
9829ddba
RS
11379 /* We have nothing to do if the current position
11380 is already for the top-left corner. */
11381 if (! ((flags & XNegative) || (flags & YNegative)))
11382 return;
11383
c81412a0 11384#ifdef USE_X_TOOLKIT
7556890b 11385 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
11386#else
11387 this_window = FRAME_X_WINDOW (f);
11388#endif
6dba1858
RS
11389
11390 /* Find the position of the outside upper-left corner of
9829ddba
RS
11391 the inner window, with respect to the outer window.
11392 But do this only if we will need the results. */
7556890b 11393 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 11394 {
9829ddba
RS
11395 int count;
11396
6dba1858 11397 BLOCK_INPUT;
9829ddba
RS
11398 count = x_catch_errors (FRAME_X_DISPLAY (f));
11399 while (1)
11400 {
11401 x_clear_errors (FRAME_X_DISPLAY (f));
11402 XTranslateCoordinates (FRAME_X_DISPLAY (f),
11403
11404 /* From-window, to-window. */
11405 this_window,
11406 f->output_data.x->parent_desc,
11407
11408 /* From-position, to-position. */
11409 0, 0, &win_x, &win_y,
11410
11411 /* Child of win. */
11412 &child);
11413 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
11414 {
11415 Window newroot, newparent = 0xdeadbeef;
11416 Window *newchildren;
2ebb2f8b 11417 unsigned int nchildren;
9829ddba
RS
11418
11419 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
11420 &newparent, &newchildren, &nchildren))
11421 break;
58769bee 11422
7c3c78a3 11423 XFree ((char *) newchildren);
6dba1858 11424
9829ddba
RS
11425 f->output_data.x->parent_desc = newparent;
11426 }
11427 else
11428 break;
11429 }
6dba1858 11430
9829ddba 11431 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
11432 UNBLOCK_INPUT;
11433 }
11434
11435 /* Treat negative positions as relative to the leftmost bottommost
11436 position that fits on the screen. */
20f55f9a 11437 if (flags & XNegative)
7556890b 11438 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
11439 - 2 * f->output_data.x->border_width - win_x
11440 - PIXEL_WIDTH (f)
11441 + f->output_data.x->left_pos);
dc6f92b8 11442
20f55f9a 11443 if (flags & YNegative)
06a2c219
GM
11444 {
11445 int menubar_height = 0;
11446
11447#ifdef USE_X_TOOLKIT
11448 if (f->output_data.x->menubar_widget)
11449 menubar_height
11450 = (f->output_data.x->menubar_widget->core.height
11451 + f->output_data.x->menubar_widget->core.border_width);
11452#endif
11453
11454 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
11455 - 2 * f->output_data.x->border_width
11456 - win_y
11457 - PIXEL_HEIGHT (f)
11458 - menubar_height
11459 + f->output_data.x->top_pos);
11460 }
2e365682 11461
3a35ab44
RS
11462 /* The left_pos and top_pos
11463 are now relative to the top and left screen edges,
11464 so the flags should correspond. */
7556890b 11465 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
11466}
11467
3a35ab44
RS
11468/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
11469 to really change the position, and 0 when calling from
11470 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
11471 position values). It is -1 when calling from x_set_frame_parameters,
11472 which means, do adjust for borders but don't change the gravity. */
3a35ab44 11473
dfcf069d 11474void
dc05a16b 11475x_set_offset (f, xoff, yoff, change_gravity)
f676886a 11476 struct frame *f;
dc6f92b8 11477 register int xoff, yoff;
dc05a16b 11478 int change_gravity;
dc6f92b8 11479{
4a4cbdd5
KH
11480 int modified_top, modified_left;
11481
aa3ff7c9 11482 if (change_gravity > 0)
3a35ab44 11483 {
7556890b
RS
11484 f->output_data.x->top_pos = yoff;
11485 f->output_data.x->left_pos = xoff;
11486 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 11487 if (xoff < 0)
7556890b 11488 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 11489 if (yoff < 0)
7556890b
RS
11490 f->output_data.x->size_hint_flags |= YNegative;
11491 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 11492 }
43bca5d5 11493 x_calc_absolute_position (f);
dc6f92b8
JB
11494
11495 BLOCK_INPUT;
c32cdd9a 11496 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 11497
7556890b
RS
11498 modified_left = f->output_data.x->left_pos;
11499 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
11500#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
11501 this seems to be unnecessary and incorrect. rms, 4/17/97. */
11502 /* It is a mystery why we need to add the border_width here
11503 when the frame is already visible, but experiment says we do. */
aa3ff7c9 11504 if (change_gravity != 0)
4a4cbdd5 11505 {
7556890b
RS
11506 modified_left += f->output_data.x->border_width;
11507 modified_top += f->output_data.x->border_width;
4a4cbdd5 11508 }
e73ec6fa 11509#endif
4a4cbdd5 11510
3afe33e7 11511#ifdef USE_X_TOOLKIT
7556890b 11512 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 11513 modified_left, modified_top);
3afe33e7 11514#else /* not USE_X_TOOLKIT */
334208b7 11515 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 11516 modified_left, modified_top);
3afe33e7 11517#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11518 UNBLOCK_INPUT;
11519}
11520
bc20ebbf
FP
11521/* Call this to change the size of frame F's x-window.
11522 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
11523 for this size change and subsequent size changes.
11524 Otherwise we leave the window gravity unchanged. */
dc6f92b8 11525
dfcf069d 11526void
bc20ebbf 11527x_set_window_size (f, change_gravity, cols, rows)
f676886a 11528 struct frame *f;
bc20ebbf 11529 int change_gravity;
b1c884c3 11530 int cols, rows;
dc6f92b8 11531{
06a2c219 11532#ifndef USE_X_TOOLKIT
dc6f92b8 11533 int pixelwidth, pixelheight;
06a2c219 11534#endif
dc6f92b8 11535
80fd1fe2 11536 BLOCK_INPUT;
aee9a898
RS
11537
11538#ifdef USE_X_TOOLKIT
3a20653d
RS
11539 {
11540 /* The x and y position of the widget is clobbered by the
11541 call to XtSetValues within EmacsFrameSetCharSize.
11542 This is a real kludge, but I don't understand Xt so I can't
11543 figure out a correct fix. Can anyone else tell me? -- rms. */
7556890b
RS
11544 int xpos = f->output_data.x->widget->core.x;
11545 int ypos = f->output_data.x->widget->core.y;
11546 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
11547 f->output_data.x->widget->core.x = xpos;
11548 f->output_data.x->widget->core.y = ypos;
3a20653d 11549 }
80fd1fe2
FP
11550
11551#else /* not USE_X_TOOLKIT */
11552
b1c884c3 11553 check_frame_size (f, &rows, &cols);
7556890b 11554 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
11555 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
11556 ? 0
11557 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 11558 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 11559 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 11560 f->output_data.x->flags_areas_extra
110859fc 11561 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
11562 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
11563 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 11564
7556890b 11565 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 11566 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 11567
334208b7
RS
11568 XSync (FRAME_X_DISPLAY (f), False);
11569 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11570 pixelwidth, pixelheight);
b1c884c3
JB
11571
11572 /* Now, strictly speaking, we can't be sure that this is accurate,
11573 but the window manager will get around to dealing with the size
11574 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
11575 ConfigureNotify event gets here.
11576
11577 We could just not bother storing any of this information here,
11578 and let the ConfigureNotify event set everything up, but that
fddd5ceb 11579 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 11580 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
11581 point in the future when the ConfigureNotify event arrives.
11582
11583 We pass 1 for DELAY since we can't run Lisp code inside of
11584 a BLOCK_INPUT. */
7d1e984f 11585 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
11586 PIXEL_WIDTH (f) = pixelwidth;
11587 PIXEL_HEIGHT (f) = pixelheight;
11588
aee9a898
RS
11589 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
11590 receive in the ConfigureNotify event; if we get what we asked
11591 for, then the event won't cause the screen to become garbaged, so
11592 we have to make sure to do it here. */
11593 SET_FRAME_GARBAGED (f);
11594
11595 XFlush (FRAME_X_DISPLAY (f));
11596
11597#endif /* not USE_X_TOOLKIT */
11598
4d73d038 11599 /* If cursor was outside the new size, mark it as off. */
06a2c219 11600 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 11601
aee9a898
RS
11602 /* Clear out any recollection of where the mouse highlighting was,
11603 since it might be in a place that's outside the new frame size.
11604 Actually checking whether it is outside is a pain in the neck,
11605 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 11606 cancel_mouse_face (f);
dbc4e1c1 11607
dc6f92b8
JB
11608 UNBLOCK_INPUT;
11609}
dc6f92b8 11610\f
d047c4eb 11611/* Mouse warping. */
dc6f92b8 11612
9b378208 11613void
f676886a
JB
11614x_set_mouse_position (f, x, y)
11615 struct frame *f;
dc6f92b8
JB
11616 int x, y;
11617{
11618 int pix_x, pix_y;
11619
7556890b
RS
11620 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
11621 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
11622
11623 if (pix_x < 0) pix_x = 0;
11624 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
11625
11626 if (pix_y < 0) pix_y = 0;
11627 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
11628
11629 BLOCK_INPUT;
dc6f92b8 11630
334208b7
RS
11631 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11632 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
11633 UNBLOCK_INPUT;
11634}
11635
9b378208
RS
11636/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
11637
11638void
11639x_set_mouse_pixel_position (f, pix_x, pix_y)
11640 struct frame *f;
11641 int pix_x, pix_y;
11642{
11643 BLOCK_INPUT;
11644
334208b7
RS
11645 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11646 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
11647 UNBLOCK_INPUT;
11648}
d047c4eb
KH
11649\f
11650/* focus shifting, raising and lowering. */
9b378208 11651
dfcf069d 11652void
f676886a
JB
11653x_focus_on_frame (f)
11654 struct frame *f;
dc6f92b8 11655{
1fb20991 11656#if 0 /* This proves to be unpleasant. */
f676886a 11657 x_raise_frame (f);
1fb20991 11658#endif
6d4238f3
JB
11659#if 0
11660 /* I don't think that the ICCCM allows programs to do things like this
11661 without the interaction of the window manager. Whatever you end up
f676886a 11662 doing with this code, do it to x_unfocus_frame too. */
334208b7 11663 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 11664 RevertToPointerRoot, CurrentTime);
c118dd06 11665#endif /* ! 0 */
dc6f92b8
JB
11666}
11667
dfcf069d 11668void
f676886a
JB
11669x_unfocus_frame (f)
11670 struct frame *f;
dc6f92b8 11671{
6d4238f3 11672#if 0
f676886a 11673 /* Look at the remarks in x_focus_on_frame. */
0f941935 11674 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 11675 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 11676 RevertToPointerRoot, CurrentTime);
c118dd06 11677#endif /* ! 0 */
dc6f92b8
JB
11678}
11679
f676886a 11680/* Raise frame F. */
dc6f92b8 11681
dfcf069d 11682void
f676886a
JB
11683x_raise_frame (f)
11684 struct frame *f;
dc6f92b8 11685{
3a88c238 11686 if (f->async_visible)
dc6f92b8
JB
11687 {
11688 BLOCK_INPUT;
3afe33e7 11689#ifdef USE_X_TOOLKIT
7556890b 11690 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11691#else /* not USE_X_TOOLKIT */
334208b7 11692 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11693#endif /* not USE_X_TOOLKIT */
334208b7 11694 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11695 UNBLOCK_INPUT;
11696 }
11697}
11698
f676886a 11699/* Lower frame F. */
dc6f92b8 11700
dfcf069d 11701void
f676886a
JB
11702x_lower_frame (f)
11703 struct frame *f;
dc6f92b8 11704{
3a88c238 11705 if (f->async_visible)
dc6f92b8
JB
11706 {
11707 BLOCK_INPUT;
3afe33e7 11708#ifdef USE_X_TOOLKIT
7556890b 11709 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11710#else /* not USE_X_TOOLKIT */
334208b7 11711 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11712#endif /* not USE_X_TOOLKIT */
334208b7 11713 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11714 UNBLOCK_INPUT;
11715 }
11716}
11717
dbc4e1c1 11718static void
6b0442dc 11719XTframe_raise_lower (f, raise_flag)
dbc4e1c1 11720 FRAME_PTR f;
6b0442dc 11721 int raise_flag;
dbc4e1c1 11722{
6b0442dc 11723 if (raise_flag)
dbc4e1c1
JB
11724 x_raise_frame (f);
11725 else
11726 x_lower_frame (f);
11727}
d047c4eb
KH
11728\f
11729/* Change of visibility. */
dc6f92b8 11730
9382638d
KH
11731/* This tries to wait until the frame is really visible.
11732 However, if the window manager asks the user where to position
11733 the frame, this will return before the user finishes doing that.
11734 The frame will not actually be visible at that time,
11735 but it will become visible later when the window manager
11736 finishes with it. */
11737
dfcf069d 11738void
f676886a
JB
11739x_make_frame_visible (f)
11740 struct frame *f;
dc6f92b8 11741{
990ba854 11742 Lisp_Object type;
1aa6072f 11743 int original_top, original_left;
dc6f92b8 11744
dc6f92b8 11745 BLOCK_INPUT;
dc6f92b8 11746
990ba854
RS
11747 type = x_icon_type (f);
11748 if (!NILP (type))
11749 x_bitmap_icon (f, type);
bdcd49ba 11750
f676886a 11751 if (! FRAME_VISIBLE_P (f))
90e65f07 11752 {
1aa6072f
RS
11753 /* We test FRAME_GARBAGED_P here to make sure we don't
11754 call x_set_offset a second time
11755 if we get to x_make_frame_visible a second time
11756 before the window gets really visible. */
11757 if (! FRAME_ICONIFIED_P (f)
11758 && ! f->output_data.x->asked_for_visible)
11759 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
11760
11761 f->output_data.x->asked_for_visible = 1;
11762
90e65f07 11763 if (! EQ (Vx_no_window_manager, Qt))
f676886a 11764 x_wm_set_window_state (f, NormalState);
3afe33e7 11765#ifdef USE_X_TOOLKIT
d7a38a2e 11766 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11767 XtMapWidget (f->output_data.x->widget);
3afe33e7 11768#else /* not USE_X_TOOLKIT */
7f9c7f94 11769 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11770#endif /* not USE_X_TOOLKIT */
0134a210
RS
11771#if 0 /* This seems to bring back scroll bars in the wrong places
11772 if the window configuration has changed. They seem
11773 to come back ok without this. */
ab648270 11774 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 11775 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 11776#endif
90e65f07 11777 }
dc6f92b8 11778
334208b7 11779 XFlush (FRAME_X_DISPLAY (f));
90e65f07 11780
0dacf791
RS
11781 /* Synchronize to ensure Emacs knows the frame is visible
11782 before we do anything else. We do this loop with input not blocked
11783 so that incoming events are handled. */
11784 {
11785 Lisp_Object frame;
12ce2351 11786 int count;
28c01ffe
RS
11787 /* This must be before UNBLOCK_INPUT
11788 since events that arrive in response to the actions above
11789 will set it when they are handled. */
11790 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
11791
11792 original_left = f->output_data.x->left_pos;
11793 original_top = f->output_data.x->top_pos;
c0a04927
RS
11794
11795 /* This must come after we set COUNT. */
11796 UNBLOCK_INPUT;
11797
2745e6c4 11798 /* We unblock here so that arriving X events are processed. */
1aa6072f 11799
dcb07ae9
RS
11800 /* Now move the window back to where it was "supposed to be".
11801 But don't do it if the gravity is negative.
11802 When the gravity is negative, this uses a position
28c01ffe
RS
11803 that is 3 pixels too low. Perhaps that's really the border width.
11804
11805 Don't do this if the window has never been visible before,
11806 because the window manager may choose the position
11807 and we don't want to override it. */
1aa6072f 11808
4d3f5d9a 11809 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 11810 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 11811 && previously_visible)
1aa6072f 11812 {
2745e6c4
RS
11813 Drawable rootw;
11814 int x, y;
11815 unsigned int width, height, border, depth;
06a2c219 11816
1aa6072f 11817 BLOCK_INPUT;
9829ddba 11818
06a2c219
GM
11819 /* On some window managers (such as FVWM) moving an existing
11820 window, even to the same place, causes the window manager
11821 to introduce an offset. This can cause the window to move
11822 to an unexpected location. Check the geometry (a little
11823 slow here) and then verify that the window is in the right
11824 place. If the window is not in the right place, move it
11825 there, and take the potential window manager hit. */
2745e6c4
RS
11826 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11827 &rootw, &x, &y, &width, &height, &border, &depth);
11828
11829 if (original_left != x || original_top != y)
11830 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11831 original_left, original_top);
11832
1aa6072f
RS
11833 UNBLOCK_INPUT;
11834 }
9829ddba 11835
e0c1aef2 11836 XSETFRAME (frame, f);
c0a04927 11837
12ce2351
GM
11838 /* Wait until the frame is visible. Process X events until a
11839 MapNotify event has been seen, or until we think we won't get a
11840 MapNotify at all.. */
11841 for (count = input_signal_count + 10;
11842 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 11843 {
12ce2351 11844 /* Force processing of queued events. */
334208b7 11845 x_sync (f);
12ce2351
GM
11846
11847 /* Machines that do polling rather than SIGIO have been
11848 observed to go into a busy-wait here. So we'll fake an
11849 alarm signal to let the handler know that there's something
11850 to be read. We used to raise a real alarm, but it seems
11851 that the handler isn't always enabled here. This is
11852 probably a bug. */
8b2f8d4e 11853 if (input_polling_used ())
3b2fa4e6 11854 {
12ce2351
GM
11855 /* It could be confusing if a real alarm arrives while
11856 processing the fake one. Turn it off and let the
11857 handler reset it. */
3e71d8f2 11858 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
11859 int old_poll_suppress_count = poll_suppress_count;
11860 poll_suppress_count = 1;
11861 poll_for_input_1 ();
11862 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 11863 }
12ce2351
GM
11864
11865 /* See if a MapNotify event has been processed. */
11866 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 11867 }
0dacf791 11868 }
dc6f92b8
JB
11869}
11870
06a2c219 11871/* Change from mapped state to withdrawn state. */
dc6f92b8 11872
d047c4eb
KH
11873/* Make the frame visible (mapped and not iconified). */
11874
dfcf069d 11875void
f676886a
JB
11876x_make_frame_invisible (f)
11877 struct frame *f;
dc6f92b8 11878{
546e6d5b
RS
11879 Window window;
11880
11881#ifdef USE_X_TOOLKIT
11882 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 11883 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
11884#else /* not USE_X_TOOLKIT */
11885 window = FRAME_X_WINDOW (f);
11886#endif /* not USE_X_TOOLKIT */
dc6f92b8 11887
9319ae23 11888 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11889 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11890 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11891
5627c40e 11892#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 11893 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 11894 return;
5627c40e 11895#endif
dc6f92b8
JB
11896
11897 BLOCK_INPUT;
c118dd06 11898
af31d76f
RS
11899 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
11900 that the current position of the window is user-specified, rather than
11901 program-specified, so that when the window is mapped again, it will be
11902 placed at the same location, without forcing the user to position it
11903 by hand again (they have already done that once for this window.) */
c32cdd9a 11904 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 11905
c118dd06
JB
11906#ifdef HAVE_X11R4
11907
334208b7
RS
11908 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
11909 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
11910 {
11911 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11912 error ("Can't notify window manager of window withdrawal");
c118dd06 11913 }
c118dd06 11914#else /* ! defined (HAVE_X11R4) */
16bd92ea 11915
c118dd06 11916 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
11917 if (! EQ (Vx_no_window_manager, Qt))
11918 {
16bd92ea 11919 XEvent unmap;
dc6f92b8 11920
16bd92ea 11921 unmap.xunmap.type = UnmapNotify;
546e6d5b 11922 unmap.xunmap.window = window;
334208b7 11923 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 11924 unmap.xunmap.from_configure = False;
334208b7
RS
11925 if (! XSendEvent (FRAME_X_DISPLAY (f),
11926 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 11927 False,
06a2c219 11928 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
11929 &unmap))
11930 {
11931 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11932 error ("Can't notify window manager of withdrawal");
16bd92ea 11933 }
dc6f92b8
JB
11934 }
11935
16bd92ea 11936 /* Unmap the window ourselves. Cheeky! */
334208b7 11937 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 11938#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 11939
5627c40e
RS
11940 /* We can't distinguish this from iconification
11941 just by the event that we get from the server.
11942 So we can't win using the usual strategy of letting
11943 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
11944 and synchronize with the server to make sure we agree. */
11945 f->visible = 0;
11946 FRAME_ICONIFIED_P (f) = 0;
11947 f->async_visible = 0;
11948 f->async_iconified = 0;
11949
334208b7 11950 x_sync (f);
5627c40e 11951
dc6f92b8
JB
11952 UNBLOCK_INPUT;
11953}
11954
06a2c219 11955/* Change window state from mapped to iconified. */
dc6f92b8 11956
dfcf069d 11957void
f676886a
JB
11958x_iconify_frame (f)
11959 struct frame *f;
dc6f92b8 11960{
3afe33e7 11961 int result;
990ba854 11962 Lisp_Object type;
dc6f92b8 11963
9319ae23 11964 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11965 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11966 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11967
3a88c238 11968 if (f->async_iconified)
dc6f92b8
JB
11969 return;
11970
3afe33e7 11971 BLOCK_INPUT;
546e6d5b 11972
9af3143a
RS
11973 FRAME_SAMPLE_VISIBILITY (f);
11974
990ba854
RS
11975 type = x_icon_type (f);
11976 if (!NILP (type))
11977 x_bitmap_icon (f, type);
bdcd49ba
RS
11978
11979#ifdef USE_X_TOOLKIT
11980
546e6d5b
RS
11981 if (! FRAME_VISIBLE_P (f))
11982 {
11983 if (! EQ (Vx_no_window_manager, Qt))
11984 x_wm_set_window_state (f, IconicState);
11985 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11986 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
11987 /* The server won't give us any event to indicate
11988 that an invisible frame was changed to an icon,
11989 so we have to record it here. */
11990 f->iconified = 1;
1e6bc770 11991 f->visible = 1;
9cf30a30 11992 f->async_iconified = 1;
1e6bc770 11993 f->async_visible = 0;
546e6d5b
RS
11994 UNBLOCK_INPUT;
11995 return;
11996 }
11997
334208b7 11998 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 11999 XtWindow (f->output_data.x->widget),
334208b7 12000 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
12001 UNBLOCK_INPUT;
12002
12003 if (!result)
546e6d5b 12004 error ("Can't notify window manager of iconification");
3afe33e7
RS
12005
12006 f->async_iconified = 1;
1e6bc770
RS
12007 f->async_visible = 0;
12008
8c002a25
KH
12009
12010 BLOCK_INPUT;
334208b7 12011 XFlush (FRAME_X_DISPLAY (f));
8c002a25 12012 UNBLOCK_INPUT;
3afe33e7
RS
12013#else /* not USE_X_TOOLKIT */
12014
fd13dbb2
RS
12015 /* Make sure the X server knows where the window should be positioned,
12016 in case the user deiconifies with the window manager. */
12017 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 12018 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 12019
16bd92ea
JB
12020 /* Since we don't know which revision of X we're running, we'll use both
12021 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
12022
12023 /* X11R4: send a ClientMessage to the window manager using the
12024 WM_CHANGE_STATE type. */
12025 {
12026 XEvent message;
58769bee 12027
c118dd06 12028 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 12029 message.xclient.type = ClientMessage;
334208b7 12030 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
12031 message.xclient.format = 32;
12032 message.xclient.data.l[0] = IconicState;
12033
334208b7
RS
12034 if (! XSendEvent (FRAME_X_DISPLAY (f),
12035 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
12036 False,
12037 SubstructureRedirectMask | SubstructureNotifyMask,
12038 &message))
dc6f92b8
JB
12039 {
12040 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12041 error ("Can't notify window manager of iconification");
dc6f92b8 12042 }
16bd92ea 12043 }
dc6f92b8 12044
58769bee 12045 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
12046 IconicState. */
12047 x_wm_set_window_state (f, IconicState);
dc6f92b8 12048
a9c00105
RS
12049 if (!FRAME_VISIBLE_P (f))
12050 {
12051 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 12052 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
12053 }
12054
3a88c238 12055 f->async_iconified = 1;
1e6bc770 12056 f->async_visible = 0;
dc6f92b8 12057
334208b7 12058 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 12059 UNBLOCK_INPUT;
8c002a25 12060#endif /* not USE_X_TOOLKIT */
dc6f92b8 12061}
d047c4eb 12062\f
c0ff3fab 12063/* Destroy the X window of frame F. */
dc6f92b8 12064
dfcf069d 12065void
c0ff3fab 12066x_destroy_window (f)
f676886a 12067 struct frame *f;
dc6f92b8 12068{
7f9c7f94
RS
12069 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12070
dc6f92b8 12071 BLOCK_INPUT;
c0ff3fab 12072
6186a4a0
RS
12073 /* If a display connection is dead, don't try sending more
12074 commands to the X server. */
12075 if (dpyinfo->display != 0)
12076 {
12077 if (f->output_data.x->icon_desc != 0)
12078 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
31f41daf 12079#ifdef HAVE_X_I18N
f5d11644
GM
12080 if (FRAME_XIC (f))
12081 free_frame_xic (f);
31f41daf 12082#endif
6186a4a0 12083 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->window_desc);
3afe33e7 12084#ifdef USE_X_TOOLKIT
06a2c219
GM
12085 if (f->output_data.x->widget)
12086 XtDestroyWidget (f->output_data.x->widget);
6186a4a0 12087 free_frame_menubar (f);
3afe33e7
RS
12088#endif /* USE_X_TOOLKIT */
12089
3e71d8f2
GM
12090 unload_color (f, f->output_data.x->foreground_pixel);
12091 unload_color (f, f->output_data.x->background_pixel);
12092 unload_color (f, f->output_data.x->cursor_pixel);
12093 unload_color (f, f->output_data.x->cursor_foreground_pixel);
12094 unload_color (f, f->output_data.x->border_pixel);
12095 unload_color (f, f->output_data.x->mouse_pixel);
12096 if (f->output_data.x->scroll_bar_background_pixel != -1)
12097 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
12098 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
12099 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
12100 if (f->output_data.x->white_relief.allocated_p)
12101 unload_color (f, f->output_data.x->white_relief.pixel);
12102 if (f->output_data.x->black_relief.allocated_p)
12103 unload_color (f, f->output_data.x->black_relief.pixel);
12104
6186a4a0
RS
12105 free_frame_faces (f);
12106 XFlush (FRAME_X_DISPLAY (f));
12107 }
dc6f92b8 12108
df89d8a4 12109 if (f->output_data.x->saved_menu_event)
06a2c219 12110 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 12111
7556890b
RS
12112 xfree (f->output_data.x);
12113 f->output_data.x = 0;
0f941935
KH
12114 if (f == dpyinfo->x_focus_frame)
12115 dpyinfo->x_focus_frame = 0;
12116 if (f == dpyinfo->x_focus_event_frame)
12117 dpyinfo->x_focus_event_frame = 0;
12118 if (f == dpyinfo->x_highlight_frame)
12119 dpyinfo->x_highlight_frame = 0;
c0ff3fab 12120
7f9c7f94
RS
12121 dpyinfo->reference_count--;
12122
12123 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 12124 {
7f9c7f94
RS
12125 dpyinfo->mouse_face_beg_row
12126 = dpyinfo->mouse_face_beg_col = -1;
12127 dpyinfo->mouse_face_end_row
12128 = dpyinfo->mouse_face_end_col = -1;
12129 dpyinfo->mouse_face_window = Qnil;
21323706
RS
12130 dpyinfo->mouse_face_deferred_gc = 0;
12131 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 12132 }
0134a210 12133
c0ff3fab 12134 UNBLOCK_INPUT;
dc6f92b8
JB
12135}
12136\f
f451eb13
JB
12137/* Setting window manager hints. */
12138
af31d76f
RS
12139/* Set the normal size hints for the window manager, for frame F.
12140 FLAGS is the flags word to use--or 0 meaning preserve the flags
12141 that the window now has.
12142 If USER_POSITION is nonzero, we set the USPosition
12143 flag (this is useful when FLAGS is 0). */
6dba1858 12144
dfcf069d 12145void
af31d76f 12146x_wm_set_size_hint (f, flags, user_position)
f676886a 12147 struct frame *f;
af31d76f
RS
12148 long flags;
12149 int user_position;
dc6f92b8
JB
12150{
12151 XSizeHints size_hints;
3afe33e7
RS
12152
12153#ifdef USE_X_TOOLKIT
7e4f2521
FP
12154 Arg al[2];
12155 int ac = 0;
12156 Dimension widget_width, widget_height;
7556890b 12157 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 12158#else /* not USE_X_TOOLKIT */
c118dd06 12159 Window window = FRAME_X_WINDOW (f);
3afe33e7 12160#endif /* not USE_X_TOOLKIT */
dc6f92b8 12161
b72a58fd
RS
12162 /* Setting PMaxSize caused various problems. */
12163 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 12164
7556890b
RS
12165 size_hints.x = f->output_data.x->left_pos;
12166 size_hints.y = f->output_data.x->top_pos;
7553a6b7 12167
7e4f2521
FP
12168#ifdef USE_X_TOOLKIT
12169 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
12170 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 12171 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
12172 size_hints.height = widget_height;
12173 size_hints.width = widget_width;
12174#else /* not USE_X_TOOLKIT */
f676886a
JB
12175 size_hints.height = PIXEL_HEIGHT (f);
12176 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 12177#endif /* not USE_X_TOOLKIT */
7553a6b7 12178
7556890b
RS
12179 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
12180 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
12181 size_hints.max_width
12182 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
12183 size_hints.max_height
12184 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 12185
d067ea8b
KH
12186 /* Calculate the base and minimum sizes.
12187
12188 (When we use the X toolkit, we don't do it here.
12189 Instead we copy the values that the widgets are using, below.) */
12190#ifndef USE_X_TOOLKIT
b1c884c3 12191 {
b0342f17 12192 int base_width, base_height;
0134a210 12193 int min_rows = 0, min_cols = 0;
b0342f17 12194
f451eb13
JB
12195 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
12196 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 12197
0134a210 12198 check_frame_size (f, &min_rows, &min_cols);
b0342f17 12199
0134a210
RS
12200 /* The window manager uses the base width hints to calculate the
12201 current number of rows and columns in the frame while
12202 resizing; min_width and min_height aren't useful for this
12203 purpose, since they might not give the dimensions for a
12204 zero-row, zero-column frame.
58769bee 12205
0134a210
RS
12206 We use the base_width and base_height members if we have
12207 them; otherwise, we set the min_width and min_height members
12208 to the size for a zero x zero frame. */
b0342f17
JB
12209
12210#ifdef HAVE_X11R4
0134a210
RS
12211 size_hints.flags |= PBaseSize;
12212 size_hints.base_width = base_width;
12213 size_hints.base_height = base_height;
12214 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
12215 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 12216#else
0134a210
RS
12217 size_hints.min_width = base_width;
12218 size_hints.min_height = base_height;
b0342f17 12219#endif
b1c884c3 12220 }
dc6f92b8 12221
d067ea8b 12222 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 12223 if (flags)
dc6f92b8 12224 {
d067ea8b
KH
12225 size_hints.flags |= flags;
12226 goto no_read;
12227 }
12228#endif /* not USE_X_TOOLKIT */
12229
12230 {
12231 XSizeHints hints; /* Sometimes I hate X Windows... */
12232 long supplied_return;
12233 int value;
af31d76f
RS
12234
12235#ifdef HAVE_X11R4
d067ea8b
KH
12236 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
12237 &supplied_return);
af31d76f 12238#else
d067ea8b 12239 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 12240#endif
58769bee 12241
d067ea8b
KH
12242#ifdef USE_X_TOOLKIT
12243 size_hints.base_height = hints.base_height;
12244 size_hints.base_width = hints.base_width;
12245 size_hints.min_height = hints.min_height;
12246 size_hints.min_width = hints.min_width;
12247#endif
12248
12249 if (flags)
12250 size_hints.flags |= flags;
12251 else
12252 {
12253 if (value == 0)
12254 hints.flags = 0;
12255 if (hints.flags & PSize)
12256 size_hints.flags |= PSize;
12257 if (hints.flags & PPosition)
12258 size_hints.flags |= PPosition;
12259 if (hints.flags & USPosition)
12260 size_hints.flags |= USPosition;
12261 if (hints.flags & USSize)
12262 size_hints.flags |= USSize;
12263 }
12264 }
12265
06a2c219 12266#ifndef USE_X_TOOLKIT
d067ea8b 12267 no_read:
06a2c219 12268#endif
0134a210 12269
af31d76f 12270#ifdef PWinGravity
7556890b 12271 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 12272 size_hints.flags |= PWinGravity;
dc05a16b 12273
af31d76f 12274 if (user_position)
6dba1858 12275 {
af31d76f
RS
12276 size_hints.flags &= ~ PPosition;
12277 size_hints.flags |= USPosition;
6dba1858 12278 }
2554751d 12279#endif /* PWinGravity */
6dba1858 12280
b0342f17 12281#ifdef HAVE_X11R4
334208b7 12282 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12283#else
334208b7 12284 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12285#endif
dc6f92b8
JB
12286}
12287
12288/* Used for IconicState or NormalState */
06a2c219 12289
dfcf069d 12290void
f676886a
JB
12291x_wm_set_window_state (f, state)
12292 struct frame *f;
dc6f92b8
JB
12293 int state;
12294{
3afe33e7 12295#ifdef USE_X_TOOLKIT
546e6d5b
RS
12296 Arg al[1];
12297
12298 XtSetArg (al[0], XtNinitialState, state);
7556890b 12299 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 12300#else /* not USE_X_TOOLKIT */
c118dd06 12301 Window window = FRAME_X_WINDOW (f);
dc6f92b8 12302
7556890b
RS
12303 f->output_data.x->wm_hints.flags |= StateHint;
12304 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 12305
7556890b 12306 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 12307#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12308}
12309
dfcf069d 12310void
7f2ae036 12311x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 12312 struct frame *f;
7f2ae036 12313 int pixmap_id;
dc6f92b8 12314{
d2bd6bc4
RS
12315 Pixmap icon_pixmap;
12316
06a2c219 12317#ifndef USE_X_TOOLKIT
c118dd06 12318 Window window = FRAME_X_WINDOW (f);
75231bad 12319#endif
dc6f92b8 12320
7f2ae036 12321 if (pixmap_id > 0)
dbc4e1c1 12322 {
d2bd6bc4 12323 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 12324 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
12325 }
12326 else
68568555
RS
12327 {
12328 /* It seems there is no way to turn off use of an icon pixmap.
12329 The following line does it, only if no icon has yet been created,
12330 for some window managers. But with mwm it crashes.
12331 Some people say it should clear the IconPixmapHint bit in this case,
12332 but that doesn't work, and the X consortium said it isn't the
12333 right thing at all. Since there is no way to win,
12334 best to explicitly give up. */
12335#if 0
12336 f->output_data.x->wm_hints.icon_pixmap = None;
12337#else
12338 return;
12339#endif
12340 }
b1c884c3 12341
d2bd6bc4
RS
12342#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
12343
12344 {
12345 Arg al[1];
12346 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
12347 XtSetValues (f->output_data.x->widget, al, 1);
12348 }
12349
12350#else /* not USE_X_TOOLKIT */
12351
7556890b
RS
12352 f->output_data.x->wm_hints.flags |= IconPixmapHint;
12353 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
12354
12355#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12356}
12357
dfcf069d 12358void
f676886a
JB
12359x_wm_set_icon_position (f, icon_x, icon_y)
12360 struct frame *f;
dc6f92b8
JB
12361 int icon_x, icon_y;
12362{
75231bad 12363#ifdef USE_X_TOOLKIT
7556890b 12364 Window window = XtWindow (f->output_data.x->widget);
75231bad 12365#else
c118dd06 12366 Window window = FRAME_X_WINDOW (f);
75231bad 12367#endif
dc6f92b8 12368
7556890b
RS
12369 f->output_data.x->wm_hints.flags |= IconPositionHint;
12370 f->output_data.x->wm_hints.icon_x = icon_x;
12371 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 12372
7556890b 12373 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
12374}
12375
12376\f
06a2c219
GM
12377/***********************************************************************
12378 Fonts
12379 ***********************************************************************/
dc43ef94
KH
12380
12381/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 12382
dc43ef94
KH
12383struct font_info *
12384x_get_font_info (f, font_idx)
12385 FRAME_PTR f;
12386 int font_idx;
12387{
12388 return (FRAME_X_FONT_TABLE (f) + font_idx);
12389}
12390
12391
12392/* Return a list of names of available fonts matching PATTERN on frame
12393 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
12394 to be listed. Frame F NULL means we have not yet created any
12395 frame on X, and consult the first display in x_display_list.
12396 MAXNAMES sets a limit on how many fonts to match. */
12397
12398Lisp_Object
12399x_list_fonts (f, pattern, size, maxnames)
12400 FRAME_PTR f;
12401 Lisp_Object pattern;
12402 int size;
12403 int maxnames;
12404{
06a2c219
GM
12405 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
12406 Lisp_Object tem, second_best;
dc43ef94 12407 Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
09c6077f 12408 int try_XLoadQueryFont = 0;
53ca4657 12409 int count;
dc43ef94 12410
6b0efe73 12411 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
12412 if (NILP (patterns))
12413 patterns = Fcons (pattern, Qnil);
81ba44e5 12414
09c6077f
KH
12415 if (maxnames == 1 && !size)
12416 /* We can return any single font matching PATTERN. */
12417 try_XLoadQueryFont = 1;
9a32686f 12418
8e713be6 12419 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 12420 {
dc43ef94 12421 int num_fonts;
3e71d8f2 12422 char **names = NULL;
dc43ef94 12423
8e713be6 12424 pattern = XCAR (patterns);
536f4067
RS
12425 /* See if we cached the result for this particular query.
12426 The cache is an alist of the form:
12427 (((PATTERN . MAXNAMES) (FONTNAME . WIDTH) ...) ...)
12428 */
8e713be6 12429 if (f && (tem = XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element),
b5210ea7
KH
12430 key = Fcons (pattern, make_number (maxnames)),
12431 !NILP (list = Fassoc (key, tem))))
12432 {
12433 list = Fcdr_safe (list);
12434 /* We have a cashed list. Don't have to get the list again. */
12435 goto label_cached;
12436 }
12437
12438 /* At first, put PATTERN in the cache. */
09c6077f 12439
dc43ef94 12440 BLOCK_INPUT;
17d85edc
KH
12441 count = x_catch_errors (dpy);
12442
09c6077f
KH
12443 if (try_XLoadQueryFont)
12444 {
12445 XFontStruct *font;
12446 unsigned long value;
12447
12448 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
12449 if (x_had_errors_p (dpy))
12450 {
12451 /* This error is perhaps due to insufficient memory on X
12452 server. Let's just ignore it. */
12453 font = NULL;
12454 x_clear_errors (dpy);
12455 }
12456
09c6077f
KH
12457 if (font
12458 && XGetFontProperty (font, XA_FONT, &value))
12459 {
12460 char *name = (char *) XGetAtomName (dpy, (Atom) value);
12461 int len = strlen (name);
01c752b5 12462 char *tmp;
09c6077f 12463
6f6512e8
KH
12464 /* If DXPC (a Differential X Protocol Compressor)
12465 Ver.3.7 is running, XGetAtomName will return null
12466 string. We must avoid such a name. */
12467 if (len == 0)
12468 try_XLoadQueryFont = 0;
12469 else
12470 {
12471 num_fonts = 1;
12472 names = (char **) alloca (sizeof (char *));
12473 /* Some systems only allow alloca assigned to a
12474 simple var. */
12475 tmp = (char *) alloca (len + 1); names[0] = tmp;
12476 bcopy (name, names[0], len + 1);
12477 XFree (name);
12478 }
09c6077f
KH
12479 }
12480 else
12481 try_XLoadQueryFont = 0;
a083fd23
RS
12482
12483 if (font)
12484 XFreeFont (dpy, font);
09c6077f
KH
12485 }
12486
12487 if (!try_XLoadQueryFont)
17d85edc
KH
12488 {
12489 /* We try at least 10 fonts because XListFonts will return
12490 auto-scaled fonts at the head. */
12491 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
12492 &num_fonts);
12493 if (x_had_errors_p (dpy))
12494 {
12495 /* This error is perhaps due to insufficient memory on X
12496 server. Let's just ignore it. */
12497 names = NULL;
12498 x_clear_errors (dpy);
12499 }
12500 }
12501
12502 x_uncatch_errors (dpy, count);
dc43ef94
KH
12503 UNBLOCK_INPUT;
12504
12505 if (names)
12506 {
12507 int i;
dc43ef94
KH
12508
12509 /* Make a list of all the fonts we got back.
12510 Store that in the font cache for the display. */
12511 for (i = 0; i < num_fonts; i++)
12512 {
06a2c219 12513 int width = 0;
dc43ef94 12514 char *p = names[i];
06a2c219
GM
12515 int average_width = -1, dashes = 0;
12516
dc43ef94 12517 /* Count the number of dashes in NAMES[I]. If there are
b5210ea7
KH
12518 14 dashes, and the field value following 12th dash
12519 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
12520 is usually too ugly to be used for editing. Let's
12521 ignore it. */
dc43ef94
KH
12522 while (*p)
12523 if (*p++ == '-')
12524 {
12525 dashes++;
12526 if (dashes == 7) /* PIXEL_SIZE field */
12527 width = atoi (p);
12528 else if (dashes == 12) /* AVERAGE_WIDTH field */
12529 average_width = atoi (p);
12530 }
12531 if (dashes < 14 || average_width != 0)
12532 {
12533 tem = build_string (names[i]);
12534 if (NILP (Fassoc (tem, list)))
12535 {
12536 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
12537 && ((fast_c_string_match_ignore_case
12538 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
12539 >= 0))
12540 /* We can set the value of PIXEL_SIZE to the
b5210ea7 12541 width of this font. */
dc43ef94
KH
12542 list = Fcons (Fcons (tem, make_number (width)), list);
12543 else
12544 /* For the moment, width is not known. */
12545 list = Fcons (Fcons (tem, Qnil), list);
12546 }
12547 }
12548 }
09c6077f
KH
12549 if (!try_XLoadQueryFont)
12550 XFreeFontNames (names);
dc43ef94
KH
12551 }
12552
b5210ea7 12553 /* Now store the result in the cache. */
dc43ef94 12554 if (f != NULL)
8e713be6 12555 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element)
dc43ef94 12556 = Fcons (Fcons (key, list),
8e713be6 12557 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
dc43ef94 12558
b5210ea7
KH
12559 label_cached:
12560 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 12561
b5210ea7
KH
12562 newlist = second_best = Qnil;
12563 /* Make a list of the fonts that have the right width. */
8e713be6 12564 for (; CONSP (list); list = XCDR (list))
b5210ea7 12565 {
536f4067
RS
12566 int found_size;
12567
8e713be6 12568 tem = XCAR (list);
dc43ef94 12569
8e713be6 12570 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
12571 continue;
12572 if (!size)
12573 {
8e713be6 12574 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
12575 continue;
12576 }
dc43ef94 12577
8e713be6 12578 if (!INTEGERP (XCDR (tem)))
dc43ef94 12579 {
b5210ea7
KH
12580 /* Since we have not yet known the size of this font, we
12581 must try slow function call XLoadQueryFont. */
dc43ef94
KH
12582 XFontStruct *thisinfo;
12583
12584 BLOCK_INPUT;
17d85edc 12585 count = x_catch_errors (dpy);
dc43ef94 12586 thisinfo = XLoadQueryFont (dpy,
8e713be6 12587 XSTRING (XCAR (tem))->data);
17d85edc
KH
12588 if (x_had_errors_p (dpy))
12589 {
12590 /* This error is perhaps due to insufficient memory on X
12591 server. Let's just ignore it. */
12592 thisinfo = NULL;
12593 x_clear_errors (dpy);
12594 }
12595 x_uncatch_errors (dpy, count);
dc43ef94
KH
12596 UNBLOCK_INPUT;
12597
12598 if (thisinfo)
12599 {
8e713be6 12600 XCDR (tem)
536f4067
RS
12601 = (thisinfo->min_bounds.width == 0
12602 ? make_number (0)
12603 : make_number (thisinfo->max_bounds.width));
dc43ef94
KH
12604 XFreeFont (dpy, thisinfo);
12605 }
12606 else
b5210ea7 12607 /* For unknown reason, the previous call of XListFont had
06a2c219 12608 returned a font which can't be opened. Record the size
b5210ea7 12609 as 0 not to try to open it again. */
8e713be6 12610 XCDR (tem) = make_number (0);
dc43ef94 12611 }
536f4067 12612
8e713be6 12613 found_size = XINT (XCDR (tem));
536f4067 12614 if (found_size == size)
8e713be6 12615 newlist = Fcons (XCAR (tem), newlist);
536f4067 12616 else if (found_size > 0)
b5210ea7 12617 {
536f4067 12618 if (NILP (second_best))
b5210ea7 12619 second_best = tem;
536f4067
RS
12620 else if (found_size < size)
12621 {
8e713be6
KR
12622 if (XINT (XCDR (second_best)) > size
12623 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
12624 second_best = tem;
12625 }
12626 else
12627 {
8e713be6
KR
12628 if (XINT (XCDR (second_best)) > size
12629 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
12630 second_best = tem;
12631 }
b5210ea7
KH
12632 }
12633 }
12634 if (!NILP (newlist))
12635 break;
12636 else if (!NILP (second_best))
12637 {
8e713be6 12638 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 12639 break;
dc43ef94 12640 }
dc43ef94
KH
12641 }
12642
12643 return newlist;
12644}
12645
06a2c219
GM
12646
12647#if GLYPH_DEBUG
12648
12649/* Check that FONT is valid on frame F. It is if it can be found in F's
12650 font table. */
12651
12652static void
12653x_check_font (f, font)
12654 struct frame *f;
12655 XFontStruct *font;
12656{
12657 int i;
12658 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12659
12660 xassert (font != NULL);
12661
12662 for (i = 0; i < dpyinfo->n_fonts; i++)
12663 if (dpyinfo->font_table[i].name
12664 && font == dpyinfo->font_table[i].font)
12665 break;
12666
12667 xassert (i < dpyinfo->n_fonts);
12668}
12669
12670#endif /* GLYPH_DEBUG != 0 */
12671
12672/* Set *W to the minimum width, *H to the minimum font height of FONT.
12673 Note: There are (broken) X fonts out there with invalid XFontStruct
12674 min_bounds contents. For example, handa@etl.go.jp reports that
12675 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
12676 have font->min_bounds.width == 0. */
12677
12678static INLINE void
12679x_font_min_bounds (font, w, h)
12680 XFontStruct *font;
12681 int *w, *h;
12682{
12683 *h = FONT_HEIGHT (font);
12684 *w = font->min_bounds.width;
12685
12686 /* Try to handle the case where FONT->min_bounds has invalid
12687 contents. Since the only font known to have invalid min_bounds
12688 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
12689 if (*w <= 0)
12690 *w = font->max_bounds.width;
12691}
12692
12693
12694/* Compute the smallest character width and smallest font height over
12695 all fonts available on frame F. Set the members smallest_char_width
12696 and smallest_font_height in F's x_display_info structure to
12697 the values computed. Value is non-zero if smallest_font_height or
12698 smallest_char_width become smaller than they were before. */
12699
12700static int
12701x_compute_min_glyph_bounds (f)
12702 struct frame *f;
12703{
12704 int i;
12705 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12706 XFontStruct *font;
12707 int old_width = dpyinfo->smallest_char_width;
12708 int old_height = dpyinfo->smallest_font_height;
12709
12710 dpyinfo->smallest_font_height = 100000;
12711 dpyinfo->smallest_char_width = 100000;
12712
12713 for (i = 0; i < dpyinfo->n_fonts; ++i)
12714 if (dpyinfo->font_table[i].name)
12715 {
12716 struct font_info *fontp = dpyinfo->font_table + i;
12717 int w, h;
12718
12719 font = (XFontStruct *) fontp->font;
12720 xassert (font != (XFontStruct *) ~0);
12721 x_font_min_bounds (font, &w, &h);
12722
12723 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
12724 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
12725 }
12726
12727 xassert (dpyinfo->smallest_char_width > 0
12728 && dpyinfo->smallest_font_height > 0);
12729
12730 return (dpyinfo->n_fonts == 1
12731 || dpyinfo->smallest_char_width < old_width
12732 || dpyinfo->smallest_font_height < old_height);
12733}
12734
12735
dc43ef94
KH
12736/* Load font named FONTNAME of the size SIZE for frame F, and return a
12737 pointer to the structure font_info while allocating it dynamically.
12738 If SIZE is 0, load any size of font.
12739 If loading is failed, return NULL. */
12740
12741struct font_info *
12742x_load_font (f, fontname, size)
12743 struct frame *f;
12744 register char *fontname;
12745 int size;
12746{
12747 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12748 Lisp_Object font_names;
d645aaa4 12749 int count;
dc43ef94
KH
12750
12751 /* Get a list of all the fonts that match this name. Once we
12752 have a list of matching fonts, we compare them against the fonts
12753 we already have by comparing names. */
09c6077f 12754 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
12755
12756 if (!NILP (font_names))
12757 {
12758 Lisp_Object tail;
12759 int i;
12760
12761 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 12762 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
12763 if (dpyinfo->font_table[i].name
12764 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 12765 XSTRING (XCAR (tail))->data)
06a2c219 12766 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 12767 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
12768 return (dpyinfo->font_table + i);
12769 }
12770
12771 /* Load the font and add it to the table. */
12772 {
12773 char *full_name;
12774 XFontStruct *font;
12775 struct font_info *fontp;
12776 unsigned long value;
06a2c219 12777 int i;
dc43ef94 12778
2da424f1
KH
12779 /* If we have found fonts by x_list_font, load one of them. If
12780 not, we still try to load a font by the name given as FONTNAME
12781 because XListFonts (called in x_list_font) of some X server has
12782 a bug of not finding a font even if the font surely exists and
12783 is loadable by XLoadQueryFont. */
e1d6d5b9 12784 if (size > 0 && !NILP (font_names))
8e713be6 12785 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
12786
12787 BLOCK_INPUT;
d645aaa4 12788 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 12789 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
12790 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12791 {
12792 /* This error is perhaps due to insufficient memory on X
12793 server. Let's just ignore it. */
12794 font = NULL;
12795 x_clear_errors (FRAME_X_DISPLAY (f));
12796 }
12797 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 12798 UNBLOCK_INPUT;
b5210ea7 12799 if (!font)
dc43ef94
KH
12800 return NULL;
12801
06a2c219
GM
12802 /* Find a free slot in the font table. */
12803 for (i = 0; i < dpyinfo->n_fonts; ++i)
12804 if (dpyinfo->font_table[i].name == NULL)
12805 break;
12806
12807 /* If no free slot found, maybe enlarge the font table. */
12808 if (i == dpyinfo->n_fonts
12809 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 12810 {
06a2c219
GM
12811 int sz;
12812 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
12813 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 12814 dpyinfo->font_table
06a2c219 12815 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
12816 }
12817
06a2c219
GM
12818 fontp = dpyinfo->font_table + i;
12819 if (i == dpyinfo->n_fonts)
12820 ++dpyinfo->n_fonts;
dc43ef94
KH
12821
12822 /* Now fill in the slots of *FONTP. */
12823 BLOCK_INPUT;
12824 fontp->font = font;
06a2c219 12825 fontp->font_idx = i;
dc43ef94
KH
12826 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
12827 bcopy (fontname, fontp->name, strlen (fontname) + 1);
12828
12829 /* Try to get the full name of FONT. Put it in FULL_NAME. */
12830 full_name = 0;
12831 if (XGetFontProperty (font, XA_FONT, &value))
12832 {
12833 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
12834 char *p = name;
12835 int dashes = 0;
12836
12837 /* Count the number of dashes in the "full name".
12838 If it is too few, this isn't really the font's full name,
12839 so don't use it.
12840 In X11R4, the fonts did not come with their canonical names
12841 stored in them. */
12842 while (*p)
12843 {
12844 if (*p == '-')
12845 dashes++;
12846 p++;
12847 }
12848
12849 if (dashes >= 13)
12850 {
12851 full_name = (char *) xmalloc (p - name + 1);
12852 bcopy (name, full_name, p - name + 1);
12853 }
12854
12855 XFree (name);
12856 }
12857
12858 if (full_name != 0)
12859 fontp->full_name = full_name;
12860 else
12861 fontp->full_name = fontp->name;
12862
12863 fontp->size = font->max_bounds.width;
d5749adb
KH
12864 fontp->height = FONT_HEIGHT (font);
12865 {
12866 /* For some font, ascent and descent in max_bounds field is
12867 larger than the above value. */
12868 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
12869 if (max_height > fontp->height)
74848a96 12870 fontp->height = max_height;
d5749adb 12871 }
dc43ef94 12872
2da424f1
KH
12873 if (NILP (font_names))
12874 {
12875 /* We come here because of a bug of XListFonts mentioned at
12876 the head of this block. Let's store this information in
12877 the cache for x_list_fonts. */
12878 Lisp_Object lispy_name = build_string (fontname);
12879 Lisp_Object lispy_full_name = build_string (fontp->full_name);
12880
8e713be6 12881 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12882 = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
12883 Fcons (Fcons (lispy_full_name,
12884 make_number (fontp->size)),
12885 Qnil)),
8e713be6 12886 XCDR (dpyinfo->name_list_element));
2da424f1 12887 if (full_name)
8e713be6 12888 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12889 = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
12890 Fcons (Fcons (lispy_full_name,
12891 make_number (fontp->size)),
12892 Qnil)),
8e713be6 12893 XCDR (dpyinfo->name_list_element));
2da424f1
KH
12894 }
12895
dc43ef94
KH
12896 /* The slot `encoding' specifies how to map a character
12897 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
12898 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
12899 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 12900 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 12901 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
12902 which is never used by any charset. If mapping can't be
12903 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
12904 fontp->encoding[1]
12905 = (font->max_byte1 == 0
12906 /* 1-byte font */
12907 ? (font->min_char_or_byte2 < 0x80
12908 ? (font->max_char_or_byte2 < 0x80
12909 ? 0 /* 0x20..0x7F */
8ff102bd 12910 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
12911 : 1) /* 0xA0..0xFF */
12912 /* 2-byte font */
12913 : (font->min_byte1 < 0x80
12914 ? (font->max_byte1 < 0x80
12915 ? (font->min_char_or_byte2 < 0x80
12916 ? (font->max_char_or_byte2 < 0x80
12917 ? 0 /* 0x2020..0x7F7F */
8ff102bd 12918 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 12919 : 3) /* 0x20A0..0x7FFF */
8ff102bd 12920 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
12921 : (font->min_char_or_byte2 < 0x80
12922 ? (font->max_char_or_byte2 < 0x80
12923 ? 2 /* 0xA020..0xFF7F */
8ff102bd 12924 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
12925 : 1))); /* 0xA0A0..0xFFFF */
12926
12927 fontp->baseline_offset
12928 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
12929 ? (long) value : 0);
12930 fontp->relative_compose
12931 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
12932 ? (long) value : 0);
f78798df
KH
12933 fontp->default_ascent
12934 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
12935 ? (long) value : 0);
dc43ef94 12936
06a2c219
GM
12937 /* Set global flag fonts_changed_p to non-zero if the font loaded
12938 has a character with a smaller width than any other character
12939 before, or if the font loaded has a smalle>r height than any
12940 other font loaded before. If this happens, it will make a
12941 glyph matrix reallocation necessary. */
12942 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 12943 UNBLOCK_INPUT;
dc43ef94
KH
12944 return fontp;
12945 }
12946}
12947
06a2c219
GM
12948
12949/* Return a pointer to struct font_info of a font named FONTNAME for
12950 frame F. If no such font is loaded, return NULL. */
12951
dc43ef94
KH
12952struct font_info *
12953x_query_font (f, fontname)
12954 struct frame *f;
12955 register char *fontname;
12956{
12957 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12958 int i;
12959
12960 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
12961 if (dpyinfo->font_table[i].name
12962 && (!strcmp (dpyinfo->font_table[i].name, fontname)
12963 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
12964 return (dpyinfo->font_table + i);
12965 return NULL;
12966}
12967
06a2c219
GM
12968
12969/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
12970 `encoder' of the structure. */
12971
12972void
12973x_find_ccl_program (fontp)
12974 struct font_info *fontp;
12975{
a42f54e6 12976 Lisp_Object list, elt;
a6582676 12977
8e713be6 12978 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 12979 {
8e713be6 12980 elt = XCAR (list);
a6582676 12981 if (CONSP (elt)
8e713be6
KR
12982 && STRINGP (XCAR (elt))
12983 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
a6582676 12984 >= 0))
a42f54e6
KH
12985 break;
12986 }
12987 if (! NILP (list))
12988 {
d27f8ca7
KH
12989 struct ccl_program *ccl
12990 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 12991
8e713be6 12992 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
12993 xfree (ccl);
12994 else
12995 fontp->font_encoder = ccl;
a6582676
KH
12996 }
12997}
12998
06a2c219 12999
dc43ef94 13000\f
06a2c219
GM
13001/***********************************************************************
13002 Initialization
13003 ***********************************************************************/
f451eb13 13004
3afe33e7
RS
13005#ifdef USE_X_TOOLKIT
13006static XrmOptionDescRec emacs_options[] = {
13007 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
13008 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
13009
13010 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
13011 XrmoptionSepArg, NULL},
13012 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
13013
13014 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13015 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13016 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13017 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13018 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13019 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
13020 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
13021};
13022#endif /* USE_X_TOOLKIT */
13023
7a13e894
RS
13024static int x_initialized;
13025
29b38361
KH
13026#ifdef MULTI_KBOARD
13027/* Test whether two display-name strings agree up to the dot that separates
13028 the screen number from the server number. */
13029static int
13030same_x_server (name1, name2)
13031 char *name1, *name2;
13032{
13033 int seen_colon = 0;
cf591cc1
RS
13034 unsigned char *system_name = XSTRING (Vsystem_name)->data;
13035 int system_name_length = strlen (system_name);
13036 int length_until_period = 0;
13037
13038 while (system_name[length_until_period] != 0
13039 && system_name[length_until_period] != '.')
13040 length_until_period++;
13041
13042 /* Treat `unix' like an empty host name. */
13043 if (! strncmp (name1, "unix:", 5))
13044 name1 += 4;
13045 if (! strncmp (name2, "unix:", 5))
13046 name2 += 4;
13047 /* Treat this host's name like an empty host name. */
13048 if (! strncmp (name1, system_name, system_name_length)
13049 && name1[system_name_length] == ':')
13050 name1 += system_name_length;
13051 if (! strncmp (name2, system_name, system_name_length)
13052 && name2[system_name_length] == ':')
13053 name2 += system_name_length;
13054 /* Treat this host's domainless name like an empty host name. */
13055 if (! strncmp (name1, system_name, length_until_period)
13056 && name1[length_until_period] == ':')
13057 name1 += length_until_period;
13058 if (! strncmp (name2, system_name, length_until_period)
13059 && name2[length_until_period] == ':')
13060 name2 += length_until_period;
13061
29b38361
KH
13062 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
13063 {
13064 if (*name1 == ':')
13065 seen_colon++;
13066 if (seen_colon && *name1 == '.')
13067 return 1;
13068 }
13069 return (seen_colon
13070 && (*name1 == '.' || *name1 == '\0')
13071 && (*name2 == '.' || *name2 == '\0'));
13072}
13073#endif
13074
334208b7 13075struct x_display_info *
1f8255f2 13076x_term_init (display_name, xrm_option, resource_name)
334208b7 13077 Lisp_Object display_name;
1f8255f2
RS
13078 char *xrm_option;
13079 char *resource_name;
dc6f92b8 13080{
334208b7 13081 int connection;
7a13e894 13082 Display *dpy;
334208b7
RS
13083 struct x_display_info *dpyinfo;
13084 XrmDatabase xrdb;
13085
60439948
KH
13086 BLOCK_INPUT;
13087
7a13e894
RS
13088 if (!x_initialized)
13089 {
13090 x_initialize ();
13091 x_initialized = 1;
13092 }
dc6f92b8 13093
3afe33e7 13094#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
13095 /* weiner@footloose.sps.mot.com reports that this causes
13096 errors with X11R5:
13097 X protocol error: BadAtom (invalid Atom parameter)
13098 on protocol request 18skiloaf.
13099 So let's not use it until R6. */
13100#ifdef HAVE_X11XTR6
bdcd49ba
RS
13101 XtSetLanguageProc (NULL, NULL, NULL);
13102#endif
13103
7f9c7f94
RS
13104 {
13105 int argc = 0;
13106 char *argv[3];
13107
13108 argv[0] = "";
13109 argc = 1;
13110 if (xrm_option)
13111 {
13112 argv[argc++] = "-xrm";
13113 argv[argc++] = xrm_option;
13114 }
13115 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
13116 resource_name, EMACS_CLASS,
13117 emacs_options, XtNumber (emacs_options),
13118 &argc, argv);
39d8bb4d
KH
13119
13120#ifdef HAVE_X11XTR6
10537cb1 13121 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 13122 fixup_locale ();
39d8bb4d 13123#endif
7f9c7f94 13124 }
3afe33e7
RS
13125
13126#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
13127#ifdef HAVE_X11R5
13128 XSetLocaleModifiers ("");
13129#endif
7a13e894 13130 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 13131#endif /* not USE_X_TOOLKIT */
334208b7 13132
7a13e894
RS
13133 /* Detect failure. */
13134 if (dpy == 0)
60439948
KH
13135 {
13136 UNBLOCK_INPUT;
13137 return 0;
13138 }
7a13e894
RS
13139
13140 /* We have definitely succeeded. Record the new connection. */
13141
13142 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
13143
29b38361
KH
13144#ifdef MULTI_KBOARD
13145 {
13146 struct x_display_info *share;
13147 Lisp_Object tail;
13148
13149 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
13150 share = share->next, tail = XCDR (tail))
13151 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
13152 XSTRING (display_name)->data))
13153 break;
13154 if (share)
13155 dpyinfo->kboard = share->kboard;
13156 else
13157 {
13158 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13159 init_kboard (dpyinfo->kboard);
59e755be
KH
13160 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
13161 {
13162 char *vendor = ServerVendor (dpy);
9b6ed9f3 13163 UNBLOCK_INPUT;
59e755be
KH
13164 dpyinfo->kboard->Vsystem_key_alist
13165 = call1 (Qvendor_specific_keysyms,
13166 build_string (vendor ? vendor : ""));
9b6ed9f3 13167 BLOCK_INPUT;
59e755be
KH
13168 }
13169
29b38361
KH
13170 dpyinfo->kboard->next_kboard = all_kboards;
13171 all_kboards = dpyinfo->kboard;
0ad5446c
KH
13172 /* Don't let the initial kboard remain current longer than necessary.
13173 That would cause problems if a file loaded on startup tries to
06a2c219 13174 prompt in the mini-buffer. */
0ad5446c
KH
13175 if (current_kboard == initial_kboard)
13176 current_kboard = dpyinfo->kboard;
29b38361
KH
13177 }
13178 dpyinfo->kboard->reference_count++;
13179 }
b9737ad3
KH
13180#endif
13181
7a13e894
RS
13182 /* Put this display on the chain. */
13183 dpyinfo->next = x_display_list;
13184 x_display_list = dpyinfo;
13185
13186 /* Put it on x_display_name_list as well, to keep them parallel. */
13187 x_display_name_list = Fcons (Fcons (display_name, Qnil),
13188 x_display_name_list);
8e713be6 13189 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
13190
13191 dpyinfo->display = dpy;
dc6f92b8 13192
dc6f92b8 13193#if 0
7a13e894 13194 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 13195#endif /* ! 0 */
7a13e894
RS
13196
13197 dpyinfo->x_id_name
fc932ac6
RS
13198 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
13199 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
13200 + 2);
13201 sprintf (dpyinfo->x_id_name, "%s@%s",
13202 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
13203
13204 /* Figure out which modifier bits mean what. */
334208b7 13205 x_find_modifier_meanings (dpyinfo);
f451eb13 13206
ab648270 13207 /* Get the scroll bar cursor. */
7a13e894 13208 dpyinfo->vertical_scroll_bar_cursor
334208b7 13209 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 13210
334208b7
RS
13211 xrdb = x_load_resources (dpyinfo->display, xrm_option,
13212 resource_name, EMACS_CLASS);
13213#ifdef HAVE_XRMSETDATABASE
13214 XrmSetDatabase (dpyinfo->display, xrdb);
13215#else
13216 dpyinfo->display->db = xrdb;
13217#endif
547d9db8 13218 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
13219 all versions. */
13220 dpyinfo->xrdb = xrdb;
334208b7
RS
13221
13222 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
13223 DefaultScreen (dpyinfo->display));
5ff67d81 13224 select_visual (dpyinfo);
43bd1b2b 13225 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
13226 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
13227 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
13228 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
13229 dpyinfo->grabbed = 0;
13230 dpyinfo->reference_count = 0;
13231 dpyinfo->icon_bitmap_id = -1;
06a2c219 13232 dpyinfo->font_table = NULL;
7a13e894
RS
13233 dpyinfo->n_fonts = 0;
13234 dpyinfo->font_table_size = 0;
13235 dpyinfo->bitmaps = 0;
13236 dpyinfo->bitmaps_size = 0;
13237 dpyinfo->bitmaps_last = 0;
13238 dpyinfo->scratch_cursor_gc = 0;
13239 dpyinfo->mouse_face_mouse_frame = 0;
13240 dpyinfo->mouse_face_deferred_gc = 0;
13241 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
13242 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 13243 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894
RS
13244 dpyinfo->mouse_face_window = Qnil;
13245 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
13246 dpyinfo->mouse_face_defer = 0;
0f941935
KH
13247 dpyinfo->x_focus_frame = 0;
13248 dpyinfo->x_focus_event_frame = 0;
13249 dpyinfo->x_highlight_frame = 0;
06a2c219 13250 dpyinfo->image_cache = make_image_cache ();
334208b7 13251
43bd1b2b 13252 /* See if a private colormap is requested. */
5ff67d81
GM
13253 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
13254 {
13255 if (dpyinfo->visual->class == PseudoColor)
13256 {
13257 Lisp_Object value;
13258 value = display_x_get_resource (dpyinfo,
13259 build_string ("privateColormap"),
13260 build_string ("PrivateColormap"),
13261 Qnil, Qnil);
13262 if (STRINGP (value)
13263 && (!strcmp (XSTRING (value)->data, "true")
13264 || !strcmp (XSTRING (value)->data, "on")))
13265 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
13266 }
43bd1b2b 13267 }
5ff67d81
GM
13268 else
13269 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
13270 dpyinfo->visual, AllocNone);
43bd1b2b 13271
06a2c219
GM
13272 {
13273 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
13274 double pixels = DisplayHeight (dpyinfo->display, screen_number);
13275 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
13276 dpyinfo->resy = pixels * 25.4 / mm;
13277 pixels = DisplayWidth (dpyinfo->display, screen_number);
13278 mm = DisplayWidthMM (dpyinfo->display, screen_number);
13279 dpyinfo->resx = pixels * 25.4 / mm;
13280 }
13281
334208b7
RS
13282 dpyinfo->Xatom_wm_protocols
13283 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
13284 dpyinfo->Xatom_wm_take_focus
13285 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
13286 dpyinfo->Xatom_wm_save_yourself
13287 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
13288 dpyinfo->Xatom_wm_delete_window
13289 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
13290 dpyinfo->Xatom_wm_change_state
13291 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
13292 dpyinfo->Xatom_wm_configure_denied
13293 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
13294 dpyinfo->Xatom_wm_window_moved
13295 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
13296 dpyinfo->Xatom_editres
13297 = XInternAtom (dpyinfo->display, "Editres", False);
13298 dpyinfo->Xatom_CLIPBOARD
13299 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
13300 dpyinfo->Xatom_TIMESTAMP
13301 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
13302 dpyinfo->Xatom_TEXT
13303 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
13304 dpyinfo->Xatom_COMPOUND_TEXT
13305 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
13306 dpyinfo->Xatom_DELETE
13307 = XInternAtom (dpyinfo->display, "DELETE", False);
13308 dpyinfo->Xatom_MULTIPLE
13309 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
13310 dpyinfo->Xatom_INCR
13311 = XInternAtom (dpyinfo->display, "INCR", False);
13312 dpyinfo->Xatom_EMACS_TMP
13313 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
13314 dpyinfo->Xatom_TARGETS
13315 = XInternAtom (dpyinfo->display, "TARGETS", False);
13316 dpyinfo->Xatom_NULL
13317 = XInternAtom (dpyinfo->display, "NULL", False);
13318 dpyinfo->Xatom_ATOM_PAIR
13319 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
13320 /* For properties of font. */
13321 dpyinfo->Xatom_PIXEL_SIZE
13322 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
13323 dpyinfo->Xatom_MULE_BASELINE_OFFSET
13324 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
13325 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
13326 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
13327 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
13328 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 13329
06a2c219
GM
13330 /* Ghostscript support. */
13331 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
13332 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
13333
13334 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
13335 False);
13336
547d9db8
KH
13337 dpyinfo->cut_buffers_initialized = 0;
13338
334208b7
RS
13339 connection = ConnectionNumber (dpyinfo->display);
13340 dpyinfo->connection = connection;
13341
dc43ef94 13342 {
5d7cc324
RS
13343 char null_bits[1];
13344
13345 null_bits[0] = 0x00;
dc43ef94
KH
13346
13347 dpyinfo->null_pixel
13348 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13349 null_bits, 1, 1, (long) 0, (long) 0,
13350 1);
13351 }
13352
06a2c219
GM
13353 {
13354 extern int gray_bitmap_width, gray_bitmap_height;
13355 extern unsigned char *gray_bitmap_bits;
13356 dpyinfo->gray
13357 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13358 gray_bitmap_bits,
13359 gray_bitmap_width, gray_bitmap_height,
13360 (unsigned long) 1, (unsigned long) 0, 1);
13361 }
13362
f5d11644
GM
13363#ifdef HAVE_X_I18N
13364 xim_initialize (dpyinfo, resource_name);
13365#endif
13366
87485d6f
MW
13367#ifdef subprocesses
13368 /* This is only needed for distinguishing keyboard and process input. */
334208b7 13369 if (connection != 0)
7a13e894 13370 add_keyboard_wait_descriptor (connection);
87485d6f 13371#endif
6d4238f3 13372
041b69ac 13373#ifndef F_SETOWN_BUG
dc6f92b8 13374#ifdef F_SETOWN
dc6f92b8 13375#ifdef F_SETOWN_SOCK_NEG
61c3ce62 13376 /* stdin is a socket here */
334208b7 13377 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 13378#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 13379 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
13380#endif /* ! defined (F_SETOWN_SOCK_NEG) */
13381#endif /* ! defined (F_SETOWN) */
041b69ac 13382#endif /* F_SETOWN_BUG */
dc6f92b8
JB
13383
13384#ifdef SIGIO
eee20f6a
KH
13385 if (interrupt_input)
13386 init_sigio (connection);
c118dd06 13387#endif /* ! defined (SIGIO) */
dc6f92b8 13388
51b592fb 13389#ifdef USE_LUCID
f8c39f51 13390#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
13391 /* Make sure that we have a valid font for dialog boxes
13392 so that Xt does not crash. */
13393 {
13394 Display *dpy = dpyinfo->display;
13395 XrmValue d, fr, to;
13396 Font font;
e99db5a1 13397 int count;
51b592fb
RS
13398
13399 d.addr = (XPointer)&dpy;
13400 d.size = sizeof (Display *);
13401 fr.addr = XtDefaultFont;
13402 fr.size = sizeof (XtDefaultFont);
13403 to.size = sizeof (Font *);
13404 to.addr = (XPointer)&font;
e99db5a1 13405 count = x_catch_errors (dpy);
51b592fb
RS
13406 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
13407 abort ();
13408 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
13409 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 13410 x_uncatch_errors (dpy, count);
51b592fb
RS
13411 }
13412#endif
f8c39f51 13413#endif
51b592fb 13414
34e23e5a
GM
13415 /* See if we should run in synchronous mode. This is useful
13416 for debugging X code. */
13417 {
13418 Lisp_Object value;
13419 value = display_x_get_resource (dpyinfo,
13420 build_string ("synchronous"),
13421 build_string ("Synchronous"),
13422 Qnil, Qnil);
13423 if (STRINGP (value)
13424 && (!strcmp (XSTRING (value)->data, "true")
13425 || !strcmp (XSTRING (value)->data, "on")))
13426 XSynchronize (dpyinfo->display, True);
13427 }
13428
60439948
KH
13429 UNBLOCK_INPUT;
13430
7a13e894
RS
13431 return dpyinfo;
13432}
13433\f
13434/* Get rid of display DPYINFO, assuming all frames are already gone,
13435 and without sending any more commands to the X server. */
dc6f92b8 13436
7a13e894
RS
13437void
13438x_delete_display (dpyinfo)
13439 struct x_display_info *dpyinfo;
13440{
13441 delete_keyboard_wait_descriptor (dpyinfo->connection);
13442
13443 /* Discard this display from x_display_name_list and x_display_list.
13444 We can't use Fdelq because that can quit. */
13445 if (! NILP (x_display_name_list)
8e713be6
KR
13446 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
13447 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
13448 else
13449 {
13450 Lisp_Object tail;
13451
13452 tail = x_display_name_list;
8e713be6 13453 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 13454 {
bffcfca9 13455 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 13456 {
8e713be6 13457 XCDR (tail) = XCDR (XCDR (tail));
7a13e894
RS
13458 break;
13459 }
8e713be6 13460 tail = XCDR (tail);
7a13e894
RS
13461 }
13462 }
13463
9bda743f
GM
13464 if (next_noop_dpyinfo == dpyinfo)
13465 next_noop_dpyinfo = dpyinfo->next;
13466
7a13e894
RS
13467 if (x_display_list == dpyinfo)
13468 x_display_list = dpyinfo->next;
7f9c7f94
RS
13469 else
13470 {
13471 struct x_display_info *tail;
7a13e894 13472
7f9c7f94
RS
13473 for (tail = x_display_list; tail; tail = tail->next)
13474 if (tail->next == dpyinfo)
13475 tail->next = tail->next->next;
13476 }
7a13e894 13477
0d777288
RS
13478#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
13479#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
13480 XrmDestroyDatabase (dpyinfo->xrdb);
13481#endif
0d777288 13482#endif
29b38361
KH
13483#ifdef MULTI_KBOARD
13484 if (--dpyinfo->kboard->reference_count == 0)
39f79001 13485 delete_kboard (dpyinfo->kboard);
b9737ad3 13486#endif
f5d11644
GM
13487#ifdef HAVE_X_I18N
13488 if (dpyinfo->xim)
13489 xim_close_dpy (dpyinfo);
13490#endif
13491
b9737ad3
KH
13492 xfree (dpyinfo->font_table);
13493 xfree (dpyinfo->x_id_name);
13494 xfree (dpyinfo);
7a13e894
RS
13495}
13496\f
13497/* Set up use of X before we make the first connection. */
13498
06a2c219
GM
13499static struct redisplay_interface x_redisplay_interface =
13500{
13501 x_produce_glyphs,
13502 x_write_glyphs,
13503 x_insert_glyphs,
13504 x_clear_end_of_line,
13505 x_scroll_run,
13506 x_after_update_window_line,
13507 x_update_window_begin,
13508 x_update_window_end,
13509 XTcursor_to,
13510 x_flush,
71b8321e 13511 x_clear_mouse_face,
66ac4b0e
GM
13512 x_get_glyph_overhangs,
13513 x_fix_overlapping_area
06a2c219
GM
13514};
13515
dfcf069d 13516void
7a13e894
RS
13517x_initialize ()
13518{
06a2c219
GM
13519 rif = &x_redisplay_interface;
13520
13521 clear_frame_hook = x_clear_frame;
13522 ins_del_lines_hook = x_ins_del_lines;
13523 change_line_highlight_hook = x_change_line_highlight;
13524 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
13525 ring_bell_hook = XTring_bell;
13526 reset_terminal_modes_hook = XTreset_terminal_modes;
13527 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
13528 update_begin_hook = x_update_begin;
13529 update_end_hook = x_update_end;
dc6f92b8
JB
13530 set_terminal_window_hook = XTset_terminal_window;
13531 read_socket_hook = XTread_socket;
b8009dd1 13532 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 13533 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 13534 mouse_position_hook = XTmouse_position;
f451eb13 13535 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 13536 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
13537 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13538 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13539 redeem_scroll_bar_hook = XTredeem_scroll_bar;
13540 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 13541 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 13542
f676886a 13543 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
13544 char_ins_del_ok = 0; /* just as fast to write the line */
13545 line_ins_del_ok = 1; /* we'll just blt 'em */
13546 fast_clear_end_of_line = 1; /* X does this well */
58769bee 13547 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
13548 off the bottom */
13549 baud_rate = 19200;
13550
7a13e894 13551 x_noop_count = 0;
9ea173e8 13552 last_tool_bar_item = -1;
06a2c219
GM
13553 any_help_event_p = 0;
13554
b30b24cb
RS
13555 /* Try to use interrupt input; if we can't, then start polling. */
13556 Fset_input_mode (Qt, Qnil, Qt, Qnil);
13557
7f9c7f94
RS
13558#ifdef USE_X_TOOLKIT
13559 XtToolkitInitialize ();
13560 Xt_app_con = XtCreateApplicationContext ();
665881ad 13561 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
13562
13563 /* Install an asynchronous timer that processes Xt timeout events
13564 every 0.1s. This is necessary because some widget sets use
13565 timeouts internally, for example the LessTif menu bar, or the
13566 Xaw3d scroll bar. When Xt timouts aren't processed, these
13567 widgets don't behave normally. */
13568 {
13569 EMACS_TIME interval;
13570 EMACS_SET_SECS_USECS (interval, 0, 100000);
13571 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
13572 }
db74249b 13573#endif
bffcfca9 13574
db74249b 13575#if USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
13576 xaw3d_arrow_scroll = False;
13577 xaw3d_pick_top = True;
7f9c7f94
RS
13578#endif
13579
58769bee 13580 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 13581 original error handler. */
e99db5a1 13582 XSetErrorHandler (x_error_handler);
334208b7 13583 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 13584
06a2c219 13585 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
13586#ifdef SIGWINCH
13587 signal (SIGWINCH, SIG_DFL);
c118dd06 13588#endif /* ! defined (SIGWINCH) */
dc6f92b8 13589
92e2441b 13590 signal (SIGPIPE, x_connection_signal);
dc6f92b8 13591}
55123275 13592
06a2c219 13593
55123275
JB
13594void
13595syms_of_xterm ()
13596{
e99db5a1
RS
13597 staticpro (&x_error_message_string);
13598 x_error_message_string = Qnil;
13599
7a13e894
RS
13600 staticpro (&x_display_name_list);
13601 x_display_name_list = Qnil;
334208b7 13602
ab648270 13603 staticpro (&last_mouse_scroll_bar);
e53cb100 13604 last_mouse_scroll_bar = Qnil;
59e755be
KH
13605
13606 staticpro (&Qvendor_specific_keysyms);
13607 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
13608
13609 staticpro (&last_mouse_press_frame);
13610 last_mouse_press_frame = Qnil;
06a2c219 13611
06a2c219 13612 help_echo = Qnil;
be010514
GM
13613 staticpro (&help_echo);
13614 help_echo_object = Qnil;
13615 staticpro (&help_echo_object);
7cea38bc
GM
13616 help_echo_window = Qnil;
13617 staticpro (&help_echo_window);
06a2c219 13618 previous_help_echo = Qnil;
be010514
GM
13619 staticpro (&previous_help_echo);
13620 help_echo_pos = -1;
06a2c219
GM
13621
13622 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
13623 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
13624For example, if a block cursor is over a tab, it will be drawn as\n\
13625wide as that tab on the display.");
13626 x_stretch_cursor_p = 0;
13627
13628 DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
13629 "If not nil, Emacs uses toolkit scroll bars.");
13630#if USE_TOOLKIT_SCROLL_BARS
13631 x_toolkit_scroll_bars_p = 1;
13632#else
13633 x_toolkit_scroll_bars_p = 0;
13634#endif
13635
06a2c219
GM
13636 staticpro (&last_mouse_motion_frame);
13637 last_mouse_motion_frame = Qnil;
55123275 13638}
6cf0ae86
RS
13639
13640#endif /* not HAVE_X_WINDOWS */
06a2c219 13641