(with_echo_area_buffer): Call FN with more arguments.
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
1c7e22fd 2 Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000
06a2c219 3 Free Software Foundation, Inc.
dc6f92b8
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4746118a 9the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
dc6f92b8 21
06a2c219 22/* New display code by Gerd Moellmann <gerd@gnu.org>. */
3afe33e7
RS
23/* Xt features made by Fred Pierresteguy. */
24
68c45bf0
PE
25#include <config.h>
26
039440c4 27/* On 4.3 these lose if they come after xterm.h. */
039440c4 28/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
29#include <signal.h>
30
4846819e
RS
31#include <stdio.h>
32
dc6f92b8
JB
33#ifdef HAVE_X_WINDOWS
34
35#include "lisp.h"
9ac0d9e0 36#include "blockinput.h"
dc6f92b8 37
ae79c227
AS
38/* Need syssignal.h for various externs and definitions that may be required
39 by some configurations for calls to signal later in this source file. */
40#include "syssignal.h"
41
dc6f92b8
JB
42/* This may include sys/types.h, and that somehow loses
43 if this is not done before the other system files. */
44#include "xterm.h"
f451eb13 45#include <X11/cursorfont.h>
dc6f92b8
JB
46
47/* Load sys/types.h if not already loaded.
48 In some systems loading it twice is suicidal. */
49#ifndef makedev
50#include <sys/types.h>
c118dd06 51#endif /* makedev */
dc6f92b8 52
6df54671 53#ifdef BSD_SYSTEM
dc6f92b8 54#include <sys/ioctl.h>
6df54671 55#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 56
2d368234 57#include "systty.h"
3a2712f9 58#include "systime.h"
dc6f92b8 59
b8009dd1 60#ifndef INCLUDED_FCNTL
dc6f92b8 61#include <fcntl.h>
b8009dd1 62#endif
dc6f92b8
JB
63#include <ctype.h>
64#include <errno.h>
65#include <setjmp.h>
66#include <sys/stat.h>
a0a7635f
RS
67/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
68/* #include <sys/param.h> */
dc6f92b8 69
dc43ef94
KH
70#include "charset.h"
71#include "ccl.h"
7a13e894 72#include "frame.h"
dc6f92b8 73#include "dispextern.h"
ee569018 74#include "fontset.h"
dc6f92b8
JB
75#include "termhooks.h"
76#include "termopts.h"
77#include "termchar.h"
78#if 0
79#include "sink.h"
80#include "sinkmask.h"
c118dd06 81#endif /* ! 0 */
dc6f92b8 82#include "gnu.h"
dc6f92b8 83#include "disptab.h"
dc6f92b8 84#include "buffer.h"
f451eb13 85#include "window.h"
3b2fa4e6 86#include "keyboard.h"
bde7c500 87#include "intervals.h"
dfcf069d 88#include "process.h"
bffcfca9 89#include "atimer.h"
dc6f92b8 90
d2bd6bc4
RS
91#ifdef USE_X_TOOLKIT
92#include <X11/Shell.h>
93#endif
94
06a2c219
GM
95#ifdef HAVE_SYS_TIME_H
96#include <sys/time.h>
97#endif
98#ifdef HAVE_UNISTD_H
99#include <unistd.h>
100#endif
101
3afe33e7 102#ifdef USE_X_TOOLKIT
06a2c219 103
9d7e2e3e 104extern void free_frame_menubar ();
2224b905 105extern FRAME_PTR x_menubar_window_to_frame ();
06a2c219 106
0fdff6bb
RS
107#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
108#define HACK_EDITRES
109extern void _XEditResCheckMessages ();
110#endif /* not NO_EDITRES */
06a2c219
GM
111
112/* Include toolkit specific headers for the scroll bar widget. */
113
114#ifdef USE_TOOLKIT_SCROLL_BARS
115#if defined USE_MOTIF
116#include <Xm/Xm.h> /* for LESSTIF_VERSION */
117#include <Xm/ScrollBar.h>
118#include <Xm/ScrollBarP.h>
ec18280f
SM
119#else /* !USE_MOTIF i.e. use Xaw */
120
121#ifdef HAVE_XAW3D
06a2c219 122#include <X11/Xaw3d/Simple.h>
06a2c219
GM
123#include <X11/Xaw3d/Scrollbar.h>
124#define ARROW_SCROLLBAR
125#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
126#else /* !HAVE_XAW3D */
127#include <X11/Xaw/Simple.h>
128#include <X11/Xaw/Scrollbar.h>
129#endif /* !HAVE_XAW3D */
130#ifndef XtNpickTop
131#define XtNpickTop "pickTop"
132#endif /* !XtNpickTop */
133#endif /* !USE_MOTIF */
06a2c219
GM
134#endif /* USE_TOOLKIT_SCROLL_BARS */
135
3afe33e7
RS
136#endif /* USE_X_TOOLKIT */
137
b849c413
RS
138#ifndef USE_X_TOOLKIT
139#define x_any_window_to_frame x_window_to_frame
5627c40e 140#define x_top_window_to_frame x_window_to_frame
b849c413
RS
141#endif
142
546e6d5b 143#ifdef USE_X_TOOLKIT
d067ea8b 144#include "widget.h"
546e6d5b
RS
145#ifndef XtNinitialState
146#define XtNinitialState "initialState"
147#endif
148#endif
149
80528801
KH
150#ifdef SOLARIS2
151/* memmove will be defined as a macro in Xfuncs.h unless
152 <string.h> is included beforehand. The declaration for memmove in
153 <string.h> will cause a syntax error when Xfuncs.h later includes it. */
154#include <string.h>
155#endif
156
e4b68333 157#ifndef min
06a2c219 158#define min(a,b) ((a) < (b) ? (a) : (b))
e4b68333
RS
159#endif
160#ifndef max
06a2c219
GM
161#define max(a,b) ((a) > (b) ? (a) : (b))
162#endif
163
164#define abs(x) ((x) < 0 ? -(x) : (x))
165
166#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
167
168\f
169/* Bitmaps for truncated lines. */
170
171enum bitmap_type
172{
173 NO_BITMAP,
174 LEFT_TRUNCATION_BITMAP,
175 RIGHT_TRUNCATION_BITMAP,
176 OVERLAY_ARROW_BITMAP,
177 CONTINUED_LINE_BITMAP,
178 CONTINUATION_LINE_BITMAP,
179 ZV_LINE_BITMAP
180};
181
182/* Bitmap drawn to indicate lines not displaying text if
183 `indicate-empty-lines' is non-nil. */
184
185#define zv_width 8
186#define zv_height 8
187static unsigned char zv_bits[] = {
188 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
189
190/* An arrow like this: `<-'. */
191
192#define left_width 8
193#define left_height 8
194static unsigned char left_bits[] = {
195 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
196
110859fc
GM
197/* Right truncation arrow bitmap `->'. */
198
199#define right_width 8
200#define right_height 8
201static unsigned char right_bits[] = {
202 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
203
06a2c219
GM
204/* Marker for continued lines. */
205
206#define continued_width 8
207#define continued_height 8
208static unsigned char continued_bits[] = {
110859fc
GM
209 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
210
211/* Marker for continuation lines. */
06a2c219
GM
212
213#define continuation_width 8
214#define continuation_height 8
215static unsigned char continuation_bits[] = {
110859fc 216 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 217
110859fc 218/* Overlay arrow bitmap. */
06a2c219 219
110859fc
GM
220#if 0
221/* A bomb. */
06a2c219
GM
222#define ov_width 8
223#define ov_height 8
224static unsigned char ov_bits[] = {
225 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 226#else
110859fc 227/* A triangular arrow. */
06a2c219
GM
228#define ov_width 8
229#define ov_height 8
230static unsigned char ov_bits[] = {
110859fc
GM
231 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
232
e4b68333 233#endif
06a2c219
GM
234
235extern Lisp_Object Qhelp_echo;
236
69388238 237\f
06a2c219
GM
238/* Non-zero means Emacs uses toolkit scroll bars. */
239
240int x_toolkit_scroll_bars_p;
241
242/* If a string, XTread_socket generates an event to display that string.
243 (The display is done in read_char.) */
244
245static Lisp_Object help_echo;
7cea38bc 246static Lisp_Object help_echo_window;
be010514
GM
247static Lisp_Object help_echo_object;
248static int help_echo_pos;
06a2c219
GM
249
250/* Temporary variable for XTread_socket. */
251
252static Lisp_Object previous_help_echo;
253
254/* Non-zero means that a HELP_EVENT has been generated since Emacs
255 start. */
256
257static int any_help_event_p;
258
259/* Non-zero means draw block and hollow cursor as wide as the glyph
260 under it. For example, if a block cursor is over a tab, it will be
261 drawn as wide as that tab on the display. */
262
263int x_stretch_cursor_p;
264
265/* This is a chain of structures for all the X displays currently in
266 use. */
267
334208b7 268struct x_display_info *x_display_list;
dc6f92b8 269
06a2c219
GM
270/* This is a list of cons cells, each of the form (NAME
271 . FONT-LIST-CACHE), one for each element of x_display_list and in
272 the same order. NAME is the name of the frame. FONT-LIST-CACHE
273 records previous values returned by x-list-fonts. */
274
7a13e894 275Lisp_Object x_display_name_list;
f451eb13 276
987d2ad1 277/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
278 This is set by update_begin and looked at by all the XT functions.
279 It is zero while not inside an update. In that case, the XT
280 functions assume that `selected_frame' is the frame to apply to. */
281
d0386f2a 282extern struct frame *updating_frame;
dc6f92b8 283
dfcf069d 284extern int waiting_for_input;
0e81d8cd 285
06a2c219
GM
286/* This is a frame waiting to be auto-raised, within XTread_socket. */
287
0134a210
RS
288struct frame *pending_autoraise_frame;
289
7f9c7f94
RS
290#ifdef USE_X_TOOLKIT
291/* The application context for Xt use. */
292XtAppContext Xt_app_con;
06a2c219
GM
293static String Xt_default_resources[] = {0};
294#endif /* USE_X_TOOLKIT */
665881ad 295
06a2c219
GM
296/* Nominal cursor position -- where to draw output.
297 HPOS and VPOS are window relative glyph matrix coordinates.
298 X and Y are window relative pixel coordinates. */
dc6f92b8 299
06a2c219 300struct cursor_pos output_cursor;
dc6f92b8 301
bffcfca9
GM
302/* Non-zero means user is interacting with a toolkit scroll bar. */
303
304static int toolkit_scroll_bar_interaction;
dc6f92b8 305
69388238
RS
306/* Mouse movement.
307
06a2c219 308 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
309 so that we would have to call XQueryPointer after each MotionNotify
310 event to ask for another such event. However, this made mouse tracking
311 slow, and there was a bug that made it eventually stop.
312
313 Simply asking for MotionNotify all the time seems to work better.
314
69388238
RS
315 In order to avoid asking for motion events and then throwing most
316 of them away or busy-polling the server for mouse positions, we ask
317 the server for pointer motion hints. This means that we get only
318 one event per group of mouse movements. "Groups" are delimited by
319 other kinds of events (focus changes and button clicks, for
320 example), or by XQueryPointer calls; when one of these happens, we
321 get another MotionNotify event the next time the mouse moves. This
322 is at least as efficient as getting motion events when mouse
323 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 324 is off. */
69388238
RS
325
326/* Where the mouse was last time we reported a mouse event. */
69388238 327
06a2c219
GM
328FRAME_PTR last_mouse_frame;
329static XRectangle last_mouse_glyph;
2237cac9
RS
330static Lisp_Object last_mouse_press_frame;
331
69388238
RS
332/* The scroll bar in which the last X motion event occurred.
333
06a2c219
GM
334 If the last X motion event occurred in a scroll bar, we set this so
335 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
336 an ordinary motion.
337
06a2c219
GM
338 If the last X motion event didn't occur in a scroll bar, we set
339 this to Qnil, to tell XTmouse_position to return an ordinary motion
340 event. */
341
69388238
RS
342static Lisp_Object last_mouse_scroll_bar;
343
69388238
RS
344/* This is a hack. We would really prefer that XTmouse_position would
345 return the time associated with the position it returns, but there
06a2c219 346 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
347 along with the position query. So, we just keep track of the time
348 of the last movement we received, and return that in hopes that
349 it's somewhat accurate. */
06a2c219 350
69388238
RS
351static Time last_mouse_movement_time;
352
06a2c219
GM
353/* Incremented by XTread_socket whenever it really tries to read
354 events. */
355
c0a04927
RS
356#ifdef __STDC__
357static int volatile input_signal_count;
358#else
359static int input_signal_count;
360#endif
361
7a13e894 362/* Used locally within XTread_socket. */
06a2c219 363
7a13e894 364static int x_noop_count;
dc6f92b8 365
7a13e894 366/* Initial values of argv and argc. */
06a2c219 367
7a13e894
RS
368extern char **initial_argv;
369extern int initial_argc;
dc6f92b8 370
7a13e894 371extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 372
06a2c219 373/* Tells if a window manager is present or not. */
7a13e894
RS
374
375extern Lisp_Object Vx_no_window_manager;
dc6f92b8 376
c2df547c 377extern Lisp_Object Qface, Qmouse_face;
b8009dd1 378
dc6f92b8
JB
379extern int errno;
380
dfeccd2d 381/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 382
64bb1782
RS
383extern int extra_keyboard_modifiers;
384
59e755be
KH
385static Lisp_Object Qvendor_specific_keysyms;
386
334208b7 387extern XrmDatabase x_load_resources ();
c32cdd9a
KH
388extern Lisp_Object x_icon_type ();
389
7a13e894 390
06a2c219
GM
391/* Enumeration for overriding/changing the face to use for drawing
392 glyphs in x_draw_glyphs. */
393
394enum draw_glyphs_face
395{
396 DRAW_NORMAL_TEXT,
397 DRAW_INVERSE_VIDEO,
398 DRAW_CURSOR,
399 DRAW_MOUSE_FACE,
400 DRAW_IMAGE_RAISED,
401 DRAW_IMAGE_SUNKEN
402};
403
71b8321e 404static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
405static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
406void x_delete_display P_ ((struct x_display_info *));
407static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
408 unsigned));
409static int fast_find_position P_ ((struct window *, int, int *, int *,
410 int *, int *));
411static void set_output_cursor P_ ((struct cursor_pos *));
412static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
413 int *, int *, int *));
414static void note_mode_line_highlight P_ ((struct window *, int, int));
06a2c219 415static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
416static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
417static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
418static void show_mouse_face P_ ((struct x_display_info *,
419 enum draw_glyphs_face));
420static int x_io_error_quitter P_ ((Display *));
421int x_catch_errors P_ ((Display *));
422void x_uncatch_errors P_ ((Display *, int));
423void x_lower_frame P_ ((struct frame *));
424void x_scroll_bar_clear P_ ((struct frame *));
425int x_had_errors_p P_ ((Display *));
426void x_wm_set_size_hint P_ ((struct frame *, long, int));
427void x_raise_frame P_ ((struct frame *));
428void x_set_window_size P_ ((struct frame *, int, int, int));
429void x_wm_set_window_state P_ ((struct frame *, int));
430void x_wm_set_icon_pixmap P_ ((struct frame *, int));
431void x_initialize P_ ((void));
432static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
433static int x_compute_min_glyph_bounds P_ ((struct frame *));
434static void x_draw_phys_cursor_glyph P_ ((struct window *,
435 struct glyph_row *,
436 enum draw_glyphs_face));
437static void x_update_end P_ ((struct frame *));
438static void XTframe_up_to_date P_ ((struct frame *));
439static void XTreassert_line_highlight P_ ((int, int));
440static void x_change_line_highlight P_ ((int, int, int, int));
441static void XTset_terminal_modes P_ ((void));
442static void XTreset_terminal_modes P_ ((void));
443static void XTcursor_to P_ ((int, int, int, int));
444static void x_write_glyphs P_ ((struct glyph *, int));
445static void x_clear_end_of_line P_ ((int));
446static void x_clear_frame P_ ((void));
447static void x_clear_cursor P_ ((struct window *));
448static void frame_highlight P_ ((struct frame *));
449static void frame_unhighlight P_ ((struct frame *));
450static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
451static void XTframe_rehighlight P_ ((struct frame *));
452static void x_frame_rehighlight P_ ((struct x_display_info *));
453static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 454static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
455static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
456 XRectangle *));
457static void expose_frame P_ ((struct frame *, int, int, int, int));
458static void expose_window_tree P_ ((struct window *, XRectangle *));
459static void expose_window P_ ((struct window *, XRectangle *));
460static void expose_area P_ ((struct window *, struct glyph_row *,
461 XRectangle *, enum glyph_row_area));
462static void expose_line P_ ((struct window *, struct glyph_row *,
463 XRectangle *));
464static void x_update_cursor_in_window_tree P_ ((struct window *, int));
465static void x_update_window_cursor P_ ((struct window *, int));
466static void x_erase_phys_cursor P_ ((struct window *));
467void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
468static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
469 enum bitmap_type));
470
471static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
472 GC, int));
473static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
474static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
475static void note_overwritten_text_cursor P_ ((struct window *, int, int));
476static void x_flush P_ ((struct frame *f));
477
478
479/* Flush display of frame F, or of all frames if F is null. */
480
481static void
482x_flush (f)
483 struct frame *f;
484{
485 BLOCK_INPUT;
486 if (f == NULL)
487 {
488 Lisp_Object rest, frame;
489 FOR_EACH_FRAME (rest, frame)
490 x_flush (XFRAME (frame));
491 }
492 else if (FRAME_X_P (f))
493 XFlush (FRAME_X_DISPLAY (f));
494 UNBLOCK_INPUT;
495}
496
dc6f92b8 497
06a2c219
GM
498/* Remove calls to XFlush by defining XFlush to an empty replacement.
499 Calls to XFlush should be unnecessary because the X output buffer
500 is flushed automatically as needed by calls to XPending,
501 XNextEvent, or XWindowEvent according to the XFlush man page.
502 XTread_socket calls XPending. Removing XFlush improves
503 performance. */
504
505#define XFlush(DISPLAY) (void) 0
b8009dd1 506
334208b7 507\f
06a2c219
GM
508/***********************************************************************
509 Debugging
510 ***********************************************************************/
511
9382638d 512#if 0
06a2c219
GM
513
514/* This is a function useful for recording debugging information about
515 the sequence of occurrences in this file. */
9382638d
KH
516
517struct record
518{
519 char *locus;
520 int type;
521};
522
523struct record event_record[100];
524
525int event_record_index;
526
527record_event (locus, type)
528 char *locus;
529 int type;
530{
531 if (event_record_index == sizeof (event_record) / sizeof (struct record))
532 event_record_index = 0;
533
534 event_record[event_record_index].locus = locus;
535 event_record[event_record_index].type = type;
536 event_record_index++;
537}
538
539#endif /* 0 */
06a2c219
GM
540
541
9382638d 542\f
334208b7
RS
543/* Return the struct x_display_info corresponding to DPY. */
544
545struct x_display_info *
546x_display_info_for_display (dpy)
547 Display *dpy;
548{
549 struct x_display_info *dpyinfo;
550
551 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
552 if (dpyinfo->display == dpy)
553 return dpyinfo;
16bd92ea 554
334208b7
RS
555 return 0;
556}
f451eb13 557
06a2c219
GM
558
559\f
560/***********************************************************************
561 Starting and ending an update
562 ***********************************************************************/
563
564/* Start an update of frame F. This function is installed as a hook
565 for update_begin, i.e. it is called when update_begin is called.
566 This function is called prior to calls to x_update_window_begin for
567 each window being updated. Currently, there is nothing to do here
568 because all interesting stuff is done on a window basis. */
dc6f92b8 569
dfcf069d 570static void
06a2c219 571x_update_begin (f)
f676886a 572 struct frame *f;
58769bee 573{
06a2c219
GM
574 /* Nothing to do. */
575}
dc6f92b8 576
dc6f92b8 577
06a2c219
GM
578/* Start update of window W. Set the global variable updated_window
579 to the window being updated and set output_cursor to the cursor
580 position of W. */
dc6f92b8 581
06a2c219
GM
582static void
583x_update_window_begin (w)
584 struct window *w;
585{
586 struct frame *f = XFRAME (WINDOW_FRAME (w));
587 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
588
589 updated_window = w;
590 set_output_cursor (&w->cursor);
b8009dd1 591
06a2c219 592 BLOCK_INPUT;
d1bc4182 593
06a2c219 594 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 595 {
514e4681 596 /* Don't do highlighting for mouse motion during the update. */
06a2c219 597 display_info->mouse_face_defer = 1;
37c2c98b 598
06a2c219
GM
599 /* If F needs to be redrawn, simply forget about any prior mouse
600 highlighting. */
9f67f20b 601 if (FRAME_GARBAGED_P (f))
06a2c219
GM
602 display_info->mouse_face_window = Qnil;
603
64f26cf5
GM
604#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
605 their mouse_face_p flag set, which means that they are always
606 unequal to rows in a desired matrix which never have that
607 flag set. So, rows containing mouse-face glyphs are never
608 scrolled, and we don't have to switch the mouse highlight off
609 here to prevent it from being scrolled. */
610
06a2c219
GM
611 /* Can we tell that this update does not affect the window
612 where the mouse highlight is? If so, no need to turn off.
613 Likewise, don't do anything if the frame is garbaged;
614 in that case, the frame's current matrix that we would use
615 is all wrong, and we will redisplay that line anyway. */
616 if (!NILP (display_info->mouse_face_window)
617 && w == XWINDOW (display_info->mouse_face_window))
514e4681 618 {
06a2c219 619 int i;
514e4681 620
06a2c219
GM
621 for (i = 0; i < w->desired_matrix->nrows; ++i)
622 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
623 break;
624
06a2c219
GM
625 if (i < w->desired_matrix->nrows)
626 clear_mouse_face (display_info);
514e4681 627 }
64f26cf5 628#endif /* 0 */
b8009dd1 629 }
6ccf47d1 630
dc6f92b8
JB
631 UNBLOCK_INPUT;
632}
633
06a2c219
GM
634
635/* Draw a vertical window border to the right of window W if W doesn't
636 have vertical scroll bars. */
637
dfcf069d 638static void
06a2c219
GM
639x_draw_vertical_border (w)
640 struct window *w;
58769bee 641{
06a2c219
GM
642 struct frame *f = XFRAME (WINDOW_FRAME (w));
643
644 /* Redraw borders between horizontally adjacent windows. Don't
645 do it for frames with vertical scroll bars because either the
646 right scroll bar of a window, or the left scroll bar of its
647 neighbor will suffice as a border. */
648 if (!WINDOW_RIGHTMOST_P (w)
649 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
650 {
651 int x0, x1, y0, y1;
dc6f92b8 652
06a2c219 653 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 654 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
655 y1 -= 1;
656
657 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
658 f->output_data.x->normal_gc, x1, y0, x1, y1);
659 }
660}
661
662
71b8321e
GM
663/* End update of window W (which is equal to updated_window).
664
665 Draw vertical borders between horizontally adjacent windows, and
666 display W's cursor if CURSOR_ON_P is non-zero.
667
668 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
669 glyphs in mouse-face were overwritten. In that case we have to
670 make sure that the mouse-highlight is properly redrawn.
671
672 W may be a menu bar pseudo-window in case we don't have X toolkit
673 support. Such windows don't have a cursor, so don't display it
674 here. */
06a2c219
GM
675
676static void
71b8321e 677x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 678 struct window *w;
71b8321e 679 int cursor_on_p, mouse_face_overwritten_p;
06a2c219
GM
680{
681 if (!w->pseudo_window_p)
682 {
71b8321e
GM
683 struct x_display_info *dpyinfo
684 = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
685
06a2c219 686 BLOCK_INPUT;
71b8321e
GM
687
688 /* If a row with mouse-face was overwritten, arrange for
689 XTframe_up_to_date to redisplay the mouse highlight. */
690 if (mouse_face_overwritten_p)
691 {
692 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
693 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
694 dpyinfo->mouse_face_window = Qnil;
695 }
696
06a2c219
GM
697 if (cursor_on_p)
698 x_display_and_set_cursor (w, 1, output_cursor.hpos,
699 output_cursor.vpos,
700 output_cursor.x, output_cursor.y);
71b8321e 701
06a2c219
GM
702 x_draw_vertical_border (w);
703 UNBLOCK_INPUT;
704 }
705
706 updated_window = NULL;
707}
dc6f92b8 708
dc6f92b8 709
06a2c219
GM
710/* End update of frame F. This function is installed as a hook in
711 update_end. */
712
713static void
714x_update_end (f)
715 struct frame *f;
716{
717 /* Mouse highlight may be displayed again. */
aa8bff2e 718 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 719
06a2c219 720 BLOCK_INPUT;
334208b7 721 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
722 UNBLOCK_INPUT;
723}
b8009dd1 724
06a2c219
GM
725
726/* This function is called from various places in xdisp.c whenever a
727 complete update has been performed. The global variable
728 updated_window is not available here. */
b8009dd1 729
dfcf069d 730static void
b8009dd1 731XTframe_up_to_date (f)
06a2c219 732 struct frame *f;
b8009dd1 733{
06a2c219 734 if (FRAME_X_P (f))
514e4681 735 {
06a2c219 736 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 737
06a2c219
GM
738 if (dpyinfo->mouse_face_deferred_gc
739 || f == dpyinfo->mouse_face_mouse_frame)
740 {
741 BLOCK_INPUT;
742 if (dpyinfo->mouse_face_mouse_frame)
743 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
744 dpyinfo->mouse_face_mouse_x,
745 dpyinfo->mouse_face_mouse_y);
746 dpyinfo->mouse_face_deferred_gc = 0;
747 UNBLOCK_INPUT;
748 }
514e4681 749 }
b8009dd1 750}
06a2c219
GM
751
752
753/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
754 arrow bitmaps, or clear the areas where they would be displayed
755 before DESIRED_ROW is made current. The window being updated is
756 found in updated_window. This function It is called from
757 update_window_line only if it is known that there are differences
758 between bitmaps to be drawn between current row and DESIRED_ROW. */
759
760static void
761x_after_update_window_line (desired_row)
762 struct glyph_row *desired_row;
763{
764 struct window *w = updated_window;
765
766 xassert (w);
767
768 if (!desired_row->mode_line_p && !w->pseudo_window_p)
769 {
770 BLOCK_INPUT;
771 x_draw_row_bitmaps (w, desired_row);
772
773 /* When a window has disappeared, make sure that no rest of
774 full-width rows stays visible in the internal border. */
775 if (windows_or_buffers_changed)
776 {
777 struct frame *f = XFRAME (w->frame);
778 int width = FRAME_INTERNAL_BORDER_WIDTH (f);
779 int height = desired_row->visible_height;
110859fc
GM
780 int x = (window_box_right (w, -1)
781 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
782 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
783
784 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
785 x, y, width, height, False);
786 }
787
788 UNBLOCK_INPUT;
789 }
790}
791
792
793/* Draw the bitmap WHICH in one of the areas to the left or right of
794 window W. ROW is the glyph row for which to display the bitmap; it
795 determines the vertical position at which the bitmap has to be
796 drawn. */
797
798static void
799x_draw_bitmap (w, row, which)
800 struct window *w;
801 struct glyph_row *row;
802 enum bitmap_type which;
803{
804 struct frame *f = XFRAME (WINDOW_FRAME (w));
805 Display *display = FRAME_X_DISPLAY (f);
806 Window window = FRAME_X_WINDOW (f);
807 int x, y, wd, h, dy;
808 unsigned char *bits;
809 Pixmap pixmap;
810 GC gc = f->output_data.x->normal_gc;
811 struct face *face;
812 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
813
814 /* Must clip because of partially visible lines. */
815 x_clip_to_row (w, row, gc, 1);
816
817 switch (which)
818 {
819 case LEFT_TRUNCATION_BITMAP:
820 wd = left_width;
821 h = left_height;
822 bits = left_bits;
823 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
824 - wd
110859fc 825 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
826 break;
827
828 case OVERLAY_ARROW_BITMAP:
829 wd = left_width;
830 h = left_height;
831 bits = ov_bits;
832 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
833 - wd
110859fc 834 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
835 break;
836
837 case RIGHT_TRUNCATION_BITMAP:
838 wd = right_width;
839 h = right_height;
840 bits = right_bits;
841 x = window_box_right (w, -1);
110859fc 842 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
843 break;
844
845 case CONTINUED_LINE_BITMAP:
846 wd = right_width;
847 h = right_height;
848 bits = continued_bits;
849 x = window_box_right (w, -1);
110859fc 850 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
851 break;
852
853 case CONTINUATION_LINE_BITMAP:
854 wd = continuation_width;
855 h = continuation_height;
856 bits = continuation_bits;
857 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
858 - wd
110859fc 859 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
860 break;
861
862 case ZV_LINE_BITMAP:
863 wd = zv_width;
864 h = zv_height;
865 bits = zv_bits;
866 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
867 - wd
110859fc 868 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
869 break;
870
871 default:
872 abort ();
873 }
874
875 /* Convert to frame coordinates. Set dy to the offset in the row to
876 start drawing the bitmap. */
877 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
878 dy = (row->height - h) / 2;
879
880 /* Draw the bitmap. I believe these small pixmaps can be cached
881 by the server. */
882 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
883 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
884 face->foreground,
885 face->background, depth);
886 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
887 XFreePixmap (display, pixmap);
888 XSetClipMask (display, gc, None);
889}
890
891
892/* Draw flags bitmaps for glyph row ROW on window W. Call this
893 function with input blocked. */
894
895static void
896x_draw_row_bitmaps (w, row)
897 struct window *w;
898 struct glyph_row *row;
899{
900 struct frame *f = XFRAME (w->frame);
901 enum bitmap_type bitmap;
902 struct face *face;
045dee35 903 int header_line_height = -1;
06a2c219
GM
904
905 xassert (interrupt_input_blocked);
906
907 /* If row is completely invisible, because of vscrolling, we
908 don't have to draw anything. */
909 if (row->visible_height <= 0)
910 return;
911
912 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
913 PREPARE_FACE_FOR_DISPLAY (f, face);
914
915 /* Decide which bitmap to draw at the left side. */
916 if (row->overlay_arrow_p)
917 bitmap = OVERLAY_ARROW_BITMAP;
918 else if (row->truncated_on_left_p)
919 bitmap = LEFT_TRUNCATION_BITMAP;
920 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
921 bitmap = CONTINUATION_LINE_BITMAP;
922 else if (row->indicate_empty_line_p)
923 bitmap = ZV_LINE_BITMAP;
924 else
925 bitmap = NO_BITMAP;
926
927 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
928 the flags area. */
929 if (bitmap == NO_BITMAP
110859fc 930 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
931 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
932 {
933 /* If W has a vertical border to its left, don't draw over it. */
934 int border = ((XFASTINT (w->left) > 0
935 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
936 ? 1 : 0);
937 int left = window_box_left (w, -1);
938
045dee35
GM
939 if (header_line_height < 0)
940 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
941
942 /* In case the same realized face is used for bitmap areas and
943 for something displayed in the text (e.g. face `region' on
944 mono-displays, the fill style may have been changed to
945 FillSolid in x_draw_glyph_string_background. */
946 if (face->stipple)
947 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
948 else
949 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
950
06a2c219
GM
951 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
952 face->gc,
953 (left
110859fc 954 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 955 + border),
045dee35 956 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 957 row->y)),
110859fc 958 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 959 row->visible_height);
dcd08bfb
GM
960 if (!face->stipple)
961 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
962 }
963
964 /* Draw the left bitmap. */
965 if (bitmap != NO_BITMAP)
966 x_draw_bitmap (w, row, bitmap);
967
968 /* Decide which bitmap to draw at the right side. */
969 if (row->truncated_on_right_p)
970 bitmap = RIGHT_TRUNCATION_BITMAP;
971 else if (row->continued_p)
972 bitmap = CONTINUED_LINE_BITMAP;
973 else
974 bitmap = NO_BITMAP;
975
976 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
977 the flags area. */
978 if (bitmap == NO_BITMAP
110859fc 979 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
980 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
981 {
982 int right = window_box_right (w, -1);
983
045dee35
GM
984 if (header_line_height < 0)
985 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
986
987 /* In case the same realized face is used for bitmap areas and
988 for something displayed in the text (e.g. face `region' on
989 mono-displays, the fill style may have been changed to
990 FillSolid in x_draw_glyph_string_background. */
991 if (face->stipple)
992 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
993 else
994 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
995 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
996 face->gc,
997 right,
045dee35 998 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 999 row->y)),
110859fc 1000 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 1001 row->visible_height);
dcd08bfb
GM
1002 if (!face->stipple)
1003 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
1004 }
1005
1006 /* Draw the right bitmap. */
1007 if (bitmap != NO_BITMAP)
1008 x_draw_bitmap (w, row, bitmap);
1009}
1010
dc6f92b8 1011\f
06a2c219
GM
1012/***********************************************************************
1013 Line Highlighting
1014 ***********************************************************************/
dc6f92b8 1015
06a2c219
GM
1016/* External interface to control of standout mode. Not used for X
1017 frames. Aborts when called. */
1018
1019static void
dc6f92b8
JB
1020XTreassert_line_highlight (new, vpos)
1021 int new, vpos;
1022{
06a2c219 1023 abort ();
dc6f92b8
JB
1024}
1025
06a2c219
GM
1026
1027/* Call this when about to modify line at position VPOS and change
1028 whether it is highlighted. Not used for X frames. Aborts when
1029 called. */
dc6f92b8 1030
dfcf069d 1031static void
06a2c219
GM
1032x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1033 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1034{
06a2c219 1035 abort ();
dc6f92b8
JB
1036}
1037
06a2c219
GM
1038
1039/* This is called when starting Emacs and when restarting after
1040 suspend. When starting Emacs, no X window is mapped. And nothing
1041 must be done to Emacs's own window if it is suspended (though that
1042 rarely happens). */
dc6f92b8 1043
dfcf069d 1044static void
dc6f92b8
JB
1045XTset_terminal_modes ()
1046{
1047}
1048
06a2c219
GM
1049/* This is called when exiting or suspending Emacs. Exiting will make
1050 the X-windows go away, and suspending requires no action. */
dc6f92b8 1051
dfcf069d 1052static void
dc6f92b8
JB
1053XTreset_terminal_modes ()
1054{
dc6f92b8 1055}
06a2c219
GM
1056
1057
dc6f92b8 1058\f
06a2c219
GM
1059/***********************************************************************
1060 Output Cursor
1061 ***********************************************************************/
1062
1063/* Set the global variable output_cursor to CURSOR. All cursor
1064 positions are relative to updated_window. */
dc6f92b8 1065
dfcf069d 1066static void
06a2c219
GM
1067set_output_cursor (cursor)
1068 struct cursor_pos *cursor;
dc6f92b8 1069{
06a2c219
GM
1070 output_cursor.hpos = cursor->hpos;
1071 output_cursor.vpos = cursor->vpos;
1072 output_cursor.x = cursor->x;
1073 output_cursor.y = cursor->y;
1074}
1075
1076
1077/* Set a nominal cursor position.
dc6f92b8 1078
06a2c219
GM
1079 HPOS and VPOS are column/row positions in a window glyph matrix. X
1080 and Y are window text area relative pixel positions.
1081
1082 If this is done during an update, updated_window will contain the
1083 window that is being updated and the position is the future output
1084 cursor position for that window. If updated_window is null, use
1085 selected_window and display the cursor at the given position. */
1086
1087static void
1088XTcursor_to (vpos, hpos, y, x)
1089 int vpos, hpos, y, x;
1090{
1091 struct window *w;
1092
1093 /* If updated_window is not set, work on selected_window. */
1094 if (updated_window)
1095 w = updated_window;
1096 else
1097 w = XWINDOW (selected_window);
dbcb258a 1098
06a2c219
GM
1099 /* Set the output cursor. */
1100 output_cursor.hpos = hpos;
1101 output_cursor.vpos = vpos;
1102 output_cursor.x = x;
1103 output_cursor.y = y;
dc6f92b8 1104
06a2c219
GM
1105 /* If not called as part of an update, really display the cursor.
1106 This will also set the cursor position of W. */
1107 if (updated_window == NULL)
dc6f92b8
JB
1108 {
1109 BLOCK_INPUT;
06a2c219 1110 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1111 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1112 UNBLOCK_INPUT;
1113 }
1114}
dc43ef94 1115
06a2c219
GM
1116
1117\f
1118/***********************************************************************
1119 Display Iterator
1120 ***********************************************************************/
1121
1122/* Function prototypes of this page. */
1123
1124static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1125 struct glyph *,
ee569018
KH
1126 XChar2b *,
1127 int *));
06a2c219
GM
1128static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1129 int, XChar2b *, int));
1130static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1131static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1132static void x_append_glyph P_ ((struct it *));
b4192550 1133static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1134static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1135 int, int, double));
1136static void x_produce_glyphs P_ ((struct it *));
06a2c219 1137static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1138
1139
1140/* Return a pointer to per-char metric information in FONT of a
1141 character pointed by B which is a pointer to an XChar2b. */
1142
1143#define PER_CHAR_METRIC(font, b) \
1144 ((font)->per_char \
1145 ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
1146 + (((font)->min_byte1 || (font)->max_byte1) \
1147 ? (((b)->byte1 - (font)->min_byte1) \
1148 * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
1149 : 0)) \
1150 : &((font)->max_bounds))
dc43ef94 1151
dc6f92b8 1152
e2ef8ee6
GM
1153/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1154 is not contained in the font. */
dc43ef94 1155
06a2c219 1156static INLINE XCharStruct *
ee569018 1157x_per_char_metric (font, char2b)
06a2c219
GM
1158 XFontStruct *font;
1159 XChar2b *char2b;
1160{
1161 /* The result metric information. */
1162 XCharStruct *pcm = NULL;
dc6f92b8 1163
06a2c219 1164 xassert (font && char2b);
dc6f92b8 1165
06a2c219 1166 if (font->per_char != NULL)
dc6f92b8 1167 {
06a2c219 1168 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1169 {
06a2c219
GM
1170 /* min_char_or_byte2 specifies the linear character index
1171 corresponding to the first element of the per_char array,
1172 max_char_or_byte2 is the index of the last character. A
1173 character with non-zero CHAR2B->byte1 is not in the font.
1174 A character with byte2 less than min_char_or_byte2 or
1175 greater max_char_or_byte2 is not in the font. */
1176 if (char2b->byte1 == 0
1177 && char2b->byte2 >= font->min_char_or_byte2
1178 && char2b->byte2 <= font->max_char_or_byte2)
1179 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1180 }
06a2c219 1181 else
dc6f92b8 1182 {
06a2c219
GM
1183 /* If either min_byte1 or max_byte1 are nonzero, both
1184 min_char_or_byte2 and max_char_or_byte2 are less than
1185 256, and the 2-byte character index values corresponding
1186 to the per_char array element N (counting from 0) are:
1187
1188 byte1 = N/D + min_byte1
1189 byte2 = N\D + min_char_or_byte2
1190
1191 where:
1192
1193 D = max_char_or_byte2 - min_char_or_byte2 + 1
1194 / = integer division
1195 \ = integer modulus */
1196 if (char2b->byte1 >= font->min_byte1
1197 && char2b->byte1 <= font->max_byte1
1198 && char2b->byte2 >= font->min_char_or_byte2
1199 && char2b->byte2 <= font->max_char_or_byte2)
1200 {
1201 pcm = (font->per_char
1202 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1203 * (char2b->byte1 - font->min_byte1))
1204 + (char2b->byte2 - font->min_char_or_byte2));
1205 }
dc6f92b8 1206 }
06a2c219
GM
1207 }
1208 else
1209 {
1210 /* If the per_char pointer is null, all glyphs between the first
1211 and last character indexes inclusive have the same
1212 information, as given by both min_bounds and max_bounds. */
1213 if (char2b->byte2 >= font->min_char_or_byte2
1214 && char2b->byte2 <= font->max_char_or_byte2)
1215 pcm = &font->max_bounds;
1216 }
dc6f92b8 1217
ee569018 1218 return ((pcm == NULL
3e71d8f2 1219 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1220 ? NULL : pcm);
06a2c219 1221}
b73b6aaf 1222
57b03282 1223
06a2c219
GM
1224/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1225 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1226
06a2c219
GM
1227static INLINE void
1228x_encode_char (c, char2b, font_info)
1229 int c;
1230 XChar2b *char2b;
1231 struct font_info *font_info;
1232{
1233 int charset = CHAR_CHARSET (c);
1234 XFontStruct *font = font_info->font;
1235
1236 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1237 This may be either a program in a special encoder language or a
1238 fixed encoding. */
1239 if (font_info->font_encoder)
1240 {
1241 /* It's a program. */
1242 struct ccl_program *ccl = font_info->font_encoder;
1243
1244 if (CHARSET_DIMENSION (charset) == 1)
1245 {
1246 ccl->reg[0] = charset;
1247 ccl->reg[1] = char2b->byte2;
1248 }
1249 else
1250 {
1251 ccl->reg[0] = charset;
1252 ccl->reg[1] = char2b->byte1;
1253 ccl->reg[2] = char2b->byte2;
1254 }
1255
1256 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1257
1258 /* We assume that MSBs are appropriately set/reset by CCL
1259 program. */
1260 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1261 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1262 else
1263 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1264 }
1265 else if (font_info->encoding[charset])
1266 {
1267 /* Fixed encoding scheme. See fontset.h for the meaning of the
1268 encoding numbers. */
1269 int enc = font_info->encoding[charset];
1270
1271 if ((enc == 1 || enc == 2)
1272 && CHARSET_DIMENSION (charset) == 2)
1273 char2b->byte1 |= 0x80;
1274
1275 if (enc == 1 || enc == 3)
1276 char2b->byte2 |= 0x80;
1277 }
1278}
1279
1280
1281/* Get face and two-byte form of character C in face FACE_ID on frame
1282 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1283 means we want to display multibyte text. Value is a pointer to a
1284 realized face that is ready for display. */
1285
1286static INLINE struct face *
1287x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1288 struct frame *f;
1289 int c, face_id;
1290 XChar2b *char2b;
1291 int multibyte_p;
1292{
1293 struct face *face = FACE_FROM_ID (f, face_id);
1294
1295 if (!multibyte_p)
1296 {
1297 /* Unibyte case. We don't have to encode, but we have to make
1298 sure to use a face suitable for unibyte. */
1299 char2b->byte1 = 0;
1300 char2b->byte2 = c;
ee569018
KH
1301 face_id = FACE_FOR_CHAR (f, face, c);
1302 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1303 }
1304 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1305 {
1306 /* Case of ASCII in a face known to fit ASCII. */
1307 char2b->byte1 = 0;
1308 char2b->byte2 = c;
1309 }
1310 else
1311 {
1312 int c1, c2, charset;
1313
1314 /* Split characters into bytes. If c2 is -1 afterwards, C is
1315 really a one-byte character so that byte1 is zero. */
1316 SPLIT_CHAR (c, charset, c1, c2);
1317 if (c2 > 0)
1318 char2b->byte1 = c1, char2b->byte2 = c2;
1319 else
1320 char2b->byte1 = 0, char2b->byte2 = c1;
1321
06a2c219 1322 /* Maybe encode the character in *CHAR2B. */
ee569018 1323 if (face->font != NULL)
06a2c219
GM
1324 {
1325 struct font_info *font_info
1326 = FONT_INFO_FROM_ID (f, face->font_info_id);
1327 if (font_info)
ee569018 1328 x_encode_char (c, char2b, font_info);
06a2c219
GM
1329 }
1330 }
1331
1332 /* Make sure X resources of the face are allocated. */
1333 xassert (face != NULL);
1334 PREPARE_FACE_FOR_DISPLAY (f, face);
1335
1336 return face;
1337}
1338
1339
1340/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1341 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1342 a pointer to a realized face that is ready for display. */
1343
1344static INLINE struct face *
ee569018 1345x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1346 struct frame *f;
1347 struct glyph *glyph;
1348 XChar2b *char2b;
ee569018 1349 int *two_byte_p;
06a2c219
GM
1350{
1351 struct face *face;
1352
1353 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1354 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1355
ee569018
KH
1356 if (two_byte_p)
1357 *two_byte_p = 0;
1358
06a2c219
GM
1359 if (!glyph->multibyte_p)
1360 {
1361 /* Unibyte case. We don't have to encode, but we have to make
1362 sure to use a face suitable for unibyte. */
1363 char2b->byte1 = 0;
43d120d8 1364 char2b->byte2 = glyph->u.ch;
06a2c219 1365 }
43d120d8
KH
1366 else if (glyph->u.ch < 128
1367 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1368 {
1369 /* Case of ASCII in a face known to fit ASCII. */
1370 char2b->byte1 = 0;
43d120d8 1371 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1372 }
1373 else
1374 {
1375 int c1, c2, charset;
1376
1377 /* Split characters into bytes. If c2 is -1 afterwards, C is
1378 really a one-byte character so that byte1 is zero. */
43d120d8 1379 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1380 if (c2 > 0)
1381 char2b->byte1 = c1, char2b->byte2 = c2;
1382 else
1383 char2b->byte1 = 0, char2b->byte2 = c1;
1384
1385 /* Maybe encode the character in *CHAR2B. */
1386 if (charset != CHARSET_ASCII)
1387 {
1388 struct font_info *font_info
1389 = FONT_INFO_FROM_ID (f, face->font_info_id);
1390 if (font_info)
1391 {
43d120d8 1392 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1393 if (two_byte_p)
1394 *two_byte_p
1395 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1396 }
1397 }
1398 }
1399
1400 /* Make sure X resources of the face are allocated. */
1401 xassert (face != NULL);
1402 PREPARE_FACE_FOR_DISPLAY (f, face);
1403 return face;
1404}
1405
1406
1407/* Store one glyph for IT->char_to_display in IT->glyph_row.
1408 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1409
1410static INLINE void
1411x_append_glyph (it)
1412 struct it *it;
1413{
1414 struct glyph *glyph;
1415 enum glyph_row_area area = it->area;
1416
1417 xassert (it->glyph_row);
1418 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1419
1420 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1421 if (glyph < it->glyph_row->glyphs[area + 1])
1422 {
06a2c219
GM
1423 glyph->charpos = CHARPOS (it->position);
1424 glyph->object = it->object;
88d75730 1425 glyph->pixel_width = it->pixel_width;
06a2c219 1426 glyph->voffset = it->voffset;
88d75730 1427 glyph->type = CHAR_GLYPH;
06a2c219 1428 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1429 glyph->left_box_line_p = it->start_of_box_run_p;
1430 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1431 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1432 || it->phys_descent > it->descent);
88d75730 1433 glyph->padding_p = 0;
ee569018 1434 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1435 glyph->face_id = it->face_id;
1436 glyph->u.ch = it->char_to_display;
06a2c219
GM
1437 ++it->glyph_row->used[area];
1438 }
1439}
1440
b4192550
KH
1441/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1442 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1443
1444static INLINE void
1445x_append_composite_glyph (it)
1446 struct it *it;
1447{
1448 struct glyph *glyph;
1449 enum glyph_row_area area = it->area;
1450
1451 xassert (it->glyph_row);
1452
1453 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1454 if (glyph < it->glyph_row->glyphs[area + 1])
1455 {
b4192550
KH
1456 glyph->charpos = CHARPOS (it->position);
1457 glyph->object = it->object;
88d75730 1458 glyph->pixel_width = it->pixel_width;
b4192550 1459 glyph->voffset = it->voffset;
88d75730 1460 glyph->type = COMPOSITE_GLYPH;
b4192550 1461 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1462 glyph->left_box_line_p = it->start_of_box_run_p;
1463 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1464 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1465 || it->phys_descent > it->descent);
88d75730
GM
1466 glyph->padding_p = 0;
1467 glyph->glyph_not_available_p = 0;
1468 glyph->face_id = it->face_id;
1469 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1470 ++it->glyph_row->used[area];
1471 }
1472}
1473
06a2c219
GM
1474
1475/* Change IT->ascent and IT->height according to the setting of
1476 IT->voffset. */
1477
1478static INLINE void
1479take_vertical_position_into_account (it)
1480 struct it *it;
1481{
1482 if (it->voffset)
1483 {
1484 if (it->voffset < 0)
1485 /* Increase the ascent so that we can display the text higher
1486 in the line. */
1487 it->ascent += abs (it->voffset);
1488 else
1489 /* Increase the descent so that we can display the text lower
1490 in the line. */
1491 it->descent += it->voffset;
1492 }
1493}
1494
1495
1496/* Produce glyphs/get display metrics for the image IT is loaded with.
1497 See the description of struct display_iterator in dispextern.h for
1498 an overview of struct display_iterator. */
1499
1500static void
1501x_produce_image_glyph (it)
1502 struct it *it;
1503{
1504 struct image *img;
1505 struct face *face;
1506
1507 xassert (it->what == IT_IMAGE);
1508
1509 face = FACE_FROM_ID (it->f, it->face_id);
1510 img = IMAGE_FROM_ID (it->f, it->image_id);
1511 xassert (img);
1512
1513 /* Make sure X resources of the face and image are loaded. */
1514 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1515 prepare_image_for_display (it->f, img);
1516
95af8492 1517 it->ascent = it->phys_ascent = image_ascent (img, face);
66ac4b0e 1518 it->descent = it->phys_descent = img->height + 2 * img->margin - it->ascent;
06a2c219
GM
1519 it->pixel_width = img->width + 2 * img->margin;
1520
1521 it->nglyphs = 1;
1522
1523 if (face->box != FACE_NO_BOX)
1524 {
1525 it->ascent += face->box_line_width;
1526 it->descent += face->box_line_width;
1527
1528 if (it->start_of_box_run_p)
1529 it->pixel_width += face->box_line_width;
1530 if (it->end_of_box_run_p)
1531 it->pixel_width += face->box_line_width;
1532 }
1533
1534 take_vertical_position_into_account (it);
1535
1536 if (it->glyph_row)
1537 {
1538 struct glyph *glyph;
1539 enum glyph_row_area area = it->area;
1540
1541 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1542 if (glyph < it->glyph_row->glyphs[area + 1])
1543 {
06a2c219
GM
1544 glyph->charpos = CHARPOS (it->position);
1545 glyph->object = it->object;
88d75730 1546 glyph->pixel_width = it->pixel_width;
06a2c219 1547 glyph->voffset = it->voffset;
88d75730 1548 glyph->type = IMAGE_GLYPH;
06a2c219 1549 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1550 glyph->left_box_line_p = it->start_of_box_run_p;
1551 glyph->right_box_line_p = it->end_of_box_run_p;
1552 glyph->overlaps_vertically_p = 0;
1553 glyph->padding_p = 0;
1554 glyph->glyph_not_available_p = 0;
1555 glyph->face_id = it->face_id;
1556 glyph->u.img_id = img->id;
06a2c219
GM
1557 ++it->glyph_row->used[area];
1558 }
1559 }
1560}
1561
1562
1563/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1564 of the glyph, WIDTH and HEIGHT are the width and height of the
1565 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1566 ascent of the glyph (0 <= ASCENT <= 1). */
1567
1568static void
1569x_append_stretch_glyph (it, object, width, height, ascent)
1570 struct it *it;
1571 Lisp_Object object;
1572 int width, height;
1573 double ascent;
1574{
1575 struct glyph *glyph;
1576 enum glyph_row_area area = it->area;
1577
1578 xassert (ascent >= 0 && ascent <= 1);
1579
1580 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1581 if (glyph < it->glyph_row->glyphs[area + 1])
1582 {
06a2c219
GM
1583 glyph->charpos = CHARPOS (it->position);
1584 glyph->object = object;
88d75730 1585 glyph->pixel_width = width;
06a2c219 1586 glyph->voffset = it->voffset;
88d75730 1587 glyph->type = STRETCH_GLYPH;
06a2c219 1588 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1589 glyph->left_box_line_p = it->start_of_box_run_p;
1590 glyph->right_box_line_p = it->end_of_box_run_p;
1591 glyph->overlaps_vertically_p = 0;
1592 glyph->padding_p = 0;
1593 glyph->glyph_not_available_p = 0;
1594 glyph->face_id = it->face_id;
1595 glyph->u.stretch.ascent = height * ascent;
1596 glyph->u.stretch.height = height;
06a2c219
GM
1597 ++it->glyph_row->used[area];
1598 }
1599}
1600
1601
1602/* Produce a stretch glyph for iterator IT. IT->object is the value
1603 of the glyph property displayed. The value must be a list
1604 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1605 being recognized:
1606
1607 1. `:width WIDTH' specifies that the space should be WIDTH *
1608 canonical char width wide. WIDTH may be an integer or floating
1609 point number.
1610
1611 2. `:relative-width FACTOR' specifies that the width of the stretch
1612 should be computed from the width of the first character having the
1613 `glyph' property, and should be FACTOR times that width.
1614
1615 3. `:align-to HPOS' specifies that the space should be wide enough
1616 to reach HPOS, a value in canonical character units.
1617
1618 Exactly one of the above pairs must be present.
1619
1620 4. `:height HEIGHT' specifies that the height of the stretch produced
1621 should be HEIGHT, measured in canonical character units.
1622
1623 5. `:relative-height FACTOR' specifies that the height of the the
1624 stretch should be FACTOR times the height of the characters having
1625 the glyph property.
1626
1627 Either none or exactly one of 4 or 5 must be present.
1628
1629 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1630 of the stretch should be used for the ascent of the stretch.
1631 ASCENT must be in the range 0 <= ASCENT <= 100. */
1632
1633#define NUMVAL(X) \
1634 ((INTEGERP (X) || FLOATP (X)) \
1635 ? XFLOATINT (X) \
1636 : - 1)
1637
1638
1639static void
1640x_produce_stretch_glyph (it)
1641 struct it *it;
1642{
1643 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1644#if GLYPH_DEBUG
1645 extern Lisp_Object Qspace;
1646#endif
1647 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1648 extern Lisp_Object QCrelative_width, QCrelative_height;
1649 extern Lisp_Object QCalign_to;
1650 Lisp_Object prop, plist;
1651 double width = 0, height = 0, ascent = 0;
1652 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1653 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1654
1655 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1656
1657 /* List should start with `space'. */
1658 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1659 plist = XCDR (it->object);
1660
1661 /* Compute the width of the stretch. */
1662 if (prop = Fplist_get (plist, QCwidth),
1663 NUMVAL (prop) > 0)
1664 /* Absolute width `:width WIDTH' specified and valid. */
1665 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1666 else if (prop = Fplist_get (plist, QCrelative_width),
1667 NUMVAL (prop) > 0)
1668 {
1669 /* Relative width `:relative-width FACTOR' specified and valid.
1670 Compute the width of the characters having the `glyph'
1671 property. */
1672 struct it it2;
1673 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1674
1675 it2 = *it;
1676 if (it->multibyte_p)
1677 {
1678 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1679 - IT_BYTEPOS (*it));
1680 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1681 }
1682 else
1683 it2.c = *p, it2.len = 1;
1684
1685 it2.glyph_row = NULL;
1686 it2.what = IT_CHARACTER;
1687 x_produce_glyphs (&it2);
1688 width = NUMVAL (prop) * it2.pixel_width;
1689 }
1690 else if (prop = Fplist_get (plist, QCalign_to),
1691 NUMVAL (prop) > 0)
1692 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1693 else
1694 /* Nothing specified -> width defaults to canonical char width. */
1695 width = CANON_X_UNIT (it->f);
1696
1697 /* Compute height. */
1698 if (prop = Fplist_get (plist, QCheight),
1699 NUMVAL (prop) > 0)
1700 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1701 else if (prop = Fplist_get (plist, QCrelative_height),
1702 NUMVAL (prop) > 0)
1703 height = FONT_HEIGHT (font) * NUMVAL (prop);
1704 else
1705 height = FONT_HEIGHT (font);
1706
1707 /* Compute percentage of height used for ascent. If
1708 `:ascent ASCENT' is present and valid, use that. Otherwise,
1709 derive the ascent from the font in use. */
1710 if (prop = Fplist_get (plist, QCascent),
1711 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1712 ascent = NUMVAL (prop) / 100.0;
1713 else
1714 ascent = (double) font->ascent / FONT_HEIGHT (font);
1715
1716 if (width <= 0)
1717 width = 1;
1718 if (height <= 0)
1719 height = 1;
1720
1721 if (it->glyph_row)
1722 {
1723 Lisp_Object object = it->stack[it->sp - 1].string;
1724 if (!STRINGP (object))
1725 object = it->w->buffer;
1726 x_append_stretch_glyph (it, object, width, height, ascent);
1727 }
1728
1729 it->pixel_width = width;
66ac4b0e
GM
1730 it->ascent = it->phys_ascent = height * ascent;
1731 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1732 it->nglyphs = 1;
1733
1734 if (face->box != FACE_NO_BOX)
1735 {
1736 it->ascent += face->box_line_width;
1737 it->descent += face->box_line_width;
1738
1739 if (it->start_of_box_run_p)
1740 it->pixel_width += face->box_line_width;
1741 if (it->end_of_box_run_p)
1742 it->pixel_width += face->box_line_width;
1743 }
1744
1745 take_vertical_position_into_account (it);
1746}
1747
b4192550
KH
1748/* Return proper value to be used as baseline offset of font that has
1749 ASCENT and DESCENT to draw characters by the font at the vertical
1750 center of the line of frame F.
1751
1752 Here, out task is to find the value of BOFF in the following figure;
1753
1754 -------------------------+-----------+-
1755 -+-+---------+-+ | |
1756 | | | | | |
1757 | | | | F_ASCENT F_HEIGHT
1758 | | | ASCENT | |
1759 HEIGHT | | | | |
1760 | | |-|-+------+-----------|------- baseline
1761 | | | | BOFF | |
1762 | |---------|-+-+ | |
1763 | | | DESCENT | |
1764 -+-+---------+-+ F_DESCENT |
1765 -------------------------+-----------+-
1766
1767 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1768 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1769 DESCENT = FONT->descent
1770 HEIGHT = FONT_HEIGHT (FONT)
1771 F_DESCENT = (F->output_data.x->font->descent
1772 - F->output_data.x->baseline_offset)
1773 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1774*/
1775
1776#define VCENTER_BASELINE_OFFSET(FONT, F) \
1777 ((FONT)->descent \
1778 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT))) / 2 \
1779 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1780
1781/* Produce glyphs/get display metrics for the display element IT is
1782 loaded with. See the description of struct display_iterator in
1783 dispextern.h for an overview of struct display_iterator. */
1784
1785static void
1786x_produce_glyphs (it)
1787 struct it *it;
1788{
ee569018
KH
1789 it->glyph_not_available_p = 0;
1790
06a2c219
GM
1791 if (it->what == IT_CHARACTER)
1792 {
1793 XChar2b char2b;
1794 XFontStruct *font;
ee569018 1795 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1796 XCharStruct *pcm;
06a2c219 1797 int font_not_found_p;
b4192550
KH
1798 struct font_info *font_info;
1799 int boff; /* baseline offset */
06a2c219 1800
ee569018
KH
1801 /* Maybe translate single-byte characters to multibyte, or the
1802 other way. */
06a2c219 1803 it->char_to_display = it->c;
ee569018 1804 if (!ASCII_BYTE_P (it->c))
06a2c219 1805 {
ee569018
KH
1806 if (unibyte_display_via_language_environment
1807 && SINGLE_BYTE_CHAR_P (it->c)
1808 && (it->c >= 0240
1809 || !NILP (Vnonascii_translation_table)))
1810 {
1811 it->char_to_display = unibyte_char_to_multibyte (it->c);
1812 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1813 face = FACE_FROM_ID (it->f, it->face_id);
1814 }
1815 else if (!SINGLE_BYTE_CHAR_P (it->c)
1816 && !it->multibyte_p)
1817 {
1818 it->char_to_display = multibyte_char_to_unibyte (it->c, Qnil);
1819 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1820 face = FACE_FROM_ID (it->f, it->face_id);
1821 }
06a2c219
GM
1822 }
1823
ee569018
KH
1824 /* Get font to use. Encode IT->char_to_display. */
1825 x_get_char_face_and_encoding (it->f, it->char_to_display,
1826 it->face_id, &char2b,
1827 it->multibyte_p);
06a2c219
GM
1828 font = face->font;
1829
1830 /* When no suitable font found, use the default font. */
1831 font_not_found_p = font == NULL;
1832 if (font_not_found_p)
b4192550
KH
1833 {
1834 font = FRAME_FONT (it->f);
1835 boff = it->f->output_data.x->baseline_offset;
1836 font_info = NULL;
1837 }
1838 else
1839 {
1840 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1841 boff = font_info->baseline_offset;
1842 if (font_info->vertical_centering)
1843 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1844 }
06a2c219
GM
1845
1846 if (it->char_to_display >= ' '
1847 && (!it->multibyte_p || it->char_to_display < 128))
1848 {
1849 /* Either unibyte or ASCII. */
1850 int stretched_p;
1851
1852 it->nglyphs = 1;
06a2c219
GM
1853
1854 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1855 it->ascent = font->ascent + boff;
1856 it->descent = font->descent - boff;
474848ac
GM
1857
1858 if (pcm)
1859 {
1860 it->phys_ascent = pcm->ascent + boff;
1861 it->phys_descent = pcm->descent - boff;
1862 it->pixel_width = pcm->width;
1863 }
1864 else
1865 {
1866 it->glyph_not_available_p = 1;
1867 it->phys_ascent = font->ascent + boff;
1868 it->phys_descent = font->descent - boff;
1869 it->pixel_width = FONT_WIDTH (font);
1870 }
06a2c219
GM
1871
1872 /* If this is a space inside a region of text with
1873 `space-width' property, change its width. */
1874 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1875 if (stretched_p)
1876 it->pixel_width *= XFLOATINT (it->space_width);
1877
1878 /* If face has a box, add the box thickness to the character
1879 height. If character has a box line to the left and/or
1880 right, add the box line width to the character's width. */
1881 if (face->box != FACE_NO_BOX)
1882 {
1883 int thick = face->box_line_width;
1884
1885 it->ascent += thick;
1886 it->descent += thick;
1887
1888 if (it->start_of_box_run_p)
1889 it->pixel_width += thick;
1890 if (it->end_of_box_run_p)
1891 it->pixel_width += thick;
1892 }
1893
1894 /* If face has an overline, add the height of the overline
1895 (1 pixel) and a 1 pixel margin to the character height. */
1896 if (face->overline_p)
1897 it->ascent += 2;
1898
1899 take_vertical_position_into_account (it);
1900
1901 /* If we have to actually produce glyphs, do it. */
1902 if (it->glyph_row)
1903 {
1904 if (stretched_p)
1905 {
1906 /* Translate a space with a `space-width' property
1907 into a stretch glyph. */
1908 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1909 x_append_stretch_glyph (it, it->object, it->pixel_width,
1910 it->ascent + it->descent, ascent);
1911 }
1912 else
1913 x_append_glyph (it);
1914
1915 /* If characters with lbearing or rbearing are displayed
1916 in this line, record that fact in a flag of the
1917 glyph row. This is used to optimize X output code. */
1c7e22fd 1918 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1919 it->glyph_row->contains_overlapping_glyphs_p = 1;
1920 }
1921 }
1922 else if (it->char_to_display == '\n')
1923 {
1924 /* A newline has no width but we need the height of the line. */
1925 it->pixel_width = 0;
1926 it->nglyphs = 0;
b4192550
KH
1927 it->ascent = it->phys_ascent = font->ascent + boff;
1928 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1929
1930 if (face->box != FACE_NO_BOX)
1931 {
1932 int thick = face->box_line_width;
1933 it->ascent += thick;
1934 it->descent += thick;
1935 }
1936 }
1937 else if (it->char_to_display == '\t')
1938 {
1939 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1940 int x = it->current_x + it->continuation_lines_width;
06a2c219
GM
1941 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
1942
1943 it->pixel_width = next_tab_x - x;
1944 it->nglyphs = 1;
b4192550
KH
1945 it->ascent = it->phys_ascent = font->ascent + boff;
1946 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1947
1948 if (it->glyph_row)
1949 {
1950 double ascent = (double) it->ascent / (it->ascent + it->descent);
1951 x_append_stretch_glyph (it, it->object, it->pixel_width,
1952 it->ascent + it->descent, ascent);
1953 }
1954 }
1955 else
1956 {
1957 /* A multi-byte character. Assume that the display width of the
1958 character is the width of the character multiplied by the
b4192550 1959 width of the font. */
06a2c219 1960
b4192550
KH
1961 /* If we found a font, this font should give us the right
1962 metrics. If we didn't find a font, use the frame's
1963 default font and calculate the width of the character
1964 from the charset width; this is what old redisplay code
1965 did. */
1966 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1967 if (font_not_found_p || !pcm)
1968 {
1969 int charset = CHAR_CHARSET (it->char_to_display);
1970
1971 it->glyph_not_available_p = 1;
1972 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
1973 * CHARSET_WIDTH (charset));
1974 it->phys_ascent = font->ascent + boff;
1975 it->phys_descent = font->descent - boff;
1976 }
1977 else
1978 {
1979 it->pixel_width = pcm->width;
1980 it->phys_ascent = pcm->ascent + boff;
1981 it->phys_descent = pcm->descent - boff;
1982 if (it->glyph_row
1983 && (pcm->lbearing < 0
1984 || pcm->rbearing > pcm->width))
1985 it->glyph_row->contains_overlapping_glyphs_p = 1;
1986 }
b4192550
KH
1987 it->nglyphs = 1;
1988 it->ascent = font->ascent + boff;
1989 it->descent = font->descent - boff;
06a2c219
GM
1990 if (face->box != FACE_NO_BOX)
1991 {
1992 int thick = face->box_line_width;
1993 it->ascent += thick;
1994 it->descent += thick;
1995
1996 if (it->start_of_box_run_p)
1997 it->pixel_width += thick;
1998 if (it->end_of_box_run_p)
1999 it->pixel_width += thick;
2000 }
2001
2002 /* If face has an overline, add the height of the overline
2003 (1 pixel) and a 1 pixel margin to the character height. */
2004 if (face->overline_p)
2005 it->ascent += 2;
2006
2007 take_vertical_position_into_account (it);
2008
2009 if (it->glyph_row)
2010 x_append_glyph (it);
2011 }
2012 }
b4192550
KH
2013 else if (it->what == IT_COMPOSITION)
2014 {
2015 /* Note: A composition is represented as one glyph in the
2016 glyph matrix. There are no padding glyphs. */
2017 XChar2b char2b;
2018 XFontStruct *font;
ee569018 2019 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2020 XCharStruct *pcm;
2021 int font_not_found_p;
2022 struct font_info *font_info;
2023 int boff; /* baseline offset */
2024 struct composition *cmp = composition_table[it->cmp_id];
2025
2026 /* Maybe translate single-byte characters to multibyte. */
2027 it->char_to_display = it->c;
2028 if (unibyte_display_via_language_environment
2029 && SINGLE_BYTE_CHAR_P (it->c)
2030 && (it->c >= 0240
2031 || (it->c >= 0200
2032 && !NILP (Vnonascii_translation_table))))
2033 {
2034 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2035 }
2036
2037 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2038 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2039 face = FACE_FROM_ID (it->f, it->face_id);
2040 x_get_char_face_and_encoding (it->f, it->char_to_display,
2041 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2042 font = face->font;
2043
2044 /* When no suitable font found, use the default font. */
2045 font_not_found_p = font == NULL;
2046 if (font_not_found_p)
2047 {
2048 font = FRAME_FONT (it->f);
2049 boff = it->f->output_data.x->baseline_offset;
2050 font_info = NULL;
2051 }
2052 else
2053 {
2054 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2055 boff = font_info->baseline_offset;
2056 if (font_info->vertical_centering)
2057 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2058 }
2059
2060 /* There are no padding glyphs, so there is only one glyph to
2061 produce for the composition. Important is that pixel_width,
2062 ascent and descent are the values of what is drawn by
2063 draw_glyphs (i.e. the values of the overall glyphs composed). */
2064 it->nglyphs = 1;
2065
2066 /* If we have not yet calculated pixel size data of glyphs of
2067 the composition for the current face font, calculate them
2068 now. Theoretically, we have to check all fonts for the
2069 glyphs, but that requires much time and memory space. So,
2070 here we check only the font of the first glyph. This leads
2071 to incorrect display very rarely, and C-l (recenter) can
2072 correct the display anyway. */
2073 if (cmp->font != (void *) font)
2074 {
2075 /* Ascent and descent of the font of the first character of
2076 this composition (adjusted by baseline offset). Ascent
2077 and descent of overall glyphs should not be less than
2078 them respectively. */
2079 int font_ascent = font->ascent + boff;
2080 int font_descent = font->descent - boff;
2081 /* Bounding box of the overall glyphs. */
2082 int leftmost, rightmost, lowest, highest;
329bed06 2083 int i, width, ascent, descent;
b4192550
KH
2084
2085 cmp->font = (void *) font;
2086
2087 /* Initialize the bounding box. */
2088 pcm = x_per_char_metric (font, &char2b);
329bed06
GM
2089 if (pcm)
2090 {
2091 width = pcm->width;
2092 ascent = pcm->ascent;
2093 descent = pcm->descent;
2094 }
2095 else
2096 {
2097 width = FONT_WIDTH (font);
2098 ascent = font->ascent;
2099 descent = font->descent;
2100 }
2101
2102 rightmost = width;
2103 lowest = - descent + boff;
2104 highest = ascent + boff;
b4192550 2105 leftmost = 0;
329bed06 2106
b4192550
KH
2107 if (font_info
2108 && font_info->default_ascent
2109 && CHAR_TABLE_P (Vuse_default_ascent)
2110 && !NILP (Faref (Vuse_default_ascent,
2111 make_number (it->char_to_display))))
2112 highest = font_info->default_ascent + boff;
2113
2114 /* Draw the first glyph at the normal position. It may be
2115 shifted to right later if some other glyphs are drawn at
2116 the left. */
2117 cmp->offsets[0] = 0;
2118 cmp->offsets[1] = boff;
2119
2120 /* Set cmp->offsets for the remaining glyphs. */
2121 for (i = 1; i < cmp->glyph_len; i++)
2122 {
2123 int left, right, btm, top;
2124 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2125 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2126
2127 face = FACE_FROM_ID (it->f, face_id);
2128 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2129 it->multibyte_p);
b4192550
KH
2130 font = face->font;
2131 if (font == NULL)
2132 {
2133 font = FRAME_FONT (it->f);
2134 boff = it->f->output_data.x->baseline_offset;
2135 font_info = NULL;
2136 }
2137 else
2138 {
2139 font_info
2140 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2141 boff = font_info->baseline_offset;
2142 if (font_info->vertical_centering)
2143 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2144 }
2145
2146 pcm = x_per_char_metric (font, &char2b);
329bed06
GM
2147 if (pcm)
2148 {
2149 width = pcm->width;
2150 ascent = pcm->ascent;
2151 descent = pcm->descent;
2152 }
2153 else
2154 {
2155 width = FONT_WIDTH (font);
2156 ascent = font->ascent;
2157 descent = font->descent;
2158 }
b4192550
KH
2159
2160 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2161 {
2162 /* Relative composition with or without
2163 alternate chars. */
329bed06
GM
2164 left = (leftmost + rightmost - width) / 2;
2165 btm = - descent + boff;
b4192550
KH
2166 if (font_info && font_info->relative_compose
2167 && (! CHAR_TABLE_P (Vignore_relative_composition)
2168 || NILP (Faref (Vignore_relative_composition,
2169 make_number (ch)))))
2170 {
2171
329bed06 2172 if (- descent >= font_info->relative_compose)
b4192550
KH
2173 /* One extra pixel between two glyphs. */
2174 btm = highest + 1;
329bed06 2175 else if (ascent <= 0)
b4192550 2176 /* One extra pixel between two glyphs. */
329bed06 2177 btm = lowest - 1 - ascent - descent;
b4192550
KH
2178 }
2179 }
2180 else
2181 {
2182 /* A composition rule is specified by an integer
2183 value that encodes global and new reference
2184 points (GREF and NREF). GREF and NREF are
2185 specified by numbers as below:
2186
2187 0---1---2 -- ascent
2188 | |
2189 | |
2190 | |
2191 9--10--11 -- center
2192 | |
2193 ---3---4---5--- baseline
2194 | |
2195 6---7---8 -- descent
2196 */
2197 int rule = COMPOSITION_RULE (cmp, i);
2198 int gref, nref, grefx, grefy, nrefx, nrefy;
2199
2200 COMPOSITION_DECODE_RULE (rule, gref, nref);
2201 grefx = gref % 3, nrefx = nref % 3;
2202 grefy = gref / 3, nrefy = nref / 3;
2203
2204 left = (leftmost
2205 + grefx * (rightmost - leftmost) / 2
329bed06 2206 - nrefx * width / 2);
b4192550
KH
2207 btm = ((grefy == 0 ? highest
2208 : grefy == 1 ? 0
2209 : grefy == 2 ? lowest
2210 : (highest + lowest) / 2)
329bed06
GM
2211 - (nrefy == 0 ? ascent + descent
2212 : nrefy == 1 ? descent - boff
b4192550 2213 : nrefy == 2 ? 0
329bed06 2214 : (ascent + descent) / 2));
b4192550
KH
2215 }
2216
2217 cmp->offsets[i * 2] = left;
329bed06 2218 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2219
2220 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2221 right = left + width;
2222 top = btm + descent + ascent;
b4192550
KH
2223 if (left < leftmost)
2224 leftmost = left;
2225 if (right > rightmost)
2226 rightmost = right;
2227 if (top > highest)
2228 highest = top;
2229 if (btm < lowest)
2230 lowest = btm;
2231 }
2232
2233 /* If there are glyphs whose x-offsets are negative,
2234 shift all glyphs to the right and make all x-offsets
2235 non-negative. */
2236 if (leftmost < 0)
2237 {
2238 for (i = 0; i < cmp->glyph_len; i++)
2239 cmp->offsets[i * 2] -= leftmost;
2240 rightmost -= leftmost;
2241 }
2242
2243 cmp->pixel_width = rightmost;
2244 cmp->ascent = highest;
2245 cmp->descent = - lowest;
2246 if (cmp->ascent < font_ascent)
2247 cmp->ascent = font_ascent;
2248 if (cmp->descent < font_descent)
2249 cmp->descent = font_descent;
2250 }
2251
2252 it->pixel_width = cmp->pixel_width;
2253 it->ascent = it->phys_ascent = cmp->ascent;
2254 it->descent = it->phys_descent = cmp->descent;
2255
2256 if (face->box != FACE_NO_BOX)
2257 {
2258 int thick = face->box_line_width;
2259 it->ascent += thick;
2260 it->descent += thick;
2261
2262 if (it->start_of_box_run_p)
2263 it->pixel_width += thick;
2264 if (it->end_of_box_run_p)
2265 it->pixel_width += thick;
2266 }
2267
2268 /* If face has an overline, add the height of the overline
2269 (1 pixel) and a 1 pixel margin to the character height. */
2270 if (face->overline_p)
2271 it->ascent += 2;
2272
2273 take_vertical_position_into_account (it);
2274
2275 if (it->glyph_row)
2276 x_append_composite_glyph (it);
2277 }
06a2c219
GM
2278 else if (it->what == IT_IMAGE)
2279 x_produce_image_glyph (it);
2280 else if (it->what == IT_STRETCH)
2281 x_produce_stretch_glyph (it);
2282
3017fdd1
GM
2283 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2284 because this isn't true for images with `:ascent 100'. */
2285 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2286 if (it->area == TEXT_AREA)
2287 it->current_x += it->pixel_width;
66ac4b0e 2288
d365f5bb
GM
2289 it->descent += it->extra_line_spacing;
2290
06a2c219
GM
2291 it->max_ascent = max (it->max_ascent, it->ascent);
2292 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2293 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2294 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2295}
2296
2297
2298/* Estimate the pixel height of the mode or top line on frame F.
2299 FACE_ID specifies what line's height to estimate. */
2300
2301int
2302x_estimate_mode_line_height (f, face_id)
2303 struct frame *f;
2304 enum face_id face_id;
2305{
2306 int height = 1;
2307
2308 /* This function is called so early when Emacs starts that the face
2309 cache and mode line face are not yet initialized. */
2310 if (FRAME_FACE_CACHE (f))
2311 {
2312 struct face *face = FACE_FROM_ID (f, face_id);
2313 if (face)
2314 height = FONT_HEIGHT (face->font) + 2 * face->box_line_width;
2315 }
2316
2317 return height;
2318}
2319
2320\f
2321/***********************************************************************
2322 Glyph display
2323 ***********************************************************************/
2324
2325/* A sequence of glyphs to be drawn in the same face.
2326
2327 This data structure is not really completely X specific, so it
2328 could possibly, at least partially, be useful for other systems. It
2329 is currently not part of the external redisplay interface because
2330 it's not clear what other systems will need. */
2331
2332struct glyph_string
2333{
2334 /* X-origin of the string. */
2335 int x;
2336
2337 /* Y-origin and y-position of the base line of this string. */
2338 int y, ybase;
2339
2340 /* The width of the string, not including a face extension. */
2341 int width;
2342
2343 /* The width of the string, including a face extension. */
2344 int background_width;
2345
2346 /* The height of this string. This is the height of the line this
2347 string is drawn in, and can be different from the height of the
2348 font the string is drawn in. */
2349 int height;
2350
2351 /* Number of pixels this string overwrites in front of its x-origin.
2352 This number is zero if the string has an lbearing >= 0; it is
2353 -lbearing, if the string has an lbearing < 0. */
2354 int left_overhang;
2355
2356 /* Number of pixels this string overwrites past its right-most
2357 nominal x-position, i.e. x + width. Zero if the string's
2358 rbearing is <= its nominal width, rbearing - width otherwise. */
2359 int right_overhang;
2360
2361 /* The frame on which the glyph string is drawn. */
2362 struct frame *f;
2363
2364 /* The window on which the glyph string is drawn. */
2365 struct window *w;
2366
2367 /* X display and window for convenience. */
2368 Display *display;
2369 Window window;
2370
2371 /* The glyph row for which this string was built. It determines the
2372 y-origin and height of the string. */
2373 struct glyph_row *row;
2374
2375 /* The area within row. */
2376 enum glyph_row_area area;
2377
2378 /* Characters to be drawn, and number of characters. */
2379 XChar2b *char2b;
2380 int nchars;
2381
06a2c219
GM
2382 /* A face-override for drawing cursors, mouse face and similar. */
2383 enum draw_glyphs_face hl;
2384
2385 /* Face in which this string is to be drawn. */
2386 struct face *face;
2387
2388 /* Font in which this string is to be drawn. */
2389 XFontStruct *font;
2390
2391 /* Font info for this string. */
2392 struct font_info *font_info;
2393
b4192550
KH
2394 /* Non-null means this string describes (part of) a composition.
2395 All characters from char2b are drawn composed. */
2396 struct composition *cmp;
06a2c219
GM
2397
2398 /* Index of this glyph string's first character in the glyph
b4192550
KH
2399 definition of CMP. If this is zero, this glyph string describes
2400 the first character of a composition. */
06a2c219
GM
2401 int gidx;
2402
2403 /* 1 means this glyph strings face has to be drawn to the right end
2404 of the window's drawing area. */
2405 unsigned extends_to_end_of_line_p : 1;
2406
2407 /* 1 means the background of this string has been drawn. */
2408 unsigned background_filled_p : 1;
2409
2410 /* 1 means glyph string must be drawn with 16-bit functions. */
2411 unsigned two_byte_p : 1;
2412
2413 /* 1 means that the original font determined for drawing this glyph
2414 string could not be loaded. The member `font' has been set to
2415 the frame's default font in this case. */
2416 unsigned font_not_found_p : 1;
2417
2418 /* 1 means that the face in which this glyph string is drawn has a
2419 stipple pattern. */
2420 unsigned stippled_p : 1;
2421
66ac4b0e
GM
2422 /* 1 means only the foreground of this glyph string must be drawn,
2423 and we should use the physical height of the line this glyph
2424 string appears in as clip rect. */
2425 unsigned for_overlaps_p : 1;
2426
06a2c219
GM
2427 /* The GC to use for drawing this glyph string. */
2428 GC gc;
2429
2430 /* A pointer to the first glyph in the string. This glyph
2431 corresponds to char2b[0]. Needed to draw rectangles if
2432 font_not_found_p is 1. */
2433 struct glyph *first_glyph;
2434
2435 /* Image, if any. */
2436 struct image *img;
2437
2438 struct glyph_string *next, *prev;
2439};
2440
2441
5c187dee 2442#if 0
06a2c219
GM
2443
2444static void
2445x_dump_glyph_string (s)
2446 struct glyph_string *s;
2447{
2448 fprintf (stderr, "glyph string\n");
2449 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2450 s->x, s->y, s->width, s->height);
2451 fprintf (stderr, " ybase = %d\n", s->ybase);
2452 fprintf (stderr, " hl = %d\n", s->hl);
2453 fprintf (stderr, " left overhang = %d, right = %d\n",
2454 s->left_overhang, s->right_overhang);
2455 fprintf (stderr, " nchars = %d\n", s->nchars);
2456 fprintf (stderr, " extends to end of line = %d\n",
2457 s->extends_to_end_of_line_p);
2458 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2459 fprintf (stderr, " bg width = %d\n", s->background_width);
2460}
2461
2462#endif /* GLYPH_DEBUG */
2463
2464
2465
2466static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2467 struct glyph_string **,
2468 struct glyph_string *,
2469 struct glyph_string *));
2470static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2471 struct glyph_string **,
2472 struct glyph_string *,
2473 struct glyph_string *));
2474static void x_append_glyph_string P_ ((struct glyph_string **,
2475 struct glyph_string **,
2476 struct glyph_string *));
2477static int x_left_overwritten P_ ((struct glyph_string *));
2478static int x_left_overwriting P_ ((struct glyph_string *));
2479static int x_right_overwritten P_ ((struct glyph_string *));
2480static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2481static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2482 int));
06a2c219
GM
2483static void x_init_glyph_string P_ ((struct glyph_string *,
2484 XChar2b *, struct window *,
2485 struct glyph_row *,
2486 enum glyph_row_area, int,
2487 enum draw_glyphs_face));
2488static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2489 enum glyph_row_area, int, int,
66ac4b0e 2490 enum draw_glyphs_face, int *, int *, int));
06a2c219
GM
2491static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2492static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2493static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2494 int));
2495static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2496static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2497static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2498static void x_draw_glyph_string P_ ((struct glyph_string *));
2499static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2500static void x_set_cursor_gc P_ ((struct glyph_string *));
2501static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2502static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2503static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2504 int *, int *));
2505static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2506static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2507 unsigned long *, double, int));
06a2c219 2508static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2509 double, int, unsigned long));
06a2c219
GM
2510static void x_setup_relief_colors P_ ((struct glyph_string *));
2511static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2512static void x_draw_image_relief P_ ((struct glyph_string *));
2513static void x_draw_image_foreground P_ ((struct glyph_string *));
2514static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2515static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2516static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2517 int, int, int));
2518static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2519 int, int, int, int, XRectangle *));
2520static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2521 int, int, int, XRectangle *));
66ac4b0e
GM
2522static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2523 enum glyph_row_area));
209f68d9
GM
2524static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2525 struct glyph_row *,
2526 enum glyph_row_area, int, int));
06a2c219 2527
163dcff3
GM
2528#if GLYPH_DEBUG
2529static void x_check_font P_ ((struct frame *, XFontStruct *));
2530#endif
2531
06a2c219 2532
06a2c219
GM
2533/* Append the list of glyph strings with head H and tail T to the list
2534 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2535
2536static INLINE void
2537x_append_glyph_string_lists (head, tail, h, t)
2538 struct glyph_string **head, **tail;
2539 struct glyph_string *h, *t;
2540{
2541 if (h)
2542 {
2543 if (*head)
2544 (*tail)->next = h;
2545 else
2546 *head = h;
2547 h->prev = *tail;
2548 *tail = t;
2549 }
2550}
2551
2552
2553/* Prepend the list of glyph strings with head H and tail T to the
2554 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2555 result. */
2556
2557static INLINE void
2558x_prepend_glyph_string_lists (head, tail, h, t)
2559 struct glyph_string **head, **tail;
2560 struct glyph_string *h, *t;
2561{
2562 if (h)
2563 {
2564 if (*head)
2565 (*head)->prev = t;
2566 else
2567 *tail = t;
2568 t->next = *head;
2569 *head = h;
2570 }
2571}
2572
2573
2574/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2575 Set *HEAD and *TAIL to the resulting list. */
2576
2577static INLINE void
2578x_append_glyph_string (head, tail, s)
2579 struct glyph_string **head, **tail;
2580 struct glyph_string *s;
2581{
2582 s->next = s->prev = NULL;
2583 x_append_glyph_string_lists (head, tail, s, s);
2584}
2585
2586
2587/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2588 face. */
2589
2590static void
2591x_set_cursor_gc (s)
2592 struct glyph_string *s;
2593{
2594 if (s->font == FRAME_FONT (s->f)
2595 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2596 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2597 && !s->cmp)
06a2c219
GM
2598 s->gc = s->f->output_data.x->cursor_gc;
2599 else
2600 {
2601 /* Cursor on non-default face: must merge. */
2602 XGCValues xgcv;
2603 unsigned long mask;
2604
2605 xgcv.background = s->f->output_data.x->cursor_pixel;
2606 xgcv.foreground = s->face->background;
2607
2608 /* If the glyph would be invisible, try a different foreground. */
2609 if (xgcv.foreground == xgcv.background)
2610 xgcv.foreground = s->face->foreground;
2611 if (xgcv.foreground == xgcv.background)
2612 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2613 if (xgcv.foreground == xgcv.background)
2614 xgcv.foreground = s->face->foreground;
2615
2616 /* Make sure the cursor is distinct from text in this face. */
2617 if (xgcv.background == s->face->background
2618 && xgcv.foreground == s->face->foreground)
2619 {
2620 xgcv.background = s->face->foreground;
2621 xgcv.foreground = s->face->background;
2622 }
2623
2624 IF_DEBUG (x_check_font (s->f, s->font));
2625 xgcv.font = s->font->fid;
2626 xgcv.graphics_exposures = False;
2627 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2628
2629 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2630 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2631 mask, &xgcv);
2632 else
2633 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2634 = XCreateGC (s->display, s->window, mask, &xgcv);
2635
2636 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2637 }
2638}
2639
2640
2641/* Set up S->gc of glyph string S for drawing text in mouse face. */
2642
2643static void
2644x_set_mouse_face_gc (s)
2645 struct glyph_string *s;
2646{
2647 int face_id;
ee569018 2648 struct face *face;
06a2c219
GM
2649
2650 /* What face has to be used for the mouse face? */
2651 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2652 face = FACE_FROM_ID (s->f, face_id);
033e3e18
GM
2653 if (s->first_glyph->type == CHAR_GLYPH)
2654 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2655 else
2656 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2657 s->face = FACE_FROM_ID (s->f, face_id);
2658 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2659
2660 /* If font in this face is same as S->font, use it. */
2661 if (s->font == s->face->font)
2662 s->gc = s->face->gc;
2663 else
2664 {
2665 /* Otherwise construct scratch_cursor_gc with values from FACE
2666 but font FONT. */
2667 XGCValues xgcv;
2668 unsigned long mask;
2669
2670 xgcv.background = s->face->background;
2671 xgcv.foreground = s->face->foreground;
2672 IF_DEBUG (x_check_font (s->f, s->font));
2673 xgcv.font = s->font->fid;
2674 xgcv.graphics_exposures = False;
2675 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2676
2677 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2678 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2679 mask, &xgcv);
2680 else
2681 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2682 = XCreateGC (s->display, s->window, mask, &xgcv);
2683
2684 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2685 }
2686
2687 xassert (s->gc != 0);
2688}
2689
2690
2691/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2692 Faces to use in the mode line have already been computed when the
2693 matrix was built, so there isn't much to do, here. */
2694
2695static INLINE void
2696x_set_mode_line_face_gc (s)
2697 struct glyph_string *s;
2698{
2699 s->gc = s->face->gc;
06a2c219
GM
2700}
2701
2702
2703/* Set S->gc of glyph string S for drawing that glyph string. Set
2704 S->stippled_p to a non-zero value if the face of S has a stipple
2705 pattern. */
2706
2707static INLINE void
2708x_set_glyph_string_gc (s)
2709 struct glyph_string *s;
2710{
209f68d9
GM
2711 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2712
06a2c219
GM
2713 if (s->hl == DRAW_NORMAL_TEXT)
2714 {
2715 s->gc = s->face->gc;
2716 s->stippled_p = s->face->stipple != 0;
2717 }
2718 else if (s->hl == DRAW_INVERSE_VIDEO)
2719 {
2720 x_set_mode_line_face_gc (s);
2721 s->stippled_p = s->face->stipple != 0;
2722 }
2723 else if (s->hl == DRAW_CURSOR)
2724 {
2725 x_set_cursor_gc (s);
2726 s->stippled_p = 0;
2727 }
2728 else if (s->hl == DRAW_MOUSE_FACE)
2729 {
2730 x_set_mouse_face_gc (s);
2731 s->stippled_p = s->face->stipple != 0;
2732 }
2733 else if (s->hl == DRAW_IMAGE_RAISED
2734 || s->hl == DRAW_IMAGE_SUNKEN)
2735 {
2736 s->gc = s->face->gc;
2737 s->stippled_p = s->face->stipple != 0;
2738 }
2739 else
2740 {
2741 s->gc = s->face->gc;
2742 s->stippled_p = s->face->stipple != 0;
2743 }
2744
2745 /* GC must have been set. */
2746 xassert (s->gc != 0);
2747}
2748
2749
2750/* Return in *R the clipping rectangle for glyph string S. */
2751
2752static void
2753x_get_glyph_string_clip_rect (s, r)
2754 struct glyph_string *s;
2755 XRectangle *r;
2756{
2757 if (s->row->full_width_p)
2758 {
2759 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2760 int canon_x = CANON_X_UNIT (s->f);
2761
2762 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2763 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2764
2765 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2766 {
1da3fd71 2767 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2768 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2769 r->x -= width;
2770 }
2771
b9432a85 2772 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2773
06a2c219
GM
2774 /* Unless displaying a mode or menu bar line, which are always
2775 fully visible, clip to the visible part of the row. */
2776 if (s->w->pseudo_window_p)
2777 r->height = s->row->visible_height;
2778 else
2779 r->height = s->height;
2780 }
2781 else
2782 {
2783 /* This is a text line that may be partially visible. */
2784 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2785 r->width = window_box_width (s->w, s->area);
2786 r->height = s->row->visible_height;
2787 }
2788
2789 /* Don't use S->y for clipping because it doesn't take partially
2790 visible lines into account. For example, it can be negative for
2791 partially visible lines at the top of a window. */
2792 if (!s->row->full_width_p
2793 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
045dee35 2794 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
06a2c219
GM
2795 else
2796 r->y = max (0, s->row->y);
06a2c219 2797
9ea173e8 2798 /* If drawing a tool-bar window, draw it over the internal border
06a2c219 2799 at the top of the window. */
9ea173e8 2800 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219 2801 r->y -= s->f->output_data.x->internal_border_width;
66ac4b0e
GM
2802
2803 /* If S draws overlapping rows, it's sufficient to use the top and
2804 bottom of the window for clipping because this glyph string
2805 intentionally draws over other lines. */
2806 if (s->for_overlaps_p)
2807 {
045dee35 2808 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2809 r->height = window_text_bottom_y (s->w) - r->y;
2810 }
2811
2812 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2813}
2814
2815
2816/* Set clipping for output of glyph string S. S may be part of a mode
2817 line or menu if we don't have X toolkit support. */
2818
2819static INLINE void
2820x_set_glyph_string_clipping (s)
2821 struct glyph_string *s;
2822{
2823 XRectangle r;
2824 x_get_glyph_string_clip_rect (s, &r);
2825 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2826}
2827
2828
2829/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2830 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2831
2832static INLINE void
2833x_compute_glyph_string_overhangs (s)
2834 struct glyph_string *s;
2835{
b4192550 2836 if (s->cmp == NULL
06a2c219
GM
2837 && s->first_glyph->type == CHAR_GLYPH)
2838 {
2839 XCharStruct cs;
2840 int direction, font_ascent, font_descent;
2841 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2842 &font_ascent, &font_descent, &cs);
2843 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2844 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2845 }
2846}
2847
2848
2849/* Compute overhangs and x-positions for glyph string S and its
2850 predecessors, or successors. X is the starting x-position for S.
2851 BACKWARD_P non-zero means process predecessors. */
2852
2853static void
2854x_compute_overhangs_and_x (s, x, backward_p)
2855 struct glyph_string *s;
2856 int x;
2857 int backward_p;
2858{
2859 if (backward_p)
2860 {
2861 while (s)
2862 {
2863 x_compute_glyph_string_overhangs (s);
2864 x -= s->width;
2865 s->x = x;
2866 s = s->prev;
2867 }
2868 }
2869 else
2870 {
2871 while (s)
2872 {
2873 x_compute_glyph_string_overhangs (s);
2874 s->x = x;
2875 x += s->width;
2876 s = s->next;
2877 }
2878 }
2879}
2880
2881
2882/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2883 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2884 assumed to be zero. */
06a2c219
GM
2885
2886static void
2887x_get_glyph_overhangs (glyph, f, left, right)
2888 struct glyph *glyph;
2889 struct frame *f;
2890 int *left, *right;
2891{
06a2c219
GM
2892 *left = *right = 0;
2893
b4192550 2894 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2895 {
2896 XFontStruct *font;
2897 struct face *face;
2898 struct font_info *font_info;
2899 XChar2b char2b;
ee569018
KH
2900 XCharStruct *pcm;
2901
2902 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2903 font = face->font;
2904 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2905 if (font
2906 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2907 {
06a2c219
GM
2908 if (pcm->rbearing > pcm->width)
2909 *right = pcm->rbearing - pcm->width;
2910 if (pcm->lbearing < 0)
2911 *left = -pcm->lbearing;
2912 }
2913 }
2914}
2915
2916
2917/* Return the index of the first glyph preceding glyph string S that
2918 is overwritten by S because of S's left overhang. Value is -1
2919 if no glyphs are overwritten. */
2920
2921static int
2922x_left_overwritten (s)
2923 struct glyph_string *s;
2924{
2925 int k;
2926
2927 if (s->left_overhang)
2928 {
2929 int x = 0, i;
2930 struct glyph *glyphs = s->row->glyphs[s->area];
2931 int first = s->first_glyph - glyphs;
2932
2933 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2934 x -= glyphs[i].pixel_width;
2935
2936 k = i + 1;
2937 }
2938 else
2939 k = -1;
2940
2941 return k;
2942}
2943
2944
2945/* Return the index of the first glyph preceding glyph string S that
2946 is overwriting S because of its right overhang. Value is -1 if no
2947 glyph in front of S overwrites S. */
2948
2949static int
2950x_left_overwriting (s)
2951 struct glyph_string *s;
2952{
2953 int i, k, x;
2954 struct glyph *glyphs = s->row->glyphs[s->area];
2955 int first = s->first_glyph - glyphs;
2956
2957 k = -1;
2958 x = 0;
2959 for (i = first - 1; i >= 0; --i)
2960 {
2961 int left, right;
2962 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2963 if (x + right > 0)
2964 k = i;
2965 x -= glyphs[i].pixel_width;
2966 }
2967
2968 return k;
2969}
2970
2971
2972/* Return the index of the last glyph following glyph string S that is
2973 not overwritten by S because of S's right overhang. Value is -1 if
2974 no such glyph is found. */
2975
2976static int
2977x_right_overwritten (s)
2978 struct glyph_string *s;
2979{
2980 int k = -1;
2981
2982 if (s->right_overhang)
2983 {
2984 int x = 0, i;
2985 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 2986 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
2987 int end = s->row->used[s->area];
2988
2989 for (i = first; i < end && s->right_overhang > x; ++i)
2990 x += glyphs[i].pixel_width;
2991
2992 k = i;
2993 }
2994
2995 return k;
2996}
2997
2998
2999/* Return the index of the last glyph following glyph string S that
3000 overwrites S because of its left overhang. Value is negative
3001 if no such glyph is found. */
3002
3003static int
3004x_right_overwriting (s)
3005 struct glyph_string *s;
3006{
3007 int i, k, x;
3008 int end = s->row->used[s->area];
3009 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3010 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3011
3012 k = -1;
3013 x = 0;
3014 for (i = first; i < end; ++i)
3015 {
3016 int left, right;
3017 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3018 if (x - left < 0)
3019 k = i;
3020 x += glyphs[i].pixel_width;
3021 }
3022
3023 return k;
3024}
3025
3026
3027/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3028
3029static INLINE void
3030x_clear_glyph_string_rect (s, x, y, w, h)
3031 struct glyph_string *s;
3032 int x, y, w, h;
3033{
3034 XGCValues xgcv;
3035 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3036 XSetForeground (s->display, s->gc, xgcv.background);
3037 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3038 XSetForeground (s->display, s->gc, xgcv.foreground);
3039}
3040
3041
3042/* Draw the background of glyph_string S. If S->background_filled_p
3043 is non-zero don't draw it. FORCE_P non-zero means draw the
3044 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3045 when a string preceding S draws into the background of S, or S
3046 contains the first component of a composition. */
06a2c219
GM
3047
3048static void
3049x_draw_glyph_string_background (s, force_p)
3050 struct glyph_string *s;
3051 int force_p;
3052{
3053 /* Nothing to do if background has already been drawn or if it
3054 shouldn't be drawn in the first place. */
3055 if (!s->background_filled_p)
3056 {
b4192550 3057 if (s->stippled_p)
06a2c219
GM
3058 {
3059 /* Fill background with a stipple pattern. */
3060 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3061 XFillRectangle (s->display, s->window, s->gc, s->x,
3062 s->y + s->face->box_line_width,
3063 s->background_width,
3064 s->height - 2 * s->face->box_line_width);
3065 XSetFillStyle (s->display, s->gc, FillSolid);
3066 s->background_filled_p = 1;
3067 }
3068 else if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
3069 || s->font_not_found_p
3070 || s->extends_to_end_of_line_p
06a2c219
GM
3071 || force_p)
3072 {
3073 x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
3074 s->background_width,
3075 s->height - 2 * s->face->box_line_width);
3076 s->background_filled_p = 1;
3077 }
3078 }
3079}
3080
3081
3082/* Draw the foreground of glyph string S. */
3083
3084static void
3085x_draw_glyph_string_foreground (s)
3086 struct glyph_string *s;
3087{
3088 int i, x;
3089
3090 /* If first glyph of S has a left box line, start drawing the text
3091 of S to the right of that box line. */
3092 if (s->face->box != FACE_NO_BOX
3093 && s->first_glyph->left_box_line_p)
3094 x = s->x + s->face->box_line_width;
3095 else
3096 x = s->x;
3097
b4192550
KH
3098 /* Draw characters of S as rectangles if S's font could not be
3099 loaded. */
3100 if (s->font_not_found_p)
06a2c219 3101 {
b4192550 3102 for (i = 0; i < s->nchars; ++i)
06a2c219 3103 {
b4192550
KH
3104 struct glyph *g = s->first_glyph + i;
3105 XDrawRectangle (s->display, s->window,
3106 s->gc, x, s->y, g->pixel_width - 1,
3107 s->height - 1);
3108 x += g->pixel_width;
06a2c219
GM
3109 }
3110 }
3111 else
3112 {
b4192550
KH
3113 char *char1b = (char *) s->char2b;
3114 int boff = s->font_info->baseline_offset;
06a2c219 3115
b4192550
KH
3116 if (s->font_info->vertical_centering)
3117 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3118
3119 /* If we can use 8-bit functions, condense S->char2b. */
3120 if (!s->two_byte_p)
3121 for (i = 0; i < s->nchars; ++i)
3122 char1b[i] = s->char2b[i].byte2;
3123
3124 /* Draw text with XDrawString if background has already been
3125 filled. Otherwise, use XDrawImageString. (Note that
3126 XDrawImageString is usually faster than XDrawString.) Always
3127 use XDrawImageString when drawing the cursor so that there is
3128 no chance that characters under a box cursor are invisible. */
3129 if (s->for_overlaps_p
3130 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3131 {
3132 /* Draw characters with 16-bit or 8-bit functions. */
3133 if (s->two_byte_p)
3134 XDrawString16 (s->display, s->window, s->gc, x,
3135 s->ybase - boff, s->char2b, s->nchars);
3136 else
3137 XDrawString (s->display, s->window, s->gc, x,
3138 s->ybase - boff, char1b, s->nchars);
3139 }
06a2c219
GM
3140 else
3141 {
b4192550
KH
3142 if (s->two_byte_p)
3143 XDrawImageString16 (s->display, s->window, s->gc, x,
3144 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3145 else
b4192550
KH
3146 XDrawImageString (s->display, s->window, s->gc, x,
3147 s->ybase - boff, char1b, s->nchars);
3148 }
3149 }
3150}
06a2c219 3151
b4192550 3152/* Draw the foreground of composite glyph string S. */
06a2c219 3153
b4192550
KH
3154static void
3155x_draw_composite_glyph_string_foreground (s)
3156 struct glyph_string *s;
3157{
3158 int i, x;
06a2c219 3159
b4192550
KH
3160 /* If first glyph of S has a left box line, start drawing the text
3161 of S to the right of that box line. */
3162 if (s->face->box != FACE_NO_BOX
3163 && s->first_glyph->left_box_line_p)
3164 x = s->x + s->face->box_line_width;
3165 else
3166 x = s->x;
06a2c219 3167
b4192550
KH
3168 /* S is a glyph string for a composition. S->gidx is the index of
3169 the first character drawn for glyphs of this composition.
3170 S->gidx == 0 means we are drawing the very first character of
3171 this composition. */
06a2c219 3172
b4192550
KH
3173 /* Draw a rectangle for the composition if the font for the very
3174 first character of the composition could not be loaded. */
3175 if (s->font_not_found_p)
3176 {
3177 if (s->gidx == 0)
3178 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3179 s->width - 1, s->height - 1);
3180 }
3181 else
3182 {
3183 for (i = 0; i < s->nchars; i++, ++s->gidx)
3184 XDrawString16 (s->display, s->window, s->gc,
3185 x + s->cmp->offsets[s->gidx * 2],
3186 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3187 s->char2b + i, 1);
06a2c219
GM
3188 }
3189}
3190
3191
80c32bcc
GM
3192#ifdef USE_X_TOOLKIT
3193
3e71d8f2 3194static struct frame *x_frame_of_widget P_ ((Widget));
80c32bcc 3195
3e71d8f2
GM
3196
3197/* Return the frame on which widget WIDGET is used.. Abort if frame
3198 cannot be determined. */
3199
e851c833 3200static struct frame *
3e71d8f2 3201x_frame_of_widget (widget)
80c32bcc 3202 Widget widget;
80c32bcc 3203{
80c32bcc 3204 struct x_display_info *dpyinfo;
5c187dee 3205 Lisp_Object tail;
3e71d8f2
GM
3206 struct frame *f;
3207
80c32bcc
GM
3208 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3209
3210 /* Find the top-level shell of the widget. Note that this function
3211 can be called when the widget is not yet realized, so XtWindow
3212 (widget) == 0. That's the reason we can't simply use
3213 x_any_window_to_frame. */
3214 while (!XtIsTopLevelShell (widget))
3215 widget = XtParent (widget);
3216
3217 /* Look for a frame with that top-level widget. Allocate the color
3218 on that frame to get the right gamma correction value. */
3219 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3220 if (GC_FRAMEP (XCAR (tail))
3221 && (f = XFRAME (XCAR (tail)),
3222 (f->output_data.nothing != 1
3223 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3224 && f->output_data.x->widget == widget)
3e71d8f2 3225 return f;
80c32bcc
GM
3226
3227 abort ();
3228}
3229
3e71d8f2
GM
3230
3231/* Allocate the color COLOR->pixel on the screen and display of
3232 widget WIDGET in colormap CMAP. If an exact match cannot be
3233 allocated, try the nearest color available. Value is non-zero
3234 if successful. This is called from lwlib. */
3235
3236int
3237x_alloc_nearest_color_for_widget (widget, cmap, color)
3238 Widget widget;
3239 Colormap cmap;
3240 XColor *color;
3241{
3242 struct frame *f = x_frame_of_widget (widget);
3243 return x_alloc_nearest_color (f, cmap, color);
3244}
3245
3246
80c32bcc
GM
3247#endif /* USE_X_TOOLKIT */
3248
3249
06a2c219
GM
3250/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3251 CMAP. If an exact match can't be allocated, try the nearest color
3252 available. Value is non-zero if successful. Set *COLOR to the
3253 color allocated. */
3254
3255int
80c32bcc
GM
3256x_alloc_nearest_color (f, cmap, color)
3257 struct frame *f;
06a2c219
GM
3258 Colormap cmap;
3259 XColor *color;
3260{
80c32bcc
GM
3261 Display *display = FRAME_X_DISPLAY (f);
3262 Screen *screen = FRAME_X_SCREEN (f);
3263 int rc;
3264
3265 gamma_correct (f, color);
3266 rc = XAllocColor (display, cmap, color);
06a2c219
GM
3267 if (rc == 0)
3268 {
3269 /* If we got to this point, the colormap is full, so we're going
3270 to try to get the next closest color. The algorithm used is
3271 a least-squares matching, which is what X uses for closest
3272 color matching with StaticColor visuals. */
3273 int nearest, i;
3274 unsigned long nearest_delta = ~0;
3275 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3276 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3277
3278 for (i = 0; i < ncells; ++i)
3279 cells[i].pixel = i;
3280 XQueryColors (display, cmap, cells, ncells);
3281
3282 for (nearest = i = 0; i < ncells; ++i)
3283 {
3284 long dred = (color->red >> 8) - (cells[i].red >> 8);
3285 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3286 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3287 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3288
3289 if (delta < nearest_delta)
3290 {
3291 nearest = i;
3292 nearest_delta = delta;
3293 }
3294 }
3295
3296 color->red = cells[nearest].red;
3297 color->green = cells[nearest].green;
3298 color->blue = cells[nearest].blue;
3299 rc = XAllocColor (display, cmap, color);
3300 }
3301
d9c545da
GM
3302#ifdef DEBUG_X_COLORS
3303 if (rc)
3304 register_color (color->pixel);
3305#endif /* DEBUG_X_COLORS */
3306
06a2c219
GM
3307 return rc;
3308}
3309
3310
d9c545da
GM
3311/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3312 It's necessary to do this instead of just using PIXEL directly to
3313 get color reference counts right. */
3314
3315unsigned long
3316x_copy_color (f, pixel)
3317 struct frame *f;
3318 unsigned long pixel;
3319{
3320 XColor color;
3321
3322 color.pixel = pixel;
3323 BLOCK_INPUT;
3324 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3325 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3326 UNBLOCK_INPUT;
3327#ifdef DEBUG_X_COLORS
3328 register_color (pixel);
3329#endif
3330 return color.pixel;
3331}
3332
3333
3e71d8f2
GM
3334/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3335 It's necessary to do this instead of just using PIXEL directly to
3336 get color reference counts right. */
3337
3338unsigned long
3339x_copy_dpy_color (dpy, cmap, pixel)
3340 Display *dpy;
3341 Colormap cmap;
3342 unsigned long pixel;
3343{
3344 XColor color;
3345
3346 color.pixel = pixel;
3347 BLOCK_INPUT;
3348 XQueryColor (dpy, cmap, &color);
3349 XAllocColor (dpy, cmap, &color);
3350 UNBLOCK_INPUT;
3351#ifdef DEBUG_X_COLORS
3352 register_color (pixel);
3353#endif
3354 return color.pixel;
3355}
3356
3357
06a2c219
GM
3358/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3359 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3360 If this produces the same color as PIXEL, try a color where all RGB
3361 values have DELTA added. Return the allocated color in *PIXEL.
3362 DISPLAY is the X display, CMAP is the colormap to operate on.
3363 Value is non-zero if successful. */
3364
3365static int
3366x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3367 struct frame *f;
3368 Display *display;
3369 Colormap cmap;
3370 unsigned long *pixel;
68c45bf0 3371 double factor;
06a2c219
GM
3372 int delta;
3373{
3374 XColor color, new;
3375 int success_p;
3376
3377 /* Get RGB color values. */
3378 color.pixel = *pixel;
3379 XQueryColor (display, cmap, &color);
3380
3381 /* Change RGB values by specified FACTOR. Avoid overflow! */
3382 xassert (factor >= 0);
3383 new.red = min (0xffff, factor * color.red);
3384 new.green = min (0xffff, factor * color.green);
3385 new.blue = min (0xffff, factor * color.blue);
3386
3387 /* Try to allocate the color. */
80c32bcc 3388 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3389 if (success_p)
3390 {
3391 if (new.pixel == *pixel)
3392 {
3393 /* If we end up with the same color as before, try adding
3394 delta to the RGB values. */
0d605c67 3395 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3396
3397 new.red = min (0xffff, delta + color.red);
3398 new.green = min (0xffff, delta + color.green);
3399 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3400 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3401 }
3402 else
3403 success_p = 1;
3404 *pixel = new.pixel;
3405 }
3406
3407 return success_p;
3408}
3409
3410
3411/* Set up the foreground color for drawing relief lines of glyph
3412 string S. RELIEF is a pointer to a struct relief containing the GC
3413 with which lines will be drawn. Use a color that is FACTOR or
3414 DELTA lighter or darker than the relief's background which is found
3415 in S->f->output_data.x->relief_background. If such a color cannot
3416 be allocated, use DEFAULT_PIXEL, instead. */
3417
3418static void
3419x_setup_relief_color (f, relief, factor, delta, default_pixel)
3420 struct frame *f;
3421 struct relief *relief;
68c45bf0 3422 double factor;
06a2c219
GM
3423 int delta;
3424 unsigned long default_pixel;
3425{
3426 XGCValues xgcv;
3427 struct x_output *di = f->output_data.x;
3428 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3429 unsigned long pixel;
3430 unsigned long background = di->relief_background;
43bd1b2b 3431 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3432 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3433 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3434
3435 xgcv.graphics_exposures = False;
3436 xgcv.line_width = 1;
3437
3438 /* Free previously allocated color. The color cell will be reused
3439 when it has been freed as many times as it was allocated, so this
3440 doesn't affect faces using the same colors. */
3441 if (relief->gc
3442 && relief->allocated_p)
3443 {
0d605c67 3444 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3445 relief->allocated_p = 0;
3446 }
3447
3448 /* Allocate new color. */
3449 xgcv.foreground = default_pixel;
3450 pixel = background;
dcd08bfb
GM
3451 if (dpyinfo->n_planes != 1
3452 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3453 {
3454 relief->allocated_p = 1;
3455 xgcv.foreground = relief->pixel = pixel;
3456 }
3457
3458 if (relief->gc == 0)
3459 {
dcd08bfb 3460 xgcv.stipple = dpyinfo->gray;
06a2c219 3461 mask |= GCStipple;
dcd08bfb 3462 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3463 }
3464 else
dcd08bfb 3465 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3466}
3467
3468
3469/* Set up colors for the relief lines around glyph string S. */
3470
3471static void
3472x_setup_relief_colors (s)
3473 struct glyph_string *s;
3474{
3475 struct x_output *di = s->f->output_data.x;
3476 unsigned long color;
3477
3478 if (s->face->use_box_color_for_shadows_p)
3479 color = s->face->box_color;
3480 else
3481 {
3482 XGCValues xgcv;
3483
3484 /* Get the background color of the face. */
3485 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3486 color = xgcv.background;
3487 }
3488
3489 if (di->white_relief.gc == 0
3490 || color != di->relief_background)
3491 {
3492 di->relief_background = color;
3493 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3494 WHITE_PIX_DEFAULT (s->f));
3495 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3496 BLACK_PIX_DEFAULT (s->f));
3497 }
3498}
3499
3500
3501/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3502 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3503 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3504 relief. LEFT_P non-zero means draw a relief on the left side of
3505 the rectangle. RIGHT_P non-zero means draw a relief on the right
3506 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3507 when drawing. */
3508
3509static void
3510x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3511 raised_p, left_p, right_p, clip_rect)
3512 struct frame *f;
3513 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3514 XRectangle *clip_rect;
3515{
3516 int i;
3517 GC gc;
3518
3519 if (raised_p)
3520 gc = f->output_data.x->white_relief.gc;
3521 else
3522 gc = f->output_data.x->black_relief.gc;
3523 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3524
3525 /* Top. */
3526 for (i = 0; i < width; ++i)
3527 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3528 left_x + i * left_p, top_y + i,
3529 right_x + 1 - i * right_p, top_y + i);
3530
3531 /* Left. */
3532 if (left_p)
3533 for (i = 0; i < width; ++i)
3534 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3535 left_x + i, top_y + i, left_x + i, bottom_y - i);
3536
3537 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3538 if (raised_p)
3539 gc = f->output_data.x->black_relief.gc;
3540 else
3541 gc = f->output_data.x->white_relief.gc;
3542 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3543
3544 /* Bottom. */
3545 for (i = 0; i < width; ++i)
3546 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3547 left_x + i * left_p, bottom_y - i,
3548 right_x + 1 - i * right_p, bottom_y - i);
3549
3550 /* Right. */
3551 if (right_p)
3552 for (i = 0; i < width; ++i)
3553 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3554 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3555
3556 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3557}
3558
3559
3560/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3561 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3562 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3563 left side of the rectangle. RIGHT_P non-zero means draw a line
3564 on the right side of the rectangle. CLIP_RECT is the clipping
3565 rectangle to use when drawing. */
3566
3567static void
3568x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3569 left_p, right_p, clip_rect)
3570 struct glyph_string *s;
3571 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3572 XRectangle *clip_rect;
3573{
3574 XGCValues xgcv;
3575
3576 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3577 XSetForeground (s->display, s->gc, s->face->box_color);
3578 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3579
3580 /* Top. */
3581 XFillRectangle (s->display, s->window, s->gc,
3582 left_x, top_y, right_x - left_x, width);
3583
3584 /* Left. */
3585 if (left_p)
3586 XFillRectangle (s->display, s->window, s->gc,
3587 left_x, top_y, width, bottom_y - top_y);
3588
3589 /* Bottom. */
3590 XFillRectangle (s->display, s->window, s->gc,
3591 left_x, bottom_y - width, right_x - left_x, width);
3592
3593 /* Right. */
3594 if (right_p)
3595 XFillRectangle (s->display, s->window, s->gc,
3596 right_x - width, top_y, width, bottom_y - top_y);
3597
3598 XSetForeground (s->display, s->gc, xgcv.foreground);
3599 XSetClipMask (s->display, s->gc, None);
3600}
3601
3602
3603/* Draw a box around glyph string S. */
3604
3605static void
3606x_draw_glyph_string_box (s)
3607 struct glyph_string *s;
3608{
3609 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3610 int left_p, right_p;
3611 struct glyph *last_glyph;
3612 XRectangle clip_rect;
3613
3614 last_x = window_box_right (s->w, s->area);
3615 if (s->row->full_width_p
3616 && !s->w->pseudo_window_p)
3617 {
110859fc 3618 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3619 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3620 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3621 }
3622
3623 /* The glyph that may have a right box line. */
b4192550 3624 last_glyph = (s->cmp || s->img
06a2c219
GM
3625 ? s->first_glyph
3626 : s->first_glyph + s->nchars - 1);
3627
3628 width = s->face->box_line_width;
3629 raised_p = s->face->box == FACE_RAISED_BOX;
3630 left_x = s->x;
3631 right_x = ((s->row->full_width_p
1da3fd71 3632 ? last_x - 1
a7aeb2de 3633 : min (last_x, s->x + s->background_width) - 1));
06a2c219
GM
3634 top_y = s->y;
3635 bottom_y = top_y + s->height - 1;
3636
3637 left_p = (s->first_glyph->left_box_line_p
3638 || (s->hl == DRAW_MOUSE_FACE
3639 && (s->prev == NULL
3640 || s->prev->hl != s->hl)));
3641 right_p = (last_glyph->right_box_line_p
3642 || (s->hl == DRAW_MOUSE_FACE
3643 && (s->next == NULL
3644 || s->next->hl != s->hl)));
3645
3646 x_get_glyph_string_clip_rect (s, &clip_rect);
3647
3648 if (s->face->box == FACE_SIMPLE_BOX)
3649 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3650 left_p, right_p, &clip_rect);
3651 else
3652 {
3653 x_setup_relief_colors (s);
3654 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3655 width, raised_p, left_p, right_p, &clip_rect);
3656 }
3657}
3658
3659
3660/* Draw foreground of image glyph string S. */
3661
3662static void
3663x_draw_image_foreground (s)
3664 struct glyph_string *s;
3665{
3666 int x;
95af8492 3667 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3668
3669 /* If first glyph of S has a left box line, start drawing it to the
3670 right of that line. */
3671 if (s->face->box != FACE_NO_BOX
3672 && s->first_glyph->left_box_line_p)
3673 x = s->x + s->face->box_line_width;
3674 else
3675 x = s->x;
3676
3677 /* If there is a margin around the image, adjust x- and y-position
3678 by that margin. */
3679 if (s->img->margin)
3680 {
3681 x += s->img->margin;
3682 y += s->img->margin;
3683 }
3684
3685 if (s->img->pixmap)
3686 {
3687 if (s->img->mask)
3688 {
3689 /* We can't set both a clip mask and use XSetClipRectangles
3690 because the latter also sets a clip mask. We also can't
3691 trust on the shape extension to be available
3692 (XShapeCombineRegion). So, compute the rectangle to draw
3693 manually. */
3694 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3695 | GCFunction);
3696 XGCValues xgcv;
3697 XRectangle clip_rect, image_rect, r;
3698
3699 xgcv.clip_mask = s->img->mask;
3700 xgcv.clip_x_origin = x;
3701 xgcv.clip_y_origin = y;
3702 xgcv.function = GXcopy;
3703 XChangeGC (s->display, s->gc, mask, &xgcv);
3704
3705 x_get_glyph_string_clip_rect (s, &clip_rect);
3706 image_rect.x = x;
3707 image_rect.y = y;
3708 image_rect.width = s->img->width;
3709 image_rect.height = s->img->height;
3710 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
3711 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3712 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
3713 }
3714 else
3715 {
3716 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3717 0, 0, s->img->width, s->img->height, x, y);
3718
3719 /* When the image has a mask, we can expect that at
3720 least part of a mouse highlight or a block cursor will
3721 be visible. If the image doesn't have a mask, make
3722 a block cursor visible by drawing a rectangle around
3723 the image. I believe it's looking better if we do
3724 nothing here for mouse-face. */
3725 if (s->hl == DRAW_CURSOR)
3726 XDrawRectangle (s->display, s->window, s->gc, x, y,
3727 s->img->width - 1, s->img->height - 1);
3728 }
3729 }
3730 else
3731 /* Draw a rectangle if image could not be loaded. */
3732 XDrawRectangle (s->display, s->window, s->gc, x, y,
3733 s->img->width - 1, s->img->height - 1);
3734}
3735
3736
3737/* Draw a relief around the image glyph string S. */
3738
3739static void
3740x_draw_image_relief (s)
3741 struct glyph_string *s;
3742{
3743 int x0, y0, x1, y1, thick, raised_p;
3744 XRectangle r;
3745 int x;
95af8492 3746 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3747
3748 /* If first glyph of S has a left box line, start drawing it to the
3749 right of that line. */
3750 if (s->face->box != FACE_NO_BOX
3751 && s->first_glyph->left_box_line_p)
3752 x = s->x + s->face->box_line_width;
3753 else
3754 x = s->x;
3755
3756 /* If there is a margin around the image, adjust x- and y-position
3757 by that margin. */
3758 if (s->img->margin)
3759 {
3760 x += s->img->margin;
3761 y += s->img->margin;
3762 }
3763
3764 if (s->hl == DRAW_IMAGE_SUNKEN
3765 || s->hl == DRAW_IMAGE_RAISED)
3766 {
9ea173e8 3767 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
3768 raised_p = s->hl == DRAW_IMAGE_RAISED;
3769 }
3770 else
3771 {
3772 thick = abs (s->img->relief);
3773 raised_p = s->img->relief > 0;
3774 }
3775
3776 x0 = x - thick;
3777 y0 = y - thick;
3778 x1 = x + s->img->width + thick - 1;
3779 y1 = y + s->img->height + thick - 1;
3780
3781 x_setup_relief_colors (s);
3782 x_get_glyph_string_clip_rect (s, &r);
3783 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
3784}
3785
3786
3787/* Draw the foreground of image glyph string S to PIXMAP. */
3788
3789static void
3790x_draw_image_foreground_1 (s, pixmap)
3791 struct glyph_string *s;
3792 Pixmap pixmap;
3793{
3794 int x;
95af8492 3795 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
3796
3797 /* If first glyph of S has a left box line, start drawing it to the
3798 right of that line. */
3799 if (s->face->box != FACE_NO_BOX
3800 && s->first_glyph->left_box_line_p)
3801 x = s->face->box_line_width;
3802 else
3803 x = 0;
3804
3805 /* If there is a margin around the image, adjust x- and y-position
3806 by that margin. */
3807 if (s->img->margin)
3808 {
3809 x += s->img->margin;
3810 y += s->img->margin;
3811 }
dc43ef94 3812
06a2c219
GM
3813 if (s->img->pixmap)
3814 {
3815 if (s->img->mask)
3816 {
3817 /* We can't set both a clip mask and use XSetClipRectangles
3818 because the latter also sets a clip mask. We also can't
3819 trust on the shape extension to be available
3820 (XShapeCombineRegion). So, compute the rectangle to draw
3821 manually. */
3822 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3823 | GCFunction);
3824 XGCValues xgcv;
3825
3826 xgcv.clip_mask = s->img->mask;
3827 xgcv.clip_x_origin = x;
3828 xgcv.clip_y_origin = y;
3829 xgcv.function = GXcopy;
3830 XChangeGC (s->display, s->gc, mask, &xgcv);
3831
3832 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3833 0, 0, s->img->width, s->img->height, x, y);
3834 XSetClipMask (s->display, s->gc, None);
3835 }
3836 else
3837 {
3838 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3839 0, 0, s->img->width, s->img->height, x, y);
3840
3841 /* When the image has a mask, we can expect that at
3842 least part of a mouse highlight or a block cursor will
3843 be visible. If the image doesn't have a mask, make
3844 a block cursor visible by drawing a rectangle around
3845 the image. I believe it's looking better if we do
3846 nothing here for mouse-face. */
3847 if (s->hl == DRAW_CURSOR)
3848 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3849 s->img->width - 1, s->img->height - 1);
3850 }
3851 }
3852 else
3853 /* Draw a rectangle if image could not be loaded. */
3854 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3855 s->img->width - 1, s->img->height - 1);
3856}
dc43ef94 3857
990ba854 3858
06a2c219
GM
3859/* Draw part of the background of glyph string S. X, Y, W, and H
3860 give the rectangle to draw. */
a9a5b0a5 3861
06a2c219
GM
3862static void
3863x_draw_glyph_string_bg_rect (s, x, y, w, h)
3864 struct glyph_string *s;
3865 int x, y, w, h;
3866{
3867 if (s->stippled_p)
3868 {
3869 /* Fill background with a stipple pattern. */
3870 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3871 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3872 XSetFillStyle (s->display, s->gc, FillSolid);
3873 }
3874 else
3875 x_clear_glyph_string_rect (s, x, y, w, h);
3876}
07e34cb0 3877
b5210ea7 3878
06a2c219 3879/* Draw image glyph string S.
dc43ef94 3880
06a2c219
GM
3881 s->y
3882 s->x +-------------------------
3883 | s->face->box
3884 |
3885 | +-------------------------
3886 | | s->img->margin
3887 | |
3888 | | +-------------------
3889 | | | the image
dc43ef94 3890
06a2c219 3891 */
dc43ef94 3892
06a2c219
GM
3893static void
3894x_draw_image_glyph_string (s)
3895 struct glyph_string *s;
3896{
3897 int x, y;
3898 int box_line_width = s->face->box_line_width;
3899 int margin = s->img->margin;
3900 int height;
3901 Pixmap pixmap = None;
3902
3903 height = s->height - 2 * box_line_width;
3904
3905 /* Fill background with face under the image. Do it only if row is
3906 taller than image or if image has a clip mask to reduce
3907 flickering. */
3908 s->stippled_p = s->face->stipple != 0;
3909 if (height > s->img->height
3910 || margin
3911 || s->img->mask
3912 || s->img->pixmap == 0
3913 || s->width != s->background_width)
3914 {
3915 if (box_line_width && s->first_glyph->left_box_line_p)
3916 x = s->x + box_line_width;
3917 else
3918 x = s->x;
3919
3920 y = s->y + box_line_width;
3921
3922 if (s->img->mask)
3923 {
3924 /* Create a pixmap as large as the glyph string Fill it with
3925 the background color. Copy the image to it, using its
3926 mask. Copy the temporary pixmap to the display. */
3927 Screen *screen = FRAME_X_SCREEN (s->f);
3928 int depth = DefaultDepthOfScreen (screen);
3929
3930 /* Create a pixmap as large as the glyph string. */
3931 pixmap = XCreatePixmap (s->display, s->window,
3932 s->background_width,
3933 s->height, depth);
3934
3935 /* Don't clip in the following because we're working on the
3936 pixmap. */
3937 XSetClipMask (s->display, s->gc, None);
3938
3939 /* Fill the pixmap with the background color/stipple. */
3940 if (s->stippled_p)
3941 {
3942 /* Fill background with a stipple pattern. */
3943 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3944 XFillRectangle (s->display, pixmap, s->gc,
3945 0, 0, s->background_width, s->height);
3946 XSetFillStyle (s->display, s->gc, FillSolid);
3947 }
3948 else
3949 {
3950 XGCValues xgcv;
3951 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
3952 &xgcv);
3953 XSetForeground (s->display, s->gc, xgcv.background);
3954 XFillRectangle (s->display, pixmap, s->gc,
3955 0, 0, s->background_width, s->height);
3956 XSetForeground (s->display, s->gc, xgcv.foreground);
3957 }
3958 }
3959 else
3960 /* Implementation idea: Is it possible to construct a mask?
3961 We could look at the color at the margins of the image, and
3962 say that this color is probably the background color of the
3963 image. */
3964 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3965
3966 s->background_filled_p = 1;
3967 }
dc43ef94 3968
06a2c219
GM
3969 /* Draw the foreground. */
3970 if (pixmap != None)
3971 {
3972 x_draw_image_foreground_1 (s, pixmap);
3973 x_set_glyph_string_clipping (s);
3974 XCopyArea (s->display, pixmap, s->window, s->gc,
3975 0, 0, s->background_width, s->height, s->x, s->y);
3976 XFreePixmap (s->display, pixmap);
3977 }
3978 else
3979 x_draw_image_foreground (s);
b5210ea7 3980
06a2c219
GM
3981 /* If we must draw a relief around the image, do it. */
3982 if (s->img->relief
3983 || s->hl == DRAW_IMAGE_RAISED
3984 || s->hl == DRAW_IMAGE_SUNKEN)
3985 x_draw_image_relief (s);
3986}
8c1a6a84 3987
990ba854 3988
06a2c219 3989/* Draw stretch glyph string S. */
dc43ef94 3990
06a2c219
GM
3991static void
3992x_draw_stretch_glyph_string (s)
3993 struct glyph_string *s;
3994{
3995 xassert (s->first_glyph->type == STRETCH_GLYPH);
3996 s->stippled_p = s->face->stipple != 0;
990ba854 3997
06a2c219
GM
3998 if (s->hl == DRAW_CURSOR
3999 && !x_stretch_cursor_p)
4000 {
4001 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4002 as wide as the stretch glyph. */
4003 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4004
06a2c219
GM
4005 /* Draw cursor. */
4006 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4007
06a2c219
GM
4008 /* Clear rest using the GC of the original non-cursor face. */
4009 if (width < s->background_width)
4010 {
4011 GC gc = s->face->gc;
4012 int x = s->x + width, y = s->y;
4013 int w = s->background_width - width, h = s->height;
4014 XRectangle r;
dc43ef94 4015
06a2c219
GM
4016 x_get_glyph_string_clip_rect (s, &r);
4017 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
97210f4e 4018
06a2c219
GM
4019 if (s->face->stipple)
4020 {
4021 /* Fill background with a stipple pattern. */
4022 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4023 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4024 XSetFillStyle (s->display, gc, FillSolid);
4025 }
4026 else
4027 {
4028 XGCValues xgcv;
4029 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4030 XSetForeground (s->display, gc, xgcv.background);
4031 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4032 XSetForeground (s->display, gc, xgcv.foreground);
4033 }
4034 }
4035 }
4036 else
4037 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4038 s->height);
4039
4040 s->background_filled_p = 1;
4041}
4042
4043
4044/* Draw glyph string S. */
4045
4046static void
4047x_draw_glyph_string (s)
4048 struct glyph_string *s;
4049{
4050 /* If S draws into the background of its successor, draw the
4051 background of the successor first so that S can draw into it.
4052 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4053 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4054 {
4055 xassert (s->next->img == NULL);
4056 x_set_glyph_string_gc (s->next);
4057 x_set_glyph_string_clipping (s->next);
4058 x_draw_glyph_string_background (s->next, 1);
4059 }
97210f4e 4060
06a2c219
GM
4061 /* Set up S->gc, set clipping and draw S. */
4062 x_set_glyph_string_gc (s);
4063 x_set_glyph_string_clipping (s);
4064
4065 switch (s->first_glyph->type)
4066 {
4067 case IMAGE_GLYPH:
4068 x_draw_image_glyph_string (s);
4069 break;
4070
4071 case STRETCH_GLYPH:
4072 x_draw_stretch_glyph_string (s);
4073 break;
4074
4075 case CHAR_GLYPH:
66ac4b0e
GM
4076 if (s->for_overlaps_p)
4077 s->background_filled_p = 1;
4078 else
4079 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4080 x_draw_glyph_string_foreground (s);
4081 break;
4082
b4192550
KH
4083 case COMPOSITE_GLYPH:
4084 if (s->for_overlaps_p || s->gidx > 0)
4085 s->background_filled_p = 1;
4086 else
4087 x_draw_glyph_string_background (s, 1);
4088 x_draw_composite_glyph_string_foreground (s);
4089 break;
4090
06a2c219
GM
4091 default:
4092 abort ();
4093 }
4094
66ac4b0e 4095 if (!s->for_overlaps_p)
06a2c219 4096 {
66ac4b0e
GM
4097 /* Draw underline. */
4098 if (s->face->underline_p)
4099 {
4100 unsigned long dy, h;
06a2c219 4101
66ac4b0e
GM
4102 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4103 h = 1;
4104 if (!XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &dy))
4105 dy = s->height - h;
06a2c219 4106
66ac4b0e
GM
4107 if (s->face->underline_defaulted_p)
4108 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4109 s->width, h);
4110 else
4111 {
4112 XGCValues xgcv;
4113 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4114 XSetForeground (s->display, s->gc, s->face->underline_color);
4115 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4116 s->width, h);
4117 XSetForeground (s->display, s->gc, xgcv.foreground);
4118 }
dc6f92b8 4119 }
07e34cb0 4120
66ac4b0e
GM
4121 /* Draw overline. */
4122 if (s->face->overline_p)
06a2c219 4123 {
66ac4b0e
GM
4124 unsigned long dy = 0, h = 1;
4125
4126 if (s->face->overline_color_defaulted_p)
4127 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4128 s->width, h);
4129 else
4130 {
4131 XGCValues xgcv;
4132 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4133 XSetForeground (s->display, s->gc, s->face->overline_color);
4134 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4135 s->width, h);
4136 XSetForeground (s->display, s->gc, xgcv.foreground);
4137 }
06a2c219 4138 }
06a2c219 4139
66ac4b0e
GM
4140 /* Draw strike-through. */
4141 if (s->face->strike_through_p)
06a2c219 4142 {
66ac4b0e
GM
4143 unsigned long h = 1;
4144 unsigned long dy = (s->height - h) / 2;
4145
4146 if (s->face->strike_through_color_defaulted_p)
4147 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4148 s->width, h);
4149 else
4150 {
4151 XGCValues xgcv;
4152 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4153 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4154 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4155 s->width, h);
4156 XSetForeground (s->display, s->gc, xgcv.foreground);
4157 }
06a2c219 4158 }
06a2c219 4159
66ac4b0e
GM
4160 /* Draw relief. */
4161 if (s->face->box != FACE_NO_BOX)
4162 x_draw_glyph_string_box (s);
4163 }
06a2c219
GM
4164
4165 /* Reset clipping. */
4166 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4167}
07e34cb0 4168
06a2c219 4169
b4192550
KH
4170static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4171 struct face **, int));
06a2c219 4172
06a2c219 4173
209f68d9
GM
4174/* Fill glyph string S with composition components specified by S->cmp.
4175
b4192550
KH
4176 FACES is an array of faces for all components of this composition.
4177 S->gidx is the index of the first component for S.
4178 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4179 use its physical height for clipping.
06a2c219 4180
b4192550 4181 Value is the index of a component not in S. */
07e34cb0 4182
b4192550
KH
4183static int
4184x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4185 struct glyph_string *s;
b4192550 4186 struct face **faces;
66ac4b0e 4187 int overlaps_p;
07e34cb0 4188{
b4192550 4189 int i;
06a2c219 4190
b4192550 4191 xassert (s);
06a2c219 4192
b4192550 4193 s->for_overlaps_p = overlaps_p;
06a2c219 4194
b4192550
KH
4195 s->face = faces[s->gidx];
4196 s->font = s->face->font;
4197 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4198
b4192550
KH
4199 /* For all glyphs of this composition, starting at the offset
4200 S->gidx, until we reach the end of the definition or encounter a
4201 glyph that requires the different face, add it to S. */
4202 ++s->nchars;
4203 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4204 ++s->nchars;
06a2c219 4205
b4192550
KH
4206 /* All glyph strings for the same composition has the same width,
4207 i.e. the width set for the first component of the composition. */
06a2c219 4208
06a2c219
GM
4209 s->width = s->first_glyph->pixel_width;
4210
4211 /* If the specified font could not be loaded, use the frame's
4212 default font, but record the fact that we couldn't load it in
4213 the glyph string so that we can draw rectangles for the
4214 characters of the glyph string. */
4215 if (s->font == NULL)
4216 {
4217 s->font_not_found_p = 1;
4218 s->font = FRAME_FONT (s->f);
4219 }
4220
4221 /* Adjust base line for subscript/superscript text. */
4222 s->ybase += s->first_glyph->voffset;
4223
4224 xassert (s->face && s->face->gc);
4225
4226 /* This glyph string must always be drawn with 16-bit functions. */
4227 s->two_byte_p = 1;
b4192550
KH
4228
4229 return s->gidx + s->nchars;
06a2c219
GM
4230}
4231
4232
209f68d9
GM
4233/* Fill glyph string S from a sequence of character glyphs.
4234
06a2c219 4235 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4236 first glyph to consider, END is the index of the last + 1.
4237 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4238 use its physical height for clipping.
66ac4b0e
GM
4239
4240 Value is the index of the first glyph not in S. */
06a2c219
GM
4241
4242static int
66ac4b0e 4243x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4244 struct glyph_string *s;
4245 int face_id;
66ac4b0e 4246 int start, end, overlaps_p;
06a2c219
GM
4247{
4248 struct glyph *glyph, *last;
4249 int voffset;
ee569018 4250 int glyph_not_available_p;
06a2c219 4251
06a2c219
GM
4252 xassert (s->f == XFRAME (s->w->frame));
4253 xassert (s->nchars == 0);
4254 xassert (start >= 0 && end > start);
4255
66ac4b0e 4256 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4257 glyph = s->row->glyphs[s->area] + start;
4258 last = s->row->glyphs[s->area] + end;
4259 voffset = glyph->voffset;
4260
ee569018
KH
4261 glyph_not_available_p = glyph->glyph_not_available_p;
4262
06a2c219
GM
4263 while (glyph < last
4264 && glyph->type == CHAR_GLYPH
4265 && glyph->voffset == voffset
ee569018
KH
4266 /* Same face id implies same font, nowadays. */
4267 && glyph->face_id == face_id
4268 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4269 {
ee569018
KH
4270 int two_byte_p;
4271
06a2c219 4272 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4273 s->char2b + s->nchars,
4274 &two_byte_p);
4275 s->two_byte_p = two_byte_p;
06a2c219
GM
4276 ++s->nchars;
4277 xassert (s->nchars <= end - start);
4278 s->width += glyph->pixel_width;
4279 ++glyph;
4280 }
4281
4282 s->font = s->face->font;
4283 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4284
4285 /* If the specified font could not be loaded, use the frame's font,
4286 but record the fact that we couldn't load it in
4287 S->font_not_found_p so that we can draw rectangles for the
4288 characters of the glyph string. */
ee569018 4289 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4290 {
4291 s->font_not_found_p = 1;
4292 s->font = FRAME_FONT (s->f);
4293 }
4294
4295 /* Adjust base line for subscript/superscript text. */
4296 s->ybase += voffset;
66ac4b0e 4297
06a2c219
GM
4298 xassert (s->face && s->face->gc);
4299 return glyph - s->row->glyphs[s->area];
07e34cb0 4300}
dc6f92b8 4301
06a2c219
GM
4302
4303/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4304
dfcf069d 4305static void
06a2c219
GM
4306x_fill_image_glyph_string (s)
4307 struct glyph_string *s;
4308{
4309 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4310 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4311 xassert (s->img);
43d120d8 4312 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4313 s->font = s->face->font;
4314 s->width = s->first_glyph->pixel_width;
4315
4316 /* Adjust base line for subscript/superscript text. */
4317 s->ybase += s->first_glyph->voffset;
4318}
4319
4320
209f68d9 4321/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4322
209f68d9
GM
4323 ROW is the glyph row in which the glyphs are found, AREA is the
4324 area within the row. START is the index of the first glyph to
4325 consider, END is the index of the last + 1.
4326
4327 Value is the index of the first glyph not in S. */
4328
4329static int
4330x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4331 struct glyph_string *s;
209f68d9
GM
4332 struct glyph_row *row;
4333 enum glyph_row_area area;
4334 int start, end;
06a2c219 4335{
209f68d9
GM
4336 struct glyph *glyph, *last;
4337 int voffset, face_id;
4338
06a2c219 4339 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4340
4341 glyph = s->row->glyphs[s->area] + start;
4342 last = s->row->glyphs[s->area] + end;
4343 face_id = glyph->face_id;
4344 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4345 s->font = s->face->font;
209f68d9
GM
4346 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4347 s->width = glyph->pixel_width;
4348 voffset = glyph->voffset;
4349
4350 for (++glyph;
4351 (glyph < last
4352 && glyph->type == STRETCH_GLYPH
4353 && glyph->voffset == voffset
4354 && glyph->face_id == face_id);
4355 ++glyph)
4356 s->width += glyph->pixel_width;
06a2c219
GM
4357
4358 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4359 s->ybase += voffset;
4360
4361 xassert (s->face && s->face->gc);
4362 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4363}
4364
4365
4366/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4367 of XChar2b structures for S; it can't be allocated in
4368 x_init_glyph_string because it must be allocated via `alloca'. W
4369 is the window on which S is drawn. ROW and AREA are the glyph row
4370 and area within the row from which S is constructed. START is the
4371 index of the first glyph structure covered by S. HL is a
4372 face-override for drawing S. */
4373
4374static void
4375x_init_glyph_string (s, char2b, w, row, area, start, hl)
4376 struct glyph_string *s;
4377 XChar2b *char2b;
4378 struct window *w;
4379 struct glyph_row *row;
4380 enum glyph_row_area area;
4381 int start;
4382 enum draw_glyphs_face hl;
4383{
4384 bzero (s, sizeof *s);
4385 s->w = w;
4386 s->f = XFRAME (w->frame);
4387 s->display = FRAME_X_DISPLAY (s->f);
4388 s->window = FRAME_X_WINDOW (s->f);
4389 s->char2b = char2b;
4390 s->hl = hl;
4391 s->row = row;
4392 s->area = area;
4393 s->first_glyph = row->glyphs[area] + start;
4394 s->height = row->height;
4395 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4396
9ea173e8
GM
4397 /* Display the internal border below the tool-bar window. */
4398 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4399 s->y -= s->f->output_data.x->internal_border_width;
4400
4401 s->ybase = s->y + row->ascent;
4402}
4403
4404
4405/* Set background width of glyph string S. START is the index of the
4406 first glyph following S. LAST_X is the right-most x-position + 1
4407 in the drawing area. */
4408
4409static INLINE void
4410x_set_glyph_string_background_width (s, start, last_x)
4411 struct glyph_string *s;
4412 int start;
4413 int last_x;
4414{
4415 /* If the face of this glyph string has to be drawn to the end of
4416 the drawing area, set S->extends_to_end_of_line_p. */
4417 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4418
4419 if (start == s->row->used[s->area]
4420 && s->hl == DRAW_NORMAL_TEXT
4421 && ((s->area == TEXT_AREA && s->row->fill_line_p)
4422 || s->face->background != default_face->background
4423 || s->face->stipple != default_face->stipple))
4424 s->extends_to_end_of_line_p = 1;
4425
4426 /* If S extends its face to the end of the line, set its
4427 background_width to the distance to the right edge of the drawing
4428 area. */
4429 if (s->extends_to_end_of_line_p)
1da3fd71 4430 s->background_width = last_x - s->x + 1;
06a2c219
GM
4431 else
4432 s->background_width = s->width;
4433}
4434
4435
4436/* Add a glyph string for a stretch glyph to the list of strings
4437 between HEAD and TAIL. START is the index of the stretch glyph in
4438 row area AREA of glyph row ROW. END is the index of the last glyph
4439 in that glyph row area. X is the current output position assigned
4440 to the new glyph string constructed. HL overrides that face of the
4441 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4442 is the right-most x-position of the drawing area. */
4443
8abee2e1
DL
4444/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4445 and below -- keep them on one line. */
4446#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4447 do \
4448 { \
4449 s = (struct glyph_string *) alloca (sizeof *s); \
4450 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4451 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4452 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4453 s->x = (X); \
4454 } \
4455 while (0)
4456
4457
4458/* Add a glyph string for an image glyph to the list of strings
4459 between HEAD and TAIL. START is the index of the image glyph in
4460 row area AREA of glyph row ROW. END is the index of the last glyph
4461 in that glyph row area. X is the current output position assigned
4462 to the new glyph string constructed. HL overrides that face of the
4463 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4464 is the right-most x-position of the drawing area. */
4465
8abee2e1 4466#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4467 do \
4468 { \
4469 s = (struct glyph_string *) alloca (sizeof *s); \
4470 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4471 x_fill_image_glyph_string (s); \
4472 x_append_glyph_string (&HEAD, &TAIL, s); \
4473 ++START; \
4474 s->x = (X); \
4475 } \
4476 while (0)
4477
4478
4479/* Add a glyph string for a sequence of character glyphs to the list
4480 of strings between HEAD and TAIL. START is the index of the first
4481 glyph in row area AREA of glyph row ROW that is part of the new
4482 glyph string. END is the index of the last glyph in that glyph row
4483 area. X is the current output position assigned to the new glyph
4484 string constructed. HL overrides that face of the glyph; e.g. it
4485 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4486 right-most x-position of the drawing area. */
4487
8abee2e1 4488#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4489 do \
4490 { \
3e71d8f2 4491 int c, face_id; \
06a2c219
GM
4492 XChar2b *char2b; \
4493 \
43d120d8 4494 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4495 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4496 \
b4192550
KH
4497 s = (struct glyph_string *) alloca (sizeof *s); \
4498 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4499 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4500 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4501 s->x = (X); \
4502 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4503 OVERLAPS_P); \
06a2c219
GM
4504 } \
4505 while (0)
4506
4507
b4192550
KH
4508/* Add a glyph string for a composite sequence to the list of strings
4509 between HEAD and TAIL. START is the index of the first glyph in
4510 row area AREA of glyph row ROW that is part of the new glyph
4511 string. END is the index of the last glyph in that glyph row area.
4512 X is the current output position assigned to the new glyph string
4513 constructed. HL overrides that face of the glyph; e.g. it is
4514 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4515 x-position of the drawing area. */
4516
6c27ec25 4517#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4518 do { \
43d120d8
KH
4519 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4520 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4521 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4522 struct composition *cmp = composition_table[cmp_id]; \
4523 int glyph_len = cmp->glyph_len; \
4524 XChar2b *char2b; \
4525 struct face **faces; \
4526 struct glyph_string *first_s = NULL; \
4527 int n; \
4528 \
ee569018 4529 base_face = base_face->ascii_face; \
b4192550
KH
4530 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4531 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4532 /* At first, fill in `char2b' and `faces'. */ \
4533 for (n = 0; n < glyph_len; n++) \
4534 { \
43d120d8 4535 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4536 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4537 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4538 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4539 this_face_id, char2b + n, 1); \
b4192550
KH
4540 } \
4541 \
4542 /* Make glyph_strings for each glyph sequence that is drawable by \
4543 the same face, and append them to HEAD/TAIL. */ \
4544 for (n = 0; n < cmp->glyph_len;) \
4545 { \
4546 s = (struct glyph_string *) alloca (sizeof *s); \
4547 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4548 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4549 s->cmp = cmp; \
4550 s->gidx = n; \
b4192550
KH
4551 s->x = (X); \
4552 \
4553 if (n == 0) \
4554 first_s = s; \
4555 \
4556 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4557 } \
4558 \
4559 ++START; \
4560 s = first_s; \
4561 } while (0)
4562
4563
06a2c219
GM
4564/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4565 of AREA of glyph row ROW on window W between indices START and END.
4566 HL overrides the face for drawing glyph strings, e.g. it is
4567 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4568 x-positions of the drawing area.
4569
4570 This is an ugly monster macro construct because we must use alloca
4571 to allocate glyph strings (because x_draw_glyphs can be called
4572 asynchronously). */
4573
8abee2e1 4574#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4575 do \
4576 { \
4577 HEAD = TAIL = NULL; \
4578 while (START < END) \
4579 { \
4580 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4581 switch (first_glyph->type) \
4582 { \
4583 case CHAR_GLYPH: \
4584 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4585 TAIL, HL, X, LAST_X, \
4586 OVERLAPS_P); \
06a2c219
GM
4587 break; \
4588 \
b4192550
KH
4589 case COMPOSITE_GLYPH: \
4590 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
4591 HEAD, TAIL, HL, X, LAST_X,\
4592 OVERLAPS_P); \
4593 break; \
4594 \
06a2c219
GM
4595 case STRETCH_GLYPH: \
4596 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
4597 HEAD, TAIL, HL, X, LAST_X); \
4598 break; \
4599 \
4600 case IMAGE_GLYPH: \
4601 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
4602 TAIL, HL, X, LAST_X); \
4603 break; \
4604 \
4605 default: \
4606 abort (); \
4607 } \
4608 \
4609 x_set_glyph_string_background_width (s, START, LAST_X); \
4610 (X) += s->width; \
4611 } \
4612 } \
4613 while (0)
4614
4615
4616/* Draw glyphs between START and END in AREA of ROW on window W,
4617 starting at x-position X. X is relative to AREA in W. HL is a
4618 face-override with the following meaning:
4619
4620 DRAW_NORMAL_TEXT draw normally
4621 DRAW_CURSOR draw in cursor face
4622 DRAW_MOUSE_FACE draw in mouse face.
4623 DRAW_INVERSE_VIDEO draw in mode line face
4624 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
4625 DRAW_IMAGE_RAISED draw an image with a raised relief around it
4626
4627 If REAL_START is non-null, return in *REAL_START the real starting
4628 position for display. This can be different from START in case
4629 overlapping glyphs must be displayed. If REAL_END is non-null,
4630 return in *REAL_END the real end position for display. This can be
4631 different from END in case overlapping glyphs must be displayed.
4632
66ac4b0e
GM
4633 If OVERLAPS_P is non-zero, draw only the foreground of characters
4634 and clip to the physical height of ROW.
4635
06a2c219
GM
4636 Value is the x-position reached, relative to AREA of W. */
4637
4638static int
66ac4b0e
GM
4639x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
4640 overlaps_p)
06a2c219
GM
4641 struct window *w;
4642 int x;
4643 struct glyph_row *row;
4644 enum glyph_row_area area;
4645 int start, end;
4646 enum draw_glyphs_face hl;
4647 int *real_start, *real_end;
66ac4b0e 4648 int overlaps_p;
dc6f92b8 4649{
06a2c219
GM
4650 struct glyph_string *head, *tail;
4651 struct glyph_string *s;
4652 int last_x, area_width;
4653 int x_reached;
4654 int i, j;
4655
4656 /* Let's rather be paranoid than getting a SEGV. */
4657 start = max (0, start);
4658 end = min (end, row->used[area]);
4659 if (real_start)
4660 *real_start = start;
4661 if (real_end)
4662 *real_end = end;
4663
4664 /* Translate X to frame coordinates. Set last_x to the right
4665 end of the drawing area. */
4666 if (row->full_width_p)
4667 {
4668 /* X is relative to the left edge of W, without scroll bars
4669 or flag areas. */
4670 struct frame *f = XFRAME (w->frame);
110859fc 4671 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 4672 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 4673
06a2c219
GM
4674 x += window_left_x;
4675 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
4676 last_x = window_left_x + area_width;
4677
4678 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4679 {
110859fc 4680 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
4681 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
4682 last_x += width;
4683 else
4684 x -= width;
4685 }
dc6f92b8 4686
b9432a85
GM
4687 x += FRAME_INTERNAL_BORDER_WIDTH (f);
4688 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
4689 }
4690 else
dc6f92b8 4691 {
06a2c219
GM
4692 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
4693 area_width = window_box_width (w, area);
4694 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
4695 }
4696
06a2c219
GM
4697 /* Build a doubly-linked list of glyph_string structures between
4698 head and tail from what we have to draw. Note that the macro
4699 BUILD_GLYPH_STRINGS will modify its start parameter. That's
4700 the reason we use a separate variable `i'. */
4701 i = start;
66ac4b0e
GM
4702 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
4703 overlaps_p);
06a2c219
GM
4704 if (tail)
4705 x_reached = tail->x + tail->background_width;
4706 else
4707 x_reached = x;
90e65f07 4708
06a2c219
GM
4709 /* If there are any glyphs with lbearing < 0 or rbearing > width in
4710 the row, redraw some glyphs in front or following the glyph
4711 strings built above. */
66ac4b0e 4712 if (!overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
4713 {
4714 int dummy_x = 0;
4715 struct glyph_string *h, *t;
4716
4717 /* Compute overhangs for all glyph strings. */
4718 for (s = head; s; s = s->next)
4719 x_compute_glyph_string_overhangs (s);
4720
4721 /* Prepend glyph strings for glyphs in front of the first glyph
4722 string that are overwritten because of the first glyph
4723 string's left overhang. The background of all strings
4724 prepended must be drawn because the first glyph string
4725 draws over it. */
4726 i = x_left_overwritten (head);
4727 if (i >= 0)
4728 {
4729 j = i;
4730 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
4731 DRAW_NORMAL_TEXT, dummy_x, last_x,
4732 overlaps_p);
06a2c219
GM
4733 start = i;
4734 if (real_start)
4735 *real_start = start;
4736 x_compute_overhangs_and_x (t, head->x, 1);
4737 x_prepend_glyph_string_lists (&head, &tail, h, t);
4738 }
58769bee 4739
06a2c219
GM
4740 /* Prepend glyph strings for glyphs in front of the first glyph
4741 string that overwrite that glyph string because of their
4742 right overhang. For these strings, only the foreground must
4743 be drawn, because it draws over the glyph string at `head'.
4744 The background must not be drawn because this would overwrite
4745 right overhangs of preceding glyphs for which no glyph
4746 strings exist. */
4747 i = x_left_overwriting (head);
4748 if (i >= 0)
4749 {
4750 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
4751 DRAW_NORMAL_TEXT, dummy_x, last_x,
4752 overlaps_p);
06a2c219
GM
4753 for (s = h; s; s = s->next)
4754 s->background_filled_p = 1;
4755 if (real_start)
4756 *real_start = i;
4757 x_compute_overhangs_and_x (t, head->x, 1);
4758 x_prepend_glyph_string_lists (&head, &tail, h, t);
4759 }
dbcb258a 4760
06a2c219
GM
4761 /* Append glyphs strings for glyphs following the last glyph
4762 string tail that are overwritten by tail. The background of
4763 these strings has to be drawn because tail's foreground draws
4764 over it. */
4765 i = x_right_overwritten (tail);
4766 if (i >= 0)
4767 {
4768 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4769 DRAW_NORMAL_TEXT, x, last_x,
4770 overlaps_p);
06a2c219
GM
4771 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4772 x_append_glyph_string_lists (&head, &tail, h, t);
4773 if (real_end)
4774 *real_end = i;
4775 }
dc6f92b8 4776
06a2c219
GM
4777 /* Append glyph strings for glyphs following the last glyph
4778 string tail that overwrite tail. The foreground of such
4779 glyphs has to be drawn because it writes into the background
4780 of tail. The background must not be drawn because it could
4781 paint over the foreground of following glyphs. */
4782 i = x_right_overwriting (tail);
4783 if (i >= 0)
4784 {
4785 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4786 DRAW_NORMAL_TEXT, x, last_x,
4787 overlaps_p);
06a2c219
GM
4788 for (s = h; s; s = s->next)
4789 s->background_filled_p = 1;
4790 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4791 x_append_glyph_string_lists (&head, &tail, h, t);
4792 if (real_end)
4793 *real_end = i;
4794 }
4795 }
58769bee 4796
06a2c219
GM
4797 /* Draw all strings. */
4798 for (s = head; s; s = s->next)
4799 x_draw_glyph_string (s);
dc6f92b8 4800
06a2c219
GM
4801 /* Value is the x-position up to which drawn, relative to AREA of W.
4802 This doesn't include parts drawn because of overhangs. */
4803 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
4804 if (!row->full_width_p)
4805 {
4806 if (area > LEFT_MARGIN_AREA)
4807 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
4808 if (area > TEXT_AREA)
4809 x_reached -= window_box_width (w, TEXT_AREA);
4810 }
4811 return x_reached;
4812}
dc6f92b8 4813
dc6f92b8 4814
66ac4b0e
GM
4815/* Fix the display of area AREA of overlapping row ROW in window W. */
4816
4817static void
4818x_fix_overlapping_area (w, row, area)
4819 struct window *w;
4820 struct glyph_row *row;
4821 enum glyph_row_area area;
4822{
4823 int i, x;
4824
4825 BLOCK_INPUT;
4826
4827 if (area == LEFT_MARGIN_AREA)
4828 x = 0;
4829 else if (area == TEXT_AREA)
4830 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
4831 else
4832 x = (window_box_width (w, LEFT_MARGIN_AREA)
4833 + window_box_width (w, TEXT_AREA));
4834
4835 for (i = 0; i < row->used[area];)
4836 {
4837 if (row->glyphs[area][i].overlaps_vertically_p)
4838 {
4839 int start = i, start_x = x;
4840
4841 do
4842 {
4843 x += row->glyphs[area][i].pixel_width;
4844 ++i;
4845 }
4846 while (i < row->used[area]
4847 && row->glyphs[area][i].overlaps_vertically_p);
4848
4849 x_draw_glyphs (w, start_x, row, area, start, i,
4850 (row->inverse_p
4851 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
4852 NULL, NULL, 1);
4853 }
4854 else
4855 {
4856 x += row->glyphs[area][i].pixel_width;
4857 ++i;
4858 }
4859 }
4860
4861 UNBLOCK_INPUT;
4862}
4863
4864
06a2c219
GM
4865/* Output LEN glyphs starting at START at the nominal cursor position.
4866 Advance the nominal cursor over the text. The global variable
4867 updated_window contains the window being updated, updated_row is
4868 the glyph row being updated, and updated_area is the area of that
4869 row being updated. */
dc6f92b8 4870
06a2c219
GM
4871static void
4872x_write_glyphs (start, len)
4873 struct glyph *start;
4874 int len;
4875{
4876 int x, hpos, real_start, real_end;
d9cdbb3d 4877
06a2c219 4878 xassert (updated_window && updated_row);
dc6f92b8 4879 BLOCK_INPUT;
06a2c219
GM
4880
4881 /* Write glyphs. */
dc6f92b8 4882
06a2c219
GM
4883 hpos = start - updated_row->glyphs[updated_area];
4884 x = x_draw_glyphs (updated_window, output_cursor.x,
4885 updated_row, updated_area,
4886 hpos, hpos + len,
4887 (updated_row->inverse_p
4888 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
66ac4b0e 4889 &real_start, &real_end, 0);
b30ec466 4890
06a2c219
GM
4891 /* If we drew over the cursor, note that it is not visible any more. */
4892 note_overwritten_text_cursor (updated_window, real_start,
4893 real_end - real_start);
dc6f92b8
JB
4894
4895 UNBLOCK_INPUT;
06a2c219
GM
4896
4897 /* Advance the output cursor. */
4898 output_cursor.hpos += len;
4899 output_cursor.x = x;
dc6f92b8
JB
4900}
4901
0cdd0c9f 4902
06a2c219 4903/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 4904
06a2c219
GM
4905static void
4906x_insert_glyphs (start, len)
4907 struct glyph *start;
4908 register int len;
4909{
4910 struct frame *f;
4911 struct window *w;
4912 int line_height, shift_by_width, shifted_region_width;
4913 struct glyph_row *row;
4914 struct glyph *glyph;
4915 int frame_x, frame_y, hpos, real_start, real_end;
58769bee 4916
06a2c219 4917 xassert (updated_window && updated_row);
0cdd0c9f 4918 BLOCK_INPUT;
06a2c219
GM
4919 w = updated_window;
4920 f = XFRAME (WINDOW_FRAME (w));
4921
4922 /* Get the height of the line we are in. */
4923 row = updated_row;
4924 line_height = row->height;
4925
4926 /* Get the width of the glyphs to insert. */
4927 shift_by_width = 0;
4928 for (glyph = start; glyph < start + len; ++glyph)
4929 shift_by_width += glyph->pixel_width;
4930
4931 /* Get the width of the region to shift right. */
4932 shifted_region_width = (window_box_width (w, updated_area)
4933 - output_cursor.x
4934 - shift_by_width);
4935
4936 /* Shift right. */
4937 frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x);
4938 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
4939 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
4940 f->output_data.x->normal_gc,
4941 frame_x, frame_y,
4942 shifted_region_width, line_height,
4943 frame_x + shift_by_width, frame_y);
4944
4945 /* Write the glyphs. */
4946 hpos = start - row->glyphs[updated_area];
4947 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
66ac4b0e 4948 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
06a2c219
GM
4949 note_overwritten_text_cursor (w, real_start, real_end - real_start);
4950
4951 /* Advance the output cursor. */
4952 output_cursor.hpos += len;
4953 output_cursor.x += shift_by_width;
0cdd0c9f
RS
4954 UNBLOCK_INPUT;
4955}
0cdd0c9f 4956
0cdd0c9f 4957
06a2c219
GM
4958/* Delete N glyphs at the nominal cursor position. Not implemented
4959 for X frames. */
c83febd7
RS
4960
4961static void
06a2c219
GM
4962x_delete_glyphs (n)
4963 register int n;
c83febd7 4964{
06a2c219 4965 abort ();
c83febd7
RS
4966}
4967
0cdd0c9f 4968
06a2c219
GM
4969/* Erase the current text line from the nominal cursor position
4970 (inclusive) to pixel column TO_X (exclusive). The idea is that
4971 everything from TO_X onward is already erased.
4972
4973 TO_X is a pixel position relative to updated_area of
4974 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 4975
06a2c219
GM
4976static void
4977x_clear_end_of_line (to_x)
4978 int to_x;
4979{
4980 struct frame *f;
4981 struct window *w = updated_window;
4982 int max_x, min_y, max_y;
4983 int from_x, from_y, to_y;
4984
4985 xassert (updated_window && updated_row);
4986 f = XFRAME (w->frame);
4987
4988 if (updated_row->full_width_p)
4989 {
4990 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
4991 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4992 && !w->pseudo_window_p)
4993 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 4994 }
06a2c219
GM
4995 else
4996 max_x = window_box_width (w, updated_area);
4997 max_y = window_text_bottom_y (w);
dc6f92b8 4998
06a2c219
GM
4999 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5000 of window. For TO_X > 0, truncate to end of drawing area. */
5001 if (to_x == 0)
5002 return;
5003 else if (to_x < 0)
5004 to_x = max_x;
5005 else
5006 to_x = min (to_x, max_x);
dbc4e1c1 5007
06a2c219
GM
5008 to_y = min (max_y, output_cursor.y + updated_row->height);
5009
5010 /* Notice if the cursor will be cleared by this operation. */
5011 if (!updated_row->full_width_p)
5012 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
dbc4e1c1 5013
06a2c219
GM
5014 from_x = output_cursor.x;
5015
5016 /* Translate to frame coordinates. */
5017 if (updated_row->full_width_p)
5018 {
5019 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5020 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5021 }
0cdd0c9f
RS
5022 else
5023 {
06a2c219
GM
5024 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5025 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5026 }
5027
045dee35 5028 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5029 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5030 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5031
5032 /* Prevent inadvertently clearing to end of the X window. */
5033 if (to_x > from_x && to_y > from_y)
5034 {
5035 BLOCK_INPUT;
5036 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5037 from_x, from_y, to_x - from_x, to_y - from_y,
5038 False);
5039 UNBLOCK_INPUT;
0cdd0c9f 5040 }
0cdd0c9f 5041}
dbc4e1c1 5042
0cdd0c9f 5043
06a2c219 5044/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5045 frame. Otherwise clear the selected frame. */
06a2c219
GM
5046
5047static void
5048x_clear_frame ()
0cdd0c9f 5049{
06a2c219 5050 struct frame *f;
0cdd0c9f 5051
06a2c219
GM
5052 if (updating_frame)
5053 f = updating_frame;
0cdd0c9f 5054 else
b86bd3dd 5055 f = SELECTED_FRAME ();
58769bee 5056
06a2c219
GM
5057 /* Clearing the frame will erase any cursor, so mark them all as no
5058 longer visible. */
5059 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5060 output_cursor.hpos = output_cursor.vpos = 0;
5061 output_cursor.x = -1;
5062
5063 /* We don't set the output cursor here because there will always
5064 follow an explicit cursor_to. */
5065 BLOCK_INPUT;
5066 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5067
5068 /* We have to clear the scroll bars, too. If we have changed
5069 colors or something like that, then they should be notified. */
5070 x_scroll_bar_clear (f);
0cdd0c9f 5071
06a2c219
GM
5072 XFlush (FRAME_X_DISPLAY (f));
5073 UNBLOCK_INPUT;
dc6f92b8 5074}
06a2c219
GM
5075
5076
dc6f92b8 5077\f
dbc4e1c1
JB
5078/* Invert the middle quarter of the frame for .15 sec. */
5079
06a2c219
GM
5080/* We use the select system call to do the waiting, so we have to make
5081 sure it's available. If it isn't, we just won't do visual bells. */
5082
dbc4e1c1
JB
5083#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5084
06a2c219
GM
5085
5086/* Subtract the `struct timeval' values X and Y, storing the result in
5087 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5088
5089static int
5090timeval_subtract (result, x, y)
5091 struct timeval *result, x, y;
5092{
06a2c219
GM
5093 /* Perform the carry for the later subtraction by updating y. This
5094 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5095 if (x.tv_usec < y.tv_usec)
5096 {
5097 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5098 y.tv_usec -= 1000000 * nsec;
5099 y.tv_sec += nsec;
5100 }
06a2c219 5101
dbc4e1c1
JB
5102 if (x.tv_usec - y.tv_usec > 1000000)
5103 {
5104 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5105 y.tv_usec += 1000000 * nsec;
5106 y.tv_sec -= nsec;
5107 }
5108
06a2c219
GM
5109 /* Compute the time remaining to wait. tv_usec is certainly
5110 positive. */
dbc4e1c1
JB
5111 result->tv_sec = x.tv_sec - y.tv_sec;
5112 result->tv_usec = x.tv_usec - y.tv_usec;
5113
06a2c219
GM
5114 /* Return indication of whether the result should be considered
5115 negative. */
dbc4e1c1
JB
5116 return x.tv_sec < y.tv_sec;
5117}
dc6f92b8 5118
dfcf069d 5119void
f676886a
JB
5120XTflash (f)
5121 struct frame *f;
dc6f92b8 5122{
dbc4e1c1 5123 BLOCK_INPUT;
dc6f92b8 5124
dbc4e1c1
JB
5125 {
5126 GC gc;
dc6f92b8 5127
06a2c219
GM
5128 /* Create a GC that will use the GXxor function to flip foreground
5129 pixels into background pixels. */
dbc4e1c1
JB
5130 {
5131 XGCValues values;
dc6f92b8 5132
dbc4e1c1 5133 values.function = GXxor;
7556890b
RS
5134 values.foreground = (f->output_data.x->foreground_pixel
5135 ^ f->output_data.x->background_pixel);
58769bee 5136
334208b7 5137 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5138 GCFunction | GCForeground, &values);
5139 }
dc6f92b8 5140
dbc4e1c1 5141 {
e84e14c3
RS
5142 /* Get the height not including a menu bar widget. */
5143 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5144 /* Height of each line to flash. */
5145 int flash_height = FRAME_LINE_HEIGHT (f);
5146 /* These will be the left and right margins of the rectangles. */
5147 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5148 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5149
5150 int width;
5151
5152 /* Don't flash the area between a scroll bar and the frame
5153 edge it is next to. */
5154 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5155 {
5156 case vertical_scroll_bar_left:
5157 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5158 break;
5159
5160 case vertical_scroll_bar_right:
5161 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5162 break;
06a2c219
GM
5163
5164 default:
5165 break;
e84e14c3
RS
5166 }
5167
5168 width = flash_right - flash_left;
5169
5170 /* If window is tall, flash top and bottom line. */
5171 if (height > 3 * FRAME_LINE_HEIGHT (f))
5172 {
5173 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5174 flash_left,
5175 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5176 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5177 width, flash_height);
5178 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5179 flash_left,
5180 (height - flash_height
5181 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5182 width, flash_height);
5183 }
5184 else
5185 /* If it is short, flash it all. */
5186 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5187 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5188 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5189
06a2c219 5190 x_flush (f);
dc6f92b8 5191
dbc4e1c1 5192 {
06a2c219 5193 struct timeval wakeup;
dc6f92b8 5194
66c30ea1 5195 EMACS_GET_TIME (wakeup);
dc6f92b8 5196
dbc4e1c1
JB
5197 /* Compute time to wait until, propagating carry from usecs. */
5198 wakeup.tv_usec += 150000;
5199 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5200 wakeup.tv_usec %= 1000000;
5201
5202 /* Keep waiting until past the time wakeup. */
5203 while (1)
5204 {
5205 struct timeval timeout;
5206
66c30ea1 5207 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
5208
5209 /* In effect, timeout = wakeup - timeout.
5210 Break if result would be negative. */
5211 if (timeval_subtract (&timeout, wakeup, timeout))
5212 break;
5213
5214 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5215 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5216 }
5217 }
58769bee 5218
e84e14c3
RS
5219 /* If window is tall, flash top and bottom line. */
5220 if (height > 3 * FRAME_LINE_HEIGHT (f))
5221 {
5222 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5223 flash_left,
5224 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5225 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5226 width, flash_height);
5227 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5228 flash_left,
5229 (height - flash_height
5230 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5231 width, flash_height);
5232 }
5233 else
5234 /* If it is short, flash it all. */
5235 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5236 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5237 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5238
334208b7 5239 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5240 x_flush (f);
dc6f92b8 5241 }
dbc4e1c1
JB
5242 }
5243
5244 UNBLOCK_INPUT;
dc6f92b8
JB
5245}
5246
06a2c219 5247#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5248
5249
dc6f92b8
JB
5250/* Make audible bell. */
5251
dfcf069d 5252void
dc6f92b8
JB
5253XTring_bell ()
5254{
b86bd3dd
GM
5255 struct frame *f = SELECTED_FRAME ();
5256
5257 if (FRAME_X_DISPLAY (f))
5258 {
dbc4e1c1 5259#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5260 if (visible_bell)
5261 XTflash (f);
5262 else
dbc4e1c1 5263#endif
b86bd3dd
GM
5264 {
5265 BLOCK_INPUT;
5266 XBell (FRAME_X_DISPLAY (f), 0);
5267 XFlush (FRAME_X_DISPLAY (f));
5268 UNBLOCK_INPUT;
5269 }
dc6f92b8
JB
5270 }
5271}
06a2c219 5272
dc6f92b8 5273\f
06a2c219
GM
5274/* Specify how many text lines, from the top of the window,
5275 should be affected by insert-lines and delete-lines operations.
5276 This, and those operations, are used only within an update
5277 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5278
dfcf069d 5279static void
06a2c219
GM
5280XTset_terminal_window (n)
5281 register int n;
dc6f92b8 5282{
06a2c219 5283 /* This function intentionally left blank. */
dc6f92b8
JB
5284}
5285
06a2c219
GM
5286
5287\f
5288/***********************************************************************
5289 Line Dance
5290 ***********************************************************************/
5291
5292/* Perform an insert-lines or delete-lines operation, inserting N
5293 lines or deleting -N lines at vertical position VPOS. */
5294
dfcf069d 5295static void
06a2c219
GM
5296x_ins_del_lines (vpos, n)
5297 int vpos, n;
dc6f92b8
JB
5298{
5299 abort ();
5300}
06a2c219
GM
5301
5302
5303/* Scroll part of the display as described by RUN. */
dc6f92b8 5304
dfcf069d 5305static void
06a2c219
GM
5306x_scroll_run (w, run)
5307 struct window *w;
5308 struct run *run;
dc6f92b8 5309{
06a2c219
GM
5310 struct frame *f = XFRAME (w->frame);
5311 int x, y, width, height, from_y, to_y, bottom_y;
5312
5313 /* Get frame-relative bounding box of the text display area of W,
5314 without mode lines. Include in this box the flags areas to the
5315 left and right of W. */
5316 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5317 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5318 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5319
5320 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5321 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5322 bottom_y = y + height;
dc6f92b8 5323
06a2c219
GM
5324 if (to_y < from_y)
5325 {
5326 /* Scrolling up. Make sure we don't copy part of the mode
5327 line at the bottom. */
5328 if (from_y + run->height > bottom_y)
5329 height = bottom_y - from_y;
5330 else
5331 height = run->height;
5332 }
dc6f92b8 5333 else
06a2c219
GM
5334 {
5335 /* Scolling down. Make sure we don't copy over the mode line.
5336 at the bottom. */
5337 if (to_y + run->height > bottom_y)
5338 height = bottom_y - to_y;
5339 else
5340 height = run->height;
5341 }
7a13e894 5342
06a2c219
GM
5343 BLOCK_INPUT;
5344
5345 /* Cursor off. Will be switched on again in x_update_window_end. */
5346 updated_window = w;
5347 x_clear_cursor (w);
5348
5349 XCopyArea (FRAME_X_DISPLAY (f),
5350 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5351 f->output_data.x->normal_gc,
5352 x, from_y,
5353 width, height,
5354 x, to_y);
5355
5356 UNBLOCK_INPUT;
5357}
dc6f92b8 5358
dc6f92b8 5359
06a2c219
GM
5360\f
5361/***********************************************************************
5362 Exposure Events
5363 ***********************************************************************/
5364
5365/* Redisplay an exposed area of frame F. X and Y are the upper-left
5366 corner of the exposed rectangle. W and H are width and height of
5367 the exposed area. All are pixel values. W or H zero means redraw
5368 the entire frame. */
dc6f92b8 5369
06a2c219
GM
5370static void
5371expose_frame (f, x, y, w, h)
5372 struct frame *f;
5373 int x, y, w, h;
dc6f92b8 5374{
06a2c219 5375 XRectangle r;
dc6f92b8 5376
06a2c219 5377 TRACE ((stderr, "expose_frame "));
dc6f92b8 5378
06a2c219
GM
5379 /* No need to redraw if frame will be redrawn soon. */
5380 if (FRAME_GARBAGED_P (f))
dc6f92b8 5381 {
06a2c219
GM
5382 TRACE ((stderr, " garbaged\n"));
5383 return;
5384 }
5385
5386 /* If basic faces haven't been realized yet, there is no point in
5387 trying to redraw anything. This can happen when we get an expose
5388 event while Emacs is starting, e.g. by moving another window. */
5389 if (FRAME_FACE_CACHE (f) == NULL
5390 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5391 {
5392 TRACE ((stderr, " no faces\n"));
5393 return;
58769bee 5394 }
06a2c219
GM
5395
5396 if (w == 0 || h == 0)
58769bee 5397 {
06a2c219
GM
5398 r.x = r.y = 0;
5399 r.width = CANON_X_UNIT (f) * f->width;
5400 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5401 }
5402 else
5403 {
06a2c219
GM
5404 r.x = x;
5405 r.y = y;
5406 r.width = w;
5407 r.height = h;
5408 }
5409
5410 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
5411 expose_window_tree (XWINDOW (f->root_window), &r);
5412
9ea173e8 5413 if (WINDOWP (f->tool_bar_window))
06a2c219 5414 {
9ea173e8 5415 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
5416 XRectangle window_rect;
5417 XRectangle intersection_rect;
5418 int window_x, window_y, window_width, window_height;
5419
5420
5421 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5422 window_rect.x = window_x;
5423 window_rect.y = window_y;
5424 window_rect.width = window_width;
5425 window_rect.height = window_height;
5426
5427 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5428 expose_window (w, &intersection_rect);
5429 }
5430
5431#ifndef USE_X_TOOLKIT
5432 if (WINDOWP (f->menu_bar_window))
5433 {
5434 struct window *w = XWINDOW (f->menu_bar_window);
5435 XRectangle window_rect;
5436 XRectangle intersection_rect;
5437 int window_x, window_y, window_width, window_height;
5438
5439
5440 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5441 window_rect.x = window_x;
5442 window_rect.y = window_y;
5443 window_rect.width = window_width;
5444 window_rect.height = window_height;
5445
5446 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5447 expose_window (w, &intersection_rect);
dc6f92b8 5448 }
06a2c219 5449#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5450}
5451
06a2c219
GM
5452
5453/* Redraw (parts) of all windows in the window tree rooted at W that
5454 intersect R. R contains frame pixel coordinates. */
5455
58769bee 5456static void
06a2c219
GM
5457expose_window_tree (w, r)
5458 struct window *w;
5459 XRectangle *r;
dc6f92b8 5460{
06a2c219
GM
5461 while (w)
5462 {
5463 if (!NILP (w->hchild))
5464 expose_window_tree (XWINDOW (w->hchild), r);
5465 else if (!NILP (w->vchild))
5466 expose_window_tree (XWINDOW (w->vchild), r);
5467 else
5468 {
5469 XRectangle window_rect;
5470 XRectangle intersection_rect;
5471 struct frame *f = XFRAME (w->frame);
5472 int window_x, window_y, window_width, window_height;
5473
5474 /* Frame-relative pixel rectangle of W. */
5475 window_box (w, -1, &window_x, &window_y, &window_width,
5476 &window_height);
5477 window_rect.x
5478 = (window_x
110859fc 5479 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
714dc26c 5480 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
06a2c219
GM
5481 window_rect.y = window_y;
5482 window_rect.width
5483 = (window_width
110859fc 5484 + FRAME_X_FLAGS_AREA_WIDTH (f)
06a2c219
GM
5485 + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
5486 window_rect.height
5487 = window_height + CURRENT_MODE_LINE_HEIGHT (w);
5488
5489 if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
5490 expose_window (w, &intersection_rect);
5491 }
58769bee 5492
06a2c219
GM
5493 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5494 }
5495}
58769bee 5496
dc6f92b8 5497
06a2c219
GM
5498/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5499 which intersects rectangle R. R is in window-relative coordinates. */
5500
5501static void
5502expose_area (w, row, r, area)
5503 struct window *w;
5504 struct glyph_row *row;
5505 XRectangle *r;
5506 enum glyph_row_area area;
5507{
5508 int x;
5509 struct glyph *first = row->glyphs[area];
5510 struct glyph *end = row->glyphs[area] + row->used[area];
5511 struct glyph *last;
5512 int first_x;
5513
5514 /* Set x to the window-relative start position for drawing glyphs of
5515 AREA. The first glyph of the text area can be partially visible.
5516 The first glyphs of other areas cannot. */
5517 if (area == LEFT_MARGIN_AREA)
5518 x = 0;
5519 else if (area == TEXT_AREA)
5520 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5521 else
5522 x = (window_box_width (w, LEFT_MARGIN_AREA)
5523 + window_box_width (w, TEXT_AREA));
5524
6fb13182
GM
5525 if (area == TEXT_AREA && row->fill_line_p)
5526 /* If row extends face to end of line write the whole line. */
5527 x_draw_glyphs (w, x, row, area,
5528 0, row->used[area],
06a2c219 5529 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5530 NULL, NULL, 0);
6fb13182
GM
5531 else
5532 {
5533 /* Find the first glyph that must be redrawn. */
5534 while (first < end
5535 && x + first->pixel_width < r->x)
5536 {
5537 x += first->pixel_width;
5538 ++first;
5539 }
5540
5541 /* Find the last one. */
5542 last = first;
5543 first_x = x;
5544 while (last < end
5545 && x < r->x + r->width)
5546 {
5547 x += last->pixel_width;
5548 ++last;
5549 }
5550
5551 /* Repaint. */
5552 if (last > first)
5553 x_draw_glyphs (w, first_x, row, area,
5554 first - row->glyphs[area],
5555 last - row->glyphs[area],
5556 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5557 NULL, NULL, 0);
5558 }
06a2c219
GM
5559}
5560
58769bee 5561
06a2c219
GM
5562/* Redraw the parts of the glyph row ROW on window W intersecting
5563 rectangle R. R is in window-relative coordinates. */
dc6f92b8 5564
06a2c219
GM
5565static void
5566expose_line (w, row, r)
5567 struct window *w;
5568 struct glyph_row *row;
5569 XRectangle *r;
5570{
5571 xassert (row->enabled_p);
5572
5573 if (row->mode_line_p || w->pseudo_window_p)
5574 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5575 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5576 NULL, NULL, 0);
06a2c219
GM
5577 else
5578 {
5579 if (row->used[LEFT_MARGIN_AREA])
5580 expose_area (w, row, r, LEFT_MARGIN_AREA);
5581 if (row->used[TEXT_AREA])
5582 expose_area (w, row, r, TEXT_AREA);
5583 if (row->used[RIGHT_MARGIN_AREA])
5584 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5585 x_draw_row_bitmaps (w, row);
5586 }
5587}
dc6f92b8 5588
58769bee 5589
06a2c219
GM
5590/* Return non-zero if W's cursor intersects rectangle R. */
5591
5592static int
5593x_phys_cursor_in_rect_p (w, r)
5594 struct window *w;
5595 XRectangle *r;
5596{
5597 XRectangle cr, result;
5598 struct glyph *cursor_glyph;
5599
5600 cursor_glyph = get_phys_cursor_glyph (w);
5601 if (cursor_glyph)
5602 {
5603 cr.x = w->phys_cursor.x;
5604 cr.y = w->phys_cursor.y;
5605 cr.width = cursor_glyph->pixel_width;
5606 cr.height = w->phys_cursor_height;
5607 return x_intersect_rectangles (&cr, r, &result);
5608 }
5609 else
5610 return 0;
dc6f92b8 5611}
dc6f92b8 5612
06a2c219
GM
5613
5614/* Redraw a rectangle of window W. R is a rectangle in window
5615 relative coordinates. Call this function with input blocked. */
dc6f92b8
JB
5616
5617static void
06a2c219
GM
5618expose_window (w, r)
5619 struct window *w;
5620 XRectangle *r;
dc6f92b8 5621{
06a2c219
GM
5622 struct glyph_row *row;
5623 int y;
5624 int yb = window_text_bottom_y (w);
5625 int cursor_cleared_p;
dc6f92b8 5626
80c32bcc
GM
5627 /* If window is not yet fully initialized, do nothing. This can
5628 happen when toolkit scroll bars are used and a window is split.
5629 Reconfiguring the scroll bar will generate an expose for a newly
5630 created window. */
5631 if (w->current_matrix == NULL)
5632 return;
5633
06a2c219
GM
5634 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
5635 r->x, r->y, r->width, r->height));
dc6f92b8 5636
06a2c219
GM
5637 /* Convert to window coordinates. */
5638 r->x = FRAME_TO_WINDOW_PIXEL_X (w, r->x);
5639 r->y = FRAME_TO_WINDOW_PIXEL_Y (w, r->y);
dc6f92b8 5640
06a2c219
GM
5641 /* Turn off the cursor. */
5642 if (!w->pseudo_window_p
5643 && x_phys_cursor_in_rect_p (w, r))
5644 {
5645 x_clear_cursor (w);
5646 cursor_cleared_p = 1;
5647 }
5648 else
5649 cursor_cleared_p = 0;
5650
5651 /* Find the first row intersecting the rectangle R. */
5652 row = w->current_matrix->rows;
5653 y = 0;
5654 while (row->enabled_p
5655 && y < yb
5656 && y + row->height < r->y)
5657 {
5658 y += row->height;
5659 ++row;
5660 }
5661
dc6f92b8 5662 /* Display the text in the rectangle, one text line at a time. */
06a2c219
GM
5663 while (row->enabled_p
5664 && y < yb
5665 && y < r->y + r->height)
5666 {
5667 expose_line (w, row, r);
5668 y += row->height;
5669 ++row;
5670 }
5671
5672 /* Display the mode line if there is one. */
5673 if (WINDOW_WANTS_MODELINE_P (w)
5674 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
5675 row->enabled_p)
5676 && row->y < r->y + r->height)
5677 expose_line (w, row, r);
dc6f92b8 5678
06a2c219 5679 if (!w->pseudo_window_p)
dc6f92b8 5680 {
06a2c219
GM
5681 /* Draw border between windows. */
5682 x_draw_vertical_border (w);
5683
5684 /* Turn the cursor on again. */
5685 if (cursor_cleared_p)
5686 x_update_window_cursor (w, 1);
5687 }
5688}
dc6f92b8 5689
dc6f92b8 5690
06a2c219
GM
5691/* Determine the intersection of two rectangles R1 and R2. Return
5692 the intersection in *RESULT. Value is non-zero if RESULT is not
5693 empty. */
5694
5695static int
5696x_intersect_rectangles (r1, r2, result)
5697 XRectangle *r1, *r2, *result;
5698{
5699 XRectangle *left, *right;
5700 XRectangle *upper, *lower;
5701 int intersection_p = 0;
5702
5703 /* Rearrange so that R1 is the left-most rectangle. */
5704 if (r1->x < r2->x)
5705 left = r1, right = r2;
5706 else
5707 left = r2, right = r1;
5708
5709 /* X0 of the intersection is right.x0, if this is inside R1,
5710 otherwise there is no intersection. */
5711 if (right->x <= left->x + left->width)
5712 {
5713 result->x = right->x;
5714
5715 /* The right end of the intersection is the minimum of the
5716 the right ends of left and right. */
5717 result->width = (min (left->x + left->width, right->x + right->width)
5718 - result->x);
5719
5720 /* Same game for Y. */
5721 if (r1->y < r2->y)
5722 upper = r1, lower = r2;
5723 else
5724 upper = r2, lower = r1;
5725
5726 /* The upper end of the intersection is lower.y0, if this is inside
5727 of upper. Otherwise, there is no intersection. */
5728 if (lower->y <= upper->y + upper->height)
dc43ef94 5729 {
06a2c219
GM
5730 result->y = lower->y;
5731
5732 /* The lower end of the intersection is the minimum of the lower
5733 ends of upper and lower. */
5734 result->height = (min (lower->y + lower->height,
5735 upper->y + upper->height)
5736 - result->y);
5737 intersection_p = 1;
dc43ef94 5738 }
dc6f92b8
JB
5739 }
5740
06a2c219 5741 return intersection_p;
dc6f92b8 5742}
06a2c219
GM
5743
5744
5745
5746
dc6f92b8 5747\f
dc6f92b8 5748static void
334208b7
RS
5749frame_highlight (f)
5750 struct frame *f;
dc6f92b8 5751{
b3e1e05c
JB
5752 /* We used to only do this if Vx_no_window_manager was non-nil, but
5753 the ICCCM (section 4.1.6) says that the window's border pixmap
5754 and border pixel are window attributes which are "private to the
5755 client", so we can always change it to whatever we want. */
5756 BLOCK_INPUT;
334208b7 5757 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5758 f->output_data.x->border_pixel);
b3e1e05c 5759 UNBLOCK_INPUT;
5d46f928 5760 x_update_cursor (f, 1);
dc6f92b8
JB
5761}
5762
5763static void
334208b7
RS
5764frame_unhighlight (f)
5765 struct frame *f;
dc6f92b8 5766{
b3e1e05c
JB
5767 /* We used to only do this if Vx_no_window_manager was non-nil, but
5768 the ICCCM (section 4.1.6) says that the window's border pixmap
5769 and border pixel are window attributes which are "private to the
5770 client", so we can always change it to whatever we want. */
5771 BLOCK_INPUT;
334208b7 5772 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5773 f->output_data.x->border_tile);
b3e1e05c 5774 UNBLOCK_INPUT;
5d46f928 5775 x_update_cursor (f, 1);
dc6f92b8 5776}
dc6f92b8 5777
f676886a
JB
5778/* The focus has changed. Update the frames as necessary to reflect
5779 the new situation. Note that we can't change the selected frame
c5acd733 5780 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 5781 Each event gets marked with the frame in which it occurred, so the
c5acd733 5782 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 5783
6d4238f3 5784static void
0f941935
KH
5785x_new_focus_frame (dpyinfo, frame)
5786 struct x_display_info *dpyinfo;
f676886a 5787 struct frame *frame;
dc6f92b8 5788{
0f941935 5789 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 5790
0f941935 5791 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 5792 {
58769bee 5793 /* Set this before calling other routines, so that they see
f676886a 5794 the correct value of x_focus_frame. */
0f941935 5795 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
5796
5797 if (old_focus && old_focus->auto_lower)
f676886a 5798 x_lower_frame (old_focus);
dc6f92b8
JB
5799
5800#if 0
f676886a 5801 selected_frame = frame;
e0c1aef2
KH
5802 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
5803 selected_frame);
f676886a
JB
5804 Fselect_window (selected_frame->selected_window);
5805 choose_minibuf_frame ();
c118dd06 5806#endif /* ! 0 */
dc6f92b8 5807
0f941935
KH
5808 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
5809 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
5810 else
5811 pending_autoraise_frame = 0;
6d4238f3 5812 }
dc6f92b8 5813
0f941935 5814 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
5815}
5816
37c2c98b
RS
5817/* Handle an event saying the mouse has moved out of an Emacs frame. */
5818
5819void
0f941935
KH
5820x_mouse_leave (dpyinfo)
5821 struct x_display_info *dpyinfo;
37c2c98b 5822{
0f941935 5823 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 5824}
6d4238f3 5825
f451eb13
JB
5826/* The focus has changed, or we have redirected a frame's focus to
5827 another frame (this happens when a frame uses a surrogate
06a2c219 5828 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
5829
5830 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 5831 frame is being highlighted or un-highlighted; we only use it to find
0f941935 5832 the appropriate X display info. */
06a2c219 5833
6d4238f3 5834static void
0f941935
KH
5835XTframe_rehighlight (frame)
5836 struct frame *frame;
6d4238f3 5837{
0f941935
KH
5838 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
5839}
6d4238f3 5840
0f941935
KH
5841static void
5842x_frame_rehighlight (dpyinfo)
5843 struct x_display_info *dpyinfo;
5844{
5845 struct frame *old_highlight = dpyinfo->x_highlight_frame;
5846
5847 if (dpyinfo->x_focus_frame)
6d4238f3 5848 {
0f941935
KH
5849 dpyinfo->x_highlight_frame
5850 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
5851 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
5852 : dpyinfo->x_focus_frame);
5853 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 5854 {
0f941935
KH
5855 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
5856 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 5857 }
dc6f92b8 5858 }
6d4238f3 5859 else
0f941935 5860 dpyinfo->x_highlight_frame = 0;
dc6f92b8 5861
0f941935 5862 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
5863 {
5864 if (old_highlight)
f676886a 5865 frame_unhighlight (old_highlight);
0f941935
KH
5866 if (dpyinfo->x_highlight_frame)
5867 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 5868 }
dc6f92b8 5869}
06a2c219
GM
5870
5871
dc6f92b8 5872\f
06a2c219 5873/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 5874
28430d3c
JB
5875/* Initialize mode_switch_bit and modifier_meaning. */
5876static void
334208b7
RS
5877x_find_modifier_meanings (dpyinfo)
5878 struct x_display_info *dpyinfo;
28430d3c 5879{
f689eb05 5880 int min_code, max_code;
28430d3c
JB
5881 KeySym *syms;
5882 int syms_per_code;
5883 XModifierKeymap *mods;
5884
334208b7
RS
5885 dpyinfo->meta_mod_mask = 0;
5886 dpyinfo->shift_lock_mask = 0;
5887 dpyinfo->alt_mod_mask = 0;
5888 dpyinfo->super_mod_mask = 0;
5889 dpyinfo->hyper_mod_mask = 0;
58769bee 5890
9658a521 5891#ifdef HAVE_X11R4
334208b7 5892 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 5893#else
4a60f8c5
RS
5894 min_code = dpyinfo->display->min_keycode;
5895 max_code = dpyinfo->display->max_keycode;
9658a521
JB
5896#endif
5897
334208b7 5898 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
5899 min_code, max_code - min_code + 1,
5900 &syms_per_code);
334208b7 5901 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 5902
58769bee 5903 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 5904 Alt keysyms are on. */
28430d3c 5905 {
06a2c219 5906 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
5907
5908 for (row = 3; row < 8; row++)
5909 for (col = 0; col < mods->max_keypermod; col++)
5910 {
0299d313
RS
5911 KeyCode code
5912 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 5913
af92970c
KH
5914 /* Zeroes are used for filler. Skip them. */
5915 if (code == 0)
5916 continue;
5917
28430d3c
JB
5918 /* Are any of this keycode's keysyms a meta key? */
5919 {
5920 int code_col;
5921
5922 for (code_col = 0; code_col < syms_per_code; code_col++)
5923 {
f689eb05 5924 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 5925
f689eb05 5926 switch (sym)
28430d3c 5927 {
f689eb05
JB
5928 case XK_Meta_L:
5929 case XK_Meta_R:
334208b7 5930 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 5931 break;
f689eb05
JB
5932
5933 case XK_Alt_L:
5934 case XK_Alt_R:
334208b7 5935 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
5936 break;
5937
5938 case XK_Hyper_L:
5939 case XK_Hyper_R:
334208b7 5940 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
5941 break;
5942
5943 case XK_Super_L:
5944 case XK_Super_R:
334208b7 5945 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 5946 break;
11edeb03
JB
5947
5948 case XK_Shift_Lock:
5949 /* Ignore this if it's not on the lock modifier. */
5950 if ((1 << row) == LockMask)
334208b7 5951 dpyinfo->shift_lock_mask = LockMask;
11edeb03 5952 break;
28430d3c
JB
5953 }
5954 }
5955 }
5956 }
5957 }
5958
f689eb05 5959 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 5960 if (! dpyinfo->meta_mod_mask)
a3c44b14 5961 {
334208b7
RS
5962 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
5963 dpyinfo->alt_mod_mask = 0;
a3c44b14 5964 }
f689eb05 5965
148c4b70
RS
5966 /* If some keys are both alt and meta,
5967 make them just meta, not alt. */
334208b7 5968 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 5969 {
334208b7 5970 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 5971 }
58769bee 5972
28430d3c 5973 XFree ((char *) syms);
f689eb05 5974 XFreeModifiermap (mods);
28430d3c
JB
5975}
5976
dfeccd2d
JB
5977/* Convert between the modifier bits X uses and the modifier bits
5978 Emacs uses. */
06a2c219 5979
7c5283e4 5980static unsigned int
334208b7
RS
5981x_x_to_emacs_modifiers (dpyinfo, state)
5982 struct x_display_info *dpyinfo;
dc6f92b8
JB
5983 unsigned int state;
5984{
334208b7
RS
5985 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
5986 | ((state & ControlMask) ? ctrl_modifier : 0)
5987 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
5988 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
5989 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
5990 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
5991}
5992
dfeccd2d 5993static unsigned int
334208b7
RS
5994x_emacs_to_x_modifiers (dpyinfo, state)
5995 struct x_display_info *dpyinfo;
dfeccd2d
JB
5996 unsigned int state;
5997{
334208b7
RS
5998 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
5999 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6000 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6001 | ((state & shift_modifier) ? ShiftMask : 0)
6002 | ((state & ctrl_modifier) ? ControlMask : 0)
6003 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6004}
d047c4eb
KH
6005
6006/* Convert a keysym to its name. */
6007
6008char *
6009x_get_keysym_name (keysym)
6010 KeySym keysym;
6011{
6012 char *value;
6013
6014 BLOCK_INPUT;
6015 value = XKeysymToString (keysym);
6016 UNBLOCK_INPUT;
6017
6018 return value;
6019}
06a2c219
GM
6020
6021
e4571a43
JB
6022\f
6023/* Mouse clicks and mouse movement. Rah. */
e4571a43 6024
06a2c219
GM
6025/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6026 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6027 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6028 not force the value into range. */
69388238 6029
c8dba240 6030void
69388238 6031pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6032 FRAME_PTR f;
69388238 6033 register int pix_x, pix_y;
e4571a43
JB
6034 register int *x, *y;
6035 XRectangle *bounds;
69388238 6036 int noclip;
e4571a43 6037{
06a2c219 6038 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6039 even for negative values. */
6040 if (pix_x < 0)
7556890b 6041 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6042 if (pix_y < 0)
7556890b 6043 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6044
e4571a43
JB
6045 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6046 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6047
6048 if (bounds)
6049 {
7556890b
RS
6050 bounds->width = FONT_WIDTH (f->output_data.x->font);
6051 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6052 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6053 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6054 }
6055
69388238
RS
6056 if (!noclip)
6057 {
6058 if (pix_x < 0)
6059 pix_x = 0;
3cbd2e0b
RS
6060 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6061 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6062
6063 if (pix_y < 0)
6064 pix_y = 0;
6065 else if (pix_y > f->height)
6066 pix_y = f->height;
6067 }
e4571a43
JB
6068
6069 *x = pix_x;
6070 *y = pix_y;
6071}
6072
06a2c219
GM
6073
6074/* Given HPOS/VPOS in the current matrix of W, return corresponding
6075 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6076 can't tell the positions because W's display is not up to date,
6077 return 0. */
6078
6079int
6080glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6081 struct window *w;
6082 int hpos, vpos;
6083 int *frame_x, *frame_y;
2b5c9e71 6084{
06a2c219
GM
6085 int success_p;
6086
6087 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6088 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6089
6090 if (display_completed)
6091 {
6092 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6093 struct glyph *glyph = row->glyphs[TEXT_AREA];
6094 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6095
6096 *frame_y = row->y;
6097 *frame_x = row->x;
6098 while (glyph < end)
6099 {
6100 *frame_x += glyph->pixel_width;
6101 ++glyph;
6102 }
6103
6104 success_p = 1;
6105 }
6106 else
6107 {
6108 *frame_y = *frame_x = 0;
6109 success_p = 0;
6110 }
6111
6112 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6113 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6114 return success_p;
2b5c9e71
RS
6115}
6116
06a2c219 6117
dc6f92b8
JB
6118/* Prepare a mouse-event in *RESULT for placement in the input queue.
6119
6120 If the event is a button press, then note that we have grabbed
f451eb13 6121 the mouse. */
dc6f92b8
JB
6122
6123static Lisp_Object
f451eb13 6124construct_mouse_click (result, event, f)
dc6f92b8
JB
6125 struct input_event *result;
6126 XButtonEvent *event;
f676886a 6127 struct frame *f;
dc6f92b8 6128{
f451eb13 6129 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6130 otherwise. */
f451eb13 6131 result->kind = mouse_click;
69388238 6132 result->code = event->button - Button1;
1113d9db 6133 result->timestamp = event->time;
334208b7
RS
6134 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6135 event->state)
f689eb05 6136 | (event->type == ButtonRelease
58769bee 6137 ? up_modifier
f689eb05 6138 : down_modifier));
dc6f92b8 6139
06a2c219
GM
6140 XSETINT (result->x, event->x);
6141 XSETINT (result->y, event->y);
6142 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6143 result->arg = Qnil;
06a2c219 6144 return Qnil;
dc6f92b8 6145}
b849c413 6146
69388238 6147\f
90e65f07
JB
6148/* Function to report a mouse movement to the mainstream Emacs code.
6149 The input handler calls this.
6150
6151 We have received a mouse movement event, which is given in *event.
6152 If the mouse is over a different glyph than it was last time, tell
6153 the mainstream emacs code by setting mouse_moved. If not, ask for
6154 another motion event, so we can check again the next time it moves. */
b8009dd1 6155
06a2c219
GM
6156static XMotionEvent last_mouse_motion_event;
6157static Lisp_Object last_mouse_motion_frame;
6158
90e65f07 6159static void
12ba150f 6160note_mouse_movement (frame, event)
f676886a 6161 FRAME_PTR frame;
90e65f07 6162 XMotionEvent *event;
90e65f07 6163{
e5d77022 6164 last_mouse_movement_time = event->time;
06a2c219
GM
6165 last_mouse_motion_event = *event;
6166 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6167
27f338af
RS
6168 if (event->window != FRAME_X_WINDOW (frame))
6169 {
39d8bb4d 6170 frame->mouse_moved = 1;
27f338af 6171 last_mouse_scroll_bar = Qnil;
27f338af 6172 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6173 }
6174
90e65f07 6175 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6176 else if (event->x < last_mouse_glyph.x
6177 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6178 || event->y < last_mouse_glyph.y
6179 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6180 {
39d8bb4d 6181 frame->mouse_moved = 1;
ab648270 6182 last_mouse_scroll_bar = Qnil;
b8009dd1 6183 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6184 }
6185}
6186
bf1c0ba1 6187/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6188
06a2c219
GM
6189 int disable_mouse_highlight;
6190
6191
6192\f
6193/************************************************************************
6194 Mouse Face
6195 ************************************************************************/
6196
6197/* Find the glyph under window-relative coordinates X/Y in window W.
6198 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6199 strings. Return in *HPOS and *VPOS the row and column number of
6200 the glyph found. Return in *AREA the glyph area containing X.
6201 Value is a pointer to the glyph found or null if X/Y is not on
6202 text, or we can't tell because W's current matrix is not up to
6203 date. */
6204
6205static struct glyph *
6206x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
6207 struct window *w;
6208 int x, y;
6209 int *hpos, *vpos, *area;
6210{
6211 struct glyph *glyph, *end;
3e71d8f2 6212 struct glyph_row *row = NULL;
06a2c219
GM
6213 int x0, i, left_area_width;
6214
6215 /* Find row containing Y. Give up if some row is not enabled. */
6216 for (i = 0; i < w->current_matrix->nrows; ++i)
6217 {
6218 row = MATRIX_ROW (w->current_matrix, i);
6219 if (!row->enabled_p)
6220 return NULL;
6221 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6222 break;
6223 }
6224
6225 *vpos = i;
6226 *hpos = 0;
6227
6228 /* Give up if Y is not in the window. */
6229 if (i == w->current_matrix->nrows)
6230 return NULL;
6231
6232 /* Get the glyph area containing X. */
6233 if (w->pseudo_window_p)
6234 {
6235 *area = TEXT_AREA;
6236 x0 = 0;
6237 }
6238 else
6239 {
6240 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6241 if (x < left_area_width)
6242 {
6243 *area = LEFT_MARGIN_AREA;
6244 x0 = 0;
6245 }
6246 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6247 {
6248 *area = TEXT_AREA;
6249 x0 = row->x + left_area_width;
6250 }
6251 else
6252 {
6253 *area = RIGHT_MARGIN_AREA;
6254 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6255 }
6256 }
6257
6258 /* Find glyph containing X. */
6259 glyph = row->glyphs[*area];
6260 end = glyph + row->used[*area];
6261 while (glyph < end)
6262 {
6263 if (x < x0 + glyph->pixel_width)
6264 {
6265 if (w->pseudo_window_p)
6266 break;
6267 else if (BUFFERP (glyph->object))
6268 break;
6269 }
6270
6271 x0 += glyph->pixel_width;
6272 ++glyph;
6273 }
6274
6275 if (glyph == end)
6276 return NULL;
6277
6278 *hpos = glyph - row->glyphs[*area];
6279 return glyph;
6280}
6281
6282
6283/* Convert frame-relative x/y to coordinates relative to window W.
6284 Takes pseudo-windows into account. */
6285
6286static void
6287frame_to_window_pixel_xy (w, x, y)
6288 struct window *w;
6289 int *x, *y;
6290{
6291 if (w->pseudo_window_p)
6292 {
6293 /* A pseudo-window is always full-width, and starts at the
6294 left edge of the frame, plus a frame border. */
6295 struct frame *f = XFRAME (w->frame);
6296 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6297 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6298 }
6299 else
6300 {
6301 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6302 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6303 }
6304}
6305
6306
6307/* Take proper action when mouse has moved to the mode or top line of
6308 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6309 mode line. X is relative to the start of the text display area of
6310 W, so the width of bitmap areas and scroll bars must be subtracted
6311 to get a position relative to the start of the mode line. */
6312
6313static void
6314note_mode_line_highlight (w, x, mode_line_p)
6315 struct window *w;
6316 int x, mode_line_p;
6317{
6318 struct frame *f = XFRAME (w->frame);
6319 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6320 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6321 struct glyph_row *row;
6322
6323 if (mode_line_p)
6324 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6325 else
045dee35 6326 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
06a2c219
GM
6327
6328 if (row->enabled_p)
6329 {
6330 struct glyph *glyph, *end;
6331 Lisp_Object help, map;
6332 int x0;
6333
6334 /* Find the glyph under X. */
6335 glyph = row->glyphs[TEXT_AREA];
6336 end = glyph + row->used[TEXT_AREA];
6337 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6338 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
6339 while (glyph < end
6340 && x >= x0 + glyph->pixel_width)
6341 {
6342 x0 += glyph->pixel_width;
6343 ++glyph;
6344 }
6345
6346 if (glyph < end
6347 && STRINGP (glyph->object)
6348 && XSTRING (glyph->object)->intervals
6349 && glyph->charpos >= 0
6350 && glyph->charpos < XSTRING (glyph->object)->size)
6351 {
6352 /* If we're on a string with `help-echo' text property,
6353 arrange for the help to be displayed. This is done by
6354 setting the global variable help_echo to the help string. */
6355 help = Fget_text_property (make_number (glyph->charpos),
6356 Qhelp_echo, glyph->object);
b7e80413 6357 if (!NILP (help))
be010514
GM
6358 {
6359 help_echo = help;
7cea38bc 6360 XSETWINDOW (help_echo_window, w);
be010514
GM
6361 help_echo_object = glyph->object;
6362 help_echo_pos = glyph->charpos;
6363 }
06a2c219
GM
6364
6365 /* Change the mouse pointer according to what is under X/Y. */
6366 map = Fget_text_property (make_number (glyph->charpos),
6367 Qlocal_map, glyph->object);
6368 if (!NILP (Fkeymapp (map)))
6369 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6370 else
6371 {
6372 map = Fget_text_property (make_number (glyph->charpos),
6373 Qkeymap, glyph->object);
6374 if (!NILP (Fkeymapp (map)))
6375 cursor = f->output_data.x->nontext_cursor;
6376 }
06a2c219
GM
6377 }
6378 }
6379
6380 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6381}
6382
6383
6384/* Take proper action when the mouse has moved to position X, Y on
6385 frame F as regards highlighting characters that have mouse-face
6386 properties. Also de-highlighting chars where the mouse was before.
27f338af 6387 X and Y can be negative or out of range. */
b8009dd1
RS
6388
6389static void
6390note_mouse_highlight (f, x, y)
06a2c219 6391 struct frame *f;
c32cdd9a 6392 int x, y;
b8009dd1 6393{
06a2c219
GM
6394 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6395 int portion;
b8009dd1
RS
6396 Lisp_Object window;
6397 struct window *w;
6398
06a2c219
GM
6399 /* When a menu is active, don't highlight because this looks odd. */
6400#ifdef USE_X_TOOLKIT
6401 if (popup_activated ())
6402 return;
6403#endif
6404
04fff9c0
GM
6405 if (disable_mouse_highlight
6406 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6407 return;
6408
06a2c219
GM
6409 dpyinfo->mouse_face_mouse_x = x;
6410 dpyinfo->mouse_face_mouse_y = y;
6411 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6412
06a2c219 6413 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6414 return;
6415
514e4681
RS
6416 if (gc_in_progress)
6417 {
06a2c219 6418 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6419 return;
6420 }
6421
b8009dd1 6422 /* Which window is that in? */
06a2c219 6423 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6424
6425 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6426 if (! EQ (window, dpyinfo->mouse_face_window))
6427 clear_mouse_face (dpyinfo);
6428
6429 /* Not on a window -> return. */
6430 if (!WINDOWP (window))
6431 return;
6432
6433 /* Convert to window-relative pixel coordinates. */
6434 w = XWINDOW (window);
6435 frame_to_window_pixel_xy (w, &x, &y);
6436
9ea173e8 6437 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6438 buffer. */
9ea173e8 6439 if (EQ (window, f->tool_bar_window))
06a2c219 6440 {
9ea173e8 6441 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6442 return;
6443 }
6444
6445 if (portion == 1 || portion == 3)
6446 {
6447 /* Mouse is on the mode or top line. */
6448 note_mode_line_highlight (w, x, portion == 1);
6449 return;
6450 }
6451 else
6452 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6453 f->output_data.x->text_cursor);
b8009dd1 6454
0cdd0c9f
RS
6455 /* Are we in a window whose display is up to date?
6456 And verify the buffer's text has not changed. */
06a2c219
GM
6457 if (/* Within text portion of the window. */
6458 portion == 0
0cdd0c9f 6459 && EQ (w->window_end_valid, w->buffer)
26459b28
KH
6460 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
6461 && (XFASTINT (w->last_overlay_modified)
6462 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
b8009dd1 6463 {
06a2c219
GM
6464 int hpos, vpos, pos, i, area;
6465 struct glyph *glyph;
b8009dd1 6466
06a2c219
GM
6467 /* Find the glyph under X/Y. */
6468 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
6469
6470 /* Clear mouse face if X/Y not over text. */
6471 if (glyph == NULL
6472 || area != TEXT_AREA
6473 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6474 {
06a2c219
GM
6475 clear_mouse_face (dpyinfo);
6476 return;
6477 }
6478
6479 pos = glyph->charpos;
6480 xassert (w->pseudo_window_p || BUFFERP (glyph->object));
6481
6482 /* Check for mouse-face and help-echo. */
6483 {
6484 Lisp_Object mouse_face, overlay, position;
6485 Lisp_Object *overlay_vec;
6486 int len, noverlays;
6487 struct buffer *obuf;
6488 int obegv, ozv;
6489
6490 /* If we get an out-of-range value, return now; avoid an error. */
6491 if (pos > BUF_Z (XBUFFER (w->buffer)))
6492 return;
6493
6494 /* Make the window's buffer temporarily current for
6495 overlays_at and compute_char_face. */
6496 obuf = current_buffer;
6497 current_buffer = XBUFFER (w->buffer);
6498 obegv = BEGV;
6499 ozv = ZV;
6500 BEGV = BEG;
6501 ZV = Z;
6502
6503 /* Is this char mouse-active or does it have help-echo? */
6504 XSETINT (position, pos);
6505
6506 /* Put all the overlays we want in a vector in overlay_vec.
6507 Store the length in len. If there are more than 10, make
6508 enough space for all, and try again. */
6509 len = 10;
6510 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6511 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6512 if (noverlays > len)
6513 {
6514 len = noverlays;
6515 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6516 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6517 }
6518
6519 noverlays = sort_overlays (overlay_vec, noverlays, w);
6520
6521 /* Check mouse-face highlighting. */
6522 if (! (EQ (window, dpyinfo->mouse_face_window)
6523 && vpos >= dpyinfo->mouse_face_beg_row
6524 && vpos <= dpyinfo->mouse_face_end_row
6525 && (vpos > dpyinfo->mouse_face_beg_row
6526 || hpos >= dpyinfo->mouse_face_beg_col)
6527 && (vpos < dpyinfo->mouse_face_end_row
6528 || hpos < dpyinfo->mouse_face_end_col
6529 || dpyinfo->mouse_face_past_end)))
6530 {
6531 /* Clear the display of the old active region, if any. */
6532 clear_mouse_face (dpyinfo);
6533
6534 /* Find the highest priority overlay that has a mouse-face prop. */
6535 overlay = Qnil;
6536 for (i = 0; i < noverlays; i++)
6537 {
6538 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6539 if (!NILP (mouse_face))
6540 {
6541 overlay = overlay_vec[i];
6542 break;
6543 }
6544 }
6545
6546 /* If no overlay applies, get a text property. */
6547 if (NILP (overlay))
6548 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6549
6550 /* Handle the overlay case. */
6551 if (! NILP (overlay))
6552 {
6553 /* Find the range of text around this char that
6554 should be active. */
6555 Lisp_Object before, after;
6556 int ignore;
6557
6558 before = Foverlay_start (overlay);
6559 after = Foverlay_end (overlay);
6560 /* Record this as the current active region. */
6561 fast_find_position (w, XFASTINT (before),
6562 &dpyinfo->mouse_face_beg_col,
6563 &dpyinfo->mouse_face_beg_row,
6564 &dpyinfo->mouse_face_beg_x,
6565 &dpyinfo->mouse_face_beg_y);
6566 dpyinfo->mouse_face_past_end
6567 = !fast_find_position (w, XFASTINT (after),
6568 &dpyinfo->mouse_face_end_col,
6569 &dpyinfo->mouse_face_end_row,
6570 &dpyinfo->mouse_face_end_x,
6571 &dpyinfo->mouse_face_end_y);
6572 dpyinfo->mouse_face_window = window;
6573 dpyinfo->mouse_face_face_id
6574 = face_at_buffer_position (w, pos, 0, 0,
6575 &ignore, pos + 1, 1);
6576
6577 /* Display it as active. */
6578 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6579 }
6580 /* Handle the text property case. */
6581 else if (! NILP (mouse_face))
6582 {
6583 /* Find the range of text around this char that
6584 should be active. */
6585 Lisp_Object before, after, beginning, end;
6586 int ignore;
6587
6588 beginning = Fmarker_position (w->start);
6589 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
6590 - XFASTINT (w->window_end_pos)));
6591 before
6592 = Fprevious_single_property_change (make_number (pos + 1),
6593 Qmouse_face,
6594 w->buffer, beginning);
6595 after
6596 = Fnext_single_property_change (position, Qmouse_face,
6597 w->buffer, end);
6598 /* Record this as the current active region. */
6599 fast_find_position (w, XFASTINT (before),
6600 &dpyinfo->mouse_face_beg_col,
6601 &dpyinfo->mouse_face_beg_row,
6602 &dpyinfo->mouse_face_beg_x,
6603 &dpyinfo->mouse_face_beg_y);
6604 dpyinfo->mouse_face_past_end
6605 = !fast_find_position (w, XFASTINT (after),
6606 &dpyinfo->mouse_face_end_col,
6607 &dpyinfo->mouse_face_end_row,
6608 &dpyinfo->mouse_face_end_x,
6609 &dpyinfo->mouse_face_end_y);
6610 dpyinfo->mouse_face_window = window;
6611 dpyinfo->mouse_face_face_id
6612 = face_at_buffer_position (w, pos, 0, 0,
6613 &ignore, pos + 1, 1);
6614
6615 /* Display it as active. */
6616 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6617 }
6618 }
6619
6620 /* Look for a `help-echo' property. */
6621 {
be010514 6622 Lisp_Object help, object, position;
06a2c219
GM
6623
6624 /* Check overlays first. */
6625 help = Qnil;
b7e80413 6626 for (i = 0; i < noverlays && NILP (help); ++i)
be010514
GM
6627 help = Foverlay_get (overlay_vec[i], Qhelp_echo);
6628
6629 if (!NILP (help))
6630 {
6631 help_echo = help;
7cea38bc 6632 help_echo_window = window;
be010514
GM
6633 help_echo_object = w->buffer;
6634 help_echo_pos = pos;
6635 }
6636 else
6637 {
6638 /* Try text properties. */
6639 if ((STRINGP (glyph->object)
06a2c219
GM
6640 && glyph->charpos >= 0
6641 && glyph->charpos < XSTRING (glyph->object)->size)
6642 || (BUFFERP (glyph->object)
6643 && glyph->charpos >= BEGV
be010514
GM
6644 && glyph->charpos < ZV))
6645 help = Fget_text_property (make_number (glyph->charpos),
6646 Qhelp_echo, glyph->object);
06a2c219 6647
be010514
GM
6648 if (!NILP (help))
6649 {
6650 help_echo = help;
7cea38bc 6651 help_echo_window = window;
be010514
GM
6652 help_echo_object = glyph->object;
6653 help_echo_pos = glyph->charpos;
6654 }
6655 }
06a2c219
GM
6656 }
6657
6658 BEGV = obegv;
6659 ZV = ozv;
6660 current_buffer = obuf;
6661 }
6662 }
6663}
6664
6665static void
6666redo_mouse_highlight ()
6667{
6668 if (!NILP (last_mouse_motion_frame)
6669 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
6670 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
6671 last_mouse_motion_event.x,
6672 last_mouse_motion_event.y);
6673}
6674
6675
6676\f
6677/***********************************************************************
9ea173e8 6678 Tool-bars
06a2c219
GM
6679 ***********************************************************************/
6680
9ea173e8
GM
6681static int x_tool_bar_item P_ ((struct frame *, int, int,
6682 struct glyph **, int *, int *, int *));
06a2c219 6683
9ea173e8 6684/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
6685 or -1. */
6686
9ea173e8 6687static int last_tool_bar_item;
06a2c219
GM
6688
6689
9ea173e8
GM
6690/* Get information about the tool-bar item at position X/Y on frame F.
6691 Return in *GLYPH a pointer to the glyph of the tool-bar item in
6692 the current matrix of the tool-bar window of F, or NULL if not
6693 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
6694 item in F->current_tool_bar_items. Value is
06a2c219 6695
9ea173e8 6696 -1 if X/Y is not on a tool-bar item
06a2c219
GM
6697 0 if X/Y is on the same item that was highlighted before.
6698 1 otherwise. */
6699
6700static int
9ea173e8 6701x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
6702 struct frame *f;
6703 int x, y;
6704 struct glyph **glyph;
6705 int *hpos, *vpos, *prop_idx;
6706{
6707 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6708 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6709 int area;
6710
6711 /* Find the glyph under X/Y. */
6712 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
6713 if (*glyph == NULL)
6714 return -1;
6715
9ea173e8
GM
6716 /* Get the start of this tool-bar item's properties in
6717 f->current_tool_bar_items. */
6718 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
6719 return -1;
6720
6721 /* Is mouse on the highlighted item? */
9ea173e8 6722 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
6723 && *vpos >= dpyinfo->mouse_face_beg_row
6724 && *vpos <= dpyinfo->mouse_face_end_row
6725 && (*vpos > dpyinfo->mouse_face_beg_row
6726 || *hpos >= dpyinfo->mouse_face_beg_col)
6727 && (*vpos < dpyinfo->mouse_face_end_row
6728 || *hpos < dpyinfo->mouse_face_end_col
6729 || dpyinfo->mouse_face_past_end))
6730 return 0;
6731
6732 return 1;
6733}
6734
6735
9ea173e8 6736/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
6737 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
6738 or ButtonRelase. */
6739
6740static void
9ea173e8 6741x_handle_tool_bar_click (f, button_event)
06a2c219
GM
6742 struct frame *f;
6743 XButtonEvent *button_event;
6744{
6745 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6746 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6747 int hpos, vpos, prop_idx;
6748 struct glyph *glyph;
6749 Lisp_Object enabled_p;
6750 int x = button_event->x;
6751 int y = button_event->y;
6752
9ea173e8 6753 /* If not on the highlighted tool-bar item, return. */
06a2c219 6754 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 6755 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
6756 return;
6757
6758 /* If item is disabled, do nothing. */
9ea173e8
GM
6759 enabled_p = (XVECTOR (f->current_tool_bar_items)
6760 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6761 if (NILP (enabled_p))
6762 return;
6763
6764 if (button_event->type == ButtonPress)
6765 {
6766 /* Show item in pressed state. */
6767 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
6768 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 6769 last_tool_bar_item = prop_idx;
06a2c219
GM
6770 }
6771 else
6772 {
6773 Lisp_Object key, frame;
6774 struct input_event event;
6775
6776 /* Show item in released state. */
6777 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
6778 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
6779
9ea173e8
GM
6780 key = (XVECTOR (f->current_tool_bar_items)
6781 ->contents[prop_idx + TOOL_BAR_ITEM_KEY]);
06a2c219
GM
6782
6783 XSETFRAME (frame, f);
9ea173e8 6784 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
6785 event.frame_or_window = frame;
6786 event.arg = frame;
06a2c219
GM
6787 kbd_buffer_store_event (&event);
6788
9ea173e8 6789 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
6790 event.frame_or_window = frame;
6791 event.arg = key;
06a2c219
GM
6792 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6793 button_event->state);
6794 kbd_buffer_store_event (&event);
9ea173e8 6795 last_tool_bar_item = -1;
06a2c219
GM
6796 }
6797}
6798
6799
9ea173e8
GM
6800/* Possibly highlight a tool-bar item on frame F when mouse moves to
6801 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
6802 note_mouse_highlight. */
6803
6804static void
9ea173e8 6805note_tool_bar_highlight (f, x, y)
06a2c219
GM
6806 struct frame *f;
6807 int x, y;
6808{
9ea173e8 6809 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
6810 struct window *w = XWINDOW (window);
6811 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6812 int hpos, vpos;
6813 struct glyph *glyph;
6814 struct glyph_row *row;
5c187dee 6815 int i;
06a2c219
GM
6816 Lisp_Object enabled_p;
6817 int prop_idx;
6818 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
5c187dee 6819 int mouse_down_p, rc;
06a2c219
GM
6820
6821 /* Function note_mouse_highlight is called with negative x(y
6822 values when mouse moves outside of the frame. */
6823 if (x <= 0 || y <= 0)
6824 {
6825 clear_mouse_face (dpyinfo);
6826 return;
6827 }
6828
9ea173e8 6829 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
6830 if (rc < 0)
6831 {
9ea173e8 6832 /* Not on tool-bar item. */
06a2c219
GM
6833 clear_mouse_face (dpyinfo);
6834 return;
6835 }
6836 else if (rc == 0)
9ea173e8 6837 /* On same tool-bar item as before. */
06a2c219 6838 goto set_help_echo;
b8009dd1 6839
06a2c219
GM
6840 clear_mouse_face (dpyinfo);
6841
9ea173e8 6842 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
6843 mouse_down_p = (dpyinfo->grabbed
6844 && f == last_mouse_frame
6845 && FRAME_LIVE_P (f));
6846 if (mouse_down_p
9ea173e8 6847 && last_tool_bar_item != prop_idx)
06a2c219
GM
6848 return;
6849
6850 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
6851 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
6852
9ea173e8
GM
6853 /* If tool-bar item is not enabled, don't highlight it. */
6854 enabled_p = (XVECTOR (f->current_tool_bar_items)
6855 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6856 if (!NILP (enabled_p))
6857 {
6858 /* Compute the x-position of the glyph. In front and past the
6859 image is a space. We include this is the highlighted area. */
6860 row = MATRIX_ROW (w->current_matrix, vpos);
6861 for (i = x = 0; i < hpos; ++i)
6862 x += row->glyphs[TEXT_AREA][i].pixel_width;
6863
6864 /* Record this as the current active region. */
6865 dpyinfo->mouse_face_beg_col = hpos;
6866 dpyinfo->mouse_face_beg_row = vpos;
6867 dpyinfo->mouse_face_beg_x = x;
6868 dpyinfo->mouse_face_beg_y = row->y;
6869 dpyinfo->mouse_face_past_end = 0;
6870
6871 dpyinfo->mouse_face_end_col = hpos + 1;
6872 dpyinfo->mouse_face_end_row = vpos;
6873 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
6874 dpyinfo->mouse_face_end_y = row->y;
6875 dpyinfo->mouse_face_window = window;
9ea173e8 6876 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
6877
6878 /* Display it as active. */
6879 show_mouse_face (dpyinfo, draw);
6880 dpyinfo->mouse_face_image_state = draw;
b8009dd1 6881 }
06a2c219
GM
6882
6883 set_help_echo:
6884
9ea173e8 6885 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 6886 XTread_socket does the rest. */
7cea38bc 6887 help_echo_object = help_echo_window = Qnil;
be010514 6888 help_echo_pos = -1;
9ea173e8
GM
6889 help_echo = (XVECTOR (f->current_tool_bar_items)
6890 ->contents[prop_idx + TOOL_BAR_ITEM_HELP]);
b7e80413 6891 if (NILP (help_echo))
9ea173e8
GM
6892 help_echo = (XVECTOR (f->current_tool_bar_items)
6893 ->contents[prop_idx + TOOL_BAR_ITEM_CAPTION]);
b8009dd1 6894}
4d73d038 6895
06a2c219
GM
6896
6897\f
6898/* Find the glyph matrix position of buffer position POS in window W.
6899 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
6900 current glyphs must be up to date. If POS is above window start
6901 return (0, 0, 0, 0). If POS is after end of W, return end of
6902 last line in W. */
b8009dd1
RS
6903
6904static int
06a2c219
GM
6905fast_find_position (w, pos, hpos, vpos, x, y)
6906 struct window *w;
b8009dd1 6907 int pos;
06a2c219 6908 int *hpos, *vpos, *x, *y;
b8009dd1 6909{
b8009dd1 6910 int i;
bf1c0ba1 6911 int lastcol;
06a2c219
GM
6912 int maybe_next_line_p = 0;
6913 int line_start_position;
6914 int yb = window_text_bottom_y (w);
6915 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
6916 struct glyph_row *best_row = row;
6917 int row_vpos = 0, best_row_vpos = 0;
6918 int current_x;
6919
6920 while (row->y < yb)
b8009dd1 6921 {
06a2c219
GM
6922 if (row->used[TEXT_AREA])
6923 line_start_position = row->glyphs[TEXT_AREA]->charpos;
6924 else
6925 line_start_position = 0;
6926
6927 if (line_start_position > pos)
b8009dd1 6928 break;
77b68646
RS
6929 /* If the position sought is the end of the buffer,
6930 don't include the blank lines at the bottom of the window. */
06a2c219
GM
6931 else if (line_start_position == pos
6932 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 6933 {
06a2c219 6934 maybe_next_line_p = 1;
77b68646
RS
6935 break;
6936 }
06a2c219
GM
6937 else if (line_start_position > 0)
6938 {
6939 best_row = row;
6940 best_row_vpos = row_vpos;
6941 }
4b0bb6f3
GM
6942
6943 if (row->y + row->height >= yb)
6944 break;
06a2c219
GM
6945
6946 ++row;
6947 ++row_vpos;
b8009dd1 6948 }
06a2c219
GM
6949
6950 /* Find the right column within BEST_ROW. */
6951 lastcol = 0;
6952 current_x = best_row->x;
6953 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 6954 {
06a2c219
GM
6955 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
6956 int charpos;
6957
6958 charpos = glyph->charpos;
6959 if (charpos == pos)
bf1c0ba1 6960 {
06a2c219
GM
6961 *hpos = i;
6962 *vpos = best_row_vpos;
6963 *x = current_x;
6964 *y = best_row->y;
bf1c0ba1
RS
6965 return 1;
6966 }
06a2c219 6967 else if (charpos > pos)
4d73d038 6968 break;
06a2c219
GM
6969 else if (charpos > 0)
6970 lastcol = i;
6971
6972 current_x += glyph->pixel_width;
bf1c0ba1 6973 }
b8009dd1 6974
77b68646
RS
6975 /* If we're looking for the end of the buffer,
6976 and we didn't find it in the line we scanned,
6977 use the start of the following line. */
06a2c219 6978 if (maybe_next_line_p)
77b68646 6979 {
06a2c219
GM
6980 ++best_row;
6981 ++best_row_vpos;
6982 lastcol = 0;
6983 current_x = best_row->x;
77b68646
RS
6984 }
6985
06a2c219
GM
6986 *vpos = best_row_vpos;
6987 *hpos = lastcol + 1;
6988 *x = current_x;
6989 *y = best_row->y;
b8009dd1
RS
6990 return 0;
6991}
6992
06a2c219 6993
b8009dd1
RS
6994/* Display the active region described by mouse_face_*
6995 in its mouse-face if HL > 0, in its normal face if HL = 0. */
6996
6997static void
06a2c219 6998show_mouse_face (dpyinfo, draw)
7a13e894 6999 struct x_display_info *dpyinfo;
06a2c219 7000 enum draw_glyphs_face draw;
b8009dd1 7001{
7a13e894 7002 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7003 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 7004 int i;
06a2c219
GM
7005 int cursor_off_p = 0;
7006 struct cursor_pos saved_cursor;
7007
7008 saved_cursor = output_cursor;
7009
7010 /* If window is in the process of being destroyed, don't bother
7011 to do anything. */
7012 if (w->current_matrix == NULL)
7013 goto set_x_cursor;
7014
7015 /* Recognize when we are called to operate on rows that don't exist
7016 anymore. This can happen when a window is split. */
7017 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
7018 goto set_x_cursor;
7019
7020 set_output_cursor (&w->phys_cursor);
7021
7022 /* Note that mouse_face_beg_row etc. are window relative. */
7023 for (i = dpyinfo->mouse_face_beg_row;
7024 i <= dpyinfo->mouse_face_end_row;
7025 i++)
7026 {
7027 int start_hpos, end_hpos, start_x;
7028 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
7029
7030 /* Don't do anything if row doesn't have valid contents. */
7031 if (!row->enabled_p)
7032 continue;
7033
7034 /* For all but the first row, the highlight starts at column 0. */
7035 if (i == dpyinfo->mouse_face_beg_row)
7036 {
7037 start_hpos = dpyinfo->mouse_face_beg_col;
7038 start_x = dpyinfo->mouse_face_beg_x;
7039 }
7040 else
7041 {
7042 start_hpos = 0;
7043 start_x = 0;
7044 }
7045
7046 if (i == dpyinfo->mouse_face_end_row)
7047 end_hpos = dpyinfo->mouse_face_end_col;
7048 else
7049 end_hpos = row->used[TEXT_AREA];
7050
7051 /* If the cursor's in the text we are about to rewrite, turn the
7052 cursor off. */
7053 if (!w->pseudo_window_p
7054 && i == output_cursor.vpos
7055 && output_cursor.hpos >= start_hpos - 1
7056 && output_cursor.hpos <= end_hpos)
514e4681 7057 {
06a2c219
GM
7058 x_update_window_cursor (w, 0);
7059 cursor_off_p = 1;
514e4681 7060 }
b8009dd1 7061
06a2c219 7062 if (end_hpos > start_hpos)
64f26cf5
GM
7063 {
7064 row->mouse_face_p = draw == DRAW_MOUSE_FACE;
7065 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7066 start_hpos, end_hpos, draw, NULL, NULL, 0);
7067 }
b8009dd1
RS
7068 }
7069
514e4681 7070 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
7071 if (cursor_off_p)
7072 x_display_cursor (w, 1,
7073 output_cursor.hpos, output_cursor.vpos,
7074 output_cursor.x, output_cursor.y);
2729a2b5 7075
06a2c219 7076 output_cursor = saved_cursor;
fb3b7de5 7077
06a2c219
GM
7078 set_x_cursor:
7079
7080 /* Change the mouse cursor. */
7081 if (draw == DRAW_NORMAL_TEXT)
7082 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7083 f->output_data.x->text_cursor);
7084 else if (draw == DRAW_MOUSE_FACE)
334208b7 7085 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7086 f->output_data.x->cross_cursor);
27ead1d5 7087 else
334208b7 7088 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7089 f->output_data.x->nontext_cursor);
b8009dd1
RS
7090}
7091
7092/* Clear out the mouse-highlighted active region.
06a2c219 7093 Redraw it un-highlighted first. */
b8009dd1 7094
06a2c219 7095void
7a13e894
RS
7096clear_mouse_face (dpyinfo)
7097 struct x_display_info *dpyinfo;
b8009dd1 7098{
06a2c219
GM
7099 if (tip_frame)
7100 return;
7101
7a13e894 7102 if (! NILP (dpyinfo->mouse_face_window))
06a2c219 7103 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
b8009dd1 7104
7a13e894
RS
7105 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7106 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7107 dpyinfo->mouse_face_window = Qnil;
b8009dd1 7108}
e687d06e 7109
71b8321e
GM
7110
7111/* Clear any mouse-face on window W. This function is part of the
7112 redisplay interface, and is called from try_window_id and similar
7113 functions to ensure the mouse-highlight is off. */
7114
7115static void
7116x_clear_mouse_face (w)
7117 struct window *w;
7118{
7119 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7120 Lisp_Object window;
7121
7122 XSETWINDOW (window, w);
7123 if (EQ (window, dpyinfo->mouse_face_window))
7124 clear_mouse_face (dpyinfo);
7125}
7126
7127
e687d06e
RS
7128/* Just discard the mouse face information for frame F, if any.
7129 This is used when the size of F is changed. */
7130
dfcf069d 7131void
e687d06e
RS
7132cancel_mouse_face (f)
7133 FRAME_PTR f;
7134{
7135 Lisp_Object window;
7136 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7137
7138 window = dpyinfo->mouse_face_window;
7139 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7140 {
7141 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7142 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7143 dpyinfo->mouse_face_window = Qnil;
7144 }
7145}
b8009dd1 7146\f
ab648270
JB
7147static struct scroll_bar *x_window_to_scroll_bar ();
7148static void x_scroll_bar_report_motion ();
12ba150f 7149
90e65f07 7150/* Return the current position of the mouse.
2d7fc7e8 7151 *fp should be a frame which indicates which display to ask about.
90e65f07 7152
2d7fc7e8 7153 If the mouse movement started in a scroll bar, set *fp, *bar_window,
ab648270 7154 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 7155 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 7156 position on the scroll bar.
12ba150f 7157
2d7fc7e8 7158 If the mouse movement started elsewhere, set *fp to the frame the
12ba150f
JB
7159 mouse is on, *bar_window to nil, and *x and *y to the character cell
7160 the mouse is over.
7161
06a2c219 7162 Set *time to the server time-stamp for the time at which the mouse
12ba150f
JB
7163 was at this position.
7164
a135645a
RS
7165 Don't store anything if we don't have a valid set of values to report.
7166
90e65f07 7167 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7168 movement. */
90e65f07
JB
7169
7170static void
1cf412ec 7171XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7172 FRAME_PTR *fp;
1cf412ec 7173 int insist;
12ba150f 7174 Lisp_Object *bar_window;
ab648270 7175 enum scroll_bar_part *part;
90e65f07 7176 Lisp_Object *x, *y;
e5d77022 7177 unsigned long *time;
90e65f07 7178{
a135645a
RS
7179 FRAME_PTR f1;
7180
90e65f07
JB
7181 BLOCK_INPUT;
7182
8bcee03e 7183 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7184 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7185 else
7186 {
12ba150f
JB
7187 Window root;
7188 int root_x, root_y;
90e65f07 7189
12ba150f
JB
7190 Window dummy_window;
7191 int dummy;
7192
39d8bb4d
KH
7193 Lisp_Object frame, tail;
7194
7195 /* Clear the mouse-moved flag for every frame on this display. */
7196 FOR_EACH_FRAME (tail, frame)
7197 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7198 XFRAME (frame)->mouse_moved = 0;
7199
ab648270 7200 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7201
7202 /* Figure out which root window we're on. */
334208b7
RS
7203 XQueryPointer (FRAME_X_DISPLAY (*fp),
7204 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7205
7206 /* The root window which contains the pointer. */
7207 &root,
7208
7209 /* Trash which we can't trust if the pointer is on
7210 a different screen. */
7211 &dummy_window,
7212
7213 /* The position on that root window. */
58769bee 7214 &root_x, &root_y,
12ba150f
JB
7215
7216 /* More trash we can't trust. */
7217 &dummy, &dummy,
7218
7219 /* Modifier keys and pointer buttons, about which
7220 we don't care. */
7221 (unsigned int *) &dummy);
7222
7223 /* Now we have a position on the root; find the innermost window
7224 containing the pointer. */
7225 {
7226 Window win, child;
7227 int win_x, win_y;
06a2c219 7228 int parent_x = 0, parent_y = 0;
e99db5a1 7229 int count;
12ba150f
JB
7230
7231 win = root;
69388238 7232
2d7fc7e8
RS
7233 /* XTranslateCoordinates can get errors if the window
7234 structure is changing at the same time this function
7235 is running. So at least we must not crash from them. */
7236
e99db5a1 7237 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 7238
334208b7 7239 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 7240 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 7241 {
69388238
RS
7242 /* If mouse was grabbed on a frame, give coords for that frame
7243 even if the mouse is now outside it. */
334208b7 7244 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 7245
12ba150f 7246 /* From-window, to-window. */
69388238 7247 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
7248
7249 /* From-position, to-position. */
7250 root_x, root_y, &win_x, &win_y,
7251
7252 /* Child of win. */
7253 &child);
69388238
RS
7254 f1 = last_mouse_frame;
7255 }
7256 else
7257 {
7258 while (1)
7259 {
334208b7 7260 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 7261
69388238
RS
7262 /* From-window, to-window. */
7263 root, win,
12ba150f 7264
69388238
RS
7265 /* From-position, to-position. */
7266 root_x, root_y, &win_x, &win_y,
7267
7268 /* Child of win. */
7269 &child);
7270
9af3143a 7271 if (child == None || child == win)
69388238
RS
7272 break;
7273
7274 win = child;
7275 parent_x = win_x;
7276 parent_y = win_y;
7277 }
12ba150f 7278
69388238
RS
7279 /* Now we know that:
7280 win is the innermost window containing the pointer
7281 (XTC says it has no child containing the pointer),
7282 win_x and win_y are the pointer's position in it
7283 (XTC did this the last time through), and
7284 parent_x and parent_y are the pointer's position in win's parent.
7285 (They are what win_x and win_y were when win was child.
7286 If win is the root window, it has no parent, and
7287 parent_{x,y} are invalid, but that's okay, because we'll
7288 never use them in that case.) */
7289
7290 /* Is win one of our frames? */
19126e11 7291 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
69388238 7292 }
58769bee 7293
2d7fc7e8
RS
7294 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
7295 f1 = 0;
7296
e99db5a1 7297 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 7298
ab648270 7299 /* If not, is it one of our scroll bars? */
a135645a 7300 if (! f1)
12ba150f 7301 {
ab648270 7302 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
7303
7304 if (bar)
7305 {
a135645a 7306 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
7307 win_x = parent_x;
7308 win_y = parent_y;
7309 }
7310 }
90e65f07 7311
8bcee03e 7312 if (f1 == 0 && insist > 0)
b86bd3dd 7313 f1 = SELECTED_FRAME ();
1cf412ec 7314
a135645a 7315 if (f1)
12ba150f 7316 {
06a2c219
GM
7317 /* Ok, we found a frame. Store all the values.
7318 last_mouse_glyph is a rectangle used to reduce the
7319 generation of mouse events. To not miss any motion
7320 events, we must divide the frame into rectangles of the
7321 size of the smallest character that could be displayed
7322 on it, i.e. into the same rectangles that matrices on
7323 the frame are divided into. */
7324
7325#if OLD_REDISPLAY_CODE
2b5c9e71 7326 int ignore1, ignore2;
2b5c9e71 7327 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
334208b7 7328 &last_mouse_glyph,
1cf412ec
RS
7329 FRAME_X_DISPLAY_INFO (f1)->grabbed
7330 || insist);
06a2c219
GM
7331#else
7332 {
7333 int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
7334 int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
7335 int x = win_x;
7336 int y = win_y;
7337
7338 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
7339 round down even for negative values. */
7340 if (x < 0)
7341 x -= width - 1;
7342 if (y < 0)
7343 y -= height - 1;
7344
7345 last_mouse_glyph.width = width;
7346 last_mouse_glyph.height = height;
7347 last_mouse_glyph.x = (x + width - 1) / width * width;
7348 last_mouse_glyph.y = (y + height - 1) / height * height;
7349 }
7350#endif
12ba150f
JB
7351
7352 *bar_window = Qnil;
7353 *part = 0;
334208b7 7354 *fp = f1;
e0c1aef2
KH
7355 XSETINT (*x, win_x);
7356 XSETINT (*y, win_y);
12ba150f
JB
7357 *time = last_mouse_movement_time;
7358 }
7359 }
7360 }
90e65f07
JB
7361
7362 UNBLOCK_INPUT;
7363}
f451eb13 7364
06a2c219 7365
06a2c219 7366#ifdef USE_X_TOOLKIT
bffcfca9
GM
7367
7368/* Atimer callback function for TIMER. Called every 0.1s to process
7369 Xt timeouts, if needed. We must avoid calling XtAppPending as
7370 much as possible because that function does an implicit XFlush
7371 that slows us down. */
7372
7373static void
7374x_process_timeouts (timer)
7375 struct atimer *timer;
7376{
7377 if (toolkit_scroll_bar_interaction || popup_activated_flag)
7378 {
7379 BLOCK_INPUT;
7380 while (XtAppPending (Xt_app_con) & XtIMTimer)
7381 XtAppProcessEvent (Xt_app_con, XtIMTimer);
7382 UNBLOCK_INPUT;
7383 }
06a2c219
GM
7384}
7385
bffcfca9 7386#endif /* USE_X_TOOLKIT */
06a2c219
GM
7387
7388\f
7389/* Scroll bar support. */
7390
7391/* Given an X window ID, find the struct scroll_bar which manages it.
7392 This can be called in GC, so we have to make sure to strip off mark
7393 bits. */
bffcfca9 7394
06a2c219
GM
7395static struct scroll_bar *
7396x_window_to_scroll_bar (window_id)
7397 Window window_id;
7398{
7399 Lisp_Object tail;
7400
7401 for (tail = Vframe_list;
7402 XGCTYPE (tail) == Lisp_Cons;
8e713be6 7403 tail = XCDR (tail))
06a2c219
GM
7404 {
7405 Lisp_Object frame, bar, condemned;
7406
8e713be6 7407 frame = XCAR (tail);
06a2c219
GM
7408 /* All elements of Vframe_list should be frames. */
7409 if (! GC_FRAMEP (frame))
7410 abort ();
7411
7412 /* Scan this frame's scroll bar list for a scroll bar with the
7413 right window ID. */
7414 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
7415 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
7416 /* This trick allows us to search both the ordinary and
7417 condemned scroll bar lists with one loop. */
7418 ! GC_NILP (bar) || (bar = condemned,
7419 condemned = Qnil,
7420 ! GC_NILP (bar));
7421 bar = XSCROLL_BAR (bar)->next)
7422 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
7423 return XSCROLL_BAR (bar);
7424 }
7425
7426 return 0;
7427}
7428
7429
7430\f
7431/************************************************************************
7432 Toolkit scroll bars
7433 ************************************************************************/
7434
7435#if USE_TOOLKIT_SCROLL_BARS
7436
7437static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
7438static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
7439static void x_create_toolkit_scroll_bar P_ ((struct frame *,
7440 struct scroll_bar *));
7441static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
7442 int, int, int));
7443
7444
7445/* Id of action hook installed for scroll bars. */
7446
7447static XtActionHookId action_hook_id;
7448
7449/* Lisp window being scrolled. Set when starting to interact with
7450 a toolkit scroll bar, reset to nil when ending the interaction. */
7451
7452static Lisp_Object window_being_scrolled;
7453
7454/* Last scroll bar part sent in xm_scroll_callback. */
7455
7456static int last_scroll_bar_part;
7457
ec18280f
SM
7458/* Whether this is an Xaw with arrow-scrollbars. This should imply
7459 that movements of 1/20 of the screen size are mapped to up/down. */
7460
7461static Boolean xaw3d_arrow_scroll;
7462
7463/* Whether the drag scrolling maintains the mouse at the top of the
7464 thumb. If not, resizing the thumb needs to be done more carefully
7465 to avoid jerkyness. */
7466
7467static Boolean xaw3d_pick_top;
7468
06a2c219
GM
7469
7470/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 7471 bars are used.. The hook is responsible for detecting when
06a2c219
GM
7472 the user ends an interaction with the scroll bar, and generates
7473 a `end-scroll' scroll_bar_click' event if so. */
7474
7475static void
7476xt_action_hook (widget, client_data, action_name, event, params,
7477 num_params)
7478 Widget widget;
7479 XtPointer client_data;
7480 String action_name;
7481 XEvent *event;
7482 String *params;
7483 Cardinal *num_params;
7484{
7485 int scroll_bar_p;
7486 char *end_action;
7487
7488#ifdef USE_MOTIF
7489 scroll_bar_p = XmIsScrollBar (widget);
7490 end_action = "Release";
ec18280f 7491#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7492 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
7493 end_action = "EndScroll";
ec18280f 7494#endif /* USE_MOTIF */
06a2c219 7495
06a2c219
GM
7496 if (scroll_bar_p
7497 && strcmp (action_name, end_action) == 0
7498 && WINDOWP (window_being_scrolled))
7499 {
7500 struct window *w;
7501
7502 x_send_scroll_bar_event (window_being_scrolled,
7503 scroll_bar_end_scroll, 0, 0);
7504 w = XWINDOW (window_being_scrolled);
7505 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
7506 window_being_scrolled = Qnil;
7507 last_scroll_bar_part = -1;
bffcfca9
GM
7508
7509 /* Xt timeouts no longer needed. */
7510 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
7511 }
7512}
7513
7514
7515/* Send a client message with message type Xatom_Scrollbar for a
7516 scroll action to the frame of WINDOW. PART is a value identifying
7517 the part of the scroll bar that was clicked on. PORTION is the
7518 amount to scroll of a whole of WHOLE. */
7519
7520static void
7521x_send_scroll_bar_event (window, part, portion, whole)
7522 Lisp_Object window;
7523 int part, portion, whole;
7524{
7525 XEvent event;
7526 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
7527 struct frame *f = XFRAME (XWINDOW (window)->frame);
7528
7529 /* Construct a ClientMessage event to send to the frame. */
7530 ev->type = ClientMessage;
7531 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
7532 ev->display = FRAME_X_DISPLAY (f);
7533 ev->window = FRAME_X_WINDOW (f);
7534 ev->format = 32;
52e386c2 7535 ev->data.l[0] = (long) XFASTINT (window);
06a2c219
GM
7536 ev->data.l[1] = (long) part;
7537 ev->data.l[2] = (long) 0;
7538 ev->data.l[3] = (long) portion;
7539 ev->data.l[4] = (long) whole;
7540
bffcfca9
GM
7541 /* Make Xt timeouts work while the scroll bar is active. */
7542 toolkit_scroll_bar_interaction = 1;
7543
06a2c219
GM
7544 /* Setting the event mask to zero means that the message will
7545 be sent to the client that created the window, and if that
7546 window no longer exists, no event will be sent. */
7547 BLOCK_INPUT;
7548 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
7549 UNBLOCK_INPUT;
7550}
7551
7552
7553/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
7554 in *IEVENT. */
7555
7556static void
7557x_scroll_bar_to_input_event (event, ievent)
7558 XEvent *event;
7559 struct input_event *ievent;
7560{
7561 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
7562 Lisp_Object window;
7563 struct frame *f;
7564
7565 XSETFASTINT (window, ev->data.l[0]);
7566 f = XFRAME (XWINDOW (window)->frame);
06a2c219
GM
7567
7568 ievent->kind = scroll_bar_click;
7569 ievent->frame_or_window = window;
0f8aabe9 7570 ievent->arg = Qnil;
06a2c219
GM
7571 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
7572 ievent->part = ev->data.l[1];
7573 ievent->code = ev->data.l[2];
7574 ievent->x = make_number ((int) ev->data.l[3]);
7575 ievent->y = make_number ((int) ev->data.l[4]);
7576 ievent->modifiers = 0;
7577}
7578
7579
7580#ifdef USE_MOTIF
7581
7582/* Minimum and maximum values used for Motif scroll bars. */
7583
7584#define XM_SB_MIN 1
7585#define XM_SB_MAX 10000000
7586#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
7587
7588
7589/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
7590 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
7591 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
7592
7593static void
7594xm_scroll_callback (widget, client_data, call_data)
7595 Widget widget;
7596 XtPointer client_data, call_data;
7597{
7598 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7599 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
7600 double percent;
7601 int part = -1, whole = 0, portion = 0;
7602
7603 switch (cs->reason)
7604 {
7605 case XmCR_DECREMENT:
7606 bar->dragging = Qnil;
7607 part = scroll_bar_up_arrow;
7608 break;
7609
7610 case XmCR_INCREMENT:
7611 bar->dragging = Qnil;
7612 part = scroll_bar_down_arrow;
7613 break;
7614
7615 case XmCR_PAGE_DECREMENT:
7616 bar->dragging = Qnil;
7617 part = scroll_bar_above_handle;
7618 break;
7619
7620 case XmCR_PAGE_INCREMENT:
7621 bar->dragging = Qnil;
7622 part = scroll_bar_below_handle;
7623 break;
7624
7625 case XmCR_TO_TOP:
7626 bar->dragging = Qnil;
7627 part = scroll_bar_to_top;
7628 break;
7629
7630 case XmCR_TO_BOTTOM:
7631 bar->dragging = Qnil;
7632 part = scroll_bar_to_bottom;
7633 break;
7634
7635 case XmCR_DRAG:
7636 {
7637 int slider_size;
7638 int dragging_down_p = (INTEGERP (bar->dragging)
7639 && XINT (bar->dragging) <= cs->value);
7640
7641 /* Get the slider size. */
7642 BLOCK_INPUT;
7643 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
7644 UNBLOCK_INPUT;
7645
7646 /* At the max position of the scroll bar, do a line-wise
7647 movement. Without doing anything, the LessTif scroll bar
7648 calls us with the same cs->value again and again. If we
7649 want to make sure that we can reach the end of the buffer,
7650 we have to do something.
7651
7652 Implementation note: setting bar->dragging always to
7653 cs->value gives a smoother movement at the max position.
7654 Setting it to nil when doing line-wise movement gives
7655 a better slider behavior. */
7656
7657 if (cs->value + slider_size == XM_SB_MAX
7658 || (dragging_down_p
7659 && last_scroll_bar_part == scroll_bar_down_arrow))
7660 {
7661 part = scroll_bar_down_arrow;
7662 bar->dragging = Qnil;
7663 }
7664 else
7665 {
7666 whole = XM_SB_RANGE;
7667 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
7668 part = scroll_bar_handle;
7669 bar->dragging = make_number (cs->value);
7670 }
7671 }
7672 break;
7673
7674 case XmCR_VALUE_CHANGED:
7675 break;
7676 };
7677
7678 if (part >= 0)
7679 {
7680 window_being_scrolled = bar->window;
7681 last_scroll_bar_part = part;
7682 x_send_scroll_bar_event (bar->window, part, portion, whole);
7683 }
7684}
7685
7686
ec18280f 7687#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
7688
7689
ec18280f 7690/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
7691 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
7692 scroll bar struct. CALL_DATA is a pointer to a float saying where
7693 the thumb is. */
7694
7695static void
ec18280f 7696xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
7697 Widget widget;
7698 XtPointer client_data, call_data;
7699{
7700 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7701 float top = *(float *) call_data;
7702 float shown;
ec18280f
SM
7703 int whole, portion, height;
7704 int part;
06a2c219
GM
7705
7706 /* Get the size of the thumb, a value between 0 and 1. */
7707 BLOCK_INPUT;
ec18280f 7708 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
7709 UNBLOCK_INPUT;
7710
7711 whole = 10000000;
7712 portion = shown < 1 ? top * whole : 0;
06a2c219 7713
ec18280f
SM
7714 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
7715 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
7716 the bottom, so we force the scrolling whenever we see that we're
7717 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
7718 we try to ensure that we always stay two pixels away from the
7719 bottom). */
06a2c219
GM
7720 part = scroll_bar_down_arrow;
7721 else
7722 part = scroll_bar_handle;
7723
7724 window_being_scrolled = bar->window;
7725 bar->dragging = make_number (portion);
7726 last_scroll_bar_part = part;
7727 x_send_scroll_bar_event (bar->window, part, portion, whole);
7728}
7729
7730
ec18280f
SM
7731/* Xaw scroll bar callback. Invoked for incremental scrolling.,
7732 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
7733 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
7734 the scroll bar. CALL_DATA is an integer specifying the action that
7735 has taken place. It's magnitude is in the range 0..height of the
7736 scroll bar. Negative values mean scroll towards buffer start.
7737 Values < height of scroll bar mean line-wise movement. */
7738
7739static void
ec18280f 7740xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
7741 Widget widget;
7742 XtPointer client_data, call_data;
7743{
7744 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7745 int position = (int) call_data;
7746 Dimension height;
7747 int part;
7748
7749 /* Get the height of the scroll bar. */
7750 BLOCK_INPUT;
7751 XtVaGetValues (widget, XtNheight, &height, NULL);
7752 UNBLOCK_INPUT;
7753
ec18280f
SM
7754 if (abs (position) >= height)
7755 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
7756
7757 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
7758 it maps line-movement to call_data = max(5, height/20). */
7759 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
7760 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 7761 else
ec18280f 7762 part = scroll_bar_move_ratio;
06a2c219
GM
7763
7764 window_being_scrolled = bar->window;
7765 bar->dragging = Qnil;
7766 last_scroll_bar_part = part;
ec18280f 7767 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
7768}
7769
7770
7771#endif /* not USE_MOTIF */
7772
7773
7774/* Create the widget for scroll bar BAR on frame F. Record the widget
7775 and X window of the scroll bar in BAR. */
7776
7777static void
7778x_create_toolkit_scroll_bar (f, bar)
7779 struct frame *f;
7780 struct scroll_bar *bar;
7781{
7782 Window xwindow;
7783 Widget widget;
7784 Arg av[20];
7785 int ac = 0;
7786 char *scroll_bar_name = "verticalScrollBar";
7787 unsigned long pixel;
7788
7789 BLOCK_INPUT;
7790
7791#ifdef USE_MOTIF
7792 /* LessTif 0.85, problems:
7793
7794 1. When the mouse if over the scroll bar, the scroll bar will
7795 get keyboard events. I didn't find a way to turn this off.
7796
7797 2. Do we have to explicitly set the cursor to get an arrow
7798 cursor (see below)? */
7799
7800 /* Set resources. Create the widget. */
7801 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7802 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
7803 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
7804 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
7805 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
7806 XtSetArg (av[ac], XmNincrement, 1); ++ac;
7807 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
7808
7809 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7810 if (pixel != -1)
7811 {
7812 XtSetArg (av[ac], XmNforeground, pixel);
7813 ++ac;
7814 }
7815
7816 pixel = f->output_data.x->scroll_bar_background_pixel;
7817 if (pixel != -1)
7818 {
7819 XtSetArg (av[ac], XmNbackground, pixel);
7820 ++ac;
7821 }
7822
7823 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
7824 scroll_bar_name, av, ac);
7825
7826 /* Add one callback for everything that can happen. */
7827 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
7828 (XtPointer) bar);
7829 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
7830 (XtPointer) bar);
7831 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
7832 (XtPointer) bar);
7833 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
7834 (XtPointer) bar);
7835 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
7836 (XtPointer) bar);
7837 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
7838 (XtPointer) bar);
7839 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
7840 (XtPointer) bar);
7841
7842 /* Realize the widget. Only after that is the X window created. */
7843 XtRealizeWidget (widget);
7844
7845 /* Set the cursor to an arrow. I didn't find a resource to do that.
7846 And I'm wondering why it hasn't an arrow cursor by default. */
7847 XDefineCursor (XtDisplay (widget), XtWindow (widget),
7848 f->output_data.x->nontext_cursor);
7849
ec18280f 7850#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7851
7852 /* Set resources. Create the widget. The background of the
7853 Xaw3d scroll bar widget is a little bit light for my taste.
7854 We don't alter it here to let users change it according
7855 to their taste with `emacs*verticalScrollBar.background: xxx'. */
7856 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7857 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
7858 /* For smoother scrolling with Xaw3d -sm */
7859 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
7860 /* XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac; */
06a2c219
GM
7861
7862 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7863 if (pixel != -1)
7864 {
7865 XtSetArg (av[ac], XtNforeground, pixel);
7866 ++ac;
7867 }
7868
7869 pixel = f->output_data.x->scroll_bar_background_pixel;
7870 if (pixel != -1)
7871 {
7872 XtSetArg (av[ac], XtNbackground, pixel);
7873 ++ac;
7874 }
7875
7876 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
7877 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
7878
7879 {
7880 char *initial = "";
7881 char *val = initial;
7882 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
7883 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
7884 if (val == initial)
7885 { /* ARROW_SCROLL */
7886 xaw3d_arrow_scroll = True;
7887 /* Isn't that just a personal preference ? -sm */
7888 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
7889 }
7890 }
06a2c219
GM
7891
7892 /* Define callbacks. */
ec18280f
SM
7893 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
7894 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
7895 (XtPointer) bar);
7896
7897 /* Realize the widget. Only after that is the X window created. */
7898 XtRealizeWidget (widget);
7899
ec18280f 7900#endif /* !USE_MOTIF */
06a2c219
GM
7901
7902 /* Install an action hook that let's us detect when the user
7903 finishes interacting with a scroll bar. */
7904 if (action_hook_id == 0)
7905 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
7906
7907 /* Remember X window and widget in the scroll bar vector. */
7908 SET_SCROLL_BAR_X_WIDGET (bar, widget);
7909 xwindow = XtWindow (widget);
7910 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
7911
7912 UNBLOCK_INPUT;
7913}
7914
7915
7916/* Set the thumb size and position of scroll bar BAR. We are currently
7917 displaying PORTION out of a whole WHOLE, and our position POSITION. */
7918
7919static void
7920x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
7921 struct scroll_bar *bar;
7922 int portion, position, whole;
f451eb13 7923{
06a2c219 7924 float top, shown;
06a2c219 7925 Widget widget = SCROLL_BAR_X_WIDGET (bar);
f451eb13 7926
06a2c219
GM
7927 if (whole == 0)
7928 top = 0, shown = 1;
7929 else
f451eb13 7930 {
06a2c219
GM
7931 top = (float) position / whole;
7932 shown = (float) portion / whole;
7933 }
f451eb13 7934
06a2c219 7935 BLOCK_INPUT;
f451eb13 7936
06a2c219
GM
7937#ifdef USE_MOTIF
7938 {
7939 int size, value;
7940 Boolean arrow1_selected, arrow2_selected;
7941 unsigned char flags;
7942 XmScrollBarWidget sb;
7943
ec18280f 7944 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
7945 is the scroll bar's maximum and MIN is the scroll bar's minimum
7946 value. */
7947 size = shown * XM_SB_RANGE;
7948 size = min (size, XM_SB_RANGE);
7949 size = max (size, 1);
7950
7951 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
7952 value = top * XM_SB_RANGE;
7953 value = min (value, XM_SB_MAX - size);
7954 value = max (value, XM_SB_MIN);
7955
7956 /* LessTif: Calling XmScrollBarSetValues after an increment or
7957 decrement turns off auto-repeat LessTif-internally. This can
7958 be seen in ScrollBar.c which resets Arrow1Selected and
7959 Arrow2Selected. It also sets internal flags so that LessTif
7960 believes the mouse is in the slider. We either have to change
7961 our code, or work around that by accessing private data. */
7962
7963 sb = (XmScrollBarWidget) widget;
7964 arrow1_selected = sb->scrollBar.arrow1_selected;
7965 arrow2_selected = sb->scrollBar.arrow2_selected;
7966 flags = sb->scrollBar.flags;
7967
7968 if (NILP (bar->dragging))
7969 XmScrollBarSetValues (widget, value, size, 0, 0, False);
7970 else if (last_scroll_bar_part == scroll_bar_down_arrow)
7971 /* This has the negative side effect that the slider value is
ec18280f 7972 not what it would be if we scrolled here using line-wise or
06a2c219
GM
7973 page-wise movement. */
7974 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
7975 else
7976 {
7977 /* If currently dragging, only update the slider size.
7978 This reduces flicker effects. */
7979 int old_value, old_size, increment, page_increment;
7980
7981 XmScrollBarGetValues (widget, &old_value, &old_size,
7982 &increment, &page_increment);
7983 XmScrollBarSetValues (widget, old_value,
7984 min (size, XM_SB_RANGE - old_value),
7985 0, 0, False);
7986 }
7987
7988 sb->scrollBar.arrow1_selected = arrow1_selected;
7989 sb->scrollBar.arrow2_selected = arrow2_selected;
7990 sb->scrollBar.flags = flags;
7991 }
ec18280f 7992#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 7993 {
ec18280f
SM
7994 float old_top, old_shown;
7995 Dimension height;
7996 XtVaGetValues (widget,
7997 XtNtopOfThumb, &old_top,
7998 XtNshown, &old_shown,
7999 XtNheight, &height,
8000 NULL);
8001
8002 /* Massage the top+shown values. */
8003 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8004 top = max (0, min (1, top));
8005 else
8006 top = old_top;
8007 /* Keep two pixels available for moving the thumb down. */
8008 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8009
8010 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8011 check that your system's configuration file contains a define
8012 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8013 if (top != old_top || shown != old_shown)
eb393530 8014 {
ec18280f 8015 if (NILP (bar->dragging))
eb393530 8016 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8017 else
8018 {
ec18280f
SM
8019#ifdef HAVE_XAW3D
8020 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8021 int scroll_mode = 0;
ec18280f
SM
8022
8023 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8024 if (xaw3d_arrow_scroll)
8025 {
8026 /* Xaw3d stupidly ignores resize requests while dragging
8027 so we have to make it believe it's not in dragging mode. */
8028 scroll_mode = sb->scrollbar.scroll_mode;
8029 if (scroll_mode == 2)
8030 sb->scrollbar.scroll_mode = 0;
8031 }
8032#endif
8033 /* Try to make the scrolling a tad smoother. */
8034 if (!xaw3d_pick_top)
8035 shown = min (shown, old_shown);
8036
8037 XawScrollbarSetThumb (widget, top, shown);
8038
8039#ifdef HAVE_XAW3D
8040 if (xaw3d_arrow_scroll && scroll_mode == 2)
8041 sb->scrollbar.scroll_mode = scroll_mode;
8042#endif
06a2c219 8043 }
06a2c219
GM
8044 }
8045 }
ec18280f 8046#endif /* !USE_MOTIF */
06a2c219
GM
8047
8048 UNBLOCK_INPUT;
f451eb13
JB
8049}
8050
06a2c219
GM
8051#endif /* USE_TOOLKIT_SCROLL_BARS */
8052
8053
8054\f
8055/************************************************************************
8056 Scroll bars, general
8057 ************************************************************************/
8058
8059/* Create a scroll bar and return the scroll bar vector for it. W is
8060 the Emacs window on which to create the scroll bar. TOP, LEFT,
8061 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8062 scroll bar. */
8063
ab648270 8064static struct scroll_bar *
06a2c219
GM
8065x_scroll_bar_create (w, top, left, width, height)
8066 struct window *w;
f451eb13
JB
8067 int top, left, width, height;
8068{
06a2c219 8069 struct frame *f = XFRAME (w->frame);
334208b7
RS
8070 struct scroll_bar *bar
8071 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8072
8073 BLOCK_INPUT;
8074
06a2c219
GM
8075#if USE_TOOLKIT_SCROLL_BARS
8076 x_create_toolkit_scroll_bar (f, bar);
8077#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8078 {
8079 XSetWindowAttributes a;
8080 unsigned long mask;
5c187dee 8081 Window window;
06a2c219
GM
8082
8083 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8084 if (a.background_pixel == -1)
8085 a.background_pixel = f->output_data.x->background_pixel;
8086
12ba150f 8087 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8088 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8089 | ExposureMask);
7a13e894 8090 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8091
dbc4e1c1 8092 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8093
06a2c219
GM
8094 /* Clear the area of W that will serve as a scroll bar. This is
8095 for the case that a window has been split horizontally. In
8096 this case, no clear_frame is generated to reduce flickering. */
8097 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8098 left, top, width,
8099 window_box_height (w), False);
8100
8101 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8102 /* Position and size of scroll bar. */
8103 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8104 top,
8105 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8106 height,
8107 /* Border width, depth, class, and visual. */
8108 0,
8109 CopyFromParent,
8110 CopyFromParent,
8111 CopyFromParent,
8112 /* Attributes. */
8113 mask, &a);
8114 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8115 }
06a2c219 8116#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8117
06a2c219 8118 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8119 XSETINT (bar->top, top);
8120 XSETINT (bar->left, left);
8121 XSETINT (bar->width, width);
8122 XSETINT (bar->height, height);
8123 XSETINT (bar->start, 0);
8124 XSETINT (bar->end, 0);
12ba150f 8125 bar->dragging = Qnil;
f451eb13
JB
8126
8127 /* Add bar to its frame's list of scroll bars. */
334208b7 8128 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8129 bar->prev = Qnil;
334208b7 8130 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 8131 if (!NILP (bar->next))
e0c1aef2 8132 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 8133
06a2c219
GM
8134 /* Map the window/widget. */
8135#if USE_TOOLKIT_SCROLL_BARS
8136 XtMapWidget (SCROLL_BAR_X_WIDGET (bar));
8137 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
8138 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8139 top,
8140 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8141 height, 0);
8142#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 8143 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 8144#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8145
8146 UNBLOCK_INPUT;
12ba150f 8147 return bar;
f451eb13
JB
8148}
8149
06a2c219 8150
12ba150f 8151/* Draw BAR's handle in the proper position.
06a2c219 8152
12ba150f
JB
8153 If the handle is already drawn from START to END, don't bother
8154 redrawing it, unless REBUILD is non-zero; in that case, always
8155 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 8156 events.)
12ba150f
JB
8157
8158 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
8159 fit inside its rectangle, but if the user is dragging the scroll
8160 bar handle, we want to let them drag it down all the way, so that
8161 the bar's top is as far down as it goes; otherwise, there's no way
8162 to move to the very end of the buffer. */
8163
5c187dee
GM
8164#ifndef USE_TOOLKIT_SCROLL_BARS
8165
f451eb13 8166static void
ab648270
JB
8167x_scroll_bar_set_handle (bar, start, end, rebuild)
8168 struct scroll_bar *bar;
f451eb13 8169 int start, end;
12ba150f 8170 int rebuild;
f451eb13 8171{
12ba150f 8172 int dragging = ! NILP (bar->dragging);
ab648270 8173 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8174 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8175 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
8176
8177 /* If the display is already accurate, do nothing. */
8178 if (! rebuild
8179 && start == XINT (bar->start)
8180 && end == XINT (bar->end))
8181 return;
8182
f451eb13
JB
8183 BLOCK_INPUT;
8184
8185 {
d9cdbb3d
RS
8186 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
8187 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
8188 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
8189
8190 /* Make sure the values are reasonable, and try to preserve
8191 the distance between start and end. */
12ba150f
JB
8192 {
8193 int length = end - start;
8194
8195 if (start < 0)
8196 start = 0;
8197 else if (start > top_range)
8198 start = top_range;
8199 end = start + length;
8200
8201 if (end < start)
8202 end = start;
8203 else if (end > top_range && ! dragging)
8204 end = top_range;
8205 }
f451eb13 8206
ab648270 8207 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
8208 XSETINT (bar->start, start);
8209 XSETINT (bar->end, end);
f451eb13 8210
12ba150f
JB
8211 /* Clip the end position, just for display. */
8212 if (end > top_range)
8213 end = top_range;
f451eb13 8214
ab648270 8215 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
8216 below top positions, to make sure the handle is always at least
8217 that many pixels tall. */
ab648270 8218 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 8219
12ba150f
JB
8220 /* Draw the empty space above the handle. Note that we can't clear
8221 zero-height areas; that means "clear to end of window." */
8222 if (0 < start)
334208b7 8223 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8224
12ba150f 8225 /* x, y, width, height, and exposures. */
ab648270
JB
8226 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8227 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
8228 inside_width, start,
8229 False);
f451eb13 8230
06a2c219
GM
8231 /* Change to proper foreground color if one is specified. */
8232 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8233 XSetForeground (FRAME_X_DISPLAY (f), gc,
8234 f->output_data.x->scroll_bar_foreground_pixel);
8235
12ba150f 8236 /* Draw the handle itself. */
334208b7 8237 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 8238
12ba150f 8239 /* x, y, width, height */
ab648270
JB
8240 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8241 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 8242 inside_width, end - start);
f451eb13 8243
06a2c219
GM
8244 /* Restore the foreground color of the GC if we changed it above. */
8245 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8246 XSetForeground (FRAME_X_DISPLAY (f), gc,
8247 f->output_data.x->foreground_pixel);
f451eb13 8248
12ba150f
JB
8249 /* Draw the empty space below the handle. Note that we can't
8250 clear zero-height areas; that means "clear to end of window." */
8251 if (end < inside_height)
334208b7 8252 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8253
12ba150f 8254 /* x, y, width, height, and exposures. */
ab648270
JB
8255 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8256 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
8257 inside_width, inside_height - end,
8258 False);
f451eb13 8259
f451eb13
JB
8260 }
8261
f451eb13
JB
8262 UNBLOCK_INPUT;
8263}
8264
5c187dee 8265#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 8266
06a2c219
GM
8267/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
8268 nil. */
58769bee 8269
12ba150f 8270static void
ab648270
JB
8271x_scroll_bar_remove (bar)
8272 struct scroll_bar *bar;
12ba150f 8273{
12ba150f
JB
8274 BLOCK_INPUT;
8275
06a2c219
GM
8276#if USE_TOOLKIT_SCROLL_BARS
8277 XtDestroyWidget (SCROLL_BAR_X_WIDGET (bar));
8278#else /* not USE_TOOLKIT_SCROLL_BARS */
5c187dee
GM
8279 {
8280 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8281 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
8282 }
06a2c219
GM
8283#endif /* not USE_TOOLKIT_SCROLL_BARS */
8284
ab648270
JB
8285 /* Disassociate this scroll bar from its window. */
8286 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
8287
8288 UNBLOCK_INPUT;
8289}
8290
06a2c219 8291
12ba150f
JB
8292/* Set the handle of the vertical scroll bar for WINDOW to indicate
8293 that we are displaying PORTION characters out of a total of WHOLE
ab648270 8294 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 8295 create one. */
06a2c219 8296
12ba150f 8297static void
06a2c219
GM
8298XTset_vertical_scroll_bar (w, portion, whole, position)
8299 struct window *w;
f451eb13
JB
8300 int portion, whole, position;
8301{
06a2c219 8302 struct frame *f = XFRAME (w->frame);
ab648270 8303 struct scroll_bar *bar;
3c6ede7b 8304 int top, height, left, sb_left, width, sb_width;
06a2c219 8305 int window_x, window_y, window_width, window_height;
06a2c219 8306
3c6ede7b 8307 /* Get window dimensions. */
06a2c219 8308 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
8309 top = window_y;
8310 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
8311 height = window_height;
06a2c219 8312
3c6ede7b 8313 /* Compute the left edge of the scroll bar area. */
06a2c219 8314 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
8315 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
8316 else
8317 left = XFASTINT (w->left);
8318 left *= CANON_X_UNIT (f);
8319 left += FRAME_INTERNAL_BORDER_WIDTH (f);
8320
8321 /* Compute the width of the scroll bar which might be less than
8322 the width of the area reserved for the scroll bar. */
8323 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
8324 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 8325 else
3c6ede7b 8326 sb_width = width;
12ba150f 8327
3c6ede7b
GM
8328 /* Compute the left edge of the scroll bar. */
8329#ifdef USE_TOOLKIT_SCROLL_BARS
8330 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8331 sb_left = left + width - sb_width - (width - sb_width) / 2;
8332 else
8333 sb_left = left + (width - sb_width) / 2;
8334#else
8335 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8336 sb_left = left + width - sb_width;
8337 else
8338 sb_left = left;
8339#endif
8340
ab648270 8341 /* Does the scroll bar exist yet? */
06a2c219 8342 if (NILP (w->vertical_scroll_bar))
3c6ede7b 8343 {
80c32bcc 8344 BLOCK_INPUT;
3c6ede7b
GM
8345 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8346 left, top, width, height, False);
80c32bcc 8347 UNBLOCK_INPUT;
3c6ede7b
GM
8348 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
8349 }
f451eb13 8350 else
12ba150f
JB
8351 {
8352 /* It may just need to be moved and resized. */
06a2c219
GM
8353 unsigned int mask = 0;
8354
8355 bar = XSCROLL_BAR (w->vertical_scroll_bar);
8356
8357 BLOCK_INPUT;
8358
3c6ede7b 8359 if (sb_left != XINT (bar->left))
06a2c219 8360 mask |= CWX;
3c6ede7b 8361 if (top != XINT (bar->top))
06a2c219 8362 mask |= CWY;
3c6ede7b 8363 if (sb_width != XINT (bar->width))
06a2c219 8364 mask |= CWWidth;
3c6ede7b 8365 if (height != XINT (bar->height))
06a2c219
GM
8366 mask |= CWHeight;
8367
8368#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
8369
8370 /* Since toolkit scroll bars are smaller than the space reserved
8371 for them on the frame, we have to clear "under" them. */
8372 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3c6ede7b 8373 left, top, width, height, False);
06a2c219
GM
8374
8375 /* Move/size the scroll bar widget. */
8376 if (mask)
8377 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
3c6ede7b
GM
8378 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8379 top,
8380 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8381 height, 0);
06a2c219
GM
8382
8383#else /* not USE_TOOLKIT_SCROLL_BARS */
8384
e1f6572f
RS
8385 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
8386 {
8387 /* Clear areas not covered by the scroll bar. This makes sure a
8388 previous mode line display is cleared after C-x 2 C-x 1, for
8389 example. Non-toolkit scroll bars are as wide as the area
8390 reserved for scroll bars - trim at both sides. */
8391 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8392 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8393 height, False);
8394 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8395 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8396 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8397 height, False);
8398 }
06a2c219
GM
8399
8400 /* Move/size the scroll bar window. */
8401 if (mask)
8402 {
8403 XWindowChanges wc;
8404
3c6ede7b
GM
8405 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
8406 wc.y = top;
8407 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
8408 wc.height = height;
06a2c219
GM
8409 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
8410 mask, &wc);
8411 }
8412
8413#endif /* not USE_TOOLKIT_SCROLL_BARS */
8414
8415 /* Remember new settings. */
3c6ede7b
GM
8416 XSETINT (bar->left, sb_left);
8417 XSETINT (bar->top, top);
8418 XSETINT (bar->width, sb_width);
8419 XSETINT (bar->height, height);
06a2c219
GM
8420
8421 UNBLOCK_INPUT;
12ba150f 8422 }
f451eb13 8423
06a2c219
GM
8424#if USE_TOOLKIT_SCROLL_BARS
8425 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
8426#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 8427 /* Set the scroll bar's current state, unless we're currently being
f451eb13 8428 dragged. */
12ba150f 8429 if (NILP (bar->dragging))
f451eb13 8430 {
92857db0 8431 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 8432
12ba150f 8433 if (whole == 0)
ab648270 8434 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
8435 else
8436 {
43f868f5
JB
8437 int start = ((double) position * top_range) / whole;
8438 int end = ((double) (position + portion) * top_range) / whole;
ab648270 8439 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 8440 }
f451eb13 8441 }
06a2c219 8442#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8443
06a2c219 8444 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
8445}
8446
12ba150f 8447
f451eb13 8448/* The following three hooks are used when we're doing a thorough
ab648270 8449 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 8450 are going to be deleted, because keeping track of when windows go
12ba150f
JB
8451 away is a real pain - "Can you say set-window-configuration, boys
8452 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 8453 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 8454 from the fiery pit when we actually redisplay its window. */
f451eb13 8455
ab648270
JB
8456/* Arrange for all scroll bars on FRAME to be removed at the next call
8457 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
8458 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
8459
58769bee 8460static void
ab648270 8461XTcondemn_scroll_bars (frame)
f451eb13
JB
8462 FRAME_PTR frame;
8463{
f9e24cb9
RS
8464 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
8465 while (! NILP (FRAME_SCROLL_BARS (frame)))
8466 {
8467 Lisp_Object bar;
8468 bar = FRAME_SCROLL_BARS (frame);
8469 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
8470 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
8471 XSCROLL_BAR (bar)->prev = Qnil;
8472 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
8473 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
8474 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
8475 }
f451eb13
JB
8476}
8477
06a2c219 8478/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 8479 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 8480static void
ab648270 8481XTredeem_scroll_bar (window)
12ba150f 8482 struct window *window;
f451eb13 8483{
ab648270 8484 struct scroll_bar *bar;
12ba150f 8485
ab648270
JB
8486 /* We can't redeem this window's scroll bar if it doesn't have one. */
8487 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
8488 abort ();
8489
ab648270 8490 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
8491
8492 /* Unlink it from the condemned list. */
8493 {
8494 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
8495
8496 if (NILP (bar->prev))
8497 {
8498 /* If the prev pointer is nil, it must be the first in one of
8499 the lists. */
ab648270 8500 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
8501 /* It's not condemned. Everything's fine. */
8502 return;
ab648270
JB
8503 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
8504 window->vertical_scroll_bar))
8505 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
8506 else
8507 /* If its prev pointer is nil, it must be at the front of
8508 one or the other! */
8509 abort ();
8510 }
8511 else
ab648270 8512 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
8513
8514 if (! NILP (bar->next))
ab648270 8515 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 8516
ab648270 8517 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8518 bar->prev = Qnil;
e0c1aef2 8519 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 8520 if (! NILP (bar->next))
e0c1aef2 8521 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
12ba150f 8522 }
f451eb13
JB
8523}
8524
ab648270
JB
8525/* Remove all scroll bars on FRAME that haven't been saved since the
8526 last call to `*condemn_scroll_bars_hook'. */
06a2c219 8527
f451eb13 8528static void
ab648270 8529XTjudge_scroll_bars (f)
12ba150f 8530 FRAME_PTR f;
f451eb13 8531{
12ba150f 8532 Lisp_Object bar, next;
f451eb13 8533
ab648270 8534 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
8535
8536 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
8537 more events on the hapless scroll bars. */
8538 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
8539
8540 for (; ! NILP (bar); bar = next)
f451eb13 8541 {
ab648270 8542 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 8543
ab648270 8544 x_scroll_bar_remove (b);
12ba150f
JB
8545
8546 next = b->next;
8547 b->next = b->prev = Qnil;
f451eb13 8548 }
12ba150f 8549
ab648270 8550 /* Now there should be no references to the condemned scroll bars,
12ba150f 8551 and they should get garbage-collected. */
f451eb13
JB
8552}
8553
8554
06a2c219
GM
8555/* Handle an Expose or GraphicsExpose event on a scroll bar. This
8556 is a no-op when using toolkit scroll bars.
ab648270
JB
8557
8558 This may be called from a signal handler, so we have to ignore GC
8559 mark bits. */
06a2c219 8560
f451eb13 8561static void
ab648270
JB
8562x_scroll_bar_expose (bar, event)
8563 struct scroll_bar *bar;
f451eb13
JB
8564 XEvent *event;
8565{
06a2c219
GM
8566#ifndef USE_TOOLKIT_SCROLL_BARS
8567
ab648270 8568 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8569 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8570 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 8571 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 8572
f451eb13
JB
8573 BLOCK_INPUT;
8574
ab648270 8575 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 8576
06a2c219 8577 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 8578 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
8579
8580 /* x, y, width, height */
d9cdbb3d 8581 0, 0,
3cbd2e0b 8582 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
8583 XINT (bar->height) - 1);
8584
f451eb13 8585 UNBLOCK_INPUT;
06a2c219
GM
8586
8587#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8588}
8589
ab648270
JB
8590/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8591 is set to something other than no_event, it is enqueued.
8592
8593 This may be called from a signal handler, so we have to ignore GC
8594 mark bits. */
06a2c219 8595
5c187dee
GM
8596#ifndef USE_TOOLKIT_SCROLL_BARS
8597
f451eb13 8598static void
ab648270
JB
8599x_scroll_bar_handle_click (bar, event, emacs_event)
8600 struct scroll_bar *bar;
f451eb13
JB
8601 XEvent *event;
8602 struct input_event *emacs_event;
8603{
0299d313 8604 if (! GC_WINDOWP (bar->window))
12ba150f
JB
8605 abort ();
8606
ab648270 8607 emacs_event->kind = scroll_bar_click;
69388238 8608 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
8609 emacs_event->modifiers
8610 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
8611 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
8612 event->xbutton.state)
8613 | (event->type == ButtonRelease
8614 ? up_modifier
8615 : down_modifier));
12ba150f 8616 emacs_event->frame_or_window = bar->window;
0f8aabe9 8617 emacs_event->arg = Qnil;
f451eb13 8618 emacs_event->timestamp = event->xbutton.time;
12ba150f 8619 {
06a2c219 8620#if 0
d9cdbb3d 8621 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 8622 int internal_height
d9cdbb3d 8623 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8624#endif
0299d313 8625 int top_range
d9cdbb3d 8626 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 8627 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
8628
8629 if (y < 0) y = 0;
8630 if (y > top_range) y = top_range;
8631
8632 if (y < XINT (bar->start))
ab648270
JB
8633 emacs_event->part = scroll_bar_above_handle;
8634 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8635 emacs_event->part = scroll_bar_handle;
12ba150f 8636 else
ab648270 8637 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
8638
8639 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
8640 they want to drag it. Lisp code needs to be able to decide
8641 whether or not we're dragging. */
929787e1 8642#if 0
12ba150f
JB
8643 /* If the user has just clicked on the handle, record where they're
8644 holding it. */
8645 if (event->type == ButtonPress
ab648270 8646 && emacs_event->part == scroll_bar_handle)
e0c1aef2 8647 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 8648#endif
12ba150f
JB
8649
8650 /* If the user has released the handle, set it to its final position. */
8651 if (event->type == ButtonRelease
8652 && ! NILP (bar->dragging))
8653 {
8654 int new_start = y - XINT (bar->dragging);
8655 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 8656
ab648270 8657 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
8658 bar->dragging = Qnil;
8659 }
f451eb13 8660
5116f055
JB
8661 /* Same deal here as the other #if 0. */
8662#if 0
58769bee 8663 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 8664 the handle. */
ab648270 8665 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
8666 emacs_event->x = bar->start;
8667 else
e0c1aef2 8668 XSETINT (emacs_event->x, y);
5116f055 8669#else
e0c1aef2 8670 XSETINT (emacs_event->x, y);
5116f055 8671#endif
f451eb13 8672
e0c1aef2 8673 XSETINT (emacs_event->y, top_range);
12ba150f
JB
8674 }
8675}
f451eb13 8676
ab648270
JB
8677/* Handle some mouse motion while someone is dragging the scroll bar.
8678
8679 This may be called from a signal handler, so we have to ignore GC
8680 mark bits. */
06a2c219 8681
f451eb13 8682static void
ab648270
JB
8683x_scroll_bar_note_movement (bar, event)
8684 struct scroll_bar *bar;
f451eb13
JB
8685 XEvent *event;
8686{
39d8bb4d
KH
8687 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
8688
f451eb13
JB
8689 last_mouse_movement_time = event->xmotion.time;
8690
39d8bb4d 8691 f->mouse_moved = 1;
e0c1aef2 8692 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
8693
8694 /* If we're dragging the bar, display it. */
ab648270 8695 if (! GC_NILP (bar->dragging))
f451eb13
JB
8696 {
8697 /* Where should the handle be now? */
12ba150f 8698 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 8699
12ba150f 8700 if (new_start != XINT (bar->start))
f451eb13 8701 {
12ba150f 8702 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 8703
ab648270 8704 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
8705 }
8706 }
f451eb13
JB
8707}
8708
5c187dee
GM
8709#endif /* !USE_TOOLKIT_SCROLL_BARS */
8710
12ba150f 8711/* Return information to the user about the current position of the mouse
ab648270 8712 on the scroll bar. */
06a2c219 8713
12ba150f 8714static void
334208b7
RS
8715x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
8716 FRAME_PTR *fp;
12ba150f 8717 Lisp_Object *bar_window;
ab648270 8718 enum scroll_bar_part *part;
12ba150f
JB
8719 Lisp_Object *x, *y;
8720 unsigned long *time;
8721{
ab648270 8722 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
8723 Window w = SCROLL_BAR_X_WINDOW (bar);
8724 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 8725 int win_x, win_y;
559cb2fb
JB
8726 Window dummy_window;
8727 int dummy_coord;
8728 unsigned int dummy_mask;
12ba150f 8729
cf7cb199
JB
8730 BLOCK_INPUT;
8731
ab648270 8732 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 8733 report that. */
334208b7 8734 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 8735
559cb2fb
JB
8736 /* Root, child, root x and root y. */
8737 &dummy_window, &dummy_window,
8738 &dummy_coord, &dummy_coord,
12ba150f 8739
559cb2fb
JB
8740 /* Position relative to scroll bar. */
8741 &win_x, &win_y,
12ba150f 8742
559cb2fb
JB
8743 /* Mouse buttons and modifier keys. */
8744 &dummy_mask))
7a13e894 8745 ;
559cb2fb
JB
8746 else
8747 {
06a2c219 8748#if 0
559cb2fb 8749 int inside_height
d9cdbb3d 8750 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8751#endif
559cb2fb 8752 int top_range
d9cdbb3d 8753 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
8754
8755 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
8756
8757 if (! NILP (bar->dragging))
8758 win_y -= XINT (bar->dragging);
8759
8760 if (win_y < 0)
8761 win_y = 0;
8762 if (win_y > top_range)
8763 win_y = top_range;
8764
334208b7 8765 *fp = f;
7a13e894 8766 *bar_window = bar->window;
559cb2fb
JB
8767
8768 if (! NILP (bar->dragging))
8769 *part = scroll_bar_handle;
8770 else if (win_y < XINT (bar->start))
8771 *part = scroll_bar_above_handle;
8772 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8773 *part = scroll_bar_handle;
8774 else
8775 *part = scroll_bar_below_handle;
12ba150f 8776
e0c1aef2
KH
8777 XSETINT (*x, win_y);
8778 XSETINT (*y, top_range);
12ba150f 8779
39d8bb4d 8780 f->mouse_moved = 0;
559cb2fb
JB
8781 last_mouse_scroll_bar = Qnil;
8782 }
12ba150f 8783
559cb2fb 8784 *time = last_mouse_movement_time;
cf7cb199 8785
cf7cb199 8786 UNBLOCK_INPUT;
12ba150f
JB
8787}
8788
f451eb13 8789
dbc4e1c1 8790/* The screen has been cleared so we may have changed foreground or
ab648270
JB
8791 background colors, and the scroll bars may need to be redrawn.
8792 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
8793 redraw them. */
8794
dfcf069d 8795void
ab648270 8796x_scroll_bar_clear (f)
dbc4e1c1
JB
8797 FRAME_PTR f;
8798{
06a2c219 8799#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
8800 Lisp_Object bar;
8801
b80c363e
RS
8802 /* We can have scroll bars even if this is 0,
8803 if we just turned off scroll bar mode.
8804 But in that case we should not clear them. */
8805 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
8806 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
8807 bar = XSCROLL_BAR (bar)->next)
8808 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
8809 0, 0, 0, 0, True);
06a2c219 8810#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
8811}
8812
06a2c219 8813/* This processes Expose events from the menu-bar specific X event
19126e11 8814 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 8815 when handling menu-bar or pop-up items. */
3afe33e7 8816
06a2c219 8817int
3afe33e7
RS
8818process_expose_from_menu (event)
8819 XEvent event;
8820{
8821 FRAME_PTR f;
19126e11 8822 struct x_display_info *dpyinfo;
06a2c219 8823 int frame_exposed_p = 0;
3afe33e7 8824
f94397b5
KH
8825 BLOCK_INPUT;
8826
19126e11
KH
8827 dpyinfo = x_display_info_for_display (event.xexpose.display);
8828 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
8829 if (f)
8830 {
8831 if (f->async_visible == 0)
8832 {
8833 f->async_visible = 1;
8834 f->async_iconified = 0;
06c488fd 8835 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
8836 SET_FRAME_GARBAGED (f);
8837 }
8838 else
8839 {
06a2c219
GM
8840 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
8841 event.xexpose.x, event.xexpose.y,
8842 event.xexpose.width, event.xexpose.height);
8843 frame_exposed_p = 1;
3afe33e7
RS
8844 }
8845 }
8846 else
8847 {
8848 struct scroll_bar *bar
8849 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 8850
3afe33e7
RS
8851 if (bar)
8852 x_scroll_bar_expose (bar, &event);
8853 }
f94397b5
KH
8854
8855 UNBLOCK_INPUT;
06a2c219 8856 return frame_exposed_p;
3afe33e7 8857}
09756a85
RS
8858\f
8859/* Define a queue to save up SelectionRequest events for later handling. */
8860
8861struct selection_event_queue
8862 {
8863 XEvent event;
8864 struct selection_event_queue *next;
8865 };
8866
8867static struct selection_event_queue *queue;
8868
8869/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 8870
09756a85
RS
8871static int x_queue_selection_requests;
8872
8873/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 8874
09756a85 8875static void
334208b7
RS
8876x_queue_event (f, event)
8877 FRAME_PTR f;
09756a85
RS
8878 XEvent *event;
8879{
8880 struct selection_event_queue *queue_tmp
06a2c219 8881 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 8882
58769bee 8883 if (queue_tmp != NULL)
09756a85
RS
8884 {
8885 queue_tmp->event = *event;
8886 queue_tmp->next = queue;
8887 queue = queue_tmp;
8888 }
8889}
8890
8891/* Take all the queued events and put them back
8892 so that they get processed afresh. */
8893
8894static void
db3906fd
RS
8895x_unqueue_events (display)
8896 Display *display;
09756a85 8897{
58769bee 8898 while (queue != NULL)
09756a85
RS
8899 {
8900 struct selection_event_queue *queue_tmp = queue;
db3906fd 8901 XPutBackEvent (display, &queue_tmp->event);
09756a85 8902 queue = queue_tmp->next;
06a2c219 8903 xfree ((char *)queue_tmp);
09756a85
RS
8904 }
8905}
8906
8907/* Start queuing SelectionRequest events. */
8908
8909void
db3906fd
RS
8910x_start_queuing_selection_requests (display)
8911 Display *display;
09756a85
RS
8912{
8913 x_queue_selection_requests++;
8914}
8915
8916/* Stop queuing SelectionRequest events. */
8917
8918void
db3906fd
RS
8919x_stop_queuing_selection_requests (display)
8920 Display *display;
09756a85
RS
8921{
8922 x_queue_selection_requests--;
db3906fd 8923 x_unqueue_events (display);
09756a85 8924}
f451eb13
JB
8925\f
8926/* The main X event-reading loop - XTread_socket. */
dc6f92b8 8927
06a2c219 8928/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
8929 but we have to put it out here, since static variables within functions
8930 sometimes don't work. */
06a2c219 8931
dc6f92b8
JB
8932static Time enter_timestamp;
8933
11edeb03 8934/* This holds the state XLookupString needs to implement dead keys
58769bee 8935 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
8936 says that a portable program can't use this, but Stephen Gildea assures
8937 me that letting the compiler initialize it to zeros will work okay.
8938
8939 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
8940 given for enter_time stamp, above. */
8941
11edeb03
JB
8942static XComposeStatus compose_status;
8943
10e6549c
RS
8944/* Record the last 100 characters stored
8945 to help debug the loss-of-chars-during-GC problem. */
06a2c219 8946
2224b905
RS
8947static int temp_index;
8948static short temp_buffer[100];
10e6549c 8949
7a13e894
RS
8950/* Set this to nonzero to fake an "X I/O error"
8951 on a particular display. */
06a2c219 8952
7a13e894
RS
8953struct x_display_info *XTread_socket_fake_io_error;
8954
2224b905
RS
8955/* When we find no input here, we occasionally do a no-op command
8956 to verify that the X server is still running and we can still talk with it.
8957 We try all the open displays, one by one.
8958 This variable is used for cycling thru the displays. */
06a2c219 8959
2224b905
RS
8960static struct x_display_info *next_noop_dpyinfo;
8961
06a2c219
GM
8962#define SET_SAVED_MENU_EVENT(size) \
8963 do \
8964 { \
8965 if (f->output_data.x->saved_menu_event == 0) \
8966 f->output_data.x->saved_menu_event \
8967 = (XEvent *) xmalloc (sizeof (XEvent)); \
8968 bcopy (&event, f->output_data.x->saved_menu_event, size); \
8969 if (numchars >= 1) \
8970 { \
8971 bufp->kind = menu_bar_activate_event; \
8972 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 8973 bufp->arg = Qnil; \
06a2c219
GM
8974 bufp++; \
8975 count++; \
8976 numchars--; \
8977 } \
8978 } \
8979 while (0)
8980
8805890a 8981#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 8982#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 8983
dc6f92b8
JB
8984/* Read events coming from the X server.
8985 This routine is called by the SIGIO handler.
8986 We return as soon as there are no more events to be read.
8987
8988 Events representing keys are stored in buffer BUFP,
8989 which can hold up to NUMCHARS characters.
8990 We return the number of characters stored into the buffer,
8991 thus pretending to be `read'.
8992
dc6f92b8
JB
8993 EXPECTED is nonzero if the caller knows input is available. */
8994
7c5283e4 8995int
f66868ba 8996XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 8997 register int sd;
8805890a
KH
8998 /* register */ struct input_event *bufp;
8999 /* register */ int numchars;
dc6f92b8
JB
9000 int expected;
9001{
9002 int count = 0;
9003 int nbytes = 0;
dc6f92b8 9004 XEvent event;
f676886a 9005 struct frame *f;
66f55a9d 9006 int event_found = 0;
334208b7 9007 struct x_display_info *dpyinfo;
dc6f92b8 9008
9ac0d9e0 9009 if (interrupt_input_blocked)
dc6f92b8 9010 {
9ac0d9e0 9011 interrupt_input_pending = 1;
dc6f92b8
JB
9012 return -1;
9013 }
9014
9ac0d9e0 9015 interrupt_input_pending = 0;
dc6f92b8 9016 BLOCK_INPUT;
c0a04927
RS
9017
9018 /* So people can tell when we have read the available input. */
9019 input_signal_count++;
9020
dc6f92b8 9021 if (numchars <= 0)
06a2c219 9022 abort (); /* Don't think this happens. */
dc6f92b8 9023
bde5503b
GM
9024 ++handling_signal;
9025
7a13e894
RS
9026 /* Find the display we are supposed to read input for.
9027 It's the one communicating on descriptor SD. */
9028 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9029 {
9030#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9031#ifdef FIOSNBIO
7a13e894
RS
9032 /* If available, Xlib uses FIOSNBIO to make the socket
9033 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9034 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9035 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9036 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9037#endif /* ! defined (FIOSNBIO) */
7a13e894 9038#endif
dc6f92b8 9039
7a13e894
RS
9040#if 0 /* This code can't be made to work, with multiple displays,
9041 and appears not to be used on any system any more.
9042 Also keyboard.c doesn't turn O_NDELAY on and off
9043 for X connections. */
dc6f92b8
JB
9044#ifndef SIGIO
9045#ifndef HAVE_SELECT
7a13e894
RS
9046 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9047 {
9048 extern int read_alarm_should_throw;
9049 read_alarm_should_throw = 1;
9050 XPeekEvent (dpyinfo->display, &event);
9051 read_alarm_should_throw = 0;
9052 }
c118dd06
JB
9053#endif /* HAVE_SELECT */
9054#endif /* SIGIO */
7a13e894 9055#endif
dc6f92b8 9056
7a13e894
RS
9057 /* For debugging, this gives a way to fake an I/O error. */
9058 if (dpyinfo == XTread_socket_fake_io_error)
9059 {
9060 XTread_socket_fake_io_error = 0;
9061 x_io_error_quitter (dpyinfo->display);
9062 }
dc6f92b8 9063
06a2c219 9064 while (XPending (dpyinfo->display))
dc6f92b8 9065 {
7a13e894 9066 XNextEvent (dpyinfo->display, &event);
06a2c219 9067
531483fb 9068#ifdef HAVE_X_I18N
d1bc4182 9069 {
f2be1146
GM
9070 /* Filter events for the current X input method.
9071 XFilterEvent returns non-zero if the input method has
9072 consumed the event. We pass the frame's X window to
9073 XFilterEvent because that's the one for which the IC
9074 was created. */
f5d11644
GM
9075 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9076 event.xclient.window);
9077 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9078 break;
9079 }
0cd6403b 9080#endif
7a13e894
RS
9081 event_found = 1;
9082
9083 switch (event.type)
9084 {
9085 case ClientMessage:
c047688c 9086 {
7a13e894
RS
9087 if (event.xclient.message_type
9088 == dpyinfo->Xatom_wm_protocols
9089 && event.xclient.format == 32)
c047688c 9090 {
7a13e894
RS
9091 if (event.xclient.data.l[0]
9092 == dpyinfo->Xatom_wm_take_focus)
c047688c 9093 {
8c1a6a84
RS
9094 /* Use x_any_window_to_frame because this
9095 could be the shell widget window
9096 if the frame has no title bar. */
9097 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
9098#ifdef HAVE_X_I18N
9099 /* Not quite sure this is needed -pd */
8c1a6a84 9100 if (f && FRAME_XIC (f))
6c183ba5
RS
9101 XSetICFocus (FRAME_XIC (f));
9102#endif
f1da8f06
GM
9103#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
9104 instructs the WM to set the input focus automatically for
9105 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
9106 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
9107 it has set the focus. So, XSetInputFocus below is not
9108 needed.
9109
9110 The call to XSetInputFocus below has also caused trouble. In
9111 cases where the XSetInputFocus done by the WM and the one
9112 below are temporally close (on a fast machine), the call
9113 below can generate additional FocusIn events which confuse
9114 Emacs. */
9115
bf7253f4
RS
9116 /* Since we set WM_TAKE_FOCUS, we must call
9117 XSetInputFocus explicitly. But not if f is null,
9118 since that might be an event for a deleted frame. */
7a13e894 9119 if (f)
bf7253f4
RS
9120 {
9121 Display *d = event.xclient.display;
9122 /* Catch and ignore errors, in case window has been
9123 iconified by a window manager such as GWM. */
9124 int count = x_catch_errors (d);
9125 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
9126 /* The ICCCM says this is
9127 the only valid choice. */
9128 RevertToParent,
bf7253f4
RS
9129 event.xclient.data.l[1]);
9130 /* This is needed to detect the error
9131 if there is an error. */
9132 XSync (d, False);
9133 x_uncatch_errors (d, count);
9134 }
7a13e894 9135 /* Not certain about handling scroll bars here */
f1da8f06 9136#endif /* 0 */
c047688c 9137 }
7a13e894
RS
9138 else if (event.xclient.data.l[0]
9139 == dpyinfo->Xatom_wm_save_yourself)
9140 {
9141 /* Save state modify the WM_COMMAND property to
06a2c219 9142 something which can reinstate us. This notifies
7a13e894
RS
9143 the session manager, who's looking for such a
9144 PropertyNotify. Can restart processing when
06a2c219 9145 a keyboard or mouse event arrives. */
7a13e894
RS
9146 if (numchars > 0)
9147 {
19126e11
KH
9148 f = x_top_window_to_frame (dpyinfo,
9149 event.xclient.window);
7a13e894
RS
9150
9151 /* This is just so we only give real data once
9152 for a single Emacs process. */
b86bd3dd 9153 if (f == SELECTED_FRAME ())
7a13e894
RS
9154 XSetCommand (FRAME_X_DISPLAY (f),
9155 event.xclient.window,
9156 initial_argv, initial_argc);
f000f5c5 9157 else if (f)
7a13e894
RS
9158 XSetCommand (FRAME_X_DISPLAY (f),
9159 event.xclient.window,
9160 0, 0);
9161 }
9162 }
9163 else if (event.xclient.data.l[0]
9164 == dpyinfo->Xatom_wm_delete_window)
1fb20991 9165 {
19126e11
KH
9166 struct frame *f
9167 = x_any_window_to_frame (dpyinfo,
9168 event.xclient.window);
1fb20991 9169
7a13e894
RS
9170 if (f)
9171 {
9172 if (numchars == 0)
9173 abort ();
1fb20991 9174
7a13e894
RS
9175 bufp->kind = delete_window_event;
9176 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9177 bufp->arg = Qnil;
7a13e894
RS
9178 bufp++;
9179
9180 count += 1;
9181 numchars -= 1;
9182 }
1fb20991 9183 }
c047688c 9184 }
7a13e894
RS
9185 else if (event.xclient.message_type
9186 == dpyinfo->Xatom_wm_configure_denied)
9187 {
9188 }
9189 else if (event.xclient.message_type
9190 == dpyinfo->Xatom_wm_window_moved)
9191 {
9192 int new_x, new_y;
19126e11
KH
9193 struct frame *f
9194 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 9195
7a13e894
RS
9196 new_x = event.xclient.data.s[0];
9197 new_y = event.xclient.data.s[1];
1fb20991 9198
7a13e894
RS
9199 if (f)
9200 {
7556890b
RS
9201 f->output_data.x->left_pos = new_x;
9202 f->output_data.x->top_pos = new_y;
7a13e894 9203 }
1fb20991 9204 }
0fdff6bb 9205#ifdef HACK_EDITRES
7a13e894
RS
9206 else if (event.xclient.message_type
9207 == dpyinfo->Xatom_editres)
9208 {
19126e11
KH
9209 struct frame *f
9210 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 9211 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 9212 &event, NULL);
7a13e894 9213 }
0fdff6bb 9214#endif /* HACK_EDITRES */
06a2c219
GM
9215 else if ((event.xclient.message_type
9216 == dpyinfo->Xatom_DONE)
9217 || (event.xclient.message_type
9218 == dpyinfo->Xatom_PAGE))
9219 {
9220 /* Ghostview job completed. Kill it. We could
9221 reply with "Next" if we received "Page", but we
9222 currently never do because we are interested in
9223 images, only, which should have 1 page. */
06a2c219
GM
9224 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
9225 struct frame *f
9226 = x_window_to_frame (dpyinfo, event.xclient.window);
9227 x_kill_gs_process (pixmap, f);
9228 expose_frame (f, 0, 0, 0, 0);
9229 }
9230#ifdef USE_TOOLKIT_SCROLL_BARS
9231 /* Scroll bar callbacks send a ClientMessage from which
9232 we construct an input_event. */
9233 else if (event.xclient.message_type
9234 == dpyinfo->Xatom_Scrollbar)
9235 {
9236 x_scroll_bar_to_input_event (&event, bufp);
9237 ++bufp, ++count, --numchars;
9238 goto out;
9239 }
9240#endif /* USE_TOOLKIT_SCROLL_BARS */
9241 else
9242 goto OTHER;
7a13e894
RS
9243 }
9244 break;
dc6f92b8 9245
7a13e894 9246 case SelectionNotify:
3afe33e7 9247#ifdef USE_X_TOOLKIT
19126e11 9248 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 9249 goto OTHER;
3afe33e7 9250#endif /* not USE_X_TOOLKIT */
dfcf069d 9251 x_handle_selection_notify (&event.xselection);
7a13e894 9252 break;
d56a553a 9253
06a2c219 9254 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 9255#ifdef USE_X_TOOLKIT
19126e11 9256 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 9257 goto OTHER;
3afe33e7 9258#endif /* USE_X_TOOLKIT */
7a13e894
RS
9259 {
9260 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 9261
7a13e894
RS
9262 if (numchars == 0)
9263 abort ();
d56a553a 9264
7a13e894
RS
9265 bufp->kind = selection_clear_event;
9266 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9267 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9268 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9269 bufp->frame_or_window = Qnil;
0f8aabe9 9270 bufp->arg = Qnil;
7a13e894 9271 bufp++;
d56a553a 9272
7a13e894
RS
9273 count += 1;
9274 numchars -= 1;
9275 }
9276 break;
dc6f92b8 9277
06a2c219 9278 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 9279#ifdef USE_X_TOOLKIT
19126e11 9280 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 9281 goto OTHER;
3afe33e7 9282#endif /* USE_X_TOOLKIT */
7a13e894 9283 if (x_queue_selection_requests)
19126e11 9284 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
9285 &event);
9286 else
9287 {
9288 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 9289
7a13e894
RS
9290 if (numchars == 0)
9291 abort ();
9292
9293 bufp->kind = selection_request_event;
9294 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9295 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
9296 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9297 SELECTION_EVENT_TARGET (bufp) = eventp->target;
9298 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
9299 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9300 bufp->frame_or_window = Qnil;
0f8aabe9 9301 bufp->arg = Qnil;
7a13e894
RS
9302 bufp++;
9303
9304 count += 1;
9305 numchars -= 1;
9306 }
9307 break;
9308
9309 case PropertyNotify:
3afe33e7 9310#ifdef USE_X_TOOLKIT
19126e11 9311 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 9312 goto OTHER;
3afe33e7 9313#endif /* not USE_X_TOOLKIT */
dfcf069d 9314 x_handle_property_notify (&event.xproperty);
7a13e894 9315 break;
dc6f92b8 9316
7a13e894 9317 case ReparentNotify:
19126e11 9318 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
9319 if (f)
9320 {
9321 int x, y;
7556890b 9322 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 9323 x_real_positions (f, &x, &y);
7556890b
RS
9324 f->output_data.x->left_pos = x;
9325 f->output_data.x->top_pos = y;
7a13e894
RS
9326 }
9327 break;
3bd330d4 9328
7a13e894 9329 case Expose:
19126e11 9330 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 9331 if (f)
dc6f92b8 9332 {
7a13e894
RS
9333 if (f->async_visible == 0)
9334 {
9335 f->async_visible = 1;
9336 f->async_iconified = 0;
06c488fd 9337 f->output_data.x->has_been_visible = 1;
7a13e894
RS
9338 SET_FRAME_GARBAGED (f);
9339 }
9340 else
06a2c219
GM
9341 expose_frame (x_window_to_frame (dpyinfo,
9342 event.xexpose.window),
9343 event.xexpose.x, event.xexpose.y,
9344 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
9345 }
9346 else
7a13e894 9347 {
06a2c219
GM
9348#ifdef USE_TOOLKIT_SCROLL_BARS
9349 /* Dispatch event to the widget. */
9350 goto OTHER;
9351#else /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9352 struct scroll_bar *bar
9353 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9354
7a13e894
RS
9355 if (bar)
9356 x_scroll_bar_expose (bar, &event);
3afe33e7 9357#ifdef USE_X_TOOLKIT
7a13e894
RS
9358 else
9359 goto OTHER;
3afe33e7 9360#endif /* USE_X_TOOLKIT */
06a2c219 9361#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9362 }
9363 break;
dc6f92b8 9364
7a13e894
RS
9365 case GraphicsExpose: /* This occurs when an XCopyArea's
9366 source area was obscured or not
9367 available.*/
19126e11 9368 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
9369 if (f)
9370 {
06a2c219
GM
9371 expose_frame (f,
9372 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
9373 event.xgraphicsexpose.width,
9374 event.xgraphicsexpose.height);
7a13e894 9375 }
3afe33e7 9376#ifdef USE_X_TOOLKIT
7a13e894
RS
9377 else
9378 goto OTHER;
3afe33e7 9379#endif /* USE_X_TOOLKIT */
7a13e894 9380 break;
dc6f92b8 9381
7a13e894 9382 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
9383 source area was completely
9384 available */
7a13e894 9385 break;
dc6f92b8 9386
7a13e894 9387 case UnmapNotify:
06a2c219
GM
9388 /* Redo the mouse-highlight after the tooltip has gone. */
9389 if (event.xmap.window == tip_window)
9390 {
9391 tip_window = 0;
9392 redo_mouse_highlight ();
9393 }
9394
91ea2a7a 9395 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
9396 if (f) /* F may no longer exist if
9397 the frame was deleted. */
9398 {
9399 /* While a frame is unmapped, display generation is
9400 disabled; you don't want to spend time updating a
9401 display that won't ever be seen. */
9402 f->async_visible = 0;
9403 /* We can't distinguish, from the event, whether the window
9404 has become iconified or invisible. So assume, if it
9405 was previously visible, than now it is iconified.
1aa6072f
RS
9406 But x_make_frame_invisible clears both
9407 the visible flag and the iconified flag;
9408 and that way, we know the window is not iconified now. */
7a13e894 9409 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
9410 {
9411 f->async_iconified = 1;
bddd097c 9412
1aa6072f
RS
9413 bufp->kind = iconify_event;
9414 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9415 bufp->arg = Qnil;
1aa6072f
RS
9416 bufp++;
9417 count++;
9418 numchars--;
9419 }
7a13e894 9420 }
7a13e894 9421 goto OTHER;
dc6f92b8 9422
7a13e894 9423 case MapNotify:
06a2c219
GM
9424 if (event.xmap.window == tip_window)
9425 /* The tooltip has been drawn already. Avoid
9426 the SET_FRAME_GARBAGED below. */
9427 goto OTHER;
9428
9429 /* We use x_top_window_to_frame because map events can
9430 come for sub-windows and they don't mean that the
9431 frame is visible. */
19126e11 9432 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
9433 if (f)
9434 {
9435 f->async_visible = 1;
9436 f->async_iconified = 0;
06c488fd 9437 f->output_data.x->has_been_visible = 1;
dc6f92b8 9438
7a13e894
RS
9439 /* wait_reading_process_input will notice this and update
9440 the frame's display structures. */
9441 SET_FRAME_GARBAGED (f);
bddd097c 9442
d806e720
RS
9443 if (f->iconified)
9444 {
9445 bufp->kind = deiconify_event;
9446 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9447 bufp->arg = Qnil;
d806e720
RS
9448 bufp++;
9449 count++;
9450 numchars--;
9451 }
e73ec6fa 9452 else if (! NILP (Vframe_list)
8e713be6 9453 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
9454 /* Force a redisplay sooner or later
9455 to update the frame titles
9456 in case this is the second frame. */
9457 record_asynch_buffer_change ();
7a13e894 9458 }
7a13e894 9459 goto OTHER;
dc6f92b8 9460
7a13e894 9461 case KeyPress:
19126e11 9462 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 9463
06a2c219
GM
9464#ifdef USE_MOTIF
9465 /* I couldn't find a way to prevent LessTif scroll bars
9466 from consuming key events. */
9467 if (f == 0)
9468 {
9469 Widget widget = XtWindowToWidget (dpyinfo->display,
9470 event.xkey.window);
9471 if (widget && XmIsScrollBar (widget))
9472 {
9473 widget = XtParent (widget);
9474 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
9475 }
9476 }
9477#endif /* USE_MOTIF */
9478
7a13e894
RS
9479 if (f != 0)
9480 {
9481 KeySym keysym, orig_keysym;
9482 /* al%imercury@uunet.uu.net says that making this 81 instead of
9483 80 fixed a bug whereby meta chars made his Emacs hang. */
9484 unsigned char copy_buffer[81];
9485 int modifiers;
64bb1782 9486
7a13e894
RS
9487 event.xkey.state
9488 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
9489 extra_keyboard_modifiers);
9490 modifiers = event.xkey.state;
3a2712f9 9491
7a13e894 9492 /* This will have to go some day... */
752a043f 9493
7a13e894
RS
9494 /* make_lispy_event turns chars into control chars.
9495 Don't do it here because XLookupString is too eager. */
9496 event.xkey.state &= ~ControlMask;
5d46f928
RS
9497 event.xkey.state &= ~(dpyinfo->meta_mod_mask
9498 | dpyinfo->super_mod_mask
9499 | dpyinfo->hyper_mod_mask
9500 | dpyinfo->alt_mod_mask);
9501
1cf4a0d1
RS
9502 /* In case Meta is ComposeCharacter,
9503 clear its status. According to Markus Ehrnsperger
9504 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
9505 this enables ComposeCharacter to work whether or
9506 not it is combined with Meta. */
9507 if (modifiers & dpyinfo->meta_mod_mask)
9508 bzero (&compose_status, sizeof (compose_status));
9509
6c183ba5
RS
9510#ifdef HAVE_X_I18N
9511 if (FRAME_XIC (f))
9512 {
f5d11644
GM
9513 unsigned char *copy_bufptr = copy_buffer;
9514 int copy_bufsiz = sizeof (copy_buffer);
9515 Status status_return;
9516
6c183ba5 9517 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
9518 &event.xkey, copy_bufptr,
9519 copy_bufsiz, &keysym,
6c183ba5 9520 &status_return);
f5d11644
GM
9521 if (status_return == XBufferOverflow)
9522 {
9523 copy_bufsiz = nbytes + 1;
9524 copy_bufptr = (char *) alloca (copy_bufsiz);
9525 nbytes = XmbLookupString (FRAME_XIC (f),
9526 &event.xkey, copy_bufptr,
9527 copy_bufsiz, &keysym,
9528 &status_return);
9529 }
9530
1decb680
PE
9531 if (status_return == XLookupNone)
9532 break;
9533 else if (status_return == XLookupChars)
fdd9d55e
GM
9534 {
9535 keysym = NoSymbol;
9536 modifiers = 0;
9537 }
1decb680
PE
9538 else if (status_return != XLookupKeySym
9539 && status_return != XLookupBoth)
9540 abort ();
6c183ba5
RS
9541 }
9542 else
9543 nbytes = XLookupString (&event.xkey, copy_buffer,
9544 80, &keysym, &compose_status);
9545#else
0299d313
RS
9546 nbytes = XLookupString (&event.xkey, copy_buffer,
9547 80, &keysym, &compose_status);
6c183ba5 9548#endif
dc6f92b8 9549
7a13e894 9550 orig_keysym = keysym;
55123275 9551
7a13e894
RS
9552 if (numchars > 1)
9553 {
9554 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
9555 || keysym == XK_Delete
1097aea0 9556#ifdef XK_ISO_Left_Tab
441affdb 9557 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 9558#endif
852bff8f 9559 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
9560 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
9561 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 9562#ifdef HPUX
7a13e894
RS
9563 /* This recognizes the "extended function keys".
9564 It seems there's no cleaner way.
9565 Test IsModifierKey to avoid handling mode_switch
9566 incorrectly. */
9567 || ((unsigned) (keysym) >= XK_Select
9568 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
9569#endif
9570#ifdef XK_dead_circumflex
7a13e894 9571 || orig_keysym == XK_dead_circumflex
69388238
RS
9572#endif
9573#ifdef XK_dead_grave
7a13e894 9574 || orig_keysym == XK_dead_grave
69388238
RS
9575#endif
9576#ifdef XK_dead_tilde
7a13e894 9577 || orig_keysym == XK_dead_tilde
69388238
RS
9578#endif
9579#ifdef XK_dead_diaeresis
7a13e894 9580 || orig_keysym == XK_dead_diaeresis
69388238
RS
9581#endif
9582#ifdef XK_dead_macron
7a13e894 9583 || orig_keysym == XK_dead_macron
69388238
RS
9584#endif
9585#ifdef XK_dead_degree
7a13e894 9586 || orig_keysym == XK_dead_degree
69388238
RS
9587#endif
9588#ifdef XK_dead_acute
7a13e894 9589 || orig_keysym == XK_dead_acute
69388238
RS
9590#endif
9591#ifdef XK_dead_cedilla
7a13e894 9592 || orig_keysym == XK_dead_cedilla
69388238
RS
9593#endif
9594#ifdef XK_dead_breve
7a13e894 9595 || orig_keysym == XK_dead_breve
69388238
RS
9596#endif
9597#ifdef XK_dead_ogonek
7a13e894 9598 || orig_keysym == XK_dead_ogonek
69388238
RS
9599#endif
9600#ifdef XK_dead_caron
7a13e894 9601 || orig_keysym == XK_dead_caron
69388238
RS
9602#endif
9603#ifdef XK_dead_doubleacute
7a13e894 9604 || orig_keysym == XK_dead_doubleacute
69388238
RS
9605#endif
9606#ifdef XK_dead_abovedot
7a13e894 9607 || orig_keysym == XK_dead_abovedot
c34790e0 9608#endif
7a13e894
RS
9609 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
9610 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
9611 /* Any "vendor-specific" key is ok. */
9612 || (orig_keysym & (1 << 28)))
9613 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
9614#ifndef HAVE_X11R5
9615#ifdef XK_Mode_switch
7a13e894 9616 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
9617#endif
9618#ifdef XK_Num_Lock
7a13e894 9619 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
9620#endif
9621#endif /* not HAVE_X11R5 */
7a13e894 9622 ))
dc6f92b8 9623 {
10e6549c
RS
9624 if (temp_index == sizeof temp_buffer / sizeof (short))
9625 temp_index = 0;
7a13e894
RS
9626 temp_buffer[temp_index++] = keysym;
9627 bufp->kind = non_ascii_keystroke;
9628 bufp->code = keysym;
e0c1aef2 9629 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9630 bufp->arg = Qnil;
334208b7
RS
9631 bufp->modifiers
9632 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9633 modifiers);
1113d9db 9634 bufp->timestamp = event.xkey.time;
dc6f92b8 9635 bufp++;
7a13e894
RS
9636 count++;
9637 numchars--;
dc6f92b8 9638 }
7a13e894
RS
9639 else if (numchars > nbytes)
9640 {
9641 register int i;
9642
9643 for (i = 0; i < nbytes; i++)
9644 {
9645 if (temp_index == sizeof temp_buffer / sizeof (short))
9646 temp_index = 0;
9647 temp_buffer[temp_index++] = copy_buffer[i];
9648 bufp->kind = ascii_keystroke;
9649 bufp->code = copy_buffer[i];
9650 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9651 bufp->arg = Qnil;
7a13e894
RS
9652 bufp->modifiers
9653 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9654 modifiers);
9655 bufp->timestamp = event.xkey.time;
9656 bufp++;
9657 }
9658
9659 count += nbytes;
9660 numchars -= nbytes;
1decb680
PE
9661
9662 if (keysym == NoSymbol)
9663 break;
7a13e894
RS
9664 }
9665 else
9666 abort ();
dc6f92b8 9667 }
10e6549c
RS
9668 else
9669 abort ();
dc6f92b8 9670 }
59ddecde
GM
9671#ifdef HAVE_X_I18N
9672 /* Don't dispatch this event since XtDispatchEvent calls
9673 XFilterEvent, and two calls in a row may freeze the
9674 client. */
9675 break;
9676#else
717ca130 9677 goto OTHER;
59ddecde 9678#endif
f451eb13 9679
f5d11644 9680 case KeyRelease:
59ddecde
GM
9681#ifdef HAVE_X_I18N
9682 /* Don't dispatch this event since XtDispatchEvent calls
9683 XFilterEvent, and two calls in a row may freeze the
9684 client. */
9685 break;
9686#else
f5d11644 9687 goto OTHER;
59ddecde 9688#endif
f5d11644 9689
7a13e894 9690 /* Here's a possible interpretation of the whole
06a2c219
GM
9691 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
9692 you get a FocusIn event, you have to get a FocusOut
9693 event before you relinquish the focus. If you
9694 haven't received a FocusIn event, then a mere
9695 LeaveNotify is enough to free you. */
f451eb13 9696
7a13e894 9697 case EnterNotify:
06a2c219
GM
9698 {
9699 int from_menu_bar_p = 0;
9700
9701 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
9702
9703#ifdef LESSTIF_VERSION
9704 /* When clicking outside of a menu bar popup to close
9705 it, we get a FocusIn/ EnterNotify sequence of
9706 events. The flag event.xcrossing.focus is not set
9707 in the EnterNotify event of that sequence because
9708 the focus is in the menu bar,
9709 event.xcrossing.window is the frame's X window.
9710 Unconditionally setting the focus frame to null in
9711 this case is not the right thing, because no event
9712 follows that could set the focus frame to the right
9713 value.
9714
9715 This could be a LessTif bug, but I wasn't able to
9716 reproduce the behavior in a simple test program.
9717
9718 (gerd, LessTif 0.88.1). */
9719
9720 if (!event.xcrossing.focus
9721 && f
9722 && f->output_data.x->menubar_widget)
9723 {
9724 Window focus;
9725 int revert;
9726
9727 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9728 if (focus == XtWindow (f->output_data.x->menubar_widget))
9729 from_menu_bar_p = 1;
9730 }
9731#endif /* LESSTIF_VERSION */
6d4238f3 9732
06a2c219
GM
9733 if (event.xcrossing.focus || from_menu_bar_p)
9734 {
9735 /* Avoid nasty pop/raise loops. */
9736 if (f && (!(f->auto_raise)
9737 || !(f->auto_lower)
9738 || (event.xcrossing.time - enter_timestamp) > 500))
9739 {
9740 x_new_focus_frame (dpyinfo, f);
9741 enter_timestamp = event.xcrossing.time;
9742 }
9743 }
9744 else if (f == dpyinfo->x_focus_frame)
9745 x_new_focus_frame (dpyinfo, 0);
9746
9747 /* EnterNotify counts as mouse movement,
9748 so update things that depend on mouse position. */
9749 if (f && !f->output_data.x->busy_p)
9750 note_mouse_movement (f, &event.xmotion);
9751 goto OTHER;
9752 }
dc6f92b8 9753
7a13e894 9754 case FocusIn:
19126e11 9755 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9756 if (event.xfocus.detail != NotifyPointer)
0f941935 9757 dpyinfo->x_focus_event_frame = f;
7a13e894 9758 if (f)
eb72635f
GM
9759 {
9760 x_new_focus_frame (dpyinfo, f);
9761
9762 /* Don't stop displaying the initial startup message
9763 for a switch-frame event we don't need. */
9764 if (GC_NILP (Vterminal_frame)
9765 && GC_CONSP (Vframe_list)
9766 && !GC_NILP (XCDR (Vframe_list)))
9767 {
9768 bufp->kind = FOCUS_IN_EVENT;
9769 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9770 bufp->arg = Qnil;
eb72635f
GM
9771 ++bufp, ++count, --numchars;
9772 }
9773 }
f9e24cb9 9774
6c183ba5
RS
9775#ifdef HAVE_X_I18N
9776 if (f && FRAME_XIC (f))
9777 XSetICFocus (FRAME_XIC (f));
9778#endif
9779
7a13e894 9780 goto OTHER;
10c5e63d 9781
7a13e894 9782 case LeaveNotify:
19126e11 9783 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 9784 if (f)
10c5e63d 9785 {
06a2c219
GM
9786 Lisp_Object frame;
9787 int from_menu_bar_p = 0;
9788
7a13e894 9789 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
9790 {
9791 /* If we move outside the frame, then we're
9792 certainly no longer on any text in the frame. */
9793 clear_mouse_face (dpyinfo);
9794 dpyinfo->mouse_face_mouse_frame = 0;
9795 }
9796
9797 /* Generate a nil HELP_EVENT to cancel a help-echo.
9798 Do it only if there's something to cancel.
9799 Otherwise, the startup message is cleared when
9800 the mouse leaves the frame. */
9801 if (any_help_event_p)
9802 {
be010514
GM
9803 Lisp_Object frame;
9804 int n;
9805
06a2c219 9806 XSETFRAME (frame, f);
7cea38bc 9807 n = gen_help_event (bufp, Qnil, frame, Qnil, Qnil, 0);
be010514 9808 bufp += n, count += n, numchars -= n;
06a2c219 9809 }
7a13e894 9810
06a2c219
GM
9811#ifdef LESSTIF_VERSION
9812 /* Please see the comment at the start of the
9813 EnterNotify case. */
9814 if (!event.xcrossing.focus
9815 && f->output_data.x->menubar_widget)
9816 {
9817 Window focus;
9818 int revert;
9819 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9820 if (focus == XtWindow (f->output_data.x->menubar_widget))
9821 from_menu_bar_p = 1;
9822 }
9823#endif /* LESSTIF_VERSION */
9824
9825 if (event.xcrossing.focus || from_menu_bar_p)
0f941935 9826 x_mouse_leave (dpyinfo);
10c5e63d 9827 else
7a13e894 9828 {
0f941935
KH
9829 if (f == dpyinfo->x_focus_event_frame)
9830 dpyinfo->x_focus_event_frame = 0;
9831 if (f == dpyinfo->x_focus_frame)
9832 x_new_focus_frame (dpyinfo, 0);
7a13e894 9833 }
10c5e63d 9834 }
7a13e894 9835 goto OTHER;
dc6f92b8 9836
7a13e894 9837 case FocusOut:
19126e11 9838 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9839 if (event.xfocus.detail != NotifyPointer
0f941935
KH
9840 && f == dpyinfo->x_focus_event_frame)
9841 dpyinfo->x_focus_event_frame = 0;
9842 if (f && f == dpyinfo->x_focus_frame)
9843 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 9844
6c183ba5
RS
9845#ifdef HAVE_X_I18N
9846 if (f && FRAME_XIC (f))
9847 XUnsetICFocus (FRAME_XIC (f));
9848#endif
9849
7a13e894 9850 goto OTHER;
dc6f92b8 9851
7a13e894 9852 case MotionNotify:
dc6f92b8 9853 {
06a2c219 9854 previous_help_echo = help_echo;
7cea38bc 9855 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 9856 help_echo_pos = -1;
06a2c219 9857
7a13e894
RS
9858 if (dpyinfo->grabbed && last_mouse_frame
9859 && FRAME_LIVE_P (last_mouse_frame))
9860 f = last_mouse_frame;
9861 else
19126e11 9862 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 9863
7a13e894
RS
9864 if (f)
9865 note_mouse_movement (f, &event.xmotion);
9866 else
9867 {
e88b3c50 9868#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
9869 struct scroll_bar *bar
9870 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 9871
7a13e894
RS
9872 if (bar)
9873 x_scroll_bar_note_movement (bar, &event);
e88b3c50 9874#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 9875
06a2c219
GM
9876 /* If we move outside the frame, then we're
9877 certainly no longer on any text in the frame. */
7a13e894
RS
9878 clear_mouse_face (dpyinfo);
9879 }
06a2c219
GM
9880
9881 /* If the contents of the global variable help_echo
9882 has changed, generate a HELP_EVENT. */
b7e80413
SM
9883 if (!NILP (help_echo)
9884 || !NILP (previous_help_echo))
06a2c219
GM
9885 {
9886 Lisp_Object frame;
be010514 9887 int n;
06a2c219
GM
9888
9889 if (f)
9890 XSETFRAME (frame, f);
9891 else
9892 frame = Qnil;
9893
9894 any_help_event_p = 1;
be010514 9895 n = gen_help_event (bufp, help_echo, frame,
7cea38bc
GM
9896 help_echo_window, help_echo_object,
9897 help_echo_pos);
be010514 9898 bufp += n, count += n, numchars -= n;
06a2c219
GM
9899 }
9900
9901 goto OTHER;
dc6f92b8 9902 }
dc6f92b8 9903
7a13e894 9904 case ConfigureNotify:
9829ddba
RS
9905 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
9906 if (f)
af395ec1 9907 {
5c187dee 9908#ifndef USE_X_TOOLKIT
bf1b7b30
KH
9909 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
9910 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 9911
2d7fc7e8
RS
9912 /* In the toolkit version, change_frame_size
9913 is called by the code that handles resizing
9914 of the EmacsFrame widget. */
7a13e894 9915
7a13e894
RS
9916 /* Even if the number of character rows and columns has
9917 not changed, the font size may have changed, so we need
9918 to check the pixel dimensions as well. */
9919 if (columns != f->width
9920 || rows != f->height
7556890b
RS
9921 || event.xconfigure.width != f->output_data.x->pixel_width
9922 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 9923 {
7d1e984f 9924 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 9925 SET_FRAME_GARBAGED (f);
e687d06e 9926 cancel_mouse_face (f);
7a13e894 9927 }
2d7fc7e8 9928#endif
af395ec1 9929
7556890b
RS
9930 f->output_data.x->pixel_width = event.xconfigure.width;
9931 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
9932
9933 /* What we have now is the position of Emacs's own window.
9934 Convert that to the position of the window manager window. */
dcb07ae9
RS
9935 x_real_positions (f, &f->output_data.x->left_pos,
9936 &f->output_data.x->top_pos);
9937
f5d11644
GM
9938#ifdef HAVE_X_I18N
9939 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
9940 xic_set_statusarea (f);
9941#endif
9942
dcb07ae9
RS
9943 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
9944 {
9945 /* Since the WM decorations come below top_pos now,
9946 we must put them below top_pos in the future. */
9947 f->output_data.x->win_gravity = NorthWestGravity;
9948 x_wm_set_size_hint (f, (long) 0, 0);
9949 }
8f08dc93
KH
9950#ifdef USE_MOTIF
9951 /* Some window managers pass (0,0) as the location of
9952 the window, and the Motif event handler stores it
9953 in the emacs widget, which messes up Motif menus. */
9954 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
9955 {
9956 event.xconfigure.x = f->output_data.x->widget->core.x;
9957 event.xconfigure.y = f->output_data.x->widget->core.y;
9958 }
06a2c219 9959#endif /* USE_MOTIF */
7a13e894 9960 }
2d7fc7e8 9961 goto OTHER;
dc6f92b8 9962
7a13e894
RS
9963 case ButtonPress:
9964 case ButtonRelease:
9965 {
9966 /* If we decide we want to generate an event to be seen
9967 by the rest of Emacs, we put it here. */
9968 struct input_event emacs_event;
9ea173e8 9969 int tool_bar_p = 0;
06a2c219 9970
7a13e894 9971 emacs_event.kind = no_event;
7a13e894 9972 bzero (&compose_status, sizeof (compose_status));
9b07615b 9973
06a2c219
GM
9974 if (dpyinfo->grabbed
9975 && last_mouse_frame
9f67f20b
RS
9976 && FRAME_LIVE_P (last_mouse_frame))
9977 f = last_mouse_frame;
9978 else
2224b905 9979 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 9980
06a2c219
GM
9981 if (f)
9982 {
9ea173e8
GM
9983 /* Is this in the tool-bar? */
9984 if (WINDOWP (f->tool_bar_window)
9985 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
9986 {
9987 Lisp_Object window;
9988 int p, x, y;
9989
9990 x = event.xbutton.x;
9991 y = event.xbutton.y;
9992
9993 /* Set x and y. */
9994 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 9995 if (EQ (window, f->tool_bar_window))
06a2c219 9996 {
9ea173e8
GM
9997 x_handle_tool_bar_click (f, &event.xbutton);
9998 tool_bar_p = 1;
06a2c219
GM
9999 }
10000 }
10001
9ea173e8 10002 if (!tool_bar_p)
06a2c219
GM
10003 if (!dpyinfo->x_focus_frame
10004 || f == dpyinfo->x_focus_frame)
10005 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10006 }
10007 else
10008 {
06a2c219 10009#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10010 struct scroll_bar *bar
10011 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10012
7a13e894
RS
10013 if (bar)
10014 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10015#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10016 }
10017
10018 if (event.type == ButtonPress)
10019 {
10020 dpyinfo->grabbed |= (1 << event.xbutton.button);
10021 last_mouse_frame = f;
edad46f6
KH
10022 /* Ignore any mouse motion that happened
10023 before this event; any subsequent mouse-movement
10024 Emacs events should reflect only motion after
10025 the ButtonPress. */
a00e91cd
KH
10026 if (f != 0)
10027 f->mouse_moved = 0;
06a2c219 10028
9ea173e8
GM
10029 if (!tool_bar_p)
10030 last_tool_bar_item = -1;
7a13e894 10031 }
3afe33e7
RS
10032 else
10033 {
7a13e894 10034 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10035 }
23faf38f 10036
7a13e894
RS
10037 if (numchars >= 1 && emacs_event.kind != no_event)
10038 {
10039 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10040 bufp++;
10041 count++;
10042 numchars--;
10043 }
3afe33e7
RS
10044
10045#ifdef USE_X_TOOLKIT
2224b905
RS
10046 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10047 /* For a down-event in the menu bar,
10048 don't pass it to Xt right now.
10049 Instead, save it away
10050 and we will pass it to Xt from kbd_buffer_get_event.
10051 That way, we can run some Lisp code first. */
91375f8f
RS
10052 if (f && event.type == ButtonPress
10053 /* Verify the event is really within the menu bar
10054 and not just sent to it due to grabbing. */
10055 && event.xbutton.x >= 0
10056 && event.xbutton.x < f->output_data.x->pixel_width
10057 && event.xbutton.y >= 0
10058 && event.xbutton.y < f->output_data.x->menubar_height
10059 && event.xbutton.same_screen)
2224b905 10060 {
8805890a 10061 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
10062 XSETFRAME (last_mouse_press_frame, f);
10063 }
10064 else if (event.type == ButtonPress)
10065 {
10066 last_mouse_press_frame = Qnil;
30e671c3 10067 goto OTHER;
ce89ef46 10068 }
06a2c219 10069
2237cac9
RS
10070#ifdef USE_MOTIF /* This should do not harm for Lucid,
10071 but I am trying to be cautious. */
ce89ef46
RS
10072 else if (event.type == ButtonRelease)
10073 {
2237cac9 10074 if (!NILP (last_mouse_press_frame))
f10ded1c 10075 {
2237cac9
RS
10076 f = XFRAME (last_mouse_press_frame);
10077 if (f->output_data.x)
06a2c219 10078 SET_SAVED_BUTTON_EVENT;
f10ded1c 10079 }
06a2c219 10080 else
30e671c3 10081 goto OTHER;
2224b905 10082 }
2237cac9 10083#endif /* USE_MOTIF */
2224b905
RS
10084 else
10085 goto OTHER;
3afe33e7 10086#endif /* USE_X_TOOLKIT */
7a13e894
RS
10087 }
10088 break;
dc6f92b8 10089
7a13e894 10090 case CirculateNotify:
06a2c219
GM
10091 goto OTHER;
10092
7a13e894 10093 case CirculateRequest:
06a2c219
GM
10094 goto OTHER;
10095
10096 case VisibilityNotify:
10097 goto OTHER;
dc6f92b8 10098
7a13e894
RS
10099 case MappingNotify:
10100 /* Someone has changed the keyboard mapping - update the
10101 local cache. */
10102 switch (event.xmapping.request)
10103 {
10104 case MappingModifier:
10105 x_find_modifier_meanings (dpyinfo);
10106 /* This is meant to fall through. */
10107 case MappingKeyboard:
10108 XRefreshKeyboardMapping (&event.xmapping);
10109 }
7a13e894 10110 goto OTHER;
dc6f92b8 10111
7a13e894 10112 default:
7a13e894 10113 OTHER:
717ca130 10114#ifdef USE_X_TOOLKIT
7a13e894
RS
10115 BLOCK_INPUT;
10116 XtDispatchEvent (&event);
10117 UNBLOCK_INPUT;
3afe33e7 10118#endif /* USE_X_TOOLKIT */
7a13e894
RS
10119 break;
10120 }
dc6f92b8
JB
10121 }
10122 }
10123
06a2c219
GM
10124 out:;
10125
9a5196d0
RS
10126 /* On some systems, an X bug causes Emacs to get no more events
10127 when the window is destroyed. Detect that. (1994.) */
58769bee 10128 if (! event_found)
ef2a22d0 10129 {
ef2a22d0
RS
10130 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
10131 One XNOOP in 100 loops will make Emacs terminate.
10132 B. Bretthauer, 1994 */
10133 x_noop_count++;
58769bee 10134 if (x_noop_count >= 100)
ef2a22d0
RS
10135 {
10136 x_noop_count=0;
2224b905
RS
10137
10138 if (next_noop_dpyinfo == 0)
10139 next_noop_dpyinfo = x_display_list;
10140
10141 XNoOp (next_noop_dpyinfo->display);
10142
10143 /* Each time we get here, cycle through the displays now open. */
10144 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
10145 }
10146 }
502add23 10147
06a2c219 10148 /* If the focus was just given to an auto-raising frame,
0134a210 10149 raise it now. */
7a13e894 10150 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
10151 if (pending_autoraise_frame)
10152 {
10153 x_raise_frame (pending_autoraise_frame);
10154 pending_autoraise_frame = 0;
10155 }
0134a210 10156
dc6f92b8 10157 UNBLOCK_INPUT;
bde5503b 10158 --handling_signal;
dc6f92b8
JB
10159 return count;
10160}
06a2c219
GM
10161
10162
10163
dc6f92b8 10164\f
06a2c219
GM
10165/***********************************************************************
10166 Text Cursor
10167 ***********************************************************************/
10168
10169/* Note if the text cursor of window W has been overwritten by a
10170 drawing operation that outputs N glyphs starting at HPOS in the
10171 line given by output_cursor.vpos. N < 0 means all the rest of the
10172 line after HPOS has been written. */
10173
10174static void
10175note_overwritten_text_cursor (w, hpos, n)
10176 struct window *w;
10177 int hpos, n;
10178{
10179 if (updated_area == TEXT_AREA
10180 && output_cursor.vpos == w->phys_cursor.vpos
10181 && hpos <= w->phys_cursor.hpos
10182 && (n < 0
10183 || hpos + n > w->phys_cursor.hpos))
10184 w->phys_cursor_on_p = 0;
10185}
f451eb13
JB
10186
10187
06a2c219
GM
10188/* Set clipping for output in glyph row ROW. W is the window in which
10189 we operate. GC is the graphics context to set clipping in.
10190 WHOLE_LINE_P non-zero means include the areas used for truncation
10191 mark display and alike in the clipping rectangle.
10192
10193 ROW may be a text row or, e.g., a mode line. Text rows must be
10194 clipped to the interior of the window dedicated to text display,
10195 mode lines must be clipped to the whole window. */
dc6f92b8
JB
10196
10197static void
06a2c219
GM
10198x_clip_to_row (w, row, gc, whole_line_p)
10199 struct window *w;
10200 struct glyph_row *row;
10201 GC gc;
10202 int whole_line_p;
dc6f92b8 10203{
06a2c219
GM
10204 struct frame *f = XFRAME (WINDOW_FRAME (w));
10205 XRectangle clip_rect;
10206 int window_x, window_y, window_width, window_height;
dc6f92b8 10207
06a2c219 10208 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 10209
06a2c219
GM
10210 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
10211 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
10212 clip_rect.y = max (clip_rect.y, window_y);
10213 clip_rect.width = window_width;
10214 clip_rect.height = row->visible_height;
5c1aae96 10215
06a2c219
GM
10216 /* If clipping to the whole line, including trunc marks, extend
10217 the rectangle to the left and increase its width. */
10218 if (whole_line_p)
10219 {
110859fc
GM
10220 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
10221 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 10222 }
5c1aae96 10223
06a2c219 10224 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
10225}
10226
06a2c219
GM
10227
10228/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
10229
10230static void
06a2c219
GM
10231x_draw_hollow_cursor (w, row)
10232 struct window *w;
10233 struct glyph_row *row;
dc6f92b8 10234{
06a2c219
GM
10235 struct frame *f = XFRAME (WINDOW_FRAME (w));
10236 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10237 Display *dpy = FRAME_X_DISPLAY (f);
10238 int x, y, wd, h;
10239 XGCValues xgcv;
10240 struct glyph *cursor_glyph;
10241 GC gc;
10242
10243 /* Compute frame-relative coordinates from window-relative
10244 coordinates. */
10245 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10246 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
10247 + row->ascent - w->phys_cursor_ascent);
10248 h = row->height - 1;
10249
10250 /* Get the glyph the cursor is on. If we can't tell because
10251 the current matrix is invalid or such, give up. */
10252 cursor_glyph = get_phys_cursor_glyph (w);
10253 if (cursor_glyph == NULL)
dc6f92b8
JB
10254 return;
10255
06a2c219
GM
10256 /* Compute the width of the rectangle to draw. If on a stretch
10257 glyph, and `x-stretch-block-cursor' is nil, don't draw a
10258 rectangle as wide as the glyph, but use a canonical character
10259 width instead. */
10260 wd = cursor_glyph->pixel_width - 1;
10261 if (cursor_glyph->type == STRETCH_GLYPH
10262 && !x_stretch_cursor_p)
10263 wd = min (CANON_X_UNIT (f), wd);
10264
10265 /* The foreground of cursor_gc is typically the same as the normal
10266 background color, which can cause the cursor box to be invisible. */
10267 xgcv.foreground = f->output_data.x->cursor_pixel;
10268 if (dpyinfo->scratch_cursor_gc)
10269 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
10270 else
10271 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
10272 GCForeground, &xgcv);
10273 gc = dpyinfo->scratch_cursor_gc;
10274
10275 /* Set clipping, draw the rectangle, and reset clipping again. */
10276 x_clip_to_row (w, row, gc, 0);
10277 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
10278 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
10279}
10280
06a2c219
GM
10281
10282/* Draw a bar cursor on window W in glyph row ROW.
10283
10284 Implementation note: One would like to draw a bar cursor with an
10285 angle equal to the one given by the font property XA_ITALIC_ANGLE.
10286 Unfortunately, I didn't find a font yet that has this property set.
10287 --gerd. */
dc6f92b8
JB
10288
10289static void
f02d8aa0 10290x_draw_bar_cursor (w, row, width)
06a2c219
GM
10291 struct window *w;
10292 struct glyph_row *row;
f02d8aa0 10293 int width;
dc6f92b8 10294{
06a2c219
GM
10295 /* If cursor hpos is out of bounds, don't draw garbage. This can
10296 happen in mini-buffer windows when switching between echo area
10297 glyphs and mini-buffer. */
10298 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
10299 {
10300 struct frame *f = XFRAME (w->frame);
10301 struct glyph *cursor_glyph;
10302 GC gc;
10303 int x;
10304 unsigned long mask;
10305 XGCValues xgcv;
10306 Display *dpy;
10307 Window window;
10308
10309 cursor_glyph = get_phys_cursor_glyph (w);
10310 if (cursor_glyph == NULL)
10311 return;
10312
10313 xgcv.background = f->output_data.x->cursor_pixel;
10314 xgcv.foreground = f->output_data.x->cursor_pixel;
10315 xgcv.graphics_exposures = 0;
10316 mask = GCForeground | GCBackground | GCGraphicsExposures;
10317 dpy = FRAME_X_DISPLAY (f);
10318 window = FRAME_X_WINDOW (f);
10319 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
10320
10321 if (gc)
10322 XChangeGC (dpy, gc, mask, &xgcv);
10323 else
10324 {
10325 gc = XCreateGC (dpy, window, mask, &xgcv);
10326 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
10327 }
10328
f02d8aa0
GM
10329 if (width < 0)
10330 width = f->output_data.x->cursor_width;
10331
06a2c219
GM
10332 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10333 x_clip_to_row (w, row, gc, 0);
10334 XFillRectangle (dpy, window, gc,
10335 x,
10336 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 10337 min (cursor_glyph->pixel_width, width),
06a2c219
GM
10338 row->height);
10339 XSetClipMask (dpy, gc, None);
10340 }
dc6f92b8
JB
10341}
10342
06a2c219
GM
10343
10344/* Clear the cursor of window W to background color, and mark the
10345 cursor as not shown. This is used when the text where the cursor
10346 is is about to be rewritten. */
10347
dc6f92b8 10348static void
06a2c219
GM
10349x_clear_cursor (w)
10350 struct window *w;
dc6f92b8 10351{
06a2c219
GM
10352 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
10353 x_update_window_cursor (w, 0);
10354}
90e65f07 10355
dbc4e1c1 10356
06a2c219
GM
10357/* Draw the cursor glyph of window W in glyph row ROW. See the
10358 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 10359
06a2c219
GM
10360static void
10361x_draw_phys_cursor_glyph (w, row, hl)
10362 struct window *w;
10363 struct glyph_row *row;
10364 enum draw_glyphs_face hl;
10365{
10366 /* If cursor hpos is out of bounds, don't draw garbage. This can
10367 happen in mini-buffer windows when switching between echo area
10368 glyphs and mini-buffer. */
10369 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
10370 {
10371 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
10372 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
10373 hl, 0, 0, 0);
10374
10375 /* When we erase the cursor, and ROW is overlapped by other
10376 rows, make sure that these overlapping parts of other rows
10377 are redrawn. */
10378 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
10379 {
10380 if (row > w->current_matrix->rows
10381 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
10382 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
10383
10384 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
10385 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
10386 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
10387 }
10388 }
06a2c219 10389}
dbc4e1c1 10390
eea6af04 10391
06a2c219 10392/* Erase the image of a cursor of window W from the screen. */
eea6af04 10393
06a2c219
GM
10394static void
10395x_erase_phys_cursor (w)
10396 struct window *w;
10397{
10398 struct frame *f = XFRAME (w->frame);
10399 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10400 int hpos = w->phys_cursor.hpos;
10401 int vpos = w->phys_cursor.vpos;
10402 int mouse_face_here_p = 0;
10403 struct glyph_matrix *active_glyphs = w->current_matrix;
10404 struct glyph_row *cursor_row;
10405 struct glyph *cursor_glyph;
10406 enum draw_glyphs_face hl;
10407
10408 /* No cursor displayed or row invalidated => nothing to do on the
10409 screen. */
10410 if (w->phys_cursor_type == NO_CURSOR)
10411 goto mark_cursor_off;
10412
10413 /* VPOS >= active_glyphs->nrows means that window has been resized.
10414 Don't bother to erase the cursor. */
10415 if (vpos >= active_glyphs->nrows)
10416 goto mark_cursor_off;
10417
10418 /* If row containing cursor is marked invalid, there is nothing we
10419 can do. */
10420 cursor_row = MATRIX_ROW (active_glyphs, vpos);
10421 if (!cursor_row->enabled_p)
10422 goto mark_cursor_off;
10423
10424 /* This can happen when the new row is shorter than the old one.
10425 In this case, either x_draw_glyphs or clear_end_of_line
10426 should have cleared the cursor. Note that we wouldn't be
10427 able to erase the cursor in this case because we don't have a
10428 cursor glyph at hand. */
10429 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
10430 goto mark_cursor_off;
10431
10432 /* If the cursor is in the mouse face area, redisplay that when
10433 we clear the cursor. */
8801a864
KR
10434 if (! NILP (dpyinfo->mouse_face_window)
10435 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
10436 && (vpos > dpyinfo->mouse_face_beg_row
10437 || (vpos == dpyinfo->mouse_face_beg_row
10438 && hpos >= dpyinfo->mouse_face_beg_col))
10439 && (vpos < dpyinfo->mouse_face_end_row
10440 || (vpos == dpyinfo->mouse_face_end_row
10441 && hpos < dpyinfo->mouse_face_end_col))
10442 /* Don't redraw the cursor's spot in mouse face if it is at the
10443 end of a line (on a newline). The cursor appears there, but
10444 mouse highlighting does not. */
10445 && cursor_row->used[TEXT_AREA] > hpos)
10446 mouse_face_here_p = 1;
10447
10448 /* Maybe clear the display under the cursor. */
10449 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
10450 {
10451 int x;
045dee35 10452 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 10453
06a2c219
GM
10454 cursor_glyph = get_phys_cursor_glyph (w);
10455 if (cursor_glyph == NULL)
10456 goto mark_cursor_off;
dbc4e1c1 10457
06a2c219
GM
10458 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
10459
10460 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10461 x,
045dee35 10462 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219
GM
10463 cursor_row->y)),
10464 cursor_glyph->pixel_width,
10465 cursor_row->visible_height,
10466 False);
dbc4e1c1 10467 }
06a2c219
GM
10468
10469 /* Erase the cursor by redrawing the character underneath it. */
10470 if (mouse_face_here_p)
10471 hl = DRAW_MOUSE_FACE;
10472 else if (cursor_row->inverse_p)
10473 hl = DRAW_INVERSE_VIDEO;
10474 else
10475 hl = DRAW_NORMAL_TEXT;
10476 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 10477
06a2c219
GM
10478 mark_cursor_off:
10479 w->phys_cursor_on_p = 0;
10480 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
10481}
10482
10483
06a2c219
GM
10484/* Display or clear cursor of window W. If ON is zero, clear the
10485 cursor. If it is non-zero, display the cursor. If ON is nonzero,
10486 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 10487
06a2c219
GM
10488void
10489x_display_and_set_cursor (w, on, hpos, vpos, x, y)
10490 struct window *w;
10491 int on, hpos, vpos, x, y;
dbc4e1c1 10492{
06a2c219
GM
10493 struct frame *f = XFRAME (w->frame);
10494 int new_cursor_type;
f02d8aa0 10495 int new_cursor_width;
06a2c219
GM
10496 struct glyph_matrix *current_glyphs;
10497 struct glyph_row *glyph_row;
10498 struct glyph *glyph;
dbc4e1c1 10499
49d838ea 10500 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
10501 windows and frames; in the latter case, the frame or window may
10502 be in the midst of changing its size, and x and y may be off the
10503 window. */
10504 if (! FRAME_VISIBLE_P (f)
10505 || FRAME_GARBAGED_P (f)
10506 || vpos >= w->current_matrix->nrows
10507 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
10508 return;
10509
10510 /* If cursor is off and we want it off, return quickly. */
06a2c219 10511 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
10512 return;
10513
06a2c219
GM
10514 current_glyphs = w->current_matrix;
10515 glyph_row = MATRIX_ROW (current_glyphs, vpos);
10516 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
10517
10518 /* If cursor row is not enabled, we don't really know where to
10519 display the cursor. */
10520 if (!glyph_row->enabled_p)
10521 {
10522 w->phys_cursor_on_p = 0;
10523 return;
10524 }
10525
10526 xassert (interrupt_input_blocked);
10527
10528 /* Set new_cursor_type to the cursor we want to be displayed. In a
10529 mini-buffer window, we want the cursor only to appear if we are
10530 reading input from this window. For the selected window, we want
10531 the cursor type given by the frame parameter. If explicitly
10532 marked off, draw no cursor. In all other cases, we want a hollow
10533 box cursor. */
f02d8aa0 10534 new_cursor_width = -1;
9b4a7047
GM
10535 if (cursor_in_echo_area
10536 && FRAME_HAS_MINIBUF_P (f)
10537 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 10538 {
9b4a7047
GM
10539 if (w == XWINDOW (echo_area_window))
10540 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
10541 else
10542 new_cursor_type = HOLLOW_BOX_CURSOR;
10543 }
06a2c219 10544 else
9b4a7047
GM
10545 {
10546 if (w != XWINDOW (selected_window)
10547 || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
10548 {
e55a0b79
GM
10549 extern int cursor_in_non_selected_windows;
10550
10551 if (MINI_WINDOW_P (w) || !cursor_in_non_selected_windows)
9b4a7047
GM
10552 new_cursor_type = NO_CURSOR;
10553 else
10554 new_cursor_type = HOLLOW_BOX_CURSOR;
10555 }
10556 else if (w->cursor_off_p)
10557 new_cursor_type = NO_CURSOR;
10558 else
f02d8aa0
GM
10559 {
10560 struct buffer *b = XBUFFER (w->buffer);
10561
10562 if (EQ (b->cursor_type, Qt))
10563 new_cursor_type = FRAME_DESIRED_CURSOR (f);
10564 else
10565 new_cursor_type = x_specified_cursor_type (b->cursor_type,
10566 &new_cursor_width);
10567 }
9b4a7047 10568 }
06a2c219
GM
10569
10570 /* If cursor is currently being shown and we don't want it to be or
10571 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 10572 erase it. */
06a2c219 10573 if (w->phys_cursor_on_p
dc6f92b8 10574 && (!on
06a2c219
GM
10575 || w->phys_cursor.x != x
10576 || w->phys_cursor.y != y
10577 || new_cursor_type != w->phys_cursor_type))
10578 x_erase_phys_cursor (w);
10579
10580 /* If the cursor is now invisible and we want it to be visible,
10581 display it. */
10582 if (on && !w->phys_cursor_on_p)
10583 {
10584 w->phys_cursor_ascent = glyph_row->ascent;
10585 w->phys_cursor_height = glyph_row->height;
10586
10587 /* Set phys_cursor_.* before x_draw_.* is called because some
10588 of them may need the information. */
10589 w->phys_cursor.x = x;
10590 w->phys_cursor.y = glyph_row->y;
10591 w->phys_cursor.hpos = hpos;
10592 w->phys_cursor.vpos = vpos;
10593 w->phys_cursor_type = new_cursor_type;
10594 w->phys_cursor_on_p = 1;
10595
10596 switch (new_cursor_type)
dc6f92b8 10597 {
06a2c219
GM
10598 case HOLLOW_BOX_CURSOR:
10599 x_draw_hollow_cursor (w, glyph_row);
10600 break;
10601
10602 case FILLED_BOX_CURSOR:
10603 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
10604 break;
10605
10606 case BAR_CURSOR:
f02d8aa0 10607 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
10608 break;
10609
10610 case NO_CURSOR:
10611 break;
dc6f92b8 10612
06a2c219
GM
10613 default:
10614 abort ();
10615 }
59ddecde
GM
10616
10617#ifdef HAVE_X_I18N
10618 if (w == XWINDOW (f->selected_window))
10619 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
10620 xic_set_preeditarea (w, x, y);
10621#endif
dc6f92b8
JB
10622 }
10623
06a2c219 10624#ifndef XFlush
f676886a 10625 if (updating_frame != f)
334208b7 10626 XFlush (FRAME_X_DISPLAY (f));
06a2c219 10627#endif
dc6f92b8
JB
10628}
10629
06a2c219
GM
10630
10631/* Display the cursor on window W, or clear it. X and Y are window
10632 relative pixel coordinates. HPOS and VPOS are glyph matrix
10633 positions. If W is not the selected window, display a hollow
10634 cursor. ON non-zero means display the cursor at X, Y which
10635 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 10636
dfcf069d 10637void
06a2c219
GM
10638x_display_cursor (w, on, hpos, vpos, x, y)
10639 struct window *w;
10640 int on, hpos, vpos, x, y;
dc6f92b8 10641{
f94397b5 10642 BLOCK_INPUT;
06a2c219 10643 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
10644 UNBLOCK_INPUT;
10645}
10646
06a2c219
GM
10647
10648/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
10649 Don't change the cursor's position. */
10650
dfcf069d 10651void
06a2c219 10652x_update_cursor (f, on_p)
5d46f928 10653 struct frame *f;
5d46f928 10654{
06a2c219
GM
10655 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
10656}
10657
10658
10659/* Call x_update_window_cursor with parameter ON_P on all leaf windows
10660 in the window tree rooted at W. */
10661
10662static void
10663x_update_cursor_in_window_tree (w, on_p)
10664 struct window *w;
10665 int on_p;
10666{
10667 while (w)
10668 {
10669 if (!NILP (w->hchild))
10670 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
10671 else if (!NILP (w->vchild))
10672 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
10673 else
10674 x_update_window_cursor (w, on_p);
10675
10676 w = NILP (w->next) ? 0 : XWINDOW (w->next);
10677 }
10678}
5d46f928 10679
f94397b5 10680
06a2c219
GM
10681/* Switch the display of W's cursor on or off, according to the value
10682 of ON. */
10683
10684static void
10685x_update_window_cursor (w, on)
10686 struct window *w;
10687 int on;
10688{
16b5d424
GM
10689 /* Don't update cursor in windows whose frame is in the process
10690 of being deleted. */
10691 if (w->current_matrix)
10692 {
10693 BLOCK_INPUT;
10694 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
10695 w->phys_cursor.x, w->phys_cursor.y);
10696 UNBLOCK_INPUT;
10697 }
dc6f92b8 10698}
06a2c219
GM
10699
10700
10701
dc6f92b8
JB
10702\f
10703/* Icons. */
10704
f676886a 10705/* Refresh bitmap kitchen sink icon for frame F
06a2c219 10706 when we get an expose event for it. */
dc6f92b8 10707
dfcf069d 10708void
f676886a
JB
10709refreshicon (f)
10710 struct frame *f;
dc6f92b8 10711{
06a2c219 10712 /* Normally, the window manager handles this function. */
dc6f92b8
JB
10713}
10714
dbc4e1c1 10715/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
10716
10717int
990ba854 10718x_bitmap_icon (f, file)
f676886a 10719 struct frame *f;
990ba854 10720 Lisp_Object file;
dc6f92b8 10721{
06a2c219 10722 int bitmap_id;
dc6f92b8 10723
c118dd06 10724 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10725 return 1;
10726
990ba854 10727 /* Free up our existing icon bitmap if any. */
7556890b
RS
10728 if (f->output_data.x->icon_bitmap > 0)
10729 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10730 f->output_data.x->icon_bitmap = 0;
990ba854
RS
10731
10732 if (STRINGP (file))
7f2ae036
RS
10733 bitmap_id = x_create_bitmap_from_file (f, file);
10734 else
10735 {
990ba854 10736 /* Create the GNU bitmap if necessary. */
5bf01b68 10737 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
10738 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
10739 = x_create_bitmap_from_data (f, gnu_bits,
10740 gnu_width, gnu_height);
990ba854
RS
10741
10742 /* The first time we create the GNU bitmap,
06a2c219 10743 this increments the ref-count one extra time.
990ba854
RS
10744 As a result, the GNU bitmap is never freed.
10745 That way, we don't have to worry about allocating it again. */
334208b7 10746 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 10747
334208b7 10748 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
10749 }
10750
10751 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 10752 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
10753
10754 return 0;
10755}
10756
10757
1be2d067
KH
10758/* Make the x-window of frame F use a rectangle with text.
10759 Use ICON_NAME as the text. */
dc6f92b8
JB
10760
10761int
f676886a
JB
10762x_text_icon (f, icon_name)
10763 struct frame *f;
dc6f92b8
JB
10764 char *icon_name;
10765{
c118dd06 10766 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10767 return 1;
10768
1be2d067
KH
10769#ifdef HAVE_X11R4
10770 {
10771 XTextProperty text;
10772 text.value = (unsigned char *) icon_name;
10773 text.encoding = XA_STRING;
10774 text.format = 8;
10775 text.nitems = strlen (icon_name);
10776#ifdef USE_X_TOOLKIT
7556890b 10777 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
10778 &text);
10779#else /* not USE_X_TOOLKIT */
10780 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
10781#endif /* not USE_X_TOOLKIT */
10782 }
10783#else /* not HAVE_X11R4 */
10784 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
10785#endif /* not HAVE_X11R4 */
58769bee 10786
7556890b
RS
10787 if (f->output_data.x->icon_bitmap > 0)
10788 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10789 f->output_data.x->icon_bitmap = 0;
b1c884c3 10790 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
10791
10792 return 0;
10793}
10794\f
e99db5a1
RS
10795#define X_ERROR_MESSAGE_SIZE 200
10796
10797/* If non-nil, this should be a string.
10798 It means catch X errors and store the error message in this string. */
10799
10800static Lisp_Object x_error_message_string;
10801
10802/* An X error handler which stores the error message in
10803 x_error_message_string. This is called from x_error_handler if
10804 x_catch_errors is in effect. */
10805
06a2c219 10806static void
e99db5a1
RS
10807x_error_catcher (display, error)
10808 Display *display;
10809 XErrorEvent *error;
10810{
10811 XGetErrorText (display, error->error_code,
10812 XSTRING (x_error_message_string)->data,
10813 X_ERROR_MESSAGE_SIZE);
10814}
10815
10816/* Begin trapping X errors for display DPY. Actually we trap X errors
10817 for all displays, but DPY should be the display you are actually
10818 operating on.
10819
10820 After calling this function, X protocol errors no longer cause
10821 Emacs to exit; instead, they are recorded in the string
10822 stored in x_error_message_string.
10823
10824 Calling x_check_errors signals an Emacs error if an X error has
10825 occurred since the last call to x_catch_errors or x_check_errors.
10826
10827 Calling x_uncatch_errors resumes the normal error handling. */
10828
10829void x_check_errors ();
10830static Lisp_Object x_catch_errors_unwind ();
10831
10832int
10833x_catch_errors (dpy)
10834 Display *dpy;
10835{
10836 int count = specpdl_ptr - specpdl;
10837
10838 /* Make sure any errors from previous requests have been dealt with. */
10839 XSync (dpy, False);
10840
10841 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
10842
10843 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
10844 XSTRING (x_error_message_string)->data[0] = 0;
10845
10846 return count;
10847}
10848
10849/* Unbind the binding that we made to check for X errors. */
10850
10851static Lisp_Object
10852x_catch_errors_unwind (old_val)
10853 Lisp_Object old_val;
10854{
10855 x_error_message_string = old_val;
10856 return Qnil;
10857}
10858
10859/* If any X protocol errors have arrived since the last call to
10860 x_catch_errors or x_check_errors, signal an Emacs error using
10861 sprintf (a buffer, FORMAT, the x error message text) as the text. */
10862
10863void
10864x_check_errors (dpy, format)
10865 Display *dpy;
10866 char *format;
10867{
10868 /* Make sure to catch any errors incurred so far. */
10869 XSync (dpy, False);
10870
10871 if (XSTRING (x_error_message_string)->data[0])
10872 error (format, XSTRING (x_error_message_string)->data);
10873}
10874
9829ddba
RS
10875/* Nonzero if we had any X protocol errors
10876 since we did x_catch_errors on DPY. */
e99db5a1
RS
10877
10878int
10879x_had_errors_p (dpy)
10880 Display *dpy;
10881{
10882 /* Make sure to catch any errors incurred so far. */
10883 XSync (dpy, False);
10884
10885 return XSTRING (x_error_message_string)->data[0] != 0;
10886}
10887
9829ddba
RS
10888/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
10889
06a2c219 10890void
9829ddba
RS
10891x_clear_errors (dpy)
10892 Display *dpy;
10893{
10894 XSTRING (x_error_message_string)->data[0] = 0;
10895}
10896
e99db5a1
RS
10897/* Stop catching X protocol errors and let them make Emacs die.
10898 DPY should be the display that was passed to x_catch_errors.
10899 COUNT should be the value that was returned by
10900 the corresponding call to x_catch_errors. */
10901
10902void
10903x_uncatch_errors (dpy, count)
10904 Display *dpy;
10905 int count;
10906{
10907 unbind_to (count, Qnil);
10908}
10909
10910#if 0
10911static unsigned int x_wire_count;
10912x_trace_wire ()
10913{
10914 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
10915}
10916#endif /* ! 0 */
10917
10918\f
10919/* Handle SIGPIPE, which can happen when the connection to a server
10920 simply goes away. SIGPIPE is handled by x_connection_signal.
10921 Don't need to do anything, because the write which caused the
10922 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 10923 which will do the appropriate cleanup for us. */
e99db5a1
RS
10924
10925static SIGTYPE
10926x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 10927 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
10928{
10929#ifdef USG
10930 /* USG systems forget handlers when they are used;
10931 must reestablish each time */
10932 signal (signalnum, x_connection_signal);
10933#endif /* USG */
10934}
10935\f
4746118a
JB
10936/* Handling X errors. */
10937
7a13e894 10938/* Handle the loss of connection to display DISPLAY. */
16bd92ea 10939
4746118a 10940static SIGTYPE
7a13e894
RS
10941x_connection_closed (display, error_message)
10942 Display *display;
10943 char *error_message;
4746118a 10944{
7a13e894
RS
10945 struct x_display_info *dpyinfo = x_display_info_for_display (display);
10946 Lisp_Object frame, tail;
10947
6186a4a0
RS
10948 /* Indicate that this display is dead. */
10949
2e465cdd 10950#if 0 /* Closing the display caused a bus error on OpenWindows. */
f613a4c8 10951#ifdef USE_X_TOOLKIT
adabc3a9 10952 XtCloseDisplay (display);
2e465cdd 10953#endif
f613a4c8 10954#endif
adabc3a9 10955
9e80b57d
KR
10956 if (dpyinfo)
10957 dpyinfo->display = 0;
6186a4a0 10958
06a2c219 10959 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
10960 that are on the dead display. */
10961 FOR_EACH_FRAME (tail, frame)
10962 {
10963 Lisp_Object minibuf_frame;
10964 minibuf_frame
10965 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
10966 if (FRAME_X_P (XFRAME (frame))
10967 && FRAME_X_P (XFRAME (minibuf_frame))
10968 && ! EQ (frame, minibuf_frame)
10969 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
10970 Fdelete_frame (frame, Qt);
10971 }
10972
10973 /* Now delete all remaining frames on the dead display.
06a2c219 10974 We are now sure none of these is used as the mini-buffer
7a13e894
RS
10975 for another frame that we need to delete. */
10976 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
10977 if (FRAME_X_P (XFRAME (frame))
10978 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
10979 {
10980 /* Set this to t so that Fdelete_frame won't get confused
10981 trying to find a replacement. */
10982 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
10983 Fdelete_frame (frame, Qt);
10984 }
7a13e894 10985
482a1bd2
KH
10986 if (dpyinfo)
10987 x_delete_display (dpyinfo);
7a13e894
RS
10988
10989 if (x_display_list == 0)
10990 {
f8d07b62 10991 fprintf (stderr, "%s\n", error_message);
7a13e894
RS
10992 shut_down_emacs (0, 0, Qnil);
10993 exit (70);
10994 }
12ba150f 10995
7a13e894
RS
10996 /* Ordinary stack unwind doesn't deal with these. */
10997#ifdef SIGIO
10998 sigunblock (sigmask (SIGIO));
10999#endif
11000 sigunblock (sigmask (SIGALRM));
11001 TOTALLY_UNBLOCK_INPUT;
11002
aa4d9a9e 11003 clear_waiting_for_input ();
7a13e894 11004 error ("%s", error_message);
4746118a
JB
11005}
11006
7a13e894
RS
11007/* This is the usual handler for X protocol errors.
11008 It kills all frames on the display that we got the error for.
11009 If that was the only one, it prints an error message and kills Emacs. */
11010
06a2c219 11011static void
c118dd06
JB
11012x_error_quitter (display, error)
11013 Display *display;
11014 XErrorEvent *error;
11015{
7a13e894 11016 char buf[256], buf1[356];
dc6f92b8 11017
58769bee 11018 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 11019 original error handler. */
dc6f92b8 11020
c118dd06 11021 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 11022 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 11023 buf, error->request_code);
7a13e894 11024 x_connection_closed (display, buf1);
dc6f92b8
JB
11025}
11026
e99db5a1
RS
11027/* This is the first-level handler for X protocol errors.
11028 It calls x_error_quitter or x_error_catcher. */
7a13e894 11029
8922af5f 11030static int
e99db5a1 11031x_error_handler (display, error)
8922af5f 11032 Display *display;
e99db5a1 11033 XErrorEvent *error;
8922af5f 11034{
e99db5a1
RS
11035 if (! NILP (x_error_message_string))
11036 x_error_catcher (display, error);
11037 else
11038 x_error_quitter (display, error);
06a2c219 11039 return 0;
f9e24cb9 11040}
c118dd06 11041
e99db5a1
RS
11042/* This is the handler for X IO errors, always.
11043 It kills all frames on the display that we lost touch with.
11044 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 11045
c118dd06 11046static int
e99db5a1 11047x_io_error_quitter (display)
c118dd06 11048 Display *display;
c118dd06 11049{
e99db5a1 11050 char buf[256];
dc6f92b8 11051
e99db5a1
RS
11052 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
11053 x_connection_closed (display, buf);
06a2c219 11054 return 0;
dc6f92b8 11055}
dc6f92b8 11056\f
f451eb13
JB
11057/* Changing the font of the frame. */
11058
76bcdf39
RS
11059/* Give frame F the font named FONTNAME as its default font, and
11060 return the full name of that font. FONTNAME may be a wildcard
11061 pattern; in that case, we choose some font that fits the pattern.
11062 The return value shows which font we chose. */
11063
b5cf7a0e 11064Lisp_Object
f676886a
JB
11065x_new_font (f, fontname)
11066 struct frame *f;
dc6f92b8
JB
11067 register char *fontname;
11068{
dc43ef94 11069 struct font_info *fontp
ee569018 11070 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 11071
dc43ef94
KH
11072 if (!fontp)
11073 return Qnil;
2224a5fc 11074
dc43ef94 11075 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 11076 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
11077 f->output_data.x->fontset = -1;
11078
b2cad826
KH
11079 /* Compute the scroll bar width in character columns. */
11080 if (f->scroll_bar_pixel_width > 0)
11081 {
7556890b 11082 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
11083 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
11084 }
11085 else
4e61bddf
RS
11086 {
11087 int wid = FONT_WIDTH (f->output_data.x->font);
11088 f->scroll_bar_cols = (14 + wid - 1) / wid;
11089 }
b2cad826 11090
f676886a 11091 /* Now make the frame display the given font. */
c118dd06 11092 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 11093 {
7556890b
RS
11094 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
11095 f->output_data.x->font->fid);
11096 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
11097 f->output_data.x->font->fid);
11098 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
11099 f->output_data.x->font->fid);
f676886a 11100
a27f9f86 11101 frame_update_line_height (f);
0134a210 11102 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 11103 }
a27f9f86
RS
11104 else
11105 /* If we are setting a new frame's font for the first time,
11106 there are no faces yet, so this font's height is the line height. */
7556890b 11107 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 11108
dc43ef94
KH
11109 return build_string (fontp->full_name);
11110}
11111
11112/* Give frame F the fontset named FONTSETNAME as its default font, and
11113 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
11114 pattern; in that case, we choose some fontset that fits the pattern.
11115 The return value shows which fontset we chose. */
b5cf7a0e 11116
dc43ef94
KH
11117Lisp_Object
11118x_new_fontset (f, fontsetname)
11119 struct frame *f;
11120 char *fontsetname;
11121{
ee569018 11122 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 11123 Lisp_Object result;
b5cf7a0e 11124
dc43ef94
KH
11125 if (fontset < 0)
11126 return Qnil;
b5cf7a0e 11127
2da424f1
KH
11128 if (f->output_data.x->fontset == fontset)
11129 /* This fontset is already set in frame F. There's nothing more
11130 to do. */
ee569018 11131 return fontset_name (fontset);
dc43ef94 11132
ee569018 11133 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
11134
11135 if (!STRINGP (result))
11136 /* Can't load ASCII font. */
11137 return Qnil;
11138
11139 /* Since x_new_font doesn't update any fontset information, do it now. */
11140 f->output_data.x->fontset = fontset;
dc43ef94 11141
f5d11644
GM
11142#ifdef HAVE_X_I18N
11143 if (FRAME_XIC (f)
11144 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 11145 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
11146#endif
11147
dc43ef94 11148 return build_string (fontsetname);
dc6f92b8 11149}
f5d11644
GM
11150
11151\f
11152/***********************************************************************
11153 X Input Methods
11154 ***********************************************************************/
11155
11156#ifdef HAVE_X_I18N
11157
11158#ifdef HAVE_X11R6
11159
11160/* XIM destroy callback function, which is called whenever the
11161 connection to input method XIM dies. CLIENT_DATA contains a
11162 pointer to the x_display_info structure corresponding to XIM. */
11163
11164static void
11165xim_destroy_callback (xim, client_data, call_data)
11166 XIM xim;
11167 XPointer client_data;
11168 XPointer call_data;
11169{
11170 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
11171 Lisp_Object frame, tail;
11172
11173 BLOCK_INPUT;
11174
11175 /* No need to call XDestroyIC.. */
11176 FOR_EACH_FRAME (tail, frame)
11177 {
11178 struct frame *f = XFRAME (frame);
11179 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
11180 {
11181 FRAME_XIC (f) = NULL;
11182 if (FRAME_XIC_FONTSET (f))
11183 {
11184 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
11185 FRAME_XIC_FONTSET (f) = NULL;
11186 }
11187 }
11188 }
11189
11190 /* No need to call XCloseIM. */
11191 dpyinfo->xim = NULL;
11192 XFree (dpyinfo->xim_styles);
11193 UNBLOCK_INPUT;
11194}
11195
11196#endif /* HAVE_X11R6 */
11197
11198/* Open the connection to the XIM server on display DPYINFO.
11199 RESOURCE_NAME is the resource name Emacs uses. */
11200
11201static void
11202xim_open_dpy (dpyinfo, resource_name)
11203 struct x_display_info *dpyinfo;
11204 char *resource_name;
11205{
287f7dd6 11206#ifdef USE_XIM
f5d11644
GM
11207 XIM xim;
11208
11209 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
11210 dpyinfo->xim = xim;
11211
11212 if (xim)
11213 {
f5d11644
GM
11214#ifdef HAVE_X11R6
11215 XIMCallback destroy;
11216#endif
11217
11218 /* Get supported styles and XIM values. */
11219 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
11220
11221#ifdef HAVE_X11R6
11222 destroy.callback = xim_destroy_callback;
11223 destroy.client_data = (XPointer)dpyinfo;
68642df6 11224 /* This isn't prptotyped in OSF 5.0. */
f5d11644
GM
11225 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
11226#endif
11227 }
287f7dd6
GM
11228
11229#else /* not USE_XIM */
11230 dpyinfo->xim = NULL;
11231#endif /* not USE_XIM */
f5d11644
GM
11232}
11233
11234
b9de836c 11235#ifdef HAVE_X11R6_XIM
f5d11644
GM
11236
11237struct xim_inst_t
11238{
11239 struct x_display_info *dpyinfo;
11240 char *resource_name;
11241};
11242
11243/* XIM instantiate callback function, which is called whenever an XIM
11244 server is available. DISPLAY is teh display of the XIM.
11245 CLIENT_DATA contains a pointer to an xim_inst_t structure created
11246 when the callback was registered. */
11247
11248static void
11249xim_instantiate_callback (display, client_data, call_data)
11250 Display *display;
11251 XPointer client_data;
11252 XPointer call_data;
11253{
11254 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
11255 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
11256
11257 /* We don't support multiple XIM connections. */
11258 if (dpyinfo->xim)
11259 return;
11260
11261 xim_open_dpy (dpyinfo, xim_inst->resource_name);
11262
11263 /* Create XIC for the existing frames on the same display, as long
11264 as they have no XIC. */
11265 if (dpyinfo->xim && dpyinfo->reference_count > 0)
11266 {
11267 Lisp_Object tail, frame;
11268
11269 BLOCK_INPUT;
11270 FOR_EACH_FRAME (tail, frame)
11271 {
11272 struct frame *f = XFRAME (frame);
11273
11274 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
11275 if (FRAME_XIC (f) == NULL)
11276 {
11277 create_frame_xic (f);
11278 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
11279 xic_set_statusarea (f);
11280 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
11281 {
11282 struct window *w = XWINDOW (f->selected_window);
11283 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
11284 }
11285 }
11286 }
11287
11288 UNBLOCK_INPUT;
11289 }
11290}
11291
b9de836c 11292#endif /* HAVE_X11R6_XIM */
f5d11644
GM
11293
11294
11295/* Open a connection to the XIM server on display DPYINFO.
11296 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
11297 connection only at the first time. On X11R6, open the connection
11298 in the XIM instantiate callback function. */
11299
11300static void
11301xim_initialize (dpyinfo, resource_name)
11302 struct x_display_info *dpyinfo;
11303 char *resource_name;
11304{
287f7dd6 11305#ifdef USE_XIM
b9de836c 11306#ifdef HAVE_X11R6_XIM
f5d11644
GM
11307 struct xim_inst_t *xim_inst;
11308 int len;
11309
11310 dpyinfo->xim = NULL;
11311 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
11312 xim_inst->dpyinfo = dpyinfo;
11313 len = strlen (resource_name);
11314 xim_inst->resource_name = (char *) xmalloc (len + 1);
11315 bcopy (resource_name, xim_inst->resource_name, len + 1);
11316 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11317 resource_name, EMACS_CLASS,
11318 xim_instantiate_callback,
2ebb2f8b
DL
11319 /* Fixme: This is XPointer in
11320 XFree86 but (XPointer *) on
11321 Tru64, at least. */
11322 (XPointer) xim_inst);
b9de836c 11323#else /* not HAVE_X11R6_XIM */
f5d11644
GM
11324 dpyinfo->xim = NULL;
11325 xim_open_dpy (dpyinfo, resource_name);
b9de836c 11326#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
11327
11328#else /* not USE_XIM */
11329 dpyinfo->xim = NULL;
11330#endif /* not USE_XIM */
f5d11644
GM
11331}
11332
11333
11334/* Close the connection to the XIM server on display DPYINFO. */
11335
11336static void
11337xim_close_dpy (dpyinfo)
11338 struct x_display_info *dpyinfo;
11339{
287f7dd6 11340#ifdef USE_XIM
b9de836c 11341#ifdef HAVE_X11R6_XIM
f5d11644
GM
11342 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11343 NULL, EMACS_CLASS,
11344 xim_instantiate_callback, NULL);
b9de836c 11345#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11346 XCloseIM (dpyinfo->xim);
11347 dpyinfo->xim = NULL;
11348 XFree (dpyinfo->xim_styles);
287f7dd6 11349#endif /* USE_XIM */
f5d11644
GM
11350}
11351
b9de836c 11352#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11353
11354
dc6f92b8 11355\f
2e365682
RS
11356/* Calculate the absolute position in frame F
11357 from its current recorded position values and gravity. */
11358
dfcf069d 11359void
43bca5d5 11360x_calc_absolute_position (f)
f676886a 11361 struct frame *f;
dc6f92b8 11362{
06a2c219 11363 Window child;
6dba1858 11364 int win_x = 0, win_y = 0;
7556890b 11365 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
11366 int this_window;
11367
9829ddba
RS
11368 /* We have nothing to do if the current position
11369 is already for the top-left corner. */
11370 if (! ((flags & XNegative) || (flags & YNegative)))
11371 return;
11372
c81412a0 11373#ifdef USE_X_TOOLKIT
7556890b 11374 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
11375#else
11376 this_window = FRAME_X_WINDOW (f);
11377#endif
6dba1858
RS
11378
11379 /* Find the position of the outside upper-left corner of
9829ddba
RS
11380 the inner window, with respect to the outer window.
11381 But do this only if we will need the results. */
7556890b 11382 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 11383 {
9829ddba
RS
11384 int count;
11385
6dba1858 11386 BLOCK_INPUT;
9829ddba
RS
11387 count = x_catch_errors (FRAME_X_DISPLAY (f));
11388 while (1)
11389 {
11390 x_clear_errors (FRAME_X_DISPLAY (f));
11391 XTranslateCoordinates (FRAME_X_DISPLAY (f),
11392
11393 /* From-window, to-window. */
11394 this_window,
11395 f->output_data.x->parent_desc,
11396
11397 /* From-position, to-position. */
11398 0, 0, &win_x, &win_y,
11399
11400 /* Child of win. */
11401 &child);
11402 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
11403 {
11404 Window newroot, newparent = 0xdeadbeef;
11405 Window *newchildren;
2ebb2f8b 11406 unsigned int nchildren;
9829ddba
RS
11407
11408 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
11409 &newparent, &newchildren, &nchildren))
11410 break;
58769bee 11411
7c3c78a3 11412 XFree ((char *) newchildren);
6dba1858 11413
9829ddba
RS
11414 f->output_data.x->parent_desc = newparent;
11415 }
11416 else
11417 break;
11418 }
6dba1858 11419
9829ddba 11420 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
11421 UNBLOCK_INPUT;
11422 }
11423
11424 /* Treat negative positions as relative to the leftmost bottommost
11425 position that fits on the screen. */
20f55f9a 11426 if (flags & XNegative)
7556890b 11427 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
11428 - 2 * f->output_data.x->border_width - win_x
11429 - PIXEL_WIDTH (f)
11430 + f->output_data.x->left_pos);
dc6f92b8 11431
20f55f9a 11432 if (flags & YNegative)
06a2c219
GM
11433 {
11434 int menubar_height = 0;
11435
11436#ifdef USE_X_TOOLKIT
11437 if (f->output_data.x->menubar_widget)
11438 menubar_height
11439 = (f->output_data.x->menubar_widget->core.height
11440 + f->output_data.x->menubar_widget->core.border_width);
11441#endif
11442
11443 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
11444 - 2 * f->output_data.x->border_width
11445 - win_y
11446 - PIXEL_HEIGHT (f)
11447 - menubar_height
11448 + f->output_data.x->top_pos);
11449 }
2e365682 11450
3a35ab44
RS
11451 /* The left_pos and top_pos
11452 are now relative to the top and left screen edges,
11453 so the flags should correspond. */
7556890b 11454 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
11455}
11456
3a35ab44
RS
11457/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
11458 to really change the position, and 0 when calling from
11459 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
11460 position values). It is -1 when calling from x_set_frame_parameters,
11461 which means, do adjust for borders but don't change the gravity. */
3a35ab44 11462
dfcf069d 11463void
dc05a16b 11464x_set_offset (f, xoff, yoff, change_gravity)
f676886a 11465 struct frame *f;
dc6f92b8 11466 register int xoff, yoff;
dc05a16b 11467 int change_gravity;
dc6f92b8 11468{
4a4cbdd5
KH
11469 int modified_top, modified_left;
11470
aa3ff7c9 11471 if (change_gravity > 0)
3a35ab44 11472 {
7556890b
RS
11473 f->output_data.x->top_pos = yoff;
11474 f->output_data.x->left_pos = xoff;
11475 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 11476 if (xoff < 0)
7556890b 11477 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 11478 if (yoff < 0)
7556890b
RS
11479 f->output_data.x->size_hint_flags |= YNegative;
11480 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 11481 }
43bca5d5 11482 x_calc_absolute_position (f);
dc6f92b8
JB
11483
11484 BLOCK_INPUT;
c32cdd9a 11485 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 11486
7556890b
RS
11487 modified_left = f->output_data.x->left_pos;
11488 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
11489#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
11490 this seems to be unnecessary and incorrect. rms, 4/17/97. */
11491 /* It is a mystery why we need to add the border_width here
11492 when the frame is already visible, but experiment says we do. */
aa3ff7c9 11493 if (change_gravity != 0)
4a4cbdd5 11494 {
7556890b
RS
11495 modified_left += f->output_data.x->border_width;
11496 modified_top += f->output_data.x->border_width;
4a4cbdd5 11497 }
e73ec6fa 11498#endif
4a4cbdd5 11499
3afe33e7 11500#ifdef USE_X_TOOLKIT
7556890b 11501 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 11502 modified_left, modified_top);
3afe33e7 11503#else /* not USE_X_TOOLKIT */
334208b7 11504 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 11505 modified_left, modified_top);
3afe33e7 11506#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11507 UNBLOCK_INPUT;
11508}
11509
bc20ebbf
FP
11510/* Call this to change the size of frame F's x-window.
11511 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
11512 for this size change and subsequent size changes.
11513 Otherwise we leave the window gravity unchanged. */
dc6f92b8 11514
dfcf069d 11515void
bc20ebbf 11516x_set_window_size (f, change_gravity, cols, rows)
f676886a 11517 struct frame *f;
bc20ebbf 11518 int change_gravity;
b1c884c3 11519 int cols, rows;
dc6f92b8 11520{
06a2c219 11521#ifndef USE_X_TOOLKIT
dc6f92b8 11522 int pixelwidth, pixelheight;
06a2c219 11523#endif
dc6f92b8 11524
80fd1fe2 11525 BLOCK_INPUT;
aee9a898
RS
11526
11527#ifdef USE_X_TOOLKIT
3a20653d
RS
11528 {
11529 /* The x and y position of the widget is clobbered by the
11530 call to XtSetValues within EmacsFrameSetCharSize.
11531 This is a real kludge, but I don't understand Xt so I can't
11532 figure out a correct fix. Can anyone else tell me? -- rms. */
7556890b
RS
11533 int xpos = f->output_data.x->widget->core.x;
11534 int ypos = f->output_data.x->widget->core.y;
11535 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
11536 f->output_data.x->widget->core.x = xpos;
11537 f->output_data.x->widget->core.y = ypos;
3a20653d 11538 }
80fd1fe2
FP
11539
11540#else /* not USE_X_TOOLKIT */
11541
b1c884c3 11542 check_frame_size (f, &rows, &cols);
7556890b 11543 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
11544 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
11545 ? 0
11546 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 11547 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 11548 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 11549 f->output_data.x->flags_areas_extra
110859fc 11550 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
11551 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
11552 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 11553
7556890b 11554 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 11555 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 11556
334208b7
RS
11557 XSync (FRAME_X_DISPLAY (f), False);
11558 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11559 pixelwidth, pixelheight);
b1c884c3
JB
11560
11561 /* Now, strictly speaking, we can't be sure that this is accurate,
11562 but the window manager will get around to dealing with the size
11563 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
11564 ConfigureNotify event gets here.
11565
11566 We could just not bother storing any of this information here,
11567 and let the ConfigureNotify event set everything up, but that
fddd5ceb 11568 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 11569 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
11570 point in the future when the ConfigureNotify event arrives.
11571
11572 We pass 1 for DELAY since we can't run Lisp code inside of
11573 a BLOCK_INPUT. */
7d1e984f 11574 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
11575 PIXEL_WIDTH (f) = pixelwidth;
11576 PIXEL_HEIGHT (f) = pixelheight;
11577
aee9a898
RS
11578 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
11579 receive in the ConfigureNotify event; if we get what we asked
11580 for, then the event won't cause the screen to become garbaged, so
11581 we have to make sure to do it here. */
11582 SET_FRAME_GARBAGED (f);
11583
11584 XFlush (FRAME_X_DISPLAY (f));
11585
11586#endif /* not USE_X_TOOLKIT */
11587
4d73d038 11588 /* If cursor was outside the new size, mark it as off. */
06a2c219 11589 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 11590
aee9a898
RS
11591 /* Clear out any recollection of where the mouse highlighting was,
11592 since it might be in a place that's outside the new frame size.
11593 Actually checking whether it is outside is a pain in the neck,
11594 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 11595 cancel_mouse_face (f);
dbc4e1c1 11596
dc6f92b8
JB
11597 UNBLOCK_INPUT;
11598}
dc6f92b8 11599\f
d047c4eb 11600/* Mouse warping. */
dc6f92b8 11601
9b378208 11602void
f676886a
JB
11603x_set_mouse_position (f, x, y)
11604 struct frame *f;
dc6f92b8
JB
11605 int x, y;
11606{
11607 int pix_x, pix_y;
11608
7556890b
RS
11609 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
11610 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
11611
11612 if (pix_x < 0) pix_x = 0;
11613 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
11614
11615 if (pix_y < 0) pix_y = 0;
11616 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
11617
11618 BLOCK_INPUT;
dc6f92b8 11619
334208b7
RS
11620 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11621 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
11622 UNBLOCK_INPUT;
11623}
11624
9b378208
RS
11625/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
11626
11627void
11628x_set_mouse_pixel_position (f, pix_x, pix_y)
11629 struct frame *f;
11630 int pix_x, pix_y;
11631{
11632 BLOCK_INPUT;
11633
334208b7
RS
11634 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11635 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
11636 UNBLOCK_INPUT;
11637}
d047c4eb
KH
11638\f
11639/* focus shifting, raising and lowering. */
9b378208 11640
dfcf069d 11641void
f676886a
JB
11642x_focus_on_frame (f)
11643 struct frame *f;
dc6f92b8 11644{
1fb20991 11645#if 0 /* This proves to be unpleasant. */
f676886a 11646 x_raise_frame (f);
1fb20991 11647#endif
6d4238f3
JB
11648#if 0
11649 /* I don't think that the ICCCM allows programs to do things like this
11650 without the interaction of the window manager. Whatever you end up
f676886a 11651 doing with this code, do it to x_unfocus_frame too. */
334208b7 11652 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 11653 RevertToPointerRoot, CurrentTime);
c118dd06 11654#endif /* ! 0 */
dc6f92b8
JB
11655}
11656
dfcf069d 11657void
f676886a
JB
11658x_unfocus_frame (f)
11659 struct frame *f;
dc6f92b8 11660{
6d4238f3 11661#if 0
f676886a 11662 /* Look at the remarks in x_focus_on_frame. */
0f941935 11663 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 11664 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 11665 RevertToPointerRoot, CurrentTime);
c118dd06 11666#endif /* ! 0 */
dc6f92b8
JB
11667}
11668
f676886a 11669/* Raise frame F. */
dc6f92b8 11670
dfcf069d 11671void
f676886a
JB
11672x_raise_frame (f)
11673 struct frame *f;
dc6f92b8 11674{
3a88c238 11675 if (f->async_visible)
dc6f92b8
JB
11676 {
11677 BLOCK_INPUT;
3afe33e7 11678#ifdef USE_X_TOOLKIT
7556890b 11679 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11680#else /* not USE_X_TOOLKIT */
334208b7 11681 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11682#endif /* not USE_X_TOOLKIT */
334208b7 11683 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11684 UNBLOCK_INPUT;
11685 }
11686}
11687
f676886a 11688/* Lower frame F. */
dc6f92b8 11689
dfcf069d 11690void
f676886a
JB
11691x_lower_frame (f)
11692 struct frame *f;
dc6f92b8 11693{
3a88c238 11694 if (f->async_visible)
dc6f92b8
JB
11695 {
11696 BLOCK_INPUT;
3afe33e7 11697#ifdef USE_X_TOOLKIT
7556890b 11698 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11699#else /* not USE_X_TOOLKIT */
334208b7 11700 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11701#endif /* not USE_X_TOOLKIT */
334208b7 11702 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11703 UNBLOCK_INPUT;
11704 }
11705}
11706
dbc4e1c1 11707static void
6b0442dc 11708XTframe_raise_lower (f, raise_flag)
dbc4e1c1 11709 FRAME_PTR f;
6b0442dc 11710 int raise_flag;
dbc4e1c1 11711{
6b0442dc 11712 if (raise_flag)
dbc4e1c1
JB
11713 x_raise_frame (f);
11714 else
11715 x_lower_frame (f);
11716}
d047c4eb
KH
11717\f
11718/* Change of visibility. */
dc6f92b8 11719
9382638d
KH
11720/* This tries to wait until the frame is really visible.
11721 However, if the window manager asks the user where to position
11722 the frame, this will return before the user finishes doing that.
11723 The frame will not actually be visible at that time,
11724 but it will become visible later when the window manager
11725 finishes with it. */
11726
dfcf069d 11727void
f676886a
JB
11728x_make_frame_visible (f)
11729 struct frame *f;
dc6f92b8 11730{
990ba854 11731 Lisp_Object type;
1aa6072f 11732 int original_top, original_left;
dc6f92b8 11733
dc6f92b8 11734 BLOCK_INPUT;
dc6f92b8 11735
990ba854
RS
11736 type = x_icon_type (f);
11737 if (!NILP (type))
11738 x_bitmap_icon (f, type);
bdcd49ba 11739
f676886a 11740 if (! FRAME_VISIBLE_P (f))
90e65f07 11741 {
1aa6072f
RS
11742 /* We test FRAME_GARBAGED_P here to make sure we don't
11743 call x_set_offset a second time
11744 if we get to x_make_frame_visible a second time
11745 before the window gets really visible. */
11746 if (! FRAME_ICONIFIED_P (f)
11747 && ! f->output_data.x->asked_for_visible)
11748 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
11749
11750 f->output_data.x->asked_for_visible = 1;
11751
90e65f07 11752 if (! EQ (Vx_no_window_manager, Qt))
f676886a 11753 x_wm_set_window_state (f, NormalState);
3afe33e7 11754#ifdef USE_X_TOOLKIT
d7a38a2e 11755 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11756 XtMapWidget (f->output_data.x->widget);
3afe33e7 11757#else /* not USE_X_TOOLKIT */
7f9c7f94 11758 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11759#endif /* not USE_X_TOOLKIT */
0134a210
RS
11760#if 0 /* This seems to bring back scroll bars in the wrong places
11761 if the window configuration has changed. They seem
11762 to come back ok without this. */
ab648270 11763 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 11764 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 11765#endif
90e65f07 11766 }
dc6f92b8 11767
334208b7 11768 XFlush (FRAME_X_DISPLAY (f));
90e65f07 11769
0dacf791
RS
11770 /* Synchronize to ensure Emacs knows the frame is visible
11771 before we do anything else. We do this loop with input not blocked
11772 so that incoming events are handled. */
11773 {
11774 Lisp_Object frame;
12ce2351 11775 int count;
28c01ffe
RS
11776 /* This must be before UNBLOCK_INPUT
11777 since events that arrive in response to the actions above
11778 will set it when they are handled. */
11779 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
11780
11781 original_left = f->output_data.x->left_pos;
11782 original_top = f->output_data.x->top_pos;
c0a04927
RS
11783
11784 /* This must come after we set COUNT. */
11785 UNBLOCK_INPUT;
11786
2745e6c4 11787 /* We unblock here so that arriving X events are processed. */
1aa6072f 11788
dcb07ae9
RS
11789 /* Now move the window back to where it was "supposed to be".
11790 But don't do it if the gravity is negative.
11791 When the gravity is negative, this uses a position
28c01ffe
RS
11792 that is 3 pixels too low. Perhaps that's really the border width.
11793
11794 Don't do this if the window has never been visible before,
11795 because the window manager may choose the position
11796 and we don't want to override it. */
1aa6072f 11797
4d3f5d9a 11798 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 11799 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 11800 && previously_visible)
1aa6072f 11801 {
2745e6c4
RS
11802 Drawable rootw;
11803 int x, y;
11804 unsigned int width, height, border, depth;
06a2c219 11805
1aa6072f 11806 BLOCK_INPUT;
9829ddba 11807
06a2c219
GM
11808 /* On some window managers (such as FVWM) moving an existing
11809 window, even to the same place, causes the window manager
11810 to introduce an offset. This can cause the window to move
11811 to an unexpected location. Check the geometry (a little
11812 slow here) and then verify that the window is in the right
11813 place. If the window is not in the right place, move it
11814 there, and take the potential window manager hit. */
2745e6c4
RS
11815 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11816 &rootw, &x, &y, &width, &height, &border, &depth);
11817
11818 if (original_left != x || original_top != y)
11819 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11820 original_left, original_top);
11821
1aa6072f
RS
11822 UNBLOCK_INPUT;
11823 }
9829ddba 11824
e0c1aef2 11825 XSETFRAME (frame, f);
c0a04927 11826
12ce2351
GM
11827 /* Wait until the frame is visible. Process X events until a
11828 MapNotify event has been seen, or until we think we won't get a
11829 MapNotify at all.. */
11830 for (count = input_signal_count + 10;
11831 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 11832 {
12ce2351 11833 /* Force processing of queued events. */
334208b7 11834 x_sync (f);
12ce2351
GM
11835
11836 /* Machines that do polling rather than SIGIO have been
11837 observed to go into a busy-wait here. So we'll fake an
11838 alarm signal to let the handler know that there's something
11839 to be read. We used to raise a real alarm, but it seems
11840 that the handler isn't always enabled here. This is
11841 probably a bug. */
8b2f8d4e 11842 if (input_polling_used ())
3b2fa4e6 11843 {
12ce2351
GM
11844 /* It could be confusing if a real alarm arrives while
11845 processing the fake one. Turn it off and let the
11846 handler reset it. */
3e71d8f2 11847 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
11848 int old_poll_suppress_count = poll_suppress_count;
11849 poll_suppress_count = 1;
11850 poll_for_input_1 ();
11851 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 11852 }
12ce2351
GM
11853
11854 /* See if a MapNotify event has been processed. */
11855 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 11856 }
0dacf791 11857 }
dc6f92b8
JB
11858}
11859
06a2c219 11860/* Change from mapped state to withdrawn state. */
dc6f92b8 11861
d047c4eb
KH
11862/* Make the frame visible (mapped and not iconified). */
11863
dfcf069d 11864void
f676886a
JB
11865x_make_frame_invisible (f)
11866 struct frame *f;
dc6f92b8 11867{
546e6d5b
RS
11868 Window window;
11869
11870#ifdef USE_X_TOOLKIT
11871 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 11872 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
11873#else /* not USE_X_TOOLKIT */
11874 window = FRAME_X_WINDOW (f);
11875#endif /* not USE_X_TOOLKIT */
dc6f92b8 11876
9319ae23 11877 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11878 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11879 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11880
5627c40e 11881#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 11882 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 11883 return;
5627c40e 11884#endif
dc6f92b8
JB
11885
11886 BLOCK_INPUT;
c118dd06 11887
af31d76f
RS
11888 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
11889 that the current position of the window is user-specified, rather than
11890 program-specified, so that when the window is mapped again, it will be
11891 placed at the same location, without forcing the user to position it
11892 by hand again (they have already done that once for this window.) */
c32cdd9a 11893 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 11894
c118dd06
JB
11895#ifdef HAVE_X11R4
11896
334208b7
RS
11897 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
11898 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
11899 {
11900 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11901 error ("Can't notify window manager of window withdrawal");
c118dd06 11902 }
c118dd06 11903#else /* ! defined (HAVE_X11R4) */
16bd92ea 11904
c118dd06 11905 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
11906 if (! EQ (Vx_no_window_manager, Qt))
11907 {
16bd92ea 11908 XEvent unmap;
dc6f92b8 11909
16bd92ea 11910 unmap.xunmap.type = UnmapNotify;
546e6d5b 11911 unmap.xunmap.window = window;
334208b7 11912 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 11913 unmap.xunmap.from_configure = False;
334208b7
RS
11914 if (! XSendEvent (FRAME_X_DISPLAY (f),
11915 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 11916 False,
06a2c219 11917 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
11918 &unmap))
11919 {
11920 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11921 error ("Can't notify window manager of withdrawal");
16bd92ea 11922 }
dc6f92b8
JB
11923 }
11924
16bd92ea 11925 /* Unmap the window ourselves. Cheeky! */
334208b7 11926 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 11927#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 11928
5627c40e
RS
11929 /* We can't distinguish this from iconification
11930 just by the event that we get from the server.
11931 So we can't win using the usual strategy of letting
11932 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
11933 and synchronize with the server to make sure we agree. */
11934 f->visible = 0;
11935 FRAME_ICONIFIED_P (f) = 0;
11936 f->async_visible = 0;
11937 f->async_iconified = 0;
11938
334208b7 11939 x_sync (f);
5627c40e 11940
dc6f92b8
JB
11941 UNBLOCK_INPUT;
11942}
11943
06a2c219 11944/* Change window state from mapped to iconified. */
dc6f92b8 11945
dfcf069d 11946void
f676886a
JB
11947x_iconify_frame (f)
11948 struct frame *f;
dc6f92b8 11949{
3afe33e7 11950 int result;
990ba854 11951 Lisp_Object type;
dc6f92b8 11952
9319ae23 11953 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11954 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11955 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11956
3a88c238 11957 if (f->async_iconified)
dc6f92b8
JB
11958 return;
11959
3afe33e7 11960 BLOCK_INPUT;
546e6d5b 11961
9af3143a
RS
11962 FRAME_SAMPLE_VISIBILITY (f);
11963
990ba854
RS
11964 type = x_icon_type (f);
11965 if (!NILP (type))
11966 x_bitmap_icon (f, type);
bdcd49ba
RS
11967
11968#ifdef USE_X_TOOLKIT
11969
546e6d5b
RS
11970 if (! FRAME_VISIBLE_P (f))
11971 {
11972 if (! EQ (Vx_no_window_manager, Qt))
11973 x_wm_set_window_state (f, IconicState);
11974 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11975 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
11976 /* The server won't give us any event to indicate
11977 that an invisible frame was changed to an icon,
11978 so we have to record it here. */
11979 f->iconified = 1;
1e6bc770 11980 f->visible = 1;
9cf30a30 11981 f->async_iconified = 1;
1e6bc770 11982 f->async_visible = 0;
546e6d5b
RS
11983 UNBLOCK_INPUT;
11984 return;
11985 }
11986
334208b7 11987 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 11988 XtWindow (f->output_data.x->widget),
334208b7 11989 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
11990 UNBLOCK_INPUT;
11991
11992 if (!result)
546e6d5b 11993 error ("Can't notify window manager of iconification");
3afe33e7
RS
11994
11995 f->async_iconified = 1;
1e6bc770
RS
11996 f->async_visible = 0;
11997
8c002a25
KH
11998
11999 BLOCK_INPUT;
334208b7 12000 XFlush (FRAME_X_DISPLAY (f));
8c002a25 12001 UNBLOCK_INPUT;
3afe33e7
RS
12002#else /* not USE_X_TOOLKIT */
12003
fd13dbb2
RS
12004 /* Make sure the X server knows where the window should be positioned,
12005 in case the user deiconifies with the window manager. */
12006 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 12007 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 12008
16bd92ea
JB
12009 /* Since we don't know which revision of X we're running, we'll use both
12010 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
12011
12012 /* X11R4: send a ClientMessage to the window manager using the
12013 WM_CHANGE_STATE type. */
12014 {
12015 XEvent message;
58769bee 12016
c118dd06 12017 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 12018 message.xclient.type = ClientMessage;
334208b7 12019 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
12020 message.xclient.format = 32;
12021 message.xclient.data.l[0] = IconicState;
12022
334208b7
RS
12023 if (! XSendEvent (FRAME_X_DISPLAY (f),
12024 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
12025 False,
12026 SubstructureRedirectMask | SubstructureNotifyMask,
12027 &message))
dc6f92b8
JB
12028 {
12029 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12030 error ("Can't notify window manager of iconification");
dc6f92b8 12031 }
16bd92ea 12032 }
dc6f92b8 12033
58769bee 12034 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
12035 IconicState. */
12036 x_wm_set_window_state (f, IconicState);
dc6f92b8 12037
a9c00105
RS
12038 if (!FRAME_VISIBLE_P (f))
12039 {
12040 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 12041 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
12042 }
12043
3a88c238 12044 f->async_iconified = 1;
1e6bc770 12045 f->async_visible = 0;
dc6f92b8 12046
334208b7 12047 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 12048 UNBLOCK_INPUT;
8c002a25 12049#endif /* not USE_X_TOOLKIT */
dc6f92b8 12050}
d047c4eb 12051\f
c0ff3fab 12052/* Destroy the X window of frame F. */
dc6f92b8 12053
dfcf069d 12054void
c0ff3fab 12055x_destroy_window (f)
f676886a 12056 struct frame *f;
dc6f92b8 12057{
7f9c7f94
RS
12058 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12059
dc6f92b8 12060 BLOCK_INPUT;
c0ff3fab 12061
6186a4a0
RS
12062 /* If a display connection is dead, don't try sending more
12063 commands to the X server. */
12064 if (dpyinfo->display != 0)
12065 {
12066 if (f->output_data.x->icon_desc != 0)
12067 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
31f41daf 12068#ifdef HAVE_X_I18N
f5d11644
GM
12069 if (FRAME_XIC (f))
12070 free_frame_xic (f);
31f41daf 12071#endif
6186a4a0 12072 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->window_desc);
3afe33e7 12073#ifdef USE_X_TOOLKIT
06a2c219
GM
12074 if (f->output_data.x->widget)
12075 XtDestroyWidget (f->output_data.x->widget);
6186a4a0 12076 free_frame_menubar (f);
3afe33e7
RS
12077#endif /* USE_X_TOOLKIT */
12078
3e71d8f2
GM
12079 unload_color (f, f->output_data.x->foreground_pixel);
12080 unload_color (f, f->output_data.x->background_pixel);
12081 unload_color (f, f->output_data.x->cursor_pixel);
12082 unload_color (f, f->output_data.x->cursor_foreground_pixel);
12083 unload_color (f, f->output_data.x->border_pixel);
12084 unload_color (f, f->output_data.x->mouse_pixel);
12085 if (f->output_data.x->scroll_bar_background_pixel != -1)
12086 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
12087 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
12088 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
12089 if (f->output_data.x->white_relief.allocated_p)
12090 unload_color (f, f->output_data.x->white_relief.pixel);
12091 if (f->output_data.x->black_relief.allocated_p)
12092 unload_color (f, f->output_data.x->black_relief.pixel);
12093
6186a4a0
RS
12094 free_frame_faces (f);
12095 XFlush (FRAME_X_DISPLAY (f));
12096 }
dc6f92b8 12097
df89d8a4 12098 if (f->output_data.x->saved_menu_event)
06a2c219 12099 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 12100
7556890b
RS
12101 xfree (f->output_data.x);
12102 f->output_data.x = 0;
0f941935
KH
12103 if (f == dpyinfo->x_focus_frame)
12104 dpyinfo->x_focus_frame = 0;
12105 if (f == dpyinfo->x_focus_event_frame)
12106 dpyinfo->x_focus_event_frame = 0;
12107 if (f == dpyinfo->x_highlight_frame)
12108 dpyinfo->x_highlight_frame = 0;
c0ff3fab 12109
7f9c7f94
RS
12110 dpyinfo->reference_count--;
12111
12112 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 12113 {
7f9c7f94
RS
12114 dpyinfo->mouse_face_beg_row
12115 = dpyinfo->mouse_face_beg_col = -1;
12116 dpyinfo->mouse_face_end_row
12117 = dpyinfo->mouse_face_end_col = -1;
12118 dpyinfo->mouse_face_window = Qnil;
21323706
RS
12119 dpyinfo->mouse_face_deferred_gc = 0;
12120 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 12121 }
0134a210 12122
c0ff3fab 12123 UNBLOCK_INPUT;
dc6f92b8
JB
12124}
12125\f
f451eb13
JB
12126/* Setting window manager hints. */
12127
af31d76f
RS
12128/* Set the normal size hints for the window manager, for frame F.
12129 FLAGS is the flags word to use--or 0 meaning preserve the flags
12130 that the window now has.
12131 If USER_POSITION is nonzero, we set the USPosition
12132 flag (this is useful when FLAGS is 0). */
6dba1858 12133
dfcf069d 12134void
af31d76f 12135x_wm_set_size_hint (f, flags, user_position)
f676886a 12136 struct frame *f;
af31d76f
RS
12137 long flags;
12138 int user_position;
dc6f92b8
JB
12139{
12140 XSizeHints size_hints;
3afe33e7
RS
12141
12142#ifdef USE_X_TOOLKIT
7e4f2521
FP
12143 Arg al[2];
12144 int ac = 0;
12145 Dimension widget_width, widget_height;
7556890b 12146 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 12147#else /* not USE_X_TOOLKIT */
c118dd06 12148 Window window = FRAME_X_WINDOW (f);
3afe33e7 12149#endif /* not USE_X_TOOLKIT */
dc6f92b8 12150
b72a58fd
RS
12151 /* Setting PMaxSize caused various problems. */
12152 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 12153
7556890b
RS
12154 size_hints.x = f->output_data.x->left_pos;
12155 size_hints.y = f->output_data.x->top_pos;
7553a6b7 12156
7e4f2521
FP
12157#ifdef USE_X_TOOLKIT
12158 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
12159 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 12160 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
12161 size_hints.height = widget_height;
12162 size_hints.width = widget_width;
12163#else /* not USE_X_TOOLKIT */
f676886a
JB
12164 size_hints.height = PIXEL_HEIGHT (f);
12165 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 12166#endif /* not USE_X_TOOLKIT */
7553a6b7 12167
7556890b
RS
12168 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
12169 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
12170 size_hints.max_width
12171 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
12172 size_hints.max_height
12173 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 12174
d067ea8b
KH
12175 /* Calculate the base and minimum sizes.
12176
12177 (When we use the X toolkit, we don't do it here.
12178 Instead we copy the values that the widgets are using, below.) */
12179#ifndef USE_X_TOOLKIT
b1c884c3 12180 {
b0342f17 12181 int base_width, base_height;
0134a210 12182 int min_rows = 0, min_cols = 0;
b0342f17 12183
f451eb13
JB
12184 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
12185 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 12186
0134a210 12187 check_frame_size (f, &min_rows, &min_cols);
b0342f17 12188
0134a210
RS
12189 /* The window manager uses the base width hints to calculate the
12190 current number of rows and columns in the frame while
12191 resizing; min_width and min_height aren't useful for this
12192 purpose, since they might not give the dimensions for a
12193 zero-row, zero-column frame.
58769bee 12194
0134a210
RS
12195 We use the base_width and base_height members if we have
12196 them; otherwise, we set the min_width and min_height members
12197 to the size for a zero x zero frame. */
b0342f17
JB
12198
12199#ifdef HAVE_X11R4
0134a210
RS
12200 size_hints.flags |= PBaseSize;
12201 size_hints.base_width = base_width;
12202 size_hints.base_height = base_height;
12203 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
12204 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 12205#else
0134a210
RS
12206 size_hints.min_width = base_width;
12207 size_hints.min_height = base_height;
b0342f17 12208#endif
b1c884c3 12209 }
dc6f92b8 12210
d067ea8b 12211 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 12212 if (flags)
dc6f92b8 12213 {
d067ea8b
KH
12214 size_hints.flags |= flags;
12215 goto no_read;
12216 }
12217#endif /* not USE_X_TOOLKIT */
12218
12219 {
12220 XSizeHints hints; /* Sometimes I hate X Windows... */
12221 long supplied_return;
12222 int value;
af31d76f
RS
12223
12224#ifdef HAVE_X11R4
d067ea8b
KH
12225 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
12226 &supplied_return);
af31d76f 12227#else
d067ea8b 12228 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 12229#endif
58769bee 12230
d067ea8b
KH
12231#ifdef USE_X_TOOLKIT
12232 size_hints.base_height = hints.base_height;
12233 size_hints.base_width = hints.base_width;
12234 size_hints.min_height = hints.min_height;
12235 size_hints.min_width = hints.min_width;
12236#endif
12237
12238 if (flags)
12239 size_hints.flags |= flags;
12240 else
12241 {
12242 if (value == 0)
12243 hints.flags = 0;
12244 if (hints.flags & PSize)
12245 size_hints.flags |= PSize;
12246 if (hints.flags & PPosition)
12247 size_hints.flags |= PPosition;
12248 if (hints.flags & USPosition)
12249 size_hints.flags |= USPosition;
12250 if (hints.flags & USSize)
12251 size_hints.flags |= USSize;
12252 }
12253 }
12254
06a2c219 12255#ifndef USE_X_TOOLKIT
d067ea8b 12256 no_read:
06a2c219 12257#endif
0134a210 12258
af31d76f 12259#ifdef PWinGravity
7556890b 12260 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 12261 size_hints.flags |= PWinGravity;
dc05a16b 12262
af31d76f 12263 if (user_position)
6dba1858 12264 {
af31d76f
RS
12265 size_hints.flags &= ~ PPosition;
12266 size_hints.flags |= USPosition;
6dba1858 12267 }
2554751d 12268#endif /* PWinGravity */
6dba1858 12269
b0342f17 12270#ifdef HAVE_X11R4
334208b7 12271 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12272#else
334208b7 12273 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12274#endif
dc6f92b8
JB
12275}
12276
12277/* Used for IconicState or NormalState */
06a2c219 12278
dfcf069d 12279void
f676886a
JB
12280x_wm_set_window_state (f, state)
12281 struct frame *f;
dc6f92b8
JB
12282 int state;
12283{
3afe33e7 12284#ifdef USE_X_TOOLKIT
546e6d5b
RS
12285 Arg al[1];
12286
12287 XtSetArg (al[0], XtNinitialState, state);
7556890b 12288 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 12289#else /* not USE_X_TOOLKIT */
c118dd06 12290 Window window = FRAME_X_WINDOW (f);
dc6f92b8 12291
7556890b
RS
12292 f->output_data.x->wm_hints.flags |= StateHint;
12293 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 12294
7556890b 12295 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 12296#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12297}
12298
dfcf069d 12299void
7f2ae036 12300x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 12301 struct frame *f;
7f2ae036 12302 int pixmap_id;
dc6f92b8 12303{
d2bd6bc4
RS
12304 Pixmap icon_pixmap;
12305
06a2c219 12306#ifndef USE_X_TOOLKIT
c118dd06 12307 Window window = FRAME_X_WINDOW (f);
75231bad 12308#endif
dc6f92b8 12309
7f2ae036 12310 if (pixmap_id > 0)
dbc4e1c1 12311 {
d2bd6bc4 12312 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 12313 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
12314 }
12315 else
68568555
RS
12316 {
12317 /* It seems there is no way to turn off use of an icon pixmap.
12318 The following line does it, only if no icon has yet been created,
12319 for some window managers. But with mwm it crashes.
12320 Some people say it should clear the IconPixmapHint bit in this case,
12321 but that doesn't work, and the X consortium said it isn't the
12322 right thing at all. Since there is no way to win,
12323 best to explicitly give up. */
12324#if 0
12325 f->output_data.x->wm_hints.icon_pixmap = None;
12326#else
12327 return;
12328#endif
12329 }
b1c884c3 12330
d2bd6bc4
RS
12331#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
12332
12333 {
12334 Arg al[1];
12335 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
12336 XtSetValues (f->output_data.x->widget, al, 1);
12337 }
12338
12339#else /* not USE_X_TOOLKIT */
12340
7556890b
RS
12341 f->output_data.x->wm_hints.flags |= IconPixmapHint;
12342 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
12343
12344#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12345}
12346
dfcf069d 12347void
f676886a
JB
12348x_wm_set_icon_position (f, icon_x, icon_y)
12349 struct frame *f;
dc6f92b8
JB
12350 int icon_x, icon_y;
12351{
75231bad 12352#ifdef USE_X_TOOLKIT
7556890b 12353 Window window = XtWindow (f->output_data.x->widget);
75231bad 12354#else
c118dd06 12355 Window window = FRAME_X_WINDOW (f);
75231bad 12356#endif
dc6f92b8 12357
7556890b
RS
12358 f->output_data.x->wm_hints.flags |= IconPositionHint;
12359 f->output_data.x->wm_hints.icon_x = icon_x;
12360 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 12361
7556890b 12362 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
12363}
12364
12365\f
06a2c219
GM
12366/***********************************************************************
12367 Fonts
12368 ***********************************************************************/
dc43ef94
KH
12369
12370/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 12371
dc43ef94
KH
12372struct font_info *
12373x_get_font_info (f, font_idx)
12374 FRAME_PTR f;
12375 int font_idx;
12376{
12377 return (FRAME_X_FONT_TABLE (f) + font_idx);
12378}
12379
12380
12381/* Return a list of names of available fonts matching PATTERN on frame
12382 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
12383 to be listed. Frame F NULL means we have not yet created any
12384 frame on X, and consult the first display in x_display_list.
12385 MAXNAMES sets a limit on how many fonts to match. */
12386
12387Lisp_Object
12388x_list_fonts (f, pattern, size, maxnames)
12389 FRAME_PTR f;
12390 Lisp_Object pattern;
12391 int size;
12392 int maxnames;
12393{
06a2c219
GM
12394 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
12395 Lisp_Object tem, second_best;
dc43ef94 12396 Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
09c6077f 12397 int try_XLoadQueryFont = 0;
53ca4657 12398 int count;
dc43ef94 12399
6b0efe73 12400 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
12401 if (NILP (patterns))
12402 patterns = Fcons (pattern, Qnil);
81ba44e5 12403
09c6077f
KH
12404 if (maxnames == 1 && !size)
12405 /* We can return any single font matching PATTERN. */
12406 try_XLoadQueryFont = 1;
9a32686f 12407
8e713be6 12408 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 12409 {
dc43ef94 12410 int num_fonts;
3e71d8f2 12411 char **names = NULL;
dc43ef94 12412
8e713be6 12413 pattern = XCAR (patterns);
536f4067
RS
12414 /* See if we cached the result for this particular query.
12415 The cache is an alist of the form:
12416 (((PATTERN . MAXNAMES) (FONTNAME . WIDTH) ...) ...)
12417 */
8e713be6 12418 if (f && (tem = XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element),
b5210ea7
KH
12419 key = Fcons (pattern, make_number (maxnames)),
12420 !NILP (list = Fassoc (key, tem))))
12421 {
12422 list = Fcdr_safe (list);
12423 /* We have a cashed list. Don't have to get the list again. */
12424 goto label_cached;
12425 }
12426
12427 /* At first, put PATTERN in the cache. */
09c6077f 12428
dc43ef94 12429 BLOCK_INPUT;
17d85edc
KH
12430 count = x_catch_errors (dpy);
12431
09c6077f
KH
12432 if (try_XLoadQueryFont)
12433 {
12434 XFontStruct *font;
12435 unsigned long value;
12436
12437 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
12438 if (x_had_errors_p (dpy))
12439 {
12440 /* This error is perhaps due to insufficient memory on X
12441 server. Let's just ignore it. */
12442 font = NULL;
12443 x_clear_errors (dpy);
12444 }
12445
09c6077f
KH
12446 if (font
12447 && XGetFontProperty (font, XA_FONT, &value))
12448 {
12449 char *name = (char *) XGetAtomName (dpy, (Atom) value);
12450 int len = strlen (name);
01c752b5 12451 char *tmp;
09c6077f 12452
6f6512e8
KH
12453 /* If DXPC (a Differential X Protocol Compressor)
12454 Ver.3.7 is running, XGetAtomName will return null
12455 string. We must avoid such a name. */
12456 if (len == 0)
12457 try_XLoadQueryFont = 0;
12458 else
12459 {
12460 num_fonts = 1;
12461 names = (char **) alloca (sizeof (char *));
12462 /* Some systems only allow alloca assigned to a
12463 simple var. */
12464 tmp = (char *) alloca (len + 1); names[0] = tmp;
12465 bcopy (name, names[0], len + 1);
12466 XFree (name);
12467 }
09c6077f
KH
12468 }
12469 else
12470 try_XLoadQueryFont = 0;
a083fd23
RS
12471
12472 if (font)
12473 XFreeFont (dpy, font);
09c6077f
KH
12474 }
12475
12476 if (!try_XLoadQueryFont)
17d85edc
KH
12477 {
12478 /* We try at least 10 fonts because XListFonts will return
12479 auto-scaled fonts at the head. */
12480 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
12481 &num_fonts);
12482 if (x_had_errors_p (dpy))
12483 {
12484 /* This error is perhaps due to insufficient memory on X
12485 server. Let's just ignore it. */
12486 names = NULL;
12487 x_clear_errors (dpy);
12488 }
12489 }
12490
12491 x_uncatch_errors (dpy, count);
dc43ef94
KH
12492 UNBLOCK_INPUT;
12493
12494 if (names)
12495 {
12496 int i;
dc43ef94
KH
12497
12498 /* Make a list of all the fonts we got back.
12499 Store that in the font cache for the display. */
12500 for (i = 0; i < num_fonts; i++)
12501 {
06a2c219 12502 int width = 0;
dc43ef94 12503 char *p = names[i];
06a2c219
GM
12504 int average_width = -1, dashes = 0;
12505
dc43ef94 12506 /* Count the number of dashes in NAMES[I]. If there are
b5210ea7
KH
12507 14 dashes, and the field value following 12th dash
12508 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
12509 is usually too ugly to be used for editing. Let's
12510 ignore it. */
dc43ef94
KH
12511 while (*p)
12512 if (*p++ == '-')
12513 {
12514 dashes++;
12515 if (dashes == 7) /* PIXEL_SIZE field */
12516 width = atoi (p);
12517 else if (dashes == 12) /* AVERAGE_WIDTH field */
12518 average_width = atoi (p);
12519 }
12520 if (dashes < 14 || average_width != 0)
12521 {
12522 tem = build_string (names[i]);
12523 if (NILP (Fassoc (tem, list)))
12524 {
12525 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
12526 && ((fast_c_string_match_ignore_case
12527 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
12528 >= 0))
12529 /* We can set the value of PIXEL_SIZE to the
b5210ea7 12530 width of this font. */
dc43ef94
KH
12531 list = Fcons (Fcons (tem, make_number (width)), list);
12532 else
12533 /* For the moment, width is not known. */
12534 list = Fcons (Fcons (tem, Qnil), list);
12535 }
12536 }
12537 }
09c6077f
KH
12538 if (!try_XLoadQueryFont)
12539 XFreeFontNames (names);
dc43ef94
KH
12540 }
12541
b5210ea7 12542 /* Now store the result in the cache. */
dc43ef94 12543 if (f != NULL)
8e713be6 12544 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element)
dc43ef94 12545 = Fcons (Fcons (key, list),
8e713be6 12546 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
dc43ef94 12547
b5210ea7
KH
12548 label_cached:
12549 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 12550
b5210ea7
KH
12551 newlist = second_best = Qnil;
12552 /* Make a list of the fonts that have the right width. */
8e713be6 12553 for (; CONSP (list); list = XCDR (list))
b5210ea7 12554 {
536f4067
RS
12555 int found_size;
12556
8e713be6 12557 tem = XCAR (list);
dc43ef94 12558
8e713be6 12559 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
12560 continue;
12561 if (!size)
12562 {
8e713be6 12563 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
12564 continue;
12565 }
dc43ef94 12566
8e713be6 12567 if (!INTEGERP (XCDR (tem)))
dc43ef94 12568 {
b5210ea7
KH
12569 /* Since we have not yet known the size of this font, we
12570 must try slow function call XLoadQueryFont. */
dc43ef94
KH
12571 XFontStruct *thisinfo;
12572
12573 BLOCK_INPUT;
17d85edc 12574 count = x_catch_errors (dpy);
dc43ef94 12575 thisinfo = XLoadQueryFont (dpy,
8e713be6 12576 XSTRING (XCAR (tem))->data);
17d85edc
KH
12577 if (x_had_errors_p (dpy))
12578 {
12579 /* This error is perhaps due to insufficient memory on X
12580 server. Let's just ignore it. */
12581 thisinfo = NULL;
12582 x_clear_errors (dpy);
12583 }
12584 x_uncatch_errors (dpy, count);
dc43ef94
KH
12585 UNBLOCK_INPUT;
12586
12587 if (thisinfo)
12588 {
8e713be6 12589 XCDR (tem)
536f4067
RS
12590 = (thisinfo->min_bounds.width == 0
12591 ? make_number (0)
12592 : make_number (thisinfo->max_bounds.width));
dc43ef94
KH
12593 XFreeFont (dpy, thisinfo);
12594 }
12595 else
b5210ea7 12596 /* For unknown reason, the previous call of XListFont had
06a2c219 12597 returned a font which can't be opened. Record the size
b5210ea7 12598 as 0 not to try to open it again. */
8e713be6 12599 XCDR (tem) = make_number (0);
dc43ef94 12600 }
536f4067 12601
8e713be6 12602 found_size = XINT (XCDR (tem));
536f4067 12603 if (found_size == size)
8e713be6 12604 newlist = Fcons (XCAR (tem), newlist);
536f4067 12605 else if (found_size > 0)
b5210ea7 12606 {
536f4067 12607 if (NILP (second_best))
b5210ea7 12608 second_best = tem;
536f4067
RS
12609 else if (found_size < size)
12610 {
8e713be6
KR
12611 if (XINT (XCDR (second_best)) > size
12612 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
12613 second_best = tem;
12614 }
12615 else
12616 {
8e713be6
KR
12617 if (XINT (XCDR (second_best)) > size
12618 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
12619 second_best = tem;
12620 }
b5210ea7
KH
12621 }
12622 }
12623 if (!NILP (newlist))
12624 break;
12625 else if (!NILP (second_best))
12626 {
8e713be6 12627 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 12628 break;
dc43ef94 12629 }
dc43ef94
KH
12630 }
12631
12632 return newlist;
12633}
12634
06a2c219
GM
12635
12636#if GLYPH_DEBUG
12637
12638/* Check that FONT is valid on frame F. It is if it can be found in F's
12639 font table. */
12640
12641static void
12642x_check_font (f, font)
12643 struct frame *f;
12644 XFontStruct *font;
12645{
12646 int i;
12647 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12648
12649 xassert (font != NULL);
12650
12651 for (i = 0; i < dpyinfo->n_fonts; i++)
12652 if (dpyinfo->font_table[i].name
12653 && font == dpyinfo->font_table[i].font)
12654 break;
12655
12656 xassert (i < dpyinfo->n_fonts);
12657}
12658
12659#endif /* GLYPH_DEBUG != 0 */
12660
12661/* Set *W to the minimum width, *H to the minimum font height of FONT.
12662 Note: There are (broken) X fonts out there with invalid XFontStruct
12663 min_bounds contents. For example, handa@etl.go.jp reports that
12664 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
12665 have font->min_bounds.width == 0. */
12666
12667static INLINE void
12668x_font_min_bounds (font, w, h)
12669 XFontStruct *font;
12670 int *w, *h;
12671{
12672 *h = FONT_HEIGHT (font);
12673 *w = font->min_bounds.width;
12674
12675 /* Try to handle the case where FONT->min_bounds has invalid
12676 contents. Since the only font known to have invalid min_bounds
12677 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
12678 if (*w <= 0)
12679 *w = font->max_bounds.width;
12680}
12681
12682
12683/* Compute the smallest character width and smallest font height over
12684 all fonts available on frame F. Set the members smallest_char_width
12685 and smallest_font_height in F's x_display_info structure to
12686 the values computed. Value is non-zero if smallest_font_height or
12687 smallest_char_width become smaller than they were before. */
12688
12689static int
12690x_compute_min_glyph_bounds (f)
12691 struct frame *f;
12692{
12693 int i;
12694 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12695 XFontStruct *font;
12696 int old_width = dpyinfo->smallest_char_width;
12697 int old_height = dpyinfo->smallest_font_height;
12698
12699 dpyinfo->smallest_font_height = 100000;
12700 dpyinfo->smallest_char_width = 100000;
12701
12702 for (i = 0; i < dpyinfo->n_fonts; ++i)
12703 if (dpyinfo->font_table[i].name)
12704 {
12705 struct font_info *fontp = dpyinfo->font_table + i;
12706 int w, h;
12707
12708 font = (XFontStruct *) fontp->font;
12709 xassert (font != (XFontStruct *) ~0);
12710 x_font_min_bounds (font, &w, &h);
12711
12712 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
12713 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
12714 }
12715
12716 xassert (dpyinfo->smallest_char_width > 0
12717 && dpyinfo->smallest_font_height > 0);
12718
12719 return (dpyinfo->n_fonts == 1
12720 || dpyinfo->smallest_char_width < old_width
12721 || dpyinfo->smallest_font_height < old_height);
12722}
12723
12724
dc43ef94
KH
12725/* Load font named FONTNAME of the size SIZE for frame F, and return a
12726 pointer to the structure font_info while allocating it dynamically.
12727 If SIZE is 0, load any size of font.
12728 If loading is failed, return NULL. */
12729
12730struct font_info *
12731x_load_font (f, fontname, size)
12732 struct frame *f;
12733 register char *fontname;
12734 int size;
12735{
12736 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12737 Lisp_Object font_names;
d645aaa4 12738 int count;
dc43ef94
KH
12739
12740 /* Get a list of all the fonts that match this name. Once we
12741 have a list of matching fonts, we compare them against the fonts
12742 we already have by comparing names. */
09c6077f 12743 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
12744
12745 if (!NILP (font_names))
12746 {
12747 Lisp_Object tail;
12748 int i;
12749
12750 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 12751 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
12752 if (dpyinfo->font_table[i].name
12753 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 12754 XSTRING (XCAR (tail))->data)
06a2c219 12755 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 12756 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
12757 return (dpyinfo->font_table + i);
12758 }
12759
12760 /* Load the font and add it to the table. */
12761 {
12762 char *full_name;
12763 XFontStruct *font;
12764 struct font_info *fontp;
12765 unsigned long value;
06a2c219 12766 int i;
dc43ef94 12767
2da424f1
KH
12768 /* If we have found fonts by x_list_font, load one of them. If
12769 not, we still try to load a font by the name given as FONTNAME
12770 because XListFonts (called in x_list_font) of some X server has
12771 a bug of not finding a font even if the font surely exists and
12772 is loadable by XLoadQueryFont. */
e1d6d5b9 12773 if (size > 0 && !NILP (font_names))
8e713be6 12774 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
12775
12776 BLOCK_INPUT;
d645aaa4 12777 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 12778 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
12779 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12780 {
12781 /* This error is perhaps due to insufficient memory on X
12782 server. Let's just ignore it. */
12783 font = NULL;
12784 x_clear_errors (FRAME_X_DISPLAY (f));
12785 }
12786 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 12787 UNBLOCK_INPUT;
b5210ea7 12788 if (!font)
dc43ef94
KH
12789 return NULL;
12790
06a2c219
GM
12791 /* Find a free slot in the font table. */
12792 for (i = 0; i < dpyinfo->n_fonts; ++i)
12793 if (dpyinfo->font_table[i].name == NULL)
12794 break;
12795
12796 /* If no free slot found, maybe enlarge the font table. */
12797 if (i == dpyinfo->n_fonts
12798 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 12799 {
06a2c219
GM
12800 int sz;
12801 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
12802 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 12803 dpyinfo->font_table
06a2c219 12804 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
12805 }
12806
06a2c219
GM
12807 fontp = dpyinfo->font_table + i;
12808 if (i == dpyinfo->n_fonts)
12809 ++dpyinfo->n_fonts;
dc43ef94
KH
12810
12811 /* Now fill in the slots of *FONTP. */
12812 BLOCK_INPUT;
12813 fontp->font = font;
06a2c219 12814 fontp->font_idx = i;
dc43ef94
KH
12815 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
12816 bcopy (fontname, fontp->name, strlen (fontname) + 1);
12817
12818 /* Try to get the full name of FONT. Put it in FULL_NAME. */
12819 full_name = 0;
12820 if (XGetFontProperty (font, XA_FONT, &value))
12821 {
12822 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
12823 char *p = name;
12824 int dashes = 0;
12825
12826 /* Count the number of dashes in the "full name".
12827 If it is too few, this isn't really the font's full name,
12828 so don't use it.
12829 In X11R4, the fonts did not come with their canonical names
12830 stored in them. */
12831 while (*p)
12832 {
12833 if (*p == '-')
12834 dashes++;
12835 p++;
12836 }
12837
12838 if (dashes >= 13)
12839 {
12840 full_name = (char *) xmalloc (p - name + 1);
12841 bcopy (name, full_name, p - name + 1);
12842 }
12843
12844 XFree (name);
12845 }
12846
12847 if (full_name != 0)
12848 fontp->full_name = full_name;
12849 else
12850 fontp->full_name = fontp->name;
12851
12852 fontp->size = font->max_bounds.width;
d5749adb
KH
12853 fontp->height = FONT_HEIGHT (font);
12854 {
12855 /* For some font, ascent and descent in max_bounds field is
12856 larger than the above value. */
12857 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
12858 if (max_height > fontp->height)
74848a96 12859 fontp->height = max_height;
d5749adb 12860 }
dc43ef94 12861
2da424f1
KH
12862 if (NILP (font_names))
12863 {
12864 /* We come here because of a bug of XListFonts mentioned at
12865 the head of this block. Let's store this information in
12866 the cache for x_list_fonts. */
12867 Lisp_Object lispy_name = build_string (fontname);
12868 Lisp_Object lispy_full_name = build_string (fontp->full_name);
12869
8e713be6 12870 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12871 = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
12872 Fcons (Fcons (lispy_full_name,
12873 make_number (fontp->size)),
12874 Qnil)),
8e713be6 12875 XCDR (dpyinfo->name_list_element));
2da424f1 12876 if (full_name)
8e713be6 12877 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12878 = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
12879 Fcons (Fcons (lispy_full_name,
12880 make_number (fontp->size)),
12881 Qnil)),
8e713be6 12882 XCDR (dpyinfo->name_list_element));
2da424f1
KH
12883 }
12884
dc43ef94
KH
12885 /* The slot `encoding' specifies how to map a character
12886 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
12887 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
12888 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 12889 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 12890 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
12891 which is never used by any charset. If mapping can't be
12892 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
12893 fontp->encoding[1]
12894 = (font->max_byte1 == 0
12895 /* 1-byte font */
12896 ? (font->min_char_or_byte2 < 0x80
12897 ? (font->max_char_or_byte2 < 0x80
12898 ? 0 /* 0x20..0x7F */
8ff102bd 12899 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
12900 : 1) /* 0xA0..0xFF */
12901 /* 2-byte font */
12902 : (font->min_byte1 < 0x80
12903 ? (font->max_byte1 < 0x80
12904 ? (font->min_char_or_byte2 < 0x80
12905 ? (font->max_char_or_byte2 < 0x80
12906 ? 0 /* 0x2020..0x7F7F */
8ff102bd 12907 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 12908 : 3) /* 0x20A0..0x7FFF */
8ff102bd 12909 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
12910 : (font->min_char_or_byte2 < 0x80
12911 ? (font->max_char_or_byte2 < 0x80
12912 ? 2 /* 0xA020..0xFF7F */
8ff102bd 12913 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
12914 : 1))); /* 0xA0A0..0xFFFF */
12915
12916 fontp->baseline_offset
12917 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
12918 ? (long) value : 0);
12919 fontp->relative_compose
12920 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
12921 ? (long) value : 0);
f78798df
KH
12922 fontp->default_ascent
12923 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
12924 ? (long) value : 0);
dc43ef94 12925
06a2c219
GM
12926 /* Set global flag fonts_changed_p to non-zero if the font loaded
12927 has a character with a smaller width than any other character
12928 before, or if the font loaded has a smalle>r height than any
12929 other font loaded before. If this happens, it will make a
12930 glyph matrix reallocation necessary. */
12931 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 12932 UNBLOCK_INPUT;
dc43ef94
KH
12933 return fontp;
12934 }
12935}
12936
06a2c219
GM
12937
12938/* Return a pointer to struct font_info of a font named FONTNAME for
12939 frame F. If no such font is loaded, return NULL. */
12940
dc43ef94
KH
12941struct font_info *
12942x_query_font (f, fontname)
12943 struct frame *f;
12944 register char *fontname;
12945{
12946 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12947 int i;
12948
12949 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
12950 if (dpyinfo->font_table[i].name
12951 && (!strcmp (dpyinfo->font_table[i].name, fontname)
12952 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
12953 return (dpyinfo->font_table + i);
12954 return NULL;
12955}
12956
06a2c219
GM
12957
12958/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
12959 `encoder' of the structure. */
12960
12961void
12962x_find_ccl_program (fontp)
12963 struct font_info *fontp;
12964{
a42f54e6 12965 Lisp_Object list, elt;
a6582676 12966
8e713be6 12967 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 12968 {
8e713be6 12969 elt = XCAR (list);
a6582676 12970 if (CONSP (elt)
8e713be6
KR
12971 && STRINGP (XCAR (elt))
12972 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
a6582676 12973 >= 0))
a42f54e6
KH
12974 break;
12975 }
12976 if (! NILP (list))
12977 {
d27f8ca7
KH
12978 struct ccl_program *ccl
12979 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 12980
8e713be6 12981 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
12982 xfree (ccl);
12983 else
12984 fontp->font_encoder = ccl;
a6582676
KH
12985 }
12986}
12987
06a2c219 12988
dc43ef94 12989\f
06a2c219
GM
12990/***********************************************************************
12991 Initialization
12992 ***********************************************************************/
f451eb13 12993
3afe33e7
RS
12994#ifdef USE_X_TOOLKIT
12995static XrmOptionDescRec emacs_options[] = {
12996 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
12997 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
12998
12999 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
13000 XrmoptionSepArg, NULL},
13001 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
13002
13003 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13004 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13005 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13006 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13007 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13008 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
13009 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
13010};
13011#endif /* USE_X_TOOLKIT */
13012
7a13e894
RS
13013static int x_initialized;
13014
29b38361
KH
13015#ifdef MULTI_KBOARD
13016/* Test whether two display-name strings agree up to the dot that separates
13017 the screen number from the server number. */
13018static int
13019same_x_server (name1, name2)
13020 char *name1, *name2;
13021{
13022 int seen_colon = 0;
cf591cc1
RS
13023 unsigned char *system_name = XSTRING (Vsystem_name)->data;
13024 int system_name_length = strlen (system_name);
13025 int length_until_period = 0;
13026
13027 while (system_name[length_until_period] != 0
13028 && system_name[length_until_period] != '.')
13029 length_until_period++;
13030
13031 /* Treat `unix' like an empty host name. */
13032 if (! strncmp (name1, "unix:", 5))
13033 name1 += 4;
13034 if (! strncmp (name2, "unix:", 5))
13035 name2 += 4;
13036 /* Treat this host's name like an empty host name. */
13037 if (! strncmp (name1, system_name, system_name_length)
13038 && name1[system_name_length] == ':')
13039 name1 += system_name_length;
13040 if (! strncmp (name2, system_name, system_name_length)
13041 && name2[system_name_length] == ':')
13042 name2 += system_name_length;
13043 /* Treat this host's domainless name like an empty host name. */
13044 if (! strncmp (name1, system_name, length_until_period)
13045 && name1[length_until_period] == ':')
13046 name1 += length_until_period;
13047 if (! strncmp (name2, system_name, length_until_period)
13048 && name2[length_until_period] == ':')
13049 name2 += length_until_period;
13050
29b38361
KH
13051 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
13052 {
13053 if (*name1 == ':')
13054 seen_colon++;
13055 if (seen_colon && *name1 == '.')
13056 return 1;
13057 }
13058 return (seen_colon
13059 && (*name1 == '.' || *name1 == '\0')
13060 && (*name2 == '.' || *name2 == '\0'));
13061}
13062#endif
13063
334208b7 13064struct x_display_info *
1f8255f2 13065x_term_init (display_name, xrm_option, resource_name)
334208b7 13066 Lisp_Object display_name;
1f8255f2
RS
13067 char *xrm_option;
13068 char *resource_name;
dc6f92b8 13069{
334208b7 13070 int connection;
7a13e894 13071 Display *dpy;
334208b7
RS
13072 struct x_display_info *dpyinfo;
13073 XrmDatabase xrdb;
13074
60439948
KH
13075 BLOCK_INPUT;
13076
7a13e894
RS
13077 if (!x_initialized)
13078 {
13079 x_initialize ();
13080 x_initialized = 1;
13081 }
dc6f92b8 13082
3afe33e7 13083#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
13084 /* weiner@footloose.sps.mot.com reports that this causes
13085 errors with X11R5:
13086 X protocol error: BadAtom (invalid Atom parameter)
13087 on protocol request 18skiloaf.
13088 So let's not use it until R6. */
13089#ifdef HAVE_X11XTR6
bdcd49ba
RS
13090 XtSetLanguageProc (NULL, NULL, NULL);
13091#endif
13092
7f9c7f94
RS
13093 {
13094 int argc = 0;
13095 char *argv[3];
13096
13097 argv[0] = "";
13098 argc = 1;
13099 if (xrm_option)
13100 {
13101 argv[argc++] = "-xrm";
13102 argv[argc++] = xrm_option;
13103 }
13104 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
13105 resource_name, EMACS_CLASS,
13106 emacs_options, XtNumber (emacs_options),
13107 &argc, argv);
39d8bb4d
KH
13108
13109#ifdef HAVE_X11XTR6
10537cb1 13110 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 13111 fixup_locale ();
39d8bb4d 13112#endif
7f9c7f94 13113 }
3afe33e7
RS
13114
13115#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
13116#ifdef HAVE_X11R5
13117 XSetLocaleModifiers ("");
13118#endif
7a13e894 13119 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 13120#endif /* not USE_X_TOOLKIT */
334208b7 13121
7a13e894
RS
13122 /* Detect failure. */
13123 if (dpy == 0)
60439948
KH
13124 {
13125 UNBLOCK_INPUT;
13126 return 0;
13127 }
7a13e894
RS
13128
13129 /* We have definitely succeeded. Record the new connection. */
13130
13131 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
13132
29b38361
KH
13133#ifdef MULTI_KBOARD
13134 {
13135 struct x_display_info *share;
13136 Lisp_Object tail;
13137
13138 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
13139 share = share->next, tail = XCDR (tail))
13140 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
13141 XSTRING (display_name)->data))
13142 break;
13143 if (share)
13144 dpyinfo->kboard = share->kboard;
13145 else
13146 {
13147 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13148 init_kboard (dpyinfo->kboard);
59e755be
KH
13149 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
13150 {
13151 char *vendor = ServerVendor (dpy);
9b6ed9f3 13152 UNBLOCK_INPUT;
59e755be
KH
13153 dpyinfo->kboard->Vsystem_key_alist
13154 = call1 (Qvendor_specific_keysyms,
13155 build_string (vendor ? vendor : ""));
9b6ed9f3 13156 BLOCK_INPUT;
59e755be
KH
13157 }
13158
29b38361
KH
13159 dpyinfo->kboard->next_kboard = all_kboards;
13160 all_kboards = dpyinfo->kboard;
0ad5446c
KH
13161 /* Don't let the initial kboard remain current longer than necessary.
13162 That would cause problems if a file loaded on startup tries to
06a2c219 13163 prompt in the mini-buffer. */
0ad5446c
KH
13164 if (current_kboard == initial_kboard)
13165 current_kboard = dpyinfo->kboard;
29b38361
KH
13166 }
13167 dpyinfo->kboard->reference_count++;
13168 }
b9737ad3
KH
13169#endif
13170
7a13e894
RS
13171 /* Put this display on the chain. */
13172 dpyinfo->next = x_display_list;
13173 x_display_list = dpyinfo;
13174
13175 /* Put it on x_display_name_list as well, to keep them parallel. */
13176 x_display_name_list = Fcons (Fcons (display_name, Qnil),
13177 x_display_name_list);
8e713be6 13178 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
13179
13180 dpyinfo->display = dpy;
dc6f92b8 13181
dc6f92b8 13182#if 0
7a13e894 13183 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 13184#endif /* ! 0 */
7a13e894
RS
13185
13186 dpyinfo->x_id_name
fc932ac6
RS
13187 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
13188 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
13189 + 2);
13190 sprintf (dpyinfo->x_id_name, "%s@%s",
13191 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
13192
13193 /* Figure out which modifier bits mean what. */
334208b7 13194 x_find_modifier_meanings (dpyinfo);
f451eb13 13195
ab648270 13196 /* Get the scroll bar cursor. */
7a13e894 13197 dpyinfo->vertical_scroll_bar_cursor
334208b7 13198 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 13199
334208b7
RS
13200 xrdb = x_load_resources (dpyinfo->display, xrm_option,
13201 resource_name, EMACS_CLASS);
13202#ifdef HAVE_XRMSETDATABASE
13203 XrmSetDatabase (dpyinfo->display, xrdb);
13204#else
13205 dpyinfo->display->db = xrdb;
13206#endif
547d9db8 13207 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
13208 all versions. */
13209 dpyinfo->xrdb = xrdb;
334208b7
RS
13210
13211 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
13212 DefaultScreen (dpyinfo->display));
5ff67d81 13213 select_visual (dpyinfo);
43bd1b2b 13214 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
13215 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
13216 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
13217 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
13218 dpyinfo->grabbed = 0;
13219 dpyinfo->reference_count = 0;
13220 dpyinfo->icon_bitmap_id = -1;
06a2c219 13221 dpyinfo->font_table = NULL;
7a13e894
RS
13222 dpyinfo->n_fonts = 0;
13223 dpyinfo->font_table_size = 0;
13224 dpyinfo->bitmaps = 0;
13225 dpyinfo->bitmaps_size = 0;
13226 dpyinfo->bitmaps_last = 0;
13227 dpyinfo->scratch_cursor_gc = 0;
13228 dpyinfo->mouse_face_mouse_frame = 0;
13229 dpyinfo->mouse_face_deferred_gc = 0;
13230 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
13231 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 13232 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894
RS
13233 dpyinfo->mouse_face_window = Qnil;
13234 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
13235 dpyinfo->mouse_face_defer = 0;
0f941935
KH
13236 dpyinfo->x_focus_frame = 0;
13237 dpyinfo->x_focus_event_frame = 0;
13238 dpyinfo->x_highlight_frame = 0;
06a2c219 13239 dpyinfo->image_cache = make_image_cache ();
334208b7 13240
43bd1b2b 13241 /* See if a private colormap is requested. */
5ff67d81
GM
13242 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
13243 {
13244 if (dpyinfo->visual->class == PseudoColor)
13245 {
13246 Lisp_Object value;
13247 value = display_x_get_resource (dpyinfo,
13248 build_string ("privateColormap"),
13249 build_string ("PrivateColormap"),
13250 Qnil, Qnil);
13251 if (STRINGP (value)
13252 && (!strcmp (XSTRING (value)->data, "true")
13253 || !strcmp (XSTRING (value)->data, "on")))
13254 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
13255 }
43bd1b2b 13256 }
5ff67d81
GM
13257 else
13258 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
13259 dpyinfo->visual, AllocNone);
43bd1b2b 13260
06a2c219
GM
13261 {
13262 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
13263 double pixels = DisplayHeight (dpyinfo->display, screen_number);
13264 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
13265 dpyinfo->resy = pixels * 25.4 / mm;
13266 pixels = DisplayWidth (dpyinfo->display, screen_number);
13267 mm = DisplayWidthMM (dpyinfo->display, screen_number);
13268 dpyinfo->resx = pixels * 25.4 / mm;
13269 }
13270
334208b7
RS
13271 dpyinfo->Xatom_wm_protocols
13272 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
13273 dpyinfo->Xatom_wm_take_focus
13274 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
13275 dpyinfo->Xatom_wm_save_yourself
13276 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
13277 dpyinfo->Xatom_wm_delete_window
13278 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
13279 dpyinfo->Xatom_wm_change_state
13280 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
13281 dpyinfo->Xatom_wm_configure_denied
13282 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
13283 dpyinfo->Xatom_wm_window_moved
13284 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
13285 dpyinfo->Xatom_editres
13286 = XInternAtom (dpyinfo->display, "Editres", False);
13287 dpyinfo->Xatom_CLIPBOARD
13288 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
13289 dpyinfo->Xatom_TIMESTAMP
13290 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
13291 dpyinfo->Xatom_TEXT
13292 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
13293 dpyinfo->Xatom_COMPOUND_TEXT
13294 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
13295 dpyinfo->Xatom_DELETE
13296 = XInternAtom (dpyinfo->display, "DELETE", False);
13297 dpyinfo->Xatom_MULTIPLE
13298 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
13299 dpyinfo->Xatom_INCR
13300 = XInternAtom (dpyinfo->display, "INCR", False);
13301 dpyinfo->Xatom_EMACS_TMP
13302 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
13303 dpyinfo->Xatom_TARGETS
13304 = XInternAtom (dpyinfo->display, "TARGETS", False);
13305 dpyinfo->Xatom_NULL
13306 = XInternAtom (dpyinfo->display, "NULL", False);
13307 dpyinfo->Xatom_ATOM_PAIR
13308 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
13309 /* For properties of font. */
13310 dpyinfo->Xatom_PIXEL_SIZE
13311 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
13312 dpyinfo->Xatom_MULE_BASELINE_OFFSET
13313 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
13314 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
13315 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
13316 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
13317 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 13318
06a2c219
GM
13319 /* Ghostscript support. */
13320 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
13321 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
13322
13323 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
13324 False);
13325
547d9db8
KH
13326 dpyinfo->cut_buffers_initialized = 0;
13327
334208b7
RS
13328 connection = ConnectionNumber (dpyinfo->display);
13329 dpyinfo->connection = connection;
13330
dc43ef94 13331 {
5d7cc324
RS
13332 char null_bits[1];
13333
13334 null_bits[0] = 0x00;
dc43ef94
KH
13335
13336 dpyinfo->null_pixel
13337 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13338 null_bits, 1, 1, (long) 0, (long) 0,
13339 1);
13340 }
13341
06a2c219
GM
13342 {
13343 extern int gray_bitmap_width, gray_bitmap_height;
13344 extern unsigned char *gray_bitmap_bits;
13345 dpyinfo->gray
13346 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13347 gray_bitmap_bits,
13348 gray_bitmap_width, gray_bitmap_height,
13349 (unsigned long) 1, (unsigned long) 0, 1);
13350 }
13351
f5d11644
GM
13352#ifdef HAVE_X_I18N
13353 xim_initialize (dpyinfo, resource_name);
13354#endif
13355
87485d6f
MW
13356#ifdef subprocesses
13357 /* This is only needed for distinguishing keyboard and process input. */
334208b7 13358 if (connection != 0)
7a13e894 13359 add_keyboard_wait_descriptor (connection);
87485d6f 13360#endif
6d4238f3 13361
041b69ac 13362#ifndef F_SETOWN_BUG
dc6f92b8 13363#ifdef F_SETOWN
dc6f92b8 13364#ifdef F_SETOWN_SOCK_NEG
61c3ce62 13365 /* stdin is a socket here */
334208b7 13366 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 13367#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 13368 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
13369#endif /* ! defined (F_SETOWN_SOCK_NEG) */
13370#endif /* ! defined (F_SETOWN) */
041b69ac 13371#endif /* F_SETOWN_BUG */
dc6f92b8
JB
13372
13373#ifdef SIGIO
eee20f6a
KH
13374 if (interrupt_input)
13375 init_sigio (connection);
c118dd06 13376#endif /* ! defined (SIGIO) */
dc6f92b8 13377
51b592fb 13378#ifdef USE_LUCID
f8c39f51 13379#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
13380 /* Make sure that we have a valid font for dialog boxes
13381 so that Xt does not crash. */
13382 {
13383 Display *dpy = dpyinfo->display;
13384 XrmValue d, fr, to;
13385 Font font;
e99db5a1 13386 int count;
51b592fb
RS
13387
13388 d.addr = (XPointer)&dpy;
13389 d.size = sizeof (Display *);
13390 fr.addr = XtDefaultFont;
13391 fr.size = sizeof (XtDefaultFont);
13392 to.size = sizeof (Font *);
13393 to.addr = (XPointer)&font;
e99db5a1 13394 count = x_catch_errors (dpy);
51b592fb
RS
13395 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
13396 abort ();
13397 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
13398 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 13399 x_uncatch_errors (dpy, count);
51b592fb
RS
13400 }
13401#endif
f8c39f51 13402#endif
51b592fb 13403
34e23e5a
GM
13404 /* See if we should run in synchronous mode. This is useful
13405 for debugging X code. */
13406 {
13407 Lisp_Object value;
13408 value = display_x_get_resource (dpyinfo,
13409 build_string ("synchronous"),
13410 build_string ("Synchronous"),
13411 Qnil, Qnil);
13412 if (STRINGP (value)
13413 && (!strcmp (XSTRING (value)->data, "true")
13414 || !strcmp (XSTRING (value)->data, "on")))
13415 XSynchronize (dpyinfo->display, True);
13416 }
13417
60439948
KH
13418 UNBLOCK_INPUT;
13419
7a13e894
RS
13420 return dpyinfo;
13421}
13422\f
13423/* Get rid of display DPYINFO, assuming all frames are already gone,
13424 and without sending any more commands to the X server. */
dc6f92b8 13425
7a13e894
RS
13426void
13427x_delete_display (dpyinfo)
13428 struct x_display_info *dpyinfo;
13429{
13430 delete_keyboard_wait_descriptor (dpyinfo->connection);
13431
13432 /* Discard this display from x_display_name_list and x_display_list.
13433 We can't use Fdelq because that can quit. */
13434 if (! NILP (x_display_name_list)
8e713be6
KR
13435 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
13436 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
13437 else
13438 {
13439 Lisp_Object tail;
13440
13441 tail = x_display_name_list;
8e713be6 13442 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 13443 {
bffcfca9 13444 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 13445 {
8e713be6 13446 XCDR (tail) = XCDR (XCDR (tail));
7a13e894
RS
13447 break;
13448 }
8e713be6 13449 tail = XCDR (tail);
7a13e894
RS
13450 }
13451 }
13452
9bda743f
GM
13453 if (next_noop_dpyinfo == dpyinfo)
13454 next_noop_dpyinfo = dpyinfo->next;
13455
7a13e894
RS
13456 if (x_display_list == dpyinfo)
13457 x_display_list = dpyinfo->next;
7f9c7f94
RS
13458 else
13459 {
13460 struct x_display_info *tail;
7a13e894 13461
7f9c7f94
RS
13462 for (tail = x_display_list; tail; tail = tail->next)
13463 if (tail->next == dpyinfo)
13464 tail->next = tail->next->next;
13465 }
7a13e894 13466
0d777288
RS
13467#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
13468#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
13469 XrmDestroyDatabase (dpyinfo->xrdb);
13470#endif
0d777288 13471#endif
29b38361
KH
13472#ifdef MULTI_KBOARD
13473 if (--dpyinfo->kboard->reference_count == 0)
39f79001 13474 delete_kboard (dpyinfo->kboard);
b9737ad3 13475#endif
f5d11644
GM
13476#ifdef HAVE_X_I18N
13477 if (dpyinfo->xim)
13478 xim_close_dpy (dpyinfo);
13479#endif
13480
b9737ad3
KH
13481 xfree (dpyinfo->font_table);
13482 xfree (dpyinfo->x_id_name);
13483 xfree (dpyinfo);
7a13e894
RS
13484}
13485\f
13486/* Set up use of X before we make the first connection. */
13487
06a2c219
GM
13488static struct redisplay_interface x_redisplay_interface =
13489{
13490 x_produce_glyphs,
13491 x_write_glyphs,
13492 x_insert_glyphs,
13493 x_clear_end_of_line,
13494 x_scroll_run,
13495 x_after_update_window_line,
13496 x_update_window_begin,
13497 x_update_window_end,
13498 XTcursor_to,
13499 x_flush,
71b8321e 13500 x_clear_mouse_face,
66ac4b0e
GM
13501 x_get_glyph_overhangs,
13502 x_fix_overlapping_area
06a2c219
GM
13503};
13504
dfcf069d 13505void
7a13e894
RS
13506x_initialize ()
13507{
06a2c219
GM
13508 rif = &x_redisplay_interface;
13509
13510 clear_frame_hook = x_clear_frame;
13511 ins_del_lines_hook = x_ins_del_lines;
13512 change_line_highlight_hook = x_change_line_highlight;
13513 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
13514 ring_bell_hook = XTring_bell;
13515 reset_terminal_modes_hook = XTreset_terminal_modes;
13516 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
13517 update_begin_hook = x_update_begin;
13518 update_end_hook = x_update_end;
dc6f92b8
JB
13519 set_terminal_window_hook = XTset_terminal_window;
13520 read_socket_hook = XTread_socket;
b8009dd1 13521 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 13522 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 13523 mouse_position_hook = XTmouse_position;
f451eb13 13524 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 13525 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
13526 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13527 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13528 redeem_scroll_bar_hook = XTredeem_scroll_bar;
13529 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 13530 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 13531
f676886a 13532 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
13533 char_ins_del_ok = 0; /* just as fast to write the line */
13534 line_ins_del_ok = 1; /* we'll just blt 'em */
13535 fast_clear_end_of_line = 1; /* X does this well */
58769bee 13536 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
13537 off the bottom */
13538 baud_rate = 19200;
13539
7a13e894 13540 x_noop_count = 0;
9ea173e8 13541 last_tool_bar_item = -1;
06a2c219
GM
13542 any_help_event_p = 0;
13543
b30b24cb
RS
13544 /* Try to use interrupt input; if we can't, then start polling. */
13545 Fset_input_mode (Qt, Qnil, Qt, Qnil);
13546
7f9c7f94
RS
13547#ifdef USE_X_TOOLKIT
13548 XtToolkitInitialize ();
13549 Xt_app_con = XtCreateApplicationContext ();
665881ad 13550 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
13551
13552 /* Install an asynchronous timer that processes Xt timeout events
13553 every 0.1s. This is necessary because some widget sets use
13554 timeouts internally, for example the LessTif menu bar, or the
13555 Xaw3d scroll bar. When Xt timouts aren't processed, these
13556 widgets don't behave normally. */
13557 {
13558 EMACS_TIME interval;
13559 EMACS_SET_SECS_USECS (interval, 0, 100000);
13560 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
13561 }
db74249b 13562#endif
bffcfca9 13563
db74249b 13564#if USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
13565 xaw3d_arrow_scroll = False;
13566 xaw3d_pick_top = True;
7f9c7f94
RS
13567#endif
13568
58769bee 13569 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 13570 original error handler. */
e99db5a1 13571 XSetErrorHandler (x_error_handler);
334208b7 13572 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 13573
06a2c219 13574 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
13575#ifdef SIGWINCH
13576 signal (SIGWINCH, SIG_DFL);
c118dd06 13577#endif /* ! defined (SIGWINCH) */
dc6f92b8 13578
92e2441b 13579 signal (SIGPIPE, x_connection_signal);
dc6f92b8 13580}
55123275 13581
06a2c219 13582
55123275
JB
13583void
13584syms_of_xterm ()
13585{
e99db5a1
RS
13586 staticpro (&x_error_message_string);
13587 x_error_message_string = Qnil;
13588
7a13e894
RS
13589 staticpro (&x_display_name_list);
13590 x_display_name_list = Qnil;
334208b7 13591
ab648270 13592 staticpro (&last_mouse_scroll_bar);
e53cb100 13593 last_mouse_scroll_bar = Qnil;
59e755be
KH
13594
13595 staticpro (&Qvendor_specific_keysyms);
13596 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
13597
13598 staticpro (&last_mouse_press_frame);
13599 last_mouse_press_frame = Qnil;
06a2c219 13600
06a2c219 13601 help_echo = Qnil;
be010514
GM
13602 staticpro (&help_echo);
13603 help_echo_object = Qnil;
13604 staticpro (&help_echo_object);
7cea38bc
GM
13605 help_echo_window = Qnil;
13606 staticpro (&help_echo_window);
06a2c219 13607 previous_help_echo = Qnil;
be010514
GM
13608 staticpro (&previous_help_echo);
13609 help_echo_pos = -1;
06a2c219
GM
13610
13611 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
13612 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
13613For example, if a block cursor is over a tab, it will be drawn as\n\
13614wide as that tab on the display.");
13615 x_stretch_cursor_p = 0;
13616
13617 DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
13618 "If not nil, Emacs uses toolkit scroll bars.");
13619#if USE_TOOLKIT_SCROLL_BARS
13620 x_toolkit_scroll_bars_p = 1;
13621#else
13622 x_toolkit_scroll_bars_p = 0;
13623#endif
13624
06a2c219
GM
13625 staticpro (&last_mouse_motion_frame);
13626 last_mouse_motion_frame = Qnil;
55123275 13627}
6cf0ae86
RS
13628
13629#endif /* not HAVE_X_WINDOWS */
06a2c219 13630