*** empty log message ***
[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
9d7e2e3e 104extern void free_frame_menubar ();
2224b905 105extern FRAME_PTR x_menubar_window_to_frame ();
06a2c219 106
0fdff6bb
RS
107#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
108#define HACK_EDITRES
109extern void _XEditResCheckMessages ();
110#endif /* not NO_EDITRES */
06a2c219
GM
111
112/* Include toolkit specific headers for the scroll bar widget. */
113
114#ifdef USE_TOOLKIT_SCROLL_BARS
115#if defined USE_MOTIF
116#include <Xm/Xm.h> /* for LESSTIF_VERSION */
117#include <Xm/ScrollBar.h>
118#include <Xm/ScrollBarP.h>
ec18280f
SM
119#else /* !USE_MOTIF i.e. use Xaw */
120
121#ifdef HAVE_XAW3D
06a2c219 122#include <X11/Xaw3d/Simple.h>
06a2c219
GM
123#include <X11/Xaw3d/Scrollbar.h>
124#define ARROW_SCROLLBAR
125#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
126#else /* !HAVE_XAW3D */
127#include <X11/Xaw/Simple.h>
128#include <X11/Xaw/Scrollbar.h>
129#endif /* !HAVE_XAW3D */
130#ifndef XtNpickTop
131#define XtNpickTop "pickTop"
132#endif /* !XtNpickTop */
133#endif /* !USE_MOTIF */
06a2c219
GM
134#endif /* USE_TOOLKIT_SCROLL_BARS */
135
3afe33e7
RS
136#endif /* USE_X_TOOLKIT */
137
b849c413
RS
138#ifndef USE_X_TOOLKIT
139#define x_any_window_to_frame x_window_to_frame
5627c40e 140#define x_top_window_to_frame x_window_to_frame
b849c413
RS
141#endif
142
546e6d5b 143#ifdef USE_X_TOOLKIT
d067ea8b 144#include "widget.h"
546e6d5b
RS
145#ifndef XtNinitialState
146#define XtNinitialState "initialState"
147#endif
148#endif
149
80528801
KH
150#ifdef SOLARIS2
151/* memmove will be defined as a macro in Xfuncs.h unless
152 <string.h> is included beforehand. The declaration for memmove in
153 <string.h> will cause a syntax error when Xfuncs.h later includes it. */
154#include <string.h>
155#endif
156
e4b68333 157#ifndef min
06a2c219 158#define min(a,b) ((a) < (b) ? (a) : (b))
e4b68333
RS
159#endif
160#ifndef max
06a2c219
GM
161#define max(a,b) ((a) > (b) ? (a) : (b))
162#endif
163
164#define abs(x) ((x) < 0 ? -(x) : (x))
165
166#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
167
168\f
169/* Bitmaps for truncated lines. */
170
171enum bitmap_type
172{
173 NO_BITMAP,
174 LEFT_TRUNCATION_BITMAP,
175 RIGHT_TRUNCATION_BITMAP,
176 OVERLAY_ARROW_BITMAP,
177 CONTINUED_LINE_BITMAP,
178 CONTINUATION_LINE_BITMAP,
179 ZV_LINE_BITMAP
180};
181
182/* Bitmap drawn to indicate lines not displaying text if
183 `indicate-empty-lines' is non-nil. */
184
185#define zv_width 8
186#define zv_height 8
187static unsigned char zv_bits[] = {
188 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
189
190/* An arrow like this: `<-'. */
191
192#define left_width 8
193#define left_height 8
194static unsigned char left_bits[] = {
195 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
196
110859fc
GM
197/* Right truncation arrow bitmap `->'. */
198
199#define right_width 8
200#define right_height 8
201static unsigned char right_bits[] = {
202 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
203
06a2c219
GM
204/* Marker for continued lines. */
205
206#define continued_width 8
207#define continued_height 8
208static unsigned char continued_bits[] = {
110859fc
GM
209 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
210
211/* Marker for continuation lines. */
06a2c219
GM
212
213#define continuation_width 8
214#define continuation_height 8
215static unsigned char continuation_bits[] = {
110859fc 216 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 217
110859fc 218/* Overlay arrow bitmap. */
06a2c219 219
110859fc
GM
220#if 0
221/* A bomb. */
06a2c219
GM
222#define ov_width 8
223#define ov_height 8
224static unsigned char ov_bits[] = {
225 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 226#else
110859fc 227/* A triangular arrow. */
06a2c219
GM
228#define ov_width 8
229#define ov_height 8
230static unsigned char ov_bits[] = {
110859fc
GM
231 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
232
e4b68333 233#endif
06a2c219
GM
234
235extern Lisp_Object Qhelp_echo;
236
69388238 237\f
06a2c219
GM
238/* Non-zero means Emacs uses toolkit scroll bars. */
239
240int x_toolkit_scroll_bars_p;
241
242/* If a string, XTread_socket generates an event to display that string.
243 (The display is done in read_char.) */
244
245static Lisp_Object help_echo;
246
247/* Temporary variable for XTread_socket. */
248
249static Lisp_Object previous_help_echo;
250
251/* Non-zero means that a HELP_EVENT has been generated since Emacs
252 start. */
253
254static int any_help_event_p;
255
256/* Non-zero means draw block and hollow cursor as wide as the glyph
257 under it. For example, if a block cursor is over a tab, it will be
258 drawn as wide as that tab on the display. */
259
260int x_stretch_cursor_p;
261
262/* This is a chain of structures for all the X displays currently in
263 use. */
264
334208b7 265struct x_display_info *x_display_list;
dc6f92b8 266
06a2c219
GM
267/* This is a list of cons cells, each of the form (NAME
268 . FONT-LIST-CACHE), one for each element of x_display_list and in
269 the same order. NAME is the name of the frame. FONT-LIST-CACHE
270 records previous values returned by x-list-fonts. */
271
7a13e894 272Lisp_Object x_display_name_list;
f451eb13 273
987d2ad1 274/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
275 This is set by update_begin and looked at by all the XT functions.
276 It is zero while not inside an update. In that case, the XT
277 functions assume that `selected_frame' is the frame to apply to. */
278
d0386f2a 279extern struct frame *updating_frame;
dc6f92b8 280
dfcf069d 281extern int waiting_for_input;
0e81d8cd 282
06a2c219
GM
283/* This is a frame waiting to be auto-raised, within XTread_socket. */
284
0134a210
RS
285struct frame *pending_autoraise_frame;
286
7f9c7f94
RS
287#ifdef USE_X_TOOLKIT
288/* The application context for Xt use. */
289XtAppContext Xt_app_con;
06a2c219
GM
290static String Xt_default_resources[] = {0};
291#endif /* USE_X_TOOLKIT */
665881ad 292
06a2c219
GM
293/* Nominal cursor position -- where to draw output.
294 HPOS and VPOS are window relative glyph matrix coordinates.
295 X and Y are window relative pixel coordinates. */
dc6f92b8 296
06a2c219 297struct cursor_pos output_cursor;
dc6f92b8 298
bffcfca9
GM
299/* Non-zero means user is interacting with a toolkit scroll bar. */
300
301static int toolkit_scroll_bar_interaction;
dc6f92b8 302
69388238
RS
303/* Mouse movement.
304
06a2c219 305 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
306 so that we would have to call XQueryPointer after each MotionNotify
307 event to ask for another such event. However, this made mouse tracking
308 slow, and there was a bug that made it eventually stop.
309
310 Simply asking for MotionNotify all the time seems to work better.
311
69388238
RS
312 In order to avoid asking for motion events and then throwing most
313 of them away or busy-polling the server for mouse positions, we ask
314 the server for pointer motion hints. This means that we get only
315 one event per group of mouse movements. "Groups" are delimited by
316 other kinds of events (focus changes and button clicks, for
317 example), or by XQueryPointer calls; when one of these happens, we
318 get another MotionNotify event the next time the mouse moves. This
319 is at least as efficient as getting motion events when mouse
320 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 321 is off. */
69388238
RS
322
323/* Where the mouse was last time we reported a mouse event. */
69388238 324
06a2c219
GM
325FRAME_PTR last_mouse_frame;
326static XRectangle last_mouse_glyph;
2237cac9
RS
327static Lisp_Object last_mouse_press_frame;
328
69388238
RS
329/* The scroll bar in which the last X motion event occurred.
330
06a2c219
GM
331 If the last X motion event occurred in a scroll bar, we set this so
332 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
333 an ordinary motion.
334
06a2c219
GM
335 If the last X motion event didn't occur in a scroll bar, we set
336 this to Qnil, to tell XTmouse_position to return an ordinary motion
337 event. */
338
69388238
RS
339static Lisp_Object last_mouse_scroll_bar;
340
69388238
RS
341/* This is a hack. We would really prefer that XTmouse_position would
342 return the time associated with the position it returns, but there
06a2c219 343 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
344 along with the position query. So, we just keep track of the time
345 of the last movement we received, and return that in hopes that
346 it's somewhat accurate. */
06a2c219 347
69388238
RS
348static Time last_mouse_movement_time;
349
06a2c219
GM
350/* Incremented by XTread_socket whenever it really tries to read
351 events. */
352
c0a04927
RS
353#ifdef __STDC__
354static int volatile input_signal_count;
355#else
356static int input_signal_count;
357#endif
358
7a13e894 359/* Used locally within XTread_socket. */
06a2c219 360
7a13e894 361static int x_noop_count;
dc6f92b8 362
7a13e894 363/* Initial values of argv and argc. */
06a2c219 364
7a13e894
RS
365extern char **initial_argv;
366extern int initial_argc;
dc6f92b8 367
7a13e894 368extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 369
06a2c219 370/* Tells if a window manager is present or not. */
7a13e894
RS
371
372extern Lisp_Object Vx_no_window_manager;
dc6f92b8 373
c2df547c 374extern Lisp_Object Qface, Qmouse_face;
b8009dd1 375
dc6f92b8
JB
376extern int errno;
377
dfeccd2d 378/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 379
64bb1782
RS
380extern int extra_keyboard_modifiers;
381
59e755be
KH
382static Lisp_Object Qvendor_specific_keysyms;
383
334208b7 384extern XrmDatabase x_load_resources ();
c32cdd9a
KH
385extern Lisp_Object x_icon_type ();
386
7a13e894 387
06a2c219
GM
388/* Enumeration for overriding/changing the face to use for drawing
389 glyphs in x_draw_glyphs. */
390
391enum draw_glyphs_face
392{
393 DRAW_NORMAL_TEXT,
394 DRAW_INVERSE_VIDEO,
395 DRAW_CURSOR,
396 DRAW_MOUSE_FACE,
397 DRAW_IMAGE_RAISED,
398 DRAW_IMAGE_SUNKEN
399};
400
71b8321e 401static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
402static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
403void x_delete_display P_ ((struct x_display_info *));
404static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
405 unsigned));
406static int fast_find_position P_ ((struct window *, int, int *, int *,
407 int *, int *));
408static void set_output_cursor P_ ((struct cursor_pos *));
409static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
410 int *, int *, int *));
411static void note_mode_line_highlight P_ ((struct window *, int, int));
06a2c219 412static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
413static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
414static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
415static void show_mouse_face P_ ((struct x_display_info *,
416 enum draw_glyphs_face));
417static int x_io_error_quitter P_ ((Display *));
418int x_catch_errors P_ ((Display *));
419void x_uncatch_errors P_ ((Display *, int));
420void x_lower_frame P_ ((struct frame *));
421void x_scroll_bar_clear P_ ((struct frame *));
422int x_had_errors_p P_ ((Display *));
423void x_wm_set_size_hint P_ ((struct frame *, long, int));
424void x_raise_frame P_ ((struct frame *));
425void x_set_window_size P_ ((struct frame *, int, int, int));
426void x_wm_set_window_state P_ ((struct frame *, int));
427void x_wm_set_icon_pixmap P_ ((struct frame *, int));
428void x_initialize P_ ((void));
429static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
430static int x_compute_min_glyph_bounds P_ ((struct frame *));
431static void x_draw_phys_cursor_glyph P_ ((struct window *,
432 struct glyph_row *,
433 enum draw_glyphs_face));
434static void x_update_end P_ ((struct frame *));
435static void XTframe_up_to_date P_ ((struct frame *));
436static void XTreassert_line_highlight P_ ((int, int));
437static void x_change_line_highlight P_ ((int, int, int, int));
438static void XTset_terminal_modes P_ ((void));
439static void XTreset_terminal_modes P_ ((void));
440static void XTcursor_to P_ ((int, int, int, int));
441static void x_write_glyphs P_ ((struct glyph *, int));
442static void x_clear_end_of_line P_ ((int));
443static void x_clear_frame P_ ((void));
444static void x_clear_cursor P_ ((struct window *));
445static void frame_highlight P_ ((struct frame *));
446static void frame_unhighlight P_ ((struct frame *));
447static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
448static void XTframe_rehighlight P_ ((struct frame *));
449static void x_frame_rehighlight P_ ((struct x_display_info *));
450static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 451static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
452static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
453 XRectangle *));
454static void expose_frame P_ ((struct frame *, int, int, int, int));
455static void expose_window_tree P_ ((struct window *, XRectangle *));
456static void expose_window P_ ((struct window *, XRectangle *));
457static void expose_area P_ ((struct window *, struct glyph_row *,
458 XRectangle *, enum glyph_row_area));
459static void expose_line P_ ((struct window *, struct glyph_row *,
460 XRectangle *));
461static void x_update_cursor_in_window_tree P_ ((struct window *, int));
462static void x_update_window_cursor P_ ((struct window *, int));
463static void x_erase_phys_cursor P_ ((struct window *));
464void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
465static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
466 enum bitmap_type));
467
468static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
469 GC, int));
470static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
471static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
472static void note_overwritten_text_cursor P_ ((struct window *, int, int));
473static void x_flush P_ ((struct frame *f));
474
475
476/* Flush display of frame F, or of all frames if F is null. */
477
478static void
479x_flush (f)
480 struct frame *f;
481{
482 BLOCK_INPUT;
483 if (f == NULL)
484 {
485 Lisp_Object rest, frame;
486 FOR_EACH_FRAME (rest, frame)
487 x_flush (XFRAME (frame));
488 }
489 else if (FRAME_X_P (f))
490 XFlush (FRAME_X_DISPLAY (f));
491 UNBLOCK_INPUT;
492}
493
dc6f92b8 494
06a2c219
GM
495/* Remove calls to XFlush by defining XFlush to an empty replacement.
496 Calls to XFlush should be unnecessary because the X output buffer
497 is flushed automatically as needed by calls to XPending,
498 XNextEvent, or XWindowEvent according to the XFlush man page.
499 XTread_socket calls XPending. Removing XFlush improves
500 performance. */
501
502#define XFlush(DISPLAY) (void) 0
b8009dd1 503
334208b7 504\f
06a2c219
GM
505/***********************************************************************
506 Debugging
507 ***********************************************************************/
508
9382638d 509#if 0
06a2c219
GM
510
511/* This is a function useful for recording debugging information about
512 the sequence of occurrences in this file. */
9382638d
KH
513
514struct record
515{
516 char *locus;
517 int type;
518};
519
520struct record event_record[100];
521
522int event_record_index;
523
524record_event (locus, type)
525 char *locus;
526 int type;
527{
528 if (event_record_index == sizeof (event_record) / sizeof (struct record))
529 event_record_index = 0;
530
531 event_record[event_record_index].locus = locus;
532 event_record[event_record_index].type = type;
533 event_record_index++;
534}
535
536#endif /* 0 */
06a2c219
GM
537
538
9382638d 539\f
334208b7
RS
540/* Return the struct x_display_info corresponding to DPY. */
541
542struct x_display_info *
543x_display_info_for_display (dpy)
544 Display *dpy;
545{
546 struct x_display_info *dpyinfo;
547
548 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
549 if (dpyinfo->display == dpy)
550 return dpyinfo;
16bd92ea 551
334208b7
RS
552 return 0;
553}
f451eb13 554
06a2c219
GM
555
556\f
557/***********************************************************************
558 Starting and ending an update
559 ***********************************************************************/
560
561/* Start an update of frame F. This function is installed as a hook
562 for update_begin, i.e. it is called when update_begin is called.
563 This function is called prior to calls to x_update_window_begin for
564 each window being updated. Currently, there is nothing to do here
565 because all interesting stuff is done on a window basis. */
dc6f92b8 566
dfcf069d 567static void
06a2c219 568x_update_begin (f)
f676886a 569 struct frame *f;
58769bee 570{
06a2c219
GM
571 /* Nothing to do. */
572}
dc6f92b8 573
dc6f92b8 574
06a2c219
GM
575/* Start update of window W. Set the global variable updated_window
576 to the window being updated and set output_cursor to the cursor
577 position of W. */
dc6f92b8 578
06a2c219
GM
579static void
580x_update_window_begin (w)
581 struct window *w;
582{
583 struct frame *f = XFRAME (WINDOW_FRAME (w));
584 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
585
586 updated_window = w;
587 set_output_cursor (&w->cursor);
b8009dd1 588
06a2c219 589 BLOCK_INPUT;
d1bc4182 590
06a2c219 591 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 592 {
514e4681 593 /* Don't do highlighting for mouse motion during the update. */
06a2c219 594 display_info->mouse_face_defer = 1;
37c2c98b 595
06a2c219
GM
596 /* If F needs to be redrawn, simply forget about any prior mouse
597 highlighting. */
9f67f20b 598 if (FRAME_GARBAGED_P (f))
06a2c219
GM
599 display_info->mouse_face_window = Qnil;
600
64f26cf5
GM
601#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
602 their mouse_face_p flag set, which means that they are always
603 unequal to rows in a desired matrix which never have that
604 flag set. So, rows containing mouse-face glyphs are never
605 scrolled, and we don't have to switch the mouse highlight off
606 here to prevent it from being scrolled. */
607
06a2c219
GM
608 /* Can we tell that this update does not affect the window
609 where the mouse highlight is? If so, no need to turn off.
610 Likewise, don't do anything if the frame is garbaged;
611 in that case, the frame's current matrix that we would use
612 is all wrong, and we will redisplay that line anyway. */
613 if (!NILP (display_info->mouse_face_window)
614 && w == XWINDOW (display_info->mouse_face_window))
514e4681 615 {
06a2c219 616 int i;
514e4681 617
06a2c219
GM
618 for (i = 0; i < w->desired_matrix->nrows; ++i)
619 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
620 break;
621
06a2c219
GM
622 if (i < w->desired_matrix->nrows)
623 clear_mouse_face (display_info);
514e4681 624 }
64f26cf5 625#endif /* 0 */
b8009dd1 626 }
6ccf47d1 627
dc6f92b8
JB
628 UNBLOCK_INPUT;
629}
630
06a2c219
GM
631
632/* Draw a vertical window border to the right of window W if W doesn't
633 have vertical scroll bars. */
634
dfcf069d 635static void
06a2c219
GM
636x_draw_vertical_border (w)
637 struct window *w;
58769bee 638{
06a2c219
GM
639 struct frame *f = XFRAME (WINDOW_FRAME (w));
640
641 /* Redraw borders between horizontally adjacent windows. Don't
642 do it for frames with vertical scroll bars because either the
643 right scroll bar of a window, or the left scroll bar of its
644 neighbor will suffice as a border. */
645 if (!WINDOW_RIGHTMOST_P (w)
646 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
647 {
648 int x0, x1, y0, y1;
dc6f92b8 649
06a2c219 650 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 651 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
652 y1 -= 1;
653
654 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
655 f->output_data.x->normal_gc, x1, y0, x1, y1);
656 }
657}
658
659
71b8321e
GM
660/* End update of window W (which is equal to updated_window).
661
662 Draw vertical borders between horizontally adjacent windows, and
663 display W's cursor if CURSOR_ON_P is non-zero.
664
665 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
666 glyphs in mouse-face were overwritten. In that case we have to
667 make sure that the mouse-highlight is properly redrawn.
668
669 W may be a menu bar pseudo-window in case we don't have X toolkit
670 support. Such windows don't have a cursor, so don't display it
671 here. */
06a2c219
GM
672
673static void
71b8321e 674x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 675 struct window *w;
71b8321e 676 int cursor_on_p, mouse_face_overwritten_p;
06a2c219
GM
677{
678 if (!w->pseudo_window_p)
679 {
71b8321e
GM
680 struct x_display_info *dpyinfo
681 = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
682
06a2c219 683 BLOCK_INPUT;
71b8321e
GM
684
685 /* If a row with mouse-face was overwritten, arrange for
686 XTframe_up_to_date to redisplay the mouse highlight. */
687 if (mouse_face_overwritten_p)
688 {
689 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
690 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
691 dpyinfo->mouse_face_window = Qnil;
692 }
693
06a2c219
GM
694 if (cursor_on_p)
695 x_display_and_set_cursor (w, 1, output_cursor.hpos,
696 output_cursor.vpos,
697 output_cursor.x, output_cursor.y);
71b8321e 698
06a2c219
GM
699 x_draw_vertical_border (w);
700 UNBLOCK_INPUT;
701 }
702
703 updated_window = NULL;
704}
dc6f92b8 705
dc6f92b8 706
06a2c219
GM
707/* End update of frame F. This function is installed as a hook in
708 update_end. */
709
710static void
711x_update_end (f)
712 struct frame *f;
713{
714 /* Mouse highlight may be displayed again. */
aa8bff2e 715 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 716
06a2c219 717 BLOCK_INPUT;
334208b7 718 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
719 UNBLOCK_INPUT;
720}
b8009dd1 721
06a2c219
GM
722
723/* This function is called from various places in xdisp.c whenever a
724 complete update has been performed. The global variable
725 updated_window is not available here. */
b8009dd1 726
dfcf069d 727static void
b8009dd1 728XTframe_up_to_date (f)
06a2c219 729 struct frame *f;
b8009dd1 730{
06a2c219 731 if (FRAME_X_P (f))
514e4681 732 {
06a2c219 733 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 734
06a2c219
GM
735 if (dpyinfo->mouse_face_deferred_gc
736 || f == dpyinfo->mouse_face_mouse_frame)
737 {
738 BLOCK_INPUT;
739 if (dpyinfo->mouse_face_mouse_frame)
740 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
741 dpyinfo->mouse_face_mouse_x,
742 dpyinfo->mouse_face_mouse_y);
743 dpyinfo->mouse_face_deferred_gc = 0;
744 UNBLOCK_INPUT;
745 }
514e4681 746 }
b8009dd1 747}
06a2c219
GM
748
749
750/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
751 arrow bitmaps, or clear the areas where they would be displayed
752 before DESIRED_ROW is made current. The window being updated is
753 found in updated_window. This function It is called from
754 update_window_line only if it is known that there are differences
755 between bitmaps to be drawn between current row and DESIRED_ROW. */
756
757static void
758x_after_update_window_line (desired_row)
759 struct glyph_row *desired_row;
760{
761 struct window *w = updated_window;
762
763 xassert (w);
764
765 if (!desired_row->mode_line_p && !w->pseudo_window_p)
766 {
767 BLOCK_INPUT;
768 x_draw_row_bitmaps (w, desired_row);
769
770 /* When a window has disappeared, make sure that no rest of
771 full-width rows stays visible in the internal border. */
772 if (windows_or_buffers_changed)
773 {
774 struct frame *f = XFRAME (w->frame);
775 int width = FRAME_INTERNAL_BORDER_WIDTH (f);
776 int height = desired_row->visible_height;
110859fc
GM
777 int x = (window_box_right (w, -1)
778 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
779 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
780
781 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
782 x, y, width, height, False);
783 }
784
785 UNBLOCK_INPUT;
786 }
787}
788
789
790/* Draw the bitmap WHICH in one of the areas to the left or right of
791 window W. ROW is the glyph row for which to display the bitmap; it
792 determines the vertical position at which the bitmap has to be
793 drawn. */
794
795static void
796x_draw_bitmap (w, row, which)
797 struct window *w;
798 struct glyph_row *row;
799 enum bitmap_type which;
800{
801 struct frame *f = XFRAME (WINDOW_FRAME (w));
802 Display *display = FRAME_X_DISPLAY (f);
803 Window window = FRAME_X_WINDOW (f);
804 int x, y, wd, h, dy;
805 unsigned char *bits;
806 Pixmap pixmap;
807 GC gc = f->output_data.x->normal_gc;
808 struct face *face;
809 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
810
811 /* Must clip because of partially visible lines. */
812 x_clip_to_row (w, row, gc, 1);
813
814 switch (which)
815 {
816 case LEFT_TRUNCATION_BITMAP:
817 wd = left_width;
818 h = left_height;
819 bits = left_bits;
820 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
821 - wd
110859fc 822 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
823 break;
824
825 case OVERLAY_ARROW_BITMAP:
826 wd = left_width;
827 h = left_height;
828 bits = ov_bits;
829 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
830 - wd
110859fc 831 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
832 break;
833
834 case RIGHT_TRUNCATION_BITMAP:
835 wd = right_width;
836 h = right_height;
837 bits = right_bits;
838 x = window_box_right (w, -1);
110859fc 839 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
840 break;
841
842 case CONTINUED_LINE_BITMAP:
843 wd = right_width;
844 h = right_height;
845 bits = continued_bits;
846 x = window_box_right (w, -1);
110859fc 847 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
848 break;
849
850 case CONTINUATION_LINE_BITMAP:
851 wd = continuation_width;
852 h = continuation_height;
853 bits = continuation_bits;
854 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
855 - wd
110859fc 856 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
857 break;
858
859 case ZV_LINE_BITMAP:
860 wd = zv_width;
861 h = zv_height;
862 bits = zv_bits;
863 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
864 - wd
110859fc 865 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
866 break;
867
868 default:
869 abort ();
870 }
871
872 /* Convert to frame coordinates. Set dy to the offset in the row to
873 start drawing the bitmap. */
874 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
875 dy = (row->height - h) / 2;
876
877 /* Draw the bitmap. I believe these small pixmaps can be cached
878 by the server. */
879 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
880 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
881 face->foreground,
882 face->background, depth);
883 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
884 XFreePixmap (display, pixmap);
885 XSetClipMask (display, gc, None);
886}
887
888
889/* Draw flags bitmaps for glyph row ROW on window W. Call this
890 function with input blocked. */
891
892static void
893x_draw_row_bitmaps (w, row)
894 struct window *w;
895 struct glyph_row *row;
896{
897 struct frame *f = XFRAME (w->frame);
898 enum bitmap_type bitmap;
899 struct face *face;
045dee35 900 int header_line_height = -1;
06a2c219
GM
901
902 xassert (interrupt_input_blocked);
903
904 /* If row is completely invisible, because of vscrolling, we
905 don't have to draw anything. */
906 if (row->visible_height <= 0)
907 return;
908
909 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
910 PREPARE_FACE_FOR_DISPLAY (f, face);
911
912 /* Decide which bitmap to draw at the left side. */
913 if (row->overlay_arrow_p)
914 bitmap = OVERLAY_ARROW_BITMAP;
915 else if (row->truncated_on_left_p)
916 bitmap = LEFT_TRUNCATION_BITMAP;
917 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
918 bitmap = CONTINUATION_LINE_BITMAP;
919 else if (row->indicate_empty_line_p)
920 bitmap = ZV_LINE_BITMAP;
921 else
922 bitmap = NO_BITMAP;
923
924 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
925 the flags area. */
926 if (bitmap == NO_BITMAP
110859fc 927 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
928 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
929 {
930 /* If W has a vertical border to its left, don't draw over it. */
931 int border = ((XFASTINT (w->left) > 0
932 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
933 ? 1 : 0);
934 int left = window_box_left (w, -1);
935
045dee35
GM
936 if (header_line_height < 0)
937 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
938
939 /* In case the same realized face is used for bitmap areas and
940 for something displayed in the text (e.g. face `region' on
941 mono-displays, the fill style may have been changed to
942 FillSolid in x_draw_glyph_string_background. */
943 if (face->stipple)
944 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
945 else
946 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
947
06a2c219
GM
948 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
949 face->gc,
950 (left
110859fc 951 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 952 + border),
045dee35 953 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 954 row->y)),
110859fc 955 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 956 row->visible_height);
dcd08bfb
GM
957 if (!face->stipple)
958 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
959 }
960
961 /* Draw the left bitmap. */
962 if (bitmap != NO_BITMAP)
963 x_draw_bitmap (w, row, bitmap);
964
965 /* Decide which bitmap to draw at the right side. */
966 if (row->truncated_on_right_p)
967 bitmap = RIGHT_TRUNCATION_BITMAP;
968 else if (row->continued_p)
969 bitmap = CONTINUED_LINE_BITMAP;
970 else
971 bitmap = NO_BITMAP;
972
973 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
974 the flags area. */
975 if (bitmap == NO_BITMAP
110859fc 976 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
977 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
978 {
979 int right = window_box_right (w, -1);
980
045dee35
GM
981 if (header_line_height < 0)
982 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
983
984 /* In case the same realized face is used for bitmap areas and
985 for something displayed in the text (e.g. face `region' on
986 mono-displays, the fill style may have been changed to
987 FillSolid in x_draw_glyph_string_background. */
988 if (face->stipple)
989 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
990 else
991 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
992 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
993 face->gc,
994 right,
045dee35 995 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 996 row->y)),
110859fc 997 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 998 row->visible_height);
dcd08bfb
GM
999 if (!face->stipple)
1000 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
1001 }
1002
1003 /* Draw the right bitmap. */
1004 if (bitmap != NO_BITMAP)
1005 x_draw_bitmap (w, row, bitmap);
1006}
1007
dc6f92b8 1008\f
06a2c219
GM
1009/***********************************************************************
1010 Line Highlighting
1011 ***********************************************************************/
dc6f92b8 1012
06a2c219
GM
1013/* External interface to control of standout mode. Not used for X
1014 frames. Aborts when called. */
1015
1016static void
dc6f92b8
JB
1017XTreassert_line_highlight (new, vpos)
1018 int new, vpos;
1019{
06a2c219 1020 abort ();
dc6f92b8
JB
1021}
1022
06a2c219
GM
1023
1024/* Call this when about to modify line at position VPOS and change
1025 whether it is highlighted. Not used for X frames. Aborts when
1026 called. */
dc6f92b8 1027
dfcf069d 1028static void
06a2c219
GM
1029x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1030 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1031{
06a2c219 1032 abort ();
dc6f92b8
JB
1033}
1034
06a2c219
GM
1035
1036/* This is called when starting Emacs and when restarting after
1037 suspend. When starting Emacs, no X window is mapped. And nothing
1038 must be done to Emacs's own window if it is suspended (though that
1039 rarely happens). */
dc6f92b8 1040
dfcf069d 1041static void
dc6f92b8
JB
1042XTset_terminal_modes ()
1043{
1044}
1045
06a2c219
GM
1046/* This is called when exiting or suspending Emacs. Exiting will make
1047 the X-windows go away, and suspending requires no action. */
dc6f92b8 1048
dfcf069d 1049static void
dc6f92b8
JB
1050XTreset_terminal_modes ()
1051{
dc6f92b8 1052}
06a2c219
GM
1053
1054
dc6f92b8 1055\f
06a2c219
GM
1056/***********************************************************************
1057 Output Cursor
1058 ***********************************************************************/
1059
1060/* Set the global variable output_cursor to CURSOR. All cursor
1061 positions are relative to updated_window. */
dc6f92b8 1062
dfcf069d 1063static void
06a2c219
GM
1064set_output_cursor (cursor)
1065 struct cursor_pos *cursor;
dc6f92b8 1066{
06a2c219
GM
1067 output_cursor.hpos = cursor->hpos;
1068 output_cursor.vpos = cursor->vpos;
1069 output_cursor.x = cursor->x;
1070 output_cursor.y = cursor->y;
1071}
1072
1073
1074/* Set a nominal cursor position.
dc6f92b8 1075
06a2c219
GM
1076 HPOS and VPOS are column/row positions in a window glyph matrix. X
1077 and Y are window text area relative pixel positions.
1078
1079 If this is done during an update, updated_window will contain the
1080 window that is being updated and the position is the future output
1081 cursor position for that window. If updated_window is null, use
1082 selected_window and display the cursor at the given position. */
1083
1084static void
1085XTcursor_to (vpos, hpos, y, x)
1086 int vpos, hpos, y, x;
1087{
1088 struct window *w;
1089
1090 /* If updated_window is not set, work on selected_window. */
1091 if (updated_window)
1092 w = updated_window;
1093 else
1094 w = XWINDOW (selected_window);
dbcb258a 1095
06a2c219
GM
1096 /* Set the output cursor. */
1097 output_cursor.hpos = hpos;
1098 output_cursor.vpos = vpos;
1099 output_cursor.x = x;
1100 output_cursor.y = y;
dc6f92b8 1101
06a2c219
GM
1102 /* If not called as part of an update, really display the cursor.
1103 This will also set the cursor position of W. */
1104 if (updated_window == NULL)
dc6f92b8
JB
1105 {
1106 BLOCK_INPUT;
06a2c219 1107 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1108 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1109 UNBLOCK_INPUT;
1110 }
1111}
dc43ef94 1112
06a2c219
GM
1113
1114\f
1115/***********************************************************************
1116 Display Iterator
1117 ***********************************************************************/
1118
1119/* Function prototypes of this page. */
1120
1121static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1122 struct glyph *,
ee569018
KH
1123 XChar2b *,
1124 int *));
06a2c219
GM
1125static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1126 int, XChar2b *, int));
1127static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1128static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1129static void x_append_glyph P_ ((struct it *));
b4192550 1130static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1131static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1132 int, int, double));
1133static void x_produce_glyphs P_ ((struct it *));
06a2c219 1134static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1135
1136
1137/* Return a pointer to per-char metric information in FONT of a
1138 character pointed by B which is a pointer to an XChar2b. */
1139
1140#define PER_CHAR_METRIC(font, b) \
1141 ((font)->per_char \
1142 ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
1143 + (((font)->min_byte1 || (font)->max_byte1) \
1144 ? (((b)->byte1 - (font)->min_byte1) \
1145 * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
1146 : 0)) \
1147 : &((font)->max_bounds))
dc43ef94 1148
dc6f92b8 1149
e2ef8ee6
GM
1150/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1151 is not contained in the font. */
dc43ef94 1152
06a2c219 1153static INLINE XCharStruct *
ee569018 1154x_per_char_metric (font, char2b)
06a2c219
GM
1155 XFontStruct *font;
1156 XChar2b *char2b;
1157{
1158 /* The result metric information. */
1159 XCharStruct *pcm = NULL;
dc6f92b8 1160
06a2c219 1161 xassert (font && char2b);
dc6f92b8 1162
06a2c219 1163 if (font->per_char != NULL)
dc6f92b8 1164 {
06a2c219 1165 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1166 {
06a2c219
GM
1167 /* min_char_or_byte2 specifies the linear character index
1168 corresponding to the first element of the per_char array,
1169 max_char_or_byte2 is the index of the last character. A
1170 character with non-zero CHAR2B->byte1 is not in the font.
1171 A character with byte2 less than min_char_or_byte2 or
1172 greater max_char_or_byte2 is not in the font. */
1173 if (char2b->byte1 == 0
1174 && char2b->byte2 >= font->min_char_or_byte2
1175 && char2b->byte2 <= font->max_char_or_byte2)
1176 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1177 }
06a2c219 1178 else
dc6f92b8 1179 {
06a2c219
GM
1180 /* If either min_byte1 or max_byte1 are nonzero, both
1181 min_char_or_byte2 and max_char_or_byte2 are less than
1182 256, and the 2-byte character index values corresponding
1183 to the per_char array element N (counting from 0) are:
1184
1185 byte1 = N/D + min_byte1
1186 byte2 = N\D + min_char_or_byte2
1187
1188 where:
1189
1190 D = max_char_or_byte2 - min_char_or_byte2 + 1
1191 / = integer division
1192 \ = integer modulus */
1193 if (char2b->byte1 >= font->min_byte1
1194 && char2b->byte1 <= font->max_byte1
1195 && char2b->byte2 >= font->min_char_or_byte2
1196 && char2b->byte2 <= font->max_char_or_byte2)
1197 {
1198 pcm = (font->per_char
1199 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1200 * (char2b->byte1 - font->min_byte1))
1201 + (char2b->byte2 - font->min_char_or_byte2));
1202 }
dc6f92b8 1203 }
06a2c219
GM
1204 }
1205 else
1206 {
1207 /* If the per_char pointer is null, all glyphs between the first
1208 and last character indexes inclusive have the same
1209 information, as given by both min_bounds and max_bounds. */
1210 if (char2b->byte2 >= font->min_char_or_byte2
1211 && char2b->byte2 <= font->max_char_or_byte2)
1212 pcm = &font->max_bounds;
1213 }
dc6f92b8 1214
ee569018 1215 return ((pcm == NULL
3e71d8f2 1216 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1217 ? NULL : pcm);
06a2c219 1218}
b73b6aaf 1219
57b03282 1220
06a2c219
GM
1221/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1222 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1223
06a2c219
GM
1224static INLINE void
1225x_encode_char (c, char2b, font_info)
1226 int c;
1227 XChar2b *char2b;
1228 struct font_info *font_info;
1229{
1230 int charset = CHAR_CHARSET (c);
1231 XFontStruct *font = font_info->font;
1232
1233 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1234 This may be either a program in a special encoder language or a
1235 fixed encoding. */
1236 if (font_info->font_encoder)
1237 {
1238 /* It's a program. */
1239 struct ccl_program *ccl = font_info->font_encoder;
1240
1241 if (CHARSET_DIMENSION (charset) == 1)
1242 {
1243 ccl->reg[0] = charset;
1244 ccl->reg[1] = char2b->byte2;
1245 }
1246 else
1247 {
1248 ccl->reg[0] = charset;
1249 ccl->reg[1] = char2b->byte1;
1250 ccl->reg[2] = char2b->byte2;
1251 }
1252
1253 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1254
1255 /* We assume that MSBs are appropriately set/reset by CCL
1256 program. */
1257 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1258 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1259 else
1260 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1261 }
1262 else if (font_info->encoding[charset])
1263 {
1264 /* Fixed encoding scheme. See fontset.h for the meaning of the
1265 encoding numbers. */
1266 int enc = font_info->encoding[charset];
1267
1268 if ((enc == 1 || enc == 2)
1269 && CHARSET_DIMENSION (charset) == 2)
1270 char2b->byte1 |= 0x80;
1271
1272 if (enc == 1 || enc == 3)
1273 char2b->byte2 |= 0x80;
1274 }
1275}
1276
1277
1278/* Get face and two-byte form of character C in face FACE_ID on frame
1279 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1280 means we want to display multibyte text. Value is a pointer to a
1281 realized face that is ready for display. */
1282
1283static INLINE struct face *
1284x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1285 struct frame *f;
1286 int c, face_id;
1287 XChar2b *char2b;
1288 int multibyte_p;
1289{
1290 struct face *face = FACE_FROM_ID (f, face_id);
1291
1292 if (!multibyte_p)
1293 {
1294 /* Unibyte case. We don't have to encode, but we have to make
1295 sure to use a face suitable for unibyte. */
1296 char2b->byte1 = 0;
1297 char2b->byte2 = c;
ee569018
KH
1298 face_id = FACE_FOR_CHAR (f, face, c);
1299 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1300 }
1301 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1302 {
1303 /* Case of ASCII in a face known to fit ASCII. */
1304 char2b->byte1 = 0;
1305 char2b->byte2 = c;
1306 }
1307 else
1308 {
1309 int c1, c2, charset;
1310
1311 /* Split characters into bytes. If c2 is -1 afterwards, C is
1312 really a one-byte character so that byte1 is zero. */
1313 SPLIT_CHAR (c, charset, c1, c2);
1314 if (c2 > 0)
1315 char2b->byte1 = c1, char2b->byte2 = c2;
1316 else
1317 char2b->byte1 = 0, char2b->byte2 = c1;
1318
06a2c219 1319 /* Maybe encode the character in *CHAR2B. */
ee569018 1320 if (face->font != NULL)
06a2c219
GM
1321 {
1322 struct font_info *font_info
1323 = FONT_INFO_FROM_ID (f, face->font_info_id);
1324 if (font_info)
ee569018 1325 x_encode_char (c, char2b, font_info);
06a2c219
GM
1326 }
1327 }
1328
1329 /* Make sure X resources of the face are allocated. */
1330 xassert (face != NULL);
1331 PREPARE_FACE_FOR_DISPLAY (f, face);
1332
1333 return face;
1334}
1335
1336
1337/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1338 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1339 a pointer to a realized face that is ready for display. */
1340
1341static INLINE struct face *
ee569018 1342x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1343 struct frame *f;
1344 struct glyph *glyph;
1345 XChar2b *char2b;
ee569018 1346 int *two_byte_p;
06a2c219
GM
1347{
1348 struct face *face;
1349
1350 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1351 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1352
ee569018
KH
1353 if (two_byte_p)
1354 *two_byte_p = 0;
1355
06a2c219
GM
1356 if (!glyph->multibyte_p)
1357 {
1358 /* Unibyte case. We don't have to encode, but we have to make
1359 sure to use a face suitable for unibyte. */
1360 char2b->byte1 = 0;
43d120d8 1361 char2b->byte2 = glyph->u.ch;
06a2c219 1362 }
43d120d8
KH
1363 else if (glyph->u.ch < 128
1364 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1365 {
1366 /* Case of ASCII in a face known to fit ASCII. */
1367 char2b->byte1 = 0;
43d120d8 1368 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1369 }
1370 else
1371 {
1372 int c1, c2, charset;
1373
1374 /* Split characters into bytes. If c2 is -1 afterwards, C is
1375 really a one-byte character so that byte1 is zero. */
43d120d8 1376 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1377 if (c2 > 0)
1378 char2b->byte1 = c1, char2b->byte2 = c2;
1379 else
1380 char2b->byte1 = 0, char2b->byte2 = c1;
1381
1382 /* Maybe encode the character in *CHAR2B. */
1383 if (charset != CHARSET_ASCII)
1384 {
1385 struct font_info *font_info
1386 = FONT_INFO_FROM_ID (f, face->font_info_id);
1387 if (font_info)
1388 {
43d120d8 1389 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1390 if (two_byte_p)
1391 *two_byte_p
1392 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1393 }
1394 }
1395 }
1396
1397 /* Make sure X resources of the face are allocated. */
1398 xassert (face != NULL);
1399 PREPARE_FACE_FOR_DISPLAY (f, face);
1400 return face;
1401}
1402
1403
1404/* Store one glyph for IT->char_to_display in IT->glyph_row.
1405 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1406
1407static INLINE void
1408x_append_glyph (it)
1409 struct it *it;
1410{
1411 struct glyph *glyph;
1412 enum glyph_row_area area = it->area;
1413
1414 xassert (it->glyph_row);
1415 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1416
1417 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1418 if (glyph < it->glyph_row->glyphs[area + 1])
1419 {
06a2c219
GM
1420 glyph->charpos = CHARPOS (it->position);
1421 glyph->object = it->object;
88d75730 1422 glyph->pixel_width = it->pixel_width;
06a2c219 1423 glyph->voffset = it->voffset;
88d75730 1424 glyph->type = CHAR_GLYPH;
06a2c219 1425 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1426 glyph->left_box_line_p = it->start_of_box_run_p;
1427 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1428 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1429 || it->phys_descent > it->descent);
88d75730 1430 glyph->padding_p = 0;
ee569018 1431 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1432 glyph->face_id = it->face_id;
1433 glyph->u.ch = it->char_to_display;
06a2c219
GM
1434 ++it->glyph_row->used[area];
1435 }
1436}
1437
b4192550
KH
1438/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1439 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1440
1441static INLINE void
1442x_append_composite_glyph (it)
1443 struct it *it;
1444{
1445 struct glyph *glyph;
1446 enum glyph_row_area area = it->area;
1447
1448 xassert (it->glyph_row);
1449
1450 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1451 if (glyph < it->glyph_row->glyphs[area + 1])
1452 {
b4192550
KH
1453 glyph->charpos = CHARPOS (it->position);
1454 glyph->object = it->object;
88d75730 1455 glyph->pixel_width = it->pixel_width;
b4192550 1456 glyph->voffset = it->voffset;
88d75730 1457 glyph->type = COMPOSITE_GLYPH;
b4192550 1458 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1459 glyph->left_box_line_p = it->start_of_box_run_p;
1460 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1461 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1462 || it->phys_descent > it->descent);
88d75730
GM
1463 glyph->padding_p = 0;
1464 glyph->glyph_not_available_p = 0;
1465 glyph->face_id = it->face_id;
1466 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1467 ++it->glyph_row->used[area];
1468 }
1469}
1470
06a2c219
GM
1471
1472/* Change IT->ascent and IT->height according to the setting of
1473 IT->voffset. */
1474
1475static INLINE void
1476take_vertical_position_into_account (it)
1477 struct it *it;
1478{
1479 if (it->voffset)
1480 {
1481 if (it->voffset < 0)
1482 /* Increase the ascent so that we can display the text higher
1483 in the line. */
1484 it->ascent += abs (it->voffset);
1485 else
1486 /* Increase the descent so that we can display the text lower
1487 in the line. */
1488 it->descent += it->voffset;
1489 }
1490}
1491
1492
1493/* Produce glyphs/get display metrics for the image IT is loaded with.
1494 See the description of struct display_iterator in dispextern.h for
1495 an overview of struct display_iterator. */
1496
1497static void
1498x_produce_image_glyph (it)
1499 struct it *it;
1500{
1501 struct image *img;
1502 struct face *face;
1503
1504 xassert (it->what == IT_IMAGE);
1505
1506 face = FACE_FROM_ID (it->f, it->face_id);
1507 img = IMAGE_FROM_ID (it->f, it->image_id);
1508 xassert (img);
1509
1510 /* Make sure X resources of the face and image are loaded. */
1511 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1512 prepare_image_for_display (it->f, img);
1513
95af8492 1514 it->ascent = it->phys_ascent = image_ascent (img, face);
66ac4b0e 1515 it->descent = it->phys_descent = img->height + 2 * img->margin - it->ascent;
06a2c219
GM
1516 it->pixel_width = img->width + 2 * img->margin;
1517
1518 it->nglyphs = 1;
1519
1520 if (face->box != FACE_NO_BOX)
1521 {
1522 it->ascent += face->box_line_width;
1523 it->descent += face->box_line_width;
1524
1525 if (it->start_of_box_run_p)
1526 it->pixel_width += face->box_line_width;
1527 if (it->end_of_box_run_p)
1528 it->pixel_width += face->box_line_width;
1529 }
1530
1531 take_vertical_position_into_account (it);
1532
1533 if (it->glyph_row)
1534 {
1535 struct glyph *glyph;
1536 enum glyph_row_area area = it->area;
1537
1538 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1539 if (glyph < it->glyph_row->glyphs[area + 1])
1540 {
06a2c219
GM
1541 glyph->charpos = CHARPOS (it->position);
1542 glyph->object = it->object;
88d75730 1543 glyph->pixel_width = it->pixel_width;
06a2c219 1544 glyph->voffset = it->voffset;
88d75730 1545 glyph->type = IMAGE_GLYPH;
06a2c219 1546 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1547 glyph->left_box_line_p = it->start_of_box_run_p;
1548 glyph->right_box_line_p = it->end_of_box_run_p;
1549 glyph->overlaps_vertically_p = 0;
1550 glyph->padding_p = 0;
1551 glyph->glyph_not_available_p = 0;
1552 glyph->face_id = it->face_id;
1553 glyph->u.img_id = img->id;
06a2c219
GM
1554 ++it->glyph_row->used[area];
1555 }
1556 }
1557}
1558
1559
1560/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1561 of the glyph, WIDTH and HEIGHT are the width and height of the
1562 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1563 ascent of the glyph (0 <= ASCENT <= 1). */
1564
1565static void
1566x_append_stretch_glyph (it, object, width, height, ascent)
1567 struct it *it;
1568 Lisp_Object object;
1569 int width, height;
1570 double ascent;
1571{
1572 struct glyph *glyph;
1573 enum glyph_row_area area = it->area;
1574
1575 xassert (ascent >= 0 && ascent <= 1);
1576
1577 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1578 if (glyph < it->glyph_row->glyphs[area + 1])
1579 {
06a2c219
GM
1580 glyph->charpos = CHARPOS (it->position);
1581 glyph->object = object;
88d75730 1582 glyph->pixel_width = width;
06a2c219 1583 glyph->voffset = it->voffset;
88d75730 1584 glyph->type = STRETCH_GLYPH;
06a2c219 1585 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1586 glyph->left_box_line_p = it->start_of_box_run_p;
1587 glyph->right_box_line_p = it->end_of_box_run_p;
1588 glyph->overlaps_vertically_p = 0;
1589 glyph->padding_p = 0;
1590 glyph->glyph_not_available_p = 0;
1591 glyph->face_id = it->face_id;
1592 glyph->u.stretch.ascent = height * ascent;
1593 glyph->u.stretch.height = height;
06a2c219
GM
1594 ++it->glyph_row->used[area];
1595 }
1596}
1597
1598
1599/* Produce a stretch glyph for iterator IT. IT->object is the value
1600 of the glyph property displayed. The value must be a list
1601 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1602 being recognized:
1603
1604 1. `:width WIDTH' specifies that the space should be WIDTH *
1605 canonical char width wide. WIDTH may be an integer or floating
1606 point number.
1607
1608 2. `:relative-width FACTOR' specifies that the width of the stretch
1609 should be computed from the width of the first character having the
1610 `glyph' property, and should be FACTOR times that width.
1611
1612 3. `:align-to HPOS' specifies that the space should be wide enough
1613 to reach HPOS, a value in canonical character units.
1614
1615 Exactly one of the above pairs must be present.
1616
1617 4. `:height HEIGHT' specifies that the height of the stretch produced
1618 should be HEIGHT, measured in canonical character units.
1619
1620 5. `:relative-height FACTOR' specifies that the height of the the
1621 stretch should be FACTOR times the height of the characters having
1622 the glyph property.
1623
1624 Either none or exactly one of 4 or 5 must be present.
1625
1626 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1627 of the stretch should be used for the ascent of the stretch.
1628 ASCENT must be in the range 0 <= ASCENT <= 100. */
1629
1630#define NUMVAL(X) \
1631 ((INTEGERP (X) || FLOATP (X)) \
1632 ? XFLOATINT (X) \
1633 : - 1)
1634
1635
1636static void
1637x_produce_stretch_glyph (it)
1638 struct it *it;
1639{
1640 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1641#if GLYPH_DEBUG
1642 extern Lisp_Object Qspace;
1643#endif
1644 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1645 extern Lisp_Object QCrelative_width, QCrelative_height;
1646 extern Lisp_Object QCalign_to;
1647 Lisp_Object prop, plist;
1648 double width = 0, height = 0, ascent = 0;
1649 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1650 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1651
1652 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1653
1654 /* List should start with `space'. */
1655 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1656 plist = XCDR (it->object);
1657
1658 /* Compute the width of the stretch. */
1659 if (prop = Fplist_get (plist, QCwidth),
1660 NUMVAL (prop) > 0)
1661 /* Absolute width `:width WIDTH' specified and valid. */
1662 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1663 else if (prop = Fplist_get (plist, QCrelative_width),
1664 NUMVAL (prop) > 0)
1665 {
1666 /* Relative width `:relative-width FACTOR' specified and valid.
1667 Compute the width of the characters having the `glyph'
1668 property. */
1669 struct it it2;
1670 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1671
1672 it2 = *it;
1673 if (it->multibyte_p)
1674 {
1675 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1676 - IT_BYTEPOS (*it));
1677 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1678 }
1679 else
1680 it2.c = *p, it2.len = 1;
1681
1682 it2.glyph_row = NULL;
1683 it2.what = IT_CHARACTER;
1684 x_produce_glyphs (&it2);
1685 width = NUMVAL (prop) * it2.pixel_width;
1686 }
1687 else if (prop = Fplist_get (plist, QCalign_to),
1688 NUMVAL (prop) > 0)
1689 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1690 else
1691 /* Nothing specified -> width defaults to canonical char width. */
1692 width = CANON_X_UNIT (it->f);
1693
1694 /* Compute height. */
1695 if (prop = Fplist_get (plist, QCheight),
1696 NUMVAL (prop) > 0)
1697 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1698 else if (prop = Fplist_get (plist, QCrelative_height),
1699 NUMVAL (prop) > 0)
1700 height = FONT_HEIGHT (font) * NUMVAL (prop);
1701 else
1702 height = FONT_HEIGHT (font);
1703
1704 /* Compute percentage of height used for ascent. If
1705 `:ascent ASCENT' is present and valid, use that. Otherwise,
1706 derive the ascent from the font in use. */
1707 if (prop = Fplist_get (plist, QCascent),
1708 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1709 ascent = NUMVAL (prop) / 100.0;
1710 else
1711 ascent = (double) font->ascent / FONT_HEIGHT (font);
1712
1713 if (width <= 0)
1714 width = 1;
1715 if (height <= 0)
1716 height = 1;
1717
1718 if (it->glyph_row)
1719 {
1720 Lisp_Object object = it->stack[it->sp - 1].string;
1721 if (!STRINGP (object))
1722 object = it->w->buffer;
1723 x_append_stretch_glyph (it, object, width, height, ascent);
1724 }
1725
1726 it->pixel_width = width;
66ac4b0e
GM
1727 it->ascent = it->phys_ascent = height * ascent;
1728 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1729 it->nglyphs = 1;
1730
1731 if (face->box != FACE_NO_BOX)
1732 {
1733 it->ascent += face->box_line_width;
1734 it->descent += face->box_line_width;
1735
1736 if (it->start_of_box_run_p)
1737 it->pixel_width += face->box_line_width;
1738 if (it->end_of_box_run_p)
1739 it->pixel_width += face->box_line_width;
1740 }
1741
1742 take_vertical_position_into_account (it);
1743}
1744
b4192550
KH
1745/* Return proper value to be used as baseline offset of font that has
1746 ASCENT and DESCENT to draw characters by the font at the vertical
1747 center of the line of frame F.
1748
1749 Here, out task is to find the value of BOFF in the following figure;
1750
1751 -------------------------+-----------+-
1752 -+-+---------+-+ | |
1753 | | | | | |
1754 | | | | F_ASCENT F_HEIGHT
1755 | | | ASCENT | |
1756 HEIGHT | | | | |
1757 | | |-|-+------+-----------|------- baseline
1758 | | | | BOFF | |
1759 | |---------|-+-+ | |
1760 | | | DESCENT | |
1761 -+-+---------+-+ F_DESCENT |
1762 -------------------------+-----------+-
1763
1764 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1765 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1766 DESCENT = FONT->descent
1767 HEIGHT = FONT_HEIGHT (FONT)
1768 F_DESCENT = (F->output_data.x->font->descent
1769 - F->output_data.x->baseline_offset)
1770 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1771*/
1772
1773#define VCENTER_BASELINE_OFFSET(FONT, F) \
1774 ((FONT)->descent \
1775 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT))) / 2 \
1776 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1777
1778/* Produce glyphs/get display metrics for the display element IT is
1779 loaded with. See the description of struct display_iterator in
1780 dispextern.h for an overview of struct display_iterator. */
1781
1782static void
1783x_produce_glyphs (it)
1784 struct it *it;
1785{
ee569018
KH
1786 it->glyph_not_available_p = 0;
1787
06a2c219
GM
1788 if (it->what == IT_CHARACTER)
1789 {
1790 XChar2b char2b;
1791 XFontStruct *font;
ee569018 1792 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1793 XCharStruct *pcm;
06a2c219 1794 int font_not_found_p;
b4192550
KH
1795 struct font_info *font_info;
1796 int boff; /* baseline offset */
06a2c219 1797
ee569018
KH
1798 /* Maybe translate single-byte characters to multibyte, or the
1799 other way. */
06a2c219 1800 it->char_to_display = it->c;
ee569018 1801 if (!ASCII_BYTE_P (it->c))
06a2c219 1802 {
ee569018
KH
1803 if (unibyte_display_via_language_environment
1804 && SINGLE_BYTE_CHAR_P (it->c)
1805 && (it->c >= 0240
1806 || !NILP (Vnonascii_translation_table)))
1807 {
1808 it->char_to_display = unibyte_char_to_multibyte (it->c);
1809 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1810 face = FACE_FROM_ID (it->f, it->face_id);
1811 }
1812 else if (!SINGLE_BYTE_CHAR_P (it->c)
1813 && !it->multibyte_p)
1814 {
1815 it->char_to_display = multibyte_char_to_unibyte (it->c, Qnil);
1816 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1817 face = FACE_FROM_ID (it->f, it->face_id);
1818 }
06a2c219
GM
1819 }
1820
ee569018
KH
1821 /* Get font to use. Encode IT->char_to_display. */
1822 x_get_char_face_and_encoding (it->f, it->char_to_display,
1823 it->face_id, &char2b,
1824 it->multibyte_p);
06a2c219
GM
1825 font = face->font;
1826
1827 /* When no suitable font found, use the default font. */
1828 font_not_found_p = font == NULL;
1829 if (font_not_found_p)
b4192550
KH
1830 {
1831 font = FRAME_FONT (it->f);
1832 boff = it->f->output_data.x->baseline_offset;
1833 font_info = NULL;
1834 }
1835 else
1836 {
1837 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1838 boff = font_info->baseline_offset;
1839 if (font_info->vertical_centering)
1840 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1841 }
06a2c219
GM
1842
1843 if (it->char_to_display >= ' '
1844 && (!it->multibyte_p || it->char_to_display < 128))
1845 {
1846 /* Either unibyte or ASCII. */
1847 int stretched_p;
1848
1849 it->nglyphs = 1;
06a2c219
GM
1850
1851 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1852 it->ascent = font->ascent + boff;
1853 it->descent = font->descent - boff;
474848ac
GM
1854
1855 if (pcm)
1856 {
1857 it->phys_ascent = pcm->ascent + boff;
1858 it->phys_descent = pcm->descent - boff;
1859 it->pixel_width = pcm->width;
1860 }
1861 else
1862 {
1863 it->glyph_not_available_p = 1;
1864 it->phys_ascent = font->ascent + boff;
1865 it->phys_descent = font->descent - boff;
1866 it->pixel_width = FONT_WIDTH (font);
1867 }
06a2c219
GM
1868
1869 /* If this is a space inside a region of text with
1870 `space-width' property, change its width. */
1871 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1872 if (stretched_p)
1873 it->pixel_width *= XFLOATINT (it->space_width);
1874
1875 /* If face has a box, add the box thickness to the character
1876 height. If character has a box line to the left and/or
1877 right, add the box line width to the character's width. */
1878 if (face->box != FACE_NO_BOX)
1879 {
1880 int thick = face->box_line_width;
1881
1882 it->ascent += thick;
1883 it->descent += thick;
1884
1885 if (it->start_of_box_run_p)
1886 it->pixel_width += thick;
1887 if (it->end_of_box_run_p)
1888 it->pixel_width += thick;
1889 }
1890
1891 /* If face has an overline, add the height of the overline
1892 (1 pixel) and a 1 pixel margin to the character height. */
1893 if (face->overline_p)
1894 it->ascent += 2;
1895
1896 take_vertical_position_into_account (it);
1897
1898 /* If we have to actually produce glyphs, do it. */
1899 if (it->glyph_row)
1900 {
1901 if (stretched_p)
1902 {
1903 /* Translate a space with a `space-width' property
1904 into a stretch glyph. */
1905 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1906 x_append_stretch_glyph (it, it->object, it->pixel_width,
1907 it->ascent + it->descent, ascent);
1908 }
1909 else
1910 x_append_glyph (it);
1911
1912 /* If characters with lbearing or rbearing are displayed
1913 in this line, record that fact in a flag of the
1914 glyph row. This is used to optimize X output code. */
1c7e22fd 1915 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1916 it->glyph_row->contains_overlapping_glyphs_p = 1;
1917 }
1918 }
1919 else if (it->char_to_display == '\n')
1920 {
1921 /* A newline has no width but we need the height of the line. */
1922 it->pixel_width = 0;
1923 it->nglyphs = 0;
b4192550
KH
1924 it->ascent = it->phys_ascent = font->ascent + boff;
1925 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1926
1927 if (face->box != FACE_NO_BOX)
1928 {
1929 int thick = face->box_line_width;
1930 it->ascent += thick;
1931 it->descent += thick;
1932 }
1933 }
1934 else if (it->char_to_display == '\t')
1935 {
1936 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1937 int x = it->current_x + it->continuation_lines_width;
06a2c219
GM
1938 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
1939
1940 it->pixel_width = next_tab_x - x;
1941 it->nglyphs = 1;
b4192550
KH
1942 it->ascent = it->phys_ascent = font->ascent + boff;
1943 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1944
1945 if (it->glyph_row)
1946 {
1947 double ascent = (double) it->ascent / (it->ascent + it->descent);
1948 x_append_stretch_glyph (it, it->object, it->pixel_width,
1949 it->ascent + it->descent, ascent);
1950 }
1951 }
1952 else
1953 {
1954 /* A multi-byte character. Assume that the display width of the
1955 character is the width of the character multiplied by the
b4192550 1956 width of the font. */
06a2c219 1957
b4192550
KH
1958 /* If we found a font, this font should give us the right
1959 metrics. If we didn't find a font, use the frame's
1960 default font and calculate the width of the character
1961 from the charset width; this is what old redisplay code
1962 did. */
1963 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1964 if (font_not_found_p || !pcm)
1965 {
1966 int charset = CHAR_CHARSET (it->char_to_display);
1967
1968 it->glyph_not_available_p = 1;
1969 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
1970 * CHARSET_WIDTH (charset));
1971 it->phys_ascent = font->ascent + boff;
1972 it->phys_descent = font->descent - boff;
1973 }
1974 else
1975 {
1976 it->pixel_width = pcm->width;
1977 it->phys_ascent = pcm->ascent + boff;
1978 it->phys_descent = pcm->descent - boff;
1979 if (it->glyph_row
1980 && (pcm->lbearing < 0
1981 || pcm->rbearing > pcm->width))
1982 it->glyph_row->contains_overlapping_glyphs_p = 1;
1983 }
b4192550
KH
1984 it->nglyphs = 1;
1985 it->ascent = font->ascent + boff;
1986 it->descent = font->descent - boff;
06a2c219
GM
1987 if (face->box != FACE_NO_BOX)
1988 {
1989 int thick = face->box_line_width;
1990 it->ascent += thick;
1991 it->descent += thick;
1992
1993 if (it->start_of_box_run_p)
1994 it->pixel_width += thick;
1995 if (it->end_of_box_run_p)
1996 it->pixel_width += thick;
1997 }
1998
1999 /* If face has an overline, add the height of the overline
2000 (1 pixel) and a 1 pixel margin to the character height. */
2001 if (face->overline_p)
2002 it->ascent += 2;
2003
2004 take_vertical_position_into_account (it);
2005
2006 if (it->glyph_row)
2007 x_append_glyph (it);
2008 }
2009 }
b4192550
KH
2010 else if (it->what == IT_COMPOSITION)
2011 {
2012 /* Note: A composition is represented as one glyph in the
2013 glyph matrix. There are no padding glyphs. */
2014 XChar2b char2b;
2015 XFontStruct *font;
ee569018 2016 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2017 XCharStruct *pcm;
2018 int font_not_found_p;
2019 struct font_info *font_info;
2020 int boff; /* baseline offset */
2021 struct composition *cmp = composition_table[it->cmp_id];
2022
2023 /* Maybe translate single-byte characters to multibyte. */
2024 it->char_to_display = it->c;
2025 if (unibyte_display_via_language_environment
2026 && SINGLE_BYTE_CHAR_P (it->c)
2027 && (it->c >= 0240
2028 || (it->c >= 0200
2029 && !NILP (Vnonascii_translation_table))))
2030 {
2031 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2032 }
2033
2034 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2035 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2036 face = FACE_FROM_ID (it->f, it->face_id);
2037 x_get_char_face_and_encoding (it->f, it->char_to_display,
2038 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2039 font = face->font;
2040
2041 /* When no suitable font found, use the default font. */
2042 font_not_found_p = font == NULL;
2043 if (font_not_found_p)
2044 {
2045 font = FRAME_FONT (it->f);
2046 boff = it->f->output_data.x->baseline_offset;
2047 font_info = NULL;
2048 }
2049 else
2050 {
2051 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2052 boff = font_info->baseline_offset;
2053 if (font_info->vertical_centering)
2054 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2055 }
2056
2057 /* There are no padding glyphs, so there is only one glyph to
2058 produce for the composition. Important is that pixel_width,
2059 ascent and descent are the values of what is drawn by
2060 draw_glyphs (i.e. the values of the overall glyphs composed). */
2061 it->nglyphs = 1;
2062
2063 /* If we have not yet calculated pixel size data of glyphs of
2064 the composition for the current face font, calculate them
2065 now. Theoretically, we have to check all fonts for the
2066 glyphs, but that requires much time and memory space. So,
2067 here we check only the font of the first glyph. This leads
2068 to incorrect display very rarely, and C-l (recenter) can
2069 correct the display anyway. */
2070 if (cmp->font != (void *) font)
2071 {
2072 /* Ascent and descent of the font of the first character of
2073 this composition (adjusted by baseline offset). Ascent
2074 and descent of overall glyphs should not be less than
2075 them respectively. */
2076 int font_ascent = font->ascent + boff;
2077 int font_descent = font->descent - boff;
2078 /* Bounding box of the overall glyphs. */
2079 int leftmost, rightmost, lowest, highest;
329bed06 2080 int i, width, ascent, descent;
b4192550
KH
2081
2082 cmp->font = (void *) font;
2083
2084 /* Initialize the bounding box. */
2085 pcm = x_per_char_metric (font, &char2b);
329bed06
GM
2086 if (pcm)
2087 {
2088 width = pcm->width;
2089 ascent = pcm->ascent;
2090 descent = pcm->descent;
2091 }
2092 else
2093 {
2094 width = FONT_WIDTH (font);
2095 ascent = font->ascent;
2096 descent = font->descent;
2097 }
2098
2099 rightmost = width;
2100 lowest = - descent + boff;
2101 highest = ascent + boff;
b4192550 2102 leftmost = 0;
329bed06 2103
b4192550
KH
2104 if (font_info
2105 && font_info->default_ascent
2106 && CHAR_TABLE_P (Vuse_default_ascent)
2107 && !NILP (Faref (Vuse_default_ascent,
2108 make_number (it->char_to_display))))
2109 highest = font_info->default_ascent + boff;
2110
2111 /* Draw the first glyph at the normal position. It may be
2112 shifted to right later if some other glyphs are drawn at
2113 the left. */
2114 cmp->offsets[0] = 0;
2115 cmp->offsets[1] = boff;
2116
2117 /* Set cmp->offsets for the remaining glyphs. */
2118 for (i = 1; i < cmp->glyph_len; i++)
2119 {
2120 int left, right, btm, top;
2121 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2122 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2123
2124 face = FACE_FROM_ID (it->f, face_id);
2125 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2126 it->multibyte_p);
b4192550
KH
2127 font = face->font;
2128 if (font == NULL)
2129 {
2130 font = FRAME_FONT (it->f);
2131 boff = it->f->output_data.x->baseline_offset;
2132 font_info = NULL;
2133 }
2134 else
2135 {
2136 font_info
2137 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2138 boff = font_info->baseline_offset;
2139 if (font_info->vertical_centering)
2140 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2141 }
2142
2143 pcm = x_per_char_metric (font, &char2b);
329bed06
GM
2144 if (pcm)
2145 {
2146 width = pcm->width;
2147 ascent = pcm->ascent;
2148 descent = pcm->descent;
2149 }
2150 else
2151 {
2152 width = FONT_WIDTH (font);
2153 ascent = font->ascent;
2154 descent = font->descent;
2155 }
b4192550
KH
2156
2157 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2158 {
2159 /* Relative composition with or without
2160 alternate chars. */
329bed06
GM
2161 left = (leftmost + rightmost - width) / 2;
2162 btm = - descent + boff;
b4192550
KH
2163 if (font_info && font_info->relative_compose
2164 && (! CHAR_TABLE_P (Vignore_relative_composition)
2165 || NILP (Faref (Vignore_relative_composition,
2166 make_number (ch)))))
2167 {
2168
329bed06 2169 if (- descent >= font_info->relative_compose)
b4192550
KH
2170 /* One extra pixel between two glyphs. */
2171 btm = highest + 1;
329bed06 2172 else if (ascent <= 0)
b4192550 2173 /* One extra pixel between two glyphs. */
329bed06 2174 btm = lowest - 1 - ascent - descent;
b4192550
KH
2175 }
2176 }
2177 else
2178 {
2179 /* A composition rule is specified by an integer
2180 value that encodes global and new reference
2181 points (GREF and NREF). GREF and NREF are
2182 specified by numbers as below:
2183
2184 0---1---2 -- ascent
2185 | |
2186 | |
2187 | |
2188 9--10--11 -- center
2189 | |
2190 ---3---4---5--- baseline
2191 | |
2192 6---7---8 -- descent
2193 */
2194 int rule = COMPOSITION_RULE (cmp, i);
2195 int gref, nref, grefx, grefy, nrefx, nrefy;
2196
2197 COMPOSITION_DECODE_RULE (rule, gref, nref);
2198 grefx = gref % 3, nrefx = nref % 3;
2199 grefy = gref / 3, nrefy = nref / 3;
2200
2201 left = (leftmost
2202 + grefx * (rightmost - leftmost) / 2
329bed06 2203 - nrefx * width / 2);
b4192550
KH
2204 btm = ((grefy == 0 ? highest
2205 : grefy == 1 ? 0
2206 : grefy == 2 ? lowest
2207 : (highest + lowest) / 2)
329bed06
GM
2208 - (nrefy == 0 ? ascent + descent
2209 : nrefy == 1 ? descent - boff
b4192550 2210 : nrefy == 2 ? 0
329bed06 2211 : (ascent + descent) / 2));
b4192550
KH
2212 }
2213
2214 cmp->offsets[i * 2] = left;
329bed06 2215 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2216
2217 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2218 right = left + width;
2219 top = btm + descent + ascent;
b4192550
KH
2220 if (left < leftmost)
2221 leftmost = left;
2222 if (right > rightmost)
2223 rightmost = right;
2224 if (top > highest)
2225 highest = top;
2226 if (btm < lowest)
2227 lowest = btm;
2228 }
2229
2230 /* If there are glyphs whose x-offsets are negative,
2231 shift all glyphs to the right and make all x-offsets
2232 non-negative. */
2233 if (leftmost < 0)
2234 {
2235 for (i = 0; i < cmp->glyph_len; i++)
2236 cmp->offsets[i * 2] -= leftmost;
2237 rightmost -= leftmost;
2238 }
2239
2240 cmp->pixel_width = rightmost;
2241 cmp->ascent = highest;
2242 cmp->descent = - lowest;
2243 if (cmp->ascent < font_ascent)
2244 cmp->ascent = font_ascent;
2245 if (cmp->descent < font_descent)
2246 cmp->descent = font_descent;
2247 }
2248
2249 it->pixel_width = cmp->pixel_width;
2250 it->ascent = it->phys_ascent = cmp->ascent;
2251 it->descent = it->phys_descent = cmp->descent;
2252
2253 if (face->box != FACE_NO_BOX)
2254 {
2255 int thick = face->box_line_width;
2256 it->ascent += thick;
2257 it->descent += thick;
2258
2259 if (it->start_of_box_run_p)
2260 it->pixel_width += thick;
2261 if (it->end_of_box_run_p)
2262 it->pixel_width += thick;
2263 }
2264
2265 /* If face has an overline, add the height of the overline
2266 (1 pixel) and a 1 pixel margin to the character height. */
2267 if (face->overline_p)
2268 it->ascent += 2;
2269
2270 take_vertical_position_into_account (it);
2271
2272 if (it->glyph_row)
2273 x_append_composite_glyph (it);
2274 }
06a2c219
GM
2275 else if (it->what == IT_IMAGE)
2276 x_produce_image_glyph (it);
2277 else if (it->what == IT_STRETCH)
2278 x_produce_stretch_glyph (it);
2279
3017fdd1
GM
2280 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2281 because this isn't true for images with `:ascent 100'. */
2282 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2283 if (it->area == TEXT_AREA)
2284 it->current_x += it->pixel_width;
66ac4b0e 2285
d365f5bb
GM
2286 it->descent += it->extra_line_spacing;
2287
06a2c219
GM
2288 it->max_ascent = max (it->max_ascent, it->ascent);
2289 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2290 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2291 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2292}
2293
2294
2295/* Estimate the pixel height of the mode or top line on frame F.
2296 FACE_ID specifies what line's height to estimate. */
2297
2298int
2299x_estimate_mode_line_height (f, face_id)
2300 struct frame *f;
2301 enum face_id face_id;
2302{
2303 int height = 1;
2304
2305 /* This function is called so early when Emacs starts that the face
2306 cache and mode line face are not yet initialized. */
2307 if (FRAME_FACE_CACHE (f))
2308 {
2309 struct face *face = FACE_FROM_ID (f, face_id);
2310 if (face)
2311 height = FONT_HEIGHT (face->font) + 2 * face->box_line_width;
2312 }
2313
2314 return height;
2315}
2316
2317\f
2318/***********************************************************************
2319 Glyph display
2320 ***********************************************************************/
2321
2322/* A sequence of glyphs to be drawn in the same face.
2323
2324 This data structure is not really completely X specific, so it
2325 could possibly, at least partially, be useful for other systems. It
2326 is currently not part of the external redisplay interface because
2327 it's not clear what other systems will need. */
2328
2329struct glyph_string
2330{
2331 /* X-origin of the string. */
2332 int x;
2333
2334 /* Y-origin and y-position of the base line of this string. */
2335 int y, ybase;
2336
2337 /* The width of the string, not including a face extension. */
2338 int width;
2339
2340 /* The width of the string, including a face extension. */
2341 int background_width;
2342
2343 /* The height of this string. This is the height of the line this
2344 string is drawn in, and can be different from the height of the
2345 font the string is drawn in. */
2346 int height;
2347
2348 /* Number of pixels this string overwrites in front of its x-origin.
2349 This number is zero if the string has an lbearing >= 0; it is
2350 -lbearing, if the string has an lbearing < 0. */
2351 int left_overhang;
2352
2353 /* Number of pixels this string overwrites past its right-most
2354 nominal x-position, i.e. x + width. Zero if the string's
2355 rbearing is <= its nominal width, rbearing - width otherwise. */
2356 int right_overhang;
2357
2358 /* The frame on which the glyph string is drawn. */
2359 struct frame *f;
2360
2361 /* The window on which the glyph string is drawn. */
2362 struct window *w;
2363
2364 /* X display and window for convenience. */
2365 Display *display;
2366 Window window;
2367
2368 /* The glyph row for which this string was built. It determines the
2369 y-origin and height of the string. */
2370 struct glyph_row *row;
2371
2372 /* The area within row. */
2373 enum glyph_row_area area;
2374
2375 /* Characters to be drawn, and number of characters. */
2376 XChar2b *char2b;
2377 int nchars;
2378
06a2c219
GM
2379 /* A face-override for drawing cursors, mouse face and similar. */
2380 enum draw_glyphs_face hl;
2381
2382 /* Face in which this string is to be drawn. */
2383 struct face *face;
2384
2385 /* Font in which this string is to be drawn. */
2386 XFontStruct *font;
2387
2388 /* Font info for this string. */
2389 struct font_info *font_info;
2390
b4192550
KH
2391 /* Non-null means this string describes (part of) a composition.
2392 All characters from char2b are drawn composed. */
2393 struct composition *cmp;
06a2c219
GM
2394
2395 /* Index of this glyph string's first character in the glyph
b4192550
KH
2396 definition of CMP. If this is zero, this glyph string describes
2397 the first character of a composition. */
06a2c219
GM
2398 int gidx;
2399
2400 /* 1 means this glyph strings face has to be drawn to the right end
2401 of the window's drawing area. */
2402 unsigned extends_to_end_of_line_p : 1;
2403
2404 /* 1 means the background of this string has been drawn. */
2405 unsigned background_filled_p : 1;
2406
2407 /* 1 means glyph string must be drawn with 16-bit functions. */
2408 unsigned two_byte_p : 1;
2409
2410 /* 1 means that the original font determined for drawing this glyph
2411 string could not be loaded. The member `font' has been set to
2412 the frame's default font in this case. */
2413 unsigned font_not_found_p : 1;
2414
2415 /* 1 means that the face in which this glyph string is drawn has a
2416 stipple pattern. */
2417 unsigned stippled_p : 1;
2418
66ac4b0e
GM
2419 /* 1 means only the foreground of this glyph string must be drawn,
2420 and we should use the physical height of the line this glyph
2421 string appears in as clip rect. */
2422 unsigned for_overlaps_p : 1;
2423
06a2c219
GM
2424 /* The GC to use for drawing this glyph string. */
2425 GC gc;
2426
2427 /* A pointer to the first glyph in the string. This glyph
2428 corresponds to char2b[0]. Needed to draw rectangles if
2429 font_not_found_p is 1. */
2430 struct glyph *first_glyph;
2431
2432 /* Image, if any. */
2433 struct image *img;
2434
2435 struct glyph_string *next, *prev;
2436};
2437
2438
5c187dee 2439#if 0
06a2c219
GM
2440
2441static void
2442x_dump_glyph_string (s)
2443 struct glyph_string *s;
2444{
2445 fprintf (stderr, "glyph string\n");
2446 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2447 s->x, s->y, s->width, s->height);
2448 fprintf (stderr, " ybase = %d\n", s->ybase);
2449 fprintf (stderr, " hl = %d\n", s->hl);
2450 fprintf (stderr, " left overhang = %d, right = %d\n",
2451 s->left_overhang, s->right_overhang);
2452 fprintf (stderr, " nchars = %d\n", s->nchars);
2453 fprintf (stderr, " extends to end of line = %d\n",
2454 s->extends_to_end_of_line_p);
2455 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2456 fprintf (stderr, " bg width = %d\n", s->background_width);
2457}
2458
2459#endif /* GLYPH_DEBUG */
2460
2461
2462
2463static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2464 struct glyph_string **,
2465 struct glyph_string *,
2466 struct glyph_string *));
2467static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2468 struct glyph_string **,
2469 struct glyph_string *,
2470 struct glyph_string *));
2471static void x_append_glyph_string P_ ((struct glyph_string **,
2472 struct glyph_string **,
2473 struct glyph_string *));
2474static int x_left_overwritten P_ ((struct glyph_string *));
2475static int x_left_overwriting P_ ((struct glyph_string *));
2476static int x_right_overwritten P_ ((struct glyph_string *));
2477static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2478static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2479 int));
06a2c219
GM
2480static void x_init_glyph_string P_ ((struct glyph_string *,
2481 XChar2b *, struct window *,
2482 struct glyph_row *,
2483 enum glyph_row_area, int,
2484 enum draw_glyphs_face));
2485static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2486 enum glyph_row_area, int, int,
66ac4b0e 2487 enum draw_glyphs_face, int *, int *, int));
06a2c219
GM
2488static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2489static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2490static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2491 int));
2492static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2493static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2494static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2495static void x_draw_glyph_string P_ ((struct glyph_string *));
2496static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2497static void x_set_cursor_gc P_ ((struct glyph_string *));
2498static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2499static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2500static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2501 int *, int *));
2502static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2503static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2504 unsigned long *, double, int));
06a2c219 2505static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2506 double, int, unsigned long));
06a2c219
GM
2507static void x_setup_relief_colors P_ ((struct glyph_string *));
2508static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2509static void x_draw_image_relief P_ ((struct glyph_string *));
2510static void x_draw_image_foreground P_ ((struct glyph_string *));
2511static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2512static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2513static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2514 int, int, int));
2515static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2516 int, int, int, int, XRectangle *));
2517static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2518 int, int, int, XRectangle *));
66ac4b0e
GM
2519static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2520 enum glyph_row_area));
209f68d9
GM
2521static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2522 struct glyph_row *,
2523 enum glyph_row_area, int, int));
06a2c219 2524
163dcff3
GM
2525#if GLYPH_DEBUG
2526static void x_check_font P_ ((struct frame *, XFontStruct *));
2527#endif
2528
06a2c219 2529
06a2c219
GM
2530/* Append the list of glyph strings with head H and tail T to the list
2531 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2532
2533static INLINE void
2534x_append_glyph_string_lists (head, tail, h, t)
2535 struct glyph_string **head, **tail;
2536 struct glyph_string *h, *t;
2537{
2538 if (h)
2539 {
2540 if (*head)
2541 (*tail)->next = h;
2542 else
2543 *head = h;
2544 h->prev = *tail;
2545 *tail = t;
2546 }
2547}
2548
2549
2550/* Prepend the list of glyph strings with head H and tail T to the
2551 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2552 result. */
2553
2554static INLINE void
2555x_prepend_glyph_string_lists (head, tail, h, t)
2556 struct glyph_string **head, **tail;
2557 struct glyph_string *h, *t;
2558{
2559 if (h)
2560 {
2561 if (*head)
2562 (*head)->prev = t;
2563 else
2564 *tail = t;
2565 t->next = *head;
2566 *head = h;
2567 }
2568}
2569
2570
2571/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2572 Set *HEAD and *TAIL to the resulting list. */
2573
2574static INLINE void
2575x_append_glyph_string (head, tail, s)
2576 struct glyph_string **head, **tail;
2577 struct glyph_string *s;
2578{
2579 s->next = s->prev = NULL;
2580 x_append_glyph_string_lists (head, tail, s, s);
2581}
2582
2583
2584/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2585 face. */
2586
2587static void
2588x_set_cursor_gc (s)
2589 struct glyph_string *s;
2590{
2591 if (s->font == FRAME_FONT (s->f)
2592 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2593 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2594 && !s->cmp)
06a2c219
GM
2595 s->gc = s->f->output_data.x->cursor_gc;
2596 else
2597 {
2598 /* Cursor on non-default face: must merge. */
2599 XGCValues xgcv;
2600 unsigned long mask;
2601
2602 xgcv.background = s->f->output_data.x->cursor_pixel;
2603 xgcv.foreground = s->face->background;
2604
2605 /* If the glyph would be invisible, try a different foreground. */
2606 if (xgcv.foreground == xgcv.background)
2607 xgcv.foreground = s->face->foreground;
2608 if (xgcv.foreground == xgcv.background)
2609 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2610 if (xgcv.foreground == xgcv.background)
2611 xgcv.foreground = s->face->foreground;
2612
2613 /* Make sure the cursor is distinct from text in this face. */
2614 if (xgcv.background == s->face->background
2615 && xgcv.foreground == s->face->foreground)
2616 {
2617 xgcv.background = s->face->foreground;
2618 xgcv.foreground = s->face->background;
2619 }
2620
2621 IF_DEBUG (x_check_font (s->f, s->font));
2622 xgcv.font = s->font->fid;
2623 xgcv.graphics_exposures = False;
2624 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2625
2626 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2627 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2628 mask, &xgcv);
2629 else
2630 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2631 = XCreateGC (s->display, s->window, mask, &xgcv);
2632
2633 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2634 }
2635}
2636
2637
2638/* Set up S->gc of glyph string S for drawing text in mouse face. */
2639
2640static void
2641x_set_mouse_face_gc (s)
2642 struct glyph_string *s;
2643{
2644 int face_id;
ee569018 2645 struct face *face;
06a2c219
GM
2646
2647 /* What face has to be used for the mouse face? */
2648 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2649 face = FACE_FROM_ID (s->f, face_id);
033e3e18
GM
2650 if (s->first_glyph->type == CHAR_GLYPH)
2651 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2652 else
2653 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2654 s->face = FACE_FROM_ID (s->f, face_id);
2655 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2656
2657 /* If font in this face is same as S->font, use it. */
2658 if (s->font == s->face->font)
2659 s->gc = s->face->gc;
2660 else
2661 {
2662 /* Otherwise construct scratch_cursor_gc with values from FACE
2663 but font FONT. */
2664 XGCValues xgcv;
2665 unsigned long mask;
2666
2667 xgcv.background = s->face->background;
2668 xgcv.foreground = s->face->foreground;
2669 IF_DEBUG (x_check_font (s->f, s->font));
2670 xgcv.font = s->font->fid;
2671 xgcv.graphics_exposures = False;
2672 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2673
2674 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2675 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2676 mask, &xgcv);
2677 else
2678 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2679 = XCreateGC (s->display, s->window, mask, &xgcv);
2680
2681 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2682 }
2683
2684 xassert (s->gc != 0);
2685}
2686
2687
2688/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2689 Faces to use in the mode line have already been computed when the
2690 matrix was built, so there isn't much to do, here. */
2691
2692static INLINE void
2693x_set_mode_line_face_gc (s)
2694 struct glyph_string *s;
2695{
2696 s->gc = s->face->gc;
06a2c219
GM
2697}
2698
2699
2700/* Set S->gc of glyph string S for drawing that glyph string. Set
2701 S->stippled_p to a non-zero value if the face of S has a stipple
2702 pattern. */
2703
2704static INLINE void
2705x_set_glyph_string_gc (s)
2706 struct glyph_string *s;
2707{
209f68d9
GM
2708 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2709
06a2c219
GM
2710 if (s->hl == DRAW_NORMAL_TEXT)
2711 {
2712 s->gc = s->face->gc;
2713 s->stippled_p = s->face->stipple != 0;
2714 }
2715 else if (s->hl == DRAW_INVERSE_VIDEO)
2716 {
2717 x_set_mode_line_face_gc (s);
2718 s->stippled_p = s->face->stipple != 0;
2719 }
2720 else if (s->hl == DRAW_CURSOR)
2721 {
2722 x_set_cursor_gc (s);
2723 s->stippled_p = 0;
2724 }
2725 else if (s->hl == DRAW_MOUSE_FACE)
2726 {
2727 x_set_mouse_face_gc (s);
2728 s->stippled_p = s->face->stipple != 0;
2729 }
2730 else if (s->hl == DRAW_IMAGE_RAISED
2731 || s->hl == DRAW_IMAGE_SUNKEN)
2732 {
2733 s->gc = s->face->gc;
2734 s->stippled_p = s->face->stipple != 0;
2735 }
2736 else
2737 {
2738 s->gc = s->face->gc;
2739 s->stippled_p = s->face->stipple != 0;
2740 }
2741
2742 /* GC must have been set. */
2743 xassert (s->gc != 0);
2744}
2745
2746
2747/* Return in *R the clipping rectangle for glyph string S. */
2748
2749static void
2750x_get_glyph_string_clip_rect (s, r)
2751 struct glyph_string *s;
2752 XRectangle *r;
2753{
2754 if (s->row->full_width_p)
2755 {
2756 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2757 int canon_x = CANON_X_UNIT (s->f);
2758
2759 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2760 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2761
2762 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2763 {
1da3fd71 2764 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2765 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2766 r->x -= width;
2767 }
2768
b9432a85 2769 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2770
06a2c219
GM
2771 /* Unless displaying a mode or menu bar line, which are always
2772 fully visible, clip to the visible part of the row. */
2773 if (s->w->pseudo_window_p)
2774 r->height = s->row->visible_height;
2775 else
2776 r->height = s->height;
2777 }
2778 else
2779 {
2780 /* This is a text line that may be partially visible. */
2781 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2782 r->width = window_box_width (s->w, s->area);
2783 r->height = s->row->visible_height;
2784 }
2785
2786 /* Don't use S->y for clipping because it doesn't take partially
2787 visible lines into account. For example, it can be negative for
2788 partially visible lines at the top of a window. */
2789 if (!s->row->full_width_p
2790 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
045dee35 2791 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
06a2c219
GM
2792 else
2793 r->y = max (0, s->row->y);
06a2c219 2794
9ea173e8 2795 /* If drawing a tool-bar window, draw it over the internal border
06a2c219 2796 at the top of the window. */
9ea173e8 2797 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219 2798 r->y -= s->f->output_data.x->internal_border_width;
66ac4b0e
GM
2799
2800 /* If S draws overlapping rows, it's sufficient to use the top and
2801 bottom of the window for clipping because this glyph string
2802 intentionally draws over other lines. */
2803 if (s->for_overlaps_p)
2804 {
045dee35 2805 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2806 r->height = window_text_bottom_y (s->w) - r->y;
2807 }
2808
2809 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2810}
2811
2812
2813/* Set clipping for output of glyph string S. S may be part of a mode
2814 line or menu if we don't have X toolkit support. */
2815
2816static INLINE void
2817x_set_glyph_string_clipping (s)
2818 struct glyph_string *s;
2819{
2820 XRectangle r;
2821 x_get_glyph_string_clip_rect (s, &r);
2822 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2823}
2824
2825
2826/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2827 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2828
2829static INLINE void
2830x_compute_glyph_string_overhangs (s)
2831 struct glyph_string *s;
2832{
b4192550 2833 if (s->cmp == NULL
06a2c219
GM
2834 && s->first_glyph->type == CHAR_GLYPH)
2835 {
2836 XCharStruct cs;
2837 int direction, font_ascent, font_descent;
2838 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2839 &font_ascent, &font_descent, &cs);
2840 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2841 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2842 }
2843}
2844
2845
2846/* Compute overhangs and x-positions for glyph string S and its
2847 predecessors, or successors. X is the starting x-position for S.
2848 BACKWARD_P non-zero means process predecessors. */
2849
2850static void
2851x_compute_overhangs_and_x (s, x, backward_p)
2852 struct glyph_string *s;
2853 int x;
2854 int backward_p;
2855{
2856 if (backward_p)
2857 {
2858 while (s)
2859 {
2860 x_compute_glyph_string_overhangs (s);
2861 x -= s->width;
2862 s->x = x;
2863 s = s->prev;
2864 }
2865 }
2866 else
2867 {
2868 while (s)
2869 {
2870 x_compute_glyph_string_overhangs (s);
2871 s->x = x;
2872 x += s->width;
2873 s = s->next;
2874 }
2875 }
2876}
2877
2878
2879/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2880 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2881 assumed to be zero. */
06a2c219
GM
2882
2883static void
2884x_get_glyph_overhangs (glyph, f, left, right)
2885 struct glyph *glyph;
2886 struct frame *f;
2887 int *left, *right;
2888{
06a2c219
GM
2889 *left = *right = 0;
2890
b4192550 2891 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2892 {
2893 XFontStruct *font;
2894 struct face *face;
2895 struct font_info *font_info;
2896 XChar2b char2b;
ee569018
KH
2897 XCharStruct *pcm;
2898
2899 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2900 font = face->font;
2901 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2902 if (font
2903 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2904 {
06a2c219
GM
2905 if (pcm->rbearing > pcm->width)
2906 *right = pcm->rbearing - pcm->width;
2907 if (pcm->lbearing < 0)
2908 *left = -pcm->lbearing;
2909 }
2910 }
2911}
2912
2913
2914/* Return the index of the first glyph preceding glyph string S that
2915 is overwritten by S because of S's left overhang. Value is -1
2916 if no glyphs are overwritten. */
2917
2918static int
2919x_left_overwritten (s)
2920 struct glyph_string *s;
2921{
2922 int k;
2923
2924 if (s->left_overhang)
2925 {
2926 int x = 0, i;
2927 struct glyph *glyphs = s->row->glyphs[s->area];
2928 int first = s->first_glyph - glyphs;
2929
2930 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2931 x -= glyphs[i].pixel_width;
2932
2933 k = i + 1;
2934 }
2935 else
2936 k = -1;
2937
2938 return k;
2939}
2940
2941
2942/* Return the index of the first glyph preceding glyph string S that
2943 is overwriting S because of its right overhang. Value is -1 if no
2944 glyph in front of S overwrites S. */
2945
2946static int
2947x_left_overwriting (s)
2948 struct glyph_string *s;
2949{
2950 int i, k, x;
2951 struct glyph *glyphs = s->row->glyphs[s->area];
2952 int first = s->first_glyph - glyphs;
2953
2954 k = -1;
2955 x = 0;
2956 for (i = first - 1; i >= 0; --i)
2957 {
2958 int left, right;
2959 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2960 if (x + right > 0)
2961 k = i;
2962 x -= glyphs[i].pixel_width;
2963 }
2964
2965 return k;
2966}
2967
2968
2969/* Return the index of the last glyph following glyph string S that is
2970 not overwritten by S because of S's right overhang. Value is -1 if
2971 no such glyph is found. */
2972
2973static int
2974x_right_overwritten (s)
2975 struct glyph_string *s;
2976{
2977 int k = -1;
2978
2979 if (s->right_overhang)
2980 {
2981 int x = 0, i;
2982 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 2983 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
2984 int end = s->row->used[s->area];
2985
2986 for (i = first; i < end && s->right_overhang > x; ++i)
2987 x += glyphs[i].pixel_width;
2988
2989 k = i;
2990 }
2991
2992 return k;
2993}
2994
2995
2996/* Return the index of the last glyph following glyph string S that
2997 overwrites S because of its left overhang. Value is negative
2998 if no such glyph is found. */
2999
3000static int
3001x_right_overwriting (s)
3002 struct glyph_string *s;
3003{
3004 int i, k, x;
3005 int end = s->row->used[s->area];
3006 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3007 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3008
3009 k = -1;
3010 x = 0;
3011 for (i = first; i < end; ++i)
3012 {
3013 int left, right;
3014 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3015 if (x - left < 0)
3016 k = i;
3017 x += glyphs[i].pixel_width;
3018 }
3019
3020 return k;
3021}
3022
3023
3024/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3025
3026static INLINE void
3027x_clear_glyph_string_rect (s, x, y, w, h)
3028 struct glyph_string *s;
3029 int x, y, w, h;
3030{
3031 XGCValues xgcv;
3032 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3033 XSetForeground (s->display, s->gc, xgcv.background);
3034 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3035 XSetForeground (s->display, s->gc, xgcv.foreground);
3036}
3037
3038
3039/* Draw the background of glyph_string S. If S->background_filled_p
3040 is non-zero don't draw it. FORCE_P non-zero means draw the
3041 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3042 when a string preceding S draws into the background of S, or S
3043 contains the first component of a composition. */
06a2c219
GM
3044
3045static void
3046x_draw_glyph_string_background (s, force_p)
3047 struct glyph_string *s;
3048 int force_p;
3049{
3050 /* Nothing to do if background has already been drawn or if it
3051 shouldn't be drawn in the first place. */
3052 if (!s->background_filled_p)
3053 {
b4192550 3054 if (s->stippled_p)
06a2c219
GM
3055 {
3056 /* Fill background with a stipple pattern. */
3057 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3058 XFillRectangle (s->display, s->window, s->gc, s->x,
3059 s->y + s->face->box_line_width,
3060 s->background_width,
3061 s->height - 2 * s->face->box_line_width);
3062 XSetFillStyle (s->display, s->gc, FillSolid);
3063 s->background_filled_p = 1;
3064 }
3065 else if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
3066 || s->font_not_found_p
3067 || s->extends_to_end_of_line_p
06a2c219
GM
3068 || force_p)
3069 {
3070 x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
3071 s->background_width,
3072 s->height - 2 * s->face->box_line_width);
3073 s->background_filled_p = 1;
3074 }
3075 }
3076}
3077
3078
3079/* Draw the foreground of glyph string S. */
3080
3081static void
3082x_draw_glyph_string_foreground (s)
3083 struct glyph_string *s;
3084{
3085 int i, x;
3086
3087 /* If first glyph of S has a left box line, start drawing the text
3088 of S to the right of that box line. */
3089 if (s->face->box != FACE_NO_BOX
3090 && s->first_glyph->left_box_line_p)
3091 x = s->x + s->face->box_line_width;
3092 else
3093 x = s->x;
3094
b4192550
KH
3095 /* Draw characters of S as rectangles if S's font could not be
3096 loaded. */
3097 if (s->font_not_found_p)
06a2c219 3098 {
b4192550 3099 for (i = 0; i < s->nchars; ++i)
06a2c219 3100 {
b4192550
KH
3101 struct glyph *g = s->first_glyph + i;
3102 XDrawRectangle (s->display, s->window,
3103 s->gc, x, s->y, g->pixel_width - 1,
3104 s->height - 1);
3105 x += g->pixel_width;
06a2c219
GM
3106 }
3107 }
3108 else
3109 {
b4192550
KH
3110 char *char1b = (char *) s->char2b;
3111 int boff = s->font_info->baseline_offset;
06a2c219 3112
b4192550
KH
3113 if (s->font_info->vertical_centering)
3114 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3115
3116 /* If we can use 8-bit functions, condense S->char2b. */
3117 if (!s->two_byte_p)
3118 for (i = 0; i < s->nchars; ++i)
3119 char1b[i] = s->char2b[i].byte2;
3120
3121 /* Draw text with XDrawString if background has already been
3122 filled. Otherwise, use XDrawImageString. (Note that
3123 XDrawImageString is usually faster than XDrawString.) Always
3124 use XDrawImageString when drawing the cursor so that there is
3125 no chance that characters under a box cursor are invisible. */
3126 if (s->for_overlaps_p
3127 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3128 {
3129 /* Draw characters with 16-bit or 8-bit functions. */
3130 if (s->two_byte_p)
3131 XDrawString16 (s->display, s->window, s->gc, x,
3132 s->ybase - boff, s->char2b, s->nchars);
3133 else
3134 XDrawString (s->display, s->window, s->gc, x,
3135 s->ybase - boff, char1b, s->nchars);
3136 }
06a2c219
GM
3137 else
3138 {
b4192550
KH
3139 if (s->two_byte_p)
3140 XDrawImageString16 (s->display, s->window, s->gc, x,
3141 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3142 else
b4192550
KH
3143 XDrawImageString (s->display, s->window, s->gc, x,
3144 s->ybase - boff, char1b, s->nchars);
3145 }
3146 }
3147}
06a2c219 3148
b4192550 3149/* Draw the foreground of composite glyph string S. */
06a2c219 3150
b4192550
KH
3151static void
3152x_draw_composite_glyph_string_foreground (s)
3153 struct glyph_string *s;
3154{
3155 int i, x;
06a2c219 3156
b4192550
KH
3157 /* If first glyph of S has a left box line, start drawing the text
3158 of S to the right of that box line. */
3159 if (s->face->box != FACE_NO_BOX
3160 && s->first_glyph->left_box_line_p)
3161 x = s->x + s->face->box_line_width;
3162 else
3163 x = s->x;
06a2c219 3164
b4192550
KH
3165 /* S is a glyph string for a composition. S->gidx is the index of
3166 the first character drawn for glyphs of this composition.
3167 S->gidx == 0 means we are drawing the very first character of
3168 this composition. */
06a2c219 3169
b4192550
KH
3170 /* Draw a rectangle for the composition if the font for the very
3171 first character of the composition could not be loaded. */
3172 if (s->font_not_found_p)
3173 {
3174 if (s->gidx == 0)
3175 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3176 s->width - 1, s->height - 1);
3177 }
3178 else
3179 {
3180 for (i = 0; i < s->nchars; i++, ++s->gidx)
3181 XDrawString16 (s->display, s->window, s->gc,
3182 x + s->cmp->offsets[s->gidx * 2],
3183 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3184 s->char2b + i, 1);
06a2c219
GM
3185 }
3186}
3187
3188
80c32bcc
GM
3189#ifdef USE_X_TOOLKIT
3190
3e71d8f2 3191static struct frame *x_frame_of_widget P_ ((Widget));
80c32bcc 3192
3e71d8f2
GM
3193
3194/* Return the frame on which widget WIDGET is used.. Abort if frame
3195 cannot be determined. */
3196
e851c833 3197static struct frame *
3e71d8f2 3198x_frame_of_widget (widget)
80c32bcc 3199 Widget widget;
80c32bcc 3200{
80c32bcc 3201 struct x_display_info *dpyinfo;
5c187dee 3202 Lisp_Object tail;
3e71d8f2
GM
3203 struct frame *f;
3204
80c32bcc
GM
3205 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3206
3207 /* Find the top-level shell of the widget. Note that this function
3208 can be called when the widget is not yet realized, so XtWindow
3209 (widget) == 0. That's the reason we can't simply use
3210 x_any_window_to_frame. */
3211 while (!XtIsTopLevelShell (widget))
3212 widget = XtParent (widget);
3213
3214 /* Look for a frame with that top-level widget. Allocate the color
3215 on that frame to get the right gamma correction value. */
3216 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3217 if (GC_FRAMEP (XCAR (tail))
3218 && (f = XFRAME (XCAR (tail)),
3219 (f->output_data.nothing != 1
3220 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3221 && f->output_data.x->widget == widget)
3e71d8f2 3222 return f;
80c32bcc
GM
3223
3224 abort ();
3225}
3226
3e71d8f2
GM
3227
3228/* Allocate the color COLOR->pixel on the screen and display of
3229 widget WIDGET in colormap CMAP. If an exact match cannot be
3230 allocated, try the nearest color available. Value is non-zero
3231 if successful. This is called from lwlib. */
3232
3233int
3234x_alloc_nearest_color_for_widget (widget, cmap, color)
3235 Widget widget;
3236 Colormap cmap;
3237 XColor *color;
3238{
3239 struct frame *f = x_frame_of_widget (widget);
3240 return x_alloc_nearest_color (f, cmap, color);
3241}
3242
3243
80c32bcc
GM
3244#endif /* USE_X_TOOLKIT */
3245
3246
06a2c219
GM
3247/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3248 CMAP. If an exact match can't be allocated, try the nearest color
3249 available. Value is non-zero if successful. Set *COLOR to the
3250 color allocated. */
3251
3252int
80c32bcc
GM
3253x_alloc_nearest_color (f, cmap, color)
3254 struct frame *f;
06a2c219
GM
3255 Colormap cmap;
3256 XColor *color;
3257{
80c32bcc
GM
3258 Display *display = FRAME_X_DISPLAY (f);
3259 Screen *screen = FRAME_X_SCREEN (f);
3260 int rc;
3261
3262 gamma_correct (f, color);
3263 rc = XAllocColor (display, cmap, color);
06a2c219
GM
3264 if (rc == 0)
3265 {
3266 /* If we got to this point, the colormap is full, so we're going
3267 to try to get the next closest color. The algorithm used is
3268 a least-squares matching, which is what X uses for closest
3269 color matching with StaticColor visuals. */
3270 int nearest, i;
3271 unsigned long nearest_delta = ~0;
3272 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3273 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3274
3275 for (i = 0; i < ncells; ++i)
3276 cells[i].pixel = i;
3277 XQueryColors (display, cmap, cells, ncells);
3278
3279 for (nearest = i = 0; i < ncells; ++i)
3280 {
3281 long dred = (color->red >> 8) - (cells[i].red >> 8);
3282 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3283 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3284 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3285
3286 if (delta < nearest_delta)
3287 {
3288 nearest = i;
3289 nearest_delta = delta;
3290 }
3291 }
3292
3293 color->red = cells[nearest].red;
3294 color->green = cells[nearest].green;
3295 color->blue = cells[nearest].blue;
3296 rc = XAllocColor (display, cmap, color);
3297 }
3298
d9c545da
GM
3299#ifdef DEBUG_X_COLORS
3300 if (rc)
3301 register_color (color->pixel);
3302#endif /* DEBUG_X_COLORS */
3303
06a2c219
GM
3304 return rc;
3305}
3306
3307
d9c545da
GM
3308/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3309 It's necessary to do this instead of just using PIXEL directly to
3310 get color reference counts right. */
3311
3312unsigned long
3313x_copy_color (f, pixel)
3314 struct frame *f;
3315 unsigned long pixel;
3316{
3317 XColor color;
3318
3319 color.pixel = pixel;
3320 BLOCK_INPUT;
3321 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3322 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3323 UNBLOCK_INPUT;
3324#ifdef DEBUG_X_COLORS
3325 register_color (pixel);
3326#endif
3327 return color.pixel;
3328}
3329
3330
3e71d8f2
GM
3331/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3332 It's necessary to do this instead of just using PIXEL directly to
3333 get color reference counts right. */
3334
3335unsigned long
3336x_copy_dpy_color (dpy, cmap, pixel)
3337 Display *dpy;
3338 Colormap cmap;
3339 unsigned long pixel;
3340{
3341 XColor color;
3342
3343 color.pixel = pixel;
3344 BLOCK_INPUT;
3345 XQueryColor (dpy, cmap, &color);
3346 XAllocColor (dpy, cmap, &color);
3347 UNBLOCK_INPUT;
3348#ifdef DEBUG_X_COLORS
3349 register_color (pixel);
3350#endif
3351 return color.pixel;
3352}
3353
3354
06a2c219
GM
3355/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3356 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3357 If this produces the same color as PIXEL, try a color where all RGB
3358 values have DELTA added. Return the allocated color in *PIXEL.
3359 DISPLAY is the X display, CMAP is the colormap to operate on.
3360 Value is non-zero if successful. */
3361
3362static int
3363x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3364 struct frame *f;
3365 Display *display;
3366 Colormap cmap;
3367 unsigned long *pixel;
68c45bf0 3368 double factor;
06a2c219
GM
3369 int delta;
3370{
3371 XColor color, new;
3372 int success_p;
3373
3374 /* Get RGB color values. */
3375 color.pixel = *pixel;
3376 XQueryColor (display, cmap, &color);
3377
3378 /* Change RGB values by specified FACTOR. Avoid overflow! */
3379 xassert (factor >= 0);
3380 new.red = min (0xffff, factor * color.red);
3381 new.green = min (0xffff, factor * color.green);
3382 new.blue = min (0xffff, factor * color.blue);
3383
3384 /* Try to allocate the color. */
80c32bcc 3385 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3386 if (success_p)
3387 {
3388 if (new.pixel == *pixel)
3389 {
3390 /* If we end up with the same color as before, try adding
3391 delta to the RGB values. */
0d605c67 3392 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3393
3394 new.red = min (0xffff, delta + color.red);
3395 new.green = min (0xffff, delta + color.green);
3396 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3397 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3398 }
3399 else
3400 success_p = 1;
3401 *pixel = new.pixel;
3402 }
3403
3404 return success_p;
3405}
3406
3407
3408/* Set up the foreground color for drawing relief lines of glyph
3409 string S. RELIEF is a pointer to a struct relief containing the GC
3410 with which lines will be drawn. Use a color that is FACTOR or
3411 DELTA lighter or darker than the relief's background which is found
3412 in S->f->output_data.x->relief_background. If such a color cannot
3413 be allocated, use DEFAULT_PIXEL, instead. */
3414
3415static void
3416x_setup_relief_color (f, relief, factor, delta, default_pixel)
3417 struct frame *f;
3418 struct relief *relief;
68c45bf0 3419 double factor;
06a2c219
GM
3420 int delta;
3421 unsigned long default_pixel;
3422{
3423 XGCValues xgcv;
3424 struct x_output *di = f->output_data.x;
3425 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3426 unsigned long pixel;
3427 unsigned long background = di->relief_background;
43bd1b2b 3428 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3429 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3430 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3431
3432 xgcv.graphics_exposures = False;
3433 xgcv.line_width = 1;
3434
3435 /* Free previously allocated color. The color cell will be reused
3436 when it has been freed as many times as it was allocated, so this
3437 doesn't affect faces using the same colors. */
3438 if (relief->gc
3439 && relief->allocated_p)
3440 {
0d605c67 3441 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3442 relief->allocated_p = 0;
3443 }
3444
3445 /* Allocate new color. */
3446 xgcv.foreground = default_pixel;
3447 pixel = background;
dcd08bfb
GM
3448 if (dpyinfo->n_planes != 1
3449 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3450 {
3451 relief->allocated_p = 1;
3452 xgcv.foreground = relief->pixel = pixel;
3453 }
3454
3455 if (relief->gc == 0)
3456 {
dcd08bfb 3457 xgcv.stipple = dpyinfo->gray;
06a2c219 3458 mask |= GCStipple;
dcd08bfb 3459 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3460 }
3461 else
dcd08bfb 3462 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3463}
3464
3465
3466/* Set up colors for the relief lines around glyph string S. */
3467
3468static void
3469x_setup_relief_colors (s)
3470 struct glyph_string *s;
3471{
3472 struct x_output *di = s->f->output_data.x;
3473 unsigned long color;
3474
3475 if (s->face->use_box_color_for_shadows_p)
3476 color = s->face->box_color;
3477 else
3478 {
3479 XGCValues xgcv;
3480
3481 /* Get the background color of the face. */
3482 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3483 color = xgcv.background;
3484 }
3485
3486 if (di->white_relief.gc == 0
3487 || color != di->relief_background)
3488 {
3489 di->relief_background = color;
3490 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3491 WHITE_PIX_DEFAULT (s->f));
3492 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3493 BLACK_PIX_DEFAULT (s->f));
3494 }
3495}
3496
3497
3498/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3499 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3500 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3501 relief. LEFT_P non-zero means draw a relief on the left side of
3502 the rectangle. RIGHT_P non-zero means draw a relief on the right
3503 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3504 when drawing. */
3505
3506static void
3507x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3508 raised_p, left_p, right_p, clip_rect)
3509 struct frame *f;
3510 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3511 XRectangle *clip_rect;
3512{
3513 int i;
3514 GC gc;
3515
3516 if (raised_p)
3517 gc = f->output_data.x->white_relief.gc;
3518 else
3519 gc = f->output_data.x->black_relief.gc;
3520 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3521
3522 /* Top. */
3523 for (i = 0; i < width; ++i)
3524 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3525 left_x + i * left_p, top_y + i,
3526 right_x + 1 - i * right_p, top_y + i);
3527
3528 /* Left. */
3529 if (left_p)
3530 for (i = 0; i < width; ++i)
3531 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3532 left_x + i, top_y + i, left_x + i, bottom_y - i);
3533
3534 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3535 if (raised_p)
3536 gc = f->output_data.x->black_relief.gc;
3537 else
3538 gc = f->output_data.x->white_relief.gc;
3539 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3540
3541 /* Bottom. */
3542 for (i = 0; i < width; ++i)
3543 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3544 left_x + i * left_p, bottom_y - i,
3545 right_x + 1 - i * right_p, bottom_y - i);
3546
3547 /* Right. */
3548 if (right_p)
3549 for (i = 0; i < width; ++i)
3550 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3551 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3552
3553 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3554}
3555
3556
3557/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3558 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3559 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3560 left side of the rectangle. RIGHT_P non-zero means draw a line
3561 on the right side of the rectangle. CLIP_RECT is the clipping
3562 rectangle to use when drawing. */
3563
3564static void
3565x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3566 left_p, right_p, clip_rect)
3567 struct glyph_string *s;
3568 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3569 XRectangle *clip_rect;
3570{
3571 XGCValues xgcv;
3572
3573 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3574 XSetForeground (s->display, s->gc, s->face->box_color);
3575 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3576
3577 /* Top. */
3578 XFillRectangle (s->display, s->window, s->gc,
3579 left_x, top_y, right_x - left_x, width);
3580
3581 /* Left. */
3582 if (left_p)
3583 XFillRectangle (s->display, s->window, s->gc,
3584 left_x, top_y, width, bottom_y - top_y);
3585
3586 /* Bottom. */
3587 XFillRectangle (s->display, s->window, s->gc,
3588 left_x, bottom_y - width, right_x - left_x, width);
3589
3590 /* Right. */
3591 if (right_p)
3592 XFillRectangle (s->display, s->window, s->gc,
3593 right_x - width, top_y, width, bottom_y - top_y);
3594
3595 XSetForeground (s->display, s->gc, xgcv.foreground);
3596 XSetClipMask (s->display, s->gc, None);
3597}
3598
3599
3600/* Draw a box around glyph string S. */
3601
3602static void
3603x_draw_glyph_string_box (s)
3604 struct glyph_string *s;
3605{
3606 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3607 int left_p, right_p;
3608 struct glyph *last_glyph;
3609 XRectangle clip_rect;
3610
3611 last_x = window_box_right (s->w, s->area);
3612 if (s->row->full_width_p
3613 && !s->w->pseudo_window_p)
3614 {
110859fc 3615 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3616 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3617 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3618 }
3619
3620 /* The glyph that may have a right box line. */
b4192550 3621 last_glyph = (s->cmp || s->img
06a2c219
GM
3622 ? s->first_glyph
3623 : s->first_glyph + s->nchars - 1);
3624
3625 width = s->face->box_line_width;
3626 raised_p = s->face->box == FACE_RAISED_BOX;
3627 left_x = s->x;
3628 right_x = ((s->row->full_width_p
1da3fd71 3629 ? last_x - 1
a7aeb2de 3630 : min (last_x, s->x + s->background_width) - 1));
06a2c219
GM
3631 top_y = s->y;
3632 bottom_y = top_y + s->height - 1;
3633
3634 left_p = (s->first_glyph->left_box_line_p
3635 || (s->hl == DRAW_MOUSE_FACE
3636 && (s->prev == NULL
3637 || s->prev->hl != s->hl)));
3638 right_p = (last_glyph->right_box_line_p
3639 || (s->hl == DRAW_MOUSE_FACE
3640 && (s->next == NULL
3641 || s->next->hl != s->hl)));
3642
3643 x_get_glyph_string_clip_rect (s, &clip_rect);
3644
3645 if (s->face->box == FACE_SIMPLE_BOX)
3646 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3647 left_p, right_p, &clip_rect);
3648 else
3649 {
3650 x_setup_relief_colors (s);
3651 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3652 width, raised_p, left_p, right_p, &clip_rect);
3653 }
3654}
3655
3656
3657/* Draw foreground of image glyph string S. */
3658
3659static void
3660x_draw_image_foreground (s)
3661 struct glyph_string *s;
3662{
3663 int x;
95af8492 3664 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3665
3666 /* If first glyph of S has a left box line, start drawing it to the
3667 right of that line. */
3668 if (s->face->box != FACE_NO_BOX
3669 && s->first_glyph->left_box_line_p)
3670 x = s->x + s->face->box_line_width;
3671 else
3672 x = s->x;
3673
3674 /* If there is a margin around the image, adjust x- and y-position
3675 by that margin. */
3676 if (s->img->margin)
3677 {
3678 x += s->img->margin;
3679 y += s->img->margin;
3680 }
3681
3682 if (s->img->pixmap)
3683 {
3684 if (s->img->mask)
3685 {
3686 /* We can't set both a clip mask and use XSetClipRectangles
3687 because the latter also sets a clip mask. We also can't
3688 trust on the shape extension to be available
3689 (XShapeCombineRegion). So, compute the rectangle to draw
3690 manually. */
3691 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3692 | GCFunction);
3693 XGCValues xgcv;
3694 XRectangle clip_rect, image_rect, r;
3695
3696 xgcv.clip_mask = s->img->mask;
3697 xgcv.clip_x_origin = x;
3698 xgcv.clip_y_origin = y;
3699 xgcv.function = GXcopy;
3700 XChangeGC (s->display, s->gc, mask, &xgcv);
3701
3702 x_get_glyph_string_clip_rect (s, &clip_rect);
3703 image_rect.x = x;
3704 image_rect.y = y;
3705 image_rect.width = s->img->width;
3706 image_rect.height = s->img->height;
3707 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
3708 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3709 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
3710 }
3711 else
3712 {
3713 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3714 0, 0, s->img->width, s->img->height, x, y);
3715
3716 /* When the image has a mask, we can expect that at
3717 least part of a mouse highlight or a block cursor will
3718 be visible. If the image doesn't have a mask, make
3719 a block cursor visible by drawing a rectangle around
3720 the image. I believe it's looking better if we do
3721 nothing here for mouse-face. */
3722 if (s->hl == DRAW_CURSOR)
3723 XDrawRectangle (s->display, s->window, s->gc, x, y,
3724 s->img->width - 1, s->img->height - 1);
3725 }
3726 }
3727 else
3728 /* Draw a rectangle if image could not be loaded. */
3729 XDrawRectangle (s->display, s->window, s->gc, x, y,
3730 s->img->width - 1, s->img->height - 1);
3731}
3732
3733
3734/* Draw a relief around the image glyph string S. */
3735
3736static void
3737x_draw_image_relief (s)
3738 struct glyph_string *s;
3739{
3740 int x0, y0, x1, y1, thick, raised_p;
3741 XRectangle r;
3742 int x;
95af8492 3743 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3744
3745 /* If first glyph of S has a left box line, start drawing it to the
3746 right of that line. */
3747 if (s->face->box != FACE_NO_BOX
3748 && s->first_glyph->left_box_line_p)
3749 x = s->x + s->face->box_line_width;
3750 else
3751 x = s->x;
3752
3753 /* If there is a margin around the image, adjust x- and y-position
3754 by that margin. */
3755 if (s->img->margin)
3756 {
3757 x += s->img->margin;
3758 y += s->img->margin;
3759 }
3760
3761 if (s->hl == DRAW_IMAGE_SUNKEN
3762 || s->hl == DRAW_IMAGE_RAISED)
3763 {
9ea173e8 3764 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
3765 raised_p = s->hl == DRAW_IMAGE_RAISED;
3766 }
3767 else
3768 {
3769 thick = abs (s->img->relief);
3770 raised_p = s->img->relief > 0;
3771 }
3772
3773 x0 = x - thick;
3774 y0 = y - thick;
3775 x1 = x + s->img->width + thick - 1;
3776 y1 = y + s->img->height + thick - 1;
3777
3778 x_setup_relief_colors (s);
3779 x_get_glyph_string_clip_rect (s, &r);
3780 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
3781}
3782
3783
3784/* Draw the foreground of image glyph string S to PIXMAP. */
3785
3786static void
3787x_draw_image_foreground_1 (s, pixmap)
3788 struct glyph_string *s;
3789 Pixmap pixmap;
3790{
3791 int x;
95af8492 3792 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
3793
3794 /* If first glyph of S has a left box line, start drawing it to the
3795 right of that line. */
3796 if (s->face->box != FACE_NO_BOX
3797 && s->first_glyph->left_box_line_p)
3798 x = s->face->box_line_width;
3799 else
3800 x = 0;
3801
3802 /* If there is a margin around the image, adjust x- and y-position
3803 by that margin. */
3804 if (s->img->margin)
3805 {
3806 x += s->img->margin;
3807 y += s->img->margin;
3808 }
dc43ef94 3809
06a2c219
GM
3810 if (s->img->pixmap)
3811 {
3812 if (s->img->mask)
3813 {
3814 /* We can't set both a clip mask and use XSetClipRectangles
3815 because the latter also sets a clip mask. We also can't
3816 trust on the shape extension to be available
3817 (XShapeCombineRegion). So, compute the rectangle to draw
3818 manually. */
3819 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3820 | GCFunction);
3821 XGCValues xgcv;
3822
3823 xgcv.clip_mask = s->img->mask;
3824 xgcv.clip_x_origin = x;
3825 xgcv.clip_y_origin = y;
3826 xgcv.function = GXcopy;
3827 XChangeGC (s->display, s->gc, mask, &xgcv);
3828
3829 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3830 0, 0, s->img->width, s->img->height, x, y);
3831 XSetClipMask (s->display, s->gc, None);
3832 }
3833 else
3834 {
3835 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3836 0, 0, s->img->width, s->img->height, x, y);
3837
3838 /* When the image has a mask, we can expect that at
3839 least part of a mouse highlight or a block cursor will
3840 be visible. If the image doesn't have a mask, make
3841 a block cursor visible by drawing a rectangle around
3842 the image. I believe it's looking better if we do
3843 nothing here for mouse-face. */
3844 if (s->hl == DRAW_CURSOR)
3845 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3846 s->img->width - 1, s->img->height - 1);
3847 }
3848 }
3849 else
3850 /* Draw a rectangle if image could not be loaded. */
3851 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3852 s->img->width - 1, s->img->height - 1);
3853}
dc43ef94 3854
990ba854 3855
06a2c219
GM
3856/* Draw part of the background of glyph string S. X, Y, W, and H
3857 give the rectangle to draw. */
a9a5b0a5 3858
06a2c219
GM
3859static void
3860x_draw_glyph_string_bg_rect (s, x, y, w, h)
3861 struct glyph_string *s;
3862 int x, y, w, h;
3863{
3864 if (s->stippled_p)
3865 {
3866 /* Fill background with a stipple pattern. */
3867 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3868 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3869 XSetFillStyle (s->display, s->gc, FillSolid);
3870 }
3871 else
3872 x_clear_glyph_string_rect (s, x, y, w, h);
3873}
07e34cb0 3874
b5210ea7 3875
06a2c219 3876/* Draw image glyph string S.
dc43ef94 3877
06a2c219
GM
3878 s->y
3879 s->x +-------------------------
3880 | s->face->box
3881 |
3882 | +-------------------------
3883 | | s->img->margin
3884 | |
3885 | | +-------------------
3886 | | | the image
dc43ef94 3887
06a2c219 3888 */
dc43ef94 3889
06a2c219
GM
3890static void
3891x_draw_image_glyph_string (s)
3892 struct glyph_string *s;
3893{
3894 int x, y;
3895 int box_line_width = s->face->box_line_width;
3896 int margin = s->img->margin;
3897 int height;
3898 Pixmap pixmap = None;
3899
3900 height = s->height - 2 * box_line_width;
3901
3902 /* Fill background with face under the image. Do it only if row is
3903 taller than image or if image has a clip mask to reduce
3904 flickering. */
3905 s->stippled_p = s->face->stipple != 0;
3906 if (height > s->img->height
3907 || margin
3908 || s->img->mask
3909 || s->img->pixmap == 0
3910 || s->width != s->background_width)
3911 {
3912 if (box_line_width && s->first_glyph->left_box_line_p)
3913 x = s->x + box_line_width;
3914 else
3915 x = s->x;
3916
3917 y = s->y + box_line_width;
3918
3919 if (s->img->mask)
3920 {
3921 /* Create a pixmap as large as the glyph string Fill it with
3922 the background color. Copy the image to it, using its
3923 mask. Copy the temporary pixmap to the display. */
3924 Screen *screen = FRAME_X_SCREEN (s->f);
3925 int depth = DefaultDepthOfScreen (screen);
3926
3927 /* Create a pixmap as large as the glyph string. */
3928 pixmap = XCreatePixmap (s->display, s->window,
3929 s->background_width,
3930 s->height, depth);
3931
3932 /* Don't clip in the following because we're working on the
3933 pixmap. */
3934 XSetClipMask (s->display, s->gc, None);
3935
3936 /* Fill the pixmap with the background color/stipple. */
3937 if (s->stippled_p)
3938 {
3939 /* Fill background with a stipple pattern. */
3940 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3941 XFillRectangle (s->display, pixmap, s->gc,
3942 0, 0, s->background_width, s->height);
3943 XSetFillStyle (s->display, s->gc, FillSolid);
3944 }
3945 else
3946 {
3947 XGCValues xgcv;
3948 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
3949 &xgcv);
3950 XSetForeground (s->display, s->gc, xgcv.background);
3951 XFillRectangle (s->display, pixmap, s->gc,
3952 0, 0, s->background_width, s->height);
3953 XSetForeground (s->display, s->gc, xgcv.foreground);
3954 }
3955 }
3956 else
3957 /* Implementation idea: Is it possible to construct a mask?
3958 We could look at the color at the margins of the image, and
3959 say that this color is probably the background color of the
3960 image. */
3961 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3962
3963 s->background_filled_p = 1;
3964 }
dc43ef94 3965
06a2c219
GM
3966 /* Draw the foreground. */
3967 if (pixmap != None)
3968 {
3969 x_draw_image_foreground_1 (s, pixmap);
3970 x_set_glyph_string_clipping (s);
3971 XCopyArea (s->display, pixmap, s->window, s->gc,
3972 0, 0, s->background_width, s->height, s->x, s->y);
3973 XFreePixmap (s->display, pixmap);
3974 }
3975 else
3976 x_draw_image_foreground (s);
b5210ea7 3977
06a2c219
GM
3978 /* If we must draw a relief around the image, do it. */
3979 if (s->img->relief
3980 || s->hl == DRAW_IMAGE_RAISED
3981 || s->hl == DRAW_IMAGE_SUNKEN)
3982 x_draw_image_relief (s);
3983}
8c1a6a84 3984
990ba854 3985
06a2c219 3986/* Draw stretch glyph string S. */
dc43ef94 3987
06a2c219
GM
3988static void
3989x_draw_stretch_glyph_string (s)
3990 struct glyph_string *s;
3991{
3992 xassert (s->first_glyph->type == STRETCH_GLYPH);
3993 s->stippled_p = s->face->stipple != 0;
990ba854 3994
06a2c219
GM
3995 if (s->hl == DRAW_CURSOR
3996 && !x_stretch_cursor_p)
3997 {
3998 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3999 as wide as the stretch glyph. */
4000 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4001
06a2c219
GM
4002 /* Draw cursor. */
4003 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4004
06a2c219
GM
4005 /* Clear rest using the GC of the original non-cursor face. */
4006 if (width < s->background_width)
4007 {
4008 GC gc = s->face->gc;
4009 int x = s->x + width, y = s->y;
4010 int w = s->background_width - width, h = s->height;
4011 XRectangle r;
dc43ef94 4012
06a2c219
GM
4013 x_get_glyph_string_clip_rect (s, &r);
4014 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
97210f4e 4015
06a2c219
GM
4016 if (s->face->stipple)
4017 {
4018 /* Fill background with a stipple pattern. */
4019 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4020 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4021 XSetFillStyle (s->display, gc, FillSolid);
4022 }
4023 else
4024 {
4025 XGCValues xgcv;
4026 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4027 XSetForeground (s->display, gc, xgcv.background);
4028 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4029 XSetForeground (s->display, gc, xgcv.foreground);
4030 }
4031 }
4032 }
4033 else
4034 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4035 s->height);
4036
4037 s->background_filled_p = 1;
4038}
4039
4040
4041/* Draw glyph string S. */
4042
4043static void
4044x_draw_glyph_string (s)
4045 struct glyph_string *s;
4046{
4047 /* If S draws into the background of its successor, draw the
4048 background of the successor first so that S can draw into it.
4049 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4050 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4051 {
4052 xassert (s->next->img == NULL);
4053 x_set_glyph_string_gc (s->next);
4054 x_set_glyph_string_clipping (s->next);
4055 x_draw_glyph_string_background (s->next, 1);
4056 }
97210f4e 4057
06a2c219
GM
4058 /* Set up S->gc, set clipping and draw S. */
4059 x_set_glyph_string_gc (s);
4060 x_set_glyph_string_clipping (s);
4061
4062 switch (s->first_glyph->type)
4063 {
4064 case IMAGE_GLYPH:
4065 x_draw_image_glyph_string (s);
4066 break;
4067
4068 case STRETCH_GLYPH:
4069 x_draw_stretch_glyph_string (s);
4070 break;
4071
4072 case CHAR_GLYPH:
66ac4b0e
GM
4073 if (s->for_overlaps_p)
4074 s->background_filled_p = 1;
4075 else
4076 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4077 x_draw_glyph_string_foreground (s);
4078 break;
4079
b4192550
KH
4080 case COMPOSITE_GLYPH:
4081 if (s->for_overlaps_p || s->gidx > 0)
4082 s->background_filled_p = 1;
4083 else
4084 x_draw_glyph_string_background (s, 1);
4085 x_draw_composite_glyph_string_foreground (s);
4086 break;
4087
06a2c219
GM
4088 default:
4089 abort ();
4090 }
4091
66ac4b0e 4092 if (!s->for_overlaps_p)
06a2c219 4093 {
66ac4b0e
GM
4094 /* Draw underline. */
4095 if (s->face->underline_p)
4096 {
4097 unsigned long dy, h;
06a2c219 4098
66ac4b0e
GM
4099 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4100 h = 1;
4101 if (!XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &dy))
4102 dy = s->height - h;
06a2c219 4103
66ac4b0e
GM
4104 if (s->face->underline_defaulted_p)
4105 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4106 s->width, h);
4107 else
4108 {
4109 XGCValues xgcv;
4110 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4111 XSetForeground (s->display, s->gc, s->face->underline_color);
4112 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4113 s->width, h);
4114 XSetForeground (s->display, s->gc, xgcv.foreground);
4115 }
dc6f92b8 4116 }
07e34cb0 4117
66ac4b0e
GM
4118 /* Draw overline. */
4119 if (s->face->overline_p)
06a2c219 4120 {
66ac4b0e
GM
4121 unsigned long dy = 0, h = 1;
4122
4123 if (s->face->overline_color_defaulted_p)
4124 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4125 s->width, h);
4126 else
4127 {
4128 XGCValues xgcv;
4129 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4130 XSetForeground (s->display, s->gc, s->face->overline_color);
4131 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4132 s->width, h);
4133 XSetForeground (s->display, s->gc, xgcv.foreground);
4134 }
06a2c219 4135 }
06a2c219 4136
66ac4b0e
GM
4137 /* Draw strike-through. */
4138 if (s->face->strike_through_p)
06a2c219 4139 {
66ac4b0e
GM
4140 unsigned long h = 1;
4141 unsigned long dy = (s->height - h) / 2;
4142
4143 if (s->face->strike_through_color_defaulted_p)
4144 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4145 s->width, h);
4146 else
4147 {
4148 XGCValues xgcv;
4149 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4150 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4151 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4152 s->width, h);
4153 XSetForeground (s->display, s->gc, xgcv.foreground);
4154 }
06a2c219 4155 }
06a2c219 4156
66ac4b0e
GM
4157 /* Draw relief. */
4158 if (s->face->box != FACE_NO_BOX)
4159 x_draw_glyph_string_box (s);
4160 }
06a2c219
GM
4161
4162 /* Reset clipping. */
4163 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4164}
07e34cb0 4165
06a2c219 4166
b4192550
KH
4167static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4168 struct face **, int));
06a2c219 4169
06a2c219 4170
209f68d9
GM
4171/* Fill glyph string S with composition components specified by S->cmp.
4172
b4192550
KH
4173 FACES is an array of faces for all components of this composition.
4174 S->gidx is the index of the first component for S.
4175 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4176 use its physical height for clipping.
06a2c219 4177
b4192550 4178 Value is the index of a component not in S. */
07e34cb0 4179
b4192550
KH
4180static int
4181x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4182 struct glyph_string *s;
b4192550 4183 struct face **faces;
66ac4b0e 4184 int overlaps_p;
07e34cb0 4185{
b4192550 4186 int i;
06a2c219 4187
b4192550 4188 xassert (s);
06a2c219 4189
b4192550 4190 s->for_overlaps_p = overlaps_p;
06a2c219 4191
b4192550
KH
4192 s->face = faces[s->gidx];
4193 s->font = s->face->font;
4194 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4195
b4192550
KH
4196 /* For all glyphs of this composition, starting at the offset
4197 S->gidx, until we reach the end of the definition or encounter a
4198 glyph that requires the different face, add it to S. */
4199 ++s->nchars;
4200 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4201 ++s->nchars;
06a2c219 4202
b4192550
KH
4203 /* All glyph strings for the same composition has the same width,
4204 i.e. the width set for the first component of the composition. */
06a2c219 4205
06a2c219
GM
4206 s->width = s->first_glyph->pixel_width;
4207
4208 /* If the specified font could not be loaded, use the frame's
4209 default font, but record the fact that we couldn't load it in
4210 the glyph string so that we can draw rectangles for the
4211 characters of the glyph string. */
4212 if (s->font == NULL)
4213 {
4214 s->font_not_found_p = 1;
4215 s->font = FRAME_FONT (s->f);
4216 }
4217
4218 /* Adjust base line for subscript/superscript text. */
4219 s->ybase += s->first_glyph->voffset;
4220
4221 xassert (s->face && s->face->gc);
4222
4223 /* This glyph string must always be drawn with 16-bit functions. */
4224 s->two_byte_p = 1;
b4192550
KH
4225
4226 return s->gidx + s->nchars;
06a2c219
GM
4227}
4228
4229
209f68d9
GM
4230/* Fill glyph string S from a sequence of character glyphs.
4231
06a2c219 4232 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4233 first glyph to consider, END is the index of the last + 1.
4234 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4235 use its physical height for clipping.
66ac4b0e
GM
4236
4237 Value is the index of the first glyph not in S. */
06a2c219
GM
4238
4239static int
66ac4b0e 4240x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4241 struct glyph_string *s;
4242 int face_id;
66ac4b0e 4243 int start, end, overlaps_p;
06a2c219
GM
4244{
4245 struct glyph *glyph, *last;
4246 int voffset;
ee569018 4247 int glyph_not_available_p;
06a2c219 4248
06a2c219
GM
4249 xassert (s->f == XFRAME (s->w->frame));
4250 xassert (s->nchars == 0);
4251 xassert (start >= 0 && end > start);
4252
66ac4b0e 4253 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4254 glyph = s->row->glyphs[s->area] + start;
4255 last = s->row->glyphs[s->area] + end;
4256 voffset = glyph->voffset;
4257
ee569018
KH
4258 glyph_not_available_p = glyph->glyph_not_available_p;
4259
06a2c219
GM
4260 while (glyph < last
4261 && glyph->type == CHAR_GLYPH
4262 && glyph->voffset == voffset
ee569018
KH
4263 /* Same face id implies same font, nowadays. */
4264 && glyph->face_id == face_id
4265 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4266 {
ee569018
KH
4267 int two_byte_p;
4268
06a2c219 4269 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4270 s->char2b + s->nchars,
4271 &two_byte_p);
4272 s->two_byte_p = two_byte_p;
06a2c219
GM
4273 ++s->nchars;
4274 xassert (s->nchars <= end - start);
4275 s->width += glyph->pixel_width;
4276 ++glyph;
4277 }
4278
4279 s->font = s->face->font;
4280 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4281
4282 /* If the specified font could not be loaded, use the frame's font,
4283 but record the fact that we couldn't load it in
4284 S->font_not_found_p so that we can draw rectangles for the
4285 characters of the glyph string. */
ee569018 4286 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4287 {
4288 s->font_not_found_p = 1;
4289 s->font = FRAME_FONT (s->f);
4290 }
4291
4292 /* Adjust base line for subscript/superscript text. */
4293 s->ybase += voffset;
66ac4b0e 4294
06a2c219
GM
4295 xassert (s->face && s->face->gc);
4296 return glyph - s->row->glyphs[s->area];
07e34cb0 4297}
dc6f92b8 4298
06a2c219
GM
4299
4300/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4301
dfcf069d 4302static void
06a2c219
GM
4303x_fill_image_glyph_string (s)
4304 struct glyph_string *s;
4305{
4306 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4307 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4308 xassert (s->img);
43d120d8 4309 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4310 s->font = s->face->font;
4311 s->width = s->first_glyph->pixel_width;
4312
4313 /* Adjust base line for subscript/superscript text. */
4314 s->ybase += s->first_glyph->voffset;
4315}
4316
4317
209f68d9 4318/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4319
209f68d9
GM
4320 ROW is the glyph row in which the glyphs are found, AREA is the
4321 area within the row. START is the index of the first glyph to
4322 consider, END is the index of the last + 1.
4323
4324 Value is the index of the first glyph not in S. */
4325
4326static int
4327x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4328 struct glyph_string *s;
209f68d9
GM
4329 struct glyph_row *row;
4330 enum glyph_row_area area;
4331 int start, end;
06a2c219 4332{
209f68d9
GM
4333 struct glyph *glyph, *last;
4334 int voffset, face_id;
4335
06a2c219 4336 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4337
4338 glyph = s->row->glyphs[s->area] + start;
4339 last = s->row->glyphs[s->area] + end;
4340 face_id = glyph->face_id;
4341 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4342 s->font = s->face->font;
209f68d9
GM
4343 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4344 s->width = glyph->pixel_width;
4345 voffset = glyph->voffset;
4346
4347 for (++glyph;
4348 (glyph < last
4349 && glyph->type == STRETCH_GLYPH
4350 && glyph->voffset == voffset
4351 && glyph->face_id == face_id);
4352 ++glyph)
4353 s->width += glyph->pixel_width;
06a2c219
GM
4354
4355 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4356 s->ybase += voffset;
4357
4358 xassert (s->face && s->face->gc);
4359 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4360}
4361
4362
4363/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4364 of XChar2b structures for S; it can't be allocated in
4365 x_init_glyph_string because it must be allocated via `alloca'. W
4366 is the window on which S is drawn. ROW and AREA are the glyph row
4367 and area within the row from which S is constructed. START is the
4368 index of the first glyph structure covered by S. HL is a
4369 face-override for drawing S. */
4370
4371static void
4372x_init_glyph_string (s, char2b, w, row, area, start, hl)
4373 struct glyph_string *s;
4374 XChar2b *char2b;
4375 struct window *w;
4376 struct glyph_row *row;
4377 enum glyph_row_area area;
4378 int start;
4379 enum draw_glyphs_face hl;
4380{
4381 bzero (s, sizeof *s);
4382 s->w = w;
4383 s->f = XFRAME (w->frame);
4384 s->display = FRAME_X_DISPLAY (s->f);
4385 s->window = FRAME_X_WINDOW (s->f);
4386 s->char2b = char2b;
4387 s->hl = hl;
4388 s->row = row;
4389 s->area = area;
4390 s->first_glyph = row->glyphs[area] + start;
4391 s->height = row->height;
4392 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4393
9ea173e8
GM
4394 /* Display the internal border below the tool-bar window. */
4395 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4396 s->y -= s->f->output_data.x->internal_border_width;
4397
4398 s->ybase = s->y + row->ascent;
4399}
4400
4401
4402/* Set background width of glyph string S. START is the index of the
4403 first glyph following S. LAST_X is the right-most x-position + 1
4404 in the drawing area. */
4405
4406static INLINE void
4407x_set_glyph_string_background_width (s, start, last_x)
4408 struct glyph_string *s;
4409 int start;
4410 int last_x;
4411{
4412 /* If the face of this glyph string has to be drawn to the end of
4413 the drawing area, set S->extends_to_end_of_line_p. */
4414 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4415
4416 if (start == s->row->used[s->area]
4417 && s->hl == DRAW_NORMAL_TEXT
4418 && ((s->area == TEXT_AREA && s->row->fill_line_p)
4419 || s->face->background != default_face->background
4420 || s->face->stipple != default_face->stipple))
4421 s->extends_to_end_of_line_p = 1;
4422
4423 /* If S extends its face to the end of the line, set its
4424 background_width to the distance to the right edge of the drawing
4425 area. */
4426 if (s->extends_to_end_of_line_p)
1da3fd71 4427 s->background_width = last_x - s->x + 1;
06a2c219
GM
4428 else
4429 s->background_width = s->width;
4430}
4431
4432
4433/* Add a glyph string for a stretch glyph to the list of strings
4434 between HEAD and TAIL. START is the index of the stretch glyph in
4435 row area AREA of glyph row ROW. END is the index of the last glyph
4436 in that glyph row area. X is the current output position assigned
4437 to the new glyph string constructed. HL overrides that face of the
4438 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4439 is the right-most x-position of the drawing area. */
4440
8abee2e1
DL
4441/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4442 and below -- keep them on one line. */
4443#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4444 do \
4445 { \
4446 s = (struct glyph_string *) alloca (sizeof *s); \
4447 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4448 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4449 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4450 s->x = (X); \
4451 } \
4452 while (0)
4453
4454
4455/* Add a glyph string for an image glyph to the list of strings
4456 between HEAD and TAIL. START is the index of the image glyph in
4457 row area AREA of glyph row ROW. END is the index of the last glyph
4458 in that glyph row area. X is the current output position assigned
4459 to the new glyph string constructed. HL overrides that face of the
4460 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4461 is the right-most x-position of the drawing area. */
4462
8abee2e1 4463#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4464 do \
4465 { \
4466 s = (struct glyph_string *) alloca (sizeof *s); \
4467 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4468 x_fill_image_glyph_string (s); \
4469 x_append_glyph_string (&HEAD, &TAIL, s); \
4470 ++START; \
4471 s->x = (X); \
4472 } \
4473 while (0)
4474
4475
4476/* Add a glyph string for a sequence of character glyphs to the list
4477 of strings between HEAD and TAIL. START is the index of the first
4478 glyph in row area AREA of glyph row ROW that is part of the new
4479 glyph string. END is the index of the last glyph in that glyph row
4480 area. X is the current output position assigned to the new glyph
4481 string constructed. HL overrides that face of the glyph; e.g. it
4482 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4483 right-most x-position of the drawing area. */
4484
8abee2e1 4485#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4486 do \
4487 { \
3e71d8f2 4488 int c, face_id; \
06a2c219
GM
4489 XChar2b *char2b; \
4490 \
43d120d8 4491 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4492 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4493 \
b4192550
KH
4494 s = (struct glyph_string *) alloca (sizeof *s); \
4495 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4496 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4497 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4498 s->x = (X); \
4499 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4500 OVERLAPS_P); \
06a2c219
GM
4501 } \
4502 while (0)
4503
4504
b4192550
KH
4505/* Add a glyph string for a composite sequence to the list of strings
4506 between HEAD and TAIL. START is the index of the first glyph in
4507 row area AREA of glyph row ROW that is part of the new glyph
4508 string. END is the index of the last glyph in that glyph row area.
4509 X is the current output position assigned to the new glyph string
4510 constructed. HL overrides that face of the glyph; e.g. it is
4511 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4512 x-position of the drawing area. */
4513
6c27ec25 4514#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4515 do { \
43d120d8
KH
4516 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4517 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4518 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4519 struct composition *cmp = composition_table[cmp_id]; \
4520 int glyph_len = cmp->glyph_len; \
4521 XChar2b *char2b; \
4522 struct face **faces; \
4523 struct glyph_string *first_s = NULL; \
4524 int n; \
4525 \
ee569018 4526 base_face = base_face->ascii_face; \
b4192550
KH
4527 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4528 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4529 /* At first, fill in `char2b' and `faces'. */ \
4530 for (n = 0; n < glyph_len; n++) \
4531 { \
43d120d8 4532 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4533 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4534 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4535 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4536 this_face_id, char2b + n, 1); \
b4192550
KH
4537 } \
4538 \
4539 /* Make glyph_strings for each glyph sequence that is drawable by \
4540 the same face, and append them to HEAD/TAIL. */ \
4541 for (n = 0; n < cmp->glyph_len;) \
4542 { \
4543 s = (struct glyph_string *) alloca (sizeof *s); \
4544 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4545 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4546 s->cmp = cmp; \
4547 s->gidx = n; \
b4192550
KH
4548 s->x = (X); \
4549 \
4550 if (n == 0) \
4551 first_s = s; \
4552 \
4553 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4554 } \
4555 \
4556 ++START; \
4557 s = first_s; \
4558 } while (0)
4559
4560
06a2c219
GM
4561/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4562 of AREA of glyph row ROW on window W between indices START and END.
4563 HL overrides the face for drawing glyph strings, e.g. it is
4564 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4565 x-positions of the drawing area.
4566
4567 This is an ugly monster macro construct because we must use alloca
4568 to allocate glyph strings (because x_draw_glyphs can be called
4569 asynchronously). */
4570
8abee2e1 4571#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4572 do \
4573 { \
4574 HEAD = TAIL = NULL; \
4575 while (START < END) \
4576 { \
4577 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4578 switch (first_glyph->type) \
4579 { \
4580 case CHAR_GLYPH: \
4581 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4582 TAIL, HL, X, LAST_X, \
4583 OVERLAPS_P); \
06a2c219
GM
4584 break; \
4585 \
b4192550
KH
4586 case COMPOSITE_GLYPH: \
4587 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
4588 HEAD, TAIL, HL, X, LAST_X,\
4589 OVERLAPS_P); \
4590 break; \
4591 \
06a2c219
GM
4592 case STRETCH_GLYPH: \
4593 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
4594 HEAD, TAIL, HL, X, LAST_X); \
4595 break; \
4596 \
4597 case IMAGE_GLYPH: \
4598 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
4599 TAIL, HL, X, LAST_X); \
4600 break; \
4601 \
4602 default: \
4603 abort (); \
4604 } \
4605 \
4606 x_set_glyph_string_background_width (s, START, LAST_X); \
4607 (X) += s->width; \
4608 } \
4609 } \
4610 while (0)
4611
4612
4613/* Draw glyphs between START and END in AREA of ROW on window W,
4614 starting at x-position X. X is relative to AREA in W. HL is a
4615 face-override with the following meaning:
4616
4617 DRAW_NORMAL_TEXT draw normally
4618 DRAW_CURSOR draw in cursor face
4619 DRAW_MOUSE_FACE draw in mouse face.
4620 DRAW_INVERSE_VIDEO draw in mode line face
4621 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
4622 DRAW_IMAGE_RAISED draw an image with a raised relief around it
4623
4624 If REAL_START is non-null, return in *REAL_START the real starting
4625 position for display. This can be different from START in case
4626 overlapping glyphs must be displayed. If REAL_END is non-null,
4627 return in *REAL_END the real end position for display. This can be
4628 different from END in case overlapping glyphs must be displayed.
4629
66ac4b0e
GM
4630 If OVERLAPS_P is non-zero, draw only the foreground of characters
4631 and clip to the physical height of ROW.
4632
06a2c219
GM
4633 Value is the x-position reached, relative to AREA of W. */
4634
4635static int
66ac4b0e
GM
4636x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
4637 overlaps_p)
06a2c219
GM
4638 struct window *w;
4639 int x;
4640 struct glyph_row *row;
4641 enum glyph_row_area area;
4642 int start, end;
4643 enum draw_glyphs_face hl;
4644 int *real_start, *real_end;
66ac4b0e 4645 int overlaps_p;
dc6f92b8 4646{
06a2c219
GM
4647 struct glyph_string *head, *tail;
4648 struct glyph_string *s;
4649 int last_x, area_width;
4650 int x_reached;
4651 int i, j;
4652
4653 /* Let's rather be paranoid than getting a SEGV. */
4654 start = max (0, start);
4655 end = min (end, row->used[area]);
4656 if (real_start)
4657 *real_start = start;
4658 if (real_end)
4659 *real_end = end;
4660
4661 /* Translate X to frame coordinates. Set last_x to the right
4662 end of the drawing area. */
4663 if (row->full_width_p)
4664 {
4665 /* X is relative to the left edge of W, without scroll bars
4666 or flag areas. */
4667 struct frame *f = XFRAME (w->frame);
110859fc 4668 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 4669 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 4670
06a2c219
GM
4671 x += window_left_x;
4672 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
4673 last_x = window_left_x + area_width;
4674
4675 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4676 {
110859fc 4677 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
4678 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
4679 last_x += width;
4680 else
4681 x -= width;
4682 }
dc6f92b8 4683
b9432a85
GM
4684 x += FRAME_INTERNAL_BORDER_WIDTH (f);
4685 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
4686 }
4687 else
dc6f92b8 4688 {
06a2c219
GM
4689 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
4690 area_width = window_box_width (w, area);
4691 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
4692 }
4693
06a2c219
GM
4694 /* Build a doubly-linked list of glyph_string structures between
4695 head and tail from what we have to draw. Note that the macro
4696 BUILD_GLYPH_STRINGS will modify its start parameter. That's
4697 the reason we use a separate variable `i'. */
4698 i = start;
66ac4b0e
GM
4699 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
4700 overlaps_p);
06a2c219
GM
4701 if (tail)
4702 x_reached = tail->x + tail->background_width;
4703 else
4704 x_reached = x;
90e65f07 4705
06a2c219
GM
4706 /* If there are any glyphs with lbearing < 0 or rbearing > width in
4707 the row, redraw some glyphs in front or following the glyph
4708 strings built above. */
66ac4b0e 4709 if (!overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
4710 {
4711 int dummy_x = 0;
4712 struct glyph_string *h, *t;
4713
4714 /* Compute overhangs for all glyph strings. */
4715 for (s = head; s; s = s->next)
4716 x_compute_glyph_string_overhangs (s);
4717
4718 /* Prepend glyph strings for glyphs in front of the first glyph
4719 string that are overwritten because of the first glyph
4720 string's left overhang. The background of all strings
4721 prepended must be drawn because the first glyph string
4722 draws over it. */
4723 i = x_left_overwritten (head);
4724 if (i >= 0)
4725 {
4726 j = i;
4727 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
4728 DRAW_NORMAL_TEXT, dummy_x, last_x,
4729 overlaps_p);
06a2c219
GM
4730 start = i;
4731 if (real_start)
4732 *real_start = start;
4733 x_compute_overhangs_and_x (t, head->x, 1);
4734 x_prepend_glyph_string_lists (&head, &tail, h, t);
4735 }
58769bee 4736
06a2c219
GM
4737 /* Prepend glyph strings for glyphs in front of the first glyph
4738 string that overwrite that glyph string because of their
4739 right overhang. For these strings, only the foreground must
4740 be drawn, because it draws over the glyph string at `head'.
4741 The background must not be drawn because this would overwrite
4742 right overhangs of preceding glyphs for which no glyph
4743 strings exist. */
4744 i = x_left_overwriting (head);
4745 if (i >= 0)
4746 {
4747 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
4748 DRAW_NORMAL_TEXT, dummy_x, last_x,
4749 overlaps_p);
06a2c219
GM
4750 for (s = h; s; s = s->next)
4751 s->background_filled_p = 1;
4752 if (real_start)
4753 *real_start = i;
4754 x_compute_overhangs_and_x (t, head->x, 1);
4755 x_prepend_glyph_string_lists (&head, &tail, h, t);
4756 }
dbcb258a 4757
06a2c219
GM
4758 /* Append glyphs strings for glyphs following the last glyph
4759 string tail that are overwritten by tail. The background of
4760 these strings has to be drawn because tail's foreground draws
4761 over it. */
4762 i = x_right_overwritten (tail);
4763 if (i >= 0)
4764 {
4765 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4766 DRAW_NORMAL_TEXT, x, last_x,
4767 overlaps_p);
06a2c219
GM
4768 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4769 x_append_glyph_string_lists (&head, &tail, h, t);
4770 if (real_end)
4771 *real_end = i;
4772 }
dc6f92b8 4773
06a2c219
GM
4774 /* Append glyph strings for glyphs following the last glyph
4775 string tail that overwrite tail. The foreground of such
4776 glyphs has to be drawn because it writes into the background
4777 of tail. The background must not be drawn because it could
4778 paint over the foreground of following glyphs. */
4779 i = x_right_overwriting (tail);
4780 if (i >= 0)
4781 {
4782 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4783 DRAW_NORMAL_TEXT, x, last_x,
4784 overlaps_p);
06a2c219
GM
4785 for (s = h; s; s = s->next)
4786 s->background_filled_p = 1;
4787 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4788 x_append_glyph_string_lists (&head, &tail, h, t);
4789 if (real_end)
4790 *real_end = i;
4791 }
4792 }
58769bee 4793
06a2c219
GM
4794 /* Draw all strings. */
4795 for (s = head; s; s = s->next)
4796 x_draw_glyph_string (s);
dc6f92b8 4797
06a2c219
GM
4798 /* Value is the x-position up to which drawn, relative to AREA of W.
4799 This doesn't include parts drawn because of overhangs. */
4800 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
4801 if (!row->full_width_p)
4802 {
4803 if (area > LEFT_MARGIN_AREA)
4804 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
4805 if (area > TEXT_AREA)
4806 x_reached -= window_box_width (w, TEXT_AREA);
4807 }
4808 return x_reached;
4809}
dc6f92b8 4810
dc6f92b8 4811
66ac4b0e
GM
4812/* Fix the display of area AREA of overlapping row ROW in window W. */
4813
4814static void
4815x_fix_overlapping_area (w, row, area)
4816 struct window *w;
4817 struct glyph_row *row;
4818 enum glyph_row_area area;
4819{
4820 int i, x;
4821
4822 BLOCK_INPUT;
4823
4824 if (area == LEFT_MARGIN_AREA)
4825 x = 0;
4826 else if (area == TEXT_AREA)
4827 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
4828 else
4829 x = (window_box_width (w, LEFT_MARGIN_AREA)
4830 + window_box_width (w, TEXT_AREA));
4831
4832 for (i = 0; i < row->used[area];)
4833 {
4834 if (row->glyphs[area][i].overlaps_vertically_p)
4835 {
4836 int start = i, start_x = x;
4837
4838 do
4839 {
4840 x += row->glyphs[area][i].pixel_width;
4841 ++i;
4842 }
4843 while (i < row->used[area]
4844 && row->glyphs[area][i].overlaps_vertically_p);
4845
4846 x_draw_glyphs (w, start_x, row, area, start, i,
4847 (row->inverse_p
4848 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
4849 NULL, NULL, 1);
4850 }
4851 else
4852 {
4853 x += row->glyphs[area][i].pixel_width;
4854 ++i;
4855 }
4856 }
4857
4858 UNBLOCK_INPUT;
4859}
4860
4861
06a2c219
GM
4862/* Output LEN glyphs starting at START at the nominal cursor position.
4863 Advance the nominal cursor over the text. The global variable
4864 updated_window contains the window being updated, updated_row is
4865 the glyph row being updated, and updated_area is the area of that
4866 row being updated. */
dc6f92b8 4867
06a2c219
GM
4868static void
4869x_write_glyphs (start, len)
4870 struct glyph *start;
4871 int len;
4872{
4873 int x, hpos, real_start, real_end;
d9cdbb3d 4874
06a2c219 4875 xassert (updated_window && updated_row);
dc6f92b8 4876 BLOCK_INPUT;
06a2c219
GM
4877
4878 /* Write glyphs. */
dc6f92b8 4879
06a2c219
GM
4880 hpos = start - updated_row->glyphs[updated_area];
4881 x = x_draw_glyphs (updated_window, output_cursor.x,
4882 updated_row, updated_area,
4883 hpos, hpos + len,
4884 (updated_row->inverse_p
4885 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
66ac4b0e 4886 &real_start, &real_end, 0);
b30ec466 4887
06a2c219
GM
4888 /* If we drew over the cursor, note that it is not visible any more. */
4889 note_overwritten_text_cursor (updated_window, real_start,
4890 real_end - real_start);
dc6f92b8
JB
4891
4892 UNBLOCK_INPUT;
06a2c219
GM
4893
4894 /* Advance the output cursor. */
4895 output_cursor.hpos += len;
4896 output_cursor.x = x;
dc6f92b8
JB
4897}
4898
0cdd0c9f 4899
06a2c219 4900/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 4901
06a2c219
GM
4902static void
4903x_insert_glyphs (start, len)
4904 struct glyph *start;
4905 register int len;
4906{
4907 struct frame *f;
4908 struct window *w;
4909 int line_height, shift_by_width, shifted_region_width;
4910 struct glyph_row *row;
4911 struct glyph *glyph;
4912 int frame_x, frame_y, hpos, real_start, real_end;
58769bee 4913
06a2c219 4914 xassert (updated_window && updated_row);
0cdd0c9f 4915 BLOCK_INPUT;
06a2c219
GM
4916 w = updated_window;
4917 f = XFRAME (WINDOW_FRAME (w));
4918
4919 /* Get the height of the line we are in. */
4920 row = updated_row;
4921 line_height = row->height;
4922
4923 /* Get the width of the glyphs to insert. */
4924 shift_by_width = 0;
4925 for (glyph = start; glyph < start + len; ++glyph)
4926 shift_by_width += glyph->pixel_width;
4927
4928 /* Get the width of the region to shift right. */
4929 shifted_region_width = (window_box_width (w, updated_area)
4930 - output_cursor.x
4931 - shift_by_width);
4932
4933 /* Shift right. */
4934 frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x);
4935 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
4936 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
4937 f->output_data.x->normal_gc,
4938 frame_x, frame_y,
4939 shifted_region_width, line_height,
4940 frame_x + shift_by_width, frame_y);
4941
4942 /* Write the glyphs. */
4943 hpos = start - row->glyphs[updated_area];
4944 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
66ac4b0e 4945 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
06a2c219
GM
4946 note_overwritten_text_cursor (w, real_start, real_end - real_start);
4947
4948 /* Advance the output cursor. */
4949 output_cursor.hpos += len;
4950 output_cursor.x += shift_by_width;
0cdd0c9f
RS
4951 UNBLOCK_INPUT;
4952}
0cdd0c9f 4953
0cdd0c9f 4954
06a2c219
GM
4955/* Delete N glyphs at the nominal cursor position. Not implemented
4956 for X frames. */
c83febd7
RS
4957
4958static void
06a2c219
GM
4959x_delete_glyphs (n)
4960 register int n;
c83febd7 4961{
06a2c219 4962 abort ();
c83febd7
RS
4963}
4964
0cdd0c9f 4965
06a2c219
GM
4966/* Erase the current text line from the nominal cursor position
4967 (inclusive) to pixel column TO_X (exclusive). The idea is that
4968 everything from TO_X onward is already erased.
4969
4970 TO_X is a pixel position relative to updated_area of
4971 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 4972
06a2c219
GM
4973static void
4974x_clear_end_of_line (to_x)
4975 int to_x;
4976{
4977 struct frame *f;
4978 struct window *w = updated_window;
4979 int max_x, min_y, max_y;
4980 int from_x, from_y, to_y;
4981
4982 xassert (updated_window && updated_row);
4983 f = XFRAME (w->frame);
4984
4985 if (updated_row->full_width_p)
4986 {
4987 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
4988 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4989 && !w->pseudo_window_p)
4990 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 4991 }
06a2c219
GM
4992 else
4993 max_x = window_box_width (w, updated_area);
4994 max_y = window_text_bottom_y (w);
dc6f92b8 4995
06a2c219
GM
4996 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
4997 of window. For TO_X > 0, truncate to end of drawing area. */
4998 if (to_x == 0)
4999 return;
5000 else if (to_x < 0)
5001 to_x = max_x;
5002 else
5003 to_x = min (to_x, max_x);
dbc4e1c1 5004
06a2c219
GM
5005 to_y = min (max_y, output_cursor.y + updated_row->height);
5006
5007 /* Notice if the cursor will be cleared by this operation. */
5008 if (!updated_row->full_width_p)
5009 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
dbc4e1c1 5010
06a2c219
GM
5011 from_x = output_cursor.x;
5012
5013 /* Translate to frame coordinates. */
5014 if (updated_row->full_width_p)
5015 {
5016 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5017 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5018 }
0cdd0c9f
RS
5019 else
5020 {
06a2c219
GM
5021 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5022 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5023 }
5024
045dee35 5025 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5026 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5027 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5028
5029 /* Prevent inadvertently clearing to end of the X window. */
5030 if (to_x > from_x && to_y > from_y)
5031 {
5032 BLOCK_INPUT;
5033 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5034 from_x, from_y, to_x - from_x, to_y - from_y,
5035 False);
5036 UNBLOCK_INPUT;
0cdd0c9f 5037 }
0cdd0c9f 5038}
dbc4e1c1 5039
0cdd0c9f 5040
06a2c219 5041/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5042 frame. Otherwise clear the selected frame. */
06a2c219
GM
5043
5044static void
5045x_clear_frame ()
0cdd0c9f 5046{
06a2c219 5047 struct frame *f;
0cdd0c9f 5048
06a2c219
GM
5049 if (updating_frame)
5050 f = updating_frame;
0cdd0c9f 5051 else
b86bd3dd 5052 f = SELECTED_FRAME ();
58769bee 5053
06a2c219
GM
5054 /* Clearing the frame will erase any cursor, so mark them all as no
5055 longer visible. */
5056 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5057 output_cursor.hpos = output_cursor.vpos = 0;
5058 output_cursor.x = -1;
5059
5060 /* We don't set the output cursor here because there will always
5061 follow an explicit cursor_to. */
5062 BLOCK_INPUT;
5063 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5064
5065 /* We have to clear the scroll bars, too. If we have changed
5066 colors or something like that, then they should be notified. */
5067 x_scroll_bar_clear (f);
0cdd0c9f 5068
06a2c219
GM
5069 XFlush (FRAME_X_DISPLAY (f));
5070 UNBLOCK_INPUT;
dc6f92b8 5071}
06a2c219
GM
5072
5073
dc6f92b8 5074\f
dbc4e1c1
JB
5075/* Invert the middle quarter of the frame for .15 sec. */
5076
06a2c219
GM
5077/* We use the select system call to do the waiting, so we have to make
5078 sure it's available. If it isn't, we just won't do visual bells. */
5079
dbc4e1c1
JB
5080#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5081
06a2c219
GM
5082
5083/* Subtract the `struct timeval' values X and Y, storing the result in
5084 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5085
5086static int
5087timeval_subtract (result, x, y)
5088 struct timeval *result, x, y;
5089{
06a2c219
GM
5090 /* Perform the carry for the later subtraction by updating y. This
5091 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5092 if (x.tv_usec < y.tv_usec)
5093 {
5094 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5095 y.tv_usec -= 1000000 * nsec;
5096 y.tv_sec += nsec;
5097 }
06a2c219 5098
dbc4e1c1
JB
5099 if (x.tv_usec - y.tv_usec > 1000000)
5100 {
5101 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5102 y.tv_usec += 1000000 * nsec;
5103 y.tv_sec -= nsec;
5104 }
5105
06a2c219
GM
5106 /* Compute the time remaining to wait. tv_usec is certainly
5107 positive. */
dbc4e1c1
JB
5108 result->tv_sec = x.tv_sec - y.tv_sec;
5109 result->tv_usec = x.tv_usec - y.tv_usec;
5110
06a2c219
GM
5111 /* Return indication of whether the result should be considered
5112 negative. */
dbc4e1c1
JB
5113 return x.tv_sec < y.tv_sec;
5114}
dc6f92b8 5115
dfcf069d 5116void
f676886a
JB
5117XTflash (f)
5118 struct frame *f;
dc6f92b8 5119{
dbc4e1c1 5120 BLOCK_INPUT;
dc6f92b8 5121
dbc4e1c1
JB
5122 {
5123 GC gc;
dc6f92b8 5124
06a2c219
GM
5125 /* Create a GC that will use the GXxor function to flip foreground
5126 pixels into background pixels. */
dbc4e1c1
JB
5127 {
5128 XGCValues values;
dc6f92b8 5129
dbc4e1c1 5130 values.function = GXxor;
7556890b
RS
5131 values.foreground = (f->output_data.x->foreground_pixel
5132 ^ f->output_data.x->background_pixel);
58769bee 5133
334208b7 5134 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5135 GCFunction | GCForeground, &values);
5136 }
dc6f92b8 5137
dbc4e1c1 5138 {
e84e14c3
RS
5139 /* Get the height not including a menu bar widget. */
5140 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5141 /* Height of each line to flash. */
5142 int flash_height = FRAME_LINE_HEIGHT (f);
5143 /* These will be the left and right margins of the rectangles. */
5144 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5145 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5146
5147 int width;
5148
5149 /* Don't flash the area between a scroll bar and the frame
5150 edge it is next to. */
5151 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5152 {
5153 case vertical_scroll_bar_left:
5154 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5155 break;
5156
5157 case vertical_scroll_bar_right:
5158 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5159 break;
06a2c219
GM
5160
5161 default:
5162 break;
e84e14c3
RS
5163 }
5164
5165 width = flash_right - flash_left;
5166
5167 /* If window is tall, flash top and bottom line. */
5168 if (height > 3 * FRAME_LINE_HEIGHT (f))
5169 {
5170 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5171 flash_left,
5172 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5173 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5174 width, flash_height);
5175 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5176 flash_left,
5177 (height - flash_height
5178 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5179 width, flash_height);
5180 }
5181 else
5182 /* If it is short, flash it all. */
5183 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5184 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5185 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5186
06a2c219 5187 x_flush (f);
dc6f92b8 5188
dbc4e1c1 5189 {
06a2c219 5190 struct timeval wakeup;
dc6f92b8 5191
66c30ea1 5192 EMACS_GET_TIME (wakeup);
dc6f92b8 5193
dbc4e1c1
JB
5194 /* Compute time to wait until, propagating carry from usecs. */
5195 wakeup.tv_usec += 150000;
5196 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5197 wakeup.tv_usec %= 1000000;
5198
5199 /* Keep waiting until past the time wakeup. */
5200 while (1)
5201 {
5202 struct timeval timeout;
5203
66c30ea1 5204 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
5205
5206 /* In effect, timeout = wakeup - timeout.
5207 Break if result would be negative. */
5208 if (timeval_subtract (&timeout, wakeup, timeout))
5209 break;
5210
5211 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5212 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5213 }
5214 }
58769bee 5215
e84e14c3
RS
5216 /* If window is tall, flash top and bottom line. */
5217 if (height > 3 * FRAME_LINE_HEIGHT (f))
5218 {
5219 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5220 flash_left,
5221 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5222 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5223 width, flash_height);
5224 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5225 flash_left,
5226 (height - flash_height
5227 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5228 width, flash_height);
5229 }
5230 else
5231 /* If it is short, flash it all. */
5232 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5233 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5234 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5235
334208b7 5236 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5237 x_flush (f);
dc6f92b8 5238 }
dbc4e1c1
JB
5239 }
5240
5241 UNBLOCK_INPUT;
dc6f92b8
JB
5242}
5243
06a2c219 5244#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5245
5246
dc6f92b8
JB
5247/* Make audible bell. */
5248
dfcf069d 5249void
dc6f92b8
JB
5250XTring_bell ()
5251{
b86bd3dd
GM
5252 struct frame *f = SELECTED_FRAME ();
5253
5254 if (FRAME_X_DISPLAY (f))
5255 {
dbc4e1c1 5256#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5257 if (visible_bell)
5258 XTflash (f);
5259 else
dbc4e1c1 5260#endif
b86bd3dd
GM
5261 {
5262 BLOCK_INPUT;
5263 XBell (FRAME_X_DISPLAY (f), 0);
5264 XFlush (FRAME_X_DISPLAY (f));
5265 UNBLOCK_INPUT;
5266 }
dc6f92b8
JB
5267 }
5268}
06a2c219 5269
dc6f92b8 5270\f
06a2c219
GM
5271/* Specify how many text lines, from the top of the window,
5272 should be affected by insert-lines and delete-lines operations.
5273 This, and those operations, are used only within an update
5274 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5275
dfcf069d 5276static void
06a2c219
GM
5277XTset_terminal_window (n)
5278 register int n;
dc6f92b8 5279{
06a2c219 5280 /* This function intentionally left blank. */
dc6f92b8
JB
5281}
5282
06a2c219
GM
5283
5284\f
5285/***********************************************************************
5286 Line Dance
5287 ***********************************************************************/
5288
5289/* Perform an insert-lines or delete-lines operation, inserting N
5290 lines or deleting -N lines at vertical position VPOS. */
5291
dfcf069d 5292static void
06a2c219
GM
5293x_ins_del_lines (vpos, n)
5294 int vpos, n;
dc6f92b8
JB
5295{
5296 abort ();
5297}
06a2c219
GM
5298
5299
5300/* Scroll part of the display as described by RUN. */
dc6f92b8 5301
dfcf069d 5302static void
06a2c219
GM
5303x_scroll_run (w, run)
5304 struct window *w;
5305 struct run *run;
dc6f92b8 5306{
06a2c219
GM
5307 struct frame *f = XFRAME (w->frame);
5308 int x, y, width, height, from_y, to_y, bottom_y;
5309
5310 /* Get frame-relative bounding box of the text display area of W,
5311 without mode lines. Include in this box the flags areas to the
5312 left and right of W. */
5313 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5314 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5315 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5316
5317 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5318 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5319 bottom_y = y + height;
dc6f92b8 5320
06a2c219
GM
5321 if (to_y < from_y)
5322 {
5323 /* Scrolling up. Make sure we don't copy part of the mode
5324 line at the bottom. */
5325 if (from_y + run->height > bottom_y)
5326 height = bottom_y - from_y;
5327 else
5328 height = run->height;
5329 }
dc6f92b8 5330 else
06a2c219
GM
5331 {
5332 /* Scolling down. Make sure we don't copy over the mode line.
5333 at the bottom. */
5334 if (to_y + run->height > bottom_y)
5335 height = bottom_y - to_y;
5336 else
5337 height = run->height;
5338 }
7a13e894 5339
06a2c219
GM
5340 BLOCK_INPUT;
5341
5342 /* Cursor off. Will be switched on again in x_update_window_end. */
5343 updated_window = w;
5344 x_clear_cursor (w);
5345
5346 XCopyArea (FRAME_X_DISPLAY (f),
5347 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5348 f->output_data.x->normal_gc,
5349 x, from_y,
5350 width, height,
5351 x, to_y);
5352
5353 UNBLOCK_INPUT;
5354}
dc6f92b8 5355
dc6f92b8 5356
06a2c219
GM
5357\f
5358/***********************************************************************
5359 Exposure Events
5360 ***********************************************************************/
5361
5362/* Redisplay an exposed area of frame F. X and Y are the upper-left
5363 corner of the exposed rectangle. W and H are width and height of
5364 the exposed area. All are pixel values. W or H zero means redraw
5365 the entire frame. */
dc6f92b8 5366
06a2c219
GM
5367static void
5368expose_frame (f, x, y, w, h)
5369 struct frame *f;
5370 int x, y, w, h;
dc6f92b8 5371{
06a2c219 5372 XRectangle r;
dc6f92b8 5373
06a2c219 5374 TRACE ((stderr, "expose_frame "));
dc6f92b8 5375
06a2c219
GM
5376 /* No need to redraw if frame will be redrawn soon. */
5377 if (FRAME_GARBAGED_P (f))
dc6f92b8 5378 {
06a2c219
GM
5379 TRACE ((stderr, " garbaged\n"));
5380 return;
5381 }
5382
5383 /* If basic faces haven't been realized yet, there is no point in
5384 trying to redraw anything. This can happen when we get an expose
5385 event while Emacs is starting, e.g. by moving another window. */
5386 if (FRAME_FACE_CACHE (f) == NULL
5387 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5388 {
5389 TRACE ((stderr, " no faces\n"));
5390 return;
58769bee 5391 }
06a2c219
GM
5392
5393 if (w == 0 || h == 0)
58769bee 5394 {
06a2c219
GM
5395 r.x = r.y = 0;
5396 r.width = CANON_X_UNIT (f) * f->width;
5397 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5398 }
5399 else
5400 {
06a2c219
GM
5401 r.x = x;
5402 r.y = y;
5403 r.width = w;
5404 r.height = h;
5405 }
5406
5407 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
5408 expose_window_tree (XWINDOW (f->root_window), &r);
5409
9ea173e8 5410 if (WINDOWP (f->tool_bar_window))
06a2c219 5411 {
9ea173e8 5412 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
5413 XRectangle window_rect;
5414 XRectangle intersection_rect;
5415 int window_x, window_y, window_width, window_height;
5416
5417
5418 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5419 window_rect.x = window_x;
5420 window_rect.y = window_y;
5421 window_rect.width = window_width;
5422 window_rect.height = window_height;
5423
5424 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5425 expose_window (w, &intersection_rect);
5426 }
5427
5428#ifndef USE_X_TOOLKIT
5429 if (WINDOWP (f->menu_bar_window))
5430 {
5431 struct window *w = XWINDOW (f->menu_bar_window);
5432 XRectangle window_rect;
5433 XRectangle intersection_rect;
5434 int window_x, window_y, window_width, window_height;
5435
5436
5437 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5438 window_rect.x = window_x;
5439 window_rect.y = window_y;
5440 window_rect.width = window_width;
5441 window_rect.height = window_height;
5442
5443 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5444 expose_window (w, &intersection_rect);
dc6f92b8 5445 }
06a2c219 5446#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5447}
5448
06a2c219
GM
5449
5450/* Redraw (parts) of all windows in the window tree rooted at W that
5451 intersect R. R contains frame pixel coordinates. */
5452
58769bee 5453static void
06a2c219
GM
5454expose_window_tree (w, r)
5455 struct window *w;
5456 XRectangle *r;
dc6f92b8 5457{
06a2c219
GM
5458 while (w)
5459 {
5460 if (!NILP (w->hchild))
5461 expose_window_tree (XWINDOW (w->hchild), r);
5462 else if (!NILP (w->vchild))
5463 expose_window_tree (XWINDOW (w->vchild), r);
5464 else
5465 {
5466 XRectangle window_rect;
5467 XRectangle intersection_rect;
5468 struct frame *f = XFRAME (w->frame);
5469 int window_x, window_y, window_width, window_height;
5470
5471 /* Frame-relative pixel rectangle of W. */
5472 window_box (w, -1, &window_x, &window_y, &window_width,
5473 &window_height);
5474 window_rect.x
5475 = (window_x
110859fc 5476 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
714dc26c 5477 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
06a2c219
GM
5478 window_rect.y = window_y;
5479 window_rect.width
5480 = (window_width
110859fc 5481 + FRAME_X_FLAGS_AREA_WIDTH (f)
06a2c219
GM
5482 + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
5483 window_rect.height
5484 = window_height + CURRENT_MODE_LINE_HEIGHT (w);
5485
5486 if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
5487 expose_window (w, &intersection_rect);
5488 }
58769bee 5489
06a2c219
GM
5490 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5491 }
5492}
58769bee 5493
dc6f92b8 5494
06a2c219
GM
5495/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5496 which intersects rectangle R. R is in window-relative coordinates. */
5497
5498static void
5499expose_area (w, row, r, area)
5500 struct window *w;
5501 struct glyph_row *row;
5502 XRectangle *r;
5503 enum glyph_row_area area;
5504{
5505 int x;
5506 struct glyph *first = row->glyphs[area];
5507 struct glyph *end = row->glyphs[area] + row->used[area];
5508 struct glyph *last;
5509 int first_x;
5510
5511 /* Set x to the window-relative start position for drawing glyphs of
5512 AREA. The first glyph of the text area can be partially visible.
5513 The first glyphs of other areas cannot. */
5514 if (area == LEFT_MARGIN_AREA)
5515 x = 0;
5516 else if (area == TEXT_AREA)
5517 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5518 else
5519 x = (window_box_width (w, LEFT_MARGIN_AREA)
5520 + window_box_width (w, TEXT_AREA));
5521
6fb13182
GM
5522 if (area == TEXT_AREA && row->fill_line_p)
5523 /* If row extends face to end of line write the whole line. */
5524 x_draw_glyphs (w, x, row, area,
5525 0, row->used[area],
06a2c219 5526 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5527 NULL, NULL, 0);
6fb13182
GM
5528 else
5529 {
5530 /* Find the first glyph that must be redrawn. */
5531 while (first < end
5532 && x + first->pixel_width < r->x)
5533 {
5534 x += first->pixel_width;
5535 ++first;
5536 }
5537
5538 /* Find the last one. */
5539 last = first;
5540 first_x = x;
5541 while (last < end
5542 && x < r->x + r->width)
5543 {
5544 x += last->pixel_width;
5545 ++last;
5546 }
5547
5548 /* Repaint. */
5549 if (last > first)
5550 x_draw_glyphs (w, first_x, row, area,
5551 first - row->glyphs[area],
5552 last - row->glyphs[area],
5553 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5554 NULL, NULL, 0);
5555 }
06a2c219
GM
5556}
5557
58769bee 5558
06a2c219
GM
5559/* Redraw the parts of the glyph row ROW on window W intersecting
5560 rectangle R. R is in window-relative coordinates. */
dc6f92b8 5561
06a2c219
GM
5562static void
5563expose_line (w, row, r)
5564 struct window *w;
5565 struct glyph_row *row;
5566 XRectangle *r;
5567{
5568 xassert (row->enabled_p);
5569
5570 if (row->mode_line_p || w->pseudo_window_p)
5571 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5572 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5573 NULL, NULL, 0);
06a2c219
GM
5574 else
5575 {
5576 if (row->used[LEFT_MARGIN_AREA])
5577 expose_area (w, row, r, LEFT_MARGIN_AREA);
5578 if (row->used[TEXT_AREA])
5579 expose_area (w, row, r, TEXT_AREA);
5580 if (row->used[RIGHT_MARGIN_AREA])
5581 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5582 x_draw_row_bitmaps (w, row);
5583 }
5584}
dc6f92b8 5585
58769bee 5586
06a2c219
GM
5587/* Return non-zero if W's cursor intersects rectangle R. */
5588
5589static int
5590x_phys_cursor_in_rect_p (w, r)
5591 struct window *w;
5592 XRectangle *r;
5593{
5594 XRectangle cr, result;
5595 struct glyph *cursor_glyph;
5596
5597 cursor_glyph = get_phys_cursor_glyph (w);
5598 if (cursor_glyph)
5599 {
5600 cr.x = w->phys_cursor.x;
5601 cr.y = w->phys_cursor.y;
5602 cr.width = cursor_glyph->pixel_width;
5603 cr.height = w->phys_cursor_height;
5604 return x_intersect_rectangles (&cr, r, &result);
5605 }
5606 else
5607 return 0;
dc6f92b8 5608}
dc6f92b8 5609
06a2c219
GM
5610
5611/* Redraw a rectangle of window W. R is a rectangle in window
5612 relative coordinates. Call this function with input blocked. */
dc6f92b8
JB
5613
5614static void
06a2c219
GM
5615expose_window (w, r)
5616 struct window *w;
5617 XRectangle *r;
dc6f92b8 5618{
06a2c219
GM
5619 struct glyph_row *row;
5620 int y;
5621 int yb = window_text_bottom_y (w);
5622 int cursor_cleared_p;
dc6f92b8 5623
80c32bcc
GM
5624 /* If window is not yet fully initialized, do nothing. This can
5625 happen when toolkit scroll bars are used and a window is split.
5626 Reconfiguring the scroll bar will generate an expose for a newly
5627 created window. */
5628 if (w->current_matrix == NULL)
5629 return;
5630
06a2c219
GM
5631 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
5632 r->x, r->y, r->width, r->height));
dc6f92b8 5633
06a2c219
GM
5634 /* Convert to window coordinates. */
5635 r->x = FRAME_TO_WINDOW_PIXEL_X (w, r->x);
5636 r->y = FRAME_TO_WINDOW_PIXEL_Y (w, r->y);
dc6f92b8 5637
06a2c219
GM
5638 /* Turn off the cursor. */
5639 if (!w->pseudo_window_p
5640 && x_phys_cursor_in_rect_p (w, r))
5641 {
5642 x_clear_cursor (w);
5643 cursor_cleared_p = 1;
5644 }
5645 else
5646 cursor_cleared_p = 0;
5647
5648 /* Find the first row intersecting the rectangle R. */
5649 row = w->current_matrix->rows;
5650 y = 0;
5651 while (row->enabled_p
5652 && y < yb
5653 && y + row->height < r->y)
5654 {
5655 y += row->height;
5656 ++row;
5657 }
5658
dc6f92b8 5659 /* Display the text in the rectangle, one text line at a time. */
06a2c219
GM
5660 while (row->enabled_p
5661 && y < yb
5662 && y < r->y + r->height)
5663 {
5664 expose_line (w, row, r);
5665 y += row->height;
5666 ++row;
5667 }
5668
5669 /* Display the mode line if there is one. */
5670 if (WINDOW_WANTS_MODELINE_P (w)
5671 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
5672 row->enabled_p)
5673 && row->y < r->y + r->height)
5674 expose_line (w, row, r);
dc6f92b8 5675
06a2c219 5676 if (!w->pseudo_window_p)
dc6f92b8 5677 {
06a2c219
GM
5678 /* Draw border between windows. */
5679 x_draw_vertical_border (w);
5680
5681 /* Turn the cursor on again. */
5682 if (cursor_cleared_p)
5683 x_update_window_cursor (w, 1);
5684 }
5685}
dc6f92b8 5686
dc6f92b8 5687
06a2c219
GM
5688/* Determine the intersection of two rectangles R1 and R2. Return
5689 the intersection in *RESULT. Value is non-zero if RESULT is not
5690 empty. */
5691
5692static int
5693x_intersect_rectangles (r1, r2, result)
5694 XRectangle *r1, *r2, *result;
5695{
5696 XRectangle *left, *right;
5697 XRectangle *upper, *lower;
5698 int intersection_p = 0;
5699
5700 /* Rearrange so that R1 is the left-most rectangle. */
5701 if (r1->x < r2->x)
5702 left = r1, right = r2;
5703 else
5704 left = r2, right = r1;
5705
5706 /* X0 of the intersection is right.x0, if this is inside R1,
5707 otherwise there is no intersection. */
5708 if (right->x <= left->x + left->width)
5709 {
5710 result->x = right->x;
5711
5712 /* The right end of the intersection is the minimum of the
5713 the right ends of left and right. */
5714 result->width = (min (left->x + left->width, right->x + right->width)
5715 - result->x);
5716
5717 /* Same game for Y. */
5718 if (r1->y < r2->y)
5719 upper = r1, lower = r2;
5720 else
5721 upper = r2, lower = r1;
5722
5723 /* The upper end of the intersection is lower.y0, if this is inside
5724 of upper. Otherwise, there is no intersection. */
5725 if (lower->y <= upper->y + upper->height)
dc43ef94 5726 {
06a2c219
GM
5727 result->y = lower->y;
5728
5729 /* The lower end of the intersection is the minimum of the lower
5730 ends of upper and lower. */
5731 result->height = (min (lower->y + lower->height,
5732 upper->y + upper->height)
5733 - result->y);
5734 intersection_p = 1;
dc43ef94 5735 }
dc6f92b8
JB
5736 }
5737
06a2c219 5738 return intersection_p;
dc6f92b8 5739}
06a2c219
GM
5740
5741
5742
5743
dc6f92b8 5744\f
dc6f92b8 5745static void
334208b7
RS
5746frame_highlight (f)
5747 struct frame *f;
dc6f92b8 5748{
b3e1e05c
JB
5749 /* We used to only do this if Vx_no_window_manager was non-nil, but
5750 the ICCCM (section 4.1.6) says that the window's border pixmap
5751 and border pixel are window attributes which are "private to the
5752 client", so we can always change it to whatever we want. */
5753 BLOCK_INPUT;
334208b7 5754 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5755 f->output_data.x->border_pixel);
b3e1e05c 5756 UNBLOCK_INPUT;
5d46f928 5757 x_update_cursor (f, 1);
dc6f92b8
JB
5758}
5759
5760static void
334208b7
RS
5761frame_unhighlight (f)
5762 struct frame *f;
dc6f92b8 5763{
b3e1e05c
JB
5764 /* We used to only do this if Vx_no_window_manager was non-nil, but
5765 the ICCCM (section 4.1.6) says that the window's border pixmap
5766 and border pixel are window attributes which are "private to the
5767 client", so we can always change it to whatever we want. */
5768 BLOCK_INPUT;
334208b7 5769 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5770 f->output_data.x->border_tile);
b3e1e05c 5771 UNBLOCK_INPUT;
5d46f928 5772 x_update_cursor (f, 1);
dc6f92b8 5773}
dc6f92b8 5774
f676886a
JB
5775/* The focus has changed. Update the frames as necessary to reflect
5776 the new situation. Note that we can't change the selected frame
c5acd733 5777 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 5778 Each event gets marked with the frame in which it occurred, so the
c5acd733 5779 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 5780
6d4238f3 5781static void
0f941935
KH
5782x_new_focus_frame (dpyinfo, frame)
5783 struct x_display_info *dpyinfo;
f676886a 5784 struct frame *frame;
dc6f92b8 5785{
0f941935 5786 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 5787
0f941935 5788 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 5789 {
58769bee 5790 /* Set this before calling other routines, so that they see
f676886a 5791 the correct value of x_focus_frame. */
0f941935 5792 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
5793
5794 if (old_focus && old_focus->auto_lower)
f676886a 5795 x_lower_frame (old_focus);
dc6f92b8
JB
5796
5797#if 0
f676886a 5798 selected_frame = frame;
e0c1aef2
KH
5799 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
5800 selected_frame);
f676886a
JB
5801 Fselect_window (selected_frame->selected_window);
5802 choose_minibuf_frame ();
c118dd06 5803#endif /* ! 0 */
dc6f92b8 5804
0f941935
KH
5805 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
5806 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
5807 else
5808 pending_autoraise_frame = 0;
6d4238f3 5809 }
dc6f92b8 5810
0f941935 5811 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
5812}
5813
37c2c98b
RS
5814/* Handle an event saying the mouse has moved out of an Emacs frame. */
5815
5816void
0f941935
KH
5817x_mouse_leave (dpyinfo)
5818 struct x_display_info *dpyinfo;
37c2c98b 5819{
0f941935 5820 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 5821}
6d4238f3 5822
f451eb13
JB
5823/* The focus has changed, or we have redirected a frame's focus to
5824 another frame (this happens when a frame uses a surrogate
06a2c219 5825 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
5826
5827 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 5828 frame is being highlighted or un-highlighted; we only use it to find
0f941935 5829 the appropriate X display info. */
06a2c219 5830
6d4238f3 5831static void
0f941935
KH
5832XTframe_rehighlight (frame)
5833 struct frame *frame;
6d4238f3 5834{
0f941935
KH
5835 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
5836}
6d4238f3 5837
0f941935
KH
5838static void
5839x_frame_rehighlight (dpyinfo)
5840 struct x_display_info *dpyinfo;
5841{
5842 struct frame *old_highlight = dpyinfo->x_highlight_frame;
5843
5844 if (dpyinfo->x_focus_frame)
6d4238f3 5845 {
0f941935
KH
5846 dpyinfo->x_highlight_frame
5847 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
5848 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
5849 : dpyinfo->x_focus_frame);
5850 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 5851 {
0f941935
KH
5852 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
5853 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 5854 }
dc6f92b8 5855 }
6d4238f3 5856 else
0f941935 5857 dpyinfo->x_highlight_frame = 0;
dc6f92b8 5858
0f941935 5859 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
5860 {
5861 if (old_highlight)
f676886a 5862 frame_unhighlight (old_highlight);
0f941935
KH
5863 if (dpyinfo->x_highlight_frame)
5864 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 5865 }
dc6f92b8 5866}
06a2c219
GM
5867
5868
dc6f92b8 5869\f
06a2c219 5870/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 5871
28430d3c
JB
5872/* Initialize mode_switch_bit and modifier_meaning. */
5873static void
334208b7
RS
5874x_find_modifier_meanings (dpyinfo)
5875 struct x_display_info *dpyinfo;
28430d3c 5876{
f689eb05 5877 int min_code, max_code;
28430d3c
JB
5878 KeySym *syms;
5879 int syms_per_code;
5880 XModifierKeymap *mods;
5881
334208b7
RS
5882 dpyinfo->meta_mod_mask = 0;
5883 dpyinfo->shift_lock_mask = 0;
5884 dpyinfo->alt_mod_mask = 0;
5885 dpyinfo->super_mod_mask = 0;
5886 dpyinfo->hyper_mod_mask = 0;
58769bee 5887
9658a521 5888#ifdef HAVE_X11R4
334208b7 5889 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 5890#else
4a60f8c5
RS
5891 min_code = dpyinfo->display->min_keycode;
5892 max_code = dpyinfo->display->max_keycode;
9658a521
JB
5893#endif
5894
334208b7 5895 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
5896 min_code, max_code - min_code + 1,
5897 &syms_per_code);
334208b7 5898 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 5899
58769bee 5900 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 5901 Alt keysyms are on. */
28430d3c 5902 {
06a2c219 5903 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
5904
5905 for (row = 3; row < 8; row++)
5906 for (col = 0; col < mods->max_keypermod; col++)
5907 {
0299d313
RS
5908 KeyCode code
5909 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 5910
af92970c
KH
5911 /* Zeroes are used for filler. Skip them. */
5912 if (code == 0)
5913 continue;
5914
28430d3c
JB
5915 /* Are any of this keycode's keysyms a meta key? */
5916 {
5917 int code_col;
5918
5919 for (code_col = 0; code_col < syms_per_code; code_col++)
5920 {
f689eb05 5921 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 5922
f689eb05 5923 switch (sym)
28430d3c 5924 {
f689eb05
JB
5925 case XK_Meta_L:
5926 case XK_Meta_R:
334208b7 5927 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 5928 break;
f689eb05
JB
5929
5930 case XK_Alt_L:
5931 case XK_Alt_R:
334208b7 5932 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
5933 break;
5934
5935 case XK_Hyper_L:
5936 case XK_Hyper_R:
334208b7 5937 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
5938 break;
5939
5940 case XK_Super_L:
5941 case XK_Super_R:
334208b7 5942 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 5943 break;
11edeb03
JB
5944
5945 case XK_Shift_Lock:
5946 /* Ignore this if it's not on the lock modifier. */
5947 if ((1 << row) == LockMask)
334208b7 5948 dpyinfo->shift_lock_mask = LockMask;
11edeb03 5949 break;
28430d3c
JB
5950 }
5951 }
5952 }
5953 }
5954 }
5955
f689eb05 5956 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 5957 if (! dpyinfo->meta_mod_mask)
a3c44b14 5958 {
334208b7
RS
5959 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
5960 dpyinfo->alt_mod_mask = 0;
a3c44b14 5961 }
f689eb05 5962
148c4b70
RS
5963 /* If some keys are both alt and meta,
5964 make them just meta, not alt. */
334208b7 5965 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 5966 {
334208b7 5967 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 5968 }
58769bee 5969
28430d3c 5970 XFree ((char *) syms);
f689eb05 5971 XFreeModifiermap (mods);
28430d3c
JB
5972}
5973
dfeccd2d
JB
5974/* Convert between the modifier bits X uses and the modifier bits
5975 Emacs uses. */
06a2c219 5976
7c5283e4 5977static unsigned int
334208b7
RS
5978x_x_to_emacs_modifiers (dpyinfo, state)
5979 struct x_display_info *dpyinfo;
dc6f92b8
JB
5980 unsigned int state;
5981{
334208b7
RS
5982 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
5983 | ((state & ControlMask) ? ctrl_modifier : 0)
5984 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
5985 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
5986 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
5987 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
5988}
5989
dfeccd2d 5990static unsigned int
334208b7
RS
5991x_emacs_to_x_modifiers (dpyinfo, state)
5992 struct x_display_info *dpyinfo;
dfeccd2d
JB
5993 unsigned int state;
5994{
334208b7
RS
5995 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
5996 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
5997 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
5998 | ((state & shift_modifier) ? ShiftMask : 0)
5999 | ((state & ctrl_modifier) ? ControlMask : 0)
6000 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6001}
d047c4eb
KH
6002
6003/* Convert a keysym to its name. */
6004
6005char *
6006x_get_keysym_name (keysym)
6007 KeySym keysym;
6008{
6009 char *value;
6010
6011 BLOCK_INPUT;
6012 value = XKeysymToString (keysym);
6013 UNBLOCK_INPUT;
6014
6015 return value;
6016}
06a2c219
GM
6017
6018
e4571a43
JB
6019\f
6020/* Mouse clicks and mouse movement. Rah. */
e4571a43 6021
06a2c219
GM
6022/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6023 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6024 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6025 not force the value into range. */
69388238 6026
c8dba240 6027void
69388238 6028pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6029 FRAME_PTR f;
69388238 6030 register int pix_x, pix_y;
e4571a43
JB
6031 register int *x, *y;
6032 XRectangle *bounds;
69388238 6033 int noclip;
e4571a43 6034{
06a2c219 6035 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6036 even for negative values. */
6037 if (pix_x < 0)
7556890b 6038 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6039 if (pix_y < 0)
7556890b 6040 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6041
e4571a43
JB
6042 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6043 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6044
6045 if (bounds)
6046 {
7556890b
RS
6047 bounds->width = FONT_WIDTH (f->output_data.x->font);
6048 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6049 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6050 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6051 }
6052
69388238
RS
6053 if (!noclip)
6054 {
6055 if (pix_x < 0)
6056 pix_x = 0;
3cbd2e0b
RS
6057 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6058 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6059
6060 if (pix_y < 0)
6061 pix_y = 0;
6062 else if (pix_y > f->height)
6063 pix_y = f->height;
6064 }
e4571a43
JB
6065
6066 *x = pix_x;
6067 *y = pix_y;
6068}
6069
06a2c219
GM
6070
6071/* Given HPOS/VPOS in the current matrix of W, return corresponding
6072 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6073 can't tell the positions because W's display is not up to date,
6074 return 0. */
6075
6076int
6077glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6078 struct window *w;
6079 int hpos, vpos;
6080 int *frame_x, *frame_y;
2b5c9e71 6081{
06a2c219
GM
6082 int success_p;
6083
6084 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6085 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6086
6087 if (display_completed)
6088 {
6089 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6090 struct glyph *glyph = row->glyphs[TEXT_AREA];
6091 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6092
6093 *frame_y = row->y;
6094 *frame_x = row->x;
6095 while (glyph < end)
6096 {
6097 *frame_x += glyph->pixel_width;
6098 ++glyph;
6099 }
6100
6101 success_p = 1;
6102 }
6103 else
6104 {
6105 *frame_y = *frame_x = 0;
6106 success_p = 0;
6107 }
6108
6109 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6110 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6111 return success_p;
2b5c9e71
RS
6112}
6113
06a2c219 6114
dc6f92b8
JB
6115/* Prepare a mouse-event in *RESULT for placement in the input queue.
6116
6117 If the event is a button press, then note that we have grabbed
f451eb13 6118 the mouse. */
dc6f92b8
JB
6119
6120static Lisp_Object
f451eb13 6121construct_mouse_click (result, event, f)
dc6f92b8
JB
6122 struct input_event *result;
6123 XButtonEvent *event;
f676886a 6124 struct frame *f;
dc6f92b8 6125{
f451eb13 6126 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6127 otherwise. */
f451eb13 6128 result->kind = mouse_click;
69388238 6129 result->code = event->button - Button1;
1113d9db 6130 result->timestamp = event->time;
334208b7
RS
6131 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6132 event->state)
f689eb05 6133 | (event->type == ButtonRelease
58769bee 6134 ? up_modifier
f689eb05 6135 : down_modifier));
dc6f92b8 6136
06a2c219
GM
6137 XSETINT (result->x, event->x);
6138 XSETINT (result->y, event->y);
6139 XSETFRAME (result->frame_or_window, f);
6140 return Qnil;
dc6f92b8 6141}
b849c413 6142
06a2c219
GM
6143#if 0 /* This function isn't called. --gerd */
6144
b849c413
RS
6145/* Prepare a menu-event in *RESULT for placement in the input queue. */
6146
6147static Lisp_Object
6148construct_menu_click (result, event, f)
6149 struct input_event *result;
6150 XButtonEvent *event;
6151 struct frame *f;
6152{
6153 /* Make the event type no_event; we'll change that when we decide
6154 otherwise. */
6155 result->kind = mouse_click;
26459b28 6156 result->code = event->button - Button1;
b849c413 6157 result->timestamp = event->time;
334208b7
RS
6158 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6159 event->state)
b849c413 6160 | (event->type == ButtonRelease
58769bee 6161 ? up_modifier
b849c413
RS
6162 : down_modifier));
6163
e0c1aef2
KH
6164 XSETINT (result->x, event->x);
6165 XSETINT (result->y, -1);
6166 XSETFRAME (result->frame_or_window, f);
b849c413 6167}
06a2c219
GM
6168
6169#endif /* 0 */
6170
69388238 6171\f
90e65f07
JB
6172/* Function to report a mouse movement to the mainstream Emacs code.
6173 The input handler calls this.
6174
6175 We have received a mouse movement event, which is given in *event.
6176 If the mouse is over a different glyph than it was last time, tell
6177 the mainstream emacs code by setting mouse_moved. If not, ask for
6178 another motion event, so we can check again the next time it moves. */
b8009dd1 6179
06a2c219
GM
6180static XMotionEvent last_mouse_motion_event;
6181static Lisp_Object last_mouse_motion_frame;
6182
90e65f07 6183static void
12ba150f 6184note_mouse_movement (frame, event)
f676886a 6185 FRAME_PTR frame;
90e65f07 6186 XMotionEvent *event;
90e65f07 6187{
e5d77022 6188 last_mouse_movement_time = event->time;
06a2c219
GM
6189 last_mouse_motion_event = *event;
6190 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6191
27f338af
RS
6192 if (event->window != FRAME_X_WINDOW (frame))
6193 {
39d8bb4d 6194 frame->mouse_moved = 1;
27f338af 6195 last_mouse_scroll_bar = Qnil;
27f338af 6196 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6197 }
6198
90e65f07 6199 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6200 else if (event->x < last_mouse_glyph.x
6201 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6202 || event->y < last_mouse_glyph.y
6203 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6204 {
39d8bb4d 6205 frame->mouse_moved = 1;
ab648270 6206 last_mouse_scroll_bar = Qnil;
b8009dd1 6207 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6208 }
6209}
6210
bf1c0ba1 6211/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6212
06a2c219
GM
6213 int disable_mouse_highlight;
6214
6215
6216\f
6217/************************************************************************
6218 Mouse Face
6219 ************************************************************************/
6220
6221/* Find the glyph under window-relative coordinates X/Y in window W.
6222 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6223 strings. Return in *HPOS and *VPOS the row and column number of
6224 the glyph found. Return in *AREA the glyph area containing X.
6225 Value is a pointer to the glyph found or null if X/Y is not on
6226 text, or we can't tell because W's current matrix is not up to
6227 date. */
6228
6229static struct glyph *
6230x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
6231 struct window *w;
6232 int x, y;
6233 int *hpos, *vpos, *area;
6234{
6235 struct glyph *glyph, *end;
3e71d8f2 6236 struct glyph_row *row = NULL;
06a2c219
GM
6237 int x0, i, left_area_width;
6238
6239 /* Find row containing Y. Give up if some row is not enabled. */
6240 for (i = 0; i < w->current_matrix->nrows; ++i)
6241 {
6242 row = MATRIX_ROW (w->current_matrix, i);
6243 if (!row->enabled_p)
6244 return NULL;
6245 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6246 break;
6247 }
6248
6249 *vpos = i;
6250 *hpos = 0;
6251
6252 /* Give up if Y is not in the window. */
6253 if (i == w->current_matrix->nrows)
6254 return NULL;
6255
6256 /* Get the glyph area containing X. */
6257 if (w->pseudo_window_p)
6258 {
6259 *area = TEXT_AREA;
6260 x0 = 0;
6261 }
6262 else
6263 {
6264 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6265 if (x < left_area_width)
6266 {
6267 *area = LEFT_MARGIN_AREA;
6268 x0 = 0;
6269 }
6270 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6271 {
6272 *area = TEXT_AREA;
6273 x0 = row->x + left_area_width;
6274 }
6275 else
6276 {
6277 *area = RIGHT_MARGIN_AREA;
6278 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6279 }
6280 }
6281
6282 /* Find glyph containing X. */
6283 glyph = row->glyphs[*area];
6284 end = glyph + row->used[*area];
6285 while (glyph < end)
6286 {
6287 if (x < x0 + glyph->pixel_width)
6288 {
6289 if (w->pseudo_window_p)
6290 break;
6291 else if (BUFFERP (glyph->object))
6292 break;
6293 }
6294
6295 x0 += glyph->pixel_width;
6296 ++glyph;
6297 }
6298
6299 if (glyph == end)
6300 return NULL;
6301
6302 *hpos = glyph - row->glyphs[*area];
6303 return glyph;
6304}
6305
6306
6307/* Convert frame-relative x/y to coordinates relative to window W.
6308 Takes pseudo-windows into account. */
6309
6310static void
6311frame_to_window_pixel_xy (w, x, y)
6312 struct window *w;
6313 int *x, *y;
6314{
6315 if (w->pseudo_window_p)
6316 {
6317 /* A pseudo-window is always full-width, and starts at the
6318 left edge of the frame, plus a frame border. */
6319 struct frame *f = XFRAME (w->frame);
6320 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6321 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6322 }
6323 else
6324 {
6325 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6326 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6327 }
6328}
6329
6330
6331/* Take proper action when mouse has moved to the mode or top line of
6332 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6333 mode line. X is relative to the start of the text display area of
6334 W, so the width of bitmap areas and scroll bars must be subtracted
6335 to get a position relative to the start of the mode line. */
6336
6337static void
6338note_mode_line_highlight (w, x, mode_line_p)
6339 struct window *w;
6340 int x, mode_line_p;
6341{
6342 struct frame *f = XFRAME (w->frame);
6343 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6344 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6345 struct glyph_row *row;
6346
6347 if (mode_line_p)
6348 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6349 else
045dee35 6350 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
06a2c219
GM
6351
6352 if (row->enabled_p)
6353 {
6354 struct glyph *glyph, *end;
6355 Lisp_Object help, map;
6356 int x0;
6357
6358 /* Find the glyph under X. */
6359 glyph = row->glyphs[TEXT_AREA];
6360 end = glyph + row->used[TEXT_AREA];
6361 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6362 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
6363 while (glyph < end
6364 && x >= x0 + glyph->pixel_width)
6365 {
6366 x0 += glyph->pixel_width;
6367 ++glyph;
6368 }
6369
6370 if (glyph < end
6371 && STRINGP (glyph->object)
6372 && XSTRING (glyph->object)->intervals
6373 && glyph->charpos >= 0
6374 && glyph->charpos < XSTRING (glyph->object)->size)
6375 {
6376 /* If we're on a string with `help-echo' text property,
6377 arrange for the help to be displayed. This is done by
6378 setting the global variable help_echo to the help string. */
6379 help = Fget_text_property (make_number (glyph->charpos),
6380 Qhelp_echo, glyph->object);
b7e80413 6381 if (!NILP (help))
06a2c219
GM
6382 help_echo = help;
6383
6384 /* Change the mouse pointer according to what is under X/Y. */
6385 map = Fget_text_property (make_number (glyph->charpos),
6386 Qlocal_map, glyph->object);
6387 if (!NILP (Fkeymapp (map)))
6388 cursor = f->output_data.x->nontext_cursor;
6389 }
6390 }
6391
6392 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6393}
6394
6395
6396/* Take proper action when the mouse has moved to position X, Y on
6397 frame F as regards highlighting characters that have mouse-face
6398 properties. Also de-highlighting chars where the mouse was before.
27f338af 6399 X and Y can be negative or out of range. */
b8009dd1
RS
6400
6401static void
6402note_mouse_highlight (f, x, y)
06a2c219 6403 struct frame *f;
c32cdd9a 6404 int x, y;
b8009dd1 6405{
06a2c219
GM
6406 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6407 int portion;
b8009dd1
RS
6408 Lisp_Object window;
6409 struct window *w;
6410
06a2c219
GM
6411 /* When a menu is active, don't highlight because this looks odd. */
6412#ifdef USE_X_TOOLKIT
6413 if (popup_activated ())
6414 return;
6415#endif
6416
04fff9c0
GM
6417 if (disable_mouse_highlight
6418 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6419 return;
6420
06a2c219
GM
6421 dpyinfo->mouse_face_mouse_x = x;
6422 dpyinfo->mouse_face_mouse_y = y;
6423 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6424
06a2c219 6425 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6426 return;
6427
514e4681
RS
6428 if (gc_in_progress)
6429 {
06a2c219 6430 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6431 return;
6432 }
6433
b8009dd1 6434 /* Which window is that in? */
06a2c219 6435 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6436
6437 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6438 if (! EQ (window, dpyinfo->mouse_face_window))
6439 clear_mouse_face (dpyinfo);
6440
6441 /* Not on a window -> return. */
6442 if (!WINDOWP (window))
6443 return;
6444
6445 /* Convert to window-relative pixel coordinates. */
6446 w = XWINDOW (window);
6447 frame_to_window_pixel_xy (w, &x, &y);
6448
9ea173e8 6449 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6450 buffer. */
9ea173e8 6451 if (EQ (window, f->tool_bar_window))
06a2c219 6452 {
9ea173e8 6453 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6454 return;
6455 }
6456
6457 if (portion == 1 || portion == 3)
6458 {
6459 /* Mouse is on the mode or top line. */
6460 note_mode_line_highlight (w, x, portion == 1);
6461 return;
6462 }
6463 else
6464 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6465 f->output_data.x->text_cursor);
b8009dd1 6466
0cdd0c9f
RS
6467 /* Are we in a window whose display is up to date?
6468 And verify the buffer's text has not changed. */
06a2c219
GM
6469 if (/* Within text portion of the window. */
6470 portion == 0
0cdd0c9f 6471 && EQ (w->window_end_valid, w->buffer)
26459b28
KH
6472 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
6473 && (XFASTINT (w->last_overlay_modified)
6474 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
b8009dd1 6475 {
06a2c219
GM
6476 int hpos, vpos, pos, i, area;
6477 struct glyph *glyph;
b8009dd1 6478
06a2c219
GM
6479 /* Find the glyph under X/Y. */
6480 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
6481
6482 /* Clear mouse face if X/Y not over text. */
6483 if (glyph == NULL
6484 || area != TEXT_AREA
6485 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6486 {
06a2c219
GM
6487 clear_mouse_face (dpyinfo);
6488 return;
6489 }
6490
6491 pos = glyph->charpos;
6492 xassert (w->pseudo_window_p || BUFFERP (glyph->object));
6493
6494 /* Check for mouse-face and help-echo. */
6495 {
6496 Lisp_Object mouse_face, overlay, position;
6497 Lisp_Object *overlay_vec;
6498 int len, noverlays;
6499 struct buffer *obuf;
6500 int obegv, ozv;
6501
6502 /* If we get an out-of-range value, return now; avoid an error. */
6503 if (pos > BUF_Z (XBUFFER (w->buffer)))
6504 return;
6505
6506 /* Make the window's buffer temporarily current for
6507 overlays_at and compute_char_face. */
6508 obuf = current_buffer;
6509 current_buffer = XBUFFER (w->buffer);
6510 obegv = BEGV;
6511 ozv = ZV;
6512 BEGV = BEG;
6513 ZV = Z;
6514
6515 /* Is this char mouse-active or does it have help-echo? */
6516 XSETINT (position, pos);
6517
6518 /* Put all the overlays we want in a vector in overlay_vec.
6519 Store the length in len. If there are more than 10, make
6520 enough space for all, and try again. */
6521 len = 10;
6522 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6523 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6524 if (noverlays > len)
6525 {
6526 len = noverlays;
6527 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6528 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6529 }
6530
6531 noverlays = sort_overlays (overlay_vec, noverlays, w);
6532
6533 /* Check mouse-face highlighting. */
6534 if (! (EQ (window, dpyinfo->mouse_face_window)
6535 && vpos >= dpyinfo->mouse_face_beg_row
6536 && vpos <= dpyinfo->mouse_face_end_row
6537 && (vpos > dpyinfo->mouse_face_beg_row
6538 || hpos >= dpyinfo->mouse_face_beg_col)
6539 && (vpos < dpyinfo->mouse_face_end_row
6540 || hpos < dpyinfo->mouse_face_end_col
6541 || dpyinfo->mouse_face_past_end)))
6542 {
6543 /* Clear the display of the old active region, if any. */
6544 clear_mouse_face (dpyinfo);
6545
6546 /* Find the highest priority overlay that has a mouse-face prop. */
6547 overlay = Qnil;
6548 for (i = 0; i < noverlays; i++)
6549 {
6550 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6551 if (!NILP (mouse_face))
6552 {
6553 overlay = overlay_vec[i];
6554 break;
6555 }
6556 }
6557
6558 /* If no overlay applies, get a text property. */
6559 if (NILP (overlay))
6560 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6561
6562 /* Handle the overlay case. */
6563 if (! NILP (overlay))
6564 {
6565 /* Find the range of text around this char that
6566 should be active. */
6567 Lisp_Object before, after;
6568 int ignore;
6569
6570 before = Foverlay_start (overlay);
6571 after = Foverlay_end (overlay);
6572 /* Record this as the current active region. */
6573 fast_find_position (w, XFASTINT (before),
6574 &dpyinfo->mouse_face_beg_col,
6575 &dpyinfo->mouse_face_beg_row,
6576 &dpyinfo->mouse_face_beg_x,
6577 &dpyinfo->mouse_face_beg_y);
6578 dpyinfo->mouse_face_past_end
6579 = !fast_find_position (w, XFASTINT (after),
6580 &dpyinfo->mouse_face_end_col,
6581 &dpyinfo->mouse_face_end_row,
6582 &dpyinfo->mouse_face_end_x,
6583 &dpyinfo->mouse_face_end_y);
6584 dpyinfo->mouse_face_window = window;
6585 dpyinfo->mouse_face_face_id
6586 = face_at_buffer_position (w, pos, 0, 0,
6587 &ignore, pos + 1, 1);
6588
6589 /* Display it as active. */
6590 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6591 }
6592 /* Handle the text property case. */
6593 else if (! NILP (mouse_face))
6594 {
6595 /* Find the range of text around this char that
6596 should be active. */
6597 Lisp_Object before, after, beginning, end;
6598 int ignore;
6599
6600 beginning = Fmarker_position (w->start);
6601 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
6602 - XFASTINT (w->window_end_pos)));
6603 before
6604 = Fprevious_single_property_change (make_number (pos + 1),
6605 Qmouse_face,
6606 w->buffer, beginning);
6607 after
6608 = Fnext_single_property_change (position, Qmouse_face,
6609 w->buffer, end);
6610 /* Record this as the current active region. */
6611 fast_find_position (w, XFASTINT (before),
6612 &dpyinfo->mouse_face_beg_col,
6613 &dpyinfo->mouse_face_beg_row,
6614 &dpyinfo->mouse_face_beg_x,
6615 &dpyinfo->mouse_face_beg_y);
6616 dpyinfo->mouse_face_past_end
6617 = !fast_find_position (w, XFASTINT (after),
6618 &dpyinfo->mouse_face_end_col,
6619 &dpyinfo->mouse_face_end_row,
6620 &dpyinfo->mouse_face_end_x,
6621 &dpyinfo->mouse_face_end_y);
6622 dpyinfo->mouse_face_window = window;
6623 dpyinfo->mouse_face_face_id
6624 = face_at_buffer_position (w, pos, 0, 0,
6625 &ignore, pos + 1, 1);
6626
6627 /* Display it as active. */
6628 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6629 }
6630 }
6631
6632 /* Look for a `help-echo' property. */
6633 {
6634 Lisp_Object help;
6635
6636 /* Check overlays first. */
6637 help = Qnil;
b7e80413 6638 for (i = 0; i < noverlays && NILP (help); ++i)
06a2c219
GM
6639 help = Foverlay_get (overlay_vec[i], Qhelp_echo);
6640
6641 /* Try text properties. */
b7e80413 6642 if (NILP (help)
06a2c219
GM
6643 && ((STRINGP (glyph->object)
6644 && glyph->charpos >= 0
6645 && glyph->charpos < XSTRING (glyph->object)->size)
6646 || (BUFFERP (glyph->object)
6647 && glyph->charpos >= BEGV
6648 && glyph->charpos < ZV)))
6649 help = Fget_text_property (make_number (glyph->charpos),
6650 Qhelp_echo, glyph->object);
6651
b7e80413 6652 if (!NILP (help))
06a2c219
GM
6653 help_echo = help;
6654 }
6655
6656 BEGV = obegv;
6657 ZV = ozv;
6658 current_buffer = obuf;
6659 }
6660 }
6661}
6662
6663static void
6664redo_mouse_highlight ()
6665{
6666 if (!NILP (last_mouse_motion_frame)
6667 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
6668 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
6669 last_mouse_motion_event.x,
6670 last_mouse_motion_event.y);
6671}
6672
6673
6674\f
6675/***********************************************************************
9ea173e8 6676 Tool-bars
06a2c219
GM
6677 ***********************************************************************/
6678
9ea173e8
GM
6679static int x_tool_bar_item P_ ((struct frame *, int, int,
6680 struct glyph **, int *, int *, int *));
06a2c219 6681
9ea173e8 6682/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
6683 or -1. */
6684
9ea173e8 6685static int last_tool_bar_item;
06a2c219
GM
6686
6687
9ea173e8
GM
6688/* Get information about the tool-bar item at position X/Y on frame F.
6689 Return in *GLYPH a pointer to the glyph of the tool-bar item in
6690 the current matrix of the tool-bar window of F, or NULL if not
6691 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
6692 item in F->current_tool_bar_items. Value is
06a2c219 6693
9ea173e8 6694 -1 if X/Y is not on a tool-bar item
06a2c219
GM
6695 0 if X/Y is on the same item that was highlighted before.
6696 1 otherwise. */
6697
6698static int
9ea173e8 6699x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
6700 struct frame *f;
6701 int x, y;
6702 struct glyph **glyph;
6703 int *hpos, *vpos, *prop_idx;
6704{
6705 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6706 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6707 int area;
6708
6709 /* Find the glyph under X/Y. */
6710 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
6711 if (*glyph == NULL)
6712 return -1;
6713
9ea173e8
GM
6714 /* Get the start of this tool-bar item's properties in
6715 f->current_tool_bar_items. */
6716 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
6717 return -1;
6718
6719 /* Is mouse on the highlighted item? */
9ea173e8 6720 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
6721 && *vpos >= dpyinfo->mouse_face_beg_row
6722 && *vpos <= dpyinfo->mouse_face_end_row
6723 && (*vpos > dpyinfo->mouse_face_beg_row
6724 || *hpos >= dpyinfo->mouse_face_beg_col)
6725 && (*vpos < dpyinfo->mouse_face_end_row
6726 || *hpos < dpyinfo->mouse_face_end_col
6727 || dpyinfo->mouse_face_past_end))
6728 return 0;
6729
6730 return 1;
6731}
6732
6733
9ea173e8 6734/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
6735 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
6736 or ButtonRelase. */
6737
6738static void
9ea173e8 6739x_handle_tool_bar_click (f, button_event)
06a2c219
GM
6740 struct frame *f;
6741 XButtonEvent *button_event;
6742{
6743 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6744 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6745 int hpos, vpos, prop_idx;
6746 struct glyph *glyph;
6747 Lisp_Object enabled_p;
6748 int x = button_event->x;
6749 int y = button_event->y;
6750
9ea173e8 6751 /* If not on the highlighted tool-bar item, return. */
06a2c219 6752 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 6753 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
6754 return;
6755
6756 /* If item is disabled, do nothing. */
9ea173e8
GM
6757 enabled_p = (XVECTOR (f->current_tool_bar_items)
6758 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6759 if (NILP (enabled_p))
6760 return;
6761
6762 if (button_event->type == ButtonPress)
6763 {
6764 /* Show item in pressed state. */
6765 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
6766 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 6767 last_tool_bar_item = prop_idx;
06a2c219
GM
6768 }
6769 else
6770 {
6771 Lisp_Object key, frame;
6772 struct input_event event;
6773
6774 /* Show item in released state. */
6775 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
6776 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
6777
9ea173e8
GM
6778 key = (XVECTOR (f->current_tool_bar_items)
6779 ->contents[prop_idx + TOOL_BAR_ITEM_KEY]);
06a2c219
GM
6780
6781 XSETFRAME (frame, f);
9ea173e8 6782 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
6783 event.frame_or_window = frame;
6784 event.arg = frame;
06a2c219
GM
6785 kbd_buffer_store_event (&event);
6786
9ea173e8 6787 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
6788 event.frame_or_window = frame;
6789 event.arg = key;
06a2c219
GM
6790 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6791 button_event->state);
6792 kbd_buffer_store_event (&event);
9ea173e8 6793 last_tool_bar_item = -1;
06a2c219
GM
6794 }
6795}
6796
6797
9ea173e8
GM
6798/* Possibly highlight a tool-bar item on frame F when mouse moves to
6799 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
6800 note_mouse_highlight. */
6801
6802static void
9ea173e8 6803note_tool_bar_highlight (f, x, y)
06a2c219
GM
6804 struct frame *f;
6805 int x, y;
6806{
9ea173e8 6807 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
6808 struct window *w = XWINDOW (window);
6809 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6810 int hpos, vpos;
6811 struct glyph *glyph;
6812 struct glyph_row *row;
5c187dee 6813 int i;
06a2c219
GM
6814 Lisp_Object enabled_p;
6815 int prop_idx;
6816 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
5c187dee 6817 int mouse_down_p, rc;
06a2c219
GM
6818
6819 /* Function note_mouse_highlight is called with negative x(y
6820 values when mouse moves outside of the frame. */
6821 if (x <= 0 || y <= 0)
6822 {
6823 clear_mouse_face (dpyinfo);
6824 return;
6825 }
6826
9ea173e8 6827 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
6828 if (rc < 0)
6829 {
9ea173e8 6830 /* Not on tool-bar item. */
06a2c219
GM
6831 clear_mouse_face (dpyinfo);
6832 return;
6833 }
6834 else if (rc == 0)
9ea173e8 6835 /* On same tool-bar item as before. */
06a2c219 6836 goto set_help_echo;
b8009dd1 6837
06a2c219
GM
6838 clear_mouse_face (dpyinfo);
6839
9ea173e8 6840 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
6841 mouse_down_p = (dpyinfo->grabbed
6842 && f == last_mouse_frame
6843 && FRAME_LIVE_P (f));
6844 if (mouse_down_p
9ea173e8 6845 && last_tool_bar_item != prop_idx)
06a2c219
GM
6846 return;
6847
6848 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
6849 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
6850
9ea173e8
GM
6851 /* If tool-bar item is not enabled, don't highlight it. */
6852 enabled_p = (XVECTOR (f->current_tool_bar_items)
6853 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6854 if (!NILP (enabled_p))
6855 {
6856 /* Compute the x-position of the glyph. In front and past the
6857 image is a space. We include this is the highlighted area. */
6858 row = MATRIX_ROW (w->current_matrix, vpos);
6859 for (i = x = 0; i < hpos; ++i)
6860 x += row->glyphs[TEXT_AREA][i].pixel_width;
6861
6862 /* Record this as the current active region. */
6863 dpyinfo->mouse_face_beg_col = hpos;
6864 dpyinfo->mouse_face_beg_row = vpos;
6865 dpyinfo->mouse_face_beg_x = x;
6866 dpyinfo->mouse_face_beg_y = row->y;
6867 dpyinfo->mouse_face_past_end = 0;
6868
6869 dpyinfo->mouse_face_end_col = hpos + 1;
6870 dpyinfo->mouse_face_end_row = vpos;
6871 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
6872 dpyinfo->mouse_face_end_y = row->y;
6873 dpyinfo->mouse_face_window = window;
9ea173e8 6874 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
6875
6876 /* Display it as active. */
6877 show_mouse_face (dpyinfo, draw);
6878 dpyinfo->mouse_face_image_state = draw;
b8009dd1 6879 }
06a2c219
GM
6880
6881 set_help_echo:
6882
9ea173e8 6883 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 6884 XTread_socket does the rest. */
9ea173e8
GM
6885 help_echo = (XVECTOR (f->current_tool_bar_items)
6886 ->contents[prop_idx + TOOL_BAR_ITEM_HELP]);
b7e80413 6887 if (NILP (help_echo))
9ea173e8
GM
6888 help_echo = (XVECTOR (f->current_tool_bar_items)
6889 ->contents[prop_idx + TOOL_BAR_ITEM_CAPTION]);
b8009dd1 6890}
4d73d038 6891
06a2c219
GM
6892
6893\f
6894/* Find the glyph matrix position of buffer position POS in window W.
6895 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
6896 current glyphs must be up to date. If POS is above window start
6897 return (0, 0, 0, 0). If POS is after end of W, return end of
6898 last line in W. */
b8009dd1
RS
6899
6900static int
06a2c219
GM
6901fast_find_position (w, pos, hpos, vpos, x, y)
6902 struct window *w;
b8009dd1 6903 int pos;
06a2c219 6904 int *hpos, *vpos, *x, *y;
b8009dd1 6905{
b8009dd1 6906 int i;
bf1c0ba1 6907 int lastcol;
06a2c219
GM
6908 int maybe_next_line_p = 0;
6909 int line_start_position;
6910 int yb = window_text_bottom_y (w);
6911 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
6912 struct glyph_row *best_row = row;
6913 int row_vpos = 0, best_row_vpos = 0;
6914 int current_x;
6915
6916 while (row->y < yb)
b8009dd1 6917 {
06a2c219
GM
6918 if (row->used[TEXT_AREA])
6919 line_start_position = row->glyphs[TEXT_AREA]->charpos;
6920 else
6921 line_start_position = 0;
6922
6923 if (line_start_position > pos)
b8009dd1 6924 break;
77b68646
RS
6925 /* If the position sought is the end of the buffer,
6926 don't include the blank lines at the bottom of the window. */
06a2c219
GM
6927 else if (line_start_position == pos
6928 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 6929 {
06a2c219 6930 maybe_next_line_p = 1;
77b68646
RS
6931 break;
6932 }
06a2c219
GM
6933 else if (line_start_position > 0)
6934 {
6935 best_row = row;
6936 best_row_vpos = row_vpos;
6937 }
4b0bb6f3
GM
6938
6939 if (row->y + row->height >= yb)
6940 break;
06a2c219
GM
6941
6942 ++row;
6943 ++row_vpos;
b8009dd1 6944 }
06a2c219
GM
6945
6946 /* Find the right column within BEST_ROW. */
6947 lastcol = 0;
6948 current_x = best_row->x;
6949 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 6950 {
06a2c219
GM
6951 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
6952 int charpos;
6953
6954 charpos = glyph->charpos;
6955 if (charpos == pos)
bf1c0ba1 6956 {
06a2c219
GM
6957 *hpos = i;
6958 *vpos = best_row_vpos;
6959 *x = current_x;
6960 *y = best_row->y;
bf1c0ba1
RS
6961 return 1;
6962 }
06a2c219 6963 else if (charpos > pos)
4d73d038 6964 break;
06a2c219
GM
6965 else if (charpos > 0)
6966 lastcol = i;
6967
6968 current_x += glyph->pixel_width;
bf1c0ba1 6969 }
b8009dd1 6970
77b68646
RS
6971 /* If we're looking for the end of the buffer,
6972 and we didn't find it in the line we scanned,
6973 use the start of the following line. */
06a2c219 6974 if (maybe_next_line_p)
77b68646 6975 {
06a2c219
GM
6976 ++best_row;
6977 ++best_row_vpos;
6978 lastcol = 0;
6979 current_x = best_row->x;
77b68646
RS
6980 }
6981
06a2c219
GM
6982 *vpos = best_row_vpos;
6983 *hpos = lastcol + 1;
6984 *x = current_x;
6985 *y = best_row->y;
b8009dd1
RS
6986 return 0;
6987}
6988
06a2c219 6989
b8009dd1
RS
6990/* Display the active region described by mouse_face_*
6991 in its mouse-face if HL > 0, in its normal face if HL = 0. */
6992
6993static void
06a2c219 6994show_mouse_face (dpyinfo, draw)
7a13e894 6995 struct x_display_info *dpyinfo;
06a2c219 6996 enum draw_glyphs_face draw;
b8009dd1 6997{
7a13e894 6998 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 6999 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 7000 int i;
06a2c219
GM
7001 int cursor_off_p = 0;
7002 struct cursor_pos saved_cursor;
7003
7004 saved_cursor = output_cursor;
7005
7006 /* If window is in the process of being destroyed, don't bother
7007 to do anything. */
7008 if (w->current_matrix == NULL)
7009 goto set_x_cursor;
7010
7011 /* Recognize when we are called to operate on rows that don't exist
7012 anymore. This can happen when a window is split. */
7013 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
7014 goto set_x_cursor;
7015
7016 set_output_cursor (&w->phys_cursor);
7017
7018 /* Note that mouse_face_beg_row etc. are window relative. */
7019 for (i = dpyinfo->mouse_face_beg_row;
7020 i <= dpyinfo->mouse_face_end_row;
7021 i++)
7022 {
7023 int start_hpos, end_hpos, start_x;
7024 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
7025
7026 /* Don't do anything if row doesn't have valid contents. */
7027 if (!row->enabled_p)
7028 continue;
7029
7030 /* For all but the first row, the highlight starts at column 0. */
7031 if (i == dpyinfo->mouse_face_beg_row)
7032 {
7033 start_hpos = dpyinfo->mouse_face_beg_col;
7034 start_x = dpyinfo->mouse_face_beg_x;
7035 }
7036 else
7037 {
7038 start_hpos = 0;
7039 start_x = 0;
7040 }
7041
7042 if (i == dpyinfo->mouse_face_end_row)
7043 end_hpos = dpyinfo->mouse_face_end_col;
7044 else
7045 end_hpos = row->used[TEXT_AREA];
7046
7047 /* If the cursor's in the text we are about to rewrite, turn the
7048 cursor off. */
7049 if (!w->pseudo_window_p
7050 && i == output_cursor.vpos
7051 && output_cursor.hpos >= start_hpos - 1
7052 && output_cursor.hpos <= end_hpos)
514e4681 7053 {
06a2c219
GM
7054 x_update_window_cursor (w, 0);
7055 cursor_off_p = 1;
514e4681 7056 }
b8009dd1 7057
06a2c219 7058 if (end_hpos > start_hpos)
64f26cf5
GM
7059 {
7060 row->mouse_face_p = draw == DRAW_MOUSE_FACE;
7061 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7062 start_hpos, end_hpos, draw, NULL, NULL, 0);
7063 }
b8009dd1
RS
7064 }
7065
514e4681 7066 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
7067 if (cursor_off_p)
7068 x_display_cursor (w, 1,
7069 output_cursor.hpos, output_cursor.vpos,
7070 output_cursor.x, output_cursor.y);
2729a2b5 7071
06a2c219 7072 output_cursor = saved_cursor;
fb3b7de5 7073
06a2c219
GM
7074 set_x_cursor:
7075
7076 /* Change the mouse cursor. */
7077 if (draw == DRAW_NORMAL_TEXT)
7078 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7079 f->output_data.x->text_cursor);
7080 else if (draw == DRAW_MOUSE_FACE)
334208b7 7081 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7082 f->output_data.x->cross_cursor);
27ead1d5 7083 else
334208b7 7084 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7085 f->output_data.x->nontext_cursor);
b8009dd1
RS
7086}
7087
7088/* Clear out the mouse-highlighted active region.
06a2c219 7089 Redraw it un-highlighted first. */
b8009dd1 7090
06a2c219 7091void
7a13e894
RS
7092clear_mouse_face (dpyinfo)
7093 struct x_display_info *dpyinfo;
b8009dd1 7094{
06a2c219
GM
7095 if (tip_frame)
7096 return;
7097
7a13e894 7098 if (! NILP (dpyinfo->mouse_face_window))
06a2c219 7099 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
b8009dd1 7100
7a13e894
RS
7101 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7102 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7103 dpyinfo->mouse_face_window = Qnil;
b8009dd1 7104}
e687d06e 7105
71b8321e
GM
7106
7107/* Clear any mouse-face on window W. This function is part of the
7108 redisplay interface, and is called from try_window_id and similar
7109 functions to ensure the mouse-highlight is off. */
7110
7111static void
7112x_clear_mouse_face (w)
7113 struct window *w;
7114{
7115 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7116 Lisp_Object window;
7117
7118 XSETWINDOW (window, w);
7119 if (EQ (window, dpyinfo->mouse_face_window))
7120 clear_mouse_face (dpyinfo);
7121}
7122
7123
e687d06e
RS
7124/* Just discard the mouse face information for frame F, if any.
7125 This is used when the size of F is changed. */
7126
dfcf069d 7127void
e687d06e
RS
7128cancel_mouse_face (f)
7129 FRAME_PTR f;
7130{
7131 Lisp_Object window;
7132 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7133
7134 window = dpyinfo->mouse_face_window;
7135 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7136 {
7137 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7138 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7139 dpyinfo->mouse_face_window = Qnil;
7140 }
7141}
b8009dd1 7142\f
ab648270
JB
7143static struct scroll_bar *x_window_to_scroll_bar ();
7144static void x_scroll_bar_report_motion ();
12ba150f 7145
90e65f07 7146/* Return the current position of the mouse.
2d7fc7e8 7147 *fp should be a frame which indicates which display to ask about.
90e65f07 7148
2d7fc7e8 7149 If the mouse movement started in a scroll bar, set *fp, *bar_window,
ab648270 7150 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 7151 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 7152 position on the scroll bar.
12ba150f 7153
2d7fc7e8 7154 If the mouse movement started elsewhere, set *fp to the frame the
12ba150f
JB
7155 mouse is on, *bar_window to nil, and *x and *y to the character cell
7156 the mouse is over.
7157
06a2c219 7158 Set *time to the server time-stamp for the time at which the mouse
12ba150f
JB
7159 was at this position.
7160
a135645a
RS
7161 Don't store anything if we don't have a valid set of values to report.
7162
90e65f07 7163 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7164 movement. */
90e65f07
JB
7165
7166static void
1cf412ec 7167XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7168 FRAME_PTR *fp;
1cf412ec 7169 int insist;
12ba150f 7170 Lisp_Object *bar_window;
ab648270 7171 enum scroll_bar_part *part;
90e65f07 7172 Lisp_Object *x, *y;
e5d77022 7173 unsigned long *time;
90e65f07 7174{
a135645a
RS
7175 FRAME_PTR f1;
7176
90e65f07
JB
7177 BLOCK_INPUT;
7178
8bcee03e 7179 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7180 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7181 else
7182 {
12ba150f
JB
7183 Window root;
7184 int root_x, root_y;
90e65f07 7185
12ba150f
JB
7186 Window dummy_window;
7187 int dummy;
7188
39d8bb4d
KH
7189 Lisp_Object frame, tail;
7190
7191 /* Clear the mouse-moved flag for every frame on this display. */
7192 FOR_EACH_FRAME (tail, frame)
7193 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7194 XFRAME (frame)->mouse_moved = 0;
7195
ab648270 7196 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7197
7198 /* Figure out which root window we're on. */
334208b7
RS
7199 XQueryPointer (FRAME_X_DISPLAY (*fp),
7200 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7201
7202 /* The root window which contains the pointer. */
7203 &root,
7204
7205 /* Trash which we can't trust if the pointer is on
7206 a different screen. */
7207 &dummy_window,
7208
7209 /* The position on that root window. */
58769bee 7210 &root_x, &root_y,
12ba150f
JB
7211
7212 /* More trash we can't trust. */
7213 &dummy, &dummy,
7214
7215 /* Modifier keys and pointer buttons, about which
7216 we don't care. */
7217 (unsigned int *) &dummy);
7218
7219 /* Now we have a position on the root; find the innermost window
7220 containing the pointer. */
7221 {
7222 Window win, child;
7223 int win_x, win_y;
06a2c219 7224 int parent_x = 0, parent_y = 0;
e99db5a1 7225 int count;
12ba150f
JB
7226
7227 win = root;
69388238 7228
2d7fc7e8
RS
7229 /* XTranslateCoordinates can get errors if the window
7230 structure is changing at the same time this function
7231 is running. So at least we must not crash from them. */
7232
e99db5a1 7233 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 7234
334208b7 7235 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 7236 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 7237 {
69388238
RS
7238 /* If mouse was grabbed on a frame, give coords for that frame
7239 even if the mouse is now outside it. */
334208b7 7240 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 7241
12ba150f 7242 /* From-window, to-window. */
69388238 7243 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
7244
7245 /* From-position, to-position. */
7246 root_x, root_y, &win_x, &win_y,
7247
7248 /* Child of win. */
7249 &child);
69388238
RS
7250 f1 = last_mouse_frame;
7251 }
7252 else
7253 {
7254 while (1)
7255 {
334208b7 7256 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 7257
69388238
RS
7258 /* From-window, to-window. */
7259 root, win,
12ba150f 7260
69388238
RS
7261 /* From-position, to-position. */
7262 root_x, root_y, &win_x, &win_y,
7263
7264 /* Child of win. */
7265 &child);
7266
9af3143a 7267 if (child == None || child == win)
69388238
RS
7268 break;
7269
7270 win = child;
7271 parent_x = win_x;
7272 parent_y = win_y;
7273 }
12ba150f 7274
69388238
RS
7275 /* Now we know that:
7276 win is the innermost window containing the pointer
7277 (XTC says it has no child containing the pointer),
7278 win_x and win_y are the pointer's position in it
7279 (XTC did this the last time through), and
7280 parent_x and parent_y are the pointer's position in win's parent.
7281 (They are what win_x and win_y were when win was child.
7282 If win is the root window, it has no parent, and
7283 parent_{x,y} are invalid, but that's okay, because we'll
7284 never use them in that case.) */
7285
7286 /* Is win one of our frames? */
19126e11 7287 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
69388238 7288 }
58769bee 7289
2d7fc7e8
RS
7290 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
7291 f1 = 0;
7292
e99db5a1 7293 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 7294
ab648270 7295 /* If not, is it one of our scroll bars? */
a135645a 7296 if (! f1)
12ba150f 7297 {
ab648270 7298 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
7299
7300 if (bar)
7301 {
a135645a 7302 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
7303 win_x = parent_x;
7304 win_y = parent_y;
7305 }
7306 }
90e65f07 7307
8bcee03e 7308 if (f1 == 0 && insist > 0)
b86bd3dd 7309 f1 = SELECTED_FRAME ();
1cf412ec 7310
a135645a 7311 if (f1)
12ba150f 7312 {
06a2c219
GM
7313 /* Ok, we found a frame. Store all the values.
7314 last_mouse_glyph is a rectangle used to reduce the
7315 generation of mouse events. To not miss any motion
7316 events, we must divide the frame into rectangles of the
7317 size of the smallest character that could be displayed
7318 on it, i.e. into the same rectangles that matrices on
7319 the frame are divided into. */
7320
7321#if OLD_REDISPLAY_CODE
2b5c9e71 7322 int ignore1, ignore2;
2b5c9e71 7323 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
334208b7 7324 &last_mouse_glyph,
1cf412ec
RS
7325 FRAME_X_DISPLAY_INFO (f1)->grabbed
7326 || insist);
06a2c219
GM
7327#else
7328 {
7329 int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
7330 int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
7331 int x = win_x;
7332 int y = win_y;
7333
7334 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
7335 round down even for negative values. */
7336 if (x < 0)
7337 x -= width - 1;
7338 if (y < 0)
7339 y -= height - 1;
7340
7341 last_mouse_glyph.width = width;
7342 last_mouse_glyph.height = height;
7343 last_mouse_glyph.x = (x + width - 1) / width * width;
7344 last_mouse_glyph.y = (y + height - 1) / height * height;
7345 }
7346#endif
12ba150f
JB
7347
7348 *bar_window = Qnil;
7349 *part = 0;
334208b7 7350 *fp = f1;
e0c1aef2
KH
7351 XSETINT (*x, win_x);
7352 XSETINT (*y, win_y);
12ba150f
JB
7353 *time = last_mouse_movement_time;
7354 }
7355 }
7356 }
90e65f07
JB
7357
7358 UNBLOCK_INPUT;
7359}
f451eb13 7360
06a2c219 7361
06a2c219 7362#ifdef USE_X_TOOLKIT
bffcfca9
GM
7363
7364/* Atimer callback function for TIMER. Called every 0.1s to process
7365 Xt timeouts, if needed. We must avoid calling XtAppPending as
7366 much as possible because that function does an implicit XFlush
7367 that slows us down. */
7368
7369static void
7370x_process_timeouts (timer)
7371 struct atimer *timer;
7372{
7373 if (toolkit_scroll_bar_interaction || popup_activated_flag)
7374 {
7375 BLOCK_INPUT;
7376 while (XtAppPending (Xt_app_con) & XtIMTimer)
7377 XtAppProcessEvent (Xt_app_con, XtIMTimer);
7378 UNBLOCK_INPUT;
7379 }
06a2c219
GM
7380}
7381
bffcfca9 7382#endif /* USE_X_TOOLKIT */
06a2c219
GM
7383
7384\f
7385/* Scroll bar support. */
7386
7387/* Given an X window ID, find the struct scroll_bar which manages it.
7388 This can be called in GC, so we have to make sure to strip off mark
7389 bits. */
bffcfca9 7390
06a2c219
GM
7391static struct scroll_bar *
7392x_window_to_scroll_bar (window_id)
7393 Window window_id;
7394{
7395 Lisp_Object tail;
7396
7397 for (tail = Vframe_list;
7398 XGCTYPE (tail) == Lisp_Cons;
8e713be6 7399 tail = XCDR (tail))
06a2c219
GM
7400 {
7401 Lisp_Object frame, bar, condemned;
7402
8e713be6 7403 frame = XCAR (tail);
06a2c219
GM
7404 /* All elements of Vframe_list should be frames. */
7405 if (! GC_FRAMEP (frame))
7406 abort ();
7407
7408 /* Scan this frame's scroll bar list for a scroll bar with the
7409 right window ID. */
7410 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
7411 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
7412 /* This trick allows us to search both the ordinary and
7413 condemned scroll bar lists with one loop. */
7414 ! GC_NILP (bar) || (bar = condemned,
7415 condemned = Qnil,
7416 ! GC_NILP (bar));
7417 bar = XSCROLL_BAR (bar)->next)
7418 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
7419 return XSCROLL_BAR (bar);
7420 }
7421
7422 return 0;
7423}
7424
7425
7426\f
7427/************************************************************************
7428 Toolkit scroll bars
7429 ************************************************************************/
7430
7431#if USE_TOOLKIT_SCROLL_BARS
7432
7433static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
7434static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
7435static void x_create_toolkit_scroll_bar P_ ((struct frame *,
7436 struct scroll_bar *));
7437static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
7438 int, int, int));
7439
7440
7441/* Id of action hook installed for scroll bars. */
7442
7443static XtActionHookId action_hook_id;
7444
7445/* Lisp window being scrolled. Set when starting to interact with
7446 a toolkit scroll bar, reset to nil when ending the interaction. */
7447
7448static Lisp_Object window_being_scrolled;
7449
7450/* Last scroll bar part sent in xm_scroll_callback. */
7451
7452static int last_scroll_bar_part;
7453
ec18280f
SM
7454/* Whether this is an Xaw with arrow-scrollbars. This should imply
7455 that movements of 1/20 of the screen size are mapped to up/down. */
7456
7457static Boolean xaw3d_arrow_scroll;
7458
7459/* Whether the drag scrolling maintains the mouse at the top of the
7460 thumb. If not, resizing the thumb needs to be done more carefully
7461 to avoid jerkyness. */
7462
7463static Boolean xaw3d_pick_top;
7464
06a2c219
GM
7465
7466/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 7467 bars are used.. The hook is responsible for detecting when
06a2c219
GM
7468 the user ends an interaction with the scroll bar, and generates
7469 a `end-scroll' scroll_bar_click' event if so. */
7470
7471static void
7472xt_action_hook (widget, client_data, action_name, event, params,
7473 num_params)
7474 Widget widget;
7475 XtPointer client_data;
7476 String action_name;
7477 XEvent *event;
7478 String *params;
7479 Cardinal *num_params;
7480{
7481 int scroll_bar_p;
7482 char *end_action;
7483
7484#ifdef USE_MOTIF
7485 scroll_bar_p = XmIsScrollBar (widget);
7486 end_action = "Release";
ec18280f 7487#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7488 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
7489 end_action = "EndScroll";
ec18280f 7490#endif /* USE_MOTIF */
06a2c219 7491
06a2c219
GM
7492 if (scroll_bar_p
7493 && strcmp (action_name, end_action) == 0
7494 && WINDOWP (window_being_scrolled))
7495 {
7496 struct window *w;
7497
7498 x_send_scroll_bar_event (window_being_scrolled,
7499 scroll_bar_end_scroll, 0, 0);
7500 w = XWINDOW (window_being_scrolled);
7501 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
7502 window_being_scrolled = Qnil;
7503 last_scroll_bar_part = -1;
bffcfca9
GM
7504
7505 /* Xt timeouts no longer needed. */
7506 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
7507 }
7508}
7509
7510
7511/* Send a client message with message type Xatom_Scrollbar for a
7512 scroll action to the frame of WINDOW. PART is a value identifying
7513 the part of the scroll bar that was clicked on. PORTION is the
7514 amount to scroll of a whole of WHOLE. */
7515
7516static void
7517x_send_scroll_bar_event (window, part, portion, whole)
7518 Lisp_Object window;
7519 int part, portion, whole;
7520{
7521 XEvent event;
7522 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
7523 struct frame *f = XFRAME (XWINDOW (window)->frame);
7524
7525 /* Construct a ClientMessage event to send to the frame. */
7526 ev->type = ClientMessage;
7527 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
7528 ev->display = FRAME_X_DISPLAY (f);
7529 ev->window = FRAME_X_WINDOW (f);
7530 ev->format = 32;
52e386c2 7531 ev->data.l[0] = (long) XFASTINT (window);
06a2c219
GM
7532 ev->data.l[1] = (long) part;
7533 ev->data.l[2] = (long) 0;
7534 ev->data.l[3] = (long) portion;
7535 ev->data.l[4] = (long) whole;
7536
bffcfca9
GM
7537 /* Make Xt timeouts work while the scroll bar is active. */
7538 toolkit_scroll_bar_interaction = 1;
7539
06a2c219
GM
7540 /* Setting the event mask to zero means that the message will
7541 be sent to the client that created the window, and if that
7542 window no longer exists, no event will be sent. */
7543 BLOCK_INPUT;
7544 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
7545 UNBLOCK_INPUT;
7546}
7547
7548
7549/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
7550 in *IEVENT. */
7551
7552static void
7553x_scroll_bar_to_input_event (event, ievent)
7554 XEvent *event;
7555 struct input_event *ievent;
7556{
7557 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
7558 Lisp_Object window;
7559 struct frame *f;
7560
7561 XSETFASTINT (window, ev->data.l[0]);
7562 f = XFRAME (XWINDOW (window)->frame);
06a2c219
GM
7563
7564 ievent->kind = scroll_bar_click;
7565 ievent->frame_or_window = window;
7566 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
7567 ievent->part = ev->data.l[1];
7568 ievent->code = ev->data.l[2];
7569 ievent->x = make_number ((int) ev->data.l[3]);
7570 ievent->y = make_number ((int) ev->data.l[4]);
7571 ievent->modifiers = 0;
7572}
7573
7574
7575#ifdef USE_MOTIF
7576
7577/* Minimum and maximum values used for Motif scroll bars. */
7578
7579#define XM_SB_MIN 1
7580#define XM_SB_MAX 10000000
7581#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
7582
7583
7584/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
7585 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
7586 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
7587
7588static void
7589xm_scroll_callback (widget, client_data, call_data)
7590 Widget widget;
7591 XtPointer client_data, call_data;
7592{
7593 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7594 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
7595 double percent;
7596 int part = -1, whole = 0, portion = 0;
7597
7598 switch (cs->reason)
7599 {
7600 case XmCR_DECREMENT:
7601 bar->dragging = Qnil;
7602 part = scroll_bar_up_arrow;
7603 break;
7604
7605 case XmCR_INCREMENT:
7606 bar->dragging = Qnil;
7607 part = scroll_bar_down_arrow;
7608 break;
7609
7610 case XmCR_PAGE_DECREMENT:
7611 bar->dragging = Qnil;
7612 part = scroll_bar_above_handle;
7613 break;
7614
7615 case XmCR_PAGE_INCREMENT:
7616 bar->dragging = Qnil;
7617 part = scroll_bar_below_handle;
7618 break;
7619
7620 case XmCR_TO_TOP:
7621 bar->dragging = Qnil;
7622 part = scroll_bar_to_top;
7623 break;
7624
7625 case XmCR_TO_BOTTOM:
7626 bar->dragging = Qnil;
7627 part = scroll_bar_to_bottom;
7628 break;
7629
7630 case XmCR_DRAG:
7631 {
7632 int slider_size;
7633 int dragging_down_p = (INTEGERP (bar->dragging)
7634 && XINT (bar->dragging) <= cs->value);
7635
7636 /* Get the slider size. */
7637 BLOCK_INPUT;
7638 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
7639 UNBLOCK_INPUT;
7640
7641 /* At the max position of the scroll bar, do a line-wise
7642 movement. Without doing anything, the LessTif scroll bar
7643 calls us with the same cs->value again and again. If we
7644 want to make sure that we can reach the end of the buffer,
7645 we have to do something.
7646
7647 Implementation note: setting bar->dragging always to
7648 cs->value gives a smoother movement at the max position.
7649 Setting it to nil when doing line-wise movement gives
7650 a better slider behavior. */
7651
7652 if (cs->value + slider_size == XM_SB_MAX
7653 || (dragging_down_p
7654 && last_scroll_bar_part == scroll_bar_down_arrow))
7655 {
7656 part = scroll_bar_down_arrow;
7657 bar->dragging = Qnil;
7658 }
7659 else
7660 {
7661 whole = XM_SB_RANGE;
7662 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
7663 part = scroll_bar_handle;
7664 bar->dragging = make_number (cs->value);
7665 }
7666 }
7667 break;
7668
7669 case XmCR_VALUE_CHANGED:
7670 break;
7671 };
7672
7673 if (part >= 0)
7674 {
7675 window_being_scrolled = bar->window;
7676 last_scroll_bar_part = part;
7677 x_send_scroll_bar_event (bar->window, part, portion, whole);
7678 }
7679}
7680
7681
ec18280f 7682#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
7683
7684
ec18280f 7685/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
7686 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
7687 scroll bar struct. CALL_DATA is a pointer to a float saying where
7688 the thumb is. */
7689
7690static void
ec18280f 7691xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
7692 Widget widget;
7693 XtPointer client_data, call_data;
7694{
7695 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7696 float top = *(float *) call_data;
7697 float shown;
ec18280f
SM
7698 int whole, portion, height;
7699 int part;
06a2c219
GM
7700
7701 /* Get the size of the thumb, a value between 0 and 1. */
7702 BLOCK_INPUT;
ec18280f 7703 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
7704 UNBLOCK_INPUT;
7705
7706 whole = 10000000;
7707 portion = shown < 1 ? top * whole : 0;
06a2c219 7708
ec18280f
SM
7709 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
7710 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
7711 the bottom, so we force the scrolling whenever we see that we're
7712 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
7713 we try to ensure that we always stay two pixels away from the
7714 bottom). */
06a2c219
GM
7715 part = scroll_bar_down_arrow;
7716 else
7717 part = scroll_bar_handle;
7718
7719 window_being_scrolled = bar->window;
7720 bar->dragging = make_number (portion);
7721 last_scroll_bar_part = part;
7722 x_send_scroll_bar_event (bar->window, part, portion, whole);
7723}
7724
7725
ec18280f
SM
7726/* Xaw scroll bar callback. Invoked for incremental scrolling.,
7727 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
7728 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
7729 the scroll bar. CALL_DATA is an integer specifying the action that
7730 has taken place. It's magnitude is in the range 0..height of the
7731 scroll bar. Negative values mean scroll towards buffer start.
7732 Values < height of scroll bar mean line-wise movement. */
7733
7734static void
ec18280f 7735xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
7736 Widget widget;
7737 XtPointer client_data, call_data;
7738{
7739 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7740 int position = (int) call_data;
7741 Dimension height;
7742 int part;
7743
7744 /* Get the height of the scroll bar. */
7745 BLOCK_INPUT;
7746 XtVaGetValues (widget, XtNheight, &height, NULL);
7747 UNBLOCK_INPUT;
7748
ec18280f
SM
7749 if (abs (position) >= height)
7750 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
7751
7752 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
7753 it maps line-movement to call_data = max(5, height/20). */
7754 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
7755 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 7756 else
ec18280f 7757 part = scroll_bar_move_ratio;
06a2c219
GM
7758
7759 window_being_scrolled = bar->window;
7760 bar->dragging = Qnil;
7761 last_scroll_bar_part = part;
ec18280f 7762 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
7763}
7764
7765
7766#endif /* not USE_MOTIF */
7767
7768
7769/* Create the widget for scroll bar BAR on frame F. Record the widget
7770 and X window of the scroll bar in BAR. */
7771
7772static void
7773x_create_toolkit_scroll_bar (f, bar)
7774 struct frame *f;
7775 struct scroll_bar *bar;
7776{
7777 Window xwindow;
7778 Widget widget;
7779 Arg av[20];
7780 int ac = 0;
7781 char *scroll_bar_name = "verticalScrollBar";
7782 unsigned long pixel;
7783
7784 BLOCK_INPUT;
7785
7786#ifdef USE_MOTIF
7787 /* LessTif 0.85, problems:
7788
7789 1. When the mouse if over the scroll bar, the scroll bar will
7790 get keyboard events. I didn't find a way to turn this off.
7791
7792 2. Do we have to explicitly set the cursor to get an arrow
7793 cursor (see below)? */
7794
7795 /* Set resources. Create the widget. */
7796 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7797 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
7798 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
7799 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
7800 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
7801 XtSetArg (av[ac], XmNincrement, 1); ++ac;
7802 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
7803
7804 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7805 if (pixel != -1)
7806 {
7807 XtSetArg (av[ac], XmNforeground, pixel);
7808 ++ac;
7809 }
7810
7811 pixel = f->output_data.x->scroll_bar_background_pixel;
7812 if (pixel != -1)
7813 {
7814 XtSetArg (av[ac], XmNbackground, pixel);
7815 ++ac;
7816 }
7817
7818 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
7819 scroll_bar_name, av, ac);
7820
7821 /* Add one callback for everything that can happen. */
7822 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
7823 (XtPointer) bar);
7824 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
7825 (XtPointer) bar);
7826 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
7827 (XtPointer) bar);
7828 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
7829 (XtPointer) bar);
7830 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
7831 (XtPointer) bar);
7832 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
7833 (XtPointer) bar);
7834 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
7835 (XtPointer) bar);
7836
7837 /* Realize the widget. Only after that is the X window created. */
7838 XtRealizeWidget (widget);
7839
7840 /* Set the cursor to an arrow. I didn't find a resource to do that.
7841 And I'm wondering why it hasn't an arrow cursor by default. */
7842 XDefineCursor (XtDisplay (widget), XtWindow (widget),
7843 f->output_data.x->nontext_cursor);
7844
ec18280f 7845#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7846
7847 /* Set resources. Create the widget. The background of the
7848 Xaw3d scroll bar widget is a little bit light for my taste.
7849 We don't alter it here to let users change it according
7850 to their taste with `emacs*verticalScrollBar.background: xxx'. */
7851 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7852 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
7853 /* For smoother scrolling with Xaw3d -sm */
7854 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
7855 /* XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac; */
06a2c219
GM
7856
7857 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7858 if (pixel != -1)
7859 {
7860 XtSetArg (av[ac], XtNforeground, pixel);
7861 ++ac;
7862 }
7863
7864 pixel = f->output_data.x->scroll_bar_background_pixel;
7865 if (pixel != -1)
7866 {
7867 XtSetArg (av[ac], XtNbackground, pixel);
7868 ++ac;
7869 }
7870
7871 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
7872 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
7873
7874 {
7875 char *initial = "";
7876 char *val = initial;
7877 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
7878 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
7879 if (val == initial)
7880 { /* ARROW_SCROLL */
7881 xaw3d_arrow_scroll = True;
7882 /* Isn't that just a personal preference ? -sm */
7883 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
7884 }
7885 }
06a2c219
GM
7886
7887 /* Define callbacks. */
ec18280f
SM
7888 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
7889 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
7890 (XtPointer) bar);
7891
7892 /* Realize the widget. Only after that is the X window created. */
7893 XtRealizeWidget (widget);
7894
ec18280f 7895#endif /* !USE_MOTIF */
06a2c219
GM
7896
7897 /* Install an action hook that let's us detect when the user
7898 finishes interacting with a scroll bar. */
7899 if (action_hook_id == 0)
7900 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
7901
7902 /* Remember X window and widget in the scroll bar vector. */
7903 SET_SCROLL_BAR_X_WIDGET (bar, widget);
7904 xwindow = XtWindow (widget);
7905 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
7906
7907 UNBLOCK_INPUT;
7908}
7909
7910
7911/* Set the thumb size and position of scroll bar BAR. We are currently
7912 displaying PORTION out of a whole WHOLE, and our position POSITION. */
7913
7914static void
7915x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
7916 struct scroll_bar *bar;
7917 int portion, position, whole;
f451eb13 7918{
06a2c219 7919 float top, shown;
06a2c219 7920 Widget widget = SCROLL_BAR_X_WIDGET (bar);
f451eb13 7921
06a2c219
GM
7922 if (whole == 0)
7923 top = 0, shown = 1;
7924 else
f451eb13 7925 {
06a2c219
GM
7926 top = (float) position / whole;
7927 shown = (float) portion / whole;
7928 }
f451eb13 7929
06a2c219 7930 BLOCK_INPUT;
f451eb13 7931
06a2c219
GM
7932#ifdef USE_MOTIF
7933 {
7934 int size, value;
7935 Boolean arrow1_selected, arrow2_selected;
7936 unsigned char flags;
7937 XmScrollBarWidget sb;
7938
ec18280f 7939 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
7940 is the scroll bar's maximum and MIN is the scroll bar's minimum
7941 value. */
7942 size = shown * XM_SB_RANGE;
7943 size = min (size, XM_SB_RANGE);
7944 size = max (size, 1);
7945
7946 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
7947 value = top * XM_SB_RANGE;
7948 value = min (value, XM_SB_MAX - size);
7949 value = max (value, XM_SB_MIN);
7950
7951 /* LessTif: Calling XmScrollBarSetValues after an increment or
7952 decrement turns off auto-repeat LessTif-internally. This can
7953 be seen in ScrollBar.c which resets Arrow1Selected and
7954 Arrow2Selected. It also sets internal flags so that LessTif
7955 believes the mouse is in the slider. We either have to change
7956 our code, or work around that by accessing private data. */
7957
7958 sb = (XmScrollBarWidget) widget;
7959 arrow1_selected = sb->scrollBar.arrow1_selected;
7960 arrow2_selected = sb->scrollBar.arrow2_selected;
7961 flags = sb->scrollBar.flags;
7962
7963 if (NILP (bar->dragging))
7964 XmScrollBarSetValues (widget, value, size, 0, 0, False);
7965 else if (last_scroll_bar_part == scroll_bar_down_arrow)
7966 /* This has the negative side effect that the slider value is
ec18280f 7967 not what it would be if we scrolled here using line-wise or
06a2c219
GM
7968 page-wise movement. */
7969 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
7970 else
7971 {
7972 /* If currently dragging, only update the slider size.
7973 This reduces flicker effects. */
7974 int old_value, old_size, increment, page_increment;
7975
7976 XmScrollBarGetValues (widget, &old_value, &old_size,
7977 &increment, &page_increment);
7978 XmScrollBarSetValues (widget, old_value,
7979 min (size, XM_SB_RANGE - old_value),
7980 0, 0, False);
7981 }
7982
7983 sb->scrollBar.arrow1_selected = arrow1_selected;
7984 sb->scrollBar.arrow2_selected = arrow2_selected;
7985 sb->scrollBar.flags = flags;
7986 }
ec18280f 7987#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 7988 {
ec18280f
SM
7989 float old_top, old_shown;
7990 Dimension height;
7991 XtVaGetValues (widget,
7992 XtNtopOfThumb, &old_top,
7993 XtNshown, &old_shown,
7994 XtNheight, &height,
7995 NULL);
7996
7997 /* Massage the top+shown values. */
7998 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
7999 top = max (0, min (1, top));
8000 else
8001 top = old_top;
8002 /* Keep two pixels available for moving the thumb down. */
8003 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8004
8005 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8006 check that your system's configuration file contains a define
8007 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8008 if (top != old_top || shown != old_shown)
eb393530 8009 {
ec18280f 8010 if (NILP (bar->dragging))
eb393530 8011 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8012 else
8013 {
ec18280f
SM
8014#ifdef HAVE_XAW3D
8015 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8016 int scroll_mode = 0;
ec18280f
SM
8017
8018 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8019 if (xaw3d_arrow_scroll)
8020 {
8021 /* Xaw3d stupidly ignores resize requests while dragging
8022 so we have to make it believe it's not in dragging mode. */
8023 scroll_mode = sb->scrollbar.scroll_mode;
8024 if (scroll_mode == 2)
8025 sb->scrollbar.scroll_mode = 0;
8026 }
8027#endif
8028 /* Try to make the scrolling a tad smoother. */
8029 if (!xaw3d_pick_top)
8030 shown = min (shown, old_shown);
8031
8032 XawScrollbarSetThumb (widget, top, shown);
8033
8034#ifdef HAVE_XAW3D
8035 if (xaw3d_arrow_scroll && scroll_mode == 2)
8036 sb->scrollbar.scroll_mode = scroll_mode;
8037#endif
06a2c219 8038 }
06a2c219
GM
8039 }
8040 }
ec18280f 8041#endif /* !USE_MOTIF */
06a2c219
GM
8042
8043 UNBLOCK_INPUT;
f451eb13
JB
8044}
8045
06a2c219
GM
8046#endif /* USE_TOOLKIT_SCROLL_BARS */
8047
8048
8049\f
8050/************************************************************************
8051 Scroll bars, general
8052 ************************************************************************/
8053
8054/* Create a scroll bar and return the scroll bar vector for it. W is
8055 the Emacs window on which to create the scroll bar. TOP, LEFT,
8056 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8057 scroll bar. */
8058
ab648270 8059static struct scroll_bar *
06a2c219
GM
8060x_scroll_bar_create (w, top, left, width, height)
8061 struct window *w;
f451eb13
JB
8062 int top, left, width, height;
8063{
06a2c219 8064 struct frame *f = XFRAME (w->frame);
334208b7
RS
8065 struct scroll_bar *bar
8066 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8067
8068 BLOCK_INPUT;
8069
06a2c219
GM
8070#if USE_TOOLKIT_SCROLL_BARS
8071 x_create_toolkit_scroll_bar (f, bar);
8072#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8073 {
8074 XSetWindowAttributes a;
8075 unsigned long mask;
5c187dee 8076 Window window;
06a2c219
GM
8077
8078 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8079 if (a.background_pixel == -1)
8080 a.background_pixel = f->output_data.x->background_pixel;
8081
12ba150f 8082 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8083 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8084 | ExposureMask);
7a13e894 8085 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8086
dbc4e1c1 8087 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8088
06a2c219
GM
8089 /* Clear the area of W that will serve as a scroll bar. This is
8090 for the case that a window has been split horizontally. In
8091 this case, no clear_frame is generated to reduce flickering. */
8092 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8093 left, top, width,
8094 window_box_height (w), False);
8095
8096 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8097 /* Position and size of scroll bar. */
8098 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8099 top,
8100 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8101 height,
8102 /* Border width, depth, class, and visual. */
8103 0,
8104 CopyFromParent,
8105 CopyFromParent,
8106 CopyFromParent,
8107 /* Attributes. */
8108 mask, &a);
8109 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8110 }
06a2c219 8111#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8112
06a2c219 8113 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8114 XSETINT (bar->top, top);
8115 XSETINT (bar->left, left);
8116 XSETINT (bar->width, width);
8117 XSETINT (bar->height, height);
8118 XSETINT (bar->start, 0);
8119 XSETINT (bar->end, 0);
12ba150f 8120 bar->dragging = Qnil;
f451eb13
JB
8121
8122 /* Add bar to its frame's list of scroll bars. */
334208b7 8123 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8124 bar->prev = Qnil;
334208b7 8125 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 8126 if (!NILP (bar->next))
e0c1aef2 8127 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 8128
06a2c219
GM
8129 /* Map the window/widget. */
8130#if USE_TOOLKIT_SCROLL_BARS
8131 XtMapWidget (SCROLL_BAR_X_WIDGET (bar));
8132 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
8133 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8134 top,
8135 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8136 height, 0);
8137#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 8138 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 8139#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8140
8141 UNBLOCK_INPUT;
12ba150f 8142 return bar;
f451eb13
JB
8143}
8144
06a2c219 8145
12ba150f 8146/* Draw BAR's handle in the proper position.
06a2c219 8147
12ba150f
JB
8148 If the handle is already drawn from START to END, don't bother
8149 redrawing it, unless REBUILD is non-zero; in that case, always
8150 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 8151 events.)
12ba150f
JB
8152
8153 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
8154 fit inside its rectangle, but if the user is dragging the scroll
8155 bar handle, we want to let them drag it down all the way, so that
8156 the bar's top is as far down as it goes; otherwise, there's no way
8157 to move to the very end of the buffer. */
8158
5c187dee
GM
8159#ifndef USE_TOOLKIT_SCROLL_BARS
8160
f451eb13 8161static void
ab648270
JB
8162x_scroll_bar_set_handle (bar, start, end, rebuild)
8163 struct scroll_bar *bar;
f451eb13 8164 int start, end;
12ba150f 8165 int rebuild;
f451eb13 8166{
12ba150f 8167 int dragging = ! NILP (bar->dragging);
ab648270 8168 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8169 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8170 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
8171
8172 /* If the display is already accurate, do nothing. */
8173 if (! rebuild
8174 && start == XINT (bar->start)
8175 && end == XINT (bar->end))
8176 return;
8177
f451eb13
JB
8178 BLOCK_INPUT;
8179
8180 {
d9cdbb3d
RS
8181 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
8182 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
8183 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
8184
8185 /* Make sure the values are reasonable, and try to preserve
8186 the distance between start and end. */
12ba150f
JB
8187 {
8188 int length = end - start;
8189
8190 if (start < 0)
8191 start = 0;
8192 else if (start > top_range)
8193 start = top_range;
8194 end = start + length;
8195
8196 if (end < start)
8197 end = start;
8198 else if (end > top_range && ! dragging)
8199 end = top_range;
8200 }
f451eb13 8201
ab648270 8202 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
8203 XSETINT (bar->start, start);
8204 XSETINT (bar->end, end);
f451eb13 8205
12ba150f
JB
8206 /* Clip the end position, just for display. */
8207 if (end > top_range)
8208 end = top_range;
f451eb13 8209
ab648270 8210 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
8211 below top positions, to make sure the handle is always at least
8212 that many pixels tall. */
ab648270 8213 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 8214
12ba150f
JB
8215 /* Draw the empty space above the handle. Note that we can't clear
8216 zero-height areas; that means "clear to end of window." */
8217 if (0 < start)
334208b7 8218 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8219
12ba150f 8220 /* x, y, width, height, and exposures. */
ab648270
JB
8221 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8222 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
8223 inside_width, start,
8224 False);
f451eb13 8225
06a2c219
GM
8226 /* Change to proper foreground color if one is specified. */
8227 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8228 XSetForeground (FRAME_X_DISPLAY (f), gc,
8229 f->output_data.x->scroll_bar_foreground_pixel);
8230
12ba150f 8231 /* Draw the handle itself. */
334208b7 8232 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 8233
12ba150f 8234 /* x, y, width, height */
ab648270
JB
8235 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8236 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 8237 inside_width, end - start);
f451eb13 8238
06a2c219
GM
8239 /* Restore the foreground color of the GC if we changed it above. */
8240 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8241 XSetForeground (FRAME_X_DISPLAY (f), gc,
8242 f->output_data.x->foreground_pixel);
f451eb13 8243
12ba150f
JB
8244 /* Draw the empty space below the handle. Note that we can't
8245 clear zero-height areas; that means "clear to end of window." */
8246 if (end < inside_height)
334208b7 8247 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8248
12ba150f 8249 /* x, y, width, height, and exposures. */
ab648270
JB
8250 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8251 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
8252 inside_width, inside_height - end,
8253 False);
f451eb13 8254
f451eb13
JB
8255 }
8256
f451eb13
JB
8257 UNBLOCK_INPUT;
8258}
8259
5c187dee 8260#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 8261
06a2c219
GM
8262/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
8263 nil. */
58769bee 8264
12ba150f 8265static void
ab648270
JB
8266x_scroll_bar_remove (bar)
8267 struct scroll_bar *bar;
12ba150f 8268{
12ba150f
JB
8269 BLOCK_INPUT;
8270
06a2c219
GM
8271#if USE_TOOLKIT_SCROLL_BARS
8272 XtDestroyWidget (SCROLL_BAR_X_WIDGET (bar));
8273#else /* not USE_TOOLKIT_SCROLL_BARS */
5c187dee
GM
8274 {
8275 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8276 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
8277 }
06a2c219
GM
8278#endif /* not USE_TOOLKIT_SCROLL_BARS */
8279
ab648270
JB
8280 /* Disassociate this scroll bar from its window. */
8281 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
8282
8283 UNBLOCK_INPUT;
8284}
8285
06a2c219 8286
12ba150f
JB
8287/* Set the handle of the vertical scroll bar for WINDOW to indicate
8288 that we are displaying PORTION characters out of a total of WHOLE
ab648270 8289 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 8290 create one. */
06a2c219 8291
12ba150f 8292static void
06a2c219
GM
8293XTset_vertical_scroll_bar (w, portion, whole, position)
8294 struct window *w;
f451eb13
JB
8295 int portion, whole, position;
8296{
06a2c219 8297 struct frame *f = XFRAME (w->frame);
ab648270 8298 struct scroll_bar *bar;
3c6ede7b 8299 int top, height, left, sb_left, width, sb_width;
06a2c219 8300 int window_x, window_y, window_width, window_height;
06a2c219 8301
3c6ede7b 8302 /* Get window dimensions. */
06a2c219 8303 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
8304 top = window_y;
8305 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
8306 height = window_height;
06a2c219 8307
3c6ede7b 8308 /* Compute the left edge of the scroll bar area. */
06a2c219 8309 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
8310 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
8311 else
8312 left = XFASTINT (w->left);
8313 left *= CANON_X_UNIT (f);
8314 left += FRAME_INTERNAL_BORDER_WIDTH (f);
8315
8316 /* Compute the width of the scroll bar which might be less than
8317 the width of the area reserved for the scroll bar. */
8318 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
8319 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 8320 else
3c6ede7b 8321 sb_width = width;
12ba150f 8322
3c6ede7b
GM
8323 /* Compute the left edge of the scroll bar. */
8324#ifdef USE_TOOLKIT_SCROLL_BARS
8325 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8326 sb_left = left + width - sb_width - (width - sb_width) / 2;
8327 else
8328 sb_left = left + (width - sb_width) / 2;
8329#else
8330 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8331 sb_left = left + width - sb_width;
8332 else
8333 sb_left = left;
8334#endif
8335
ab648270 8336 /* Does the scroll bar exist yet? */
06a2c219 8337 if (NILP (w->vertical_scroll_bar))
3c6ede7b 8338 {
80c32bcc 8339 BLOCK_INPUT;
3c6ede7b
GM
8340 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8341 left, top, width, height, False);
80c32bcc 8342 UNBLOCK_INPUT;
3c6ede7b
GM
8343 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
8344 }
f451eb13 8345 else
12ba150f
JB
8346 {
8347 /* It may just need to be moved and resized. */
06a2c219
GM
8348 unsigned int mask = 0;
8349
8350 bar = XSCROLL_BAR (w->vertical_scroll_bar);
8351
8352 BLOCK_INPUT;
8353
3c6ede7b 8354 if (sb_left != XINT (bar->left))
06a2c219 8355 mask |= CWX;
3c6ede7b 8356 if (top != XINT (bar->top))
06a2c219 8357 mask |= CWY;
3c6ede7b 8358 if (sb_width != XINT (bar->width))
06a2c219 8359 mask |= CWWidth;
3c6ede7b 8360 if (height != XINT (bar->height))
06a2c219
GM
8361 mask |= CWHeight;
8362
8363#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
8364
8365 /* Since toolkit scroll bars are smaller than the space reserved
8366 for them on the frame, we have to clear "under" them. */
8367 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3c6ede7b 8368 left, top, width, height, False);
06a2c219
GM
8369
8370 /* Move/size the scroll bar widget. */
8371 if (mask)
8372 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
3c6ede7b
GM
8373 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8374 top,
8375 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8376 height, 0);
06a2c219
GM
8377
8378#else /* not USE_TOOLKIT_SCROLL_BARS */
8379
e1f6572f
RS
8380 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
8381 {
8382 /* Clear areas not covered by the scroll bar. This makes sure a
8383 previous mode line display is cleared after C-x 2 C-x 1, for
8384 example. Non-toolkit scroll bars are as wide as the area
8385 reserved for scroll bars - trim at both sides. */
8386 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8387 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8388 height, False);
8389 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8390 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8391 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8392 height, False);
8393 }
06a2c219
GM
8394
8395 /* Move/size the scroll bar window. */
8396 if (mask)
8397 {
8398 XWindowChanges wc;
8399
3c6ede7b
GM
8400 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
8401 wc.y = top;
8402 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
8403 wc.height = height;
06a2c219
GM
8404 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
8405 mask, &wc);
8406 }
8407
8408#endif /* not USE_TOOLKIT_SCROLL_BARS */
8409
8410 /* Remember new settings. */
3c6ede7b
GM
8411 XSETINT (bar->left, sb_left);
8412 XSETINT (bar->top, top);
8413 XSETINT (bar->width, sb_width);
8414 XSETINT (bar->height, height);
06a2c219
GM
8415
8416 UNBLOCK_INPUT;
12ba150f 8417 }
f451eb13 8418
06a2c219
GM
8419#if USE_TOOLKIT_SCROLL_BARS
8420 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
8421#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 8422 /* Set the scroll bar's current state, unless we're currently being
f451eb13 8423 dragged. */
12ba150f 8424 if (NILP (bar->dragging))
f451eb13 8425 {
92857db0 8426 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 8427
12ba150f 8428 if (whole == 0)
ab648270 8429 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
8430 else
8431 {
43f868f5
JB
8432 int start = ((double) position * top_range) / whole;
8433 int end = ((double) (position + portion) * top_range) / whole;
ab648270 8434 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 8435 }
f451eb13 8436 }
06a2c219 8437#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8438
06a2c219 8439 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
8440}
8441
12ba150f 8442
f451eb13 8443/* The following three hooks are used when we're doing a thorough
ab648270 8444 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 8445 are going to be deleted, because keeping track of when windows go
12ba150f
JB
8446 away is a real pain - "Can you say set-window-configuration, boys
8447 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 8448 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 8449 from the fiery pit when we actually redisplay its window. */
f451eb13 8450
ab648270
JB
8451/* Arrange for all scroll bars on FRAME to be removed at the next call
8452 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
8453 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
8454
58769bee 8455static void
ab648270 8456XTcondemn_scroll_bars (frame)
f451eb13
JB
8457 FRAME_PTR frame;
8458{
f9e24cb9
RS
8459 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
8460 while (! NILP (FRAME_SCROLL_BARS (frame)))
8461 {
8462 Lisp_Object bar;
8463 bar = FRAME_SCROLL_BARS (frame);
8464 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
8465 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
8466 XSCROLL_BAR (bar)->prev = Qnil;
8467 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
8468 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
8469 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
8470 }
f451eb13
JB
8471}
8472
06a2c219 8473/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 8474 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 8475static void
ab648270 8476XTredeem_scroll_bar (window)
12ba150f 8477 struct window *window;
f451eb13 8478{
ab648270 8479 struct scroll_bar *bar;
12ba150f 8480
ab648270
JB
8481 /* We can't redeem this window's scroll bar if it doesn't have one. */
8482 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
8483 abort ();
8484
ab648270 8485 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
8486
8487 /* Unlink it from the condemned list. */
8488 {
8489 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
8490
8491 if (NILP (bar->prev))
8492 {
8493 /* If the prev pointer is nil, it must be the first in one of
8494 the lists. */
ab648270 8495 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
8496 /* It's not condemned. Everything's fine. */
8497 return;
ab648270
JB
8498 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
8499 window->vertical_scroll_bar))
8500 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
8501 else
8502 /* If its prev pointer is nil, it must be at the front of
8503 one or the other! */
8504 abort ();
8505 }
8506 else
ab648270 8507 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
8508
8509 if (! NILP (bar->next))
ab648270 8510 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 8511
ab648270 8512 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8513 bar->prev = Qnil;
e0c1aef2 8514 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 8515 if (! NILP (bar->next))
e0c1aef2 8516 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
12ba150f 8517 }
f451eb13
JB
8518}
8519
ab648270
JB
8520/* Remove all scroll bars on FRAME that haven't been saved since the
8521 last call to `*condemn_scroll_bars_hook'. */
06a2c219 8522
f451eb13 8523static void
ab648270 8524XTjudge_scroll_bars (f)
12ba150f 8525 FRAME_PTR f;
f451eb13 8526{
12ba150f 8527 Lisp_Object bar, next;
f451eb13 8528
ab648270 8529 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
8530
8531 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
8532 more events on the hapless scroll bars. */
8533 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
8534
8535 for (; ! NILP (bar); bar = next)
f451eb13 8536 {
ab648270 8537 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 8538
ab648270 8539 x_scroll_bar_remove (b);
12ba150f
JB
8540
8541 next = b->next;
8542 b->next = b->prev = Qnil;
f451eb13 8543 }
12ba150f 8544
ab648270 8545 /* Now there should be no references to the condemned scroll bars,
12ba150f 8546 and they should get garbage-collected. */
f451eb13
JB
8547}
8548
8549
06a2c219
GM
8550/* Handle an Expose or GraphicsExpose event on a scroll bar. This
8551 is a no-op when using toolkit scroll bars.
ab648270
JB
8552
8553 This may be called from a signal handler, so we have to ignore GC
8554 mark bits. */
06a2c219 8555
f451eb13 8556static void
ab648270
JB
8557x_scroll_bar_expose (bar, event)
8558 struct scroll_bar *bar;
f451eb13
JB
8559 XEvent *event;
8560{
06a2c219
GM
8561#ifndef USE_TOOLKIT_SCROLL_BARS
8562
ab648270 8563 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8564 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8565 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 8566 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 8567
f451eb13
JB
8568 BLOCK_INPUT;
8569
ab648270 8570 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 8571
06a2c219 8572 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 8573 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
8574
8575 /* x, y, width, height */
d9cdbb3d 8576 0, 0,
3cbd2e0b 8577 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
8578 XINT (bar->height) - 1);
8579
f451eb13 8580 UNBLOCK_INPUT;
06a2c219
GM
8581
8582#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8583}
8584
ab648270
JB
8585/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8586 is set to something other than no_event, it is enqueued.
8587
8588 This may be called from a signal handler, so we have to ignore GC
8589 mark bits. */
06a2c219 8590
5c187dee
GM
8591#ifndef USE_TOOLKIT_SCROLL_BARS
8592
f451eb13 8593static void
ab648270
JB
8594x_scroll_bar_handle_click (bar, event, emacs_event)
8595 struct scroll_bar *bar;
f451eb13
JB
8596 XEvent *event;
8597 struct input_event *emacs_event;
8598{
0299d313 8599 if (! GC_WINDOWP (bar->window))
12ba150f
JB
8600 abort ();
8601
ab648270 8602 emacs_event->kind = scroll_bar_click;
69388238 8603 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
8604 emacs_event->modifiers
8605 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
8606 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
8607 event->xbutton.state)
8608 | (event->type == ButtonRelease
8609 ? up_modifier
8610 : down_modifier));
12ba150f 8611 emacs_event->frame_or_window = bar->window;
f451eb13 8612 emacs_event->timestamp = event->xbutton.time;
12ba150f 8613 {
06a2c219 8614#if 0
d9cdbb3d 8615 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 8616 int internal_height
d9cdbb3d 8617 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8618#endif
0299d313 8619 int top_range
d9cdbb3d 8620 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 8621 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
8622
8623 if (y < 0) y = 0;
8624 if (y > top_range) y = top_range;
8625
8626 if (y < XINT (bar->start))
ab648270
JB
8627 emacs_event->part = scroll_bar_above_handle;
8628 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8629 emacs_event->part = scroll_bar_handle;
12ba150f 8630 else
ab648270 8631 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
8632
8633 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
8634 they want to drag it. Lisp code needs to be able to decide
8635 whether or not we're dragging. */
929787e1 8636#if 0
12ba150f
JB
8637 /* If the user has just clicked on the handle, record where they're
8638 holding it. */
8639 if (event->type == ButtonPress
ab648270 8640 && emacs_event->part == scroll_bar_handle)
e0c1aef2 8641 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 8642#endif
12ba150f
JB
8643
8644 /* If the user has released the handle, set it to its final position. */
8645 if (event->type == ButtonRelease
8646 && ! NILP (bar->dragging))
8647 {
8648 int new_start = y - XINT (bar->dragging);
8649 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 8650
ab648270 8651 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
8652 bar->dragging = Qnil;
8653 }
f451eb13 8654
5116f055
JB
8655 /* Same deal here as the other #if 0. */
8656#if 0
58769bee 8657 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 8658 the handle. */
ab648270 8659 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
8660 emacs_event->x = bar->start;
8661 else
e0c1aef2 8662 XSETINT (emacs_event->x, y);
5116f055 8663#else
e0c1aef2 8664 XSETINT (emacs_event->x, y);
5116f055 8665#endif
f451eb13 8666
e0c1aef2 8667 XSETINT (emacs_event->y, top_range);
12ba150f
JB
8668 }
8669}
f451eb13 8670
ab648270
JB
8671/* Handle some mouse motion while someone is dragging the scroll bar.
8672
8673 This may be called from a signal handler, so we have to ignore GC
8674 mark bits. */
06a2c219 8675
f451eb13 8676static void
ab648270
JB
8677x_scroll_bar_note_movement (bar, event)
8678 struct scroll_bar *bar;
f451eb13
JB
8679 XEvent *event;
8680{
39d8bb4d
KH
8681 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
8682
f451eb13
JB
8683 last_mouse_movement_time = event->xmotion.time;
8684
39d8bb4d 8685 f->mouse_moved = 1;
e0c1aef2 8686 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
8687
8688 /* If we're dragging the bar, display it. */
ab648270 8689 if (! GC_NILP (bar->dragging))
f451eb13
JB
8690 {
8691 /* Where should the handle be now? */
12ba150f 8692 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 8693
12ba150f 8694 if (new_start != XINT (bar->start))
f451eb13 8695 {
12ba150f 8696 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 8697
ab648270 8698 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
8699 }
8700 }
f451eb13
JB
8701}
8702
5c187dee
GM
8703#endif /* !USE_TOOLKIT_SCROLL_BARS */
8704
12ba150f 8705/* Return information to the user about the current position of the mouse
ab648270 8706 on the scroll bar. */
06a2c219 8707
12ba150f 8708static void
334208b7
RS
8709x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
8710 FRAME_PTR *fp;
12ba150f 8711 Lisp_Object *bar_window;
ab648270 8712 enum scroll_bar_part *part;
12ba150f
JB
8713 Lisp_Object *x, *y;
8714 unsigned long *time;
8715{
ab648270 8716 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
8717 Window w = SCROLL_BAR_X_WINDOW (bar);
8718 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 8719 int win_x, win_y;
559cb2fb
JB
8720 Window dummy_window;
8721 int dummy_coord;
8722 unsigned int dummy_mask;
12ba150f 8723
cf7cb199
JB
8724 BLOCK_INPUT;
8725
ab648270 8726 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 8727 report that. */
334208b7 8728 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 8729
559cb2fb
JB
8730 /* Root, child, root x and root y. */
8731 &dummy_window, &dummy_window,
8732 &dummy_coord, &dummy_coord,
12ba150f 8733
559cb2fb
JB
8734 /* Position relative to scroll bar. */
8735 &win_x, &win_y,
12ba150f 8736
559cb2fb
JB
8737 /* Mouse buttons and modifier keys. */
8738 &dummy_mask))
7a13e894 8739 ;
559cb2fb
JB
8740 else
8741 {
06a2c219 8742#if 0
559cb2fb 8743 int inside_height
d9cdbb3d 8744 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8745#endif
559cb2fb 8746 int top_range
d9cdbb3d 8747 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
8748
8749 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
8750
8751 if (! NILP (bar->dragging))
8752 win_y -= XINT (bar->dragging);
8753
8754 if (win_y < 0)
8755 win_y = 0;
8756 if (win_y > top_range)
8757 win_y = top_range;
8758
334208b7 8759 *fp = f;
7a13e894 8760 *bar_window = bar->window;
559cb2fb
JB
8761
8762 if (! NILP (bar->dragging))
8763 *part = scroll_bar_handle;
8764 else if (win_y < XINT (bar->start))
8765 *part = scroll_bar_above_handle;
8766 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8767 *part = scroll_bar_handle;
8768 else
8769 *part = scroll_bar_below_handle;
12ba150f 8770
e0c1aef2
KH
8771 XSETINT (*x, win_y);
8772 XSETINT (*y, top_range);
12ba150f 8773
39d8bb4d 8774 f->mouse_moved = 0;
559cb2fb
JB
8775 last_mouse_scroll_bar = Qnil;
8776 }
12ba150f 8777
559cb2fb 8778 *time = last_mouse_movement_time;
cf7cb199 8779
cf7cb199 8780 UNBLOCK_INPUT;
12ba150f
JB
8781}
8782
f451eb13 8783
dbc4e1c1 8784/* The screen has been cleared so we may have changed foreground or
ab648270
JB
8785 background colors, and the scroll bars may need to be redrawn.
8786 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
8787 redraw them. */
8788
dfcf069d 8789void
ab648270 8790x_scroll_bar_clear (f)
dbc4e1c1
JB
8791 FRAME_PTR f;
8792{
06a2c219 8793#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
8794 Lisp_Object bar;
8795
b80c363e
RS
8796 /* We can have scroll bars even if this is 0,
8797 if we just turned off scroll bar mode.
8798 But in that case we should not clear them. */
8799 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
8800 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
8801 bar = XSCROLL_BAR (bar)->next)
8802 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
8803 0, 0, 0, 0, True);
06a2c219 8804#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
8805}
8806
06a2c219 8807/* This processes Expose events from the menu-bar specific X event
19126e11 8808 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 8809 when handling menu-bar or pop-up items. */
3afe33e7 8810
06a2c219 8811int
3afe33e7
RS
8812process_expose_from_menu (event)
8813 XEvent event;
8814{
8815 FRAME_PTR f;
19126e11 8816 struct x_display_info *dpyinfo;
06a2c219 8817 int frame_exposed_p = 0;
3afe33e7 8818
f94397b5
KH
8819 BLOCK_INPUT;
8820
19126e11
KH
8821 dpyinfo = x_display_info_for_display (event.xexpose.display);
8822 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
8823 if (f)
8824 {
8825 if (f->async_visible == 0)
8826 {
8827 f->async_visible = 1;
8828 f->async_iconified = 0;
06c488fd 8829 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
8830 SET_FRAME_GARBAGED (f);
8831 }
8832 else
8833 {
06a2c219
GM
8834 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
8835 event.xexpose.x, event.xexpose.y,
8836 event.xexpose.width, event.xexpose.height);
8837 frame_exposed_p = 1;
3afe33e7
RS
8838 }
8839 }
8840 else
8841 {
8842 struct scroll_bar *bar
8843 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 8844
3afe33e7
RS
8845 if (bar)
8846 x_scroll_bar_expose (bar, &event);
8847 }
f94397b5
KH
8848
8849 UNBLOCK_INPUT;
06a2c219 8850 return frame_exposed_p;
3afe33e7 8851}
09756a85
RS
8852\f
8853/* Define a queue to save up SelectionRequest events for later handling. */
8854
8855struct selection_event_queue
8856 {
8857 XEvent event;
8858 struct selection_event_queue *next;
8859 };
8860
8861static struct selection_event_queue *queue;
8862
8863/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 8864
09756a85
RS
8865static int x_queue_selection_requests;
8866
8867/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 8868
09756a85 8869static void
334208b7
RS
8870x_queue_event (f, event)
8871 FRAME_PTR f;
09756a85
RS
8872 XEvent *event;
8873{
8874 struct selection_event_queue *queue_tmp
06a2c219 8875 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 8876
58769bee 8877 if (queue_tmp != NULL)
09756a85
RS
8878 {
8879 queue_tmp->event = *event;
8880 queue_tmp->next = queue;
8881 queue = queue_tmp;
8882 }
8883}
8884
8885/* Take all the queued events and put them back
8886 so that they get processed afresh. */
8887
8888static void
db3906fd
RS
8889x_unqueue_events (display)
8890 Display *display;
09756a85 8891{
58769bee 8892 while (queue != NULL)
09756a85
RS
8893 {
8894 struct selection_event_queue *queue_tmp = queue;
db3906fd 8895 XPutBackEvent (display, &queue_tmp->event);
09756a85 8896 queue = queue_tmp->next;
06a2c219 8897 xfree ((char *)queue_tmp);
09756a85
RS
8898 }
8899}
8900
8901/* Start queuing SelectionRequest events. */
8902
8903void
db3906fd
RS
8904x_start_queuing_selection_requests (display)
8905 Display *display;
09756a85
RS
8906{
8907 x_queue_selection_requests++;
8908}
8909
8910/* Stop queuing SelectionRequest events. */
8911
8912void
db3906fd
RS
8913x_stop_queuing_selection_requests (display)
8914 Display *display;
09756a85
RS
8915{
8916 x_queue_selection_requests--;
db3906fd 8917 x_unqueue_events (display);
09756a85 8918}
f451eb13
JB
8919\f
8920/* The main X event-reading loop - XTread_socket. */
dc6f92b8 8921
06a2c219 8922/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
8923 but we have to put it out here, since static variables within functions
8924 sometimes don't work. */
06a2c219 8925
dc6f92b8
JB
8926static Time enter_timestamp;
8927
11edeb03 8928/* This holds the state XLookupString needs to implement dead keys
58769bee 8929 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
8930 says that a portable program can't use this, but Stephen Gildea assures
8931 me that letting the compiler initialize it to zeros will work okay.
8932
8933 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
8934 given for enter_time stamp, above. */
8935
11edeb03
JB
8936static XComposeStatus compose_status;
8937
10e6549c
RS
8938/* Record the last 100 characters stored
8939 to help debug the loss-of-chars-during-GC problem. */
06a2c219 8940
2224b905
RS
8941static int temp_index;
8942static short temp_buffer[100];
10e6549c 8943
7a13e894
RS
8944/* Set this to nonzero to fake an "X I/O error"
8945 on a particular display. */
06a2c219 8946
7a13e894
RS
8947struct x_display_info *XTread_socket_fake_io_error;
8948
2224b905
RS
8949/* When we find no input here, we occasionally do a no-op command
8950 to verify that the X server is still running and we can still talk with it.
8951 We try all the open displays, one by one.
8952 This variable is used for cycling thru the displays. */
06a2c219 8953
2224b905
RS
8954static struct x_display_info *next_noop_dpyinfo;
8955
06a2c219
GM
8956#define SET_SAVED_MENU_EVENT(size) \
8957 do \
8958 { \
8959 if (f->output_data.x->saved_menu_event == 0) \
8960 f->output_data.x->saved_menu_event \
8961 = (XEvent *) xmalloc (sizeof (XEvent)); \
8962 bcopy (&event, f->output_data.x->saved_menu_event, size); \
8963 if (numchars >= 1) \
8964 { \
8965 bufp->kind = menu_bar_activate_event; \
8966 XSETFRAME (bufp->frame_or_window, f); \
8967 bufp++; \
8968 count++; \
8969 numchars--; \
8970 } \
8971 } \
8972 while (0)
8973
8805890a 8974#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 8975#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 8976
dc6f92b8
JB
8977/* Read events coming from the X server.
8978 This routine is called by the SIGIO handler.
8979 We return as soon as there are no more events to be read.
8980
8981 Events representing keys are stored in buffer BUFP,
8982 which can hold up to NUMCHARS characters.
8983 We return the number of characters stored into the buffer,
8984 thus pretending to be `read'.
8985
dc6f92b8
JB
8986 EXPECTED is nonzero if the caller knows input is available. */
8987
7c5283e4 8988int
f66868ba 8989XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 8990 register int sd;
8805890a
KH
8991 /* register */ struct input_event *bufp;
8992 /* register */ int numchars;
dc6f92b8
JB
8993 int expected;
8994{
8995 int count = 0;
8996 int nbytes = 0;
dc6f92b8 8997 XEvent event;
f676886a 8998 struct frame *f;
66f55a9d 8999 int event_found = 0;
334208b7 9000 struct x_display_info *dpyinfo;
dc6f92b8 9001
9ac0d9e0 9002 if (interrupt_input_blocked)
dc6f92b8 9003 {
9ac0d9e0 9004 interrupt_input_pending = 1;
dc6f92b8
JB
9005 return -1;
9006 }
9007
9ac0d9e0 9008 interrupt_input_pending = 0;
dc6f92b8 9009 BLOCK_INPUT;
c0a04927
RS
9010
9011 /* So people can tell when we have read the available input. */
9012 input_signal_count++;
9013
dc6f92b8 9014 if (numchars <= 0)
06a2c219 9015 abort (); /* Don't think this happens. */
dc6f92b8 9016
bde5503b
GM
9017 ++handling_signal;
9018
7a13e894
RS
9019 /* Find the display we are supposed to read input for.
9020 It's the one communicating on descriptor SD. */
9021 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9022 {
9023#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9024#ifdef FIOSNBIO
7a13e894
RS
9025 /* If available, Xlib uses FIOSNBIO to make the socket
9026 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9027 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9028 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9029 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9030#endif /* ! defined (FIOSNBIO) */
7a13e894 9031#endif
dc6f92b8 9032
7a13e894
RS
9033#if 0 /* This code can't be made to work, with multiple displays,
9034 and appears not to be used on any system any more.
9035 Also keyboard.c doesn't turn O_NDELAY on and off
9036 for X connections. */
dc6f92b8
JB
9037#ifndef SIGIO
9038#ifndef HAVE_SELECT
7a13e894
RS
9039 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9040 {
9041 extern int read_alarm_should_throw;
9042 read_alarm_should_throw = 1;
9043 XPeekEvent (dpyinfo->display, &event);
9044 read_alarm_should_throw = 0;
9045 }
c118dd06
JB
9046#endif /* HAVE_SELECT */
9047#endif /* SIGIO */
7a13e894 9048#endif
dc6f92b8 9049
7a13e894
RS
9050 /* For debugging, this gives a way to fake an I/O error. */
9051 if (dpyinfo == XTread_socket_fake_io_error)
9052 {
9053 XTread_socket_fake_io_error = 0;
9054 x_io_error_quitter (dpyinfo->display);
9055 }
dc6f92b8 9056
06a2c219 9057 while (XPending (dpyinfo->display))
dc6f92b8 9058 {
7a13e894 9059 XNextEvent (dpyinfo->display, &event);
06a2c219 9060
531483fb 9061#ifdef HAVE_X_I18N
d1bc4182 9062 {
f2be1146
GM
9063 /* Filter events for the current X input method.
9064 XFilterEvent returns non-zero if the input method has
9065 consumed the event. We pass the frame's X window to
9066 XFilterEvent because that's the one for which the IC
9067 was created. */
f5d11644
GM
9068 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9069 event.xclient.window);
9070 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9071 break;
9072 }
0cd6403b 9073#endif
7a13e894
RS
9074 event_found = 1;
9075
9076 switch (event.type)
9077 {
9078 case ClientMessage:
c047688c 9079 {
7a13e894
RS
9080 if (event.xclient.message_type
9081 == dpyinfo->Xatom_wm_protocols
9082 && event.xclient.format == 32)
c047688c 9083 {
7a13e894
RS
9084 if (event.xclient.data.l[0]
9085 == dpyinfo->Xatom_wm_take_focus)
c047688c 9086 {
8c1a6a84
RS
9087 /* Use x_any_window_to_frame because this
9088 could be the shell widget window
9089 if the frame has no title bar. */
9090 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
9091#ifdef HAVE_X_I18N
9092 /* Not quite sure this is needed -pd */
8c1a6a84 9093 if (f && FRAME_XIC (f))
6c183ba5
RS
9094 XSetICFocus (FRAME_XIC (f));
9095#endif
f1da8f06
GM
9096#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
9097 instructs the WM to set the input focus automatically for
9098 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
9099 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
9100 it has set the focus. So, XSetInputFocus below is not
9101 needed.
9102
9103 The call to XSetInputFocus below has also caused trouble. In
9104 cases where the XSetInputFocus done by the WM and the one
9105 below are temporally close (on a fast machine), the call
9106 below can generate additional FocusIn events which confuse
9107 Emacs. */
9108
bf7253f4
RS
9109 /* Since we set WM_TAKE_FOCUS, we must call
9110 XSetInputFocus explicitly. But not if f is null,
9111 since that might be an event for a deleted frame. */
7a13e894 9112 if (f)
bf7253f4
RS
9113 {
9114 Display *d = event.xclient.display;
9115 /* Catch and ignore errors, in case window has been
9116 iconified by a window manager such as GWM. */
9117 int count = x_catch_errors (d);
9118 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
9119 /* The ICCCM says this is
9120 the only valid choice. */
9121 RevertToParent,
bf7253f4
RS
9122 event.xclient.data.l[1]);
9123 /* This is needed to detect the error
9124 if there is an error. */
9125 XSync (d, False);
9126 x_uncatch_errors (d, count);
9127 }
7a13e894 9128 /* Not certain about handling scroll bars here */
f1da8f06 9129#endif /* 0 */
c047688c 9130 }
7a13e894
RS
9131 else if (event.xclient.data.l[0]
9132 == dpyinfo->Xatom_wm_save_yourself)
9133 {
9134 /* Save state modify the WM_COMMAND property to
06a2c219 9135 something which can reinstate us. This notifies
7a13e894
RS
9136 the session manager, who's looking for such a
9137 PropertyNotify. Can restart processing when
06a2c219 9138 a keyboard or mouse event arrives. */
7a13e894
RS
9139 if (numchars > 0)
9140 {
19126e11
KH
9141 f = x_top_window_to_frame (dpyinfo,
9142 event.xclient.window);
7a13e894
RS
9143
9144 /* This is just so we only give real data once
9145 for a single Emacs process. */
b86bd3dd 9146 if (f == SELECTED_FRAME ())
7a13e894
RS
9147 XSetCommand (FRAME_X_DISPLAY (f),
9148 event.xclient.window,
9149 initial_argv, initial_argc);
f000f5c5 9150 else if (f)
7a13e894
RS
9151 XSetCommand (FRAME_X_DISPLAY (f),
9152 event.xclient.window,
9153 0, 0);
9154 }
9155 }
9156 else if (event.xclient.data.l[0]
9157 == dpyinfo->Xatom_wm_delete_window)
1fb20991 9158 {
19126e11
KH
9159 struct frame *f
9160 = x_any_window_to_frame (dpyinfo,
9161 event.xclient.window);
1fb20991 9162
7a13e894
RS
9163 if (f)
9164 {
9165 if (numchars == 0)
9166 abort ();
1fb20991 9167
7a13e894
RS
9168 bufp->kind = delete_window_event;
9169 XSETFRAME (bufp->frame_or_window, f);
9170 bufp++;
9171
9172 count += 1;
9173 numchars -= 1;
9174 }
1fb20991 9175 }
c047688c 9176 }
7a13e894
RS
9177 else if (event.xclient.message_type
9178 == dpyinfo->Xatom_wm_configure_denied)
9179 {
9180 }
9181 else if (event.xclient.message_type
9182 == dpyinfo->Xatom_wm_window_moved)
9183 {
9184 int new_x, new_y;
19126e11
KH
9185 struct frame *f
9186 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 9187
7a13e894
RS
9188 new_x = event.xclient.data.s[0];
9189 new_y = event.xclient.data.s[1];
1fb20991 9190
7a13e894
RS
9191 if (f)
9192 {
7556890b
RS
9193 f->output_data.x->left_pos = new_x;
9194 f->output_data.x->top_pos = new_y;
7a13e894 9195 }
1fb20991 9196 }
0fdff6bb 9197#ifdef HACK_EDITRES
7a13e894
RS
9198 else if (event.xclient.message_type
9199 == dpyinfo->Xatom_editres)
9200 {
19126e11
KH
9201 struct frame *f
9202 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 9203 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 9204 &event, NULL);
7a13e894 9205 }
0fdff6bb 9206#endif /* HACK_EDITRES */
06a2c219
GM
9207 else if ((event.xclient.message_type
9208 == dpyinfo->Xatom_DONE)
9209 || (event.xclient.message_type
9210 == dpyinfo->Xatom_PAGE))
9211 {
9212 /* Ghostview job completed. Kill it. We could
9213 reply with "Next" if we received "Page", but we
9214 currently never do because we are interested in
9215 images, only, which should have 1 page. */
06a2c219
GM
9216 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
9217 struct frame *f
9218 = x_window_to_frame (dpyinfo, event.xclient.window);
9219 x_kill_gs_process (pixmap, f);
9220 expose_frame (f, 0, 0, 0, 0);
9221 }
9222#ifdef USE_TOOLKIT_SCROLL_BARS
9223 /* Scroll bar callbacks send a ClientMessage from which
9224 we construct an input_event. */
9225 else if (event.xclient.message_type
9226 == dpyinfo->Xatom_Scrollbar)
9227 {
9228 x_scroll_bar_to_input_event (&event, bufp);
9229 ++bufp, ++count, --numchars;
9230 goto out;
9231 }
9232#endif /* USE_TOOLKIT_SCROLL_BARS */
9233 else
9234 goto OTHER;
7a13e894
RS
9235 }
9236 break;
dc6f92b8 9237
7a13e894 9238 case SelectionNotify:
3afe33e7 9239#ifdef USE_X_TOOLKIT
19126e11 9240 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 9241 goto OTHER;
3afe33e7 9242#endif /* not USE_X_TOOLKIT */
dfcf069d 9243 x_handle_selection_notify (&event.xselection);
7a13e894 9244 break;
d56a553a 9245
06a2c219 9246 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 9247#ifdef USE_X_TOOLKIT
19126e11 9248 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 9249 goto OTHER;
3afe33e7 9250#endif /* USE_X_TOOLKIT */
7a13e894
RS
9251 {
9252 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 9253
7a13e894
RS
9254 if (numchars == 0)
9255 abort ();
d56a553a 9256
7a13e894
RS
9257 bufp->kind = selection_clear_event;
9258 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9259 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9260 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9261 bufp->frame_or_window = Qnil;
7a13e894 9262 bufp++;
d56a553a 9263
7a13e894
RS
9264 count += 1;
9265 numchars -= 1;
9266 }
9267 break;
dc6f92b8 9268
06a2c219 9269 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 9270#ifdef USE_X_TOOLKIT
19126e11 9271 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 9272 goto OTHER;
3afe33e7 9273#endif /* USE_X_TOOLKIT */
7a13e894 9274 if (x_queue_selection_requests)
19126e11 9275 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
9276 &event);
9277 else
9278 {
9279 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 9280
7a13e894
RS
9281 if (numchars == 0)
9282 abort ();
9283
9284 bufp->kind = selection_request_event;
9285 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9286 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
9287 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9288 SELECTION_EVENT_TARGET (bufp) = eventp->target;
9289 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
9290 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9291 bufp->frame_or_window = Qnil;
7a13e894
RS
9292 bufp++;
9293
9294 count += 1;
9295 numchars -= 1;
9296 }
9297 break;
9298
9299 case PropertyNotify:
3afe33e7 9300#ifdef USE_X_TOOLKIT
19126e11 9301 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 9302 goto OTHER;
3afe33e7 9303#endif /* not USE_X_TOOLKIT */
dfcf069d 9304 x_handle_property_notify (&event.xproperty);
7a13e894 9305 break;
dc6f92b8 9306
7a13e894 9307 case ReparentNotify:
19126e11 9308 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
9309 if (f)
9310 {
9311 int x, y;
7556890b 9312 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 9313 x_real_positions (f, &x, &y);
7556890b
RS
9314 f->output_data.x->left_pos = x;
9315 f->output_data.x->top_pos = y;
7a13e894
RS
9316 }
9317 break;
3bd330d4 9318
7a13e894 9319 case Expose:
19126e11 9320 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 9321 if (f)
dc6f92b8 9322 {
7a13e894
RS
9323 if (f->async_visible == 0)
9324 {
9325 f->async_visible = 1;
9326 f->async_iconified = 0;
06c488fd 9327 f->output_data.x->has_been_visible = 1;
7a13e894
RS
9328 SET_FRAME_GARBAGED (f);
9329 }
9330 else
06a2c219
GM
9331 expose_frame (x_window_to_frame (dpyinfo,
9332 event.xexpose.window),
9333 event.xexpose.x, event.xexpose.y,
9334 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
9335 }
9336 else
7a13e894 9337 {
06a2c219
GM
9338#ifdef USE_TOOLKIT_SCROLL_BARS
9339 /* Dispatch event to the widget. */
9340 goto OTHER;
9341#else /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9342 struct scroll_bar *bar
9343 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9344
7a13e894
RS
9345 if (bar)
9346 x_scroll_bar_expose (bar, &event);
3afe33e7 9347#ifdef USE_X_TOOLKIT
7a13e894
RS
9348 else
9349 goto OTHER;
3afe33e7 9350#endif /* USE_X_TOOLKIT */
06a2c219 9351#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9352 }
9353 break;
dc6f92b8 9354
7a13e894
RS
9355 case GraphicsExpose: /* This occurs when an XCopyArea's
9356 source area was obscured or not
9357 available.*/
19126e11 9358 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
9359 if (f)
9360 {
06a2c219
GM
9361 expose_frame (f,
9362 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
9363 event.xgraphicsexpose.width,
9364 event.xgraphicsexpose.height);
7a13e894 9365 }
3afe33e7 9366#ifdef USE_X_TOOLKIT
7a13e894
RS
9367 else
9368 goto OTHER;
3afe33e7 9369#endif /* USE_X_TOOLKIT */
7a13e894 9370 break;
dc6f92b8 9371
7a13e894 9372 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
9373 source area was completely
9374 available */
7a13e894 9375 break;
dc6f92b8 9376
7a13e894 9377 case UnmapNotify:
06a2c219
GM
9378 /* Redo the mouse-highlight after the tooltip has gone. */
9379 if (event.xmap.window == tip_window)
9380 {
9381 tip_window = 0;
9382 redo_mouse_highlight ();
9383 }
9384
91ea2a7a 9385 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
9386 if (f) /* F may no longer exist if
9387 the frame was deleted. */
9388 {
9389 /* While a frame is unmapped, display generation is
9390 disabled; you don't want to spend time updating a
9391 display that won't ever be seen. */
9392 f->async_visible = 0;
9393 /* We can't distinguish, from the event, whether the window
9394 has become iconified or invisible. So assume, if it
9395 was previously visible, than now it is iconified.
1aa6072f
RS
9396 But x_make_frame_invisible clears both
9397 the visible flag and the iconified flag;
9398 and that way, we know the window is not iconified now. */
7a13e894 9399 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
9400 {
9401 f->async_iconified = 1;
bddd097c 9402
1aa6072f
RS
9403 bufp->kind = iconify_event;
9404 XSETFRAME (bufp->frame_or_window, f);
9405 bufp++;
9406 count++;
9407 numchars--;
9408 }
7a13e894 9409 }
7a13e894 9410 goto OTHER;
dc6f92b8 9411
7a13e894 9412 case MapNotify:
06a2c219
GM
9413 if (event.xmap.window == tip_window)
9414 /* The tooltip has been drawn already. Avoid
9415 the SET_FRAME_GARBAGED below. */
9416 goto OTHER;
9417
9418 /* We use x_top_window_to_frame because map events can
9419 come for sub-windows and they don't mean that the
9420 frame is visible. */
19126e11 9421 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
9422 if (f)
9423 {
9424 f->async_visible = 1;
9425 f->async_iconified = 0;
06c488fd 9426 f->output_data.x->has_been_visible = 1;
dc6f92b8 9427
7a13e894
RS
9428 /* wait_reading_process_input will notice this and update
9429 the frame's display structures. */
9430 SET_FRAME_GARBAGED (f);
bddd097c 9431
d806e720
RS
9432 if (f->iconified)
9433 {
9434 bufp->kind = deiconify_event;
9435 XSETFRAME (bufp->frame_or_window, f);
9436 bufp++;
9437 count++;
9438 numchars--;
9439 }
e73ec6fa 9440 else if (! NILP (Vframe_list)
8e713be6 9441 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
9442 /* Force a redisplay sooner or later
9443 to update the frame titles
9444 in case this is the second frame. */
9445 record_asynch_buffer_change ();
7a13e894 9446 }
7a13e894 9447 goto OTHER;
dc6f92b8 9448
7a13e894 9449 case KeyPress:
19126e11 9450 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 9451
06a2c219
GM
9452#ifdef USE_MOTIF
9453 /* I couldn't find a way to prevent LessTif scroll bars
9454 from consuming key events. */
9455 if (f == 0)
9456 {
9457 Widget widget = XtWindowToWidget (dpyinfo->display,
9458 event.xkey.window);
9459 if (widget && XmIsScrollBar (widget))
9460 {
9461 widget = XtParent (widget);
9462 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
9463 }
9464 }
9465#endif /* USE_MOTIF */
9466
7a13e894
RS
9467 if (f != 0)
9468 {
9469 KeySym keysym, orig_keysym;
9470 /* al%imercury@uunet.uu.net says that making this 81 instead of
9471 80 fixed a bug whereby meta chars made his Emacs hang. */
9472 unsigned char copy_buffer[81];
9473 int modifiers;
64bb1782 9474
7a13e894
RS
9475 event.xkey.state
9476 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
9477 extra_keyboard_modifiers);
9478 modifiers = event.xkey.state;
3a2712f9 9479
7a13e894 9480 /* This will have to go some day... */
752a043f 9481
7a13e894
RS
9482 /* make_lispy_event turns chars into control chars.
9483 Don't do it here because XLookupString is too eager. */
9484 event.xkey.state &= ~ControlMask;
5d46f928
RS
9485 event.xkey.state &= ~(dpyinfo->meta_mod_mask
9486 | dpyinfo->super_mod_mask
9487 | dpyinfo->hyper_mod_mask
9488 | dpyinfo->alt_mod_mask);
9489
1cf4a0d1
RS
9490 /* In case Meta is ComposeCharacter,
9491 clear its status. According to Markus Ehrnsperger
9492 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
9493 this enables ComposeCharacter to work whether or
9494 not it is combined with Meta. */
9495 if (modifiers & dpyinfo->meta_mod_mask)
9496 bzero (&compose_status, sizeof (compose_status));
9497
6c183ba5
RS
9498#ifdef HAVE_X_I18N
9499 if (FRAME_XIC (f))
9500 {
f5d11644
GM
9501 unsigned char *copy_bufptr = copy_buffer;
9502 int copy_bufsiz = sizeof (copy_buffer);
9503 Status status_return;
9504
6c183ba5 9505 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
9506 &event.xkey, copy_bufptr,
9507 copy_bufsiz, &keysym,
6c183ba5 9508 &status_return);
f5d11644
GM
9509 if (status_return == XBufferOverflow)
9510 {
9511 copy_bufsiz = nbytes + 1;
9512 copy_bufptr = (char *) alloca (copy_bufsiz);
9513 nbytes = XmbLookupString (FRAME_XIC (f),
9514 &event.xkey, copy_bufptr,
9515 copy_bufsiz, &keysym,
9516 &status_return);
9517 }
9518
1decb680
PE
9519 if (status_return == XLookupNone)
9520 break;
9521 else if (status_return == XLookupChars)
fdd9d55e
GM
9522 {
9523 keysym = NoSymbol;
9524 modifiers = 0;
9525 }
1decb680
PE
9526 else if (status_return != XLookupKeySym
9527 && status_return != XLookupBoth)
9528 abort ();
6c183ba5
RS
9529 }
9530 else
9531 nbytes = XLookupString (&event.xkey, copy_buffer,
9532 80, &keysym, &compose_status);
9533#else
0299d313
RS
9534 nbytes = XLookupString (&event.xkey, copy_buffer,
9535 80, &keysym, &compose_status);
6c183ba5 9536#endif
dc6f92b8 9537
7a13e894 9538 orig_keysym = keysym;
55123275 9539
7a13e894
RS
9540 if (numchars > 1)
9541 {
9542 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
9543 || keysym == XK_Delete
1097aea0 9544#ifdef XK_ISO_Left_Tab
441affdb 9545 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 9546#endif
852bff8f 9547 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
9548 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
9549 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 9550#ifdef HPUX
7a13e894
RS
9551 /* This recognizes the "extended function keys".
9552 It seems there's no cleaner way.
9553 Test IsModifierKey to avoid handling mode_switch
9554 incorrectly. */
9555 || ((unsigned) (keysym) >= XK_Select
9556 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
9557#endif
9558#ifdef XK_dead_circumflex
7a13e894 9559 || orig_keysym == XK_dead_circumflex
69388238
RS
9560#endif
9561#ifdef XK_dead_grave
7a13e894 9562 || orig_keysym == XK_dead_grave
69388238
RS
9563#endif
9564#ifdef XK_dead_tilde
7a13e894 9565 || orig_keysym == XK_dead_tilde
69388238
RS
9566#endif
9567#ifdef XK_dead_diaeresis
7a13e894 9568 || orig_keysym == XK_dead_diaeresis
69388238
RS
9569#endif
9570#ifdef XK_dead_macron
7a13e894 9571 || orig_keysym == XK_dead_macron
69388238
RS
9572#endif
9573#ifdef XK_dead_degree
7a13e894 9574 || orig_keysym == XK_dead_degree
69388238
RS
9575#endif
9576#ifdef XK_dead_acute
7a13e894 9577 || orig_keysym == XK_dead_acute
69388238
RS
9578#endif
9579#ifdef XK_dead_cedilla
7a13e894 9580 || orig_keysym == XK_dead_cedilla
69388238
RS
9581#endif
9582#ifdef XK_dead_breve
7a13e894 9583 || orig_keysym == XK_dead_breve
69388238
RS
9584#endif
9585#ifdef XK_dead_ogonek
7a13e894 9586 || orig_keysym == XK_dead_ogonek
69388238
RS
9587#endif
9588#ifdef XK_dead_caron
7a13e894 9589 || orig_keysym == XK_dead_caron
69388238
RS
9590#endif
9591#ifdef XK_dead_doubleacute
7a13e894 9592 || orig_keysym == XK_dead_doubleacute
69388238
RS
9593#endif
9594#ifdef XK_dead_abovedot
7a13e894 9595 || orig_keysym == XK_dead_abovedot
c34790e0 9596#endif
7a13e894
RS
9597 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
9598 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
9599 /* Any "vendor-specific" key is ok. */
9600 || (orig_keysym & (1 << 28)))
9601 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
9602#ifndef HAVE_X11R5
9603#ifdef XK_Mode_switch
7a13e894 9604 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
9605#endif
9606#ifdef XK_Num_Lock
7a13e894 9607 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
9608#endif
9609#endif /* not HAVE_X11R5 */
7a13e894 9610 ))
dc6f92b8 9611 {
10e6549c
RS
9612 if (temp_index == sizeof temp_buffer / sizeof (short))
9613 temp_index = 0;
7a13e894
RS
9614 temp_buffer[temp_index++] = keysym;
9615 bufp->kind = non_ascii_keystroke;
9616 bufp->code = keysym;
e0c1aef2 9617 XSETFRAME (bufp->frame_or_window, f);
334208b7
RS
9618 bufp->modifiers
9619 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9620 modifiers);
1113d9db 9621 bufp->timestamp = event.xkey.time;
dc6f92b8 9622 bufp++;
7a13e894
RS
9623 count++;
9624 numchars--;
dc6f92b8 9625 }
7a13e894
RS
9626 else if (numchars > nbytes)
9627 {
9628 register int i;
9629
9630 for (i = 0; i < nbytes; i++)
9631 {
9632 if (temp_index == sizeof temp_buffer / sizeof (short))
9633 temp_index = 0;
9634 temp_buffer[temp_index++] = copy_buffer[i];
9635 bufp->kind = ascii_keystroke;
9636 bufp->code = copy_buffer[i];
9637 XSETFRAME (bufp->frame_or_window, f);
9638 bufp->modifiers
9639 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9640 modifiers);
9641 bufp->timestamp = event.xkey.time;
9642 bufp++;
9643 }
9644
9645 count += nbytes;
9646 numchars -= nbytes;
1decb680
PE
9647
9648 if (keysym == NoSymbol)
9649 break;
7a13e894
RS
9650 }
9651 else
9652 abort ();
dc6f92b8 9653 }
10e6549c
RS
9654 else
9655 abort ();
dc6f92b8 9656 }
59ddecde
GM
9657#ifdef HAVE_X_I18N
9658 /* Don't dispatch this event since XtDispatchEvent calls
9659 XFilterEvent, and two calls in a row may freeze the
9660 client. */
9661 break;
9662#else
717ca130 9663 goto OTHER;
59ddecde 9664#endif
f451eb13 9665
f5d11644 9666 case KeyRelease:
59ddecde
GM
9667#ifdef HAVE_X_I18N
9668 /* Don't dispatch this event since XtDispatchEvent calls
9669 XFilterEvent, and two calls in a row may freeze the
9670 client. */
9671 break;
9672#else
f5d11644 9673 goto OTHER;
59ddecde 9674#endif
f5d11644 9675
7a13e894 9676 /* Here's a possible interpretation of the whole
06a2c219
GM
9677 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
9678 you get a FocusIn event, you have to get a FocusOut
9679 event before you relinquish the focus. If you
9680 haven't received a FocusIn event, then a mere
9681 LeaveNotify is enough to free you. */
f451eb13 9682
7a13e894 9683 case EnterNotify:
06a2c219
GM
9684 {
9685 int from_menu_bar_p = 0;
9686
9687 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
9688
9689#ifdef LESSTIF_VERSION
9690 /* When clicking outside of a menu bar popup to close
9691 it, we get a FocusIn/ EnterNotify sequence of
9692 events. The flag event.xcrossing.focus is not set
9693 in the EnterNotify event of that sequence because
9694 the focus is in the menu bar,
9695 event.xcrossing.window is the frame's X window.
9696 Unconditionally setting the focus frame to null in
9697 this case is not the right thing, because no event
9698 follows that could set the focus frame to the right
9699 value.
9700
9701 This could be a LessTif bug, but I wasn't able to
9702 reproduce the behavior in a simple test program.
9703
9704 (gerd, LessTif 0.88.1). */
9705
9706 if (!event.xcrossing.focus
9707 && f
9708 && f->output_data.x->menubar_widget)
9709 {
9710 Window focus;
9711 int revert;
9712
9713 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9714 if (focus == XtWindow (f->output_data.x->menubar_widget))
9715 from_menu_bar_p = 1;
9716 }
9717#endif /* LESSTIF_VERSION */
6d4238f3 9718
06a2c219
GM
9719 if (event.xcrossing.focus || from_menu_bar_p)
9720 {
9721 /* Avoid nasty pop/raise loops. */
9722 if (f && (!(f->auto_raise)
9723 || !(f->auto_lower)
9724 || (event.xcrossing.time - enter_timestamp) > 500))
9725 {
9726 x_new_focus_frame (dpyinfo, f);
9727 enter_timestamp = event.xcrossing.time;
9728 }
9729 }
9730 else if (f == dpyinfo->x_focus_frame)
9731 x_new_focus_frame (dpyinfo, 0);
9732
9733 /* EnterNotify counts as mouse movement,
9734 so update things that depend on mouse position. */
9735 if (f && !f->output_data.x->busy_p)
9736 note_mouse_movement (f, &event.xmotion);
9737 goto OTHER;
9738 }
dc6f92b8 9739
7a13e894 9740 case FocusIn:
19126e11 9741 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9742 if (event.xfocus.detail != NotifyPointer)
0f941935 9743 dpyinfo->x_focus_event_frame = f;
7a13e894 9744 if (f)
eb72635f
GM
9745 {
9746 x_new_focus_frame (dpyinfo, f);
9747
9748 /* Don't stop displaying the initial startup message
9749 for a switch-frame event we don't need. */
9750 if (GC_NILP (Vterminal_frame)
9751 && GC_CONSP (Vframe_list)
9752 && !GC_NILP (XCDR (Vframe_list)))
9753 {
9754 bufp->kind = FOCUS_IN_EVENT;
9755 XSETFRAME (bufp->frame_or_window, f);
9756 ++bufp, ++count, --numchars;
9757 }
9758 }
f9e24cb9 9759
6c183ba5
RS
9760#ifdef HAVE_X_I18N
9761 if (f && FRAME_XIC (f))
9762 XSetICFocus (FRAME_XIC (f));
9763#endif
9764
7a13e894 9765 goto OTHER;
10c5e63d 9766
7a13e894 9767 case LeaveNotify:
19126e11 9768 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 9769 if (f)
10c5e63d 9770 {
06a2c219
GM
9771 Lisp_Object frame;
9772 int from_menu_bar_p = 0;
9773
7a13e894 9774 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
9775 {
9776 /* If we move outside the frame, then we're
9777 certainly no longer on any text in the frame. */
9778 clear_mouse_face (dpyinfo);
9779 dpyinfo->mouse_face_mouse_frame = 0;
9780 }
9781
9782 /* Generate a nil HELP_EVENT to cancel a help-echo.
9783 Do it only if there's something to cancel.
9784 Otherwise, the startup message is cleared when
9785 the mouse leaves the frame. */
9786 if (any_help_event_p)
9787 {
9788 XSETFRAME (frame, f);
9789 bufp->kind = HELP_EVENT;
0f1a9b23
GM
9790 bufp->frame_or_window = frame;
9791 bufp->arg = Qnil;
06a2c219
GM
9792 ++bufp, ++count, --numchars;
9793 }
7a13e894 9794
06a2c219
GM
9795#ifdef LESSTIF_VERSION
9796 /* Please see the comment at the start of the
9797 EnterNotify case. */
9798 if (!event.xcrossing.focus
9799 && f->output_data.x->menubar_widget)
9800 {
9801 Window focus;
9802 int revert;
9803 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9804 if (focus == XtWindow (f->output_data.x->menubar_widget))
9805 from_menu_bar_p = 1;
9806 }
9807#endif /* LESSTIF_VERSION */
9808
9809 if (event.xcrossing.focus || from_menu_bar_p)
0f941935 9810 x_mouse_leave (dpyinfo);
10c5e63d 9811 else
7a13e894 9812 {
0f941935
KH
9813 if (f == dpyinfo->x_focus_event_frame)
9814 dpyinfo->x_focus_event_frame = 0;
9815 if (f == dpyinfo->x_focus_frame)
9816 x_new_focus_frame (dpyinfo, 0);
7a13e894 9817 }
10c5e63d 9818 }
7a13e894 9819 goto OTHER;
dc6f92b8 9820
7a13e894 9821 case FocusOut:
19126e11 9822 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9823 if (event.xfocus.detail != NotifyPointer
0f941935
KH
9824 && f == dpyinfo->x_focus_event_frame)
9825 dpyinfo->x_focus_event_frame = 0;
9826 if (f && f == dpyinfo->x_focus_frame)
9827 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 9828
6c183ba5
RS
9829#ifdef HAVE_X_I18N
9830 if (f && FRAME_XIC (f))
9831 XUnsetICFocus (FRAME_XIC (f));
9832#endif
9833
7a13e894 9834 goto OTHER;
dc6f92b8 9835
7a13e894 9836 case MotionNotify:
dc6f92b8 9837 {
06a2c219
GM
9838 previous_help_echo = help_echo;
9839 help_echo = Qnil;
9840
7a13e894
RS
9841 if (dpyinfo->grabbed && last_mouse_frame
9842 && FRAME_LIVE_P (last_mouse_frame))
9843 f = last_mouse_frame;
9844 else
19126e11 9845 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 9846
7a13e894
RS
9847 if (f)
9848 note_mouse_movement (f, &event.xmotion);
9849 else
9850 {
e88b3c50 9851#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
9852 struct scroll_bar *bar
9853 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 9854
7a13e894
RS
9855 if (bar)
9856 x_scroll_bar_note_movement (bar, &event);
e88b3c50 9857#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 9858
06a2c219
GM
9859 /* If we move outside the frame, then we're
9860 certainly no longer on any text in the frame. */
7a13e894
RS
9861 clear_mouse_face (dpyinfo);
9862 }
06a2c219
GM
9863
9864 /* If the contents of the global variable help_echo
9865 has changed, generate a HELP_EVENT. */
b7e80413
SM
9866 if (!NILP (help_echo)
9867 || !NILP (previous_help_echo))
06a2c219
GM
9868 {
9869 Lisp_Object frame;
9870
9871 if (f)
9872 XSETFRAME (frame, f);
9873 else
9874 frame = Qnil;
9875
9876 any_help_event_p = 1;
9877 bufp->kind = HELP_EVENT;
0f1a9b23
GM
9878 bufp->frame_or_window = frame;
9879 bufp->arg = help_echo;
06a2c219
GM
9880 ++bufp, ++count, --numchars;
9881 }
9882
9883 goto OTHER;
dc6f92b8 9884 }
dc6f92b8 9885
7a13e894 9886 case ConfigureNotify:
9829ddba
RS
9887 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
9888 if (f)
af395ec1 9889 {
5c187dee 9890#ifndef USE_X_TOOLKIT
bf1b7b30
KH
9891 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
9892 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 9893
2d7fc7e8
RS
9894 /* In the toolkit version, change_frame_size
9895 is called by the code that handles resizing
9896 of the EmacsFrame widget. */
7a13e894 9897
7a13e894
RS
9898 /* Even if the number of character rows and columns has
9899 not changed, the font size may have changed, so we need
9900 to check the pixel dimensions as well. */
9901 if (columns != f->width
9902 || rows != f->height
7556890b
RS
9903 || event.xconfigure.width != f->output_data.x->pixel_width
9904 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 9905 {
7d1e984f 9906 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 9907 SET_FRAME_GARBAGED (f);
e687d06e 9908 cancel_mouse_face (f);
7a13e894 9909 }
2d7fc7e8 9910#endif
af395ec1 9911
7556890b
RS
9912 f->output_data.x->pixel_width = event.xconfigure.width;
9913 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
9914
9915 /* What we have now is the position of Emacs's own window.
9916 Convert that to the position of the window manager window. */
dcb07ae9
RS
9917 x_real_positions (f, &f->output_data.x->left_pos,
9918 &f->output_data.x->top_pos);
9919
f5d11644
GM
9920#ifdef HAVE_X_I18N
9921 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
9922 xic_set_statusarea (f);
9923#endif
9924
dcb07ae9
RS
9925 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
9926 {
9927 /* Since the WM decorations come below top_pos now,
9928 we must put them below top_pos in the future. */
9929 f->output_data.x->win_gravity = NorthWestGravity;
9930 x_wm_set_size_hint (f, (long) 0, 0);
9931 }
8f08dc93
KH
9932#ifdef USE_MOTIF
9933 /* Some window managers pass (0,0) as the location of
9934 the window, and the Motif event handler stores it
9935 in the emacs widget, which messes up Motif menus. */
9936 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
9937 {
9938 event.xconfigure.x = f->output_data.x->widget->core.x;
9939 event.xconfigure.y = f->output_data.x->widget->core.y;
9940 }
06a2c219 9941#endif /* USE_MOTIF */
7a13e894 9942 }
2d7fc7e8 9943 goto OTHER;
dc6f92b8 9944
7a13e894
RS
9945 case ButtonPress:
9946 case ButtonRelease:
9947 {
9948 /* If we decide we want to generate an event to be seen
9949 by the rest of Emacs, we put it here. */
9950 struct input_event emacs_event;
9ea173e8 9951 int tool_bar_p = 0;
06a2c219 9952
7a13e894 9953 emacs_event.kind = no_event;
7a13e894 9954 bzero (&compose_status, sizeof (compose_status));
9b07615b 9955
06a2c219
GM
9956 if (dpyinfo->grabbed
9957 && last_mouse_frame
9f67f20b
RS
9958 && FRAME_LIVE_P (last_mouse_frame))
9959 f = last_mouse_frame;
9960 else
2224b905 9961 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 9962
06a2c219
GM
9963 if (f)
9964 {
9ea173e8
GM
9965 /* Is this in the tool-bar? */
9966 if (WINDOWP (f->tool_bar_window)
9967 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
9968 {
9969 Lisp_Object window;
9970 int p, x, y;
9971
9972 x = event.xbutton.x;
9973 y = event.xbutton.y;
9974
9975 /* Set x and y. */
9976 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 9977 if (EQ (window, f->tool_bar_window))
06a2c219 9978 {
9ea173e8
GM
9979 x_handle_tool_bar_click (f, &event.xbutton);
9980 tool_bar_p = 1;
06a2c219
GM
9981 }
9982 }
9983
9ea173e8 9984 if (!tool_bar_p)
06a2c219
GM
9985 if (!dpyinfo->x_focus_frame
9986 || f == dpyinfo->x_focus_frame)
9987 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
9988 }
9989 else
9990 {
06a2c219 9991#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
9992 struct scroll_bar *bar
9993 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 9994
7a13e894
RS
9995 if (bar)
9996 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 9997#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9998 }
9999
10000 if (event.type == ButtonPress)
10001 {
10002 dpyinfo->grabbed |= (1 << event.xbutton.button);
10003 last_mouse_frame = f;
edad46f6
KH
10004 /* Ignore any mouse motion that happened
10005 before this event; any subsequent mouse-movement
10006 Emacs events should reflect only motion after
10007 the ButtonPress. */
a00e91cd
KH
10008 if (f != 0)
10009 f->mouse_moved = 0;
06a2c219 10010
9ea173e8
GM
10011 if (!tool_bar_p)
10012 last_tool_bar_item = -1;
7a13e894 10013 }
3afe33e7
RS
10014 else
10015 {
7a13e894 10016 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10017 }
23faf38f 10018
7a13e894
RS
10019 if (numchars >= 1 && emacs_event.kind != no_event)
10020 {
10021 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10022 bufp++;
10023 count++;
10024 numchars--;
10025 }
3afe33e7
RS
10026
10027#ifdef USE_X_TOOLKIT
2224b905
RS
10028 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10029 /* For a down-event in the menu bar,
10030 don't pass it to Xt right now.
10031 Instead, save it away
10032 and we will pass it to Xt from kbd_buffer_get_event.
10033 That way, we can run some Lisp code first. */
91375f8f
RS
10034 if (f && event.type == ButtonPress
10035 /* Verify the event is really within the menu bar
10036 and not just sent to it due to grabbing. */
10037 && event.xbutton.x >= 0
10038 && event.xbutton.x < f->output_data.x->pixel_width
10039 && event.xbutton.y >= 0
10040 && event.xbutton.y < f->output_data.x->menubar_height
10041 && event.xbutton.same_screen)
2224b905 10042 {
8805890a 10043 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
10044 XSETFRAME (last_mouse_press_frame, f);
10045 }
10046 else if (event.type == ButtonPress)
10047 {
10048 last_mouse_press_frame = Qnil;
30e671c3 10049 goto OTHER;
ce89ef46 10050 }
06a2c219 10051
2237cac9
RS
10052#ifdef USE_MOTIF /* This should do not harm for Lucid,
10053 but I am trying to be cautious. */
ce89ef46
RS
10054 else if (event.type == ButtonRelease)
10055 {
2237cac9 10056 if (!NILP (last_mouse_press_frame))
f10ded1c 10057 {
2237cac9
RS
10058 f = XFRAME (last_mouse_press_frame);
10059 if (f->output_data.x)
06a2c219 10060 SET_SAVED_BUTTON_EVENT;
f10ded1c 10061 }
06a2c219 10062 else
30e671c3 10063 goto OTHER;
2224b905 10064 }
2237cac9 10065#endif /* USE_MOTIF */
2224b905
RS
10066 else
10067 goto OTHER;
3afe33e7 10068#endif /* USE_X_TOOLKIT */
7a13e894
RS
10069 }
10070 break;
dc6f92b8 10071
7a13e894 10072 case CirculateNotify:
06a2c219
GM
10073 goto OTHER;
10074
7a13e894 10075 case CirculateRequest:
06a2c219
GM
10076 goto OTHER;
10077
10078 case VisibilityNotify:
10079 goto OTHER;
dc6f92b8 10080
7a13e894
RS
10081 case MappingNotify:
10082 /* Someone has changed the keyboard mapping - update the
10083 local cache. */
10084 switch (event.xmapping.request)
10085 {
10086 case MappingModifier:
10087 x_find_modifier_meanings (dpyinfo);
10088 /* This is meant to fall through. */
10089 case MappingKeyboard:
10090 XRefreshKeyboardMapping (&event.xmapping);
10091 }
7a13e894 10092 goto OTHER;
dc6f92b8 10093
7a13e894 10094 default:
7a13e894 10095 OTHER:
717ca130 10096#ifdef USE_X_TOOLKIT
7a13e894
RS
10097 BLOCK_INPUT;
10098 XtDispatchEvent (&event);
10099 UNBLOCK_INPUT;
3afe33e7 10100#endif /* USE_X_TOOLKIT */
7a13e894
RS
10101 break;
10102 }
dc6f92b8
JB
10103 }
10104 }
10105
06a2c219
GM
10106 out:;
10107
9a5196d0
RS
10108 /* On some systems, an X bug causes Emacs to get no more events
10109 when the window is destroyed. Detect that. (1994.) */
58769bee 10110 if (! event_found)
ef2a22d0 10111 {
ef2a22d0
RS
10112 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
10113 One XNOOP in 100 loops will make Emacs terminate.
10114 B. Bretthauer, 1994 */
10115 x_noop_count++;
58769bee 10116 if (x_noop_count >= 100)
ef2a22d0
RS
10117 {
10118 x_noop_count=0;
2224b905
RS
10119
10120 if (next_noop_dpyinfo == 0)
10121 next_noop_dpyinfo = x_display_list;
10122
10123 XNoOp (next_noop_dpyinfo->display);
10124
10125 /* Each time we get here, cycle through the displays now open. */
10126 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
10127 }
10128 }
502add23 10129
06a2c219 10130 /* If the focus was just given to an auto-raising frame,
0134a210 10131 raise it now. */
7a13e894 10132 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
10133 if (pending_autoraise_frame)
10134 {
10135 x_raise_frame (pending_autoraise_frame);
10136 pending_autoraise_frame = 0;
10137 }
0134a210 10138
dc6f92b8 10139 UNBLOCK_INPUT;
bde5503b 10140 --handling_signal;
dc6f92b8
JB
10141 return count;
10142}
06a2c219
GM
10143
10144
10145
dc6f92b8 10146\f
06a2c219
GM
10147/***********************************************************************
10148 Text Cursor
10149 ***********************************************************************/
10150
10151/* Note if the text cursor of window W has been overwritten by a
10152 drawing operation that outputs N glyphs starting at HPOS in the
10153 line given by output_cursor.vpos. N < 0 means all the rest of the
10154 line after HPOS has been written. */
10155
10156static void
10157note_overwritten_text_cursor (w, hpos, n)
10158 struct window *w;
10159 int hpos, n;
10160{
10161 if (updated_area == TEXT_AREA
10162 && output_cursor.vpos == w->phys_cursor.vpos
10163 && hpos <= w->phys_cursor.hpos
10164 && (n < 0
10165 || hpos + n > w->phys_cursor.hpos))
10166 w->phys_cursor_on_p = 0;
10167}
f451eb13
JB
10168
10169
06a2c219
GM
10170/* Set clipping for output in glyph row ROW. W is the window in which
10171 we operate. GC is the graphics context to set clipping in.
10172 WHOLE_LINE_P non-zero means include the areas used for truncation
10173 mark display and alike in the clipping rectangle.
10174
10175 ROW may be a text row or, e.g., a mode line. Text rows must be
10176 clipped to the interior of the window dedicated to text display,
10177 mode lines must be clipped to the whole window. */
dc6f92b8
JB
10178
10179static void
06a2c219
GM
10180x_clip_to_row (w, row, gc, whole_line_p)
10181 struct window *w;
10182 struct glyph_row *row;
10183 GC gc;
10184 int whole_line_p;
dc6f92b8 10185{
06a2c219
GM
10186 struct frame *f = XFRAME (WINDOW_FRAME (w));
10187 XRectangle clip_rect;
10188 int window_x, window_y, window_width, window_height;
dc6f92b8 10189
06a2c219 10190 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 10191
06a2c219
GM
10192 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
10193 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
10194 clip_rect.y = max (clip_rect.y, window_y);
10195 clip_rect.width = window_width;
10196 clip_rect.height = row->visible_height;
5c1aae96 10197
06a2c219
GM
10198 /* If clipping to the whole line, including trunc marks, extend
10199 the rectangle to the left and increase its width. */
10200 if (whole_line_p)
10201 {
110859fc
GM
10202 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
10203 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 10204 }
5c1aae96 10205
06a2c219 10206 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
10207}
10208
06a2c219
GM
10209
10210/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
10211
10212static void
06a2c219
GM
10213x_draw_hollow_cursor (w, row)
10214 struct window *w;
10215 struct glyph_row *row;
dc6f92b8 10216{
06a2c219
GM
10217 struct frame *f = XFRAME (WINDOW_FRAME (w));
10218 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10219 Display *dpy = FRAME_X_DISPLAY (f);
10220 int x, y, wd, h;
10221 XGCValues xgcv;
10222 struct glyph *cursor_glyph;
10223 GC gc;
10224
10225 /* Compute frame-relative coordinates from window-relative
10226 coordinates. */
10227 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10228 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
10229 + row->ascent - w->phys_cursor_ascent);
10230 h = row->height - 1;
10231
10232 /* Get the glyph the cursor is on. If we can't tell because
10233 the current matrix is invalid or such, give up. */
10234 cursor_glyph = get_phys_cursor_glyph (w);
10235 if (cursor_glyph == NULL)
dc6f92b8
JB
10236 return;
10237
06a2c219
GM
10238 /* Compute the width of the rectangle to draw. If on a stretch
10239 glyph, and `x-stretch-block-cursor' is nil, don't draw a
10240 rectangle as wide as the glyph, but use a canonical character
10241 width instead. */
10242 wd = cursor_glyph->pixel_width - 1;
10243 if (cursor_glyph->type == STRETCH_GLYPH
10244 && !x_stretch_cursor_p)
10245 wd = min (CANON_X_UNIT (f), wd);
10246
10247 /* The foreground of cursor_gc is typically the same as the normal
10248 background color, which can cause the cursor box to be invisible. */
10249 xgcv.foreground = f->output_data.x->cursor_pixel;
10250 if (dpyinfo->scratch_cursor_gc)
10251 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
10252 else
10253 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
10254 GCForeground, &xgcv);
10255 gc = dpyinfo->scratch_cursor_gc;
10256
10257 /* Set clipping, draw the rectangle, and reset clipping again. */
10258 x_clip_to_row (w, row, gc, 0);
10259 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
10260 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
10261}
10262
06a2c219
GM
10263
10264/* Draw a bar cursor on window W in glyph row ROW.
10265
10266 Implementation note: One would like to draw a bar cursor with an
10267 angle equal to the one given by the font property XA_ITALIC_ANGLE.
10268 Unfortunately, I didn't find a font yet that has this property set.
10269 --gerd. */
dc6f92b8
JB
10270
10271static void
f02d8aa0 10272x_draw_bar_cursor (w, row, width)
06a2c219
GM
10273 struct window *w;
10274 struct glyph_row *row;
f02d8aa0 10275 int width;
dc6f92b8 10276{
06a2c219
GM
10277 /* If cursor hpos is out of bounds, don't draw garbage. This can
10278 happen in mini-buffer windows when switching between echo area
10279 glyphs and mini-buffer. */
10280 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
10281 {
10282 struct frame *f = XFRAME (w->frame);
10283 struct glyph *cursor_glyph;
10284 GC gc;
10285 int x;
10286 unsigned long mask;
10287 XGCValues xgcv;
10288 Display *dpy;
10289 Window window;
10290
10291 cursor_glyph = get_phys_cursor_glyph (w);
10292 if (cursor_glyph == NULL)
10293 return;
10294
10295 xgcv.background = f->output_data.x->cursor_pixel;
10296 xgcv.foreground = f->output_data.x->cursor_pixel;
10297 xgcv.graphics_exposures = 0;
10298 mask = GCForeground | GCBackground | GCGraphicsExposures;
10299 dpy = FRAME_X_DISPLAY (f);
10300 window = FRAME_X_WINDOW (f);
10301 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
10302
10303 if (gc)
10304 XChangeGC (dpy, gc, mask, &xgcv);
10305 else
10306 {
10307 gc = XCreateGC (dpy, window, mask, &xgcv);
10308 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
10309 }
10310
f02d8aa0
GM
10311 if (width < 0)
10312 width = f->output_data.x->cursor_width;
10313
06a2c219
GM
10314 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10315 x_clip_to_row (w, row, gc, 0);
10316 XFillRectangle (dpy, window, gc,
10317 x,
10318 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 10319 min (cursor_glyph->pixel_width, width),
06a2c219
GM
10320 row->height);
10321 XSetClipMask (dpy, gc, None);
10322 }
dc6f92b8
JB
10323}
10324
06a2c219
GM
10325
10326/* Clear the cursor of window W to background color, and mark the
10327 cursor as not shown. This is used when the text where the cursor
10328 is is about to be rewritten. */
10329
dc6f92b8 10330static void
06a2c219
GM
10331x_clear_cursor (w)
10332 struct window *w;
dc6f92b8 10333{
06a2c219
GM
10334 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
10335 x_update_window_cursor (w, 0);
10336}
90e65f07 10337
dbc4e1c1 10338
06a2c219
GM
10339/* Draw the cursor glyph of window W in glyph row ROW. See the
10340 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 10341
06a2c219
GM
10342static void
10343x_draw_phys_cursor_glyph (w, row, hl)
10344 struct window *w;
10345 struct glyph_row *row;
10346 enum draw_glyphs_face hl;
10347{
10348 /* If cursor hpos is out of bounds, don't draw garbage. This can
10349 happen in mini-buffer windows when switching between echo area
10350 glyphs and mini-buffer. */
10351 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
10352 {
10353 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
10354 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
10355 hl, 0, 0, 0);
10356
10357 /* When we erase the cursor, and ROW is overlapped by other
10358 rows, make sure that these overlapping parts of other rows
10359 are redrawn. */
10360 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
10361 {
10362 if (row > w->current_matrix->rows
10363 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
10364 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
10365
10366 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
10367 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
10368 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
10369 }
10370 }
06a2c219 10371}
dbc4e1c1 10372
eea6af04 10373
06a2c219 10374/* Erase the image of a cursor of window W from the screen. */
eea6af04 10375
06a2c219
GM
10376static void
10377x_erase_phys_cursor (w)
10378 struct window *w;
10379{
10380 struct frame *f = XFRAME (w->frame);
10381 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10382 int hpos = w->phys_cursor.hpos;
10383 int vpos = w->phys_cursor.vpos;
10384 int mouse_face_here_p = 0;
10385 struct glyph_matrix *active_glyphs = w->current_matrix;
10386 struct glyph_row *cursor_row;
10387 struct glyph *cursor_glyph;
10388 enum draw_glyphs_face hl;
10389
10390 /* No cursor displayed or row invalidated => nothing to do on the
10391 screen. */
10392 if (w->phys_cursor_type == NO_CURSOR)
10393 goto mark_cursor_off;
10394
10395 /* VPOS >= active_glyphs->nrows means that window has been resized.
10396 Don't bother to erase the cursor. */
10397 if (vpos >= active_glyphs->nrows)
10398 goto mark_cursor_off;
10399
10400 /* If row containing cursor is marked invalid, there is nothing we
10401 can do. */
10402 cursor_row = MATRIX_ROW (active_glyphs, vpos);
10403 if (!cursor_row->enabled_p)
10404 goto mark_cursor_off;
10405
10406 /* This can happen when the new row is shorter than the old one.
10407 In this case, either x_draw_glyphs or clear_end_of_line
10408 should have cleared the cursor. Note that we wouldn't be
10409 able to erase the cursor in this case because we don't have a
10410 cursor glyph at hand. */
10411 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
10412 goto mark_cursor_off;
10413
10414 /* If the cursor is in the mouse face area, redisplay that when
10415 we clear the cursor. */
8801a864
KR
10416 if (! NILP (dpyinfo->mouse_face_window)
10417 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
10418 && (vpos > dpyinfo->mouse_face_beg_row
10419 || (vpos == dpyinfo->mouse_face_beg_row
10420 && hpos >= dpyinfo->mouse_face_beg_col))
10421 && (vpos < dpyinfo->mouse_face_end_row
10422 || (vpos == dpyinfo->mouse_face_end_row
10423 && hpos < dpyinfo->mouse_face_end_col))
10424 /* Don't redraw the cursor's spot in mouse face if it is at the
10425 end of a line (on a newline). The cursor appears there, but
10426 mouse highlighting does not. */
10427 && cursor_row->used[TEXT_AREA] > hpos)
10428 mouse_face_here_p = 1;
10429
10430 /* Maybe clear the display under the cursor. */
10431 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
10432 {
10433 int x;
045dee35 10434 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 10435
06a2c219
GM
10436 cursor_glyph = get_phys_cursor_glyph (w);
10437 if (cursor_glyph == NULL)
10438 goto mark_cursor_off;
dbc4e1c1 10439
06a2c219
GM
10440 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
10441
10442 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10443 x,
045dee35 10444 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219
GM
10445 cursor_row->y)),
10446 cursor_glyph->pixel_width,
10447 cursor_row->visible_height,
10448 False);
dbc4e1c1 10449 }
06a2c219
GM
10450
10451 /* Erase the cursor by redrawing the character underneath it. */
10452 if (mouse_face_here_p)
10453 hl = DRAW_MOUSE_FACE;
10454 else if (cursor_row->inverse_p)
10455 hl = DRAW_INVERSE_VIDEO;
10456 else
10457 hl = DRAW_NORMAL_TEXT;
10458 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 10459
06a2c219
GM
10460 mark_cursor_off:
10461 w->phys_cursor_on_p = 0;
10462 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
10463}
10464
10465
06a2c219
GM
10466/* Display or clear cursor of window W. If ON is zero, clear the
10467 cursor. If it is non-zero, display the cursor. If ON is nonzero,
10468 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 10469
06a2c219
GM
10470void
10471x_display_and_set_cursor (w, on, hpos, vpos, x, y)
10472 struct window *w;
10473 int on, hpos, vpos, x, y;
dbc4e1c1 10474{
06a2c219
GM
10475 struct frame *f = XFRAME (w->frame);
10476 int new_cursor_type;
f02d8aa0 10477 int new_cursor_width;
06a2c219
GM
10478 struct glyph_matrix *current_glyphs;
10479 struct glyph_row *glyph_row;
10480 struct glyph *glyph;
dbc4e1c1 10481
49d838ea 10482 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
10483 windows and frames; in the latter case, the frame or window may
10484 be in the midst of changing its size, and x and y may be off the
10485 window. */
10486 if (! FRAME_VISIBLE_P (f)
10487 || FRAME_GARBAGED_P (f)
10488 || vpos >= w->current_matrix->nrows
10489 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
10490 return;
10491
10492 /* If cursor is off and we want it off, return quickly. */
06a2c219 10493 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
10494 return;
10495
06a2c219
GM
10496 current_glyphs = w->current_matrix;
10497 glyph_row = MATRIX_ROW (current_glyphs, vpos);
10498 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
10499
10500 /* If cursor row is not enabled, we don't really know where to
10501 display the cursor. */
10502 if (!glyph_row->enabled_p)
10503 {
10504 w->phys_cursor_on_p = 0;
10505 return;
10506 }
10507
10508 xassert (interrupt_input_blocked);
10509
10510 /* Set new_cursor_type to the cursor we want to be displayed. In a
10511 mini-buffer window, we want the cursor only to appear if we are
10512 reading input from this window. For the selected window, we want
10513 the cursor type given by the frame parameter. If explicitly
10514 marked off, draw no cursor. In all other cases, we want a hollow
10515 box cursor. */
f02d8aa0 10516 new_cursor_width = -1;
9b4a7047
GM
10517 if (cursor_in_echo_area
10518 && FRAME_HAS_MINIBUF_P (f)
10519 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 10520 {
9b4a7047
GM
10521 if (w == XWINDOW (echo_area_window))
10522 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
10523 else
10524 new_cursor_type = HOLLOW_BOX_CURSOR;
10525 }
06a2c219 10526 else
9b4a7047
GM
10527 {
10528 if (w != XWINDOW (selected_window)
10529 || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
10530 {
e55a0b79
GM
10531 extern int cursor_in_non_selected_windows;
10532
10533 if (MINI_WINDOW_P (w) || !cursor_in_non_selected_windows)
9b4a7047
GM
10534 new_cursor_type = NO_CURSOR;
10535 else
10536 new_cursor_type = HOLLOW_BOX_CURSOR;
10537 }
10538 else if (w->cursor_off_p)
10539 new_cursor_type = NO_CURSOR;
10540 else
f02d8aa0
GM
10541 {
10542 struct buffer *b = XBUFFER (w->buffer);
10543
10544 if (EQ (b->cursor_type, Qt))
10545 new_cursor_type = FRAME_DESIRED_CURSOR (f);
10546 else
10547 new_cursor_type = x_specified_cursor_type (b->cursor_type,
10548 &new_cursor_width);
10549 }
9b4a7047 10550 }
06a2c219
GM
10551
10552 /* If cursor is currently being shown and we don't want it to be or
10553 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 10554 erase it. */
06a2c219 10555 if (w->phys_cursor_on_p
dc6f92b8 10556 && (!on
06a2c219
GM
10557 || w->phys_cursor.x != x
10558 || w->phys_cursor.y != y
10559 || new_cursor_type != w->phys_cursor_type))
10560 x_erase_phys_cursor (w);
10561
10562 /* If the cursor is now invisible and we want it to be visible,
10563 display it. */
10564 if (on && !w->phys_cursor_on_p)
10565 {
10566 w->phys_cursor_ascent = glyph_row->ascent;
10567 w->phys_cursor_height = glyph_row->height;
10568
10569 /* Set phys_cursor_.* before x_draw_.* is called because some
10570 of them may need the information. */
10571 w->phys_cursor.x = x;
10572 w->phys_cursor.y = glyph_row->y;
10573 w->phys_cursor.hpos = hpos;
10574 w->phys_cursor.vpos = vpos;
10575 w->phys_cursor_type = new_cursor_type;
10576 w->phys_cursor_on_p = 1;
10577
10578 switch (new_cursor_type)
dc6f92b8 10579 {
06a2c219
GM
10580 case HOLLOW_BOX_CURSOR:
10581 x_draw_hollow_cursor (w, glyph_row);
10582 break;
10583
10584 case FILLED_BOX_CURSOR:
10585 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
10586 break;
10587
10588 case BAR_CURSOR:
f02d8aa0 10589 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
10590 break;
10591
10592 case NO_CURSOR:
10593 break;
dc6f92b8 10594
06a2c219
GM
10595 default:
10596 abort ();
10597 }
59ddecde
GM
10598
10599#ifdef HAVE_X_I18N
10600 if (w == XWINDOW (f->selected_window))
10601 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
10602 xic_set_preeditarea (w, x, y);
10603#endif
dc6f92b8
JB
10604 }
10605
06a2c219 10606#ifndef XFlush
f676886a 10607 if (updating_frame != f)
334208b7 10608 XFlush (FRAME_X_DISPLAY (f));
06a2c219 10609#endif
dc6f92b8
JB
10610}
10611
06a2c219
GM
10612
10613/* Display the cursor on window W, or clear it. X and Y are window
10614 relative pixel coordinates. HPOS and VPOS are glyph matrix
10615 positions. If W is not the selected window, display a hollow
10616 cursor. ON non-zero means display the cursor at X, Y which
10617 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 10618
dfcf069d 10619void
06a2c219
GM
10620x_display_cursor (w, on, hpos, vpos, x, y)
10621 struct window *w;
10622 int on, hpos, vpos, x, y;
dc6f92b8 10623{
f94397b5 10624 BLOCK_INPUT;
06a2c219 10625 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
10626 UNBLOCK_INPUT;
10627}
10628
06a2c219
GM
10629
10630/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
10631 Don't change the cursor's position. */
10632
dfcf069d 10633void
06a2c219 10634x_update_cursor (f, on_p)
5d46f928 10635 struct frame *f;
5d46f928 10636{
06a2c219
GM
10637 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
10638}
10639
10640
10641/* Call x_update_window_cursor with parameter ON_P on all leaf windows
10642 in the window tree rooted at W. */
10643
10644static void
10645x_update_cursor_in_window_tree (w, on_p)
10646 struct window *w;
10647 int on_p;
10648{
10649 while (w)
10650 {
10651 if (!NILP (w->hchild))
10652 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
10653 else if (!NILP (w->vchild))
10654 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
10655 else
10656 x_update_window_cursor (w, on_p);
10657
10658 w = NILP (w->next) ? 0 : XWINDOW (w->next);
10659 }
10660}
5d46f928 10661
f94397b5 10662
06a2c219
GM
10663/* Switch the display of W's cursor on or off, according to the value
10664 of ON. */
10665
10666static void
10667x_update_window_cursor (w, on)
10668 struct window *w;
10669 int on;
10670{
16b5d424
GM
10671 /* Don't update cursor in windows whose frame is in the process
10672 of being deleted. */
10673 if (w->current_matrix)
10674 {
10675 BLOCK_INPUT;
10676 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
10677 w->phys_cursor.x, w->phys_cursor.y);
10678 UNBLOCK_INPUT;
10679 }
dc6f92b8 10680}
06a2c219
GM
10681
10682
10683
dc6f92b8
JB
10684\f
10685/* Icons. */
10686
f676886a 10687/* Refresh bitmap kitchen sink icon for frame F
06a2c219 10688 when we get an expose event for it. */
dc6f92b8 10689
dfcf069d 10690void
f676886a
JB
10691refreshicon (f)
10692 struct frame *f;
dc6f92b8 10693{
06a2c219 10694 /* Normally, the window manager handles this function. */
dc6f92b8
JB
10695}
10696
dbc4e1c1 10697/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
10698
10699int
990ba854 10700x_bitmap_icon (f, file)
f676886a 10701 struct frame *f;
990ba854 10702 Lisp_Object file;
dc6f92b8 10703{
06a2c219 10704 int bitmap_id;
dc6f92b8 10705
c118dd06 10706 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10707 return 1;
10708
990ba854 10709 /* Free up our existing icon bitmap if any. */
7556890b
RS
10710 if (f->output_data.x->icon_bitmap > 0)
10711 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10712 f->output_data.x->icon_bitmap = 0;
990ba854
RS
10713
10714 if (STRINGP (file))
7f2ae036
RS
10715 bitmap_id = x_create_bitmap_from_file (f, file);
10716 else
10717 {
990ba854 10718 /* Create the GNU bitmap if necessary. */
5bf01b68 10719 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
10720 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
10721 = x_create_bitmap_from_data (f, gnu_bits,
10722 gnu_width, gnu_height);
990ba854
RS
10723
10724 /* The first time we create the GNU bitmap,
06a2c219 10725 this increments the ref-count one extra time.
990ba854
RS
10726 As a result, the GNU bitmap is never freed.
10727 That way, we don't have to worry about allocating it again. */
334208b7 10728 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 10729
334208b7 10730 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
10731 }
10732
10733 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 10734 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
10735
10736 return 0;
10737}
10738
10739
1be2d067
KH
10740/* Make the x-window of frame F use a rectangle with text.
10741 Use ICON_NAME as the text. */
dc6f92b8
JB
10742
10743int
f676886a
JB
10744x_text_icon (f, icon_name)
10745 struct frame *f;
dc6f92b8
JB
10746 char *icon_name;
10747{
c118dd06 10748 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10749 return 1;
10750
1be2d067
KH
10751#ifdef HAVE_X11R4
10752 {
10753 XTextProperty text;
10754 text.value = (unsigned char *) icon_name;
10755 text.encoding = XA_STRING;
10756 text.format = 8;
10757 text.nitems = strlen (icon_name);
10758#ifdef USE_X_TOOLKIT
7556890b 10759 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
10760 &text);
10761#else /* not USE_X_TOOLKIT */
10762 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
10763#endif /* not USE_X_TOOLKIT */
10764 }
10765#else /* not HAVE_X11R4 */
10766 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
10767#endif /* not HAVE_X11R4 */
58769bee 10768
7556890b
RS
10769 if (f->output_data.x->icon_bitmap > 0)
10770 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10771 f->output_data.x->icon_bitmap = 0;
b1c884c3 10772 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
10773
10774 return 0;
10775}
10776\f
e99db5a1
RS
10777#define X_ERROR_MESSAGE_SIZE 200
10778
10779/* If non-nil, this should be a string.
10780 It means catch X errors and store the error message in this string. */
10781
10782static Lisp_Object x_error_message_string;
10783
10784/* An X error handler which stores the error message in
10785 x_error_message_string. This is called from x_error_handler if
10786 x_catch_errors is in effect. */
10787
06a2c219 10788static void
e99db5a1
RS
10789x_error_catcher (display, error)
10790 Display *display;
10791 XErrorEvent *error;
10792{
10793 XGetErrorText (display, error->error_code,
10794 XSTRING (x_error_message_string)->data,
10795 X_ERROR_MESSAGE_SIZE);
10796}
10797
10798/* Begin trapping X errors for display DPY. Actually we trap X errors
10799 for all displays, but DPY should be the display you are actually
10800 operating on.
10801
10802 After calling this function, X protocol errors no longer cause
10803 Emacs to exit; instead, they are recorded in the string
10804 stored in x_error_message_string.
10805
10806 Calling x_check_errors signals an Emacs error if an X error has
10807 occurred since the last call to x_catch_errors or x_check_errors.
10808
10809 Calling x_uncatch_errors resumes the normal error handling. */
10810
10811void x_check_errors ();
10812static Lisp_Object x_catch_errors_unwind ();
10813
10814int
10815x_catch_errors (dpy)
10816 Display *dpy;
10817{
10818 int count = specpdl_ptr - specpdl;
10819
10820 /* Make sure any errors from previous requests have been dealt with. */
10821 XSync (dpy, False);
10822
10823 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
10824
10825 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
10826 XSTRING (x_error_message_string)->data[0] = 0;
10827
10828 return count;
10829}
10830
10831/* Unbind the binding that we made to check for X errors. */
10832
10833static Lisp_Object
10834x_catch_errors_unwind (old_val)
10835 Lisp_Object old_val;
10836{
10837 x_error_message_string = old_val;
10838 return Qnil;
10839}
10840
10841/* If any X protocol errors have arrived since the last call to
10842 x_catch_errors or x_check_errors, signal an Emacs error using
10843 sprintf (a buffer, FORMAT, the x error message text) as the text. */
10844
10845void
10846x_check_errors (dpy, format)
10847 Display *dpy;
10848 char *format;
10849{
10850 /* Make sure to catch any errors incurred so far. */
10851 XSync (dpy, False);
10852
10853 if (XSTRING (x_error_message_string)->data[0])
10854 error (format, XSTRING (x_error_message_string)->data);
10855}
10856
9829ddba
RS
10857/* Nonzero if we had any X protocol errors
10858 since we did x_catch_errors on DPY. */
e99db5a1
RS
10859
10860int
10861x_had_errors_p (dpy)
10862 Display *dpy;
10863{
10864 /* Make sure to catch any errors incurred so far. */
10865 XSync (dpy, False);
10866
10867 return XSTRING (x_error_message_string)->data[0] != 0;
10868}
10869
9829ddba
RS
10870/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
10871
06a2c219 10872void
9829ddba
RS
10873x_clear_errors (dpy)
10874 Display *dpy;
10875{
10876 XSTRING (x_error_message_string)->data[0] = 0;
10877}
10878
e99db5a1
RS
10879/* Stop catching X protocol errors and let them make Emacs die.
10880 DPY should be the display that was passed to x_catch_errors.
10881 COUNT should be the value that was returned by
10882 the corresponding call to x_catch_errors. */
10883
10884void
10885x_uncatch_errors (dpy, count)
10886 Display *dpy;
10887 int count;
10888{
10889 unbind_to (count, Qnil);
10890}
10891
10892#if 0
10893static unsigned int x_wire_count;
10894x_trace_wire ()
10895{
10896 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
10897}
10898#endif /* ! 0 */
10899
10900\f
10901/* Handle SIGPIPE, which can happen when the connection to a server
10902 simply goes away. SIGPIPE is handled by x_connection_signal.
10903 Don't need to do anything, because the write which caused the
10904 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 10905 which will do the appropriate cleanup for us. */
e99db5a1
RS
10906
10907static SIGTYPE
10908x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 10909 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
10910{
10911#ifdef USG
10912 /* USG systems forget handlers when they are used;
10913 must reestablish each time */
10914 signal (signalnum, x_connection_signal);
10915#endif /* USG */
10916}
10917\f
4746118a
JB
10918/* Handling X errors. */
10919
7a13e894 10920/* Handle the loss of connection to display DISPLAY. */
16bd92ea 10921
4746118a 10922static SIGTYPE
7a13e894
RS
10923x_connection_closed (display, error_message)
10924 Display *display;
10925 char *error_message;
4746118a 10926{
7a13e894
RS
10927 struct x_display_info *dpyinfo = x_display_info_for_display (display);
10928 Lisp_Object frame, tail;
10929
6186a4a0
RS
10930 /* Indicate that this display is dead. */
10931
2e465cdd 10932#if 0 /* Closing the display caused a bus error on OpenWindows. */
f613a4c8 10933#ifdef USE_X_TOOLKIT
adabc3a9 10934 XtCloseDisplay (display);
2e465cdd 10935#endif
f613a4c8 10936#endif
adabc3a9 10937
9e80b57d
KR
10938 if (dpyinfo)
10939 dpyinfo->display = 0;
6186a4a0 10940
06a2c219 10941 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
10942 that are on the dead display. */
10943 FOR_EACH_FRAME (tail, frame)
10944 {
10945 Lisp_Object minibuf_frame;
10946 minibuf_frame
10947 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
10948 if (FRAME_X_P (XFRAME (frame))
10949 && FRAME_X_P (XFRAME (minibuf_frame))
10950 && ! EQ (frame, minibuf_frame)
10951 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
10952 Fdelete_frame (frame, Qt);
10953 }
10954
10955 /* Now delete all remaining frames on the dead display.
06a2c219 10956 We are now sure none of these is used as the mini-buffer
7a13e894
RS
10957 for another frame that we need to delete. */
10958 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
10959 if (FRAME_X_P (XFRAME (frame))
10960 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
10961 {
10962 /* Set this to t so that Fdelete_frame won't get confused
10963 trying to find a replacement. */
10964 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
10965 Fdelete_frame (frame, Qt);
10966 }
7a13e894 10967
482a1bd2
KH
10968 if (dpyinfo)
10969 x_delete_display (dpyinfo);
7a13e894
RS
10970
10971 if (x_display_list == 0)
10972 {
f8d07b62 10973 fprintf (stderr, "%s\n", error_message);
7a13e894
RS
10974 shut_down_emacs (0, 0, Qnil);
10975 exit (70);
10976 }
12ba150f 10977
7a13e894
RS
10978 /* Ordinary stack unwind doesn't deal with these. */
10979#ifdef SIGIO
10980 sigunblock (sigmask (SIGIO));
10981#endif
10982 sigunblock (sigmask (SIGALRM));
10983 TOTALLY_UNBLOCK_INPUT;
10984
aa4d9a9e 10985 clear_waiting_for_input ();
7a13e894 10986 error ("%s", error_message);
4746118a
JB
10987}
10988
7a13e894
RS
10989/* This is the usual handler for X protocol errors.
10990 It kills all frames on the display that we got the error for.
10991 If that was the only one, it prints an error message and kills Emacs. */
10992
06a2c219 10993static void
c118dd06
JB
10994x_error_quitter (display, error)
10995 Display *display;
10996 XErrorEvent *error;
10997{
7a13e894 10998 char buf[256], buf1[356];
dc6f92b8 10999
58769bee 11000 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 11001 original error handler. */
dc6f92b8 11002
c118dd06 11003 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 11004 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 11005 buf, error->request_code);
7a13e894 11006 x_connection_closed (display, buf1);
dc6f92b8
JB
11007}
11008
e99db5a1
RS
11009/* This is the first-level handler for X protocol errors.
11010 It calls x_error_quitter or x_error_catcher. */
7a13e894 11011
8922af5f 11012static int
e99db5a1 11013x_error_handler (display, error)
8922af5f 11014 Display *display;
e99db5a1 11015 XErrorEvent *error;
8922af5f 11016{
e99db5a1
RS
11017 if (! NILP (x_error_message_string))
11018 x_error_catcher (display, error);
11019 else
11020 x_error_quitter (display, error);
06a2c219 11021 return 0;
f9e24cb9 11022}
c118dd06 11023
e99db5a1
RS
11024/* This is the handler for X IO errors, always.
11025 It kills all frames on the display that we lost touch with.
11026 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 11027
c118dd06 11028static int
e99db5a1 11029x_io_error_quitter (display)
c118dd06 11030 Display *display;
c118dd06 11031{
e99db5a1 11032 char buf[256];
dc6f92b8 11033
e99db5a1
RS
11034 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
11035 x_connection_closed (display, buf);
06a2c219 11036 return 0;
dc6f92b8 11037}
dc6f92b8 11038\f
f451eb13
JB
11039/* Changing the font of the frame. */
11040
76bcdf39
RS
11041/* Give frame F the font named FONTNAME as its default font, and
11042 return the full name of that font. FONTNAME may be a wildcard
11043 pattern; in that case, we choose some font that fits the pattern.
11044 The return value shows which font we chose. */
11045
b5cf7a0e 11046Lisp_Object
f676886a
JB
11047x_new_font (f, fontname)
11048 struct frame *f;
dc6f92b8
JB
11049 register char *fontname;
11050{
dc43ef94 11051 struct font_info *fontp
ee569018 11052 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 11053
dc43ef94
KH
11054 if (!fontp)
11055 return Qnil;
2224a5fc 11056
dc43ef94 11057 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 11058 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
11059 f->output_data.x->fontset = -1;
11060
b2cad826
KH
11061 /* Compute the scroll bar width in character columns. */
11062 if (f->scroll_bar_pixel_width > 0)
11063 {
7556890b 11064 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
11065 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
11066 }
11067 else
4e61bddf
RS
11068 {
11069 int wid = FONT_WIDTH (f->output_data.x->font);
11070 f->scroll_bar_cols = (14 + wid - 1) / wid;
11071 }
b2cad826 11072
f676886a 11073 /* Now make the frame display the given font. */
c118dd06 11074 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 11075 {
7556890b
RS
11076 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
11077 f->output_data.x->font->fid);
11078 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
11079 f->output_data.x->font->fid);
11080 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
11081 f->output_data.x->font->fid);
f676886a 11082
a27f9f86 11083 frame_update_line_height (f);
0134a210 11084 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 11085 }
a27f9f86
RS
11086 else
11087 /* If we are setting a new frame's font for the first time,
11088 there are no faces yet, so this font's height is the line height. */
7556890b 11089 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 11090
dc43ef94
KH
11091 return build_string (fontp->full_name);
11092}
11093
11094/* Give frame F the fontset named FONTSETNAME as its default font, and
11095 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
11096 pattern; in that case, we choose some fontset that fits the pattern.
11097 The return value shows which fontset we chose. */
b5cf7a0e 11098
dc43ef94
KH
11099Lisp_Object
11100x_new_fontset (f, fontsetname)
11101 struct frame *f;
11102 char *fontsetname;
11103{
ee569018 11104 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 11105 Lisp_Object result;
b5cf7a0e 11106
dc43ef94
KH
11107 if (fontset < 0)
11108 return Qnil;
b5cf7a0e 11109
2da424f1
KH
11110 if (f->output_data.x->fontset == fontset)
11111 /* This fontset is already set in frame F. There's nothing more
11112 to do. */
ee569018 11113 return fontset_name (fontset);
dc43ef94 11114
ee569018 11115 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
11116
11117 if (!STRINGP (result))
11118 /* Can't load ASCII font. */
11119 return Qnil;
11120
11121 /* Since x_new_font doesn't update any fontset information, do it now. */
11122 f->output_data.x->fontset = fontset;
dc43ef94 11123
f5d11644
GM
11124#ifdef HAVE_X_I18N
11125 if (FRAME_XIC (f)
11126 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 11127 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
11128#endif
11129
dc43ef94 11130 return build_string (fontsetname);
dc6f92b8 11131}
f5d11644
GM
11132
11133\f
11134/***********************************************************************
11135 X Input Methods
11136 ***********************************************************************/
11137
11138#ifdef HAVE_X_I18N
11139
11140#ifdef HAVE_X11R6
11141
11142/* XIM destroy callback function, which is called whenever the
11143 connection to input method XIM dies. CLIENT_DATA contains a
11144 pointer to the x_display_info structure corresponding to XIM. */
11145
11146static void
11147xim_destroy_callback (xim, client_data, call_data)
11148 XIM xim;
11149 XPointer client_data;
11150 XPointer call_data;
11151{
11152 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
11153 Lisp_Object frame, tail;
11154
11155 BLOCK_INPUT;
11156
11157 /* No need to call XDestroyIC.. */
11158 FOR_EACH_FRAME (tail, frame)
11159 {
11160 struct frame *f = XFRAME (frame);
11161 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
11162 {
11163 FRAME_XIC (f) = NULL;
11164 if (FRAME_XIC_FONTSET (f))
11165 {
11166 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
11167 FRAME_XIC_FONTSET (f) = NULL;
11168 }
11169 }
11170 }
11171
11172 /* No need to call XCloseIM. */
11173 dpyinfo->xim = NULL;
11174 XFree (dpyinfo->xim_styles);
11175 UNBLOCK_INPUT;
11176}
11177
11178#endif /* HAVE_X11R6 */
11179
11180/* Open the connection to the XIM server on display DPYINFO.
11181 RESOURCE_NAME is the resource name Emacs uses. */
11182
11183static void
11184xim_open_dpy (dpyinfo, resource_name)
11185 struct x_display_info *dpyinfo;
11186 char *resource_name;
11187{
287f7dd6 11188#ifdef USE_XIM
f5d11644
GM
11189 XIM xim;
11190
11191 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
11192 dpyinfo->xim = xim;
11193
11194 if (xim)
11195 {
f5d11644
GM
11196#ifdef HAVE_X11R6
11197 XIMCallback destroy;
11198#endif
11199
11200 /* Get supported styles and XIM values. */
11201 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
11202
11203#ifdef HAVE_X11R6
11204 destroy.callback = xim_destroy_callback;
11205 destroy.client_data = (XPointer)dpyinfo;
68642df6 11206 /* This isn't prptotyped in OSF 5.0. */
f5d11644
GM
11207 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
11208#endif
11209 }
287f7dd6
GM
11210
11211#else /* not USE_XIM */
11212 dpyinfo->xim = NULL;
11213#endif /* not USE_XIM */
f5d11644
GM
11214}
11215
11216
b9de836c 11217#ifdef HAVE_X11R6_XIM
f5d11644
GM
11218
11219struct xim_inst_t
11220{
11221 struct x_display_info *dpyinfo;
11222 char *resource_name;
11223};
11224
11225/* XIM instantiate callback function, which is called whenever an XIM
11226 server is available. DISPLAY is teh display of the XIM.
11227 CLIENT_DATA contains a pointer to an xim_inst_t structure created
11228 when the callback was registered. */
11229
11230static void
11231xim_instantiate_callback (display, client_data, call_data)
11232 Display *display;
11233 XPointer client_data;
11234 XPointer call_data;
11235{
11236 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
11237 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
11238
11239 /* We don't support multiple XIM connections. */
11240 if (dpyinfo->xim)
11241 return;
11242
11243 xim_open_dpy (dpyinfo, xim_inst->resource_name);
11244
11245 /* Create XIC for the existing frames on the same display, as long
11246 as they have no XIC. */
11247 if (dpyinfo->xim && dpyinfo->reference_count > 0)
11248 {
11249 Lisp_Object tail, frame;
11250
11251 BLOCK_INPUT;
11252 FOR_EACH_FRAME (tail, frame)
11253 {
11254 struct frame *f = XFRAME (frame);
11255
11256 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
11257 if (FRAME_XIC (f) == NULL)
11258 {
11259 create_frame_xic (f);
11260 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
11261 xic_set_statusarea (f);
11262 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
11263 {
11264 struct window *w = XWINDOW (f->selected_window);
11265 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
11266 }
11267 }
11268 }
11269
11270 UNBLOCK_INPUT;
11271 }
11272}
11273
b9de836c 11274#endif /* HAVE_X11R6_XIM */
f5d11644
GM
11275
11276
11277/* Open a connection to the XIM server on display DPYINFO.
11278 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
11279 connection only at the first time. On X11R6, open the connection
11280 in the XIM instantiate callback function. */
11281
11282static void
11283xim_initialize (dpyinfo, resource_name)
11284 struct x_display_info *dpyinfo;
11285 char *resource_name;
11286{
287f7dd6 11287#ifdef USE_XIM
b9de836c 11288#ifdef HAVE_X11R6_XIM
f5d11644
GM
11289 struct xim_inst_t *xim_inst;
11290 int len;
11291
11292 dpyinfo->xim = NULL;
11293 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
11294 xim_inst->dpyinfo = dpyinfo;
11295 len = strlen (resource_name);
11296 xim_inst->resource_name = (char *) xmalloc (len + 1);
11297 bcopy (resource_name, xim_inst->resource_name, len + 1);
11298 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11299 resource_name, EMACS_CLASS,
11300 xim_instantiate_callback,
2ebb2f8b
DL
11301 /* Fixme: This is XPointer in
11302 XFree86 but (XPointer *) on
11303 Tru64, at least. */
11304 (XPointer) xim_inst);
b9de836c 11305#else /* not HAVE_X11R6_XIM */
f5d11644
GM
11306 dpyinfo->xim = NULL;
11307 xim_open_dpy (dpyinfo, resource_name);
b9de836c 11308#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
11309
11310#else /* not USE_XIM */
11311 dpyinfo->xim = NULL;
11312#endif /* not USE_XIM */
f5d11644
GM
11313}
11314
11315
11316/* Close the connection to the XIM server on display DPYINFO. */
11317
11318static void
11319xim_close_dpy (dpyinfo)
11320 struct x_display_info *dpyinfo;
11321{
287f7dd6 11322#ifdef USE_XIM
b9de836c 11323#ifdef HAVE_X11R6_XIM
f5d11644
GM
11324 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11325 NULL, EMACS_CLASS,
11326 xim_instantiate_callback, NULL);
b9de836c 11327#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11328 XCloseIM (dpyinfo->xim);
11329 dpyinfo->xim = NULL;
11330 XFree (dpyinfo->xim_styles);
287f7dd6 11331#endif /* USE_XIM */
f5d11644
GM
11332}
11333
b9de836c 11334#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11335
11336
dc6f92b8 11337\f
2e365682
RS
11338/* Calculate the absolute position in frame F
11339 from its current recorded position values and gravity. */
11340
dfcf069d 11341void
43bca5d5 11342x_calc_absolute_position (f)
f676886a 11343 struct frame *f;
dc6f92b8 11344{
06a2c219 11345 Window child;
6dba1858 11346 int win_x = 0, win_y = 0;
7556890b 11347 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
11348 int this_window;
11349
9829ddba
RS
11350 /* We have nothing to do if the current position
11351 is already for the top-left corner. */
11352 if (! ((flags & XNegative) || (flags & YNegative)))
11353 return;
11354
c81412a0 11355#ifdef USE_X_TOOLKIT
7556890b 11356 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
11357#else
11358 this_window = FRAME_X_WINDOW (f);
11359#endif
6dba1858
RS
11360
11361 /* Find the position of the outside upper-left corner of
9829ddba
RS
11362 the inner window, with respect to the outer window.
11363 But do this only if we will need the results. */
7556890b 11364 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 11365 {
9829ddba
RS
11366 int count;
11367
6dba1858 11368 BLOCK_INPUT;
9829ddba
RS
11369 count = x_catch_errors (FRAME_X_DISPLAY (f));
11370 while (1)
11371 {
11372 x_clear_errors (FRAME_X_DISPLAY (f));
11373 XTranslateCoordinates (FRAME_X_DISPLAY (f),
11374
11375 /* From-window, to-window. */
11376 this_window,
11377 f->output_data.x->parent_desc,
11378
11379 /* From-position, to-position. */
11380 0, 0, &win_x, &win_y,
11381
11382 /* Child of win. */
11383 &child);
11384 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
11385 {
11386 Window newroot, newparent = 0xdeadbeef;
11387 Window *newchildren;
2ebb2f8b 11388 unsigned int nchildren;
9829ddba
RS
11389
11390 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
11391 &newparent, &newchildren, &nchildren))
11392 break;
58769bee 11393
7c3c78a3 11394 XFree ((char *) newchildren);
6dba1858 11395
9829ddba
RS
11396 f->output_data.x->parent_desc = newparent;
11397 }
11398 else
11399 break;
11400 }
6dba1858 11401
9829ddba 11402 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
11403 UNBLOCK_INPUT;
11404 }
11405
11406 /* Treat negative positions as relative to the leftmost bottommost
11407 position that fits on the screen. */
20f55f9a 11408 if (flags & XNegative)
7556890b 11409 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
11410 - 2 * f->output_data.x->border_width - win_x
11411 - PIXEL_WIDTH (f)
11412 + f->output_data.x->left_pos);
dc6f92b8 11413
20f55f9a 11414 if (flags & YNegative)
06a2c219
GM
11415 {
11416 int menubar_height = 0;
11417
11418#ifdef USE_X_TOOLKIT
11419 if (f->output_data.x->menubar_widget)
11420 menubar_height
11421 = (f->output_data.x->menubar_widget->core.height
11422 + f->output_data.x->menubar_widget->core.border_width);
11423#endif
11424
11425 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
11426 - 2 * f->output_data.x->border_width
11427 - win_y
11428 - PIXEL_HEIGHT (f)
11429 - menubar_height
11430 + f->output_data.x->top_pos);
11431 }
2e365682 11432
3a35ab44
RS
11433 /* The left_pos and top_pos
11434 are now relative to the top and left screen edges,
11435 so the flags should correspond. */
7556890b 11436 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
11437}
11438
3a35ab44
RS
11439/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
11440 to really change the position, and 0 when calling from
11441 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
11442 position values). It is -1 when calling from x_set_frame_parameters,
11443 which means, do adjust for borders but don't change the gravity. */
3a35ab44 11444
dfcf069d 11445void
dc05a16b 11446x_set_offset (f, xoff, yoff, change_gravity)
f676886a 11447 struct frame *f;
dc6f92b8 11448 register int xoff, yoff;
dc05a16b 11449 int change_gravity;
dc6f92b8 11450{
4a4cbdd5
KH
11451 int modified_top, modified_left;
11452
aa3ff7c9 11453 if (change_gravity > 0)
3a35ab44 11454 {
7556890b
RS
11455 f->output_data.x->top_pos = yoff;
11456 f->output_data.x->left_pos = xoff;
11457 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 11458 if (xoff < 0)
7556890b 11459 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 11460 if (yoff < 0)
7556890b
RS
11461 f->output_data.x->size_hint_flags |= YNegative;
11462 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 11463 }
43bca5d5 11464 x_calc_absolute_position (f);
dc6f92b8
JB
11465
11466 BLOCK_INPUT;
c32cdd9a 11467 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 11468
7556890b
RS
11469 modified_left = f->output_data.x->left_pos;
11470 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
11471#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
11472 this seems to be unnecessary and incorrect. rms, 4/17/97. */
11473 /* It is a mystery why we need to add the border_width here
11474 when the frame is already visible, but experiment says we do. */
aa3ff7c9 11475 if (change_gravity != 0)
4a4cbdd5 11476 {
7556890b
RS
11477 modified_left += f->output_data.x->border_width;
11478 modified_top += f->output_data.x->border_width;
4a4cbdd5 11479 }
e73ec6fa 11480#endif
4a4cbdd5 11481
3afe33e7 11482#ifdef USE_X_TOOLKIT
7556890b 11483 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 11484 modified_left, modified_top);
3afe33e7 11485#else /* not USE_X_TOOLKIT */
334208b7 11486 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 11487 modified_left, modified_top);
3afe33e7 11488#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11489 UNBLOCK_INPUT;
11490}
11491
bc20ebbf
FP
11492/* Call this to change the size of frame F's x-window.
11493 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
11494 for this size change and subsequent size changes.
11495 Otherwise we leave the window gravity unchanged. */
dc6f92b8 11496
dfcf069d 11497void
bc20ebbf 11498x_set_window_size (f, change_gravity, cols, rows)
f676886a 11499 struct frame *f;
bc20ebbf 11500 int change_gravity;
b1c884c3 11501 int cols, rows;
dc6f92b8 11502{
06a2c219 11503#ifndef USE_X_TOOLKIT
dc6f92b8 11504 int pixelwidth, pixelheight;
06a2c219 11505#endif
dc6f92b8 11506
80fd1fe2 11507 BLOCK_INPUT;
aee9a898
RS
11508
11509#ifdef USE_X_TOOLKIT
3a20653d
RS
11510 {
11511 /* The x and y position of the widget is clobbered by the
11512 call to XtSetValues within EmacsFrameSetCharSize.
11513 This is a real kludge, but I don't understand Xt so I can't
11514 figure out a correct fix. Can anyone else tell me? -- rms. */
7556890b
RS
11515 int xpos = f->output_data.x->widget->core.x;
11516 int ypos = f->output_data.x->widget->core.y;
11517 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
11518 f->output_data.x->widget->core.x = xpos;
11519 f->output_data.x->widget->core.y = ypos;
3a20653d 11520 }
80fd1fe2
FP
11521
11522#else /* not USE_X_TOOLKIT */
11523
b1c884c3 11524 check_frame_size (f, &rows, &cols);
7556890b 11525 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
11526 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
11527 ? 0
11528 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 11529 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 11530 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 11531 f->output_data.x->flags_areas_extra
110859fc 11532 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
11533 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
11534 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 11535
7556890b 11536 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 11537 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 11538
334208b7
RS
11539 XSync (FRAME_X_DISPLAY (f), False);
11540 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11541 pixelwidth, pixelheight);
b1c884c3
JB
11542
11543 /* Now, strictly speaking, we can't be sure that this is accurate,
11544 but the window manager will get around to dealing with the size
11545 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
11546 ConfigureNotify event gets here.
11547
11548 We could just not bother storing any of this information here,
11549 and let the ConfigureNotify event set everything up, but that
fddd5ceb 11550 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 11551 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
11552 point in the future when the ConfigureNotify event arrives.
11553
11554 We pass 1 for DELAY since we can't run Lisp code inside of
11555 a BLOCK_INPUT. */
7d1e984f 11556 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
11557 PIXEL_WIDTH (f) = pixelwidth;
11558 PIXEL_HEIGHT (f) = pixelheight;
11559
aee9a898
RS
11560 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
11561 receive in the ConfigureNotify event; if we get what we asked
11562 for, then the event won't cause the screen to become garbaged, so
11563 we have to make sure to do it here. */
11564 SET_FRAME_GARBAGED (f);
11565
11566 XFlush (FRAME_X_DISPLAY (f));
11567
11568#endif /* not USE_X_TOOLKIT */
11569
4d73d038 11570 /* If cursor was outside the new size, mark it as off. */
06a2c219 11571 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 11572
aee9a898
RS
11573 /* Clear out any recollection of where the mouse highlighting was,
11574 since it might be in a place that's outside the new frame size.
11575 Actually checking whether it is outside is a pain in the neck,
11576 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 11577 cancel_mouse_face (f);
dbc4e1c1 11578
dc6f92b8
JB
11579 UNBLOCK_INPUT;
11580}
dc6f92b8 11581\f
d047c4eb 11582/* Mouse warping. */
dc6f92b8 11583
9b378208 11584void
f676886a
JB
11585x_set_mouse_position (f, x, y)
11586 struct frame *f;
dc6f92b8
JB
11587 int x, y;
11588{
11589 int pix_x, pix_y;
11590
7556890b
RS
11591 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
11592 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
11593
11594 if (pix_x < 0) pix_x = 0;
11595 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
11596
11597 if (pix_y < 0) pix_y = 0;
11598 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
11599
11600 BLOCK_INPUT;
dc6f92b8 11601
334208b7
RS
11602 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11603 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
11604 UNBLOCK_INPUT;
11605}
11606
9b378208
RS
11607/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
11608
11609void
11610x_set_mouse_pixel_position (f, pix_x, pix_y)
11611 struct frame *f;
11612 int pix_x, pix_y;
11613{
11614 BLOCK_INPUT;
11615
334208b7
RS
11616 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11617 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
11618 UNBLOCK_INPUT;
11619}
d047c4eb
KH
11620\f
11621/* focus shifting, raising and lowering. */
9b378208 11622
dfcf069d 11623void
f676886a
JB
11624x_focus_on_frame (f)
11625 struct frame *f;
dc6f92b8 11626{
1fb20991 11627#if 0 /* This proves to be unpleasant. */
f676886a 11628 x_raise_frame (f);
1fb20991 11629#endif
6d4238f3
JB
11630#if 0
11631 /* I don't think that the ICCCM allows programs to do things like this
11632 without the interaction of the window manager. Whatever you end up
f676886a 11633 doing with this code, do it to x_unfocus_frame too. */
334208b7 11634 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 11635 RevertToPointerRoot, CurrentTime);
c118dd06 11636#endif /* ! 0 */
dc6f92b8
JB
11637}
11638
dfcf069d 11639void
f676886a
JB
11640x_unfocus_frame (f)
11641 struct frame *f;
dc6f92b8 11642{
6d4238f3 11643#if 0
f676886a 11644 /* Look at the remarks in x_focus_on_frame. */
0f941935 11645 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 11646 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 11647 RevertToPointerRoot, CurrentTime);
c118dd06 11648#endif /* ! 0 */
dc6f92b8
JB
11649}
11650
f676886a 11651/* Raise frame F. */
dc6f92b8 11652
dfcf069d 11653void
f676886a
JB
11654x_raise_frame (f)
11655 struct frame *f;
dc6f92b8 11656{
3a88c238 11657 if (f->async_visible)
dc6f92b8
JB
11658 {
11659 BLOCK_INPUT;
3afe33e7 11660#ifdef USE_X_TOOLKIT
7556890b 11661 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11662#else /* not USE_X_TOOLKIT */
334208b7 11663 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11664#endif /* not USE_X_TOOLKIT */
334208b7 11665 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11666 UNBLOCK_INPUT;
11667 }
11668}
11669
f676886a 11670/* Lower frame F. */
dc6f92b8 11671
dfcf069d 11672void
f676886a
JB
11673x_lower_frame (f)
11674 struct frame *f;
dc6f92b8 11675{
3a88c238 11676 if (f->async_visible)
dc6f92b8
JB
11677 {
11678 BLOCK_INPUT;
3afe33e7 11679#ifdef USE_X_TOOLKIT
7556890b 11680 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11681#else /* not USE_X_TOOLKIT */
334208b7 11682 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11683#endif /* not USE_X_TOOLKIT */
334208b7 11684 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11685 UNBLOCK_INPUT;
11686 }
11687}
11688
dbc4e1c1 11689static void
6b0442dc 11690XTframe_raise_lower (f, raise_flag)
dbc4e1c1 11691 FRAME_PTR f;
6b0442dc 11692 int raise_flag;
dbc4e1c1 11693{
6b0442dc 11694 if (raise_flag)
dbc4e1c1
JB
11695 x_raise_frame (f);
11696 else
11697 x_lower_frame (f);
11698}
d047c4eb
KH
11699\f
11700/* Change of visibility. */
dc6f92b8 11701
9382638d
KH
11702/* This tries to wait until the frame is really visible.
11703 However, if the window manager asks the user where to position
11704 the frame, this will return before the user finishes doing that.
11705 The frame will not actually be visible at that time,
11706 but it will become visible later when the window manager
11707 finishes with it. */
11708
dfcf069d 11709void
f676886a
JB
11710x_make_frame_visible (f)
11711 struct frame *f;
dc6f92b8 11712{
990ba854 11713 Lisp_Object type;
1aa6072f 11714 int original_top, original_left;
dc6f92b8 11715
dc6f92b8 11716 BLOCK_INPUT;
dc6f92b8 11717
990ba854
RS
11718 type = x_icon_type (f);
11719 if (!NILP (type))
11720 x_bitmap_icon (f, type);
bdcd49ba 11721
f676886a 11722 if (! FRAME_VISIBLE_P (f))
90e65f07 11723 {
1aa6072f
RS
11724 /* We test FRAME_GARBAGED_P here to make sure we don't
11725 call x_set_offset a second time
11726 if we get to x_make_frame_visible a second time
11727 before the window gets really visible. */
11728 if (! FRAME_ICONIFIED_P (f)
11729 && ! f->output_data.x->asked_for_visible)
11730 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
11731
11732 f->output_data.x->asked_for_visible = 1;
11733
90e65f07 11734 if (! EQ (Vx_no_window_manager, Qt))
f676886a 11735 x_wm_set_window_state (f, NormalState);
3afe33e7 11736#ifdef USE_X_TOOLKIT
d7a38a2e 11737 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11738 XtMapWidget (f->output_data.x->widget);
3afe33e7 11739#else /* not USE_X_TOOLKIT */
7f9c7f94 11740 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11741#endif /* not USE_X_TOOLKIT */
0134a210
RS
11742#if 0 /* This seems to bring back scroll bars in the wrong places
11743 if the window configuration has changed. They seem
11744 to come back ok without this. */
ab648270 11745 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 11746 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 11747#endif
90e65f07 11748 }
dc6f92b8 11749
334208b7 11750 XFlush (FRAME_X_DISPLAY (f));
90e65f07 11751
0dacf791
RS
11752 /* Synchronize to ensure Emacs knows the frame is visible
11753 before we do anything else. We do this loop with input not blocked
11754 so that incoming events are handled. */
11755 {
11756 Lisp_Object frame;
12ce2351 11757 int count;
28c01ffe
RS
11758 /* This must be before UNBLOCK_INPUT
11759 since events that arrive in response to the actions above
11760 will set it when they are handled. */
11761 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
11762
11763 original_left = f->output_data.x->left_pos;
11764 original_top = f->output_data.x->top_pos;
c0a04927
RS
11765
11766 /* This must come after we set COUNT. */
11767 UNBLOCK_INPUT;
11768
2745e6c4 11769 /* We unblock here so that arriving X events are processed. */
1aa6072f 11770
dcb07ae9
RS
11771 /* Now move the window back to where it was "supposed to be".
11772 But don't do it if the gravity is negative.
11773 When the gravity is negative, this uses a position
28c01ffe
RS
11774 that is 3 pixels too low. Perhaps that's really the border width.
11775
11776 Don't do this if the window has never been visible before,
11777 because the window manager may choose the position
11778 and we don't want to override it. */
1aa6072f 11779
4d3f5d9a 11780 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 11781 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 11782 && previously_visible)
1aa6072f 11783 {
2745e6c4
RS
11784 Drawable rootw;
11785 int x, y;
11786 unsigned int width, height, border, depth;
06a2c219 11787
1aa6072f 11788 BLOCK_INPUT;
9829ddba 11789
06a2c219
GM
11790 /* On some window managers (such as FVWM) moving an existing
11791 window, even to the same place, causes the window manager
11792 to introduce an offset. This can cause the window to move
11793 to an unexpected location. Check the geometry (a little
11794 slow here) and then verify that the window is in the right
11795 place. If the window is not in the right place, move it
11796 there, and take the potential window manager hit. */
2745e6c4
RS
11797 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11798 &rootw, &x, &y, &width, &height, &border, &depth);
11799
11800 if (original_left != x || original_top != y)
11801 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11802 original_left, original_top);
11803
1aa6072f
RS
11804 UNBLOCK_INPUT;
11805 }
9829ddba 11806
e0c1aef2 11807 XSETFRAME (frame, f);
c0a04927 11808
12ce2351
GM
11809 /* Wait until the frame is visible. Process X events until a
11810 MapNotify event has been seen, or until we think we won't get a
11811 MapNotify at all.. */
11812 for (count = input_signal_count + 10;
11813 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 11814 {
12ce2351 11815 /* Force processing of queued events. */
334208b7 11816 x_sync (f);
12ce2351
GM
11817
11818 /* Machines that do polling rather than SIGIO have been
11819 observed to go into a busy-wait here. So we'll fake an
11820 alarm signal to let the handler know that there's something
11821 to be read. We used to raise a real alarm, but it seems
11822 that the handler isn't always enabled here. This is
11823 probably a bug. */
8b2f8d4e 11824 if (input_polling_used ())
3b2fa4e6 11825 {
12ce2351
GM
11826 /* It could be confusing if a real alarm arrives while
11827 processing the fake one. Turn it off and let the
11828 handler reset it. */
3e71d8f2 11829 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
11830 int old_poll_suppress_count = poll_suppress_count;
11831 poll_suppress_count = 1;
11832 poll_for_input_1 ();
11833 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 11834 }
12ce2351
GM
11835
11836 /* See if a MapNotify event has been processed. */
11837 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 11838 }
0dacf791 11839 }
dc6f92b8
JB
11840}
11841
06a2c219 11842/* Change from mapped state to withdrawn state. */
dc6f92b8 11843
d047c4eb
KH
11844/* Make the frame visible (mapped and not iconified). */
11845
dfcf069d 11846void
f676886a
JB
11847x_make_frame_invisible (f)
11848 struct frame *f;
dc6f92b8 11849{
546e6d5b
RS
11850 Window window;
11851
11852#ifdef USE_X_TOOLKIT
11853 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 11854 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
11855#else /* not USE_X_TOOLKIT */
11856 window = FRAME_X_WINDOW (f);
11857#endif /* not USE_X_TOOLKIT */
dc6f92b8 11858
9319ae23 11859 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11860 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11861 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11862
5627c40e 11863#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 11864 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 11865 return;
5627c40e 11866#endif
dc6f92b8
JB
11867
11868 BLOCK_INPUT;
c118dd06 11869
af31d76f
RS
11870 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
11871 that the current position of the window is user-specified, rather than
11872 program-specified, so that when the window is mapped again, it will be
11873 placed at the same location, without forcing the user to position it
11874 by hand again (they have already done that once for this window.) */
c32cdd9a 11875 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 11876
c118dd06
JB
11877#ifdef HAVE_X11R4
11878
334208b7
RS
11879 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
11880 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
11881 {
11882 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11883 error ("Can't notify window manager of window withdrawal");
c118dd06 11884 }
c118dd06 11885#else /* ! defined (HAVE_X11R4) */
16bd92ea 11886
c118dd06 11887 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
11888 if (! EQ (Vx_no_window_manager, Qt))
11889 {
16bd92ea 11890 XEvent unmap;
dc6f92b8 11891
16bd92ea 11892 unmap.xunmap.type = UnmapNotify;
546e6d5b 11893 unmap.xunmap.window = window;
334208b7 11894 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 11895 unmap.xunmap.from_configure = False;
334208b7
RS
11896 if (! XSendEvent (FRAME_X_DISPLAY (f),
11897 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 11898 False,
06a2c219 11899 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
11900 &unmap))
11901 {
11902 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11903 error ("Can't notify window manager of withdrawal");
16bd92ea 11904 }
dc6f92b8
JB
11905 }
11906
16bd92ea 11907 /* Unmap the window ourselves. Cheeky! */
334208b7 11908 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 11909#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 11910
5627c40e
RS
11911 /* We can't distinguish this from iconification
11912 just by the event that we get from the server.
11913 So we can't win using the usual strategy of letting
11914 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
11915 and synchronize with the server to make sure we agree. */
11916 f->visible = 0;
11917 FRAME_ICONIFIED_P (f) = 0;
11918 f->async_visible = 0;
11919 f->async_iconified = 0;
11920
334208b7 11921 x_sync (f);
5627c40e 11922
dc6f92b8
JB
11923 UNBLOCK_INPUT;
11924}
11925
06a2c219 11926/* Change window state from mapped to iconified. */
dc6f92b8 11927
dfcf069d 11928void
f676886a
JB
11929x_iconify_frame (f)
11930 struct frame *f;
dc6f92b8 11931{
3afe33e7 11932 int result;
990ba854 11933 Lisp_Object type;
dc6f92b8 11934
9319ae23 11935 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11936 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11937 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11938
3a88c238 11939 if (f->async_iconified)
dc6f92b8
JB
11940 return;
11941
3afe33e7 11942 BLOCK_INPUT;
546e6d5b 11943
9af3143a
RS
11944 FRAME_SAMPLE_VISIBILITY (f);
11945
990ba854
RS
11946 type = x_icon_type (f);
11947 if (!NILP (type))
11948 x_bitmap_icon (f, type);
bdcd49ba
RS
11949
11950#ifdef USE_X_TOOLKIT
11951
546e6d5b
RS
11952 if (! FRAME_VISIBLE_P (f))
11953 {
11954 if (! EQ (Vx_no_window_manager, Qt))
11955 x_wm_set_window_state (f, IconicState);
11956 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11957 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
11958 /* The server won't give us any event to indicate
11959 that an invisible frame was changed to an icon,
11960 so we have to record it here. */
11961 f->iconified = 1;
1e6bc770 11962 f->visible = 1;
9cf30a30 11963 f->async_iconified = 1;
1e6bc770 11964 f->async_visible = 0;
546e6d5b
RS
11965 UNBLOCK_INPUT;
11966 return;
11967 }
11968
334208b7 11969 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 11970 XtWindow (f->output_data.x->widget),
334208b7 11971 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
11972 UNBLOCK_INPUT;
11973
11974 if (!result)
546e6d5b 11975 error ("Can't notify window manager of iconification");
3afe33e7
RS
11976
11977 f->async_iconified = 1;
1e6bc770
RS
11978 f->async_visible = 0;
11979
8c002a25
KH
11980
11981 BLOCK_INPUT;
334208b7 11982 XFlush (FRAME_X_DISPLAY (f));
8c002a25 11983 UNBLOCK_INPUT;
3afe33e7
RS
11984#else /* not USE_X_TOOLKIT */
11985
fd13dbb2
RS
11986 /* Make sure the X server knows where the window should be positioned,
11987 in case the user deiconifies with the window manager. */
11988 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 11989 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 11990
16bd92ea
JB
11991 /* Since we don't know which revision of X we're running, we'll use both
11992 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
11993
11994 /* X11R4: send a ClientMessage to the window manager using the
11995 WM_CHANGE_STATE type. */
11996 {
11997 XEvent message;
58769bee 11998
c118dd06 11999 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 12000 message.xclient.type = ClientMessage;
334208b7 12001 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
12002 message.xclient.format = 32;
12003 message.xclient.data.l[0] = IconicState;
12004
334208b7
RS
12005 if (! XSendEvent (FRAME_X_DISPLAY (f),
12006 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
12007 False,
12008 SubstructureRedirectMask | SubstructureNotifyMask,
12009 &message))
dc6f92b8
JB
12010 {
12011 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12012 error ("Can't notify window manager of iconification");
dc6f92b8 12013 }
16bd92ea 12014 }
dc6f92b8 12015
58769bee 12016 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
12017 IconicState. */
12018 x_wm_set_window_state (f, IconicState);
dc6f92b8 12019
a9c00105
RS
12020 if (!FRAME_VISIBLE_P (f))
12021 {
12022 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 12023 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
12024 }
12025
3a88c238 12026 f->async_iconified = 1;
1e6bc770 12027 f->async_visible = 0;
dc6f92b8 12028
334208b7 12029 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 12030 UNBLOCK_INPUT;
8c002a25 12031#endif /* not USE_X_TOOLKIT */
dc6f92b8 12032}
d047c4eb 12033\f
c0ff3fab 12034/* Destroy the X window of frame F. */
dc6f92b8 12035
dfcf069d 12036void
c0ff3fab 12037x_destroy_window (f)
f676886a 12038 struct frame *f;
dc6f92b8 12039{
7f9c7f94
RS
12040 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12041
dc6f92b8 12042 BLOCK_INPUT;
c0ff3fab 12043
6186a4a0
RS
12044 /* If a display connection is dead, don't try sending more
12045 commands to the X server. */
12046 if (dpyinfo->display != 0)
12047 {
12048 if (f->output_data.x->icon_desc != 0)
12049 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
31f41daf 12050#ifdef HAVE_X_I18N
f5d11644
GM
12051 if (FRAME_XIC (f))
12052 free_frame_xic (f);
31f41daf 12053#endif
6186a4a0 12054 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->window_desc);
3afe33e7 12055#ifdef USE_X_TOOLKIT
06a2c219
GM
12056 if (f->output_data.x->widget)
12057 XtDestroyWidget (f->output_data.x->widget);
6186a4a0 12058 free_frame_menubar (f);
3afe33e7
RS
12059#endif /* USE_X_TOOLKIT */
12060
3e71d8f2
GM
12061 unload_color (f, f->output_data.x->foreground_pixel);
12062 unload_color (f, f->output_data.x->background_pixel);
12063 unload_color (f, f->output_data.x->cursor_pixel);
12064 unload_color (f, f->output_data.x->cursor_foreground_pixel);
12065 unload_color (f, f->output_data.x->border_pixel);
12066 unload_color (f, f->output_data.x->mouse_pixel);
12067 if (f->output_data.x->scroll_bar_background_pixel != -1)
12068 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
12069 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
12070 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
12071 if (f->output_data.x->white_relief.allocated_p)
12072 unload_color (f, f->output_data.x->white_relief.pixel);
12073 if (f->output_data.x->black_relief.allocated_p)
12074 unload_color (f, f->output_data.x->black_relief.pixel);
12075
6186a4a0
RS
12076 free_frame_faces (f);
12077 XFlush (FRAME_X_DISPLAY (f));
12078 }
dc6f92b8 12079
df89d8a4 12080 if (f->output_data.x->saved_menu_event)
06a2c219 12081 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 12082
7556890b
RS
12083 xfree (f->output_data.x);
12084 f->output_data.x = 0;
0f941935
KH
12085 if (f == dpyinfo->x_focus_frame)
12086 dpyinfo->x_focus_frame = 0;
12087 if (f == dpyinfo->x_focus_event_frame)
12088 dpyinfo->x_focus_event_frame = 0;
12089 if (f == dpyinfo->x_highlight_frame)
12090 dpyinfo->x_highlight_frame = 0;
c0ff3fab 12091
7f9c7f94
RS
12092 dpyinfo->reference_count--;
12093
12094 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 12095 {
7f9c7f94
RS
12096 dpyinfo->mouse_face_beg_row
12097 = dpyinfo->mouse_face_beg_col = -1;
12098 dpyinfo->mouse_face_end_row
12099 = dpyinfo->mouse_face_end_col = -1;
12100 dpyinfo->mouse_face_window = Qnil;
21323706
RS
12101 dpyinfo->mouse_face_deferred_gc = 0;
12102 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 12103 }
0134a210 12104
c0ff3fab 12105 UNBLOCK_INPUT;
dc6f92b8
JB
12106}
12107\f
f451eb13
JB
12108/* Setting window manager hints. */
12109
af31d76f
RS
12110/* Set the normal size hints for the window manager, for frame F.
12111 FLAGS is the flags word to use--or 0 meaning preserve the flags
12112 that the window now has.
12113 If USER_POSITION is nonzero, we set the USPosition
12114 flag (this is useful when FLAGS is 0). */
6dba1858 12115
dfcf069d 12116void
af31d76f 12117x_wm_set_size_hint (f, flags, user_position)
f676886a 12118 struct frame *f;
af31d76f
RS
12119 long flags;
12120 int user_position;
dc6f92b8
JB
12121{
12122 XSizeHints size_hints;
3afe33e7
RS
12123
12124#ifdef USE_X_TOOLKIT
7e4f2521
FP
12125 Arg al[2];
12126 int ac = 0;
12127 Dimension widget_width, widget_height;
7556890b 12128 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 12129#else /* not USE_X_TOOLKIT */
c118dd06 12130 Window window = FRAME_X_WINDOW (f);
3afe33e7 12131#endif /* not USE_X_TOOLKIT */
dc6f92b8 12132
b72a58fd
RS
12133 /* Setting PMaxSize caused various problems. */
12134 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 12135
7556890b
RS
12136 size_hints.x = f->output_data.x->left_pos;
12137 size_hints.y = f->output_data.x->top_pos;
7553a6b7 12138
7e4f2521
FP
12139#ifdef USE_X_TOOLKIT
12140 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
12141 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 12142 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
12143 size_hints.height = widget_height;
12144 size_hints.width = widget_width;
12145#else /* not USE_X_TOOLKIT */
f676886a
JB
12146 size_hints.height = PIXEL_HEIGHT (f);
12147 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 12148#endif /* not USE_X_TOOLKIT */
7553a6b7 12149
7556890b
RS
12150 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
12151 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
12152 size_hints.max_width
12153 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
12154 size_hints.max_height
12155 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 12156
d067ea8b
KH
12157 /* Calculate the base and minimum sizes.
12158
12159 (When we use the X toolkit, we don't do it here.
12160 Instead we copy the values that the widgets are using, below.) */
12161#ifndef USE_X_TOOLKIT
b1c884c3 12162 {
b0342f17 12163 int base_width, base_height;
0134a210 12164 int min_rows = 0, min_cols = 0;
b0342f17 12165
f451eb13
JB
12166 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
12167 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 12168
0134a210 12169 check_frame_size (f, &min_rows, &min_cols);
b0342f17 12170
0134a210
RS
12171 /* The window manager uses the base width hints to calculate the
12172 current number of rows and columns in the frame while
12173 resizing; min_width and min_height aren't useful for this
12174 purpose, since they might not give the dimensions for a
12175 zero-row, zero-column frame.
58769bee 12176
0134a210
RS
12177 We use the base_width and base_height members if we have
12178 them; otherwise, we set the min_width and min_height members
12179 to the size for a zero x zero frame. */
b0342f17
JB
12180
12181#ifdef HAVE_X11R4
0134a210
RS
12182 size_hints.flags |= PBaseSize;
12183 size_hints.base_width = base_width;
12184 size_hints.base_height = base_height;
12185 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
12186 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 12187#else
0134a210
RS
12188 size_hints.min_width = base_width;
12189 size_hints.min_height = base_height;
b0342f17 12190#endif
b1c884c3 12191 }
dc6f92b8 12192
d067ea8b 12193 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 12194 if (flags)
dc6f92b8 12195 {
d067ea8b
KH
12196 size_hints.flags |= flags;
12197 goto no_read;
12198 }
12199#endif /* not USE_X_TOOLKIT */
12200
12201 {
12202 XSizeHints hints; /* Sometimes I hate X Windows... */
12203 long supplied_return;
12204 int value;
af31d76f
RS
12205
12206#ifdef HAVE_X11R4
d067ea8b
KH
12207 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
12208 &supplied_return);
af31d76f 12209#else
d067ea8b 12210 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 12211#endif
58769bee 12212
d067ea8b
KH
12213#ifdef USE_X_TOOLKIT
12214 size_hints.base_height = hints.base_height;
12215 size_hints.base_width = hints.base_width;
12216 size_hints.min_height = hints.min_height;
12217 size_hints.min_width = hints.min_width;
12218#endif
12219
12220 if (flags)
12221 size_hints.flags |= flags;
12222 else
12223 {
12224 if (value == 0)
12225 hints.flags = 0;
12226 if (hints.flags & PSize)
12227 size_hints.flags |= PSize;
12228 if (hints.flags & PPosition)
12229 size_hints.flags |= PPosition;
12230 if (hints.flags & USPosition)
12231 size_hints.flags |= USPosition;
12232 if (hints.flags & USSize)
12233 size_hints.flags |= USSize;
12234 }
12235 }
12236
06a2c219 12237#ifndef USE_X_TOOLKIT
d067ea8b 12238 no_read:
06a2c219 12239#endif
0134a210 12240
af31d76f 12241#ifdef PWinGravity
7556890b 12242 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 12243 size_hints.flags |= PWinGravity;
dc05a16b 12244
af31d76f 12245 if (user_position)
6dba1858 12246 {
af31d76f
RS
12247 size_hints.flags &= ~ PPosition;
12248 size_hints.flags |= USPosition;
6dba1858 12249 }
2554751d 12250#endif /* PWinGravity */
6dba1858 12251
b0342f17 12252#ifdef HAVE_X11R4
334208b7 12253 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12254#else
334208b7 12255 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12256#endif
dc6f92b8
JB
12257}
12258
12259/* Used for IconicState or NormalState */
06a2c219 12260
dfcf069d 12261void
f676886a
JB
12262x_wm_set_window_state (f, state)
12263 struct frame *f;
dc6f92b8
JB
12264 int state;
12265{
3afe33e7 12266#ifdef USE_X_TOOLKIT
546e6d5b
RS
12267 Arg al[1];
12268
12269 XtSetArg (al[0], XtNinitialState, state);
7556890b 12270 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 12271#else /* not USE_X_TOOLKIT */
c118dd06 12272 Window window = FRAME_X_WINDOW (f);
dc6f92b8 12273
7556890b
RS
12274 f->output_data.x->wm_hints.flags |= StateHint;
12275 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 12276
7556890b 12277 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 12278#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12279}
12280
dfcf069d 12281void
7f2ae036 12282x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 12283 struct frame *f;
7f2ae036 12284 int pixmap_id;
dc6f92b8 12285{
d2bd6bc4
RS
12286 Pixmap icon_pixmap;
12287
06a2c219 12288#ifndef USE_X_TOOLKIT
c118dd06 12289 Window window = FRAME_X_WINDOW (f);
75231bad 12290#endif
dc6f92b8 12291
7f2ae036 12292 if (pixmap_id > 0)
dbc4e1c1 12293 {
d2bd6bc4 12294 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 12295 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
12296 }
12297 else
68568555
RS
12298 {
12299 /* It seems there is no way to turn off use of an icon pixmap.
12300 The following line does it, only if no icon has yet been created,
12301 for some window managers. But with mwm it crashes.
12302 Some people say it should clear the IconPixmapHint bit in this case,
12303 but that doesn't work, and the X consortium said it isn't the
12304 right thing at all. Since there is no way to win,
12305 best to explicitly give up. */
12306#if 0
12307 f->output_data.x->wm_hints.icon_pixmap = None;
12308#else
12309 return;
12310#endif
12311 }
b1c884c3 12312
d2bd6bc4
RS
12313#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
12314
12315 {
12316 Arg al[1];
12317 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
12318 XtSetValues (f->output_data.x->widget, al, 1);
12319 }
12320
12321#else /* not USE_X_TOOLKIT */
12322
7556890b
RS
12323 f->output_data.x->wm_hints.flags |= IconPixmapHint;
12324 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
12325
12326#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12327}
12328
dfcf069d 12329void
f676886a
JB
12330x_wm_set_icon_position (f, icon_x, icon_y)
12331 struct frame *f;
dc6f92b8
JB
12332 int icon_x, icon_y;
12333{
75231bad 12334#ifdef USE_X_TOOLKIT
7556890b 12335 Window window = XtWindow (f->output_data.x->widget);
75231bad 12336#else
c118dd06 12337 Window window = FRAME_X_WINDOW (f);
75231bad 12338#endif
dc6f92b8 12339
7556890b
RS
12340 f->output_data.x->wm_hints.flags |= IconPositionHint;
12341 f->output_data.x->wm_hints.icon_x = icon_x;
12342 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 12343
7556890b 12344 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
12345}
12346
12347\f
06a2c219
GM
12348/***********************************************************************
12349 Fonts
12350 ***********************************************************************/
dc43ef94
KH
12351
12352/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 12353
dc43ef94
KH
12354struct font_info *
12355x_get_font_info (f, font_idx)
12356 FRAME_PTR f;
12357 int font_idx;
12358{
12359 return (FRAME_X_FONT_TABLE (f) + font_idx);
12360}
12361
12362
12363/* Return a list of names of available fonts matching PATTERN on frame
12364 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
12365 to be listed. Frame F NULL means we have not yet created any
12366 frame on X, and consult the first display in x_display_list.
12367 MAXNAMES sets a limit on how many fonts to match. */
12368
12369Lisp_Object
12370x_list_fonts (f, pattern, size, maxnames)
12371 FRAME_PTR f;
12372 Lisp_Object pattern;
12373 int size;
12374 int maxnames;
12375{
06a2c219
GM
12376 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
12377 Lisp_Object tem, second_best;
dc43ef94 12378 Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
09c6077f 12379 int try_XLoadQueryFont = 0;
53ca4657 12380 int count;
dc43ef94 12381
6b0efe73 12382 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
12383 if (NILP (patterns))
12384 patterns = Fcons (pattern, Qnil);
81ba44e5 12385
09c6077f
KH
12386 if (maxnames == 1 && !size)
12387 /* We can return any single font matching PATTERN. */
12388 try_XLoadQueryFont = 1;
9a32686f 12389
8e713be6 12390 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 12391 {
dc43ef94 12392 int num_fonts;
3e71d8f2 12393 char **names = NULL;
dc43ef94 12394
8e713be6 12395 pattern = XCAR (patterns);
536f4067
RS
12396 /* See if we cached the result for this particular query.
12397 The cache is an alist of the form:
12398 (((PATTERN . MAXNAMES) (FONTNAME . WIDTH) ...) ...)
12399 */
8e713be6 12400 if (f && (tem = XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element),
b5210ea7
KH
12401 key = Fcons (pattern, make_number (maxnames)),
12402 !NILP (list = Fassoc (key, tem))))
12403 {
12404 list = Fcdr_safe (list);
12405 /* We have a cashed list. Don't have to get the list again. */
12406 goto label_cached;
12407 }
12408
12409 /* At first, put PATTERN in the cache. */
09c6077f 12410
dc43ef94 12411 BLOCK_INPUT;
17d85edc
KH
12412 count = x_catch_errors (dpy);
12413
09c6077f
KH
12414 if (try_XLoadQueryFont)
12415 {
12416 XFontStruct *font;
12417 unsigned long value;
12418
12419 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
12420 if (x_had_errors_p (dpy))
12421 {
12422 /* This error is perhaps due to insufficient memory on X
12423 server. Let's just ignore it. */
12424 font = NULL;
12425 x_clear_errors (dpy);
12426 }
12427
09c6077f
KH
12428 if (font
12429 && XGetFontProperty (font, XA_FONT, &value))
12430 {
12431 char *name = (char *) XGetAtomName (dpy, (Atom) value);
12432 int len = strlen (name);
01c752b5 12433 char *tmp;
09c6077f 12434
6f6512e8
KH
12435 /* If DXPC (a Differential X Protocol Compressor)
12436 Ver.3.7 is running, XGetAtomName will return null
12437 string. We must avoid such a name. */
12438 if (len == 0)
12439 try_XLoadQueryFont = 0;
12440 else
12441 {
12442 num_fonts = 1;
12443 names = (char **) alloca (sizeof (char *));
12444 /* Some systems only allow alloca assigned to a
12445 simple var. */
12446 tmp = (char *) alloca (len + 1); names[0] = tmp;
12447 bcopy (name, names[0], len + 1);
12448 XFree (name);
12449 }
09c6077f
KH
12450 }
12451 else
12452 try_XLoadQueryFont = 0;
a083fd23
RS
12453
12454 if (font)
12455 XFreeFont (dpy, font);
09c6077f
KH
12456 }
12457
12458 if (!try_XLoadQueryFont)
17d85edc
KH
12459 {
12460 /* We try at least 10 fonts because XListFonts will return
12461 auto-scaled fonts at the head. */
12462 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
12463 &num_fonts);
12464 if (x_had_errors_p (dpy))
12465 {
12466 /* This error is perhaps due to insufficient memory on X
12467 server. Let's just ignore it. */
12468 names = NULL;
12469 x_clear_errors (dpy);
12470 }
12471 }
12472
12473 x_uncatch_errors (dpy, count);
dc43ef94
KH
12474 UNBLOCK_INPUT;
12475
12476 if (names)
12477 {
12478 int i;
dc43ef94
KH
12479
12480 /* Make a list of all the fonts we got back.
12481 Store that in the font cache for the display. */
12482 for (i = 0; i < num_fonts; i++)
12483 {
06a2c219 12484 int width = 0;
dc43ef94 12485 char *p = names[i];
06a2c219
GM
12486 int average_width = -1, dashes = 0;
12487
dc43ef94 12488 /* Count the number of dashes in NAMES[I]. If there are
b5210ea7
KH
12489 14 dashes, and the field value following 12th dash
12490 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
12491 is usually too ugly to be used for editing. Let's
12492 ignore it. */
dc43ef94
KH
12493 while (*p)
12494 if (*p++ == '-')
12495 {
12496 dashes++;
12497 if (dashes == 7) /* PIXEL_SIZE field */
12498 width = atoi (p);
12499 else if (dashes == 12) /* AVERAGE_WIDTH field */
12500 average_width = atoi (p);
12501 }
12502 if (dashes < 14 || average_width != 0)
12503 {
12504 tem = build_string (names[i]);
12505 if (NILP (Fassoc (tem, list)))
12506 {
12507 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
12508 && ((fast_c_string_match_ignore_case
12509 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
12510 >= 0))
12511 /* We can set the value of PIXEL_SIZE to the
b5210ea7 12512 width of this font. */
dc43ef94
KH
12513 list = Fcons (Fcons (tem, make_number (width)), list);
12514 else
12515 /* For the moment, width is not known. */
12516 list = Fcons (Fcons (tem, Qnil), list);
12517 }
12518 }
12519 }
09c6077f
KH
12520 if (!try_XLoadQueryFont)
12521 XFreeFontNames (names);
dc43ef94
KH
12522 }
12523
b5210ea7 12524 /* Now store the result in the cache. */
dc43ef94 12525 if (f != NULL)
8e713be6 12526 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element)
dc43ef94 12527 = Fcons (Fcons (key, list),
8e713be6 12528 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
dc43ef94 12529
b5210ea7
KH
12530 label_cached:
12531 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 12532
b5210ea7
KH
12533 newlist = second_best = Qnil;
12534 /* Make a list of the fonts that have the right width. */
8e713be6 12535 for (; CONSP (list); list = XCDR (list))
b5210ea7 12536 {
536f4067
RS
12537 int found_size;
12538
8e713be6 12539 tem = XCAR (list);
dc43ef94 12540
8e713be6 12541 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
12542 continue;
12543 if (!size)
12544 {
8e713be6 12545 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
12546 continue;
12547 }
dc43ef94 12548
8e713be6 12549 if (!INTEGERP (XCDR (tem)))
dc43ef94 12550 {
b5210ea7
KH
12551 /* Since we have not yet known the size of this font, we
12552 must try slow function call XLoadQueryFont. */
dc43ef94
KH
12553 XFontStruct *thisinfo;
12554
12555 BLOCK_INPUT;
17d85edc 12556 count = x_catch_errors (dpy);
dc43ef94 12557 thisinfo = XLoadQueryFont (dpy,
8e713be6 12558 XSTRING (XCAR (tem))->data);
17d85edc
KH
12559 if (x_had_errors_p (dpy))
12560 {
12561 /* This error is perhaps due to insufficient memory on X
12562 server. Let's just ignore it. */
12563 thisinfo = NULL;
12564 x_clear_errors (dpy);
12565 }
12566 x_uncatch_errors (dpy, count);
dc43ef94
KH
12567 UNBLOCK_INPUT;
12568
12569 if (thisinfo)
12570 {
8e713be6 12571 XCDR (tem)
536f4067
RS
12572 = (thisinfo->min_bounds.width == 0
12573 ? make_number (0)
12574 : make_number (thisinfo->max_bounds.width));
dc43ef94
KH
12575 XFreeFont (dpy, thisinfo);
12576 }
12577 else
b5210ea7 12578 /* For unknown reason, the previous call of XListFont had
06a2c219 12579 returned a font which can't be opened. Record the size
b5210ea7 12580 as 0 not to try to open it again. */
8e713be6 12581 XCDR (tem) = make_number (0);
dc43ef94 12582 }
536f4067 12583
8e713be6 12584 found_size = XINT (XCDR (tem));
536f4067 12585 if (found_size == size)
8e713be6 12586 newlist = Fcons (XCAR (tem), newlist);
536f4067 12587 else if (found_size > 0)
b5210ea7 12588 {
536f4067 12589 if (NILP (second_best))
b5210ea7 12590 second_best = tem;
536f4067
RS
12591 else if (found_size < size)
12592 {
8e713be6
KR
12593 if (XINT (XCDR (second_best)) > size
12594 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
12595 second_best = tem;
12596 }
12597 else
12598 {
8e713be6
KR
12599 if (XINT (XCDR (second_best)) > size
12600 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
12601 second_best = tem;
12602 }
b5210ea7
KH
12603 }
12604 }
12605 if (!NILP (newlist))
12606 break;
12607 else if (!NILP (second_best))
12608 {
8e713be6 12609 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 12610 break;
dc43ef94 12611 }
dc43ef94
KH
12612 }
12613
12614 return newlist;
12615}
12616
06a2c219
GM
12617
12618#if GLYPH_DEBUG
12619
12620/* Check that FONT is valid on frame F. It is if it can be found in F's
12621 font table. */
12622
12623static void
12624x_check_font (f, font)
12625 struct frame *f;
12626 XFontStruct *font;
12627{
12628 int i;
12629 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12630
12631 xassert (font != NULL);
12632
12633 for (i = 0; i < dpyinfo->n_fonts; i++)
12634 if (dpyinfo->font_table[i].name
12635 && font == dpyinfo->font_table[i].font)
12636 break;
12637
12638 xassert (i < dpyinfo->n_fonts);
12639}
12640
12641#endif /* GLYPH_DEBUG != 0 */
12642
12643/* Set *W to the minimum width, *H to the minimum font height of FONT.
12644 Note: There are (broken) X fonts out there with invalid XFontStruct
12645 min_bounds contents. For example, handa@etl.go.jp reports that
12646 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
12647 have font->min_bounds.width == 0. */
12648
12649static INLINE void
12650x_font_min_bounds (font, w, h)
12651 XFontStruct *font;
12652 int *w, *h;
12653{
12654 *h = FONT_HEIGHT (font);
12655 *w = font->min_bounds.width;
12656
12657 /* Try to handle the case where FONT->min_bounds has invalid
12658 contents. Since the only font known to have invalid min_bounds
12659 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
12660 if (*w <= 0)
12661 *w = font->max_bounds.width;
12662}
12663
12664
12665/* Compute the smallest character width and smallest font height over
12666 all fonts available on frame F. Set the members smallest_char_width
12667 and smallest_font_height in F's x_display_info structure to
12668 the values computed. Value is non-zero if smallest_font_height or
12669 smallest_char_width become smaller than they were before. */
12670
12671static int
12672x_compute_min_glyph_bounds (f)
12673 struct frame *f;
12674{
12675 int i;
12676 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12677 XFontStruct *font;
12678 int old_width = dpyinfo->smallest_char_width;
12679 int old_height = dpyinfo->smallest_font_height;
12680
12681 dpyinfo->smallest_font_height = 100000;
12682 dpyinfo->smallest_char_width = 100000;
12683
12684 for (i = 0; i < dpyinfo->n_fonts; ++i)
12685 if (dpyinfo->font_table[i].name)
12686 {
12687 struct font_info *fontp = dpyinfo->font_table + i;
12688 int w, h;
12689
12690 font = (XFontStruct *) fontp->font;
12691 xassert (font != (XFontStruct *) ~0);
12692 x_font_min_bounds (font, &w, &h);
12693
12694 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
12695 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
12696 }
12697
12698 xassert (dpyinfo->smallest_char_width > 0
12699 && dpyinfo->smallest_font_height > 0);
12700
12701 return (dpyinfo->n_fonts == 1
12702 || dpyinfo->smallest_char_width < old_width
12703 || dpyinfo->smallest_font_height < old_height);
12704}
12705
12706
dc43ef94
KH
12707/* Load font named FONTNAME of the size SIZE for frame F, and return a
12708 pointer to the structure font_info while allocating it dynamically.
12709 If SIZE is 0, load any size of font.
12710 If loading is failed, return NULL. */
12711
12712struct font_info *
12713x_load_font (f, fontname, size)
12714 struct frame *f;
12715 register char *fontname;
12716 int size;
12717{
12718 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12719 Lisp_Object font_names;
d645aaa4 12720 int count;
dc43ef94
KH
12721
12722 /* Get a list of all the fonts that match this name. Once we
12723 have a list of matching fonts, we compare them against the fonts
12724 we already have by comparing names. */
09c6077f 12725 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
12726
12727 if (!NILP (font_names))
12728 {
12729 Lisp_Object tail;
12730 int i;
12731
12732 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 12733 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
12734 if (dpyinfo->font_table[i].name
12735 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 12736 XSTRING (XCAR (tail))->data)
06a2c219 12737 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 12738 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
12739 return (dpyinfo->font_table + i);
12740 }
12741
12742 /* Load the font and add it to the table. */
12743 {
12744 char *full_name;
12745 XFontStruct *font;
12746 struct font_info *fontp;
12747 unsigned long value;
06a2c219 12748 int i;
dc43ef94 12749
2da424f1
KH
12750 /* If we have found fonts by x_list_font, load one of them. If
12751 not, we still try to load a font by the name given as FONTNAME
12752 because XListFonts (called in x_list_font) of some X server has
12753 a bug of not finding a font even if the font surely exists and
12754 is loadable by XLoadQueryFont. */
e1d6d5b9 12755 if (size > 0 && !NILP (font_names))
8e713be6 12756 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
12757
12758 BLOCK_INPUT;
d645aaa4 12759 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 12760 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
12761 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12762 {
12763 /* This error is perhaps due to insufficient memory on X
12764 server. Let's just ignore it. */
12765 font = NULL;
12766 x_clear_errors (FRAME_X_DISPLAY (f));
12767 }
12768 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 12769 UNBLOCK_INPUT;
b5210ea7 12770 if (!font)
dc43ef94
KH
12771 return NULL;
12772
06a2c219
GM
12773 /* Find a free slot in the font table. */
12774 for (i = 0; i < dpyinfo->n_fonts; ++i)
12775 if (dpyinfo->font_table[i].name == NULL)
12776 break;
12777
12778 /* If no free slot found, maybe enlarge the font table. */
12779 if (i == dpyinfo->n_fonts
12780 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 12781 {
06a2c219
GM
12782 int sz;
12783 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
12784 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 12785 dpyinfo->font_table
06a2c219 12786 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
12787 }
12788
06a2c219
GM
12789 fontp = dpyinfo->font_table + i;
12790 if (i == dpyinfo->n_fonts)
12791 ++dpyinfo->n_fonts;
dc43ef94
KH
12792
12793 /* Now fill in the slots of *FONTP. */
12794 BLOCK_INPUT;
12795 fontp->font = font;
06a2c219 12796 fontp->font_idx = i;
dc43ef94
KH
12797 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
12798 bcopy (fontname, fontp->name, strlen (fontname) + 1);
12799
12800 /* Try to get the full name of FONT. Put it in FULL_NAME. */
12801 full_name = 0;
12802 if (XGetFontProperty (font, XA_FONT, &value))
12803 {
12804 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
12805 char *p = name;
12806 int dashes = 0;
12807
12808 /* Count the number of dashes in the "full name".
12809 If it is too few, this isn't really the font's full name,
12810 so don't use it.
12811 In X11R4, the fonts did not come with their canonical names
12812 stored in them. */
12813 while (*p)
12814 {
12815 if (*p == '-')
12816 dashes++;
12817 p++;
12818 }
12819
12820 if (dashes >= 13)
12821 {
12822 full_name = (char *) xmalloc (p - name + 1);
12823 bcopy (name, full_name, p - name + 1);
12824 }
12825
12826 XFree (name);
12827 }
12828
12829 if (full_name != 0)
12830 fontp->full_name = full_name;
12831 else
12832 fontp->full_name = fontp->name;
12833
12834 fontp->size = font->max_bounds.width;
d5749adb
KH
12835 fontp->height = FONT_HEIGHT (font);
12836 {
12837 /* For some font, ascent and descent in max_bounds field is
12838 larger than the above value. */
12839 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
12840 if (max_height > fontp->height)
74848a96 12841 fontp->height = max_height;
d5749adb 12842 }
dc43ef94 12843
2da424f1
KH
12844 if (NILP (font_names))
12845 {
12846 /* We come here because of a bug of XListFonts mentioned at
12847 the head of this block. Let's store this information in
12848 the cache for x_list_fonts. */
12849 Lisp_Object lispy_name = build_string (fontname);
12850 Lisp_Object lispy_full_name = build_string (fontp->full_name);
12851
8e713be6 12852 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12853 = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
12854 Fcons (Fcons (lispy_full_name,
12855 make_number (fontp->size)),
12856 Qnil)),
8e713be6 12857 XCDR (dpyinfo->name_list_element));
2da424f1 12858 if (full_name)
8e713be6 12859 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12860 = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
12861 Fcons (Fcons (lispy_full_name,
12862 make_number (fontp->size)),
12863 Qnil)),
8e713be6 12864 XCDR (dpyinfo->name_list_element));
2da424f1
KH
12865 }
12866
dc43ef94
KH
12867 /* The slot `encoding' specifies how to map a character
12868 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
12869 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
12870 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 12871 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 12872 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
12873 which is never used by any charset. If mapping can't be
12874 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
12875 fontp->encoding[1]
12876 = (font->max_byte1 == 0
12877 /* 1-byte font */
12878 ? (font->min_char_or_byte2 < 0x80
12879 ? (font->max_char_or_byte2 < 0x80
12880 ? 0 /* 0x20..0x7F */
8ff102bd 12881 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
12882 : 1) /* 0xA0..0xFF */
12883 /* 2-byte font */
12884 : (font->min_byte1 < 0x80
12885 ? (font->max_byte1 < 0x80
12886 ? (font->min_char_or_byte2 < 0x80
12887 ? (font->max_char_or_byte2 < 0x80
12888 ? 0 /* 0x2020..0x7F7F */
8ff102bd 12889 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 12890 : 3) /* 0x20A0..0x7FFF */
8ff102bd 12891 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
12892 : (font->min_char_or_byte2 < 0x80
12893 ? (font->max_char_or_byte2 < 0x80
12894 ? 2 /* 0xA020..0xFF7F */
8ff102bd 12895 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
12896 : 1))); /* 0xA0A0..0xFFFF */
12897
12898 fontp->baseline_offset
12899 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
12900 ? (long) value : 0);
12901 fontp->relative_compose
12902 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
12903 ? (long) value : 0);
f78798df
KH
12904 fontp->default_ascent
12905 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
12906 ? (long) value : 0);
dc43ef94 12907
06a2c219
GM
12908 /* Set global flag fonts_changed_p to non-zero if the font loaded
12909 has a character with a smaller width than any other character
12910 before, or if the font loaded has a smalle>r height than any
12911 other font loaded before. If this happens, it will make a
12912 glyph matrix reallocation necessary. */
12913 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 12914 UNBLOCK_INPUT;
dc43ef94
KH
12915 return fontp;
12916 }
12917}
12918
06a2c219
GM
12919
12920/* Return a pointer to struct font_info of a font named FONTNAME for
12921 frame F. If no such font is loaded, return NULL. */
12922
dc43ef94
KH
12923struct font_info *
12924x_query_font (f, fontname)
12925 struct frame *f;
12926 register char *fontname;
12927{
12928 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12929 int i;
12930
12931 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
12932 if (dpyinfo->font_table[i].name
12933 && (!strcmp (dpyinfo->font_table[i].name, fontname)
12934 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
12935 return (dpyinfo->font_table + i);
12936 return NULL;
12937}
12938
06a2c219
GM
12939
12940/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
12941 `encoder' of the structure. */
12942
12943void
12944x_find_ccl_program (fontp)
12945 struct font_info *fontp;
12946{
a42f54e6 12947 Lisp_Object list, elt;
a6582676 12948
8e713be6 12949 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 12950 {
8e713be6 12951 elt = XCAR (list);
a6582676 12952 if (CONSP (elt)
8e713be6
KR
12953 && STRINGP (XCAR (elt))
12954 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
a6582676 12955 >= 0))
a42f54e6
KH
12956 break;
12957 }
12958 if (! NILP (list))
12959 {
d27f8ca7
KH
12960 struct ccl_program *ccl
12961 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 12962
8e713be6 12963 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
12964 xfree (ccl);
12965 else
12966 fontp->font_encoder = ccl;
a6582676
KH
12967 }
12968}
12969
06a2c219 12970
dc43ef94 12971\f
06a2c219
GM
12972/***********************************************************************
12973 Initialization
12974 ***********************************************************************/
f451eb13 12975
3afe33e7
RS
12976#ifdef USE_X_TOOLKIT
12977static XrmOptionDescRec emacs_options[] = {
12978 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
12979 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
12980
12981 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
12982 XrmoptionSepArg, NULL},
12983 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
12984
12985 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12986 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12987 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12988 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
12989 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
12990 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
12991 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
12992};
12993#endif /* USE_X_TOOLKIT */
12994
7a13e894
RS
12995static int x_initialized;
12996
29b38361
KH
12997#ifdef MULTI_KBOARD
12998/* Test whether two display-name strings agree up to the dot that separates
12999 the screen number from the server number. */
13000static int
13001same_x_server (name1, name2)
13002 char *name1, *name2;
13003{
13004 int seen_colon = 0;
cf591cc1
RS
13005 unsigned char *system_name = XSTRING (Vsystem_name)->data;
13006 int system_name_length = strlen (system_name);
13007 int length_until_period = 0;
13008
13009 while (system_name[length_until_period] != 0
13010 && system_name[length_until_period] != '.')
13011 length_until_period++;
13012
13013 /* Treat `unix' like an empty host name. */
13014 if (! strncmp (name1, "unix:", 5))
13015 name1 += 4;
13016 if (! strncmp (name2, "unix:", 5))
13017 name2 += 4;
13018 /* Treat this host's name like an empty host name. */
13019 if (! strncmp (name1, system_name, system_name_length)
13020 && name1[system_name_length] == ':')
13021 name1 += system_name_length;
13022 if (! strncmp (name2, system_name, system_name_length)
13023 && name2[system_name_length] == ':')
13024 name2 += system_name_length;
13025 /* Treat this host's domainless name like an empty host name. */
13026 if (! strncmp (name1, system_name, length_until_period)
13027 && name1[length_until_period] == ':')
13028 name1 += length_until_period;
13029 if (! strncmp (name2, system_name, length_until_period)
13030 && name2[length_until_period] == ':')
13031 name2 += length_until_period;
13032
29b38361
KH
13033 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
13034 {
13035 if (*name1 == ':')
13036 seen_colon++;
13037 if (seen_colon && *name1 == '.')
13038 return 1;
13039 }
13040 return (seen_colon
13041 && (*name1 == '.' || *name1 == '\0')
13042 && (*name2 == '.' || *name2 == '\0'));
13043}
13044#endif
13045
334208b7 13046struct x_display_info *
1f8255f2 13047x_term_init (display_name, xrm_option, resource_name)
334208b7 13048 Lisp_Object display_name;
1f8255f2
RS
13049 char *xrm_option;
13050 char *resource_name;
dc6f92b8 13051{
334208b7 13052 int connection;
7a13e894 13053 Display *dpy;
334208b7
RS
13054 struct x_display_info *dpyinfo;
13055 XrmDatabase xrdb;
13056
60439948
KH
13057 BLOCK_INPUT;
13058
7a13e894
RS
13059 if (!x_initialized)
13060 {
13061 x_initialize ();
13062 x_initialized = 1;
13063 }
dc6f92b8 13064
3afe33e7 13065#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
13066 /* weiner@footloose.sps.mot.com reports that this causes
13067 errors with X11R5:
13068 X protocol error: BadAtom (invalid Atom parameter)
13069 on protocol request 18skiloaf.
13070 So let's not use it until R6. */
13071#ifdef HAVE_X11XTR6
bdcd49ba
RS
13072 XtSetLanguageProc (NULL, NULL, NULL);
13073#endif
13074
7f9c7f94
RS
13075 {
13076 int argc = 0;
13077 char *argv[3];
13078
13079 argv[0] = "";
13080 argc = 1;
13081 if (xrm_option)
13082 {
13083 argv[argc++] = "-xrm";
13084 argv[argc++] = xrm_option;
13085 }
13086 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
13087 resource_name, EMACS_CLASS,
13088 emacs_options, XtNumber (emacs_options),
13089 &argc, argv);
39d8bb4d
KH
13090
13091#ifdef HAVE_X11XTR6
10537cb1 13092 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 13093 fixup_locale ();
39d8bb4d 13094#endif
7f9c7f94 13095 }
3afe33e7
RS
13096
13097#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
13098#ifdef HAVE_X11R5
13099 XSetLocaleModifiers ("");
13100#endif
7a13e894 13101 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 13102#endif /* not USE_X_TOOLKIT */
334208b7 13103
7a13e894
RS
13104 /* Detect failure. */
13105 if (dpy == 0)
60439948
KH
13106 {
13107 UNBLOCK_INPUT;
13108 return 0;
13109 }
7a13e894
RS
13110
13111 /* We have definitely succeeded. Record the new connection. */
13112
13113 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
13114
29b38361
KH
13115#ifdef MULTI_KBOARD
13116 {
13117 struct x_display_info *share;
13118 Lisp_Object tail;
13119
13120 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
13121 share = share->next, tail = XCDR (tail))
13122 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
13123 XSTRING (display_name)->data))
13124 break;
13125 if (share)
13126 dpyinfo->kboard = share->kboard;
13127 else
13128 {
13129 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13130 init_kboard (dpyinfo->kboard);
59e755be
KH
13131 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
13132 {
13133 char *vendor = ServerVendor (dpy);
9b6ed9f3 13134 UNBLOCK_INPUT;
59e755be
KH
13135 dpyinfo->kboard->Vsystem_key_alist
13136 = call1 (Qvendor_specific_keysyms,
13137 build_string (vendor ? vendor : ""));
9b6ed9f3 13138 BLOCK_INPUT;
59e755be
KH
13139 }
13140
29b38361
KH
13141 dpyinfo->kboard->next_kboard = all_kboards;
13142 all_kboards = dpyinfo->kboard;
0ad5446c
KH
13143 /* Don't let the initial kboard remain current longer than necessary.
13144 That would cause problems if a file loaded on startup tries to
06a2c219 13145 prompt in the mini-buffer. */
0ad5446c
KH
13146 if (current_kboard == initial_kboard)
13147 current_kboard = dpyinfo->kboard;
29b38361
KH
13148 }
13149 dpyinfo->kboard->reference_count++;
13150 }
b9737ad3
KH
13151#endif
13152
7a13e894
RS
13153 /* Put this display on the chain. */
13154 dpyinfo->next = x_display_list;
13155 x_display_list = dpyinfo;
13156
13157 /* Put it on x_display_name_list as well, to keep them parallel. */
13158 x_display_name_list = Fcons (Fcons (display_name, Qnil),
13159 x_display_name_list);
8e713be6 13160 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
13161
13162 dpyinfo->display = dpy;
dc6f92b8 13163
dc6f92b8 13164#if 0
7a13e894 13165 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 13166#endif /* ! 0 */
7a13e894
RS
13167
13168 dpyinfo->x_id_name
fc932ac6
RS
13169 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
13170 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
13171 + 2);
13172 sprintf (dpyinfo->x_id_name, "%s@%s",
13173 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
13174
13175 /* Figure out which modifier bits mean what. */
334208b7 13176 x_find_modifier_meanings (dpyinfo);
f451eb13 13177
ab648270 13178 /* Get the scroll bar cursor. */
7a13e894 13179 dpyinfo->vertical_scroll_bar_cursor
334208b7 13180 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 13181
334208b7
RS
13182 xrdb = x_load_resources (dpyinfo->display, xrm_option,
13183 resource_name, EMACS_CLASS);
13184#ifdef HAVE_XRMSETDATABASE
13185 XrmSetDatabase (dpyinfo->display, xrdb);
13186#else
13187 dpyinfo->display->db = xrdb;
13188#endif
547d9db8 13189 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
13190 all versions. */
13191 dpyinfo->xrdb = xrdb;
334208b7
RS
13192
13193 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
13194 DefaultScreen (dpyinfo->display));
5ff67d81 13195 select_visual (dpyinfo);
43bd1b2b 13196 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
13197 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
13198 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
13199 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
13200 dpyinfo->grabbed = 0;
13201 dpyinfo->reference_count = 0;
13202 dpyinfo->icon_bitmap_id = -1;
06a2c219 13203 dpyinfo->font_table = NULL;
7a13e894
RS
13204 dpyinfo->n_fonts = 0;
13205 dpyinfo->font_table_size = 0;
13206 dpyinfo->bitmaps = 0;
13207 dpyinfo->bitmaps_size = 0;
13208 dpyinfo->bitmaps_last = 0;
13209 dpyinfo->scratch_cursor_gc = 0;
13210 dpyinfo->mouse_face_mouse_frame = 0;
13211 dpyinfo->mouse_face_deferred_gc = 0;
13212 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
13213 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 13214 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894
RS
13215 dpyinfo->mouse_face_window = Qnil;
13216 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
13217 dpyinfo->mouse_face_defer = 0;
0f941935
KH
13218 dpyinfo->x_focus_frame = 0;
13219 dpyinfo->x_focus_event_frame = 0;
13220 dpyinfo->x_highlight_frame = 0;
06a2c219 13221 dpyinfo->image_cache = make_image_cache ();
334208b7 13222
43bd1b2b 13223 /* See if a private colormap is requested. */
5ff67d81
GM
13224 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
13225 {
13226 if (dpyinfo->visual->class == PseudoColor)
13227 {
13228 Lisp_Object value;
13229 value = display_x_get_resource (dpyinfo,
13230 build_string ("privateColormap"),
13231 build_string ("PrivateColormap"),
13232 Qnil, Qnil);
13233 if (STRINGP (value)
13234 && (!strcmp (XSTRING (value)->data, "true")
13235 || !strcmp (XSTRING (value)->data, "on")))
13236 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
13237 }
43bd1b2b 13238 }
5ff67d81
GM
13239 else
13240 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
13241 dpyinfo->visual, AllocNone);
43bd1b2b 13242
06a2c219
GM
13243 {
13244 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
13245 double pixels = DisplayHeight (dpyinfo->display, screen_number);
13246 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
13247 dpyinfo->resy = pixels * 25.4 / mm;
13248 pixels = DisplayWidth (dpyinfo->display, screen_number);
13249 mm = DisplayWidthMM (dpyinfo->display, screen_number);
13250 dpyinfo->resx = pixels * 25.4 / mm;
13251 }
13252
334208b7
RS
13253 dpyinfo->Xatom_wm_protocols
13254 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
13255 dpyinfo->Xatom_wm_take_focus
13256 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
13257 dpyinfo->Xatom_wm_save_yourself
13258 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
13259 dpyinfo->Xatom_wm_delete_window
13260 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
13261 dpyinfo->Xatom_wm_change_state
13262 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
13263 dpyinfo->Xatom_wm_configure_denied
13264 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
13265 dpyinfo->Xatom_wm_window_moved
13266 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
13267 dpyinfo->Xatom_editres
13268 = XInternAtom (dpyinfo->display, "Editres", False);
13269 dpyinfo->Xatom_CLIPBOARD
13270 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
13271 dpyinfo->Xatom_TIMESTAMP
13272 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
13273 dpyinfo->Xatom_TEXT
13274 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
13275 dpyinfo->Xatom_COMPOUND_TEXT
13276 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
13277 dpyinfo->Xatom_DELETE
13278 = XInternAtom (dpyinfo->display, "DELETE", False);
13279 dpyinfo->Xatom_MULTIPLE
13280 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
13281 dpyinfo->Xatom_INCR
13282 = XInternAtom (dpyinfo->display, "INCR", False);
13283 dpyinfo->Xatom_EMACS_TMP
13284 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
13285 dpyinfo->Xatom_TARGETS
13286 = XInternAtom (dpyinfo->display, "TARGETS", False);
13287 dpyinfo->Xatom_NULL
13288 = XInternAtom (dpyinfo->display, "NULL", False);
13289 dpyinfo->Xatom_ATOM_PAIR
13290 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
13291 /* For properties of font. */
13292 dpyinfo->Xatom_PIXEL_SIZE
13293 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
13294 dpyinfo->Xatom_MULE_BASELINE_OFFSET
13295 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
13296 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
13297 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
13298 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
13299 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 13300
06a2c219
GM
13301 /* Ghostscript support. */
13302 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
13303 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
13304
13305 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
13306 False);
13307
547d9db8
KH
13308 dpyinfo->cut_buffers_initialized = 0;
13309
334208b7
RS
13310 connection = ConnectionNumber (dpyinfo->display);
13311 dpyinfo->connection = connection;
13312
dc43ef94 13313 {
5d7cc324
RS
13314 char null_bits[1];
13315
13316 null_bits[0] = 0x00;
dc43ef94
KH
13317
13318 dpyinfo->null_pixel
13319 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13320 null_bits, 1, 1, (long) 0, (long) 0,
13321 1);
13322 }
13323
06a2c219
GM
13324 {
13325 extern int gray_bitmap_width, gray_bitmap_height;
13326 extern unsigned char *gray_bitmap_bits;
13327 dpyinfo->gray
13328 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13329 gray_bitmap_bits,
13330 gray_bitmap_width, gray_bitmap_height,
13331 (unsigned long) 1, (unsigned long) 0, 1);
13332 }
13333
f5d11644
GM
13334#ifdef HAVE_X_I18N
13335 xim_initialize (dpyinfo, resource_name);
13336#endif
13337
87485d6f
MW
13338#ifdef subprocesses
13339 /* This is only needed for distinguishing keyboard and process input. */
334208b7 13340 if (connection != 0)
7a13e894 13341 add_keyboard_wait_descriptor (connection);
87485d6f 13342#endif
6d4238f3 13343
041b69ac 13344#ifndef F_SETOWN_BUG
dc6f92b8 13345#ifdef F_SETOWN
dc6f92b8 13346#ifdef F_SETOWN_SOCK_NEG
61c3ce62 13347 /* stdin is a socket here */
334208b7 13348 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 13349#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 13350 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
13351#endif /* ! defined (F_SETOWN_SOCK_NEG) */
13352#endif /* ! defined (F_SETOWN) */
041b69ac 13353#endif /* F_SETOWN_BUG */
dc6f92b8
JB
13354
13355#ifdef SIGIO
eee20f6a
KH
13356 if (interrupt_input)
13357 init_sigio (connection);
c118dd06 13358#endif /* ! defined (SIGIO) */
dc6f92b8 13359
51b592fb 13360#ifdef USE_LUCID
f8c39f51 13361#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
13362 /* Make sure that we have a valid font for dialog boxes
13363 so that Xt does not crash. */
13364 {
13365 Display *dpy = dpyinfo->display;
13366 XrmValue d, fr, to;
13367 Font font;
e99db5a1 13368 int count;
51b592fb
RS
13369
13370 d.addr = (XPointer)&dpy;
13371 d.size = sizeof (Display *);
13372 fr.addr = XtDefaultFont;
13373 fr.size = sizeof (XtDefaultFont);
13374 to.size = sizeof (Font *);
13375 to.addr = (XPointer)&font;
e99db5a1 13376 count = x_catch_errors (dpy);
51b592fb
RS
13377 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
13378 abort ();
13379 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
13380 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 13381 x_uncatch_errors (dpy, count);
51b592fb
RS
13382 }
13383#endif
f8c39f51 13384#endif
51b592fb 13385
34e23e5a
GM
13386 /* See if we should run in synchronous mode. This is useful
13387 for debugging X code. */
13388 {
13389 Lisp_Object value;
13390 value = display_x_get_resource (dpyinfo,
13391 build_string ("synchronous"),
13392 build_string ("Synchronous"),
13393 Qnil, Qnil);
13394 if (STRINGP (value)
13395 && (!strcmp (XSTRING (value)->data, "true")
13396 || !strcmp (XSTRING (value)->data, "on")))
13397 XSynchronize (dpyinfo->display, True);
13398 }
13399
60439948
KH
13400 UNBLOCK_INPUT;
13401
7a13e894
RS
13402 return dpyinfo;
13403}
13404\f
13405/* Get rid of display DPYINFO, assuming all frames are already gone,
13406 and without sending any more commands to the X server. */
dc6f92b8 13407
7a13e894
RS
13408void
13409x_delete_display (dpyinfo)
13410 struct x_display_info *dpyinfo;
13411{
13412 delete_keyboard_wait_descriptor (dpyinfo->connection);
13413
13414 /* Discard this display from x_display_name_list and x_display_list.
13415 We can't use Fdelq because that can quit. */
13416 if (! NILP (x_display_name_list)
8e713be6
KR
13417 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
13418 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
13419 else
13420 {
13421 Lisp_Object tail;
13422
13423 tail = x_display_name_list;
8e713be6 13424 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 13425 {
bffcfca9 13426 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 13427 {
8e713be6 13428 XCDR (tail) = XCDR (XCDR (tail));
7a13e894
RS
13429 break;
13430 }
8e713be6 13431 tail = XCDR (tail);
7a13e894
RS
13432 }
13433 }
13434
9bda743f
GM
13435 if (next_noop_dpyinfo == dpyinfo)
13436 next_noop_dpyinfo = dpyinfo->next;
13437
7a13e894
RS
13438 if (x_display_list == dpyinfo)
13439 x_display_list = dpyinfo->next;
7f9c7f94
RS
13440 else
13441 {
13442 struct x_display_info *tail;
7a13e894 13443
7f9c7f94
RS
13444 for (tail = x_display_list; tail; tail = tail->next)
13445 if (tail->next == dpyinfo)
13446 tail->next = tail->next->next;
13447 }
7a13e894 13448
0d777288
RS
13449#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
13450#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
13451 XrmDestroyDatabase (dpyinfo->xrdb);
13452#endif
0d777288 13453#endif
29b38361
KH
13454#ifdef MULTI_KBOARD
13455 if (--dpyinfo->kboard->reference_count == 0)
39f79001 13456 delete_kboard (dpyinfo->kboard);
b9737ad3 13457#endif
f5d11644
GM
13458#ifdef HAVE_X_I18N
13459 if (dpyinfo->xim)
13460 xim_close_dpy (dpyinfo);
13461#endif
13462
b9737ad3
KH
13463 xfree (dpyinfo->font_table);
13464 xfree (dpyinfo->x_id_name);
13465 xfree (dpyinfo);
7a13e894
RS
13466}
13467\f
13468/* Set up use of X before we make the first connection. */
13469
06a2c219
GM
13470static struct redisplay_interface x_redisplay_interface =
13471{
13472 x_produce_glyphs,
13473 x_write_glyphs,
13474 x_insert_glyphs,
13475 x_clear_end_of_line,
13476 x_scroll_run,
13477 x_after_update_window_line,
13478 x_update_window_begin,
13479 x_update_window_end,
13480 XTcursor_to,
13481 x_flush,
71b8321e 13482 x_clear_mouse_face,
66ac4b0e
GM
13483 x_get_glyph_overhangs,
13484 x_fix_overlapping_area
06a2c219
GM
13485};
13486
dfcf069d 13487void
7a13e894
RS
13488x_initialize ()
13489{
06a2c219
GM
13490 rif = &x_redisplay_interface;
13491
13492 clear_frame_hook = x_clear_frame;
13493 ins_del_lines_hook = x_ins_del_lines;
13494 change_line_highlight_hook = x_change_line_highlight;
13495 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
13496 ring_bell_hook = XTring_bell;
13497 reset_terminal_modes_hook = XTreset_terminal_modes;
13498 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
13499 update_begin_hook = x_update_begin;
13500 update_end_hook = x_update_end;
dc6f92b8
JB
13501 set_terminal_window_hook = XTset_terminal_window;
13502 read_socket_hook = XTread_socket;
b8009dd1 13503 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 13504 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 13505 mouse_position_hook = XTmouse_position;
f451eb13 13506 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 13507 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
13508 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13509 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13510 redeem_scroll_bar_hook = XTredeem_scroll_bar;
13511 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 13512 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 13513
f676886a 13514 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
13515 char_ins_del_ok = 0; /* just as fast to write the line */
13516 line_ins_del_ok = 1; /* we'll just blt 'em */
13517 fast_clear_end_of_line = 1; /* X does this well */
58769bee 13518 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
13519 off the bottom */
13520 baud_rate = 19200;
13521
7a13e894 13522 x_noop_count = 0;
9ea173e8 13523 last_tool_bar_item = -1;
06a2c219
GM
13524 any_help_event_p = 0;
13525
b30b24cb
RS
13526 /* Try to use interrupt input; if we can't, then start polling. */
13527 Fset_input_mode (Qt, Qnil, Qt, Qnil);
13528
7f9c7f94
RS
13529#ifdef USE_X_TOOLKIT
13530 XtToolkitInitialize ();
13531 Xt_app_con = XtCreateApplicationContext ();
665881ad 13532 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
13533
13534 /* Install an asynchronous timer that processes Xt timeout events
13535 every 0.1s. This is necessary because some widget sets use
13536 timeouts internally, for example the LessTif menu bar, or the
13537 Xaw3d scroll bar. When Xt timouts aren't processed, these
13538 widgets don't behave normally. */
13539 {
13540 EMACS_TIME interval;
13541 EMACS_SET_SECS_USECS (interval, 0, 100000);
13542 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
13543 }
db74249b 13544#endif
bffcfca9 13545
db74249b 13546#if USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
13547 xaw3d_arrow_scroll = False;
13548 xaw3d_pick_top = True;
7f9c7f94
RS
13549#endif
13550
58769bee 13551 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 13552 original error handler. */
e99db5a1 13553 XSetErrorHandler (x_error_handler);
334208b7 13554 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 13555
06a2c219 13556 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
13557#ifdef SIGWINCH
13558 signal (SIGWINCH, SIG_DFL);
c118dd06 13559#endif /* ! defined (SIGWINCH) */
dc6f92b8 13560
92e2441b 13561 signal (SIGPIPE, x_connection_signal);
dc6f92b8 13562}
55123275 13563
06a2c219 13564
55123275
JB
13565void
13566syms_of_xterm ()
13567{
e99db5a1
RS
13568 staticpro (&x_error_message_string);
13569 x_error_message_string = Qnil;
13570
7a13e894
RS
13571 staticpro (&x_display_name_list);
13572 x_display_name_list = Qnil;
334208b7 13573
ab648270 13574 staticpro (&last_mouse_scroll_bar);
e53cb100 13575 last_mouse_scroll_bar = Qnil;
59e755be
KH
13576
13577 staticpro (&Qvendor_specific_keysyms);
13578 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
13579
13580 staticpro (&last_mouse_press_frame);
13581 last_mouse_press_frame = Qnil;
06a2c219
GM
13582
13583 staticpro (&help_echo);
13584 help_echo = Qnil;
13585 staticpro (&previous_help_echo);
13586 previous_help_echo = Qnil;
13587
13588 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
13589 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
13590For example, if a block cursor is over a tab, it will be drawn as\n\
13591wide as that tab on the display.");
13592 x_stretch_cursor_p = 0;
13593
13594 DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
13595 "If not nil, Emacs uses toolkit scroll bars.");
13596#if USE_TOOLKIT_SCROLL_BARS
13597 x_toolkit_scroll_bars_p = 1;
13598#else
13599 x_toolkit_scroll_bars_p = 0;
13600#endif
13601
06a2c219
GM
13602 staticpro (&last_mouse_motion_frame);
13603 last_mouse_motion_frame = Qnil;
55123275 13604}
6cf0ae86
RS
13605
13606#endif /* not HAVE_X_WINDOWS */
06a2c219 13607