(internal_equal): Fix overlay comparison.
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
06a2c219
GM
2 Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999
3 Free Software Foundation, Inc.
dc6f92b8
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4746118a 9the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
dc6f92b8 21
06a2c219 22/* New display code by Gerd Moellmann <gerd@gnu.org>. */
3afe33e7
RS
23/* Xt features made by Fred Pierresteguy. */
24
039440c4
RS
25/* On 4.3 these lose if they come after xterm.h. */
26/* On HP-UX 8.0 signal.h loses if it comes after config.h. */
27/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
28#include <signal.h>
29
18160b98 30#include <config.h>
dc6f92b8 31
4846819e 32#include <stdio.h>
06a2c219
GM
33#ifdef STDC_HEADERS
34#include <stdlib.h>
35#endif
4846819e 36
dc6f92b8
JB
37#ifdef HAVE_X_WINDOWS
38
39#include "lisp.h"
9ac0d9e0 40#include "blockinput.h"
dc6f92b8 41
ae79c227
AS
42/* Need syssignal.h for various externs and definitions that may be required
43 by some configurations for calls to signal later in this source file. */
44#include "syssignal.h"
45
dc6f92b8
JB
46/* This may include sys/types.h, and that somehow loses
47 if this is not done before the other system files. */
48#include "xterm.h"
f451eb13 49#include <X11/cursorfont.h>
dc6f92b8 50
16bd92ea 51#ifndef USG
dc6f92b8
JB
52/* Load sys/types.h if not already loaded.
53 In some systems loading it twice is suicidal. */
54#ifndef makedev
55#include <sys/types.h>
c118dd06
JB
56#endif /* makedev */
57#endif /* USG */
dc6f92b8 58
6df54671 59#ifdef BSD_SYSTEM
dc6f92b8 60#include <sys/ioctl.h>
6df54671 61#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 62
2d368234 63#include "systty.h"
3a2712f9 64#include "systime.h"
dc6f92b8 65
b8009dd1 66#ifndef INCLUDED_FCNTL
dc6f92b8 67#include <fcntl.h>
b8009dd1 68#endif
dc6f92b8
JB
69#include <ctype.h>
70#include <errno.h>
71#include <setjmp.h>
72#include <sys/stat.h>
a0a7635f
RS
73/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
74/* #include <sys/param.h> */
dc6f92b8 75
dc43ef94
KH
76#include "charset.h"
77#include "ccl.h"
7a13e894 78#include "frame.h"
a1dfb88a 79#include "fontset.h"
dc6f92b8
JB
80#include "dispextern.h"
81#include "termhooks.h"
82#include "termopts.h"
83#include "termchar.h"
84#if 0
85#include "sink.h"
86#include "sinkmask.h"
c118dd06 87#endif /* ! 0 */
dc6f92b8 88#include "gnu.h"
dc6f92b8 89#include "disptab.h"
dc6f92b8 90#include "buffer.h"
f451eb13 91#include "window.h"
3b2fa4e6 92#include "keyboard.h"
bde7c500 93#include "intervals.h"
dfcf069d 94#include "process.h"
dc6f92b8 95
d2bd6bc4
RS
96#ifdef USE_X_TOOLKIT
97#include <X11/Shell.h>
98#endif
99
06a2c219
GM
100#include <sys/types.h>
101#ifdef HAVE_SYS_TIME_H
102#include <sys/time.h>
103#endif
104#ifdef HAVE_UNISTD_H
105#include <unistd.h>
106#endif
107
3afe33e7 108#ifdef USE_X_TOOLKIT
06a2c219 109
9d7e2e3e 110extern void free_frame_menubar ();
2224b905 111extern FRAME_PTR x_menubar_window_to_frame ();
06a2c219 112
0fdff6bb
RS
113#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
114#define HACK_EDITRES
115extern void _XEditResCheckMessages ();
116#endif /* not NO_EDITRES */
06a2c219
GM
117
118/* Include toolkit specific headers for the scroll bar widget. */
119
120#ifdef USE_TOOLKIT_SCROLL_BARS
121#if defined USE_MOTIF
122#include <Xm/Xm.h> /* for LESSTIF_VERSION */
123#include <Xm/ScrollBar.h>
124#include <Xm/ScrollBarP.h>
125#elif defined HAVE_XAW3D
126#include <X11/Xaw3d/Simple.h>
127#include <X11/Xaw3d/ThreeD.h>
128#include <X11/Xaw3d/Scrollbar.h>
129#define ARROW_SCROLLBAR
130#include <X11/Xaw3d/ScrollbarP.h>
131#endif /* HAVE_XAW3D */
132#endif /* USE_TOOLKIT_SCROLL_BARS */
133
3afe33e7
RS
134#endif /* USE_X_TOOLKIT */
135
b849c413
RS
136#ifndef USE_X_TOOLKIT
137#define x_any_window_to_frame x_window_to_frame
5627c40e 138#define x_top_window_to_frame x_window_to_frame
b849c413
RS
139#endif
140
546e6d5b 141#ifdef USE_X_TOOLKIT
d067ea8b 142#include "widget.h"
546e6d5b
RS
143#ifndef XtNinitialState
144#define XtNinitialState "initialState"
145#endif
146#endif
147
10537cb1 148#ifdef HAVE_SETLOCALE
39d8bb4d
KH
149/* So we can do setlocale. */
150#include <locale.h>
151#endif
152
80528801
KH
153#ifdef SOLARIS2
154/* memmove will be defined as a macro in Xfuncs.h unless
155 <string.h> is included beforehand. The declaration for memmove in
156 <string.h> will cause a syntax error when Xfuncs.h later includes it. */
157#include <string.h>
158#endif
159
e4b68333 160#ifndef min
06a2c219 161#define min(a,b) ((a) < (b) ? (a) : (b))
e4b68333
RS
162#endif
163#ifndef max
06a2c219
GM
164#define max(a,b) ((a) > (b) ? (a) : (b))
165#endif
166
167#define abs(x) ((x) < 0 ? -(x) : (x))
168
169#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
170
171\f
172/* Bitmaps for truncated lines. */
173
174enum bitmap_type
175{
176 NO_BITMAP,
177 LEFT_TRUNCATION_BITMAP,
178 RIGHT_TRUNCATION_BITMAP,
179 OVERLAY_ARROW_BITMAP,
180 CONTINUED_LINE_BITMAP,
181 CONTINUATION_LINE_BITMAP,
182 ZV_LINE_BITMAP
183};
184
185/* Bitmap drawn to indicate lines not displaying text if
186 `indicate-empty-lines' is non-nil. */
187
188#define zv_width 8
189#define zv_height 8
190static unsigned char zv_bits[] = {
191 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
192
193/* An arrow like this: `<-'. */
194
195#define left_width 8
196#define left_height 8
197static unsigned char left_bits[] = {
198 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
199
200/* Marker for continued lines. */
201
202#define continued_width 8
203#define continued_height 8
204static unsigned char continued_bits[] = {
205 0x30, 0x30, 0x30, 0x30, 0xb4, 0xfc, 0x78, 0x30};
206
207#define continuation_width 8
208#define continuation_height 8
209static unsigned char continuation_bits[] = {
210 0x0c, 0x1e, 0x3f, 0x2d, 0x0c, 0x0c, 0x0c, 0x0c};
211
212/* Right truncation arrow bitmap `->'. */
213
214#define right_width 8
215#define right_height 8
216static unsigned char right_bits[] = {
217 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
218
219/* Overlay arrow bitmap; a filled `<>'. */
220
221#if 1
222#define ov_width 8
223#define ov_height 8
224static unsigned char ov_bits[] = {
225 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
226
227#elif 0
228#define ov_width 8
229#define ov_height 8
230static unsigned char ov_bits[] = {
231 0x18, 0x04, 0x08, 0x1c, 0x3e, 0x3a, 0x32, 0x1c};
232#else
233#define ov_width 8
234#define ov_height 8
235static unsigned char ov_bits[] = {
236 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x3c, 0x18};
e4b68333 237#endif
06a2c219
GM
238
239extern Lisp_Object Qhelp_echo;
240
69388238 241\f
06a2c219
GM
242/* Non-zero means Emacs uses toolkit scroll bars. */
243
244int x_toolkit_scroll_bars_p;
245
246/* If a string, XTread_socket generates an event to display that string.
247 (The display is done in read_char.) */
248
249static Lisp_Object help_echo;
250
251/* Temporary variable for XTread_socket. */
252
253static Lisp_Object previous_help_echo;
254
255/* Non-zero means that a HELP_EVENT has been generated since Emacs
256 start. */
257
258static int any_help_event_p;
259
260/* Non-zero means draw block and hollow cursor as wide as the glyph
261 under it. For example, if a block cursor is over a tab, it will be
262 drawn as wide as that tab on the display. */
263
264int x_stretch_cursor_p;
265
266/* This is a chain of structures for all the X displays currently in
267 use. */
268
334208b7 269struct x_display_info *x_display_list;
dc6f92b8 270
06a2c219
GM
271/* This is a list of cons cells, each of the form (NAME
272 . FONT-LIST-CACHE), one for each element of x_display_list and in
273 the same order. NAME is the name of the frame. FONT-LIST-CACHE
274 records previous values returned by x-list-fonts. */
275
7a13e894 276Lisp_Object x_display_name_list;
f451eb13 277
987d2ad1 278/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
279 This is set by update_begin and looked at by all the XT functions.
280 It is zero while not inside an update. In that case, the XT
281 functions assume that `selected_frame' is the frame to apply to. */
282
d0386f2a 283extern struct frame *updating_frame;
dc6f92b8 284
dfcf069d 285extern int waiting_for_input;
0e81d8cd 286
06a2c219
GM
287/* This is a frame waiting to be auto-raised, within XTread_socket. */
288
0134a210
RS
289struct frame *pending_autoraise_frame;
290
7f9c7f94
RS
291#ifdef USE_X_TOOLKIT
292/* The application context for Xt use. */
293XtAppContext Xt_app_con;
06a2c219
GM
294static String Xt_default_resources[] = {0};
295#endif /* USE_X_TOOLKIT */
665881ad 296
06a2c219
GM
297/* Nominal cursor position -- where to draw output.
298 HPOS and VPOS are window relative glyph matrix coordinates.
299 X and Y are window relative pixel coordinates. */
dc6f92b8 300
06a2c219 301struct cursor_pos output_cursor;
dc6f92b8 302
dc6f92b8 303
69388238
RS
304/* Mouse movement.
305
06a2c219 306 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
307 so that we would have to call XQueryPointer after each MotionNotify
308 event to ask for another such event. However, this made mouse tracking
309 slow, and there was a bug that made it eventually stop.
310
311 Simply asking for MotionNotify all the time seems to work better.
312
69388238
RS
313 In order to avoid asking for motion events and then throwing most
314 of them away or busy-polling the server for mouse positions, we ask
315 the server for pointer motion hints. This means that we get only
316 one event per group of mouse movements. "Groups" are delimited by
317 other kinds of events (focus changes and button clicks, for
318 example), or by XQueryPointer calls; when one of these happens, we
319 get another MotionNotify event the next time the mouse moves. This
320 is at least as efficient as getting motion events when mouse
321 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 322 is off. */
69388238
RS
323
324/* Where the mouse was last time we reported a mouse event. */
69388238 325
06a2c219
GM
326FRAME_PTR last_mouse_frame;
327static XRectangle last_mouse_glyph;
2237cac9
RS
328static Lisp_Object last_mouse_press_frame;
329
69388238
RS
330/* The scroll bar in which the last X motion event occurred.
331
06a2c219
GM
332 If the last X motion event occurred in a scroll bar, we set this so
333 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
334 an ordinary motion.
335
06a2c219
GM
336 If the last X motion event didn't occur in a scroll bar, we set
337 this to Qnil, to tell XTmouse_position to return an ordinary motion
338 event. */
339
69388238
RS
340static Lisp_Object last_mouse_scroll_bar;
341
69388238
RS
342/* This is a hack. We would really prefer that XTmouse_position would
343 return the time associated with the position it returns, but there
06a2c219 344 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
345 along with the position query. So, we just keep track of the time
346 of the last movement we received, and return that in hopes that
347 it's somewhat accurate. */
06a2c219 348
69388238
RS
349static Time last_mouse_movement_time;
350
06a2c219
GM
351/* Incremented by XTread_socket whenever it really tries to read
352 events. */
353
c0a04927
RS
354#ifdef __STDC__
355static int volatile input_signal_count;
356#else
357static int input_signal_count;
358#endif
359
7a13e894 360/* Used locally within XTread_socket. */
06a2c219 361
7a13e894 362static int x_noop_count;
dc6f92b8 363
7a13e894 364/* Initial values of argv and argc. */
06a2c219 365
7a13e894
RS
366extern char **initial_argv;
367extern int initial_argc;
dc6f92b8 368
7a13e894 369extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 370
06a2c219 371/* Tells if a window manager is present or not. */
7a13e894
RS
372
373extern Lisp_Object Vx_no_window_manager;
dc6f92b8 374
c2df547c 375extern Lisp_Object Qface, Qmouse_face;
b8009dd1 376
dc6f92b8
JB
377extern int errno;
378
dfeccd2d 379/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 380
64bb1782
RS
381extern int extra_keyboard_modifiers;
382
59e755be
KH
383static Lisp_Object Qvendor_specific_keysyms;
384
334208b7 385extern XrmDatabase x_load_resources ();
c32cdd9a
KH
386extern Lisp_Object x_icon_type ();
387
7a13e894 388
06a2c219
GM
389/* Enumeration for overriding/changing the face to use for drawing
390 glyphs in x_draw_glyphs. */
391
392enum draw_glyphs_face
393{
394 DRAW_NORMAL_TEXT,
395 DRAW_INVERSE_VIDEO,
396 DRAW_CURSOR,
397 DRAW_MOUSE_FACE,
398 DRAW_IMAGE_RAISED,
399 DRAW_IMAGE_SUNKEN
400};
401
402static void x_update_window_end P_ ((struct window *, int));
403static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
404void x_delete_display P_ ((struct x_display_info *));
405static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
406 unsigned));
407static int fast_find_position P_ ((struct window *, int, int *, int *,
408 int *, int *));
409static void set_output_cursor P_ ((struct cursor_pos *));
410static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
411 int *, int *, int *));
412static void note_mode_line_highlight P_ ((struct window *, int, int));
413static void x_check_font P_ ((struct frame *, XFontStruct *));
414static void note_mouse_highlight P_ ((struct frame *, int, int));
415static void note_toolbar_highlight P_ ((struct frame *f, int, int));
416static void x_handle_toolbar_click P_ ((struct frame *, XButtonEvent *));
417static void show_mouse_face P_ ((struct x_display_info *,
418 enum draw_glyphs_face));
419static int x_io_error_quitter P_ ((Display *));
420int x_catch_errors P_ ((Display *));
421void x_uncatch_errors P_ ((Display *, int));
422void x_lower_frame P_ ((struct frame *));
423void x_scroll_bar_clear P_ ((struct frame *));
424int x_had_errors_p P_ ((Display *));
425void x_wm_set_size_hint P_ ((struct frame *, long, int));
426void x_raise_frame P_ ((struct frame *));
427void x_set_window_size P_ ((struct frame *, int, int, int));
428void x_wm_set_window_state P_ ((struct frame *, int));
429void x_wm_set_icon_pixmap P_ ((struct frame *, int));
430void x_initialize P_ ((void));
431static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
432static int x_compute_min_glyph_bounds P_ ((struct frame *));
433static void x_draw_phys_cursor_glyph P_ ((struct window *,
434 struct glyph_row *,
435 enum draw_glyphs_face));
436static void x_update_end P_ ((struct frame *));
437static void XTframe_up_to_date P_ ((struct frame *));
438static void XTreassert_line_highlight P_ ((int, int));
439static void x_change_line_highlight P_ ((int, int, int, int));
440static void XTset_terminal_modes P_ ((void));
441static void XTreset_terminal_modes P_ ((void));
442static void XTcursor_to P_ ((int, int, int, int));
443static void x_write_glyphs P_ ((struct glyph *, int));
444static void x_clear_end_of_line P_ ((int));
445static void x_clear_frame P_ ((void));
446static void x_clear_cursor P_ ((struct window *));
447static void frame_highlight P_ ((struct frame *));
448static void frame_unhighlight P_ ((struct frame *));
449static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
450static void XTframe_rehighlight P_ ((struct frame *));
451static void x_frame_rehighlight P_ ((struct x_display_info *));
452static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
453static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *));
454static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
455 XRectangle *));
456static void expose_frame P_ ((struct frame *, int, int, int, int));
457static void expose_window_tree P_ ((struct window *, XRectangle *));
458static void expose_window P_ ((struct window *, XRectangle *));
459static void expose_area P_ ((struct window *, struct glyph_row *,
460 XRectangle *, enum glyph_row_area));
461static void expose_line P_ ((struct window *, struct glyph_row *,
462 XRectangle *));
463static void x_update_cursor_in_window_tree P_ ((struct window *, int));
464static void x_update_window_cursor P_ ((struct window *, int));
465static void x_erase_phys_cursor P_ ((struct window *));
466void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
467static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
468 enum bitmap_type));
469
470static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
471 GC, int));
472static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
473static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
474static void note_overwritten_text_cursor P_ ((struct window *, int, int));
475static void x_flush P_ ((struct frame *f));
476
477
478/* Flush display of frame F, or of all frames if F is null. */
479
480static void
481x_flush (f)
482 struct frame *f;
483{
484 BLOCK_INPUT;
485 if (f == NULL)
486 {
487 Lisp_Object rest, frame;
488 FOR_EACH_FRAME (rest, frame)
489 x_flush (XFRAME (frame));
490 }
491 else if (FRAME_X_P (f))
492 XFlush (FRAME_X_DISPLAY (f));
493 UNBLOCK_INPUT;
494}
495
dc6f92b8 496
06a2c219
GM
497/* Remove calls to XFlush by defining XFlush to an empty replacement.
498 Calls to XFlush should be unnecessary because the X output buffer
499 is flushed automatically as needed by calls to XPending,
500 XNextEvent, or XWindowEvent according to the XFlush man page.
501 XTread_socket calls XPending. Removing XFlush improves
502 performance. */
503
504#define XFlush(DISPLAY) (void) 0
b8009dd1 505
334208b7 506\f
06a2c219
GM
507/***********************************************************************
508 Debugging
509 ***********************************************************************/
510
9382638d 511#if 0
06a2c219
GM
512
513/* This is a function useful for recording debugging information about
514 the sequence of occurrences in this file. */
9382638d
KH
515
516struct record
517{
518 char *locus;
519 int type;
520};
521
522struct record event_record[100];
523
524int event_record_index;
525
526record_event (locus, type)
527 char *locus;
528 int type;
529{
530 if (event_record_index == sizeof (event_record) / sizeof (struct record))
531 event_record_index = 0;
532
533 event_record[event_record_index].locus = locus;
534 event_record[event_record_index].type = type;
535 event_record_index++;
536}
537
538#endif /* 0 */
06a2c219
GM
539
540
9382638d 541\f
334208b7
RS
542/* Return the struct x_display_info corresponding to DPY. */
543
544struct x_display_info *
545x_display_info_for_display (dpy)
546 Display *dpy;
547{
548 struct x_display_info *dpyinfo;
549
550 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
551 if (dpyinfo->display == dpy)
552 return dpyinfo;
16bd92ea 553
334208b7
RS
554 return 0;
555}
f451eb13 556
06a2c219
GM
557
558\f
559/***********************************************************************
560 Starting and ending an update
561 ***********************************************************************/
562
563/* Start an update of frame F. This function is installed as a hook
564 for update_begin, i.e. it is called when update_begin is called.
565 This function is called prior to calls to x_update_window_begin for
566 each window being updated. Currently, there is nothing to do here
567 because all interesting stuff is done on a window basis. */
dc6f92b8 568
dfcf069d 569static void
06a2c219 570x_update_begin (f)
f676886a 571 struct frame *f;
58769bee 572{
06a2c219
GM
573 /* Nothing to do. */
574}
dc6f92b8 575
dc6f92b8 576
06a2c219
GM
577/* Start update of window W. Set the global variable updated_window
578 to the window being updated and set output_cursor to the cursor
579 position of W. */
dc6f92b8 580
06a2c219
GM
581static void
582x_update_window_begin (w)
583 struct window *w;
584{
585 struct frame *f = XFRAME (WINDOW_FRAME (w));
586 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
587
588 updated_window = w;
589 set_output_cursor (&w->cursor);
b8009dd1 590
06a2c219 591 BLOCK_INPUT;
d1bc4182 592
06a2c219 593 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 594 {
514e4681 595 /* Don't do highlighting for mouse motion during the update. */
06a2c219 596 display_info->mouse_face_defer = 1;
37c2c98b 597
06a2c219
GM
598 /* If F needs to be redrawn, simply forget about any prior mouse
599 highlighting. */
9f67f20b 600 if (FRAME_GARBAGED_P (f))
06a2c219
GM
601 display_info->mouse_face_window = Qnil;
602
603 /* Can we tell that this update does not affect the window
604 where the mouse highlight is? If so, no need to turn off.
605 Likewise, don't do anything if the frame is garbaged;
606 in that case, the frame's current matrix that we would use
607 is all wrong, and we will redisplay that line anyway. */
608 if (!NILP (display_info->mouse_face_window)
609 && w == XWINDOW (display_info->mouse_face_window))
514e4681 610 {
06a2c219 611 int i;
514e4681 612
06a2c219
GM
613 for (i = 0; i < w->desired_matrix->nrows; ++i)
614 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
615 break;
616
06a2c219
GM
617 if (i < w->desired_matrix->nrows)
618 clear_mouse_face (display_info);
514e4681 619 }
b8009dd1 620 }
6ccf47d1 621
dc6f92b8
JB
622 UNBLOCK_INPUT;
623}
624
06a2c219
GM
625
626/* Draw a vertical window border to the right of window W if W doesn't
627 have vertical scroll bars. */
628
dfcf069d 629static void
06a2c219
GM
630x_draw_vertical_border (w)
631 struct window *w;
58769bee 632{
06a2c219
GM
633 struct frame *f = XFRAME (WINDOW_FRAME (w));
634
635 /* Redraw borders between horizontally adjacent windows. Don't
636 do it for frames with vertical scroll bars because either the
637 right scroll bar of a window, or the left scroll bar of its
638 neighbor will suffice as a border. */
639 if (!WINDOW_RIGHTMOST_P (w)
640 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
641 {
642 int x0, x1, y0, y1;
dc6f92b8 643
06a2c219
GM
644 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
645 x1 += FRAME_X_FLAGS_AREA_WIDTH (f);
646 y1 -= 1;
647
648 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
649 f->output_data.x->normal_gc, x1, y0, x1, y1);
650 }
651}
652
653
654/* End update of window W (which is equal to updated_window). Draw
655 vertical borders between horizontally adjacent windows, and display
656 W's cursor if CURSOR_ON_P is non-zero. W may be a menu bar
657 pseudo-window in case we don't have X toolkit support. Such
658 windows don't have a cursor, so don't display it here. */
659
660static void
661x_update_window_end (w, cursor_on_p)
662 struct window *w;
663 int cursor_on_p;
664{
665 if (!w->pseudo_window_p)
666 {
667 BLOCK_INPUT;
668 if (cursor_on_p)
669 x_display_and_set_cursor (w, 1, output_cursor.hpos,
670 output_cursor.vpos,
671 output_cursor.x, output_cursor.y);
672 x_draw_vertical_border (w);
673 UNBLOCK_INPUT;
674 }
675
676 updated_window = NULL;
677}
dc6f92b8 678
dc6f92b8 679
06a2c219
GM
680/* End update of frame F. This function is installed as a hook in
681 update_end. */
682
683static void
684x_update_end (f)
685 struct frame *f;
686{
687 /* Mouse highlight may be displayed again. */
aa8bff2e 688 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 689
06a2c219 690 BLOCK_INPUT;
334208b7 691 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
692 UNBLOCK_INPUT;
693}
b8009dd1 694
06a2c219
GM
695
696/* This function is called from various places in xdisp.c whenever a
697 complete update has been performed. The global variable
698 updated_window is not available here. */
b8009dd1 699
dfcf069d 700static void
b8009dd1 701XTframe_up_to_date (f)
06a2c219 702 struct frame *f;
b8009dd1 703{
06a2c219 704 if (FRAME_X_P (f))
514e4681 705 {
06a2c219
GM
706 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
707 if (dpyinfo->mouse_face_deferred_gc
708 || f == dpyinfo->mouse_face_mouse_frame)
709 {
710 BLOCK_INPUT;
711 if (dpyinfo->mouse_face_mouse_frame)
712 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
713 dpyinfo->mouse_face_mouse_x,
714 dpyinfo->mouse_face_mouse_y);
715 dpyinfo->mouse_face_deferred_gc = 0;
716 UNBLOCK_INPUT;
717 }
514e4681 718 }
b8009dd1 719}
06a2c219
GM
720
721
722/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
723 arrow bitmaps, or clear the areas where they would be displayed
724 before DESIRED_ROW is made current. The window being updated is
725 found in updated_window. This function It is called from
726 update_window_line only if it is known that there are differences
727 between bitmaps to be drawn between current row and DESIRED_ROW. */
728
729static void
730x_after_update_window_line (desired_row)
731 struct glyph_row *desired_row;
732{
733 struct window *w = updated_window;
734
735 xassert (w);
736
737 if (!desired_row->mode_line_p && !w->pseudo_window_p)
738 {
739 BLOCK_INPUT;
740 x_draw_row_bitmaps (w, desired_row);
741
742 /* When a window has disappeared, make sure that no rest of
743 full-width rows stays visible in the internal border. */
744 if (windows_or_buffers_changed)
745 {
746 struct frame *f = XFRAME (w->frame);
747 int width = FRAME_INTERNAL_BORDER_WIDTH (f);
748 int height = desired_row->visible_height;
749 int x = window_box_right (w, -1) + FRAME_X_FLAGS_AREA_WIDTH (f);
750 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
751
752 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
753 x, y, width, height, False);
754 }
755
756 UNBLOCK_INPUT;
757 }
758}
759
760
761/* Draw the bitmap WHICH in one of the areas to the left or right of
762 window W. ROW is the glyph row for which to display the bitmap; it
763 determines the vertical position at which the bitmap has to be
764 drawn. */
765
766static void
767x_draw_bitmap (w, row, which)
768 struct window *w;
769 struct glyph_row *row;
770 enum bitmap_type which;
771{
772 struct frame *f = XFRAME (WINDOW_FRAME (w));
773 Display *display = FRAME_X_DISPLAY (f);
774 Window window = FRAME_X_WINDOW (f);
775 int x, y, wd, h, dy;
776 unsigned char *bits;
777 Pixmap pixmap;
778 GC gc = f->output_data.x->normal_gc;
779 struct face *face;
780 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
781
782 /* Must clip because of partially visible lines. */
783 x_clip_to_row (w, row, gc, 1);
784
785 switch (which)
786 {
787 case LEFT_TRUNCATION_BITMAP:
788 wd = left_width;
789 h = left_height;
790 bits = left_bits;
791 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
792 - wd
793 - (FRAME_X_FLAGS_AREA_WIDTH (f) - wd) / 2);
794 break;
795
796 case OVERLAY_ARROW_BITMAP:
797 wd = left_width;
798 h = left_height;
799 bits = ov_bits;
800 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
801 - wd
802 - (FRAME_X_FLAGS_AREA_WIDTH (f) - wd) / 2);
803 break;
804
805 case RIGHT_TRUNCATION_BITMAP:
806 wd = right_width;
807 h = right_height;
808 bits = right_bits;
809 x = window_box_right (w, -1);
810 x += (FRAME_X_FLAGS_AREA_WIDTH (f) - wd) / 2;
811 break;
812
813 case CONTINUED_LINE_BITMAP:
814 wd = right_width;
815 h = right_height;
816 bits = continued_bits;
817 x = window_box_right (w, -1);
818 x += (FRAME_X_FLAGS_AREA_WIDTH (f) - wd) / 2;
819 break;
820
821 case CONTINUATION_LINE_BITMAP:
822 wd = continuation_width;
823 h = continuation_height;
824 bits = continuation_bits;
825 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
826 - wd
827 - (FRAME_X_FLAGS_AREA_WIDTH (f) - wd) / 2);
828 break;
829
830 case ZV_LINE_BITMAP:
831 wd = zv_width;
832 h = zv_height;
833 bits = zv_bits;
834 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
835 - wd
836 - (FRAME_X_FLAGS_AREA_WIDTH (f) - wd) / 2);
837 break;
838
839 default:
840 abort ();
841 }
842
843 /* Convert to frame coordinates. Set dy to the offset in the row to
844 start drawing the bitmap. */
845 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
846 dy = (row->height - h) / 2;
847
848 /* Draw the bitmap. I believe these small pixmaps can be cached
849 by the server. */
850 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
851 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
852 face->foreground,
853 face->background, depth);
854 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
855 XFreePixmap (display, pixmap);
856 XSetClipMask (display, gc, None);
857}
858
859
860/* Draw flags bitmaps for glyph row ROW on window W. Call this
861 function with input blocked. */
862
863static void
864x_draw_row_bitmaps (w, row)
865 struct window *w;
866 struct glyph_row *row;
867{
868 struct frame *f = XFRAME (w->frame);
869 enum bitmap_type bitmap;
870 struct face *face;
871 int top_line_height = -1;
872
873 xassert (interrupt_input_blocked);
874
875 /* If row is completely invisible, because of vscrolling, we
876 don't have to draw anything. */
877 if (row->visible_height <= 0)
878 return;
879
880 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
881 PREPARE_FACE_FOR_DISPLAY (f, face);
882
883 /* Decide which bitmap to draw at the left side. */
884 if (row->overlay_arrow_p)
885 bitmap = OVERLAY_ARROW_BITMAP;
886 else if (row->truncated_on_left_p)
887 bitmap = LEFT_TRUNCATION_BITMAP;
888 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
889 bitmap = CONTINUATION_LINE_BITMAP;
890 else if (row->indicate_empty_line_p)
891 bitmap = ZV_LINE_BITMAP;
892 else
893 bitmap = NO_BITMAP;
894
895 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
896 the flags area. */
897 if (bitmap == NO_BITMAP
898 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_FLAGS_AREA_WIDTH (f)
899 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
900 {
901 /* If W has a vertical border to its left, don't draw over it. */
902 int border = ((XFASTINT (w->left) > 0
903 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
904 ? 1 : 0);
905 int left = window_box_left (w, -1);
906
907 if (top_line_height < 0)
908 top_line_height = WINDOW_DISPLAY_TOP_LINE_HEIGHT (w);
dcd08bfb
GM
909
910 /* In case the same realized face is used for bitmap areas and
911 for something displayed in the text (e.g. face `region' on
912 mono-displays, the fill style may have been changed to
913 FillSolid in x_draw_glyph_string_background. */
914 if (face->stipple)
915 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
916 else
917 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
918
06a2c219
GM
919 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
920 face->gc,
921 (left
922 - FRAME_X_FLAGS_AREA_WIDTH (f)
923 + border),
924 WINDOW_TO_FRAME_PIXEL_Y (w, max (top_line_height,
925 row->y)),
926 FRAME_X_FLAGS_AREA_WIDTH (f) - border,
927 row->visible_height);
dcd08bfb
GM
928 if (!face->stipple)
929 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
930 }
931
932 /* Draw the left bitmap. */
933 if (bitmap != NO_BITMAP)
934 x_draw_bitmap (w, row, bitmap);
935
936 /* Decide which bitmap to draw at the right side. */
937 if (row->truncated_on_right_p)
938 bitmap = RIGHT_TRUNCATION_BITMAP;
939 else if (row->continued_p)
940 bitmap = CONTINUED_LINE_BITMAP;
941 else
942 bitmap = NO_BITMAP;
943
944 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
945 the flags area. */
946 if (bitmap == NO_BITMAP
947 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_FLAGS_AREA_WIDTH (f)
948 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
949 {
950 int right = window_box_right (w, -1);
951
952 if (top_line_height < 0)
953 top_line_height = WINDOW_DISPLAY_TOP_LINE_HEIGHT (w);
dcd08bfb
GM
954
955 /* In case the same realized face is used for bitmap areas and
956 for something displayed in the text (e.g. face `region' on
957 mono-displays, the fill style may have been changed to
958 FillSolid in x_draw_glyph_string_background. */
959 if (face->stipple)
960 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
961 else
962 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
963 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
964 face->gc,
965 right,
966 WINDOW_TO_FRAME_PIXEL_Y (w, max (top_line_height,
967 row->y)),
968 FRAME_X_FLAGS_AREA_WIDTH (f),
969 row->visible_height);
dcd08bfb
GM
970 if (!face->stipple)
971 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
972 }
973
974 /* Draw the right bitmap. */
975 if (bitmap != NO_BITMAP)
976 x_draw_bitmap (w, row, bitmap);
977}
978
dc6f92b8 979\f
06a2c219
GM
980/***********************************************************************
981 Line Highlighting
982 ***********************************************************************/
dc6f92b8 983
06a2c219
GM
984/* External interface to control of standout mode. Not used for X
985 frames. Aborts when called. */
986
987static void
dc6f92b8
JB
988XTreassert_line_highlight (new, vpos)
989 int new, vpos;
990{
06a2c219 991 abort ();
dc6f92b8
JB
992}
993
06a2c219
GM
994
995/* Call this when about to modify line at position VPOS and change
996 whether it is highlighted. Not used for X frames. Aborts when
997 called. */
dc6f92b8 998
dfcf069d 999static void
06a2c219
GM
1000x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1001 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1002{
06a2c219 1003 abort ();
dc6f92b8
JB
1004}
1005
06a2c219
GM
1006
1007/* This is called when starting Emacs and when restarting after
1008 suspend. When starting Emacs, no X window is mapped. And nothing
1009 must be done to Emacs's own window if it is suspended (though that
1010 rarely happens). */
dc6f92b8 1011
dfcf069d 1012static void
dc6f92b8
JB
1013XTset_terminal_modes ()
1014{
1015}
1016
06a2c219
GM
1017/* This is called when exiting or suspending Emacs. Exiting will make
1018 the X-windows go away, and suspending requires no action. */
dc6f92b8 1019
dfcf069d 1020static void
dc6f92b8
JB
1021XTreset_terminal_modes ()
1022{
dc6f92b8 1023}
06a2c219
GM
1024
1025
dc6f92b8 1026\f
06a2c219
GM
1027/***********************************************************************
1028 Output Cursor
1029 ***********************************************************************/
1030
1031/* Set the global variable output_cursor to CURSOR. All cursor
1032 positions are relative to updated_window. */
dc6f92b8 1033
dfcf069d 1034static void
06a2c219
GM
1035set_output_cursor (cursor)
1036 struct cursor_pos *cursor;
dc6f92b8 1037{
06a2c219
GM
1038 output_cursor.hpos = cursor->hpos;
1039 output_cursor.vpos = cursor->vpos;
1040 output_cursor.x = cursor->x;
1041 output_cursor.y = cursor->y;
1042}
1043
1044
1045/* Set a nominal cursor position.
dc6f92b8 1046
06a2c219
GM
1047 HPOS and VPOS are column/row positions in a window glyph matrix. X
1048 and Y are window text area relative pixel positions.
1049
1050 If this is done during an update, updated_window will contain the
1051 window that is being updated and the position is the future output
1052 cursor position for that window. If updated_window is null, use
1053 selected_window and display the cursor at the given position. */
1054
1055static void
1056XTcursor_to (vpos, hpos, y, x)
1057 int vpos, hpos, y, x;
1058{
1059 struct window *w;
1060
1061 /* If updated_window is not set, work on selected_window. */
1062 if (updated_window)
1063 w = updated_window;
1064 else
1065 w = XWINDOW (selected_window);
dbcb258a 1066
06a2c219
GM
1067 /* Set the output cursor. */
1068 output_cursor.hpos = hpos;
1069 output_cursor.vpos = vpos;
1070 output_cursor.x = x;
1071 output_cursor.y = y;
dc6f92b8 1072
06a2c219
GM
1073 /* If not called as part of an update, really display the cursor.
1074 This will also set the cursor position of W. */
1075 if (updated_window == NULL)
dc6f92b8
JB
1076 {
1077 BLOCK_INPUT;
06a2c219 1078 x_display_cursor (w, 1, hpos, vpos, x, y);
334208b7 1079 XFlush (FRAME_X_DISPLAY (selected_frame));
dc6f92b8
JB
1080 UNBLOCK_INPUT;
1081 }
1082}
dc43ef94 1083
06a2c219
GM
1084
1085\f
1086/***********************************************************************
1087 Display Iterator
1088 ***********************************************************************/
1089
1090/* Function prototypes of this page. */
1091
1092static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1093 struct glyph *,
1094 XChar2b *));
1095static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1096 int, XChar2b *, int));
1097static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1098static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1099static void x_append_glyph P_ ((struct it *));
1100static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1101 int, int, double));
1102static void x_produce_glyphs P_ ((struct it *));
1103static void x_produce_special_glyphs P_ ((struct it *, enum display_element_type));
1104static void x_produce_image_glyph P_ ((struct it *it));
1105
1106
1107/* Return a pointer to per-char metric information in FONT of a
1108 character pointed by B which is a pointer to an XChar2b. */
dc43ef94
KH
1109
1110#define PER_CHAR_METRIC(font, b) \
1111 ((font)->per_char \
1112 ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
1113 + (((font)->min_byte1 || (font)->max_byte1) \
1114 ? (((b)->byte1 - (font)->min_byte1) \
1115 * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
1116 : 0)) \
1117 : &((font)->max_bounds))
1118
dc6f92b8 1119
06a2c219
GM
1120/* Get metrics of character CHAR2B in FONT. Value is always non-null.
1121 If CHAR2B is not contained in FONT, the font's default character
1122 metric is returned. */
dc43ef94 1123
06a2c219
GM
1124static INLINE XCharStruct *
1125x_per_char_metric (font, char2b)
1126 XFontStruct *font;
1127 XChar2b *char2b;
1128{
1129 /* The result metric information. */
1130 XCharStruct *pcm = NULL;
dc6f92b8 1131
06a2c219 1132 xassert (font && char2b);
dc6f92b8 1133
06a2c219 1134 if (font->per_char != NULL)
dc6f92b8 1135 {
06a2c219 1136 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1137 {
06a2c219
GM
1138 /* min_char_or_byte2 specifies the linear character index
1139 corresponding to the first element of the per_char array,
1140 max_char_or_byte2 is the index of the last character. A
1141 character with non-zero CHAR2B->byte1 is not in the font.
1142 A character with byte2 less than min_char_or_byte2 or
1143 greater max_char_or_byte2 is not in the font. */
1144 if (char2b->byte1 == 0
1145 && char2b->byte2 >= font->min_char_or_byte2
1146 && char2b->byte2 <= font->max_char_or_byte2)
1147 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1148 }
06a2c219 1149 else
dc6f92b8 1150 {
06a2c219
GM
1151 /* If either min_byte1 or max_byte1 are nonzero, both
1152 min_char_or_byte2 and max_char_or_byte2 are less than
1153 256, and the 2-byte character index values corresponding
1154 to the per_char array element N (counting from 0) are:
1155
1156 byte1 = N/D + min_byte1
1157 byte2 = N\D + min_char_or_byte2
1158
1159 where:
1160
1161 D = max_char_or_byte2 - min_char_or_byte2 + 1
1162 / = integer division
1163 \ = integer modulus */
1164 if (char2b->byte1 >= font->min_byte1
1165 && char2b->byte1 <= font->max_byte1
1166 && char2b->byte2 >= font->min_char_or_byte2
1167 && char2b->byte2 <= font->max_char_or_byte2)
1168 {
1169 pcm = (font->per_char
1170 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1171 * (char2b->byte1 - font->min_byte1))
1172 + (char2b->byte2 - font->min_char_or_byte2));
1173 }
dc6f92b8 1174 }
06a2c219
GM
1175 }
1176 else
1177 {
1178 /* If the per_char pointer is null, all glyphs between the first
1179 and last character indexes inclusive have the same
1180 information, as given by both min_bounds and max_bounds. */
1181 if (char2b->byte2 >= font->min_char_or_byte2
1182 && char2b->byte2 <= font->max_char_or_byte2)
1183 pcm = &font->max_bounds;
1184 }
dc6f92b8 1185
4a4dc352 1186
06a2c219
GM
1187 if (pcm == NULL || pcm->width == 0)
1188 {
1189 /* Character not contained in the font. FONT->default_char
1190 gives the character that will be printed. FONT->default_char
1191 is a 16-bit character code with byte1 in the most significant
1192 byte and byte2 in the least significant byte. */
1193 XChar2b default_char;
1194 default_char.byte1 = (font->default_char >> BITS_PER_CHAR) & 0xff;
1195 default_char.byte2 = font->default_char & 0xff;
1196
1197 /* Avoid an endless recursion if FONT->default_char itself
1198 hasn't per char metrics. handa@etl.go.jp reports that some
1199 fonts have this problem. */
1200 if (default_char.byte1 != char2b->byte1
1201 || default_char.byte2 != char2b->byte2)
1202 pcm = x_per_char_metric (font, &default_char);
1203 else
1204 pcm = &font->max_bounds;
1205 }
1206
1207 return pcm;
1208}
b73b6aaf 1209
57b03282 1210
06a2c219
GM
1211/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1212 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1213
06a2c219
GM
1214static INLINE void
1215x_encode_char (c, char2b, font_info)
1216 int c;
1217 XChar2b *char2b;
1218 struct font_info *font_info;
1219{
1220 int charset = CHAR_CHARSET (c);
1221 XFontStruct *font = font_info->font;
1222
1223 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1224 This may be either a program in a special encoder language or a
1225 fixed encoding. */
1226 if (font_info->font_encoder)
1227 {
1228 /* It's a program. */
1229 struct ccl_program *ccl = font_info->font_encoder;
1230
1231 if (CHARSET_DIMENSION (charset) == 1)
1232 {
1233 ccl->reg[0] = charset;
1234 ccl->reg[1] = char2b->byte2;
1235 }
1236 else
1237 {
1238 ccl->reg[0] = charset;
1239 ccl->reg[1] = char2b->byte1;
1240 ccl->reg[2] = char2b->byte2;
1241 }
1242
1243 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1244
1245 /* We assume that MSBs are appropriately set/reset by CCL
1246 program. */
1247 if (font->max_byte1 == 0) /* 1-byte font */
1248 char2b->byte2 = ccl->reg[1];
1249 else
1250 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1251 }
1252 else if (font_info->encoding[charset])
1253 {
1254 /* Fixed encoding scheme. See fontset.h for the meaning of the
1255 encoding numbers. */
1256 int enc = font_info->encoding[charset];
1257
1258 if ((enc == 1 || enc == 2)
1259 && CHARSET_DIMENSION (charset) == 2)
1260 char2b->byte1 |= 0x80;
1261
1262 if (enc == 1 || enc == 3)
1263 char2b->byte2 |= 0x80;
1264 }
1265}
1266
1267
1268/* Get face and two-byte form of character C in face FACE_ID on frame
1269 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1270 means we want to display multibyte text. Value is a pointer to a
1271 realized face that is ready for display. */
1272
1273static INLINE struct face *
1274x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1275 struct frame *f;
1276 int c, face_id;
1277 XChar2b *char2b;
1278 int multibyte_p;
1279{
1280 struct face *face = FACE_FROM_ID (f, face_id);
1281
1282 if (!multibyte_p)
1283 {
1284 /* Unibyte case. We don't have to encode, but we have to make
1285 sure to use a face suitable for unibyte. */
1286 char2b->byte1 = 0;
1287 char2b->byte2 = c;
1288
1289 if (!FACE_SUITABLE_FOR_CHARSET_P (face, -1))
1290 {
1291 face_id = FACE_FOR_CHARSET (f, face_id, -1);
1292 face = FACE_FROM_ID (f, face_id);
1293 }
1294 }
1295 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1296 {
1297 /* Case of ASCII in a face known to fit ASCII. */
1298 char2b->byte1 = 0;
1299 char2b->byte2 = c;
1300 }
1301 else
1302 {
1303 int c1, c2, charset;
1304
1305 /* Split characters into bytes. If c2 is -1 afterwards, C is
1306 really a one-byte character so that byte1 is zero. */
1307 SPLIT_CHAR (c, charset, c1, c2);
1308 if (c2 > 0)
1309 char2b->byte1 = c1, char2b->byte2 = c2;
1310 else
1311 char2b->byte1 = 0, char2b->byte2 = c1;
1312
1313 /* Get the face for displaying C. If `face' is not suitable for
1314 charset, get the one that fits. (This can happen for the
1315 translations of composite characters where the glyph
1316 specifies a face for ASCII, but translations have a different
1317 charset.) */
1318 if (!FACE_SUITABLE_FOR_CHARSET_P (face, charset))
1319 {
1320 face_id = FACE_FOR_CHARSET (f, face_id, charset);
1321 face = FACE_FROM_ID (f, face_id);
1322 }
1323
1324 /* Maybe encode the character in *CHAR2B. */
1325 if (charset != CHARSET_ASCII)
1326 {
1327 struct font_info *font_info
1328 = FONT_INFO_FROM_ID (f, face->font_info_id);
1329 if (font_info)
1330 {
1331 x_encode_char (c, char2b, font_info);
1332 if (charset == charset_latin_iso8859_1)
1333 {
1334 xassert (((XFontStruct *) font_info->font)->max_char_or_byte2
1335 >= 0x80);
1336 char2b->byte2 |= 0x80;
1337 }
1338 }
1339 }
1340 }
1341
1342 /* Make sure X resources of the face are allocated. */
1343 xassert (face != NULL);
1344 PREPARE_FACE_FOR_DISPLAY (f, face);
1345
1346 return face;
1347}
1348
1349
1350/* Get face and two-byte form of character glyph GLYPH on frame F.
1351 The encoding of GLYPH->u.ch.code is returned in *CHAR2B. Value is
1352 a pointer to a realized face that is ready for display. */
1353
1354static INLINE struct face *
1355x_get_glyph_face_and_encoding (f, glyph, char2b)
1356 struct frame *f;
1357 struct glyph *glyph;
1358 XChar2b *char2b;
1359{
1360 struct face *face;
1361
1362 xassert (glyph->type == CHAR_GLYPH);
1363 face = FACE_FROM_ID (f, glyph->u.ch.face_id);
1364
1365 if (!glyph->multibyte_p)
1366 {
1367 /* Unibyte case. We don't have to encode, but we have to make
1368 sure to use a face suitable for unibyte. */
1369 char2b->byte1 = 0;
1370 char2b->byte2 = glyph->u.ch.code;
1371 }
1372 else if (glyph->u.ch.code < 128
1373 && glyph->u.ch.face_id < BASIC_FACE_ID_SENTINEL)
1374 {
1375 /* Case of ASCII in a face known to fit ASCII. */
1376 char2b->byte1 = 0;
1377 char2b->byte2 = glyph->u.ch.code;
1378 }
1379 else
1380 {
1381 int c1, c2, charset;
1382
1383 /* Split characters into bytes. If c2 is -1 afterwards, C is
1384 really a one-byte character so that byte1 is zero. */
1385 SPLIT_CHAR (glyph->u.ch.code, charset, c1, c2);
1386 if (c2 > 0)
1387 char2b->byte1 = c1, char2b->byte2 = c2;
1388 else
1389 char2b->byte1 = 0, char2b->byte2 = c1;
1390
1391 /* Maybe encode the character in *CHAR2B. */
1392 if (charset != CHARSET_ASCII)
1393 {
1394 struct font_info *font_info
1395 = FONT_INFO_FROM_ID (f, face->font_info_id);
1396 if (font_info)
1397 {
1398 x_encode_char (glyph->u.ch.code, char2b, font_info);
1399 if (charset == charset_latin_iso8859_1)
1400 char2b->byte2 |= 0x80;
1401 }
1402 }
1403 }
1404
1405 /* Make sure X resources of the face are allocated. */
1406 xassert (face != NULL);
1407 PREPARE_FACE_FOR_DISPLAY (f, face);
1408 return face;
1409}
1410
1411
1412/* Store one glyph for IT->char_to_display in IT->glyph_row.
1413 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1414
1415static INLINE void
1416x_append_glyph (it)
1417 struct it *it;
1418{
1419 struct glyph *glyph;
1420 enum glyph_row_area area = it->area;
1421
1422 xassert (it->glyph_row);
1423 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1424
1425 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1426 if (glyph < it->glyph_row->glyphs[area + 1])
1427 {
1428 /* Play it safe. If sub-structures of the glyph are not all the
1429 same size, it otherwise be that some bits stay set. This
1430 would prevent a comparison with GLYPH_EQUAL_P. */
1431 glyph->u.val = 0;
1432
1433 glyph->type = CHAR_GLYPH;
1434 glyph->pixel_width = it->pixel_width;
1435 glyph->u.ch.code = it->char_to_display;
1436 glyph->u.ch.face_id = it->face_id;
1437 glyph->charpos = CHARPOS (it->position);
1438 glyph->object = it->object;
1439 glyph->left_box_line_p = it->start_of_box_run_p;
1440 glyph->right_box_line_p = it->end_of_box_run_p;
1441 glyph->voffset = it->voffset;
1442 glyph->multibyte_p = it->multibyte_p;
1443 ++it->glyph_row->used[area];
1444 }
1445}
1446
1447
1448/* Change IT->ascent and IT->height according to the setting of
1449 IT->voffset. */
1450
1451static INLINE void
1452take_vertical_position_into_account (it)
1453 struct it *it;
1454{
1455 if (it->voffset)
1456 {
1457 if (it->voffset < 0)
1458 /* Increase the ascent so that we can display the text higher
1459 in the line. */
1460 it->ascent += abs (it->voffset);
1461 else
1462 /* Increase the descent so that we can display the text lower
1463 in the line. */
1464 it->descent += it->voffset;
1465 }
1466}
1467
1468
1469/* Produce glyphs/get display metrics for the image IT is loaded with.
1470 See the description of struct display_iterator in dispextern.h for
1471 an overview of struct display_iterator. */
1472
1473static void
1474x_produce_image_glyph (it)
1475 struct it *it;
1476{
1477 struct image *img;
1478 struct face *face;
1479
1480 xassert (it->what == IT_IMAGE);
1481
1482 face = FACE_FROM_ID (it->f, it->face_id);
1483 img = IMAGE_FROM_ID (it->f, it->image_id);
1484 xassert (img);
1485
1486 /* Make sure X resources of the face and image are loaded. */
1487 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1488 prepare_image_for_display (it->f, img);
1489
1490 it->ascent = IMAGE_ASCENT (img);
1491 it->descent = img->height + 2 * img->margin - it->ascent;
1492 it->pixel_width = img->width + 2 * img->margin;
1493
1494 it->nglyphs = 1;
1495
1496 if (face->box != FACE_NO_BOX)
1497 {
1498 it->ascent += face->box_line_width;
1499 it->descent += face->box_line_width;
1500
1501 if (it->start_of_box_run_p)
1502 it->pixel_width += face->box_line_width;
1503 if (it->end_of_box_run_p)
1504 it->pixel_width += face->box_line_width;
1505 }
1506
1507 take_vertical_position_into_account (it);
1508
1509 if (it->glyph_row)
1510 {
1511 struct glyph *glyph;
1512 enum glyph_row_area area = it->area;
1513
1514 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1515 if (glyph < it->glyph_row->glyphs[area + 1])
1516 {
1517 glyph->type = IMAGE_GLYPH;
1518 glyph->u.img.id = img->id;
1519 glyph->u.img.face_id = it->face_id;
1520 glyph->pixel_width = it->pixel_width;
1521 glyph->charpos = CHARPOS (it->position);
1522 glyph->object = it->object;
1523 glyph->left_box_line_p = it->start_of_box_run_p;
1524 glyph->right_box_line_p = it->end_of_box_run_p;
1525 glyph->voffset = it->voffset;
1526 glyph->multibyte_p = it->multibyte_p;
1527 ++it->glyph_row->used[area];
1528 }
1529 }
1530}
1531
1532
1533/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1534 of the glyph, WIDTH and HEIGHT are the width and height of the
1535 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1536 ascent of the glyph (0 <= ASCENT <= 1). */
1537
1538static void
1539x_append_stretch_glyph (it, object, width, height, ascent)
1540 struct it *it;
1541 Lisp_Object object;
1542 int width, height;
1543 double ascent;
1544{
1545 struct glyph *glyph;
1546 enum glyph_row_area area = it->area;
1547
1548 xassert (ascent >= 0 && ascent <= 1);
1549
1550 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1551 if (glyph < it->glyph_row->glyphs[area + 1])
1552 {
1553 glyph->type = STRETCH_GLYPH;
1554 glyph->u.stretch.ascent = height * ascent;
1555 glyph->u.stretch.height = height;
1556 glyph->u.stretch.face_id = it->face_id;
1557 glyph->pixel_width = width;
1558 glyph->charpos = CHARPOS (it->position);
1559 glyph->object = object;
1560 glyph->left_box_line_p = it->start_of_box_run_p;
1561 glyph->right_box_line_p = it->end_of_box_run_p;
1562 glyph->voffset = it->voffset;
1563 glyph->multibyte_p = it->multibyte_p;
1564 ++it->glyph_row->used[area];
1565 }
1566}
1567
1568
1569/* Produce a stretch glyph for iterator IT. IT->object is the value
1570 of the glyph property displayed. The value must be a list
1571 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1572 being recognized:
1573
1574 1. `:width WIDTH' specifies that the space should be WIDTH *
1575 canonical char width wide. WIDTH may be an integer or floating
1576 point number.
1577
1578 2. `:relative-width FACTOR' specifies that the width of the stretch
1579 should be computed from the width of the first character having the
1580 `glyph' property, and should be FACTOR times that width.
1581
1582 3. `:align-to HPOS' specifies that the space should be wide enough
1583 to reach HPOS, a value in canonical character units.
1584
1585 Exactly one of the above pairs must be present.
1586
1587 4. `:height HEIGHT' specifies that the height of the stretch produced
1588 should be HEIGHT, measured in canonical character units.
1589
1590 5. `:relative-height FACTOR' specifies that the height of the the
1591 stretch should be FACTOR times the height of the characters having
1592 the glyph property.
1593
1594 Either none or exactly one of 4 or 5 must be present.
1595
1596 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1597 of the stretch should be used for the ascent of the stretch.
1598 ASCENT must be in the range 0 <= ASCENT <= 100. */
1599
1600#define NUMVAL(X) \
1601 ((INTEGERP (X) || FLOATP (X)) \
1602 ? XFLOATINT (X) \
1603 : - 1)
1604
1605
1606static void
1607x_produce_stretch_glyph (it)
1608 struct it *it;
1609{
1610 /* (space :width WIDTH :height HEIGHT. */
1611 extern Lisp_Object QCwidth, QCheight, QCascent, Qspace;
1612 extern Lisp_Object QCrelative_width, QCrelative_height;
1613 extern Lisp_Object QCalign_to;
1614 Lisp_Object prop, plist;
1615 double width = 0, height = 0, ascent = 0;
1616 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1617 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1618
1619 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1620
1621 /* List should start with `space'. */
1622 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1623 plist = XCDR (it->object);
1624
1625 /* Compute the width of the stretch. */
1626 if (prop = Fplist_get (plist, QCwidth),
1627 NUMVAL (prop) > 0)
1628 /* Absolute width `:width WIDTH' specified and valid. */
1629 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1630 else if (prop = Fplist_get (plist, QCrelative_width),
1631 NUMVAL (prop) > 0)
1632 {
1633 /* Relative width `:relative-width FACTOR' specified and valid.
1634 Compute the width of the characters having the `glyph'
1635 property. */
1636 struct it it2;
1637 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1638
1639 it2 = *it;
1640 if (it->multibyte_p)
1641 {
1642 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1643 - IT_BYTEPOS (*it));
1644 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1645 }
1646 else
1647 it2.c = *p, it2.len = 1;
1648
1649 it2.glyph_row = NULL;
1650 it2.what = IT_CHARACTER;
1651 x_produce_glyphs (&it2);
1652 width = NUMVAL (prop) * it2.pixel_width;
1653 }
1654 else if (prop = Fplist_get (plist, QCalign_to),
1655 NUMVAL (prop) > 0)
1656 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1657 else
1658 /* Nothing specified -> width defaults to canonical char width. */
1659 width = CANON_X_UNIT (it->f);
1660
1661 /* Compute height. */
1662 if (prop = Fplist_get (plist, QCheight),
1663 NUMVAL (prop) > 0)
1664 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1665 else if (prop = Fplist_get (plist, QCrelative_height),
1666 NUMVAL (prop) > 0)
1667 height = FONT_HEIGHT (font) * NUMVAL (prop);
1668 else
1669 height = FONT_HEIGHT (font);
1670
1671 /* Compute percentage of height used for ascent. If
1672 `:ascent ASCENT' is present and valid, use that. Otherwise,
1673 derive the ascent from the font in use. */
1674 if (prop = Fplist_get (plist, QCascent),
1675 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1676 ascent = NUMVAL (prop) / 100.0;
1677 else
1678 ascent = (double) font->ascent / FONT_HEIGHT (font);
1679
1680 if (width <= 0)
1681 width = 1;
1682 if (height <= 0)
1683 height = 1;
1684
1685 if (it->glyph_row)
1686 {
1687 Lisp_Object object = it->stack[it->sp - 1].string;
1688 if (!STRINGP (object))
1689 object = it->w->buffer;
1690 x_append_stretch_glyph (it, object, width, height, ascent);
1691 }
1692
1693 it->pixel_width = width;
1694 it->ascent = height * ascent;
1695 it->descent = height - it->ascent;
1696 it->nglyphs = 1;
1697
1698 if (face->box != FACE_NO_BOX)
1699 {
1700 it->ascent += face->box_line_width;
1701 it->descent += face->box_line_width;
1702
1703 if (it->start_of_box_run_p)
1704 it->pixel_width += face->box_line_width;
1705 if (it->end_of_box_run_p)
1706 it->pixel_width += face->box_line_width;
1707 }
1708
1709 take_vertical_position_into_account (it);
1710}
1711
1712
1713/* Produce glyphs/get display metrics for the display element IT is
1714 loaded with. See the description of struct display_iterator in
1715 dispextern.h for an overview of struct display_iterator. */
1716
1717static void
1718x_produce_glyphs (it)
1719 struct it *it;
1720{
1721 if (it->what == IT_CHARACTER)
1722 {
1723 XChar2b char2b;
1724 XFontStruct *font;
1725 struct face *face;
1726 XCharStruct *pcm;
1727 struct it ci;
1728 int font_not_found_p;
1729 int c;
1730
1731 /* Maybe translate single-byte characters to multibyte. */
1732 it->char_to_display = it->c;
1733 if (unibyte_display_via_language_environment
1734 && SINGLE_BYTE_CHAR_P (it->c)
1735 && (it->c >= 0240
1736 || (it->c >= 0200
1737 && !NILP (Vnonascii_translation_table))))
1738 {
1739 it->char_to_display = unibyte_char_to_multibyte (it->c);
1740 it->charset = CHAR_CHARSET (it->char_to_display);
1741 }
1742
1743 /* Get face and font to use. Encode IT->char_to_display. */
1744 face = x_get_char_face_and_encoding (it->f, it->char_to_display,
1745 it->face_id, &char2b,
1746 it->multibyte_p);
1747 font = face->font;
1748
1749 /* When no suitable font found, use the default font. */
1750 font_not_found_p = font == NULL;
1751 if (font_not_found_p)
1752 font = FRAME_FONT (it->f);
1753
1754 if (it->char_to_display >= ' '
1755 && (!it->multibyte_p || it->char_to_display < 128))
1756 {
1757 /* Either unibyte or ASCII. */
1758 int stretched_p;
1759
1760 it->nglyphs = 1;
1761 it->ascent = font->ascent;
1762 it->descent = font->descent;
1763
1764 pcm = x_per_char_metric (font, &char2b);
1765 it->pixel_width = pcm->width;
1766
1767 /* If this is a space inside a region of text with
1768 `space-width' property, change its width. */
1769 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1770 if (stretched_p)
1771 it->pixel_width *= XFLOATINT (it->space_width);
1772
1773 /* If face has a box, add the box thickness to the character
1774 height. If character has a box line to the left and/or
1775 right, add the box line width to the character's width. */
1776 if (face->box != FACE_NO_BOX)
1777 {
1778 int thick = face->box_line_width;
1779
1780 it->ascent += thick;
1781 it->descent += thick;
1782
1783 if (it->start_of_box_run_p)
1784 it->pixel_width += thick;
1785 if (it->end_of_box_run_p)
1786 it->pixel_width += thick;
1787 }
1788
1789 /* If face has an overline, add the height of the overline
1790 (1 pixel) and a 1 pixel margin to the character height. */
1791 if (face->overline_p)
1792 it->ascent += 2;
1793
1794 take_vertical_position_into_account (it);
1795
1796 /* If we have to actually produce glyphs, do it. */
1797 if (it->glyph_row)
1798 {
1799 if (stretched_p)
1800 {
1801 /* Translate a space with a `space-width' property
1802 into a stretch glyph. */
1803 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1804 x_append_stretch_glyph (it, it->object, it->pixel_width,
1805 it->ascent + it->descent, ascent);
1806 }
1807 else
1808 x_append_glyph (it);
1809
1810 /* If characters with lbearing or rbearing are displayed
1811 in this line, record that fact in a flag of the
1812 glyph row. This is used to optimize X output code. */
1813 if (pcm->lbearing < 0
1814 || pcm->rbearing > pcm->width)
1815 it->glyph_row->contains_overlapping_glyphs_p = 1;
1816 }
1817 }
1818 else if (it->char_to_display == '\n')
1819 {
1820 /* A newline has no width but we need the height of the line. */
1821 it->pixel_width = 0;
1822 it->nglyphs = 0;
1823 it->ascent = font->ascent;
1824 it->descent = font->descent;
1825
1826 if (face->box != FACE_NO_BOX)
1827 {
1828 int thick = face->box_line_width;
1829 it->ascent += thick;
1830 it->descent += thick;
1831 }
1832 }
1833 else if (it->char_to_display == '\t')
1834 {
1835 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
1836 int x = (it->current_x
1837 - it->prompt_width
1838 + it->continuation_lines_width);
1839 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
1840
1841 it->pixel_width = next_tab_x - x;
1842 it->nglyphs = 1;
1843 it->ascent = font->ascent;
1844 it->descent = font->descent;
1845
1846 if (it->glyph_row)
1847 {
1848 double ascent = (double) it->ascent / (it->ascent + it->descent);
1849 x_append_stretch_glyph (it, it->object, it->pixel_width,
1850 it->ascent + it->descent, ascent);
1851 }
1852 }
1853 else
1854 {
1855 /* A multi-byte character. Assume that the display width of the
1856 character is the width of the character multiplied by the
1857 width of the font. There has to be better support for
1858 variable sizes in cmpchar_info to do anything better than
1859 that.
1860
1861 Note: composite characters are represented as one glyph in
1862 the glyph matrix. There are no padding glyphs. */
1863 if (it->charset == CHARSET_COMPOSITION)
1864 {
1865 struct cmpchar_info *cmpcharp;
1866 int idx;
1867
1868 idx = COMPOSITE_CHAR_ID (it->char_to_display);
1869 cmpcharp = cmpchar_table[idx];
1870 it->pixel_width = font->max_bounds.width * cmpcharp->width;
1871
1872 /* There are no padding glyphs, so there is only one glyph
1873 to produce for the composite char. Important is that
1874 pixel_width, ascent and descent are the values of what is
1875 drawn by draw_glyphs. */
1876 it->nglyphs = 1;
1877
1878 /* These settings may not be correct. We must have more
1879 information in cmpcharp to do the correct setting. */
1880 it->ascent = font->ascent;
1881 it->descent = font->descent;
1882 }
1883 else
1884 {
1885 /* If we found a font, this font should give us the right
1886 metrics. If we didn't find a font, use the frame's
1887 default font and calculate the width of the character
1888 from the charset width; this is what old redisplay code
1889 did. */
1890 pcm = x_per_char_metric (font, &char2b);
1891 it->pixel_width = pcm->width;
1892 if (font_not_found_p)
1893 it->pixel_width *= CHARSET_WIDTH (it->charset);
1894 it->nglyphs = 1;
1895 it->ascent = font->ascent;
1896 it->descent = font->descent;
1897 if (it->glyph_row
1898 && (pcm->lbearing < 0
1899 || pcm->rbearing > pcm->width))
1900 it->glyph_row->contains_overlapping_glyphs_p = 1;
1901 }
1902
1903 if (face->box != FACE_NO_BOX)
1904 {
1905 int thick = face->box_line_width;
1906 it->ascent += thick;
1907 it->descent += thick;
1908
1909 if (it->start_of_box_run_p)
1910 it->pixel_width += thick;
1911 if (it->end_of_box_run_p)
1912 it->pixel_width += thick;
1913 }
1914
1915 /* If face has an overline, add the height of the overline
1916 (1 pixel) and a 1 pixel margin to the character height. */
1917 if (face->overline_p)
1918 it->ascent += 2;
1919
1920 take_vertical_position_into_account (it);
1921
1922 if (it->glyph_row)
1923 x_append_glyph (it);
1924 }
1925 }
1926 else if (it->what == IT_IMAGE)
1927 x_produce_image_glyph (it);
1928 else if (it->what == IT_STRETCH)
1929 x_produce_stretch_glyph (it);
1930
1931 /* Accumulate dimensions. */
1932 xassert (it->ascent >= 0 && it->descent > 0);
1933 if (it->area == TEXT_AREA)
1934 it->current_x += it->pixel_width;
1935 it->max_ascent = max (it->max_ascent, it->ascent);
1936 it->max_descent = max (it->max_descent, it->descent);
1937}
1938
1939
1940/* Estimate the pixel height of the mode or top line on frame F.
1941 FACE_ID specifies what line's height to estimate. */
1942
1943int
1944x_estimate_mode_line_height (f, face_id)
1945 struct frame *f;
1946 enum face_id face_id;
1947{
1948 int height = 1;
1949
1950 /* This function is called so early when Emacs starts that the face
1951 cache and mode line face are not yet initialized. */
1952 if (FRAME_FACE_CACHE (f))
1953 {
1954 struct face *face = FACE_FROM_ID (f, face_id);
1955 if (face)
1956 height = FONT_HEIGHT (face->font) + 2 * face->box_line_width;
1957 }
1958
1959 return height;
1960}
1961
1962\f
1963/***********************************************************************
1964 Glyph display
1965 ***********************************************************************/
1966
1967/* A sequence of glyphs to be drawn in the same face.
1968
1969 This data structure is not really completely X specific, so it
1970 could possibly, at least partially, be useful for other systems. It
1971 is currently not part of the external redisplay interface because
1972 it's not clear what other systems will need. */
1973
1974struct glyph_string
1975{
1976 /* X-origin of the string. */
1977 int x;
1978
1979 /* Y-origin and y-position of the base line of this string. */
1980 int y, ybase;
1981
1982 /* The width of the string, not including a face extension. */
1983 int width;
1984
1985 /* The width of the string, including a face extension. */
1986 int background_width;
1987
1988 /* The height of this string. This is the height of the line this
1989 string is drawn in, and can be different from the height of the
1990 font the string is drawn in. */
1991 int height;
1992
1993 /* Number of pixels this string overwrites in front of its x-origin.
1994 This number is zero if the string has an lbearing >= 0; it is
1995 -lbearing, if the string has an lbearing < 0. */
1996 int left_overhang;
1997
1998 /* Number of pixels this string overwrites past its right-most
1999 nominal x-position, i.e. x + width. Zero if the string's
2000 rbearing is <= its nominal width, rbearing - width otherwise. */
2001 int right_overhang;
2002
2003 /* The frame on which the glyph string is drawn. */
2004 struct frame *f;
2005
2006 /* The window on which the glyph string is drawn. */
2007 struct window *w;
2008
2009 /* X display and window for convenience. */
2010 Display *display;
2011 Window window;
2012
2013 /* The glyph row for which this string was built. It determines the
2014 y-origin and height of the string. */
2015 struct glyph_row *row;
2016
2017 /* The area within row. */
2018 enum glyph_row_area area;
2019
2020 /* Characters to be drawn, and number of characters. */
2021 XChar2b *char2b;
2022 int nchars;
2023
2024 /* Character set of this glyph string. */
2025 int charset;
2026
2027 /* A face-override for drawing cursors, mouse face and similar. */
2028 enum draw_glyphs_face hl;
2029
2030 /* Face in which this string is to be drawn. */
2031 struct face *face;
2032
2033 /* Font in which this string is to be drawn. */
2034 XFontStruct *font;
2035
2036 /* Font info for this string. */
2037 struct font_info *font_info;
2038
2039 /* Non-null means this string describes (part of) a composite
2040 character. All characters from char2b are drawn at the same
2041 x-origin in that case. */
2042 struct cmpchar_info *cmpcharp;
2043
2044 /* Index of this glyph string's first character in the glyph
2045 definition of cmpcharp. If this is zero, this glyph string
2046 describes the first character of a composite character. */
2047 int gidx;
2048
2049 /* 1 means this glyph strings face has to be drawn to the right end
2050 of the window's drawing area. */
2051 unsigned extends_to_end_of_line_p : 1;
2052
2053 /* 1 means the background of this string has been drawn. */
2054 unsigned background_filled_p : 1;
2055
2056 /* 1 means glyph string must be drawn with 16-bit functions. */
2057 unsigned two_byte_p : 1;
2058
2059 /* 1 means that the original font determined for drawing this glyph
2060 string could not be loaded. The member `font' has been set to
2061 the frame's default font in this case. */
2062 unsigned font_not_found_p : 1;
2063
2064 /* 1 means that the face in which this glyph string is drawn has a
2065 stipple pattern. */
2066 unsigned stippled_p : 1;
2067
2068 /* The GC to use for drawing this glyph string. */
2069 GC gc;
2070
2071 /* A pointer to the first glyph in the string. This glyph
2072 corresponds to char2b[0]. Needed to draw rectangles if
2073 font_not_found_p is 1. */
2074 struct glyph *first_glyph;
2075
2076 /* Image, if any. */
2077 struct image *img;
2078
2079 struct glyph_string *next, *prev;
2080};
2081
2082
2083#if GLYPH_DEBUG
2084
2085static void
2086x_dump_glyph_string (s)
2087 struct glyph_string *s;
2088{
2089 fprintf (stderr, "glyph string\n");
2090 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2091 s->x, s->y, s->width, s->height);
2092 fprintf (stderr, " ybase = %d\n", s->ybase);
2093 fprintf (stderr, " hl = %d\n", s->hl);
2094 fprintf (stderr, " left overhang = %d, right = %d\n",
2095 s->left_overhang, s->right_overhang);
2096 fprintf (stderr, " nchars = %d\n", s->nchars);
2097 fprintf (stderr, " extends to end of line = %d\n",
2098 s->extends_to_end_of_line_p);
2099 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2100 fprintf (stderr, " bg width = %d\n", s->background_width);
2101}
2102
2103#endif /* GLYPH_DEBUG */
2104
2105
2106
2107static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2108 struct glyph_string **,
2109 struct glyph_string *,
2110 struct glyph_string *));
2111static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2112 struct glyph_string **,
2113 struct glyph_string *,
2114 struct glyph_string *));
2115static void x_append_glyph_string P_ ((struct glyph_string **,
2116 struct glyph_string **,
2117 struct glyph_string *));
2118static int x_left_overwritten P_ ((struct glyph_string *));
2119static int x_left_overwriting P_ ((struct glyph_string *));
2120static int x_right_overwritten P_ ((struct glyph_string *));
2121static int x_right_overwriting P_ ((struct glyph_string *));
2122static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int));
2123static void x_init_glyph_string P_ ((struct glyph_string *,
2124 XChar2b *, struct window *,
2125 struct glyph_row *,
2126 enum glyph_row_area, int,
2127 enum draw_glyphs_face));
2128static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2129 enum glyph_row_area, int, int,
2130 enum draw_glyphs_face, int *, int *));
2131static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2132static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2133static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2134 int));
2135static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
2136static void x_draw_glyph_string_underline P_ ((struct glyph_string *));
2137static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2138static void x_draw_glyph_string P_ ((struct glyph_string *));
2139static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2140static void x_set_cursor_gc P_ ((struct glyph_string *));
2141static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2142static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2143static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2144 int *, int *));
2145static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2146static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
2147 unsigned long *, float, int));
2148static void x_setup_relief_color P_ ((struct frame *, struct relief *,
2149 float, int, unsigned long));
2150static void x_setup_relief_colors P_ ((struct glyph_string *));
2151static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2152static void x_draw_image_relief P_ ((struct glyph_string *));
2153static void x_draw_image_foreground P_ ((struct glyph_string *));
2154static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2155static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2156static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2157 int, int, int));
2158static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2159 int, int, int, int, XRectangle *));
2160static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2161 int, int, int, XRectangle *));
2162
2163
2164
2165/* Append the list of glyph strings with head H and tail T to the list
2166 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2167
2168static INLINE void
2169x_append_glyph_string_lists (head, tail, h, t)
2170 struct glyph_string **head, **tail;
2171 struct glyph_string *h, *t;
2172{
2173 if (h)
2174 {
2175 if (*head)
2176 (*tail)->next = h;
2177 else
2178 *head = h;
2179 h->prev = *tail;
2180 *tail = t;
2181 }
2182}
2183
2184
2185/* Prepend the list of glyph strings with head H and tail T to the
2186 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2187 result. */
2188
2189static INLINE void
2190x_prepend_glyph_string_lists (head, tail, h, t)
2191 struct glyph_string **head, **tail;
2192 struct glyph_string *h, *t;
2193{
2194 if (h)
2195 {
2196 if (*head)
2197 (*head)->prev = t;
2198 else
2199 *tail = t;
2200 t->next = *head;
2201 *head = h;
2202 }
2203}
2204
2205
2206/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2207 Set *HEAD and *TAIL to the resulting list. */
2208
2209static INLINE void
2210x_append_glyph_string (head, tail, s)
2211 struct glyph_string **head, **tail;
2212 struct glyph_string *s;
2213{
2214 s->next = s->prev = NULL;
2215 x_append_glyph_string_lists (head, tail, s, s);
2216}
2217
2218
2219/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2220 face. */
2221
2222static void
2223x_set_cursor_gc (s)
2224 struct glyph_string *s;
2225{
2226 if (s->font == FRAME_FONT (s->f)
2227 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2228 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
2229 && !s->cmpcharp)
2230 s->gc = s->f->output_data.x->cursor_gc;
2231 else
2232 {
2233 /* Cursor on non-default face: must merge. */
2234 XGCValues xgcv;
2235 unsigned long mask;
2236
2237 xgcv.background = s->f->output_data.x->cursor_pixel;
2238 xgcv.foreground = s->face->background;
2239
2240 /* If the glyph would be invisible, try a different foreground. */
2241 if (xgcv.foreground == xgcv.background)
2242 xgcv.foreground = s->face->foreground;
2243 if (xgcv.foreground == xgcv.background)
2244 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2245 if (xgcv.foreground == xgcv.background)
2246 xgcv.foreground = s->face->foreground;
2247
2248 /* Make sure the cursor is distinct from text in this face. */
2249 if (xgcv.background == s->face->background
2250 && xgcv.foreground == s->face->foreground)
2251 {
2252 xgcv.background = s->face->foreground;
2253 xgcv.foreground = s->face->background;
2254 }
2255
2256 IF_DEBUG (x_check_font (s->f, s->font));
2257 xgcv.font = s->font->fid;
2258 xgcv.graphics_exposures = False;
2259 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2260
2261 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2262 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2263 mask, &xgcv);
2264 else
2265 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2266 = XCreateGC (s->display, s->window, mask, &xgcv);
2267
2268 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2269 }
2270}
2271
2272
2273/* Set up S->gc of glyph string S for drawing text in mouse face. */
2274
2275static void
2276x_set_mouse_face_gc (s)
2277 struct glyph_string *s;
2278{
2279 int face_id;
2280
2281 /* What face has to be used for the mouse face? */
2282 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
2283 face_id = FACE_FOR_CHARSET (s->f, face_id, s->charset);
2284 s->face = FACE_FROM_ID (s->f, face_id);
2285 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2286
2287 /* If font in this face is same as S->font, use it. */
2288 if (s->font == s->face->font)
2289 s->gc = s->face->gc;
2290 else
2291 {
2292 /* Otherwise construct scratch_cursor_gc with values from FACE
2293 but font FONT. */
2294 XGCValues xgcv;
2295 unsigned long mask;
2296
2297 xgcv.background = s->face->background;
2298 xgcv.foreground = s->face->foreground;
2299 IF_DEBUG (x_check_font (s->f, s->font));
2300 xgcv.font = s->font->fid;
2301 xgcv.graphics_exposures = False;
2302 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2303
2304 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2305 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2306 mask, &xgcv);
2307 else
2308 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2309 = XCreateGC (s->display, s->window, mask, &xgcv);
2310
2311 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2312 }
2313
2314 xassert (s->gc != 0);
2315}
2316
2317
2318/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2319 Faces to use in the mode line have already been computed when the
2320 matrix was built, so there isn't much to do, here. */
2321
2322static INLINE void
2323x_set_mode_line_face_gc (s)
2324 struct glyph_string *s;
2325{
2326 s->gc = s->face->gc;
2327 xassert (s->gc != 0);
2328}
2329
2330
2331/* Set S->gc of glyph string S for drawing that glyph string. Set
2332 S->stippled_p to a non-zero value if the face of S has a stipple
2333 pattern. */
2334
2335static INLINE void
2336x_set_glyph_string_gc (s)
2337 struct glyph_string *s;
2338{
2339 if (s->hl == DRAW_NORMAL_TEXT)
2340 {
2341 s->gc = s->face->gc;
2342 s->stippled_p = s->face->stipple != 0;
2343 }
2344 else if (s->hl == DRAW_INVERSE_VIDEO)
2345 {
2346 x_set_mode_line_face_gc (s);
2347 s->stippled_p = s->face->stipple != 0;
2348 }
2349 else if (s->hl == DRAW_CURSOR)
2350 {
2351 x_set_cursor_gc (s);
2352 s->stippled_p = 0;
2353 }
2354 else if (s->hl == DRAW_MOUSE_FACE)
2355 {
2356 x_set_mouse_face_gc (s);
2357 s->stippled_p = s->face->stipple != 0;
2358 }
2359 else if (s->hl == DRAW_IMAGE_RAISED
2360 || s->hl == DRAW_IMAGE_SUNKEN)
2361 {
2362 s->gc = s->face->gc;
2363 s->stippled_p = s->face->stipple != 0;
2364 }
2365 else
2366 {
2367 s->gc = s->face->gc;
2368 s->stippled_p = s->face->stipple != 0;
2369 }
2370
2371 /* GC must have been set. */
2372 xassert (s->gc != 0);
2373}
2374
2375
2376/* Return in *R the clipping rectangle for glyph string S. */
2377
2378static void
2379x_get_glyph_string_clip_rect (s, r)
2380 struct glyph_string *s;
2381 XRectangle *r;
2382{
2383 if (s->row->full_width_p)
2384 {
2385 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2386 int canon_x = CANON_X_UNIT (s->f);
2387
2388 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2389 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2390
2391 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2392 {
1da3fd71 2393 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2394 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2395 r->x -= width;
2396 }
2397
b9432a85 2398 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2399
06a2c219
GM
2400 /* Unless displaying a mode or menu bar line, which are always
2401 fully visible, clip to the visible part of the row. */
2402 if (s->w->pseudo_window_p)
2403 r->height = s->row->visible_height;
2404 else
2405 r->height = s->height;
2406 }
2407 else
2408 {
2409 /* This is a text line that may be partially visible. */
2410 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2411 r->width = window_box_width (s->w, s->area);
2412 r->height = s->row->visible_height;
2413 }
2414
2415 /* Don't use S->y for clipping because it doesn't take partially
2416 visible lines into account. For example, it can be negative for
2417 partially visible lines at the top of a window. */
2418 if (!s->row->full_width_p
2419 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
2420 r->y = WINDOW_DISPLAY_TOP_LINE_HEIGHT (s->w);
2421 else
2422 r->y = max (0, s->row->y);
2423 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
2424
2425 /* If drawing a toolbar window, draw it over the internal border
2426 at the top of the window. */
2427 if (s->w == XWINDOW (s->f->toolbar_window))
2428 r->y -= s->f->output_data.x->internal_border_width;
2429}
2430
2431
2432/* Set clipping for output of glyph string S. S may be part of a mode
2433 line or menu if we don't have X toolkit support. */
2434
2435static INLINE void
2436x_set_glyph_string_clipping (s)
2437 struct glyph_string *s;
2438{
2439 XRectangle r;
2440 x_get_glyph_string_clip_rect (s, &r);
2441 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2442}
2443
2444
2445/* Compute left and right overhang of glyph string S. If S is a glyph
2446 string for a composite character, assume overhangs don't exist. */
2447
2448static INLINE void
2449x_compute_glyph_string_overhangs (s)
2450 struct glyph_string *s;
2451{
2452 if (s->cmpcharp == NULL
2453 && s->first_glyph->type == CHAR_GLYPH)
2454 {
2455 XCharStruct cs;
2456 int direction, font_ascent, font_descent;
2457 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2458 &font_ascent, &font_descent, &cs);
2459 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2460 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2461 }
2462}
2463
2464
2465/* Compute overhangs and x-positions for glyph string S and its
2466 predecessors, or successors. X is the starting x-position for S.
2467 BACKWARD_P non-zero means process predecessors. */
2468
2469static void
2470x_compute_overhangs_and_x (s, x, backward_p)
2471 struct glyph_string *s;
2472 int x;
2473 int backward_p;
2474{
2475 if (backward_p)
2476 {
2477 while (s)
2478 {
2479 x_compute_glyph_string_overhangs (s);
2480 x -= s->width;
2481 s->x = x;
2482 s = s->prev;
2483 }
2484 }
2485 else
2486 {
2487 while (s)
2488 {
2489 x_compute_glyph_string_overhangs (s);
2490 s->x = x;
2491 x += s->width;
2492 s = s->next;
2493 }
2494 }
2495}
2496
2497
2498/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
2499 frame F. Overhangs of glyphs other than type CHAR_GLYPH or of
2500 character glyphs for composite characters are assumed to be zero. */
2501
2502static void
2503x_get_glyph_overhangs (glyph, f, left, right)
2504 struct glyph *glyph;
2505 struct frame *f;
2506 int *left, *right;
2507{
2508 int c;
2509
2510 *left = *right = 0;
2511
2512 if (glyph->type == CHAR_GLYPH
2513 && (c = glyph->u.ch.code,
2514 CHAR_CHARSET (c) != CHARSET_COMPOSITION))
2515 {
2516 XFontStruct *font;
2517 struct face *face;
2518 struct font_info *font_info;
2519 XChar2b char2b;
2520
2521 face = x_get_glyph_face_and_encoding (f, glyph, &char2b);
2522 font = face->font;
2523 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
2524 if (font)
2525 {
2526 XCharStruct *pcm = x_per_char_metric (font, &char2b);
2527
2528 if (pcm->rbearing > pcm->width)
2529 *right = pcm->rbearing - pcm->width;
2530 if (pcm->lbearing < 0)
2531 *left = -pcm->lbearing;
2532 }
2533 }
2534}
2535
2536
2537/* Return the index of the first glyph preceding glyph string S that
2538 is overwritten by S because of S's left overhang. Value is -1
2539 if no glyphs are overwritten. */
2540
2541static int
2542x_left_overwritten (s)
2543 struct glyph_string *s;
2544{
2545 int k;
2546
2547 if (s->left_overhang)
2548 {
2549 int x = 0, i;
2550 struct glyph *glyphs = s->row->glyphs[s->area];
2551 int first = s->first_glyph - glyphs;
2552
2553 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2554 x -= glyphs[i].pixel_width;
2555
2556 k = i + 1;
2557 }
2558 else
2559 k = -1;
2560
2561 return k;
2562}
2563
2564
2565/* Return the index of the first glyph preceding glyph string S that
2566 is overwriting S because of its right overhang. Value is -1 if no
2567 glyph in front of S overwrites S. */
2568
2569static int
2570x_left_overwriting (s)
2571 struct glyph_string *s;
2572{
2573 int i, k, x;
2574 struct glyph *glyphs = s->row->glyphs[s->area];
2575 int first = s->first_glyph - glyphs;
2576
2577 k = -1;
2578 x = 0;
2579 for (i = first - 1; i >= 0; --i)
2580 {
2581 int left, right;
2582 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2583 if (x + right > 0)
2584 k = i;
2585 x -= glyphs[i].pixel_width;
2586 }
2587
2588 return k;
2589}
2590
2591
2592/* Return the index of the last glyph following glyph string S that is
2593 not overwritten by S because of S's right overhang. Value is -1 if
2594 no such glyph is found. */
2595
2596static int
2597x_right_overwritten (s)
2598 struct glyph_string *s;
2599{
2600 int k = -1;
2601
2602 if (s->right_overhang)
2603 {
2604 int x = 0, i;
2605 struct glyph *glyphs = s->row->glyphs[s->area];
2606 int first = (s->first_glyph - glyphs) + (s->cmpcharp ? 1 : s->nchars);
2607 int end = s->row->used[s->area];
2608
2609 for (i = first; i < end && s->right_overhang > x; ++i)
2610 x += glyphs[i].pixel_width;
2611
2612 k = i;
2613 }
2614
2615 return k;
2616}
2617
2618
2619/* Return the index of the last glyph following glyph string S that
2620 overwrites S because of its left overhang. Value is negative
2621 if no such glyph is found. */
2622
2623static int
2624x_right_overwriting (s)
2625 struct glyph_string *s;
2626{
2627 int i, k, x;
2628 int end = s->row->used[s->area];
2629 struct glyph *glyphs = s->row->glyphs[s->area];
2630 int first = (s->first_glyph - glyphs) + (s->cmpcharp ? 1 : s->nchars);
2631
2632 k = -1;
2633 x = 0;
2634 for (i = first; i < end; ++i)
2635 {
2636 int left, right;
2637 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2638 if (x - left < 0)
2639 k = i;
2640 x += glyphs[i].pixel_width;
2641 }
2642
2643 return k;
2644}
2645
2646
2647/* Fill rectangle X, Y, W, H with background color of glyph string S. */
2648
2649static INLINE void
2650x_clear_glyph_string_rect (s, x, y, w, h)
2651 struct glyph_string *s;
2652 int x, y, w, h;
2653{
2654 XGCValues xgcv;
2655 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
2656 XSetForeground (s->display, s->gc, xgcv.background);
2657 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
2658 XSetForeground (s->display, s->gc, xgcv.foreground);
2659}
2660
2661
2662/* Draw the background of glyph_string S. If S->background_filled_p
2663 is non-zero don't draw it. FORCE_P non-zero means draw the
2664 background even if it wouldn't be drawn normally. This is used
2665 when a string preceding S draws into the background of S. */
2666
2667static void
2668x_draw_glyph_string_background (s, force_p)
2669 struct glyph_string *s;
2670 int force_p;
2671{
2672 /* Nothing to do if background has already been drawn or if it
2673 shouldn't be drawn in the first place. */
2674 if (!s->background_filled_p)
2675 {
2676 if (s->cmpcharp
2677 && s->gidx > 0
2678 && !s->font_not_found_p
2679 && !s->extends_to_end_of_line_p)
2680 {
2681 /* Don't draw background for glyphs of a composite
2682 characters, except for the first one. */
2683 s->background_filled_p = 1;
2684 }
2685 else if (s->stippled_p)
2686 {
2687 /* Fill background with a stipple pattern. */
2688 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
2689 XFillRectangle (s->display, s->window, s->gc, s->x,
2690 s->y + s->face->box_line_width,
2691 s->background_width,
2692 s->height - 2 * s->face->box_line_width);
2693 XSetFillStyle (s->display, s->gc, FillSolid);
2694 s->background_filled_p = 1;
2695 }
2696 else if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
2697 || s->font_not_found_p
2698 || s->extends_to_end_of_line_p
2699 || s->cmpcharp
2700 || force_p)
2701 {
2702 x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
2703 s->background_width,
2704 s->height - 2 * s->face->box_line_width);
2705 s->background_filled_p = 1;
2706 }
2707 }
2708}
2709
2710
2711/* Draw the foreground of glyph string S. */
2712
2713static void
2714x_draw_glyph_string_foreground (s)
2715 struct glyph_string *s;
2716{
2717 int i, x;
2718
2719 /* If first glyph of S has a left box line, start drawing the text
2720 of S to the right of that box line. */
2721 if (s->face->box != FACE_NO_BOX
2722 && s->first_glyph->left_box_line_p)
2723 x = s->x + s->face->box_line_width;
2724 else
2725 x = s->x;
2726
2727 if (s->cmpcharp == NULL)
2728 {
2729 /* Not a composite character. Draw characters of S as
2730 rectangles if S's font could not be loaded. */
2731 if (s->font_not_found_p)
2732 {
2733 for (i = 0; i < s->nchars; ++i)
2734 {
2735 struct glyph *g = s->first_glyph + i;
2736 XDrawRectangle (s->display, s->window,
2737 s->gc, x, s->y, g->pixel_width - 1,
2738 s->height - 1);
2739 x += g->pixel_width;
2740 }
2741 }
2742 else
2743 {
2744 char *char1b = (char *) s->char2b;
2745
2746 /* If we can use 8-bit functions, condense S->char2b. */
2747 if (!s->two_byte_p)
2748 for (i = 0; i < s->nchars; ++i)
2749 char1b[i] = s->char2b[i].byte2;
2750
2751 /* Draw text with XDrawString if background has already been
2752 filled. Otherwise, use XDrawImageString. (Note that
2753 XDrawImageString is usually faster than XDrawString.)
2754 Always use XDrawImageString when drawing the cursor so
2755 that there is no chance that characters under a box
2756 cursor are invisible. */
2757 if (s->background_filled_p && s->hl != DRAW_CURSOR)
2758 {
2759 /* Draw characters with 16-bit or 8-bit functions. */
2760 if (s->two_byte_p)
2761 XDrawString16 (s->display, s->window, s->gc, x, s->ybase,
2762 s->char2b, s->nchars);
2763 else
2764 XDrawString (s->display, s->window, s->gc, x, s->ybase,
2765 char1b, s->nchars);
2766 }
2767 else
2768 {
2769 if (s->two_byte_p)
2770 XDrawImageString16 (s->display, s->window, s->gc,
2771 x, s->ybase, s->char2b, s->nchars);
2772 else
2773 XDrawImageString (s->display, s->window, s->gc,
2774 x, s->ybase, char1b, s->nchars);
2775 }
2776 }
2777 }
2778 else
2779 {
2780 /* S is a glyph string for a composite character. S->gidx is the
2781 index of the first character drawn in the vector
2782 S->cmpcharp->glyph. S->gidx == 0 means we are drawing the
2783 very first component character of a composite char. */
2784
2785 /* Draw a single rectangle for the composite character if S's
2786 font could not be loaded. */
2787 if (s->font_not_found_p && s->gidx == 0)
2788 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
2789 s->width - 1, s->height - 1);
2790 else
2791 {
2792 XCharStruct *pcm;
2793 int relative_compose, default_ascent, i;
2794 int highest = 0, lowest = 0;
2795
2796 /* The value of font_info my be null if we couldn't find it
2797 in x_get_char_face_and_encoding. */
2798 if (s->cmpcharp->cmp_rule == NULL && s->font_info)
2799 {
2800 relative_compose = s->font_info->relative_compose;
2801 default_ascent = s->font_info->default_ascent;
2802 }
2803 else
2804 relative_compose = default_ascent = 0;
2805
2806 if ((s->cmpcharp->cmp_rule || relative_compose)
2807 && s->gidx == 0)
2808 {
2809 /* This is the first character. Initialize variables.
2810 Highest is the highest position of glyphs ever
2811 written, lowest the lowest position. */
2812 int x_offset = 0;
2813 int first_ch = s->first_glyph->u.ch.code;
2814
2815 if (default_ascent
2816 && CHAR_TABLE_P (Vuse_default_ascent)
2817 && !NILP (Faref (Vuse_default_ascent, first_ch)))
2818 {
2819 highest = default_ascent;
2820 lowest = 0;
2821 }
2822 else
2823 {
2824 pcm = PER_CHAR_METRIC (s->font, s->char2b);
2825 highest = pcm->ascent + 1;
2826 lowest = - pcm->descent;
2827 }
2828
2829 if (s->cmpcharp->cmp_rule)
2830 x_offset = (s->cmpcharp->col_offset[0]
2831 * FONT_WIDTH (s->f->output_data.x->font));
2832
2833 /* Draw the first character at the normal position. */
2834 XDrawString16 (s->display, s->window, s->gc,
2835 x + x_offset,
2836 s->ybase, s->char2b, 1);
2837 i = 1;
2838 ++s->gidx;
2839 }
2840 else
2841 i = 0;
2842
2843 for (; i < s->nchars; i++, ++s->gidx)
2844 {
2845 int x_offset = 0, y_offset = 0;
2846
2847 if (relative_compose)
2848 {
2849 pcm = PER_CHAR_METRIC (s->font, s->char2b + i);
2850 if (NILP (Vignore_relative_composition)
2851 || NILP (Faref (Vignore_relative_composition,
2852 make_number (s->cmpcharp->glyph[s->gidx]))))
2853 {
2854 if (- pcm->descent >= relative_compose)
2855 {
2856 /* Draw above the current glyphs. */
2857 y_offset = highest + pcm->descent;
2858 highest += pcm->ascent + pcm->descent;
2859 }
2860 else if (pcm->ascent <= 0)
2861 {
2862 /* Draw beneath the current glyphs. */
2863 y_offset = lowest - pcm->ascent;
2864 lowest -= pcm->ascent + pcm->descent;
2865 }
2866 }
2867 else
2868 {
2869 /* Draw the glyph at normal position. If
2870 it sticks out of HIGHEST or LOWEST,
2871 update them appropriately. */
2872 if (pcm->ascent > highest)
2873 highest = pcm->ascent;
2874 else if (- pcm->descent < lowest)
2875 lowest = - pcm->descent;
2876 }
2877 }
2878 else if (s->cmpcharp->cmp_rule)
2879 {
2880 int gref = (s->cmpcharp->cmp_rule[s->gidx] - 0xA0) / 9;
2881 int nref = (s->cmpcharp->cmp_rule[s->gidx] - 0xA0) % 9;
2882 int bottom, top;
2883
2884 /* Re-encode GREF and NREF so that they specify
2885 only Y-axis information:
2886 0:top, 1:base, 2:bottom, 3:center */
2887 gref = gref / 3 + (gref == 4) * 2;
2888 nref = nref / 3 + (nref == 4) * 2;
2889
2890 pcm = PER_CHAR_METRIC (s->font, s->char2b + i);
2891 bottom = ((gref == 0 ? highest : gref == 1 ? 0
2892 : gref == 2 ? lowest
2893 : (highest + lowest) / 2)
2894 - (nref == 0 ? pcm->ascent + pcm->descent
2895 : nref == 1 ? pcm->descent : nref == 2 ? 0
2896 : (pcm->ascent + pcm->descent) / 2));
2897 top = bottom + (pcm->ascent + pcm->descent);
2898 if (top > highest)
2899 highest = top;
2900 if (bottom < lowest)
2901 lowest = bottom;
2902 y_offset = bottom + pcm->descent;
2903 x_offset = (s->cmpcharp->col_offset[s->gidx]
2904 * FONT_WIDTH (FRAME_FONT (s->f)));
2905 }
2906
2907 XDrawString16 (s->display, s->window, s->gc,
2908 x + x_offset, s->ybase - y_offset,
2909 s->char2b + i, 1);
2910 }
2911 }
2912 }
2913}
2914
2915
2916/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
2917 CMAP. If an exact match can't be allocated, try the nearest color
2918 available. Value is non-zero if successful. Set *COLOR to the
2919 color allocated. */
2920
2921int
2922x_alloc_nearest_color (display, screen, cmap, color)
2923 Display *display;
2924 Screen *screen;
2925 Colormap cmap;
2926 XColor *color;
2927{
2928 int rc = XAllocColor (display, cmap, color);
2929 if (rc == 0)
2930 {
2931 /* If we got to this point, the colormap is full, so we're going
2932 to try to get the next closest color. The algorithm used is
2933 a least-squares matching, which is what X uses for closest
2934 color matching with StaticColor visuals. */
2935 int nearest, i;
2936 unsigned long nearest_delta = ~0;
2937 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
2938 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
2939
2940 for (i = 0; i < ncells; ++i)
2941 cells[i].pixel = i;
2942 XQueryColors (display, cmap, cells, ncells);
2943
2944 for (nearest = i = 0; i < ncells; ++i)
2945 {
2946 long dred = (color->red >> 8) - (cells[i].red >> 8);
2947 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
2948 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
2949 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
2950
2951 if (delta < nearest_delta)
2952 {
2953 nearest = i;
2954 nearest_delta = delta;
2955 }
2956 }
2957
2958 color->red = cells[nearest].red;
2959 color->green = cells[nearest].green;
2960 color->blue = cells[nearest].blue;
2961 rc = XAllocColor (display, cmap, color);
2962 }
2963
2964 return rc;
2965}
2966
2967
2968/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
2969 or DELTA. Try a color with RGB values multiplied by FACTOR first.
2970 If this produces the same color as PIXEL, try a color where all RGB
2971 values have DELTA added. Return the allocated color in *PIXEL.
2972 DISPLAY is the X display, CMAP is the colormap to operate on.
2973 Value is non-zero if successful. */
2974
2975static int
2976x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
2977 struct frame *f;
2978 Display *display;
2979 Colormap cmap;
2980 unsigned long *pixel;
2981 float factor;
2982 int delta;
2983{
2984 XColor color, new;
2985 int success_p;
2986
2987 /* Get RGB color values. */
2988 color.pixel = *pixel;
2989 XQueryColor (display, cmap, &color);
2990
2991 /* Change RGB values by specified FACTOR. Avoid overflow! */
2992 xassert (factor >= 0);
2993 new.red = min (0xffff, factor * color.red);
2994 new.green = min (0xffff, factor * color.green);
2995 new.blue = min (0xffff, factor * color.blue);
2996
2997 /* Try to allocate the color. */
2998 success_p = x_alloc_nearest_color (display, FRAME_X_SCREEN (f), cmap, &new);
2999 if (success_p)
3000 {
3001 if (new.pixel == *pixel)
3002 {
3003 /* If we end up with the same color as before, try adding
3004 delta to the RGB values. */
3005 int class = FRAME_X_DISPLAY_INFO (f)->visual->class;
3006
3007 /* If display has an immutable color map, freeing colors is
3008 not necessary and some servers don't allow it. So don't
3009 do it. */
3010 if (class != StaticColor
3011 && class != StaticGray
3012 && class != TrueColor)
3013 XFreeColors (display, cmap, &new.pixel, 1, 0);
3014
3015 new.red = min (0xffff, delta + color.red);
3016 new.green = min (0xffff, delta + color.green);
3017 new.blue = min (0xffff, delta + color.blue);
3018 success_p = x_alloc_nearest_color (display, FRAME_X_SCREEN (f),
3019 cmap, &new);
3020 }
3021 else
3022 success_p = 1;
3023 *pixel = new.pixel;
3024 }
3025
3026 return success_p;
3027}
3028
3029
3030/* Set up the foreground color for drawing relief lines of glyph
3031 string S. RELIEF is a pointer to a struct relief containing the GC
3032 with which lines will be drawn. Use a color that is FACTOR or
3033 DELTA lighter or darker than the relief's background which is found
3034 in S->f->output_data.x->relief_background. If such a color cannot
3035 be allocated, use DEFAULT_PIXEL, instead. */
3036
3037static void
3038x_setup_relief_color (f, relief, factor, delta, default_pixel)
3039 struct frame *f;
3040 struct relief *relief;
3041 float factor;
3042 int delta;
3043 unsigned long default_pixel;
3044{
3045 XGCValues xgcv;
3046 struct x_output *di = f->output_data.x;
3047 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3048 unsigned long pixel;
3049 unsigned long background = di->relief_background;
3050 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
dcd08bfb
GM
3051 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3052 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3053
3054 xgcv.graphics_exposures = False;
3055 xgcv.line_width = 1;
3056
3057 /* Free previously allocated color. The color cell will be reused
3058 when it has been freed as many times as it was allocated, so this
3059 doesn't affect faces using the same colors. */
3060 if (relief->gc
3061 && relief->allocated_p)
3062 {
3063 /* If display has an immutable color map, freeing colors is not
3064 necessary and some servers don't allow it. So don't do it. */
dcd08bfb 3065 int class = dpyinfo->visual->class;
06a2c219
GM
3066 if (class != StaticColor
3067 && class != StaticGray
3068 && class != TrueColor)
dcd08bfb 3069 XFreeColors (dpy, cmap, &relief->pixel, 1, 0);
06a2c219
GM
3070 relief->allocated_p = 0;
3071 }
3072
3073 /* Allocate new color. */
3074 xgcv.foreground = default_pixel;
3075 pixel = background;
dcd08bfb
GM
3076 if (dpyinfo->n_planes != 1
3077 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3078 {
3079 relief->allocated_p = 1;
3080 xgcv.foreground = relief->pixel = pixel;
3081 }
3082
3083 if (relief->gc == 0)
3084 {
dcd08bfb 3085 xgcv.stipple = dpyinfo->gray;
06a2c219 3086 mask |= GCStipple;
dcd08bfb 3087 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3088 }
3089 else
dcd08bfb 3090 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3091}
3092
3093
3094/* Set up colors for the relief lines around glyph string S. */
3095
3096static void
3097x_setup_relief_colors (s)
3098 struct glyph_string *s;
3099{
3100 struct x_output *di = s->f->output_data.x;
3101 unsigned long color;
3102
3103 if (s->face->use_box_color_for_shadows_p)
3104 color = s->face->box_color;
3105 else
3106 {
3107 XGCValues xgcv;
3108
3109 /* Get the background color of the face. */
3110 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3111 color = xgcv.background;
3112 }
3113
3114 if (di->white_relief.gc == 0
3115 || color != di->relief_background)
3116 {
3117 di->relief_background = color;
3118 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3119 WHITE_PIX_DEFAULT (s->f));
3120 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3121 BLACK_PIX_DEFAULT (s->f));
3122 }
3123}
3124
3125
3126/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3127 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3128 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3129 relief. LEFT_P non-zero means draw a relief on the left side of
3130 the rectangle. RIGHT_P non-zero means draw a relief on the right
3131 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3132 when drawing. */
3133
3134static void
3135x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3136 raised_p, left_p, right_p, clip_rect)
3137 struct frame *f;
3138 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3139 XRectangle *clip_rect;
3140{
3141 int i;
3142 GC gc;
3143
3144 if (raised_p)
3145 gc = f->output_data.x->white_relief.gc;
3146 else
3147 gc = f->output_data.x->black_relief.gc;
3148 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3149
3150 /* Top. */
3151 for (i = 0; i < width; ++i)
3152 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3153 left_x + i * left_p, top_y + i,
3154 right_x + 1 - i * right_p, top_y + i);
3155
3156 /* Left. */
3157 if (left_p)
3158 for (i = 0; i < width; ++i)
3159 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3160 left_x + i, top_y + i, left_x + i, bottom_y - i);
3161
3162 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3163 if (raised_p)
3164 gc = f->output_data.x->black_relief.gc;
3165 else
3166 gc = f->output_data.x->white_relief.gc;
3167 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3168
3169 /* Bottom. */
3170 for (i = 0; i < width; ++i)
3171 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3172 left_x + i * left_p, bottom_y - i,
3173 right_x + 1 - i * right_p, bottom_y - i);
3174
3175 /* Right. */
3176 if (right_p)
3177 for (i = 0; i < width; ++i)
3178 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3179 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3180
3181 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3182}
3183
3184
3185/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3186 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3187 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3188 left side of the rectangle. RIGHT_P non-zero means draw a line
3189 on the right side of the rectangle. CLIP_RECT is the clipping
3190 rectangle to use when drawing. */
3191
3192static void
3193x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3194 left_p, right_p, clip_rect)
3195 struct glyph_string *s;
3196 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3197 XRectangle *clip_rect;
3198{
3199 XGCValues xgcv;
3200
3201 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3202 XSetForeground (s->display, s->gc, s->face->box_color);
3203 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3204
3205 /* Top. */
3206 XFillRectangle (s->display, s->window, s->gc,
3207 left_x, top_y, right_x - left_x, width);
3208
3209 /* Left. */
3210 if (left_p)
3211 XFillRectangle (s->display, s->window, s->gc,
3212 left_x, top_y, width, bottom_y - top_y);
3213
3214 /* Bottom. */
3215 XFillRectangle (s->display, s->window, s->gc,
3216 left_x, bottom_y - width, right_x - left_x, width);
3217
3218 /* Right. */
3219 if (right_p)
3220 XFillRectangle (s->display, s->window, s->gc,
3221 right_x - width, top_y, width, bottom_y - top_y);
3222
3223 XSetForeground (s->display, s->gc, xgcv.foreground);
3224 XSetClipMask (s->display, s->gc, None);
3225}
3226
3227
3228/* Draw a box around glyph string S. */
3229
3230static void
3231x_draw_glyph_string_box (s)
3232 struct glyph_string *s;
3233{
3234 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3235 int left_p, right_p;
3236 struct glyph *last_glyph;
3237 XRectangle clip_rect;
3238
3239 last_x = window_box_right (s->w, s->area);
3240 if (s->row->full_width_p
3241 && !s->w->pseudo_window_p)
3242 {
3243 last_x += FRAME_X_FLAGS_AREA_WIDTH (s->f);
3244 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3245 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3246 }
3247
3248 /* The glyph that may have a right box line. */
3249 last_glyph = (s->cmpcharp || s->img
3250 ? s->first_glyph
3251 : s->first_glyph + s->nchars - 1);
3252
3253 width = s->face->box_line_width;
3254 raised_p = s->face->box == FACE_RAISED_BOX;
3255 left_x = s->x;
3256 right_x = ((s->row->full_width_p
1da3fd71 3257 ? last_x - 1
06a2c219
GM
3258 : min (last_x, s->x + s->width) - 1));
3259 top_y = s->y;
3260 bottom_y = top_y + s->height - 1;
3261
3262 left_p = (s->first_glyph->left_box_line_p
3263 || (s->hl == DRAW_MOUSE_FACE
3264 && (s->prev == NULL
3265 || s->prev->hl != s->hl)));
3266 right_p = (last_glyph->right_box_line_p
3267 || (s->hl == DRAW_MOUSE_FACE
3268 && (s->next == NULL
3269 || s->next->hl != s->hl)));
3270
3271 x_get_glyph_string_clip_rect (s, &clip_rect);
3272
3273 if (s->face->box == FACE_SIMPLE_BOX)
3274 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3275 left_p, right_p, &clip_rect);
3276 else
3277 {
3278 x_setup_relief_colors (s);
3279 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3280 width, raised_p, left_p, right_p, &clip_rect);
3281 }
3282}
3283
3284
3285/* Draw foreground of image glyph string S. */
3286
3287static void
3288x_draw_image_foreground (s)
3289 struct glyph_string *s;
3290{
3291 int x;
3292 int y = s->ybase - IMAGE_ASCENT (s->img);
3293
3294 /* If first glyph of S has a left box line, start drawing it to the
3295 right of that line. */
3296 if (s->face->box != FACE_NO_BOX
3297 && s->first_glyph->left_box_line_p)
3298 x = s->x + s->face->box_line_width;
3299 else
3300 x = s->x;
3301
3302 /* If there is a margin around the image, adjust x- and y-position
3303 by that margin. */
3304 if (s->img->margin)
3305 {
3306 x += s->img->margin;
3307 y += s->img->margin;
3308 }
3309
3310 if (s->img->pixmap)
3311 {
3312 if (s->img->mask)
3313 {
3314 /* We can't set both a clip mask and use XSetClipRectangles
3315 because the latter also sets a clip mask. We also can't
3316 trust on the shape extension to be available
3317 (XShapeCombineRegion). So, compute the rectangle to draw
3318 manually. */
3319 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3320 | GCFunction);
3321 XGCValues xgcv;
3322 XRectangle clip_rect, image_rect, r;
3323
3324 xgcv.clip_mask = s->img->mask;
3325 xgcv.clip_x_origin = x;
3326 xgcv.clip_y_origin = y;
3327 xgcv.function = GXcopy;
3328 XChangeGC (s->display, s->gc, mask, &xgcv);
3329
3330 x_get_glyph_string_clip_rect (s, &clip_rect);
3331 image_rect.x = x;
3332 image_rect.y = y;
3333 image_rect.width = s->img->width;
3334 image_rect.height = s->img->height;
3335 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
3336 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3337 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
3338 }
3339 else
3340 {
3341 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3342 0, 0, s->img->width, s->img->height, x, y);
3343
3344 /* When the image has a mask, we can expect that at
3345 least part of a mouse highlight or a block cursor will
3346 be visible. If the image doesn't have a mask, make
3347 a block cursor visible by drawing a rectangle around
3348 the image. I believe it's looking better if we do
3349 nothing here for mouse-face. */
3350 if (s->hl == DRAW_CURSOR)
3351 XDrawRectangle (s->display, s->window, s->gc, x, y,
3352 s->img->width - 1, s->img->height - 1);
3353 }
3354 }
3355 else
3356 /* Draw a rectangle if image could not be loaded. */
3357 XDrawRectangle (s->display, s->window, s->gc, x, y,
3358 s->img->width - 1, s->img->height - 1);
3359}
3360
3361
3362/* Draw a relief around the image glyph string S. */
3363
3364static void
3365x_draw_image_relief (s)
3366 struct glyph_string *s;
3367{
3368 int x0, y0, x1, y1, thick, raised_p;
3369 XRectangle r;
3370 int x;
3371 int y = s->ybase - IMAGE_ASCENT (s->img);
3372
3373 /* If first glyph of S has a left box line, start drawing it to the
3374 right of that line. */
3375 if (s->face->box != FACE_NO_BOX
3376 && s->first_glyph->left_box_line_p)
3377 x = s->x + s->face->box_line_width;
3378 else
3379 x = s->x;
3380
3381 /* If there is a margin around the image, adjust x- and y-position
3382 by that margin. */
3383 if (s->img->margin)
3384 {
3385 x += s->img->margin;
3386 y += s->img->margin;
3387 }
3388
3389 if (s->hl == DRAW_IMAGE_SUNKEN
3390 || s->hl == DRAW_IMAGE_RAISED)
3391 {
3392 thick = toolbar_button_relief > 0 ? toolbar_button_relief : 3;
3393 raised_p = s->hl == DRAW_IMAGE_RAISED;
3394 }
3395 else
3396 {
3397 thick = abs (s->img->relief);
3398 raised_p = s->img->relief > 0;
3399 }
3400
3401 x0 = x - thick;
3402 y0 = y - thick;
3403 x1 = x + s->img->width + thick - 1;
3404 y1 = y + s->img->height + thick - 1;
3405
3406 x_setup_relief_colors (s);
3407 x_get_glyph_string_clip_rect (s, &r);
3408 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
3409}
3410
3411
3412/* Draw the foreground of image glyph string S to PIXMAP. */
3413
3414static void
3415x_draw_image_foreground_1 (s, pixmap)
3416 struct glyph_string *s;
3417 Pixmap pixmap;
3418{
3419 int x;
3420 int y = s->ybase - s->y - IMAGE_ASCENT (s->img);
3421
3422 /* If first glyph of S has a left box line, start drawing it to the
3423 right of that line. */
3424 if (s->face->box != FACE_NO_BOX
3425 && s->first_glyph->left_box_line_p)
3426 x = s->face->box_line_width;
3427 else
3428 x = 0;
3429
3430 /* If there is a margin around the image, adjust x- and y-position
3431 by that margin. */
3432 if (s->img->margin)
3433 {
3434 x += s->img->margin;
3435 y += s->img->margin;
3436 }
dc43ef94 3437
06a2c219
GM
3438 if (s->img->pixmap)
3439 {
3440 if (s->img->mask)
3441 {
3442 /* We can't set both a clip mask and use XSetClipRectangles
3443 because the latter also sets a clip mask. We also can't
3444 trust on the shape extension to be available
3445 (XShapeCombineRegion). So, compute the rectangle to draw
3446 manually. */
3447 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3448 | GCFunction);
3449 XGCValues xgcv;
3450
3451 xgcv.clip_mask = s->img->mask;
3452 xgcv.clip_x_origin = x;
3453 xgcv.clip_y_origin = y;
3454 xgcv.function = GXcopy;
3455 XChangeGC (s->display, s->gc, mask, &xgcv);
3456
3457 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3458 0, 0, s->img->width, s->img->height, x, y);
3459 XSetClipMask (s->display, s->gc, None);
3460 }
3461 else
3462 {
3463 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3464 0, 0, s->img->width, s->img->height, x, y);
3465
3466 /* When the image has a mask, we can expect that at
3467 least part of a mouse highlight or a block cursor will
3468 be visible. If the image doesn't have a mask, make
3469 a block cursor visible by drawing a rectangle around
3470 the image. I believe it's looking better if we do
3471 nothing here for mouse-face. */
3472 if (s->hl == DRAW_CURSOR)
3473 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3474 s->img->width - 1, s->img->height - 1);
3475 }
3476 }
3477 else
3478 /* Draw a rectangle if image could not be loaded. */
3479 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3480 s->img->width - 1, s->img->height - 1);
3481}
dc43ef94 3482
990ba854 3483
06a2c219
GM
3484/* Draw part of the background of glyph string S. X, Y, W, and H
3485 give the rectangle to draw. */
a9a5b0a5 3486
06a2c219
GM
3487static void
3488x_draw_glyph_string_bg_rect (s, x, y, w, h)
3489 struct glyph_string *s;
3490 int x, y, w, h;
3491{
3492 if (s->stippled_p)
3493 {
3494 /* Fill background with a stipple pattern. */
3495 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3496 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3497 XSetFillStyle (s->display, s->gc, FillSolid);
3498 }
3499 else
3500 x_clear_glyph_string_rect (s, x, y, w, h);
3501}
07e34cb0 3502
b5210ea7 3503
06a2c219 3504/* Draw image glyph string S.
dc43ef94 3505
06a2c219
GM
3506 s->y
3507 s->x +-------------------------
3508 | s->face->box
3509 |
3510 | +-------------------------
3511 | | s->img->margin
3512 | |
3513 | | +-------------------
3514 | | | the image
dc43ef94 3515
06a2c219 3516 */
dc43ef94 3517
06a2c219
GM
3518static void
3519x_draw_image_glyph_string (s)
3520 struct glyph_string *s;
3521{
3522 int x, y;
3523 int box_line_width = s->face->box_line_width;
3524 int margin = s->img->margin;
3525 int height;
3526 Pixmap pixmap = None;
3527
3528 height = s->height - 2 * box_line_width;
3529
3530 /* Fill background with face under the image. Do it only if row is
3531 taller than image or if image has a clip mask to reduce
3532 flickering. */
3533 s->stippled_p = s->face->stipple != 0;
3534 if (height > s->img->height
3535 || margin
3536 || s->img->mask
3537 || s->img->pixmap == 0
3538 || s->width != s->background_width)
3539 {
3540 if (box_line_width && s->first_glyph->left_box_line_p)
3541 x = s->x + box_line_width;
3542 else
3543 x = s->x;
3544
3545 y = s->y + box_line_width;
3546
3547 if (s->img->mask)
3548 {
3549 /* Create a pixmap as large as the glyph string Fill it with
3550 the background color. Copy the image to it, using its
3551 mask. Copy the temporary pixmap to the display. */
3552 Screen *screen = FRAME_X_SCREEN (s->f);
3553 int depth = DefaultDepthOfScreen (screen);
3554
3555 /* Create a pixmap as large as the glyph string. */
3556 pixmap = XCreatePixmap (s->display, s->window,
3557 s->background_width,
3558 s->height, depth);
3559
3560 /* Don't clip in the following because we're working on the
3561 pixmap. */
3562 XSetClipMask (s->display, s->gc, None);
3563
3564 /* Fill the pixmap with the background color/stipple. */
3565 if (s->stippled_p)
3566 {
3567 /* Fill background with a stipple pattern. */
3568 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3569 XFillRectangle (s->display, pixmap, s->gc,
3570 0, 0, s->background_width, s->height);
3571 XSetFillStyle (s->display, s->gc, FillSolid);
3572 }
3573 else
3574 {
3575 XGCValues xgcv;
3576 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
3577 &xgcv);
3578 XSetForeground (s->display, s->gc, xgcv.background);
3579 XFillRectangle (s->display, pixmap, s->gc,
3580 0, 0, s->background_width, s->height);
3581 XSetForeground (s->display, s->gc, xgcv.foreground);
3582 }
3583 }
3584 else
3585 /* Implementation idea: Is it possible to construct a mask?
3586 We could look at the color at the margins of the image, and
3587 say that this color is probably the background color of the
3588 image. */
3589 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3590
3591 s->background_filled_p = 1;
3592 }
dc43ef94 3593
06a2c219
GM
3594 /* Draw the foreground. */
3595 if (pixmap != None)
3596 {
3597 x_draw_image_foreground_1 (s, pixmap);
3598 x_set_glyph_string_clipping (s);
3599 XCopyArea (s->display, pixmap, s->window, s->gc,
3600 0, 0, s->background_width, s->height, s->x, s->y);
3601 XFreePixmap (s->display, pixmap);
3602 }
3603 else
3604 x_draw_image_foreground (s);
b5210ea7 3605
06a2c219
GM
3606 /* If we must draw a relief around the image, do it. */
3607 if (s->img->relief
3608 || s->hl == DRAW_IMAGE_RAISED
3609 || s->hl == DRAW_IMAGE_SUNKEN)
3610 x_draw_image_relief (s);
3611}
8c1a6a84 3612
990ba854 3613
06a2c219 3614/* Draw stretch glyph string S. */
dc43ef94 3615
06a2c219
GM
3616static void
3617x_draw_stretch_glyph_string (s)
3618 struct glyph_string *s;
3619{
3620 xassert (s->first_glyph->type == STRETCH_GLYPH);
3621 s->stippled_p = s->face->stipple != 0;
990ba854 3622
06a2c219
GM
3623 if (s->hl == DRAW_CURSOR
3624 && !x_stretch_cursor_p)
3625 {
3626 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3627 as wide as the stretch glyph. */
3628 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 3629
06a2c219
GM
3630 /* Draw cursor. */
3631 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 3632
06a2c219
GM
3633 /* Clear rest using the GC of the original non-cursor face. */
3634 if (width < s->background_width)
3635 {
3636 GC gc = s->face->gc;
3637 int x = s->x + width, y = s->y;
3638 int w = s->background_width - width, h = s->height;
3639 XRectangle r;
dc43ef94 3640
06a2c219
GM
3641 x_get_glyph_string_clip_rect (s, &r);
3642 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
97210f4e 3643
06a2c219
GM
3644 if (s->face->stipple)
3645 {
3646 /* Fill background with a stipple pattern. */
3647 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3648 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3649 XSetFillStyle (s->display, gc, FillSolid);
3650 }
3651 else
3652 {
3653 XGCValues xgcv;
3654 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
3655 XSetForeground (s->display, gc, xgcv.background);
3656 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3657 XSetForeground (s->display, gc, xgcv.foreground);
3658 }
3659 }
3660 }
3661 else
3662 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
3663 s->height);
3664
3665 s->background_filled_p = 1;
3666}
3667
3668
3669/* Draw glyph string S. */
3670
3671static void
3672x_draw_glyph_string (s)
3673 struct glyph_string *s;
3674{
3675 /* If S draws into the background of its successor, draw the
3676 background of the successor first so that S can draw into it.
3677 This makes S->next use XDrawString instead of XDrawImageString. */
3678 if (s->next && s->right_overhang)
3679 {
3680 xassert (s->next->img == NULL);
3681 x_set_glyph_string_gc (s->next);
3682 x_set_glyph_string_clipping (s->next);
3683 x_draw_glyph_string_background (s->next, 1);
3684 }
97210f4e 3685
06a2c219
GM
3686 /* Set up S->gc, set clipping and draw S. */
3687 x_set_glyph_string_gc (s);
3688 x_set_glyph_string_clipping (s);
3689
3690 switch (s->first_glyph->type)
3691 {
3692 case IMAGE_GLYPH:
3693 x_draw_image_glyph_string (s);
3694 break;
3695
3696 case STRETCH_GLYPH:
3697 x_draw_stretch_glyph_string (s);
3698 break;
3699
3700 case CHAR_GLYPH:
3701 x_draw_glyph_string_background (s, 0);
3702 x_draw_glyph_string_foreground (s);
3703 break;
3704
3705 default:
3706 abort ();
3707 }
3708
3709 /* Draw underline. */
3710 if (s->face->underline_p)
3711 {
3712 unsigned long dy, h;
3713
3714 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
3715 h = 1;
3716 if (!XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &dy))
3717 dy = s->height - h;
3718
3719 if (s->face->underline_defaulted_p)
3720 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3721 s->width, h);
3722 else
dc6f92b8 3723 {
06a2c219
GM
3724 XGCValues xgcv;
3725 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3726 XSetForeground (s->display, s->gc, s->face->underline_color);
3727 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3728 s->width, h);
3729 XSetForeground (s->display, s->gc, xgcv.foreground);
dc6f92b8 3730 }
06a2c219 3731 }
07e34cb0 3732
06a2c219
GM
3733 /* Draw overline. */
3734 if (s->face->overline_p)
3735 {
3736 unsigned long dy = 0, h = 1;
3737
3738 if (s->face->overline_color_defaulted_p)
3739 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3740 s->width, h);
3741 else
3742 {
3743 XGCValues xgcv;
3744 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3745 XSetForeground (s->display, s->gc, s->face->overline_color);
3746 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3747 s->width, h);
3748 XSetForeground (s->display, s->gc, xgcv.foreground);
3749 }
dc6f92b8 3750 }
06a2c219
GM
3751
3752 /* Draw strike-through. */
3753 if (s->face->strike_through_p)
3754 {
3755 unsigned long h = 1;
3756 unsigned long dy = (s->height - h) / 2;
dc43ef94 3757
06a2c219
GM
3758 if (s->face->strike_through_color_defaulted_p)
3759 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3760 s->width, h);
3761 else
3762 {
3763 XGCValues xgcv;
3764 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3765 XSetForeground (s->display, s->gc, s->face->strike_through_color);
3766 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
3767 s->width, h);
3768 XSetForeground (s->display, s->gc, xgcv.foreground);
3769 }
3770 }
3771
3772 /* Draw relief. */
3773 if (s->face->box != FACE_NO_BOX)
3774 x_draw_glyph_string_box (s);
3775
3776 /* Reset clipping. */
3777 XSetClipMask (s->display, s->gc, None);
dc6f92b8 3778}
07e34cb0 3779
06a2c219
GM
3780
3781/* A work-list entry used during the construction of glyph_string
3782 structures for a composite character. */
3783
3784struct work
3785{
3786 /* Pointer to composite char info defining has the composite
3787 character is drawn. */
3788 struct cmpchar_info *cmpcharp;
3789
3790 /* Start index in compcharp->glyph[]. */
3791 int gidx;
3792
3793 /* Next in stack. */
3794 struct work *next;
3795};
3796
3797
3798static void x_fill_composite_glyph_string P_ ((struct glyph_string *,
3799 int, struct work **,
3800 struct work **));
3801
3802
3803/* Load glyph string S with information from the top of *STACK for a
3804 composite character. FACE_ID is the id of the face in which S is
3805 drawn. *NEW is a pointer to a struct work not on the stack, that
3806 can be used if this function needs to push a new structure on the
3807 stack. If it uses it, *NEW is set to null. */
07e34cb0
JB
3808
3809static void
06a2c219
GM
3810x_fill_composite_glyph_string (s, face_id, stack, new)
3811 struct glyph_string *s;
3812 int face_id;
3813 struct work **stack, **new;
07e34cb0 3814{
06a2c219
GM
3815 int i, c;
3816 struct work *work;
3817
3818 xassert (s && *new && *stack);
3819
3820 /* Pop the work stack. */
3821 work = *stack;
3822 *stack = work->next;
3823
3824 /* For all glyphs of cmpcharp->glyph, starting at the offset
3825 work->offset, until we reach the end of the definition or
3826 encounter another composite char, get the font and face to use,
3827 and add it to S. */
3828 for (i = work->gidx; i < work->cmpcharp->glyph_len; ++i)
3829 {
3830 c = FAST_GLYPH_CHAR (work->cmpcharp->glyph[i]);
3831 if (CHAR_CHARSET (c) == CHARSET_COMPOSITION)
3832 break;
3833 s->face = x_get_char_face_and_encoding (s->f, c, face_id,
3834 s->char2b + s->nchars, 1);
3835 s->font = s->face->font;
3836 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
3837 ++s->nchars;
3838 }
3839
3840 /* If we find another composite char in the glyph definition of
3841 work->cmpcharp, put back the rest of the glyphs on the work
3842 stack, and make a new entry for the composite char. */
3843 if (i < work->cmpcharp->glyph_len)
3844 {
3845 /* Push back an unprocessed rest of this glyph spec. */
3846 if (i < work->cmpcharp->glyph_len - 1)
3847 {
3848 work->gidx = i + 1;
3849 work->next = *stack;
3850 *stack = work;
3851 work = *new;
3852 *new = NULL;
3853 }
3854
3855 /* Make an entry for the composite char on the work stack. */
3856 work->cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (c)];
3857 work->gidx = 0;
3858 work->next = *stack;
3859 *stack = work;
3860 }
3861
3862 /* The width of this glyph string equals the width of the first
3863 glyph. All characters are drawn at the same x-position. */
3864 s->width = s->first_glyph->pixel_width;
3865
3866 /* If the specified font could not be loaded, use the frame's
3867 default font, but record the fact that we couldn't load it in
3868 the glyph string so that we can draw rectangles for the
3869 characters of the glyph string. */
3870 if (s->font == NULL)
3871 {
3872 s->font_not_found_p = 1;
3873 s->font = FRAME_FONT (s->f);
3874 }
3875
3876 /* Adjust base line for subscript/superscript text. */
3877 s->ybase += s->first_glyph->voffset;
3878
3879 xassert (s->face && s->face->gc);
3880
3881 /* This glyph string must always be drawn with 16-bit functions. */
3882 s->two_byte_p = 1;
3883}
3884
3885
3886/* Load glyph string S with a sequence of non-composite characters.
3887 FACE_ID is the face id of the string. START is the index of the
3888 first glyph to consider, END is the index of the last + 1. Value
3889 is the index of the first glyph not in S. */
3890
3891static int
3892x_fill_glyph_string (s, face_id, start, end)
3893 struct glyph_string *s;
3894 int face_id;
3895 int start, end;
3896{
3897 struct glyph *glyph, *last;
3898 int voffset;
3899
3900 xassert (s->charset != CHARSET_COMPOSITION);
3901 xassert (s->f == XFRAME (s->w->frame));
3902 xassert (s->nchars == 0);
3903 xassert (start >= 0 && end > start);
3904
3905 glyph = s->row->glyphs[s->area] + start;
3906 last = s->row->glyphs[s->area] + end;
3907 voffset = glyph->voffset;
3908
3909 while (glyph < last
3910 && glyph->type == CHAR_GLYPH
3911 && glyph->voffset == voffset
3912 /* Same face id implies same charset, nowadays. */
3913 && glyph->u.ch.face_id == face_id)
3914 {
3915 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
3916 s->char2b + s->nchars);
3917 if (s->char2b[s->nchars].byte2 != 0)
3918 s->two_byte_p = 1;
3919
3920 ++s->nchars;
3921 xassert (s->nchars <= end - start);
3922 s->width += glyph->pixel_width;
3923 ++glyph;
3924 }
3925
3926 s->font = s->face->font;
3927 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
3928
3929 /* If the specified font could not be loaded, use the frame's font,
3930 but record the fact that we couldn't load it in
3931 S->font_not_found_p so that we can draw rectangles for the
3932 characters of the glyph string. */
3933 if (s->font == NULL)
3934 {
3935 s->font_not_found_p = 1;
3936 s->font = FRAME_FONT (s->f);
3937 }
3938
3939 /* Adjust base line for subscript/superscript text. */
3940 s->ybase += voffset;
3941
3942 xassert (s->face && s->face->gc);
3943 return glyph - s->row->glyphs[s->area];
07e34cb0 3944}
dc6f92b8 3945
06a2c219
GM
3946
3947/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 3948
dfcf069d 3949static void
06a2c219
GM
3950x_fill_image_glyph_string (s)
3951 struct glyph_string *s;
3952{
3953 xassert (s->first_glyph->type == IMAGE_GLYPH);
3954 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img.id);
3955 xassert (s->img);
3956 s->face = FACE_FROM_ID (s->f, s->first_glyph->u.img.face_id);
3957 s->font = s->face->font;
3958 s->width = s->first_glyph->pixel_width;
3959
3960 /* Adjust base line for subscript/superscript text. */
3961 s->ybase += s->first_glyph->voffset;
3962}
3963
3964
3965/* Fill glyph string S from stretch glyph S->first_glyph. */
3966
3967static void
3968x_fill_stretch_glyph_string (s)
3969 struct glyph_string *s;
3970{
3971 xassert (s->first_glyph->type == STRETCH_GLYPH);
3972 s->face = FACE_FROM_ID (s->f, s->first_glyph->u.stretch.face_id);
3973 s->font = s->face->font;
3974 s->width = s->first_glyph->pixel_width;
3975
3976 /* Adjust base line for subscript/superscript text. */
3977 s->ybase += s->first_glyph->voffset;
3978}
3979
3980
3981/* Initialize glyph string S. CHAR2B is a suitably allocated vector
3982 of XChar2b structures for S; it can't be allocated in
3983 x_init_glyph_string because it must be allocated via `alloca'. W
3984 is the window on which S is drawn. ROW and AREA are the glyph row
3985 and area within the row from which S is constructed. START is the
3986 index of the first glyph structure covered by S. HL is a
3987 face-override for drawing S. */
3988
3989static void
3990x_init_glyph_string (s, char2b, w, row, area, start, hl)
3991 struct glyph_string *s;
3992 XChar2b *char2b;
3993 struct window *w;
3994 struct glyph_row *row;
3995 enum glyph_row_area area;
3996 int start;
3997 enum draw_glyphs_face hl;
3998{
3999 bzero (s, sizeof *s);
4000 s->w = w;
4001 s->f = XFRAME (w->frame);
4002 s->display = FRAME_X_DISPLAY (s->f);
4003 s->window = FRAME_X_WINDOW (s->f);
4004 s->char2b = char2b;
4005 s->hl = hl;
4006 s->row = row;
4007 s->area = area;
4008 s->first_glyph = row->glyphs[area] + start;
4009 s->height = row->height;
4010 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4011
4012 /* Display the internal border below the toolbar window. */
4013 if (s->w == XWINDOW (s->f->toolbar_window))
4014 s->y -= s->f->output_data.x->internal_border_width;
4015
4016 s->ybase = s->y + row->ascent;
4017}
4018
4019
4020/* Set background width of glyph string S. START is the index of the
4021 first glyph following S. LAST_X is the right-most x-position + 1
4022 in the drawing area. */
4023
4024static INLINE void
4025x_set_glyph_string_background_width (s, start, last_x)
4026 struct glyph_string *s;
4027 int start;
4028 int last_x;
4029{
4030 /* If the face of this glyph string has to be drawn to the end of
4031 the drawing area, set S->extends_to_end_of_line_p. */
4032 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4033
4034 if (start == s->row->used[s->area]
4035 && s->hl == DRAW_NORMAL_TEXT
4036 && ((s->area == TEXT_AREA && s->row->fill_line_p)
4037 || s->face->background != default_face->background
4038 || s->face->stipple != default_face->stipple))
4039 s->extends_to_end_of_line_p = 1;
4040
4041 /* If S extends its face to the end of the line, set its
4042 background_width to the distance to the right edge of the drawing
4043 area. */
4044 if (s->extends_to_end_of_line_p)
1da3fd71 4045 s->background_width = last_x - s->x + 1;
06a2c219
GM
4046 else
4047 s->background_width = s->width;
4048}
4049
4050
4051/* Add a glyph string for a stretch glyph to the list of strings
4052 between HEAD and TAIL. START is the index of the stretch glyph in
4053 row area AREA of glyph row ROW. END is the index of the last glyph
4054 in that glyph row area. X is the current output position assigned
4055 to the new glyph string constructed. HL overrides that face of the
4056 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4057 is the right-most x-position of the drawing area. */
4058
4059#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, \
4060 HL, X, LAST_X) \
4061 do \
4062 { \
4063 s = (struct glyph_string *) alloca (sizeof *s); \
4064 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4065 x_fill_stretch_glyph_string (s); \
4066 x_append_glyph_string (&HEAD, &TAIL, s); \
4067 ++START; \
4068 s->x = (X); \
4069 } \
4070 while (0)
4071
4072
4073/* Add a glyph string for an image glyph to the list of strings
4074 between HEAD and TAIL. START is the index of the image glyph in
4075 row area AREA of glyph row ROW. END is the index of the last glyph
4076 in that glyph row area. X is the current output position assigned
4077 to the new glyph string constructed. HL overrides that face of the
4078 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4079 is the right-most x-position of the drawing area. */
4080
4081#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, \
4082 HL, X, LAST_X) \
4083 do \
4084 { \
4085 s = (struct glyph_string *) alloca (sizeof *s); \
4086 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4087 x_fill_image_glyph_string (s); \
4088 x_append_glyph_string (&HEAD, &TAIL, s); \
4089 ++START; \
4090 s->x = (X); \
4091 } \
4092 while (0)
4093
4094
4095/* Add a glyph string for a sequence of character glyphs to the list
4096 of strings between HEAD and TAIL. START is the index of the first
4097 glyph in row area AREA of glyph row ROW that is part of the new
4098 glyph string. END is the index of the last glyph in that glyph row
4099 area. X is the current output position assigned to the new glyph
4100 string constructed. HL overrides that face of the glyph; e.g. it
4101 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4102 right-most x-position of the drawing area. */
4103
4104#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, \
4105 X, LAST_X) \
4106 do \
4107 { \
4108 int c, charset, face_id; \
4109 XChar2b *char2b; \
4110 \
4111 c = (ROW)->glyphs[AREA][START].u.ch.code; \
4112 charset = CHAR_CHARSET (c); \
4113 face_id = (ROW)->glyphs[AREA][START].u.ch.face_id; \
4114 \
4115 if (charset == CHARSET_COMPOSITION) \
4116 { \
4117 struct work *stack, *work, *new = NULL; \
4118 int n = 0; \
4119 struct glyph_string *first_s = NULL; \
4120 \
4121 /* Push an initial entry for character c on the stack. */ \
4122 stack = NULL; \
4123 work = (struct work *) alloca (sizeof *work); \
4124 work->cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (c)]; \
4125 work->gidx = 0; \
4126 work->next = stack; \
4127 stack = work; \
4128 \
4129 /* While the stack is not empty, append glyph_strings \
4130 to head/tail for glyphs to draw. */ \
4131 while (stack) \
4132 { \
4133 s = (struct glyph_string *) alloca (sizeof *s); \
4134 char2b = (XChar2b *) alloca (stack->cmpcharp->glyph_len \
4135 * sizeof (XChar2b)); \
4136 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4137 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4138 s->cmpcharp = stack->cmpcharp; \
4139 s->gidx = stack->gidx; \
4140 s->charset = charset; \
4141 s->x = (X); \
4142 \
4143 if (n == 0) \
4144 { \
4145 /* Don't draw the background except for the \
4146 first glyph string. */ \
4147 s->background_filled_p = n > 0; \
4148 first_s = s; \
4149 } \
4150 ++n; \
4151 \
4152 if (new == NULL) \
4153 new = (struct work *) alloca (sizeof *new); \
4154 x_fill_composite_glyph_string (s, face_id, &stack, \
4155 &new); \
4156 } \
4157 \
4158 ++START; \
4159 s = first_s; \
4160 } \
4161 else \
4162 { \
4163 s = (struct glyph_string *) alloca (sizeof *s); \
4164 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4165 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4166 x_append_glyph_string (&HEAD, &TAIL, s); \
4167 s->charset = charset; \
4168 s->x = (X); \
4169 START = x_fill_glyph_string (s, face_id, START, END); \
4170 } \
4171 } \
4172 while (0)
4173
4174
4175/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4176 of AREA of glyph row ROW on window W between indices START and END.
4177 HL overrides the face for drawing glyph strings, e.g. it is
4178 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4179 x-positions of the drawing area.
4180
4181 This is an ugly monster macro construct because we must use alloca
4182 to allocate glyph strings (because x_draw_glyphs can be called
4183 asynchronously). */
4184
4185#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, \
4186 X, LAST_X) \
4187 do \
4188 { \
4189 HEAD = TAIL = NULL; \
4190 while (START < END) \
4191 { \
4192 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4193 switch (first_glyph->type) \
4194 { \
4195 case CHAR_GLYPH: \
4196 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
4197 TAIL, HL, X, LAST_X); \
4198 break; \
4199 \
4200 case STRETCH_GLYPH: \
4201 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
4202 HEAD, TAIL, HL, X, LAST_X); \
4203 break; \
4204 \
4205 case IMAGE_GLYPH: \
4206 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
4207 TAIL, HL, X, LAST_X); \
4208 break; \
4209 \
4210 default: \
4211 abort (); \
4212 } \
4213 \
4214 x_set_glyph_string_background_width (s, START, LAST_X); \
4215 (X) += s->width; \
4216 } \
4217 } \
4218 while (0)
4219
4220
4221/* Draw glyphs between START and END in AREA of ROW on window W,
4222 starting at x-position X. X is relative to AREA in W. HL is a
4223 face-override with the following meaning:
4224
4225 DRAW_NORMAL_TEXT draw normally
4226 DRAW_CURSOR draw in cursor face
4227 DRAW_MOUSE_FACE draw in mouse face.
4228 DRAW_INVERSE_VIDEO draw in mode line face
4229 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
4230 DRAW_IMAGE_RAISED draw an image with a raised relief around it
4231
4232 If REAL_START is non-null, return in *REAL_START the real starting
4233 position for display. This can be different from START in case
4234 overlapping glyphs must be displayed. If REAL_END is non-null,
4235 return in *REAL_END the real end position for display. This can be
4236 different from END in case overlapping glyphs must be displayed.
4237
4238 Value is the x-position reached, relative to AREA of W. */
4239
4240static int
4241x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end)
4242 struct window *w;
4243 int x;
4244 struct glyph_row *row;
4245 enum glyph_row_area area;
4246 int start, end;
4247 enum draw_glyphs_face hl;
4248 int *real_start, *real_end;
dc6f92b8 4249{
06a2c219
GM
4250 struct glyph_string *head, *tail;
4251 struct glyph_string *s;
4252 int last_x, area_width;
4253 int x_reached;
4254 int i, j;
4255
4256 /* Let's rather be paranoid than getting a SEGV. */
4257 start = max (0, start);
4258 end = min (end, row->used[area]);
4259 if (real_start)
4260 *real_start = start;
4261 if (real_end)
4262 *real_end = end;
4263
4264 /* Translate X to frame coordinates. Set last_x to the right
4265 end of the drawing area. */
4266 if (row->full_width_p)
4267 {
4268 /* X is relative to the left edge of W, without scroll bars
4269 or flag areas. */
4270 struct frame *f = XFRAME (w->frame);
4271 int width = FRAME_FLAGS_AREA_WIDTH (f);
4272 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 4273
06a2c219
GM
4274 x += window_left_x;
4275 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
4276 last_x = window_left_x + area_width;
4277
4278 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4279 {
4280 width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
4281 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
4282 last_x += width;
4283 else
4284 x -= width;
4285 }
dc6f92b8 4286
b9432a85
GM
4287 x += FRAME_INTERNAL_BORDER_WIDTH (f);
4288 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
4289 }
4290 else
dc6f92b8 4291 {
06a2c219
GM
4292 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
4293 area_width = window_box_width (w, area);
4294 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
4295 }
4296
06a2c219
GM
4297 /* Build a doubly-linked list of glyph_string structures between
4298 head and tail from what we have to draw. Note that the macro
4299 BUILD_GLYPH_STRINGS will modify its start parameter. That's
4300 the reason we use a separate variable `i'. */
4301 i = start;
4302 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x);
4303 if (tail)
4304 x_reached = tail->x + tail->background_width;
4305 else
4306 x_reached = x;
90e65f07 4307
06a2c219
GM
4308 /* If there are any glyphs with lbearing < 0 or rbearing > width in
4309 the row, redraw some glyphs in front or following the glyph
4310 strings built above. */
4311 if (row->contains_overlapping_glyphs_p)
4312 {
4313 int dummy_x = 0;
4314 struct glyph_string *h, *t;
4315
4316 /* Compute overhangs for all glyph strings. */
4317 for (s = head; s; s = s->next)
4318 x_compute_glyph_string_overhangs (s);
4319
4320 /* Prepend glyph strings for glyphs in front of the first glyph
4321 string that are overwritten because of the first glyph
4322 string's left overhang. The background of all strings
4323 prepended must be drawn because the first glyph string
4324 draws over it. */
4325 i = x_left_overwritten (head);
4326 if (i >= 0)
4327 {
4328 j = i;
4329 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
4330 DRAW_NORMAL_TEXT, dummy_x, last_x);
4331 start = i;
4332 if (real_start)
4333 *real_start = start;
4334 x_compute_overhangs_and_x (t, head->x, 1);
4335 x_prepend_glyph_string_lists (&head, &tail, h, t);
4336 }
58769bee 4337
06a2c219
GM
4338 /* Prepend glyph strings for glyphs in front of the first glyph
4339 string that overwrite that glyph string because of their
4340 right overhang. For these strings, only the foreground must
4341 be drawn, because it draws over the glyph string at `head'.
4342 The background must not be drawn because this would overwrite
4343 right overhangs of preceding glyphs for which no glyph
4344 strings exist. */
4345 i = x_left_overwriting (head);
4346 if (i >= 0)
4347 {
4348 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
4349 DRAW_NORMAL_TEXT, dummy_x, last_x);
4350 for (s = h; s; s = s->next)
4351 s->background_filled_p = 1;
4352 if (real_start)
4353 *real_start = i;
4354 x_compute_overhangs_and_x (t, head->x, 1);
4355 x_prepend_glyph_string_lists (&head, &tail, h, t);
4356 }
dbcb258a 4357
06a2c219
GM
4358 /* Append glyphs strings for glyphs following the last glyph
4359 string tail that are overwritten by tail. The background of
4360 these strings has to be drawn because tail's foreground draws
4361 over it. */
4362 i = x_right_overwritten (tail);
4363 if (i >= 0)
4364 {
4365 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
4366 DRAW_NORMAL_TEXT, x, last_x);
4367 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4368 x_append_glyph_string_lists (&head, &tail, h, t);
4369 if (real_end)
4370 *real_end = i;
4371 }
dc6f92b8 4372
06a2c219
GM
4373 /* Append glyph strings for glyphs following the last glyph
4374 string tail that overwrite tail. The foreground of such
4375 glyphs has to be drawn because it writes into the background
4376 of tail. The background must not be drawn because it could
4377 paint over the foreground of following glyphs. */
4378 i = x_right_overwriting (tail);
4379 if (i >= 0)
4380 {
4381 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
4382 DRAW_NORMAL_TEXT, x, last_x);
4383 for (s = h; s; s = s->next)
4384 s->background_filled_p = 1;
4385 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4386 x_append_glyph_string_lists (&head, &tail, h, t);
4387 if (real_end)
4388 *real_end = i;
4389 }
4390 }
58769bee 4391
06a2c219
GM
4392 /* Draw all strings. */
4393 for (s = head; s; s = s->next)
4394 x_draw_glyph_string (s);
dc6f92b8 4395
06a2c219
GM
4396 /* Value is the x-position up to which drawn, relative to AREA of W.
4397 This doesn't include parts drawn because of overhangs. */
4398 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
4399 if (!row->full_width_p)
4400 {
4401 if (area > LEFT_MARGIN_AREA)
4402 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
4403 if (area > TEXT_AREA)
4404 x_reached -= window_box_width (w, TEXT_AREA);
4405 }
4406 return x_reached;
4407}
dc6f92b8 4408
dc6f92b8 4409
06a2c219
GM
4410/* Output LEN glyphs starting at START at the nominal cursor position.
4411 Advance the nominal cursor over the text. The global variable
4412 updated_window contains the window being updated, updated_row is
4413 the glyph row being updated, and updated_area is the area of that
4414 row being updated. */
dc6f92b8 4415
06a2c219
GM
4416static void
4417x_write_glyphs (start, len)
4418 struct glyph *start;
4419 int len;
4420{
4421 int x, hpos, real_start, real_end;
d9cdbb3d 4422
06a2c219 4423 xassert (updated_window && updated_row);
dc6f92b8 4424 BLOCK_INPUT;
06a2c219
GM
4425
4426 /* Write glyphs. */
dc6f92b8 4427
06a2c219
GM
4428 hpos = start - updated_row->glyphs[updated_area];
4429 x = x_draw_glyphs (updated_window, output_cursor.x,
4430 updated_row, updated_area,
4431 hpos, hpos + len,
4432 (updated_row->inverse_p
4433 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
4434 &real_start, &real_end);
b30ec466 4435
06a2c219
GM
4436 /* If we drew over the cursor, note that it is not visible any more. */
4437 note_overwritten_text_cursor (updated_window, real_start,
4438 real_end - real_start);
dc6f92b8
JB
4439
4440 UNBLOCK_INPUT;
06a2c219
GM
4441
4442 /* Advance the output cursor. */
4443 output_cursor.hpos += len;
4444 output_cursor.x = x;
dc6f92b8
JB
4445}
4446
0cdd0c9f 4447
06a2c219 4448/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 4449
06a2c219
GM
4450static void
4451x_insert_glyphs (start, len)
4452 struct glyph *start;
4453 register int len;
4454{
4455 struct frame *f;
4456 struct window *w;
4457 int line_height, shift_by_width, shifted_region_width;
4458 struct glyph_row *row;
4459 struct glyph *glyph;
4460 int frame_x, frame_y, hpos, real_start, real_end;
58769bee 4461
06a2c219 4462 xassert (updated_window && updated_row);
0cdd0c9f 4463 BLOCK_INPUT;
06a2c219
GM
4464 w = updated_window;
4465 f = XFRAME (WINDOW_FRAME (w));
4466
4467 /* Get the height of the line we are in. */
4468 row = updated_row;
4469 line_height = row->height;
4470
4471 /* Get the width of the glyphs to insert. */
4472 shift_by_width = 0;
4473 for (glyph = start; glyph < start + len; ++glyph)
4474 shift_by_width += glyph->pixel_width;
4475
4476 /* Get the width of the region to shift right. */
4477 shifted_region_width = (window_box_width (w, updated_area)
4478 - output_cursor.x
4479 - shift_by_width);
4480
4481 /* Shift right. */
4482 frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x);
4483 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
4484 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
4485 f->output_data.x->normal_gc,
4486 frame_x, frame_y,
4487 shifted_region_width, line_height,
4488 frame_x + shift_by_width, frame_y);
4489
4490 /* Write the glyphs. */
4491 hpos = start - row->glyphs[updated_area];
4492 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
4493 DRAW_NORMAL_TEXT, &real_start, &real_end);
4494 note_overwritten_text_cursor (w, real_start, real_end - real_start);
4495
4496 /* Advance the output cursor. */
4497 output_cursor.hpos += len;
4498 output_cursor.x += shift_by_width;
0cdd0c9f
RS
4499 UNBLOCK_INPUT;
4500}
0cdd0c9f 4501
0cdd0c9f 4502
06a2c219
GM
4503/* Delete N glyphs at the nominal cursor position. Not implemented
4504 for X frames. */
c83febd7
RS
4505
4506static void
06a2c219
GM
4507x_delete_glyphs (n)
4508 register int n;
c83febd7 4509{
06a2c219 4510 abort ();
c83febd7
RS
4511}
4512
0cdd0c9f 4513
06a2c219
GM
4514/* Erase the current text line from the nominal cursor position
4515 (inclusive) to pixel column TO_X (exclusive). The idea is that
4516 everything from TO_X onward is already erased.
4517
4518 TO_X is a pixel position relative to updated_area of
4519 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 4520
06a2c219
GM
4521static void
4522x_clear_end_of_line (to_x)
4523 int to_x;
4524{
4525 struct frame *f;
4526 struct window *w = updated_window;
4527 int max_x, min_y, max_y;
4528 int from_x, from_y, to_y;
4529
4530 xassert (updated_window && updated_row);
4531 f = XFRAME (w->frame);
4532
4533 if (updated_row->full_width_p)
4534 {
4535 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
4536 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4537 && !w->pseudo_window_p)
4538 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 4539 }
06a2c219
GM
4540 else
4541 max_x = window_box_width (w, updated_area);
4542 max_y = window_text_bottom_y (w);
dc6f92b8 4543
06a2c219
GM
4544 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
4545 of window. For TO_X > 0, truncate to end of drawing area. */
4546 if (to_x == 0)
4547 return;
4548 else if (to_x < 0)
4549 to_x = max_x;
4550 else
4551 to_x = min (to_x, max_x);
dbc4e1c1 4552
06a2c219
GM
4553 to_y = min (max_y, output_cursor.y + updated_row->height);
4554
4555 /* Notice if the cursor will be cleared by this operation. */
4556 if (!updated_row->full_width_p)
4557 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
dbc4e1c1 4558
06a2c219
GM
4559 from_x = output_cursor.x;
4560
4561 /* Translate to frame coordinates. */
4562 if (updated_row->full_width_p)
4563 {
4564 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
4565 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
4566 }
0cdd0c9f
RS
4567 else
4568 {
06a2c219
GM
4569 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
4570 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
4571 }
4572
4573 min_y = WINDOW_DISPLAY_TOP_LINE_HEIGHT (w);
4574 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
4575 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
4576
4577 /* Prevent inadvertently clearing to end of the X window. */
4578 if (to_x > from_x && to_y > from_y)
4579 {
4580 BLOCK_INPUT;
4581 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4582 from_x, from_y, to_x - from_x, to_y - from_y,
4583 False);
4584 UNBLOCK_INPUT;
0cdd0c9f 4585 }
0cdd0c9f 4586}
dbc4e1c1 4587
0cdd0c9f 4588
06a2c219
GM
4589/* Clear entire frame. If updating_frame is non-null, clear that
4590 frame. Otherwise clear selected_frame. */
4591
4592static void
4593x_clear_frame ()
0cdd0c9f 4594{
06a2c219 4595 struct frame *f;
0cdd0c9f 4596
06a2c219
GM
4597 if (updating_frame)
4598 f = updating_frame;
0cdd0c9f 4599 else
06a2c219 4600 f = selected_frame;
58769bee 4601
06a2c219
GM
4602 /* Clearing the frame will erase any cursor, so mark them all as no
4603 longer visible. */
4604 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4605 output_cursor.hpos = output_cursor.vpos = 0;
4606 output_cursor.x = -1;
4607
4608 /* We don't set the output cursor here because there will always
4609 follow an explicit cursor_to. */
4610 BLOCK_INPUT;
4611 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
4612
4613 /* We have to clear the scroll bars, too. If we have changed
4614 colors or something like that, then they should be notified. */
4615 x_scroll_bar_clear (f);
0cdd0c9f 4616
06a2c219
GM
4617 XFlush (FRAME_X_DISPLAY (f));
4618 UNBLOCK_INPUT;
dc6f92b8 4619}
06a2c219
GM
4620
4621
dc6f92b8 4622\f
dbc4e1c1
JB
4623/* Invert the middle quarter of the frame for .15 sec. */
4624
06a2c219
GM
4625/* We use the select system call to do the waiting, so we have to make
4626 sure it's available. If it isn't, we just won't do visual bells. */
4627
dbc4e1c1
JB
4628#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
4629
06a2c219
GM
4630
4631/* Subtract the `struct timeval' values X and Y, storing the result in
4632 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
4633
4634static int
4635timeval_subtract (result, x, y)
4636 struct timeval *result, x, y;
4637{
06a2c219
GM
4638 /* Perform the carry for the later subtraction by updating y. This
4639 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
4640 if (x.tv_usec < y.tv_usec)
4641 {
4642 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
4643 y.tv_usec -= 1000000 * nsec;
4644 y.tv_sec += nsec;
4645 }
06a2c219 4646
dbc4e1c1
JB
4647 if (x.tv_usec - y.tv_usec > 1000000)
4648 {
4649 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
4650 y.tv_usec += 1000000 * nsec;
4651 y.tv_sec -= nsec;
4652 }
4653
06a2c219
GM
4654 /* Compute the time remaining to wait. tv_usec is certainly
4655 positive. */
dbc4e1c1
JB
4656 result->tv_sec = x.tv_sec - y.tv_sec;
4657 result->tv_usec = x.tv_usec - y.tv_usec;
4658
06a2c219
GM
4659 /* Return indication of whether the result should be considered
4660 negative. */
dbc4e1c1
JB
4661 return x.tv_sec < y.tv_sec;
4662}
dc6f92b8 4663
dfcf069d 4664void
f676886a
JB
4665XTflash (f)
4666 struct frame *f;
dc6f92b8 4667{
dbc4e1c1 4668 BLOCK_INPUT;
dc6f92b8 4669
dbc4e1c1
JB
4670 {
4671 GC gc;
dc6f92b8 4672
06a2c219
GM
4673 /* Create a GC that will use the GXxor function to flip foreground
4674 pixels into background pixels. */
dbc4e1c1
JB
4675 {
4676 XGCValues values;
dc6f92b8 4677
dbc4e1c1 4678 values.function = GXxor;
7556890b
RS
4679 values.foreground = (f->output_data.x->foreground_pixel
4680 ^ f->output_data.x->background_pixel);
58769bee 4681
334208b7 4682 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
4683 GCFunction | GCForeground, &values);
4684 }
dc6f92b8 4685
dbc4e1c1 4686 {
e84e14c3
RS
4687 /* Get the height not including a menu bar widget. */
4688 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
4689 /* Height of each line to flash. */
4690 int flash_height = FRAME_LINE_HEIGHT (f);
4691 /* These will be the left and right margins of the rectangles. */
4692 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
4693 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
4694
4695 int width;
4696
4697 /* Don't flash the area between a scroll bar and the frame
4698 edge it is next to. */
4699 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
4700 {
4701 case vertical_scroll_bar_left:
4702 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4703 break;
4704
4705 case vertical_scroll_bar_right:
4706 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
4707 break;
06a2c219
GM
4708
4709 default:
4710 break;
e84e14c3
RS
4711 }
4712
4713 width = flash_right - flash_left;
4714
4715 /* If window is tall, flash top and bottom line. */
4716 if (height > 3 * FRAME_LINE_HEIGHT (f))
4717 {
4718 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
4719 flash_left,
4720 (FRAME_INTERNAL_BORDER_WIDTH (f)
4721 + FRAME_TOOLBAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
4722 width, flash_height);
4723 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4724 flash_left,
4725 (height - flash_height
4726 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4727 width, flash_height);
4728 }
4729 else
4730 /* If it is short, flash it all. */
4731 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4732 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4733 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 4734
06a2c219 4735 x_flush (f);
dc6f92b8 4736
dbc4e1c1 4737 {
06a2c219 4738 struct timeval wakeup;
dc6f92b8 4739
66c30ea1 4740 EMACS_GET_TIME (wakeup);
dc6f92b8 4741
dbc4e1c1
JB
4742 /* Compute time to wait until, propagating carry from usecs. */
4743 wakeup.tv_usec += 150000;
4744 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
4745 wakeup.tv_usec %= 1000000;
4746
4747 /* Keep waiting until past the time wakeup. */
4748 while (1)
4749 {
4750 struct timeval timeout;
4751
66c30ea1 4752 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
4753
4754 /* In effect, timeout = wakeup - timeout.
4755 Break if result would be negative. */
4756 if (timeval_subtract (&timeout, wakeup, timeout))
4757 break;
4758
4759 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 4760 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
4761 }
4762 }
58769bee 4763
e84e14c3
RS
4764 /* If window is tall, flash top and bottom line. */
4765 if (height > 3 * FRAME_LINE_HEIGHT (f))
4766 {
4767 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
4768 flash_left,
4769 (FRAME_INTERNAL_BORDER_WIDTH (f)
4770 + FRAME_TOOLBAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
4771 width, flash_height);
4772 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4773 flash_left,
4774 (height - flash_height
4775 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4776 width, flash_height);
4777 }
4778 else
4779 /* If it is short, flash it all. */
4780 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4781 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4782 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4783
334208b7 4784 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 4785 x_flush (f);
dc6f92b8 4786 }
dbc4e1c1
JB
4787 }
4788
4789 UNBLOCK_INPUT;
dc6f92b8
JB
4790}
4791
06a2c219 4792#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
4793
4794
dc6f92b8
JB
4795/* Make audible bell. */
4796
334208b7 4797#define XRINGBELL XBell (FRAME_X_DISPLAY (selected_frame), 0)
dc6f92b8 4798
dfcf069d 4799void
dc6f92b8
JB
4800XTring_bell ()
4801{
334208b7 4802 if (FRAME_X_DISPLAY (selected_frame) == 0)
5a6ef893
RS
4803 return;
4804
dbc4e1c1 4805#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
dc6f92b8 4806 if (visible_bell)
f676886a 4807 XTflash (selected_frame);
dc6f92b8 4808 else
dbc4e1c1 4809#endif
dc6f92b8
JB
4810 {
4811 BLOCK_INPUT;
4812 XRINGBELL;
334208b7 4813 XFlush (FRAME_X_DISPLAY (selected_frame));
dc6f92b8
JB
4814 UNBLOCK_INPUT;
4815 }
4816}
06a2c219 4817
dc6f92b8 4818\f
06a2c219
GM
4819/* Specify how many text lines, from the top of the window,
4820 should be affected by insert-lines and delete-lines operations.
4821 This, and those operations, are used only within an update
4822 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 4823
dfcf069d 4824static void
06a2c219
GM
4825XTset_terminal_window (n)
4826 register int n;
dc6f92b8 4827{
06a2c219 4828 /* This function intentionally left blank. */
dc6f92b8
JB
4829}
4830
06a2c219
GM
4831
4832\f
4833/***********************************************************************
4834 Line Dance
4835 ***********************************************************************/
4836
4837/* Perform an insert-lines or delete-lines operation, inserting N
4838 lines or deleting -N lines at vertical position VPOS. */
4839
dfcf069d 4840static void
06a2c219
GM
4841x_ins_del_lines (vpos, n)
4842 int vpos, n;
dc6f92b8
JB
4843{
4844 abort ();
4845}
06a2c219
GM
4846
4847
4848/* Scroll part of the display as described by RUN. */
dc6f92b8 4849
dfcf069d 4850static void
06a2c219
GM
4851x_scroll_run (w, run)
4852 struct window *w;
4853 struct run *run;
dc6f92b8 4854{
06a2c219
GM
4855 struct frame *f = XFRAME (w->frame);
4856 int x, y, width, height, from_y, to_y, bottom_y;
4857
4858 /* Get frame-relative bounding box of the text display area of W,
4859 without mode lines. Include in this box the flags areas to the
4860 left and right of W. */
4861 window_box (w, -1, &x, &y, &width, &height);
4862 width += 2 * FRAME_X_FLAGS_AREA_WIDTH (f);
4863 x -= FRAME_X_FLAGS_AREA_WIDTH (f);
4864
4865 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4866 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4867 bottom_y = y + height;
dc6f92b8 4868
06a2c219
GM
4869 if (to_y < from_y)
4870 {
4871 /* Scrolling up. Make sure we don't copy part of the mode
4872 line at the bottom. */
4873 if (from_y + run->height > bottom_y)
4874 height = bottom_y - from_y;
4875 else
4876 height = run->height;
4877 }
dc6f92b8 4878 else
06a2c219
GM
4879 {
4880 /* Scolling down. Make sure we don't copy over the mode line.
4881 at the bottom. */
4882 if (to_y + run->height > bottom_y)
4883 height = bottom_y - to_y;
4884 else
4885 height = run->height;
4886 }
7a13e894 4887
06a2c219
GM
4888 BLOCK_INPUT;
4889
4890 /* Cursor off. Will be switched on again in x_update_window_end. */
4891 updated_window = w;
4892 x_clear_cursor (w);
4893
4894 XCopyArea (FRAME_X_DISPLAY (f),
4895 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
4896 f->output_data.x->normal_gc,
4897 x, from_y,
4898 width, height,
4899 x, to_y);
4900
4901 UNBLOCK_INPUT;
4902}
dc6f92b8 4903
dc6f92b8 4904
06a2c219
GM
4905\f
4906/***********************************************************************
4907 Exposure Events
4908 ***********************************************************************/
4909
4910/* Redisplay an exposed area of frame F. X and Y are the upper-left
4911 corner of the exposed rectangle. W and H are width and height of
4912 the exposed area. All are pixel values. W or H zero means redraw
4913 the entire frame. */
dc6f92b8 4914
06a2c219
GM
4915static void
4916expose_frame (f, x, y, w, h)
4917 struct frame *f;
4918 int x, y, w, h;
dc6f92b8 4919{
06a2c219 4920 XRectangle r;
dc6f92b8 4921
06a2c219 4922 TRACE ((stderr, "expose_frame "));
dc6f92b8 4923
06a2c219
GM
4924 /* No need to redraw if frame will be redrawn soon. */
4925 if (FRAME_GARBAGED_P (f))
dc6f92b8 4926 {
06a2c219
GM
4927 TRACE ((stderr, " garbaged\n"));
4928 return;
4929 }
4930
4931 /* If basic faces haven't been realized yet, there is no point in
4932 trying to redraw anything. This can happen when we get an expose
4933 event while Emacs is starting, e.g. by moving another window. */
4934 if (FRAME_FACE_CACHE (f) == NULL
4935 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
4936 {
4937 TRACE ((stderr, " no faces\n"));
4938 return;
58769bee 4939 }
06a2c219
GM
4940
4941 if (w == 0 || h == 0)
58769bee 4942 {
06a2c219
GM
4943 r.x = r.y = 0;
4944 r.width = CANON_X_UNIT (f) * f->width;
4945 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
4946 }
4947 else
4948 {
06a2c219
GM
4949 r.x = x;
4950 r.y = y;
4951 r.width = w;
4952 r.height = h;
4953 }
4954
4955 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
4956 expose_window_tree (XWINDOW (f->root_window), &r);
4957
4958 if (WINDOWP (f->toolbar_window))
4959 {
4960 struct window *w = XWINDOW (f->toolbar_window);
4961 XRectangle window_rect;
4962 XRectangle intersection_rect;
4963 int window_x, window_y, window_width, window_height;
4964
4965
4966 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
4967 window_rect.x = window_x;
4968 window_rect.y = window_y;
4969 window_rect.width = window_width;
4970 window_rect.height = window_height;
4971
4972 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
4973 expose_window (w, &intersection_rect);
4974 }
4975
4976#ifndef USE_X_TOOLKIT
4977 if (WINDOWP (f->menu_bar_window))
4978 {
4979 struct window *w = XWINDOW (f->menu_bar_window);
4980 XRectangle window_rect;
4981 XRectangle intersection_rect;
4982 int window_x, window_y, window_width, window_height;
4983
4984
4985 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
4986 window_rect.x = window_x;
4987 window_rect.y = window_y;
4988 window_rect.width = window_width;
4989 window_rect.height = window_height;
4990
4991 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
4992 expose_window (w, &intersection_rect);
dc6f92b8 4993 }
06a2c219 4994#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
4995}
4996
06a2c219
GM
4997
4998/* Redraw (parts) of all windows in the window tree rooted at W that
4999 intersect R. R contains frame pixel coordinates. */
5000
58769bee 5001static void
06a2c219
GM
5002expose_window_tree (w, r)
5003 struct window *w;
5004 XRectangle *r;
dc6f92b8 5005{
06a2c219
GM
5006 while (w)
5007 {
5008 if (!NILP (w->hchild))
5009 expose_window_tree (XWINDOW (w->hchild), r);
5010 else if (!NILP (w->vchild))
5011 expose_window_tree (XWINDOW (w->vchild), r);
5012 else
5013 {
5014 XRectangle window_rect;
5015 XRectangle intersection_rect;
5016 struct frame *f = XFRAME (w->frame);
5017 int window_x, window_y, window_width, window_height;
5018
5019 /* Frame-relative pixel rectangle of W. */
5020 window_box (w, -1, &window_x, &window_y, &window_width,
5021 &window_height);
5022 window_rect.x
5023 = (window_x
5024 - FRAME_X_FLAGS_AREA_WIDTH (f)
5025 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_Y_UNIT (f));
5026 window_rect.y = window_y;
5027 window_rect.width
5028 = (window_width
5029 + 2 * FRAME_X_FLAGS_AREA_WIDTH (f)
5030 + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
5031 window_rect.height
5032 = window_height + CURRENT_MODE_LINE_HEIGHT (w);
5033
5034 if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
5035 expose_window (w, &intersection_rect);
5036 }
58769bee 5037
06a2c219
GM
5038 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5039 }
5040}
58769bee 5041
dc6f92b8 5042
06a2c219
GM
5043/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5044 which intersects rectangle R. R is in window-relative coordinates. */
5045
5046static void
5047expose_area (w, row, r, area)
5048 struct window *w;
5049 struct glyph_row *row;
5050 XRectangle *r;
5051 enum glyph_row_area area;
5052{
5053 int x;
5054 struct glyph *first = row->glyphs[area];
5055 struct glyph *end = row->glyphs[area] + row->used[area];
5056 struct glyph *last;
5057 int first_x;
5058
5059 /* Set x to the window-relative start position for drawing glyphs of
5060 AREA. The first glyph of the text area can be partially visible.
5061 The first glyphs of other areas cannot. */
5062 if (area == LEFT_MARGIN_AREA)
5063 x = 0;
5064 else if (area == TEXT_AREA)
5065 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5066 else
5067 x = (window_box_width (w, LEFT_MARGIN_AREA)
5068 + window_box_width (w, TEXT_AREA));
5069
5070 /* Find the first glyph that must be redrawn. */
5071 while (first < end
5072 && x + first->pixel_width < r->x)
5073 {
5074 x += first->pixel_width;
5075 ++first;
5076 }
5077
5078 /* Find the last one. */
5079 last = first;
5080 first_x = x;
5081 while (last < end
5082 && x < r->x + r->width)
5083 {
5084 x += last->pixel_width;
5085 ++last;
5086 }
5087
5088 /* Repaint. */
5089 if (last > first)
5090 x_draw_glyphs (w, first_x, row, area,
5091 first - row->glyphs[area],
5092 last - row->glyphs[area],
5093 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5094 NULL, NULL);
5095}
5096
58769bee 5097
06a2c219
GM
5098/* Redraw the parts of the glyph row ROW on window W intersecting
5099 rectangle R. R is in window-relative coordinates. */
dc6f92b8 5100
06a2c219
GM
5101static void
5102expose_line (w, row, r)
5103 struct window *w;
5104 struct glyph_row *row;
5105 XRectangle *r;
5106{
5107 xassert (row->enabled_p);
5108
5109 if (row->mode_line_p || w->pseudo_window_p)
5110 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5111 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5112 NULL, NULL);
5113 else
5114 {
5115 if (row->used[LEFT_MARGIN_AREA])
5116 expose_area (w, row, r, LEFT_MARGIN_AREA);
5117 if (row->used[TEXT_AREA])
5118 expose_area (w, row, r, TEXT_AREA);
5119 if (row->used[RIGHT_MARGIN_AREA])
5120 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5121 x_draw_row_bitmaps (w, row);
5122 }
5123}
dc6f92b8 5124
58769bee 5125
06a2c219
GM
5126/* Return non-zero if W's cursor intersects rectangle R. */
5127
5128static int
5129x_phys_cursor_in_rect_p (w, r)
5130 struct window *w;
5131 XRectangle *r;
5132{
5133 XRectangle cr, result;
5134 struct glyph *cursor_glyph;
5135
5136 cursor_glyph = get_phys_cursor_glyph (w);
5137 if (cursor_glyph)
5138 {
5139 cr.x = w->phys_cursor.x;
5140 cr.y = w->phys_cursor.y;
5141 cr.width = cursor_glyph->pixel_width;
5142 cr.height = w->phys_cursor_height;
5143 return x_intersect_rectangles (&cr, r, &result);
5144 }
5145 else
5146 return 0;
dc6f92b8 5147}
dc6f92b8 5148
06a2c219
GM
5149
5150/* Redraw a rectangle of window W. R is a rectangle in window
5151 relative coordinates. Call this function with input blocked. */
dc6f92b8
JB
5152
5153static void
06a2c219
GM
5154expose_window (w, r)
5155 struct window *w;
5156 XRectangle *r;
dc6f92b8 5157{
06a2c219
GM
5158 struct glyph_row *row;
5159 int y;
5160 int yb = window_text_bottom_y (w);
5161 int cursor_cleared_p;
dc6f92b8 5162
06a2c219
GM
5163 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
5164 r->x, r->y, r->width, r->height));
dc6f92b8 5165
06a2c219
GM
5166 /* Convert to window coordinates. */
5167 r->x = FRAME_TO_WINDOW_PIXEL_X (w, r->x);
5168 r->y = FRAME_TO_WINDOW_PIXEL_Y (w, r->y);
dc6f92b8 5169
06a2c219
GM
5170 /* Turn off the cursor. */
5171 if (!w->pseudo_window_p
5172 && x_phys_cursor_in_rect_p (w, r))
5173 {
5174 x_clear_cursor (w);
5175 cursor_cleared_p = 1;
5176 }
5177 else
5178 cursor_cleared_p = 0;
5179
5180 /* Find the first row intersecting the rectangle R. */
5181 row = w->current_matrix->rows;
5182 y = 0;
5183 while (row->enabled_p
5184 && y < yb
5185 && y + row->height < r->y)
5186 {
5187 y += row->height;
5188 ++row;
5189 }
5190
dc6f92b8 5191 /* Display the text in the rectangle, one text line at a time. */
06a2c219
GM
5192 while (row->enabled_p
5193 && y < yb
5194 && y < r->y + r->height)
5195 {
5196 expose_line (w, row, r);
5197 y += row->height;
5198 ++row;
5199 }
5200
5201 /* Display the mode line if there is one. */
5202 if (WINDOW_WANTS_MODELINE_P (w)
5203 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
5204 row->enabled_p)
5205 && row->y < r->y + r->height)
5206 expose_line (w, row, r);
dc6f92b8 5207
06a2c219 5208 if (!w->pseudo_window_p)
dc6f92b8 5209 {
06a2c219
GM
5210 /* Draw border between windows. */
5211 x_draw_vertical_border (w);
5212
5213 /* Turn the cursor on again. */
5214 if (cursor_cleared_p)
5215 x_update_window_cursor (w, 1);
5216 }
5217}
dc6f92b8 5218
dc6f92b8 5219
06a2c219
GM
5220/* Determine the intersection of two rectangles R1 and R2. Return
5221 the intersection in *RESULT. Value is non-zero if RESULT is not
5222 empty. */
5223
5224static int
5225x_intersect_rectangles (r1, r2, result)
5226 XRectangle *r1, *r2, *result;
5227{
5228 XRectangle *left, *right;
5229 XRectangle *upper, *lower;
5230 int intersection_p = 0;
5231
5232 /* Rearrange so that R1 is the left-most rectangle. */
5233 if (r1->x < r2->x)
5234 left = r1, right = r2;
5235 else
5236 left = r2, right = r1;
5237
5238 /* X0 of the intersection is right.x0, if this is inside R1,
5239 otherwise there is no intersection. */
5240 if (right->x <= left->x + left->width)
5241 {
5242 result->x = right->x;
5243
5244 /* The right end of the intersection is the minimum of the
5245 the right ends of left and right. */
5246 result->width = (min (left->x + left->width, right->x + right->width)
5247 - result->x);
5248
5249 /* Same game for Y. */
5250 if (r1->y < r2->y)
5251 upper = r1, lower = r2;
5252 else
5253 upper = r2, lower = r1;
5254
5255 /* The upper end of the intersection is lower.y0, if this is inside
5256 of upper. Otherwise, there is no intersection. */
5257 if (lower->y <= upper->y + upper->height)
dc43ef94 5258 {
06a2c219
GM
5259 result->y = lower->y;
5260
5261 /* The lower end of the intersection is the minimum of the lower
5262 ends of upper and lower. */
5263 result->height = (min (lower->y + lower->height,
5264 upper->y + upper->height)
5265 - result->y);
5266 intersection_p = 1;
dc43ef94 5267 }
dc6f92b8
JB
5268 }
5269
06a2c219 5270 return intersection_p;
dc6f92b8 5271}
06a2c219
GM
5272
5273
5274
5275
dc6f92b8 5276\f
dc6f92b8 5277static void
334208b7
RS
5278frame_highlight (f)
5279 struct frame *f;
dc6f92b8 5280{
b3e1e05c
JB
5281 /* We used to only do this if Vx_no_window_manager was non-nil, but
5282 the ICCCM (section 4.1.6) says that the window's border pixmap
5283 and border pixel are window attributes which are "private to the
5284 client", so we can always change it to whatever we want. */
5285 BLOCK_INPUT;
334208b7 5286 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5287 f->output_data.x->border_pixel);
b3e1e05c 5288 UNBLOCK_INPUT;
5d46f928 5289 x_update_cursor (f, 1);
dc6f92b8
JB
5290}
5291
5292static void
334208b7
RS
5293frame_unhighlight (f)
5294 struct frame *f;
dc6f92b8 5295{
b3e1e05c
JB
5296 /* We used to only do this if Vx_no_window_manager was non-nil, but
5297 the ICCCM (section 4.1.6) says that the window's border pixmap
5298 and border pixel are window attributes which are "private to the
5299 client", so we can always change it to whatever we want. */
5300 BLOCK_INPUT;
334208b7 5301 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5302 f->output_data.x->border_tile);
b3e1e05c 5303 UNBLOCK_INPUT;
5d46f928 5304 x_update_cursor (f, 1);
dc6f92b8 5305}
dc6f92b8 5306
f676886a
JB
5307/* The focus has changed. Update the frames as necessary to reflect
5308 the new situation. Note that we can't change the selected frame
c5acd733 5309 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 5310 Each event gets marked with the frame in which it occurred, so the
c5acd733 5311 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 5312
6d4238f3 5313static void
0f941935
KH
5314x_new_focus_frame (dpyinfo, frame)
5315 struct x_display_info *dpyinfo;
f676886a 5316 struct frame *frame;
dc6f92b8 5317{
0f941935 5318 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 5319
0f941935 5320 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 5321 {
58769bee 5322 /* Set this before calling other routines, so that they see
f676886a 5323 the correct value of x_focus_frame. */
0f941935 5324 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
5325
5326 if (old_focus && old_focus->auto_lower)
f676886a 5327 x_lower_frame (old_focus);
dc6f92b8
JB
5328
5329#if 0
f676886a 5330 selected_frame = frame;
e0c1aef2
KH
5331 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
5332 selected_frame);
f676886a
JB
5333 Fselect_window (selected_frame->selected_window);
5334 choose_minibuf_frame ();
c118dd06 5335#endif /* ! 0 */
dc6f92b8 5336
0f941935
KH
5337 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
5338 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
5339 else
5340 pending_autoraise_frame = 0;
6d4238f3 5341 }
dc6f92b8 5342
0f941935 5343 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
5344}
5345
37c2c98b
RS
5346/* Handle an event saying the mouse has moved out of an Emacs frame. */
5347
5348void
0f941935
KH
5349x_mouse_leave (dpyinfo)
5350 struct x_display_info *dpyinfo;
37c2c98b 5351{
0f941935 5352 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 5353}
6d4238f3 5354
f451eb13
JB
5355/* The focus has changed, or we have redirected a frame's focus to
5356 another frame (this happens when a frame uses a surrogate
06a2c219 5357 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
5358
5359 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 5360 frame is being highlighted or un-highlighted; we only use it to find
0f941935 5361 the appropriate X display info. */
06a2c219 5362
6d4238f3 5363static void
0f941935
KH
5364XTframe_rehighlight (frame)
5365 struct frame *frame;
6d4238f3 5366{
0f941935
KH
5367 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
5368}
6d4238f3 5369
0f941935
KH
5370static void
5371x_frame_rehighlight (dpyinfo)
5372 struct x_display_info *dpyinfo;
5373{
5374 struct frame *old_highlight = dpyinfo->x_highlight_frame;
5375
5376 if (dpyinfo->x_focus_frame)
6d4238f3 5377 {
0f941935
KH
5378 dpyinfo->x_highlight_frame
5379 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
5380 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
5381 : dpyinfo->x_focus_frame);
5382 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 5383 {
0f941935
KH
5384 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
5385 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 5386 }
dc6f92b8 5387 }
6d4238f3 5388 else
0f941935 5389 dpyinfo->x_highlight_frame = 0;
dc6f92b8 5390
0f941935 5391 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
5392 {
5393 if (old_highlight)
f676886a 5394 frame_unhighlight (old_highlight);
0f941935
KH
5395 if (dpyinfo->x_highlight_frame)
5396 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 5397 }
dc6f92b8 5398}
06a2c219
GM
5399
5400
dc6f92b8 5401\f
06a2c219 5402/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 5403
28430d3c
JB
5404/* Initialize mode_switch_bit and modifier_meaning. */
5405static void
334208b7
RS
5406x_find_modifier_meanings (dpyinfo)
5407 struct x_display_info *dpyinfo;
28430d3c 5408{
f689eb05 5409 int min_code, max_code;
28430d3c
JB
5410 KeySym *syms;
5411 int syms_per_code;
5412 XModifierKeymap *mods;
5413
334208b7
RS
5414 dpyinfo->meta_mod_mask = 0;
5415 dpyinfo->shift_lock_mask = 0;
5416 dpyinfo->alt_mod_mask = 0;
5417 dpyinfo->super_mod_mask = 0;
5418 dpyinfo->hyper_mod_mask = 0;
58769bee 5419
9658a521 5420#ifdef HAVE_X11R4
334208b7 5421 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 5422#else
4a60f8c5
RS
5423 min_code = dpyinfo->display->min_keycode;
5424 max_code = dpyinfo->display->max_keycode;
9658a521
JB
5425#endif
5426
334208b7 5427 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
5428 min_code, max_code - min_code + 1,
5429 &syms_per_code);
334208b7 5430 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 5431
58769bee 5432 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 5433 Alt keysyms are on. */
28430d3c 5434 {
06a2c219 5435 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
5436
5437 for (row = 3; row < 8; row++)
5438 for (col = 0; col < mods->max_keypermod; col++)
5439 {
0299d313
RS
5440 KeyCode code
5441 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 5442
af92970c
KH
5443 /* Zeroes are used for filler. Skip them. */
5444 if (code == 0)
5445 continue;
5446
28430d3c
JB
5447 /* Are any of this keycode's keysyms a meta key? */
5448 {
5449 int code_col;
5450
5451 for (code_col = 0; code_col < syms_per_code; code_col++)
5452 {
f689eb05 5453 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 5454
f689eb05 5455 switch (sym)
28430d3c 5456 {
f689eb05
JB
5457 case XK_Meta_L:
5458 case XK_Meta_R:
334208b7 5459 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 5460 break;
f689eb05
JB
5461
5462 case XK_Alt_L:
5463 case XK_Alt_R:
334208b7 5464 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
5465 break;
5466
5467 case XK_Hyper_L:
5468 case XK_Hyper_R:
334208b7 5469 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
5470 break;
5471
5472 case XK_Super_L:
5473 case XK_Super_R:
334208b7 5474 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 5475 break;
11edeb03
JB
5476
5477 case XK_Shift_Lock:
5478 /* Ignore this if it's not on the lock modifier. */
5479 if ((1 << row) == LockMask)
334208b7 5480 dpyinfo->shift_lock_mask = LockMask;
11edeb03 5481 break;
28430d3c
JB
5482 }
5483 }
5484 }
5485 }
5486 }
5487
f689eb05 5488 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 5489 if (! dpyinfo->meta_mod_mask)
a3c44b14 5490 {
334208b7
RS
5491 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
5492 dpyinfo->alt_mod_mask = 0;
a3c44b14 5493 }
f689eb05 5494
148c4b70
RS
5495 /* If some keys are both alt and meta,
5496 make them just meta, not alt. */
334208b7 5497 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 5498 {
334208b7 5499 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 5500 }
58769bee 5501
28430d3c 5502 XFree ((char *) syms);
f689eb05 5503 XFreeModifiermap (mods);
28430d3c
JB
5504}
5505
dfeccd2d
JB
5506/* Convert between the modifier bits X uses and the modifier bits
5507 Emacs uses. */
06a2c219 5508
7c5283e4 5509static unsigned int
334208b7
RS
5510x_x_to_emacs_modifiers (dpyinfo, state)
5511 struct x_display_info *dpyinfo;
dc6f92b8
JB
5512 unsigned int state;
5513{
334208b7
RS
5514 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
5515 | ((state & ControlMask) ? ctrl_modifier : 0)
5516 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
5517 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
5518 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
5519 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
5520}
5521
dfeccd2d 5522static unsigned int
334208b7
RS
5523x_emacs_to_x_modifiers (dpyinfo, state)
5524 struct x_display_info *dpyinfo;
dfeccd2d
JB
5525 unsigned int state;
5526{
334208b7
RS
5527 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
5528 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
5529 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
5530 | ((state & shift_modifier) ? ShiftMask : 0)
5531 | ((state & ctrl_modifier) ? ControlMask : 0)
5532 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 5533}
d047c4eb
KH
5534
5535/* Convert a keysym to its name. */
5536
5537char *
5538x_get_keysym_name (keysym)
5539 KeySym keysym;
5540{
5541 char *value;
5542
5543 BLOCK_INPUT;
5544 value = XKeysymToString (keysym);
5545 UNBLOCK_INPUT;
5546
5547 return value;
5548}
06a2c219
GM
5549
5550
e4571a43
JB
5551\f
5552/* Mouse clicks and mouse movement. Rah. */
e4571a43 5553
06a2c219
GM
5554/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
5555 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
5556 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
5557 not force the value into range. */
69388238 5558
c8dba240 5559void
69388238 5560pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 5561 FRAME_PTR f;
69388238 5562 register int pix_x, pix_y;
e4571a43
JB
5563 register int *x, *y;
5564 XRectangle *bounds;
69388238 5565 int noclip;
e4571a43 5566{
06a2c219 5567 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
5568 even for negative values. */
5569 if (pix_x < 0)
7556890b 5570 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 5571 if (pix_y < 0)
7556890b 5572 pix_y -= (f)->output_data.x->line_height - 1;
69388238 5573
e4571a43
JB
5574 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
5575 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
5576
5577 if (bounds)
5578 {
7556890b
RS
5579 bounds->width = FONT_WIDTH (f->output_data.x->font);
5580 bounds->height = f->output_data.x->line_height;
e4571a43
JB
5581 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
5582 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
5583 }
5584
69388238
RS
5585 if (!noclip)
5586 {
5587 if (pix_x < 0)
5588 pix_x = 0;
3cbd2e0b
RS
5589 else if (pix_x > FRAME_WINDOW_WIDTH (f))
5590 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
5591
5592 if (pix_y < 0)
5593 pix_y = 0;
5594 else if (pix_y > f->height)
5595 pix_y = f->height;
5596 }
e4571a43
JB
5597
5598 *x = pix_x;
5599 *y = pix_y;
5600}
5601
06a2c219
GM
5602
5603/* Given HPOS/VPOS in the current matrix of W, return corresponding
5604 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
5605 can't tell the positions because W's display is not up to date,
5606 return 0. */
5607
5608int
5609glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
5610 struct window *w;
5611 int hpos, vpos;
5612 int *frame_x, *frame_y;
2b5c9e71 5613{
06a2c219
GM
5614 int success_p;
5615
5616 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
5617 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
5618
5619 if (display_completed)
5620 {
5621 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
5622 struct glyph *glyph = row->glyphs[TEXT_AREA];
5623 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
5624
5625 *frame_y = row->y;
5626 *frame_x = row->x;
5627 while (glyph < end)
5628 {
5629 *frame_x += glyph->pixel_width;
5630 ++glyph;
5631 }
5632
5633 success_p = 1;
5634 }
5635 else
5636 {
5637 *frame_y = *frame_x = 0;
5638 success_p = 0;
5639 }
5640
5641 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
5642 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
5643 return success_p;
2b5c9e71
RS
5644}
5645
06a2c219 5646
dc6f92b8
JB
5647/* Prepare a mouse-event in *RESULT for placement in the input queue.
5648
5649 If the event is a button press, then note that we have grabbed
f451eb13 5650 the mouse. */
dc6f92b8
JB
5651
5652static Lisp_Object
f451eb13 5653construct_mouse_click (result, event, f)
dc6f92b8
JB
5654 struct input_event *result;
5655 XButtonEvent *event;
f676886a 5656 struct frame *f;
dc6f92b8 5657{
f451eb13 5658 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 5659 otherwise. */
f451eb13 5660 result->kind = mouse_click;
69388238 5661 result->code = event->button - Button1;
1113d9db 5662 result->timestamp = event->time;
334208b7
RS
5663 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
5664 event->state)
f689eb05 5665 | (event->type == ButtonRelease
58769bee 5666 ? up_modifier
f689eb05 5667 : down_modifier));
dc6f92b8 5668
06a2c219
GM
5669 XSETINT (result->x, event->x);
5670 XSETINT (result->y, event->y);
5671 XSETFRAME (result->frame_or_window, f);
5672 return Qnil;
dc6f92b8 5673}
b849c413 5674
06a2c219
GM
5675#if 0 /* This function isn't called. --gerd */
5676
b849c413
RS
5677/* Prepare a menu-event in *RESULT for placement in the input queue. */
5678
5679static Lisp_Object
5680construct_menu_click (result, event, f)
5681 struct input_event *result;
5682 XButtonEvent *event;
5683 struct frame *f;
5684{
5685 /* Make the event type no_event; we'll change that when we decide
5686 otherwise. */
5687 result->kind = mouse_click;
26459b28 5688 result->code = event->button - Button1;
b849c413 5689 result->timestamp = event->time;
334208b7
RS
5690 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
5691 event->state)
b849c413 5692 | (event->type == ButtonRelease
58769bee 5693 ? up_modifier
b849c413
RS
5694 : down_modifier));
5695
e0c1aef2
KH
5696 XSETINT (result->x, event->x);
5697 XSETINT (result->y, -1);
5698 XSETFRAME (result->frame_or_window, f);
b849c413 5699}
06a2c219
GM
5700
5701#endif /* 0 */
5702
69388238 5703\f
90e65f07
JB
5704/* Function to report a mouse movement to the mainstream Emacs code.
5705 The input handler calls this.
5706
5707 We have received a mouse movement event, which is given in *event.
5708 If the mouse is over a different glyph than it was last time, tell
5709 the mainstream emacs code by setting mouse_moved. If not, ask for
5710 another motion event, so we can check again the next time it moves. */
b8009dd1 5711
06a2c219
GM
5712static XMotionEvent last_mouse_motion_event;
5713static Lisp_Object last_mouse_motion_frame;
5714
90e65f07 5715static void
12ba150f 5716note_mouse_movement (frame, event)
f676886a 5717 FRAME_PTR frame;
90e65f07 5718 XMotionEvent *event;
90e65f07 5719{
e5d77022 5720 last_mouse_movement_time = event->time;
06a2c219
GM
5721 last_mouse_motion_event = *event;
5722 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 5723
27f338af
RS
5724 if (event->window != FRAME_X_WINDOW (frame))
5725 {
39d8bb4d 5726 frame->mouse_moved = 1;
27f338af 5727 last_mouse_scroll_bar = Qnil;
27f338af 5728 note_mouse_highlight (frame, -1, -1);
27f338af
RS
5729 }
5730
90e65f07 5731 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
5732 else if (event->x < last_mouse_glyph.x
5733 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
5734 || event->y < last_mouse_glyph.y
5735 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 5736 {
39d8bb4d 5737 frame->mouse_moved = 1;
ab648270 5738 last_mouse_scroll_bar = Qnil;
b8009dd1 5739 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
5740 }
5741}
5742
bf1c0ba1 5743/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 5744
06a2c219
GM
5745 int disable_mouse_highlight;
5746
5747
5748\f
5749/************************************************************************
5750 Mouse Face
5751 ************************************************************************/
5752
5753/* Find the glyph under window-relative coordinates X/Y in window W.
5754 Consider only glyphs from buffer text, i.e. no glyphs from overlay
5755 strings. Return in *HPOS and *VPOS the row and column number of
5756 the glyph found. Return in *AREA the glyph area containing X.
5757 Value is a pointer to the glyph found or null if X/Y is not on
5758 text, or we can't tell because W's current matrix is not up to
5759 date. */
5760
5761static struct glyph *
5762x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
5763 struct window *w;
5764 int x, y;
5765 int *hpos, *vpos, *area;
5766{
5767 struct glyph *glyph, *end;
5768 struct glyph_row *row;
5769 int x0, i, left_area_width;
5770
5771 /* Find row containing Y. Give up if some row is not enabled. */
5772 for (i = 0; i < w->current_matrix->nrows; ++i)
5773 {
5774 row = MATRIX_ROW (w->current_matrix, i);
5775 if (!row->enabled_p)
5776 return NULL;
5777 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
5778 break;
5779 }
5780
5781 *vpos = i;
5782 *hpos = 0;
5783
5784 /* Give up if Y is not in the window. */
5785 if (i == w->current_matrix->nrows)
5786 return NULL;
5787
5788 /* Get the glyph area containing X. */
5789 if (w->pseudo_window_p)
5790 {
5791 *area = TEXT_AREA;
5792 x0 = 0;
5793 }
5794 else
5795 {
5796 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
5797 if (x < left_area_width)
5798 {
5799 *area = LEFT_MARGIN_AREA;
5800 x0 = 0;
5801 }
5802 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
5803 {
5804 *area = TEXT_AREA;
5805 x0 = row->x + left_area_width;
5806 }
5807 else
5808 {
5809 *area = RIGHT_MARGIN_AREA;
5810 x0 = left_area_width + window_box_width (w, TEXT_AREA);
5811 }
5812 }
5813
5814 /* Find glyph containing X. */
5815 glyph = row->glyphs[*area];
5816 end = glyph + row->used[*area];
5817 while (glyph < end)
5818 {
5819 if (x < x0 + glyph->pixel_width)
5820 {
5821 if (w->pseudo_window_p)
5822 break;
5823 else if (BUFFERP (glyph->object))
5824 break;
5825 }
5826
5827 x0 += glyph->pixel_width;
5828 ++glyph;
5829 }
5830
5831 if (glyph == end)
5832 return NULL;
5833
5834 *hpos = glyph - row->glyphs[*area];
5835 return glyph;
5836}
5837
5838
5839/* Convert frame-relative x/y to coordinates relative to window W.
5840 Takes pseudo-windows into account. */
5841
5842static void
5843frame_to_window_pixel_xy (w, x, y)
5844 struct window *w;
5845 int *x, *y;
5846{
5847 if (w->pseudo_window_p)
5848 {
5849 /* A pseudo-window is always full-width, and starts at the
5850 left edge of the frame, plus a frame border. */
5851 struct frame *f = XFRAME (w->frame);
5852 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
5853 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
5854 }
5855 else
5856 {
5857 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
5858 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
5859 }
5860}
5861
5862
5863/* Take proper action when mouse has moved to the mode or top line of
5864 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
5865 mode line. X is relative to the start of the text display area of
5866 W, so the width of bitmap areas and scroll bars must be subtracted
5867 to get a position relative to the start of the mode line. */
5868
5869static void
5870note_mode_line_highlight (w, x, mode_line_p)
5871 struct window *w;
5872 int x, mode_line_p;
5873{
5874 struct frame *f = XFRAME (w->frame);
5875 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5876 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
5877 struct glyph_row *row;
5878
5879 if (mode_line_p)
5880 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
5881 else
5882 row = MATRIX_TOP_LINE_ROW (w->current_matrix);
5883
5884 if (row->enabled_p)
5885 {
5886 struct glyph *glyph, *end;
5887 Lisp_Object help, map;
5888 int x0;
5889
5890 /* Find the glyph under X. */
5891 glyph = row->glyphs[TEXT_AREA];
5892 end = glyph + row->used[TEXT_AREA];
5893 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
5894 + FRAME_X_FLAGS_AREA_WIDTH (f));
5895 while (glyph < end
5896 && x >= x0 + glyph->pixel_width)
5897 {
5898 x0 += glyph->pixel_width;
5899 ++glyph;
5900 }
5901
5902 if (glyph < end
5903 && STRINGP (glyph->object)
5904 && XSTRING (glyph->object)->intervals
5905 && glyph->charpos >= 0
5906 && glyph->charpos < XSTRING (glyph->object)->size)
5907 {
5908 /* If we're on a string with `help-echo' text property,
5909 arrange for the help to be displayed. This is done by
5910 setting the global variable help_echo to the help string. */
5911 help = Fget_text_property (make_number (glyph->charpos),
5912 Qhelp_echo, glyph->object);
5913 if (STRINGP (help))
5914 help_echo = help;
5915
5916 /* Change the mouse pointer according to what is under X/Y. */
5917 map = Fget_text_property (make_number (glyph->charpos),
5918 Qlocal_map, glyph->object);
5919 if (!NILP (Fkeymapp (map)))
5920 cursor = f->output_data.x->nontext_cursor;
5921 }
5922 }
5923
5924 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
5925}
5926
5927
5928/* Take proper action when the mouse has moved to position X, Y on
5929 frame F as regards highlighting characters that have mouse-face
5930 properties. Also de-highlighting chars where the mouse was before.
27f338af 5931 X and Y can be negative or out of range. */
b8009dd1
RS
5932
5933static void
5934note_mouse_highlight (f, x, y)
06a2c219 5935 struct frame *f;
c32cdd9a 5936 int x, y;
b8009dd1 5937{
06a2c219
GM
5938 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5939 int portion;
b8009dd1
RS
5940 Lisp_Object window;
5941 struct window *w;
5942
06a2c219
GM
5943 /* When a menu is active, don't highlight because this looks odd. */
5944#ifdef USE_X_TOOLKIT
5945 if (popup_activated ())
5946 return;
5947#endif
5948
bf1c0ba1
RS
5949 if (disable_mouse_highlight)
5950 return;
5951
06a2c219
GM
5952 dpyinfo->mouse_face_mouse_x = x;
5953 dpyinfo->mouse_face_mouse_y = y;
5954 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 5955
06a2c219 5956 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
5957 return;
5958
514e4681
RS
5959 if (gc_in_progress)
5960 {
06a2c219 5961 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
5962 return;
5963 }
5964
b8009dd1 5965 /* Which window is that in? */
06a2c219 5966 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
5967
5968 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
5969 if (! EQ (window, dpyinfo->mouse_face_window))
5970 clear_mouse_face (dpyinfo);
5971
5972 /* Not on a window -> return. */
5973 if (!WINDOWP (window))
5974 return;
5975
5976 /* Convert to window-relative pixel coordinates. */
5977 w = XWINDOW (window);
5978 frame_to_window_pixel_xy (w, &x, &y);
5979
5980 /* Handle toolbar window differently since it doesn't display a
5981 buffer. */
5982 if (EQ (window, f->toolbar_window))
5983 {
5984 note_toolbar_highlight (f, x, y);
5985 return;
5986 }
5987
5988 if (portion == 1 || portion == 3)
5989 {
5990 /* Mouse is on the mode or top line. */
5991 note_mode_line_highlight (w, x, portion == 1);
5992 return;
5993 }
5994 else
5995 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5996 f->output_data.x->text_cursor);
b8009dd1 5997
0cdd0c9f
RS
5998 /* Are we in a window whose display is up to date?
5999 And verify the buffer's text has not changed. */
06a2c219
GM
6000 if (/* Within text portion of the window. */
6001 portion == 0
0cdd0c9f 6002 && EQ (w->window_end_valid, w->buffer)
26459b28
KH
6003 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
6004 && (XFASTINT (w->last_overlay_modified)
6005 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
b8009dd1 6006 {
06a2c219
GM
6007 int hpos, vpos, pos, i, area;
6008 struct glyph *glyph;
b8009dd1 6009
06a2c219
GM
6010 /* Find the glyph under X/Y. */
6011 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
6012
6013 /* Clear mouse face if X/Y not over text. */
6014 if (glyph == NULL
6015 || area != TEXT_AREA
6016 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6017 {
06a2c219
GM
6018 clear_mouse_face (dpyinfo);
6019 return;
6020 }
6021
6022 pos = glyph->charpos;
6023 xassert (w->pseudo_window_p || BUFFERP (glyph->object));
6024
6025 /* Check for mouse-face and help-echo. */
6026 {
6027 Lisp_Object mouse_face, overlay, position;
6028 Lisp_Object *overlay_vec;
6029 int len, noverlays;
6030 struct buffer *obuf;
6031 int obegv, ozv;
6032
6033 /* If we get an out-of-range value, return now; avoid an error. */
6034 if (pos > BUF_Z (XBUFFER (w->buffer)))
6035 return;
6036
6037 /* Make the window's buffer temporarily current for
6038 overlays_at and compute_char_face. */
6039 obuf = current_buffer;
6040 current_buffer = XBUFFER (w->buffer);
6041 obegv = BEGV;
6042 ozv = ZV;
6043 BEGV = BEG;
6044 ZV = Z;
6045
6046 /* Is this char mouse-active or does it have help-echo? */
6047 XSETINT (position, pos);
6048
6049 /* Put all the overlays we want in a vector in overlay_vec.
6050 Store the length in len. If there are more than 10, make
6051 enough space for all, and try again. */
6052 len = 10;
6053 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6054 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6055 if (noverlays > len)
6056 {
6057 len = noverlays;
6058 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6059 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6060 }
6061
6062 noverlays = sort_overlays (overlay_vec, noverlays, w);
6063
6064 /* Check mouse-face highlighting. */
6065 if (! (EQ (window, dpyinfo->mouse_face_window)
6066 && vpos >= dpyinfo->mouse_face_beg_row
6067 && vpos <= dpyinfo->mouse_face_end_row
6068 && (vpos > dpyinfo->mouse_face_beg_row
6069 || hpos >= dpyinfo->mouse_face_beg_col)
6070 && (vpos < dpyinfo->mouse_face_end_row
6071 || hpos < dpyinfo->mouse_face_end_col
6072 || dpyinfo->mouse_face_past_end)))
6073 {
6074 /* Clear the display of the old active region, if any. */
6075 clear_mouse_face (dpyinfo);
6076
6077 /* Find the highest priority overlay that has a mouse-face prop. */
6078 overlay = Qnil;
6079 for (i = 0; i < noverlays; i++)
6080 {
6081 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6082 if (!NILP (mouse_face))
6083 {
6084 overlay = overlay_vec[i];
6085 break;
6086 }
6087 }
6088
6089 /* If no overlay applies, get a text property. */
6090 if (NILP (overlay))
6091 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6092
6093 /* Handle the overlay case. */
6094 if (! NILP (overlay))
6095 {
6096 /* Find the range of text around this char that
6097 should be active. */
6098 Lisp_Object before, after;
6099 int ignore;
6100
6101 before = Foverlay_start (overlay);
6102 after = Foverlay_end (overlay);
6103 /* Record this as the current active region. */
6104 fast_find_position (w, XFASTINT (before),
6105 &dpyinfo->mouse_face_beg_col,
6106 &dpyinfo->mouse_face_beg_row,
6107 &dpyinfo->mouse_face_beg_x,
6108 &dpyinfo->mouse_face_beg_y);
6109 dpyinfo->mouse_face_past_end
6110 = !fast_find_position (w, XFASTINT (after),
6111 &dpyinfo->mouse_face_end_col,
6112 &dpyinfo->mouse_face_end_row,
6113 &dpyinfo->mouse_face_end_x,
6114 &dpyinfo->mouse_face_end_y);
6115 dpyinfo->mouse_face_window = window;
6116 dpyinfo->mouse_face_face_id
6117 = face_at_buffer_position (w, pos, 0, 0,
6118 &ignore, pos + 1, 1);
6119
6120 /* Display it as active. */
6121 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6122 }
6123 /* Handle the text property case. */
6124 else if (! NILP (mouse_face))
6125 {
6126 /* Find the range of text around this char that
6127 should be active. */
6128 Lisp_Object before, after, beginning, end;
6129 int ignore;
6130
6131 beginning = Fmarker_position (w->start);
6132 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
6133 - XFASTINT (w->window_end_pos)));
6134 before
6135 = Fprevious_single_property_change (make_number (pos + 1),
6136 Qmouse_face,
6137 w->buffer, beginning);
6138 after
6139 = Fnext_single_property_change (position, Qmouse_face,
6140 w->buffer, end);
6141 /* Record this as the current active region. */
6142 fast_find_position (w, XFASTINT (before),
6143 &dpyinfo->mouse_face_beg_col,
6144 &dpyinfo->mouse_face_beg_row,
6145 &dpyinfo->mouse_face_beg_x,
6146 &dpyinfo->mouse_face_beg_y);
6147 dpyinfo->mouse_face_past_end
6148 = !fast_find_position (w, XFASTINT (after),
6149 &dpyinfo->mouse_face_end_col,
6150 &dpyinfo->mouse_face_end_row,
6151 &dpyinfo->mouse_face_end_x,
6152 &dpyinfo->mouse_face_end_y);
6153 dpyinfo->mouse_face_window = window;
6154 dpyinfo->mouse_face_face_id
6155 = face_at_buffer_position (w, pos, 0, 0,
6156 &ignore, pos + 1, 1);
6157
6158 /* Display it as active. */
6159 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6160 }
6161 }
6162
6163 /* Look for a `help-echo' property. */
6164 {
6165 Lisp_Object help;
6166
6167 /* Check overlays first. */
6168 help = Qnil;
6169 for (i = 0; i < noverlays && !STRINGP (help); ++i)
6170 help = Foverlay_get (overlay_vec[i], Qhelp_echo);
6171
6172 /* Try text properties. */
6173 if (!STRINGP (help)
6174 && ((STRINGP (glyph->object)
6175 && glyph->charpos >= 0
6176 && glyph->charpos < XSTRING (glyph->object)->size)
6177 || (BUFFERP (glyph->object)
6178 && glyph->charpos >= BEGV
6179 && glyph->charpos < ZV)))
6180 help = Fget_text_property (make_number (glyph->charpos),
6181 Qhelp_echo, glyph->object);
6182
6183 if (STRINGP (help))
6184 help_echo = help;
6185 }
6186
6187 BEGV = obegv;
6188 ZV = ozv;
6189 current_buffer = obuf;
6190 }
6191 }
6192}
6193
6194static void
6195redo_mouse_highlight ()
6196{
6197 if (!NILP (last_mouse_motion_frame)
6198 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
6199 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
6200 last_mouse_motion_event.x,
6201 last_mouse_motion_event.y);
6202}
6203
6204
6205\f
6206/***********************************************************************
6207 Toolbars
6208 ***********************************************************************/
6209
6210static int x_toolbar_item P_ ((struct frame *, int, int,
6211 struct glyph **, int *, int *, int *));
6212
6213/* Toolbar item index of the item on which a mouse button was pressed
6214 or -1. */
6215
6216static int last_toolbar_item;
6217
6218
6219/* Get information about the toolbar item at position X/Y on frame F.
6220 Return in *GLYPH a pointer to the glyph of the toolbar item in
6221 the current matrix of the toolbar window of F, or NULL if not
6222 on a toolbar item. Return in *PROP_IDX the index of the toolbar
6223 item in F->current_toolbar_items. Value is
6224
6225 -1 if X/Y is not on a toolbar item
6226 0 if X/Y is on the same item that was highlighted before.
6227 1 otherwise. */
6228
6229static int
6230x_toolbar_item (f, x, y, glyph, hpos, vpos, prop_idx)
6231 struct frame *f;
6232 int x, y;
6233 struct glyph **glyph;
6234 int *hpos, *vpos, *prop_idx;
6235{
6236 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6237 struct window *w = XWINDOW (f->toolbar_window);
6238 int area;
6239
6240 /* Find the glyph under X/Y. */
6241 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
6242 if (*glyph == NULL)
6243 return -1;
6244
6245 /* Get the start of this toolbar item's properties in
6246 f->current_toolbar_items. */
6247 if (!toolbar_item_info (f, *glyph, prop_idx))
6248 return -1;
6249
6250 /* Is mouse on the highlighted item? */
6251 if (EQ (f->toolbar_window, dpyinfo->mouse_face_window)
6252 && *vpos >= dpyinfo->mouse_face_beg_row
6253 && *vpos <= dpyinfo->mouse_face_end_row
6254 && (*vpos > dpyinfo->mouse_face_beg_row
6255 || *hpos >= dpyinfo->mouse_face_beg_col)
6256 && (*vpos < dpyinfo->mouse_face_end_row
6257 || *hpos < dpyinfo->mouse_face_end_col
6258 || dpyinfo->mouse_face_past_end))
6259 return 0;
6260
6261 return 1;
6262}
6263
6264
6265/* Handle mouse button event on the toolbar of frame F, at
6266 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
6267 or ButtonRelase. */
6268
6269static void
6270x_handle_toolbar_click (f, button_event)
6271 struct frame *f;
6272 XButtonEvent *button_event;
6273{
6274 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6275 struct window *w = XWINDOW (f->toolbar_window);
6276 int hpos, vpos, prop_idx;
6277 struct glyph *glyph;
6278 Lisp_Object enabled_p;
6279 int x = button_event->x;
6280 int y = button_event->y;
6281
6282 /* If not on the highlighted toolbar item, return. */
6283 frame_to_window_pixel_xy (w, &x, &y);
6284 if (x_toolbar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
6285 return;
6286
6287 /* If item is disabled, do nothing. */
6288 enabled_p = (XVECTOR (f->current_toolbar_items)
6289 ->contents[prop_idx + TOOLBAR_ITEM_ENABLED_P]);
6290 if (NILP (enabled_p))
6291 return;
6292
6293 if (button_event->type == ButtonPress)
6294 {
6295 /* Show item in pressed state. */
6296 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
6297 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
6298 last_toolbar_item = prop_idx;
6299 }
6300 else
6301 {
6302 Lisp_Object key, frame;
6303 struct input_event event;
6304
6305 /* Show item in released state. */
6306 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
6307 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
6308
6309 key = (XVECTOR (f->current_toolbar_items)
6310 ->contents[prop_idx + TOOLBAR_ITEM_KEY]);
6311
6312 XSETFRAME (frame, f);
6313 event.kind = TOOLBAR_EVENT;
6314 event.frame_or_window = Fcons (frame, Fcons (Qtoolbar, Qnil));
6315 kbd_buffer_store_event (&event);
6316
6317 event.kind = TOOLBAR_EVENT;
6318 event.frame_or_window = Fcons (frame, key);
6319 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6320 button_event->state);
6321 kbd_buffer_store_event (&event);
6322 last_toolbar_item = -1;
6323 }
6324}
6325
6326
6327/* Possibly highlight a toolbar item on frame F when mouse moves to
6328 toolbar window-relative coordinates X/Y. Called from
6329 note_mouse_highlight. */
6330
6331static void
6332note_toolbar_highlight (f, x, y)
6333 struct frame *f;
6334 int x, y;
6335{
6336 Lisp_Object window = f->toolbar_window;
6337 struct window *w = XWINDOW (window);
6338 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6339 int hpos, vpos;
6340 struct glyph *glyph;
6341 struct glyph_row *row;
6342 int i, j, area;
6343 Lisp_Object enabled_p;
6344 int prop_idx;
6345 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
6346 int on_highlight_p, mouse_down_p, rc;
6347
6348 /* Function note_mouse_highlight is called with negative x(y
6349 values when mouse moves outside of the frame. */
6350 if (x <= 0 || y <= 0)
6351 {
6352 clear_mouse_face (dpyinfo);
6353 return;
6354 }
6355
6356 rc = x_toolbar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
6357 if (rc < 0)
6358 {
6359 /* Not on toolbar item. */
6360 clear_mouse_face (dpyinfo);
6361 return;
6362 }
6363 else if (rc == 0)
6364 /* On same toolbar item as before. */
6365 goto set_help_echo;
b8009dd1 6366
06a2c219
GM
6367 clear_mouse_face (dpyinfo);
6368
6369 /* Mouse is down, but on different toolbar item? */
6370 mouse_down_p = (dpyinfo->grabbed
6371 && f == last_mouse_frame
6372 && FRAME_LIVE_P (f));
6373 if (mouse_down_p
6374 && last_toolbar_item != prop_idx)
6375 return;
6376
6377 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
6378 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
6379
6380 /* If toolbar item is not enabled, don't highlight it. */
6381 enabled_p = (XVECTOR (f->current_toolbar_items)
6382 ->contents[prop_idx + TOOLBAR_ITEM_ENABLED_P]);
6383 if (!NILP (enabled_p))
6384 {
6385 /* Compute the x-position of the glyph. In front and past the
6386 image is a space. We include this is the highlighted area. */
6387 row = MATRIX_ROW (w->current_matrix, vpos);
6388 for (i = x = 0; i < hpos; ++i)
6389 x += row->glyphs[TEXT_AREA][i].pixel_width;
6390
6391 /* Record this as the current active region. */
6392 dpyinfo->mouse_face_beg_col = hpos;
6393 dpyinfo->mouse_face_beg_row = vpos;
6394 dpyinfo->mouse_face_beg_x = x;
6395 dpyinfo->mouse_face_beg_y = row->y;
6396 dpyinfo->mouse_face_past_end = 0;
6397
6398 dpyinfo->mouse_face_end_col = hpos + 1;
6399 dpyinfo->mouse_face_end_row = vpos;
6400 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
6401 dpyinfo->mouse_face_end_y = row->y;
6402 dpyinfo->mouse_face_window = window;
6403 dpyinfo->mouse_face_face_id = TOOLBAR_FACE_ID;
6404
6405 /* Display it as active. */
6406 show_mouse_face (dpyinfo, draw);
6407 dpyinfo->mouse_face_image_state = draw;
b8009dd1 6408 }
06a2c219
GM
6409
6410 set_help_echo:
6411
6412 /* Set help_echo to a help string.to display for this toolbar item.
6413 XTread_socket does the rest. */
6414 help_echo = (XVECTOR (f->current_toolbar_items)
6415 ->contents[prop_idx + TOOLBAR_ITEM_HELP]);
6416 if (!STRINGP (help_echo))
6417 help_echo = (XVECTOR (f->current_toolbar_items)
6418 ->contents[prop_idx + TOOLBAR_ITEM_CAPTION]);
b8009dd1 6419}
4d73d038 6420
06a2c219
GM
6421
6422\f
6423/* Find the glyph matrix position of buffer position POS in window W.
6424 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
6425 current glyphs must be up to date. If POS is above window start
6426 return (0, 0, 0, 0). If POS is after end of W, return end of
6427 last line in W. */
b8009dd1
RS
6428
6429static int
06a2c219
GM
6430fast_find_position (w, pos, hpos, vpos, x, y)
6431 struct window *w;
b8009dd1 6432 int pos;
06a2c219 6433 int *hpos, *vpos, *x, *y;
b8009dd1 6434{
b8009dd1 6435 int i;
bf1c0ba1 6436 int lastcol;
06a2c219
GM
6437 int maybe_next_line_p = 0;
6438 int line_start_position;
6439 int yb = window_text_bottom_y (w);
6440 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
6441 struct glyph_row *best_row = row;
6442 int row_vpos = 0, best_row_vpos = 0;
6443 int current_x;
6444
6445 while (row->y < yb)
b8009dd1 6446 {
06a2c219
GM
6447 if (row->used[TEXT_AREA])
6448 line_start_position = row->glyphs[TEXT_AREA]->charpos;
6449 else
6450 line_start_position = 0;
6451
6452 if (line_start_position > pos)
b8009dd1 6453 break;
77b68646
RS
6454 /* If the position sought is the end of the buffer,
6455 don't include the blank lines at the bottom of the window. */
06a2c219
GM
6456 else if (line_start_position == pos
6457 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 6458 {
06a2c219 6459 maybe_next_line_p = 1;
77b68646
RS
6460 break;
6461 }
06a2c219
GM
6462 else if (line_start_position > 0)
6463 {
6464 best_row = row;
6465 best_row_vpos = row_vpos;
6466 }
6467
6468 ++row;
6469 ++row_vpos;
b8009dd1 6470 }
06a2c219
GM
6471
6472 /* Find the right column within BEST_ROW. */
6473 lastcol = 0;
6474 current_x = best_row->x;
6475 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 6476 {
06a2c219
GM
6477 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
6478 int charpos;
6479
6480 charpos = glyph->charpos;
6481 if (charpos == pos)
bf1c0ba1 6482 {
06a2c219
GM
6483 *hpos = i;
6484 *vpos = best_row_vpos;
6485 *x = current_x;
6486 *y = best_row->y;
bf1c0ba1
RS
6487 return 1;
6488 }
06a2c219 6489 else if (charpos > pos)
4d73d038 6490 break;
06a2c219
GM
6491 else if (charpos > 0)
6492 lastcol = i;
6493
6494 current_x += glyph->pixel_width;
bf1c0ba1 6495 }
b8009dd1 6496
77b68646
RS
6497 /* If we're looking for the end of the buffer,
6498 and we didn't find it in the line we scanned,
6499 use the start of the following line. */
06a2c219 6500 if (maybe_next_line_p)
77b68646 6501 {
06a2c219
GM
6502 ++best_row;
6503 ++best_row_vpos;
6504 lastcol = 0;
6505 current_x = best_row->x;
77b68646
RS
6506 }
6507
06a2c219
GM
6508 *vpos = best_row_vpos;
6509 *hpos = lastcol + 1;
6510 *x = current_x;
6511 *y = best_row->y;
b8009dd1
RS
6512 return 0;
6513}
6514
06a2c219 6515
b8009dd1
RS
6516/* Display the active region described by mouse_face_*
6517 in its mouse-face if HL > 0, in its normal face if HL = 0. */
6518
6519static void
06a2c219 6520show_mouse_face (dpyinfo, draw)
7a13e894 6521 struct x_display_info *dpyinfo;
06a2c219 6522 enum draw_glyphs_face draw;
b8009dd1 6523{
7a13e894 6524 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 6525 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 6526 int i;
06a2c219
GM
6527 int cursor_off_p = 0;
6528 struct cursor_pos saved_cursor;
6529
6530 saved_cursor = output_cursor;
6531
6532 /* If window is in the process of being destroyed, don't bother
6533 to do anything. */
6534 if (w->current_matrix == NULL)
6535 goto set_x_cursor;
6536
6537 /* Recognize when we are called to operate on rows that don't exist
6538 anymore. This can happen when a window is split. */
6539 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
6540 goto set_x_cursor;
6541
6542 set_output_cursor (&w->phys_cursor);
6543
6544 /* Note that mouse_face_beg_row etc. are window relative. */
6545 for (i = dpyinfo->mouse_face_beg_row;
6546 i <= dpyinfo->mouse_face_end_row;
6547 i++)
6548 {
6549 int start_hpos, end_hpos, start_x;
6550 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
6551
6552 /* Don't do anything if row doesn't have valid contents. */
6553 if (!row->enabled_p)
6554 continue;
6555
6556 /* For all but the first row, the highlight starts at column 0. */
6557 if (i == dpyinfo->mouse_face_beg_row)
6558 {
6559 start_hpos = dpyinfo->mouse_face_beg_col;
6560 start_x = dpyinfo->mouse_face_beg_x;
6561 }
6562 else
6563 {
6564 start_hpos = 0;
6565 start_x = 0;
6566 }
6567
6568 if (i == dpyinfo->mouse_face_end_row)
6569 end_hpos = dpyinfo->mouse_face_end_col;
6570 else
6571 end_hpos = row->used[TEXT_AREA];
6572
6573 /* If the cursor's in the text we are about to rewrite, turn the
6574 cursor off. */
6575 if (!w->pseudo_window_p
6576 && i == output_cursor.vpos
6577 && output_cursor.hpos >= start_hpos - 1
6578 && output_cursor.hpos <= end_hpos)
514e4681 6579 {
06a2c219
GM
6580 x_update_window_cursor (w, 0);
6581 cursor_off_p = 1;
514e4681 6582 }
b8009dd1 6583
06a2c219
GM
6584 if (end_hpos > start_hpos)
6585 x_draw_glyphs (w, start_x, row, updated_area,
6586 start_hpos, end_hpos, draw, NULL, NULL);
b8009dd1
RS
6587 }
6588
514e4681 6589 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
6590 if (cursor_off_p)
6591 x_display_cursor (w, 1,
6592 output_cursor.hpos, output_cursor.vpos,
6593 output_cursor.x, output_cursor.y);
2729a2b5 6594
06a2c219 6595 output_cursor = saved_cursor;
fb3b7de5 6596
06a2c219
GM
6597 set_x_cursor:
6598
6599 /* Change the mouse cursor. */
6600 if (draw == DRAW_NORMAL_TEXT)
6601 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6602 f->output_data.x->text_cursor);
6603 else if (draw == DRAW_MOUSE_FACE)
334208b7 6604 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6605 f->output_data.x->cross_cursor);
27ead1d5 6606 else
334208b7 6607 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 6608 f->output_data.x->nontext_cursor);
b8009dd1
RS
6609}
6610
6611/* Clear out the mouse-highlighted active region.
06a2c219 6612 Redraw it un-highlighted first. */
b8009dd1 6613
06a2c219 6614void
7a13e894
RS
6615clear_mouse_face (dpyinfo)
6616 struct x_display_info *dpyinfo;
b8009dd1 6617{
06a2c219
GM
6618 if (tip_frame)
6619 return;
6620
7a13e894 6621 if (! NILP (dpyinfo->mouse_face_window))
06a2c219 6622 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
b8009dd1 6623
7a13e894
RS
6624 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
6625 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
6626 dpyinfo->mouse_face_window = Qnil;
b8009dd1 6627}
e687d06e
RS
6628
6629/* Just discard the mouse face information for frame F, if any.
6630 This is used when the size of F is changed. */
6631
dfcf069d 6632void
e687d06e
RS
6633cancel_mouse_face (f)
6634 FRAME_PTR f;
6635{
6636 Lisp_Object window;
6637 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6638
6639 window = dpyinfo->mouse_face_window;
6640 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
6641 {
6642 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
6643 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
6644 dpyinfo->mouse_face_window = Qnil;
6645 }
6646}
b8009dd1 6647\f
ab648270
JB
6648static struct scroll_bar *x_window_to_scroll_bar ();
6649static void x_scroll_bar_report_motion ();
12ba150f 6650
90e65f07 6651/* Return the current position of the mouse.
2d7fc7e8 6652 *fp should be a frame which indicates which display to ask about.
90e65f07 6653
2d7fc7e8 6654 If the mouse movement started in a scroll bar, set *fp, *bar_window,
ab648270 6655 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 6656 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 6657 position on the scroll bar.
12ba150f 6658
2d7fc7e8 6659 If the mouse movement started elsewhere, set *fp to the frame the
12ba150f
JB
6660 mouse is on, *bar_window to nil, and *x and *y to the character cell
6661 the mouse is over.
6662
06a2c219 6663 Set *time to the server time-stamp for the time at which the mouse
12ba150f
JB
6664 was at this position.
6665
a135645a
RS
6666 Don't store anything if we don't have a valid set of values to report.
6667
90e65f07 6668 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 6669 movement. */
90e65f07
JB
6670
6671static void
1cf412ec 6672XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 6673 FRAME_PTR *fp;
1cf412ec 6674 int insist;
12ba150f 6675 Lisp_Object *bar_window;
ab648270 6676 enum scroll_bar_part *part;
90e65f07 6677 Lisp_Object *x, *y;
e5d77022 6678 unsigned long *time;
90e65f07 6679{
a135645a
RS
6680 FRAME_PTR f1;
6681
90e65f07
JB
6682 BLOCK_INPUT;
6683
8bcee03e 6684 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 6685 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
6686 else
6687 {
12ba150f
JB
6688 Window root;
6689 int root_x, root_y;
90e65f07 6690
12ba150f
JB
6691 Window dummy_window;
6692 int dummy;
6693
39d8bb4d
KH
6694 Lisp_Object frame, tail;
6695
6696 /* Clear the mouse-moved flag for every frame on this display. */
6697 FOR_EACH_FRAME (tail, frame)
6698 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
6699 XFRAME (frame)->mouse_moved = 0;
6700
ab648270 6701 last_mouse_scroll_bar = Qnil;
12ba150f
JB
6702
6703 /* Figure out which root window we're on. */
334208b7
RS
6704 XQueryPointer (FRAME_X_DISPLAY (*fp),
6705 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
6706
6707 /* The root window which contains the pointer. */
6708 &root,
6709
6710 /* Trash which we can't trust if the pointer is on
6711 a different screen. */
6712 &dummy_window,
6713
6714 /* The position on that root window. */
58769bee 6715 &root_x, &root_y,
12ba150f
JB
6716
6717 /* More trash we can't trust. */
6718 &dummy, &dummy,
6719
6720 /* Modifier keys and pointer buttons, about which
6721 we don't care. */
6722 (unsigned int *) &dummy);
6723
6724 /* Now we have a position on the root; find the innermost window
6725 containing the pointer. */
6726 {
6727 Window win, child;
6728 int win_x, win_y;
06a2c219 6729 int parent_x = 0, parent_y = 0;
e99db5a1 6730 int count;
12ba150f
JB
6731
6732 win = root;
69388238 6733
2d7fc7e8
RS
6734 /* XTranslateCoordinates can get errors if the window
6735 structure is changing at the same time this function
6736 is running. So at least we must not crash from them. */
6737
e99db5a1 6738 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 6739
334208b7 6740 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 6741 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 6742 {
69388238
RS
6743 /* If mouse was grabbed on a frame, give coords for that frame
6744 even if the mouse is now outside it. */
334208b7 6745 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 6746
12ba150f 6747 /* From-window, to-window. */
69388238 6748 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
6749
6750 /* From-position, to-position. */
6751 root_x, root_y, &win_x, &win_y,
6752
6753 /* Child of win. */
6754 &child);
69388238
RS
6755 f1 = last_mouse_frame;
6756 }
6757 else
6758 {
6759 while (1)
6760 {
334208b7 6761 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 6762
69388238
RS
6763 /* From-window, to-window. */
6764 root, win,
12ba150f 6765
69388238
RS
6766 /* From-position, to-position. */
6767 root_x, root_y, &win_x, &win_y,
6768
6769 /* Child of win. */
6770 &child);
6771
9af3143a 6772 if (child == None || child == win)
69388238
RS
6773 break;
6774
6775 win = child;
6776 parent_x = win_x;
6777 parent_y = win_y;
6778 }
12ba150f 6779
69388238
RS
6780 /* Now we know that:
6781 win is the innermost window containing the pointer
6782 (XTC says it has no child containing the pointer),
6783 win_x and win_y are the pointer's position in it
6784 (XTC did this the last time through), and
6785 parent_x and parent_y are the pointer's position in win's parent.
6786 (They are what win_x and win_y were when win was child.
6787 If win is the root window, it has no parent, and
6788 parent_{x,y} are invalid, but that's okay, because we'll
6789 never use them in that case.) */
6790
6791 /* Is win one of our frames? */
19126e11 6792 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
69388238 6793 }
58769bee 6794
2d7fc7e8
RS
6795 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
6796 f1 = 0;
6797
e99db5a1 6798 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 6799
ab648270 6800 /* If not, is it one of our scroll bars? */
a135645a 6801 if (! f1)
12ba150f 6802 {
ab648270 6803 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
6804
6805 if (bar)
6806 {
a135645a 6807 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
6808 win_x = parent_x;
6809 win_y = parent_y;
6810 }
6811 }
90e65f07 6812
8bcee03e 6813 if (f1 == 0 && insist > 0)
1cf412ec
RS
6814 f1 = selected_frame;
6815
a135645a 6816 if (f1)
12ba150f 6817 {
06a2c219
GM
6818 /* Ok, we found a frame. Store all the values.
6819 last_mouse_glyph is a rectangle used to reduce the
6820 generation of mouse events. To not miss any motion
6821 events, we must divide the frame into rectangles of the
6822 size of the smallest character that could be displayed
6823 on it, i.e. into the same rectangles that matrices on
6824 the frame are divided into. */
6825
6826#if OLD_REDISPLAY_CODE
2b5c9e71 6827 int ignore1, ignore2;
2b5c9e71 6828 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
334208b7 6829 &last_mouse_glyph,
1cf412ec
RS
6830 FRAME_X_DISPLAY_INFO (f1)->grabbed
6831 || insist);
06a2c219
GM
6832#else
6833 {
6834 int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
6835 int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
6836 int x = win_x;
6837 int y = win_y;
6838
6839 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
6840 round down even for negative values. */
6841 if (x < 0)
6842 x -= width - 1;
6843 if (y < 0)
6844 y -= height - 1;
6845
6846 last_mouse_glyph.width = width;
6847 last_mouse_glyph.height = height;
6848 last_mouse_glyph.x = (x + width - 1) / width * width;
6849 last_mouse_glyph.y = (y + height - 1) / height * height;
6850 }
6851#endif
12ba150f
JB
6852
6853 *bar_window = Qnil;
6854 *part = 0;
334208b7 6855 *fp = f1;
e0c1aef2
KH
6856 XSETINT (*x, win_x);
6857 XSETINT (*y, win_y);
12ba150f
JB
6858 *time = last_mouse_movement_time;
6859 }
6860 }
6861 }
90e65f07
JB
6862
6863 UNBLOCK_INPUT;
6864}
f451eb13 6865
06a2c219
GM
6866
6867DEFUN ("xt-process-timeouts", Fxt_process_timeouts, Sxt_process_timeouts,
6868 0, 0, 0,
6869 "Arrange for Xt timeout callbacks to be called.")
6870 ()
6871{
6872#ifdef USE_X_TOOLKIT
6873 BLOCK_INPUT;
6874 while (XtAppPending (Xt_app_con) & XtIMTimer)
6875 XtAppProcessEvent (Xt_app_con, XtIMTimer);
6876 UNBLOCK_INPUT;
6877#endif /* USE_X_TOOLKIT */
6878
6879 return Qnil;
6880}
6881
6882
6883\f
6884/* Scroll bar support. */
6885
6886/* Given an X window ID, find the struct scroll_bar which manages it.
6887 This can be called in GC, so we have to make sure to strip off mark
6888 bits. */
6889static struct scroll_bar *
6890x_window_to_scroll_bar (window_id)
6891 Window window_id;
6892{
6893 Lisp_Object tail;
6894
6895 for (tail = Vframe_list;
6896 XGCTYPE (tail) == Lisp_Cons;
6897 tail = XCONS (tail)->cdr)
6898 {
6899 Lisp_Object frame, bar, condemned;
6900
6901 frame = XCONS (tail)->car;
6902 /* All elements of Vframe_list should be frames. */
6903 if (! GC_FRAMEP (frame))
6904 abort ();
6905
6906 /* Scan this frame's scroll bar list for a scroll bar with the
6907 right window ID. */
6908 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
6909 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
6910 /* This trick allows us to search both the ordinary and
6911 condemned scroll bar lists with one loop. */
6912 ! GC_NILP (bar) || (bar = condemned,
6913 condemned = Qnil,
6914 ! GC_NILP (bar));
6915 bar = XSCROLL_BAR (bar)->next)
6916 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
6917 return XSCROLL_BAR (bar);
6918 }
6919
6920 return 0;
6921}
6922
6923
6924\f
6925/************************************************************************
6926 Toolkit scroll bars
6927 ************************************************************************/
6928
6929#if USE_TOOLKIT_SCROLL_BARS
6930
6931static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
6932static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
6933static void x_create_toolkit_scroll_bar P_ ((struct frame *,
6934 struct scroll_bar *));
6935static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
6936 int, int, int));
6937
6938
6939/* Id of action hook installed for scroll bars. */
6940
6941static XtActionHookId action_hook_id;
6942
6943/* Lisp window being scrolled. Set when starting to interact with
6944 a toolkit scroll bar, reset to nil when ending the interaction. */
6945
6946static Lisp_Object window_being_scrolled;
6947
6948/* Last scroll bar part sent in xm_scroll_callback. */
6949
6950static int last_scroll_bar_part;
6951
6952
6953/* Action hook installed via XtAppAddActionHook when toolkit scroll
6954 bars are used.. The hoos is responsible for detecting when
6955 the user ends an interaction with the scroll bar, and generates
6956 a `end-scroll' scroll_bar_click' event if so. */
6957
6958static void
6959xt_action_hook (widget, client_data, action_name, event, params,
6960 num_params)
6961 Widget widget;
6962 XtPointer client_data;
6963 String action_name;
6964 XEvent *event;
6965 String *params;
6966 Cardinal *num_params;
6967{
6968 int scroll_bar_p;
6969 char *end_action;
6970
6971#ifdef USE_MOTIF
6972 scroll_bar_p = XmIsScrollBar (widget);
6973 end_action = "Release";
6974#elif defined HAVE_XAW3D
6975 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
6976 end_action = "EndScroll";
6977#else
6978#error unknown scroll bar toolkit
6979#endif /* HAVE_XAW3D */
6980
6981 /* Although LessTif uses XtTimeouts like Xaw3d, the timer hack to
6982 let Xt timeouts be processed doesn't work. */
6983 if (scroll_bar_p
6984 && strcmp (action_name, end_action) == 0
6985 && WINDOWP (window_being_scrolled))
6986 {
6987 struct window *w;
6988
6989 x_send_scroll_bar_event (window_being_scrolled,
6990 scroll_bar_end_scroll, 0, 0);
6991 w = XWINDOW (window_being_scrolled);
6992 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
6993 window_being_scrolled = Qnil;
6994 last_scroll_bar_part = -1;
6995 }
6996}
6997
6998
6999/* Send a client message with message type Xatom_Scrollbar for a
7000 scroll action to the frame of WINDOW. PART is a value identifying
7001 the part of the scroll bar that was clicked on. PORTION is the
7002 amount to scroll of a whole of WHOLE. */
7003
7004static void
7005x_send_scroll_bar_event (window, part, portion, whole)
7006 Lisp_Object window;
7007 int part, portion, whole;
7008{
7009 XEvent event;
7010 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
7011 struct frame *f = XFRAME (XWINDOW (window)->frame);
7012
7013 /* Construct a ClientMessage event to send to the frame. */
7014 ev->type = ClientMessage;
7015 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
7016 ev->display = FRAME_X_DISPLAY (f);
7017 ev->window = FRAME_X_WINDOW (f);
7018 ev->format = 32;
7019 ev->data.l[0] = (long) window;
7020 ev->data.l[1] = (long) part;
7021 ev->data.l[2] = (long) 0;
7022 ev->data.l[3] = (long) portion;
7023 ev->data.l[4] = (long) whole;
7024
7025 /* Setting the event mask to zero means that the message will
7026 be sent to the client that created the window, and if that
7027 window no longer exists, no event will be sent. */
7028 BLOCK_INPUT;
7029 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
7030 UNBLOCK_INPUT;
7031}
7032
7033
7034/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
7035 in *IEVENT. */
7036
7037static void
7038x_scroll_bar_to_input_event (event, ievent)
7039 XEvent *event;
7040 struct input_event *ievent;
7041{
7042 XClientMessageEvent *ev = (XClientMessageEvent *) event;
7043 Lisp_Object window = (Lisp_Object) ev->data.l[0];
7044 struct frame *f = XFRAME (XWINDOW (window)->frame);
7045
7046 ievent->kind = scroll_bar_click;
7047 ievent->frame_or_window = window;
7048 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
7049 ievent->part = ev->data.l[1];
7050 ievent->code = ev->data.l[2];
7051 ievent->x = make_number ((int) ev->data.l[3]);
7052 ievent->y = make_number ((int) ev->data.l[4]);
7053 ievent->modifiers = 0;
7054}
7055
7056
7057#ifdef USE_MOTIF
7058
7059/* Minimum and maximum values used for Motif scroll bars. */
7060
7061#define XM_SB_MIN 1
7062#define XM_SB_MAX 10000000
7063#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
7064
7065
7066/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
7067 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
7068 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
7069
7070static void
7071xm_scroll_callback (widget, client_data, call_data)
7072 Widget widget;
7073 XtPointer client_data, call_data;
7074{
7075 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7076 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
7077 double percent;
7078 int part = -1, whole = 0, portion = 0;
7079
7080 switch (cs->reason)
7081 {
7082 case XmCR_DECREMENT:
7083 bar->dragging = Qnil;
7084 part = scroll_bar_up_arrow;
7085 break;
7086
7087 case XmCR_INCREMENT:
7088 bar->dragging = Qnil;
7089 part = scroll_bar_down_arrow;
7090 break;
7091
7092 case XmCR_PAGE_DECREMENT:
7093 bar->dragging = Qnil;
7094 part = scroll_bar_above_handle;
7095 break;
7096
7097 case XmCR_PAGE_INCREMENT:
7098 bar->dragging = Qnil;
7099 part = scroll_bar_below_handle;
7100 break;
7101
7102 case XmCR_TO_TOP:
7103 bar->dragging = Qnil;
7104 part = scroll_bar_to_top;
7105 break;
7106
7107 case XmCR_TO_BOTTOM:
7108 bar->dragging = Qnil;
7109 part = scroll_bar_to_bottom;
7110 break;
7111
7112 case XmCR_DRAG:
7113 {
7114 int slider_size;
7115 int dragging_down_p = (INTEGERP (bar->dragging)
7116 && XINT (bar->dragging) <= cs->value);
7117
7118 /* Get the slider size. */
7119 BLOCK_INPUT;
7120 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
7121 UNBLOCK_INPUT;
7122
7123 /* At the max position of the scroll bar, do a line-wise
7124 movement. Without doing anything, the LessTif scroll bar
7125 calls us with the same cs->value again and again. If we
7126 want to make sure that we can reach the end of the buffer,
7127 we have to do something.
7128
7129 Implementation note: setting bar->dragging always to
7130 cs->value gives a smoother movement at the max position.
7131 Setting it to nil when doing line-wise movement gives
7132 a better slider behavior. */
7133
7134 if (cs->value + slider_size == XM_SB_MAX
7135 || (dragging_down_p
7136 && last_scroll_bar_part == scroll_bar_down_arrow))
7137 {
7138 part = scroll_bar_down_arrow;
7139 bar->dragging = Qnil;
7140 }
7141 else
7142 {
7143 whole = XM_SB_RANGE;
7144 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
7145 part = scroll_bar_handle;
7146 bar->dragging = make_number (cs->value);
7147 }
7148 }
7149 break;
7150
7151 case XmCR_VALUE_CHANGED:
7152 break;
7153 };
7154
7155 if (part >= 0)
7156 {
7157 window_being_scrolled = bar->window;
7158 last_scroll_bar_part = part;
7159 x_send_scroll_bar_event (bar->window, part, portion, whole);
7160 }
7161}
7162
7163
7164#else /* not USE_MOTIF, i.e. XAW3D. */
7165
7166
7167/* Xaw3d scroll bar callback. Invoked when the thumb is dragged.
7168 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
7169 scroll bar struct. CALL_DATA is a pointer to a float saying where
7170 the thumb is. */
7171
7172static void
7173xaw3d_jump_callback (widget, client_data, call_data)
7174 Widget widget;
7175 XtPointer client_data, call_data;
7176{
7177 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7178 float top = *(float *) call_data;
7179 float shown;
7180 int whole, portion;
7181 int dragging_down_p, part;
7182 double epsilon = 0.01;
7183
7184 /* Get the size of the thumb, a value between 0 and 1. */
7185 BLOCK_INPUT;
7186 XtVaGetValues (widget, XtNshown, &shown, NULL);
7187 UNBLOCK_INPUT;
7188
7189 whole = 10000000;
7190 portion = shown < 1 ? top * whole : 0;
7191 dragging_down_p = (INTEGERP (bar->dragging)
7192 && XINT (bar->dragging) < portion);
7193
7194 if (shown < 1
7195 && (abs (top + shown - 1) < epsilon
7196 || (dragging_down_p
7197 && last_scroll_bar_part == scroll_bar_down_arrow)))
7198 part = scroll_bar_down_arrow;
7199 else
7200 part = scroll_bar_handle;
7201
7202 window_being_scrolled = bar->window;
7203 bar->dragging = make_number (portion);
7204 last_scroll_bar_part = part;
7205 x_send_scroll_bar_event (bar->window, part, portion, whole);
7206}
7207
7208
7209/* Xaw3d scroll bar callback. Invoked for incremental scrolling.,
7210 i.e. line or page up or down. WIDGET is the Xaw3d scroll bar
7211 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
7212 the scroll bar. CALL_DATA is an integer specifying the action that
7213 has taken place. It's magnitude is in the range 0..height of the
7214 scroll bar. Negative values mean scroll towards buffer start.
7215 Values < height of scroll bar mean line-wise movement. */
7216
7217static void
7218xaw3d_scroll_callback (widget, client_data, call_data)
7219 Widget widget;
7220 XtPointer client_data, call_data;
7221{
7222 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7223 int position = (int) call_data;
7224 Dimension height;
7225 int part;
7226
7227 /* Get the height of the scroll bar. */
7228 BLOCK_INPUT;
7229 XtVaGetValues (widget, XtNheight, &height, NULL);
7230 UNBLOCK_INPUT;
7231
7232 if (position < 0)
7233 {
7234 if (abs (position) < height)
7235 part = scroll_bar_up_arrow;
7236 else
7237 part = scroll_bar_above_handle;
7238 }
7239 else
7240 {
7241 if (abs (position) < height)
7242 part = scroll_bar_down_arrow;
7243 else
7244 part = scroll_bar_below_handle;
7245 }
7246
7247 window_being_scrolled = bar->window;
7248 bar->dragging = Qnil;
7249 last_scroll_bar_part = part;
7250 x_send_scroll_bar_event (bar->window, part, 0, 0);
7251}
7252
7253
7254#endif /* not USE_MOTIF */
7255
7256
7257/* Create the widget for scroll bar BAR on frame F. Record the widget
7258 and X window of the scroll bar in BAR. */
7259
7260static void
7261x_create_toolkit_scroll_bar (f, bar)
7262 struct frame *f;
7263 struct scroll_bar *bar;
7264{
7265 Window xwindow;
7266 Widget widget;
7267 Arg av[20];
7268 int ac = 0;
7269 char *scroll_bar_name = "verticalScrollBar";
7270 unsigned long pixel;
7271
7272 BLOCK_INPUT;
7273
7274#ifdef USE_MOTIF
7275 /* LessTif 0.85, problems:
7276
7277 1. When the mouse if over the scroll bar, the scroll bar will
7278 get keyboard events. I didn't find a way to turn this off.
7279
7280 2. Do we have to explicitly set the cursor to get an arrow
7281 cursor (see below)? */
7282
7283 /* Set resources. Create the widget. */
7284 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7285 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
7286 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
7287 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
7288 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
7289 XtSetArg (av[ac], XmNincrement, 1); ++ac;
7290 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
7291
7292 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7293 if (pixel != -1)
7294 {
7295 XtSetArg (av[ac], XmNforeground, pixel);
7296 ++ac;
7297 }
7298
7299 pixel = f->output_data.x->scroll_bar_background_pixel;
7300 if (pixel != -1)
7301 {
7302 XtSetArg (av[ac], XmNbackground, pixel);
7303 ++ac;
7304 }
7305
7306 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
7307 scroll_bar_name, av, ac);
7308
7309 /* Add one callback for everything that can happen. */
7310 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
7311 (XtPointer) bar);
7312 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
7313 (XtPointer) bar);
7314 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
7315 (XtPointer) bar);
7316 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
7317 (XtPointer) bar);
7318 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
7319 (XtPointer) bar);
7320 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
7321 (XtPointer) bar);
7322 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
7323 (XtPointer) bar);
7324
7325 /* Realize the widget. Only after that is the X window created. */
7326 XtRealizeWidget (widget);
7327
7328 /* Set the cursor to an arrow. I didn't find a resource to do that.
7329 And I'm wondering why it hasn't an arrow cursor by default. */
7330 XDefineCursor (XtDisplay (widget), XtWindow (widget),
7331 f->output_data.x->nontext_cursor);
7332
7333#elif defined HAVE_XAW3D
7334
7335 /* Set resources. Create the widget. The background of the
7336 Xaw3d scroll bar widget is a little bit light for my taste.
7337 We don't alter it here to let users change it according
7338 to their taste with `emacs*verticalScrollBar.background: xxx'. */
7339 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7340 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
7341 XtSetArg (av[ac], XtNcursorName, "left_ptr"); ++ac;
7342 XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac;
7343
7344 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7345 if (pixel != -1)
7346 {
7347 XtSetArg (av[ac], XtNforeground, pixel);
7348 ++ac;
7349 }
7350
7351 pixel = f->output_data.x->scroll_bar_background_pixel;
7352 if (pixel != -1)
7353 {
7354 XtSetArg (av[ac], XtNbackground, pixel);
7355 ++ac;
7356 }
7357
7358 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
7359 f->output_data.x->edit_widget, av, ac);
7360
7361 /* Define callbacks. */
7362 XtAddCallback (widget, XtNjumpProc, xaw3d_jump_callback, (XtPointer) bar);
7363 XtAddCallback (widget, XtNscrollProc, xaw3d_scroll_callback,
7364 (XtPointer) bar);
7365
7366 /* Realize the widget. Only after that is the X window created. */
7367 XtRealizeWidget (widget);
7368
7369#endif /* HAVE_XAW3D */
7370
7371 /* Install an action hook that let's us detect when the user
7372 finishes interacting with a scroll bar. */
7373 if (action_hook_id == 0)
7374 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
7375
7376 /* Remember X window and widget in the scroll bar vector. */
7377 SET_SCROLL_BAR_X_WIDGET (bar, widget);
7378 xwindow = XtWindow (widget);
7379 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
7380
7381 UNBLOCK_INPUT;
7382}
7383
7384
7385/* Set the thumb size and position of scroll bar BAR. We are currently
7386 displaying PORTION out of a whole WHOLE, and our position POSITION. */
7387
7388static void
7389x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
7390 struct scroll_bar *bar;
7391 int portion, position, whole;
f451eb13 7392{
06a2c219
GM
7393 float top, shown;
7394 Arg av[2];
7395 Widget widget = SCROLL_BAR_X_WIDGET (bar);
f451eb13 7396
06a2c219
GM
7397 if (whole == 0)
7398 top = 0, shown = 1;
7399 else
f451eb13 7400 {
06a2c219
GM
7401 top = (float) position / whole;
7402 shown = (float) portion / whole;
7403 }
f451eb13 7404
06a2c219 7405 BLOCK_INPUT;
f451eb13 7406
06a2c219
GM
7407#ifdef USE_MOTIF
7408 {
7409 int size, value;
7410 Boolean arrow1_selected, arrow2_selected;
7411 unsigned char flags;
7412 XmScrollBarWidget sb;
7413
7414 /* Slider size. Must be in the range [1 .. MAX - MIN] where NAX
7415 is the scroll bar's maximum and MIN is the scroll bar's minimum
7416 value. */
7417 size = shown * XM_SB_RANGE;
7418 size = min (size, XM_SB_RANGE);
7419 size = max (size, 1);
7420
7421 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
7422 value = top * XM_SB_RANGE;
7423 value = min (value, XM_SB_MAX - size);
7424 value = max (value, XM_SB_MIN);
7425
7426 /* LessTif: Calling XmScrollBarSetValues after an increment or
7427 decrement turns off auto-repeat LessTif-internally. This can
7428 be seen in ScrollBar.c which resets Arrow1Selected and
7429 Arrow2Selected. It also sets internal flags so that LessTif
7430 believes the mouse is in the slider. We either have to change
7431 our code, or work around that by accessing private data. */
7432
7433 sb = (XmScrollBarWidget) widget;
7434 arrow1_selected = sb->scrollBar.arrow1_selected;
7435 arrow2_selected = sb->scrollBar.arrow2_selected;
7436 flags = sb->scrollBar.flags;
7437
7438 if (NILP (bar->dragging))
7439 XmScrollBarSetValues (widget, value, size, 0, 0, False);
7440 else if (last_scroll_bar_part == scroll_bar_down_arrow)
7441 /* This has the negative side effect that the slider value is
7442 not would it would be if we scrolled here using line-wise or
7443 page-wise movement. */
7444 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
7445 else
7446 {
7447 /* If currently dragging, only update the slider size.
7448 This reduces flicker effects. */
7449 int old_value, old_size, increment, page_increment;
7450
7451 XmScrollBarGetValues (widget, &old_value, &old_size,
7452 &increment, &page_increment);
7453 XmScrollBarSetValues (widget, old_value,
7454 min (size, XM_SB_RANGE - old_value),
7455 0, 0, False);
7456 }
7457
7458 sb->scrollBar.arrow1_selected = arrow1_selected;
7459 sb->scrollBar.arrow2_selected = arrow2_selected;
7460 sb->scrollBar.flags = flags;
7461 }
7462#elif defined HAVE_XAW3D
7463 {
7464 /* Restrict to [0 1]. */
7465 top = max (0, min (1, top));
7466 shown = max (0, min (1, shown));
7467
7468 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
7469 check that your system's configuration file contains a define
7470 for `NARROWPROTO'. See s/freebsd.h for an example. */
7471 if (NILP (bar->dragging))
eb393530
GM
7472 {
7473 float old_top, old_shown;
7474 XtVaGetValues (widget, XtNtopOfThumb, &old_top, XtNshown, &old_shown,
7475 NULL);
7476 if (top != old_top || shown != old_shown)
7477 XawScrollbarSetThumb (widget, top, shown);
7478 }
06a2c219
GM
7479 else
7480 {
7481 ScrollbarWidget sb = (ScrollbarWidget) widget;
7482 int scroll_mode = sb->scrollbar.scroll_mode;
f451eb13 7483
06a2c219
GM
7484 sb->scrollbar.scroll_mode = 0;
7485
7486 if (last_scroll_bar_part == scroll_bar_down_arrow)
7487 XawScrollbarSetThumb (widget, top, 1 - top);
7488 else
7489 {
7490 float old_top;
7491 XtVaGetValues (widget, XtNtopOfThumb, &old_top, NULL);
7492 XawScrollbarSetThumb (widget, old_top, min (shown, 1 - old_top));
7493 }
7494
7495 sb->scrollbar.scroll_mode = scroll_mode;
7496 }
7497 }
7498#endif /* HAVE_XAW3D */
7499
7500 UNBLOCK_INPUT;
f451eb13
JB
7501}
7502
06a2c219
GM
7503#endif /* USE_TOOLKIT_SCROLL_BARS */
7504
7505
7506\f
7507/************************************************************************
7508 Scroll bars, general
7509 ************************************************************************/
7510
7511/* Create a scroll bar and return the scroll bar vector for it. W is
7512 the Emacs window on which to create the scroll bar. TOP, LEFT,
7513 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
7514 scroll bar. */
7515
ab648270 7516static struct scroll_bar *
06a2c219
GM
7517x_scroll_bar_create (w, top, left, width, height)
7518 struct window *w;
f451eb13
JB
7519 int top, left, width, height;
7520{
06a2c219
GM
7521 struct frame *f = XFRAME (w->frame);
7522#ifdef USE_X_TOOLKIT
7523 Arg av[10];
7524#endif
7525 int ac = 0;
7526 Window window;
334208b7
RS
7527 struct scroll_bar *bar
7528 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
7529
7530 BLOCK_INPUT;
7531
06a2c219
GM
7532#if USE_TOOLKIT_SCROLL_BARS
7533 x_create_toolkit_scroll_bar (f, bar);
7534#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
7535 {
7536 XSetWindowAttributes a;
7537 unsigned long mask;
06a2c219
GM
7538
7539 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
7540 if (a.background_pixel == -1)
7541 a.background_pixel = f->output_data.x->background_pixel;
7542
12ba150f 7543 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 7544 | ButtonMotionMask | PointerMotionHintMask
12ba150f 7545 | ExposureMask);
7a13e894 7546 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 7547
dbc4e1c1 7548 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 7549
06a2c219
GM
7550 /* Clear the area of W that will serve as a scroll bar. This is
7551 for the case that a window has been split horizontally. In
7552 this case, no clear_frame is generated to reduce flickering. */
7553 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7554 left, top, width,
7555 window_box_height (w), False);
7556
7557 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7558 /* Position and size of scroll bar. */
7559 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7560 top,
7561 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
7562 height,
7563 /* Border width, depth, class, and visual. */
7564 0,
7565 CopyFromParent,
7566 CopyFromParent,
7567 CopyFromParent,
7568 /* Attributes. */
7569 mask, &a);
7570 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 7571 }
06a2c219 7572#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 7573
06a2c219 7574 XSETWINDOW (bar->window, w);
e0c1aef2
KH
7575 XSETINT (bar->top, top);
7576 XSETINT (bar->left, left);
7577 XSETINT (bar->width, width);
7578 XSETINT (bar->height, height);
7579 XSETINT (bar->start, 0);
7580 XSETINT (bar->end, 0);
12ba150f 7581 bar->dragging = Qnil;
f451eb13
JB
7582
7583 /* Add bar to its frame's list of scroll bars. */
334208b7 7584 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 7585 bar->prev = Qnil;
334208b7 7586 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 7587 if (!NILP (bar->next))
e0c1aef2 7588 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 7589
06a2c219
GM
7590 /* Map the window/widget. */
7591#if USE_TOOLKIT_SCROLL_BARS
7592 XtMapWidget (SCROLL_BAR_X_WIDGET (bar));
7593 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
7594 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7595 top,
7596 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
7597 height, 0);
7598#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 7599 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 7600#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
7601
7602 UNBLOCK_INPUT;
12ba150f 7603 return bar;
f451eb13
JB
7604}
7605
06a2c219 7606
12ba150f 7607/* Draw BAR's handle in the proper position.
06a2c219 7608
12ba150f
JB
7609 If the handle is already drawn from START to END, don't bother
7610 redrawing it, unless REBUILD is non-zero; in that case, always
7611 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 7612 events.)
12ba150f
JB
7613
7614 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
7615 fit inside its rectangle, but if the user is dragging the scroll
7616 bar handle, we want to let them drag it down all the way, so that
7617 the bar's top is as far down as it goes; otherwise, there's no way
7618 to move to the very end of the buffer. */
7619
f451eb13 7620static void
ab648270
JB
7621x_scroll_bar_set_handle (bar, start, end, rebuild)
7622 struct scroll_bar *bar;
f451eb13 7623 int start, end;
12ba150f 7624 int rebuild;
f451eb13 7625{
06a2c219 7626#ifndef USE_TOOLKIT_SCROLL_BARS
12ba150f 7627 int dragging = ! NILP (bar->dragging);
ab648270 7628 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 7629 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 7630 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
7631
7632 /* If the display is already accurate, do nothing. */
7633 if (! rebuild
7634 && start == XINT (bar->start)
7635 && end == XINT (bar->end))
7636 return;
7637
f451eb13
JB
7638 BLOCK_INPUT;
7639
7640 {
d9cdbb3d
RS
7641 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
7642 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
7643 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
7644
7645 /* Make sure the values are reasonable, and try to preserve
7646 the distance between start and end. */
12ba150f
JB
7647 {
7648 int length = end - start;
7649
7650 if (start < 0)
7651 start = 0;
7652 else if (start > top_range)
7653 start = top_range;
7654 end = start + length;
7655
7656 if (end < start)
7657 end = start;
7658 else if (end > top_range && ! dragging)
7659 end = top_range;
7660 }
f451eb13 7661
ab648270 7662 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
7663 XSETINT (bar->start, start);
7664 XSETINT (bar->end, end);
f451eb13 7665
12ba150f
JB
7666 /* Clip the end position, just for display. */
7667 if (end > top_range)
7668 end = top_range;
f451eb13 7669
ab648270 7670 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
7671 below top positions, to make sure the handle is always at least
7672 that many pixels tall. */
ab648270 7673 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 7674
12ba150f
JB
7675 /* Draw the empty space above the handle. Note that we can't clear
7676 zero-height areas; that means "clear to end of window." */
7677 if (0 < start)
334208b7 7678 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 7679
12ba150f 7680 /* x, y, width, height, and exposures. */
ab648270
JB
7681 VERTICAL_SCROLL_BAR_LEFT_BORDER,
7682 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
7683 inside_width, start,
7684 False);
f451eb13 7685
06a2c219
GM
7686 /* Change to proper foreground color if one is specified. */
7687 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
7688 XSetForeground (FRAME_X_DISPLAY (f), gc,
7689 f->output_data.x->scroll_bar_foreground_pixel);
7690
12ba150f 7691 /* Draw the handle itself. */
334208b7 7692 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 7693
12ba150f 7694 /* x, y, width, height */
ab648270
JB
7695 VERTICAL_SCROLL_BAR_LEFT_BORDER,
7696 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 7697 inside_width, end - start);
f451eb13 7698
06a2c219
GM
7699 /* Restore the foreground color of the GC if we changed it above. */
7700 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
7701 XSetForeground (FRAME_X_DISPLAY (f), gc,
7702 f->output_data.x->foreground_pixel);
f451eb13 7703
12ba150f
JB
7704 /* Draw the empty space below the handle. Note that we can't
7705 clear zero-height areas; that means "clear to end of window." */
7706 if (end < inside_height)
334208b7 7707 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 7708
12ba150f 7709 /* x, y, width, height, and exposures. */
ab648270
JB
7710 VERTICAL_SCROLL_BAR_LEFT_BORDER,
7711 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
7712 inside_width, inside_height - end,
7713 False);
f451eb13 7714
f451eb13
JB
7715 }
7716
f451eb13 7717 UNBLOCK_INPUT;
06a2c219 7718#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
7719}
7720
f451eb13 7721
06a2c219
GM
7722/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
7723 nil. */
58769bee 7724
12ba150f 7725static void
ab648270
JB
7726x_scroll_bar_remove (bar)
7727 struct scroll_bar *bar;
12ba150f
JB
7728{
7729 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7730
7731 BLOCK_INPUT;
7732
06a2c219
GM
7733#if USE_TOOLKIT_SCROLL_BARS
7734 XtDestroyWidget (SCROLL_BAR_X_WIDGET (bar));
7735#else /* not USE_TOOLKIT_SCROLL_BARS */
334208b7 7736 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219
GM
7737#endif /* not USE_TOOLKIT_SCROLL_BARS */
7738
ab648270
JB
7739 /* Disassociate this scroll bar from its window. */
7740 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
7741
7742 UNBLOCK_INPUT;
7743}
7744
06a2c219 7745
12ba150f
JB
7746/* Set the handle of the vertical scroll bar for WINDOW to indicate
7747 that we are displaying PORTION characters out of a total of WHOLE
ab648270 7748 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 7749 create one. */
06a2c219 7750
12ba150f 7751static void
06a2c219
GM
7752XTset_vertical_scroll_bar (w, portion, whole, position)
7753 struct window *w;
f451eb13
JB
7754 int portion, whole, position;
7755{
06a2c219 7756 struct frame *f = XFRAME (w->frame);
ab648270 7757 struct scroll_bar *bar;
06a2c219
GM
7758 int pixel_top, pixel_left, pixel_width, pixel_height;
7759 int window_x, window_y, window_width, window_height;
7760 int scroll_bar_area_width;
7761
7762 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
7763
7764 /* Where should this scroll bar be, pixel-wise? */
7765 pixel_top = window_y;
7766 pixel_height = window_height;
7767
7768 /* The width of the scroll bar itself. */
7769 pixel_width = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
7770 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7771 : (FRAME_SCROLL_BAR_COLS (f)
7772 * FONT_WIDTH (FRAME_FONT (f))));
7773
7774 /* The width on the screen reserved for the scroll bar plus maybe
7775 some empty room at both sides of the scroll bar. */
7776 scroll_bar_area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
7777
7778 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
7779 pixel_left = (window_x
7780 + window_width
7781 + FRAME_FLAGS_AREA_WIDTH (f)
7782 + scroll_bar_area_width
7783 - pixel_width + 1);
7784 else
7785 pixel_left = (window_x
7786 - FRAME_FLAGS_AREA_WIDTH (f)
7787 - scroll_bar_area_width);
12ba150f 7788
ab648270 7789 /* Does the scroll bar exist yet? */
06a2c219
GM
7790 if (NILP (w->vertical_scroll_bar))
7791 bar = x_scroll_bar_create (w, pixel_top, pixel_left, pixel_width,
7792 pixel_height);
f451eb13 7793 else
12ba150f
JB
7794 {
7795 /* It may just need to be moved and resized. */
06a2c219
GM
7796 unsigned int mask = 0;
7797
7798 bar = XSCROLL_BAR (w->vertical_scroll_bar);
7799
7800 BLOCK_INPUT;
7801
7802 if (pixel_left != XINT (bar->left))
7803 mask |= CWX;
7804 if (pixel_top != XINT (bar->top))
7805 mask |= CWY;
7806 if (pixel_width != XINT (bar->width))
7807 mask |= CWWidth;
7808 if (pixel_height != XINT (bar->height))
7809 mask |= CWHeight;
7810
7811#ifdef USE_TOOLKIT_SCROLL_BARS
7812
7813 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
7814 {
7815 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7816 pixel_left + pixel_width - scroll_bar_area_width,
7817 pixel_top,
7818 (scroll_bar_area_width
7819 - pixel_width
7820 + VERTICAL_SCROLL_BAR_WIDTH_TRIM),
7821 pixel_height, False);
7822 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7823 (pixel_left
7824 + pixel_width
7825 - VERTICAL_SCROLL_BAR_WIDTH_TRIM),
7826 pixel_top,
7827 VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7828 pixel_height, False);
7829 }
7830 else
7831 {
7832 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7833 pixel_left, pixel_top,
7834 VERTICAL_SCROLL_BAR_WIDTH_TRIM, pixel_height, False);
7835 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7836 (pixel_left
7837 + pixel_width
7838 - VERTICAL_SCROLL_BAR_WIDTH_TRIM),
7839 pixel_top,
7840 (scroll_bar_area_width
7841 - pixel_width
7842 + VERTICAL_SCROLL_BAR_WIDTH_TRIM),
7843 pixel_height, False);
7844 }
7845
7846 /* Move/size the scroll bar widget. */
7847 if (mask)
7848 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
7849 pixel_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7850 pixel_top,
7851 pixel_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
7852 pixel_height, 0);
7853
7854#else /* not USE_TOOLKIT_SCROLL_BARS */
7855
7856 /* Clear areas not covered by the scroll bar. This makes sure a
7857 previous mode line display is cleared after C-x 2 C-x 1, for
7858 example. Non-toolkit scroll bars are as wide as the area
7859 reserved for scroll bars - trim at both sides. */
7860 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7861 pixel_left, pixel_top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7862 pixel_height, False);
7863 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7864 (pixel_left
7865 + pixel_width
7866 - VERTICAL_SCROLL_BAR_WIDTH_TRIM),
7867 pixel_top,
7868 VERTICAL_SCROLL_BAR_WIDTH_TRIM,
7869 pixel_height, False);
7870
7871 /* Move/size the scroll bar window. */
7872 if (mask)
7873 {
7874 XWindowChanges wc;
7875
7876 wc.x = pixel_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
7877 wc.y = pixel_top;
7878 wc.width = pixel_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
7879 wc.height = pixel_height;
7880 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
7881 mask, &wc);
7882 }
7883
7884#endif /* not USE_TOOLKIT_SCROLL_BARS */
7885
7886 /* Remember new settings. */
7887 XSETINT (bar->left, pixel_left);
7888 XSETINT (bar->top, pixel_top);
7889 XSETINT (bar->width, pixel_width);
7890 XSETINT (bar->height, pixel_height);
7891
7892 UNBLOCK_INPUT;
12ba150f 7893 }
f451eb13 7894
06a2c219
GM
7895#if USE_TOOLKIT_SCROLL_BARS
7896 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
7897#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 7898 /* Set the scroll bar's current state, unless we're currently being
f451eb13 7899 dragged. */
12ba150f 7900 if (NILP (bar->dragging))
f451eb13 7901 {
d9cdbb3d 7902 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, pixel_height);
f451eb13 7903
12ba150f 7904 if (whole == 0)
ab648270 7905 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
7906 else
7907 {
43f868f5
JB
7908 int start = ((double) position * top_range) / whole;
7909 int end = ((double) (position + portion) * top_range) / whole;
ab648270 7910 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 7911 }
f451eb13 7912 }
06a2c219 7913#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 7914
06a2c219 7915 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
7916}
7917
12ba150f 7918
f451eb13 7919/* The following three hooks are used when we're doing a thorough
ab648270 7920 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 7921 are going to be deleted, because keeping track of when windows go
12ba150f
JB
7922 away is a real pain - "Can you say set-window-configuration, boys
7923 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 7924 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 7925 from the fiery pit when we actually redisplay its window. */
f451eb13 7926
ab648270
JB
7927/* Arrange for all scroll bars on FRAME to be removed at the next call
7928 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
7929 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
7930
58769bee 7931static void
ab648270 7932XTcondemn_scroll_bars (frame)
f451eb13
JB
7933 FRAME_PTR frame;
7934{
f9e24cb9
RS
7935 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
7936 while (! NILP (FRAME_SCROLL_BARS (frame)))
7937 {
7938 Lisp_Object bar;
7939 bar = FRAME_SCROLL_BARS (frame);
7940 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
7941 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
7942 XSCROLL_BAR (bar)->prev = Qnil;
7943 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
7944 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
7945 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
7946 }
f451eb13
JB
7947}
7948
06a2c219 7949/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 7950 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 7951static void
ab648270 7952XTredeem_scroll_bar (window)
12ba150f 7953 struct window *window;
f451eb13 7954{
ab648270 7955 struct scroll_bar *bar;
12ba150f 7956
ab648270
JB
7957 /* We can't redeem this window's scroll bar if it doesn't have one. */
7958 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
7959 abort ();
7960
ab648270 7961 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
7962
7963 /* Unlink it from the condemned list. */
7964 {
7965 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
7966
7967 if (NILP (bar->prev))
7968 {
7969 /* If the prev pointer is nil, it must be the first in one of
7970 the lists. */
ab648270 7971 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
7972 /* It's not condemned. Everything's fine. */
7973 return;
ab648270
JB
7974 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
7975 window->vertical_scroll_bar))
7976 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
7977 else
7978 /* If its prev pointer is nil, it must be at the front of
7979 one or the other! */
7980 abort ();
7981 }
7982 else
ab648270 7983 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
7984
7985 if (! NILP (bar->next))
ab648270 7986 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 7987
ab648270 7988 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 7989 bar->prev = Qnil;
e0c1aef2 7990 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 7991 if (! NILP (bar->next))
e0c1aef2 7992 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
12ba150f 7993 }
f451eb13
JB
7994}
7995
ab648270
JB
7996/* Remove all scroll bars on FRAME that haven't been saved since the
7997 last call to `*condemn_scroll_bars_hook'. */
06a2c219 7998
f451eb13 7999static void
ab648270 8000XTjudge_scroll_bars (f)
12ba150f 8001 FRAME_PTR f;
f451eb13 8002{
12ba150f 8003 Lisp_Object bar, next;
f451eb13 8004
ab648270 8005 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
8006
8007 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
8008 more events on the hapless scroll bars. */
8009 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
8010
8011 for (; ! NILP (bar); bar = next)
f451eb13 8012 {
ab648270 8013 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 8014
ab648270 8015 x_scroll_bar_remove (b);
12ba150f
JB
8016
8017 next = b->next;
8018 b->next = b->prev = Qnil;
f451eb13 8019 }
12ba150f 8020
ab648270 8021 /* Now there should be no references to the condemned scroll bars,
12ba150f 8022 and they should get garbage-collected. */
f451eb13
JB
8023}
8024
8025
06a2c219
GM
8026/* Handle an Expose or GraphicsExpose event on a scroll bar. This
8027 is a no-op when using toolkit scroll bars.
ab648270
JB
8028
8029 This may be called from a signal handler, so we have to ignore GC
8030 mark bits. */
06a2c219 8031
f451eb13 8032static void
ab648270
JB
8033x_scroll_bar_expose (bar, event)
8034 struct scroll_bar *bar;
f451eb13
JB
8035 XEvent *event;
8036{
06a2c219
GM
8037#ifndef USE_TOOLKIT_SCROLL_BARS
8038
ab648270 8039 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8040 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8041 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 8042 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 8043
f451eb13
JB
8044 BLOCK_INPUT;
8045
ab648270 8046 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 8047
06a2c219 8048 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 8049 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
8050
8051 /* x, y, width, height */
d9cdbb3d 8052 0, 0,
3cbd2e0b 8053 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
8054 XINT (bar->height) - 1);
8055
f451eb13 8056 UNBLOCK_INPUT;
06a2c219
GM
8057
8058#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8059}
8060
ab648270
JB
8061/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8062 is set to something other than no_event, it is enqueued.
8063
8064 This may be called from a signal handler, so we have to ignore GC
8065 mark bits. */
06a2c219 8066
f451eb13 8067static void
ab648270
JB
8068x_scroll_bar_handle_click (bar, event, emacs_event)
8069 struct scroll_bar *bar;
f451eb13
JB
8070 XEvent *event;
8071 struct input_event *emacs_event;
8072{
0299d313 8073 if (! GC_WINDOWP (bar->window))
12ba150f
JB
8074 abort ();
8075
ab648270 8076 emacs_event->kind = scroll_bar_click;
69388238 8077 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
8078 emacs_event->modifiers
8079 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
8080 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
8081 event->xbutton.state)
8082 | (event->type == ButtonRelease
8083 ? up_modifier
8084 : down_modifier));
12ba150f 8085 emacs_event->frame_or_window = bar->window;
f451eb13 8086 emacs_event->timestamp = event->xbutton.time;
12ba150f 8087 {
06a2c219 8088#if 0
d9cdbb3d 8089 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 8090 int internal_height
d9cdbb3d 8091 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8092#endif
0299d313 8093 int top_range
d9cdbb3d 8094 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 8095 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
8096
8097 if (y < 0) y = 0;
8098 if (y > top_range) y = top_range;
8099
8100 if (y < XINT (bar->start))
ab648270
JB
8101 emacs_event->part = scroll_bar_above_handle;
8102 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8103 emacs_event->part = scroll_bar_handle;
12ba150f 8104 else
ab648270 8105 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
8106
8107 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
8108 they want to drag it. Lisp code needs to be able to decide
8109 whether or not we're dragging. */
929787e1 8110#if 0
12ba150f
JB
8111 /* If the user has just clicked on the handle, record where they're
8112 holding it. */
8113 if (event->type == ButtonPress
ab648270 8114 && emacs_event->part == scroll_bar_handle)
e0c1aef2 8115 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 8116#endif
12ba150f
JB
8117
8118 /* If the user has released the handle, set it to its final position. */
8119 if (event->type == ButtonRelease
8120 && ! NILP (bar->dragging))
8121 {
8122 int new_start = y - XINT (bar->dragging);
8123 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 8124
ab648270 8125 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
8126 bar->dragging = Qnil;
8127 }
f451eb13 8128
5116f055
JB
8129 /* Same deal here as the other #if 0. */
8130#if 0
58769bee 8131 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 8132 the handle. */
ab648270 8133 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
8134 emacs_event->x = bar->start;
8135 else
e0c1aef2 8136 XSETINT (emacs_event->x, y);
5116f055 8137#else
e0c1aef2 8138 XSETINT (emacs_event->x, y);
5116f055 8139#endif
f451eb13 8140
e0c1aef2 8141 XSETINT (emacs_event->y, top_range);
12ba150f
JB
8142 }
8143}
f451eb13 8144
ab648270
JB
8145/* Handle some mouse motion while someone is dragging the scroll bar.
8146
8147 This may be called from a signal handler, so we have to ignore GC
8148 mark bits. */
06a2c219 8149
f451eb13 8150static void
ab648270
JB
8151x_scroll_bar_note_movement (bar, event)
8152 struct scroll_bar *bar;
f451eb13
JB
8153 XEvent *event;
8154{
39d8bb4d
KH
8155 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
8156
f451eb13
JB
8157 last_mouse_movement_time = event->xmotion.time;
8158
39d8bb4d 8159 f->mouse_moved = 1;
e0c1aef2 8160 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
8161
8162 /* If we're dragging the bar, display it. */
ab648270 8163 if (! GC_NILP (bar->dragging))
f451eb13
JB
8164 {
8165 /* Where should the handle be now? */
12ba150f 8166 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 8167
12ba150f 8168 if (new_start != XINT (bar->start))
f451eb13 8169 {
12ba150f 8170 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 8171
ab648270 8172 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
8173 }
8174 }
f451eb13
JB
8175}
8176
12ba150f 8177/* Return information to the user about the current position of the mouse
ab648270 8178 on the scroll bar. */
06a2c219 8179
12ba150f 8180static void
334208b7
RS
8181x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
8182 FRAME_PTR *fp;
12ba150f 8183 Lisp_Object *bar_window;
ab648270 8184 enum scroll_bar_part *part;
12ba150f
JB
8185 Lisp_Object *x, *y;
8186 unsigned long *time;
8187{
ab648270 8188 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
8189 Window w = SCROLL_BAR_X_WINDOW (bar);
8190 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 8191 int win_x, win_y;
559cb2fb
JB
8192 Window dummy_window;
8193 int dummy_coord;
8194 unsigned int dummy_mask;
12ba150f 8195
cf7cb199
JB
8196 BLOCK_INPUT;
8197
ab648270 8198 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 8199 report that. */
334208b7 8200 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 8201
559cb2fb
JB
8202 /* Root, child, root x and root y. */
8203 &dummy_window, &dummy_window,
8204 &dummy_coord, &dummy_coord,
12ba150f 8205
559cb2fb
JB
8206 /* Position relative to scroll bar. */
8207 &win_x, &win_y,
12ba150f 8208
559cb2fb
JB
8209 /* Mouse buttons and modifier keys. */
8210 &dummy_mask))
7a13e894 8211 ;
559cb2fb
JB
8212 else
8213 {
06a2c219 8214#if 0
559cb2fb 8215 int inside_height
d9cdbb3d 8216 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8217#endif
559cb2fb 8218 int top_range
d9cdbb3d 8219 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
8220
8221 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
8222
8223 if (! NILP (bar->dragging))
8224 win_y -= XINT (bar->dragging);
8225
8226 if (win_y < 0)
8227 win_y = 0;
8228 if (win_y > top_range)
8229 win_y = top_range;
8230
334208b7 8231 *fp = f;
7a13e894 8232 *bar_window = bar->window;
559cb2fb
JB
8233
8234 if (! NILP (bar->dragging))
8235 *part = scroll_bar_handle;
8236 else if (win_y < XINT (bar->start))
8237 *part = scroll_bar_above_handle;
8238 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8239 *part = scroll_bar_handle;
8240 else
8241 *part = scroll_bar_below_handle;
12ba150f 8242
e0c1aef2
KH
8243 XSETINT (*x, win_y);
8244 XSETINT (*y, top_range);
12ba150f 8245
39d8bb4d 8246 f->mouse_moved = 0;
559cb2fb
JB
8247 last_mouse_scroll_bar = Qnil;
8248 }
12ba150f 8249
559cb2fb 8250 *time = last_mouse_movement_time;
cf7cb199 8251
cf7cb199 8252 UNBLOCK_INPUT;
12ba150f
JB
8253}
8254
f451eb13 8255
dbc4e1c1 8256/* The screen has been cleared so we may have changed foreground or
ab648270
JB
8257 background colors, and the scroll bars may need to be redrawn.
8258 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
8259 redraw them. */
8260
dfcf069d 8261void
ab648270 8262x_scroll_bar_clear (f)
dbc4e1c1
JB
8263 FRAME_PTR f;
8264{
06a2c219 8265#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
8266 Lisp_Object bar;
8267
b80c363e
RS
8268 /* We can have scroll bars even if this is 0,
8269 if we just turned off scroll bar mode.
8270 But in that case we should not clear them. */
8271 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
8272 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
8273 bar = XSCROLL_BAR (bar)->next)
8274 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
8275 0, 0, 0, 0, True);
06a2c219 8276#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
8277}
8278
06a2c219 8279/* This processes Expose events from the menu-bar specific X event
19126e11 8280 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 8281 when handling menu-bar or pop-up items. */
3afe33e7 8282
06a2c219 8283int
3afe33e7
RS
8284process_expose_from_menu (event)
8285 XEvent event;
8286{
8287 FRAME_PTR f;
19126e11 8288 struct x_display_info *dpyinfo;
06a2c219 8289 int frame_exposed_p = 0;
3afe33e7 8290
f94397b5
KH
8291 BLOCK_INPUT;
8292
19126e11
KH
8293 dpyinfo = x_display_info_for_display (event.xexpose.display);
8294 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
8295 if (f)
8296 {
8297 if (f->async_visible == 0)
8298 {
8299 f->async_visible = 1;
8300 f->async_iconified = 0;
06c488fd 8301 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
8302 SET_FRAME_GARBAGED (f);
8303 }
8304 else
8305 {
06a2c219
GM
8306 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
8307 event.xexpose.x, event.xexpose.y,
8308 event.xexpose.width, event.xexpose.height);
8309 frame_exposed_p = 1;
3afe33e7
RS
8310 }
8311 }
8312 else
8313 {
8314 struct scroll_bar *bar
8315 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 8316
3afe33e7
RS
8317 if (bar)
8318 x_scroll_bar_expose (bar, &event);
8319 }
f94397b5
KH
8320
8321 UNBLOCK_INPUT;
06a2c219 8322 return frame_exposed_p;
3afe33e7 8323}
09756a85
RS
8324\f
8325/* Define a queue to save up SelectionRequest events for later handling. */
8326
8327struct selection_event_queue
8328 {
8329 XEvent event;
8330 struct selection_event_queue *next;
8331 };
8332
8333static struct selection_event_queue *queue;
8334
8335/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 8336
09756a85
RS
8337static int x_queue_selection_requests;
8338
8339/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 8340
09756a85 8341static void
334208b7
RS
8342x_queue_event (f, event)
8343 FRAME_PTR f;
09756a85
RS
8344 XEvent *event;
8345{
8346 struct selection_event_queue *queue_tmp
06a2c219 8347 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 8348
58769bee 8349 if (queue_tmp != NULL)
09756a85
RS
8350 {
8351 queue_tmp->event = *event;
8352 queue_tmp->next = queue;
8353 queue = queue_tmp;
8354 }
8355}
8356
8357/* Take all the queued events and put them back
8358 so that they get processed afresh. */
8359
8360static void
db3906fd
RS
8361x_unqueue_events (display)
8362 Display *display;
09756a85 8363{
58769bee 8364 while (queue != NULL)
09756a85
RS
8365 {
8366 struct selection_event_queue *queue_tmp = queue;
db3906fd 8367 XPutBackEvent (display, &queue_tmp->event);
09756a85 8368 queue = queue_tmp->next;
06a2c219 8369 xfree ((char *)queue_tmp);
09756a85
RS
8370 }
8371}
8372
8373/* Start queuing SelectionRequest events. */
8374
8375void
db3906fd
RS
8376x_start_queuing_selection_requests (display)
8377 Display *display;
09756a85
RS
8378{
8379 x_queue_selection_requests++;
8380}
8381
8382/* Stop queuing SelectionRequest events. */
8383
8384void
db3906fd
RS
8385x_stop_queuing_selection_requests (display)
8386 Display *display;
09756a85
RS
8387{
8388 x_queue_selection_requests--;
db3906fd 8389 x_unqueue_events (display);
09756a85 8390}
f451eb13
JB
8391\f
8392/* The main X event-reading loop - XTread_socket. */
dc6f92b8 8393
06a2c219 8394/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
8395 but we have to put it out here, since static variables within functions
8396 sometimes don't work. */
06a2c219 8397
dc6f92b8
JB
8398static Time enter_timestamp;
8399
11edeb03 8400/* This holds the state XLookupString needs to implement dead keys
58769bee 8401 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
8402 says that a portable program can't use this, but Stephen Gildea assures
8403 me that letting the compiler initialize it to zeros will work okay.
8404
8405 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
8406 given for enter_time stamp, above. */
8407
11edeb03
JB
8408static XComposeStatus compose_status;
8409
10e6549c
RS
8410/* Record the last 100 characters stored
8411 to help debug the loss-of-chars-during-GC problem. */
06a2c219 8412
2224b905
RS
8413static int temp_index;
8414static short temp_buffer[100];
10e6549c 8415
7a13e894
RS
8416/* Set this to nonzero to fake an "X I/O error"
8417 on a particular display. */
06a2c219 8418
7a13e894
RS
8419struct x_display_info *XTread_socket_fake_io_error;
8420
2224b905
RS
8421/* When we find no input here, we occasionally do a no-op command
8422 to verify that the X server is still running and we can still talk with it.
8423 We try all the open displays, one by one.
8424 This variable is used for cycling thru the displays. */
06a2c219 8425
2224b905
RS
8426static struct x_display_info *next_noop_dpyinfo;
8427
06a2c219
GM
8428#define SET_SAVED_MENU_EVENT(size) \
8429 do \
8430 { \
8431 if (f->output_data.x->saved_menu_event == 0) \
8432 f->output_data.x->saved_menu_event \
8433 = (XEvent *) xmalloc (sizeof (XEvent)); \
8434 bcopy (&event, f->output_data.x->saved_menu_event, size); \
8435 if (numchars >= 1) \
8436 { \
8437 bufp->kind = menu_bar_activate_event; \
8438 XSETFRAME (bufp->frame_or_window, f); \
8439 bufp++; \
8440 count++; \
8441 numchars--; \
8442 } \
8443 } \
8444 while (0)
8445
8805890a 8446#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 8447#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 8448
dc6f92b8
JB
8449/* Read events coming from the X server.
8450 This routine is called by the SIGIO handler.
8451 We return as soon as there are no more events to be read.
8452
8453 Events representing keys are stored in buffer BUFP,
8454 which can hold up to NUMCHARS characters.
8455 We return the number of characters stored into the buffer,
8456 thus pretending to be `read'.
8457
dc6f92b8
JB
8458 EXPECTED is nonzero if the caller knows input is available. */
8459
7c5283e4 8460int
f66868ba 8461XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 8462 register int sd;
8805890a
KH
8463 /* register */ struct input_event *bufp;
8464 /* register */ int numchars;
dc6f92b8
JB
8465 int expected;
8466{
8467 int count = 0;
8468 int nbytes = 0;
dc6f92b8 8469 XEvent event;
f676886a 8470 struct frame *f;
66f55a9d 8471 int event_found = 0;
334208b7 8472 struct x_display_info *dpyinfo;
6c183ba5
RS
8473#ifdef HAVE_X_I18N
8474 Status status_return;
8475#endif
dc6f92b8 8476
9ac0d9e0 8477 if (interrupt_input_blocked)
dc6f92b8 8478 {
9ac0d9e0 8479 interrupt_input_pending = 1;
dc6f92b8
JB
8480 return -1;
8481 }
8482
9ac0d9e0 8483 interrupt_input_pending = 0;
dc6f92b8 8484 BLOCK_INPUT;
c0a04927
RS
8485
8486 /* So people can tell when we have read the available input. */
8487 input_signal_count++;
8488
dc6f92b8 8489 if (numchars <= 0)
06a2c219 8490 abort (); /* Don't think this happens. */
dc6f92b8 8491
7a13e894
RS
8492 /* Find the display we are supposed to read input for.
8493 It's the one communicating on descriptor SD. */
8494 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
8495 {
8496#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 8497#ifdef FIOSNBIO
7a13e894
RS
8498 /* If available, Xlib uses FIOSNBIO to make the socket
8499 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 8500 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 8501 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 8502 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 8503#endif /* ! defined (FIOSNBIO) */
7a13e894 8504#endif
dc6f92b8 8505
7a13e894
RS
8506#if 0 /* This code can't be made to work, with multiple displays,
8507 and appears not to be used on any system any more.
8508 Also keyboard.c doesn't turn O_NDELAY on and off
8509 for X connections. */
dc6f92b8
JB
8510#ifndef SIGIO
8511#ifndef HAVE_SELECT
7a13e894
RS
8512 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
8513 {
8514 extern int read_alarm_should_throw;
8515 read_alarm_should_throw = 1;
8516 XPeekEvent (dpyinfo->display, &event);
8517 read_alarm_should_throw = 0;
8518 }
c118dd06
JB
8519#endif /* HAVE_SELECT */
8520#endif /* SIGIO */
7a13e894 8521#endif
dc6f92b8 8522
7a13e894
RS
8523 /* For debugging, this gives a way to fake an I/O error. */
8524 if (dpyinfo == XTread_socket_fake_io_error)
8525 {
8526 XTread_socket_fake_io_error = 0;
8527 x_io_error_quitter (dpyinfo->display);
8528 }
dc6f92b8 8529
06a2c219 8530 while (XPending (dpyinfo->display))
dc6f92b8 8531 {
7a13e894 8532 XNextEvent (dpyinfo->display, &event);
06a2c219
GM
8533
8534 if (display_busy_cursor_p)
8535 {
8536 /* Setting inhibit_busy_cursor to 2 inhibits busy-cursor
8537 display until the next X event is read and we come
8538 here again. Setting it to 1 inhibits busy-cursor
8539 display for direct commands. */
8540 if (event.type == MotionNotify
8541 || event.type == EnterNotify
8542 || (dpyinfo->grabbed
8543 && event.type != ButtonRelease))
8544 inhibit_busy_cursor = 2;
8545 else
8546 inhibit_busy_cursor = 1;
8547 }
8548
531483fb 8549#ifdef HAVE_X_I18N
d1bc4182
RS
8550 {
8551 struct frame *f1 = x_any_window_to_frame (dpyinfo,
c99babf2 8552 event.xclient.window);
d1bc4182
RS
8553 /* The necessity of the following line took me
8554 a full work-day to decipher from the docs!! */
8555 if (f1 != 0 && FRAME_XIC (f1) && XFilterEvent (&event, None))
8556 break;
8557 }
0cd6403b 8558#endif
7a13e894
RS
8559 event_found = 1;
8560
8561 switch (event.type)
8562 {
8563 case ClientMessage:
c047688c 8564 {
7a13e894
RS
8565 if (event.xclient.message_type
8566 == dpyinfo->Xatom_wm_protocols
8567 && event.xclient.format == 32)
c047688c 8568 {
7a13e894
RS
8569 if (event.xclient.data.l[0]
8570 == dpyinfo->Xatom_wm_take_focus)
c047688c 8571 {
8c1a6a84
RS
8572 /* Use x_any_window_to_frame because this
8573 could be the shell widget window
8574 if the frame has no title bar. */
8575 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
8576#ifdef HAVE_X_I18N
8577 /* Not quite sure this is needed -pd */
8c1a6a84 8578 if (f && FRAME_XIC (f))
6c183ba5
RS
8579 XSetICFocus (FRAME_XIC (f));
8580#endif
bf7253f4
RS
8581 /* Since we set WM_TAKE_FOCUS, we must call
8582 XSetInputFocus explicitly. But not if f is null,
8583 since that might be an event for a deleted frame. */
7a13e894 8584 if (f)
bf7253f4
RS
8585 {
8586 Display *d = event.xclient.display;
8587 /* Catch and ignore errors, in case window has been
8588 iconified by a window manager such as GWM. */
8589 int count = x_catch_errors (d);
8590 XSetInputFocus (d, event.xclient.window,
8591 RevertToPointerRoot,
8592 event.xclient.data.l[1]);
8593 /* This is needed to detect the error
8594 if there is an error. */
8595 XSync (d, False);
8596 x_uncatch_errors (d, count);
8597 }
7a13e894 8598 /* Not certain about handling scroll bars here */
c047688c 8599 }
7a13e894
RS
8600 else if (event.xclient.data.l[0]
8601 == dpyinfo->Xatom_wm_save_yourself)
8602 {
8603 /* Save state modify the WM_COMMAND property to
06a2c219 8604 something which can reinstate us. This notifies
7a13e894
RS
8605 the session manager, who's looking for such a
8606 PropertyNotify. Can restart processing when
06a2c219 8607 a keyboard or mouse event arrives. */
7a13e894
RS
8608 if (numchars > 0)
8609 {
19126e11
KH
8610 f = x_top_window_to_frame (dpyinfo,
8611 event.xclient.window);
7a13e894
RS
8612
8613 /* This is just so we only give real data once
8614 for a single Emacs process. */
8615 if (f == selected_frame)
8616 XSetCommand (FRAME_X_DISPLAY (f),
8617 event.xclient.window,
8618 initial_argv, initial_argc);
f000f5c5 8619 else if (f)
7a13e894
RS
8620 XSetCommand (FRAME_X_DISPLAY (f),
8621 event.xclient.window,
8622 0, 0);
8623 }
8624 }
8625 else if (event.xclient.data.l[0]
8626 == dpyinfo->Xatom_wm_delete_window)
1fb20991 8627 {
19126e11
KH
8628 struct frame *f
8629 = x_any_window_to_frame (dpyinfo,
8630 event.xclient.window);
1fb20991 8631
7a13e894
RS
8632 if (f)
8633 {
8634 if (numchars == 0)
8635 abort ();
1fb20991 8636
7a13e894
RS
8637 bufp->kind = delete_window_event;
8638 XSETFRAME (bufp->frame_or_window, f);
8639 bufp++;
8640
8641 count += 1;
8642 numchars -= 1;
8643 }
1fb20991 8644 }
c047688c 8645 }
7a13e894
RS
8646 else if (event.xclient.message_type
8647 == dpyinfo->Xatom_wm_configure_denied)
8648 {
8649 }
8650 else if (event.xclient.message_type
8651 == dpyinfo->Xatom_wm_window_moved)
8652 {
8653 int new_x, new_y;
19126e11
KH
8654 struct frame *f
8655 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 8656
7a13e894
RS
8657 new_x = event.xclient.data.s[0];
8658 new_y = event.xclient.data.s[1];
1fb20991 8659
7a13e894
RS
8660 if (f)
8661 {
7556890b
RS
8662 f->output_data.x->left_pos = new_x;
8663 f->output_data.x->top_pos = new_y;
7a13e894 8664 }
1fb20991 8665 }
0fdff6bb 8666#ifdef HACK_EDITRES
7a13e894
RS
8667 else if (event.xclient.message_type
8668 == dpyinfo->Xatom_editres)
8669 {
19126e11
KH
8670 struct frame *f
8671 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 8672 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 8673 &event, NULL);
7a13e894 8674 }
0fdff6bb 8675#endif /* HACK_EDITRES */
06a2c219
GM
8676 else if ((event.xclient.message_type
8677 == dpyinfo->Xatom_DONE)
8678 || (event.xclient.message_type
8679 == dpyinfo->Xatom_PAGE))
8680 {
8681 /* Ghostview job completed. Kill it. We could
8682 reply with "Next" if we received "Page", but we
8683 currently never do because we are interested in
8684 images, only, which should have 1 page. */
8685 Window gs_window = (Window) event.xclient.data.l[0];
8686 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
8687 struct frame *f
8688 = x_window_to_frame (dpyinfo, event.xclient.window);
8689 x_kill_gs_process (pixmap, f);
8690 expose_frame (f, 0, 0, 0, 0);
8691 }
8692#ifdef USE_TOOLKIT_SCROLL_BARS
8693 /* Scroll bar callbacks send a ClientMessage from which
8694 we construct an input_event. */
8695 else if (event.xclient.message_type
8696 == dpyinfo->Xatom_Scrollbar)
8697 {
8698 x_scroll_bar_to_input_event (&event, bufp);
8699 ++bufp, ++count, --numchars;
8700 goto out;
8701 }
8702#endif /* USE_TOOLKIT_SCROLL_BARS */
8703 else
8704 goto OTHER;
7a13e894
RS
8705 }
8706 break;
dc6f92b8 8707
7a13e894 8708 case SelectionNotify:
3afe33e7 8709#ifdef USE_X_TOOLKIT
19126e11 8710 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 8711 goto OTHER;
3afe33e7 8712#endif /* not USE_X_TOOLKIT */
dfcf069d 8713 x_handle_selection_notify (&event.xselection);
7a13e894 8714 break;
d56a553a 8715
06a2c219 8716 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 8717#ifdef USE_X_TOOLKIT
19126e11 8718 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 8719 goto OTHER;
3afe33e7 8720#endif /* USE_X_TOOLKIT */
7a13e894
RS
8721 {
8722 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 8723
7a13e894
RS
8724 if (numchars == 0)
8725 abort ();
d56a553a 8726
7a13e894
RS
8727 bufp->kind = selection_clear_event;
8728 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
8729 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
8730 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 8731 bufp->frame_or_window = Qnil;
7a13e894 8732 bufp++;
d56a553a 8733
7a13e894
RS
8734 count += 1;
8735 numchars -= 1;
8736 }
8737 break;
dc6f92b8 8738
06a2c219 8739 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 8740#ifdef USE_X_TOOLKIT
19126e11 8741 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 8742 goto OTHER;
3afe33e7 8743#endif /* USE_X_TOOLKIT */
7a13e894 8744 if (x_queue_selection_requests)
19126e11 8745 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
8746 &event);
8747 else
8748 {
8749 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 8750
7a13e894
RS
8751 if (numchars == 0)
8752 abort ();
8753
8754 bufp->kind = selection_request_event;
8755 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
8756 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
8757 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
8758 SELECTION_EVENT_TARGET (bufp) = eventp->target;
8759 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
8760 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 8761 bufp->frame_or_window = Qnil;
7a13e894
RS
8762 bufp++;
8763
8764 count += 1;
8765 numchars -= 1;
8766 }
8767 break;
8768
8769 case PropertyNotify:
3afe33e7 8770#ifdef USE_X_TOOLKIT
19126e11 8771 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 8772 goto OTHER;
3afe33e7 8773#endif /* not USE_X_TOOLKIT */
dfcf069d 8774 x_handle_property_notify (&event.xproperty);
7a13e894 8775 break;
dc6f92b8 8776
7a13e894 8777 case ReparentNotify:
19126e11 8778 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
8779 if (f)
8780 {
8781 int x, y;
7556890b 8782 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 8783 x_real_positions (f, &x, &y);
7556890b
RS
8784 f->output_data.x->left_pos = x;
8785 f->output_data.x->top_pos = y;
7a13e894
RS
8786 }
8787 break;
3bd330d4 8788
7a13e894 8789 case Expose:
19126e11 8790 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 8791 if (f)
dc6f92b8 8792 {
7a13e894
RS
8793 if (f->async_visible == 0)
8794 {
8795 f->async_visible = 1;
8796 f->async_iconified = 0;
06c488fd 8797 f->output_data.x->has_been_visible = 1;
7a13e894
RS
8798 SET_FRAME_GARBAGED (f);
8799 }
8800 else
06a2c219
GM
8801 expose_frame (x_window_to_frame (dpyinfo,
8802 event.xexpose.window),
8803 event.xexpose.x, event.xexpose.y,
8804 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
8805 }
8806 else
7a13e894 8807 {
06a2c219
GM
8808#ifdef USE_TOOLKIT_SCROLL_BARS
8809 /* Dispatch event to the widget. */
8810 goto OTHER;
8811#else /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
8812 struct scroll_bar *bar
8813 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 8814
7a13e894
RS
8815 if (bar)
8816 x_scroll_bar_expose (bar, &event);
3afe33e7 8817#ifdef USE_X_TOOLKIT
7a13e894
RS
8818 else
8819 goto OTHER;
3afe33e7 8820#endif /* USE_X_TOOLKIT */
06a2c219 8821#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
8822 }
8823 break;
dc6f92b8 8824
7a13e894
RS
8825 case GraphicsExpose: /* This occurs when an XCopyArea's
8826 source area was obscured or not
8827 available.*/
19126e11 8828 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
8829 if (f)
8830 {
06a2c219
GM
8831 expose_frame (f,
8832 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
8833 event.xgraphicsexpose.width,
8834 event.xgraphicsexpose.height);
7a13e894 8835 }
3afe33e7 8836#ifdef USE_X_TOOLKIT
7a13e894
RS
8837 else
8838 goto OTHER;
3afe33e7 8839#endif /* USE_X_TOOLKIT */
7a13e894 8840 break;
dc6f92b8 8841
7a13e894 8842 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
8843 source area was completely
8844 available */
7a13e894 8845 break;
dc6f92b8 8846
7a13e894 8847 case UnmapNotify:
06a2c219
GM
8848 /* Redo the mouse-highlight after the tooltip has gone. */
8849 if (event.xmap.window == tip_window)
8850 {
8851 tip_window = 0;
8852 redo_mouse_highlight ();
8853 }
8854
91ea2a7a 8855 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
8856 if (f) /* F may no longer exist if
8857 the frame was deleted. */
8858 {
8859 /* While a frame is unmapped, display generation is
8860 disabled; you don't want to spend time updating a
8861 display that won't ever be seen. */
8862 f->async_visible = 0;
8863 /* We can't distinguish, from the event, whether the window
8864 has become iconified or invisible. So assume, if it
8865 was previously visible, than now it is iconified.
1aa6072f
RS
8866 But x_make_frame_invisible clears both
8867 the visible flag and the iconified flag;
8868 and that way, we know the window is not iconified now. */
7a13e894 8869 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
8870 {
8871 f->async_iconified = 1;
bddd097c 8872
1aa6072f
RS
8873 bufp->kind = iconify_event;
8874 XSETFRAME (bufp->frame_or_window, f);
8875 bufp++;
8876 count++;
8877 numchars--;
8878 }
7a13e894 8879 }
7a13e894 8880 goto OTHER;
dc6f92b8 8881
7a13e894 8882 case MapNotify:
06a2c219
GM
8883 if (event.xmap.window == tip_window)
8884 /* The tooltip has been drawn already. Avoid
8885 the SET_FRAME_GARBAGED below. */
8886 goto OTHER;
8887
8888 /* We use x_top_window_to_frame because map events can
8889 come for sub-windows and they don't mean that the
8890 frame is visible. */
19126e11 8891 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
8892 if (f)
8893 {
8894 f->async_visible = 1;
8895 f->async_iconified = 0;
06c488fd 8896 f->output_data.x->has_been_visible = 1;
dc6f92b8 8897
7a13e894
RS
8898 /* wait_reading_process_input will notice this and update
8899 the frame's display structures. */
8900 SET_FRAME_GARBAGED (f);
bddd097c 8901
d806e720
RS
8902 if (f->iconified)
8903 {
8904 bufp->kind = deiconify_event;
8905 XSETFRAME (bufp->frame_or_window, f);
8906 bufp++;
8907 count++;
8908 numchars--;
8909 }
e73ec6fa 8910 else if (! NILP (Vframe_list)
8c29f6bf 8911 && ! NILP (XCONS (Vframe_list)->cdr))
78aa2ba5
KH
8912 /* Force a redisplay sooner or later
8913 to update the frame titles
8914 in case this is the second frame. */
8915 record_asynch_buffer_change ();
7a13e894 8916 }
7a13e894 8917 goto OTHER;
dc6f92b8 8918
7a13e894 8919 case KeyPress:
19126e11 8920 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 8921
06a2c219
GM
8922#ifdef USE_MOTIF
8923 /* I couldn't find a way to prevent LessTif scroll bars
8924 from consuming key events. */
8925 if (f == 0)
8926 {
8927 Widget widget = XtWindowToWidget (dpyinfo->display,
8928 event.xkey.window);
8929 if (widget && XmIsScrollBar (widget))
8930 {
8931 widget = XtParent (widget);
8932 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
8933 }
8934 }
8935#endif /* USE_MOTIF */
8936
7a13e894
RS
8937 if (f != 0)
8938 {
8939 KeySym keysym, orig_keysym;
8940 /* al%imercury@uunet.uu.net says that making this 81 instead of
8941 80 fixed a bug whereby meta chars made his Emacs hang. */
8942 unsigned char copy_buffer[81];
8943 int modifiers;
64bb1782 8944
7a13e894
RS
8945 event.xkey.state
8946 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
8947 extra_keyboard_modifiers);
8948 modifiers = event.xkey.state;
3a2712f9 8949
7a13e894 8950 /* This will have to go some day... */
752a043f 8951
7a13e894
RS
8952 /* make_lispy_event turns chars into control chars.
8953 Don't do it here because XLookupString is too eager. */
8954 event.xkey.state &= ~ControlMask;
5d46f928
RS
8955 event.xkey.state &= ~(dpyinfo->meta_mod_mask
8956 | dpyinfo->super_mod_mask
8957 | dpyinfo->hyper_mod_mask
8958 | dpyinfo->alt_mod_mask);
8959
1cf4a0d1
RS
8960 /* In case Meta is ComposeCharacter,
8961 clear its status. According to Markus Ehrnsperger
8962 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
8963 this enables ComposeCharacter to work whether or
8964 not it is combined with Meta. */
8965 if (modifiers & dpyinfo->meta_mod_mask)
8966 bzero (&compose_status, sizeof (compose_status));
8967
6c183ba5
RS
8968#ifdef HAVE_X_I18N
8969 if (FRAME_XIC (f))
8970 {
5d7cc324
RS
8971 /* The necessity of the following line took me
8972 a full work-day to decipher from the docs!! */
8973 if (XFilterEvent (&event, None))
8974 break;
6c183ba5
RS
8975 nbytes = XmbLookupString (FRAME_XIC (f),
8976 &event.xkey, copy_buffer,
8977 80, &keysym,
8978 &status_return);
1decb680
PE
8979 if (status_return == XLookupNone)
8980 break;
8981 else if (status_return == XLookupChars)
8982 keysym = NoSymbol;
8983 else if (status_return != XLookupKeySym
8984 && status_return != XLookupBoth)
8985 abort ();
6c183ba5
RS
8986 }
8987 else
8988 nbytes = XLookupString (&event.xkey, copy_buffer,
8989 80, &keysym, &compose_status);
8990#else
0299d313
RS
8991 nbytes = XLookupString (&event.xkey, copy_buffer,
8992 80, &keysym, &compose_status);
6c183ba5 8993#endif
dc6f92b8 8994
7a13e894 8995 orig_keysym = keysym;
55123275 8996
7a13e894
RS
8997 if (numchars > 1)
8998 {
8999 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
9000 || keysym == XK_Delete
1097aea0 9001#ifdef XK_ISO_Left_Tab
441affdb 9002 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 9003#endif
852bff8f 9004 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
9005 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
9006 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 9007#ifdef HPUX
7a13e894
RS
9008 /* This recognizes the "extended function keys".
9009 It seems there's no cleaner way.
9010 Test IsModifierKey to avoid handling mode_switch
9011 incorrectly. */
9012 || ((unsigned) (keysym) >= XK_Select
9013 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
9014#endif
9015#ifdef XK_dead_circumflex
7a13e894 9016 || orig_keysym == XK_dead_circumflex
69388238
RS
9017#endif
9018#ifdef XK_dead_grave
7a13e894 9019 || orig_keysym == XK_dead_grave
69388238
RS
9020#endif
9021#ifdef XK_dead_tilde
7a13e894 9022 || orig_keysym == XK_dead_tilde
69388238
RS
9023#endif
9024#ifdef XK_dead_diaeresis
7a13e894 9025 || orig_keysym == XK_dead_diaeresis
69388238
RS
9026#endif
9027#ifdef XK_dead_macron
7a13e894 9028 || orig_keysym == XK_dead_macron
69388238
RS
9029#endif
9030#ifdef XK_dead_degree
7a13e894 9031 || orig_keysym == XK_dead_degree
69388238
RS
9032#endif
9033#ifdef XK_dead_acute
7a13e894 9034 || orig_keysym == XK_dead_acute
69388238
RS
9035#endif
9036#ifdef XK_dead_cedilla
7a13e894 9037 || orig_keysym == XK_dead_cedilla
69388238
RS
9038#endif
9039#ifdef XK_dead_breve
7a13e894 9040 || orig_keysym == XK_dead_breve
69388238
RS
9041#endif
9042#ifdef XK_dead_ogonek
7a13e894 9043 || orig_keysym == XK_dead_ogonek
69388238
RS
9044#endif
9045#ifdef XK_dead_caron
7a13e894 9046 || orig_keysym == XK_dead_caron
69388238
RS
9047#endif
9048#ifdef XK_dead_doubleacute
7a13e894 9049 || orig_keysym == XK_dead_doubleacute
69388238
RS
9050#endif
9051#ifdef XK_dead_abovedot
7a13e894 9052 || orig_keysym == XK_dead_abovedot
c34790e0 9053#endif
7a13e894
RS
9054 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
9055 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
9056 /* Any "vendor-specific" key is ok. */
9057 || (orig_keysym & (1 << 28)))
9058 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
9059#ifndef HAVE_X11R5
9060#ifdef XK_Mode_switch
7a13e894 9061 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
9062#endif
9063#ifdef XK_Num_Lock
7a13e894 9064 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
9065#endif
9066#endif /* not HAVE_X11R5 */
7a13e894 9067 ))
dc6f92b8 9068 {
10e6549c
RS
9069 if (temp_index == sizeof temp_buffer / sizeof (short))
9070 temp_index = 0;
7a13e894
RS
9071 temp_buffer[temp_index++] = keysym;
9072 bufp->kind = non_ascii_keystroke;
9073 bufp->code = keysym;
e0c1aef2 9074 XSETFRAME (bufp->frame_or_window, f);
334208b7
RS
9075 bufp->modifiers
9076 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9077 modifiers);
1113d9db 9078 bufp->timestamp = event.xkey.time;
dc6f92b8 9079 bufp++;
7a13e894
RS
9080 count++;
9081 numchars--;
06a2c219
GM
9082
9083 if (display_busy_cursor_p)
9084 if (keysym != XK_Return || minibuf_level == 0)
9085 inhibit_busy_cursor = 2;
dc6f92b8 9086 }
7a13e894
RS
9087 else if (numchars > nbytes)
9088 {
9089 register int i;
9090
9091 for (i = 0; i < nbytes; i++)
9092 {
9093 if (temp_index == sizeof temp_buffer / sizeof (short))
9094 temp_index = 0;
9095 temp_buffer[temp_index++] = copy_buffer[i];
9096 bufp->kind = ascii_keystroke;
9097 bufp->code = copy_buffer[i];
9098 XSETFRAME (bufp->frame_or_window, f);
9099 bufp->modifiers
9100 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9101 modifiers);
9102 bufp->timestamp = event.xkey.time;
9103 bufp++;
9104 }
9105
9106 count += nbytes;
9107 numchars -= nbytes;
1decb680
PE
9108
9109 if (keysym == NoSymbol)
9110 break;
7a13e894
RS
9111 }
9112 else
9113 abort ();
dc6f92b8 9114 }
10e6549c
RS
9115 else
9116 abort ();
dc6f92b8 9117 }
717ca130 9118 goto OTHER;
f451eb13 9119
7a13e894 9120 /* Here's a possible interpretation of the whole
06a2c219
GM
9121 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
9122 you get a FocusIn event, you have to get a FocusOut
9123 event before you relinquish the focus. If you
9124 haven't received a FocusIn event, then a mere
9125 LeaveNotify is enough to free you. */
f451eb13 9126
7a13e894 9127 case EnterNotify:
06a2c219
GM
9128 {
9129 int from_menu_bar_p = 0;
9130
9131 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
9132
9133#ifdef LESSTIF_VERSION
9134 /* When clicking outside of a menu bar popup to close
9135 it, we get a FocusIn/ EnterNotify sequence of
9136 events. The flag event.xcrossing.focus is not set
9137 in the EnterNotify event of that sequence because
9138 the focus is in the menu bar,
9139 event.xcrossing.window is the frame's X window.
9140 Unconditionally setting the focus frame to null in
9141 this case is not the right thing, because no event
9142 follows that could set the focus frame to the right
9143 value.
9144
9145 This could be a LessTif bug, but I wasn't able to
9146 reproduce the behavior in a simple test program.
9147
9148 (gerd, LessTif 0.88.1). */
9149
9150 if (!event.xcrossing.focus
9151 && f
9152 && f->output_data.x->menubar_widget)
9153 {
9154 Window focus;
9155 int revert;
9156
9157 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9158 if (focus == XtWindow (f->output_data.x->menubar_widget))
9159 from_menu_bar_p = 1;
9160 }
9161#endif /* LESSTIF_VERSION */
6d4238f3 9162
06a2c219
GM
9163 if (event.xcrossing.focus || from_menu_bar_p)
9164 {
9165 /* Avoid nasty pop/raise loops. */
9166 if (f && (!(f->auto_raise)
9167 || !(f->auto_lower)
9168 || (event.xcrossing.time - enter_timestamp) > 500))
9169 {
9170 x_new_focus_frame (dpyinfo, f);
9171 enter_timestamp = event.xcrossing.time;
9172 }
9173 }
9174 else if (f == dpyinfo->x_focus_frame)
9175 x_new_focus_frame (dpyinfo, 0);
9176
9177 /* EnterNotify counts as mouse movement,
9178 so update things that depend on mouse position. */
9179 if (f && !f->output_data.x->busy_p)
9180 note_mouse_movement (f, &event.xmotion);
9181 goto OTHER;
9182 }
dc6f92b8 9183
7a13e894 9184 case FocusIn:
19126e11 9185 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9186 if (event.xfocus.detail != NotifyPointer)
0f941935 9187 dpyinfo->x_focus_event_frame = f;
7a13e894 9188 if (f)
0f941935 9189 x_new_focus_frame (dpyinfo, f);
f9e24cb9 9190
6c183ba5
RS
9191#ifdef HAVE_X_I18N
9192 if (f && FRAME_XIC (f))
9193 XSetICFocus (FRAME_XIC (f));
9194#endif
9195
7a13e894 9196 goto OTHER;
10c5e63d 9197
7a13e894 9198 case LeaveNotify:
19126e11 9199 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 9200 if (f)
10c5e63d 9201 {
06a2c219
GM
9202 Lisp_Object frame;
9203 int from_menu_bar_p = 0;
9204
7a13e894 9205 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
9206 {
9207 /* If we move outside the frame, then we're
9208 certainly no longer on any text in the frame. */
9209 clear_mouse_face (dpyinfo);
9210 dpyinfo->mouse_face_mouse_frame = 0;
9211 }
9212
9213 /* Generate a nil HELP_EVENT to cancel a help-echo.
9214 Do it only if there's something to cancel.
9215 Otherwise, the startup message is cleared when
9216 the mouse leaves the frame. */
9217 if (any_help_event_p)
9218 {
9219 XSETFRAME (frame, f);
9220 bufp->kind = HELP_EVENT;
9221 bufp->frame_or_window = Fcons (frame, Qnil);
9222 ++bufp, ++count, --numchars;
9223 }
7a13e894 9224
06a2c219
GM
9225#ifdef LESSTIF_VERSION
9226 /* Please see the comment at the start of the
9227 EnterNotify case. */
9228 if (!event.xcrossing.focus
9229 && f->output_data.x->menubar_widget)
9230 {
9231 Window focus;
9232 int revert;
9233 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9234 if (focus == XtWindow (f->output_data.x->menubar_widget))
9235 from_menu_bar_p = 1;
9236 }
9237#endif /* LESSTIF_VERSION */
9238
9239 if (event.xcrossing.focus || from_menu_bar_p)
0f941935 9240 x_mouse_leave (dpyinfo);
10c5e63d 9241 else
7a13e894 9242 {
0f941935
KH
9243 if (f == dpyinfo->x_focus_event_frame)
9244 dpyinfo->x_focus_event_frame = 0;
9245 if (f == dpyinfo->x_focus_frame)
9246 x_new_focus_frame (dpyinfo, 0);
7a13e894 9247 }
10c5e63d 9248 }
7a13e894 9249 goto OTHER;
dc6f92b8 9250
7a13e894 9251 case FocusOut:
19126e11 9252 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9253 if (event.xfocus.detail != NotifyPointer
0f941935
KH
9254 && f == dpyinfo->x_focus_event_frame)
9255 dpyinfo->x_focus_event_frame = 0;
9256 if (f && f == dpyinfo->x_focus_frame)
9257 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 9258
6c183ba5
RS
9259#ifdef HAVE_X_I18N
9260 if (f && FRAME_XIC (f))
9261 XUnsetICFocus (FRAME_XIC (f));
9262#endif
9263
7a13e894 9264 goto OTHER;
dc6f92b8 9265
7a13e894 9266 case MotionNotify:
dc6f92b8 9267 {
06a2c219
GM
9268 previous_help_echo = help_echo;
9269 help_echo = Qnil;
9270
7a13e894
RS
9271 if (dpyinfo->grabbed && last_mouse_frame
9272 && FRAME_LIVE_P (last_mouse_frame))
9273 f = last_mouse_frame;
9274 else
19126e11 9275 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 9276
7a13e894
RS
9277 if (f)
9278 note_mouse_movement (f, &event.xmotion);
9279 else
9280 {
06a2c219 9281#ifndef USE_X_TOOLKIT
7a13e894
RS
9282 struct scroll_bar *bar
9283 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 9284
7a13e894
RS
9285 if (bar)
9286 x_scroll_bar_note_movement (bar, &event);
06a2c219 9287#endif /* USE_X_TOOLKIT */
b8009dd1 9288
06a2c219
GM
9289 /* If we move outside the frame, then we're
9290 certainly no longer on any text in the frame. */
7a13e894
RS
9291 clear_mouse_face (dpyinfo);
9292 }
06a2c219
GM
9293
9294 /* If the contents of the global variable help_echo
9295 has changed, generate a HELP_EVENT. */
9296 if (STRINGP (help_echo)
9297 || STRINGP (previous_help_echo))
9298 {
9299 Lisp_Object frame;
9300
9301 if (f)
9302 XSETFRAME (frame, f);
9303 else
9304 frame = Qnil;
9305
9306 any_help_event_p = 1;
9307 bufp->kind = HELP_EVENT;
9308 bufp->frame_or_window = Fcons (frame, help_echo);
9309 ++bufp, ++count, --numchars;
9310 }
9311
9312 goto OTHER;
dc6f92b8 9313 }
dc6f92b8 9314
7a13e894 9315 case ConfigureNotify:
9829ddba
RS
9316 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
9317 if (f)
af395ec1 9318 {
bf1b7b30
KH
9319 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
9320 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
06a2c219 9321
2d7fc7e8
RS
9322#ifndef USE_X_TOOLKIT
9323 /* In the toolkit version, change_frame_size
9324 is called by the code that handles resizing
9325 of the EmacsFrame widget. */
7a13e894 9326
7a13e894
RS
9327 /* Even if the number of character rows and columns has
9328 not changed, the font size may have changed, so we need
9329 to check the pixel dimensions as well. */
9330 if (columns != f->width
9331 || rows != f->height
7556890b
RS
9332 || event.xconfigure.width != f->output_data.x->pixel_width
9333 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894
RS
9334 {
9335 change_frame_size (f, rows, columns, 0, 1);
9336 SET_FRAME_GARBAGED (f);
e687d06e 9337 cancel_mouse_face (f);
7a13e894 9338 }
2d7fc7e8 9339#endif
af395ec1 9340
7556890b
RS
9341 f->output_data.x->pixel_width = event.xconfigure.width;
9342 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
9343
9344 /* What we have now is the position of Emacs's own window.
9345 Convert that to the position of the window manager window. */
dcb07ae9
RS
9346 x_real_positions (f, &f->output_data.x->left_pos,
9347 &f->output_data.x->top_pos);
9348
9349 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
9350 {
9351 /* Since the WM decorations come below top_pos now,
9352 we must put them below top_pos in the future. */
9353 f->output_data.x->win_gravity = NorthWestGravity;
9354 x_wm_set_size_hint (f, (long) 0, 0);
9355 }
8f08dc93
KH
9356#ifdef USE_MOTIF
9357 /* Some window managers pass (0,0) as the location of
9358 the window, and the Motif event handler stores it
9359 in the emacs widget, which messes up Motif menus. */
9360 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
9361 {
9362 event.xconfigure.x = f->output_data.x->widget->core.x;
9363 event.xconfigure.y = f->output_data.x->widget->core.y;
9364 }
06a2c219 9365#endif /* USE_MOTIF */
7a13e894 9366 }
2d7fc7e8 9367 goto OTHER;
dc6f92b8 9368
7a13e894
RS
9369 case ButtonPress:
9370 case ButtonRelease:
9371 {
9372 /* If we decide we want to generate an event to be seen
9373 by the rest of Emacs, we put it here. */
9374 struct input_event emacs_event;
06a2c219
GM
9375 int toolbar_p = 0;
9376
7a13e894 9377 emacs_event.kind = no_event;
7a13e894 9378 bzero (&compose_status, sizeof (compose_status));
9b07615b 9379
06a2c219
GM
9380 if (dpyinfo->grabbed
9381 && last_mouse_frame
9f67f20b
RS
9382 && FRAME_LIVE_P (last_mouse_frame))
9383 f = last_mouse_frame;
9384 else
2224b905 9385 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 9386
06a2c219
GM
9387 if (f)
9388 {
9389 /* Is this in the toolbar? */
9390 if (WINDOWP (f->toolbar_window)
9391 && XFASTINT (XWINDOW (f->toolbar_window)->height))
9392 {
9393 Lisp_Object window;
9394 int p, x, y;
9395
9396 x = event.xbutton.x;
9397 y = event.xbutton.y;
9398
9399 /* Set x and y. */
9400 window = window_from_coordinates (f, x, y, &p, 1);
9401 if (EQ (window, f->toolbar_window))
9402 {
9403 x_handle_toolbar_click (f, &event.xbutton);
9404 toolbar_p = 1;
9405 }
9406 }
9407
9408 if (!toolbar_p)
9409 if (!dpyinfo->x_focus_frame
9410 || f == dpyinfo->x_focus_frame)
9411 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
9412 }
9413 else
9414 {
06a2c219 9415#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
9416 struct scroll_bar *bar
9417 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 9418
7a13e894
RS
9419 if (bar)
9420 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 9421#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9422 }
9423
9424 if (event.type == ButtonPress)
9425 {
9426 dpyinfo->grabbed |= (1 << event.xbutton.button);
9427 last_mouse_frame = f;
edad46f6
KH
9428 /* Ignore any mouse motion that happened
9429 before this event; any subsequent mouse-movement
9430 Emacs events should reflect only motion after
9431 the ButtonPress. */
a00e91cd
KH
9432 if (f != 0)
9433 f->mouse_moved = 0;
06a2c219
GM
9434
9435 if (!toolbar_p)
9436 last_toolbar_item = -1;
9437 if (display_busy_cursor_p)
9438 inhibit_busy_cursor = 2;
7a13e894 9439 }
3afe33e7
RS
9440 else
9441 {
7a13e894 9442 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 9443 }
23faf38f 9444
7a13e894
RS
9445 if (numchars >= 1 && emacs_event.kind != no_event)
9446 {
9447 bcopy (&emacs_event, bufp, sizeof (struct input_event));
9448 bufp++;
9449 count++;
9450 numchars--;
9451 }
3afe33e7
RS
9452
9453#ifdef USE_X_TOOLKIT
2224b905
RS
9454 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
9455 /* For a down-event in the menu bar,
9456 don't pass it to Xt right now.
9457 Instead, save it away
9458 and we will pass it to Xt from kbd_buffer_get_event.
9459 That way, we can run some Lisp code first. */
91375f8f
RS
9460 if (f && event.type == ButtonPress
9461 /* Verify the event is really within the menu bar
9462 and not just sent to it due to grabbing. */
9463 && event.xbutton.x >= 0
9464 && event.xbutton.x < f->output_data.x->pixel_width
9465 && event.xbutton.y >= 0
9466 && event.xbutton.y < f->output_data.x->menubar_height
9467 && event.xbutton.same_screen)
2224b905 9468 {
8805890a 9469 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
9470 XSETFRAME (last_mouse_press_frame, f);
9471 }
9472 else if (event.type == ButtonPress)
9473 {
9474 last_mouse_press_frame = Qnil;
30e671c3 9475 goto OTHER;
ce89ef46 9476 }
06a2c219 9477
2237cac9
RS
9478#ifdef USE_MOTIF /* This should do not harm for Lucid,
9479 but I am trying to be cautious. */
ce89ef46
RS
9480 else if (event.type == ButtonRelease)
9481 {
2237cac9 9482 if (!NILP (last_mouse_press_frame))
f10ded1c 9483 {
2237cac9
RS
9484 f = XFRAME (last_mouse_press_frame);
9485 if (f->output_data.x)
06a2c219 9486 SET_SAVED_BUTTON_EVENT;
f10ded1c 9487 }
06a2c219 9488 else
30e671c3 9489 goto OTHER;
2224b905 9490 }
2237cac9 9491#endif /* USE_MOTIF */
2224b905
RS
9492 else
9493 goto OTHER;
3afe33e7 9494#endif /* USE_X_TOOLKIT */
7a13e894
RS
9495 }
9496 break;
dc6f92b8 9497
7a13e894 9498 case CirculateNotify:
06a2c219
GM
9499 goto OTHER;
9500
7a13e894 9501 case CirculateRequest:
06a2c219
GM
9502 goto OTHER;
9503
9504 case VisibilityNotify:
9505 goto OTHER;
dc6f92b8 9506
7a13e894
RS
9507 case MappingNotify:
9508 /* Someone has changed the keyboard mapping - update the
9509 local cache. */
9510 switch (event.xmapping.request)
9511 {
9512 case MappingModifier:
9513 x_find_modifier_meanings (dpyinfo);
9514 /* This is meant to fall through. */
9515 case MappingKeyboard:
9516 XRefreshKeyboardMapping (&event.xmapping);
9517 }
7a13e894 9518 goto OTHER;
dc6f92b8 9519
7a13e894 9520 default:
7a13e894 9521 OTHER:
717ca130 9522#ifdef USE_X_TOOLKIT
7a13e894
RS
9523 BLOCK_INPUT;
9524 XtDispatchEvent (&event);
9525 UNBLOCK_INPUT;
3afe33e7 9526#endif /* USE_X_TOOLKIT */
7a13e894
RS
9527 break;
9528 }
dc6f92b8
JB
9529 }
9530 }
9531
06a2c219
GM
9532 out:;
9533
9a5196d0
RS
9534 /* On some systems, an X bug causes Emacs to get no more events
9535 when the window is destroyed. Detect that. (1994.) */
58769bee 9536 if (! event_found)
ef2a22d0 9537 {
ef2a22d0
RS
9538 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
9539 One XNOOP in 100 loops will make Emacs terminate.
9540 B. Bretthauer, 1994 */
9541 x_noop_count++;
58769bee 9542 if (x_noop_count >= 100)
ef2a22d0
RS
9543 {
9544 x_noop_count=0;
2224b905
RS
9545
9546 if (next_noop_dpyinfo == 0)
9547 next_noop_dpyinfo = x_display_list;
9548
9549 XNoOp (next_noop_dpyinfo->display);
9550
9551 /* Each time we get here, cycle through the displays now open. */
9552 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
9553 }
9554 }
502add23 9555
06a2c219 9556 /* If the focus was just given to an auto-raising frame,
0134a210 9557 raise it now. */
7a13e894 9558 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
9559 if (pending_autoraise_frame)
9560 {
9561 x_raise_frame (pending_autoraise_frame);
9562 pending_autoraise_frame = 0;
9563 }
0134a210 9564
dc6f92b8
JB
9565 UNBLOCK_INPUT;
9566 return count;
9567}
06a2c219
GM
9568
9569
9570
dc6f92b8 9571\f
06a2c219
GM
9572/***********************************************************************
9573 Text Cursor
9574 ***********************************************************************/
9575
9576/* Note if the text cursor of window W has been overwritten by a
9577 drawing operation that outputs N glyphs starting at HPOS in the
9578 line given by output_cursor.vpos. N < 0 means all the rest of the
9579 line after HPOS has been written. */
9580
9581static void
9582note_overwritten_text_cursor (w, hpos, n)
9583 struct window *w;
9584 int hpos, n;
9585{
9586 if (updated_area == TEXT_AREA
9587 && output_cursor.vpos == w->phys_cursor.vpos
9588 && hpos <= w->phys_cursor.hpos
9589 && (n < 0
9590 || hpos + n > w->phys_cursor.hpos))
9591 w->phys_cursor_on_p = 0;
9592}
f451eb13
JB
9593
9594
06a2c219
GM
9595/* Set clipping for output in glyph row ROW. W is the window in which
9596 we operate. GC is the graphics context to set clipping in.
9597 WHOLE_LINE_P non-zero means include the areas used for truncation
9598 mark display and alike in the clipping rectangle.
9599
9600 ROW may be a text row or, e.g., a mode line. Text rows must be
9601 clipped to the interior of the window dedicated to text display,
9602 mode lines must be clipped to the whole window. */
dc6f92b8
JB
9603
9604static void
06a2c219
GM
9605x_clip_to_row (w, row, gc, whole_line_p)
9606 struct window *w;
9607 struct glyph_row *row;
9608 GC gc;
9609 int whole_line_p;
dc6f92b8 9610{
06a2c219
GM
9611 struct frame *f = XFRAME (WINDOW_FRAME (w));
9612 XRectangle clip_rect;
9613 int window_x, window_y, window_width, window_height;
dc6f92b8 9614
06a2c219 9615 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 9616
06a2c219
GM
9617 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
9618 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
9619 clip_rect.y = max (clip_rect.y, window_y);
9620 clip_rect.width = window_width;
9621 clip_rect.height = row->visible_height;
5c1aae96 9622
06a2c219
GM
9623 /* If clipping to the whole line, including trunc marks, extend
9624 the rectangle to the left and increase its width. */
9625 if (whole_line_p)
9626 {
9627 clip_rect.x -= FRAME_X_FLAGS_AREA_WIDTH (f);
9628 clip_rect.width += 2 * FRAME_X_FLAGS_AREA_WIDTH (f);
9629 }
5c1aae96 9630
06a2c219 9631 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
9632}
9633
06a2c219
GM
9634
9635/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
9636
9637static void
06a2c219
GM
9638x_draw_hollow_cursor (w, row)
9639 struct window *w;
9640 struct glyph_row *row;
dc6f92b8 9641{
06a2c219
GM
9642 struct frame *f = XFRAME (WINDOW_FRAME (w));
9643 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9644 Display *dpy = FRAME_X_DISPLAY (f);
9645 int x, y, wd, h;
9646 XGCValues xgcv;
9647 struct glyph *cursor_glyph;
9648 GC gc;
9649
9650 /* Compute frame-relative coordinates from window-relative
9651 coordinates. */
9652 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
9653 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
9654 + row->ascent - w->phys_cursor_ascent);
9655 h = row->height - 1;
9656
9657 /* Get the glyph the cursor is on. If we can't tell because
9658 the current matrix is invalid or such, give up. */
9659 cursor_glyph = get_phys_cursor_glyph (w);
9660 if (cursor_glyph == NULL)
dc6f92b8
JB
9661 return;
9662
06a2c219
GM
9663 /* Compute the width of the rectangle to draw. If on a stretch
9664 glyph, and `x-stretch-block-cursor' is nil, don't draw a
9665 rectangle as wide as the glyph, but use a canonical character
9666 width instead. */
9667 wd = cursor_glyph->pixel_width - 1;
9668 if (cursor_glyph->type == STRETCH_GLYPH
9669 && !x_stretch_cursor_p)
9670 wd = min (CANON_X_UNIT (f), wd);
9671
9672 /* The foreground of cursor_gc is typically the same as the normal
9673 background color, which can cause the cursor box to be invisible. */
9674 xgcv.foreground = f->output_data.x->cursor_pixel;
9675 if (dpyinfo->scratch_cursor_gc)
9676 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
9677 else
9678 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
9679 GCForeground, &xgcv);
9680 gc = dpyinfo->scratch_cursor_gc;
9681
9682 /* Set clipping, draw the rectangle, and reset clipping again. */
9683 x_clip_to_row (w, row, gc, 0);
9684 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
9685 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
9686}
9687
06a2c219
GM
9688
9689/* Draw a bar cursor on window W in glyph row ROW.
9690
9691 Implementation note: One would like to draw a bar cursor with an
9692 angle equal to the one given by the font property XA_ITALIC_ANGLE.
9693 Unfortunately, I didn't find a font yet that has this property set.
9694 --gerd. */
dc6f92b8
JB
9695
9696static void
06a2c219
GM
9697x_draw_bar_cursor (w, row)
9698 struct window *w;
9699 struct glyph_row *row;
dc6f92b8 9700{
06a2c219
GM
9701 /* If cursor hpos is out of bounds, don't draw garbage. This can
9702 happen in mini-buffer windows when switching between echo area
9703 glyphs and mini-buffer. */
9704 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
9705 {
9706 struct frame *f = XFRAME (w->frame);
9707 struct glyph *cursor_glyph;
9708 GC gc;
9709 int x;
9710 unsigned long mask;
9711 XGCValues xgcv;
9712 Display *dpy;
9713 Window window;
9714
9715 cursor_glyph = get_phys_cursor_glyph (w);
9716 if (cursor_glyph == NULL)
9717 return;
9718
9719 xgcv.background = f->output_data.x->cursor_pixel;
9720 xgcv.foreground = f->output_data.x->cursor_pixel;
9721 xgcv.graphics_exposures = 0;
9722 mask = GCForeground | GCBackground | GCGraphicsExposures;
9723 dpy = FRAME_X_DISPLAY (f);
9724 window = FRAME_X_WINDOW (f);
9725 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
9726
9727 if (gc)
9728 XChangeGC (dpy, gc, mask, &xgcv);
9729 else
9730 {
9731 gc = XCreateGC (dpy, window, mask, &xgcv);
9732 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
9733 }
9734
9735 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
9736 x_clip_to_row (w, row, gc, 0);
9737 XFillRectangle (dpy, window, gc,
9738 x,
9739 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
9740 min (cursor_glyph->pixel_width,
9741 f->output_data.x->cursor_width),
9742 row->height);
9743 XSetClipMask (dpy, gc, None);
9744 }
dc6f92b8
JB
9745}
9746
06a2c219
GM
9747
9748/* Clear the cursor of window W to background color, and mark the
9749 cursor as not shown. This is used when the text where the cursor
9750 is is about to be rewritten. */
9751
dc6f92b8 9752static void
06a2c219
GM
9753x_clear_cursor (w)
9754 struct window *w;
dc6f92b8 9755{
06a2c219
GM
9756 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
9757 x_update_window_cursor (w, 0);
9758}
90e65f07 9759
dbc4e1c1 9760
06a2c219
GM
9761/* Draw the cursor glyph of window W in glyph row ROW. See the
9762 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 9763
06a2c219
GM
9764static void
9765x_draw_phys_cursor_glyph (w, row, hl)
9766 struct window *w;
9767 struct glyph_row *row;
9768 enum draw_glyphs_face hl;
9769{
9770 /* If cursor hpos is out of bounds, don't draw garbage. This can
9771 happen in mini-buffer windows when switching between echo area
9772 glyphs and mini-buffer. */
9773 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
9774 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
9775 w->phys_cursor.hpos, w->phys_cursor.hpos + 1, hl, 0, 0);
9776}
dbc4e1c1 9777
eea6af04 9778
06a2c219 9779/* Erase the image of a cursor of window W from the screen. */
eea6af04 9780
06a2c219
GM
9781static void
9782x_erase_phys_cursor (w)
9783 struct window *w;
9784{
9785 struct frame *f = XFRAME (w->frame);
9786 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9787 int hpos = w->phys_cursor.hpos;
9788 int vpos = w->phys_cursor.vpos;
9789 int mouse_face_here_p = 0;
9790 struct glyph_matrix *active_glyphs = w->current_matrix;
9791 struct glyph_row *cursor_row;
9792 struct glyph *cursor_glyph;
9793 enum draw_glyphs_face hl;
9794
9795 /* No cursor displayed or row invalidated => nothing to do on the
9796 screen. */
9797 if (w->phys_cursor_type == NO_CURSOR)
9798 goto mark_cursor_off;
9799
9800 /* VPOS >= active_glyphs->nrows means that window has been resized.
9801 Don't bother to erase the cursor. */
9802 if (vpos >= active_glyphs->nrows)
9803 goto mark_cursor_off;
9804
9805 /* If row containing cursor is marked invalid, there is nothing we
9806 can do. */
9807 cursor_row = MATRIX_ROW (active_glyphs, vpos);
9808 if (!cursor_row->enabled_p)
9809 goto mark_cursor_off;
9810
9811 /* This can happen when the new row is shorter than the old one.
9812 In this case, either x_draw_glyphs or clear_end_of_line
9813 should have cleared the cursor. Note that we wouldn't be
9814 able to erase the cursor in this case because we don't have a
9815 cursor glyph at hand. */
9816 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
9817 goto mark_cursor_off;
9818
9819 /* If the cursor is in the mouse face area, redisplay that when
9820 we clear the cursor. */
9821 if (w == XWINDOW (dpyinfo->mouse_face_window)
9822 && (vpos > dpyinfo->mouse_face_beg_row
9823 || (vpos == dpyinfo->mouse_face_beg_row
9824 && hpos >= dpyinfo->mouse_face_beg_col))
9825 && (vpos < dpyinfo->mouse_face_end_row
9826 || (vpos == dpyinfo->mouse_face_end_row
9827 && hpos < dpyinfo->mouse_face_end_col))
9828 /* Don't redraw the cursor's spot in mouse face if it is at the
9829 end of a line (on a newline). The cursor appears there, but
9830 mouse highlighting does not. */
9831 && cursor_row->used[TEXT_AREA] > hpos)
9832 mouse_face_here_p = 1;
9833
9834 /* Maybe clear the display under the cursor. */
9835 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
9836 {
9837 int x;
9838 int top_line_height = WINDOW_DISPLAY_TOP_LINE_HEIGHT (w);
dbc4e1c1 9839
06a2c219
GM
9840 cursor_glyph = get_phys_cursor_glyph (w);
9841 if (cursor_glyph == NULL)
9842 goto mark_cursor_off;
dbc4e1c1 9843
06a2c219
GM
9844 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
9845
9846 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9847 x,
9848 WINDOW_TO_FRAME_PIXEL_Y (w, max (top_line_height,
9849 cursor_row->y)),
9850 cursor_glyph->pixel_width,
9851 cursor_row->visible_height,
9852 False);
dbc4e1c1 9853 }
06a2c219
GM
9854
9855 /* Erase the cursor by redrawing the character underneath it. */
9856 if (mouse_face_here_p)
9857 hl = DRAW_MOUSE_FACE;
9858 else if (cursor_row->inverse_p)
9859 hl = DRAW_INVERSE_VIDEO;
9860 else
9861 hl = DRAW_NORMAL_TEXT;
9862 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 9863
06a2c219
GM
9864 mark_cursor_off:
9865 w->phys_cursor_on_p = 0;
9866 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
9867}
9868
9869
06a2c219
GM
9870/* Display or clear cursor of window W. If ON is zero, clear the
9871 cursor. If it is non-zero, display the cursor. If ON is nonzero,
9872 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 9873
06a2c219
GM
9874void
9875x_display_and_set_cursor (w, on, hpos, vpos, x, y)
9876 struct window *w;
9877 int on, hpos, vpos, x, y;
dbc4e1c1 9878{
06a2c219
GM
9879 struct frame *f = XFRAME (w->frame);
9880 int new_cursor_type;
9881 struct glyph_matrix *current_glyphs;
9882 struct glyph_row *glyph_row;
9883 struct glyph *glyph;
dbc4e1c1 9884
49d838ea 9885 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
9886 windows and frames; in the latter case, the frame or window may
9887 be in the midst of changing its size, and x and y may be off the
9888 window. */
9889 if (! FRAME_VISIBLE_P (f)
9890 || FRAME_GARBAGED_P (f)
9891 || vpos >= w->current_matrix->nrows
9892 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
9893 return;
9894
9895 /* If cursor is off and we want it off, return quickly. */
06a2c219 9896 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
9897 return;
9898
06a2c219
GM
9899 current_glyphs = w->current_matrix;
9900 glyph_row = MATRIX_ROW (current_glyphs, vpos);
9901 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
9902
9903 /* If cursor row is not enabled, we don't really know where to
9904 display the cursor. */
9905 if (!glyph_row->enabled_p)
9906 {
9907 w->phys_cursor_on_p = 0;
9908 return;
9909 }
9910
9911 xassert (interrupt_input_blocked);
9912
9913 /* Set new_cursor_type to the cursor we want to be displayed. In a
9914 mini-buffer window, we want the cursor only to appear if we are
9915 reading input from this window. For the selected window, we want
9916 the cursor type given by the frame parameter. If explicitly
9917 marked off, draw no cursor. In all other cases, we want a hollow
9918 box cursor. */
9919 if (w != XWINDOW (selected_window)
9920 || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
9921 {
9922 if (MINI_WINDOW_P (w))
9923 new_cursor_type = NO_CURSOR;
9924 else
9925 new_cursor_type = HOLLOW_BOX_CURSOR;
9926 }
9927 else if (w->cursor_off_p)
9928 new_cursor_type = NO_CURSOR;
9929 else
9930 new_cursor_type = FRAME_DESIRED_CURSOR (f);
9931
9932 /* If cursor is currently being shown and we don't want it to be or
9933 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 9934 erase it. */
06a2c219 9935 if (w->phys_cursor_on_p
dc6f92b8 9936 && (!on
06a2c219
GM
9937 || w->phys_cursor.x != x
9938 || w->phys_cursor.y != y
9939 || new_cursor_type != w->phys_cursor_type))
9940 x_erase_phys_cursor (w);
9941
9942 /* If the cursor is now invisible and we want it to be visible,
9943 display it. */
9944 if (on && !w->phys_cursor_on_p)
9945 {
9946 w->phys_cursor_ascent = glyph_row->ascent;
9947 w->phys_cursor_height = glyph_row->height;
9948
9949 /* Set phys_cursor_.* before x_draw_.* is called because some
9950 of them may need the information. */
9951 w->phys_cursor.x = x;
9952 w->phys_cursor.y = glyph_row->y;
9953 w->phys_cursor.hpos = hpos;
9954 w->phys_cursor.vpos = vpos;
9955 w->phys_cursor_type = new_cursor_type;
9956 w->phys_cursor_on_p = 1;
9957
9958 switch (new_cursor_type)
dc6f92b8 9959 {
06a2c219
GM
9960 case HOLLOW_BOX_CURSOR:
9961 x_draw_hollow_cursor (w, glyph_row);
9962 break;
9963
9964 case FILLED_BOX_CURSOR:
9965 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
9966 break;
9967
9968 case BAR_CURSOR:
9969 x_draw_bar_cursor (w, glyph_row);
9970 break;
9971
9972 case NO_CURSOR:
9973 break;
dc6f92b8 9974
06a2c219
GM
9975 default:
9976 abort ();
9977 }
dc6f92b8
JB
9978 }
9979
06a2c219 9980#ifndef XFlush
f676886a 9981 if (updating_frame != f)
334208b7 9982 XFlush (FRAME_X_DISPLAY (f));
06a2c219 9983#endif
dc6f92b8
JB
9984}
9985
06a2c219
GM
9986
9987/* Display the cursor on window W, or clear it. X and Y are window
9988 relative pixel coordinates. HPOS and VPOS are glyph matrix
9989 positions. If W is not the selected window, display a hollow
9990 cursor. ON non-zero means display the cursor at X, Y which
9991 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 9992
dfcf069d 9993void
06a2c219
GM
9994x_display_cursor (w, on, hpos, vpos, x, y)
9995 struct window *w;
9996 int on, hpos, vpos, x, y;
dc6f92b8 9997{
f94397b5 9998 BLOCK_INPUT;
06a2c219 9999 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
10000 UNBLOCK_INPUT;
10001}
10002
06a2c219
GM
10003
10004/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
10005 Don't change the cursor's position. */
10006
dfcf069d 10007void
06a2c219 10008x_update_cursor (f, on_p)
5d46f928 10009 struct frame *f;
5d46f928 10010{
06a2c219
GM
10011 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
10012}
10013
10014
10015/* Call x_update_window_cursor with parameter ON_P on all leaf windows
10016 in the window tree rooted at W. */
10017
10018static void
10019x_update_cursor_in_window_tree (w, on_p)
10020 struct window *w;
10021 int on_p;
10022{
10023 while (w)
10024 {
10025 if (!NILP (w->hchild))
10026 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
10027 else if (!NILP (w->vchild))
10028 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
10029 else
10030 x_update_window_cursor (w, on_p);
10031
10032 w = NILP (w->next) ? 0 : XWINDOW (w->next);
10033 }
10034}
5d46f928 10035
f94397b5 10036
06a2c219
GM
10037/* Switch the display of W's cursor on or off, according to the value
10038 of ON. */
10039
10040static void
10041x_update_window_cursor (w, on)
10042 struct window *w;
10043 int on;
10044{
10045 BLOCK_INPUT;
10046 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
10047 w->phys_cursor.x, w->phys_cursor.y);
f94397b5 10048 UNBLOCK_INPUT;
dc6f92b8 10049}
06a2c219
GM
10050
10051
10052
dc6f92b8
JB
10053\f
10054/* Icons. */
10055
f676886a 10056/* Refresh bitmap kitchen sink icon for frame F
06a2c219 10057 when we get an expose event for it. */
dc6f92b8 10058
dfcf069d 10059void
f676886a
JB
10060refreshicon (f)
10061 struct frame *f;
dc6f92b8 10062{
06a2c219 10063 /* Normally, the window manager handles this function. */
dc6f92b8
JB
10064}
10065
dbc4e1c1 10066/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
10067
10068int
990ba854 10069x_bitmap_icon (f, file)
f676886a 10070 struct frame *f;
990ba854 10071 Lisp_Object file;
dc6f92b8 10072{
06a2c219 10073 int bitmap_id;
dc6f92b8 10074
c118dd06 10075 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10076 return 1;
10077
990ba854 10078 /* Free up our existing icon bitmap if any. */
7556890b
RS
10079 if (f->output_data.x->icon_bitmap > 0)
10080 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10081 f->output_data.x->icon_bitmap = 0;
990ba854
RS
10082
10083 if (STRINGP (file))
7f2ae036
RS
10084 bitmap_id = x_create_bitmap_from_file (f, file);
10085 else
10086 {
990ba854 10087 /* Create the GNU bitmap if necessary. */
5bf01b68 10088 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
10089 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
10090 = x_create_bitmap_from_data (f, gnu_bits,
10091 gnu_width, gnu_height);
990ba854
RS
10092
10093 /* The first time we create the GNU bitmap,
06a2c219 10094 this increments the ref-count one extra time.
990ba854
RS
10095 As a result, the GNU bitmap is never freed.
10096 That way, we don't have to worry about allocating it again. */
334208b7 10097 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 10098
334208b7 10099 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
10100 }
10101
10102 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 10103 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
10104
10105 return 0;
10106}
10107
10108
1be2d067
KH
10109/* Make the x-window of frame F use a rectangle with text.
10110 Use ICON_NAME as the text. */
dc6f92b8
JB
10111
10112int
f676886a
JB
10113x_text_icon (f, icon_name)
10114 struct frame *f;
dc6f92b8
JB
10115 char *icon_name;
10116{
c118dd06 10117 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10118 return 1;
10119
1be2d067
KH
10120#ifdef HAVE_X11R4
10121 {
10122 XTextProperty text;
10123 text.value = (unsigned char *) icon_name;
10124 text.encoding = XA_STRING;
10125 text.format = 8;
10126 text.nitems = strlen (icon_name);
10127#ifdef USE_X_TOOLKIT
7556890b 10128 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
10129 &text);
10130#else /* not USE_X_TOOLKIT */
10131 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
10132#endif /* not USE_X_TOOLKIT */
10133 }
10134#else /* not HAVE_X11R4 */
10135 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
10136#endif /* not HAVE_X11R4 */
58769bee 10137
7556890b
RS
10138 if (f->output_data.x->icon_bitmap > 0)
10139 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10140 f->output_data.x->icon_bitmap = 0;
b1c884c3 10141 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
10142
10143 return 0;
10144}
10145\f
e99db5a1
RS
10146#define X_ERROR_MESSAGE_SIZE 200
10147
10148/* If non-nil, this should be a string.
10149 It means catch X errors and store the error message in this string. */
10150
10151static Lisp_Object x_error_message_string;
10152
10153/* An X error handler which stores the error message in
10154 x_error_message_string. This is called from x_error_handler if
10155 x_catch_errors is in effect. */
10156
06a2c219 10157static void
e99db5a1
RS
10158x_error_catcher (display, error)
10159 Display *display;
10160 XErrorEvent *error;
10161{
10162 XGetErrorText (display, error->error_code,
10163 XSTRING (x_error_message_string)->data,
10164 X_ERROR_MESSAGE_SIZE);
10165}
10166
10167/* Begin trapping X errors for display DPY. Actually we trap X errors
10168 for all displays, but DPY should be the display you are actually
10169 operating on.
10170
10171 After calling this function, X protocol errors no longer cause
10172 Emacs to exit; instead, they are recorded in the string
10173 stored in x_error_message_string.
10174
10175 Calling x_check_errors signals an Emacs error if an X error has
10176 occurred since the last call to x_catch_errors or x_check_errors.
10177
10178 Calling x_uncatch_errors resumes the normal error handling. */
10179
10180void x_check_errors ();
10181static Lisp_Object x_catch_errors_unwind ();
10182
10183int
10184x_catch_errors (dpy)
10185 Display *dpy;
10186{
10187 int count = specpdl_ptr - specpdl;
10188
10189 /* Make sure any errors from previous requests have been dealt with. */
10190 XSync (dpy, False);
10191
10192 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
10193
10194 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
10195 XSTRING (x_error_message_string)->data[0] = 0;
10196
10197 return count;
10198}
10199
10200/* Unbind the binding that we made to check for X errors. */
10201
10202static Lisp_Object
10203x_catch_errors_unwind (old_val)
10204 Lisp_Object old_val;
10205{
10206 x_error_message_string = old_val;
10207 return Qnil;
10208}
10209
10210/* If any X protocol errors have arrived since the last call to
10211 x_catch_errors or x_check_errors, signal an Emacs error using
10212 sprintf (a buffer, FORMAT, the x error message text) as the text. */
10213
10214void
10215x_check_errors (dpy, format)
10216 Display *dpy;
10217 char *format;
10218{
10219 /* Make sure to catch any errors incurred so far. */
10220 XSync (dpy, False);
10221
10222 if (XSTRING (x_error_message_string)->data[0])
10223 error (format, XSTRING (x_error_message_string)->data);
10224}
10225
9829ddba
RS
10226/* Nonzero if we had any X protocol errors
10227 since we did x_catch_errors on DPY. */
e99db5a1
RS
10228
10229int
10230x_had_errors_p (dpy)
10231 Display *dpy;
10232{
10233 /* Make sure to catch any errors incurred so far. */
10234 XSync (dpy, False);
10235
10236 return XSTRING (x_error_message_string)->data[0] != 0;
10237}
10238
9829ddba
RS
10239/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
10240
06a2c219 10241void
9829ddba
RS
10242x_clear_errors (dpy)
10243 Display *dpy;
10244{
10245 XSTRING (x_error_message_string)->data[0] = 0;
10246}
10247
e99db5a1
RS
10248/* Stop catching X protocol errors and let them make Emacs die.
10249 DPY should be the display that was passed to x_catch_errors.
10250 COUNT should be the value that was returned by
10251 the corresponding call to x_catch_errors. */
10252
10253void
10254x_uncatch_errors (dpy, count)
10255 Display *dpy;
10256 int count;
10257{
10258 unbind_to (count, Qnil);
10259}
10260
10261#if 0
10262static unsigned int x_wire_count;
10263x_trace_wire ()
10264{
10265 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
10266}
10267#endif /* ! 0 */
10268
10269\f
10270/* Handle SIGPIPE, which can happen when the connection to a server
10271 simply goes away. SIGPIPE is handled by x_connection_signal.
10272 Don't need to do anything, because the write which caused the
10273 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 10274 which will do the appropriate cleanup for us. */
e99db5a1
RS
10275
10276static SIGTYPE
10277x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 10278 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
10279{
10280#ifdef USG
10281 /* USG systems forget handlers when they are used;
10282 must reestablish each time */
10283 signal (signalnum, x_connection_signal);
10284#endif /* USG */
10285}
10286\f
4746118a
JB
10287/* Handling X errors. */
10288
7a13e894 10289/* Handle the loss of connection to display DISPLAY. */
16bd92ea 10290
4746118a 10291static SIGTYPE
7a13e894
RS
10292x_connection_closed (display, error_message)
10293 Display *display;
10294 char *error_message;
4746118a 10295{
7a13e894
RS
10296 struct x_display_info *dpyinfo = x_display_info_for_display (display);
10297 Lisp_Object frame, tail;
10298
6186a4a0
RS
10299 /* Indicate that this display is dead. */
10300
f613a4c8 10301#ifdef USE_X_TOOLKIT
adabc3a9 10302 XtCloseDisplay (display);
f613a4c8 10303#endif
adabc3a9 10304
6186a4a0
RS
10305 dpyinfo->display = 0;
10306
06a2c219 10307 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
10308 that are on the dead display. */
10309 FOR_EACH_FRAME (tail, frame)
10310 {
10311 Lisp_Object minibuf_frame;
10312 minibuf_frame
10313 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
10314 if (FRAME_X_P (XFRAME (frame))
10315 && FRAME_X_P (XFRAME (minibuf_frame))
10316 && ! EQ (frame, minibuf_frame)
10317 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
10318 Fdelete_frame (frame, Qt);
10319 }
10320
10321 /* Now delete all remaining frames on the dead display.
06a2c219 10322 We are now sure none of these is used as the mini-buffer
7a13e894
RS
10323 for another frame that we need to delete. */
10324 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
10325 if (FRAME_X_P (XFRAME (frame))
10326 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
10327 {
10328 /* Set this to t so that Fdelete_frame won't get confused
10329 trying to find a replacement. */
10330 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
10331 Fdelete_frame (frame, Qt);
10332 }
7a13e894 10333
482a1bd2
KH
10334 if (dpyinfo)
10335 x_delete_display (dpyinfo);
7a13e894
RS
10336
10337 if (x_display_list == 0)
10338 {
f8d07b62 10339 fprintf (stderr, "%s\n", error_message);
7a13e894
RS
10340 shut_down_emacs (0, 0, Qnil);
10341 exit (70);
10342 }
12ba150f 10343
7a13e894
RS
10344 /* Ordinary stack unwind doesn't deal with these. */
10345#ifdef SIGIO
10346 sigunblock (sigmask (SIGIO));
10347#endif
10348 sigunblock (sigmask (SIGALRM));
10349 TOTALLY_UNBLOCK_INPUT;
10350
aa4d9a9e 10351 clear_waiting_for_input ();
7a13e894 10352 error ("%s", error_message);
4746118a
JB
10353}
10354
7a13e894
RS
10355/* This is the usual handler for X protocol errors.
10356 It kills all frames on the display that we got the error for.
10357 If that was the only one, it prints an error message and kills Emacs. */
10358
06a2c219 10359static void
c118dd06
JB
10360x_error_quitter (display, error)
10361 Display *display;
10362 XErrorEvent *error;
10363{
7a13e894 10364 char buf[256], buf1[356];
dc6f92b8 10365
58769bee 10366 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 10367 original error handler. */
dc6f92b8 10368
c118dd06 10369 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 10370 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 10371 buf, error->request_code);
7a13e894 10372 x_connection_closed (display, buf1);
dc6f92b8
JB
10373}
10374
e99db5a1
RS
10375/* This is the first-level handler for X protocol errors.
10376 It calls x_error_quitter or x_error_catcher. */
7a13e894 10377
8922af5f 10378static int
e99db5a1 10379x_error_handler (display, error)
8922af5f 10380 Display *display;
e99db5a1 10381 XErrorEvent *error;
8922af5f 10382{
e99db5a1
RS
10383 if (! NILP (x_error_message_string))
10384 x_error_catcher (display, error);
10385 else
10386 x_error_quitter (display, error);
06a2c219 10387 return 0;
f9e24cb9 10388}
c118dd06 10389
e99db5a1
RS
10390/* This is the handler for X IO errors, always.
10391 It kills all frames on the display that we lost touch with.
10392 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 10393
c118dd06 10394static int
e99db5a1 10395x_io_error_quitter (display)
c118dd06 10396 Display *display;
c118dd06 10397{
e99db5a1 10398 char buf[256];
dc6f92b8 10399
e99db5a1
RS
10400 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
10401 x_connection_closed (display, buf);
06a2c219 10402 return 0;
dc6f92b8 10403}
dc6f92b8 10404\f
f451eb13
JB
10405/* Changing the font of the frame. */
10406
76bcdf39
RS
10407/* Give frame F the font named FONTNAME as its default font, and
10408 return the full name of that font. FONTNAME may be a wildcard
10409 pattern; in that case, we choose some font that fits the pattern.
10410 The return value shows which font we chose. */
10411
b5cf7a0e 10412Lisp_Object
f676886a
JB
10413x_new_font (f, fontname)
10414 struct frame *f;
dc6f92b8
JB
10415 register char *fontname;
10416{
dc43ef94
KH
10417 struct font_info *fontp
10418 = fs_load_font (f, FRAME_X_FONT_TABLE (f), CHARSET_ASCII, fontname, -1);
dc6f92b8 10419
dc43ef94
KH
10420 if (!fontp)
10421 return Qnil;
2224a5fc 10422
dc43ef94
KH
10423 f->output_data.x->font = (XFontStruct *) (fontp->font);
10424 f->output_data.x->font_baseline
10425 = (f->output_data.x->font->ascent + fontp->baseline_offset);
10426 f->output_data.x->fontset = -1;
10427
b2cad826
KH
10428 /* Compute the scroll bar width in character columns. */
10429 if (f->scroll_bar_pixel_width > 0)
10430 {
7556890b 10431 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
10432 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
10433 }
10434 else
4e61bddf
RS
10435 {
10436 int wid = FONT_WIDTH (f->output_data.x->font);
10437 f->scroll_bar_cols = (14 + wid - 1) / wid;
10438 }
b2cad826 10439
f676886a 10440 /* Now make the frame display the given font. */
c118dd06 10441 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 10442 {
7556890b
RS
10443 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
10444 f->output_data.x->font->fid);
10445 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
10446 f->output_data.x->font->fid);
10447 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
10448 f->output_data.x->font->fid);
f676886a 10449
a27f9f86 10450 frame_update_line_height (f);
0134a210 10451 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 10452 }
a27f9f86
RS
10453 else
10454 /* If we are setting a new frame's font for the first time,
10455 there are no faces yet, so this font's height is the line height. */
7556890b 10456 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 10457
dc43ef94
KH
10458 return build_string (fontp->full_name);
10459}
10460
10461/* Give frame F the fontset named FONTSETNAME as its default font, and
10462 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
10463 pattern; in that case, we choose some fontset that fits the pattern.
10464 The return value shows which fontset we chose. */
b5cf7a0e 10465
dc43ef94
KH
10466Lisp_Object
10467x_new_fontset (f, fontsetname)
10468 struct frame *f;
10469 char *fontsetname;
10470{
10471 int fontset = fs_query_fontset (f, fontsetname);
10472 struct fontset_info *fontsetp;
10473 Lisp_Object result;
b5cf7a0e 10474
dc43ef94
KH
10475 if (fontset < 0)
10476 return Qnil;
b5cf7a0e 10477
2da424f1
KH
10478 if (f->output_data.x->fontset == fontset)
10479 /* This fontset is already set in frame F. There's nothing more
10480 to do. */
10481 return build_string (fontsetname);
10482
dc43ef94
KH
10483 fontsetp = FRAME_FONTSET_DATA (f)->fontset_table[fontset];
10484
10485 if (!fontsetp->fontname[CHARSET_ASCII])
10486 /* This fontset doesn't contain ASCII font. */
10487 return Qnil;
10488
10489 result = x_new_font (f, fontsetp->fontname[CHARSET_ASCII]);
10490
10491 if (!STRINGP (result))
10492 /* Can't load ASCII font. */
10493 return Qnil;
10494
10495 /* Since x_new_font doesn't update any fontset information, do it now. */
10496 f->output_data.x->fontset = fontset;
2da424f1 10497 FS_LOAD_FONT (f, FRAME_X_FONT_TABLE (f),
715a159b 10498 CHARSET_ASCII, fontsetp->fontname[CHARSET_ASCII], fontset);
dc43ef94
KH
10499
10500 return build_string (fontsetname);
dc6f92b8 10501}
dc6f92b8 10502\f
2e365682
RS
10503/* Calculate the absolute position in frame F
10504 from its current recorded position values and gravity. */
10505
dfcf069d 10506void
43bca5d5 10507x_calc_absolute_position (f)
f676886a 10508 struct frame *f;
dc6f92b8 10509{
06a2c219 10510 Window child;
6dba1858 10511 int win_x = 0, win_y = 0;
7556890b 10512 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
10513 int this_window;
10514
9829ddba
RS
10515 /* We have nothing to do if the current position
10516 is already for the top-left corner. */
10517 if (! ((flags & XNegative) || (flags & YNegative)))
10518 return;
10519
c81412a0 10520#ifdef USE_X_TOOLKIT
7556890b 10521 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
10522#else
10523 this_window = FRAME_X_WINDOW (f);
10524#endif
6dba1858
RS
10525
10526 /* Find the position of the outside upper-left corner of
9829ddba
RS
10527 the inner window, with respect to the outer window.
10528 But do this only if we will need the results. */
7556890b 10529 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 10530 {
9829ddba
RS
10531 int count;
10532
6dba1858 10533 BLOCK_INPUT;
9829ddba
RS
10534 count = x_catch_errors (FRAME_X_DISPLAY (f));
10535 while (1)
10536 {
10537 x_clear_errors (FRAME_X_DISPLAY (f));
10538 XTranslateCoordinates (FRAME_X_DISPLAY (f),
10539
10540 /* From-window, to-window. */
10541 this_window,
10542 f->output_data.x->parent_desc,
10543
10544 /* From-position, to-position. */
10545 0, 0, &win_x, &win_y,
10546
10547 /* Child of win. */
10548 &child);
10549 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
10550 {
10551 Window newroot, newparent = 0xdeadbeef;
10552 Window *newchildren;
10553 int nchildren;
10554
10555 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
10556 &newparent, &newchildren, &nchildren))
10557 break;
58769bee 10558
7c3c78a3 10559 XFree ((char *) newchildren);
6dba1858 10560
9829ddba
RS
10561 f->output_data.x->parent_desc = newparent;
10562 }
10563 else
10564 break;
10565 }
6dba1858 10566
9829ddba 10567 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
10568 UNBLOCK_INPUT;
10569 }
10570
10571 /* Treat negative positions as relative to the leftmost bottommost
10572 position that fits on the screen. */
20f55f9a 10573 if (flags & XNegative)
7556890b 10574 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
10575 - 2 * f->output_data.x->border_width - win_x
10576 - PIXEL_WIDTH (f)
10577 + f->output_data.x->left_pos);
dc6f92b8 10578
20f55f9a 10579 if (flags & YNegative)
06a2c219
GM
10580 {
10581 int menubar_height = 0;
10582
10583#ifdef USE_X_TOOLKIT
10584 if (f->output_data.x->menubar_widget)
10585 menubar_height
10586 = (f->output_data.x->menubar_widget->core.height
10587 + f->output_data.x->menubar_widget->core.border_width);
10588#endif
10589
10590 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
10591 - 2 * f->output_data.x->border_width
10592 - win_y
10593 - PIXEL_HEIGHT (f)
10594 - menubar_height
10595 + f->output_data.x->top_pos);
10596 }
2e365682 10597
3a35ab44
RS
10598 /* The left_pos and top_pos
10599 are now relative to the top and left screen edges,
10600 so the flags should correspond. */
7556890b 10601 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
10602}
10603
3a35ab44
RS
10604/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
10605 to really change the position, and 0 when calling from
10606 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
10607 position values). It is -1 when calling from x_set_frame_parameters,
10608 which means, do adjust for borders but don't change the gravity. */
3a35ab44 10609
dfcf069d 10610void
dc05a16b 10611x_set_offset (f, xoff, yoff, change_gravity)
f676886a 10612 struct frame *f;
dc6f92b8 10613 register int xoff, yoff;
dc05a16b 10614 int change_gravity;
dc6f92b8 10615{
4a4cbdd5
KH
10616 int modified_top, modified_left;
10617
aa3ff7c9 10618 if (change_gravity > 0)
3a35ab44 10619 {
7556890b
RS
10620 f->output_data.x->top_pos = yoff;
10621 f->output_data.x->left_pos = xoff;
10622 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 10623 if (xoff < 0)
7556890b 10624 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 10625 if (yoff < 0)
7556890b
RS
10626 f->output_data.x->size_hint_flags |= YNegative;
10627 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 10628 }
43bca5d5 10629 x_calc_absolute_position (f);
dc6f92b8
JB
10630
10631 BLOCK_INPUT;
c32cdd9a 10632 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 10633
7556890b
RS
10634 modified_left = f->output_data.x->left_pos;
10635 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
10636#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
10637 this seems to be unnecessary and incorrect. rms, 4/17/97. */
10638 /* It is a mystery why we need to add the border_width here
10639 when the frame is already visible, but experiment says we do. */
aa3ff7c9 10640 if (change_gravity != 0)
4a4cbdd5 10641 {
7556890b
RS
10642 modified_left += f->output_data.x->border_width;
10643 modified_top += f->output_data.x->border_width;
4a4cbdd5 10644 }
e73ec6fa 10645#endif
4a4cbdd5 10646
3afe33e7 10647#ifdef USE_X_TOOLKIT
7556890b 10648 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 10649 modified_left, modified_top);
3afe33e7 10650#else /* not USE_X_TOOLKIT */
334208b7 10651 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 10652 modified_left, modified_top);
3afe33e7 10653#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
10654 UNBLOCK_INPUT;
10655}
10656
bc20ebbf
FP
10657/* Call this to change the size of frame F's x-window.
10658 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
10659 for this size change and subsequent size changes.
10660 Otherwise we leave the window gravity unchanged. */
dc6f92b8 10661
dfcf069d 10662void
bc20ebbf 10663x_set_window_size (f, change_gravity, cols, rows)
f676886a 10664 struct frame *f;
bc20ebbf 10665 int change_gravity;
b1c884c3 10666 int cols, rows;
dc6f92b8 10667{
06a2c219 10668#ifndef USE_X_TOOLKIT
dc6f92b8 10669 int pixelwidth, pixelheight;
06a2c219 10670#endif
dc6f92b8 10671
80fd1fe2 10672 BLOCK_INPUT;
aee9a898
RS
10673
10674#ifdef USE_X_TOOLKIT
3a20653d
RS
10675 {
10676 /* The x and y position of the widget is clobbered by the
10677 call to XtSetValues within EmacsFrameSetCharSize.
10678 This is a real kludge, but I don't understand Xt so I can't
10679 figure out a correct fix. Can anyone else tell me? -- rms. */
7556890b
RS
10680 int xpos = f->output_data.x->widget->core.x;
10681 int ypos = f->output_data.x->widget->core.y;
10682 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
10683 f->output_data.x->widget->core.x = xpos;
10684 f->output_data.x->widget->core.y = ypos;
3a20653d 10685 }
80fd1fe2
FP
10686
10687#else /* not USE_X_TOOLKIT */
10688
b1c884c3 10689 check_frame_size (f, &rows, &cols);
7556890b 10690 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
10691 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
10692 ? 0
10693 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 10694 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 10695 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219
GM
10696 f->output_data.x->flags_areas_extra
10697 = 2 * FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
10698 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
10699 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 10700
7556890b 10701 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 10702 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 10703
334208b7
RS
10704 XSync (FRAME_X_DISPLAY (f), False);
10705 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10706 pixelwidth, pixelheight);
b1c884c3
JB
10707
10708 /* Now, strictly speaking, we can't be sure that this is accurate,
10709 but the window manager will get around to dealing with the size
10710 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
10711 ConfigureNotify event gets here.
10712
10713 We could just not bother storing any of this information here,
10714 and let the ConfigureNotify event set everything up, but that
10715 might be kind of confusing to the lisp code, since size changes
10716 wouldn't be reported in the frame parameters until some random
10717 point in the future when the ConfigureNotify event arrives. */
8922af5f 10718 change_frame_size (f, rows, cols, 0, 0);
b1c884c3
JB
10719 PIXEL_WIDTH (f) = pixelwidth;
10720 PIXEL_HEIGHT (f) = pixelheight;
10721
aee9a898
RS
10722 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
10723 receive in the ConfigureNotify event; if we get what we asked
10724 for, then the event won't cause the screen to become garbaged, so
10725 we have to make sure to do it here. */
10726 SET_FRAME_GARBAGED (f);
10727
10728 XFlush (FRAME_X_DISPLAY (f));
10729
10730#endif /* not USE_X_TOOLKIT */
10731
4d73d038 10732 /* If cursor was outside the new size, mark it as off. */
06a2c219 10733 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 10734
aee9a898
RS
10735 /* Clear out any recollection of where the mouse highlighting was,
10736 since it might be in a place that's outside the new frame size.
10737 Actually checking whether it is outside is a pain in the neck,
10738 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 10739 cancel_mouse_face (f);
dbc4e1c1 10740
dc6f92b8
JB
10741 UNBLOCK_INPUT;
10742}
dc6f92b8 10743\f
d047c4eb 10744/* Mouse warping. */
dc6f92b8 10745
9b378208 10746void
f676886a
JB
10747x_set_mouse_position (f, x, y)
10748 struct frame *f;
dc6f92b8
JB
10749 int x, y;
10750{
10751 int pix_x, pix_y;
10752
7556890b
RS
10753 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
10754 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
10755
10756 if (pix_x < 0) pix_x = 0;
10757 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
10758
10759 if (pix_y < 0) pix_y = 0;
10760 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
10761
10762 BLOCK_INPUT;
dc6f92b8 10763
334208b7
RS
10764 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
10765 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
10766 UNBLOCK_INPUT;
10767}
10768
9b378208
RS
10769/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
10770
10771void
10772x_set_mouse_pixel_position (f, pix_x, pix_y)
10773 struct frame *f;
10774 int pix_x, pix_y;
10775{
10776 BLOCK_INPUT;
10777
334208b7
RS
10778 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
10779 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
10780 UNBLOCK_INPUT;
10781}
d047c4eb
KH
10782\f
10783/* focus shifting, raising and lowering. */
9b378208 10784
dfcf069d 10785void
f676886a
JB
10786x_focus_on_frame (f)
10787 struct frame *f;
dc6f92b8 10788{
1fb20991 10789#if 0 /* This proves to be unpleasant. */
f676886a 10790 x_raise_frame (f);
1fb20991 10791#endif
6d4238f3
JB
10792#if 0
10793 /* I don't think that the ICCCM allows programs to do things like this
10794 without the interaction of the window manager. Whatever you end up
f676886a 10795 doing with this code, do it to x_unfocus_frame too. */
334208b7 10796 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 10797 RevertToPointerRoot, CurrentTime);
c118dd06 10798#endif /* ! 0 */
dc6f92b8
JB
10799}
10800
dfcf069d 10801void
f676886a
JB
10802x_unfocus_frame (f)
10803 struct frame *f;
dc6f92b8 10804{
6d4238f3 10805#if 0
f676886a 10806 /* Look at the remarks in x_focus_on_frame. */
0f941935 10807 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 10808 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 10809 RevertToPointerRoot, CurrentTime);
c118dd06 10810#endif /* ! 0 */
dc6f92b8
JB
10811}
10812
f676886a 10813/* Raise frame F. */
dc6f92b8 10814
dfcf069d 10815void
f676886a
JB
10816x_raise_frame (f)
10817 struct frame *f;
dc6f92b8 10818{
3a88c238 10819 if (f->async_visible)
dc6f92b8
JB
10820 {
10821 BLOCK_INPUT;
3afe33e7 10822#ifdef USE_X_TOOLKIT
7556890b 10823 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 10824#else /* not USE_X_TOOLKIT */
334208b7 10825 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 10826#endif /* not USE_X_TOOLKIT */
334208b7 10827 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
10828 UNBLOCK_INPUT;
10829 }
10830}
10831
f676886a 10832/* Lower frame F. */
dc6f92b8 10833
dfcf069d 10834void
f676886a
JB
10835x_lower_frame (f)
10836 struct frame *f;
dc6f92b8 10837{
3a88c238 10838 if (f->async_visible)
dc6f92b8
JB
10839 {
10840 BLOCK_INPUT;
3afe33e7 10841#ifdef USE_X_TOOLKIT
7556890b 10842 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 10843#else /* not USE_X_TOOLKIT */
334208b7 10844 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 10845#endif /* not USE_X_TOOLKIT */
334208b7 10846 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
10847 UNBLOCK_INPUT;
10848 }
10849}
10850
dbc4e1c1 10851static void
6b0442dc 10852XTframe_raise_lower (f, raise_flag)
dbc4e1c1 10853 FRAME_PTR f;
6b0442dc 10854 int raise_flag;
dbc4e1c1 10855{
6b0442dc 10856 if (raise_flag)
dbc4e1c1
JB
10857 x_raise_frame (f);
10858 else
10859 x_lower_frame (f);
10860}
d047c4eb
KH
10861\f
10862/* Change of visibility. */
dc6f92b8 10863
9382638d
KH
10864/* This tries to wait until the frame is really visible.
10865 However, if the window manager asks the user where to position
10866 the frame, this will return before the user finishes doing that.
10867 The frame will not actually be visible at that time,
10868 but it will become visible later when the window manager
10869 finishes with it. */
10870
dfcf069d 10871void
f676886a
JB
10872x_make_frame_visible (f)
10873 struct frame *f;
dc6f92b8 10874{
990ba854 10875 Lisp_Object type;
1aa6072f 10876 int original_top, original_left;
dc6f92b8 10877
dc6f92b8 10878 BLOCK_INPUT;
dc6f92b8 10879
990ba854
RS
10880 type = x_icon_type (f);
10881 if (!NILP (type))
10882 x_bitmap_icon (f, type);
bdcd49ba 10883
f676886a 10884 if (! FRAME_VISIBLE_P (f))
90e65f07 10885 {
1aa6072f
RS
10886 /* We test FRAME_GARBAGED_P here to make sure we don't
10887 call x_set_offset a second time
10888 if we get to x_make_frame_visible a second time
10889 before the window gets really visible. */
10890 if (! FRAME_ICONIFIED_P (f)
10891 && ! f->output_data.x->asked_for_visible)
10892 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
10893
10894 f->output_data.x->asked_for_visible = 1;
10895
90e65f07 10896 if (! EQ (Vx_no_window_manager, Qt))
f676886a 10897 x_wm_set_window_state (f, NormalState);
3afe33e7 10898#ifdef USE_X_TOOLKIT
d7a38a2e 10899 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 10900 XtMapWidget (f->output_data.x->widget);
3afe33e7 10901#else /* not USE_X_TOOLKIT */
7f9c7f94 10902 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 10903#endif /* not USE_X_TOOLKIT */
0134a210
RS
10904#if 0 /* This seems to bring back scroll bars in the wrong places
10905 if the window configuration has changed. They seem
10906 to come back ok without this. */
ab648270 10907 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 10908 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 10909#endif
90e65f07 10910 }
dc6f92b8 10911
334208b7 10912 XFlush (FRAME_X_DISPLAY (f));
90e65f07 10913
0dacf791
RS
10914 /* Synchronize to ensure Emacs knows the frame is visible
10915 before we do anything else. We do this loop with input not blocked
10916 so that incoming events are handled. */
10917 {
10918 Lisp_Object frame;
c0a04927 10919 int count = input_signal_count;
28c01ffe
RS
10920 /* This must be before UNBLOCK_INPUT
10921 since events that arrive in response to the actions above
10922 will set it when they are handled. */
10923 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
10924
10925 original_left = f->output_data.x->left_pos;
10926 original_top = f->output_data.x->top_pos;
c0a04927
RS
10927
10928 /* This must come after we set COUNT. */
10929 UNBLOCK_INPUT;
10930
2745e6c4 10931 /* We unblock here so that arriving X events are processed. */
1aa6072f 10932
dcb07ae9
RS
10933 /* Now move the window back to where it was "supposed to be".
10934 But don't do it if the gravity is negative.
10935 When the gravity is negative, this uses a position
28c01ffe
RS
10936 that is 3 pixels too low. Perhaps that's really the border width.
10937
10938 Don't do this if the window has never been visible before,
10939 because the window manager may choose the position
10940 and we don't want to override it. */
1aa6072f 10941
4d3f5d9a 10942 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 10943 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 10944 && previously_visible)
1aa6072f 10945 {
2745e6c4
RS
10946 Drawable rootw;
10947 int x, y;
10948 unsigned int width, height, border, depth;
06a2c219 10949
1aa6072f 10950 BLOCK_INPUT;
9829ddba 10951
06a2c219
GM
10952 /* On some window managers (such as FVWM) moving an existing
10953 window, even to the same place, causes the window manager
10954 to introduce an offset. This can cause the window to move
10955 to an unexpected location. Check the geometry (a little
10956 slow here) and then verify that the window is in the right
10957 place. If the window is not in the right place, move it
10958 there, and take the potential window manager hit. */
2745e6c4
RS
10959 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10960 &rootw, &x, &y, &width, &height, &border, &depth);
10961
10962 if (original_left != x || original_top != y)
10963 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10964 original_left, original_top);
10965
1aa6072f
RS
10966 UNBLOCK_INPUT;
10967 }
9829ddba 10968
e0c1aef2 10969 XSETFRAME (frame, f);
c0a04927
RS
10970
10971 while (1)
2a6cf806 10972 {
334208b7 10973 x_sync (f);
c0a04927
RS
10974 /* Once we have handled input events,
10975 we should have received the MapNotify if one is coming.
10976 So if we have not got it yet, stop looping.
10977 Some window managers make their own decisions
10978 about visibility. */
10979 if (input_signal_count != count)
10980 break;
c12a7cbd 10981 /* Machines that do polling rather than SIGIO have been observed
23cf7c60
KH
10982 to go into a busy-wait here. So we'll fake an alarm signal
10983 to let the handler know that there's something to be read.
10984 We used to raise a real alarm, but it seems that the handler
10985 isn't always enabled here. This is probably a bug. */
8b2f8d4e 10986 if (input_polling_used ())
3b2fa4e6
RS
10987 {
10988 /* It could be confusing if a real alarm arrives while processing
10989 the fake one. Turn it off and let the handler reset it. */
10990 alarm (0);
5e8e68ce 10991 input_poll_signal (0);
3b2fa4e6 10992 }
c0a04927
RS
10993 /* Once we have handled input events,
10994 we should have received the MapNotify if one is coming.
10995 So if we have not got it yet, stop looping.
10996 Some window managers make their own decisions
10997 about visibility. */
10998 if (input_signal_count != count)
10999 break;
2a6cf806 11000 }
0dacf791
RS
11001 FRAME_SAMPLE_VISIBILITY (f);
11002 }
dc6f92b8
JB
11003}
11004
06a2c219 11005/* Change from mapped state to withdrawn state. */
dc6f92b8 11006
d047c4eb
KH
11007/* Make the frame visible (mapped and not iconified). */
11008
dfcf069d 11009void
f676886a
JB
11010x_make_frame_invisible (f)
11011 struct frame *f;
dc6f92b8 11012{
546e6d5b
RS
11013 Window window;
11014
11015#ifdef USE_X_TOOLKIT
11016 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 11017 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
11018#else /* not USE_X_TOOLKIT */
11019 window = FRAME_X_WINDOW (f);
11020#endif /* not USE_X_TOOLKIT */
dc6f92b8 11021
9319ae23 11022 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11023 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11024 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11025
5627c40e 11026#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 11027 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 11028 return;
5627c40e 11029#endif
dc6f92b8
JB
11030
11031 BLOCK_INPUT;
c118dd06 11032
af31d76f
RS
11033 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
11034 that the current position of the window is user-specified, rather than
11035 program-specified, so that when the window is mapped again, it will be
11036 placed at the same location, without forcing the user to position it
11037 by hand again (they have already done that once for this window.) */
c32cdd9a 11038 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 11039
c118dd06
JB
11040#ifdef HAVE_X11R4
11041
334208b7
RS
11042 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
11043 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
11044 {
11045 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11046 error ("Can't notify window manager of window withdrawal");
c118dd06 11047 }
c118dd06 11048#else /* ! defined (HAVE_X11R4) */
16bd92ea 11049
c118dd06 11050 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
11051 if (! EQ (Vx_no_window_manager, Qt))
11052 {
16bd92ea 11053 XEvent unmap;
dc6f92b8 11054
16bd92ea 11055 unmap.xunmap.type = UnmapNotify;
546e6d5b 11056 unmap.xunmap.window = window;
334208b7 11057 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 11058 unmap.xunmap.from_configure = False;
334208b7
RS
11059 if (! XSendEvent (FRAME_X_DISPLAY (f),
11060 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 11061 False,
06a2c219 11062 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
11063 &unmap))
11064 {
11065 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11066 error ("Can't notify window manager of withdrawal");
16bd92ea 11067 }
dc6f92b8
JB
11068 }
11069
16bd92ea 11070 /* Unmap the window ourselves. Cheeky! */
334208b7 11071 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 11072#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 11073
5627c40e
RS
11074 /* We can't distinguish this from iconification
11075 just by the event that we get from the server.
11076 So we can't win using the usual strategy of letting
11077 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
11078 and synchronize with the server to make sure we agree. */
11079 f->visible = 0;
11080 FRAME_ICONIFIED_P (f) = 0;
11081 f->async_visible = 0;
11082 f->async_iconified = 0;
11083
334208b7 11084 x_sync (f);
5627c40e 11085
dc6f92b8
JB
11086 UNBLOCK_INPUT;
11087}
11088
06a2c219 11089/* Change window state from mapped to iconified. */
dc6f92b8 11090
dfcf069d 11091void
f676886a
JB
11092x_iconify_frame (f)
11093 struct frame *f;
dc6f92b8 11094{
3afe33e7 11095 int result;
990ba854 11096 Lisp_Object type;
dc6f92b8 11097
9319ae23 11098 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11099 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11100 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11101
3a88c238 11102 if (f->async_iconified)
dc6f92b8
JB
11103 return;
11104
3afe33e7 11105 BLOCK_INPUT;
546e6d5b 11106
9af3143a
RS
11107 FRAME_SAMPLE_VISIBILITY (f);
11108
990ba854
RS
11109 type = x_icon_type (f);
11110 if (!NILP (type))
11111 x_bitmap_icon (f, type);
bdcd49ba
RS
11112
11113#ifdef USE_X_TOOLKIT
11114
546e6d5b
RS
11115 if (! FRAME_VISIBLE_P (f))
11116 {
11117 if (! EQ (Vx_no_window_manager, Qt))
11118 x_wm_set_window_state (f, IconicState);
11119 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11120 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
11121 /* The server won't give us any event to indicate
11122 that an invisible frame was changed to an icon,
11123 so we have to record it here. */
11124 f->iconified = 1;
1e6bc770 11125 f->visible = 1;
9cf30a30 11126 f->async_iconified = 1;
1e6bc770 11127 f->async_visible = 0;
546e6d5b
RS
11128 UNBLOCK_INPUT;
11129 return;
11130 }
11131
334208b7 11132 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 11133 XtWindow (f->output_data.x->widget),
334208b7 11134 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
11135 UNBLOCK_INPUT;
11136
11137 if (!result)
546e6d5b 11138 error ("Can't notify window manager of iconification");
3afe33e7
RS
11139
11140 f->async_iconified = 1;
1e6bc770
RS
11141 f->async_visible = 0;
11142
8c002a25
KH
11143
11144 BLOCK_INPUT;
334208b7 11145 XFlush (FRAME_X_DISPLAY (f));
8c002a25 11146 UNBLOCK_INPUT;
3afe33e7
RS
11147#else /* not USE_X_TOOLKIT */
11148
fd13dbb2
RS
11149 /* Make sure the X server knows where the window should be positioned,
11150 in case the user deiconifies with the window manager. */
11151 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 11152 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 11153
16bd92ea
JB
11154 /* Since we don't know which revision of X we're running, we'll use both
11155 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
11156
11157 /* X11R4: send a ClientMessage to the window manager using the
11158 WM_CHANGE_STATE type. */
11159 {
11160 XEvent message;
58769bee 11161
c118dd06 11162 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 11163 message.xclient.type = ClientMessage;
334208b7 11164 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
11165 message.xclient.format = 32;
11166 message.xclient.data.l[0] = IconicState;
11167
334208b7
RS
11168 if (! XSendEvent (FRAME_X_DISPLAY (f),
11169 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
11170 False,
11171 SubstructureRedirectMask | SubstructureNotifyMask,
11172 &message))
dc6f92b8
JB
11173 {
11174 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11175 error ("Can't notify window manager of iconification");
dc6f92b8 11176 }
16bd92ea 11177 }
dc6f92b8 11178
58769bee 11179 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
11180 IconicState. */
11181 x_wm_set_window_state (f, IconicState);
dc6f92b8 11182
a9c00105
RS
11183 if (!FRAME_VISIBLE_P (f))
11184 {
11185 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 11186 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
11187 }
11188
3a88c238 11189 f->async_iconified = 1;
1e6bc770 11190 f->async_visible = 0;
dc6f92b8 11191
334208b7 11192 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 11193 UNBLOCK_INPUT;
8c002a25 11194#endif /* not USE_X_TOOLKIT */
dc6f92b8 11195}
d047c4eb 11196\f
c0ff3fab 11197/* Destroy the X window of frame F. */
dc6f92b8 11198
dfcf069d 11199void
c0ff3fab 11200x_destroy_window (f)
f676886a 11201 struct frame *f;
dc6f92b8 11202{
7f9c7f94
RS
11203 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11204
dc6f92b8 11205 BLOCK_INPUT;
c0ff3fab 11206
6186a4a0
RS
11207 /* If a display connection is dead, don't try sending more
11208 commands to the X server. */
11209 if (dpyinfo->display != 0)
11210 {
11211 if (f->output_data.x->icon_desc != 0)
11212 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
31f41daf
RS
11213#ifdef HAVE_X_I18N
11214 if (FRAME_XIM (f))
11215 {
11216 XDestroyIC (FRAME_XIC (f));
408be661
RS
11217#if ! defined (SOLARIS2) || defined (HAVE_X11R6)
11218 /* This line causes crashes on Solaris with Openwin,
11219 due to an apparent bug in XCloseIM.
11220 X11R6 seems not to have the bug. */
31f41daf 11221 XCloseIM (FRAME_XIM (f));
a9978dd8 11222#endif
31f41daf
RS
11223 }
11224#endif
6186a4a0 11225 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->window_desc);
3afe33e7 11226#ifdef USE_X_TOOLKIT
06a2c219
GM
11227 if (f->output_data.x->widget)
11228 XtDestroyWidget (f->output_data.x->widget);
6186a4a0 11229 free_frame_menubar (f);
3afe33e7
RS
11230#endif /* USE_X_TOOLKIT */
11231
6186a4a0
RS
11232 free_frame_faces (f);
11233 XFlush (FRAME_X_DISPLAY (f));
11234 }
dc6f92b8 11235
df89d8a4 11236 if (f->output_data.x->saved_menu_event)
06a2c219 11237 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 11238
7556890b
RS
11239 xfree (f->output_data.x);
11240 f->output_data.x = 0;
0f941935
KH
11241 if (f == dpyinfo->x_focus_frame)
11242 dpyinfo->x_focus_frame = 0;
11243 if (f == dpyinfo->x_focus_event_frame)
11244 dpyinfo->x_focus_event_frame = 0;
11245 if (f == dpyinfo->x_highlight_frame)
11246 dpyinfo->x_highlight_frame = 0;
c0ff3fab 11247
7f9c7f94
RS
11248 dpyinfo->reference_count--;
11249
11250 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 11251 {
7f9c7f94
RS
11252 dpyinfo->mouse_face_beg_row
11253 = dpyinfo->mouse_face_beg_col = -1;
11254 dpyinfo->mouse_face_end_row
11255 = dpyinfo->mouse_face_end_col = -1;
11256 dpyinfo->mouse_face_window = Qnil;
21323706
RS
11257 dpyinfo->mouse_face_deferred_gc = 0;
11258 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 11259 }
0134a210 11260
c0ff3fab 11261 UNBLOCK_INPUT;
dc6f92b8
JB
11262}
11263\f
f451eb13
JB
11264/* Setting window manager hints. */
11265
af31d76f
RS
11266/* Set the normal size hints for the window manager, for frame F.
11267 FLAGS is the flags word to use--or 0 meaning preserve the flags
11268 that the window now has.
11269 If USER_POSITION is nonzero, we set the USPosition
11270 flag (this is useful when FLAGS is 0). */
6dba1858 11271
dfcf069d 11272void
af31d76f 11273x_wm_set_size_hint (f, flags, user_position)
f676886a 11274 struct frame *f;
af31d76f
RS
11275 long flags;
11276 int user_position;
dc6f92b8
JB
11277{
11278 XSizeHints size_hints;
3afe33e7
RS
11279
11280#ifdef USE_X_TOOLKIT
7e4f2521
FP
11281 Arg al[2];
11282 int ac = 0;
11283 Dimension widget_width, widget_height;
7556890b 11284 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 11285#else /* not USE_X_TOOLKIT */
c118dd06 11286 Window window = FRAME_X_WINDOW (f);
3afe33e7 11287#endif /* not USE_X_TOOLKIT */
dc6f92b8 11288
b72a58fd
RS
11289 /* Setting PMaxSize caused various problems. */
11290 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 11291
7556890b
RS
11292 size_hints.x = f->output_data.x->left_pos;
11293 size_hints.y = f->output_data.x->top_pos;
7553a6b7 11294
7e4f2521
FP
11295#ifdef USE_X_TOOLKIT
11296 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
11297 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 11298 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
11299 size_hints.height = widget_height;
11300 size_hints.width = widget_width;
11301#else /* not USE_X_TOOLKIT */
f676886a
JB
11302 size_hints.height = PIXEL_HEIGHT (f);
11303 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 11304#endif /* not USE_X_TOOLKIT */
7553a6b7 11305
7556890b
RS
11306 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
11307 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
11308 size_hints.max_width
11309 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
11310 size_hints.max_height
11311 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 11312
d067ea8b
KH
11313 /* Calculate the base and minimum sizes.
11314
11315 (When we use the X toolkit, we don't do it here.
11316 Instead we copy the values that the widgets are using, below.) */
11317#ifndef USE_X_TOOLKIT
b1c884c3 11318 {
b0342f17 11319 int base_width, base_height;
0134a210 11320 int min_rows = 0, min_cols = 0;
b0342f17 11321
f451eb13
JB
11322 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
11323 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 11324
0134a210 11325 check_frame_size (f, &min_rows, &min_cols);
b0342f17 11326
0134a210
RS
11327 /* The window manager uses the base width hints to calculate the
11328 current number of rows and columns in the frame while
11329 resizing; min_width and min_height aren't useful for this
11330 purpose, since they might not give the dimensions for a
11331 zero-row, zero-column frame.
58769bee 11332
0134a210
RS
11333 We use the base_width and base_height members if we have
11334 them; otherwise, we set the min_width and min_height members
11335 to the size for a zero x zero frame. */
b0342f17
JB
11336
11337#ifdef HAVE_X11R4
0134a210
RS
11338 size_hints.flags |= PBaseSize;
11339 size_hints.base_width = base_width;
11340 size_hints.base_height = base_height;
11341 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
11342 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 11343#else
0134a210
RS
11344 size_hints.min_width = base_width;
11345 size_hints.min_height = base_height;
b0342f17 11346#endif
b1c884c3 11347 }
dc6f92b8 11348
d067ea8b 11349 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 11350 if (flags)
dc6f92b8 11351 {
d067ea8b
KH
11352 size_hints.flags |= flags;
11353 goto no_read;
11354 }
11355#endif /* not USE_X_TOOLKIT */
11356
11357 {
11358 XSizeHints hints; /* Sometimes I hate X Windows... */
11359 long supplied_return;
11360 int value;
af31d76f
RS
11361
11362#ifdef HAVE_X11R4
d067ea8b
KH
11363 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
11364 &supplied_return);
af31d76f 11365#else
d067ea8b 11366 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 11367#endif
58769bee 11368
d067ea8b
KH
11369#ifdef USE_X_TOOLKIT
11370 size_hints.base_height = hints.base_height;
11371 size_hints.base_width = hints.base_width;
11372 size_hints.min_height = hints.min_height;
11373 size_hints.min_width = hints.min_width;
11374#endif
11375
11376 if (flags)
11377 size_hints.flags |= flags;
11378 else
11379 {
11380 if (value == 0)
11381 hints.flags = 0;
11382 if (hints.flags & PSize)
11383 size_hints.flags |= PSize;
11384 if (hints.flags & PPosition)
11385 size_hints.flags |= PPosition;
11386 if (hints.flags & USPosition)
11387 size_hints.flags |= USPosition;
11388 if (hints.flags & USSize)
11389 size_hints.flags |= USSize;
11390 }
11391 }
11392
06a2c219 11393#ifndef USE_X_TOOLKIT
d067ea8b 11394 no_read:
06a2c219 11395#endif
0134a210 11396
af31d76f 11397#ifdef PWinGravity
7556890b 11398 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 11399 size_hints.flags |= PWinGravity;
dc05a16b 11400
af31d76f 11401 if (user_position)
6dba1858 11402 {
af31d76f
RS
11403 size_hints.flags &= ~ PPosition;
11404 size_hints.flags |= USPosition;
6dba1858 11405 }
2554751d 11406#endif /* PWinGravity */
6dba1858 11407
b0342f17 11408#ifdef HAVE_X11R4
334208b7 11409 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 11410#else
334208b7 11411 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 11412#endif
dc6f92b8
JB
11413}
11414
11415/* Used for IconicState or NormalState */
06a2c219 11416
dfcf069d 11417void
f676886a
JB
11418x_wm_set_window_state (f, state)
11419 struct frame *f;
dc6f92b8
JB
11420 int state;
11421{
3afe33e7 11422#ifdef USE_X_TOOLKIT
546e6d5b
RS
11423 Arg al[1];
11424
11425 XtSetArg (al[0], XtNinitialState, state);
7556890b 11426 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 11427#else /* not USE_X_TOOLKIT */
c118dd06 11428 Window window = FRAME_X_WINDOW (f);
dc6f92b8 11429
7556890b
RS
11430 f->output_data.x->wm_hints.flags |= StateHint;
11431 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 11432
7556890b 11433 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 11434#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11435}
11436
dfcf069d 11437void
7f2ae036 11438x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 11439 struct frame *f;
7f2ae036 11440 int pixmap_id;
dc6f92b8 11441{
d2bd6bc4
RS
11442 Pixmap icon_pixmap;
11443
06a2c219 11444#ifndef USE_X_TOOLKIT
c118dd06 11445 Window window = FRAME_X_WINDOW (f);
75231bad 11446#endif
dc6f92b8 11447
7f2ae036 11448 if (pixmap_id > 0)
dbc4e1c1 11449 {
d2bd6bc4 11450 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 11451 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
11452 }
11453 else
68568555
RS
11454 {
11455 /* It seems there is no way to turn off use of an icon pixmap.
11456 The following line does it, only if no icon has yet been created,
11457 for some window managers. But with mwm it crashes.
11458 Some people say it should clear the IconPixmapHint bit in this case,
11459 but that doesn't work, and the X consortium said it isn't the
11460 right thing at all. Since there is no way to win,
11461 best to explicitly give up. */
11462#if 0
11463 f->output_data.x->wm_hints.icon_pixmap = None;
11464#else
11465 return;
11466#endif
11467 }
b1c884c3 11468
d2bd6bc4
RS
11469#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
11470
11471 {
11472 Arg al[1];
11473 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
11474 XtSetValues (f->output_data.x->widget, al, 1);
11475 }
11476
11477#else /* not USE_X_TOOLKIT */
11478
7556890b
RS
11479 f->output_data.x->wm_hints.flags |= IconPixmapHint;
11480 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
11481
11482#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11483}
11484
dfcf069d 11485void
f676886a
JB
11486x_wm_set_icon_position (f, icon_x, icon_y)
11487 struct frame *f;
dc6f92b8
JB
11488 int icon_x, icon_y;
11489{
75231bad 11490#ifdef USE_X_TOOLKIT
7556890b 11491 Window window = XtWindow (f->output_data.x->widget);
75231bad 11492#else
c118dd06 11493 Window window = FRAME_X_WINDOW (f);
75231bad 11494#endif
dc6f92b8 11495
7556890b
RS
11496 f->output_data.x->wm_hints.flags |= IconPositionHint;
11497 f->output_data.x->wm_hints.icon_x = icon_x;
11498 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 11499
7556890b 11500 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
11501}
11502
11503\f
06a2c219
GM
11504/***********************************************************************
11505 Fonts
11506 ***********************************************************************/
dc43ef94
KH
11507
11508/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 11509
dc43ef94
KH
11510struct font_info *
11511x_get_font_info (f, font_idx)
11512 FRAME_PTR f;
11513 int font_idx;
11514{
11515 return (FRAME_X_FONT_TABLE (f) + font_idx);
11516}
11517
11518
11519/* Return a list of names of available fonts matching PATTERN on frame
11520 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
11521 to be listed. Frame F NULL means we have not yet created any
11522 frame on X, and consult the first display in x_display_list.
11523 MAXNAMES sets a limit on how many fonts to match. */
11524
11525Lisp_Object
11526x_list_fonts (f, pattern, size, maxnames)
11527 FRAME_PTR f;
11528 Lisp_Object pattern;
11529 int size;
11530 int maxnames;
11531{
06a2c219
GM
11532 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
11533 Lisp_Object tem, second_best;
dc43ef94 11534 Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
09c6077f 11535 int try_XLoadQueryFont = 0;
53ca4657 11536 int count;
dc43ef94 11537
6b0efe73 11538 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
11539 if (NILP (patterns))
11540 patterns = Fcons (pattern, Qnil);
81ba44e5 11541
09c6077f
KH
11542 if (maxnames == 1 && !size)
11543 /* We can return any single font matching PATTERN. */
11544 try_XLoadQueryFont = 1;
9a32686f 11545
2da424f1 11546 for (; CONSP (patterns); patterns = XCONS (patterns)->cdr)
dc43ef94 11547 {
dc43ef94
KH
11548 int num_fonts;
11549 char **names;
11550
2da424f1 11551 pattern = XCONS (patterns)->car;
536f4067
RS
11552 /* See if we cached the result for this particular query.
11553 The cache is an alist of the form:
11554 (((PATTERN . MAXNAMES) (FONTNAME . WIDTH) ...) ...)
11555 */
b5210ea7
KH
11556 if (f && (tem = XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr,
11557 key = Fcons (pattern, make_number (maxnames)),
11558 !NILP (list = Fassoc (key, tem))))
11559 {
11560 list = Fcdr_safe (list);
11561 /* We have a cashed list. Don't have to get the list again. */
11562 goto label_cached;
11563 }
11564
11565 /* At first, put PATTERN in the cache. */
09c6077f 11566
dc43ef94 11567 BLOCK_INPUT;
17d85edc
KH
11568 count = x_catch_errors (dpy);
11569
09c6077f
KH
11570 if (try_XLoadQueryFont)
11571 {
11572 XFontStruct *font;
11573 unsigned long value;
11574
11575 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
11576 if (x_had_errors_p (dpy))
11577 {
11578 /* This error is perhaps due to insufficient memory on X
11579 server. Let's just ignore it. */
11580 font = NULL;
11581 x_clear_errors (dpy);
11582 }
11583
09c6077f
KH
11584 if (font
11585 && XGetFontProperty (font, XA_FONT, &value))
11586 {
11587 char *name = (char *) XGetAtomName (dpy, (Atom) value);
11588 int len = strlen (name);
01c752b5 11589 char *tmp;
09c6077f 11590
6f6512e8
KH
11591 /* If DXPC (a Differential X Protocol Compressor)
11592 Ver.3.7 is running, XGetAtomName will return null
11593 string. We must avoid such a name. */
11594 if (len == 0)
11595 try_XLoadQueryFont = 0;
11596 else
11597 {
11598 num_fonts = 1;
11599 names = (char **) alloca (sizeof (char *));
11600 /* Some systems only allow alloca assigned to a
11601 simple var. */
11602 tmp = (char *) alloca (len + 1); names[0] = tmp;
11603 bcopy (name, names[0], len + 1);
11604 XFree (name);
11605 }
09c6077f
KH
11606 }
11607 else
11608 try_XLoadQueryFont = 0;
a083fd23
RS
11609
11610 if (font)
11611 XFreeFont (dpy, font);
09c6077f
KH
11612 }
11613
11614 if (!try_XLoadQueryFont)
17d85edc
KH
11615 {
11616 /* We try at least 10 fonts because XListFonts will return
11617 auto-scaled fonts at the head. */
11618 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
11619 &num_fonts);
11620 if (x_had_errors_p (dpy))
11621 {
11622 /* This error is perhaps due to insufficient memory on X
11623 server. Let's just ignore it. */
11624 names = NULL;
11625 x_clear_errors (dpy);
11626 }
11627 }
11628
11629 x_uncatch_errors (dpy, count);
dc43ef94
KH
11630 UNBLOCK_INPUT;
11631
11632 if (names)
11633 {
11634 int i;
dc43ef94
KH
11635
11636 /* Make a list of all the fonts we got back.
11637 Store that in the font cache for the display. */
11638 for (i = 0; i < num_fonts; i++)
11639 {
06a2c219 11640 int width = 0;
dc43ef94 11641 char *p = names[i];
06a2c219
GM
11642 int average_width = -1, dashes = 0;
11643
dc43ef94 11644 /* Count the number of dashes in NAMES[I]. If there are
b5210ea7
KH
11645 14 dashes, and the field value following 12th dash
11646 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
11647 is usually too ugly to be used for editing. Let's
11648 ignore it. */
dc43ef94
KH
11649 while (*p)
11650 if (*p++ == '-')
11651 {
11652 dashes++;
11653 if (dashes == 7) /* PIXEL_SIZE field */
11654 width = atoi (p);
11655 else if (dashes == 12) /* AVERAGE_WIDTH field */
11656 average_width = atoi (p);
11657 }
11658 if (dashes < 14 || average_width != 0)
11659 {
11660 tem = build_string (names[i]);
11661 if (NILP (Fassoc (tem, list)))
11662 {
11663 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
11664 && ((fast_c_string_match_ignore_case
11665 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
11666 >= 0))
11667 /* We can set the value of PIXEL_SIZE to the
b5210ea7 11668 width of this font. */
dc43ef94
KH
11669 list = Fcons (Fcons (tem, make_number (width)), list);
11670 else
11671 /* For the moment, width is not known. */
11672 list = Fcons (Fcons (tem, Qnil), list);
11673 }
11674 }
11675 }
09c6077f
KH
11676 if (!try_XLoadQueryFont)
11677 XFreeFontNames (names);
dc43ef94
KH
11678 }
11679
b5210ea7 11680 /* Now store the result in the cache. */
dc43ef94
KH
11681 if (f != NULL)
11682 XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr
11683 = Fcons (Fcons (key, list),
11684 XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr);
dc43ef94 11685
b5210ea7
KH
11686 label_cached:
11687 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 11688
b5210ea7
KH
11689 newlist = second_best = Qnil;
11690 /* Make a list of the fonts that have the right width. */
11691 for (; CONSP (list); list = XCONS (list)->cdr)
11692 {
536f4067
RS
11693 int found_size;
11694
b5210ea7 11695 tem = XCONS (list)->car;
dc43ef94 11696
b5210ea7
KH
11697 if (!CONSP (tem) || NILP (XCONS (tem)->car))
11698 continue;
11699 if (!size)
11700 {
11701 newlist = Fcons (XCONS (tem)->car, newlist);
11702 continue;
11703 }
dc43ef94 11704
dc43ef94
KH
11705 if (!INTEGERP (XCONS (tem)->cdr))
11706 {
b5210ea7
KH
11707 /* Since we have not yet known the size of this font, we
11708 must try slow function call XLoadQueryFont. */
dc43ef94
KH
11709 XFontStruct *thisinfo;
11710
11711 BLOCK_INPUT;
17d85edc 11712 count = x_catch_errors (dpy);
dc43ef94
KH
11713 thisinfo = XLoadQueryFont (dpy,
11714 XSTRING (XCONS (tem)->car)->data);
17d85edc
KH
11715 if (x_had_errors_p (dpy))
11716 {
11717 /* This error is perhaps due to insufficient memory on X
11718 server. Let's just ignore it. */
11719 thisinfo = NULL;
11720 x_clear_errors (dpy);
11721 }
11722 x_uncatch_errors (dpy, count);
dc43ef94
KH
11723 UNBLOCK_INPUT;
11724
11725 if (thisinfo)
11726 {
536f4067
RS
11727 XCONS (tem)->cdr
11728 = (thisinfo->min_bounds.width == 0
11729 ? make_number (0)
11730 : make_number (thisinfo->max_bounds.width));
dc43ef94
KH
11731 XFreeFont (dpy, thisinfo);
11732 }
11733 else
b5210ea7 11734 /* For unknown reason, the previous call of XListFont had
06a2c219 11735 returned a font which can't be opened. Record the size
b5210ea7 11736 as 0 not to try to open it again. */
dc43ef94
KH
11737 XCONS (tem)->cdr = make_number (0);
11738 }
536f4067
RS
11739
11740 found_size = XINT (XCONS (tem)->cdr);
11741 if (found_size == size)
b5210ea7 11742 newlist = Fcons (XCONS (tem)->car, newlist);
536f4067 11743 else if (found_size > 0)
b5210ea7 11744 {
536f4067 11745 if (NILP (second_best))
b5210ea7 11746 second_best = tem;
536f4067
RS
11747 else if (found_size < size)
11748 {
11749 if (XINT (XCONS (second_best)->cdr) > size
11750 || XINT (XCONS (second_best)->cdr) < found_size)
11751 second_best = tem;
11752 }
11753 else
11754 {
11755 if (XINT (XCONS (second_best)->cdr) > size
11756 && XINT (XCONS (second_best)->cdr) > found_size)
11757 second_best = tem;
11758 }
b5210ea7
KH
11759 }
11760 }
11761 if (!NILP (newlist))
11762 break;
11763 else if (!NILP (second_best))
11764 {
11765 newlist = Fcons (XCONS (second_best)->car, Qnil);
11766 break;
dc43ef94 11767 }
dc43ef94
KH
11768 }
11769
11770 return newlist;
11771}
11772
06a2c219
GM
11773
11774#if GLYPH_DEBUG
11775
11776/* Check that FONT is valid on frame F. It is if it can be found in F's
11777 font table. */
11778
11779static void
11780x_check_font (f, font)
11781 struct frame *f;
11782 XFontStruct *font;
11783{
11784 int i;
11785 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11786
11787 xassert (font != NULL);
11788
11789 for (i = 0; i < dpyinfo->n_fonts; i++)
11790 if (dpyinfo->font_table[i].name
11791 && font == dpyinfo->font_table[i].font)
11792 break;
11793
11794 xassert (i < dpyinfo->n_fonts);
11795}
11796
11797#endif /* GLYPH_DEBUG != 0 */
11798
11799/* Set *W to the minimum width, *H to the minimum font height of FONT.
11800 Note: There are (broken) X fonts out there with invalid XFontStruct
11801 min_bounds contents. For example, handa@etl.go.jp reports that
11802 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
11803 have font->min_bounds.width == 0. */
11804
11805static INLINE void
11806x_font_min_bounds (font, w, h)
11807 XFontStruct *font;
11808 int *w, *h;
11809{
11810 *h = FONT_HEIGHT (font);
11811 *w = font->min_bounds.width;
11812
11813 /* Try to handle the case where FONT->min_bounds has invalid
11814 contents. Since the only font known to have invalid min_bounds
11815 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
11816 if (*w <= 0)
11817 *w = font->max_bounds.width;
11818}
11819
11820
11821/* Compute the smallest character width and smallest font height over
11822 all fonts available on frame F. Set the members smallest_char_width
11823 and smallest_font_height in F's x_display_info structure to
11824 the values computed. Value is non-zero if smallest_font_height or
11825 smallest_char_width become smaller than they were before. */
11826
11827static int
11828x_compute_min_glyph_bounds (f)
11829 struct frame *f;
11830{
11831 int i;
11832 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11833 XFontStruct *font;
11834 int old_width = dpyinfo->smallest_char_width;
11835 int old_height = dpyinfo->smallest_font_height;
11836
11837 dpyinfo->smallest_font_height = 100000;
11838 dpyinfo->smallest_char_width = 100000;
11839
11840 for (i = 0; i < dpyinfo->n_fonts; ++i)
11841 if (dpyinfo->font_table[i].name)
11842 {
11843 struct font_info *fontp = dpyinfo->font_table + i;
11844 int w, h;
11845
11846 font = (XFontStruct *) fontp->font;
11847 xassert (font != (XFontStruct *) ~0);
11848 x_font_min_bounds (font, &w, &h);
11849
11850 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
11851 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
11852 }
11853
11854 xassert (dpyinfo->smallest_char_width > 0
11855 && dpyinfo->smallest_font_height > 0);
11856
11857 return (dpyinfo->n_fonts == 1
11858 || dpyinfo->smallest_char_width < old_width
11859 || dpyinfo->smallest_font_height < old_height);
11860}
11861
11862
dc43ef94
KH
11863/* Load font named FONTNAME of the size SIZE for frame F, and return a
11864 pointer to the structure font_info while allocating it dynamically.
11865 If SIZE is 0, load any size of font.
11866 If loading is failed, return NULL. */
11867
11868struct font_info *
11869x_load_font (f, fontname, size)
11870 struct frame *f;
11871 register char *fontname;
11872 int size;
11873{
11874 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11875 Lisp_Object font_names;
d645aaa4 11876 int count;
dc43ef94
KH
11877
11878 /* Get a list of all the fonts that match this name. Once we
11879 have a list of matching fonts, we compare them against the fonts
11880 we already have by comparing names. */
09c6077f 11881 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
11882
11883 if (!NILP (font_names))
11884 {
11885 Lisp_Object tail;
11886 int i;
11887
11888 for (i = 0; i < dpyinfo->n_fonts; i++)
11889 for (tail = font_names; CONSP (tail); tail = XCONS (tail)->cdr)
06a2c219
GM
11890 if (dpyinfo->font_table[i].name
11891 && (!strcmp (dpyinfo->font_table[i].name,
11892 XSTRING (XCONS (tail)->car)->data)
11893 || !strcmp (dpyinfo->font_table[i].full_name,
11894 XSTRING (XCONS (tail)->car)->data)))
dc43ef94
KH
11895 return (dpyinfo->font_table + i);
11896 }
11897
11898 /* Load the font and add it to the table. */
11899 {
11900 char *full_name;
11901 XFontStruct *font;
11902 struct font_info *fontp;
11903 unsigned long value;
06a2c219 11904 int i;
dc43ef94 11905
2da424f1
KH
11906 /* If we have found fonts by x_list_font, load one of them. If
11907 not, we still try to load a font by the name given as FONTNAME
11908 because XListFonts (called in x_list_font) of some X server has
11909 a bug of not finding a font even if the font surely exists and
11910 is loadable by XLoadQueryFont. */
e1d6d5b9 11911 if (size > 0 && !NILP (font_names))
f613a4c8 11912 fontname = (char *) XSTRING (XCONS (font_names)->car)->data;
dc43ef94
KH
11913
11914 BLOCK_INPUT;
d645aaa4 11915 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 11916 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
11917 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
11918 {
11919 /* This error is perhaps due to insufficient memory on X
11920 server. Let's just ignore it. */
11921 font = NULL;
11922 x_clear_errors (FRAME_X_DISPLAY (f));
11923 }
11924 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 11925 UNBLOCK_INPUT;
b5210ea7 11926 if (!font)
dc43ef94
KH
11927 return NULL;
11928
06a2c219
GM
11929 /* Find a free slot in the font table. */
11930 for (i = 0; i < dpyinfo->n_fonts; ++i)
11931 if (dpyinfo->font_table[i].name == NULL)
11932 break;
11933
11934 /* If no free slot found, maybe enlarge the font table. */
11935 if (i == dpyinfo->n_fonts
11936 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 11937 {
06a2c219
GM
11938 int sz;
11939 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
11940 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 11941 dpyinfo->font_table
06a2c219 11942 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
11943 }
11944
06a2c219
GM
11945 fontp = dpyinfo->font_table + i;
11946 if (i == dpyinfo->n_fonts)
11947 ++dpyinfo->n_fonts;
dc43ef94
KH
11948
11949 /* Now fill in the slots of *FONTP. */
11950 BLOCK_INPUT;
11951 fontp->font = font;
06a2c219 11952 fontp->font_idx = i;
dc43ef94
KH
11953 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
11954 bcopy (fontname, fontp->name, strlen (fontname) + 1);
11955
11956 /* Try to get the full name of FONT. Put it in FULL_NAME. */
11957 full_name = 0;
11958 if (XGetFontProperty (font, XA_FONT, &value))
11959 {
11960 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
11961 char *p = name;
11962 int dashes = 0;
11963
11964 /* Count the number of dashes in the "full name".
11965 If it is too few, this isn't really the font's full name,
11966 so don't use it.
11967 In X11R4, the fonts did not come with their canonical names
11968 stored in them. */
11969 while (*p)
11970 {
11971 if (*p == '-')
11972 dashes++;
11973 p++;
11974 }
11975
11976 if (dashes >= 13)
11977 {
11978 full_name = (char *) xmalloc (p - name + 1);
11979 bcopy (name, full_name, p - name + 1);
11980 }
11981
11982 XFree (name);
11983 }
11984
11985 if (full_name != 0)
11986 fontp->full_name = full_name;
11987 else
11988 fontp->full_name = fontp->name;
11989
11990 fontp->size = font->max_bounds.width;
d5749adb
KH
11991 fontp->height = FONT_HEIGHT (font);
11992 {
11993 /* For some font, ascent and descent in max_bounds field is
11994 larger than the above value. */
11995 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
11996 if (max_height > fontp->height)
74848a96 11997 fontp->height = max_height;
d5749adb 11998 }
dc43ef94 11999
2da424f1
KH
12000 if (NILP (font_names))
12001 {
12002 /* We come here because of a bug of XListFonts mentioned at
12003 the head of this block. Let's store this information in
12004 the cache for x_list_fonts. */
12005 Lisp_Object lispy_name = build_string (fontname);
12006 Lisp_Object lispy_full_name = build_string (fontp->full_name);
12007
12008 XCONS (dpyinfo->name_list_element)->cdr
12009 = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
12010 Fcons (Fcons (lispy_full_name,
12011 make_number (fontp->size)),
12012 Qnil)),
12013 XCONS (dpyinfo->name_list_element)->cdr);
12014 if (full_name)
12015 XCONS (dpyinfo->name_list_element)->cdr
12016 = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
12017 Fcons (Fcons (lispy_full_name,
12018 make_number (fontp->size)),
12019 Qnil)),
12020 XCONS (dpyinfo->name_list_element)->cdr);
12021 }
12022
dc43ef94
KH
12023 /* The slot `encoding' specifies how to map a character
12024 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ce667c3e 12025 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
8ff102bd
RS
12026 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
12027 0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
12028 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 12029 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
12030 which is never used by any charset. If mapping can't be
12031 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
12032 fontp->encoding[1]
12033 = (font->max_byte1 == 0
12034 /* 1-byte font */
12035 ? (font->min_char_or_byte2 < 0x80
12036 ? (font->max_char_or_byte2 < 0x80
12037 ? 0 /* 0x20..0x7F */
8ff102bd 12038 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
12039 : 1) /* 0xA0..0xFF */
12040 /* 2-byte font */
12041 : (font->min_byte1 < 0x80
12042 ? (font->max_byte1 < 0x80
12043 ? (font->min_char_or_byte2 < 0x80
12044 ? (font->max_char_or_byte2 < 0x80
12045 ? 0 /* 0x2020..0x7F7F */
8ff102bd 12046 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 12047 : 3) /* 0x20A0..0x7FFF */
8ff102bd 12048 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
12049 : (font->min_char_or_byte2 < 0x80
12050 ? (font->max_char_or_byte2 < 0x80
12051 ? 2 /* 0xA020..0xFF7F */
8ff102bd 12052 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
12053 : 1))); /* 0xA0A0..0xFFFF */
12054
12055 fontp->baseline_offset
12056 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
12057 ? (long) value : 0);
12058 fontp->relative_compose
12059 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
12060 ? (long) value : 0);
f78798df
KH
12061 fontp->default_ascent
12062 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
12063 ? (long) value : 0);
dc43ef94 12064
06a2c219
GM
12065 /* Set global flag fonts_changed_p to non-zero if the font loaded
12066 has a character with a smaller width than any other character
12067 before, or if the font loaded has a smalle>r height than any
12068 other font loaded before. If this happens, it will make a
12069 glyph matrix reallocation necessary. */
12070 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 12071 UNBLOCK_INPUT;
dc43ef94
KH
12072 return fontp;
12073 }
12074}
12075
06a2c219
GM
12076
12077/* Return a pointer to struct font_info of a font named FONTNAME for
12078 frame F. If no such font is loaded, return NULL. */
12079
dc43ef94
KH
12080struct font_info *
12081x_query_font (f, fontname)
12082 struct frame *f;
12083 register char *fontname;
12084{
12085 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12086 int i;
12087
12088 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
12089 if (dpyinfo->font_table[i].name
12090 && (!strcmp (dpyinfo->font_table[i].name, fontname)
12091 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
12092 return (dpyinfo->font_table + i);
12093 return NULL;
12094}
12095
06a2c219
GM
12096
12097/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
12098 `encoder' of the structure. */
12099
12100void
12101x_find_ccl_program (fontp)
12102 struct font_info *fontp;
12103{
a42f54e6 12104 Lisp_Object list, elt;
a6582676
KH
12105
12106 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCONS (list)->cdr)
12107 {
12108 elt = XCONS (list)->car;
12109 if (CONSP (elt)
12110 && STRINGP (XCONS (elt)->car)
12111 && (fast_c_string_match_ignore_case (XCONS (elt)->car, fontp->name)
12112 >= 0))
a42f54e6
KH
12113 break;
12114 }
12115 if (! NILP (list))
12116 {
d27f8ca7
KH
12117 struct ccl_program *ccl
12118 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6
KH
12119
12120 if (setup_ccl_program (ccl, XCONS (elt)->cdr) < 0)
12121 xfree (ccl);
12122 else
12123 fontp->font_encoder = ccl;
a6582676
KH
12124 }
12125}
12126
06a2c219 12127
dc43ef94 12128\f
06a2c219
GM
12129/***********************************************************************
12130 Initialization
12131 ***********************************************************************/
f451eb13 12132
3afe33e7
RS
12133#ifdef USE_X_TOOLKIT
12134static XrmOptionDescRec emacs_options[] = {
12135 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
12136 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
12137
12138 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
12139 XrmoptionSepArg, NULL},
12140 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
12141
12142 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12143 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12144 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12145 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
12146 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
12147 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
12148 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
12149};
12150#endif /* USE_X_TOOLKIT */
12151
7a13e894
RS
12152static int x_initialized;
12153
29b38361
KH
12154#ifdef MULTI_KBOARD
12155/* Test whether two display-name strings agree up to the dot that separates
12156 the screen number from the server number. */
12157static int
12158same_x_server (name1, name2)
12159 char *name1, *name2;
12160{
12161 int seen_colon = 0;
cf591cc1
RS
12162 unsigned char *system_name = XSTRING (Vsystem_name)->data;
12163 int system_name_length = strlen (system_name);
12164 int length_until_period = 0;
12165
12166 while (system_name[length_until_period] != 0
12167 && system_name[length_until_period] != '.')
12168 length_until_period++;
12169
12170 /* Treat `unix' like an empty host name. */
12171 if (! strncmp (name1, "unix:", 5))
12172 name1 += 4;
12173 if (! strncmp (name2, "unix:", 5))
12174 name2 += 4;
12175 /* Treat this host's name like an empty host name. */
12176 if (! strncmp (name1, system_name, system_name_length)
12177 && name1[system_name_length] == ':')
12178 name1 += system_name_length;
12179 if (! strncmp (name2, system_name, system_name_length)
12180 && name2[system_name_length] == ':')
12181 name2 += system_name_length;
12182 /* Treat this host's domainless name like an empty host name. */
12183 if (! strncmp (name1, system_name, length_until_period)
12184 && name1[length_until_period] == ':')
12185 name1 += length_until_period;
12186 if (! strncmp (name2, system_name, length_until_period)
12187 && name2[length_until_period] == ':')
12188 name2 += length_until_period;
12189
29b38361
KH
12190 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
12191 {
12192 if (*name1 == ':')
12193 seen_colon++;
12194 if (seen_colon && *name1 == '.')
12195 return 1;
12196 }
12197 return (seen_colon
12198 && (*name1 == '.' || *name1 == '\0')
12199 && (*name2 == '.' || *name2 == '\0'));
12200}
12201#endif
12202
71f8198a
PE
12203#if defined (HAVE_X_I18N) || (defined (USE_X_TOOLKIT) && defined (HAVE_X11XTR6))
12204/* Recover from setlocale (LC_ALL, ""). */
12205static void
12206fixup_locale ()
12207{
12208 /* Currently we require strerror to use the "C" locale,
12209 since we don't yet support decoding its string result. */
12210#ifdef LC_MESSAGES
12211 setlocale (LC_MESSAGES, "C");
12212#endif
12213
12214 /* The Emacs Lisp reader needs LC_NUMERIC to be "C",
12215 so that numbers are read and printed properly for Emacs Lisp. */
12216 setlocale (LC_NUMERIC, "C");
12217
12218 /* Currently we require strftime to use the "C" locale,
12219 since we don't yet support encoding its format argument,
12220 or decoding its string result. */
12221 setlocale (LC_TIME, "C");
12222}
12223#endif
12224
334208b7 12225struct x_display_info *
1f8255f2 12226x_term_init (display_name, xrm_option, resource_name)
334208b7 12227 Lisp_Object display_name;
1f8255f2
RS
12228 char *xrm_option;
12229 char *resource_name;
dc6f92b8 12230{
334208b7 12231 int connection;
7a13e894 12232 Display *dpy;
334208b7
RS
12233 struct x_display_info *dpyinfo;
12234 XrmDatabase xrdb;
12235
60439948
KH
12236 BLOCK_INPUT;
12237
7a13e894
RS
12238 if (!x_initialized)
12239 {
12240 x_initialize ();
12241 x_initialized = 1;
12242 }
dc6f92b8 12243
6c183ba5 12244#ifdef HAVE_X_I18N
6186a4a0 12245 setlocale (LC_ALL, "");
71f8198a 12246 fixup_locale ();
6c183ba5
RS
12247#endif
12248
3afe33e7 12249#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
12250 /* weiner@footloose.sps.mot.com reports that this causes
12251 errors with X11R5:
12252 X protocol error: BadAtom (invalid Atom parameter)
12253 on protocol request 18skiloaf.
12254 So let's not use it until R6. */
12255#ifdef HAVE_X11XTR6
bdcd49ba
RS
12256 XtSetLanguageProc (NULL, NULL, NULL);
12257#endif
12258
7f9c7f94
RS
12259 {
12260 int argc = 0;
12261 char *argv[3];
12262
12263 argv[0] = "";
12264 argc = 1;
12265 if (xrm_option)
12266 {
12267 argv[argc++] = "-xrm";
12268 argv[argc++] = xrm_option;
12269 }
12270 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
12271 resource_name, EMACS_CLASS,
12272 emacs_options, XtNumber (emacs_options),
12273 &argc, argv);
39d8bb4d
KH
12274
12275#ifdef HAVE_X11XTR6
10537cb1 12276 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 12277 fixup_locale ();
39d8bb4d 12278#endif
7f9c7f94 12279 }
3afe33e7
RS
12280
12281#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
12282#ifdef HAVE_X11R5
12283 XSetLocaleModifiers ("");
12284#endif
7a13e894 12285 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 12286#endif /* not USE_X_TOOLKIT */
334208b7 12287
7a13e894
RS
12288 /* Detect failure. */
12289 if (dpy == 0)
60439948
KH
12290 {
12291 UNBLOCK_INPUT;
12292 return 0;
12293 }
7a13e894
RS
12294
12295 /* We have definitely succeeded. Record the new connection. */
12296
12297 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
12298
29b38361
KH
12299#ifdef MULTI_KBOARD
12300 {
12301 struct x_display_info *share;
12302 Lisp_Object tail;
12303
12304 for (share = x_display_list, tail = x_display_name_list; share;
12305 share = share->next, tail = XCONS (tail)->cdr)
12306 if (same_x_server (XSTRING (XCONS (XCONS (tail)->car)->car)->data,
12307 XSTRING (display_name)->data))
12308 break;
12309 if (share)
12310 dpyinfo->kboard = share->kboard;
12311 else
12312 {
12313 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
12314 init_kboard (dpyinfo->kboard);
59e755be
KH
12315 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
12316 {
12317 char *vendor = ServerVendor (dpy);
12318 dpyinfo->kboard->Vsystem_key_alist
12319 = call1 (Qvendor_specific_keysyms,
12320 build_string (vendor ? vendor : ""));
12321 }
12322
29b38361
KH
12323 dpyinfo->kboard->next_kboard = all_kboards;
12324 all_kboards = dpyinfo->kboard;
0ad5446c
KH
12325 /* Don't let the initial kboard remain current longer than necessary.
12326 That would cause problems if a file loaded on startup tries to
06a2c219 12327 prompt in the mini-buffer. */
0ad5446c
KH
12328 if (current_kboard == initial_kboard)
12329 current_kboard = dpyinfo->kboard;
29b38361
KH
12330 }
12331 dpyinfo->kboard->reference_count++;
12332 }
b9737ad3
KH
12333#endif
12334
7a13e894
RS
12335 /* Put this display on the chain. */
12336 dpyinfo->next = x_display_list;
12337 x_display_list = dpyinfo;
12338
12339 /* Put it on x_display_name_list as well, to keep them parallel. */
12340 x_display_name_list = Fcons (Fcons (display_name, Qnil),
12341 x_display_name_list);
12342 dpyinfo->name_list_element = XCONS (x_display_name_list)->car;
12343
12344 dpyinfo->display = dpy;
dc6f92b8 12345
dc6f92b8 12346#if 0
7a13e894 12347 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 12348#endif /* ! 0 */
7a13e894
RS
12349
12350 dpyinfo->x_id_name
fc932ac6
RS
12351 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
12352 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
12353 + 2);
12354 sprintf (dpyinfo->x_id_name, "%s@%s",
12355 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
12356
12357 /* Figure out which modifier bits mean what. */
334208b7 12358 x_find_modifier_meanings (dpyinfo);
f451eb13 12359
ab648270 12360 /* Get the scroll bar cursor. */
7a13e894 12361 dpyinfo->vertical_scroll_bar_cursor
334208b7 12362 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 12363
334208b7
RS
12364 xrdb = x_load_resources (dpyinfo->display, xrm_option,
12365 resource_name, EMACS_CLASS);
12366#ifdef HAVE_XRMSETDATABASE
12367 XrmSetDatabase (dpyinfo->display, xrdb);
12368#else
12369 dpyinfo->display->db = xrdb;
12370#endif
547d9db8 12371 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
12372 all versions. */
12373 dpyinfo->xrdb = xrdb;
334208b7
RS
12374
12375 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
12376 DefaultScreen (dpyinfo->display));
12377 dpyinfo->visual = select_visual (dpyinfo->display, dpyinfo->screen,
12378 &dpyinfo->n_planes);
12379 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
12380 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
12381 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
12382 dpyinfo->grabbed = 0;
12383 dpyinfo->reference_count = 0;
12384 dpyinfo->icon_bitmap_id = -1;
06a2c219 12385 dpyinfo->font_table = NULL;
7a13e894
RS
12386 dpyinfo->n_fonts = 0;
12387 dpyinfo->font_table_size = 0;
12388 dpyinfo->bitmaps = 0;
12389 dpyinfo->bitmaps_size = 0;
12390 dpyinfo->bitmaps_last = 0;
12391 dpyinfo->scratch_cursor_gc = 0;
12392 dpyinfo->mouse_face_mouse_frame = 0;
12393 dpyinfo->mouse_face_deferred_gc = 0;
12394 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
12395 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 12396 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894
RS
12397 dpyinfo->mouse_face_window = Qnil;
12398 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
12399 dpyinfo->mouse_face_defer = 0;
0f941935
KH
12400 dpyinfo->x_focus_frame = 0;
12401 dpyinfo->x_focus_event_frame = 0;
12402 dpyinfo->x_highlight_frame = 0;
06a2c219 12403 dpyinfo->image_cache = make_image_cache ();
334208b7 12404
06a2c219
GM
12405 {
12406 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
12407 double pixels = DisplayHeight (dpyinfo->display, screen_number);
12408 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
12409 dpyinfo->resy = pixels * 25.4 / mm;
12410 pixels = DisplayWidth (dpyinfo->display, screen_number);
12411 mm = DisplayWidthMM (dpyinfo->display, screen_number);
12412 dpyinfo->resx = pixels * 25.4 / mm;
12413 }
12414
334208b7
RS
12415 dpyinfo->Xatom_wm_protocols
12416 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
12417 dpyinfo->Xatom_wm_take_focus
12418 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
12419 dpyinfo->Xatom_wm_save_yourself
12420 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
12421 dpyinfo->Xatom_wm_delete_window
12422 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
12423 dpyinfo->Xatom_wm_change_state
12424 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
12425 dpyinfo->Xatom_wm_configure_denied
12426 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
12427 dpyinfo->Xatom_wm_window_moved
12428 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
12429 dpyinfo->Xatom_editres
12430 = XInternAtom (dpyinfo->display, "Editres", False);
12431 dpyinfo->Xatom_CLIPBOARD
12432 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
12433 dpyinfo->Xatom_TIMESTAMP
12434 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
12435 dpyinfo->Xatom_TEXT
12436 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
12437 dpyinfo->Xatom_COMPOUND_TEXT
12438 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
12439 dpyinfo->Xatom_DELETE
12440 = XInternAtom (dpyinfo->display, "DELETE", False);
12441 dpyinfo->Xatom_MULTIPLE
12442 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
12443 dpyinfo->Xatom_INCR
12444 = XInternAtom (dpyinfo->display, "INCR", False);
12445 dpyinfo->Xatom_EMACS_TMP
12446 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
12447 dpyinfo->Xatom_TARGETS
12448 = XInternAtom (dpyinfo->display, "TARGETS", False);
12449 dpyinfo->Xatom_NULL
12450 = XInternAtom (dpyinfo->display, "NULL", False);
12451 dpyinfo->Xatom_ATOM_PAIR
12452 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
12453 /* For properties of font. */
12454 dpyinfo->Xatom_PIXEL_SIZE
12455 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
12456 dpyinfo->Xatom_MULE_BASELINE_OFFSET
12457 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
12458 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
12459 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
12460 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
12461 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 12462
06a2c219
GM
12463 /* Ghostscript support. */
12464 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
12465 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
12466
12467 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
12468 False);
12469
547d9db8
KH
12470 dpyinfo->cut_buffers_initialized = 0;
12471
334208b7
RS
12472 connection = ConnectionNumber (dpyinfo->display);
12473 dpyinfo->connection = connection;
12474
dc43ef94 12475 {
5d7cc324
RS
12476 char null_bits[1];
12477
12478 null_bits[0] = 0x00;
dc43ef94
KH
12479
12480 dpyinfo->null_pixel
12481 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
12482 null_bits, 1, 1, (long) 0, (long) 0,
12483 1);
12484 }
12485
06a2c219
GM
12486 {
12487 extern int gray_bitmap_width, gray_bitmap_height;
12488 extern unsigned char *gray_bitmap_bits;
12489 dpyinfo->gray
12490 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
12491 gray_bitmap_bits,
12492 gray_bitmap_width, gray_bitmap_height,
12493 (unsigned long) 1, (unsigned long) 0, 1);
12494 }
12495
87485d6f
MW
12496#ifdef subprocesses
12497 /* This is only needed for distinguishing keyboard and process input. */
334208b7 12498 if (connection != 0)
7a13e894 12499 add_keyboard_wait_descriptor (connection);
87485d6f 12500#endif
6d4238f3 12501
041b69ac 12502#ifndef F_SETOWN_BUG
dc6f92b8 12503#ifdef F_SETOWN
dc6f92b8 12504#ifdef F_SETOWN_SOCK_NEG
61c3ce62 12505 /* stdin is a socket here */
334208b7 12506 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 12507#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 12508 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
12509#endif /* ! defined (F_SETOWN_SOCK_NEG) */
12510#endif /* ! defined (F_SETOWN) */
041b69ac 12511#endif /* F_SETOWN_BUG */
dc6f92b8
JB
12512
12513#ifdef SIGIO
eee20f6a
KH
12514 if (interrupt_input)
12515 init_sigio (connection);
c118dd06 12516#endif /* ! defined (SIGIO) */
dc6f92b8 12517
51b592fb 12518#ifdef USE_LUCID
f8c39f51 12519#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
12520 /* Make sure that we have a valid font for dialog boxes
12521 so that Xt does not crash. */
12522 {
12523 Display *dpy = dpyinfo->display;
12524 XrmValue d, fr, to;
12525 Font font;
e99db5a1 12526 int count;
51b592fb
RS
12527
12528 d.addr = (XPointer)&dpy;
12529 d.size = sizeof (Display *);
12530 fr.addr = XtDefaultFont;
12531 fr.size = sizeof (XtDefaultFont);
12532 to.size = sizeof (Font *);
12533 to.addr = (XPointer)&font;
e99db5a1 12534 count = x_catch_errors (dpy);
51b592fb
RS
12535 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
12536 abort ();
12537 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
12538 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 12539 x_uncatch_errors (dpy, count);
51b592fb
RS
12540 }
12541#endif
f8c39f51 12542#endif
51b592fb 12543
60439948
KH
12544 UNBLOCK_INPUT;
12545
7a13e894
RS
12546 return dpyinfo;
12547}
12548\f
12549/* Get rid of display DPYINFO, assuming all frames are already gone,
12550 and without sending any more commands to the X server. */
dc6f92b8 12551
7a13e894
RS
12552void
12553x_delete_display (dpyinfo)
12554 struct x_display_info *dpyinfo;
12555{
12556 delete_keyboard_wait_descriptor (dpyinfo->connection);
12557
12558 /* Discard this display from x_display_name_list and x_display_list.
12559 We can't use Fdelq because that can quit. */
12560 if (! NILP (x_display_name_list)
12561 && EQ (XCONS (x_display_name_list)->car, dpyinfo->name_list_element))
12562 x_display_name_list = XCONS (x_display_name_list)->cdr;
12563 else
12564 {
12565 Lisp_Object tail;
12566
12567 tail = x_display_name_list;
12568 while (CONSP (tail) && CONSP (XCONS (tail)->cdr))
12569 {
12570 if (EQ (XCONS (XCONS (tail)->cdr)->car,
12571 dpyinfo->name_list_element))
12572 {
12573 XCONS (tail)->cdr = XCONS (XCONS (tail)->cdr)->cdr;
12574 break;
12575 }
12576 tail = XCONS (tail)->cdr;
12577 }
12578 }
12579
12580 if (x_display_list == dpyinfo)
12581 x_display_list = dpyinfo->next;
7f9c7f94
RS
12582 else
12583 {
12584 struct x_display_info *tail;
7a13e894 12585
7f9c7f94
RS
12586 for (tail = x_display_list; tail; tail = tail->next)
12587 if (tail->next == dpyinfo)
12588 tail->next = tail->next->next;
12589 }
7a13e894 12590
0d777288
RS
12591#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
12592#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
12593 XrmDestroyDatabase (dpyinfo->xrdb);
12594#endif
0d777288 12595#endif
29b38361
KH
12596#ifdef MULTI_KBOARD
12597 if (--dpyinfo->kboard->reference_count == 0)
39f79001 12598 delete_kboard (dpyinfo->kboard);
b9737ad3
KH
12599#endif
12600 xfree (dpyinfo->font_table);
12601 xfree (dpyinfo->x_id_name);
12602 xfree (dpyinfo);
7a13e894
RS
12603}
12604\f
12605/* Set up use of X before we make the first connection. */
12606
06a2c219
GM
12607static struct redisplay_interface x_redisplay_interface =
12608{
12609 x_produce_glyphs,
12610 x_write_glyphs,
12611 x_insert_glyphs,
12612 x_clear_end_of_line,
12613 x_scroll_run,
12614 x_after_update_window_line,
12615 x_update_window_begin,
12616 x_update_window_end,
12617 XTcursor_to,
12618 x_flush,
12619 x_get_glyph_overhangs
12620};
12621
dfcf069d 12622void
7a13e894
RS
12623x_initialize ()
12624{
06a2c219
GM
12625 rif = &x_redisplay_interface;
12626
12627 clear_frame_hook = x_clear_frame;
12628 ins_del_lines_hook = x_ins_del_lines;
12629 change_line_highlight_hook = x_change_line_highlight;
12630 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
12631 ring_bell_hook = XTring_bell;
12632 reset_terminal_modes_hook = XTreset_terminal_modes;
12633 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
12634 update_begin_hook = x_update_begin;
12635 update_end_hook = x_update_end;
dc6f92b8
JB
12636 set_terminal_window_hook = XTset_terminal_window;
12637 read_socket_hook = XTread_socket;
b8009dd1 12638 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 12639 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 12640 mouse_position_hook = XTmouse_position;
f451eb13 12641 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 12642 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
12643 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
12644 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
12645 redeem_scroll_bar_hook = XTredeem_scroll_bar;
12646 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 12647 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 12648
f676886a 12649 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
12650 char_ins_del_ok = 0; /* just as fast to write the line */
12651 line_ins_del_ok = 1; /* we'll just blt 'em */
12652 fast_clear_end_of_line = 1; /* X does this well */
58769bee 12653 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
12654 off the bottom */
12655 baud_rate = 19200;
12656
7a13e894 12657 x_noop_count = 0;
06a2c219
GM
12658 last_toolbar_item = -1;
12659 any_help_event_p = 0;
12660
b30b24cb
RS
12661 /* Try to use interrupt input; if we can't, then start polling. */
12662 Fset_input_mode (Qt, Qnil, Qt, Qnil);
12663
7f9c7f94
RS
12664#ifdef USE_X_TOOLKIT
12665 XtToolkitInitialize ();
12666 Xt_app_con = XtCreateApplicationContext ();
665881ad 12667 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
7f9c7f94
RS
12668#endif
12669
58769bee 12670 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 12671 original error handler. */
e99db5a1 12672 XSetErrorHandler (x_error_handler);
334208b7 12673 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 12674
06a2c219 12675 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
12676#ifdef SIGWINCH
12677 signal (SIGWINCH, SIG_DFL);
c118dd06 12678#endif /* ! defined (SIGWINCH) */
dc6f92b8 12679
92e2441b 12680 signal (SIGPIPE, x_connection_signal);
dc6f92b8 12681}
55123275 12682
06a2c219 12683
55123275
JB
12684void
12685syms_of_xterm ()
12686{
e99db5a1
RS
12687 staticpro (&x_error_message_string);
12688 x_error_message_string = Qnil;
12689
7a13e894
RS
12690 staticpro (&x_display_name_list);
12691 x_display_name_list = Qnil;
334208b7 12692
ab648270 12693 staticpro (&last_mouse_scroll_bar);
e53cb100 12694 last_mouse_scroll_bar = Qnil;
59e755be
KH
12695
12696 staticpro (&Qvendor_specific_keysyms);
12697 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
12698
12699 staticpro (&last_mouse_press_frame);
12700 last_mouse_press_frame = Qnil;
06a2c219
GM
12701
12702 staticpro (&help_echo);
12703 help_echo = Qnil;
12704 staticpro (&previous_help_echo);
12705 previous_help_echo = Qnil;
12706
12707 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
12708 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
12709For example, if a block cursor is over a tab, it will be drawn as\n\
12710wide as that tab on the display.");
12711 x_stretch_cursor_p = 0;
12712
12713 DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
12714 "If not nil, Emacs uses toolkit scroll bars.");
12715#if USE_TOOLKIT_SCROLL_BARS
12716 x_toolkit_scroll_bars_p = 1;
12717#else
12718 x_toolkit_scroll_bars_p = 0;
12719#endif
12720
12721 defsubr (&Sxt_process_timeouts);
12722 staticpro (&last_mouse_motion_frame);
12723 last_mouse_motion_frame = Qnil;
55123275 12724}
6cf0ae86
RS
12725
12726#endif /* not HAVE_X_WINDOWS */
06a2c219 12727