(note_mouse_highlight): If help-echo was found in an
[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 }
6525
6526 noverlays = sort_overlays (overlay_vec, noverlays, w);
6527
6528 /* Check mouse-face highlighting. */
6529 if (! (EQ (window, dpyinfo->mouse_face_window)
6530 && vpos >= dpyinfo->mouse_face_beg_row
6531 && vpos <= dpyinfo->mouse_face_end_row
6532 && (vpos > dpyinfo->mouse_face_beg_row
6533 || hpos >= dpyinfo->mouse_face_beg_col)
6534 && (vpos < dpyinfo->mouse_face_end_row
6535 || hpos < dpyinfo->mouse_face_end_col
6536 || dpyinfo->mouse_face_past_end)))
6537 {
6538 /* Clear the display of the old active region, if any. */
6539 clear_mouse_face (dpyinfo);
6540
6541 /* Find the highest priority overlay that has a mouse-face prop. */
6542 overlay = Qnil;
6543 for (i = 0; i < noverlays; i++)
6544 {
6545 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6546 if (!NILP (mouse_face))
6547 {
6548 overlay = overlay_vec[i];
6549 break;
6550 }
6551 }
6552
6553 /* If no overlay applies, get a text property. */
6554 if (NILP (overlay))
6555 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6556
6557 /* Handle the overlay case. */
6558 if (! NILP (overlay))
6559 {
6560 /* Find the range of text around this char that
6561 should be active. */
6562 Lisp_Object before, after;
6563 int ignore;
6564
6565 before = Foverlay_start (overlay);
6566 after = Foverlay_end (overlay);
6567 /* Record this as the current active region. */
6568 fast_find_position (w, XFASTINT (before),
6569 &dpyinfo->mouse_face_beg_col,
6570 &dpyinfo->mouse_face_beg_row,
6571 &dpyinfo->mouse_face_beg_x,
6572 &dpyinfo->mouse_face_beg_y);
6573 dpyinfo->mouse_face_past_end
6574 = !fast_find_position (w, XFASTINT (after),
6575 &dpyinfo->mouse_face_end_col,
6576 &dpyinfo->mouse_face_end_row,
6577 &dpyinfo->mouse_face_end_x,
6578 &dpyinfo->mouse_face_end_y);
6579 dpyinfo->mouse_face_window = window;
6580 dpyinfo->mouse_face_face_id
6581 = face_at_buffer_position (w, pos, 0, 0,
6582 &ignore, pos + 1, 1);
6583
6584 /* Display it as active. */
6585 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6586 }
6587 /* Handle the text property case. */
6588 else if (! NILP (mouse_face))
6589 {
6590 /* Find the range of text around this char that
6591 should be active. */
6592 Lisp_Object before, after, beginning, end;
6593 int ignore;
6594
6595 beginning = Fmarker_position (w->start);
6596 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
6597 - XFASTINT (w->window_end_pos)));
6598 before
6599 = Fprevious_single_property_change (make_number (pos + 1),
6600 Qmouse_face,
6601 w->buffer, beginning);
6602 after
6603 = Fnext_single_property_change (position, Qmouse_face,
6604 w->buffer, end);
6605 /* Record this as the current active region. */
6606 fast_find_position (w, XFASTINT (before),
6607 &dpyinfo->mouse_face_beg_col,
6608 &dpyinfo->mouse_face_beg_row,
6609 &dpyinfo->mouse_face_beg_x,
6610 &dpyinfo->mouse_face_beg_y);
6611 dpyinfo->mouse_face_past_end
6612 = !fast_find_position (w, XFASTINT (after),
6613 &dpyinfo->mouse_face_end_col,
6614 &dpyinfo->mouse_face_end_row,
6615 &dpyinfo->mouse_face_end_x,
6616 &dpyinfo->mouse_face_end_y);
6617 dpyinfo->mouse_face_window = window;
6618 dpyinfo->mouse_face_face_id
6619 = face_at_buffer_position (w, pos, 0, 0,
6620 &ignore, pos + 1, 1);
6621
6622 /* Display it as active. */
6623 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6624 }
6625 }
6626
6627 /* Look for a `help-echo' property. */
6628 {
743934db 6629 Lisp_Object help, overlay;
06a2c219
GM
6630
6631 /* Check overlays first. */
6632 help = Qnil;
b7e80413 6633 for (i = 0; i < noverlays && NILP (help); ++i)
743934db
GM
6634 {
6635 overlay = overlay_vec[i];
6636 help = Foverlay_get (overlay, Qhelp_echo);
6637 }
be010514
GM
6638
6639 if (!NILP (help))
6640 {
6641 help_echo = help;
7cea38bc 6642 help_echo_window = window;
743934db 6643 help_echo_object = overlay;
be010514
GM
6644 help_echo_pos = pos;
6645 }
6646 else
6647 {
6648 /* Try text properties. */
6649 if ((STRINGP (glyph->object)
06a2c219
GM
6650 && glyph->charpos >= 0
6651 && glyph->charpos < XSTRING (glyph->object)->size)
6652 || (BUFFERP (glyph->object)
6653 && glyph->charpos >= BEGV
be010514
GM
6654 && glyph->charpos < ZV))
6655 help = Fget_text_property (make_number (glyph->charpos),
6656 Qhelp_echo, glyph->object);
06a2c219 6657
be010514
GM
6658 if (!NILP (help))
6659 {
6660 help_echo = help;
7cea38bc 6661 help_echo_window = window;
be010514
GM
6662 help_echo_object = glyph->object;
6663 help_echo_pos = glyph->charpos;
6664 }
6665 }
06a2c219
GM
6666 }
6667
6668 BEGV = obegv;
6669 ZV = ozv;
6670 current_buffer = obuf;
6671 }
6672 }
6673}
6674
6675static void
6676redo_mouse_highlight ()
6677{
6678 if (!NILP (last_mouse_motion_frame)
6679 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
6680 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
6681 last_mouse_motion_event.x,
6682 last_mouse_motion_event.y);
6683}
6684
6685
6686\f
6687/***********************************************************************
9ea173e8 6688 Tool-bars
06a2c219
GM
6689 ***********************************************************************/
6690
9ea173e8
GM
6691static int x_tool_bar_item P_ ((struct frame *, int, int,
6692 struct glyph **, int *, int *, int *));
06a2c219 6693
9ea173e8 6694/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
6695 or -1. */
6696
9ea173e8 6697static int last_tool_bar_item;
06a2c219
GM
6698
6699
9ea173e8
GM
6700/* Get information about the tool-bar item at position X/Y on frame F.
6701 Return in *GLYPH a pointer to the glyph of the tool-bar item in
6702 the current matrix of the tool-bar window of F, or NULL if not
6703 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
6704 item in F->current_tool_bar_items. Value is
06a2c219 6705
9ea173e8 6706 -1 if X/Y is not on a tool-bar item
06a2c219
GM
6707 0 if X/Y is on the same item that was highlighted before.
6708 1 otherwise. */
6709
6710static int
9ea173e8 6711x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
6712 struct frame *f;
6713 int x, y;
6714 struct glyph **glyph;
6715 int *hpos, *vpos, *prop_idx;
6716{
6717 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6718 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6719 int area;
6720
6721 /* Find the glyph under X/Y. */
6722 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
6723 if (*glyph == NULL)
6724 return -1;
6725
9ea173e8
GM
6726 /* Get the start of this tool-bar item's properties in
6727 f->current_tool_bar_items. */
6728 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
6729 return -1;
6730
6731 /* Is mouse on the highlighted item? */
9ea173e8 6732 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
6733 && *vpos >= dpyinfo->mouse_face_beg_row
6734 && *vpos <= dpyinfo->mouse_face_end_row
6735 && (*vpos > dpyinfo->mouse_face_beg_row
6736 || *hpos >= dpyinfo->mouse_face_beg_col)
6737 && (*vpos < dpyinfo->mouse_face_end_row
6738 || *hpos < dpyinfo->mouse_face_end_col
6739 || dpyinfo->mouse_face_past_end))
6740 return 0;
6741
6742 return 1;
6743}
6744
6745
9ea173e8 6746/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
6747 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
6748 or ButtonRelase. */
6749
6750static void
9ea173e8 6751x_handle_tool_bar_click (f, button_event)
06a2c219
GM
6752 struct frame *f;
6753 XButtonEvent *button_event;
6754{
6755 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6756 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6757 int hpos, vpos, prop_idx;
6758 struct glyph *glyph;
6759 Lisp_Object enabled_p;
6760 int x = button_event->x;
6761 int y = button_event->y;
6762
9ea173e8 6763 /* If not on the highlighted tool-bar item, return. */
06a2c219 6764 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 6765 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
6766 return;
6767
6768 /* If item is disabled, do nothing. */
9ea173e8
GM
6769 enabled_p = (XVECTOR (f->current_tool_bar_items)
6770 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6771 if (NILP (enabled_p))
6772 return;
6773
6774 if (button_event->type == ButtonPress)
6775 {
6776 /* Show item in pressed state. */
6777 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
6778 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 6779 last_tool_bar_item = prop_idx;
06a2c219
GM
6780 }
6781 else
6782 {
6783 Lisp_Object key, frame;
6784 struct input_event event;
6785
6786 /* Show item in released state. */
6787 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
6788 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
6789
9ea173e8
GM
6790 key = (XVECTOR (f->current_tool_bar_items)
6791 ->contents[prop_idx + TOOL_BAR_ITEM_KEY]);
06a2c219
GM
6792
6793 XSETFRAME (frame, f);
9ea173e8 6794 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
6795 event.frame_or_window = frame;
6796 event.arg = frame;
06a2c219
GM
6797 kbd_buffer_store_event (&event);
6798
9ea173e8 6799 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
6800 event.frame_or_window = frame;
6801 event.arg = key;
06a2c219
GM
6802 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6803 button_event->state);
6804 kbd_buffer_store_event (&event);
9ea173e8 6805 last_tool_bar_item = -1;
06a2c219
GM
6806 }
6807}
6808
6809
9ea173e8
GM
6810/* Possibly highlight a tool-bar item on frame F when mouse moves to
6811 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
6812 note_mouse_highlight. */
6813
6814static void
9ea173e8 6815note_tool_bar_highlight (f, x, y)
06a2c219
GM
6816 struct frame *f;
6817 int x, y;
6818{
9ea173e8 6819 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
6820 struct window *w = XWINDOW (window);
6821 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6822 int hpos, vpos;
6823 struct glyph *glyph;
6824 struct glyph_row *row;
5c187dee 6825 int i;
06a2c219
GM
6826 Lisp_Object enabled_p;
6827 int prop_idx;
6828 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
5c187dee 6829 int mouse_down_p, rc;
06a2c219
GM
6830
6831 /* Function note_mouse_highlight is called with negative x(y
6832 values when mouse moves outside of the frame. */
6833 if (x <= 0 || y <= 0)
6834 {
6835 clear_mouse_face (dpyinfo);
6836 return;
6837 }
6838
9ea173e8 6839 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
6840 if (rc < 0)
6841 {
9ea173e8 6842 /* Not on tool-bar item. */
06a2c219
GM
6843 clear_mouse_face (dpyinfo);
6844 return;
6845 }
6846 else if (rc == 0)
9ea173e8 6847 /* On same tool-bar item as before. */
06a2c219 6848 goto set_help_echo;
b8009dd1 6849
06a2c219
GM
6850 clear_mouse_face (dpyinfo);
6851
9ea173e8 6852 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
6853 mouse_down_p = (dpyinfo->grabbed
6854 && f == last_mouse_frame
6855 && FRAME_LIVE_P (f));
6856 if (mouse_down_p
9ea173e8 6857 && last_tool_bar_item != prop_idx)
06a2c219
GM
6858 return;
6859
6860 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
6861 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
6862
9ea173e8
GM
6863 /* If tool-bar item is not enabled, don't highlight it. */
6864 enabled_p = (XVECTOR (f->current_tool_bar_items)
6865 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6866 if (!NILP (enabled_p))
6867 {
6868 /* Compute the x-position of the glyph. In front and past the
6869 image is a space. We include this is the highlighted area. */
6870 row = MATRIX_ROW (w->current_matrix, vpos);
6871 for (i = x = 0; i < hpos; ++i)
6872 x += row->glyphs[TEXT_AREA][i].pixel_width;
6873
6874 /* Record this as the current active region. */
6875 dpyinfo->mouse_face_beg_col = hpos;
6876 dpyinfo->mouse_face_beg_row = vpos;
6877 dpyinfo->mouse_face_beg_x = x;
6878 dpyinfo->mouse_face_beg_y = row->y;
6879 dpyinfo->mouse_face_past_end = 0;
6880
6881 dpyinfo->mouse_face_end_col = hpos + 1;
6882 dpyinfo->mouse_face_end_row = vpos;
6883 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
6884 dpyinfo->mouse_face_end_y = row->y;
6885 dpyinfo->mouse_face_window = window;
9ea173e8 6886 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
6887
6888 /* Display it as active. */
6889 show_mouse_face (dpyinfo, draw);
6890 dpyinfo->mouse_face_image_state = draw;
b8009dd1 6891 }
06a2c219
GM
6892
6893 set_help_echo:
6894
9ea173e8 6895 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 6896 XTread_socket does the rest. */
7cea38bc 6897 help_echo_object = help_echo_window = Qnil;
be010514 6898 help_echo_pos = -1;
9ea173e8
GM
6899 help_echo = (XVECTOR (f->current_tool_bar_items)
6900 ->contents[prop_idx + TOOL_BAR_ITEM_HELP]);
b7e80413 6901 if (NILP (help_echo))
9ea173e8
GM
6902 help_echo = (XVECTOR (f->current_tool_bar_items)
6903 ->contents[prop_idx + TOOL_BAR_ITEM_CAPTION]);
b8009dd1 6904}
4d73d038 6905
06a2c219
GM
6906
6907\f
6908/* Find the glyph matrix position of buffer position POS in window W.
6909 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
6910 current glyphs must be up to date. If POS is above window start
6911 return (0, 0, 0, 0). If POS is after end of W, return end of
6912 last line in W. */
b8009dd1
RS
6913
6914static int
06a2c219
GM
6915fast_find_position (w, pos, hpos, vpos, x, y)
6916 struct window *w;
b8009dd1 6917 int pos;
06a2c219 6918 int *hpos, *vpos, *x, *y;
b8009dd1 6919{
b8009dd1 6920 int i;
bf1c0ba1 6921 int lastcol;
06a2c219
GM
6922 int maybe_next_line_p = 0;
6923 int line_start_position;
6924 int yb = window_text_bottom_y (w);
6925 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
6926 struct glyph_row *best_row = row;
6927 int row_vpos = 0, best_row_vpos = 0;
6928 int current_x;
6929
6930 while (row->y < yb)
b8009dd1 6931 {
06a2c219
GM
6932 if (row->used[TEXT_AREA])
6933 line_start_position = row->glyphs[TEXT_AREA]->charpos;
6934 else
6935 line_start_position = 0;
6936
6937 if (line_start_position > pos)
b8009dd1 6938 break;
77b68646
RS
6939 /* If the position sought is the end of the buffer,
6940 don't include the blank lines at the bottom of the window. */
06a2c219
GM
6941 else if (line_start_position == pos
6942 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 6943 {
06a2c219 6944 maybe_next_line_p = 1;
77b68646
RS
6945 break;
6946 }
06a2c219
GM
6947 else if (line_start_position > 0)
6948 {
6949 best_row = row;
6950 best_row_vpos = row_vpos;
6951 }
4b0bb6f3
GM
6952
6953 if (row->y + row->height >= yb)
6954 break;
06a2c219
GM
6955
6956 ++row;
6957 ++row_vpos;
b8009dd1 6958 }
06a2c219
GM
6959
6960 /* Find the right column within BEST_ROW. */
6961 lastcol = 0;
6962 current_x = best_row->x;
6963 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 6964 {
06a2c219
GM
6965 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
6966 int charpos;
6967
6968 charpos = glyph->charpos;
6969 if (charpos == pos)
bf1c0ba1 6970 {
06a2c219
GM
6971 *hpos = i;
6972 *vpos = best_row_vpos;
6973 *x = current_x;
6974 *y = best_row->y;
bf1c0ba1
RS
6975 return 1;
6976 }
06a2c219 6977 else if (charpos > pos)
4d73d038 6978 break;
06a2c219
GM
6979 else if (charpos > 0)
6980 lastcol = i;
6981
6982 current_x += glyph->pixel_width;
bf1c0ba1 6983 }
b8009dd1 6984
77b68646
RS
6985 /* If we're looking for the end of the buffer,
6986 and we didn't find it in the line we scanned,
6987 use the start of the following line. */
06a2c219 6988 if (maybe_next_line_p)
77b68646 6989 {
06a2c219
GM
6990 ++best_row;
6991 ++best_row_vpos;
6992 lastcol = 0;
6993 current_x = best_row->x;
77b68646
RS
6994 }
6995
06a2c219
GM
6996 *vpos = best_row_vpos;
6997 *hpos = lastcol + 1;
6998 *x = current_x;
6999 *y = best_row->y;
b8009dd1
RS
7000 return 0;
7001}
7002
06a2c219 7003
b8009dd1
RS
7004/* Display the active region described by mouse_face_*
7005 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7006
7007static void
06a2c219 7008show_mouse_face (dpyinfo, draw)
7a13e894 7009 struct x_display_info *dpyinfo;
06a2c219 7010 enum draw_glyphs_face draw;
b8009dd1 7011{
7a13e894 7012 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7013 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 7014 int i;
06a2c219
GM
7015 int cursor_off_p = 0;
7016 struct cursor_pos saved_cursor;
7017
7018 saved_cursor = output_cursor;
7019
7020 /* If window is in the process of being destroyed, don't bother
7021 to do anything. */
7022 if (w->current_matrix == NULL)
7023 goto set_x_cursor;
7024
7025 /* Recognize when we are called to operate on rows that don't exist
7026 anymore. This can happen when a window is split. */
7027 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
7028 goto set_x_cursor;
7029
7030 set_output_cursor (&w->phys_cursor);
7031
7032 /* Note that mouse_face_beg_row etc. are window relative. */
7033 for (i = dpyinfo->mouse_face_beg_row;
7034 i <= dpyinfo->mouse_face_end_row;
7035 i++)
7036 {
7037 int start_hpos, end_hpos, start_x;
7038 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
7039
7040 /* Don't do anything if row doesn't have valid contents. */
7041 if (!row->enabled_p)
7042 continue;
7043
7044 /* For all but the first row, the highlight starts at column 0. */
7045 if (i == dpyinfo->mouse_face_beg_row)
7046 {
7047 start_hpos = dpyinfo->mouse_face_beg_col;
7048 start_x = dpyinfo->mouse_face_beg_x;
7049 }
7050 else
7051 {
7052 start_hpos = 0;
7053 start_x = 0;
7054 }
7055
7056 if (i == dpyinfo->mouse_face_end_row)
7057 end_hpos = dpyinfo->mouse_face_end_col;
7058 else
7059 end_hpos = row->used[TEXT_AREA];
7060
7061 /* If the cursor's in the text we are about to rewrite, turn the
7062 cursor off. */
7063 if (!w->pseudo_window_p
7064 && i == output_cursor.vpos
7065 && output_cursor.hpos >= start_hpos - 1
7066 && output_cursor.hpos <= end_hpos)
514e4681 7067 {
06a2c219
GM
7068 x_update_window_cursor (w, 0);
7069 cursor_off_p = 1;
514e4681 7070 }
b8009dd1 7071
06a2c219 7072 if (end_hpos > start_hpos)
64f26cf5
GM
7073 {
7074 row->mouse_face_p = draw == DRAW_MOUSE_FACE;
7075 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7076 start_hpos, end_hpos, draw, NULL, NULL, 0);
7077 }
b8009dd1
RS
7078 }
7079
514e4681 7080 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
7081 if (cursor_off_p)
7082 x_display_cursor (w, 1,
7083 output_cursor.hpos, output_cursor.vpos,
7084 output_cursor.x, output_cursor.y);
2729a2b5 7085
06a2c219 7086 output_cursor = saved_cursor;
fb3b7de5 7087
06a2c219
GM
7088 set_x_cursor:
7089
7090 /* Change the mouse cursor. */
7091 if (draw == DRAW_NORMAL_TEXT)
7092 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7093 f->output_data.x->text_cursor);
7094 else if (draw == DRAW_MOUSE_FACE)
334208b7 7095 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7096 f->output_data.x->cross_cursor);
27ead1d5 7097 else
334208b7 7098 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7099 f->output_data.x->nontext_cursor);
b8009dd1
RS
7100}
7101
7102/* Clear out the mouse-highlighted active region.
06a2c219 7103 Redraw it un-highlighted first. */
b8009dd1 7104
06a2c219 7105void
7a13e894
RS
7106clear_mouse_face (dpyinfo)
7107 struct x_display_info *dpyinfo;
b8009dd1 7108{
06a2c219
GM
7109 if (tip_frame)
7110 return;
7111
7a13e894 7112 if (! NILP (dpyinfo->mouse_face_window))
06a2c219 7113 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
b8009dd1 7114
7a13e894
RS
7115 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7116 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7117 dpyinfo->mouse_face_window = Qnil;
b8009dd1 7118}
e687d06e 7119
71b8321e
GM
7120
7121/* Clear any mouse-face on window W. This function is part of the
7122 redisplay interface, and is called from try_window_id and similar
7123 functions to ensure the mouse-highlight is off. */
7124
7125static void
7126x_clear_mouse_face (w)
7127 struct window *w;
7128{
7129 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7130 Lisp_Object window;
7131
7132 XSETWINDOW (window, w);
7133 if (EQ (window, dpyinfo->mouse_face_window))
7134 clear_mouse_face (dpyinfo);
7135}
7136
7137
e687d06e
RS
7138/* Just discard the mouse face information for frame F, if any.
7139 This is used when the size of F is changed. */
7140
dfcf069d 7141void
e687d06e
RS
7142cancel_mouse_face (f)
7143 FRAME_PTR f;
7144{
7145 Lisp_Object window;
7146 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7147
7148 window = dpyinfo->mouse_face_window;
7149 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7150 {
7151 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7152 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7153 dpyinfo->mouse_face_window = Qnil;
7154 }
7155}
b8009dd1 7156\f
ab648270
JB
7157static struct scroll_bar *x_window_to_scroll_bar ();
7158static void x_scroll_bar_report_motion ();
12ba150f 7159
90e65f07 7160/* Return the current position of the mouse.
2d7fc7e8 7161 *fp should be a frame which indicates which display to ask about.
90e65f07 7162
2d7fc7e8 7163 If the mouse movement started in a scroll bar, set *fp, *bar_window,
ab648270 7164 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 7165 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 7166 position on the scroll bar.
12ba150f 7167
2d7fc7e8 7168 If the mouse movement started elsewhere, set *fp to the frame the
12ba150f
JB
7169 mouse is on, *bar_window to nil, and *x and *y to the character cell
7170 the mouse is over.
7171
06a2c219 7172 Set *time to the server time-stamp for the time at which the mouse
12ba150f
JB
7173 was at this position.
7174
a135645a
RS
7175 Don't store anything if we don't have a valid set of values to report.
7176
90e65f07 7177 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7178 movement. */
90e65f07
JB
7179
7180static void
1cf412ec 7181XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7182 FRAME_PTR *fp;
1cf412ec 7183 int insist;
12ba150f 7184 Lisp_Object *bar_window;
ab648270 7185 enum scroll_bar_part *part;
90e65f07 7186 Lisp_Object *x, *y;
e5d77022 7187 unsigned long *time;
90e65f07 7188{
a135645a
RS
7189 FRAME_PTR f1;
7190
90e65f07
JB
7191 BLOCK_INPUT;
7192
8bcee03e 7193 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7194 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7195 else
7196 {
12ba150f
JB
7197 Window root;
7198 int root_x, root_y;
90e65f07 7199
12ba150f
JB
7200 Window dummy_window;
7201 int dummy;
7202
39d8bb4d
KH
7203 Lisp_Object frame, tail;
7204
7205 /* Clear the mouse-moved flag for every frame on this display. */
7206 FOR_EACH_FRAME (tail, frame)
7207 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7208 XFRAME (frame)->mouse_moved = 0;
7209
ab648270 7210 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7211
7212 /* Figure out which root window we're on. */
334208b7
RS
7213 XQueryPointer (FRAME_X_DISPLAY (*fp),
7214 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7215
7216 /* The root window which contains the pointer. */
7217 &root,
7218
7219 /* Trash which we can't trust if the pointer is on
7220 a different screen. */
7221 &dummy_window,
7222
7223 /* The position on that root window. */
58769bee 7224 &root_x, &root_y,
12ba150f
JB
7225
7226 /* More trash we can't trust. */
7227 &dummy, &dummy,
7228
7229 /* Modifier keys and pointer buttons, about which
7230 we don't care. */
7231 (unsigned int *) &dummy);
7232
7233 /* Now we have a position on the root; find the innermost window
7234 containing the pointer. */
7235 {
7236 Window win, child;
7237 int win_x, win_y;
06a2c219 7238 int parent_x = 0, parent_y = 0;
e99db5a1 7239 int count;
12ba150f
JB
7240
7241 win = root;
69388238 7242
2d7fc7e8
RS
7243 /* XTranslateCoordinates can get errors if the window
7244 structure is changing at the same time this function
7245 is running. So at least we must not crash from them. */
7246
e99db5a1 7247 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 7248
334208b7 7249 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 7250 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 7251 {
69388238
RS
7252 /* If mouse was grabbed on a frame, give coords for that frame
7253 even if the mouse is now outside it. */
334208b7 7254 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 7255
12ba150f 7256 /* From-window, to-window. */
69388238 7257 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
7258
7259 /* From-position, to-position. */
7260 root_x, root_y, &win_x, &win_y,
7261
7262 /* Child of win. */
7263 &child);
69388238
RS
7264 f1 = last_mouse_frame;
7265 }
7266 else
7267 {
7268 while (1)
7269 {
334208b7 7270 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 7271
69388238
RS
7272 /* From-window, to-window. */
7273 root, win,
12ba150f 7274
69388238
RS
7275 /* From-position, to-position. */
7276 root_x, root_y, &win_x, &win_y,
7277
7278 /* Child of win. */
7279 &child);
7280
9af3143a 7281 if (child == None || child == win)
69388238
RS
7282 break;
7283
7284 win = child;
7285 parent_x = win_x;
7286 parent_y = win_y;
7287 }
12ba150f 7288
69388238
RS
7289 /* Now we know that:
7290 win is the innermost window containing the pointer
7291 (XTC says it has no child containing the pointer),
7292 win_x and win_y are the pointer's position in it
7293 (XTC did this the last time through), and
7294 parent_x and parent_y are the pointer's position in win's parent.
7295 (They are what win_x and win_y were when win was child.
7296 If win is the root window, it has no parent, and
7297 parent_{x,y} are invalid, but that's okay, because we'll
7298 never use them in that case.) */
7299
7300 /* Is win one of our frames? */
19126e11 7301 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
69388238 7302 }
58769bee 7303
2d7fc7e8
RS
7304 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
7305 f1 = 0;
7306
e99db5a1 7307 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 7308
ab648270 7309 /* If not, is it one of our scroll bars? */
a135645a 7310 if (! f1)
12ba150f 7311 {
ab648270 7312 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
7313
7314 if (bar)
7315 {
a135645a 7316 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
7317 win_x = parent_x;
7318 win_y = parent_y;
7319 }
7320 }
90e65f07 7321
8bcee03e 7322 if (f1 == 0 && insist > 0)
b86bd3dd 7323 f1 = SELECTED_FRAME ();
1cf412ec 7324
a135645a 7325 if (f1)
12ba150f 7326 {
06a2c219
GM
7327 /* Ok, we found a frame. Store all the values.
7328 last_mouse_glyph is a rectangle used to reduce the
7329 generation of mouse events. To not miss any motion
7330 events, we must divide the frame into rectangles of the
7331 size of the smallest character that could be displayed
7332 on it, i.e. into the same rectangles that matrices on
7333 the frame are divided into. */
7334
7335#if OLD_REDISPLAY_CODE
2b5c9e71 7336 int ignore1, ignore2;
2b5c9e71 7337 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
334208b7 7338 &last_mouse_glyph,
1cf412ec
RS
7339 FRAME_X_DISPLAY_INFO (f1)->grabbed
7340 || insist);
06a2c219
GM
7341#else
7342 {
7343 int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
7344 int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
7345 int x = win_x;
7346 int y = win_y;
7347
7348 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
7349 round down even for negative values. */
7350 if (x < 0)
7351 x -= width - 1;
7352 if (y < 0)
7353 y -= height - 1;
7354
7355 last_mouse_glyph.width = width;
7356 last_mouse_glyph.height = height;
7357 last_mouse_glyph.x = (x + width - 1) / width * width;
7358 last_mouse_glyph.y = (y + height - 1) / height * height;
7359 }
7360#endif
12ba150f
JB
7361
7362 *bar_window = Qnil;
7363 *part = 0;
334208b7 7364 *fp = f1;
e0c1aef2
KH
7365 XSETINT (*x, win_x);
7366 XSETINT (*y, win_y);
12ba150f
JB
7367 *time = last_mouse_movement_time;
7368 }
7369 }
7370 }
90e65f07
JB
7371
7372 UNBLOCK_INPUT;
7373}
f451eb13 7374
06a2c219 7375
06a2c219 7376#ifdef USE_X_TOOLKIT
bffcfca9
GM
7377
7378/* Atimer callback function for TIMER. Called every 0.1s to process
7379 Xt timeouts, if needed. We must avoid calling XtAppPending as
7380 much as possible because that function does an implicit XFlush
7381 that slows us down. */
7382
7383static void
7384x_process_timeouts (timer)
7385 struct atimer *timer;
7386{
7387 if (toolkit_scroll_bar_interaction || popup_activated_flag)
7388 {
7389 BLOCK_INPUT;
7390 while (XtAppPending (Xt_app_con) & XtIMTimer)
7391 XtAppProcessEvent (Xt_app_con, XtIMTimer);
7392 UNBLOCK_INPUT;
7393 }
06a2c219
GM
7394}
7395
bffcfca9 7396#endif /* USE_X_TOOLKIT */
06a2c219
GM
7397
7398\f
7399/* Scroll bar support. */
7400
7401/* Given an X window ID, find the struct scroll_bar which manages it.
7402 This can be called in GC, so we have to make sure to strip off mark
7403 bits. */
bffcfca9 7404
06a2c219
GM
7405static struct scroll_bar *
7406x_window_to_scroll_bar (window_id)
7407 Window window_id;
7408{
7409 Lisp_Object tail;
7410
7411 for (tail = Vframe_list;
7412 XGCTYPE (tail) == Lisp_Cons;
8e713be6 7413 tail = XCDR (tail))
06a2c219
GM
7414 {
7415 Lisp_Object frame, bar, condemned;
7416
8e713be6 7417 frame = XCAR (tail);
06a2c219
GM
7418 /* All elements of Vframe_list should be frames. */
7419 if (! GC_FRAMEP (frame))
7420 abort ();
7421
7422 /* Scan this frame's scroll bar list for a scroll bar with the
7423 right window ID. */
7424 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
7425 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
7426 /* This trick allows us to search both the ordinary and
7427 condemned scroll bar lists with one loop. */
7428 ! GC_NILP (bar) || (bar = condemned,
7429 condemned = Qnil,
7430 ! GC_NILP (bar));
7431 bar = XSCROLL_BAR (bar)->next)
7432 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
7433 return XSCROLL_BAR (bar);
7434 }
7435
7436 return 0;
7437}
7438
7439
7440\f
7441/************************************************************************
7442 Toolkit scroll bars
7443 ************************************************************************/
7444
7445#if USE_TOOLKIT_SCROLL_BARS
7446
7447static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
7448static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
7449static void x_create_toolkit_scroll_bar P_ ((struct frame *,
7450 struct scroll_bar *));
7451static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
7452 int, int, int));
7453
7454
7455/* Id of action hook installed for scroll bars. */
7456
7457static XtActionHookId action_hook_id;
7458
7459/* Lisp window being scrolled. Set when starting to interact with
7460 a toolkit scroll bar, reset to nil when ending the interaction. */
7461
7462static Lisp_Object window_being_scrolled;
7463
7464/* Last scroll bar part sent in xm_scroll_callback. */
7465
7466static int last_scroll_bar_part;
7467
ec18280f
SM
7468/* Whether this is an Xaw with arrow-scrollbars. This should imply
7469 that movements of 1/20 of the screen size are mapped to up/down. */
7470
7471static Boolean xaw3d_arrow_scroll;
7472
7473/* Whether the drag scrolling maintains the mouse at the top of the
7474 thumb. If not, resizing the thumb needs to be done more carefully
7475 to avoid jerkyness. */
7476
7477static Boolean xaw3d_pick_top;
7478
06a2c219
GM
7479
7480/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 7481 bars are used.. The hook is responsible for detecting when
06a2c219
GM
7482 the user ends an interaction with the scroll bar, and generates
7483 a `end-scroll' scroll_bar_click' event if so. */
7484
7485static void
7486xt_action_hook (widget, client_data, action_name, event, params,
7487 num_params)
7488 Widget widget;
7489 XtPointer client_data;
7490 String action_name;
7491 XEvent *event;
7492 String *params;
7493 Cardinal *num_params;
7494{
7495 int scroll_bar_p;
7496 char *end_action;
7497
7498#ifdef USE_MOTIF
7499 scroll_bar_p = XmIsScrollBar (widget);
7500 end_action = "Release";
ec18280f 7501#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7502 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
7503 end_action = "EndScroll";
ec18280f 7504#endif /* USE_MOTIF */
06a2c219 7505
06a2c219
GM
7506 if (scroll_bar_p
7507 && strcmp (action_name, end_action) == 0
7508 && WINDOWP (window_being_scrolled))
7509 {
7510 struct window *w;
7511
7512 x_send_scroll_bar_event (window_being_scrolled,
7513 scroll_bar_end_scroll, 0, 0);
7514 w = XWINDOW (window_being_scrolled);
7515 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
7516 window_being_scrolled = Qnil;
7517 last_scroll_bar_part = -1;
bffcfca9
GM
7518
7519 /* Xt timeouts no longer needed. */
7520 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
7521 }
7522}
7523
7524
7525/* Send a client message with message type Xatom_Scrollbar for a
7526 scroll action to the frame of WINDOW. PART is a value identifying
7527 the part of the scroll bar that was clicked on. PORTION is the
7528 amount to scroll of a whole of WHOLE. */
7529
7530static void
7531x_send_scroll_bar_event (window, part, portion, whole)
7532 Lisp_Object window;
7533 int part, portion, whole;
7534{
7535 XEvent event;
7536 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
7537 struct frame *f = XFRAME (XWINDOW (window)->frame);
7538
7539 /* Construct a ClientMessage event to send to the frame. */
7540 ev->type = ClientMessage;
7541 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
7542 ev->display = FRAME_X_DISPLAY (f);
7543 ev->window = FRAME_X_WINDOW (f);
7544 ev->format = 32;
52e386c2 7545 ev->data.l[0] = (long) XFASTINT (window);
06a2c219
GM
7546 ev->data.l[1] = (long) part;
7547 ev->data.l[2] = (long) 0;
7548 ev->data.l[3] = (long) portion;
7549 ev->data.l[4] = (long) whole;
7550
bffcfca9
GM
7551 /* Make Xt timeouts work while the scroll bar is active. */
7552 toolkit_scroll_bar_interaction = 1;
7553
06a2c219
GM
7554 /* Setting the event mask to zero means that the message will
7555 be sent to the client that created the window, and if that
7556 window no longer exists, no event will be sent. */
7557 BLOCK_INPUT;
7558 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
7559 UNBLOCK_INPUT;
7560}
7561
7562
7563/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
7564 in *IEVENT. */
7565
7566static void
7567x_scroll_bar_to_input_event (event, ievent)
7568 XEvent *event;
7569 struct input_event *ievent;
7570{
7571 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
7572 Lisp_Object window;
7573 struct frame *f;
7574
7575 XSETFASTINT (window, ev->data.l[0]);
7576 f = XFRAME (XWINDOW (window)->frame);
06a2c219
GM
7577
7578 ievent->kind = scroll_bar_click;
7579 ievent->frame_or_window = window;
0f8aabe9 7580 ievent->arg = Qnil;
06a2c219
GM
7581 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
7582 ievent->part = ev->data.l[1];
7583 ievent->code = ev->data.l[2];
7584 ievent->x = make_number ((int) ev->data.l[3]);
7585 ievent->y = make_number ((int) ev->data.l[4]);
7586 ievent->modifiers = 0;
7587}
7588
7589
7590#ifdef USE_MOTIF
7591
7592/* Minimum and maximum values used for Motif scroll bars. */
7593
7594#define XM_SB_MIN 1
7595#define XM_SB_MAX 10000000
7596#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
7597
7598
7599/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
7600 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
7601 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
7602
7603static void
7604xm_scroll_callback (widget, client_data, call_data)
7605 Widget widget;
7606 XtPointer client_data, call_data;
7607{
7608 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7609 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
7610 double percent;
7611 int part = -1, whole = 0, portion = 0;
7612
7613 switch (cs->reason)
7614 {
7615 case XmCR_DECREMENT:
7616 bar->dragging = Qnil;
7617 part = scroll_bar_up_arrow;
7618 break;
7619
7620 case XmCR_INCREMENT:
7621 bar->dragging = Qnil;
7622 part = scroll_bar_down_arrow;
7623 break;
7624
7625 case XmCR_PAGE_DECREMENT:
7626 bar->dragging = Qnil;
7627 part = scroll_bar_above_handle;
7628 break;
7629
7630 case XmCR_PAGE_INCREMENT:
7631 bar->dragging = Qnil;
7632 part = scroll_bar_below_handle;
7633 break;
7634
7635 case XmCR_TO_TOP:
7636 bar->dragging = Qnil;
7637 part = scroll_bar_to_top;
7638 break;
7639
7640 case XmCR_TO_BOTTOM:
7641 bar->dragging = Qnil;
7642 part = scroll_bar_to_bottom;
7643 break;
7644
7645 case XmCR_DRAG:
7646 {
7647 int slider_size;
7648 int dragging_down_p = (INTEGERP (bar->dragging)
7649 && XINT (bar->dragging) <= cs->value);
7650
7651 /* Get the slider size. */
7652 BLOCK_INPUT;
7653 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
7654 UNBLOCK_INPUT;
7655
7656 /* At the max position of the scroll bar, do a line-wise
7657 movement. Without doing anything, the LessTif scroll bar
7658 calls us with the same cs->value again and again. If we
7659 want to make sure that we can reach the end of the buffer,
7660 we have to do something.
7661
7662 Implementation note: setting bar->dragging always to
7663 cs->value gives a smoother movement at the max position.
7664 Setting it to nil when doing line-wise movement gives
7665 a better slider behavior. */
7666
7667 if (cs->value + slider_size == XM_SB_MAX
7668 || (dragging_down_p
7669 && last_scroll_bar_part == scroll_bar_down_arrow))
7670 {
7671 part = scroll_bar_down_arrow;
7672 bar->dragging = Qnil;
7673 }
7674 else
7675 {
7676 whole = XM_SB_RANGE;
7677 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
7678 part = scroll_bar_handle;
7679 bar->dragging = make_number (cs->value);
7680 }
7681 }
7682 break;
7683
7684 case XmCR_VALUE_CHANGED:
7685 break;
7686 };
7687
7688 if (part >= 0)
7689 {
7690 window_being_scrolled = bar->window;
7691 last_scroll_bar_part = part;
7692 x_send_scroll_bar_event (bar->window, part, portion, whole);
7693 }
7694}
7695
7696
ec18280f 7697#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
7698
7699
ec18280f 7700/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
7701 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
7702 scroll bar struct. CALL_DATA is a pointer to a float saying where
7703 the thumb is. */
7704
7705static void
ec18280f 7706xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
7707 Widget widget;
7708 XtPointer client_data, call_data;
7709{
7710 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7711 float top = *(float *) call_data;
7712 float shown;
ec18280f
SM
7713 int whole, portion, height;
7714 int part;
06a2c219
GM
7715
7716 /* Get the size of the thumb, a value between 0 and 1. */
7717 BLOCK_INPUT;
ec18280f 7718 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
7719 UNBLOCK_INPUT;
7720
7721 whole = 10000000;
7722 portion = shown < 1 ? top * whole : 0;
06a2c219 7723
ec18280f
SM
7724 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
7725 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
7726 the bottom, so we force the scrolling whenever we see that we're
7727 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
7728 we try to ensure that we always stay two pixels away from the
7729 bottom). */
06a2c219
GM
7730 part = scroll_bar_down_arrow;
7731 else
7732 part = scroll_bar_handle;
7733
7734 window_being_scrolled = bar->window;
7735 bar->dragging = make_number (portion);
7736 last_scroll_bar_part = part;
7737 x_send_scroll_bar_event (bar->window, part, portion, whole);
7738}
7739
7740
ec18280f
SM
7741/* Xaw scroll bar callback. Invoked for incremental scrolling.,
7742 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
7743 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
7744 the scroll bar. CALL_DATA is an integer specifying the action that
7745 has taken place. It's magnitude is in the range 0..height of the
7746 scroll bar. Negative values mean scroll towards buffer start.
7747 Values < height of scroll bar mean line-wise movement. */
7748
7749static void
ec18280f 7750xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
7751 Widget widget;
7752 XtPointer client_data, call_data;
7753{
7754 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7755 int position = (int) call_data;
7756 Dimension height;
7757 int part;
7758
7759 /* Get the height of the scroll bar. */
7760 BLOCK_INPUT;
7761 XtVaGetValues (widget, XtNheight, &height, NULL);
7762 UNBLOCK_INPUT;
7763
ec18280f
SM
7764 if (abs (position) >= height)
7765 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
7766
7767 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
7768 it maps line-movement to call_data = max(5, height/20). */
7769 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
7770 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 7771 else
ec18280f 7772 part = scroll_bar_move_ratio;
06a2c219
GM
7773
7774 window_being_scrolled = bar->window;
7775 bar->dragging = Qnil;
7776 last_scroll_bar_part = part;
ec18280f 7777 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
7778}
7779
7780
7781#endif /* not USE_MOTIF */
7782
7783
7784/* Create the widget for scroll bar BAR on frame F. Record the widget
7785 and X window of the scroll bar in BAR. */
7786
7787static void
7788x_create_toolkit_scroll_bar (f, bar)
7789 struct frame *f;
7790 struct scroll_bar *bar;
7791{
7792 Window xwindow;
7793 Widget widget;
7794 Arg av[20];
7795 int ac = 0;
7796 char *scroll_bar_name = "verticalScrollBar";
7797 unsigned long pixel;
7798
7799 BLOCK_INPUT;
7800
7801#ifdef USE_MOTIF
7802 /* LessTif 0.85, problems:
7803
7804 1. When the mouse if over the scroll bar, the scroll bar will
7805 get keyboard events. I didn't find a way to turn this off.
7806
7807 2. Do we have to explicitly set the cursor to get an arrow
7808 cursor (see below)? */
7809
7810 /* Set resources. Create the widget. */
7811 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7812 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
7813 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
7814 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
7815 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
7816 XtSetArg (av[ac], XmNincrement, 1); ++ac;
7817 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
7818
7819 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7820 if (pixel != -1)
7821 {
7822 XtSetArg (av[ac], XmNforeground, pixel);
7823 ++ac;
7824 }
7825
7826 pixel = f->output_data.x->scroll_bar_background_pixel;
7827 if (pixel != -1)
7828 {
7829 XtSetArg (av[ac], XmNbackground, pixel);
7830 ++ac;
7831 }
7832
7833 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
7834 scroll_bar_name, av, ac);
7835
7836 /* Add one callback for everything that can happen. */
7837 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
7838 (XtPointer) bar);
7839 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
7840 (XtPointer) bar);
7841 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
7842 (XtPointer) bar);
7843 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
7844 (XtPointer) bar);
7845 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
7846 (XtPointer) bar);
7847 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
7848 (XtPointer) bar);
7849 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
7850 (XtPointer) bar);
7851
7852 /* Realize the widget. Only after that is the X window created. */
7853 XtRealizeWidget (widget);
7854
7855 /* Set the cursor to an arrow. I didn't find a resource to do that.
7856 And I'm wondering why it hasn't an arrow cursor by default. */
7857 XDefineCursor (XtDisplay (widget), XtWindow (widget),
7858 f->output_data.x->nontext_cursor);
7859
ec18280f 7860#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7861
7862 /* Set resources. Create the widget. The background of the
7863 Xaw3d scroll bar widget is a little bit light for my taste.
7864 We don't alter it here to let users change it according
7865 to their taste with `emacs*verticalScrollBar.background: xxx'. */
7866 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7867 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
7868 /* For smoother scrolling with Xaw3d -sm */
7869 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
7870 /* XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac; */
06a2c219
GM
7871
7872 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7873 if (pixel != -1)
7874 {
7875 XtSetArg (av[ac], XtNforeground, pixel);
7876 ++ac;
7877 }
7878
7879 pixel = f->output_data.x->scroll_bar_background_pixel;
7880 if (pixel != -1)
7881 {
7882 XtSetArg (av[ac], XtNbackground, pixel);
7883 ++ac;
7884 }
7885
7886 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
7887 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
7888
7889 {
7890 char *initial = "";
7891 char *val = initial;
7892 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
7893 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
7894 if (val == initial)
7895 { /* ARROW_SCROLL */
7896 xaw3d_arrow_scroll = True;
7897 /* Isn't that just a personal preference ? -sm */
7898 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
7899 }
7900 }
06a2c219
GM
7901
7902 /* Define callbacks. */
ec18280f
SM
7903 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
7904 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
7905 (XtPointer) bar);
7906
7907 /* Realize the widget. Only after that is the X window created. */
7908 XtRealizeWidget (widget);
7909
ec18280f 7910#endif /* !USE_MOTIF */
06a2c219
GM
7911
7912 /* Install an action hook that let's us detect when the user
7913 finishes interacting with a scroll bar. */
7914 if (action_hook_id == 0)
7915 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
7916
7917 /* Remember X window and widget in the scroll bar vector. */
7918 SET_SCROLL_BAR_X_WIDGET (bar, widget);
7919 xwindow = XtWindow (widget);
7920 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
7921
7922 UNBLOCK_INPUT;
7923}
7924
7925
7926/* Set the thumb size and position of scroll bar BAR. We are currently
7927 displaying PORTION out of a whole WHOLE, and our position POSITION. */
7928
7929static void
7930x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
7931 struct scroll_bar *bar;
7932 int portion, position, whole;
f451eb13 7933{
06a2c219 7934 float top, shown;
06a2c219 7935 Widget widget = SCROLL_BAR_X_WIDGET (bar);
f451eb13 7936
06a2c219
GM
7937 if (whole == 0)
7938 top = 0, shown = 1;
7939 else
f451eb13 7940 {
06a2c219
GM
7941 top = (float) position / whole;
7942 shown = (float) portion / whole;
7943 }
f451eb13 7944
06a2c219 7945 BLOCK_INPUT;
f451eb13 7946
06a2c219
GM
7947#ifdef USE_MOTIF
7948 {
7949 int size, value;
7950 Boolean arrow1_selected, arrow2_selected;
7951 unsigned char flags;
7952 XmScrollBarWidget sb;
7953
ec18280f 7954 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
7955 is the scroll bar's maximum and MIN is the scroll bar's minimum
7956 value. */
7957 size = shown * XM_SB_RANGE;
7958 size = min (size, XM_SB_RANGE);
7959 size = max (size, 1);
7960
7961 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
7962 value = top * XM_SB_RANGE;
7963 value = min (value, XM_SB_MAX - size);
7964 value = max (value, XM_SB_MIN);
7965
7966 /* LessTif: Calling XmScrollBarSetValues after an increment or
7967 decrement turns off auto-repeat LessTif-internally. This can
7968 be seen in ScrollBar.c which resets Arrow1Selected and
7969 Arrow2Selected. It also sets internal flags so that LessTif
7970 believes the mouse is in the slider. We either have to change
7971 our code, or work around that by accessing private data. */
7972
7973 sb = (XmScrollBarWidget) widget;
7974 arrow1_selected = sb->scrollBar.arrow1_selected;
7975 arrow2_selected = sb->scrollBar.arrow2_selected;
7976 flags = sb->scrollBar.flags;
7977
7978 if (NILP (bar->dragging))
7979 XmScrollBarSetValues (widget, value, size, 0, 0, False);
7980 else if (last_scroll_bar_part == scroll_bar_down_arrow)
7981 /* This has the negative side effect that the slider value is
ec18280f 7982 not what it would be if we scrolled here using line-wise or
06a2c219
GM
7983 page-wise movement. */
7984 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
7985 else
7986 {
7987 /* If currently dragging, only update the slider size.
7988 This reduces flicker effects. */
7989 int old_value, old_size, increment, page_increment;
7990
7991 XmScrollBarGetValues (widget, &old_value, &old_size,
7992 &increment, &page_increment);
7993 XmScrollBarSetValues (widget, old_value,
7994 min (size, XM_SB_RANGE - old_value),
7995 0, 0, False);
7996 }
7997
7998 sb->scrollBar.arrow1_selected = arrow1_selected;
7999 sb->scrollBar.arrow2_selected = arrow2_selected;
8000 sb->scrollBar.flags = flags;
8001 }
ec18280f 8002#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8003 {
ec18280f
SM
8004 float old_top, old_shown;
8005 Dimension height;
8006 XtVaGetValues (widget,
8007 XtNtopOfThumb, &old_top,
8008 XtNshown, &old_shown,
8009 XtNheight, &height,
8010 NULL);
8011
8012 /* Massage the top+shown values. */
8013 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8014 top = max (0, min (1, top));
8015 else
8016 top = old_top;
8017 /* Keep two pixels available for moving the thumb down. */
8018 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8019
8020 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8021 check that your system's configuration file contains a define
8022 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8023 if (top != old_top || shown != old_shown)
eb393530 8024 {
ec18280f 8025 if (NILP (bar->dragging))
eb393530 8026 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8027 else
8028 {
ec18280f
SM
8029#ifdef HAVE_XAW3D
8030 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8031 int scroll_mode = 0;
ec18280f
SM
8032
8033 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8034 if (xaw3d_arrow_scroll)
8035 {
8036 /* Xaw3d stupidly ignores resize requests while dragging
8037 so we have to make it believe it's not in dragging mode. */
8038 scroll_mode = sb->scrollbar.scroll_mode;
8039 if (scroll_mode == 2)
8040 sb->scrollbar.scroll_mode = 0;
8041 }
8042#endif
8043 /* Try to make the scrolling a tad smoother. */
8044 if (!xaw3d_pick_top)
8045 shown = min (shown, old_shown);
8046
8047 XawScrollbarSetThumb (widget, top, shown);
8048
8049#ifdef HAVE_XAW3D
8050 if (xaw3d_arrow_scroll && scroll_mode == 2)
8051 sb->scrollbar.scroll_mode = scroll_mode;
8052#endif
06a2c219 8053 }
06a2c219
GM
8054 }
8055 }
ec18280f 8056#endif /* !USE_MOTIF */
06a2c219
GM
8057
8058 UNBLOCK_INPUT;
f451eb13
JB
8059}
8060
06a2c219
GM
8061#endif /* USE_TOOLKIT_SCROLL_BARS */
8062
8063
8064\f
8065/************************************************************************
8066 Scroll bars, general
8067 ************************************************************************/
8068
8069/* Create a scroll bar and return the scroll bar vector for it. W is
8070 the Emacs window on which to create the scroll bar. TOP, LEFT,
8071 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8072 scroll bar. */
8073
ab648270 8074static struct scroll_bar *
06a2c219
GM
8075x_scroll_bar_create (w, top, left, width, height)
8076 struct window *w;
f451eb13
JB
8077 int top, left, width, height;
8078{
06a2c219 8079 struct frame *f = XFRAME (w->frame);
334208b7
RS
8080 struct scroll_bar *bar
8081 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8082
8083 BLOCK_INPUT;
8084
06a2c219
GM
8085#if USE_TOOLKIT_SCROLL_BARS
8086 x_create_toolkit_scroll_bar (f, bar);
8087#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8088 {
8089 XSetWindowAttributes a;
8090 unsigned long mask;
5c187dee 8091 Window window;
06a2c219
GM
8092
8093 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8094 if (a.background_pixel == -1)
8095 a.background_pixel = f->output_data.x->background_pixel;
8096
12ba150f 8097 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8098 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8099 | ExposureMask);
7a13e894 8100 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8101
dbc4e1c1 8102 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8103
06a2c219
GM
8104 /* Clear the area of W that will serve as a scroll bar. This is
8105 for the case that a window has been split horizontally. In
8106 this case, no clear_frame is generated to reduce flickering. */
8107 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8108 left, top, width,
8109 window_box_height (w), False);
8110
8111 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8112 /* Position and size of scroll bar. */
8113 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8114 top,
8115 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8116 height,
8117 /* Border width, depth, class, and visual. */
8118 0,
8119 CopyFromParent,
8120 CopyFromParent,
8121 CopyFromParent,
8122 /* Attributes. */
8123 mask, &a);
8124 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8125 }
06a2c219 8126#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8127
06a2c219 8128 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8129 XSETINT (bar->top, top);
8130 XSETINT (bar->left, left);
8131 XSETINT (bar->width, width);
8132 XSETINT (bar->height, height);
8133 XSETINT (bar->start, 0);
8134 XSETINT (bar->end, 0);
12ba150f 8135 bar->dragging = Qnil;
f451eb13
JB
8136
8137 /* Add bar to its frame's list of scroll bars. */
334208b7 8138 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8139 bar->prev = Qnil;
334208b7 8140 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 8141 if (!NILP (bar->next))
e0c1aef2 8142 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 8143
06a2c219
GM
8144 /* Map the window/widget. */
8145#if USE_TOOLKIT_SCROLL_BARS
8146 XtMapWidget (SCROLL_BAR_X_WIDGET (bar));
8147 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
8148 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8149 top,
8150 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8151 height, 0);
8152#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 8153 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 8154#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8155
8156 UNBLOCK_INPUT;
12ba150f 8157 return bar;
f451eb13
JB
8158}
8159
06a2c219 8160
12ba150f 8161/* Draw BAR's handle in the proper position.
06a2c219 8162
12ba150f
JB
8163 If the handle is already drawn from START to END, don't bother
8164 redrawing it, unless REBUILD is non-zero; in that case, always
8165 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 8166 events.)
12ba150f
JB
8167
8168 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
8169 fit inside its rectangle, but if the user is dragging the scroll
8170 bar handle, we want to let them drag it down all the way, so that
8171 the bar's top is as far down as it goes; otherwise, there's no way
8172 to move to the very end of the buffer. */
8173
5c187dee
GM
8174#ifndef USE_TOOLKIT_SCROLL_BARS
8175
f451eb13 8176static void
ab648270
JB
8177x_scroll_bar_set_handle (bar, start, end, rebuild)
8178 struct scroll_bar *bar;
f451eb13 8179 int start, end;
12ba150f 8180 int rebuild;
f451eb13 8181{
12ba150f 8182 int dragging = ! NILP (bar->dragging);
ab648270 8183 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8184 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8185 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
8186
8187 /* If the display is already accurate, do nothing. */
8188 if (! rebuild
8189 && start == XINT (bar->start)
8190 && end == XINT (bar->end))
8191 return;
8192
f451eb13
JB
8193 BLOCK_INPUT;
8194
8195 {
d9cdbb3d
RS
8196 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
8197 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
8198 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
8199
8200 /* Make sure the values are reasonable, and try to preserve
8201 the distance between start and end. */
12ba150f
JB
8202 {
8203 int length = end - start;
8204
8205 if (start < 0)
8206 start = 0;
8207 else if (start > top_range)
8208 start = top_range;
8209 end = start + length;
8210
8211 if (end < start)
8212 end = start;
8213 else if (end > top_range && ! dragging)
8214 end = top_range;
8215 }
f451eb13 8216
ab648270 8217 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
8218 XSETINT (bar->start, start);
8219 XSETINT (bar->end, end);
f451eb13 8220
12ba150f
JB
8221 /* Clip the end position, just for display. */
8222 if (end > top_range)
8223 end = top_range;
f451eb13 8224
ab648270 8225 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
8226 below top positions, to make sure the handle is always at least
8227 that many pixels tall. */
ab648270 8228 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 8229
12ba150f
JB
8230 /* Draw the empty space above the handle. Note that we can't clear
8231 zero-height areas; that means "clear to end of window." */
8232 if (0 < start)
334208b7 8233 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8234
12ba150f 8235 /* x, y, width, height, and exposures. */
ab648270
JB
8236 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8237 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
8238 inside_width, start,
8239 False);
f451eb13 8240
06a2c219
GM
8241 /* Change to proper foreground color if one is specified. */
8242 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8243 XSetForeground (FRAME_X_DISPLAY (f), gc,
8244 f->output_data.x->scroll_bar_foreground_pixel);
8245
12ba150f 8246 /* Draw the handle itself. */
334208b7 8247 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 8248
12ba150f 8249 /* x, y, width, height */
ab648270
JB
8250 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8251 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 8252 inside_width, end - start);
f451eb13 8253
06a2c219
GM
8254 /* Restore the foreground color of the GC if we changed it above. */
8255 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8256 XSetForeground (FRAME_X_DISPLAY (f), gc,
8257 f->output_data.x->foreground_pixel);
f451eb13 8258
12ba150f
JB
8259 /* Draw the empty space below the handle. Note that we can't
8260 clear zero-height areas; that means "clear to end of window." */
8261 if (end < inside_height)
334208b7 8262 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8263
12ba150f 8264 /* x, y, width, height, and exposures. */
ab648270
JB
8265 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8266 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
8267 inside_width, inside_height - end,
8268 False);
f451eb13 8269
f451eb13
JB
8270 }
8271
f451eb13
JB
8272 UNBLOCK_INPUT;
8273}
8274
5c187dee 8275#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 8276
06a2c219
GM
8277/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
8278 nil. */
58769bee 8279
12ba150f 8280static void
ab648270
JB
8281x_scroll_bar_remove (bar)
8282 struct scroll_bar *bar;
12ba150f 8283{
12ba150f
JB
8284 BLOCK_INPUT;
8285
06a2c219
GM
8286#if USE_TOOLKIT_SCROLL_BARS
8287 XtDestroyWidget (SCROLL_BAR_X_WIDGET (bar));
8288#else /* not USE_TOOLKIT_SCROLL_BARS */
5c187dee
GM
8289 {
8290 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8291 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
8292 }
06a2c219
GM
8293#endif /* not USE_TOOLKIT_SCROLL_BARS */
8294
ab648270
JB
8295 /* Disassociate this scroll bar from its window. */
8296 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
8297
8298 UNBLOCK_INPUT;
8299}
8300
06a2c219 8301
12ba150f
JB
8302/* Set the handle of the vertical scroll bar for WINDOW to indicate
8303 that we are displaying PORTION characters out of a total of WHOLE
ab648270 8304 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 8305 create one. */
06a2c219 8306
12ba150f 8307static void
06a2c219
GM
8308XTset_vertical_scroll_bar (w, portion, whole, position)
8309 struct window *w;
f451eb13
JB
8310 int portion, whole, position;
8311{
06a2c219 8312 struct frame *f = XFRAME (w->frame);
ab648270 8313 struct scroll_bar *bar;
3c6ede7b 8314 int top, height, left, sb_left, width, sb_width;
06a2c219 8315 int window_x, window_y, window_width, window_height;
06a2c219 8316
3c6ede7b 8317 /* Get window dimensions. */
06a2c219 8318 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
8319 top = window_y;
8320 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
8321 height = window_height;
06a2c219 8322
3c6ede7b 8323 /* Compute the left edge of the scroll bar area. */
06a2c219 8324 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
8325 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
8326 else
8327 left = XFASTINT (w->left);
8328 left *= CANON_X_UNIT (f);
8329 left += FRAME_INTERNAL_BORDER_WIDTH (f);
8330
8331 /* Compute the width of the scroll bar which might be less than
8332 the width of the area reserved for the scroll bar. */
8333 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
8334 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 8335 else
3c6ede7b 8336 sb_width = width;
12ba150f 8337
3c6ede7b
GM
8338 /* Compute the left edge of the scroll bar. */
8339#ifdef USE_TOOLKIT_SCROLL_BARS
8340 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8341 sb_left = left + width - sb_width - (width - sb_width) / 2;
8342 else
8343 sb_left = left + (width - sb_width) / 2;
8344#else
8345 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8346 sb_left = left + width - sb_width;
8347 else
8348 sb_left = left;
8349#endif
8350
ab648270 8351 /* Does the scroll bar exist yet? */
06a2c219 8352 if (NILP (w->vertical_scroll_bar))
3c6ede7b 8353 {
80c32bcc 8354 BLOCK_INPUT;
3c6ede7b
GM
8355 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8356 left, top, width, height, False);
80c32bcc 8357 UNBLOCK_INPUT;
3c6ede7b
GM
8358 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
8359 }
f451eb13 8360 else
12ba150f
JB
8361 {
8362 /* It may just need to be moved and resized. */
06a2c219
GM
8363 unsigned int mask = 0;
8364
8365 bar = XSCROLL_BAR (w->vertical_scroll_bar);
8366
8367 BLOCK_INPUT;
8368
3c6ede7b 8369 if (sb_left != XINT (bar->left))
06a2c219 8370 mask |= CWX;
3c6ede7b 8371 if (top != XINT (bar->top))
06a2c219 8372 mask |= CWY;
3c6ede7b 8373 if (sb_width != XINT (bar->width))
06a2c219 8374 mask |= CWWidth;
3c6ede7b 8375 if (height != XINT (bar->height))
06a2c219
GM
8376 mask |= CWHeight;
8377
8378#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
8379
8380 /* Since toolkit scroll bars are smaller than the space reserved
8381 for them on the frame, we have to clear "under" them. */
8382 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3c6ede7b 8383 left, top, width, height, False);
06a2c219
GM
8384
8385 /* Move/size the scroll bar widget. */
8386 if (mask)
8387 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
3c6ede7b
GM
8388 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8389 top,
8390 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8391 height, 0);
06a2c219
GM
8392
8393#else /* not USE_TOOLKIT_SCROLL_BARS */
8394
e1f6572f
RS
8395 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
8396 {
8397 /* Clear areas not covered by the scroll bar. This makes sure a
8398 previous mode line display is cleared after C-x 2 C-x 1, for
8399 example. Non-toolkit scroll bars are as wide as the area
8400 reserved for scroll bars - trim at both sides. */
8401 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8402 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8403 height, False);
8404 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8405 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8406 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8407 height, False);
8408 }
06a2c219
GM
8409
8410 /* Move/size the scroll bar window. */
8411 if (mask)
8412 {
8413 XWindowChanges wc;
8414
3c6ede7b
GM
8415 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
8416 wc.y = top;
8417 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
8418 wc.height = height;
06a2c219
GM
8419 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
8420 mask, &wc);
8421 }
8422
8423#endif /* not USE_TOOLKIT_SCROLL_BARS */
8424
8425 /* Remember new settings. */
3c6ede7b
GM
8426 XSETINT (bar->left, sb_left);
8427 XSETINT (bar->top, top);
8428 XSETINT (bar->width, sb_width);
8429 XSETINT (bar->height, height);
06a2c219
GM
8430
8431 UNBLOCK_INPUT;
12ba150f 8432 }
f451eb13 8433
06a2c219
GM
8434#if USE_TOOLKIT_SCROLL_BARS
8435 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
8436#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 8437 /* Set the scroll bar's current state, unless we're currently being
f451eb13 8438 dragged. */
12ba150f 8439 if (NILP (bar->dragging))
f451eb13 8440 {
92857db0 8441 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 8442
12ba150f 8443 if (whole == 0)
ab648270 8444 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
8445 else
8446 {
43f868f5
JB
8447 int start = ((double) position * top_range) / whole;
8448 int end = ((double) (position + portion) * top_range) / whole;
ab648270 8449 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 8450 }
f451eb13 8451 }
06a2c219 8452#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8453
06a2c219 8454 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
8455}
8456
12ba150f 8457
f451eb13 8458/* The following three hooks are used when we're doing a thorough
ab648270 8459 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 8460 are going to be deleted, because keeping track of when windows go
12ba150f
JB
8461 away is a real pain - "Can you say set-window-configuration, boys
8462 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 8463 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 8464 from the fiery pit when we actually redisplay its window. */
f451eb13 8465
ab648270
JB
8466/* Arrange for all scroll bars on FRAME to be removed at the next call
8467 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
8468 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
8469
58769bee 8470static void
ab648270 8471XTcondemn_scroll_bars (frame)
f451eb13
JB
8472 FRAME_PTR frame;
8473{
f9e24cb9
RS
8474 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
8475 while (! NILP (FRAME_SCROLL_BARS (frame)))
8476 {
8477 Lisp_Object bar;
8478 bar = FRAME_SCROLL_BARS (frame);
8479 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
8480 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
8481 XSCROLL_BAR (bar)->prev = Qnil;
8482 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
8483 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
8484 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
8485 }
f451eb13
JB
8486}
8487
06a2c219 8488/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 8489 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 8490static void
ab648270 8491XTredeem_scroll_bar (window)
12ba150f 8492 struct window *window;
f451eb13 8493{
ab648270 8494 struct scroll_bar *bar;
12ba150f 8495
ab648270
JB
8496 /* We can't redeem this window's scroll bar if it doesn't have one. */
8497 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
8498 abort ();
8499
ab648270 8500 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
8501
8502 /* Unlink it from the condemned list. */
8503 {
8504 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
8505
8506 if (NILP (bar->prev))
8507 {
8508 /* If the prev pointer is nil, it must be the first in one of
8509 the lists. */
ab648270 8510 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
8511 /* It's not condemned. Everything's fine. */
8512 return;
ab648270
JB
8513 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
8514 window->vertical_scroll_bar))
8515 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
8516 else
8517 /* If its prev pointer is nil, it must be at the front of
8518 one or the other! */
8519 abort ();
8520 }
8521 else
ab648270 8522 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
8523
8524 if (! NILP (bar->next))
ab648270 8525 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 8526
ab648270 8527 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8528 bar->prev = Qnil;
e0c1aef2 8529 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 8530 if (! NILP (bar->next))
e0c1aef2 8531 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
12ba150f 8532 }
f451eb13
JB
8533}
8534
ab648270
JB
8535/* Remove all scroll bars on FRAME that haven't been saved since the
8536 last call to `*condemn_scroll_bars_hook'. */
06a2c219 8537
f451eb13 8538static void
ab648270 8539XTjudge_scroll_bars (f)
12ba150f 8540 FRAME_PTR f;
f451eb13 8541{
12ba150f 8542 Lisp_Object bar, next;
f451eb13 8543
ab648270 8544 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
8545
8546 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
8547 more events on the hapless scroll bars. */
8548 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
8549
8550 for (; ! NILP (bar); bar = next)
f451eb13 8551 {
ab648270 8552 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 8553
ab648270 8554 x_scroll_bar_remove (b);
12ba150f
JB
8555
8556 next = b->next;
8557 b->next = b->prev = Qnil;
f451eb13 8558 }
12ba150f 8559
ab648270 8560 /* Now there should be no references to the condemned scroll bars,
12ba150f 8561 and they should get garbage-collected. */
f451eb13
JB
8562}
8563
8564
06a2c219
GM
8565/* Handle an Expose or GraphicsExpose event on a scroll bar. This
8566 is a no-op when using toolkit scroll bars.
ab648270
JB
8567
8568 This may be called from a signal handler, so we have to ignore GC
8569 mark bits. */
06a2c219 8570
f451eb13 8571static void
ab648270
JB
8572x_scroll_bar_expose (bar, event)
8573 struct scroll_bar *bar;
f451eb13
JB
8574 XEvent *event;
8575{
06a2c219
GM
8576#ifndef USE_TOOLKIT_SCROLL_BARS
8577
ab648270 8578 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8579 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8580 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 8581 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 8582
f451eb13
JB
8583 BLOCK_INPUT;
8584
ab648270 8585 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 8586
06a2c219 8587 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 8588 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
8589
8590 /* x, y, width, height */
d9cdbb3d 8591 0, 0,
3cbd2e0b 8592 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
8593 XINT (bar->height) - 1);
8594
f451eb13 8595 UNBLOCK_INPUT;
06a2c219
GM
8596
8597#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8598}
8599
ab648270
JB
8600/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8601 is set to something other than no_event, it is enqueued.
8602
8603 This may be called from a signal handler, so we have to ignore GC
8604 mark bits. */
06a2c219 8605
5c187dee
GM
8606#ifndef USE_TOOLKIT_SCROLL_BARS
8607
f451eb13 8608static void
ab648270
JB
8609x_scroll_bar_handle_click (bar, event, emacs_event)
8610 struct scroll_bar *bar;
f451eb13
JB
8611 XEvent *event;
8612 struct input_event *emacs_event;
8613{
0299d313 8614 if (! GC_WINDOWP (bar->window))
12ba150f
JB
8615 abort ();
8616
ab648270 8617 emacs_event->kind = scroll_bar_click;
69388238 8618 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
8619 emacs_event->modifiers
8620 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
8621 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
8622 event->xbutton.state)
8623 | (event->type == ButtonRelease
8624 ? up_modifier
8625 : down_modifier));
12ba150f 8626 emacs_event->frame_or_window = bar->window;
0f8aabe9 8627 emacs_event->arg = Qnil;
f451eb13 8628 emacs_event->timestamp = event->xbutton.time;
12ba150f 8629 {
06a2c219 8630#if 0
d9cdbb3d 8631 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 8632 int internal_height
d9cdbb3d 8633 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8634#endif
0299d313 8635 int top_range
d9cdbb3d 8636 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 8637 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
8638
8639 if (y < 0) y = 0;
8640 if (y > top_range) y = top_range;
8641
8642 if (y < XINT (bar->start))
ab648270
JB
8643 emacs_event->part = scroll_bar_above_handle;
8644 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8645 emacs_event->part = scroll_bar_handle;
12ba150f 8646 else
ab648270 8647 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
8648
8649 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
8650 they want to drag it. Lisp code needs to be able to decide
8651 whether or not we're dragging. */
929787e1 8652#if 0
12ba150f
JB
8653 /* If the user has just clicked on the handle, record where they're
8654 holding it. */
8655 if (event->type == ButtonPress
ab648270 8656 && emacs_event->part == scroll_bar_handle)
e0c1aef2 8657 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 8658#endif
12ba150f
JB
8659
8660 /* If the user has released the handle, set it to its final position. */
8661 if (event->type == ButtonRelease
8662 && ! NILP (bar->dragging))
8663 {
8664 int new_start = y - XINT (bar->dragging);
8665 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 8666
ab648270 8667 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
8668 bar->dragging = Qnil;
8669 }
f451eb13 8670
5116f055
JB
8671 /* Same deal here as the other #if 0. */
8672#if 0
58769bee 8673 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 8674 the handle. */
ab648270 8675 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
8676 emacs_event->x = bar->start;
8677 else
e0c1aef2 8678 XSETINT (emacs_event->x, y);
5116f055 8679#else
e0c1aef2 8680 XSETINT (emacs_event->x, y);
5116f055 8681#endif
f451eb13 8682
e0c1aef2 8683 XSETINT (emacs_event->y, top_range);
12ba150f
JB
8684 }
8685}
f451eb13 8686
ab648270
JB
8687/* Handle some mouse motion while someone is dragging the scroll bar.
8688
8689 This may be called from a signal handler, so we have to ignore GC
8690 mark bits. */
06a2c219 8691
f451eb13 8692static void
ab648270
JB
8693x_scroll_bar_note_movement (bar, event)
8694 struct scroll_bar *bar;
f451eb13
JB
8695 XEvent *event;
8696{
39d8bb4d
KH
8697 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
8698
f451eb13
JB
8699 last_mouse_movement_time = event->xmotion.time;
8700
39d8bb4d 8701 f->mouse_moved = 1;
e0c1aef2 8702 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
8703
8704 /* If we're dragging the bar, display it. */
ab648270 8705 if (! GC_NILP (bar->dragging))
f451eb13
JB
8706 {
8707 /* Where should the handle be now? */
12ba150f 8708 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 8709
12ba150f 8710 if (new_start != XINT (bar->start))
f451eb13 8711 {
12ba150f 8712 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 8713
ab648270 8714 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
8715 }
8716 }
f451eb13
JB
8717}
8718
5c187dee
GM
8719#endif /* !USE_TOOLKIT_SCROLL_BARS */
8720
12ba150f 8721/* Return information to the user about the current position of the mouse
ab648270 8722 on the scroll bar. */
06a2c219 8723
12ba150f 8724static void
334208b7
RS
8725x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
8726 FRAME_PTR *fp;
12ba150f 8727 Lisp_Object *bar_window;
ab648270 8728 enum scroll_bar_part *part;
12ba150f
JB
8729 Lisp_Object *x, *y;
8730 unsigned long *time;
8731{
ab648270 8732 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
8733 Window w = SCROLL_BAR_X_WINDOW (bar);
8734 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 8735 int win_x, win_y;
559cb2fb
JB
8736 Window dummy_window;
8737 int dummy_coord;
8738 unsigned int dummy_mask;
12ba150f 8739
cf7cb199
JB
8740 BLOCK_INPUT;
8741
ab648270 8742 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 8743 report that. */
334208b7 8744 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 8745
559cb2fb
JB
8746 /* Root, child, root x and root y. */
8747 &dummy_window, &dummy_window,
8748 &dummy_coord, &dummy_coord,
12ba150f 8749
559cb2fb
JB
8750 /* Position relative to scroll bar. */
8751 &win_x, &win_y,
12ba150f 8752
559cb2fb
JB
8753 /* Mouse buttons and modifier keys. */
8754 &dummy_mask))
7a13e894 8755 ;
559cb2fb
JB
8756 else
8757 {
06a2c219 8758#if 0
559cb2fb 8759 int inside_height
d9cdbb3d 8760 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8761#endif
559cb2fb 8762 int top_range
d9cdbb3d 8763 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
8764
8765 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
8766
8767 if (! NILP (bar->dragging))
8768 win_y -= XINT (bar->dragging);
8769
8770 if (win_y < 0)
8771 win_y = 0;
8772 if (win_y > top_range)
8773 win_y = top_range;
8774
334208b7 8775 *fp = f;
7a13e894 8776 *bar_window = bar->window;
559cb2fb
JB
8777
8778 if (! NILP (bar->dragging))
8779 *part = scroll_bar_handle;
8780 else if (win_y < XINT (bar->start))
8781 *part = scroll_bar_above_handle;
8782 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8783 *part = scroll_bar_handle;
8784 else
8785 *part = scroll_bar_below_handle;
12ba150f 8786
e0c1aef2
KH
8787 XSETINT (*x, win_y);
8788 XSETINT (*y, top_range);
12ba150f 8789
39d8bb4d 8790 f->mouse_moved = 0;
559cb2fb
JB
8791 last_mouse_scroll_bar = Qnil;
8792 }
12ba150f 8793
559cb2fb 8794 *time = last_mouse_movement_time;
cf7cb199 8795
cf7cb199 8796 UNBLOCK_INPUT;
12ba150f
JB
8797}
8798
f451eb13 8799
dbc4e1c1 8800/* The screen has been cleared so we may have changed foreground or
ab648270
JB
8801 background colors, and the scroll bars may need to be redrawn.
8802 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
8803 redraw them. */
8804
dfcf069d 8805void
ab648270 8806x_scroll_bar_clear (f)
dbc4e1c1
JB
8807 FRAME_PTR f;
8808{
06a2c219 8809#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
8810 Lisp_Object bar;
8811
b80c363e
RS
8812 /* We can have scroll bars even if this is 0,
8813 if we just turned off scroll bar mode.
8814 But in that case we should not clear them. */
8815 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
8816 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
8817 bar = XSCROLL_BAR (bar)->next)
8818 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
8819 0, 0, 0, 0, True);
06a2c219 8820#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
8821}
8822
06a2c219 8823/* This processes Expose events from the menu-bar specific X event
19126e11 8824 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 8825 when handling menu-bar or pop-up items. */
3afe33e7 8826
06a2c219 8827int
3afe33e7
RS
8828process_expose_from_menu (event)
8829 XEvent event;
8830{
8831 FRAME_PTR f;
19126e11 8832 struct x_display_info *dpyinfo;
06a2c219 8833 int frame_exposed_p = 0;
3afe33e7 8834
f94397b5
KH
8835 BLOCK_INPUT;
8836
19126e11
KH
8837 dpyinfo = x_display_info_for_display (event.xexpose.display);
8838 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
8839 if (f)
8840 {
8841 if (f->async_visible == 0)
8842 {
8843 f->async_visible = 1;
8844 f->async_iconified = 0;
06c488fd 8845 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
8846 SET_FRAME_GARBAGED (f);
8847 }
8848 else
8849 {
06a2c219
GM
8850 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
8851 event.xexpose.x, event.xexpose.y,
8852 event.xexpose.width, event.xexpose.height);
8853 frame_exposed_p = 1;
3afe33e7
RS
8854 }
8855 }
8856 else
8857 {
8858 struct scroll_bar *bar
8859 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 8860
3afe33e7
RS
8861 if (bar)
8862 x_scroll_bar_expose (bar, &event);
8863 }
f94397b5
KH
8864
8865 UNBLOCK_INPUT;
06a2c219 8866 return frame_exposed_p;
3afe33e7 8867}
09756a85
RS
8868\f
8869/* Define a queue to save up SelectionRequest events for later handling. */
8870
8871struct selection_event_queue
8872 {
8873 XEvent event;
8874 struct selection_event_queue *next;
8875 };
8876
8877static struct selection_event_queue *queue;
8878
8879/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 8880
09756a85
RS
8881static int x_queue_selection_requests;
8882
8883/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 8884
09756a85 8885static void
334208b7
RS
8886x_queue_event (f, event)
8887 FRAME_PTR f;
09756a85
RS
8888 XEvent *event;
8889{
8890 struct selection_event_queue *queue_tmp
06a2c219 8891 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 8892
58769bee 8893 if (queue_tmp != NULL)
09756a85
RS
8894 {
8895 queue_tmp->event = *event;
8896 queue_tmp->next = queue;
8897 queue = queue_tmp;
8898 }
8899}
8900
8901/* Take all the queued events and put them back
8902 so that they get processed afresh. */
8903
8904static void
db3906fd
RS
8905x_unqueue_events (display)
8906 Display *display;
09756a85 8907{
58769bee 8908 while (queue != NULL)
09756a85
RS
8909 {
8910 struct selection_event_queue *queue_tmp = queue;
db3906fd 8911 XPutBackEvent (display, &queue_tmp->event);
09756a85 8912 queue = queue_tmp->next;
06a2c219 8913 xfree ((char *)queue_tmp);
09756a85
RS
8914 }
8915}
8916
8917/* Start queuing SelectionRequest events. */
8918
8919void
db3906fd
RS
8920x_start_queuing_selection_requests (display)
8921 Display *display;
09756a85
RS
8922{
8923 x_queue_selection_requests++;
8924}
8925
8926/* Stop queuing SelectionRequest events. */
8927
8928void
db3906fd
RS
8929x_stop_queuing_selection_requests (display)
8930 Display *display;
09756a85
RS
8931{
8932 x_queue_selection_requests--;
db3906fd 8933 x_unqueue_events (display);
09756a85 8934}
f451eb13
JB
8935\f
8936/* The main X event-reading loop - XTread_socket. */
dc6f92b8 8937
06a2c219 8938/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
8939 but we have to put it out here, since static variables within functions
8940 sometimes don't work. */
06a2c219 8941
dc6f92b8
JB
8942static Time enter_timestamp;
8943
11edeb03 8944/* This holds the state XLookupString needs to implement dead keys
58769bee 8945 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
8946 says that a portable program can't use this, but Stephen Gildea assures
8947 me that letting the compiler initialize it to zeros will work okay.
8948
8949 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
8950 given for enter_time stamp, above. */
8951
11edeb03
JB
8952static XComposeStatus compose_status;
8953
10e6549c
RS
8954/* Record the last 100 characters stored
8955 to help debug the loss-of-chars-during-GC problem. */
06a2c219 8956
2224b905
RS
8957static int temp_index;
8958static short temp_buffer[100];
10e6549c 8959
7a13e894
RS
8960/* Set this to nonzero to fake an "X I/O error"
8961 on a particular display. */
06a2c219 8962
7a13e894
RS
8963struct x_display_info *XTread_socket_fake_io_error;
8964
2224b905
RS
8965/* When we find no input here, we occasionally do a no-op command
8966 to verify that the X server is still running and we can still talk with it.
8967 We try all the open displays, one by one.
8968 This variable is used for cycling thru the displays. */
06a2c219 8969
2224b905
RS
8970static struct x_display_info *next_noop_dpyinfo;
8971
06a2c219
GM
8972#define SET_SAVED_MENU_EVENT(size) \
8973 do \
8974 { \
8975 if (f->output_data.x->saved_menu_event == 0) \
8976 f->output_data.x->saved_menu_event \
8977 = (XEvent *) xmalloc (sizeof (XEvent)); \
8978 bcopy (&event, f->output_data.x->saved_menu_event, size); \
8979 if (numchars >= 1) \
8980 { \
8981 bufp->kind = menu_bar_activate_event; \
8982 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 8983 bufp->arg = Qnil; \
06a2c219
GM
8984 bufp++; \
8985 count++; \
8986 numchars--; \
8987 } \
8988 } \
8989 while (0)
8990
8805890a 8991#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 8992#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 8993
dc6f92b8
JB
8994/* Read events coming from the X server.
8995 This routine is called by the SIGIO handler.
8996 We return as soon as there are no more events to be read.
8997
8998 Events representing keys are stored in buffer BUFP,
8999 which can hold up to NUMCHARS characters.
9000 We return the number of characters stored into the buffer,
9001 thus pretending to be `read'.
9002
dc6f92b8
JB
9003 EXPECTED is nonzero if the caller knows input is available. */
9004
7c5283e4 9005int
f66868ba 9006XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9007 register int sd;
8805890a
KH
9008 /* register */ struct input_event *bufp;
9009 /* register */ int numchars;
dc6f92b8
JB
9010 int expected;
9011{
9012 int count = 0;
9013 int nbytes = 0;
dc6f92b8 9014 XEvent event;
f676886a 9015 struct frame *f;
66f55a9d 9016 int event_found = 0;
334208b7 9017 struct x_display_info *dpyinfo;
dc6f92b8 9018
9ac0d9e0 9019 if (interrupt_input_blocked)
dc6f92b8 9020 {
9ac0d9e0 9021 interrupt_input_pending = 1;
dc6f92b8
JB
9022 return -1;
9023 }
9024
9ac0d9e0 9025 interrupt_input_pending = 0;
dc6f92b8 9026 BLOCK_INPUT;
c0a04927
RS
9027
9028 /* So people can tell when we have read the available input. */
9029 input_signal_count++;
9030
dc6f92b8 9031 if (numchars <= 0)
06a2c219 9032 abort (); /* Don't think this happens. */
dc6f92b8 9033
bde5503b
GM
9034 ++handling_signal;
9035
7a13e894
RS
9036 /* Find the display we are supposed to read input for.
9037 It's the one communicating on descriptor SD. */
9038 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9039 {
9040#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9041#ifdef FIOSNBIO
7a13e894
RS
9042 /* If available, Xlib uses FIOSNBIO to make the socket
9043 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9044 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9045 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9046 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9047#endif /* ! defined (FIOSNBIO) */
7a13e894 9048#endif
dc6f92b8 9049
7a13e894
RS
9050#if 0 /* This code can't be made to work, with multiple displays,
9051 and appears not to be used on any system any more.
9052 Also keyboard.c doesn't turn O_NDELAY on and off
9053 for X connections. */
dc6f92b8
JB
9054#ifndef SIGIO
9055#ifndef HAVE_SELECT
7a13e894
RS
9056 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9057 {
9058 extern int read_alarm_should_throw;
9059 read_alarm_should_throw = 1;
9060 XPeekEvent (dpyinfo->display, &event);
9061 read_alarm_should_throw = 0;
9062 }
c118dd06
JB
9063#endif /* HAVE_SELECT */
9064#endif /* SIGIO */
7a13e894 9065#endif
dc6f92b8 9066
7a13e894
RS
9067 /* For debugging, this gives a way to fake an I/O error. */
9068 if (dpyinfo == XTread_socket_fake_io_error)
9069 {
9070 XTread_socket_fake_io_error = 0;
9071 x_io_error_quitter (dpyinfo->display);
9072 }
dc6f92b8 9073
06a2c219 9074 while (XPending (dpyinfo->display))
dc6f92b8 9075 {
7a13e894 9076 XNextEvent (dpyinfo->display, &event);
06a2c219 9077
531483fb 9078#ifdef HAVE_X_I18N
d1bc4182 9079 {
f2be1146
GM
9080 /* Filter events for the current X input method.
9081 XFilterEvent returns non-zero if the input method has
9082 consumed the event. We pass the frame's X window to
9083 XFilterEvent because that's the one for which the IC
9084 was created. */
f5d11644
GM
9085 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9086 event.xclient.window);
9087 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9088 break;
9089 }
0cd6403b 9090#endif
7a13e894
RS
9091 event_found = 1;
9092
9093 switch (event.type)
9094 {
9095 case ClientMessage:
c047688c 9096 {
7a13e894
RS
9097 if (event.xclient.message_type
9098 == dpyinfo->Xatom_wm_protocols
9099 && event.xclient.format == 32)
c047688c 9100 {
7a13e894
RS
9101 if (event.xclient.data.l[0]
9102 == dpyinfo->Xatom_wm_take_focus)
c047688c 9103 {
8c1a6a84
RS
9104 /* Use x_any_window_to_frame because this
9105 could be the shell widget window
9106 if the frame has no title bar. */
9107 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
9108#ifdef HAVE_X_I18N
9109 /* Not quite sure this is needed -pd */
8c1a6a84 9110 if (f && FRAME_XIC (f))
6c183ba5
RS
9111 XSetICFocus (FRAME_XIC (f));
9112#endif
f1da8f06
GM
9113#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
9114 instructs the WM to set the input focus automatically for
9115 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
9116 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
9117 it has set the focus. So, XSetInputFocus below is not
9118 needed.
9119
9120 The call to XSetInputFocus below has also caused trouble. In
9121 cases where the XSetInputFocus done by the WM and the one
9122 below are temporally close (on a fast machine), the call
9123 below can generate additional FocusIn events which confuse
9124 Emacs. */
9125
bf7253f4
RS
9126 /* Since we set WM_TAKE_FOCUS, we must call
9127 XSetInputFocus explicitly. But not if f is null,
9128 since that might be an event for a deleted frame. */
7a13e894 9129 if (f)
bf7253f4
RS
9130 {
9131 Display *d = event.xclient.display;
9132 /* Catch and ignore errors, in case window has been
9133 iconified by a window manager such as GWM. */
9134 int count = x_catch_errors (d);
9135 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
9136 /* The ICCCM says this is
9137 the only valid choice. */
9138 RevertToParent,
bf7253f4
RS
9139 event.xclient.data.l[1]);
9140 /* This is needed to detect the error
9141 if there is an error. */
9142 XSync (d, False);
9143 x_uncatch_errors (d, count);
9144 }
7a13e894 9145 /* Not certain about handling scroll bars here */
f1da8f06 9146#endif /* 0 */
c047688c 9147 }
7a13e894
RS
9148 else if (event.xclient.data.l[0]
9149 == dpyinfo->Xatom_wm_save_yourself)
9150 {
9151 /* Save state modify the WM_COMMAND property to
06a2c219 9152 something which can reinstate us. This notifies
7a13e894
RS
9153 the session manager, who's looking for such a
9154 PropertyNotify. Can restart processing when
06a2c219 9155 a keyboard or mouse event arrives. */
7a13e894
RS
9156 if (numchars > 0)
9157 {
19126e11
KH
9158 f = x_top_window_to_frame (dpyinfo,
9159 event.xclient.window);
7a13e894
RS
9160
9161 /* This is just so we only give real data once
9162 for a single Emacs process. */
b86bd3dd 9163 if (f == SELECTED_FRAME ())
7a13e894
RS
9164 XSetCommand (FRAME_X_DISPLAY (f),
9165 event.xclient.window,
9166 initial_argv, initial_argc);
f000f5c5 9167 else if (f)
7a13e894
RS
9168 XSetCommand (FRAME_X_DISPLAY (f),
9169 event.xclient.window,
9170 0, 0);
9171 }
9172 }
9173 else if (event.xclient.data.l[0]
9174 == dpyinfo->Xatom_wm_delete_window)
1fb20991 9175 {
19126e11
KH
9176 struct frame *f
9177 = x_any_window_to_frame (dpyinfo,
9178 event.xclient.window);
1fb20991 9179
7a13e894
RS
9180 if (f)
9181 {
9182 if (numchars == 0)
9183 abort ();
1fb20991 9184
7a13e894
RS
9185 bufp->kind = delete_window_event;
9186 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9187 bufp->arg = Qnil;
7a13e894
RS
9188 bufp++;
9189
9190 count += 1;
9191 numchars -= 1;
9192 }
1fb20991 9193 }
c047688c 9194 }
7a13e894
RS
9195 else if (event.xclient.message_type
9196 == dpyinfo->Xatom_wm_configure_denied)
9197 {
9198 }
9199 else if (event.xclient.message_type
9200 == dpyinfo->Xatom_wm_window_moved)
9201 {
9202 int new_x, new_y;
19126e11
KH
9203 struct frame *f
9204 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 9205
7a13e894
RS
9206 new_x = event.xclient.data.s[0];
9207 new_y = event.xclient.data.s[1];
1fb20991 9208
7a13e894
RS
9209 if (f)
9210 {
7556890b
RS
9211 f->output_data.x->left_pos = new_x;
9212 f->output_data.x->top_pos = new_y;
7a13e894 9213 }
1fb20991 9214 }
0fdff6bb 9215#ifdef HACK_EDITRES
7a13e894
RS
9216 else if (event.xclient.message_type
9217 == dpyinfo->Xatom_editres)
9218 {
19126e11
KH
9219 struct frame *f
9220 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 9221 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 9222 &event, NULL);
7a13e894 9223 }
0fdff6bb 9224#endif /* HACK_EDITRES */
06a2c219
GM
9225 else if ((event.xclient.message_type
9226 == dpyinfo->Xatom_DONE)
9227 || (event.xclient.message_type
9228 == dpyinfo->Xatom_PAGE))
9229 {
9230 /* Ghostview job completed. Kill it. We could
9231 reply with "Next" if we received "Page", but we
9232 currently never do because we are interested in
9233 images, only, which should have 1 page. */
06a2c219
GM
9234 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
9235 struct frame *f
9236 = x_window_to_frame (dpyinfo, event.xclient.window);
9237 x_kill_gs_process (pixmap, f);
9238 expose_frame (f, 0, 0, 0, 0);
9239 }
9240#ifdef USE_TOOLKIT_SCROLL_BARS
9241 /* Scroll bar callbacks send a ClientMessage from which
9242 we construct an input_event. */
9243 else if (event.xclient.message_type
9244 == dpyinfo->Xatom_Scrollbar)
9245 {
9246 x_scroll_bar_to_input_event (&event, bufp);
9247 ++bufp, ++count, --numchars;
9248 goto out;
9249 }
9250#endif /* USE_TOOLKIT_SCROLL_BARS */
9251 else
9252 goto OTHER;
7a13e894
RS
9253 }
9254 break;
dc6f92b8 9255
7a13e894 9256 case SelectionNotify:
3afe33e7 9257#ifdef USE_X_TOOLKIT
19126e11 9258 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 9259 goto OTHER;
3afe33e7 9260#endif /* not USE_X_TOOLKIT */
dfcf069d 9261 x_handle_selection_notify (&event.xselection);
7a13e894 9262 break;
d56a553a 9263
06a2c219 9264 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 9265#ifdef USE_X_TOOLKIT
19126e11 9266 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 9267 goto OTHER;
3afe33e7 9268#endif /* USE_X_TOOLKIT */
7a13e894
RS
9269 {
9270 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 9271
7a13e894
RS
9272 if (numchars == 0)
9273 abort ();
d56a553a 9274
7a13e894
RS
9275 bufp->kind = selection_clear_event;
9276 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9277 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9278 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9279 bufp->frame_or_window = Qnil;
0f8aabe9 9280 bufp->arg = Qnil;
7a13e894 9281 bufp++;
d56a553a 9282
7a13e894
RS
9283 count += 1;
9284 numchars -= 1;
9285 }
9286 break;
dc6f92b8 9287
06a2c219 9288 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 9289#ifdef USE_X_TOOLKIT
19126e11 9290 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 9291 goto OTHER;
3afe33e7 9292#endif /* USE_X_TOOLKIT */
7a13e894 9293 if (x_queue_selection_requests)
19126e11 9294 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
9295 &event);
9296 else
9297 {
9298 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 9299
7a13e894
RS
9300 if (numchars == 0)
9301 abort ();
9302
9303 bufp->kind = selection_request_event;
9304 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9305 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
9306 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9307 SELECTION_EVENT_TARGET (bufp) = eventp->target;
9308 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
9309 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9310 bufp->frame_or_window = Qnil;
0f8aabe9 9311 bufp->arg = Qnil;
7a13e894
RS
9312 bufp++;
9313
9314 count += 1;
9315 numchars -= 1;
9316 }
9317 break;
9318
9319 case PropertyNotify:
3afe33e7 9320#ifdef USE_X_TOOLKIT
19126e11 9321 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 9322 goto OTHER;
3afe33e7 9323#endif /* not USE_X_TOOLKIT */
dfcf069d 9324 x_handle_property_notify (&event.xproperty);
7a13e894 9325 break;
dc6f92b8 9326
7a13e894 9327 case ReparentNotify:
19126e11 9328 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
9329 if (f)
9330 {
9331 int x, y;
7556890b 9332 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 9333 x_real_positions (f, &x, &y);
7556890b
RS
9334 f->output_data.x->left_pos = x;
9335 f->output_data.x->top_pos = y;
7a13e894
RS
9336 }
9337 break;
3bd330d4 9338
7a13e894 9339 case Expose:
19126e11 9340 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 9341 if (f)
dc6f92b8 9342 {
7a13e894
RS
9343 if (f->async_visible == 0)
9344 {
9345 f->async_visible = 1;
9346 f->async_iconified = 0;
06c488fd 9347 f->output_data.x->has_been_visible = 1;
7a13e894
RS
9348 SET_FRAME_GARBAGED (f);
9349 }
9350 else
06a2c219
GM
9351 expose_frame (x_window_to_frame (dpyinfo,
9352 event.xexpose.window),
9353 event.xexpose.x, event.xexpose.y,
9354 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
9355 }
9356 else
7a13e894 9357 {
06a2c219
GM
9358#ifdef USE_TOOLKIT_SCROLL_BARS
9359 /* Dispatch event to the widget. */
9360 goto OTHER;
9361#else /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9362 struct scroll_bar *bar
9363 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9364
7a13e894
RS
9365 if (bar)
9366 x_scroll_bar_expose (bar, &event);
3afe33e7 9367#ifdef USE_X_TOOLKIT
7a13e894
RS
9368 else
9369 goto OTHER;
3afe33e7 9370#endif /* USE_X_TOOLKIT */
06a2c219 9371#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9372 }
9373 break;
dc6f92b8 9374
7a13e894
RS
9375 case GraphicsExpose: /* This occurs when an XCopyArea's
9376 source area was obscured or not
9377 available.*/
19126e11 9378 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
9379 if (f)
9380 {
06a2c219
GM
9381 expose_frame (f,
9382 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
9383 event.xgraphicsexpose.width,
9384 event.xgraphicsexpose.height);
7a13e894 9385 }
3afe33e7 9386#ifdef USE_X_TOOLKIT
7a13e894
RS
9387 else
9388 goto OTHER;
3afe33e7 9389#endif /* USE_X_TOOLKIT */
7a13e894 9390 break;
dc6f92b8 9391
7a13e894 9392 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
9393 source area was completely
9394 available */
7a13e894 9395 break;
dc6f92b8 9396
7a13e894 9397 case UnmapNotify:
06a2c219
GM
9398 /* Redo the mouse-highlight after the tooltip has gone. */
9399 if (event.xmap.window == tip_window)
9400 {
9401 tip_window = 0;
9402 redo_mouse_highlight ();
9403 }
9404
91ea2a7a 9405 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
9406 if (f) /* F may no longer exist if
9407 the frame was deleted. */
9408 {
9409 /* While a frame is unmapped, display generation is
9410 disabled; you don't want to spend time updating a
9411 display that won't ever be seen. */
9412 f->async_visible = 0;
9413 /* We can't distinguish, from the event, whether the window
9414 has become iconified or invisible. So assume, if it
9415 was previously visible, than now it is iconified.
1aa6072f
RS
9416 But x_make_frame_invisible clears both
9417 the visible flag and the iconified flag;
9418 and that way, we know the window is not iconified now. */
7a13e894 9419 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
9420 {
9421 f->async_iconified = 1;
bddd097c 9422
1aa6072f
RS
9423 bufp->kind = iconify_event;
9424 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9425 bufp->arg = Qnil;
1aa6072f
RS
9426 bufp++;
9427 count++;
9428 numchars--;
9429 }
7a13e894 9430 }
7a13e894 9431 goto OTHER;
dc6f92b8 9432
7a13e894 9433 case MapNotify:
06a2c219
GM
9434 if (event.xmap.window == tip_window)
9435 /* The tooltip has been drawn already. Avoid
9436 the SET_FRAME_GARBAGED below. */
9437 goto OTHER;
9438
9439 /* We use x_top_window_to_frame because map events can
9440 come for sub-windows and they don't mean that the
9441 frame is visible. */
19126e11 9442 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
9443 if (f)
9444 {
9445 f->async_visible = 1;
9446 f->async_iconified = 0;
06c488fd 9447 f->output_data.x->has_been_visible = 1;
dc6f92b8 9448
7a13e894
RS
9449 /* wait_reading_process_input will notice this and update
9450 the frame's display structures. */
9451 SET_FRAME_GARBAGED (f);
bddd097c 9452
d806e720
RS
9453 if (f->iconified)
9454 {
9455 bufp->kind = deiconify_event;
9456 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9457 bufp->arg = Qnil;
d806e720
RS
9458 bufp++;
9459 count++;
9460 numchars--;
9461 }
e73ec6fa 9462 else if (! NILP (Vframe_list)
8e713be6 9463 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
9464 /* Force a redisplay sooner or later
9465 to update the frame titles
9466 in case this is the second frame. */
9467 record_asynch_buffer_change ();
7a13e894 9468 }
7a13e894 9469 goto OTHER;
dc6f92b8 9470
7a13e894 9471 case KeyPress:
19126e11 9472 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 9473
06a2c219
GM
9474#ifdef USE_MOTIF
9475 /* I couldn't find a way to prevent LessTif scroll bars
9476 from consuming key events. */
9477 if (f == 0)
9478 {
9479 Widget widget = XtWindowToWidget (dpyinfo->display,
9480 event.xkey.window);
9481 if (widget && XmIsScrollBar (widget))
9482 {
9483 widget = XtParent (widget);
9484 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
9485 }
9486 }
9487#endif /* USE_MOTIF */
9488
7a13e894
RS
9489 if (f != 0)
9490 {
9491 KeySym keysym, orig_keysym;
9492 /* al%imercury@uunet.uu.net says that making this 81 instead of
9493 80 fixed a bug whereby meta chars made his Emacs hang. */
9494 unsigned char copy_buffer[81];
9495 int modifiers;
64bb1782 9496
7a13e894
RS
9497 event.xkey.state
9498 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
9499 extra_keyboard_modifiers);
9500 modifiers = event.xkey.state;
3a2712f9 9501
7a13e894 9502 /* This will have to go some day... */
752a043f 9503
7a13e894
RS
9504 /* make_lispy_event turns chars into control chars.
9505 Don't do it here because XLookupString is too eager. */
9506 event.xkey.state &= ~ControlMask;
5d46f928
RS
9507 event.xkey.state &= ~(dpyinfo->meta_mod_mask
9508 | dpyinfo->super_mod_mask
9509 | dpyinfo->hyper_mod_mask
9510 | dpyinfo->alt_mod_mask);
9511
1cf4a0d1
RS
9512 /* In case Meta is ComposeCharacter,
9513 clear its status. According to Markus Ehrnsperger
9514 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
9515 this enables ComposeCharacter to work whether or
9516 not it is combined with Meta. */
9517 if (modifiers & dpyinfo->meta_mod_mask)
9518 bzero (&compose_status, sizeof (compose_status));
9519
6c183ba5
RS
9520#ifdef HAVE_X_I18N
9521 if (FRAME_XIC (f))
9522 {
f5d11644
GM
9523 unsigned char *copy_bufptr = copy_buffer;
9524 int copy_bufsiz = sizeof (copy_buffer);
9525 Status status_return;
9526
6c183ba5 9527 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
9528 &event.xkey, copy_bufptr,
9529 copy_bufsiz, &keysym,
6c183ba5 9530 &status_return);
f5d11644
GM
9531 if (status_return == XBufferOverflow)
9532 {
9533 copy_bufsiz = nbytes + 1;
9534 copy_bufptr = (char *) alloca (copy_bufsiz);
9535 nbytes = XmbLookupString (FRAME_XIC (f),
9536 &event.xkey, copy_bufptr,
9537 copy_bufsiz, &keysym,
9538 &status_return);
9539 }
9540
1decb680
PE
9541 if (status_return == XLookupNone)
9542 break;
9543 else if (status_return == XLookupChars)
fdd9d55e
GM
9544 {
9545 keysym = NoSymbol;
9546 modifiers = 0;
9547 }
1decb680
PE
9548 else if (status_return != XLookupKeySym
9549 && status_return != XLookupBoth)
9550 abort ();
6c183ba5
RS
9551 }
9552 else
9553 nbytes = XLookupString (&event.xkey, copy_buffer,
9554 80, &keysym, &compose_status);
9555#else
0299d313
RS
9556 nbytes = XLookupString (&event.xkey, copy_buffer,
9557 80, &keysym, &compose_status);
6c183ba5 9558#endif
dc6f92b8 9559
7a13e894 9560 orig_keysym = keysym;
55123275 9561
7a13e894
RS
9562 if (numchars > 1)
9563 {
9564 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
9565 || keysym == XK_Delete
1097aea0 9566#ifdef XK_ISO_Left_Tab
441affdb 9567 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 9568#endif
852bff8f 9569 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
9570 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
9571 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 9572#ifdef HPUX
7a13e894
RS
9573 /* This recognizes the "extended function keys".
9574 It seems there's no cleaner way.
9575 Test IsModifierKey to avoid handling mode_switch
9576 incorrectly. */
9577 || ((unsigned) (keysym) >= XK_Select
9578 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
9579#endif
9580#ifdef XK_dead_circumflex
7a13e894 9581 || orig_keysym == XK_dead_circumflex
69388238
RS
9582#endif
9583#ifdef XK_dead_grave
7a13e894 9584 || orig_keysym == XK_dead_grave
69388238
RS
9585#endif
9586#ifdef XK_dead_tilde
7a13e894 9587 || orig_keysym == XK_dead_tilde
69388238
RS
9588#endif
9589#ifdef XK_dead_diaeresis
7a13e894 9590 || orig_keysym == XK_dead_diaeresis
69388238
RS
9591#endif
9592#ifdef XK_dead_macron
7a13e894 9593 || orig_keysym == XK_dead_macron
69388238
RS
9594#endif
9595#ifdef XK_dead_degree
7a13e894 9596 || orig_keysym == XK_dead_degree
69388238
RS
9597#endif
9598#ifdef XK_dead_acute
7a13e894 9599 || orig_keysym == XK_dead_acute
69388238
RS
9600#endif
9601#ifdef XK_dead_cedilla
7a13e894 9602 || orig_keysym == XK_dead_cedilla
69388238
RS
9603#endif
9604#ifdef XK_dead_breve
7a13e894 9605 || orig_keysym == XK_dead_breve
69388238
RS
9606#endif
9607#ifdef XK_dead_ogonek
7a13e894 9608 || orig_keysym == XK_dead_ogonek
69388238
RS
9609#endif
9610#ifdef XK_dead_caron
7a13e894 9611 || orig_keysym == XK_dead_caron
69388238
RS
9612#endif
9613#ifdef XK_dead_doubleacute
7a13e894 9614 || orig_keysym == XK_dead_doubleacute
69388238
RS
9615#endif
9616#ifdef XK_dead_abovedot
7a13e894 9617 || orig_keysym == XK_dead_abovedot
c34790e0 9618#endif
7a13e894
RS
9619 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
9620 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
9621 /* Any "vendor-specific" key is ok. */
9622 || (orig_keysym & (1 << 28)))
9623 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
9624#ifndef HAVE_X11R5
9625#ifdef XK_Mode_switch
7a13e894 9626 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
9627#endif
9628#ifdef XK_Num_Lock
7a13e894 9629 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
9630#endif
9631#endif /* not HAVE_X11R5 */
7a13e894 9632 ))
dc6f92b8 9633 {
10e6549c
RS
9634 if (temp_index == sizeof temp_buffer / sizeof (short))
9635 temp_index = 0;
7a13e894
RS
9636 temp_buffer[temp_index++] = keysym;
9637 bufp->kind = non_ascii_keystroke;
9638 bufp->code = keysym;
e0c1aef2 9639 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9640 bufp->arg = Qnil;
334208b7
RS
9641 bufp->modifiers
9642 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9643 modifiers);
1113d9db 9644 bufp->timestamp = event.xkey.time;
dc6f92b8 9645 bufp++;
7a13e894
RS
9646 count++;
9647 numchars--;
dc6f92b8 9648 }
7a13e894
RS
9649 else if (numchars > nbytes)
9650 {
9651 register int i;
9652
9653 for (i = 0; i < nbytes; i++)
9654 {
9655 if (temp_index == sizeof temp_buffer / sizeof (short))
9656 temp_index = 0;
9657 temp_buffer[temp_index++] = copy_buffer[i];
9658 bufp->kind = ascii_keystroke;
9659 bufp->code = copy_buffer[i];
9660 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9661 bufp->arg = Qnil;
7a13e894
RS
9662 bufp->modifiers
9663 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9664 modifiers);
9665 bufp->timestamp = event.xkey.time;
9666 bufp++;
9667 }
9668
9669 count += nbytes;
9670 numchars -= nbytes;
1decb680
PE
9671
9672 if (keysym == NoSymbol)
9673 break;
7a13e894
RS
9674 }
9675 else
9676 abort ();
dc6f92b8 9677 }
10e6549c
RS
9678 else
9679 abort ();
dc6f92b8 9680 }
59ddecde
GM
9681#ifdef HAVE_X_I18N
9682 /* Don't dispatch this event since XtDispatchEvent calls
9683 XFilterEvent, and two calls in a row may freeze the
9684 client. */
9685 break;
9686#else
717ca130 9687 goto OTHER;
59ddecde 9688#endif
f451eb13 9689
f5d11644 9690 case KeyRelease:
59ddecde
GM
9691#ifdef HAVE_X_I18N
9692 /* Don't dispatch this event since XtDispatchEvent calls
9693 XFilterEvent, and two calls in a row may freeze the
9694 client. */
9695 break;
9696#else
f5d11644 9697 goto OTHER;
59ddecde 9698#endif
f5d11644 9699
7a13e894 9700 /* Here's a possible interpretation of the whole
06a2c219
GM
9701 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
9702 you get a FocusIn event, you have to get a FocusOut
9703 event before you relinquish the focus. If you
9704 haven't received a FocusIn event, then a mere
9705 LeaveNotify is enough to free you. */
f451eb13 9706
7a13e894 9707 case EnterNotify:
06a2c219
GM
9708 {
9709 int from_menu_bar_p = 0;
9710
9711 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
9712
9713#ifdef LESSTIF_VERSION
9714 /* When clicking outside of a menu bar popup to close
9715 it, we get a FocusIn/ EnterNotify sequence of
9716 events. The flag event.xcrossing.focus is not set
9717 in the EnterNotify event of that sequence because
9718 the focus is in the menu bar,
9719 event.xcrossing.window is the frame's X window.
9720 Unconditionally setting the focus frame to null in
9721 this case is not the right thing, because no event
9722 follows that could set the focus frame to the right
9723 value.
9724
9725 This could be a LessTif bug, but I wasn't able to
9726 reproduce the behavior in a simple test program.
9727
9728 (gerd, LessTif 0.88.1). */
9729
9730 if (!event.xcrossing.focus
9731 && f
9732 && f->output_data.x->menubar_widget)
9733 {
9734 Window focus;
9735 int revert;
9736
9737 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9738 if (focus == XtWindow (f->output_data.x->menubar_widget))
9739 from_menu_bar_p = 1;
9740 }
9741#endif /* LESSTIF_VERSION */
6d4238f3 9742
06a2c219
GM
9743 if (event.xcrossing.focus || from_menu_bar_p)
9744 {
9745 /* Avoid nasty pop/raise loops. */
9746 if (f && (!(f->auto_raise)
9747 || !(f->auto_lower)
9748 || (event.xcrossing.time - enter_timestamp) > 500))
9749 {
9750 x_new_focus_frame (dpyinfo, f);
9751 enter_timestamp = event.xcrossing.time;
9752 }
9753 }
9754 else if (f == dpyinfo->x_focus_frame)
9755 x_new_focus_frame (dpyinfo, 0);
9756
9757 /* EnterNotify counts as mouse movement,
9758 so update things that depend on mouse position. */
9759 if (f && !f->output_data.x->busy_p)
9760 note_mouse_movement (f, &event.xmotion);
9761 goto OTHER;
9762 }
dc6f92b8 9763
7a13e894 9764 case FocusIn:
19126e11 9765 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9766 if (event.xfocus.detail != NotifyPointer)
0f941935 9767 dpyinfo->x_focus_event_frame = f;
7a13e894 9768 if (f)
eb72635f
GM
9769 {
9770 x_new_focus_frame (dpyinfo, f);
9771
9772 /* Don't stop displaying the initial startup message
9773 for a switch-frame event we don't need. */
9774 if (GC_NILP (Vterminal_frame)
9775 && GC_CONSP (Vframe_list)
9776 && !GC_NILP (XCDR (Vframe_list)))
9777 {
9778 bufp->kind = FOCUS_IN_EVENT;
9779 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9780 bufp->arg = Qnil;
eb72635f
GM
9781 ++bufp, ++count, --numchars;
9782 }
9783 }
f9e24cb9 9784
6c183ba5
RS
9785#ifdef HAVE_X_I18N
9786 if (f && FRAME_XIC (f))
9787 XSetICFocus (FRAME_XIC (f));
9788#endif
9789
7a13e894 9790 goto OTHER;
10c5e63d 9791
7a13e894 9792 case LeaveNotify:
19126e11 9793 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 9794 if (f)
10c5e63d 9795 {
06a2c219
GM
9796 Lisp_Object frame;
9797 int from_menu_bar_p = 0;
9798
7a13e894 9799 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
9800 {
9801 /* If we move outside the frame, then we're
9802 certainly no longer on any text in the frame. */
9803 clear_mouse_face (dpyinfo);
9804 dpyinfo->mouse_face_mouse_frame = 0;
9805 }
9806
9807 /* Generate a nil HELP_EVENT to cancel a help-echo.
9808 Do it only if there's something to cancel.
9809 Otherwise, the startup message is cleared when
9810 the mouse leaves the frame. */
9811 if (any_help_event_p)
9812 {
be010514
GM
9813 Lisp_Object frame;
9814 int n;
9815
06a2c219 9816 XSETFRAME (frame, f);
7cea38bc 9817 n = gen_help_event (bufp, Qnil, frame, Qnil, Qnil, 0);
be010514 9818 bufp += n, count += n, numchars -= n;
06a2c219 9819 }
7a13e894 9820
06a2c219
GM
9821#ifdef LESSTIF_VERSION
9822 /* Please see the comment at the start of the
9823 EnterNotify case. */
9824 if (!event.xcrossing.focus
9825 && f->output_data.x->menubar_widget)
9826 {
9827 Window focus;
9828 int revert;
9829 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9830 if (focus == XtWindow (f->output_data.x->menubar_widget))
9831 from_menu_bar_p = 1;
9832 }
9833#endif /* LESSTIF_VERSION */
9834
9835 if (event.xcrossing.focus || from_menu_bar_p)
0f941935 9836 x_mouse_leave (dpyinfo);
10c5e63d 9837 else
7a13e894 9838 {
0f941935
KH
9839 if (f == dpyinfo->x_focus_event_frame)
9840 dpyinfo->x_focus_event_frame = 0;
9841 if (f == dpyinfo->x_focus_frame)
9842 x_new_focus_frame (dpyinfo, 0);
7a13e894 9843 }
10c5e63d 9844 }
7a13e894 9845 goto OTHER;
dc6f92b8 9846
7a13e894 9847 case FocusOut:
19126e11 9848 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9849 if (event.xfocus.detail != NotifyPointer
0f941935
KH
9850 && f == dpyinfo->x_focus_event_frame)
9851 dpyinfo->x_focus_event_frame = 0;
9852 if (f && f == dpyinfo->x_focus_frame)
9853 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 9854
6c183ba5
RS
9855#ifdef HAVE_X_I18N
9856 if (f && FRAME_XIC (f))
9857 XUnsetICFocus (FRAME_XIC (f));
9858#endif
9859
7a13e894 9860 goto OTHER;
dc6f92b8 9861
7a13e894 9862 case MotionNotify:
dc6f92b8 9863 {
06a2c219 9864 previous_help_echo = help_echo;
7cea38bc 9865 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 9866 help_echo_pos = -1;
06a2c219 9867
7a13e894
RS
9868 if (dpyinfo->grabbed && last_mouse_frame
9869 && FRAME_LIVE_P (last_mouse_frame))
9870 f = last_mouse_frame;
9871 else
19126e11 9872 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 9873
7a13e894
RS
9874 if (f)
9875 note_mouse_movement (f, &event.xmotion);
9876 else
9877 {
e88b3c50 9878#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
9879 struct scroll_bar *bar
9880 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 9881
7a13e894
RS
9882 if (bar)
9883 x_scroll_bar_note_movement (bar, &event);
e88b3c50 9884#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 9885
06a2c219
GM
9886 /* If we move outside the frame, then we're
9887 certainly no longer on any text in the frame. */
7a13e894
RS
9888 clear_mouse_face (dpyinfo);
9889 }
06a2c219
GM
9890
9891 /* If the contents of the global variable help_echo
9892 has changed, generate a HELP_EVENT. */
b7e80413
SM
9893 if (!NILP (help_echo)
9894 || !NILP (previous_help_echo))
06a2c219
GM
9895 {
9896 Lisp_Object frame;
be010514 9897 int n;
06a2c219
GM
9898
9899 if (f)
9900 XSETFRAME (frame, f);
9901 else
9902 frame = Qnil;
9903
9904 any_help_event_p = 1;
be010514 9905 n = gen_help_event (bufp, help_echo, frame,
7cea38bc
GM
9906 help_echo_window, help_echo_object,
9907 help_echo_pos);
be010514 9908 bufp += n, count += n, numchars -= n;
06a2c219
GM
9909 }
9910
9911 goto OTHER;
dc6f92b8 9912 }
dc6f92b8 9913
7a13e894 9914 case ConfigureNotify:
9829ddba
RS
9915 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
9916 if (f)
af395ec1 9917 {
5c187dee 9918#ifndef USE_X_TOOLKIT
bf1b7b30
KH
9919 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
9920 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 9921
2d7fc7e8
RS
9922 /* In the toolkit version, change_frame_size
9923 is called by the code that handles resizing
9924 of the EmacsFrame widget. */
7a13e894 9925
7a13e894
RS
9926 /* Even if the number of character rows and columns has
9927 not changed, the font size may have changed, so we need
9928 to check the pixel dimensions as well. */
9929 if (columns != f->width
9930 || rows != f->height
7556890b
RS
9931 || event.xconfigure.width != f->output_data.x->pixel_width
9932 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 9933 {
7d1e984f 9934 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 9935 SET_FRAME_GARBAGED (f);
e687d06e 9936 cancel_mouse_face (f);
7a13e894 9937 }
2d7fc7e8 9938#endif
af395ec1 9939
7556890b
RS
9940 f->output_data.x->pixel_width = event.xconfigure.width;
9941 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
9942
9943 /* What we have now is the position of Emacs's own window.
9944 Convert that to the position of the window manager window. */
dcb07ae9
RS
9945 x_real_positions (f, &f->output_data.x->left_pos,
9946 &f->output_data.x->top_pos);
9947
f5d11644
GM
9948#ifdef HAVE_X_I18N
9949 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
9950 xic_set_statusarea (f);
9951#endif
9952
dcb07ae9
RS
9953 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
9954 {
9955 /* Since the WM decorations come below top_pos now,
9956 we must put them below top_pos in the future. */
9957 f->output_data.x->win_gravity = NorthWestGravity;
9958 x_wm_set_size_hint (f, (long) 0, 0);
9959 }
8f08dc93
KH
9960#ifdef USE_MOTIF
9961 /* Some window managers pass (0,0) as the location of
9962 the window, and the Motif event handler stores it
9963 in the emacs widget, which messes up Motif menus. */
9964 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
9965 {
9966 event.xconfigure.x = f->output_data.x->widget->core.x;
9967 event.xconfigure.y = f->output_data.x->widget->core.y;
9968 }
06a2c219 9969#endif /* USE_MOTIF */
7a13e894 9970 }
2d7fc7e8 9971 goto OTHER;
dc6f92b8 9972
7a13e894
RS
9973 case ButtonPress:
9974 case ButtonRelease:
9975 {
9976 /* If we decide we want to generate an event to be seen
9977 by the rest of Emacs, we put it here. */
9978 struct input_event emacs_event;
9ea173e8 9979 int tool_bar_p = 0;
06a2c219 9980
7a13e894 9981 emacs_event.kind = no_event;
7a13e894 9982 bzero (&compose_status, sizeof (compose_status));
9b07615b 9983
06a2c219
GM
9984 if (dpyinfo->grabbed
9985 && last_mouse_frame
9f67f20b
RS
9986 && FRAME_LIVE_P (last_mouse_frame))
9987 f = last_mouse_frame;
9988 else
2224b905 9989 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 9990
06a2c219
GM
9991 if (f)
9992 {
9ea173e8
GM
9993 /* Is this in the tool-bar? */
9994 if (WINDOWP (f->tool_bar_window)
9995 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
9996 {
9997 Lisp_Object window;
9998 int p, x, y;
9999
10000 x = event.xbutton.x;
10001 y = event.xbutton.y;
10002
10003 /* Set x and y. */
10004 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10005 if (EQ (window, f->tool_bar_window))
06a2c219 10006 {
9ea173e8
GM
10007 x_handle_tool_bar_click (f, &event.xbutton);
10008 tool_bar_p = 1;
06a2c219
GM
10009 }
10010 }
10011
9ea173e8 10012 if (!tool_bar_p)
06a2c219
GM
10013 if (!dpyinfo->x_focus_frame
10014 || f == dpyinfo->x_focus_frame)
10015 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10016 }
10017 else
10018 {
06a2c219 10019#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10020 struct scroll_bar *bar
10021 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10022
7a13e894
RS
10023 if (bar)
10024 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10025#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10026 }
10027
10028 if (event.type == ButtonPress)
10029 {
10030 dpyinfo->grabbed |= (1 << event.xbutton.button);
10031 last_mouse_frame = f;
edad46f6
KH
10032 /* Ignore any mouse motion that happened
10033 before this event; any subsequent mouse-movement
10034 Emacs events should reflect only motion after
10035 the ButtonPress. */
a00e91cd
KH
10036 if (f != 0)
10037 f->mouse_moved = 0;
06a2c219 10038
9ea173e8
GM
10039 if (!tool_bar_p)
10040 last_tool_bar_item = -1;
7a13e894 10041 }
3afe33e7
RS
10042 else
10043 {
7a13e894 10044 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10045 }
23faf38f 10046
7a13e894
RS
10047 if (numchars >= 1 && emacs_event.kind != no_event)
10048 {
10049 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10050 bufp++;
10051 count++;
10052 numchars--;
10053 }
3afe33e7
RS
10054
10055#ifdef USE_X_TOOLKIT
2224b905
RS
10056 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10057 /* For a down-event in the menu bar,
10058 don't pass it to Xt right now.
10059 Instead, save it away
10060 and we will pass it to Xt from kbd_buffer_get_event.
10061 That way, we can run some Lisp code first. */
91375f8f
RS
10062 if (f && event.type == ButtonPress
10063 /* Verify the event is really within the menu bar
10064 and not just sent to it due to grabbing. */
10065 && event.xbutton.x >= 0
10066 && event.xbutton.x < f->output_data.x->pixel_width
10067 && event.xbutton.y >= 0
10068 && event.xbutton.y < f->output_data.x->menubar_height
10069 && event.xbutton.same_screen)
2224b905 10070 {
8805890a 10071 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
10072 XSETFRAME (last_mouse_press_frame, f);
10073 }
10074 else if (event.type == ButtonPress)
10075 {
10076 last_mouse_press_frame = Qnil;
30e671c3 10077 goto OTHER;
ce89ef46 10078 }
06a2c219 10079
2237cac9
RS
10080#ifdef USE_MOTIF /* This should do not harm for Lucid,
10081 but I am trying to be cautious. */
ce89ef46
RS
10082 else if (event.type == ButtonRelease)
10083 {
2237cac9 10084 if (!NILP (last_mouse_press_frame))
f10ded1c 10085 {
2237cac9
RS
10086 f = XFRAME (last_mouse_press_frame);
10087 if (f->output_data.x)
06a2c219 10088 SET_SAVED_BUTTON_EVENT;
f10ded1c 10089 }
06a2c219 10090 else
30e671c3 10091 goto OTHER;
2224b905 10092 }
2237cac9 10093#endif /* USE_MOTIF */
2224b905
RS
10094 else
10095 goto OTHER;
3afe33e7 10096#endif /* USE_X_TOOLKIT */
7a13e894
RS
10097 }
10098 break;
dc6f92b8 10099
7a13e894 10100 case CirculateNotify:
06a2c219
GM
10101 goto OTHER;
10102
7a13e894 10103 case CirculateRequest:
06a2c219
GM
10104 goto OTHER;
10105
10106 case VisibilityNotify:
10107 goto OTHER;
dc6f92b8 10108
7a13e894
RS
10109 case MappingNotify:
10110 /* Someone has changed the keyboard mapping - update the
10111 local cache. */
10112 switch (event.xmapping.request)
10113 {
10114 case MappingModifier:
10115 x_find_modifier_meanings (dpyinfo);
10116 /* This is meant to fall through. */
10117 case MappingKeyboard:
10118 XRefreshKeyboardMapping (&event.xmapping);
10119 }
7a13e894 10120 goto OTHER;
dc6f92b8 10121
7a13e894 10122 default:
7a13e894 10123 OTHER:
717ca130 10124#ifdef USE_X_TOOLKIT
7a13e894
RS
10125 BLOCK_INPUT;
10126 XtDispatchEvent (&event);
10127 UNBLOCK_INPUT;
3afe33e7 10128#endif /* USE_X_TOOLKIT */
7a13e894
RS
10129 break;
10130 }
dc6f92b8
JB
10131 }
10132 }
10133
06a2c219
GM
10134 out:;
10135
9a5196d0
RS
10136 /* On some systems, an X bug causes Emacs to get no more events
10137 when the window is destroyed. Detect that. (1994.) */
58769bee 10138 if (! event_found)
ef2a22d0 10139 {
ef2a22d0
RS
10140 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
10141 One XNOOP in 100 loops will make Emacs terminate.
10142 B. Bretthauer, 1994 */
10143 x_noop_count++;
58769bee 10144 if (x_noop_count >= 100)
ef2a22d0
RS
10145 {
10146 x_noop_count=0;
2224b905
RS
10147
10148 if (next_noop_dpyinfo == 0)
10149 next_noop_dpyinfo = x_display_list;
10150
10151 XNoOp (next_noop_dpyinfo->display);
10152
10153 /* Each time we get here, cycle through the displays now open. */
10154 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
10155 }
10156 }
502add23 10157
06a2c219 10158 /* If the focus was just given to an auto-raising frame,
0134a210 10159 raise it now. */
7a13e894 10160 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
10161 if (pending_autoraise_frame)
10162 {
10163 x_raise_frame (pending_autoraise_frame);
10164 pending_autoraise_frame = 0;
10165 }
0134a210 10166
dc6f92b8 10167 UNBLOCK_INPUT;
bde5503b 10168 --handling_signal;
dc6f92b8
JB
10169 return count;
10170}
06a2c219
GM
10171
10172
10173
dc6f92b8 10174\f
06a2c219
GM
10175/***********************************************************************
10176 Text Cursor
10177 ***********************************************************************/
10178
10179/* Note if the text cursor of window W has been overwritten by a
10180 drawing operation that outputs N glyphs starting at HPOS in the
10181 line given by output_cursor.vpos. N < 0 means all the rest of the
10182 line after HPOS has been written. */
10183
10184static void
10185note_overwritten_text_cursor (w, hpos, n)
10186 struct window *w;
10187 int hpos, n;
10188{
10189 if (updated_area == TEXT_AREA
10190 && output_cursor.vpos == w->phys_cursor.vpos
10191 && hpos <= w->phys_cursor.hpos
10192 && (n < 0
10193 || hpos + n > w->phys_cursor.hpos))
10194 w->phys_cursor_on_p = 0;
10195}
f451eb13
JB
10196
10197
06a2c219
GM
10198/* Set clipping for output in glyph row ROW. W is the window in which
10199 we operate. GC is the graphics context to set clipping in.
10200 WHOLE_LINE_P non-zero means include the areas used for truncation
10201 mark display and alike in the clipping rectangle.
10202
10203 ROW may be a text row or, e.g., a mode line. Text rows must be
10204 clipped to the interior of the window dedicated to text display,
10205 mode lines must be clipped to the whole window. */
dc6f92b8
JB
10206
10207static void
06a2c219
GM
10208x_clip_to_row (w, row, gc, whole_line_p)
10209 struct window *w;
10210 struct glyph_row *row;
10211 GC gc;
10212 int whole_line_p;
dc6f92b8 10213{
06a2c219
GM
10214 struct frame *f = XFRAME (WINDOW_FRAME (w));
10215 XRectangle clip_rect;
10216 int window_x, window_y, window_width, window_height;
dc6f92b8 10217
06a2c219 10218 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 10219
06a2c219
GM
10220 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
10221 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
10222 clip_rect.y = max (clip_rect.y, window_y);
10223 clip_rect.width = window_width;
10224 clip_rect.height = row->visible_height;
5c1aae96 10225
06a2c219
GM
10226 /* If clipping to the whole line, including trunc marks, extend
10227 the rectangle to the left and increase its width. */
10228 if (whole_line_p)
10229 {
110859fc
GM
10230 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
10231 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 10232 }
5c1aae96 10233
06a2c219 10234 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
10235}
10236
06a2c219
GM
10237
10238/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
10239
10240static void
06a2c219
GM
10241x_draw_hollow_cursor (w, row)
10242 struct window *w;
10243 struct glyph_row *row;
dc6f92b8 10244{
06a2c219
GM
10245 struct frame *f = XFRAME (WINDOW_FRAME (w));
10246 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10247 Display *dpy = FRAME_X_DISPLAY (f);
10248 int x, y, wd, h;
10249 XGCValues xgcv;
10250 struct glyph *cursor_glyph;
10251 GC gc;
10252
10253 /* Compute frame-relative coordinates from window-relative
10254 coordinates. */
10255 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10256 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
10257 + row->ascent - w->phys_cursor_ascent);
10258 h = row->height - 1;
10259
10260 /* Get the glyph the cursor is on. If we can't tell because
10261 the current matrix is invalid or such, give up. */
10262 cursor_glyph = get_phys_cursor_glyph (w);
10263 if (cursor_glyph == NULL)
dc6f92b8
JB
10264 return;
10265
06a2c219
GM
10266 /* Compute the width of the rectangle to draw. If on a stretch
10267 glyph, and `x-stretch-block-cursor' is nil, don't draw a
10268 rectangle as wide as the glyph, but use a canonical character
10269 width instead. */
10270 wd = cursor_glyph->pixel_width - 1;
10271 if (cursor_glyph->type == STRETCH_GLYPH
10272 && !x_stretch_cursor_p)
10273 wd = min (CANON_X_UNIT (f), wd);
10274
10275 /* The foreground of cursor_gc is typically the same as the normal
10276 background color, which can cause the cursor box to be invisible. */
10277 xgcv.foreground = f->output_data.x->cursor_pixel;
10278 if (dpyinfo->scratch_cursor_gc)
10279 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
10280 else
10281 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
10282 GCForeground, &xgcv);
10283 gc = dpyinfo->scratch_cursor_gc;
10284
10285 /* Set clipping, draw the rectangle, and reset clipping again. */
10286 x_clip_to_row (w, row, gc, 0);
10287 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
10288 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
10289}
10290
06a2c219
GM
10291
10292/* Draw a bar cursor on window W in glyph row ROW.
10293
10294 Implementation note: One would like to draw a bar cursor with an
10295 angle equal to the one given by the font property XA_ITALIC_ANGLE.
10296 Unfortunately, I didn't find a font yet that has this property set.
10297 --gerd. */
dc6f92b8
JB
10298
10299static void
f02d8aa0 10300x_draw_bar_cursor (w, row, width)
06a2c219
GM
10301 struct window *w;
10302 struct glyph_row *row;
f02d8aa0 10303 int width;
dc6f92b8 10304{
06a2c219
GM
10305 /* If cursor hpos is out of bounds, don't draw garbage. This can
10306 happen in mini-buffer windows when switching between echo area
10307 glyphs and mini-buffer. */
10308 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
10309 {
10310 struct frame *f = XFRAME (w->frame);
10311 struct glyph *cursor_glyph;
10312 GC gc;
10313 int x;
10314 unsigned long mask;
10315 XGCValues xgcv;
10316 Display *dpy;
10317 Window window;
10318
10319 cursor_glyph = get_phys_cursor_glyph (w);
10320 if (cursor_glyph == NULL)
10321 return;
10322
10323 xgcv.background = f->output_data.x->cursor_pixel;
10324 xgcv.foreground = f->output_data.x->cursor_pixel;
10325 xgcv.graphics_exposures = 0;
10326 mask = GCForeground | GCBackground | GCGraphicsExposures;
10327 dpy = FRAME_X_DISPLAY (f);
10328 window = FRAME_X_WINDOW (f);
10329 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
10330
10331 if (gc)
10332 XChangeGC (dpy, gc, mask, &xgcv);
10333 else
10334 {
10335 gc = XCreateGC (dpy, window, mask, &xgcv);
10336 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
10337 }
10338
f02d8aa0
GM
10339 if (width < 0)
10340 width = f->output_data.x->cursor_width;
10341
06a2c219
GM
10342 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10343 x_clip_to_row (w, row, gc, 0);
10344 XFillRectangle (dpy, window, gc,
10345 x,
10346 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 10347 min (cursor_glyph->pixel_width, width),
06a2c219
GM
10348 row->height);
10349 XSetClipMask (dpy, gc, None);
10350 }
dc6f92b8
JB
10351}
10352
06a2c219
GM
10353
10354/* Clear the cursor of window W to background color, and mark the
10355 cursor as not shown. This is used when the text where the cursor
10356 is is about to be rewritten. */
10357
dc6f92b8 10358static void
06a2c219
GM
10359x_clear_cursor (w)
10360 struct window *w;
dc6f92b8 10361{
06a2c219
GM
10362 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
10363 x_update_window_cursor (w, 0);
10364}
90e65f07 10365
dbc4e1c1 10366
06a2c219
GM
10367/* Draw the cursor glyph of window W in glyph row ROW. See the
10368 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 10369
06a2c219
GM
10370static void
10371x_draw_phys_cursor_glyph (w, row, hl)
10372 struct window *w;
10373 struct glyph_row *row;
10374 enum draw_glyphs_face hl;
10375{
10376 /* If cursor hpos is out of bounds, don't draw garbage. This can
10377 happen in mini-buffer windows when switching between echo area
10378 glyphs and mini-buffer. */
10379 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
10380 {
10381 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
10382 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
10383 hl, 0, 0, 0);
10384
10385 /* When we erase the cursor, and ROW is overlapped by other
10386 rows, make sure that these overlapping parts of other rows
10387 are redrawn. */
10388 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
10389 {
10390 if (row > w->current_matrix->rows
10391 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
10392 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
10393
10394 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
10395 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
10396 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
10397 }
10398 }
06a2c219 10399}
dbc4e1c1 10400
eea6af04 10401
06a2c219 10402/* Erase the image of a cursor of window W from the screen. */
eea6af04 10403
06a2c219
GM
10404static void
10405x_erase_phys_cursor (w)
10406 struct window *w;
10407{
10408 struct frame *f = XFRAME (w->frame);
10409 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10410 int hpos = w->phys_cursor.hpos;
10411 int vpos = w->phys_cursor.vpos;
10412 int mouse_face_here_p = 0;
10413 struct glyph_matrix *active_glyphs = w->current_matrix;
10414 struct glyph_row *cursor_row;
10415 struct glyph *cursor_glyph;
10416 enum draw_glyphs_face hl;
10417
10418 /* No cursor displayed or row invalidated => nothing to do on the
10419 screen. */
10420 if (w->phys_cursor_type == NO_CURSOR)
10421 goto mark_cursor_off;
10422
10423 /* VPOS >= active_glyphs->nrows means that window has been resized.
10424 Don't bother to erase the cursor. */
10425 if (vpos >= active_glyphs->nrows)
10426 goto mark_cursor_off;
10427
10428 /* If row containing cursor is marked invalid, there is nothing we
10429 can do. */
10430 cursor_row = MATRIX_ROW (active_glyphs, vpos);
10431 if (!cursor_row->enabled_p)
10432 goto mark_cursor_off;
10433
10434 /* This can happen when the new row is shorter than the old one.
10435 In this case, either x_draw_glyphs or clear_end_of_line
10436 should have cleared the cursor. Note that we wouldn't be
10437 able to erase the cursor in this case because we don't have a
10438 cursor glyph at hand. */
10439 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
10440 goto mark_cursor_off;
10441
10442 /* If the cursor is in the mouse face area, redisplay that when
10443 we clear the cursor. */
8801a864
KR
10444 if (! NILP (dpyinfo->mouse_face_window)
10445 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
10446 && (vpos > dpyinfo->mouse_face_beg_row
10447 || (vpos == dpyinfo->mouse_face_beg_row
10448 && hpos >= dpyinfo->mouse_face_beg_col))
10449 && (vpos < dpyinfo->mouse_face_end_row
10450 || (vpos == dpyinfo->mouse_face_end_row
10451 && hpos < dpyinfo->mouse_face_end_col))
10452 /* Don't redraw the cursor's spot in mouse face if it is at the
10453 end of a line (on a newline). The cursor appears there, but
10454 mouse highlighting does not. */
10455 && cursor_row->used[TEXT_AREA] > hpos)
10456 mouse_face_here_p = 1;
10457
10458 /* Maybe clear the display under the cursor. */
10459 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
10460 {
10461 int x;
045dee35 10462 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 10463
06a2c219
GM
10464 cursor_glyph = get_phys_cursor_glyph (w);
10465 if (cursor_glyph == NULL)
10466 goto mark_cursor_off;
dbc4e1c1 10467
06a2c219
GM
10468 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
10469
10470 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10471 x,
045dee35 10472 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219
GM
10473 cursor_row->y)),
10474 cursor_glyph->pixel_width,
10475 cursor_row->visible_height,
10476 False);
dbc4e1c1 10477 }
06a2c219
GM
10478
10479 /* Erase the cursor by redrawing the character underneath it. */
10480 if (mouse_face_here_p)
10481 hl = DRAW_MOUSE_FACE;
10482 else if (cursor_row->inverse_p)
10483 hl = DRAW_INVERSE_VIDEO;
10484 else
10485 hl = DRAW_NORMAL_TEXT;
10486 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 10487
06a2c219
GM
10488 mark_cursor_off:
10489 w->phys_cursor_on_p = 0;
10490 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
10491}
10492
10493
06a2c219
GM
10494/* Display or clear cursor of window W. If ON is zero, clear the
10495 cursor. If it is non-zero, display the cursor. If ON is nonzero,
10496 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 10497
06a2c219
GM
10498void
10499x_display_and_set_cursor (w, on, hpos, vpos, x, y)
10500 struct window *w;
10501 int on, hpos, vpos, x, y;
dbc4e1c1 10502{
06a2c219
GM
10503 struct frame *f = XFRAME (w->frame);
10504 int new_cursor_type;
f02d8aa0 10505 int new_cursor_width;
06a2c219
GM
10506 struct glyph_matrix *current_glyphs;
10507 struct glyph_row *glyph_row;
10508 struct glyph *glyph;
dbc4e1c1 10509
49d838ea 10510 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
10511 windows and frames; in the latter case, the frame or window may
10512 be in the midst of changing its size, and x and y may be off the
10513 window. */
10514 if (! FRAME_VISIBLE_P (f)
10515 || FRAME_GARBAGED_P (f)
10516 || vpos >= w->current_matrix->nrows
10517 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
10518 return;
10519
10520 /* If cursor is off and we want it off, return quickly. */
06a2c219 10521 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
10522 return;
10523
06a2c219
GM
10524 current_glyphs = w->current_matrix;
10525 glyph_row = MATRIX_ROW (current_glyphs, vpos);
10526 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
10527
10528 /* If cursor row is not enabled, we don't really know where to
10529 display the cursor. */
10530 if (!glyph_row->enabled_p)
10531 {
10532 w->phys_cursor_on_p = 0;
10533 return;
10534 }
10535
10536 xassert (interrupt_input_blocked);
10537
10538 /* Set new_cursor_type to the cursor we want to be displayed. In a
10539 mini-buffer window, we want the cursor only to appear if we are
10540 reading input from this window. For the selected window, we want
10541 the cursor type given by the frame parameter. If explicitly
10542 marked off, draw no cursor. In all other cases, we want a hollow
10543 box cursor. */
f02d8aa0 10544 new_cursor_width = -1;
9b4a7047
GM
10545 if (cursor_in_echo_area
10546 && FRAME_HAS_MINIBUF_P (f)
10547 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 10548 {
9b4a7047
GM
10549 if (w == XWINDOW (echo_area_window))
10550 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
10551 else
10552 new_cursor_type = HOLLOW_BOX_CURSOR;
10553 }
06a2c219 10554 else
9b4a7047
GM
10555 {
10556 if (w != XWINDOW (selected_window)
10557 || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
10558 {
e55a0b79
GM
10559 extern int cursor_in_non_selected_windows;
10560
10561 if (MINI_WINDOW_P (w) || !cursor_in_non_selected_windows)
9b4a7047
GM
10562 new_cursor_type = NO_CURSOR;
10563 else
10564 new_cursor_type = HOLLOW_BOX_CURSOR;
10565 }
10566 else if (w->cursor_off_p)
10567 new_cursor_type = NO_CURSOR;
10568 else
f02d8aa0
GM
10569 {
10570 struct buffer *b = XBUFFER (w->buffer);
10571
10572 if (EQ (b->cursor_type, Qt))
10573 new_cursor_type = FRAME_DESIRED_CURSOR (f);
10574 else
10575 new_cursor_type = x_specified_cursor_type (b->cursor_type,
10576 &new_cursor_width);
10577 }
9b4a7047 10578 }
06a2c219
GM
10579
10580 /* If cursor is currently being shown and we don't want it to be or
10581 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 10582 erase it. */
06a2c219 10583 if (w->phys_cursor_on_p
dc6f92b8 10584 && (!on
06a2c219
GM
10585 || w->phys_cursor.x != x
10586 || w->phys_cursor.y != y
10587 || new_cursor_type != w->phys_cursor_type))
10588 x_erase_phys_cursor (w);
10589
10590 /* If the cursor is now invisible and we want it to be visible,
10591 display it. */
10592 if (on && !w->phys_cursor_on_p)
10593 {
10594 w->phys_cursor_ascent = glyph_row->ascent;
10595 w->phys_cursor_height = glyph_row->height;
10596
10597 /* Set phys_cursor_.* before x_draw_.* is called because some
10598 of them may need the information. */
10599 w->phys_cursor.x = x;
10600 w->phys_cursor.y = glyph_row->y;
10601 w->phys_cursor.hpos = hpos;
10602 w->phys_cursor.vpos = vpos;
10603 w->phys_cursor_type = new_cursor_type;
10604 w->phys_cursor_on_p = 1;
10605
10606 switch (new_cursor_type)
dc6f92b8 10607 {
06a2c219
GM
10608 case HOLLOW_BOX_CURSOR:
10609 x_draw_hollow_cursor (w, glyph_row);
10610 break;
10611
10612 case FILLED_BOX_CURSOR:
10613 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
10614 break;
10615
10616 case BAR_CURSOR:
f02d8aa0 10617 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
10618 break;
10619
10620 case NO_CURSOR:
10621 break;
dc6f92b8 10622
06a2c219
GM
10623 default:
10624 abort ();
10625 }
59ddecde
GM
10626
10627#ifdef HAVE_X_I18N
10628 if (w == XWINDOW (f->selected_window))
10629 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
10630 xic_set_preeditarea (w, x, y);
10631#endif
dc6f92b8
JB
10632 }
10633
06a2c219 10634#ifndef XFlush
f676886a 10635 if (updating_frame != f)
334208b7 10636 XFlush (FRAME_X_DISPLAY (f));
06a2c219 10637#endif
dc6f92b8
JB
10638}
10639
06a2c219
GM
10640
10641/* Display the cursor on window W, or clear it. X and Y are window
10642 relative pixel coordinates. HPOS and VPOS are glyph matrix
10643 positions. If W is not the selected window, display a hollow
10644 cursor. ON non-zero means display the cursor at X, Y which
10645 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 10646
dfcf069d 10647void
06a2c219
GM
10648x_display_cursor (w, on, hpos, vpos, x, y)
10649 struct window *w;
10650 int on, hpos, vpos, x, y;
dc6f92b8 10651{
f94397b5 10652 BLOCK_INPUT;
06a2c219 10653 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
10654 UNBLOCK_INPUT;
10655}
10656
06a2c219
GM
10657
10658/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
10659 Don't change the cursor's position. */
10660
dfcf069d 10661void
06a2c219 10662x_update_cursor (f, on_p)
5d46f928 10663 struct frame *f;
5d46f928 10664{
06a2c219
GM
10665 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
10666}
10667
10668
10669/* Call x_update_window_cursor with parameter ON_P on all leaf windows
10670 in the window tree rooted at W. */
10671
10672static void
10673x_update_cursor_in_window_tree (w, on_p)
10674 struct window *w;
10675 int on_p;
10676{
10677 while (w)
10678 {
10679 if (!NILP (w->hchild))
10680 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
10681 else if (!NILP (w->vchild))
10682 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
10683 else
10684 x_update_window_cursor (w, on_p);
10685
10686 w = NILP (w->next) ? 0 : XWINDOW (w->next);
10687 }
10688}
5d46f928 10689
f94397b5 10690
06a2c219
GM
10691/* Switch the display of W's cursor on or off, according to the value
10692 of ON. */
10693
10694static void
10695x_update_window_cursor (w, on)
10696 struct window *w;
10697 int on;
10698{
16b5d424
GM
10699 /* Don't update cursor in windows whose frame is in the process
10700 of being deleted. */
10701 if (w->current_matrix)
10702 {
10703 BLOCK_INPUT;
10704 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
10705 w->phys_cursor.x, w->phys_cursor.y);
10706 UNBLOCK_INPUT;
10707 }
dc6f92b8 10708}
06a2c219
GM
10709
10710
10711
dc6f92b8
JB
10712\f
10713/* Icons. */
10714
f676886a 10715/* Refresh bitmap kitchen sink icon for frame F
06a2c219 10716 when we get an expose event for it. */
dc6f92b8 10717
dfcf069d 10718void
f676886a
JB
10719refreshicon (f)
10720 struct frame *f;
dc6f92b8 10721{
06a2c219 10722 /* Normally, the window manager handles this function. */
dc6f92b8
JB
10723}
10724
dbc4e1c1 10725/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
10726
10727int
990ba854 10728x_bitmap_icon (f, file)
f676886a 10729 struct frame *f;
990ba854 10730 Lisp_Object file;
dc6f92b8 10731{
06a2c219 10732 int bitmap_id;
dc6f92b8 10733
c118dd06 10734 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10735 return 1;
10736
990ba854 10737 /* Free up our existing icon bitmap if any. */
7556890b
RS
10738 if (f->output_data.x->icon_bitmap > 0)
10739 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10740 f->output_data.x->icon_bitmap = 0;
990ba854
RS
10741
10742 if (STRINGP (file))
7f2ae036
RS
10743 bitmap_id = x_create_bitmap_from_file (f, file);
10744 else
10745 {
990ba854 10746 /* Create the GNU bitmap if necessary. */
5bf01b68 10747 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
10748 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
10749 = x_create_bitmap_from_data (f, gnu_bits,
10750 gnu_width, gnu_height);
990ba854
RS
10751
10752 /* The first time we create the GNU bitmap,
06a2c219 10753 this increments the ref-count one extra time.
990ba854
RS
10754 As a result, the GNU bitmap is never freed.
10755 That way, we don't have to worry about allocating it again. */
334208b7 10756 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 10757
334208b7 10758 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
10759 }
10760
10761 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 10762 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
10763
10764 return 0;
10765}
10766
10767
1be2d067
KH
10768/* Make the x-window of frame F use a rectangle with text.
10769 Use ICON_NAME as the text. */
dc6f92b8
JB
10770
10771int
f676886a
JB
10772x_text_icon (f, icon_name)
10773 struct frame *f;
dc6f92b8
JB
10774 char *icon_name;
10775{
c118dd06 10776 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10777 return 1;
10778
1be2d067
KH
10779#ifdef HAVE_X11R4
10780 {
10781 XTextProperty text;
10782 text.value = (unsigned char *) icon_name;
10783 text.encoding = XA_STRING;
10784 text.format = 8;
10785 text.nitems = strlen (icon_name);
10786#ifdef USE_X_TOOLKIT
7556890b 10787 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
10788 &text);
10789#else /* not USE_X_TOOLKIT */
10790 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
10791#endif /* not USE_X_TOOLKIT */
10792 }
10793#else /* not HAVE_X11R4 */
10794 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
10795#endif /* not HAVE_X11R4 */
58769bee 10796
7556890b
RS
10797 if (f->output_data.x->icon_bitmap > 0)
10798 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10799 f->output_data.x->icon_bitmap = 0;
b1c884c3 10800 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
10801
10802 return 0;
10803}
10804\f
e99db5a1
RS
10805#define X_ERROR_MESSAGE_SIZE 200
10806
10807/* If non-nil, this should be a string.
10808 It means catch X errors and store the error message in this string. */
10809
10810static Lisp_Object x_error_message_string;
10811
10812/* An X error handler which stores the error message in
10813 x_error_message_string. This is called from x_error_handler if
10814 x_catch_errors is in effect. */
10815
06a2c219 10816static void
e99db5a1
RS
10817x_error_catcher (display, error)
10818 Display *display;
10819 XErrorEvent *error;
10820{
10821 XGetErrorText (display, error->error_code,
10822 XSTRING (x_error_message_string)->data,
10823 X_ERROR_MESSAGE_SIZE);
10824}
10825
10826/* Begin trapping X errors for display DPY. Actually we trap X errors
10827 for all displays, but DPY should be the display you are actually
10828 operating on.
10829
10830 After calling this function, X protocol errors no longer cause
10831 Emacs to exit; instead, they are recorded in the string
10832 stored in x_error_message_string.
10833
10834 Calling x_check_errors signals an Emacs error if an X error has
10835 occurred since the last call to x_catch_errors or x_check_errors.
10836
10837 Calling x_uncatch_errors resumes the normal error handling. */
10838
10839void x_check_errors ();
10840static Lisp_Object x_catch_errors_unwind ();
10841
10842int
10843x_catch_errors (dpy)
10844 Display *dpy;
10845{
10846 int count = specpdl_ptr - specpdl;
10847
10848 /* Make sure any errors from previous requests have been dealt with. */
10849 XSync (dpy, False);
10850
10851 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
10852
10853 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
10854 XSTRING (x_error_message_string)->data[0] = 0;
10855
10856 return count;
10857}
10858
10859/* Unbind the binding that we made to check for X errors. */
10860
10861static Lisp_Object
10862x_catch_errors_unwind (old_val)
10863 Lisp_Object old_val;
10864{
10865 x_error_message_string = old_val;
10866 return Qnil;
10867}
10868
10869/* If any X protocol errors have arrived since the last call to
10870 x_catch_errors or x_check_errors, signal an Emacs error using
10871 sprintf (a buffer, FORMAT, the x error message text) as the text. */
10872
10873void
10874x_check_errors (dpy, format)
10875 Display *dpy;
10876 char *format;
10877{
10878 /* Make sure to catch any errors incurred so far. */
10879 XSync (dpy, False);
10880
10881 if (XSTRING (x_error_message_string)->data[0])
10882 error (format, XSTRING (x_error_message_string)->data);
10883}
10884
9829ddba
RS
10885/* Nonzero if we had any X protocol errors
10886 since we did x_catch_errors on DPY. */
e99db5a1
RS
10887
10888int
10889x_had_errors_p (dpy)
10890 Display *dpy;
10891{
10892 /* Make sure to catch any errors incurred so far. */
10893 XSync (dpy, False);
10894
10895 return XSTRING (x_error_message_string)->data[0] != 0;
10896}
10897
9829ddba
RS
10898/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
10899
06a2c219 10900void
9829ddba
RS
10901x_clear_errors (dpy)
10902 Display *dpy;
10903{
10904 XSTRING (x_error_message_string)->data[0] = 0;
10905}
10906
e99db5a1
RS
10907/* Stop catching X protocol errors and let them make Emacs die.
10908 DPY should be the display that was passed to x_catch_errors.
10909 COUNT should be the value that was returned by
10910 the corresponding call to x_catch_errors. */
10911
10912void
10913x_uncatch_errors (dpy, count)
10914 Display *dpy;
10915 int count;
10916{
10917 unbind_to (count, Qnil);
10918}
10919
10920#if 0
10921static unsigned int x_wire_count;
10922x_trace_wire ()
10923{
10924 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
10925}
10926#endif /* ! 0 */
10927
10928\f
10929/* Handle SIGPIPE, which can happen when the connection to a server
10930 simply goes away. SIGPIPE is handled by x_connection_signal.
10931 Don't need to do anything, because the write which caused the
10932 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 10933 which will do the appropriate cleanup for us. */
e99db5a1
RS
10934
10935static SIGTYPE
10936x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 10937 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
10938{
10939#ifdef USG
10940 /* USG systems forget handlers when they are used;
10941 must reestablish each time */
10942 signal (signalnum, x_connection_signal);
10943#endif /* USG */
10944}
10945\f
4746118a
JB
10946/* Handling X errors. */
10947
7a13e894 10948/* Handle the loss of connection to display DISPLAY. */
16bd92ea 10949
4746118a 10950static SIGTYPE
7a13e894
RS
10951x_connection_closed (display, error_message)
10952 Display *display;
10953 char *error_message;
4746118a 10954{
7a13e894
RS
10955 struct x_display_info *dpyinfo = x_display_info_for_display (display);
10956 Lisp_Object frame, tail;
10957
6186a4a0
RS
10958 /* Indicate that this display is dead. */
10959
2e465cdd 10960#if 0 /* Closing the display caused a bus error on OpenWindows. */
f613a4c8 10961#ifdef USE_X_TOOLKIT
adabc3a9 10962 XtCloseDisplay (display);
2e465cdd 10963#endif
f613a4c8 10964#endif
adabc3a9 10965
9e80b57d
KR
10966 if (dpyinfo)
10967 dpyinfo->display = 0;
6186a4a0 10968
06a2c219 10969 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
10970 that are on the dead display. */
10971 FOR_EACH_FRAME (tail, frame)
10972 {
10973 Lisp_Object minibuf_frame;
10974 minibuf_frame
10975 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
10976 if (FRAME_X_P (XFRAME (frame))
10977 && FRAME_X_P (XFRAME (minibuf_frame))
10978 && ! EQ (frame, minibuf_frame)
10979 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
10980 Fdelete_frame (frame, Qt);
10981 }
10982
10983 /* Now delete all remaining frames on the dead display.
06a2c219 10984 We are now sure none of these is used as the mini-buffer
7a13e894
RS
10985 for another frame that we need to delete. */
10986 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
10987 if (FRAME_X_P (XFRAME (frame))
10988 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
10989 {
10990 /* Set this to t so that Fdelete_frame won't get confused
10991 trying to find a replacement. */
10992 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
10993 Fdelete_frame (frame, Qt);
10994 }
7a13e894 10995
482a1bd2
KH
10996 if (dpyinfo)
10997 x_delete_display (dpyinfo);
7a13e894
RS
10998
10999 if (x_display_list == 0)
11000 {
f8d07b62 11001 fprintf (stderr, "%s\n", error_message);
7a13e894
RS
11002 shut_down_emacs (0, 0, Qnil);
11003 exit (70);
11004 }
12ba150f 11005
7a13e894
RS
11006 /* Ordinary stack unwind doesn't deal with these. */
11007#ifdef SIGIO
11008 sigunblock (sigmask (SIGIO));
11009#endif
11010 sigunblock (sigmask (SIGALRM));
11011 TOTALLY_UNBLOCK_INPUT;
11012
aa4d9a9e 11013 clear_waiting_for_input ();
7a13e894 11014 error ("%s", error_message);
4746118a
JB
11015}
11016
7a13e894
RS
11017/* This is the usual handler for X protocol errors.
11018 It kills all frames on the display that we got the error for.
11019 If that was the only one, it prints an error message and kills Emacs. */
11020
06a2c219 11021static void
c118dd06
JB
11022x_error_quitter (display, error)
11023 Display *display;
11024 XErrorEvent *error;
11025{
7a13e894 11026 char buf[256], buf1[356];
dc6f92b8 11027
58769bee 11028 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 11029 original error handler. */
dc6f92b8 11030
c118dd06 11031 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 11032 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 11033 buf, error->request_code);
7a13e894 11034 x_connection_closed (display, buf1);
dc6f92b8
JB
11035}
11036
e99db5a1
RS
11037/* This is the first-level handler for X protocol errors.
11038 It calls x_error_quitter or x_error_catcher. */
7a13e894 11039
8922af5f 11040static int
e99db5a1 11041x_error_handler (display, error)
8922af5f 11042 Display *display;
e99db5a1 11043 XErrorEvent *error;
8922af5f 11044{
e99db5a1
RS
11045 if (! NILP (x_error_message_string))
11046 x_error_catcher (display, error);
11047 else
11048 x_error_quitter (display, error);
06a2c219 11049 return 0;
f9e24cb9 11050}
c118dd06 11051
e99db5a1
RS
11052/* This is the handler for X IO errors, always.
11053 It kills all frames on the display that we lost touch with.
11054 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 11055
c118dd06 11056static int
e99db5a1 11057x_io_error_quitter (display)
c118dd06 11058 Display *display;
c118dd06 11059{
e99db5a1 11060 char buf[256];
dc6f92b8 11061
e99db5a1
RS
11062 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
11063 x_connection_closed (display, buf);
06a2c219 11064 return 0;
dc6f92b8 11065}
dc6f92b8 11066\f
f451eb13
JB
11067/* Changing the font of the frame. */
11068
76bcdf39
RS
11069/* Give frame F the font named FONTNAME as its default font, and
11070 return the full name of that font. FONTNAME may be a wildcard
11071 pattern; in that case, we choose some font that fits the pattern.
11072 The return value shows which font we chose. */
11073
b5cf7a0e 11074Lisp_Object
f676886a
JB
11075x_new_font (f, fontname)
11076 struct frame *f;
dc6f92b8
JB
11077 register char *fontname;
11078{
dc43ef94 11079 struct font_info *fontp
ee569018 11080 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 11081
dc43ef94
KH
11082 if (!fontp)
11083 return Qnil;
2224a5fc 11084
dc43ef94 11085 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 11086 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
11087 f->output_data.x->fontset = -1;
11088
b2cad826
KH
11089 /* Compute the scroll bar width in character columns. */
11090 if (f->scroll_bar_pixel_width > 0)
11091 {
7556890b 11092 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
11093 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
11094 }
11095 else
4e61bddf
RS
11096 {
11097 int wid = FONT_WIDTH (f->output_data.x->font);
11098 f->scroll_bar_cols = (14 + wid - 1) / wid;
11099 }
b2cad826 11100
f676886a 11101 /* Now make the frame display the given font. */
c118dd06 11102 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 11103 {
7556890b
RS
11104 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
11105 f->output_data.x->font->fid);
11106 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
11107 f->output_data.x->font->fid);
11108 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
11109 f->output_data.x->font->fid);
f676886a 11110
a27f9f86 11111 frame_update_line_height (f);
0134a210 11112 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 11113 }
a27f9f86
RS
11114 else
11115 /* If we are setting a new frame's font for the first time,
11116 there are no faces yet, so this font's height is the line height. */
7556890b 11117 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 11118
dc43ef94
KH
11119 return build_string (fontp->full_name);
11120}
11121
11122/* Give frame F the fontset named FONTSETNAME as its default font, and
11123 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
11124 pattern; in that case, we choose some fontset that fits the pattern.
11125 The return value shows which fontset we chose. */
b5cf7a0e 11126
dc43ef94
KH
11127Lisp_Object
11128x_new_fontset (f, fontsetname)
11129 struct frame *f;
11130 char *fontsetname;
11131{
ee569018 11132 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 11133 Lisp_Object result;
b5cf7a0e 11134
dc43ef94
KH
11135 if (fontset < 0)
11136 return Qnil;
b5cf7a0e 11137
2da424f1
KH
11138 if (f->output_data.x->fontset == fontset)
11139 /* This fontset is already set in frame F. There's nothing more
11140 to do. */
ee569018 11141 return fontset_name (fontset);
dc43ef94 11142
ee569018 11143 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
11144
11145 if (!STRINGP (result))
11146 /* Can't load ASCII font. */
11147 return Qnil;
11148
11149 /* Since x_new_font doesn't update any fontset information, do it now. */
11150 f->output_data.x->fontset = fontset;
dc43ef94 11151
f5d11644
GM
11152#ifdef HAVE_X_I18N
11153 if (FRAME_XIC (f)
11154 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 11155 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
11156#endif
11157
dc43ef94 11158 return build_string (fontsetname);
dc6f92b8 11159}
f5d11644
GM
11160
11161\f
11162/***********************************************************************
11163 X Input Methods
11164 ***********************************************************************/
11165
11166#ifdef HAVE_X_I18N
11167
11168#ifdef HAVE_X11R6
11169
11170/* XIM destroy callback function, which is called whenever the
11171 connection to input method XIM dies. CLIENT_DATA contains a
11172 pointer to the x_display_info structure corresponding to XIM. */
11173
11174static void
11175xim_destroy_callback (xim, client_data, call_data)
11176 XIM xim;
11177 XPointer client_data;
11178 XPointer call_data;
11179{
11180 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
11181 Lisp_Object frame, tail;
11182
11183 BLOCK_INPUT;
11184
11185 /* No need to call XDestroyIC.. */
11186 FOR_EACH_FRAME (tail, frame)
11187 {
11188 struct frame *f = XFRAME (frame);
11189 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
11190 {
11191 FRAME_XIC (f) = NULL;
11192 if (FRAME_XIC_FONTSET (f))
11193 {
11194 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
11195 FRAME_XIC_FONTSET (f) = NULL;
11196 }
11197 }
11198 }
11199
11200 /* No need to call XCloseIM. */
11201 dpyinfo->xim = NULL;
11202 XFree (dpyinfo->xim_styles);
11203 UNBLOCK_INPUT;
11204}
11205
11206#endif /* HAVE_X11R6 */
11207
11208/* Open the connection to the XIM server on display DPYINFO.
11209 RESOURCE_NAME is the resource name Emacs uses. */
11210
11211static void
11212xim_open_dpy (dpyinfo, resource_name)
11213 struct x_display_info *dpyinfo;
11214 char *resource_name;
11215{
287f7dd6 11216#ifdef USE_XIM
f5d11644
GM
11217 XIM xim;
11218
11219 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
11220 dpyinfo->xim = xim;
11221
11222 if (xim)
11223 {
f5d11644
GM
11224#ifdef HAVE_X11R6
11225 XIMCallback destroy;
11226#endif
11227
11228 /* Get supported styles and XIM values. */
11229 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
11230
11231#ifdef HAVE_X11R6
11232 destroy.callback = xim_destroy_callback;
11233 destroy.client_data = (XPointer)dpyinfo;
68642df6 11234 /* This isn't prptotyped in OSF 5.0. */
f5d11644
GM
11235 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
11236#endif
11237 }
287f7dd6
GM
11238
11239#else /* not USE_XIM */
11240 dpyinfo->xim = NULL;
11241#endif /* not USE_XIM */
f5d11644
GM
11242}
11243
11244
b9de836c 11245#ifdef HAVE_X11R6_XIM
f5d11644
GM
11246
11247struct xim_inst_t
11248{
11249 struct x_display_info *dpyinfo;
11250 char *resource_name;
11251};
11252
11253/* XIM instantiate callback function, which is called whenever an XIM
11254 server is available. DISPLAY is teh display of the XIM.
11255 CLIENT_DATA contains a pointer to an xim_inst_t structure created
11256 when the callback was registered. */
11257
11258static void
11259xim_instantiate_callback (display, client_data, call_data)
11260 Display *display;
11261 XPointer client_data;
11262 XPointer call_data;
11263{
11264 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
11265 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
11266
11267 /* We don't support multiple XIM connections. */
11268 if (dpyinfo->xim)
11269 return;
11270
11271 xim_open_dpy (dpyinfo, xim_inst->resource_name);
11272
11273 /* Create XIC for the existing frames on the same display, as long
11274 as they have no XIC. */
11275 if (dpyinfo->xim && dpyinfo->reference_count > 0)
11276 {
11277 Lisp_Object tail, frame;
11278
11279 BLOCK_INPUT;
11280 FOR_EACH_FRAME (tail, frame)
11281 {
11282 struct frame *f = XFRAME (frame);
11283
11284 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
11285 if (FRAME_XIC (f) == NULL)
11286 {
11287 create_frame_xic (f);
11288 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
11289 xic_set_statusarea (f);
11290 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
11291 {
11292 struct window *w = XWINDOW (f->selected_window);
11293 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
11294 }
11295 }
11296 }
11297
11298 UNBLOCK_INPUT;
11299 }
11300}
11301
b9de836c 11302#endif /* HAVE_X11R6_XIM */
f5d11644
GM
11303
11304
11305/* Open a connection to the XIM server on display DPYINFO.
11306 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
11307 connection only at the first time. On X11R6, open the connection
11308 in the XIM instantiate callback function. */
11309
11310static void
11311xim_initialize (dpyinfo, resource_name)
11312 struct x_display_info *dpyinfo;
11313 char *resource_name;
11314{
287f7dd6 11315#ifdef USE_XIM
b9de836c 11316#ifdef HAVE_X11R6_XIM
f5d11644
GM
11317 struct xim_inst_t *xim_inst;
11318 int len;
11319
11320 dpyinfo->xim = NULL;
11321 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
11322 xim_inst->dpyinfo = dpyinfo;
11323 len = strlen (resource_name);
11324 xim_inst->resource_name = (char *) xmalloc (len + 1);
11325 bcopy (resource_name, xim_inst->resource_name, len + 1);
11326 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11327 resource_name, EMACS_CLASS,
11328 xim_instantiate_callback,
2ebb2f8b
DL
11329 /* Fixme: This is XPointer in
11330 XFree86 but (XPointer *) on
11331 Tru64, at least. */
11332 (XPointer) xim_inst);
b9de836c 11333#else /* not HAVE_X11R6_XIM */
f5d11644
GM
11334 dpyinfo->xim = NULL;
11335 xim_open_dpy (dpyinfo, resource_name);
b9de836c 11336#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
11337
11338#else /* not USE_XIM */
11339 dpyinfo->xim = NULL;
11340#endif /* not USE_XIM */
f5d11644
GM
11341}
11342
11343
11344/* Close the connection to the XIM server on display DPYINFO. */
11345
11346static void
11347xim_close_dpy (dpyinfo)
11348 struct x_display_info *dpyinfo;
11349{
287f7dd6 11350#ifdef USE_XIM
b9de836c 11351#ifdef HAVE_X11R6_XIM
f5d11644
GM
11352 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11353 NULL, EMACS_CLASS,
11354 xim_instantiate_callback, NULL);
b9de836c 11355#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11356 XCloseIM (dpyinfo->xim);
11357 dpyinfo->xim = NULL;
11358 XFree (dpyinfo->xim_styles);
287f7dd6 11359#endif /* USE_XIM */
f5d11644
GM
11360}
11361
b9de836c 11362#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11363
11364
dc6f92b8 11365\f
2e365682
RS
11366/* Calculate the absolute position in frame F
11367 from its current recorded position values and gravity. */
11368
dfcf069d 11369void
43bca5d5 11370x_calc_absolute_position (f)
f676886a 11371 struct frame *f;
dc6f92b8 11372{
06a2c219 11373 Window child;
6dba1858 11374 int win_x = 0, win_y = 0;
7556890b 11375 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
11376 int this_window;
11377
9829ddba
RS
11378 /* We have nothing to do if the current position
11379 is already for the top-left corner. */
11380 if (! ((flags & XNegative) || (flags & YNegative)))
11381 return;
11382
c81412a0 11383#ifdef USE_X_TOOLKIT
7556890b 11384 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
11385#else
11386 this_window = FRAME_X_WINDOW (f);
11387#endif
6dba1858
RS
11388
11389 /* Find the position of the outside upper-left corner of
9829ddba
RS
11390 the inner window, with respect to the outer window.
11391 But do this only if we will need the results. */
7556890b 11392 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 11393 {
9829ddba
RS
11394 int count;
11395
6dba1858 11396 BLOCK_INPUT;
9829ddba
RS
11397 count = x_catch_errors (FRAME_X_DISPLAY (f));
11398 while (1)
11399 {
11400 x_clear_errors (FRAME_X_DISPLAY (f));
11401 XTranslateCoordinates (FRAME_X_DISPLAY (f),
11402
11403 /* From-window, to-window. */
11404 this_window,
11405 f->output_data.x->parent_desc,
11406
11407 /* From-position, to-position. */
11408 0, 0, &win_x, &win_y,
11409
11410 /* Child of win. */
11411 &child);
11412 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
11413 {
11414 Window newroot, newparent = 0xdeadbeef;
11415 Window *newchildren;
2ebb2f8b 11416 unsigned int nchildren;
9829ddba
RS
11417
11418 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
11419 &newparent, &newchildren, &nchildren))
11420 break;
58769bee 11421
7c3c78a3 11422 XFree ((char *) newchildren);
6dba1858 11423
9829ddba
RS
11424 f->output_data.x->parent_desc = newparent;
11425 }
11426 else
11427 break;
11428 }
6dba1858 11429
9829ddba 11430 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
11431 UNBLOCK_INPUT;
11432 }
11433
11434 /* Treat negative positions as relative to the leftmost bottommost
11435 position that fits on the screen. */
20f55f9a 11436 if (flags & XNegative)
7556890b 11437 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
11438 - 2 * f->output_data.x->border_width - win_x
11439 - PIXEL_WIDTH (f)
11440 + f->output_data.x->left_pos);
dc6f92b8 11441
20f55f9a 11442 if (flags & YNegative)
06a2c219
GM
11443 {
11444 int menubar_height = 0;
11445
11446#ifdef USE_X_TOOLKIT
11447 if (f->output_data.x->menubar_widget)
11448 menubar_height
11449 = (f->output_data.x->menubar_widget->core.height
11450 + f->output_data.x->menubar_widget->core.border_width);
11451#endif
11452
11453 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
11454 - 2 * f->output_data.x->border_width
11455 - win_y
11456 - PIXEL_HEIGHT (f)
11457 - menubar_height
11458 + f->output_data.x->top_pos);
11459 }
2e365682 11460
3a35ab44
RS
11461 /* The left_pos and top_pos
11462 are now relative to the top and left screen edges,
11463 so the flags should correspond. */
7556890b 11464 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
11465}
11466
3a35ab44
RS
11467/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
11468 to really change the position, and 0 when calling from
11469 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
11470 position values). It is -1 when calling from x_set_frame_parameters,
11471 which means, do adjust for borders but don't change the gravity. */
3a35ab44 11472
dfcf069d 11473void
dc05a16b 11474x_set_offset (f, xoff, yoff, change_gravity)
f676886a 11475 struct frame *f;
dc6f92b8 11476 register int xoff, yoff;
dc05a16b 11477 int change_gravity;
dc6f92b8 11478{
4a4cbdd5
KH
11479 int modified_top, modified_left;
11480
aa3ff7c9 11481 if (change_gravity > 0)
3a35ab44 11482 {
7556890b
RS
11483 f->output_data.x->top_pos = yoff;
11484 f->output_data.x->left_pos = xoff;
11485 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 11486 if (xoff < 0)
7556890b 11487 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 11488 if (yoff < 0)
7556890b
RS
11489 f->output_data.x->size_hint_flags |= YNegative;
11490 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 11491 }
43bca5d5 11492 x_calc_absolute_position (f);
dc6f92b8
JB
11493
11494 BLOCK_INPUT;
c32cdd9a 11495 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 11496
7556890b
RS
11497 modified_left = f->output_data.x->left_pos;
11498 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
11499#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
11500 this seems to be unnecessary and incorrect. rms, 4/17/97. */
11501 /* It is a mystery why we need to add the border_width here
11502 when the frame is already visible, but experiment says we do. */
aa3ff7c9 11503 if (change_gravity != 0)
4a4cbdd5 11504 {
7556890b
RS
11505 modified_left += f->output_data.x->border_width;
11506 modified_top += f->output_data.x->border_width;
4a4cbdd5 11507 }
e73ec6fa 11508#endif
4a4cbdd5 11509
3afe33e7 11510#ifdef USE_X_TOOLKIT
7556890b 11511 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 11512 modified_left, modified_top);
3afe33e7 11513#else /* not USE_X_TOOLKIT */
334208b7 11514 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 11515 modified_left, modified_top);
3afe33e7 11516#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11517 UNBLOCK_INPUT;
11518}
11519
bc20ebbf
FP
11520/* Call this to change the size of frame F's x-window.
11521 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
11522 for this size change and subsequent size changes.
11523 Otherwise we leave the window gravity unchanged. */
dc6f92b8 11524
dfcf069d 11525void
bc20ebbf 11526x_set_window_size (f, change_gravity, cols, rows)
f676886a 11527 struct frame *f;
bc20ebbf 11528 int change_gravity;
b1c884c3 11529 int cols, rows;
dc6f92b8 11530{
06a2c219 11531#ifndef USE_X_TOOLKIT
dc6f92b8 11532 int pixelwidth, pixelheight;
06a2c219 11533#endif
dc6f92b8 11534
80fd1fe2 11535 BLOCK_INPUT;
aee9a898
RS
11536
11537#ifdef USE_X_TOOLKIT
3a20653d
RS
11538 {
11539 /* The x and y position of the widget is clobbered by the
11540 call to XtSetValues within EmacsFrameSetCharSize.
11541 This is a real kludge, but I don't understand Xt so I can't
11542 figure out a correct fix. Can anyone else tell me? -- rms. */
7556890b
RS
11543 int xpos = f->output_data.x->widget->core.x;
11544 int ypos = f->output_data.x->widget->core.y;
11545 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
11546 f->output_data.x->widget->core.x = xpos;
11547 f->output_data.x->widget->core.y = ypos;
3a20653d 11548 }
80fd1fe2
FP
11549
11550#else /* not USE_X_TOOLKIT */
11551
b1c884c3 11552 check_frame_size (f, &rows, &cols);
7556890b 11553 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
11554 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
11555 ? 0
11556 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 11557 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 11558 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 11559 f->output_data.x->flags_areas_extra
110859fc 11560 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
11561 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
11562 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 11563
7556890b 11564 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 11565 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 11566
334208b7
RS
11567 XSync (FRAME_X_DISPLAY (f), False);
11568 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11569 pixelwidth, pixelheight);
b1c884c3
JB
11570
11571 /* Now, strictly speaking, we can't be sure that this is accurate,
11572 but the window manager will get around to dealing with the size
11573 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
11574 ConfigureNotify event gets here.
11575
11576 We could just not bother storing any of this information here,
11577 and let the ConfigureNotify event set everything up, but that
fddd5ceb 11578 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 11579 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
11580 point in the future when the ConfigureNotify event arrives.
11581
11582 We pass 1 for DELAY since we can't run Lisp code inside of
11583 a BLOCK_INPUT. */
7d1e984f 11584 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
11585 PIXEL_WIDTH (f) = pixelwidth;
11586 PIXEL_HEIGHT (f) = pixelheight;
11587
aee9a898
RS
11588 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
11589 receive in the ConfigureNotify event; if we get what we asked
11590 for, then the event won't cause the screen to become garbaged, so
11591 we have to make sure to do it here. */
11592 SET_FRAME_GARBAGED (f);
11593
11594 XFlush (FRAME_X_DISPLAY (f));
11595
11596#endif /* not USE_X_TOOLKIT */
11597
4d73d038 11598 /* If cursor was outside the new size, mark it as off. */
06a2c219 11599 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 11600
aee9a898
RS
11601 /* Clear out any recollection of where the mouse highlighting was,
11602 since it might be in a place that's outside the new frame size.
11603 Actually checking whether it is outside is a pain in the neck,
11604 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 11605 cancel_mouse_face (f);
dbc4e1c1 11606
dc6f92b8
JB
11607 UNBLOCK_INPUT;
11608}
dc6f92b8 11609\f
d047c4eb 11610/* Mouse warping. */
dc6f92b8 11611
9b378208 11612void
f676886a
JB
11613x_set_mouse_position (f, x, y)
11614 struct frame *f;
dc6f92b8
JB
11615 int x, y;
11616{
11617 int pix_x, pix_y;
11618
7556890b
RS
11619 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
11620 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
11621
11622 if (pix_x < 0) pix_x = 0;
11623 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
11624
11625 if (pix_y < 0) pix_y = 0;
11626 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
11627
11628 BLOCK_INPUT;
dc6f92b8 11629
334208b7
RS
11630 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11631 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
11632 UNBLOCK_INPUT;
11633}
11634
9b378208
RS
11635/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
11636
11637void
11638x_set_mouse_pixel_position (f, pix_x, pix_y)
11639 struct frame *f;
11640 int pix_x, pix_y;
11641{
11642 BLOCK_INPUT;
11643
334208b7
RS
11644 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11645 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
11646 UNBLOCK_INPUT;
11647}
d047c4eb
KH
11648\f
11649/* focus shifting, raising and lowering. */
9b378208 11650
dfcf069d 11651void
f676886a
JB
11652x_focus_on_frame (f)
11653 struct frame *f;
dc6f92b8 11654{
1fb20991 11655#if 0 /* This proves to be unpleasant. */
f676886a 11656 x_raise_frame (f);
1fb20991 11657#endif
6d4238f3
JB
11658#if 0
11659 /* I don't think that the ICCCM allows programs to do things like this
11660 without the interaction of the window manager. Whatever you end up
f676886a 11661 doing with this code, do it to x_unfocus_frame too. */
334208b7 11662 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 11663 RevertToPointerRoot, CurrentTime);
c118dd06 11664#endif /* ! 0 */
dc6f92b8
JB
11665}
11666
dfcf069d 11667void
f676886a
JB
11668x_unfocus_frame (f)
11669 struct frame *f;
dc6f92b8 11670{
6d4238f3 11671#if 0
f676886a 11672 /* Look at the remarks in x_focus_on_frame. */
0f941935 11673 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 11674 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 11675 RevertToPointerRoot, CurrentTime);
c118dd06 11676#endif /* ! 0 */
dc6f92b8
JB
11677}
11678
f676886a 11679/* Raise frame F. */
dc6f92b8 11680
dfcf069d 11681void
f676886a
JB
11682x_raise_frame (f)
11683 struct frame *f;
dc6f92b8 11684{
3a88c238 11685 if (f->async_visible)
dc6f92b8
JB
11686 {
11687 BLOCK_INPUT;
3afe33e7 11688#ifdef USE_X_TOOLKIT
7556890b 11689 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11690#else /* not USE_X_TOOLKIT */
334208b7 11691 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11692#endif /* not USE_X_TOOLKIT */
334208b7 11693 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11694 UNBLOCK_INPUT;
11695 }
11696}
11697
f676886a 11698/* Lower frame F. */
dc6f92b8 11699
dfcf069d 11700void
f676886a
JB
11701x_lower_frame (f)
11702 struct frame *f;
dc6f92b8 11703{
3a88c238 11704 if (f->async_visible)
dc6f92b8
JB
11705 {
11706 BLOCK_INPUT;
3afe33e7 11707#ifdef USE_X_TOOLKIT
7556890b 11708 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11709#else /* not USE_X_TOOLKIT */
334208b7 11710 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11711#endif /* not USE_X_TOOLKIT */
334208b7 11712 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11713 UNBLOCK_INPUT;
11714 }
11715}
11716
dbc4e1c1 11717static void
6b0442dc 11718XTframe_raise_lower (f, raise_flag)
dbc4e1c1 11719 FRAME_PTR f;
6b0442dc 11720 int raise_flag;
dbc4e1c1 11721{
6b0442dc 11722 if (raise_flag)
dbc4e1c1
JB
11723 x_raise_frame (f);
11724 else
11725 x_lower_frame (f);
11726}
d047c4eb
KH
11727\f
11728/* Change of visibility. */
dc6f92b8 11729
9382638d
KH
11730/* This tries to wait until the frame is really visible.
11731 However, if the window manager asks the user where to position
11732 the frame, this will return before the user finishes doing that.
11733 The frame will not actually be visible at that time,
11734 but it will become visible later when the window manager
11735 finishes with it. */
11736
dfcf069d 11737void
f676886a
JB
11738x_make_frame_visible (f)
11739 struct frame *f;
dc6f92b8 11740{
990ba854 11741 Lisp_Object type;
1aa6072f 11742 int original_top, original_left;
dc6f92b8 11743
dc6f92b8 11744 BLOCK_INPUT;
dc6f92b8 11745
990ba854
RS
11746 type = x_icon_type (f);
11747 if (!NILP (type))
11748 x_bitmap_icon (f, type);
bdcd49ba 11749
f676886a 11750 if (! FRAME_VISIBLE_P (f))
90e65f07 11751 {
1aa6072f
RS
11752 /* We test FRAME_GARBAGED_P here to make sure we don't
11753 call x_set_offset a second time
11754 if we get to x_make_frame_visible a second time
11755 before the window gets really visible. */
11756 if (! FRAME_ICONIFIED_P (f)
11757 && ! f->output_data.x->asked_for_visible)
11758 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
11759
11760 f->output_data.x->asked_for_visible = 1;
11761
90e65f07 11762 if (! EQ (Vx_no_window_manager, Qt))
f676886a 11763 x_wm_set_window_state (f, NormalState);
3afe33e7 11764#ifdef USE_X_TOOLKIT
d7a38a2e 11765 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11766 XtMapWidget (f->output_data.x->widget);
3afe33e7 11767#else /* not USE_X_TOOLKIT */
7f9c7f94 11768 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11769#endif /* not USE_X_TOOLKIT */
0134a210
RS
11770#if 0 /* This seems to bring back scroll bars in the wrong places
11771 if the window configuration has changed. They seem
11772 to come back ok without this. */
ab648270 11773 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 11774 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 11775#endif
90e65f07 11776 }
dc6f92b8 11777
334208b7 11778 XFlush (FRAME_X_DISPLAY (f));
90e65f07 11779
0dacf791
RS
11780 /* Synchronize to ensure Emacs knows the frame is visible
11781 before we do anything else. We do this loop with input not blocked
11782 so that incoming events are handled. */
11783 {
11784 Lisp_Object frame;
12ce2351 11785 int count;
28c01ffe
RS
11786 /* This must be before UNBLOCK_INPUT
11787 since events that arrive in response to the actions above
11788 will set it when they are handled. */
11789 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
11790
11791 original_left = f->output_data.x->left_pos;
11792 original_top = f->output_data.x->top_pos;
c0a04927
RS
11793
11794 /* This must come after we set COUNT. */
11795 UNBLOCK_INPUT;
11796
2745e6c4 11797 /* We unblock here so that arriving X events are processed. */
1aa6072f 11798
dcb07ae9
RS
11799 /* Now move the window back to where it was "supposed to be".
11800 But don't do it if the gravity is negative.
11801 When the gravity is negative, this uses a position
28c01ffe
RS
11802 that is 3 pixels too low. Perhaps that's really the border width.
11803
11804 Don't do this if the window has never been visible before,
11805 because the window manager may choose the position
11806 and we don't want to override it. */
1aa6072f 11807
4d3f5d9a 11808 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 11809 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 11810 && previously_visible)
1aa6072f 11811 {
2745e6c4
RS
11812 Drawable rootw;
11813 int x, y;
11814 unsigned int width, height, border, depth;
06a2c219 11815
1aa6072f 11816 BLOCK_INPUT;
9829ddba 11817
06a2c219
GM
11818 /* On some window managers (such as FVWM) moving an existing
11819 window, even to the same place, causes the window manager
11820 to introduce an offset. This can cause the window to move
11821 to an unexpected location. Check the geometry (a little
11822 slow here) and then verify that the window is in the right
11823 place. If the window is not in the right place, move it
11824 there, and take the potential window manager hit. */
2745e6c4
RS
11825 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11826 &rootw, &x, &y, &width, &height, &border, &depth);
11827
11828 if (original_left != x || original_top != y)
11829 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11830 original_left, original_top);
11831
1aa6072f
RS
11832 UNBLOCK_INPUT;
11833 }
9829ddba 11834
e0c1aef2 11835 XSETFRAME (frame, f);
c0a04927 11836
12ce2351
GM
11837 /* Wait until the frame is visible. Process X events until a
11838 MapNotify event has been seen, or until we think we won't get a
11839 MapNotify at all.. */
11840 for (count = input_signal_count + 10;
11841 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 11842 {
12ce2351 11843 /* Force processing of queued events. */
334208b7 11844 x_sync (f);
12ce2351
GM
11845
11846 /* Machines that do polling rather than SIGIO have been
11847 observed to go into a busy-wait here. So we'll fake an
11848 alarm signal to let the handler know that there's something
11849 to be read. We used to raise a real alarm, but it seems
11850 that the handler isn't always enabled here. This is
11851 probably a bug. */
8b2f8d4e 11852 if (input_polling_used ())
3b2fa4e6 11853 {
12ce2351
GM
11854 /* It could be confusing if a real alarm arrives while
11855 processing the fake one. Turn it off and let the
11856 handler reset it. */
3e71d8f2 11857 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
11858 int old_poll_suppress_count = poll_suppress_count;
11859 poll_suppress_count = 1;
11860 poll_for_input_1 ();
11861 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 11862 }
12ce2351
GM
11863
11864 /* See if a MapNotify event has been processed. */
11865 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 11866 }
0dacf791 11867 }
dc6f92b8
JB
11868}
11869
06a2c219 11870/* Change from mapped state to withdrawn state. */
dc6f92b8 11871
d047c4eb
KH
11872/* Make the frame visible (mapped and not iconified). */
11873
dfcf069d 11874void
f676886a
JB
11875x_make_frame_invisible (f)
11876 struct frame *f;
dc6f92b8 11877{
546e6d5b
RS
11878 Window window;
11879
11880#ifdef USE_X_TOOLKIT
11881 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 11882 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
11883#else /* not USE_X_TOOLKIT */
11884 window = FRAME_X_WINDOW (f);
11885#endif /* not USE_X_TOOLKIT */
dc6f92b8 11886
9319ae23 11887 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11888 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11889 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11890
5627c40e 11891#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 11892 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 11893 return;
5627c40e 11894#endif
dc6f92b8
JB
11895
11896 BLOCK_INPUT;
c118dd06 11897
af31d76f
RS
11898 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
11899 that the current position of the window is user-specified, rather than
11900 program-specified, so that when the window is mapped again, it will be
11901 placed at the same location, without forcing the user to position it
11902 by hand again (they have already done that once for this window.) */
c32cdd9a 11903 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 11904
c118dd06
JB
11905#ifdef HAVE_X11R4
11906
334208b7
RS
11907 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
11908 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
11909 {
11910 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11911 error ("Can't notify window manager of window withdrawal");
c118dd06 11912 }
c118dd06 11913#else /* ! defined (HAVE_X11R4) */
16bd92ea 11914
c118dd06 11915 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
11916 if (! EQ (Vx_no_window_manager, Qt))
11917 {
16bd92ea 11918 XEvent unmap;
dc6f92b8 11919
16bd92ea 11920 unmap.xunmap.type = UnmapNotify;
546e6d5b 11921 unmap.xunmap.window = window;
334208b7 11922 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 11923 unmap.xunmap.from_configure = False;
334208b7
RS
11924 if (! XSendEvent (FRAME_X_DISPLAY (f),
11925 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 11926 False,
06a2c219 11927 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
11928 &unmap))
11929 {
11930 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11931 error ("Can't notify window manager of withdrawal");
16bd92ea 11932 }
dc6f92b8
JB
11933 }
11934
16bd92ea 11935 /* Unmap the window ourselves. Cheeky! */
334208b7 11936 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 11937#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 11938
5627c40e
RS
11939 /* We can't distinguish this from iconification
11940 just by the event that we get from the server.
11941 So we can't win using the usual strategy of letting
11942 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
11943 and synchronize with the server to make sure we agree. */
11944 f->visible = 0;
11945 FRAME_ICONIFIED_P (f) = 0;
11946 f->async_visible = 0;
11947 f->async_iconified = 0;
11948
334208b7 11949 x_sync (f);
5627c40e 11950
dc6f92b8
JB
11951 UNBLOCK_INPUT;
11952}
11953
06a2c219 11954/* Change window state from mapped to iconified. */
dc6f92b8 11955
dfcf069d 11956void
f676886a
JB
11957x_iconify_frame (f)
11958 struct frame *f;
dc6f92b8 11959{
3afe33e7 11960 int result;
990ba854 11961 Lisp_Object type;
dc6f92b8 11962
9319ae23 11963 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11964 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11965 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11966
3a88c238 11967 if (f->async_iconified)
dc6f92b8
JB
11968 return;
11969
3afe33e7 11970 BLOCK_INPUT;
546e6d5b 11971
9af3143a
RS
11972 FRAME_SAMPLE_VISIBILITY (f);
11973
990ba854
RS
11974 type = x_icon_type (f);
11975 if (!NILP (type))
11976 x_bitmap_icon (f, type);
bdcd49ba
RS
11977
11978#ifdef USE_X_TOOLKIT
11979
546e6d5b
RS
11980 if (! FRAME_VISIBLE_P (f))
11981 {
11982 if (! EQ (Vx_no_window_manager, Qt))
11983 x_wm_set_window_state (f, IconicState);
11984 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11985 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
11986 /* The server won't give us any event to indicate
11987 that an invisible frame was changed to an icon,
11988 so we have to record it here. */
11989 f->iconified = 1;
1e6bc770 11990 f->visible = 1;
9cf30a30 11991 f->async_iconified = 1;
1e6bc770 11992 f->async_visible = 0;
546e6d5b
RS
11993 UNBLOCK_INPUT;
11994 return;
11995 }
11996
334208b7 11997 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 11998 XtWindow (f->output_data.x->widget),
334208b7 11999 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
12000 UNBLOCK_INPUT;
12001
12002 if (!result)
546e6d5b 12003 error ("Can't notify window manager of iconification");
3afe33e7
RS
12004
12005 f->async_iconified = 1;
1e6bc770
RS
12006 f->async_visible = 0;
12007
8c002a25
KH
12008
12009 BLOCK_INPUT;
334208b7 12010 XFlush (FRAME_X_DISPLAY (f));
8c002a25 12011 UNBLOCK_INPUT;
3afe33e7
RS
12012#else /* not USE_X_TOOLKIT */
12013
fd13dbb2
RS
12014 /* Make sure the X server knows where the window should be positioned,
12015 in case the user deiconifies with the window manager. */
12016 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 12017 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 12018
16bd92ea
JB
12019 /* Since we don't know which revision of X we're running, we'll use both
12020 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
12021
12022 /* X11R4: send a ClientMessage to the window manager using the
12023 WM_CHANGE_STATE type. */
12024 {
12025 XEvent message;
58769bee 12026
c118dd06 12027 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 12028 message.xclient.type = ClientMessage;
334208b7 12029 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
12030 message.xclient.format = 32;
12031 message.xclient.data.l[0] = IconicState;
12032
334208b7
RS
12033 if (! XSendEvent (FRAME_X_DISPLAY (f),
12034 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
12035 False,
12036 SubstructureRedirectMask | SubstructureNotifyMask,
12037 &message))
dc6f92b8
JB
12038 {
12039 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12040 error ("Can't notify window manager of iconification");
dc6f92b8 12041 }
16bd92ea 12042 }
dc6f92b8 12043
58769bee 12044 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
12045 IconicState. */
12046 x_wm_set_window_state (f, IconicState);
dc6f92b8 12047
a9c00105
RS
12048 if (!FRAME_VISIBLE_P (f))
12049 {
12050 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 12051 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
12052 }
12053
3a88c238 12054 f->async_iconified = 1;
1e6bc770 12055 f->async_visible = 0;
dc6f92b8 12056
334208b7 12057 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 12058 UNBLOCK_INPUT;
8c002a25 12059#endif /* not USE_X_TOOLKIT */
dc6f92b8 12060}
d047c4eb 12061\f
c0ff3fab 12062/* Destroy the X window of frame F. */
dc6f92b8 12063
dfcf069d 12064void
c0ff3fab 12065x_destroy_window (f)
f676886a 12066 struct frame *f;
dc6f92b8 12067{
7f9c7f94
RS
12068 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12069
dc6f92b8 12070 BLOCK_INPUT;
c0ff3fab 12071
6186a4a0
RS
12072 /* If a display connection is dead, don't try sending more
12073 commands to the X server. */
12074 if (dpyinfo->display != 0)
12075 {
12076 if (f->output_data.x->icon_desc != 0)
12077 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
31f41daf 12078#ifdef HAVE_X_I18N
f5d11644
GM
12079 if (FRAME_XIC (f))
12080 free_frame_xic (f);
31f41daf 12081#endif
6186a4a0 12082 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->window_desc);
3afe33e7 12083#ifdef USE_X_TOOLKIT
06a2c219
GM
12084 if (f->output_data.x->widget)
12085 XtDestroyWidget (f->output_data.x->widget);
6186a4a0 12086 free_frame_menubar (f);
3afe33e7
RS
12087#endif /* USE_X_TOOLKIT */
12088
3e71d8f2
GM
12089 unload_color (f, f->output_data.x->foreground_pixel);
12090 unload_color (f, f->output_data.x->background_pixel);
12091 unload_color (f, f->output_data.x->cursor_pixel);
12092 unload_color (f, f->output_data.x->cursor_foreground_pixel);
12093 unload_color (f, f->output_data.x->border_pixel);
12094 unload_color (f, f->output_data.x->mouse_pixel);
12095 if (f->output_data.x->scroll_bar_background_pixel != -1)
12096 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
12097 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
12098 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
12099 if (f->output_data.x->white_relief.allocated_p)
12100 unload_color (f, f->output_data.x->white_relief.pixel);
12101 if (f->output_data.x->black_relief.allocated_p)
12102 unload_color (f, f->output_data.x->black_relief.pixel);
12103
6186a4a0
RS
12104 free_frame_faces (f);
12105 XFlush (FRAME_X_DISPLAY (f));
12106 }
dc6f92b8 12107
df89d8a4 12108 if (f->output_data.x->saved_menu_event)
06a2c219 12109 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 12110
7556890b
RS
12111 xfree (f->output_data.x);
12112 f->output_data.x = 0;
0f941935
KH
12113 if (f == dpyinfo->x_focus_frame)
12114 dpyinfo->x_focus_frame = 0;
12115 if (f == dpyinfo->x_focus_event_frame)
12116 dpyinfo->x_focus_event_frame = 0;
12117 if (f == dpyinfo->x_highlight_frame)
12118 dpyinfo->x_highlight_frame = 0;
c0ff3fab 12119
7f9c7f94
RS
12120 dpyinfo->reference_count--;
12121
12122 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 12123 {
7f9c7f94
RS
12124 dpyinfo->mouse_face_beg_row
12125 = dpyinfo->mouse_face_beg_col = -1;
12126 dpyinfo->mouse_face_end_row
12127 = dpyinfo->mouse_face_end_col = -1;
12128 dpyinfo->mouse_face_window = Qnil;
21323706
RS
12129 dpyinfo->mouse_face_deferred_gc = 0;
12130 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 12131 }
0134a210 12132
c0ff3fab 12133 UNBLOCK_INPUT;
dc6f92b8
JB
12134}
12135\f
f451eb13
JB
12136/* Setting window manager hints. */
12137
af31d76f
RS
12138/* Set the normal size hints for the window manager, for frame F.
12139 FLAGS is the flags word to use--or 0 meaning preserve the flags
12140 that the window now has.
12141 If USER_POSITION is nonzero, we set the USPosition
12142 flag (this is useful when FLAGS is 0). */
6dba1858 12143
dfcf069d 12144void
af31d76f 12145x_wm_set_size_hint (f, flags, user_position)
f676886a 12146 struct frame *f;
af31d76f
RS
12147 long flags;
12148 int user_position;
dc6f92b8
JB
12149{
12150 XSizeHints size_hints;
3afe33e7
RS
12151
12152#ifdef USE_X_TOOLKIT
7e4f2521
FP
12153 Arg al[2];
12154 int ac = 0;
12155 Dimension widget_width, widget_height;
7556890b 12156 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 12157#else /* not USE_X_TOOLKIT */
c118dd06 12158 Window window = FRAME_X_WINDOW (f);
3afe33e7 12159#endif /* not USE_X_TOOLKIT */
dc6f92b8 12160
b72a58fd
RS
12161 /* Setting PMaxSize caused various problems. */
12162 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 12163
7556890b
RS
12164 size_hints.x = f->output_data.x->left_pos;
12165 size_hints.y = f->output_data.x->top_pos;
7553a6b7 12166
7e4f2521
FP
12167#ifdef USE_X_TOOLKIT
12168 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
12169 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 12170 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
12171 size_hints.height = widget_height;
12172 size_hints.width = widget_width;
12173#else /* not USE_X_TOOLKIT */
f676886a
JB
12174 size_hints.height = PIXEL_HEIGHT (f);
12175 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 12176#endif /* not USE_X_TOOLKIT */
7553a6b7 12177
7556890b
RS
12178 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
12179 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
12180 size_hints.max_width
12181 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
12182 size_hints.max_height
12183 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 12184
d067ea8b
KH
12185 /* Calculate the base and minimum sizes.
12186
12187 (When we use the X toolkit, we don't do it here.
12188 Instead we copy the values that the widgets are using, below.) */
12189#ifndef USE_X_TOOLKIT
b1c884c3 12190 {
b0342f17 12191 int base_width, base_height;
0134a210 12192 int min_rows = 0, min_cols = 0;
b0342f17 12193
f451eb13
JB
12194 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
12195 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 12196
0134a210 12197 check_frame_size (f, &min_rows, &min_cols);
b0342f17 12198
0134a210
RS
12199 /* The window manager uses the base width hints to calculate the
12200 current number of rows and columns in the frame while
12201 resizing; min_width and min_height aren't useful for this
12202 purpose, since they might not give the dimensions for a
12203 zero-row, zero-column frame.
58769bee 12204
0134a210
RS
12205 We use the base_width and base_height members if we have
12206 them; otherwise, we set the min_width and min_height members
12207 to the size for a zero x zero frame. */
b0342f17
JB
12208
12209#ifdef HAVE_X11R4
0134a210
RS
12210 size_hints.flags |= PBaseSize;
12211 size_hints.base_width = base_width;
12212 size_hints.base_height = base_height;
12213 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
12214 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 12215#else
0134a210
RS
12216 size_hints.min_width = base_width;
12217 size_hints.min_height = base_height;
b0342f17 12218#endif
b1c884c3 12219 }
dc6f92b8 12220
d067ea8b 12221 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 12222 if (flags)
dc6f92b8 12223 {
d067ea8b
KH
12224 size_hints.flags |= flags;
12225 goto no_read;
12226 }
12227#endif /* not USE_X_TOOLKIT */
12228
12229 {
12230 XSizeHints hints; /* Sometimes I hate X Windows... */
12231 long supplied_return;
12232 int value;
af31d76f
RS
12233
12234#ifdef HAVE_X11R4
d067ea8b
KH
12235 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
12236 &supplied_return);
af31d76f 12237#else
d067ea8b 12238 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 12239#endif
58769bee 12240
d067ea8b
KH
12241#ifdef USE_X_TOOLKIT
12242 size_hints.base_height = hints.base_height;
12243 size_hints.base_width = hints.base_width;
12244 size_hints.min_height = hints.min_height;
12245 size_hints.min_width = hints.min_width;
12246#endif
12247
12248 if (flags)
12249 size_hints.flags |= flags;
12250 else
12251 {
12252 if (value == 0)
12253 hints.flags = 0;
12254 if (hints.flags & PSize)
12255 size_hints.flags |= PSize;
12256 if (hints.flags & PPosition)
12257 size_hints.flags |= PPosition;
12258 if (hints.flags & USPosition)
12259 size_hints.flags |= USPosition;
12260 if (hints.flags & USSize)
12261 size_hints.flags |= USSize;
12262 }
12263 }
12264
06a2c219 12265#ifndef USE_X_TOOLKIT
d067ea8b 12266 no_read:
06a2c219 12267#endif
0134a210 12268
af31d76f 12269#ifdef PWinGravity
7556890b 12270 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 12271 size_hints.flags |= PWinGravity;
dc05a16b 12272
af31d76f 12273 if (user_position)
6dba1858 12274 {
af31d76f
RS
12275 size_hints.flags &= ~ PPosition;
12276 size_hints.flags |= USPosition;
6dba1858 12277 }
2554751d 12278#endif /* PWinGravity */
6dba1858 12279
b0342f17 12280#ifdef HAVE_X11R4
334208b7 12281 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12282#else
334208b7 12283 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12284#endif
dc6f92b8
JB
12285}
12286
12287/* Used for IconicState or NormalState */
06a2c219 12288
dfcf069d 12289void
f676886a
JB
12290x_wm_set_window_state (f, state)
12291 struct frame *f;
dc6f92b8
JB
12292 int state;
12293{
3afe33e7 12294#ifdef USE_X_TOOLKIT
546e6d5b
RS
12295 Arg al[1];
12296
12297 XtSetArg (al[0], XtNinitialState, state);
7556890b 12298 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 12299#else /* not USE_X_TOOLKIT */
c118dd06 12300 Window window = FRAME_X_WINDOW (f);
dc6f92b8 12301
7556890b
RS
12302 f->output_data.x->wm_hints.flags |= StateHint;
12303 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 12304
7556890b 12305 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 12306#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12307}
12308
dfcf069d 12309void
7f2ae036 12310x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 12311 struct frame *f;
7f2ae036 12312 int pixmap_id;
dc6f92b8 12313{
d2bd6bc4
RS
12314 Pixmap icon_pixmap;
12315
06a2c219 12316#ifndef USE_X_TOOLKIT
c118dd06 12317 Window window = FRAME_X_WINDOW (f);
75231bad 12318#endif
dc6f92b8 12319
7f2ae036 12320 if (pixmap_id > 0)
dbc4e1c1 12321 {
d2bd6bc4 12322 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 12323 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
12324 }
12325 else
68568555
RS
12326 {
12327 /* It seems there is no way to turn off use of an icon pixmap.
12328 The following line does it, only if no icon has yet been created,
12329 for some window managers. But with mwm it crashes.
12330 Some people say it should clear the IconPixmapHint bit in this case,
12331 but that doesn't work, and the X consortium said it isn't the
12332 right thing at all. Since there is no way to win,
12333 best to explicitly give up. */
12334#if 0
12335 f->output_data.x->wm_hints.icon_pixmap = None;
12336#else
12337 return;
12338#endif
12339 }
b1c884c3 12340
d2bd6bc4
RS
12341#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
12342
12343 {
12344 Arg al[1];
12345 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
12346 XtSetValues (f->output_data.x->widget, al, 1);
12347 }
12348
12349#else /* not USE_X_TOOLKIT */
12350
7556890b
RS
12351 f->output_data.x->wm_hints.flags |= IconPixmapHint;
12352 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
12353
12354#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12355}
12356
dfcf069d 12357void
f676886a
JB
12358x_wm_set_icon_position (f, icon_x, icon_y)
12359 struct frame *f;
dc6f92b8
JB
12360 int icon_x, icon_y;
12361{
75231bad 12362#ifdef USE_X_TOOLKIT
7556890b 12363 Window window = XtWindow (f->output_data.x->widget);
75231bad 12364#else
c118dd06 12365 Window window = FRAME_X_WINDOW (f);
75231bad 12366#endif
dc6f92b8 12367
7556890b
RS
12368 f->output_data.x->wm_hints.flags |= IconPositionHint;
12369 f->output_data.x->wm_hints.icon_x = icon_x;
12370 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 12371
7556890b 12372 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
12373}
12374
12375\f
06a2c219
GM
12376/***********************************************************************
12377 Fonts
12378 ***********************************************************************/
dc43ef94
KH
12379
12380/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 12381
dc43ef94
KH
12382struct font_info *
12383x_get_font_info (f, font_idx)
12384 FRAME_PTR f;
12385 int font_idx;
12386{
12387 return (FRAME_X_FONT_TABLE (f) + font_idx);
12388}
12389
12390
12391/* Return a list of names of available fonts matching PATTERN on frame
12392 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
12393 to be listed. Frame F NULL means we have not yet created any
12394 frame on X, and consult the first display in x_display_list.
12395 MAXNAMES sets a limit on how many fonts to match. */
12396
12397Lisp_Object
12398x_list_fonts (f, pattern, size, maxnames)
12399 FRAME_PTR f;
12400 Lisp_Object pattern;
12401 int size;
12402 int maxnames;
12403{
06a2c219
GM
12404 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
12405 Lisp_Object tem, second_best;
dc43ef94 12406 Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
09c6077f 12407 int try_XLoadQueryFont = 0;
53ca4657 12408 int count;
dc43ef94 12409
6b0efe73 12410 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
12411 if (NILP (patterns))
12412 patterns = Fcons (pattern, Qnil);
81ba44e5 12413
09c6077f
KH
12414 if (maxnames == 1 && !size)
12415 /* We can return any single font matching PATTERN. */
12416 try_XLoadQueryFont = 1;
9a32686f 12417
8e713be6 12418 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 12419 {
dc43ef94 12420 int num_fonts;
3e71d8f2 12421 char **names = NULL;
dc43ef94 12422
8e713be6 12423 pattern = XCAR (patterns);
536f4067
RS
12424 /* See if we cached the result for this particular query.
12425 The cache is an alist of the form:
12426 (((PATTERN . MAXNAMES) (FONTNAME . WIDTH) ...) ...)
12427 */
8e713be6 12428 if (f && (tem = XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element),
b5210ea7
KH
12429 key = Fcons (pattern, make_number (maxnames)),
12430 !NILP (list = Fassoc (key, tem))))
12431 {
12432 list = Fcdr_safe (list);
12433 /* We have a cashed list. Don't have to get the list again. */
12434 goto label_cached;
12435 }
12436
12437 /* At first, put PATTERN in the cache. */
09c6077f 12438
dc43ef94 12439 BLOCK_INPUT;
17d85edc
KH
12440 count = x_catch_errors (dpy);
12441
09c6077f
KH
12442 if (try_XLoadQueryFont)
12443 {
12444 XFontStruct *font;
12445 unsigned long value;
12446
12447 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
12448 if (x_had_errors_p (dpy))
12449 {
12450 /* This error is perhaps due to insufficient memory on X
12451 server. Let's just ignore it. */
12452 font = NULL;
12453 x_clear_errors (dpy);
12454 }
12455
09c6077f
KH
12456 if (font
12457 && XGetFontProperty (font, XA_FONT, &value))
12458 {
12459 char *name = (char *) XGetAtomName (dpy, (Atom) value);
12460 int len = strlen (name);
01c752b5 12461 char *tmp;
09c6077f 12462
6f6512e8
KH
12463 /* If DXPC (a Differential X Protocol Compressor)
12464 Ver.3.7 is running, XGetAtomName will return null
12465 string. We must avoid such a name. */
12466 if (len == 0)
12467 try_XLoadQueryFont = 0;
12468 else
12469 {
12470 num_fonts = 1;
12471 names = (char **) alloca (sizeof (char *));
12472 /* Some systems only allow alloca assigned to a
12473 simple var. */
12474 tmp = (char *) alloca (len + 1); names[0] = tmp;
12475 bcopy (name, names[0], len + 1);
12476 XFree (name);
12477 }
09c6077f
KH
12478 }
12479 else
12480 try_XLoadQueryFont = 0;
a083fd23
RS
12481
12482 if (font)
12483 XFreeFont (dpy, font);
09c6077f
KH
12484 }
12485
12486 if (!try_XLoadQueryFont)
17d85edc
KH
12487 {
12488 /* We try at least 10 fonts because XListFonts will return
12489 auto-scaled fonts at the head. */
12490 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
12491 &num_fonts);
12492 if (x_had_errors_p (dpy))
12493 {
12494 /* This error is perhaps due to insufficient memory on X
12495 server. Let's just ignore it. */
12496 names = NULL;
12497 x_clear_errors (dpy);
12498 }
12499 }
12500
12501 x_uncatch_errors (dpy, count);
dc43ef94
KH
12502 UNBLOCK_INPUT;
12503
12504 if (names)
12505 {
12506 int i;
dc43ef94
KH
12507
12508 /* Make a list of all the fonts we got back.
12509 Store that in the font cache for the display. */
12510 for (i = 0; i < num_fonts; i++)
12511 {
06a2c219 12512 int width = 0;
dc43ef94 12513 char *p = names[i];
06a2c219
GM
12514 int average_width = -1, dashes = 0;
12515
dc43ef94 12516 /* Count the number of dashes in NAMES[I]. If there are
b5210ea7
KH
12517 14 dashes, and the field value following 12th dash
12518 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
12519 is usually too ugly to be used for editing. Let's
12520 ignore it. */
dc43ef94
KH
12521 while (*p)
12522 if (*p++ == '-')
12523 {
12524 dashes++;
12525 if (dashes == 7) /* PIXEL_SIZE field */
12526 width = atoi (p);
12527 else if (dashes == 12) /* AVERAGE_WIDTH field */
12528 average_width = atoi (p);
12529 }
12530 if (dashes < 14 || average_width != 0)
12531 {
12532 tem = build_string (names[i]);
12533 if (NILP (Fassoc (tem, list)))
12534 {
12535 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
12536 && ((fast_c_string_match_ignore_case
12537 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
12538 >= 0))
12539 /* We can set the value of PIXEL_SIZE to the
b5210ea7 12540 width of this font. */
dc43ef94
KH
12541 list = Fcons (Fcons (tem, make_number (width)), list);
12542 else
12543 /* For the moment, width is not known. */
12544 list = Fcons (Fcons (tem, Qnil), list);
12545 }
12546 }
12547 }
09c6077f
KH
12548 if (!try_XLoadQueryFont)
12549 XFreeFontNames (names);
dc43ef94
KH
12550 }
12551
b5210ea7 12552 /* Now store the result in the cache. */
dc43ef94 12553 if (f != NULL)
8e713be6 12554 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element)
dc43ef94 12555 = Fcons (Fcons (key, list),
8e713be6 12556 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
dc43ef94 12557
b5210ea7
KH
12558 label_cached:
12559 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 12560
b5210ea7
KH
12561 newlist = second_best = Qnil;
12562 /* Make a list of the fonts that have the right width. */
8e713be6 12563 for (; CONSP (list); list = XCDR (list))
b5210ea7 12564 {
536f4067
RS
12565 int found_size;
12566
8e713be6 12567 tem = XCAR (list);
dc43ef94 12568
8e713be6 12569 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
12570 continue;
12571 if (!size)
12572 {
8e713be6 12573 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
12574 continue;
12575 }
dc43ef94 12576
8e713be6 12577 if (!INTEGERP (XCDR (tem)))
dc43ef94 12578 {
b5210ea7
KH
12579 /* Since we have not yet known the size of this font, we
12580 must try slow function call XLoadQueryFont. */
dc43ef94
KH
12581 XFontStruct *thisinfo;
12582
12583 BLOCK_INPUT;
17d85edc 12584 count = x_catch_errors (dpy);
dc43ef94 12585 thisinfo = XLoadQueryFont (dpy,
8e713be6 12586 XSTRING (XCAR (tem))->data);
17d85edc
KH
12587 if (x_had_errors_p (dpy))
12588 {
12589 /* This error is perhaps due to insufficient memory on X
12590 server. Let's just ignore it. */
12591 thisinfo = NULL;
12592 x_clear_errors (dpy);
12593 }
12594 x_uncatch_errors (dpy, count);
dc43ef94
KH
12595 UNBLOCK_INPUT;
12596
12597 if (thisinfo)
12598 {
8e713be6 12599 XCDR (tem)
536f4067
RS
12600 = (thisinfo->min_bounds.width == 0
12601 ? make_number (0)
12602 : make_number (thisinfo->max_bounds.width));
dc43ef94
KH
12603 XFreeFont (dpy, thisinfo);
12604 }
12605 else
b5210ea7 12606 /* For unknown reason, the previous call of XListFont had
06a2c219 12607 returned a font which can't be opened. Record the size
b5210ea7 12608 as 0 not to try to open it again. */
8e713be6 12609 XCDR (tem) = make_number (0);
dc43ef94 12610 }
536f4067 12611
8e713be6 12612 found_size = XINT (XCDR (tem));
536f4067 12613 if (found_size == size)
8e713be6 12614 newlist = Fcons (XCAR (tem), newlist);
536f4067 12615 else if (found_size > 0)
b5210ea7 12616 {
536f4067 12617 if (NILP (second_best))
b5210ea7 12618 second_best = tem;
536f4067
RS
12619 else if (found_size < size)
12620 {
8e713be6
KR
12621 if (XINT (XCDR (second_best)) > size
12622 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
12623 second_best = tem;
12624 }
12625 else
12626 {
8e713be6
KR
12627 if (XINT (XCDR (second_best)) > size
12628 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
12629 second_best = tem;
12630 }
b5210ea7
KH
12631 }
12632 }
12633 if (!NILP (newlist))
12634 break;
12635 else if (!NILP (second_best))
12636 {
8e713be6 12637 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 12638 break;
dc43ef94 12639 }
dc43ef94
KH
12640 }
12641
12642 return newlist;
12643}
12644
06a2c219
GM
12645
12646#if GLYPH_DEBUG
12647
12648/* Check that FONT is valid on frame F. It is if it can be found in F's
12649 font table. */
12650
12651static void
12652x_check_font (f, font)
12653 struct frame *f;
12654 XFontStruct *font;
12655{
12656 int i;
12657 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12658
12659 xassert (font != NULL);
12660
12661 for (i = 0; i < dpyinfo->n_fonts; i++)
12662 if (dpyinfo->font_table[i].name
12663 && font == dpyinfo->font_table[i].font)
12664 break;
12665
12666 xassert (i < dpyinfo->n_fonts);
12667}
12668
12669#endif /* GLYPH_DEBUG != 0 */
12670
12671/* Set *W to the minimum width, *H to the minimum font height of FONT.
12672 Note: There are (broken) X fonts out there with invalid XFontStruct
12673 min_bounds contents. For example, handa@etl.go.jp reports that
12674 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
12675 have font->min_bounds.width == 0. */
12676
12677static INLINE void
12678x_font_min_bounds (font, w, h)
12679 XFontStruct *font;
12680 int *w, *h;
12681{
12682 *h = FONT_HEIGHT (font);
12683 *w = font->min_bounds.width;
12684
12685 /* Try to handle the case where FONT->min_bounds has invalid
12686 contents. Since the only font known to have invalid min_bounds
12687 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
12688 if (*w <= 0)
12689 *w = font->max_bounds.width;
12690}
12691
12692
12693/* Compute the smallest character width and smallest font height over
12694 all fonts available on frame F. Set the members smallest_char_width
12695 and smallest_font_height in F's x_display_info structure to
12696 the values computed. Value is non-zero if smallest_font_height or
12697 smallest_char_width become smaller than they were before. */
12698
12699static int
12700x_compute_min_glyph_bounds (f)
12701 struct frame *f;
12702{
12703 int i;
12704 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12705 XFontStruct *font;
12706 int old_width = dpyinfo->smallest_char_width;
12707 int old_height = dpyinfo->smallest_font_height;
12708
12709 dpyinfo->smallest_font_height = 100000;
12710 dpyinfo->smallest_char_width = 100000;
12711
12712 for (i = 0; i < dpyinfo->n_fonts; ++i)
12713 if (dpyinfo->font_table[i].name)
12714 {
12715 struct font_info *fontp = dpyinfo->font_table + i;
12716 int w, h;
12717
12718 font = (XFontStruct *) fontp->font;
12719 xassert (font != (XFontStruct *) ~0);
12720 x_font_min_bounds (font, &w, &h);
12721
12722 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
12723 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
12724 }
12725
12726 xassert (dpyinfo->smallest_char_width > 0
12727 && dpyinfo->smallest_font_height > 0);
12728
12729 return (dpyinfo->n_fonts == 1
12730 || dpyinfo->smallest_char_width < old_width
12731 || dpyinfo->smallest_font_height < old_height);
12732}
12733
12734
dc43ef94
KH
12735/* Load font named FONTNAME of the size SIZE for frame F, and return a
12736 pointer to the structure font_info while allocating it dynamically.
12737 If SIZE is 0, load any size of font.
12738 If loading is failed, return NULL. */
12739
12740struct font_info *
12741x_load_font (f, fontname, size)
12742 struct frame *f;
12743 register char *fontname;
12744 int size;
12745{
12746 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12747 Lisp_Object font_names;
d645aaa4 12748 int count;
dc43ef94
KH
12749
12750 /* Get a list of all the fonts that match this name. Once we
12751 have a list of matching fonts, we compare them against the fonts
12752 we already have by comparing names. */
09c6077f 12753 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
12754
12755 if (!NILP (font_names))
12756 {
12757 Lisp_Object tail;
12758 int i;
12759
12760 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 12761 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
12762 if (dpyinfo->font_table[i].name
12763 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 12764 XSTRING (XCAR (tail))->data)
06a2c219 12765 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 12766 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
12767 return (dpyinfo->font_table + i);
12768 }
12769
12770 /* Load the font and add it to the table. */
12771 {
12772 char *full_name;
12773 XFontStruct *font;
12774 struct font_info *fontp;
12775 unsigned long value;
06a2c219 12776 int i;
dc43ef94 12777
2da424f1
KH
12778 /* If we have found fonts by x_list_font, load one of them. If
12779 not, we still try to load a font by the name given as FONTNAME
12780 because XListFonts (called in x_list_font) of some X server has
12781 a bug of not finding a font even if the font surely exists and
12782 is loadable by XLoadQueryFont. */
e1d6d5b9 12783 if (size > 0 && !NILP (font_names))
8e713be6 12784 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
12785
12786 BLOCK_INPUT;
d645aaa4 12787 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 12788 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
12789 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12790 {
12791 /* This error is perhaps due to insufficient memory on X
12792 server. Let's just ignore it. */
12793 font = NULL;
12794 x_clear_errors (FRAME_X_DISPLAY (f));
12795 }
12796 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 12797 UNBLOCK_INPUT;
b5210ea7 12798 if (!font)
dc43ef94
KH
12799 return NULL;
12800
06a2c219
GM
12801 /* Find a free slot in the font table. */
12802 for (i = 0; i < dpyinfo->n_fonts; ++i)
12803 if (dpyinfo->font_table[i].name == NULL)
12804 break;
12805
12806 /* If no free slot found, maybe enlarge the font table. */
12807 if (i == dpyinfo->n_fonts
12808 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 12809 {
06a2c219
GM
12810 int sz;
12811 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
12812 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 12813 dpyinfo->font_table
06a2c219 12814 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
12815 }
12816
06a2c219
GM
12817 fontp = dpyinfo->font_table + i;
12818 if (i == dpyinfo->n_fonts)
12819 ++dpyinfo->n_fonts;
dc43ef94
KH
12820
12821 /* Now fill in the slots of *FONTP. */
12822 BLOCK_INPUT;
12823 fontp->font = font;
06a2c219 12824 fontp->font_idx = i;
dc43ef94
KH
12825 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
12826 bcopy (fontname, fontp->name, strlen (fontname) + 1);
12827
12828 /* Try to get the full name of FONT. Put it in FULL_NAME. */
12829 full_name = 0;
12830 if (XGetFontProperty (font, XA_FONT, &value))
12831 {
12832 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
12833 char *p = name;
12834 int dashes = 0;
12835
12836 /* Count the number of dashes in the "full name".
12837 If it is too few, this isn't really the font's full name,
12838 so don't use it.
12839 In X11R4, the fonts did not come with their canonical names
12840 stored in them. */
12841 while (*p)
12842 {
12843 if (*p == '-')
12844 dashes++;
12845 p++;
12846 }
12847
12848 if (dashes >= 13)
12849 {
12850 full_name = (char *) xmalloc (p - name + 1);
12851 bcopy (name, full_name, p - name + 1);
12852 }
12853
12854 XFree (name);
12855 }
12856
12857 if (full_name != 0)
12858 fontp->full_name = full_name;
12859 else
12860 fontp->full_name = fontp->name;
12861
12862 fontp->size = font->max_bounds.width;
d5749adb
KH
12863 fontp->height = FONT_HEIGHT (font);
12864 {
12865 /* For some font, ascent and descent in max_bounds field is
12866 larger than the above value. */
12867 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
12868 if (max_height > fontp->height)
74848a96 12869 fontp->height = max_height;
d5749adb 12870 }
dc43ef94 12871
2da424f1
KH
12872 if (NILP (font_names))
12873 {
12874 /* We come here because of a bug of XListFonts mentioned at
12875 the head of this block. Let's store this information in
12876 the cache for x_list_fonts. */
12877 Lisp_Object lispy_name = build_string (fontname);
12878 Lisp_Object lispy_full_name = build_string (fontp->full_name);
12879
8e713be6 12880 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12881 = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
12882 Fcons (Fcons (lispy_full_name,
12883 make_number (fontp->size)),
12884 Qnil)),
8e713be6 12885 XCDR (dpyinfo->name_list_element));
2da424f1 12886 if (full_name)
8e713be6 12887 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12888 = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
12889 Fcons (Fcons (lispy_full_name,
12890 make_number (fontp->size)),
12891 Qnil)),
8e713be6 12892 XCDR (dpyinfo->name_list_element));
2da424f1
KH
12893 }
12894
dc43ef94
KH
12895 /* The slot `encoding' specifies how to map a character
12896 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
12897 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
12898 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 12899 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 12900 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
12901 which is never used by any charset. If mapping can't be
12902 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
12903 fontp->encoding[1]
12904 = (font->max_byte1 == 0
12905 /* 1-byte font */
12906 ? (font->min_char_or_byte2 < 0x80
12907 ? (font->max_char_or_byte2 < 0x80
12908 ? 0 /* 0x20..0x7F */
8ff102bd 12909 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
12910 : 1) /* 0xA0..0xFF */
12911 /* 2-byte font */
12912 : (font->min_byte1 < 0x80
12913 ? (font->max_byte1 < 0x80
12914 ? (font->min_char_or_byte2 < 0x80
12915 ? (font->max_char_or_byte2 < 0x80
12916 ? 0 /* 0x2020..0x7F7F */
8ff102bd 12917 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 12918 : 3) /* 0x20A0..0x7FFF */
8ff102bd 12919 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
12920 : (font->min_char_or_byte2 < 0x80
12921 ? (font->max_char_or_byte2 < 0x80
12922 ? 2 /* 0xA020..0xFF7F */
8ff102bd 12923 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
12924 : 1))); /* 0xA0A0..0xFFFF */
12925
12926 fontp->baseline_offset
12927 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
12928 ? (long) value : 0);
12929 fontp->relative_compose
12930 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
12931 ? (long) value : 0);
f78798df
KH
12932 fontp->default_ascent
12933 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
12934 ? (long) value : 0);
dc43ef94 12935
06a2c219
GM
12936 /* Set global flag fonts_changed_p to non-zero if the font loaded
12937 has a character with a smaller width than any other character
12938 before, or if the font loaded has a smalle>r height than any
12939 other font loaded before. If this happens, it will make a
12940 glyph matrix reallocation necessary. */
12941 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 12942 UNBLOCK_INPUT;
dc43ef94
KH
12943 return fontp;
12944 }
12945}
12946
06a2c219
GM
12947
12948/* Return a pointer to struct font_info of a font named FONTNAME for
12949 frame F. If no such font is loaded, return NULL. */
12950
dc43ef94
KH
12951struct font_info *
12952x_query_font (f, fontname)
12953 struct frame *f;
12954 register char *fontname;
12955{
12956 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12957 int i;
12958
12959 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
12960 if (dpyinfo->font_table[i].name
12961 && (!strcmp (dpyinfo->font_table[i].name, fontname)
12962 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
12963 return (dpyinfo->font_table + i);
12964 return NULL;
12965}
12966
06a2c219
GM
12967
12968/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
12969 `encoder' of the structure. */
12970
12971void
12972x_find_ccl_program (fontp)
12973 struct font_info *fontp;
12974{
a42f54e6 12975 Lisp_Object list, elt;
a6582676 12976
8e713be6 12977 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 12978 {
8e713be6 12979 elt = XCAR (list);
a6582676 12980 if (CONSP (elt)
8e713be6
KR
12981 && STRINGP (XCAR (elt))
12982 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
a6582676 12983 >= 0))
a42f54e6
KH
12984 break;
12985 }
12986 if (! NILP (list))
12987 {
d27f8ca7
KH
12988 struct ccl_program *ccl
12989 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 12990
8e713be6 12991 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
12992 xfree (ccl);
12993 else
12994 fontp->font_encoder = ccl;
a6582676
KH
12995 }
12996}
12997
06a2c219 12998
dc43ef94 12999\f
06a2c219
GM
13000/***********************************************************************
13001 Initialization
13002 ***********************************************************************/
f451eb13 13003
3afe33e7
RS
13004#ifdef USE_X_TOOLKIT
13005static XrmOptionDescRec emacs_options[] = {
13006 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
13007 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
13008
13009 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
13010 XrmoptionSepArg, NULL},
13011 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
13012
13013 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13014 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13015 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13016 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13017 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13018 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
13019 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
13020};
13021#endif /* USE_X_TOOLKIT */
13022
7a13e894
RS
13023static int x_initialized;
13024
29b38361
KH
13025#ifdef MULTI_KBOARD
13026/* Test whether two display-name strings agree up to the dot that separates
13027 the screen number from the server number. */
13028static int
13029same_x_server (name1, name2)
13030 char *name1, *name2;
13031{
13032 int seen_colon = 0;
cf591cc1
RS
13033 unsigned char *system_name = XSTRING (Vsystem_name)->data;
13034 int system_name_length = strlen (system_name);
13035 int length_until_period = 0;
13036
13037 while (system_name[length_until_period] != 0
13038 && system_name[length_until_period] != '.')
13039 length_until_period++;
13040
13041 /* Treat `unix' like an empty host name. */
13042 if (! strncmp (name1, "unix:", 5))
13043 name1 += 4;
13044 if (! strncmp (name2, "unix:", 5))
13045 name2 += 4;
13046 /* Treat this host's name like an empty host name. */
13047 if (! strncmp (name1, system_name, system_name_length)
13048 && name1[system_name_length] == ':')
13049 name1 += system_name_length;
13050 if (! strncmp (name2, system_name, system_name_length)
13051 && name2[system_name_length] == ':')
13052 name2 += system_name_length;
13053 /* Treat this host's domainless name like an empty host name. */
13054 if (! strncmp (name1, system_name, length_until_period)
13055 && name1[length_until_period] == ':')
13056 name1 += length_until_period;
13057 if (! strncmp (name2, system_name, length_until_period)
13058 && name2[length_until_period] == ':')
13059 name2 += length_until_period;
13060
29b38361
KH
13061 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
13062 {
13063 if (*name1 == ':')
13064 seen_colon++;
13065 if (seen_colon && *name1 == '.')
13066 return 1;
13067 }
13068 return (seen_colon
13069 && (*name1 == '.' || *name1 == '\0')
13070 && (*name2 == '.' || *name2 == '\0'));
13071}
13072#endif
13073
334208b7 13074struct x_display_info *
1f8255f2 13075x_term_init (display_name, xrm_option, resource_name)
334208b7 13076 Lisp_Object display_name;
1f8255f2
RS
13077 char *xrm_option;
13078 char *resource_name;
dc6f92b8 13079{
334208b7 13080 int connection;
7a13e894 13081 Display *dpy;
334208b7
RS
13082 struct x_display_info *dpyinfo;
13083 XrmDatabase xrdb;
13084
60439948
KH
13085 BLOCK_INPUT;
13086
7a13e894
RS
13087 if (!x_initialized)
13088 {
13089 x_initialize ();
13090 x_initialized = 1;
13091 }
dc6f92b8 13092
3afe33e7 13093#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
13094 /* weiner@footloose.sps.mot.com reports that this causes
13095 errors with X11R5:
13096 X protocol error: BadAtom (invalid Atom parameter)
13097 on protocol request 18skiloaf.
13098 So let's not use it until R6. */
13099#ifdef HAVE_X11XTR6
bdcd49ba
RS
13100 XtSetLanguageProc (NULL, NULL, NULL);
13101#endif
13102
7f9c7f94
RS
13103 {
13104 int argc = 0;
13105 char *argv[3];
13106
13107 argv[0] = "";
13108 argc = 1;
13109 if (xrm_option)
13110 {
13111 argv[argc++] = "-xrm";
13112 argv[argc++] = xrm_option;
13113 }
13114 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
13115 resource_name, EMACS_CLASS,
13116 emacs_options, XtNumber (emacs_options),
13117 &argc, argv);
39d8bb4d
KH
13118
13119#ifdef HAVE_X11XTR6
10537cb1 13120 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 13121 fixup_locale ();
39d8bb4d 13122#endif
7f9c7f94 13123 }
3afe33e7
RS
13124
13125#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
13126#ifdef HAVE_X11R5
13127 XSetLocaleModifiers ("");
13128#endif
7a13e894 13129 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 13130#endif /* not USE_X_TOOLKIT */
334208b7 13131
7a13e894
RS
13132 /* Detect failure. */
13133 if (dpy == 0)
60439948
KH
13134 {
13135 UNBLOCK_INPUT;
13136 return 0;
13137 }
7a13e894
RS
13138
13139 /* We have definitely succeeded. Record the new connection. */
13140
13141 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
13142
29b38361
KH
13143#ifdef MULTI_KBOARD
13144 {
13145 struct x_display_info *share;
13146 Lisp_Object tail;
13147
13148 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
13149 share = share->next, tail = XCDR (tail))
13150 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
13151 XSTRING (display_name)->data))
13152 break;
13153 if (share)
13154 dpyinfo->kboard = share->kboard;
13155 else
13156 {
13157 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13158 init_kboard (dpyinfo->kboard);
59e755be
KH
13159 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
13160 {
13161 char *vendor = ServerVendor (dpy);
9b6ed9f3 13162 UNBLOCK_INPUT;
59e755be
KH
13163 dpyinfo->kboard->Vsystem_key_alist
13164 = call1 (Qvendor_specific_keysyms,
13165 build_string (vendor ? vendor : ""));
9b6ed9f3 13166 BLOCK_INPUT;
59e755be
KH
13167 }
13168
29b38361
KH
13169 dpyinfo->kboard->next_kboard = all_kboards;
13170 all_kboards = dpyinfo->kboard;
0ad5446c
KH
13171 /* Don't let the initial kboard remain current longer than necessary.
13172 That would cause problems if a file loaded on startup tries to
06a2c219 13173 prompt in the mini-buffer. */
0ad5446c
KH
13174 if (current_kboard == initial_kboard)
13175 current_kboard = dpyinfo->kboard;
29b38361
KH
13176 }
13177 dpyinfo->kboard->reference_count++;
13178 }
b9737ad3
KH
13179#endif
13180
7a13e894
RS
13181 /* Put this display on the chain. */
13182 dpyinfo->next = x_display_list;
13183 x_display_list = dpyinfo;
13184
13185 /* Put it on x_display_name_list as well, to keep them parallel. */
13186 x_display_name_list = Fcons (Fcons (display_name, Qnil),
13187 x_display_name_list);
8e713be6 13188 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
13189
13190 dpyinfo->display = dpy;
dc6f92b8 13191
dc6f92b8 13192#if 0
7a13e894 13193 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 13194#endif /* ! 0 */
7a13e894
RS
13195
13196 dpyinfo->x_id_name
fc932ac6
RS
13197 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
13198 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
13199 + 2);
13200 sprintf (dpyinfo->x_id_name, "%s@%s",
13201 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
13202
13203 /* Figure out which modifier bits mean what. */
334208b7 13204 x_find_modifier_meanings (dpyinfo);
f451eb13 13205
ab648270 13206 /* Get the scroll bar cursor. */
7a13e894 13207 dpyinfo->vertical_scroll_bar_cursor
334208b7 13208 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 13209
334208b7
RS
13210 xrdb = x_load_resources (dpyinfo->display, xrm_option,
13211 resource_name, EMACS_CLASS);
13212#ifdef HAVE_XRMSETDATABASE
13213 XrmSetDatabase (dpyinfo->display, xrdb);
13214#else
13215 dpyinfo->display->db = xrdb;
13216#endif
547d9db8 13217 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
13218 all versions. */
13219 dpyinfo->xrdb = xrdb;
334208b7
RS
13220
13221 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
13222 DefaultScreen (dpyinfo->display));
5ff67d81 13223 select_visual (dpyinfo);
43bd1b2b 13224 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
13225 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
13226 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
13227 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
13228 dpyinfo->grabbed = 0;
13229 dpyinfo->reference_count = 0;
13230 dpyinfo->icon_bitmap_id = -1;
06a2c219 13231 dpyinfo->font_table = NULL;
7a13e894
RS
13232 dpyinfo->n_fonts = 0;
13233 dpyinfo->font_table_size = 0;
13234 dpyinfo->bitmaps = 0;
13235 dpyinfo->bitmaps_size = 0;
13236 dpyinfo->bitmaps_last = 0;
13237 dpyinfo->scratch_cursor_gc = 0;
13238 dpyinfo->mouse_face_mouse_frame = 0;
13239 dpyinfo->mouse_face_deferred_gc = 0;
13240 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
13241 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 13242 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894
RS
13243 dpyinfo->mouse_face_window = Qnil;
13244 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
13245 dpyinfo->mouse_face_defer = 0;
0f941935
KH
13246 dpyinfo->x_focus_frame = 0;
13247 dpyinfo->x_focus_event_frame = 0;
13248 dpyinfo->x_highlight_frame = 0;
06a2c219 13249 dpyinfo->image_cache = make_image_cache ();
334208b7 13250
43bd1b2b 13251 /* See if a private colormap is requested. */
5ff67d81
GM
13252 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
13253 {
13254 if (dpyinfo->visual->class == PseudoColor)
13255 {
13256 Lisp_Object value;
13257 value = display_x_get_resource (dpyinfo,
13258 build_string ("privateColormap"),
13259 build_string ("PrivateColormap"),
13260 Qnil, Qnil);
13261 if (STRINGP (value)
13262 && (!strcmp (XSTRING (value)->data, "true")
13263 || !strcmp (XSTRING (value)->data, "on")))
13264 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
13265 }
43bd1b2b 13266 }
5ff67d81
GM
13267 else
13268 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
13269 dpyinfo->visual, AllocNone);
43bd1b2b 13270
06a2c219
GM
13271 {
13272 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
13273 double pixels = DisplayHeight (dpyinfo->display, screen_number);
13274 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
13275 dpyinfo->resy = pixels * 25.4 / mm;
13276 pixels = DisplayWidth (dpyinfo->display, screen_number);
13277 mm = DisplayWidthMM (dpyinfo->display, screen_number);
13278 dpyinfo->resx = pixels * 25.4 / mm;
13279 }
13280
334208b7
RS
13281 dpyinfo->Xatom_wm_protocols
13282 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
13283 dpyinfo->Xatom_wm_take_focus
13284 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
13285 dpyinfo->Xatom_wm_save_yourself
13286 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
13287 dpyinfo->Xatom_wm_delete_window
13288 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
13289 dpyinfo->Xatom_wm_change_state
13290 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
13291 dpyinfo->Xatom_wm_configure_denied
13292 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
13293 dpyinfo->Xatom_wm_window_moved
13294 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
13295 dpyinfo->Xatom_editres
13296 = XInternAtom (dpyinfo->display, "Editres", False);
13297 dpyinfo->Xatom_CLIPBOARD
13298 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
13299 dpyinfo->Xatom_TIMESTAMP
13300 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
13301 dpyinfo->Xatom_TEXT
13302 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
13303 dpyinfo->Xatom_COMPOUND_TEXT
13304 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
13305 dpyinfo->Xatom_DELETE
13306 = XInternAtom (dpyinfo->display, "DELETE", False);
13307 dpyinfo->Xatom_MULTIPLE
13308 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
13309 dpyinfo->Xatom_INCR
13310 = XInternAtom (dpyinfo->display, "INCR", False);
13311 dpyinfo->Xatom_EMACS_TMP
13312 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
13313 dpyinfo->Xatom_TARGETS
13314 = XInternAtom (dpyinfo->display, "TARGETS", False);
13315 dpyinfo->Xatom_NULL
13316 = XInternAtom (dpyinfo->display, "NULL", False);
13317 dpyinfo->Xatom_ATOM_PAIR
13318 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
13319 /* For properties of font. */
13320 dpyinfo->Xatom_PIXEL_SIZE
13321 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
13322 dpyinfo->Xatom_MULE_BASELINE_OFFSET
13323 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
13324 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
13325 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
13326 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
13327 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 13328
06a2c219
GM
13329 /* Ghostscript support. */
13330 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
13331 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
13332
13333 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
13334 False);
13335
547d9db8
KH
13336 dpyinfo->cut_buffers_initialized = 0;
13337
334208b7
RS
13338 connection = ConnectionNumber (dpyinfo->display);
13339 dpyinfo->connection = connection;
13340
dc43ef94 13341 {
5d7cc324
RS
13342 char null_bits[1];
13343
13344 null_bits[0] = 0x00;
dc43ef94
KH
13345
13346 dpyinfo->null_pixel
13347 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13348 null_bits, 1, 1, (long) 0, (long) 0,
13349 1);
13350 }
13351
06a2c219
GM
13352 {
13353 extern int gray_bitmap_width, gray_bitmap_height;
13354 extern unsigned char *gray_bitmap_bits;
13355 dpyinfo->gray
13356 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13357 gray_bitmap_bits,
13358 gray_bitmap_width, gray_bitmap_height,
13359 (unsigned long) 1, (unsigned long) 0, 1);
13360 }
13361
f5d11644
GM
13362#ifdef HAVE_X_I18N
13363 xim_initialize (dpyinfo, resource_name);
13364#endif
13365
87485d6f
MW
13366#ifdef subprocesses
13367 /* This is only needed for distinguishing keyboard and process input. */
334208b7 13368 if (connection != 0)
7a13e894 13369 add_keyboard_wait_descriptor (connection);
87485d6f 13370#endif
6d4238f3 13371
041b69ac 13372#ifndef F_SETOWN_BUG
dc6f92b8 13373#ifdef F_SETOWN
dc6f92b8 13374#ifdef F_SETOWN_SOCK_NEG
61c3ce62 13375 /* stdin is a socket here */
334208b7 13376 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 13377#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 13378 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
13379#endif /* ! defined (F_SETOWN_SOCK_NEG) */
13380#endif /* ! defined (F_SETOWN) */
041b69ac 13381#endif /* F_SETOWN_BUG */
dc6f92b8
JB
13382
13383#ifdef SIGIO
eee20f6a
KH
13384 if (interrupt_input)
13385 init_sigio (connection);
c118dd06 13386#endif /* ! defined (SIGIO) */
dc6f92b8 13387
51b592fb 13388#ifdef USE_LUCID
f8c39f51 13389#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
13390 /* Make sure that we have a valid font for dialog boxes
13391 so that Xt does not crash. */
13392 {
13393 Display *dpy = dpyinfo->display;
13394 XrmValue d, fr, to;
13395 Font font;
e99db5a1 13396 int count;
51b592fb
RS
13397
13398 d.addr = (XPointer)&dpy;
13399 d.size = sizeof (Display *);
13400 fr.addr = XtDefaultFont;
13401 fr.size = sizeof (XtDefaultFont);
13402 to.size = sizeof (Font *);
13403 to.addr = (XPointer)&font;
e99db5a1 13404 count = x_catch_errors (dpy);
51b592fb
RS
13405 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
13406 abort ();
13407 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
13408 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 13409 x_uncatch_errors (dpy, count);
51b592fb
RS
13410 }
13411#endif
f8c39f51 13412#endif
51b592fb 13413
34e23e5a
GM
13414 /* See if we should run in synchronous mode. This is useful
13415 for debugging X code. */
13416 {
13417 Lisp_Object value;
13418 value = display_x_get_resource (dpyinfo,
13419 build_string ("synchronous"),
13420 build_string ("Synchronous"),
13421 Qnil, Qnil);
13422 if (STRINGP (value)
13423 && (!strcmp (XSTRING (value)->data, "true")
13424 || !strcmp (XSTRING (value)->data, "on")))
13425 XSynchronize (dpyinfo->display, True);
13426 }
13427
60439948
KH
13428 UNBLOCK_INPUT;
13429
7a13e894
RS
13430 return dpyinfo;
13431}
13432\f
13433/* Get rid of display DPYINFO, assuming all frames are already gone,
13434 and without sending any more commands to the X server. */
dc6f92b8 13435
7a13e894
RS
13436void
13437x_delete_display (dpyinfo)
13438 struct x_display_info *dpyinfo;
13439{
13440 delete_keyboard_wait_descriptor (dpyinfo->connection);
13441
13442 /* Discard this display from x_display_name_list and x_display_list.
13443 We can't use Fdelq because that can quit. */
13444 if (! NILP (x_display_name_list)
8e713be6
KR
13445 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
13446 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
13447 else
13448 {
13449 Lisp_Object tail;
13450
13451 tail = x_display_name_list;
8e713be6 13452 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 13453 {
bffcfca9 13454 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 13455 {
8e713be6 13456 XCDR (tail) = XCDR (XCDR (tail));
7a13e894
RS
13457 break;
13458 }
8e713be6 13459 tail = XCDR (tail);
7a13e894
RS
13460 }
13461 }
13462
9bda743f
GM
13463 if (next_noop_dpyinfo == dpyinfo)
13464 next_noop_dpyinfo = dpyinfo->next;
13465
7a13e894
RS
13466 if (x_display_list == dpyinfo)
13467 x_display_list = dpyinfo->next;
7f9c7f94
RS
13468 else
13469 {
13470 struct x_display_info *tail;
7a13e894 13471
7f9c7f94
RS
13472 for (tail = x_display_list; tail; tail = tail->next)
13473 if (tail->next == dpyinfo)
13474 tail->next = tail->next->next;
13475 }
7a13e894 13476
0d777288
RS
13477#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
13478#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
13479 XrmDestroyDatabase (dpyinfo->xrdb);
13480#endif
0d777288 13481#endif
29b38361
KH
13482#ifdef MULTI_KBOARD
13483 if (--dpyinfo->kboard->reference_count == 0)
39f79001 13484 delete_kboard (dpyinfo->kboard);
b9737ad3 13485#endif
f5d11644
GM
13486#ifdef HAVE_X_I18N
13487 if (dpyinfo->xim)
13488 xim_close_dpy (dpyinfo);
13489#endif
13490
b9737ad3
KH
13491 xfree (dpyinfo->font_table);
13492 xfree (dpyinfo->x_id_name);
13493 xfree (dpyinfo);
7a13e894
RS
13494}
13495\f
13496/* Set up use of X before we make the first connection. */
13497
06a2c219
GM
13498static struct redisplay_interface x_redisplay_interface =
13499{
13500 x_produce_glyphs,
13501 x_write_glyphs,
13502 x_insert_glyphs,
13503 x_clear_end_of_line,
13504 x_scroll_run,
13505 x_after_update_window_line,
13506 x_update_window_begin,
13507 x_update_window_end,
13508 XTcursor_to,
13509 x_flush,
71b8321e 13510 x_clear_mouse_face,
66ac4b0e
GM
13511 x_get_glyph_overhangs,
13512 x_fix_overlapping_area
06a2c219
GM
13513};
13514
dfcf069d 13515void
7a13e894
RS
13516x_initialize ()
13517{
06a2c219
GM
13518 rif = &x_redisplay_interface;
13519
13520 clear_frame_hook = x_clear_frame;
13521 ins_del_lines_hook = x_ins_del_lines;
13522 change_line_highlight_hook = x_change_line_highlight;
13523 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
13524 ring_bell_hook = XTring_bell;
13525 reset_terminal_modes_hook = XTreset_terminal_modes;
13526 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
13527 update_begin_hook = x_update_begin;
13528 update_end_hook = x_update_end;
dc6f92b8
JB
13529 set_terminal_window_hook = XTset_terminal_window;
13530 read_socket_hook = XTread_socket;
b8009dd1 13531 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 13532 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 13533 mouse_position_hook = XTmouse_position;
f451eb13 13534 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 13535 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
13536 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13537 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13538 redeem_scroll_bar_hook = XTredeem_scroll_bar;
13539 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 13540 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 13541
f676886a 13542 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
13543 char_ins_del_ok = 0; /* just as fast to write the line */
13544 line_ins_del_ok = 1; /* we'll just blt 'em */
13545 fast_clear_end_of_line = 1; /* X does this well */
58769bee 13546 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
13547 off the bottom */
13548 baud_rate = 19200;
13549
7a13e894 13550 x_noop_count = 0;
9ea173e8 13551 last_tool_bar_item = -1;
06a2c219
GM
13552 any_help_event_p = 0;
13553
b30b24cb
RS
13554 /* Try to use interrupt input; if we can't, then start polling. */
13555 Fset_input_mode (Qt, Qnil, Qt, Qnil);
13556
7f9c7f94
RS
13557#ifdef USE_X_TOOLKIT
13558 XtToolkitInitialize ();
13559 Xt_app_con = XtCreateApplicationContext ();
665881ad 13560 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
13561
13562 /* Install an asynchronous timer that processes Xt timeout events
13563 every 0.1s. This is necessary because some widget sets use
13564 timeouts internally, for example the LessTif menu bar, or the
13565 Xaw3d scroll bar. When Xt timouts aren't processed, these
13566 widgets don't behave normally. */
13567 {
13568 EMACS_TIME interval;
13569 EMACS_SET_SECS_USECS (interval, 0, 100000);
13570 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
13571 }
db74249b 13572#endif
bffcfca9 13573
db74249b 13574#if USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
13575 xaw3d_arrow_scroll = False;
13576 xaw3d_pick_top = True;
7f9c7f94
RS
13577#endif
13578
58769bee 13579 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 13580 original error handler. */
e99db5a1 13581 XSetErrorHandler (x_error_handler);
334208b7 13582 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 13583
06a2c219 13584 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
13585#ifdef SIGWINCH
13586 signal (SIGWINCH, SIG_DFL);
c118dd06 13587#endif /* ! defined (SIGWINCH) */
dc6f92b8 13588
92e2441b 13589 signal (SIGPIPE, x_connection_signal);
dc6f92b8 13590}
55123275 13591
06a2c219 13592
55123275
JB
13593void
13594syms_of_xterm ()
13595{
e99db5a1
RS
13596 staticpro (&x_error_message_string);
13597 x_error_message_string = Qnil;
13598
7a13e894
RS
13599 staticpro (&x_display_name_list);
13600 x_display_name_list = Qnil;
334208b7 13601
ab648270 13602 staticpro (&last_mouse_scroll_bar);
e53cb100 13603 last_mouse_scroll_bar = Qnil;
59e755be
KH
13604
13605 staticpro (&Qvendor_specific_keysyms);
13606 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
13607
13608 staticpro (&last_mouse_press_frame);
13609 last_mouse_press_frame = Qnil;
06a2c219 13610
06a2c219 13611 help_echo = Qnil;
be010514
GM
13612 staticpro (&help_echo);
13613 help_echo_object = Qnil;
13614 staticpro (&help_echo_object);
7cea38bc
GM
13615 help_echo_window = Qnil;
13616 staticpro (&help_echo_window);
06a2c219 13617 previous_help_echo = Qnil;
be010514
GM
13618 staticpro (&previous_help_echo);
13619 help_echo_pos = -1;
06a2c219
GM
13620
13621 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
13622 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
13623For example, if a block cursor is over a tab, it will be drawn as\n\
13624wide as that tab on the display.");
13625 x_stretch_cursor_p = 0;
13626
13627 DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
13628 "If not nil, Emacs uses toolkit scroll bars.");
13629#if USE_TOOLKIT_SCROLL_BARS
13630 x_toolkit_scroll_bars_p = 1;
13631#else
13632 x_toolkit_scroll_bars_p = 0;
13633#endif
13634
06a2c219
GM
13635 staticpro (&last_mouse_motion_frame);
13636 last_mouse_motion_frame = Qnil;
55123275 13637}
6cf0ae86
RS
13638
13639#endif /* not HAVE_X_WINDOWS */
06a2c219 13640