*** empty log message ***
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
1c7e22fd 2 Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000
06a2c219 3 Free Software Foundation, Inc.
dc6f92b8
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4746118a 9the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
dc6f92b8 21
06a2c219 22/* New display code by Gerd Moellmann <gerd@gnu.org>. */
3afe33e7
RS
23/* Xt features made by Fred Pierresteguy. */
24
68c45bf0
PE
25#include <config.h>
26
039440c4 27/* On 4.3 these lose if they come after xterm.h. */
039440c4 28/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
29#include <signal.h>
30
4846819e
RS
31#include <stdio.h>
32
dc6f92b8
JB
33#ifdef HAVE_X_WINDOWS
34
35#include "lisp.h"
9ac0d9e0 36#include "blockinput.h"
dc6f92b8 37
ae79c227
AS
38/* Need syssignal.h for various externs and definitions that may be required
39 by some configurations for calls to signal later in this source file. */
40#include "syssignal.h"
41
dc6f92b8
JB
42/* This may include sys/types.h, and that somehow loses
43 if this is not done before the other system files. */
44#include "xterm.h"
f451eb13 45#include <X11/cursorfont.h>
dc6f92b8
JB
46
47/* Load sys/types.h if not already loaded.
48 In some systems loading it twice is suicidal. */
49#ifndef makedev
50#include <sys/types.h>
c118dd06 51#endif /* makedev */
dc6f92b8 52
6df54671 53#ifdef BSD_SYSTEM
dc6f92b8 54#include <sys/ioctl.h>
6df54671 55#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 56
2d368234 57#include "systty.h"
3a2712f9 58#include "systime.h"
dc6f92b8 59
b8009dd1 60#ifndef INCLUDED_FCNTL
dc6f92b8 61#include <fcntl.h>
b8009dd1 62#endif
dc6f92b8
JB
63#include <ctype.h>
64#include <errno.h>
65#include <setjmp.h>
66#include <sys/stat.h>
a0a7635f
RS
67/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
68/* #include <sys/param.h> */
dc6f92b8 69
dc43ef94
KH
70#include "charset.h"
71#include "ccl.h"
7a13e894 72#include "frame.h"
dc6f92b8 73#include "dispextern.h"
ee569018 74#include "fontset.h"
dc6f92b8
JB
75#include "termhooks.h"
76#include "termopts.h"
77#include "termchar.h"
78#if 0
79#include "sink.h"
80#include "sinkmask.h"
c118dd06 81#endif /* ! 0 */
dc6f92b8 82#include "gnu.h"
dc6f92b8 83#include "disptab.h"
dc6f92b8 84#include "buffer.h"
f451eb13 85#include "window.h"
3b2fa4e6 86#include "keyboard.h"
bde7c500 87#include "intervals.h"
dfcf069d 88#include "process.h"
bffcfca9 89#include "atimer.h"
dc6f92b8 90
d2bd6bc4
RS
91#ifdef USE_X_TOOLKIT
92#include <X11/Shell.h>
93#endif
94
06a2c219
GM
95#ifdef HAVE_SYS_TIME_H
96#include <sys/time.h>
97#endif
98#ifdef HAVE_UNISTD_H
99#include <unistd.h>
100#endif
101
3afe33e7 102#ifdef USE_X_TOOLKIT
06a2c219 103
9d7e2e3e 104extern void free_frame_menubar ();
2224b905 105extern FRAME_PTR x_menubar_window_to_frame ();
06a2c219 106
0fdff6bb
RS
107#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
108#define HACK_EDITRES
109extern void _XEditResCheckMessages ();
110#endif /* not NO_EDITRES */
06a2c219
GM
111
112/* Include toolkit specific headers for the scroll bar widget. */
113
114#ifdef USE_TOOLKIT_SCROLL_BARS
115#if defined USE_MOTIF
116#include <Xm/Xm.h> /* for LESSTIF_VERSION */
117#include <Xm/ScrollBar.h>
118#include <Xm/ScrollBarP.h>
ec18280f
SM
119#else /* !USE_MOTIF i.e. use Xaw */
120
121#ifdef HAVE_XAW3D
06a2c219 122#include <X11/Xaw3d/Simple.h>
06a2c219
GM
123#include <X11/Xaw3d/Scrollbar.h>
124#define ARROW_SCROLLBAR
125#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
126#else /* !HAVE_XAW3D */
127#include <X11/Xaw/Simple.h>
128#include <X11/Xaw/Scrollbar.h>
129#endif /* !HAVE_XAW3D */
130#ifndef XtNpickTop
131#define XtNpickTop "pickTop"
132#endif /* !XtNpickTop */
133#endif /* !USE_MOTIF */
06a2c219
GM
134#endif /* USE_TOOLKIT_SCROLL_BARS */
135
3afe33e7
RS
136#endif /* USE_X_TOOLKIT */
137
b849c413
RS
138#ifndef USE_X_TOOLKIT
139#define x_any_window_to_frame x_window_to_frame
5627c40e 140#define x_top_window_to_frame x_window_to_frame
b849c413
RS
141#endif
142
546e6d5b 143#ifdef USE_X_TOOLKIT
d067ea8b 144#include "widget.h"
546e6d5b
RS
145#ifndef XtNinitialState
146#define XtNinitialState "initialState"
147#endif
148#endif
149
80528801
KH
150#ifdef SOLARIS2
151/* memmove will be defined as a macro in Xfuncs.h unless
152 <string.h> is included beforehand. The declaration for memmove in
153 <string.h> will cause a syntax error when Xfuncs.h later includes it. */
154#include <string.h>
155#endif
156
e4b68333 157#ifndef min
06a2c219 158#define min(a,b) ((a) < (b) ? (a) : (b))
e4b68333
RS
159#endif
160#ifndef max
06a2c219
GM
161#define max(a,b) ((a) > (b) ? (a) : (b))
162#endif
163
164#define abs(x) ((x) < 0 ? -(x) : (x))
165
166#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
167
168\f
169/* Bitmaps for truncated lines. */
170
171enum bitmap_type
172{
173 NO_BITMAP,
174 LEFT_TRUNCATION_BITMAP,
175 RIGHT_TRUNCATION_BITMAP,
176 OVERLAY_ARROW_BITMAP,
177 CONTINUED_LINE_BITMAP,
178 CONTINUATION_LINE_BITMAP,
179 ZV_LINE_BITMAP
180};
181
182/* Bitmap drawn to indicate lines not displaying text if
183 `indicate-empty-lines' is non-nil. */
184
185#define zv_width 8
186#define zv_height 8
187static unsigned char zv_bits[] = {
188 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
189
190/* An arrow like this: `<-'. */
191
192#define left_width 8
193#define left_height 8
194static unsigned char left_bits[] = {
195 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
196
110859fc
GM
197/* Right truncation arrow bitmap `->'. */
198
199#define right_width 8
200#define right_height 8
201static unsigned char right_bits[] = {
202 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
203
06a2c219
GM
204/* Marker for continued lines. */
205
206#define continued_width 8
207#define continued_height 8
208static unsigned char continued_bits[] = {
110859fc
GM
209 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
210
211/* Marker for continuation lines. */
06a2c219
GM
212
213#define continuation_width 8
214#define continuation_height 8
215static unsigned char continuation_bits[] = {
110859fc 216 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 217
110859fc 218/* Overlay arrow bitmap. */
06a2c219 219
110859fc
GM
220#if 0
221/* A bomb. */
06a2c219
GM
222#define ov_width 8
223#define ov_height 8
224static unsigned char ov_bits[] = {
225 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 226#else
110859fc 227/* A triangular arrow. */
06a2c219
GM
228#define ov_width 8
229#define ov_height 8
230static unsigned char ov_bits[] = {
110859fc
GM
231 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
232
e4b68333 233#endif
06a2c219
GM
234
235extern Lisp_Object Qhelp_echo;
236
69388238 237\f
06a2c219
GM
238/* Non-zero means Emacs uses toolkit scroll bars. */
239
240int x_toolkit_scroll_bars_p;
241
242/* If a string, XTread_socket generates an event to display that string.
243 (The display is done in read_char.) */
244
245static Lisp_Object help_echo;
246
247/* Temporary variable for XTread_socket. */
248
249static Lisp_Object previous_help_echo;
250
251/* Non-zero means that a HELP_EVENT has been generated since Emacs
252 start. */
253
254static int any_help_event_p;
255
256/* Non-zero means draw block and hollow cursor as wide as the glyph
257 under it. For example, if a block cursor is over a tab, it will be
258 drawn as wide as that tab on the display. */
259
260int x_stretch_cursor_p;
261
262/* This is a chain of structures for all the X displays currently in
263 use. */
264
334208b7 265struct x_display_info *x_display_list;
dc6f92b8 266
06a2c219
GM
267/* This is a list of cons cells, each of the form (NAME
268 . FONT-LIST-CACHE), one for each element of x_display_list and in
269 the same order. NAME is the name of the frame. FONT-LIST-CACHE
270 records previous values returned by x-list-fonts. */
271
7a13e894 272Lisp_Object x_display_name_list;
f451eb13 273
987d2ad1 274/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
275 This is set by update_begin and looked at by all the XT functions.
276 It is zero while not inside an update. In that case, the XT
277 functions assume that `selected_frame' is the frame to apply to. */
278
d0386f2a 279extern struct frame *updating_frame;
dc6f92b8 280
dfcf069d 281extern int waiting_for_input;
0e81d8cd 282
06a2c219
GM
283/* This is a frame waiting to be auto-raised, within XTread_socket. */
284
0134a210
RS
285struct frame *pending_autoraise_frame;
286
7f9c7f94
RS
287#ifdef USE_X_TOOLKIT
288/* The application context for Xt use. */
289XtAppContext Xt_app_con;
06a2c219
GM
290static String Xt_default_resources[] = {0};
291#endif /* USE_X_TOOLKIT */
665881ad 292
06a2c219
GM
293/* Nominal cursor position -- where to draw output.
294 HPOS and VPOS are window relative glyph matrix coordinates.
295 X and Y are window relative pixel coordinates. */
dc6f92b8 296
06a2c219 297struct cursor_pos output_cursor;
dc6f92b8 298
bffcfca9
GM
299/* Non-zero means user is interacting with a toolkit scroll bar. */
300
301static int toolkit_scroll_bar_interaction;
dc6f92b8 302
69388238
RS
303/* Mouse movement.
304
06a2c219 305 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
306 so that we would have to call XQueryPointer after each MotionNotify
307 event to ask for another such event. However, this made mouse tracking
308 slow, and there was a bug that made it eventually stop.
309
310 Simply asking for MotionNotify all the time seems to work better.
311
69388238
RS
312 In order to avoid asking for motion events and then throwing most
313 of them away or busy-polling the server for mouse positions, we ask
314 the server for pointer motion hints. This means that we get only
315 one event per group of mouse movements. "Groups" are delimited by
316 other kinds of events (focus changes and button clicks, for
317 example), or by XQueryPointer calls; when one of these happens, we
318 get another MotionNotify event the next time the mouse moves. This
319 is at least as efficient as getting motion events when mouse
320 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 321 is off. */
69388238
RS
322
323/* Where the mouse was last time we reported a mouse event. */
69388238 324
06a2c219
GM
325FRAME_PTR last_mouse_frame;
326static XRectangle last_mouse_glyph;
2237cac9
RS
327static Lisp_Object last_mouse_press_frame;
328
69388238
RS
329/* The scroll bar in which the last X motion event occurred.
330
06a2c219
GM
331 If the last X motion event occurred in a scroll bar, we set this so
332 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
333 an ordinary motion.
334
06a2c219
GM
335 If the last X motion event didn't occur in a scroll bar, we set
336 this to Qnil, to tell XTmouse_position to return an ordinary motion
337 event. */
338
69388238
RS
339static Lisp_Object last_mouse_scroll_bar;
340
69388238
RS
341/* This is a hack. We would really prefer that XTmouse_position would
342 return the time associated with the position it returns, but there
06a2c219 343 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
344 along with the position query. So, we just keep track of the time
345 of the last movement we received, and return that in hopes that
346 it's somewhat accurate. */
06a2c219 347
69388238
RS
348static Time last_mouse_movement_time;
349
06a2c219
GM
350/* Incremented by XTread_socket whenever it really tries to read
351 events. */
352
c0a04927
RS
353#ifdef __STDC__
354static int volatile input_signal_count;
355#else
356static int input_signal_count;
357#endif
358
7a13e894 359/* Used locally within XTread_socket. */
06a2c219 360
7a13e894 361static int x_noop_count;
dc6f92b8 362
7a13e894 363/* Initial values of argv and argc. */
06a2c219 364
7a13e894
RS
365extern char **initial_argv;
366extern int initial_argc;
dc6f92b8 367
7a13e894 368extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 369
06a2c219 370/* Tells if a window manager is present or not. */
7a13e894
RS
371
372extern Lisp_Object Vx_no_window_manager;
dc6f92b8 373
c2df547c 374extern Lisp_Object Qface, Qmouse_face;
b8009dd1 375
dc6f92b8
JB
376extern int errno;
377
dfeccd2d 378/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 379
64bb1782
RS
380extern int extra_keyboard_modifiers;
381
59e755be
KH
382static Lisp_Object Qvendor_specific_keysyms;
383
334208b7 384extern XrmDatabase x_load_resources ();
c32cdd9a
KH
385extern Lisp_Object x_icon_type ();
386
7a13e894 387
06a2c219
GM
388/* Enumeration for overriding/changing the face to use for drawing
389 glyphs in x_draw_glyphs. */
390
391enum draw_glyphs_face
392{
393 DRAW_NORMAL_TEXT,
394 DRAW_INVERSE_VIDEO,
395 DRAW_CURSOR,
396 DRAW_MOUSE_FACE,
397 DRAW_IMAGE_RAISED,
398 DRAW_IMAGE_SUNKEN
399};
400
401static void x_update_window_end P_ ((struct window *, int));
402static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
403void x_delete_display P_ ((struct x_display_info *));
404static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
405 unsigned));
406static int fast_find_position P_ ((struct window *, int, int *, int *,
407 int *, int *));
408static void set_output_cursor P_ ((struct cursor_pos *));
409static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
410 int *, int *, int *));
411static void note_mode_line_highlight P_ ((struct window *, int, int));
06a2c219 412static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
413static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
414static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
415static void show_mouse_face P_ ((struct x_display_info *,
416 enum draw_glyphs_face));
417static int x_io_error_quitter P_ ((Display *));
418int x_catch_errors P_ ((Display *));
419void x_uncatch_errors P_ ((Display *, int));
420void x_lower_frame P_ ((struct frame *));
421void x_scroll_bar_clear P_ ((struct frame *));
422int x_had_errors_p P_ ((Display *));
423void x_wm_set_size_hint P_ ((struct frame *, long, int));
424void x_raise_frame P_ ((struct frame *));
425void x_set_window_size P_ ((struct frame *, int, int, int));
426void x_wm_set_window_state P_ ((struct frame *, int));
427void x_wm_set_icon_pixmap P_ ((struct frame *, int));
428void x_initialize P_ ((void));
429static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
430static int x_compute_min_glyph_bounds P_ ((struct frame *));
431static void x_draw_phys_cursor_glyph P_ ((struct window *,
432 struct glyph_row *,
433 enum draw_glyphs_face));
434static void x_update_end P_ ((struct frame *));
435static void XTframe_up_to_date P_ ((struct frame *));
436static void XTreassert_line_highlight P_ ((int, int));
437static void x_change_line_highlight P_ ((int, int, int, int));
438static void XTset_terminal_modes P_ ((void));
439static void XTreset_terminal_modes P_ ((void));
440static void XTcursor_to P_ ((int, int, int, int));
441static void x_write_glyphs P_ ((struct glyph *, int));
442static void x_clear_end_of_line P_ ((int));
443static void x_clear_frame P_ ((void));
444static void x_clear_cursor P_ ((struct window *));
445static void frame_highlight P_ ((struct frame *));
446static void frame_unhighlight P_ ((struct frame *));
447static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
448static void XTframe_rehighlight P_ ((struct frame *));
449static void x_frame_rehighlight P_ ((struct x_display_info *));
450static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 451static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
452static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
453 XRectangle *));
454static void expose_frame P_ ((struct frame *, int, int, int, int));
455static void expose_window_tree P_ ((struct window *, XRectangle *));
456static void expose_window P_ ((struct window *, XRectangle *));
457static void expose_area P_ ((struct window *, struct glyph_row *,
458 XRectangle *, enum glyph_row_area));
459static void expose_line P_ ((struct window *, struct glyph_row *,
460 XRectangle *));
461static void x_update_cursor_in_window_tree P_ ((struct window *, int));
462static void x_update_window_cursor P_ ((struct window *, int));
463static void x_erase_phys_cursor P_ ((struct window *));
464void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
465static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
466 enum bitmap_type));
467
468static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
469 GC, int));
470static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
471static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
472static void note_overwritten_text_cursor P_ ((struct window *, int, int));
473static void x_flush P_ ((struct frame *f));
474
475
476/* Flush display of frame F, or of all frames if F is null. */
477
478static void
479x_flush (f)
480 struct frame *f;
481{
482 BLOCK_INPUT;
483 if (f == NULL)
484 {
485 Lisp_Object rest, frame;
486 FOR_EACH_FRAME (rest, frame)
487 x_flush (XFRAME (frame));
488 }
489 else if (FRAME_X_P (f))
490 XFlush (FRAME_X_DISPLAY (f));
491 UNBLOCK_INPUT;
492}
493
dc6f92b8 494
06a2c219
GM
495/* Remove calls to XFlush by defining XFlush to an empty replacement.
496 Calls to XFlush should be unnecessary because the X output buffer
497 is flushed automatically as needed by calls to XPending,
498 XNextEvent, or XWindowEvent according to the XFlush man page.
499 XTread_socket calls XPending. Removing XFlush improves
500 performance. */
501
502#define XFlush(DISPLAY) (void) 0
b8009dd1 503
334208b7 504\f
06a2c219
GM
505/***********************************************************************
506 Debugging
507 ***********************************************************************/
508
9382638d 509#if 0
06a2c219
GM
510
511/* This is a function useful for recording debugging information about
512 the sequence of occurrences in this file. */
9382638d
KH
513
514struct record
515{
516 char *locus;
517 int type;
518};
519
520struct record event_record[100];
521
522int event_record_index;
523
524record_event (locus, type)
525 char *locus;
526 int type;
527{
528 if (event_record_index == sizeof (event_record) / sizeof (struct record))
529 event_record_index = 0;
530
531 event_record[event_record_index].locus = locus;
532 event_record[event_record_index].type = type;
533 event_record_index++;
534}
535
536#endif /* 0 */
06a2c219
GM
537
538
9382638d 539\f
334208b7
RS
540/* Return the struct x_display_info corresponding to DPY. */
541
542struct x_display_info *
543x_display_info_for_display (dpy)
544 Display *dpy;
545{
546 struct x_display_info *dpyinfo;
547
548 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
549 if (dpyinfo->display == dpy)
550 return dpyinfo;
16bd92ea 551
334208b7
RS
552 return 0;
553}
f451eb13 554
06a2c219
GM
555
556\f
557/***********************************************************************
558 Starting and ending an update
559 ***********************************************************************/
560
561/* Start an update of frame F. This function is installed as a hook
562 for update_begin, i.e. it is called when update_begin is called.
563 This function is called prior to calls to x_update_window_begin for
564 each window being updated. Currently, there is nothing to do here
565 because all interesting stuff is done on a window basis. */
dc6f92b8 566
dfcf069d 567static void
06a2c219 568x_update_begin (f)
f676886a 569 struct frame *f;
58769bee 570{
06a2c219
GM
571 /* Nothing to do. */
572}
dc6f92b8 573
dc6f92b8 574
06a2c219
GM
575/* Start update of window W. Set the global variable updated_window
576 to the window being updated and set output_cursor to the cursor
577 position of W. */
dc6f92b8 578
06a2c219
GM
579static void
580x_update_window_begin (w)
581 struct window *w;
582{
583 struct frame *f = XFRAME (WINDOW_FRAME (w));
584 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
585
586 updated_window = w;
587 set_output_cursor (&w->cursor);
b8009dd1 588
06a2c219 589 BLOCK_INPUT;
d1bc4182 590
06a2c219 591 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 592 {
514e4681 593 /* Don't do highlighting for mouse motion during the update. */
06a2c219 594 display_info->mouse_face_defer = 1;
37c2c98b 595
06a2c219
GM
596 /* If F needs to be redrawn, simply forget about any prior mouse
597 highlighting. */
9f67f20b 598 if (FRAME_GARBAGED_P (f))
06a2c219
GM
599 display_info->mouse_face_window = Qnil;
600
601 /* Can we tell that this update does not affect the window
602 where the mouse highlight is? If so, no need to turn off.
603 Likewise, don't do anything if the frame is garbaged;
604 in that case, the frame's current matrix that we would use
605 is all wrong, and we will redisplay that line anyway. */
606 if (!NILP (display_info->mouse_face_window)
607 && w == XWINDOW (display_info->mouse_face_window))
514e4681 608 {
06a2c219 609 int i;
514e4681 610
06a2c219
GM
611 for (i = 0; i < w->desired_matrix->nrows; ++i)
612 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
613 break;
614
06a2c219
GM
615 if (i < w->desired_matrix->nrows)
616 clear_mouse_face (display_info);
514e4681 617 }
b8009dd1 618 }
6ccf47d1 619
dc6f92b8
JB
620 UNBLOCK_INPUT;
621}
622
06a2c219
GM
623
624/* Draw a vertical window border to the right of window W if W doesn't
625 have vertical scroll bars. */
626
dfcf069d 627static void
06a2c219
GM
628x_draw_vertical_border (w)
629 struct window *w;
58769bee 630{
06a2c219
GM
631 struct frame *f = XFRAME (WINDOW_FRAME (w));
632
633 /* Redraw borders between horizontally adjacent windows. Don't
634 do it for frames with vertical scroll bars because either the
635 right scroll bar of a window, or the left scroll bar of its
636 neighbor will suffice as a border. */
637 if (!WINDOW_RIGHTMOST_P (w)
638 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
639 {
640 int x0, x1, y0, y1;
dc6f92b8 641
06a2c219 642 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 643 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
644 y1 -= 1;
645
646 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
647 f->output_data.x->normal_gc, x1, y0, x1, y1);
648 }
649}
650
651
652/* End update of window W (which is equal to updated_window). Draw
653 vertical borders between horizontally adjacent windows, and display
654 W's cursor if CURSOR_ON_P is non-zero. W may be a menu bar
655 pseudo-window in case we don't have X toolkit support. Such
656 windows don't have a cursor, so don't display it here. */
657
658static void
659x_update_window_end (w, cursor_on_p)
660 struct window *w;
661 int cursor_on_p;
662{
663 if (!w->pseudo_window_p)
664 {
665 BLOCK_INPUT;
666 if (cursor_on_p)
667 x_display_and_set_cursor (w, 1, output_cursor.hpos,
668 output_cursor.vpos,
669 output_cursor.x, output_cursor.y);
670 x_draw_vertical_border (w);
671 UNBLOCK_INPUT;
672 }
673
674 updated_window = NULL;
675}
dc6f92b8 676
dc6f92b8 677
06a2c219
GM
678/* End update of frame F. This function is installed as a hook in
679 update_end. */
680
681static void
682x_update_end (f)
683 struct frame *f;
684{
685 /* Mouse highlight may be displayed again. */
aa8bff2e 686 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 687
06a2c219 688 BLOCK_INPUT;
334208b7 689 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
690 UNBLOCK_INPUT;
691}
b8009dd1 692
06a2c219
GM
693
694/* This function is called from various places in xdisp.c whenever a
695 complete update has been performed. The global variable
696 updated_window is not available here. */
b8009dd1 697
dfcf069d 698static void
b8009dd1 699XTframe_up_to_date (f)
06a2c219 700 struct frame *f;
b8009dd1 701{
06a2c219 702 if (FRAME_X_P (f))
514e4681 703 {
06a2c219
GM
704 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
705 if (dpyinfo->mouse_face_deferred_gc
706 || f == dpyinfo->mouse_face_mouse_frame)
707 {
708 BLOCK_INPUT;
709 if (dpyinfo->mouse_face_mouse_frame)
710 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
711 dpyinfo->mouse_face_mouse_x,
712 dpyinfo->mouse_face_mouse_y);
713 dpyinfo->mouse_face_deferred_gc = 0;
714 UNBLOCK_INPUT;
715 }
514e4681 716 }
b8009dd1 717}
06a2c219
GM
718
719
720/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
721 arrow bitmaps, or clear the areas where they would be displayed
722 before DESIRED_ROW is made current. The window being updated is
723 found in updated_window. This function It is called from
724 update_window_line only if it is known that there are differences
725 between bitmaps to be drawn between current row and DESIRED_ROW. */
726
727static void
728x_after_update_window_line (desired_row)
729 struct glyph_row *desired_row;
730{
731 struct window *w = updated_window;
732
733 xassert (w);
734
735 if (!desired_row->mode_line_p && !w->pseudo_window_p)
736 {
737 BLOCK_INPUT;
738 x_draw_row_bitmaps (w, desired_row);
739
740 /* When a window has disappeared, make sure that no rest of
741 full-width rows stays visible in the internal border. */
742 if (windows_or_buffers_changed)
743 {
744 struct frame *f = XFRAME (w->frame);
745 int width = FRAME_INTERNAL_BORDER_WIDTH (f);
746 int height = desired_row->visible_height;
110859fc
GM
747 int x = (window_box_right (w, -1)
748 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
749 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
750
751 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
752 x, y, width, height, False);
753 }
754
755 UNBLOCK_INPUT;
756 }
757}
758
759
760/* Draw the bitmap WHICH in one of the areas to the left or right of
761 window W. ROW is the glyph row for which to display the bitmap; it
762 determines the vertical position at which the bitmap has to be
763 drawn. */
764
765static void
766x_draw_bitmap (w, row, which)
767 struct window *w;
768 struct glyph_row *row;
769 enum bitmap_type which;
770{
771 struct frame *f = XFRAME (WINDOW_FRAME (w));
772 Display *display = FRAME_X_DISPLAY (f);
773 Window window = FRAME_X_WINDOW (f);
774 int x, y, wd, h, dy;
775 unsigned char *bits;
776 Pixmap pixmap;
777 GC gc = f->output_data.x->normal_gc;
778 struct face *face;
779 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
780
781 /* Must clip because of partially visible lines. */
782 x_clip_to_row (w, row, gc, 1);
783
784 switch (which)
785 {
786 case LEFT_TRUNCATION_BITMAP:
787 wd = left_width;
788 h = left_height;
789 bits = left_bits;
790 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
791 - wd
110859fc 792 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
793 break;
794
795 case OVERLAY_ARROW_BITMAP:
796 wd = left_width;
797 h = left_height;
798 bits = ov_bits;
799 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
800 - wd
110859fc 801 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
802 break;
803
804 case RIGHT_TRUNCATION_BITMAP:
805 wd = right_width;
806 h = right_height;
807 bits = right_bits;
808 x = window_box_right (w, -1);
110859fc 809 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
810 break;
811
812 case CONTINUED_LINE_BITMAP:
813 wd = right_width;
814 h = right_height;
815 bits = continued_bits;
816 x = window_box_right (w, -1);
110859fc 817 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
818 break;
819
820 case CONTINUATION_LINE_BITMAP:
821 wd = continuation_width;
822 h = continuation_height;
823 bits = continuation_bits;
824 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
825 - wd
110859fc 826 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
827 break;
828
829 case ZV_LINE_BITMAP:
830 wd = zv_width;
831 h = zv_height;
832 bits = zv_bits;
833 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
834 - wd
110859fc 835 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
836 break;
837
838 default:
839 abort ();
840 }
841
842 /* Convert to frame coordinates. Set dy to the offset in the row to
843 start drawing the bitmap. */
844 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
845 dy = (row->height - h) / 2;
846
847 /* Draw the bitmap. I believe these small pixmaps can be cached
848 by the server. */
849 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
850 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
851 face->foreground,
852 face->background, depth);
853 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
854 XFreePixmap (display, pixmap);
855 XSetClipMask (display, gc, None);
856}
857
858
859/* Draw flags bitmaps for glyph row ROW on window W. Call this
860 function with input blocked. */
861
862static void
863x_draw_row_bitmaps (w, row)
864 struct window *w;
865 struct glyph_row *row;
866{
867 struct frame *f = XFRAME (w->frame);
868 enum bitmap_type bitmap;
869 struct face *face;
045dee35 870 int header_line_height = -1;
06a2c219
GM
871
872 xassert (interrupt_input_blocked);
873
874 /* If row is completely invisible, because of vscrolling, we
875 don't have to draw anything. */
876 if (row->visible_height <= 0)
877 return;
878
879 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
880 PREPARE_FACE_FOR_DISPLAY (f, face);
881
882 /* Decide which bitmap to draw at the left side. */
883 if (row->overlay_arrow_p)
884 bitmap = OVERLAY_ARROW_BITMAP;
885 else if (row->truncated_on_left_p)
886 bitmap = LEFT_TRUNCATION_BITMAP;
887 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
888 bitmap = CONTINUATION_LINE_BITMAP;
889 else if (row->indicate_empty_line_p)
890 bitmap = ZV_LINE_BITMAP;
891 else
892 bitmap = NO_BITMAP;
893
894 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
895 the flags area. */
896 if (bitmap == NO_BITMAP
110859fc 897 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
898 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
899 {
900 /* If W has a vertical border to its left, don't draw over it. */
901 int border = ((XFASTINT (w->left) > 0
902 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
903 ? 1 : 0);
904 int left = window_box_left (w, -1);
905
045dee35
GM
906 if (header_line_height < 0)
907 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
908
909 /* In case the same realized face is used for bitmap areas and
910 for something displayed in the text (e.g. face `region' on
911 mono-displays, the fill style may have been changed to
912 FillSolid in x_draw_glyph_string_background. */
913 if (face->stipple)
914 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
915 else
916 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
917
06a2c219
GM
918 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
919 face->gc,
920 (left
110859fc 921 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 922 + border),
045dee35 923 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 924 row->y)),
110859fc 925 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 926 row->visible_height);
dcd08bfb
GM
927 if (!face->stipple)
928 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
929 }
930
931 /* Draw the left bitmap. */
932 if (bitmap != NO_BITMAP)
933 x_draw_bitmap (w, row, bitmap);
934
935 /* Decide which bitmap to draw at the right side. */
936 if (row->truncated_on_right_p)
937 bitmap = RIGHT_TRUNCATION_BITMAP;
938 else if (row->continued_p)
939 bitmap = CONTINUED_LINE_BITMAP;
940 else
941 bitmap = NO_BITMAP;
942
943 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
944 the flags area. */
945 if (bitmap == NO_BITMAP
110859fc 946 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
947 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
948 {
949 int right = window_box_right (w, -1);
950
045dee35
GM
951 if (header_line_height < 0)
952 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
953
954 /* In case the same realized face is used for bitmap areas and
955 for something displayed in the text (e.g. face `region' on
956 mono-displays, the fill style may have been changed to
957 FillSolid in x_draw_glyph_string_background. */
958 if (face->stipple)
959 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
960 else
961 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
962 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
963 face->gc,
964 right,
045dee35 965 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 966 row->y)),
110859fc 967 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 968 row->visible_height);
dcd08bfb
GM
969 if (!face->stipple)
970 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
971 }
972
973 /* Draw the right bitmap. */
974 if (bitmap != NO_BITMAP)
975 x_draw_bitmap (w, row, bitmap);
976}
977
dc6f92b8 978\f
06a2c219
GM
979/***********************************************************************
980 Line Highlighting
981 ***********************************************************************/
dc6f92b8 982
06a2c219
GM
983/* External interface to control of standout mode. Not used for X
984 frames. Aborts when called. */
985
986static void
dc6f92b8
JB
987XTreassert_line_highlight (new, vpos)
988 int new, vpos;
989{
06a2c219 990 abort ();
dc6f92b8
JB
991}
992
06a2c219
GM
993
994/* Call this when about to modify line at position VPOS and change
995 whether it is highlighted. Not used for X frames. Aborts when
996 called. */
dc6f92b8 997
dfcf069d 998static void
06a2c219
GM
999x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1000 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1001{
06a2c219 1002 abort ();
dc6f92b8
JB
1003}
1004
06a2c219
GM
1005
1006/* This is called when starting Emacs and when restarting after
1007 suspend. When starting Emacs, no X window is mapped. And nothing
1008 must be done to Emacs's own window if it is suspended (though that
1009 rarely happens). */
dc6f92b8 1010
dfcf069d 1011static void
dc6f92b8
JB
1012XTset_terminal_modes ()
1013{
1014}
1015
06a2c219
GM
1016/* This is called when exiting or suspending Emacs. Exiting will make
1017 the X-windows go away, and suspending requires no action. */
dc6f92b8 1018
dfcf069d 1019static void
dc6f92b8
JB
1020XTreset_terminal_modes ()
1021{
dc6f92b8 1022}
06a2c219
GM
1023
1024
dc6f92b8 1025\f
06a2c219
GM
1026/***********************************************************************
1027 Output Cursor
1028 ***********************************************************************/
1029
1030/* Set the global variable output_cursor to CURSOR. All cursor
1031 positions are relative to updated_window. */
dc6f92b8 1032
dfcf069d 1033static void
06a2c219
GM
1034set_output_cursor (cursor)
1035 struct cursor_pos *cursor;
dc6f92b8 1036{
06a2c219
GM
1037 output_cursor.hpos = cursor->hpos;
1038 output_cursor.vpos = cursor->vpos;
1039 output_cursor.x = cursor->x;
1040 output_cursor.y = cursor->y;
1041}
1042
1043
1044/* Set a nominal cursor position.
dc6f92b8 1045
06a2c219
GM
1046 HPOS and VPOS are column/row positions in a window glyph matrix. X
1047 and Y are window text area relative pixel positions.
1048
1049 If this is done during an update, updated_window will contain the
1050 window that is being updated and the position is the future output
1051 cursor position for that window. If updated_window is null, use
1052 selected_window and display the cursor at the given position. */
1053
1054static void
1055XTcursor_to (vpos, hpos, y, x)
1056 int vpos, hpos, y, x;
1057{
1058 struct window *w;
1059
1060 /* If updated_window is not set, work on selected_window. */
1061 if (updated_window)
1062 w = updated_window;
1063 else
1064 w = XWINDOW (selected_window);
dbcb258a 1065
06a2c219
GM
1066 /* Set the output cursor. */
1067 output_cursor.hpos = hpos;
1068 output_cursor.vpos = vpos;
1069 output_cursor.x = x;
1070 output_cursor.y = y;
dc6f92b8 1071
06a2c219
GM
1072 /* If not called as part of an update, really display the cursor.
1073 This will also set the cursor position of W. */
1074 if (updated_window == NULL)
dc6f92b8
JB
1075 {
1076 BLOCK_INPUT;
06a2c219 1077 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1078 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1079 UNBLOCK_INPUT;
1080 }
1081}
dc43ef94 1082
06a2c219
GM
1083
1084\f
1085/***********************************************************************
1086 Display Iterator
1087 ***********************************************************************/
1088
1089/* Function prototypes of this page. */
1090
1091static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1092 struct glyph *,
ee569018
KH
1093 XChar2b *,
1094 int *));
06a2c219
GM
1095static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1096 int, XChar2b *, int));
1097static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1098static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1099static void x_append_glyph P_ ((struct it *));
b4192550 1100static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1101static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1102 int, int, double));
1103static void x_produce_glyphs P_ ((struct it *));
06a2c219 1104static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1105
1106
1107/* Return a pointer to per-char metric information in FONT of a
1108 character pointed by B which is a pointer to an XChar2b. */
1109
1110#define PER_CHAR_METRIC(font, b) \
1111 ((font)->per_char \
1112 ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
1113 + (((font)->min_byte1 || (font)->max_byte1) \
1114 ? (((b)->byte1 - (font)->min_byte1) \
1115 * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
1116 : 0)) \
1117 : &((font)->max_bounds))
dc43ef94 1118
dc6f92b8 1119
e2ef8ee6
GM
1120/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1121 is not contained in the font. */
dc43ef94 1122
06a2c219 1123static INLINE XCharStruct *
ee569018 1124x_per_char_metric (font, char2b)
06a2c219
GM
1125 XFontStruct *font;
1126 XChar2b *char2b;
1127{
1128 /* The result metric information. */
1129 XCharStruct *pcm = NULL;
dc6f92b8 1130
06a2c219 1131 xassert (font && char2b);
dc6f92b8 1132
06a2c219 1133 if (font->per_char != NULL)
dc6f92b8 1134 {
06a2c219 1135 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1136 {
06a2c219
GM
1137 /* min_char_or_byte2 specifies the linear character index
1138 corresponding to the first element of the per_char array,
1139 max_char_or_byte2 is the index of the last character. A
1140 character with non-zero CHAR2B->byte1 is not in the font.
1141 A character with byte2 less than min_char_or_byte2 or
1142 greater max_char_or_byte2 is not in the font. */
1143 if (char2b->byte1 == 0
1144 && char2b->byte2 >= font->min_char_or_byte2
1145 && char2b->byte2 <= font->max_char_or_byte2)
1146 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1147 }
06a2c219 1148 else
dc6f92b8 1149 {
06a2c219
GM
1150 /* If either min_byte1 or max_byte1 are nonzero, both
1151 min_char_or_byte2 and max_char_or_byte2 are less than
1152 256, and the 2-byte character index values corresponding
1153 to the per_char array element N (counting from 0) are:
1154
1155 byte1 = N/D + min_byte1
1156 byte2 = N\D + min_char_or_byte2
1157
1158 where:
1159
1160 D = max_char_or_byte2 - min_char_or_byte2 + 1
1161 / = integer division
1162 \ = integer modulus */
1163 if (char2b->byte1 >= font->min_byte1
1164 && char2b->byte1 <= font->max_byte1
1165 && char2b->byte2 >= font->min_char_or_byte2
1166 && char2b->byte2 <= font->max_char_or_byte2)
1167 {
1168 pcm = (font->per_char
1169 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1170 * (char2b->byte1 - font->min_byte1))
1171 + (char2b->byte2 - font->min_char_or_byte2));
1172 }
dc6f92b8 1173 }
06a2c219
GM
1174 }
1175 else
1176 {
1177 /* If the per_char pointer is null, all glyphs between the first
1178 and last character indexes inclusive have the same
1179 information, as given by both min_bounds and max_bounds. */
1180 if (char2b->byte2 >= font->min_char_or_byte2
1181 && char2b->byte2 <= font->max_char_or_byte2)
1182 pcm = &font->max_bounds;
1183 }
dc6f92b8 1184
ee569018 1185 return ((pcm == NULL
3e71d8f2 1186 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1187 ? NULL : pcm);
06a2c219 1188}
b73b6aaf 1189
57b03282 1190
06a2c219
GM
1191/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1192 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1193
06a2c219
GM
1194static INLINE void
1195x_encode_char (c, char2b, font_info)
1196 int c;
1197 XChar2b *char2b;
1198 struct font_info *font_info;
1199{
1200 int charset = CHAR_CHARSET (c);
1201 XFontStruct *font = font_info->font;
1202
1203 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1204 This may be either a program in a special encoder language or a
1205 fixed encoding. */
1206 if (font_info->font_encoder)
1207 {
1208 /* It's a program. */
1209 struct ccl_program *ccl = font_info->font_encoder;
1210
1211 if (CHARSET_DIMENSION (charset) == 1)
1212 {
1213 ccl->reg[0] = charset;
1214 ccl->reg[1] = char2b->byte2;
1215 }
1216 else
1217 {
1218 ccl->reg[0] = charset;
1219 ccl->reg[1] = char2b->byte1;
1220 ccl->reg[2] = char2b->byte2;
1221 }
1222
1223 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1224
1225 /* We assume that MSBs are appropriately set/reset by CCL
1226 program. */
1227 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1228 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1229 else
1230 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1231 }
1232 else if (font_info->encoding[charset])
1233 {
1234 /* Fixed encoding scheme. See fontset.h for the meaning of the
1235 encoding numbers. */
1236 int enc = font_info->encoding[charset];
1237
1238 if ((enc == 1 || enc == 2)
1239 && CHARSET_DIMENSION (charset) == 2)
1240 char2b->byte1 |= 0x80;
1241
1242 if (enc == 1 || enc == 3)
1243 char2b->byte2 |= 0x80;
1244 }
1245}
1246
1247
1248/* Get face and two-byte form of character C in face FACE_ID on frame
1249 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1250 means we want to display multibyte text. Value is a pointer to a
1251 realized face that is ready for display. */
1252
1253static INLINE struct face *
1254x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1255 struct frame *f;
1256 int c, face_id;
1257 XChar2b *char2b;
1258 int multibyte_p;
1259{
1260 struct face *face = FACE_FROM_ID (f, face_id);
1261
1262 if (!multibyte_p)
1263 {
1264 /* Unibyte case. We don't have to encode, but we have to make
1265 sure to use a face suitable for unibyte. */
1266 char2b->byte1 = 0;
1267 char2b->byte2 = c;
ee569018
KH
1268 face_id = FACE_FOR_CHAR (f, face, c);
1269 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1270 }
1271 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1272 {
1273 /* Case of ASCII in a face known to fit ASCII. */
1274 char2b->byte1 = 0;
1275 char2b->byte2 = c;
1276 }
1277 else
1278 {
1279 int c1, c2, charset;
1280
1281 /* Split characters into bytes. If c2 is -1 afterwards, C is
1282 really a one-byte character so that byte1 is zero. */
1283 SPLIT_CHAR (c, charset, c1, c2);
1284 if (c2 > 0)
1285 char2b->byte1 = c1, char2b->byte2 = c2;
1286 else
1287 char2b->byte1 = 0, char2b->byte2 = c1;
1288
06a2c219 1289 /* Maybe encode the character in *CHAR2B. */
ee569018 1290 if (face->font != NULL)
06a2c219
GM
1291 {
1292 struct font_info *font_info
1293 = FONT_INFO_FROM_ID (f, face->font_info_id);
1294 if (font_info)
ee569018 1295 x_encode_char (c, char2b, font_info);
06a2c219
GM
1296 }
1297 }
1298
1299 /* Make sure X resources of the face are allocated. */
1300 xassert (face != NULL);
1301 PREPARE_FACE_FOR_DISPLAY (f, face);
1302
1303 return face;
1304}
1305
1306
1307/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1308 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1309 a pointer to a realized face that is ready for display. */
1310
1311static INLINE struct face *
ee569018 1312x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1313 struct frame *f;
1314 struct glyph *glyph;
1315 XChar2b *char2b;
ee569018 1316 int *two_byte_p;
06a2c219
GM
1317{
1318 struct face *face;
1319
1320 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1321 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1322
ee569018
KH
1323 if (two_byte_p)
1324 *two_byte_p = 0;
1325
06a2c219
GM
1326 if (!glyph->multibyte_p)
1327 {
1328 /* Unibyte case. We don't have to encode, but we have to make
1329 sure to use a face suitable for unibyte. */
1330 char2b->byte1 = 0;
43d120d8 1331 char2b->byte2 = glyph->u.ch;
06a2c219 1332 }
43d120d8
KH
1333 else if (glyph->u.ch < 128
1334 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1335 {
1336 /* Case of ASCII in a face known to fit ASCII. */
1337 char2b->byte1 = 0;
43d120d8 1338 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1339 }
1340 else
1341 {
1342 int c1, c2, charset;
1343
1344 /* Split characters into bytes. If c2 is -1 afterwards, C is
1345 really a one-byte character so that byte1 is zero. */
43d120d8 1346 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1347 if (c2 > 0)
1348 char2b->byte1 = c1, char2b->byte2 = c2;
1349 else
1350 char2b->byte1 = 0, char2b->byte2 = c1;
1351
1352 /* Maybe encode the character in *CHAR2B. */
1353 if (charset != CHARSET_ASCII)
1354 {
1355 struct font_info *font_info
1356 = FONT_INFO_FROM_ID (f, face->font_info_id);
1357 if (font_info)
1358 {
43d120d8 1359 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1360 if (two_byte_p)
1361 *two_byte_p
1362 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1363 }
1364 }
1365 }
1366
1367 /* Make sure X resources of the face are allocated. */
1368 xassert (face != NULL);
1369 PREPARE_FACE_FOR_DISPLAY (f, face);
1370 return face;
1371}
1372
1373
1374/* Store one glyph for IT->char_to_display in IT->glyph_row.
1375 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1376
1377static INLINE void
1378x_append_glyph (it)
1379 struct it *it;
1380{
1381 struct glyph *glyph;
1382 enum glyph_row_area area = it->area;
1383
1384 xassert (it->glyph_row);
1385 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1386
1387 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1388 if (glyph < it->glyph_row->glyphs[area + 1])
1389 {
06a2c219
GM
1390 glyph->charpos = CHARPOS (it->position);
1391 glyph->object = it->object;
88d75730 1392 glyph->pixel_width = it->pixel_width;
06a2c219 1393 glyph->voffset = it->voffset;
88d75730 1394 glyph->type = CHAR_GLYPH;
06a2c219 1395 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1396 glyph->left_box_line_p = it->start_of_box_run_p;
1397 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1398 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1399 || it->phys_descent > it->descent);
88d75730 1400 glyph->padding_p = 0;
ee569018 1401 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1402 glyph->face_id = it->face_id;
1403 glyph->u.ch = it->char_to_display;
06a2c219
GM
1404 ++it->glyph_row->used[area];
1405 }
1406}
1407
b4192550
KH
1408/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1409 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1410
1411static INLINE void
1412x_append_composite_glyph (it)
1413 struct it *it;
1414{
1415 struct glyph *glyph;
1416 enum glyph_row_area area = it->area;
1417
1418 xassert (it->glyph_row);
1419
1420 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1421 if (glyph < it->glyph_row->glyphs[area + 1])
1422 {
b4192550
KH
1423 glyph->charpos = CHARPOS (it->position);
1424 glyph->object = it->object;
88d75730 1425 glyph->pixel_width = it->pixel_width;
b4192550 1426 glyph->voffset = it->voffset;
88d75730 1427 glyph->type = COMPOSITE_GLYPH;
b4192550 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;
b4192550
KH
1431 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1432 || it->phys_descent > it->descent);
88d75730
GM
1433 glyph->padding_p = 0;
1434 glyph->glyph_not_available_p = 0;
1435 glyph->face_id = it->face_id;
1436 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1437 ++it->glyph_row->used[area];
1438 }
1439}
1440
06a2c219
GM
1441
1442/* Change IT->ascent and IT->height according to the setting of
1443 IT->voffset. */
1444
1445static INLINE void
1446take_vertical_position_into_account (it)
1447 struct it *it;
1448{
1449 if (it->voffset)
1450 {
1451 if (it->voffset < 0)
1452 /* Increase the ascent so that we can display the text higher
1453 in the line. */
1454 it->ascent += abs (it->voffset);
1455 else
1456 /* Increase the descent so that we can display the text lower
1457 in the line. */
1458 it->descent += it->voffset;
1459 }
1460}
1461
1462
1463/* Produce glyphs/get display metrics for the image IT is loaded with.
1464 See the description of struct display_iterator in dispextern.h for
1465 an overview of struct display_iterator. */
1466
1467static void
1468x_produce_image_glyph (it)
1469 struct it *it;
1470{
1471 struct image *img;
1472 struct face *face;
1473
1474 xassert (it->what == IT_IMAGE);
1475
1476 face = FACE_FROM_ID (it->f, it->face_id);
1477 img = IMAGE_FROM_ID (it->f, it->image_id);
1478 xassert (img);
1479
1480 /* Make sure X resources of the face and image are loaded. */
1481 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1482 prepare_image_for_display (it->f, img);
1483
95af8492 1484 it->ascent = it->phys_ascent = image_ascent (img, face);
66ac4b0e 1485 it->descent = it->phys_descent = img->height + 2 * img->margin - it->ascent;
06a2c219
GM
1486 it->pixel_width = img->width + 2 * img->margin;
1487
1488 it->nglyphs = 1;
1489
1490 if (face->box != FACE_NO_BOX)
1491 {
1492 it->ascent += face->box_line_width;
1493 it->descent += face->box_line_width;
1494
1495 if (it->start_of_box_run_p)
1496 it->pixel_width += face->box_line_width;
1497 if (it->end_of_box_run_p)
1498 it->pixel_width += face->box_line_width;
1499 }
1500
1501 take_vertical_position_into_account (it);
1502
1503 if (it->glyph_row)
1504 {
1505 struct glyph *glyph;
1506 enum glyph_row_area area = it->area;
1507
1508 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1509 if (glyph < it->glyph_row->glyphs[area + 1])
1510 {
06a2c219
GM
1511 glyph->charpos = CHARPOS (it->position);
1512 glyph->object = it->object;
88d75730 1513 glyph->pixel_width = it->pixel_width;
06a2c219 1514 glyph->voffset = it->voffset;
88d75730 1515 glyph->type = IMAGE_GLYPH;
06a2c219 1516 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1517 glyph->left_box_line_p = it->start_of_box_run_p;
1518 glyph->right_box_line_p = it->end_of_box_run_p;
1519 glyph->overlaps_vertically_p = 0;
1520 glyph->padding_p = 0;
1521 glyph->glyph_not_available_p = 0;
1522 glyph->face_id = it->face_id;
1523 glyph->u.img_id = img->id;
06a2c219
GM
1524 ++it->glyph_row->used[area];
1525 }
1526 }
1527}
1528
1529
1530/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1531 of the glyph, WIDTH and HEIGHT are the width and height of the
1532 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1533 ascent of the glyph (0 <= ASCENT <= 1). */
1534
1535static void
1536x_append_stretch_glyph (it, object, width, height, ascent)
1537 struct it *it;
1538 Lisp_Object object;
1539 int width, height;
1540 double ascent;
1541{
1542 struct glyph *glyph;
1543 enum glyph_row_area area = it->area;
1544
1545 xassert (ascent >= 0 && ascent <= 1);
1546
1547 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1548 if (glyph < it->glyph_row->glyphs[area + 1])
1549 {
06a2c219
GM
1550 glyph->charpos = CHARPOS (it->position);
1551 glyph->object = object;
88d75730 1552 glyph->pixel_width = width;
06a2c219 1553 glyph->voffset = it->voffset;
88d75730 1554 glyph->type = STRETCH_GLYPH;
06a2c219 1555 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1556 glyph->left_box_line_p = it->start_of_box_run_p;
1557 glyph->right_box_line_p = it->end_of_box_run_p;
1558 glyph->overlaps_vertically_p = 0;
1559 glyph->padding_p = 0;
1560 glyph->glyph_not_available_p = 0;
1561 glyph->face_id = it->face_id;
1562 glyph->u.stretch.ascent = height * ascent;
1563 glyph->u.stretch.height = height;
06a2c219
GM
1564 ++it->glyph_row->used[area];
1565 }
1566}
1567
1568
1569/* Produce a stretch glyph for iterator IT. IT->object is the value
1570 of the glyph property displayed. The value must be a list
1571 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1572 being recognized:
1573
1574 1. `:width WIDTH' specifies that the space should be WIDTH *
1575 canonical char width wide. WIDTH may be an integer or floating
1576 point number.
1577
1578 2. `:relative-width FACTOR' specifies that the width of the stretch
1579 should be computed from the width of the first character having the
1580 `glyph' property, and should be FACTOR times that width.
1581
1582 3. `:align-to HPOS' specifies that the space should be wide enough
1583 to reach HPOS, a value in canonical character units.
1584
1585 Exactly one of the above pairs must be present.
1586
1587 4. `:height HEIGHT' specifies that the height of the stretch produced
1588 should be HEIGHT, measured in canonical character units.
1589
1590 5. `:relative-height FACTOR' specifies that the height of the the
1591 stretch should be FACTOR times the height of the characters having
1592 the glyph property.
1593
1594 Either none or exactly one of 4 or 5 must be present.
1595
1596 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1597 of the stretch should be used for the ascent of the stretch.
1598 ASCENT must be in the range 0 <= ASCENT <= 100. */
1599
1600#define NUMVAL(X) \
1601 ((INTEGERP (X) || FLOATP (X)) \
1602 ? XFLOATINT (X) \
1603 : - 1)
1604
1605
1606static void
1607x_produce_stretch_glyph (it)
1608 struct it *it;
1609{
1610 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1611#if GLYPH_DEBUG
1612 extern Lisp_Object Qspace;
1613#endif
1614 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1615 extern Lisp_Object QCrelative_width, QCrelative_height;
1616 extern Lisp_Object QCalign_to;
1617 Lisp_Object prop, plist;
1618 double width = 0, height = 0, ascent = 0;
1619 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1620 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1621
1622 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1623
1624 /* List should start with `space'. */
1625 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1626 plist = XCDR (it->object);
1627
1628 /* Compute the width of the stretch. */
1629 if (prop = Fplist_get (plist, QCwidth),
1630 NUMVAL (prop) > 0)
1631 /* Absolute width `:width WIDTH' specified and valid. */
1632 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1633 else if (prop = Fplist_get (plist, QCrelative_width),
1634 NUMVAL (prop) > 0)
1635 {
1636 /* Relative width `:relative-width FACTOR' specified and valid.
1637 Compute the width of the characters having the `glyph'
1638 property. */
1639 struct it it2;
1640 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1641
1642 it2 = *it;
1643 if (it->multibyte_p)
1644 {
1645 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1646 - IT_BYTEPOS (*it));
1647 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1648 }
1649 else
1650 it2.c = *p, it2.len = 1;
1651
1652 it2.glyph_row = NULL;
1653 it2.what = IT_CHARACTER;
1654 x_produce_glyphs (&it2);
1655 width = NUMVAL (prop) * it2.pixel_width;
1656 }
1657 else if (prop = Fplist_get (plist, QCalign_to),
1658 NUMVAL (prop) > 0)
1659 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1660 else
1661 /* Nothing specified -> width defaults to canonical char width. */
1662 width = CANON_X_UNIT (it->f);
1663
1664 /* Compute height. */
1665 if (prop = Fplist_get (plist, QCheight),
1666 NUMVAL (prop) > 0)
1667 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1668 else if (prop = Fplist_get (plist, QCrelative_height),
1669 NUMVAL (prop) > 0)
1670 height = FONT_HEIGHT (font) * NUMVAL (prop);
1671 else
1672 height = FONT_HEIGHT (font);
1673
1674 /* Compute percentage of height used for ascent. If
1675 `:ascent ASCENT' is present and valid, use that. Otherwise,
1676 derive the ascent from the font in use. */
1677 if (prop = Fplist_get (plist, QCascent),
1678 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1679 ascent = NUMVAL (prop) / 100.0;
1680 else
1681 ascent = (double) font->ascent / FONT_HEIGHT (font);
1682
1683 if (width <= 0)
1684 width = 1;
1685 if (height <= 0)
1686 height = 1;
1687
1688 if (it->glyph_row)
1689 {
1690 Lisp_Object object = it->stack[it->sp - 1].string;
1691 if (!STRINGP (object))
1692 object = it->w->buffer;
1693 x_append_stretch_glyph (it, object, width, height, ascent);
1694 }
1695
1696 it->pixel_width = width;
66ac4b0e
GM
1697 it->ascent = it->phys_ascent = height * ascent;
1698 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1699 it->nglyphs = 1;
1700
1701 if (face->box != FACE_NO_BOX)
1702 {
1703 it->ascent += face->box_line_width;
1704 it->descent += face->box_line_width;
1705
1706 if (it->start_of_box_run_p)
1707 it->pixel_width += face->box_line_width;
1708 if (it->end_of_box_run_p)
1709 it->pixel_width += face->box_line_width;
1710 }
1711
1712 take_vertical_position_into_account (it);
1713}
1714
b4192550
KH
1715/* Return proper value to be used as baseline offset of font that has
1716 ASCENT and DESCENT to draw characters by the font at the vertical
1717 center of the line of frame F.
1718
1719 Here, out task is to find the value of BOFF in the following figure;
1720
1721 -------------------------+-----------+-
1722 -+-+---------+-+ | |
1723 | | | | | |
1724 | | | | F_ASCENT F_HEIGHT
1725 | | | ASCENT | |
1726 HEIGHT | | | | |
1727 | | |-|-+------+-----------|------- baseline
1728 | | | | BOFF | |
1729 | |---------|-+-+ | |
1730 | | | DESCENT | |
1731 -+-+---------+-+ F_DESCENT |
1732 -------------------------+-----------+-
1733
1734 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1735 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1736 DESCENT = FONT->descent
1737 HEIGHT = FONT_HEIGHT (FONT)
1738 F_DESCENT = (F->output_data.x->font->descent
1739 - F->output_data.x->baseline_offset)
1740 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1741*/
1742
1743#define VCENTER_BASELINE_OFFSET(FONT, F) \
1744 ((FONT)->descent \
1745 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT))) / 2 \
1746 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1747
1748/* Produce glyphs/get display metrics for the display element IT is
1749 loaded with. See the description of struct display_iterator in
1750 dispextern.h for an overview of struct display_iterator. */
1751
1752static void
1753x_produce_glyphs (it)
1754 struct it *it;
1755{
ee569018
KH
1756 it->glyph_not_available_p = 0;
1757
06a2c219
GM
1758 if (it->what == IT_CHARACTER)
1759 {
1760 XChar2b char2b;
1761 XFontStruct *font;
ee569018 1762 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1763 XCharStruct *pcm;
06a2c219 1764 int font_not_found_p;
b4192550
KH
1765 struct font_info *font_info;
1766 int boff; /* baseline offset */
06a2c219 1767
ee569018
KH
1768 /* Maybe translate single-byte characters to multibyte, or the
1769 other way. */
06a2c219 1770 it->char_to_display = it->c;
ee569018 1771 if (!ASCII_BYTE_P (it->c))
06a2c219 1772 {
ee569018
KH
1773 if (unibyte_display_via_language_environment
1774 && SINGLE_BYTE_CHAR_P (it->c)
1775 && (it->c >= 0240
1776 || !NILP (Vnonascii_translation_table)))
1777 {
1778 it->char_to_display = unibyte_char_to_multibyte (it->c);
1779 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1780 face = FACE_FROM_ID (it->f, it->face_id);
1781 }
1782 else if (!SINGLE_BYTE_CHAR_P (it->c)
1783 && !it->multibyte_p)
1784 {
1785 it->char_to_display = multibyte_char_to_unibyte (it->c, Qnil);
1786 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1787 face = FACE_FROM_ID (it->f, it->face_id);
1788 }
06a2c219
GM
1789 }
1790
ee569018
KH
1791 /* Get font to use. Encode IT->char_to_display. */
1792 x_get_char_face_and_encoding (it->f, it->char_to_display,
1793 it->face_id, &char2b,
1794 it->multibyte_p);
06a2c219
GM
1795 font = face->font;
1796
1797 /* When no suitable font found, use the default font. */
1798 font_not_found_p = font == NULL;
1799 if (font_not_found_p)
b4192550
KH
1800 {
1801 font = FRAME_FONT (it->f);
1802 boff = it->f->output_data.x->baseline_offset;
1803 font_info = NULL;
1804 }
1805 else
1806 {
1807 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1808 boff = font_info->baseline_offset;
1809 if (font_info->vertical_centering)
1810 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1811 }
06a2c219
GM
1812
1813 if (it->char_to_display >= ' '
1814 && (!it->multibyte_p || it->char_to_display < 128))
1815 {
1816 /* Either unibyte or ASCII. */
1817 int stretched_p;
1818
1819 it->nglyphs = 1;
06a2c219
GM
1820
1821 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1822 it->ascent = font->ascent + boff;
1823 it->descent = font->descent - boff;
474848ac
GM
1824
1825 if (pcm)
1826 {
1827 it->phys_ascent = pcm->ascent + boff;
1828 it->phys_descent = pcm->descent - boff;
1829 it->pixel_width = pcm->width;
1830 }
1831 else
1832 {
1833 it->glyph_not_available_p = 1;
1834 it->phys_ascent = font->ascent + boff;
1835 it->phys_descent = font->descent - boff;
1836 it->pixel_width = FONT_WIDTH (font);
1837 }
06a2c219
GM
1838
1839 /* If this is a space inside a region of text with
1840 `space-width' property, change its width. */
1841 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1842 if (stretched_p)
1843 it->pixel_width *= XFLOATINT (it->space_width);
1844
1845 /* If face has a box, add the box thickness to the character
1846 height. If character has a box line to the left and/or
1847 right, add the box line width to the character's width. */
1848 if (face->box != FACE_NO_BOX)
1849 {
1850 int thick = face->box_line_width;
1851
1852 it->ascent += thick;
1853 it->descent += thick;
1854
1855 if (it->start_of_box_run_p)
1856 it->pixel_width += thick;
1857 if (it->end_of_box_run_p)
1858 it->pixel_width += thick;
1859 }
1860
1861 /* If face has an overline, add the height of the overline
1862 (1 pixel) and a 1 pixel margin to the character height. */
1863 if (face->overline_p)
1864 it->ascent += 2;
1865
1866 take_vertical_position_into_account (it);
1867
1868 /* If we have to actually produce glyphs, do it. */
1869 if (it->glyph_row)
1870 {
1871 if (stretched_p)
1872 {
1873 /* Translate a space with a `space-width' property
1874 into a stretch glyph. */
1875 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1876 x_append_stretch_glyph (it, it->object, it->pixel_width,
1877 it->ascent + it->descent, ascent);
1878 }
1879 else
1880 x_append_glyph (it);
1881
1882 /* If characters with lbearing or rbearing are displayed
1883 in this line, record that fact in a flag of the
1884 glyph row. This is used to optimize X output code. */
1c7e22fd 1885 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1886 it->glyph_row->contains_overlapping_glyphs_p = 1;
1887 }
1888 }
1889 else if (it->char_to_display == '\n')
1890 {
1891 /* A newline has no width but we need the height of the line. */
1892 it->pixel_width = 0;
1893 it->nglyphs = 0;
b4192550
KH
1894 it->ascent = it->phys_ascent = font->ascent + boff;
1895 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1896
1897 if (face->box != FACE_NO_BOX)
1898 {
1899 int thick = face->box_line_width;
1900 it->ascent += thick;
1901 it->descent += thick;
1902 }
1903 }
1904 else if (it->char_to_display == '\t')
1905 {
1906 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1907 int x = it->current_x + it->continuation_lines_width;
06a2c219
GM
1908 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
1909
1910 it->pixel_width = next_tab_x - x;
1911 it->nglyphs = 1;
b4192550
KH
1912 it->ascent = it->phys_ascent = font->ascent + boff;
1913 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1914
1915 if (it->glyph_row)
1916 {
1917 double ascent = (double) it->ascent / (it->ascent + it->descent);
1918 x_append_stretch_glyph (it, it->object, it->pixel_width,
1919 it->ascent + it->descent, ascent);
1920 }
1921 }
1922 else
1923 {
1924 /* A multi-byte character. Assume that the display width of the
1925 character is the width of the character multiplied by the
b4192550 1926 width of the font. */
06a2c219 1927
b4192550
KH
1928 /* If we found a font, this font should give us the right
1929 metrics. If we didn't find a font, use the frame's
1930 default font and calculate the width of the character
1931 from the charset width; this is what old redisplay code
1932 did. */
1933 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1934 if (font_not_found_p || !pcm)
1935 {
1936 int charset = CHAR_CHARSET (it->char_to_display);
1937
1938 it->glyph_not_available_p = 1;
1939 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
1940 * CHARSET_WIDTH (charset));
1941 it->phys_ascent = font->ascent + boff;
1942 it->phys_descent = font->descent - boff;
1943 }
1944 else
1945 {
1946 it->pixel_width = pcm->width;
1947 it->phys_ascent = pcm->ascent + boff;
1948 it->phys_descent = pcm->descent - boff;
1949 if (it->glyph_row
1950 && (pcm->lbearing < 0
1951 || pcm->rbearing > pcm->width))
1952 it->glyph_row->contains_overlapping_glyphs_p = 1;
1953 }
b4192550
KH
1954 it->nglyphs = 1;
1955 it->ascent = font->ascent + boff;
1956 it->descent = font->descent - boff;
06a2c219
GM
1957 if (face->box != FACE_NO_BOX)
1958 {
1959 int thick = face->box_line_width;
1960 it->ascent += thick;
1961 it->descent += thick;
1962
1963 if (it->start_of_box_run_p)
1964 it->pixel_width += thick;
1965 if (it->end_of_box_run_p)
1966 it->pixel_width += thick;
1967 }
1968
1969 /* If face has an overline, add the height of the overline
1970 (1 pixel) and a 1 pixel margin to the character height. */
1971 if (face->overline_p)
1972 it->ascent += 2;
1973
1974 take_vertical_position_into_account (it);
1975
1976 if (it->glyph_row)
1977 x_append_glyph (it);
1978 }
1979 }
b4192550
KH
1980 else if (it->what == IT_COMPOSITION)
1981 {
1982 /* Note: A composition is represented as one glyph in the
1983 glyph matrix. There are no padding glyphs. */
1984 XChar2b char2b;
1985 XFontStruct *font;
ee569018 1986 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
1987 XCharStruct *pcm;
1988 int font_not_found_p;
1989 struct font_info *font_info;
1990 int boff; /* baseline offset */
1991 struct composition *cmp = composition_table[it->cmp_id];
1992
1993 /* Maybe translate single-byte characters to multibyte. */
1994 it->char_to_display = it->c;
1995 if (unibyte_display_via_language_environment
1996 && SINGLE_BYTE_CHAR_P (it->c)
1997 && (it->c >= 0240
1998 || (it->c >= 0200
1999 && !NILP (Vnonascii_translation_table))))
2000 {
2001 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2002 }
2003
2004 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2005 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2006 face = FACE_FROM_ID (it->f, it->face_id);
2007 x_get_char_face_and_encoding (it->f, it->char_to_display,
2008 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2009 font = face->font;
2010
2011 /* When no suitable font found, use the default font. */
2012 font_not_found_p = font == NULL;
2013 if (font_not_found_p)
2014 {
2015 font = FRAME_FONT (it->f);
2016 boff = it->f->output_data.x->baseline_offset;
2017 font_info = NULL;
2018 }
2019 else
2020 {
2021 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2022 boff = font_info->baseline_offset;
2023 if (font_info->vertical_centering)
2024 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2025 }
2026
2027 /* There are no padding glyphs, so there is only one glyph to
2028 produce for the composition. Important is that pixel_width,
2029 ascent and descent are the values of what is drawn by
2030 draw_glyphs (i.e. the values of the overall glyphs composed). */
2031 it->nglyphs = 1;
2032
2033 /* If we have not yet calculated pixel size data of glyphs of
2034 the composition for the current face font, calculate them
2035 now. Theoretically, we have to check all fonts for the
2036 glyphs, but that requires much time and memory space. So,
2037 here we check only the font of the first glyph. This leads
2038 to incorrect display very rarely, and C-l (recenter) can
2039 correct the display anyway. */
2040 if (cmp->font != (void *) font)
2041 {
2042 /* Ascent and descent of the font of the first character of
2043 this composition (adjusted by baseline offset). Ascent
2044 and descent of overall glyphs should not be less than
2045 them respectively. */
2046 int font_ascent = font->ascent + boff;
2047 int font_descent = font->descent - boff;
2048 /* Bounding box of the overall glyphs. */
2049 int leftmost, rightmost, lowest, highest;
329bed06 2050 int i, width, ascent, descent;
b4192550
KH
2051
2052 cmp->font = (void *) font;
2053
2054 /* Initialize the bounding box. */
2055 pcm = x_per_char_metric (font, &char2b);
329bed06
GM
2056 if (pcm)
2057 {
2058 width = pcm->width;
2059 ascent = pcm->ascent;
2060 descent = pcm->descent;
2061 }
2062 else
2063 {
2064 width = FONT_WIDTH (font);
2065 ascent = font->ascent;
2066 descent = font->descent;
2067 }
2068
2069 rightmost = width;
2070 lowest = - descent + boff;
2071 highest = ascent + boff;
b4192550 2072 leftmost = 0;
329bed06 2073
b4192550
KH
2074 if (font_info
2075 && font_info->default_ascent
2076 && CHAR_TABLE_P (Vuse_default_ascent)
2077 && !NILP (Faref (Vuse_default_ascent,
2078 make_number (it->char_to_display))))
2079 highest = font_info->default_ascent + boff;
2080
2081 /* Draw the first glyph at the normal position. It may be
2082 shifted to right later if some other glyphs are drawn at
2083 the left. */
2084 cmp->offsets[0] = 0;
2085 cmp->offsets[1] = boff;
2086
2087 /* Set cmp->offsets for the remaining glyphs. */
2088 for (i = 1; i < cmp->glyph_len; i++)
2089 {
2090 int left, right, btm, top;
2091 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2092 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2093
2094 face = FACE_FROM_ID (it->f, face_id);
2095 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2096 it->multibyte_p);
b4192550
KH
2097 font = face->font;
2098 if (font == NULL)
2099 {
2100 font = FRAME_FONT (it->f);
2101 boff = it->f->output_data.x->baseline_offset;
2102 font_info = NULL;
2103 }
2104 else
2105 {
2106 font_info
2107 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2108 boff = font_info->baseline_offset;
2109 if (font_info->vertical_centering)
2110 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2111 }
2112
2113 pcm = x_per_char_metric (font, &char2b);
329bed06
GM
2114 if (pcm)
2115 {
2116 width = pcm->width;
2117 ascent = pcm->ascent;
2118 descent = pcm->descent;
2119 }
2120 else
2121 {
2122 width = FONT_WIDTH (font);
2123 ascent = font->ascent;
2124 descent = font->descent;
2125 }
b4192550
KH
2126
2127 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2128 {
2129 /* Relative composition with or without
2130 alternate chars. */
329bed06
GM
2131 left = (leftmost + rightmost - width) / 2;
2132 btm = - descent + boff;
b4192550
KH
2133 if (font_info && font_info->relative_compose
2134 && (! CHAR_TABLE_P (Vignore_relative_composition)
2135 || NILP (Faref (Vignore_relative_composition,
2136 make_number (ch)))))
2137 {
2138
329bed06 2139 if (- descent >= font_info->relative_compose)
b4192550
KH
2140 /* One extra pixel between two glyphs. */
2141 btm = highest + 1;
329bed06 2142 else if (ascent <= 0)
b4192550 2143 /* One extra pixel between two glyphs. */
329bed06 2144 btm = lowest - 1 - ascent - descent;
b4192550
KH
2145 }
2146 }
2147 else
2148 {
2149 /* A composition rule is specified by an integer
2150 value that encodes global and new reference
2151 points (GREF and NREF). GREF and NREF are
2152 specified by numbers as below:
2153
2154 0---1---2 -- ascent
2155 | |
2156 | |
2157 | |
2158 9--10--11 -- center
2159 | |
2160 ---3---4---5--- baseline
2161 | |
2162 6---7---8 -- descent
2163 */
2164 int rule = COMPOSITION_RULE (cmp, i);
2165 int gref, nref, grefx, grefy, nrefx, nrefy;
2166
2167 COMPOSITION_DECODE_RULE (rule, gref, nref);
2168 grefx = gref % 3, nrefx = nref % 3;
2169 grefy = gref / 3, nrefy = nref / 3;
2170
2171 left = (leftmost
2172 + grefx * (rightmost - leftmost) / 2
329bed06 2173 - nrefx * width / 2);
b4192550
KH
2174 btm = ((grefy == 0 ? highest
2175 : grefy == 1 ? 0
2176 : grefy == 2 ? lowest
2177 : (highest + lowest) / 2)
329bed06
GM
2178 - (nrefy == 0 ? ascent + descent
2179 : nrefy == 1 ? descent - boff
b4192550 2180 : nrefy == 2 ? 0
329bed06 2181 : (ascent + descent) / 2));
b4192550
KH
2182 }
2183
2184 cmp->offsets[i * 2] = left;
329bed06 2185 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2186
2187 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2188 right = left + width;
2189 top = btm + descent + ascent;
b4192550
KH
2190 if (left < leftmost)
2191 leftmost = left;
2192 if (right > rightmost)
2193 rightmost = right;
2194 if (top > highest)
2195 highest = top;
2196 if (btm < lowest)
2197 lowest = btm;
2198 }
2199
2200 /* If there are glyphs whose x-offsets are negative,
2201 shift all glyphs to the right and make all x-offsets
2202 non-negative. */
2203 if (leftmost < 0)
2204 {
2205 for (i = 0; i < cmp->glyph_len; i++)
2206 cmp->offsets[i * 2] -= leftmost;
2207 rightmost -= leftmost;
2208 }
2209
2210 cmp->pixel_width = rightmost;
2211 cmp->ascent = highest;
2212 cmp->descent = - lowest;
2213 if (cmp->ascent < font_ascent)
2214 cmp->ascent = font_ascent;
2215 if (cmp->descent < font_descent)
2216 cmp->descent = font_descent;
2217 }
2218
2219 it->pixel_width = cmp->pixel_width;
2220 it->ascent = it->phys_ascent = cmp->ascent;
2221 it->descent = it->phys_descent = cmp->descent;
2222
2223 if (face->box != FACE_NO_BOX)
2224 {
2225 int thick = face->box_line_width;
2226 it->ascent += thick;
2227 it->descent += thick;
2228
2229 if (it->start_of_box_run_p)
2230 it->pixel_width += thick;
2231 if (it->end_of_box_run_p)
2232 it->pixel_width += thick;
2233 }
2234
2235 /* If face has an overline, add the height of the overline
2236 (1 pixel) and a 1 pixel margin to the character height. */
2237 if (face->overline_p)
2238 it->ascent += 2;
2239
2240 take_vertical_position_into_account (it);
2241
2242 if (it->glyph_row)
2243 x_append_composite_glyph (it);
2244 }
06a2c219
GM
2245 else if (it->what == IT_IMAGE)
2246 x_produce_image_glyph (it);
2247 else if (it->what == IT_STRETCH)
2248 x_produce_stretch_glyph (it);
2249
3017fdd1
GM
2250 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2251 because this isn't true for images with `:ascent 100'. */
2252 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2253 if (it->area == TEXT_AREA)
2254 it->current_x += it->pixel_width;
66ac4b0e 2255
d365f5bb
GM
2256 it->descent += it->extra_line_spacing;
2257
06a2c219
GM
2258 it->max_ascent = max (it->max_ascent, it->ascent);
2259 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2260 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2261 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2262}
2263
2264
2265/* Estimate the pixel height of the mode or top line on frame F.
2266 FACE_ID specifies what line's height to estimate. */
2267
2268int
2269x_estimate_mode_line_height (f, face_id)
2270 struct frame *f;
2271 enum face_id face_id;
2272{
2273 int height = 1;
2274
2275 /* This function is called so early when Emacs starts that the face
2276 cache and mode line face are not yet initialized. */
2277 if (FRAME_FACE_CACHE (f))
2278 {
2279 struct face *face = FACE_FROM_ID (f, face_id);
2280 if (face)
2281 height = FONT_HEIGHT (face->font) + 2 * face->box_line_width;
2282 }
2283
2284 return height;
2285}
2286
2287\f
2288/***********************************************************************
2289 Glyph display
2290 ***********************************************************************/
2291
2292/* A sequence of glyphs to be drawn in the same face.
2293
2294 This data structure is not really completely X specific, so it
2295 could possibly, at least partially, be useful for other systems. It
2296 is currently not part of the external redisplay interface because
2297 it's not clear what other systems will need. */
2298
2299struct glyph_string
2300{
2301 /* X-origin of the string. */
2302 int x;
2303
2304 /* Y-origin and y-position of the base line of this string. */
2305 int y, ybase;
2306
2307 /* The width of the string, not including a face extension. */
2308 int width;
2309
2310 /* The width of the string, including a face extension. */
2311 int background_width;
2312
2313 /* The height of this string. This is the height of the line this
2314 string is drawn in, and can be different from the height of the
2315 font the string is drawn in. */
2316 int height;
2317
2318 /* Number of pixels this string overwrites in front of its x-origin.
2319 This number is zero if the string has an lbearing >= 0; it is
2320 -lbearing, if the string has an lbearing < 0. */
2321 int left_overhang;
2322
2323 /* Number of pixels this string overwrites past its right-most
2324 nominal x-position, i.e. x + width. Zero if the string's
2325 rbearing is <= its nominal width, rbearing - width otherwise. */
2326 int right_overhang;
2327
2328 /* The frame on which the glyph string is drawn. */
2329 struct frame *f;
2330
2331 /* The window on which the glyph string is drawn. */
2332 struct window *w;
2333
2334 /* X display and window for convenience. */
2335 Display *display;
2336 Window window;
2337
2338 /* The glyph row for which this string was built. It determines the
2339 y-origin and height of the string. */
2340 struct glyph_row *row;
2341
2342 /* The area within row. */
2343 enum glyph_row_area area;
2344
2345 /* Characters to be drawn, and number of characters. */
2346 XChar2b *char2b;
2347 int nchars;
2348
06a2c219
GM
2349 /* A face-override for drawing cursors, mouse face and similar. */
2350 enum draw_glyphs_face hl;
2351
2352 /* Face in which this string is to be drawn. */
2353 struct face *face;
2354
2355 /* Font in which this string is to be drawn. */
2356 XFontStruct *font;
2357
2358 /* Font info for this string. */
2359 struct font_info *font_info;
2360
b4192550
KH
2361 /* Non-null means this string describes (part of) a composition.
2362 All characters from char2b are drawn composed. */
2363 struct composition *cmp;
06a2c219
GM
2364
2365 /* Index of this glyph string's first character in the glyph
b4192550
KH
2366 definition of CMP. If this is zero, this glyph string describes
2367 the first character of a composition. */
06a2c219
GM
2368 int gidx;
2369
2370 /* 1 means this glyph strings face has to be drawn to the right end
2371 of the window's drawing area. */
2372 unsigned extends_to_end_of_line_p : 1;
2373
2374 /* 1 means the background of this string has been drawn. */
2375 unsigned background_filled_p : 1;
2376
2377 /* 1 means glyph string must be drawn with 16-bit functions. */
2378 unsigned two_byte_p : 1;
2379
2380 /* 1 means that the original font determined for drawing this glyph
2381 string could not be loaded. The member `font' has been set to
2382 the frame's default font in this case. */
2383 unsigned font_not_found_p : 1;
2384
2385 /* 1 means that the face in which this glyph string is drawn has a
2386 stipple pattern. */
2387 unsigned stippled_p : 1;
2388
66ac4b0e
GM
2389 /* 1 means only the foreground of this glyph string must be drawn,
2390 and we should use the physical height of the line this glyph
2391 string appears in as clip rect. */
2392 unsigned for_overlaps_p : 1;
2393
06a2c219
GM
2394 /* The GC to use for drawing this glyph string. */
2395 GC gc;
2396
2397 /* A pointer to the first glyph in the string. This glyph
2398 corresponds to char2b[0]. Needed to draw rectangles if
2399 font_not_found_p is 1. */
2400 struct glyph *first_glyph;
2401
2402 /* Image, if any. */
2403 struct image *img;
2404
2405 struct glyph_string *next, *prev;
2406};
2407
2408
5c187dee 2409#if 0
06a2c219
GM
2410
2411static void
2412x_dump_glyph_string (s)
2413 struct glyph_string *s;
2414{
2415 fprintf (stderr, "glyph string\n");
2416 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2417 s->x, s->y, s->width, s->height);
2418 fprintf (stderr, " ybase = %d\n", s->ybase);
2419 fprintf (stderr, " hl = %d\n", s->hl);
2420 fprintf (stderr, " left overhang = %d, right = %d\n",
2421 s->left_overhang, s->right_overhang);
2422 fprintf (stderr, " nchars = %d\n", s->nchars);
2423 fprintf (stderr, " extends to end of line = %d\n",
2424 s->extends_to_end_of_line_p);
2425 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2426 fprintf (stderr, " bg width = %d\n", s->background_width);
2427}
2428
2429#endif /* GLYPH_DEBUG */
2430
2431
2432
2433static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2434 struct glyph_string **,
2435 struct glyph_string *,
2436 struct glyph_string *));
2437static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2438 struct glyph_string **,
2439 struct glyph_string *,
2440 struct glyph_string *));
2441static void x_append_glyph_string P_ ((struct glyph_string **,
2442 struct glyph_string **,
2443 struct glyph_string *));
2444static int x_left_overwritten P_ ((struct glyph_string *));
2445static int x_left_overwriting P_ ((struct glyph_string *));
2446static int x_right_overwritten P_ ((struct glyph_string *));
2447static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2448static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2449 int));
06a2c219
GM
2450static void x_init_glyph_string P_ ((struct glyph_string *,
2451 XChar2b *, struct window *,
2452 struct glyph_row *,
2453 enum glyph_row_area, int,
2454 enum draw_glyphs_face));
2455static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2456 enum glyph_row_area, int, int,
66ac4b0e 2457 enum draw_glyphs_face, int *, int *, int));
06a2c219
GM
2458static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2459static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2460static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2461 int));
2462static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2463static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2464static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2465static void x_draw_glyph_string P_ ((struct glyph_string *));
2466static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2467static void x_set_cursor_gc P_ ((struct glyph_string *));
2468static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2469static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2470static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2471 int *, int *));
2472static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2473static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2474 unsigned long *, double, int));
06a2c219 2475static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2476 double, int, unsigned long));
06a2c219
GM
2477static void x_setup_relief_colors P_ ((struct glyph_string *));
2478static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2479static void x_draw_image_relief P_ ((struct glyph_string *));
2480static void x_draw_image_foreground P_ ((struct glyph_string *));
2481static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2482static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2483static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2484 int, int, int));
2485static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2486 int, int, int, int, XRectangle *));
2487static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2488 int, int, int, XRectangle *));
66ac4b0e
GM
2489static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2490 enum glyph_row_area));
06a2c219 2491
163dcff3
GM
2492#if GLYPH_DEBUG
2493static void x_check_font P_ ((struct frame *, XFontStruct *));
2494#endif
2495
06a2c219 2496
06a2c219
GM
2497/* Append the list of glyph strings with head H and tail T to the list
2498 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2499
2500static INLINE void
2501x_append_glyph_string_lists (head, tail, h, t)
2502 struct glyph_string **head, **tail;
2503 struct glyph_string *h, *t;
2504{
2505 if (h)
2506 {
2507 if (*head)
2508 (*tail)->next = h;
2509 else
2510 *head = h;
2511 h->prev = *tail;
2512 *tail = t;
2513 }
2514}
2515
2516
2517/* Prepend the list of glyph strings with head H and tail T to the
2518 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2519 result. */
2520
2521static INLINE void
2522x_prepend_glyph_string_lists (head, tail, h, t)
2523 struct glyph_string **head, **tail;
2524 struct glyph_string *h, *t;
2525{
2526 if (h)
2527 {
2528 if (*head)
2529 (*head)->prev = t;
2530 else
2531 *tail = t;
2532 t->next = *head;
2533 *head = h;
2534 }
2535}
2536
2537
2538/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2539 Set *HEAD and *TAIL to the resulting list. */
2540
2541static INLINE void
2542x_append_glyph_string (head, tail, s)
2543 struct glyph_string **head, **tail;
2544 struct glyph_string *s;
2545{
2546 s->next = s->prev = NULL;
2547 x_append_glyph_string_lists (head, tail, s, s);
2548}
2549
2550
2551/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2552 face. */
2553
2554static void
2555x_set_cursor_gc (s)
2556 struct glyph_string *s;
2557{
2558 if (s->font == FRAME_FONT (s->f)
2559 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2560 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2561 && !s->cmp)
06a2c219
GM
2562 s->gc = s->f->output_data.x->cursor_gc;
2563 else
2564 {
2565 /* Cursor on non-default face: must merge. */
2566 XGCValues xgcv;
2567 unsigned long mask;
2568
2569 xgcv.background = s->f->output_data.x->cursor_pixel;
2570 xgcv.foreground = s->face->background;
2571
2572 /* If the glyph would be invisible, try a different foreground. */
2573 if (xgcv.foreground == xgcv.background)
2574 xgcv.foreground = s->face->foreground;
2575 if (xgcv.foreground == xgcv.background)
2576 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2577 if (xgcv.foreground == xgcv.background)
2578 xgcv.foreground = s->face->foreground;
2579
2580 /* Make sure the cursor is distinct from text in this face. */
2581 if (xgcv.background == s->face->background
2582 && xgcv.foreground == s->face->foreground)
2583 {
2584 xgcv.background = s->face->foreground;
2585 xgcv.foreground = s->face->background;
2586 }
2587
2588 IF_DEBUG (x_check_font (s->f, s->font));
2589 xgcv.font = s->font->fid;
2590 xgcv.graphics_exposures = False;
2591 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2592
2593 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2594 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2595 mask, &xgcv);
2596 else
2597 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2598 = XCreateGC (s->display, s->window, mask, &xgcv);
2599
2600 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2601 }
2602}
2603
2604
2605/* Set up S->gc of glyph string S for drawing text in mouse face. */
2606
2607static void
2608x_set_mouse_face_gc (s)
2609 struct glyph_string *s;
2610{
2611 int face_id;
ee569018 2612 struct face *face;
06a2c219
GM
2613
2614 /* What face has to be used for the mouse face? */
2615 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2616 face = FACE_FROM_ID (s->f, face_id);
033e3e18
GM
2617 if (s->first_glyph->type == CHAR_GLYPH)
2618 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2619 else
2620 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2621 s->face = FACE_FROM_ID (s->f, face_id);
2622 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2623
2624 /* If font in this face is same as S->font, use it. */
2625 if (s->font == s->face->font)
2626 s->gc = s->face->gc;
2627 else
2628 {
2629 /* Otherwise construct scratch_cursor_gc with values from FACE
2630 but font FONT. */
2631 XGCValues xgcv;
2632 unsigned long mask;
2633
2634 xgcv.background = s->face->background;
2635 xgcv.foreground = s->face->foreground;
2636 IF_DEBUG (x_check_font (s->f, s->font));
2637 xgcv.font = s->font->fid;
2638 xgcv.graphics_exposures = False;
2639 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2640
2641 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2642 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2643 mask, &xgcv);
2644 else
2645 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2646 = XCreateGC (s->display, s->window, mask, &xgcv);
2647
2648 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2649 }
2650
2651 xassert (s->gc != 0);
2652}
2653
2654
2655/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2656 Faces to use in the mode line have already been computed when the
2657 matrix was built, so there isn't much to do, here. */
2658
2659static INLINE void
2660x_set_mode_line_face_gc (s)
2661 struct glyph_string *s;
2662{
2663 s->gc = s->face->gc;
2664 xassert (s->gc != 0);
2665}
2666
2667
2668/* Set S->gc of glyph string S for drawing that glyph string. Set
2669 S->stippled_p to a non-zero value if the face of S has a stipple
2670 pattern. */
2671
2672static INLINE void
2673x_set_glyph_string_gc (s)
2674 struct glyph_string *s;
2675{
2676 if (s->hl == DRAW_NORMAL_TEXT)
2677 {
2678 s->gc = s->face->gc;
2679 s->stippled_p = s->face->stipple != 0;
2680 }
2681 else if (s->hl == DRAW_INVERSE_VIDEO)
2682 {
2683 x_set_mode_line_face_gc (s);
2684 s->stippled_p = s->face->stipple != 0;
2685 }
2686 else if (s->hl == DRAW_CURSOR)
2687 {
2688 x_set_cursor_gc (s);
2689 s->stippled_p = 0;
2690 }
2691 else if (s->hl == DRAW_MOUSE_FACE)
2692 {
2693 x_set_mouse_face_gc (s);
2694 s->stippled_p = s->face->stipple != 0;
2695 }
2696 else if (s->hl == DRAW_IMAGE_RAISED
2697 || s->hl == DRAW_IMAGE_SUNKEN)
2698 {
2699 s->gc = s->face->gc;
2700 s->stippled_p = s->face->stipple != 0;
2701 }
2702 else
2703 {
2704 s->gc = s->face->gc;
2705 s->stippled_p = s->face->stipple != 0;
2706 }
2707
2708 /* GC must have been set. */
2709 xassert (s->gc != 0);
2710}
2711
2712
2713/* Return in *R the clipping rectangle for glyph string S. */
2714
2715static void
2716x_get_glyph_string_clip_rect (s, r)
2717 struct glyph_string *s;
2718 XRectangle *r;
2719{
2720 if (s->row->full_width_p)
2721 {
2722 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2723 int canon_x = CANON_X_UNIT (s->f);
2724
2725 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2726 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2727
2728 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2729 {
1da3fd71 2730 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2731 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2732 r->x -= width;
2733 }
2734
b9432a85 2735 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2736
06a2c219
GM
2737 /* Unless displaying a mode or menu bar line, which are always
2738 fully visible, clip to the visible part of the row. */
2739 if (s->w->pseudo_window_p)
2740 r->height = s->row->visible_height;
2741 else
2742 r->height = s->height;
2743 }
2744 else
2745 {
2746 /* This is a text line that may be partially visible. */
2747 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2748 r->width = window_box_width (s->w, s->area);
2749 r->height = s->row->visible_height;
2750 }
2751
2752 /* Don't use S->y for clipping because it doesn't take partially
2753 visible lines into account. For example, it can be negative for
2754 partially visible lines at the top of a window. */
2755 if (!s->row->full_width_p
2756 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
045dee35 2757 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
06a2c219
GM
2758 else
2759 r->y = max (0, s->row->y);
06a2c219 2760
9ea173e8 2761 /* If drawing a tool-bar window, draw it over the internal border
06a2c219 2762 at the top of the window. */
9ea173e8 2763 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219 2764 r->y -= s->f->output_data.x->internal_border_width;
66ac4b0e
GM
2765
2766 /* If S draws overlapping rows, it's sufficient to use the top and
2767 bottom of the window for clipping because this glyph string
2768 intentionally draws over other lines. */
2769 if (s->for_overlaps_p)
2770 {
045dee35 2771 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2772 r->height = window_text_bottom_y (s->w) - r->y;
2773 }
2774
2775 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2776}
2777
2778
2779/* Set clipping for output of glyph string S. S may be part of a mode
2780 line or menu if we don't have X toolkit support. */
2781
2782static INLINE void
2783x_set_glyph_string_clipping (s)
2784 struct glyph_string *s;
2785{
2786 XRectangle r;
2787 x_get_glyph_string_clip_rect (s, &r);
2788 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2789}
2790
2791
2792/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2793 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2794
2795static INLINE void
2796x_compute_glyph_string_overhangs (s)
2797 struct glyph_string *s;
2798{
b4192550 2799 if (s->cmp == NULL
06a2c219
GM
2800 && s->first_glyph->type == CHAR_GLYPH)
2801 {
2802 XCharStruct cs;
2803 int direction, font_ascent, font_descent;
2804 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2805 &font_ascent, &font_descent, &cs);
2806 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2807 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2808 }
2809}
2810
2811
2812/* Compute overhangs and x-positions for glyph string S and its
2813 predecessors, or successors. X is the starting x-position for S.
2814 BACKWARD_P non-zero means process predecessors. */
2815
2816static void
2817x_compute_overhangs_and_x (s, x, backward_p)
2818 struct glyph_string *s;
2819 int x;
2820 int backward_p;
2821{
2822 if (backward_p)
2823 {
2824 while (s)
2825 {
2826 x_compute_glyph_string_overhangs (s);
2827 x -= s->width;
2828 s->x = x;
2829 s = s->prev;
2830 }
2831 }
2832 else
2833 {
2834 while (s)
2835 {
2836 x_compute_glyph_string_overhangs (s);
2837 s->x = x;
2838 x += s->width;
2839 s = s->next;
2840 }
2841 }
2842}
2843
2844
2845/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2846 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2847 assumed to be zero. */
06a2c219
GM
2848
2849static void
2850x_get_glyph_overhangs (glyph, f, left, right)
2851 struct glyph *glyph;
2852 struct frame *f;
2853 int *left, *right;
2854{
06a2c219
GM
2855 *left = *right = 0;
2856
b4192550 2857 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2858 {
2859 XFontStruct *font;
2860 struct face *face;
2861 struct font_info *font_info;
2862 XChar2b char2b;
ee569018
KH
2863 XCharStruct *pcm;
2864
2865 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2866 font = face->font;
2867 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2868 if (font
2869 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2870 {
06a2c219
GM
2871 if (pcm->rbearing > pcm->width)
2872 *right = pcm->rbearing - pcm->width;
2873 if (pcm->lbearing < 0)
2874 *left = -pcm->lbearing;
2875 }
2876 }
2877}
2878
2879
2880/* Return the index of the first glyph preceding glyph string S that
2881 is overwritten by S because of S's left overhang. Value is -1
2882 if no glyphs are overwritten. */
2883
2884static int
2885x_left_overwritten (s)
2886 struct glyph_string *s;
2887{
2888 int k;
2889
2890 if (s->left_overhang)
2891 {
2892 int x = 0, i;
2893 struct glyph *glyphs = s->row->glyphs[s->area];
2894 int first = s->first_glyph - glyphs;
2895
2896 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2897 x -= glyphs[i].pixel_width;
2898
2899 k = i + 1;
2900 }
2901 else
2902 k = -1;
2903
2904 return k;
2905}
2906
2907
2908/* Return the index of the first glyph preceding glyph string S that
2909 is overwriting S because of its right overhang. Value is -1 if no
2910 glyph in front of S overwrites S. */
2911
2912static int
2913x_left_overwriting (s)
2914 struct glyph_string *s;
2915{
2916 int i, k, x;
2917 struct glyph *glyphs = s->row->glyphs[s->area];
2918 int first = s->first_glyph - glyphs;
2919
2920 k = -1;
2921 x = 0;
2922 for (i = first - 1; i >= 0; --i)
2923 {
2924 int left, right;
2925 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2926 if (x + right > 0)
2927 k = i;
2928 x -= glyphs[i].pixel_width;
2929 }
2930
2931 return k;
2932}
2933
2934
2935/* Return the index of the last glyph following glyph string S that is
2936 not overwritten by S because of S's right overhang. Value is -1 if
2937 no such glyph is found. */
2938
2939static int
2940x_right_overwritten (s)
2941 struct glyph_string *s;
2942{
2943 int k = -1;
2944
2945 if (s->right_overhang)
2946 {
2947 int x = 0, i;
2948 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 2949 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
2950 int end = s->row->used[s->area];
2951
2952 for (i = first; i < end && s->right_overhang > x; ++i)
2953 x += glyphs[i].pixel_width;
2954
2955 k = i;
2956 }
2957
2958 return k;
2959}
2960
2961
2962/* Return the index of the last glyph following glyph string S that
2963 overwrites S because of its left overhang. Value is negative
2964 if no such glyph is found. */
2965
2966static int
2967x_right_overwriting (s)
2968 struct glyph_string *s;
2969{
2970 int i, k, x;
2971 int end = s->row->used[s->area];
2972 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 2973 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
2974
2975 k = -1;
2976 x = 0;
2977 for (i = first; i < end; ++i)
2978 {
2979 int left, right;
2980 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2981 if (x - left < 0)
2982 k = i;
2983 x += glyphs[i].pixel_width;
2984 }
2985
2986 return k;
2987}
2988
2989
2990/* Fill rectangle X, Y, W, H with background color of glyph string S. */
2991
2992static INLINE void
2993x_clear_glyph_string_rect (s, x, y, w, h)
2994 struct glyph_string *s;
2995 int x, y, w, h;
2996{
2997 XGCValues xgcv;
2998 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
2999 XSetForeground (s->display, s->gc, xgcv.background);
3000 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3001 XSetForeground (s->display, s->gc, xgcv.foreground);
3002}
3003
3004
3005/* Draw the background of glyph_string S. If S->background_filled_p
3006 is non-zero don't draw it. FORCE_P non-zero means draw the
3007 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3008 when a string preceding S draws into the background of S, or S
3009 contains the first component of a composition. */
06a2c219
GM
3010
3011static void
3012x_draw_glyph_string_background (s, force_p)
3013 struct glyph_string *s;
3014 int force_p;
3015{
3016 /* Nothing to do if background has already been drawn or if it
3017 shouldn't be drawn in the first place. */
3018 if (!s->background_filled_p)
3019 {
b4192550 3020 if (s->stippled_p)
06a2c219
GM
3021 {
3022 /* Fill background with a stipple pattern. */
3023 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3024 XFillRectangle (s->display, s->window, s->gc, s->x,
3025 s->y + s->face->box_line_width,
3026 s->background_width,
3027 s->height - 2 * s->face->box_line_width);
3028 XSetFillStyle (s->display, s->gc, FillSolid);
3029 s->background_filled_p = 1;
3030 }
3031 else if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
3032 || s->font_not_found_p
3033 || s->extends_to_end_of_line_p
06a2c219
GM
3034 || force_p)
3035 {
3036 x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
3037 s->background_width,
3038 s->height - 2 * s->face->box_line_width);
3039 s->background_filled_p = 1;
3040 }
3041 }
3042}
3043
3044
3045/* Draw the foreground of glyph string S. */
3046
3047static void
3048x_draw_glyph_string_foreground (s)
3049 struct glyph_string *s;
3050{
3051 int i, x;
3052
3053 /* If first glyph of S has a left box line, start drawing the text
3054 of S to the right of that box line. */
3055 if (s->face->box != FACE_NO_BOX
3056 && s->first_glyph->left_box_line_p)
3057 x = s->x + s->face->box_line_width;
3058 else
3059 x = s->x;
3060
b4192550
KH
3061 /* Draw characters of S as rectangles if S's font could not be
3062 loaded. */
3063 if (s->font_not_found_p)
06a2c219 3064 {
b4192550 3065 for (i = 0; i < s->nchars; ++i)
06a2c219 3066 {
b4192550
KH
3067 struct glyph *g = s->first_glyph + i;
3068 XDrawRectangle (s->display, s->window,
3069 s->gc, x, s->y, g->pixel_width - 1,
3070 s->height - 1);
3071 x += g->pixel_width;
06a2c219
GM
3072 }
3073 }
3074 else
3075 {
b4192550
KH
3076 char *char1b = (char *) s->char2b;
3077 int boff = s->font_info->baseline_offset;
06a2c219 3078
b4192550
KH
3079 if (s->font_info->vertical_centering)
3080 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3081
3082 /* If we can use 8-bit functions, condense S->char2b. */
3083 if (!s->two_byte_p)
3084 for (i = 0; i < s->nchars; ++i)
3085 char1b[i] = s->char2b[i].byte2;
3086
3087 /* Draw text with XDrawString if background has already been
3088 filled. Otherwise, use XDrawImageString. (Note that
3089 XDrawImageString is usually faster than XDrawString.) Always
3090 use XDrawImageString when drawing the cursor so that there is
3091 no chance that characters under a box cursor are invisible. */
3092 if (s->for_overlaps_p
3093 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3094 {
3095 /* Draw characters with 16-bit or 8-bit functions. */
3096 if (s->two_byte_p)
3097 XDrawString16 (s->display, s->window, s->gc, x,
3098 s->ybase - boff, s->char2b, s->nchars);
3099 else
3100 XDrawString (s->display, s->window, s->gc, x,
3101 s->ybase - boff, char1b, s->nchars);
3102 }
06a2c219
GM
3103 else
3104 {
b4192550
KH
3105 if (s->two_byte_p)
3106 XDrawImageString16 (s->display, s->window, s->gc, x,
3107 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3108 else
b4192550
KH
3109 XDrawImageString (s->display, s->window, s->gc, x,
3110 s->ybase - boff, char1b, s->nchars);
3111 }
3112 }
3113}
06a2c219 3114
b4192550 3115/* Draw the foreground of composite glyph string S. */
06a2c219 3116
b4192550
KH
3117static void
3118x_draw_composite_glyph_string_foreground (s)
3119 struct glyph_string *s;
3120{
3121 int i, x;
06a2c219 3122
b4192550
KH
3123 /* If first glyph of S has a left box line, start drawing the text
3124 of S to the right of that box line. */
3125 if (s->face->box != FACE_NO_BOX
3126 && s->first_glyph->left_box_line_p)
3127 x = s->x + s->face->box_line_width;
3128 else
3129 x = s->x;
06a2c219 3130
b4192550
KH
3131 /* S is a glyph string for a composition. S->gidx is the index of
3132 the first character drawn for glyphs of this composition.
3133 S->gidx == 0 means we are drawing the very first character of
3134 this composition. */
06a2c219 3135
b4192550
KH
3136 /* Draw a rectangle for the composition if the font for the very
3137 first character of the composition could not be loaded. */
3138 if (s->font_not_found_p)
3139 {
3140 if (s->gidx == 0)
3141 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3142 s->width - 1, s->height - 1);
3143 }
3144 else
3145 {
3146 for (i = 0; i < s->nchars; i++, ++s->gidx)
3147 XDrawString16 (s->display, s->window, s->gc,
3148 x + s->cmp->offsets[s->gidx * 2],
3149 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3150 s->char2b + i, 1);
06a2c219
GM
3151 }
3152}
3153
3154
80c32bcc
GM
3155#ifdef USE_X_TOOLKIT
3156
3e71d8f2 3157static struct frame *x_frame_of_widget P_ ((Widget));
80c32bcc 3158
3e71d8f2
GM
3159
3160/* Return the frame on which widget WIDGET is used.. Abort if frame
3161 cannot be determined. */
3162
e851c833 3163static struct frame *
3e71d8f2 3164x_frame_of_widget (widget)
80c32bcc 3165 Widget widget;
80c32bcc 3166{
80c32bcc 3167 struct x_display_info *dpyinfo;
5c187dee 3168 Lisp_Object tail;
3e71d8f2
GM
3169 struct frame *f;
3170
80c32bcc
GM
3171 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3172
3173 /* Find the top-level shell of the widget. Note that this function
3174 can be called when the widget is not yet realized, so XtWindow
3175 (widget) == 0. That's the reason we can't simply use
3176 x_any_window_to_frame. */
3177 while (!XtIsTopLevelShell (widget))
3178 widget = XtParent (widget);
3179
3180 /* Look for a frame with that top-level widget. Allocate the color
3181 on that frame to get the right gamma correction value. */
3182 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3183 if (GC_FRAMEP (XCAR (tail))
3184 && (f = XFRAME (XCAR (tail)),
3185 (f->output_data.nothing != 1
3186 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3187 && f->output_data.x->widget == widget)
3e71d8f2 3188 return f;
80c32bcc
GM
3189
3190 abort ();
3191}
3192
3e71d8f2
GM
3193
3194/* Allocate the color COLOR->pixel on the screen and display of
3195 widget WIDGET in colormap CMAP. If an exact match cannot be
3196 allocated, try the nearest color available. Value is non-zero
3197 if successful. This is called from lwlib. */
3198
3199int
3200x_alloc_nearest_color_for_widget (widget, cmap, color)
3201 Widget widget;
3202 Colormap cmap;
3203 XColor *color;
3204{
3205 struct frame *f = x_frame_of_widget (widget);
3206 return x_alloc_nearest_color (f, cmap, color);
3207}
3208
3209
80c32bcc
GM
3210#endif /* USE_X_TOOLKIT */
3211
3212
06a2c219
GM
3213/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3214 CMAP. If an exact match can't be allocated, try the nearest color
3215 available. Value is non-zero if successful. Set *COLOR to the
3216 color allocated. */
3217
3218int
80c32bcc
GM
3219x_alloc_nearest_color (f, cmap, color)
3220 struct frame *f;
06a2c219
GM
3221 Colormap cmap;
3222 XColor *color;
3223{
80c32bcc
GM
3224 Display *display = FRAME_X_DISPLAY (f);
3225 Screen *screen = FRAME_X_SCREEN (f);
3226 int rc;
3227
3228 gamma_correct (f, color);
3229 rc = XAllocColor (display, cmap, color);
06a2c219
GM
3230 if (rc == 0)
3231 {
3232 /* If we got to this point, the colormap is full, so we're going
3233 to try to get the next closest color. The algorithm used is
3234 a least-squares matching, which is what X uses for closest
3235 color matching with StaticColor visuals. */
3236 int nearest, i;
3237 unsigned long nearest_delta = ~0;
3238 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
3239 XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
3240
3241 for (i = 0; i < ncells; ++i)
3242 cells[i].pixel = i;
3243 XQueryColors (display, cmap, cells, ncells);
3244
3245 for (nearest = i = 0; i < ncells; ++i)
3246 {
3247 long dred = (color->red >> 8) - (cells[i].red >> 8);
3248 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3249 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3250 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3251
3252 if (delta < nearest_delta)
3253 {
3254 nearest = i;
3255 nearest_delta = delta;
3256 }
3257 }
3258
3259 color->red = cells[nearest].red;
3260 color->green = cells[nearest].green;
3261 color->blue = cells[nearest].blue;
3262 rc = XAllocColor (display, cmap, color);
3263 }
3264
d9c545da
GM
3265#ifdef DEBUG_X_COLORS
3266 if (rc)
3267 register_color (color->pixel);
3268#endif /* DEBUG_X_COLORS */
3269
06a2c219
GM
3270 return rc;
3271}
3272
3273
d9c545da
GM
3274/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3275 It's necessary to do this instead of just using PIXEL directly to
3276 get color reference counts right. */
3277
3278unsigned long
3279x_copy_color (f, pixel)
3280 struct frame *f;
3281 unsigned long pixel;
3282{
3283 XColor color;
3284
3285 color.pixel = pixel;
3286 BLOCK_INPUT;
3287 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3288 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3289 UNBLOCK_INPUT;
3290#ifdef DEBUG_X_COLORS
3291 register_color (pixel);
3292#endif
3293 return color.pixel;
3294}
3295
3296
3e71d8f2
GM
3297/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3298 It's necessary to do this instead of just using PIXEL directly to
3299 get color reference counts right. */
3300
3301unsigned long
3302x_copy_dpy_color (dpy, cmap, pixel)
3303 Display *dpy;
3304 Colormap cmap;
3305 unsigned long pixel;
3306{
3307 XColor color;
3308
3309 color.pixel = pixel;
3310 BLOCK_INPUT;
3311 XQueryColor (dpy, cmap, &color);
3312 XAllocColor (dpy, cmap, &color);
3313 UNBLOCK_INPUT;
3314#ifdef DEBUG_X_COLORS
3315 register_color (pixel);
3316#endif
3317 return color.pixel;
3318}
3319
3320
06a2c219
GM
3321/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3322 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3323 If this produces the same color as PIXEL, try a color where all RGB
3324 values have DELTA added. Return the allocated color in *PIXEL.
3325 DISPLAY is the X display, CMAP is the colormap to operate on.
3326 Value is non-zero if successful. */
3327
3328static int
3329x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3330 struct frame *f;
3331 Display *display;
3332 Colormap cmap;
3333 unsigned long *pixel;
68c45bf0 3334 double factor;
06a2c219
GM
3335 int delta;
3336{
3337 XColor color, new;
3338 int success_p;
3339
3340 /* Get RGB color values. */
3341 color.pixel = *pixel;
3342 XQueryColor (display, cmap, &color);
3343
3344 /* Change RGB values by specified FACTOR. Avoid overflow! */
3345 xassert (factor >= 0);
3346 new.red = min (0xffff, factor * color.red);
3347 new.green = min (0xffff, factor * color.green);
3348 new.blue = min (0xffff, factor * color.blue);
3349
3350 /* Try to allocate the color. */
80c32bcc 3351 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3352 if (success_p)
3353 {
3354 if (new.pixel == *pixel)
3355 {
3356 /* If we end up with the same color as before, try adding
3357 delta to the RGB values. */
0d605c67 3358 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3359
3360 new.red = min (0xffff, delta + color.red);
3361 new.green = min (0xffff, delta + color.green);
3362 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3363 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3364 }
3365 else
3366 success_p = 1;
3367 *pixel = new.pixel;
3368 }
3369
3370 return success_p;
3371}
3372
3373
3374/* Set up the foreground color for drawing relief lines of glyph
3375 string S. RELIEF is a pointer to a struct relief containing the GC
3376 with which lines will be drawn. Use a color that is FACTOR or
3377 DELTA lighter or darker than the relief's background which is found
3378 in S->f->output_data.x->relief_background. If such a color cannot
3379 be allocated, use DEFAULT_PIXEL, instead. */
3380
3381static void
3382x_setup_relief_color (f, relief, factor, delta, default_pixel)
3383 struct frame *f;
3384 struct relief *relief;
68c45bf0 3385 double factor;
06a2c219
GM
3386 int delta;
3387 unsigned long default_pixel;
3388{
3389 XGCValues xgcv;
3390 struct x_output *di = f->output_data.x;
3391 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3392 unsigned long pixel;
3393 unsigned long background = di->relief_background;
43bd1b2b 3394 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3395 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3396 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3397
3398 xgcv.graphics_exposures = False;
3399 xgcv.line_width = 1;
3400
3401 /* Free previously allocated color. The color cell will be reused
3402 when it has been freed as many times as it was allocated, so this
3403 doesn't affect faces using the same colors. */
3404 if (relief->gc
3405 && relief->allocated_p)
3406 {
0d605c67 3407 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3408 relief->allocated_p = 0;
3409 }
3410
3411 /* Allocate new color. */
3412 xgcv.foreground = default_pixel;
3413 pixel = background;
dcd08bfb
GM
3414 if (dpyinfo->n_planes != 1
3415 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3416 {
3417 relief->allocated_p = 1;
3418 xgcv.foreground = relief->pixel = pixel;
3419 }
3420
3421 if (relief->gc == 0)
3422 {
dcd08bfb 3423 xgcv.stipple = dpyinfo->gray;
06a2c219 3424 mask |= GCStipple;
dcd08bfb 3425 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3426 }
3427 else
dcd08bfb 3428 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3429}
3430
3431
3432/* Set up colors for the relief lines around glyph string S. */
3433
3434static void
3435x_setup_relief_colors (s)
3436 struct glyph_string *s;
3437{
3438 struct x_output *di = s->f->output_data.x;
3439 unsigned long color;
3440
3441 if (s->face->use_box_color_for_shadows_p)
3442 color = s->face->box_color;
3443 else
3444 {
3445 XGCValues xgcv;
3446
3447 /* Get the background color of the face. */
3448 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3449 color = xgcv.background;
3450 }
3451
3452 if (di->white_relief.gc == 0
3453 || color != di->relief_background)
3454 {
3455 di->relief_background = color;
3456 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3457 WHITE_PIX_DEFAULT (s->f));
3458 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3459 BLACK_PIX_DEFAULT (s->f));
3460 }
3461}
3462
3463
3464/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3465 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3466 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3467 relief. LEFT_P non-zero means draw a relief on the left side of
3468 the rectangle. RIGHT_P non-zero means draw a relief on the right
3469 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3470 when drawing. */
3471
3472static void
3473x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3474 raised_p, left_p, right_p, clip_rect)
3475 struct frame *f;
3476 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3477 XRectangle *clip_rect;
3478{
3479 int i;
3480 GC gc;
3481
3482 if (raised_p)
3483 gc = f->output_data.x->white_relief.gc;
3484 else
3485 gc = f->output_data.x->black_relief.gc;
3486 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3487
3488 /* Top. */
3489 for (i = 0; i < width; ++i)
3490 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3491 left_x + i * left_p, top_y + i,
3492 right_x + 1 - i * right_p, top_y + i);
3493
3494 /* Left. */
3495 if (left_p)
3496 for (i = 0; i < width; ++i)
3497 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3498 left_x + i, top_y + i, left_x + i, bottom_y - i);
3499
3500 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3501 if (raised_p)
3502 gc = f->output_data.x->black_relief.gc;
3503 else
3504 gc = f->output_data.x->white_relief.gc;
3505 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3506
3507 /* Bottom. */
3508 for (i = 0; i < width; ++i)
3509 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3510 left_x + i * left_p, bottom_y - i,
3511 right_x + 1 - i * right_p, bottom_y - i);
3512
3513 /* Right. */
3514 if (right_p)
3515 for (i = 0; i < width; ++i)
3516 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3517 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3518
3519 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3520}
3521
3522
3523/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3524 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3525 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3526 left side of the rectangle. RIGHT_P non-zero means draw a line
3527 on the right side of the rectangle. CLIP_RECT is the clipping
3528 rectangle to use when drawing. */
3529
3530static void
3531x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3532 left_p, right_p, clip_rect)
3533 struct glyph_string *s;
3534 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3535 XRectangle *clip_rect;
3536{
3537 XGCValues xgcv;
3538
3539 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3540 XSetForeground (s->display, s->gc, s->face->box_color);
3541 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3542
3543 /* Top. */
3544 XFillRectangle (s->display, s->window, s->gc,
3545 left_x, top_y, right_x - left_x, width);
3546
3547 /* Left. */
3548 if (left_p)
3549 XFillRectangle (s->display, s->window, s->gc,
3550 left_x, top_y, width, bottom_y - top_y);
3551
3552 /* Bottom. */
3553 XFillRectangle (s->display, s->window, s->gc,
3554 left_x, bottom_y - width, right_x - left_x, width);
3555
3556 /* Right. */
3557 if (right_p)
3558 XFillRectangle (s->display, s->window, s->gc,
3559 right_x - width, top_y, width, bottom_y - top_y);
3560
3561 XSetForeground (s->display, s->gc, xgcv.foreground);
3562 XSetClipMask (s->display, s->gc, None);
3563}
3564
3565
3566/* Draw a box around glyph string S. */
3567
3568static void
3569x_draw_glyph_string_box (s)
3570 struct glyph_string *s;
3571{
3572 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3573 int left_p, right_p;
3574 struct glyph *last_glyph;
3575 XRectangle clip_rect;
3576
3577 last_x = window_box_right (s->w, s->area);
3578 if (s->row->full_width_p
3579 && !s->w->pseudo_window_p)
3580 {
110859fc 3581 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3582 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3583 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3584 }
3585
3586 /* The glyph that may have a right box line. */
b4192550 3587 last_glyph = (s->cmp || s->img
06a2c219
GM
3588 ? s->first_glyph
3589 : s->first_glyph + s->nchars - 1);
3590
3591 width = s->face->box_line_width;
3592 raised_p = s->face->box == FACE_RAISED_BOX;
3593 left_x = s->x;
3594 right_x = ((s->row->full_width_p
1da3fd71 3595 ? last_x - 1
a7aeb2de 3596 : min (last_x, s->x + s->background_width) - 1));
06a2c219
GM
3597 top_y = s->y;
3598 bottom_y = top_y + s->height - 1;
3599
3600 left_p = (s->first_glyph->left_box_line_p
3601 || (s->hl == DRAW_MOUSE_FACE
3602 && (s->prev == NULL
3603 || s->prev->hl != s->hl)));
3604 right_p = (last_glyph->right_box_line_p
3605 || (s->hl == DRAW_MOUSE_FACE
3606 && (s->next == NULL
3607 || s->next->hl != s->hl)));
3608
3609 x_get_glyph_string_clip_rect (s, &clip_rect);
3610
3611 if (s->face->box == FACE_SIMPLE_BOX)
3612 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3613 left_p, right_p, &clip_rect);
3614 else
3615 {
3616 x_setup_relief_colors (s);
3617 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3618 width, raised_p, left_p, right_p, &clip_rect);
3619 }
3620}
3621
3622
3623/* Draw foreground of image glyph string S. */
3624
3625static void
3626x_draw_image_foreground (s)
3627 struct glyph_string *s;
3628{
3629 int x;
95af8492 3630 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3631
3632 /* If first glyph of S has a left box line, start drawing it to the
3633 right of that line. */
3634 if (s->face->box != FACE_NO_BOX
3635 && s->first_glyph->left_box_line_p)
3636 x = s->x + s->face->box_line_width;
3637 else
3638 x = s->x;
3639
3640 /* If there is a margin around the image, adjust x- and y-position
3641 by that margin. */
3642 if (s->img->margin)
3643 {
3644 x += s->img->margin;
3645 y += s->img->margin;
3646 }
3647
3648 if (s->img->pixmap)
3649 {
3650 if (s->img->mask)
3651 {
3652 /* We can't set both a clip mask and use XSetClipRectangles
3653 because the latter also sets a clip mask. We also can't
3654 trust on the shape extension to be available
3655 (XShapeCombineRegion). So, compute the rectangle to draw
3656 manually. */
3657 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3658 | GCFunction);
3659 XGCValues xgcv;
3660 XRectangle clip_rect, image_rect, r;
3661
3662 xgcv.clip_mask = s->img->mask;
3663 xgcv.clip_x_origin = x;
3664 xgcv.clip_y_origin = y;
3665 xgcv.function = GXcopy;
3666 XChangeGC (s->display, s->gc, mask, &xgcv);
3667
3668 x_get_glyph_string_clip_rect (s, &clip_rect);
3669 image_rect.x = x;
3670 image_rect.y = y;
3671 image_rect.width = s->img->width;
3672 image_rect.height = s->img->height;
3673 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
3674 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3675 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
3676 }
3677 else
3678 {
3679 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3680 0, 0, s->img->width, s->img->height, x, y);
3681
3682 /* When the image has a mask, we can expect that at
3683 least part of a mouse highlight or a block cursor will
3684 be visible. If the image doesn't have a mask, make
3685 a block cursor visible by drawing a rectangle around
3686 the image. I believe it's looking better if we do
3687 nothing here for mouse-face. */
3688 if (s->hl == DRAW_CURSOR)
3689 XDrawRectangle (s->display, s->window, s->gc, x, y,
3690 s->img->width - 1, s->img->height - 1);
3691 }
3692 }
3693 else
3694 /* Draw a rectangle if image could not be loaded. */
3695 XDrawRectangle (s->display, s->window, s->gc, x, y,
3696 s->img->width - 1, s->img->height - 1);
3697}
3698
3699
3700/* Draw a relief around the image glyph string S. */
3701
3702static void
3703x_draw_image_relief (s)
3704 struct glyph_string *s;
3705{
3706 int x0, y0, x1, y1, thick, raised_p;
3707 XRectangle r;
3708 int x;
95af8492 3709 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3710
3711 /* If first glyph of S has a left box line, start drawing it to the
3712 right of that line. */
3713 if (s->face->box != FACE_NO_BOX
3714 && s->first_glyph->left_box_line_p)
3715 x = s->x + s->face->box_line_width;
3716 else
3717 x = s->x;
3718
3719 /* If there is a margin around the image, adjust x- and y-position
3720 by that margin. */
3721 if (s->img->margin)
3722 {
3723 x += s->img->margin;
3724 y += s->img->margin;
3725 }
3726
3727 if (s->hl == DRAW_IMAGE_SUNKEN
3728 || s->hl == DRAW_IMAGE_RAISED)
3729 {
9ea173e8 3730 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
3731 raised_p = s->hl == DRAW_IMAGE_RAISED;
3732 }
3733 else
3734 {
3735 thick = abs (s->img->relief);
3736 raised_p = s->img->relief > 0;
3737 }
3738
3739 x0 = x - thick;
3740 y0 = y - thick;
3741 x1 = x + s->img->width + thick - 1;
3742 y1 = y + s->img->height + thick - 1;
3743
3744 x_setup_relief_colors (s);
3745 x_get_glyph_string_clip_rect (s, &r);
3746 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
3747}
3748
3749
3750/* Draw the foreground of image glyph string S to PIXMAP. */
3751
3752static void
3753x_draw_image_foreground_1 (s, pixmap)
3754 struct glyph_string *s;
3755 Pixmap pixmap;
3756{
3757 int x;
95af8492 3758 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
3759
3760 /* If first glyph of S has a left box line, start drawing it to the
3761 right of that line. */
3762 if (s->face->box != FACE_NO_BOX
3763 && s->first_glyph->left_box_line_p)
3764 x = s->face->box_line_width;
3765 else
3766 x = 0;
3767
3768 /* If there is a margin around the image, adjust x- and y-position
3769 by that margin. */
3770 if (s->img->margin)
3771 {
3772 x += s->img->margin;
3773 y += s->img->margin;
3774 }
dc43ef94 3775
06a2c219
GM
3776 if (s->img->pixmap)
3777 {
3778 if (s->img->mask)
3779 {
3780 /* We can't set both a clip mask and use XSetClipRectangles
3781 because the latter also sets a clip mask. We also can't
3782 trust on the shape extension to be available
3783 (XShapeCombineRegion). So, compute the rectangle to draw
3784 manually. */
3785 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3786 | GCFunction);
3787 XGCValues xgcv;
3788
3789 xgcv.clip_mask = s->img->mask;
3790 xgcv.clip_x_origin = x;
3791 xgcv.clip_y_origin = y;
3792 xgcv.function = GXcopy;
3793 XChangeGC (s->display, s->gc, mask, &xgcv);
3794
3795 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3796 0, 0, s->img->width, s->img->height, x, y);
3797 XSetClipMask (s->display, s->gc, None);
3798 }
3799 else
3800 {
3801 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3802 0, 0, s->img->width, s->img->height, x, y);
3803
3804 /* When the image has a mask, we can expect that at
3805 least part of a mouse highlight or a block cursor will
3806 be visible. If the image doesn't have a mask, make
3807 a block cursor visible by drawing a rectangle around
3808 the image. I believe it's looking better if we do
3809 nothing here for mouse-face. */
3810 if (s->hl == DRAW_CURSOR)
3811 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3812 s->img->width - 1, s->img->height - 1);
3813 }
3814 }
3815 else
3816 /* Draw a rectangle if image could not be loaded. */
3817 XDrawRectangle (s->display, pixmap, s->gc, x, y,
3818 s->img->width - 1, s->img->height - 1);
3819}
dc43ef94 3820
990ba854 3821
06a2c219
GM
3822/* Draw part of the background of glyph string S. X, Y, W, and H
3823 give the rectangle to draw. */
a9a5b0a5 3824
06a2c219
GM
3825static void
3826x_draw_glyph_string_bg_rect (s, x, y, w, h)
3827 struct glyph_string *s;
3828 int x, y, w, h;
3829{
3830 if (s->stippled_p)
3831 {
3832 /* Fill background with a stipple pattern. */
3833 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3834 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3835 XSetFillStyle (s->display, s->gc, FillSolid);
3836 }
3837 else
3838 x_clear_glyph_string_rect (s, x, y, w, h);
3839}
07e34cb0 3840
b5210ea7 3841
06a2c219 3842/* Draw image glyph string S.
dc43ef94 3843
06a2c219
GM
3844 s->y
3845 s->x +-------------------------
3846 | s->face->box
3847 |
3848 | +-------------------------
3849 | | s->img->margin
3850 | |
3851 | | +-------------------
3852 | | | the image
dc43ef94 3853
06a2c219 3854 */
dc43ef94 3855
06a2c219
GM
3856static void
3857x_draw_image_glyph_string (s)
3858 struct glyph_string *s;
3859{
3860 int x, y;
3861 int box_line_width = s->face->box_line_width;
3862 int margin = s->img->margin;
3863 int height;
3864 Pixmap pixmap = None;
3865
3866 height = s->height - 2 * box_line_width;
3867
3868 /* Fill background with face under the image. Do it only if row is
3869 taller than image or if image has a clip mask to reduce
3870 flickering. */
3871 s->stippled_p = s->face->stipple != 0;
3872 if (height > s->img->height
3873 || margin
3874 || s->img->mask
3875 || s->img->pixmap == 0
3876 || s->width != s->background_width)
3877 {
3878 if (box_line_width && s->first_glyph->left_box_line_p)
3879 x = s->x + box_line_width;
3880 else
3881 x = s->x;
3882
3883 y = s->y + box_line_width;
3884
3885 if (s->img->mask)
3886 {
3887 /* Create a pixmap as large as the glyph string Fill it with
3888 the background color. Copy the image to it, using its
3889 mask. Copy the temporary pixmap to the display. */
3890 Screen *screen = FRAME_X_SCREEN (s->f);
3891 int depth = DefaultDepthOfScreen (screen);
3892
3893 /* Create a pixmap as large as the glyph string. */
3894 pixmap = XCreatePixmap (s->display, s->window,
3895 s->background_width,
3896 s->height, depth);
3897
3898 /* Don't clip in the following because we're working on the
3899 pixmap. */
3900 XSetClipMask (s->display, s->gc, None);
3901
3902 /* Fill the pixmap with the background color/stipple. */
3903 if (s->stippled_p)
3904 {
3905 /* Fill background with a stipple pattern. */
3906 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3907 XFillRectangle (s->display, pixmap, s->gc,
3908 0, 0, s->background_width, s->height);
3909 XSetFillStyle (s->display, s->gc, FillSolid);
3910 }
3911 else
3912 {
3913 XGCValues xgcv;
3914 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
3915 &xgcv);
3916 XSetForeground (s->display, s->gc, xgcv.background);
3917 XFillRectangle (s->display, pixmap, s->gc,
3918 0, 0, s->background_width, s->height);
3919 XSetForeground (s->display, s->gc, xgcv.foreground);
3920 }
3921 }
3922 else
3923 /* Implementation idea: Is it possible to construct a mask?
3924 We could look at the color at the margins of the image, and
3925 say that this color is probably the background color of the
3926 image. */
3927 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
3928
3929 s->background_filled_p = 1;
3930 }
dc43ef94 3931
06a2c219
GM
3932 /* Draw the foreground. */
3933 if (pixmap != None)
3934 {
3935 x_draw_image_foreground_1 (s, pixmap);
3936 x_set_glyph_string_clipping (s);
3937 XCopyArea (s->display, pixmap, s->window, s->gc,
3938 0, 0, s->background_width, s->height, s->x, s->y);
3939 XFreePixmap (s->display, pixmap);
3940 }
3941 else
3942 x_draw_image_foreground (s);
b5210ea7 3943
06a2c219
GM
3944 /* If we must draw a relief around the image, do it. */
3945 if (s->img->relief
3946 || s->hl == DRAW_IMAGE_RAISED
3947 || s->hl == DRAW_IMAGE_SUNKEN)
3948 x_draw_image_relief (s);
3949}
8c1a6a84 3950
990ba854 3951
06a2c219 3952/* Draw stretch glyph string S. */
dc43ef94 3953
06a2c219
GM
3954static void
3955x_draw_stretch_glyph_string (s)
3956 struct glyph_string *s;
3957{
3958 xassert (s->first_glyph->type == STRETCH_GLYPH);
3959 s->stippled_p = s->face->stipple != 0;
990ba854 3960
06a2c219
GM
3961 if (s->hl == DRAW_CURSOR
3962 && !x_stretch_cursor_p)
3963 {
3964 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
3965 as wide as the stretch glyph. */
3966 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 3967
06a2c219
GM
3968 /* Draw cursor. */
3969 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 3970
06a2c219
GM
3971 /* Clear rest using the GC of the original non-cursor face. */
3972 if (width < s->background_width)
3973 {
3974 GC gc = s->face->gc;
3975 int x = s->x + width, y = s->y;
3976 int w = s->background_width - width, h = s->height;
3977 XRectangle r;
dc43ef94 3978
06a2c219
GM
3979 x_get_glyph_string_clip_rect (s, &r);
3980 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
97210f4e 3981
06a2c219
GM
3982 if (s->face->stipple)
3983 {
3984 /* Fill background with a stipple pattern. */
3985 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3986 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3987 XSetFillStyle (s->display, gc, FillSolid);
3988 }
3989 else
3990 {
3991 XGCValues xgcv;
3992 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
3993 XSetForeground (s->display, gc, xgcv.background);
3994 XFillRectangle (s->display, s->window, gc, x, y, w, h);
3995 XSetForeground (s->display, gc, xgcv.foreground);
3996 }
3997 }
3998 }
3999 else
4000 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4001 s->height);
4002
4003 s->background_filled_p = 1;
4004}
4005
4006
4007/* Draw glyph string S. */
4008
4009static void
4010x_draw_glyph_string (s)
4011 struct glyph_string *s;
4012{
4013 /* If S draws into the background of its successor, draw the
4014 background of the successor first so that S can draw into it.
4015 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4016 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4017 {
4018 xassert (s->next->img == NULL);
4019 x_set_glyph_string_gc (s->next);
4020 x_set_glyph_string_clipping (s->next);
4021 x_draw_glyph_string_background (s->next, 1);
4022 }
97210f4e 4023
06a2c219
GM
4024 /* Set up S->gc, set clipping and draw S. */
4025 x_set_glyph_string_gc (s);
4026 x_set_glyph_string_clipping (s);
4027
4028 switch (s->first_glyph->type)
4029 {
4030 case IMAGE_GLYPH:
4031 x_draw_image_glyph_string (s);
4032 break;
4033
4034 case STRETCH_GLYPH:
4035 x_draw_stretch_glyph_string (s);
4036 break;
4037
4038 case CHAR_GLYPH:
66ac4b0e
GM
4039 if (s->for_overlaps_p)
4040 s->background_filled_p = 1;
4041 else
4042 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4043 x_draw_glyph_string_foreground (s);
4044 break;
4045
b4192550
KH
4046 case COMPOSITE_GLYPH:
4047 if (s->for_overlaps_p || s->gidx > 0)
4048 s->background_filled_p = 1;
4049 else
4050 x_draw_glyph_string_background (s, 1);
4051 x_draw_composite_glyph_string_foreground (s);
4052 break;
4053
06a2c219
GM
4054 default:
4055 abort ();
4056 }
4057
66ac4b0e 4058 if (!s->for_overlaps_p)
06a2c219 4059 {
66ac4b0e
GM
4060 /* Draw underline. */
4061 if (s->face->underline_p)
4062 {
4063 unsigned long dy, h;
06a2c219 4064
66ac4b0e
GM
4065 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4066 h = 1;
4067 if (!XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &dy))
4068 dy = s->height - h;
06a2c219 4069
66ac4b0e
GM
4070 if (s->face->underline_defaulted_p)
4071 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4072 s->width, h);
4073 else
4074 {
4075 XGCValues xgcv;
4076 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4077 XSetForeground (s->display, s->gc, s->face->underline_color);
4078 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4079 s->width, h);
4080 XSetForeground (s->display, s->gc, xgcv.foreground);
4081 }
dc6f92b8 4082 }
07e34cb0 4083
66ac4b0e
GM
4084 /* Draw overline. */
4085 if (s->face->overline_p)
06a2c219 4086 {
66ac4b0e
GM
4087 unsigned long dy = 0, h = 1;
4088
4089 if (s->face->overline_color_defaulted_p)
4090 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4091 s->width, h);
4092 else
4093 {
4094 XGCValues xgcv;
4095 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4096 XSetForeground (s->display, s->gc, s->face->overline_color);
4097 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4098 s->width, h);
4099 XSetForeground (s->display, s->gc, xgcv.foreground);
4100 }
06a2c219 4101 }
06a2c219 4102
66ac4b0e
GM
4103 /* Draw strike-through. */
4104 if (s->face->strike_through_p)
06a2c219 4105 {
66ac4b0e
GM
4106 unsigned long h = 1;
4107 unsigned long dy = (s->height - h) / 2;
4108
4109 if (s->face->strike_through_color_defaulted_p)
4110 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4111 s->width, h);
4112 else
4113 {
4114 XGCValues xgcv;
4115 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4116 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4117 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4118 s->width, h);
4119 XSetForeground (s->display, s->gc, xgcv.foreground);
4120 }
06a2c219 4121 }
06a2c219 4122
66ac4b0e
GM
4123 /* Draw relief. */
4124 if (s->face->box != FACE_NO_BOX)
4125 x_draw_glyph_string_box (s);
4126 }
06a2c219
GM
4127
4128 /* Reset clipping. */
4129 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4130}
07e34cb0 4131
06a2c219 4132
b4192550
KH
4133static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4134 struct face **, int));
06a2c219 4135
06a2c219 4136
b4192550
KH
4137/* Load glyph string S with a composition components specified by S->cmp.
4138 FACES is an array of faces for all components of this composition.
4139 S->gidx is the index of the first component for S.
4140 OVERLAPS_P non-zero means S should draw the foreground only, and
4141 use its lines physical height for clipping.
06a2c219 4142
b4192550 4143 Value is the index of a component not in S. */
07e34cb0 4144
b4192550
KH
4145static int
4146x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4147 struct glyph_string *s;
b4192550 4148 struct face **faces;
66ac4b0e 4149 int overlaps_p;
07e34cb0 4150{
b4192550 4151 int i;
06a2c219 4152
b4192550 4153 xassert (s);
06a2c219 4154
b4192550 4155 s->for_overlaps_p = overlaps_p;
06a2c219 4156
b4192550
KH
4157 s->face = faces[s->gidx];
4158 s->font = s->face->font;
4159 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4160
b4192550
KH
4161 /* For all glyphs of this composition, starting at the offset
4162 S->gidx, until we reach the end of the definition or encounter a
4163 glyph that requires the different face, add it to S. */
4164 ++s->nchars;
4165 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4166 ++s->nchars;
06a2c219 4167
b4192550
KH
4168 /* All glyph strings for the same composition has the same width,
4169 i.e. the width set for the first component of the composition. */
06a2c219 4170
06a2c219
GM
4171 s->width = s->first_glyph->pixel_width;
4172
4173 /* If the specified font could not be loaded, use the frame's
4174 default font, but record the fact that we couldn't load it in
4175 the glyph string so that we can draw rectangles for the
4176 characters of the glyph string. */
4177 if (s->font == NULL)
4178 {
4179 s->font_not_found_p = 1;
4180 s->font = FRAME_FONT (s->f);
4181 }
4182
4183 /* Adjust base line for subscript/superscript text. */
4184 s->ybase += s->first_glyph->voffset;
4185
4186 xassert (s->face && s->face->gc);
4187
4188 /* This glyph string must always be drawn with 16-bit functions. */
4189 s->two_byte_p = 1;
b4192550
KH
4190
4191 return s->gidx + s->nchars;
06a2c219
GM
4192}
4193
4194
b4192550 4195/* Load glyph string S with a sequence characters.
06a2c219 4196 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4197 first glyph to consider, END is the index of the last + 1.
4198 OVERLAPS_P non-zero means S should draw the foreground only, and
4199 use its lines physical height for clipping.
4200
4201 Value is the index of the first glyph not in S. */
06a2c219
GM
4202
4203static int
66ac4b0e 4204x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4205 struct glyph_string *s;
4206 int face_id;
66ac4b0e 4207 int start, end, overlaps_p;
06a2c219
GM
4208{
4209 struct glyph *glyph, *last;
4210 int voffset;
ee569018 4211 int glyph_not_available_p;
06a2c219 4212
06a2c219
GM
4213 xassert (s->f == XFRAME (s->w->frame));
4214 xassert (s->nchars == 0);
4215 xassert (start >= 0 && end > start);
4216
66ac4b0e 4217 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4218 glyph = s->row->glyphs[s->area] + start;
4219 last = s->row->glyphs[s->area] + end;
4220 voffset = glyph->voffset;
4221
ee569018
KH
4222 glyph_not_available_p = glyph->glyph_not_available_p;
4223
06a2c219
GM
4224 while (glyph < last
4225 && glyph->type == CHAR_GLYPH
4226 && glyph->voffset == voffset
ee569018
KH
4227 /* Same face id implies same font, nowadays. */
4228 && glyph->face_id == face_id
4229 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4230 {
ee569018
KH
4231 int two_byte_p;
4232
06a2c219 4233 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4234 s->char2b + s->nchars,
4235 &two_byte_p);
4236 s->two_byte_p = two_byte_p;
06a2c219
GM
4237 ++s->nchars;
4238 xassert (s->nchars <= end - start);
4239 s->width += glyph->pixel_width;
4240 ++glyph;
4241 }
4242
4243 s->font = s->face->font;
4244 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4245
4246 /* If the specified font could not be loaded, use the frame's font,
4247 but record the fact that we couldn't load it in
4248 S->font_not_found_p so that we can draw rectangles for the
4249 characters of the glyph string. */
ee569018 4250 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4251 {
4252 s->font_not_found_p = 1;
4253 s->font = FRAME_FONT (s->f);
4254 }
4255
4256 /* Adjust base line for subscript/superscript text. */
4257 s->ybase += voffset;
66ac4b0e 4258
06a2c219
GM
4259 xassert (s->face && s->face->gc);
4260 return glyph - s->row->glyphs[s->area];
07e34cb0 4261}
dc6f92b8 4262
06a2c219
GM
4263
4264/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4265
dfcf069d 4266static void
06a2c219
GM
4267x_fill_image_glyph_string (s)
4268 struct glyph_string *s;
4269{
4270 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4271 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4272 xassert (s->img);
43d120d8 4273 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4274 s->font = s->face->font;
4275 s->width = s->first_glyph->pixel_width;
4276
4277 /* Adjust base line for subscript/superscript text. */
4278 s->ybase += s->first_glyph->voffset;
4279}
4280
4281
4282/* Fill glyph string S from stretch glyph S->first_glyph. */
4283
4284static void
4285x_fill_stretch_glyph_string (s)
4286 struct glyph_string *s;
4287{
4288 xassert (s->first_glyph->type == STRETCH_GLYPH);
43d120d8 4289 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4290 s->font = s->face->font;
4291 s->width = s->first_glyph->pixel_width;
4292
4293 /* Adjust base line for subscript/superscript text. */
4294 s->ybase += s->first_glyph->voffset;
4295}
4296
4297
4298/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4299 of XChar2b structures for S; it can't be allocated in
4300 x_init_glyph_string because it must be allocated via `alloca'. W
4301 is the window on which S is drawn. ROW and AREA are the glyph row
4302 and area within the row from which S is constructed. START is the
4303 index of the first glyph structure covered by S. HL is a
4304 face-override for drawing S. */
4305
4306static void
4307x_init_glyph_string (s, char2b, w, row, area, start, hl)
4308 struct glyph_string *s;
4309 XChar2b *char2b;
4310 struct window *w;
4311 struct glyph_row *row;
4312 enum glyph_row_area area;
4313 int start;
4314 enum draw_glyphs_face hl;
4315{
4316 bzero (s, sizeof *s);
4317 s->w = w;
4318 s->f = XFRAME (w->frame);
4319 s->display = FRAME_X_DISPLAY (s->f);
4320 s->window = FRAME_X_WINDOW (s->f);
4321 s->char2b = char2b;
4322 s->hl = hl;
4323 s->row = row;
4324 s->area = area;
4325 s->first_glyph = row->glyphs[area] + start;
4326 s->height = row->height;
4327 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4328
9ea173e8
GM
4329 /* Display the internal border below the tool-bar window. */
4330 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4331 s->y -= s->f->output_data.x->internal_border_width;
4332
4333 s->ybase = s->y + row->ascent;
4334}
4335
4336
4337/* Set background width of glyph string S. START is the index of the
4338 first glyph following S. LAST_X is the right-most x-position + 1
4339 in the drawing area. */
4340
4341static INLINE void
4342x_set_glyph_string_background_width (s, start, last_x)
4343 struct glyph_string *s;
4344 int start;
4345 int last_x;
4346{
4347 /* If the face of this glyph string has to be drawn to the end of
4348 the drawing area, set S->extends_to_end_of_line_p. */
4349 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4350
4351 if (start == s->row->used[s->area]
4352 && s->hl == DRAW_NORMAL_TEXT
4353 && ((s->area == TEXT_AREA && s->row->fill_line_p)
4354 || s->face->background != default_face->background
4355 || s->face->stipple != default_face->stipple))
4356 s->extends_to_end_of_line_p = 1;
4357
4358 /* If S extends its face to the end of the line, set its
4359 background_width to the distance to the right edge of the drawing
4360 area. */
4361 if (s->extends_to_end_of_line_p)
1da3fd71 4362 s->background_width = last_x - s->x + 1;
06a2c219
GM
4363 else
4364 s->background_width = s->width;
4365}
4366
4367
4368/* Add a glyph string for a stretch glyph to the list of strings
4369 between HEAD and TAIL. START is the index of the stretch glyph in
4370 row area AREA of glyph row ROW. END is the index of the last glyph
4371 in that glyph row area. X is the current output position assigned
4372 to the new glyph string constructed. HL overrides that face of the
4373 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4374 is the right-most x-position of the drawing area. */
4375
8abee2e1
DL
4376/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4377 and below -- keep them on one line. */
4378#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4379 do \
4380 { \
4381 s = (struct glyph_string *) alloca (sizeof *s); \
4382 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4383 x_fill_stretch_glyph_string (s); \
4384 x_append_glyph_string (&HEAD, &TAIL, s); \
4385 ++START; \
4386 s->x = (X); \
4387 } \
4388 while (0)
4389
4390
4391/* Add a glyph string for an image glyph to the list of strings
4392 between HEAD and TAIL. START is the index of the image glyph in
4393 row area AREA of glyph row ROW. END is the index of the last glyph
4394 in that glyph row area. X is the current output position assigned
4395 to the new glyph string constructed. HL overrides that face of the
4396 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4397 is the right-most x-position of the drawing area. */
4398
8abee2e1 4399#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4400 do \
4401 { \
4402 s = (struct glyph_string *) alloca (sizeof *s); \
4403 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4404 x_fill_image_glyph_string (s); \
4405 x_append_glyph_string (&HEAD, &TAIL, s); \
4406 ++START; \
4407 s->x = (X); \
4408 } \
4409 while (0)
4410
4411
4412/* Add a glyph string for a sequence of character glyphs to the list
4413 of strings between HEAD and TAIL. START is the index of the first
4414 glyph in row area AREA of glyph row ROW that is part of the new
4415 glyph string. END is the index of the last glyph in that glyph row
4416 area. X is the current output position assigned to the new glyph
4417 string constructed. HL overrides that face of the glyph; e.g. it
4418 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4419 right-most x-position of the drawing area. */
4420
8abee2e1 4421#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4422 do \
4423 { \
3e71d8f2 4424 int c, face_id; \
06a2c219
GM
4425 XChar2b *char2b; \
4426 \
43d120d8 4427 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4428 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4429 \
b4192550
KH
4430 s = (struct glyph_string *) alloca (sizeof *s); \
4431 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4432 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4433 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4434 s->x = (X); \
4435 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4436 OVERLAPS_P); \
06a2c219
GM
4437 } \
4438 while (0)
4439
4440
b4192550
KH
4441/* Add a glyph string for a composite sequence to the list of strings
4442 between HEAD and TAIL. START is the index of the first glyph in
4443 row area AREA of glyph row ROW that is part of the new glyph
4444 string. END is the index of the last glyph in that glyph row area.
4445 X is the current output position assigned to the new glyph string
4446 constructed. HL overrides that face of the glyph; e.g. it is
4447 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4448 x-position of the drawing area. */
4449
6c27ec25 4450#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4451 do { \
43d120d8
KH
4452 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4453 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4454 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4455 struct composition *cmp = composition_table[cmp_id]; \
4456 int glyph_len = cmp->glyph_len; \
4457 XChar2b *char2b; \
4458 struct face **faces; \
4459 struct glyph_string *first_s = NULL; \
4460 int n; \
4461 \
ee569018 4462 base_face = base_face->ascii_face; \
b4192550
KH
4463 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4464 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4465 /* At first, fill in `char2b' and `faces'. */ \
4466 for (n = 0; n < glyph_len; n++) \
4467 { \
43d120d8 4468 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4469 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4470 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4471 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4472 this_face_id, char2b + n, 1); \
b4192550
KH
4473 } \
4474 \
4475 /* Make glyph_strings for each glyph sequence that is drawable by \
4476 the same face, and append them to HEAD/TAIL. */ \
4477 for (n = 0; n < cmp->glyph_len;) \
4478 { \
4479 s = (struct glyph_string *) alloca (sizeof *s); \
4480 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4481 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4482 s->cmp = cmp; \
4483 s->gidx = n; \
b4192550
KH
4484 s->x = (X); \
4485 \
4486 if (n == 0) \
4487 first_s = s; \
4488 \
4489 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4490 } \
4491 \
4492 ++START; \
4493 s = first_s; \
4494 } while (0)
4495
4496
06a2c219
GM
4497/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4498 of AREA of glyph row ROW on window W between indices START and END.
4499 HL overrides the face for drawing glyph strings, e.g. it is
4500 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4501 x-positions of the drawing area.
4502
4503 This is an ugly monster macro construct because we must use alloca
4504 to allocate glyph strings (because x_draw_glyphs can be called
4505 asynchronously). */
4506
8abee2e1 4507#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4508 do \
4509 { \
4510 HEAD = TAIL = NULL; \
4511 while (START < END) \
4512 { \
4513 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4514 switch (first_glyph->type) \
4515 { \
4516 case CHAR_GLYPH: \
4517 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4518 TAIL, HL, X, LAST_X, \
4519 OVERLAPS_P); \
06a2c219
GM
4520 break; \
4521 \
b4192550
KH
4522 case COMPOSITE_GLYPH: \
4523 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
4524 HEAD, TAIL, HL, X, LAST_X,\
4525 OVERLAPS_P); \
4526 break; \
4527 \
06a2c219
GM
4528 case STRETCH_GLYPH: \
4529 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
4530 HEAD, TAIL, HL, X, LAST_X); \
4531 break; \
4532 \
4533 case IMAGE_GLYPH: \
4534 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
4535 TAIL, HL, X, LAST_X); \
4536 break; \
4537 \
4538 default: \
4539 abort (); \
4540 } \
4541 \
4542 x_set_glyph_string_background_width (s, START, LAST_X); \
4543 (X) += s->width; \
4544 } \
4545 } \
4546 while (0)
4547
4548
4549/* Draw glyphs between START and END in AREA of ROW on window W,
4550 starting at x-position X. X is relative to AREA in W. HL is a
4551 face-override with the following meaning:
4552
4553 DRAW_NORMAL_TEXT draw normally
4554 DRAW_CURSOR draw in cursor face
4555 DRAW_MOUSE_FACE draw in mouse face.
4556 DRAW_INVERSE_VIDEO draw in mode line face
4557 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
4558 DRAW_IMAGE_RAISED draw an image with a raised relief around it
4559
4560 If REAL_START is non-null, return in *REAL_START the real starting
4561 position for display. This can be different from START in case
4562 overlapping glyphs must be displayed. If REAL_END is non-null,
4563 return in *REAL_END the real end position for display. This can be
4564 different from END in case overlapping glyphs must be displayed.
4565
66ac4b0e
GM
4566 If OVERLAPS_P is non-zero, draw only the foreground of characters
4567 and clip to the physical height of ROW.
4568
06a2c219
GM
4569 Value is the x-position reached, relative to AREA of W. */
4570
4571static int
66ac4b0e
GM
4572x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
4573 overlaps_p)
06a2c219
GM
4574 struct window *w;
4575 int x;
4576 struct glyph_row *row;
4577 enum glyph_row_area area;
4578 int start, end;
4579 enum draw_glyphs_face hl;
4580 int *real_start, *real_end;
66ac4b0e 4581 int overlaps_p;
dc6f92b8 4582{
06a2c219
GM
4583 struct glyph_string *head, *tail;
4584 struct glyph_string *s;
4585 int last_x, area_width;
4586 int x_reached;
4587 int i, j;
4588
4589 /* Let's rather be paranoid than getting a SEGV. */
4590 start = max (0, start);
4591 end = min (end, row->used[area]);
4592 if (real_start)
4593 *real_start = start;
4594 if (real_end)
4595 *real_end = end;
4596
4597 /* Translate X to frame coordinates. Set last_x to the right
4598 end of the drawing area. */
4599 if (row->full_width_p)
4600 {
4601 /* X is relative to the left edge of W, without scroll bars
4602 or flag areas. */
4603 struct frame *f = XFRAME (w->frame);
110859fc 4604 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 4605 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 4606
06a2c219
GM
4607 x += window_left_x;
4608 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
4609 last_x = window_left_x + area_width;
4610
4611 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4612 {
110859fc 4613 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
4614 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
4615 last_x += width;
4616 else
4617 x -= width;
4618 }
dc6f92b8 4619
b9432a85
GM
4620 x += FRAME_INTERNAL_BORDER_WIDTH (f);
4621 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
4622 }
4623 else
dc6f92b8 4624 {
06a2c219
GM
4625 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
4626 area_width = window_box_width (w, area);
4627 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
4628 }
4629
06a2c219
GM
4630 /* Build a doubly-linked list of glyph_string structures between
4631 head and tail from what we have to draw. Note that the macro
4632 BUILD_GLYPH_STRINGS will modify its start parameter. That's
4633 the reason we use a separate variable `i'. */
4634 i = start;
66ac4b0e
GM
4635 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
4636 overlaps_p);
06a2c219
GM
4637 if (tail)
4638 x_reached = tail->x + tail->background_width;
4639 else
4640 x_reached = x;
90e65f07 4641
06a2c219
GM
4642 /* If there are any glyphs with lbearing < 0 or rbearing > width in
4643 the row, redraw some glyphs in front or following the glyph
4644 strings built above. */
66ac4b0e 4645 if (!overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
4646 {
4647 int dummy_x = 0;
4648 struct glyph_string *h, *t;
4649
4650 /* Compute overhangs for all glyph strings. */
4651 for (s = head; s; s = s->next)
4652 x_compute_glyph_string_overhangs (s);
4653
4654 /* Prepend glyph strings for glyphs in front of the first glyph
4655 string that are overwritten because of the first glyph
4656 string's left overhang. The background of all strings
4657 prepended must be drawn because the first glyph string
4658 draws over it. */
4659 i = x_left_overwritten (head);
4660 if (i >= 0)
4661 {
4662 j = i;
4663 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
4664 DRAW_NORMAL_TEXT, dummy_x, last_x,
4665 overlaps_p);
06a2c219
GM
4666 start = i;
4667 if (real_start)
4668 *real_start = start;
4669 x_compute_overhangs_and_x (t, head->x, 1);
4670 x_prepend_glyph_string_lists (&head, &tail, h, t);
4671 }
58769bee 4672
06a2c219
GM
4673 /* Prepend glyph strings for glyphs in front of the first glyph
4674 string that overwrite that glyph string because of their
4675 right overhang. For these strings, only the foreground must
4676 be drawn, because it draws over the glyph string at `head'.
4677 The background must not be drawn because this would overwrite
4678 right overhangs of preceding glyphs for which no glyph
4679 strings exist. */
4680 i = x_left_overwriting (head);
4681 if (i >= 0)
4682 {
4683 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
4684 DRAW_NORMAL_TEXT, dummy_x, last_x,
4685 overlaps_p);
06a2c219
GM
4686 for (s = h; s; s = s->next)
4687 s->background_filled_p = 1;
4688 if (real_start)
4689 *real_start = i;
4690 x_compute_overhangs_and_x (t, head->x, 1);
4691 x_prepend_glyph_string_lists (&head, &tail, h, t);
4692 }
dbcb258a 4693
06a2c219
GM
4694 /* Append glyphs strings for glyphs following the last glyph
4695 string tail that are overwritten by tail. The background of
4696 these strings has to be drawn because tail's foreground draws
4697 over it. */
4698 i = x_right_overwritten (tail);
4699 if (i >= 0)
4700 {
4701 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4702 DRAW_NORMAL_TEXT, x, last_x,
4703 overlaps_p);
06a2c219
GM
4704 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4705 x_append_glyph_string_lists (&head, &tail, h, t);
4706 if (real_end)
4707 *real_end = i;
4708 }
dc6f92b8 4709
06a2c219
GM
4710 /* Append glyph strings for glyphs following the last glyph
4711 string tail that overwrite tail. The foreground of such
4712 glyphs has to be drawn because it writes into the background
4713 of tail. The background must not be drawn because it could
4714 paint over the foreground of following glyphs. */
4715 i = x_right_overwriting (tail);
4716 if (i >= 0)
4717 {
4718 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4719 DRAW_NORMAL_TEXT, x, last_x,
4720 overlaps_p);
06a2c219
GM
4721 for (s = h; s; s = s->next)
4722 s->background_filled_p = 1;
4723 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4724 x_append_glyph_string_lists (&head, &tail, h, t);
4725 if (real_end)
4726 *real_end = i;
4727 }
4728 }
58769bee 4729
06a2c219
GM
4730 /* Draw all strings. */
4731 for (s = head; s; s = s->next)
4732 x_draw_glyph_string (s);
dc6f92b8 4733
06a2c219
GM
4734 /* Value is the x-position up to which drawn, relative to AREA of W.
4735 This doesn't include parts drawn because of overhangs. */
4736 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
4737 if (!row->full_width_p)
4738 {
4739 if (area > LEFT_MARGIN_AREA)
4740 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
4741 if (area > TEXT_AREA)
4742 x_reached -= window_box_width (w, TEXT_AREA);
4743 }
4744 return x_reached;
4745}
dc6f92b8 4746
dc6f92b8 4747
66ac4b0e
GM
4748/* Fix the display of area AREA of overlapping row ROW in window W. */
4749
4750static void
4751x_fix_overlapping_area (w, row, area)
4752 struct window *w;
4753 struct glyph_row *row;
4754 enum glyph_row_area area;
4755{
4756 int i, x;
4757
4758 BLOCK_INPUT;
4759
4760 if (area == LEFT_MARGIN_AREA)
4761 x = 0;
4762 else if (area == TEXT_AREA)
4763 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
4764 else
4765 x = (window_box_width (w, LEFT_MARGIN_AREA)
4766 + window_box_width (w, TEXT_AREA));
4767
4768 for (i = 0; i < row->used[area];)
4769 {
4770 if (row->glyphs[area][i].overlaps_vertically_p)
4771 {
4772 int start = i, start_x = x;
4773
4774 do
4775 {
4776 x += row->glyphs[area][i].pixel_width;
4777 ++i;
4778 }
4779 while (i < row->used[area]
4780 && row->glyphs[area][i].overlaps_vertically_p);
4781
4782 x_draw_glyphs (w, start_x, row, area, start, i,
4783 (row->inverse_p
4784 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
4785 NULL, NULL, 1);
4786 }
4787 else
4788 {
4789 x += row->glyphs[area][i].pixel_width;
4790 ++i;
4791 }
4792 }
4793
4794 UNBLOCK_INPUT;
4795}
4796
4797
06a2c219
GM
4798/* Output LEN glyphs starting at START at the nominal cursor position.
4799 Advance the nominal cursor over the text. The global variable
4800 updated_window contains the window being updated, updated_row is
4801 the glyph row being updated, and updated_area is the area of that
4802 row being updated. */
dc6f92b8 4803
06a2c219
GM
4804static void
4805x_write_glyphs (start, len)
4806 struct glyph *start;
4807 int len;
4808{
4809 int x, hpos, real_start, real_end;
d9cdbb3d 4810
06a2c219 4811 xassert (updated_window && updated_row);
dc6f92b8 4812 BLOCK_INPUT;
06a2c219
GM
4813
4814 /* Write glyphs. */
dc6f92b8 4815
06a2c219
GM
4816 hpos = start - updated_row->glyphs[updated_area];
4817 x = x_draw_glyphs (updated_window, output_cursor.x,
4818 updated_row, updated_area,
4819 hpos, hpos + len,
4820 (updated_row->inverse_p
4821 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
66ac4b0e 4822 &real_start, &real_end, 0);
b30ec466 4823
06a2c219
GM
4824 /* If we drew over the cursor, note that it is not visible any more. */
4825 note_overwritten_text_cursor (updated_window, real_start,
4826 real_end - real_start);
dc6f92b8
JB
4827
4828 UNBLOCK_INPUT;
06a2c219
GM
4829
4830 /* Advance the output cursor. */
4831 output_cursor.hpos += len;
4832 output_cursor.x = x;
dc6f92b8
JB
4833}
4834
0cdd0c9f 4835
06a2c219 4836/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 4837
06a2c219
GM
4838static void
4839x_insert_glyphs (start, len)
4840 struct glyph *start;
4841 register int len;
4842{
4843 struct frame *f;
4844 struct window *w;
4845 int line_height, shift_by_width, shifted_region_width;
4846 struct glyph_row *row;
4847 struct glyph *glyph;
4848 int frame_x, frame_y, hpos, real_start, real_end;
58769bee 4849
06a2c219 4850 xassert (updated_window && updated_row);
0cdd0c9f 4851 BLOCK_INPUT;
06a2c219
GM
4852 w = updated_window;
4853 f = XFRAME (WINDOW_FRAME (w));
4854
4855 /* Get the height of the line we are in. */
4856 row = updated_row;
4857 line_height = row->height;
4858
4859 /* Get the width of the glyphs to insert. */
4860 shift_by_width = 0;
4861 for (glyph = start; glyph < start + len; ++glyph)
4862 shift_by_width += glyph->pixel_width;
4863
4864 /* Get the width of the region to shift right. */
4865 shifted_region_width = (window_box_width (w, updated_area)
4866 - output_cursor.x
4867 - shift_by_width);
4868
4869 /* Shift right. */
4870 frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x);
4871 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
4872 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
4873 f->output_data.x->normal_gc,
4874 frame_x, frame_y,
4875 shifted_region_width, line_height,
4876 frame_x + shift_by_width, frame_y);
4877
4878 /* Write the glyphs. */
4879 hpos = start - row->glyphs[updated_area];
4880 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
66ac4b0e 4881 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
06a2c219
GM
4882 note_overwritten_text_cursor (w, real_start, real_end - real_start);
4883
4884 /* Advance the output cursor. */
4885 output_cursor.hpos += len;
4886 output_cursor.x += shift_by_width;
0cdd0c9f
RS
4887 UNBLOCK_INPUT;
4888}
0cdd0c9f 4889
0cdd0c9f 4890
06a2c219
GM
4891/* Delete N glyphs at the nominal cursor position. Not implemented
4892 for X frames. */
c83febd7
RS
4893
4894static void
06a2c219
GM
4895x_delete_glyphs (n)
4896 register int n;
c83febd7 4897{
06a2c219 4898 abort ();
c83febd7
RS
4899}
4900
0cdd0c9f 4901
06a2c219
GM
4902/* Erase the current text line from the nominal cursor position
4903 (inclusive) to pixel column TO_X (exclusive). The idea is that
4904 everything from TO_X onward is already erased.
4905
4906 TO_X is a pixel position relative to updated_area of
4907 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 4908
06a2c219
GM
4909static void
4910x_clear_end_of_line (to_x)
4911 int to_x;
4912{
4913 struct frame *f;
4914 struct window *w = updated_window;
4915 int max_x, min_y, max_y;
4916 int from_x, from_y, to_y;
4917
4918 xassert (updated_window && updated_row);
4919 f = XFRAME (w->frame);
4920
4921 if (updated_row->full_width_p)
4922 {
4923 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
4924 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4925 && !w->pseudo_window_p)
4926 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 4927 }
06a2c219
GM
4928 else
4929 max_x = window_box_width (w, updated_area);
4930 max_y = window_text_bottom_y (w);
dc6f92b8 4931
06a2c219
GM
4932 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
4933 of window. For TO_X > 0, truncate to end of drawing area. */
4934 if (to_x == 0)
4935 return;
4936 else if (to_x < 0)
4937 to_x = max_x;
4938 else
4939 to_x = min (to_x, max_x);
dbc4e1c1 4940
06a2c219
GM
4941 to_y = min (max_y, output_cursor.y + updated_row->height);
4942
4943 /* Notice if the cursor will be cleared by this operation. */
4944 if (!updated_row->full_width_p)
4945 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
dbc4e1c1 4946
06a2c219
GM
4947 from_x = output_cursor.x;
4948
4949 /* Translate to frame coordinates. */
4950 if (updated_row->full_width_p)
4951 {
4952 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
4953 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
4954 }
0cdd0c9f
RS
4955 else
4956 {
06a2c219
GM
4957 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
4958 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
4959 }
4960
045dee35 4961 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
4962 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
4963 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
4964
4965 /* Prevent inadvertently clearing to end of the X window. */
4966 if (to_x > from_x && to_y > from_y)
4967 {
4968 BLOCK_INPUT;
4969 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4970 from_x, from_y, to_x - from_x, to_y - from_y,
4971 False);
4972 UNBLOCK_INPUT;
0cdd0c9f 4973 }
0cdd0c9f 4974}
dbc4e1c1 4975
0cdd0c9f 4976
06a2c219 4977/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 4978 frame. Otherwise clear the selected frame. */
06a2c219
GM
4979
4980static void
4981x_clear_frame ()
0cdd0c9f 4982{
06a2c219 4983 struct frame *f;
0cdd0c9f 4984
06a2c219
GM
4985 if (updating_frame)
4986 f = updating_frame;
0cdd0c9f 4987 else
b86bd3dd 4988 f = SELECTED_FRAME ();
58769bee 4989
06a2c219
GM
4990 /* Clearing the frame will erase any cursor, so mark them all as no
4991 longer visible. */
4992 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4993 output_cursor.hpos = output_cursor.vpos = 0;
4994 output_cursor.x = -1;
4995
4996 /* We don't set the output cursor here because there will always
4997 follow an explicit cursor_to. */
4998 BLOCK_INPUT;
4999 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5000
5001 /* We have to clear the scroll bars, too. If we have changed
5002 colors or something like that, then they should be notified. */
5003 x_scroll_bar_clear (f);
0cdd0c9f 5004
06a2c219
GM
5005 XFlush (FRAME_X_DISPLAY (f));
5006 UNBLOCK_INPUT;
dc6f92b8 5007}
06a2c219
GM
5008
5009
dc6f92b8 5010\f
dbc4e1c1
JB
5011/* Invert the middle quarter of the frame for .15 sec. */
5012
06a2c219
GM
5013/* We use the select system call to do the waiting, so we have to make
5014 sure it's available. If it isn't, we just won't do visual bells. */
5015
dbc4e1c1
JB
5016#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5017
06a2c219
GM
5018
5019/* Subtract the `struct timeval' values X and Y, storing the result in
5020 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5021
5022static int
5023timeval_subtract (result, x, y)
5024 struct timeval *result, x, y;
5025{
06a2c219
GM
5026 /* Perform the carry for the later subtraction by updating y. This
5027 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5028 if (x.tv_usec < y.tv_usec)
5029 {
5030 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5031 y.tv_usec -= 1000000 * nsec;
5032 y.tv_sec += nsec;
5033 }
06a2c219 5034
dbc4e1c1
JB
5035 if (x.tv_usec - y.tv_usec > 1000000)
5036 {
5037 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5038 y.tv_usec += 1000000 * nsec;
5039 y.tv_sec -= nsec;
5040 }
5041
06a2c219
GM
5042 /* Compute the time remaining to wait. tv_usec is certainly
5043 positive. */
dbc4e1c1
JB
5044 result->tv_sec = x.tv_sec - y.tv_sec;
5045 result->tv_usec = x.tv_usec - y.tv_usec;
5046
06a2c219
GM
5047 /* Return indication of whether the result should be considered
5048 negative. */
dbc4e1c1
JB
5049 return x.tv_sec < y.tv_sec;
5050}
dc6f92b8 5051
dfcf069d 5052void
f676886a
JB
5053XTflash (f)
5054 struct frame *f;
dc6f92b8 5055{
dbc4e1c1 5056 BLOCK_INPUT;
dc6f92b8 5057
dbc4e1c1
JB
5058 {
5059 GC gc;
dc6f92b8 5060
06a2c219
GM
5061 /* Create a GC that will use the GXxor function to flip foreground
5062 pixels into background pixels. */
dbc4e1c1
JB
5063 {
5064 XGCValues values;
dc6f92b8 5065
dbc4e1c1 5066 values.function = GXxor;
7556890b
RS
5067 values.foreground = (f->output_data.x->foreground_pixel
5068 ^ f->output_data.x->background_pixel);
58769bee 5069
334208b7 5070 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5071 GCFunction | GCForeground, &values);
5072 }
dc6f92b8 5073
dbc4e1c1 5074 {
e84e14c3
RS
5075 /* Get the height not including a menu bar widget. */
5076 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5077 /* Height of each line to flash. */
5078 int flash_height = FRAME_LINE_HEIGHT (f);
5079 /* These will be the left and right margins of the rectangles. */
5080 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5081 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5082
5083 int width;
5084
5085 /* Don't flash the area between a scroll bar and the frame
5086 edge it is next to. */
5087 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5088 {
5089 case vertical_scroll_bar_left:
5090 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5091 break;
5092
5093 case vertical_scroll_bar_right:
5094 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5095 break;
06a2c219
GM
5096
5097 default:
5098 break;
e84e14c3
RS
5099 }
5100
5101 width = flash_right - flash_left;
5102
5103 /* If window is tall, flash top and bottom line. */
5104 if (height > 3 * FRAME_LINE_HEIGHT (f))
5105 {
5106 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5107 flash_left,
5108 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5109 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5110 width, flash_height);
5111 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5112 flash_left,
5113 (height - flash_height
5114 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5115 width, flash_height);
5116 }
5117 else
5118 /* If it is short, flash it all. */
5119 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5120 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5121 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5122
06a2c219 5123 x_flush (f);
dc6f92b8 5124
dbc4e1c1 5125 {
06a2c219 5126 struct timeval wakeup;
dc6f92b8 5127
66c30ea1 5128 EMACS_GET_TIME (wakeup);
dc6f92b8 5129
dbc4e1c1
JB
5130 /* Compute time to wait until, propagating carry from usecs. */
5131 wakeup.tv_usec += 150000;
5132 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5133 wakeup.tv_usec %= 1000000;
5134
5135 /* Keep waiting until past the time wakeup. */
5136 while (1)
5137 {
5138 struct timeval timeout;
5139
66c30ea1 5140 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
5141
5142 /* In effect, timeout = wakeup - timeout.
5143 Break if result would be negative. */
5144 if (timeval_subtract (&timeout, wakeup, timeout))
5145 break;
5146
5147 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5148 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5149 }
5150 }
58769bee 5151
e84e14c3
RS
5152 /* If window is tall, flash top and bottom line. */
5153 if (height > 3 * FRAME_LINE_HEIGHT (f))
5154 {
5155 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5156 flash_left,
5157 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5158 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5159 width, flash_height);
5160 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5161 flash_left,
5162 (height - flash_height
5163 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5164 width, flash_height);
5165 }
5166 else
5167 /* If it is short, flash it all. */
5168 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5169 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5170 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5171
334208b7 5172 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5173 x_flush (f);
dc6f92b8 5174 }
dbc4e1c1
JB
5175 }
5176
5177 UNBLOCK_INPUT;
dc6f92b8
JB
5178}
5179
06a2c219 5180#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5181
5182
dc6f92b8
JB
5183/* Make audible bell. */
5184
dfcf069d 5185void
dc6f92b8
JB
5186XTring_bell ()
5187{
b86bd3dd
GM
5188 struct frame *f = SELECTED_FRAME ();
5189
5190 if (FRAME_X_DISPLAY (f))
5191 {
dbc4e1c1 5192#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5193 if (visible_bell)
5194 XTflash (f);
5195 else
dbc4e1c1 5196#endif
b86bd3dd
GM
5197 {
5198 BLOCK_INPUT;
5199 XBell (FRAME_X_DISPLAY (f), 0);
5200 XFlush (FRAME_X_DISPLAY (f));
5201 UNBLOCK_INPUT;
5202 }
dc6f92b8
JB
5203 }
5204}
06a2c219 5205
dc6f92b8 5206\f
06a2c219
GM
5207/* Specify how many text lines, from the top of the window,
5208 should be affected by insert-lines and delete-lines operations.
5209 This, and those operations, are used only within an update
5210 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5211
dfcf069d 5212static void
06a2c219
GM
5213XTset_terminal_window (n)
5214 register int n;
dc6f92b8 5215{
06a2c219 5216 /* This function intentionally left blank. */
dc6f92b8
JB
5217}
5218
06a2c219
GM
5219
5220\f
5221/***********************************************************************
5222 Line Dance
5223 ***********************************************************************/
5224
5225/* Perform an insert-lines or delete-lines operation, inserting N
5226 lines or deleting -N lines at vertical position VPOS. */
5227
dfcf069d 5228static void
06a2c219
GM
5229x_ins_del_lines (vpos, n)
5230 int vpos, n;
dc6f92b8
JB
5231{
5232 abort ();
5233}
06a2c219
GM
5234
5235
5236/* Scroll part of the display as described by RUN. */
dc6f92b8 5237
dfcf069d 5238static void
06a2c219
GM
5239x_scroll_run (w, run)
5240 struct window *w;
5241 struct run *run;
dc6f92b8 5242{
06a2c219
GM
5243 struct frame *f = XFRAME (w->frame);
5244 int x, y, width, height, from_y, to_y, bottom_y;
5245
5246 /* Get frame-relative bounding box of the text display area of W,
5247 without mode lines. Include in this box the flags areas to the
5248 left and right of W. */
5249 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5250 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5251 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5252
5253 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5254 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5255 bottom_y = y + height;
dc6f92b8 5256
06a2c219
GM
5257 if (to_y < from_y)
5258 {
5259 /* Scrolling up. Make sure we don't copy part of the mode
5260 line at the bottom. */
5261 if (from_y + run->height > bottom_y)
5262 height = bottom_y - from_y;
5263 else
5264 height = run->height;
5265 }
dc6f92b8 5266 else
06a2c219
GM
5267 {
5268 /* Scolling down. Make sure we don't copy over the mode line.
5269 at the bottom. */
5270 if (to_y + run->height > bottom_y)
5271 height = bottom_y - to_y;
5272 else
5273 height = run->height;
5274 }
7a13e894 5275
06a2c219
GM
5276 BLOCK_INPUT;
5277
5278 /* Cursor off. Will be switched on again in x_update_window_end. */
5279 updated_window = w;
5280 x_clear_cursor (w);
5281
5282 XCopyArea (FRAME_X_DISPLAY (f),
5283 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5284 f->output_data.x->normal_gc,
5285 x, from_y,
5286 width, height,
5287 x, to_y);
5288
5289 UNBLOCK_INPUT;
5290}
dc6f92b8 5291
dc6f92b8 5292
06a2c219
GM
5293\f
5294/***********************************************************************
5295 Exposure Events
5296 ***********************************************************************/
5297
5298/* Redisplay an exposed area of frame F. X and Y are the upper-left
5299 corner of the exposed rectangle. W and H are width and height of
5300 the exposed area. All are pixel values. W or H zero means redraw
5301 the entire frame. */
dc6f92b8 5302
06a2c219
GM
5303static void
5304expose_frame (f, x, y, w, h)
5305 struct frame *f;
5306 int x, y, w, h;
dc6f92b8 5307{
06a2c219 5308 XRectangle r;
dc6f92b8 5309
06a2c219 5310 TRACE ((stderr, "expose_frame "));
dc6f92b8 5311
06a2c219
GM
5312 /* No need to redraw if frame will be redrawn soon. */
5313 if (FRAME_GARBAGED_P (f))
dc6f92b8 5314 {
06a2c219
GM
5315 TRACE ((stderr, " garbaged\n"));
5316 return;
5317 }
5318
5319 /* If basic faces haven't been realized yet, there is no point in
5320 trying to redraw anything. This can happen when we get an expose
5321 event while Emacs is starting, e.g. by moving another window. */
5322 if (FRAME_FACE_CACHE (f) == NULL
5323 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5324 {
5325 TRACE ((stderr, " no faces\n"));
5326 return;
58769bee 5327 }
06a2c219
GM
5328
5329 if (w == 0 || h == 0)
58769bee 5330 {
06a2c219
GM
5331 r.x = r.y = 0;
5332 r.width = CANON_X_UNIT (f) * f->width;
5333 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5334 }
5335 else
5336 {
06a2c219
GM
5337 r.x = x;
5338 r.y = y;
5339 r.width = w;
5340 r.height = h;
5341 }
5342
5343 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
5344 expose_window_tree (XWINDOW (f->root_window), &r);
5345
9ea173e8 5346 if (WINDOWP (f->tool_bar_window))
06a2c219 5347 {
9ea173e8 5348 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
5349 XRectangle window_rect;
5350 XRectangle intersection_rect;
5351 int window_x, window_y, window_width, window_height;
5352
5353
5354 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5355 window_rect.x = window_x;
5356 window_rect.y = window_y;
5357 window_rect.width = window_width;
5358 window_rect.height = window_height;
5359
5360 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5361 expose_window (w, &intersection_rect);
5362 }
5363
5364#ifndef USE_X_TOOLKIT
5365 if (WINDOWP (f->menu_bar_window))
5366 {
5367 struct window *w = XWINDOW (f->menu_bar_window);
5368 XRectangle window_rect;
5369 XRectangle intersection_rect;
5370 int window_x, window_y, window_width, window_height;
5371
5372
5373 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5374 window_rect.x = window_x;
5375 window_rect.y = window_y;
5376 window_rect.width = window_width;
5377 window_rect.height = window_height;
5378
5379 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5380 expose_window (w, &intersection_rect);
dc6f92b8 5381 }
06a2c219 5382#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5383}
5384
06a2c219
GM
5385
5386/* Redraw (parts) of all windows in the window tree rooted at W that
5387 intersect R. R contains frame pixel coordinates. */
5388
58769bee 5389static void
06a2c219
GM
5390expose_window_tree (w, r)
5391 struct window *w;
5392 XRectangle *r;
dc6f92b8 5393{
06a2c219
GM
5394 while (w)
5395 {
5396 if (!NILP (w->hchild))
5397 expose_window_tree (XWINDOW (w->hchild), r);
5398 else if (!NILP (w->vchild))
5399 expose_window_tree (XWINDOW (w->vchild), r);
5400 else
5401 {
5402 XRectangle window_rect;
5403 XRectangle intersection_rect;
5404 struct frame *f = XFRAME (w->frame);
5405 int window_x, window_y, window_width, window_height;
5406
5407 /* Frame-relative pixel rectangle of W. */
5408 window_box (w, -1, &window_x, &window_y, &window_width,
5409 &window_height);
5410 window_rect.x
5411 = (window_x
110859fc 5412 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
714dc26c 5413 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
06a2c219
GM
5414 window_rect.y = window_y;
5415 window_rect.width
5416 = (window_width
110859fc 5417 + FRAME_X_FLAGS_AREA_WIDTH (f)
06a2c219
GM
5418 + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
5419 window_rect.height
5420 = window_height + CURRENT_MODE_LINE_HEIGHT (w);
5421
5422 if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
5423 expose_window (w, &intersection_rect);
5424 }
58769bee 5425
06a2c219
GM
5426 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5427 }
5428}
58769bee 5429
dc6f92b8 5430
06a2c219
GM
5431/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5432 which intersects rectangle R. R is in window-relative coordinates. */
5433
5434static void
5435expose_area (w, row, r, area)
5436 struct window *w;
5437 struct glyph_row *row;
5438 XRectangle *r;
5439 enum glyph_row_area area;
5440{
5441 int x;
5442 struct glyph *first = row->glyphs[area];
5443 struct glyph *end = row->glyphs[area] + row->used[area];
5444 struct glyph *last;
5445 int first_x;
5446
5447 /* Set x to the window-relative start position for drawing glyphs of
5448 AREA. The first glyph of the text area can be partially visible.
5449 The first glyphs of other areas cannot. */
5450 if (area == LEFT_MARGIN_AREA)
5451 x = 0;
5452 else if (area == TEXT_AREA)
5453 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5454 else
5455 x = (window_box_width (w, LEFT_MARGIN_AREA)
5456 + window_box_width (w, TEXT_AREA));
5457
6fb13182
GM
5458 if (area == TEXT_AREA && row->fill_line_p)
5459 /* If row extends face to end of line write the whole line. */
5460 x_draw_glyphs (w, x, row, area,
5461 0, row->used[area],
06a2c219 5462 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5463 NULL, NULL, 0);
6fb13182
GM
5464 else
5465 {
5466 /* Find the first glyph that must be redrawn. */
5467 while (first < end
5468 && x + first->pixel_width < r->x)
5469 {
5470 x += first->pixel_width;
5471 ++first;
5472 }
5473
5474 /* Find the last one. */
5475 last = first;
5476 first_x = x;
5477 while (last < end
5478 && x < r->x + r->width)
5479 {
5480 x += last->pixel_width;
5481 ++last;
5482 }
5483
5484 /* Repaint. */
5485 if (last > first)
5486 x_draw_glyphs (w, first_x, row, area,
5487 first - row->glyphs[area],
5488 last - row->glyphs[area],
5489 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5490 NULL, NULL, 0);
5491 }
06a2c219
GM
5492}
5493
58769bee 5494
06a2c219
GM
5495/* Redraw the parts of the glyph row ROW on window W intersecting
5496 rectangle R. R is in window-relative coordinates. */
dc6f92b8 5497
06a2c219
GM
5498static void
5499expose_line (w, row, r)
5500 struct window *w;
5501 struct glyph_row *row;
5502 XRectangle *r;
5503{
5504 xassert (row->enabled_p);
5505
5506 if (row->mode_line_p || w->pseudo_window_p)
5507 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5508 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5509 NULL, NULL, 0);
06a2c219
GM
5510 else
5511 {
5512 if (row->used[LEFT_MARGIN_AREA])
5513 expose_area (w, row, r, LEFT_MARGIN_AREA);
5514 if (row->used[TEXT_AREA])
5515 expose_area (w, row, r, TEXT_AREA);
5516 if (row->used[RIGHT_MARGIN_AREA])
5517 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5518 x_draw_row_bitmaps (w, row);
5519 }
5520}
dc6f92b8 5521
58769bee 5522
06a2c219
GM
5523/* Return non-zero if W's cursor intersects rectangle R. */
5524
5525static int
5526x_phys_cursor_in_rect_p (w, r)
5527 struct window *w;
5528 XRectangle *r;
5529{
5530 XRectangle cr, result;
5531 struct glyph *cursor_glyph;
5532
5533 cursor_glyph = get_phys_cursor_glyph (w);
5534 if (cursor_glyph)
5535 {
5536 cr.x = w->phys_cursor.x;
5537 cr.y = w->phys_cursor.y;
5538 cr.width = cursor_glyph->pixel_width;
5539 cr.height = w->phys_cursor_height;
5540 return x_intersect_rectangles (&cr, r, &result);
5541 }
5542 else
5543 return 0;
dc6f92b8 5544}
dc6f92b8 5545
06a2c219
GM
5546
5547/* Redraw a rectangle of window W. R is a rectangle in window
5548 relative coordinates. Call this function with input blocked. */
dc6f92b8
JB
5549
5550static void
06a2c219
GM
5551expose_window (w, r)
5552 struct window *w;
5553 XRectangle *r;
dc6f92b8 5554{
06a2c219
GM
5555 struct glyph_row *row;
5556 int y;
5557 int yb = window_text_bottom_y (w);
5558 int cursor_cleared_p;
dc6f92b8 5559
80c32bcc
GM
5560 /* If window is not yet fully initialized, do nothing. This can
5561 happen when toolkit scroll bars are used and a window is split.
5562 Reconfiguring the scroll bar will generate an expose for a newly
5563 created window. */
5564 if (w->current_matrix == NULL)
5565 return;
5566
06a2c219
GM
5567 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
5568 r->x, r->y, r->width, r->height));
dc6f92b8 5569
06a2c219
GM
5570 /* Convert to window coordinates. */
5571 r->x = FRAME_TO_WINDOW_PIXEL_X (w, r->x);
5572 r->y = FRAME_TO_WINDOW_PIXEL_Y (w, r->y);
dc6f92b8 5573
06a2c219
GM
5574 /* Turn off the cursor. */
5575 if (!w->pseudo_window_p
5576 && x_phys_cursor_in_rect_p (w, r))
5577 {
5578 x_clear_cursor (w);
5579 cursor_cleared_p = 1;
5580 }
5581 else
5582 cursor_cleared_p = 0;
5583
5584 /* Find the first row intersecting the rectangle R. */
5585 row = w->current_matrix->rows;
5586 y = 0;
5587 while (row->enabled_p
5588 && y < yb
5589 && y + row->height < r->y)
5590 {
5591 y += row->height;
5592 ++row;
5593 }
5594
dc6f92b8 5595 /* Display the text in the rectangle, one text line at a time. */
06a2c219
GM
5596 while (row->enabled_p
5597 && y < yb
5598 && y < r->y + r->height)
5599 {
5600 expose_line (w, row, r);
5601 y += row->height;
5602 ++row;
5603 }
5604
5605 /* Display the mode line if there is one. */
5606 if (WINDOW_WANTS_MODELINE_P (w)
5607 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
5608 row->enabled_p)
5609 && row->y < r->y + r->height)
5610 expose_line (w, row, r);
dc6f92b8 5611
06a2c219 5612 if (!w->pseudo_window_p)
dc6f92b8 5613 {
06a2c219
GM
5614 /* Draw border between windows. */
5615 x_draw_vertical_border (w);
5616
5617 /* Turn the cursor on again. */
5618 if (cursor_cleared_p)
5619 x_update_window_cursor (w, 1);
5620 }
5621}
dc6f92b8 5622
dc6f92b8 5623
06a2c219
GM
5624/* Determine the intersection of two rectangles R1 and R2. Return
5625 the intersection in *RESULT. Value is non-zero if RESULT is not
5626 empty. */
5627
5628static int
5629x_intersect_rectangles (r1, r2, result)
5630 XRectangle *r1, *r2, *result;
5631{
5632 XRectangle *left, *right;
5633 XRectangle *upper, *lower;
5634 int intersection_p = 0;
5635
5636 /* Rearrange so that R1 is the left-most rectangle. */
5637 if (r1->x < r2->x)
5638 left = r1, right = r2;
5639 else
5640 left = r2, right = r1;
5641
5642 /* X0 of the intersection is right.x0, if this is inside R1,
5643 otherwise there is no intersection. */
5644 if (right->x <= left->x + left->width)
5645 {
5646 result->x = right->x;
5647
5648 /* The right end of the intersection is the minimum of the
5649 the right ends of left and right. */
5650 result->width = (min (left->x + left->width, right->x + right->width)
5651 - result->x);
5652
5653 /* Same game for Y. */
5654 if (r1->y < r2->y)
5655 upper = r1, lower = r2;
5656 else
5657 upper = r2, lower = r1;
5658
5659 /* The upper end of the intersection is lower.y0, if this is inside
5660 of upper. Otherwise, there is no intersection. */
5661 if (lower->y <= upper->y + upper->height)
dc43ef94 5662 {
06a2c219
GM
5663 result->y = lower->y;
5664
5665 /* The lower end of the intersection is the minimum of the lower
5666 ends of upper and lower. */
5667 result->height = (min (lower->y + lower->height,
5668 upper->y + upper->height)
5669 - result->y);
5670 intersection_p = 1;
dc43ef94 5671 }
dc6f92b8
JB
5672 }
5673
06a2c219 5674 return intersection_p;
dc6f92b8 5675}
06a2c219
GM
5676
5677
5678
5679
dc6f92b8 5680\f
dc6f92b8 5681static void
334208b7
RS
5682frame_highlight (f)
5683 struct frame *f;
dc6f92b8 5684{
b3e1e05c
JB
5685 /* We used to only do this if Vx_no_window_manager was non-nil, but
5686 the ICCCM (section 4.1.6) says that the window's border pixmap
5687 and border pixel are window attributes which are "private to the
5688 client", so we can always change it to whatever we want. */
5689 BLOCK_INPUT;
334208b7 5690 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5691 f->output_data.x->border_pixel);
b3e1e05c 5692 UNBLOCK_INPUT;
5d46f928 5693 x_update_cursor (f, 1);
dc6f92b8
JB
5694}
5695
5696static void
334208b7
RS
5697frame_unhighlight (f)
5698 struct frame *f;
dc6f92b8 5699{
b3e1e05c
JB
5700 /* We used to only do this if Vx_no_window_manager was non-nil, but
5701 the ICCCM (section 4.1.6) says that the window's border pixmap
5702 and border pixel are window attributes which are "private to the
5703 client", so we can always change it to whatever we want. */
5704 BLOCK_INPUT;
334208b7 5705 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5706 f->output_data.x->border_tile);
b3e1e05c 5707 UNBLOCK_INPUT;
5d46f928 5708 x_update_cursor (f, 1);
dc6f92b8 5709}
dc6f92b8 5710
f676886a
JB
5711/* The focus has changed. Update the frames as necessary to reflect
5712 the new situation. Note that we can't change the selected frame
c5acd733 5713 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 5714 Each event gets marked with the frame in which it occurred, so the
c5acd733 5715 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 5716
6d4238f3 5717static void
0f941935
KH
5718x_new_focus_frame (dpyinfo, frame)
5719 struct x_display_info *dpyinfo;
f676886a 5720 struct frame *frame;
dc6f92b8 5721{
0f941935 5722 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 5723
0f941935 5724 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 5725 {
58769bee 5726 /* Set this before calling other routines, so that they see
f676886a 5727 the correct value of x_focus_frame. */
0f941935 5728 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
5729
5730 if (old_focus && old_focus->auto_lower)
f676886a 5731 x_lower_frame (old_focus);
dc6f92b8
JB
5732
5733#if 0
f676886a 5734 selected_frame = frame;
e0c1aef2
KH
5735 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
5736 selected_frame);
f676886a
JB
5737 Fselect_window (selected_frame->selected_window);
5738 choose_minibuf_frame ();
c118dd06 5739#endif /* ! 0 */
dc6f92b8 5740
0f941935
KH
5741 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
5742 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
5743 else
5744 pending_autoraise_frame = 0;
6d4238f3 5745 }
dc6f92b8 5746
0f941935 5747 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
5748}
5749
37c2c98b
RS
5750/* Handle an event saying the mouse has moved out of an Emacs frame. */
5751
5752void
0f941935
KH
5753x_mouse_leave (dpyinfo)
5754 struct x_display_info *dpyinfo;
37c2c98b 5755{
0f941935 5756 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 5757}
6d4238f3 5758
f451eb13
JB
5759/* The focus has changed, or we have redirected a frame's focus to
5760 another frame (this happens when a frame uses a surrogate
06a2c219 5761 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
5762
5763 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 5764 frame is being highlighted or un-highlighted; we only use it to find
0f941935 5765 the appropriate X display info. */
06a2c219 5766
6d4238f3 5767static void
0f941935
KH
5768XTframe_rehighlight (frame)
5769 struct frame *frame;
6d4238f3 5770{
0f941935
KH
5771 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
5772}
6d4238f3 5773
0f941935
KH
5774static void
5775x_frame_rehighlight (dpyinfo)
5776 struct x_display_info *dpyinfo;
5777{
5778 struct frame *old_highlight = dpyinfo->x_highlight_frame;
5779
5780 if (dpyinfo->x_focus_frame)
6d4238f3 5781 {
0f941935
KH
5782 dpyinfo->x_highlight_frame
5783 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
5784 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
5785 : dpyinfo->x_focus_frame);
5786 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 5787 {
0f941935
KH
5788 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
5789 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 5790 }
dc6f92b8 5791 }
6d4238f3 5792 else
0f941935 5793 dpyinfo->x_highlight_frame = 0;
dc6f92b8 5794
0f941935 5795 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
5796 {
5797 if (old_highlight)
f676886a 5798 frame_unhighlight (old_highlight);
0f941935
KH
5799 if (dpyinfo->x_highlight_frame)
5800 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 5801 }
dc6f92b8 5802}
06a2c219
GM
5803
5804
dc6f92b8 5805\f
06a2c219 5806/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 5807
28430d3c
JB
5808/* Initialize mode_switch_bit and modifier_meaning. */
5809static void
334208b7
RS
5810x_find_modifier_meanings (dpyinfo)
5811 struct x_display_info *dpyinfo;
28430d3c 5812{
f689eb05 5813 int min_code, max_code;
28430d3c
JB
5814 KeySym *syms;
5815 int syms_per_code;
5816 XModifierKeymap *mods;
5817
334208b7
RS
5818 dpyinfo->meta_mod_mask = 0;
5819 dpyinfo->shift_lock_mask = 0;
5820 dpyinfo->alt_mod_mask = 0;
5821 dpyinfo->super_mod_mask = 0;
5822 dpyinfo->hyper_mod_mask = 0;
58769bee 5823
9658a521 5824#ifdef HAVE_X11R4
334208b7 5825 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 5826#else
4a60f8c5
RS
5827 min_code = dpyinfo->display->min_keycode;
5828 max_code = dpyinfo->display->max_keycode;
9658a521
JB
5829#endif
5830
334208b7 5831 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
5832 min_code, max_code - min_code + 1,
5833 &syms_per_code);
334208b7 5834 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 5835
58769bee 5836 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 5837 Alt keysyms are on. */
28430d3c 5838 {
06a2c219 5839 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
5840
5841 for (row = 3; row < 8; row++)
5842 for (col = 0; col < mods->max_keypermod; col++)
5843 {
0299d313
RS
5844 KeyCode code
5845 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 5846
af92970c
KH
5847 /* Zeroes are used for filler. Skip them. */
5848 if (code == 0)
5849 continue;
5850
28430d3c
JB
5851 /* Are any of this keycode's keysyms a meta key? */
5852 {
5853 int code_col;
5854
5855 for (code_col = 0; code_col < syms_per_code; code_col++)
5856 {
f689eb05 5857 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 5858
f689eb05 5859 switch (sym)
28430d3c 5860 {
f689eb05
JB
5861 case XK_Meta_L:
5862 case XK_Meta_R:
334208b7 5863 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 5864 break;
f689eb05
JB
5865
5866 case XK_Alt_L:
5867 case XK_Alt_R:
334208b7 5868 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
5869 break;
5870
5871 case XK_Hyper_L:
5872 case XK_Hyper_R:
334208b7 5873 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
5874 break;
5875
5876 case XK_Super_L:
5877 case XK_Super_R:
334208b7 5878 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 5879 break;
11edeb03
JB
5880
5881 case XK_Shift_Lock:
5882 /* Ignore this if it's not on the lock modifier. */
5883 if ((1 << row) == LockMask)
334208b7 5884 dpyinfo->shift_lock_mask = LockMask;
11edeb03 5885 break;
28430d3c
JB
5886 }
5887 }
5888 }
5889 }
5890 }
5891
f689eb05 5892 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 5893 if (! dpyinfo->meta_mod_mask)
a3c44b14 5894 {
334208b7
RS
5895 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
5896 dpyinfo->alt_mod_mask = 0;
a3c44b14 5897 }
f689eb05 5898
148c4b70
RS
5899 /* If some keys are both alt and meta,
5900 make them just meta, not alt. */
334208b7 5901 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 5902 {
334208b7 5903 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 5904 }
58769bee 5905
28430d3c 5906 XFree ((char *) syms);
f689eb05 5907 XFreeModifiermap (mods);
28430d3c
JB
5908}
5909
dfeccd2d
JB
5910/* Convert between the modifier bits X uses and the modifier bits
5911 Emacs uses. */
06a2c219 5912
7c5283e4 5913static unsigned int
334208b7
RS
5914x_x_to_emacs_modifiers (dpyinfo, state)
5915 struct x_display_info *dpyinfo;
dc6f92b8
JB
5916 unsigned int state;
5917{
334208b7
RS
5918 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
5919 | ((state & ControlMask) ? ctrl_modifier : 0)
5920 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
5921 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
5922 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
5923 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
5924}
5925
dfeccd2d 5926static unsigned int
334208b7
RS
5927x_emacs_to_x_modifiers (dpyinfo, state)
5928 struct x_display_info *dpyinfo;
dfeccd2d
JB
5929 unsigned int state;
5930{
334208b7
RS
5931 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
5932 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
5933 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
5934 | ((state & shift_modifier) ? ShiftMask : 0)
5935 | ((state & ctrl_modifier) ? ControlMask : 0)
5936 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 5937}
d047c4eb
KH
5938
5939/* Convert a keysym to its name. */
5940
5941char *
5942x_get_keysym_name (keysym)
5943 KeySym keysym;
5944{
5945 char *value;
5946
5947 BLOCK_INPUT;
5948 value = XKeysymToString (keysym);
5949 UNBLOCK_INPUT;
5950
5951 return value;
5952}
06a2c219
GM
5953
5954
e4571a43
JB
5955\f
5956/* Mouse clicks and mouse movement. Rah. */
e4571a43 5957
06a2c219
GM
5958/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
5959 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
5960 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
5961 not force the value into range. */
69388238 5962
c8dba240 5963void
69388238 5964pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 5965 FRAME_PTR f;
69388238 5966 register int pix_x, pix_y;
e4571a43
JB
5967 register int *x, *y;
5968 XRectangle *bounds;
69388238 5969 int noclip;
e4571a43 5970{
06a2c219 5971 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
5972 even for negative values. */
5973 if (pix_x < 0)
7556890b 5974 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 5975 if (pix_y < 0)
7556890b 5976 pix_y -= (f)->output_data.x->line_height - 1;
69388238 5977
e4571a43
JB
5978 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
5979 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
5980
5981 if (bounds)
5982 {
7556890b
RS
5983 bounds->width = FONT_WIDTH (f->output_data.x->font);
5984 bounds->height = f->output_data.x->line_height;
e4571a43
JB
5985 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
5986 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
5987 }
5988
69388238
RS
5989 if (!noclip)
5990 {
5991 if (pix_x < 0)
5992 pix_x = 0;
3cbd2e0b
RS
5993 else if (pix_x > FRAME_WINDOW_WIDTH (f))
5994 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
5995
5996 if (pix_y < 0)
5997 pix_y = 0;
5998 else if (pix_y > f->height)
5999 pix_y = f->height;
6000 }
e4571a43
JB
6001
6002 *x = pix_x;
6003 *y = pix_y;
6004}
6005
06a2c219
GM
6006
6007/* Given HPOS/VPOS in the current matrix of W, return corresponding
6008 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6009 can't tell the positions because W's display is not up to date,
6010 return 0. */
6011
6012int
6013glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6014 struct window *w;
6015 int hpos, vpos;
6016 int *frame_x, *frame_y;
2b5c9e71 6017{
06a2c219
GM
6018 int success_p;
6019
6020 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6021 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6022
6023 if (display_completed)
6024 {
6025 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6026 struct glyph *glyph = row->glyphs[TEXT_AREA];
6027 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6028
6029 *frame_y = row->y;
6030 *frame_x = row->x;
6031 while (glyph < end)
6032 {
6033 *frame_x += glyph->pixel_width;
6034 ++glyph;
6035 }
6036
6037 success_p = 1;
6038 }
6039 else
6040 {
6041 *frame_y = *frame_x = 0;
6042 success_p = 0;
6043 }
6044
6045 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6046 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6047 return success_p;
2b5c9e71
RS
6048}
6049
06a2c219 6050
dc6f92b8
JB
6051/* Prepare a mouse-event in *RESULT for placement in the input queue.
6052
6053 If the event is a button press, then note that we have grabbed
f451eb13 6054 the mouse. */
dc6f92b8
JB
6055
6056static Lisp_Object
f451eb13 6057construct_mouse_click (result, event, f)
dc6f92b8
JB
6058 struct input_event *result;
6059 XButtonEvent *event;
f676886a 6060 struct frame *f;
dc6f92b8 6061{
f451eb13 6062 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6063 otherwise. */
f451eb13 6064 result->kind = mouse_click;
69388238 6065 result->code = event->button - Button1;
1113d9db 6066 result->timestamp = event->time;
334208b7
RS
6067 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6068 event->state)
f689eb05 6069 | (event->type == ButtonRelease
58769bee 6070 ? up_modifier
f689eb05 6071 : down_modifier));
dc6f92b8 6072
06a2c219
GM
6073 XSETINT (result->x, event->x);
6074 XSETINT (result->y, event->y);
6075 XSETFRAME (result->frame_or_window, f);
6076 return Qnil;
dc6f92b8 6077}
b849c413 6078
06a2c219
GM
6079#if 0 /* This function isn't called. --gerd */
6080
b849c413
RS
6081/* Prepare a menu-event in *RESULT for placement in the input queue. */
6082
6083static Lisp_Object
6084construct_menu_click (result, event, f)
6085 struct input_event *result;
6086 XButtonEvent *event;
6087 struct frame *f;
6088{
6089 /* Make the event type no_event; we'll change that when we decide
6090 otherwise. */
6091 result->kind = mouse_click;
26459b28 6092 result->code = event->button - Button1;
b849c413 6093 result->timestamp = event->time;
334208b7
RS
6094 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6095 event->state)
b849c413 6096 | (event->type == ButtonRelease
58769bee 6097 ? up_modifier
b849c413
RS
6098 : down_modifier));
6099
e0c1aef2
KH
6100 XSETINT (result->x, event->x);
6101 XSETINT (result->y, -1);
6102 XSETFRAME (result->frame_or_window, f);
b849c413 6103}
06a2c219
GM
6104
6105#endif /* 0 */
6106
69388238 6107\f
90e65f07
JB
6108/* Function to report a mouse movement to the mainstream Emacs code.
6109 The input handler calls this.
6110
6111 We have received a mouse movement event, which is given in *event.
6112 If the mouse is over a different glyph than it was last time, tell
6113 the mainstream emacs code by setting mouse_moved. If not, ask for
6114 another motion event, so we can check again the next time it moves. */
b8009dd1 6115
06a2c219
GM
6116static XMotionEvent last_mouse_motion_event;
6117static Lisp_Object last_mouse_motion_frame;
6118
90e65f07 6119static void
12ba150f 6120note_mouse_movement (frame, event)
f676886a 6121 FRAME_PTR frame;
90e65f07 6122 XMotionEvent *event;
90e65f07 6123{
e5d77022 6124 last_mouse_movement_time = event->time;
06a2c219
GM
6125 last_mouse_motion_event = *event;
6126 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6127
27f338af
RS
6128 if (event->window != FRAME_X_WINDOW (frame))
6129 {
39d8bb4d 6130 frame->mouse_moved = 1;
27f338af 6131 last_mouse_scroll_bar = Qnil;
27f338af 6132 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6133 }
6134
90e65f07 6135 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6136 else if (event->x < last_mouse_glyph.x
6137 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6138 || event->y < last_mouse_glyph.y
6139 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6140 {
39d8bb4d 6141 frame->mouse_moved = 1;
ab648270 6142 last_mouse_scroll_bar = Qnil;
b8009dd1 6143 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6144 }
6145}
6146
bf1c0ba1 6147/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6148
06a2c219
GM
6149 int disable_mouse_highlight;
6150
6151
6152\f
6153/************************************************************************
6154 Mouse Face
6155 ************************************************************************/
6156
6157/* Find the glyph under window-relative coordinates X/Y in window W.
6158 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6159 strings. Return in *HPOS and *VPOS the row and column number of
6160 the glyph found. Return in *AREA the glyph area containing X.
6161 Value is a pointer to the glyph found or null if X/Y is not on
6162 text, or we can't tell because W's current matrix is not up to
6163 date. */
6164
6165static struct glyph *
6166x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
6167 struct window *w;
6168 int x, y;
6169 int *hpos, *vpos, *area;
6170{
6171 struct glyph *glyph, *end;
3e71d8f2 6172 struct glyph_row *row = NULL;
06a2c219
GM
6173 int x0, i, left_area_width;
6174
6175 /* Find row containing Y. Give up if some row is not enabled. */
6176 for (i = 0; i < w->current_matrix->nrows; ++i)
6177 {
6178 row = MATRIX_ROW (w->current_matrix, i);
6179 if (!row->enabled_p)
6180 return NULL;
6181 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6182 break;
6183 }
6184
6185 *vpos = i;
6186 *hpos = 0;
6187
6188 /* Give up if Y is not in the window. */
6189 if (i == w->current_matrix->nrows)
6190 return NULL;
6191
6192 /* Get the glyph area containing X. */
6193 if (w->pseudo_window_p)
6194 {
6195 *area = TEXT_AREA;
6196 x0 = 0;
6197 }
6198 else
6199 {
6200 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6201 if (x < left_area_width)
6202 {
6203 *area = LEFT_MARGIN_AREA;
6204 x0 = 0;
6205 }
6206 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6207 {
6208 *area = TEXT_AREA;
6209 x0 = row->x + left_area_width;
6210 }
6211 else
6212 {
6213 *area = RIGHT_MARGIN_AREA;
6214 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6215 }
6216 }
6217
6218 /* Find glyph containing X. */
6219 glyph = row->glyphs[*area];
6220 end = glyph + row->used[*area];
6221 while (glyph < end)
6222 {
6223 if (x < x0 + glyph->pixel_width)
6224 {
6225 if (w->pseudo_window_p)
6226 break;
6227 else if (BUFFERP (glyph->object))
6228 break;
6229 }
6230
6231 x0 += glyph->pixel_width;
6232 ++glyph;
6233 }
6234
6235 if (glyph == end)
6236 return NULL;
6237
6238 *hpos = glyph - row->glyphs[*area];
6239 return glyph;
6240}
6241
6242
6243/* Convert frame-relative x/y to coordinates relative to window W.
6244 Takes pseudo-windows into account. */
6245
6246static void
6247frame_to_window_pixel_xy (w, x, y)
6248 struct window *w;
6249 int *x, *y;
6250{
6251 if (w->pseudo_window_p)
6252 {
6253 /* A pseudo-window is always full-width, and starts at the
6254 left edge of the frame, plus a frame border. */
6255 struct frame *f = XFRAME (w->frame);
6256 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6257 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6258 }
6259 else
6260 {
6261 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6262 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6263 }
6264}
6265
6266
6267/* Take proper action when mouse has moved to the mode or top line of
6268 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6269 mode line. X is relative to the start of the text display area of
6270 W, so the width of bitmap areas and scroll bars must be subtracted
6271 to get a position relative to the start of the mode line. */
6272
6273static void
6274note_mode_line_highlight (w, x, mode_line_p)
6275 struct window *w;
6276 int x, mode_line_p;
6277{
6278 struct frame *f = XFRAME (w->frame);
6279 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6280 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6281 struct glyph_row *row;
6282
6283 if (mode_line_p)
6284 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6285 else
045dee35 6286 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
06a2c219
GM
6287
6288 if (row->enabled_p)
6289 {
6290 struct glyph *glyph, *end;
6291 Lisp_Object help, map;
6292 int x0;
6293
6294 /* Find the glyph under X. */
6295 glyph = row->glyphs[TEXT_AREA];
6296 end = glyph + row->used[TEXT_AREA];
6297 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6298 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
6299 while (glyph < end
6300 && x >= x0 + glyph->pixel_width)
6301 {
6302 x0 += glyph->pixel_width;
6303 ++glyph;
6304 }
6305
6306 if (glyph < end
6307 && STRINGP (glyph->object)
6308 && XSTRING (glyph->object)->intervals
6309 && glyph->charpos >= 0
6310 && glyph->charpos < XSTRING (glyph->object)->size)
6311 {
6312 /* If we're on a string with `help-echo' text property,
6313 arrange for the help to be displayed. This is done by
6314 setting the global variable help_echo to the help string. */
6315 help = Fget_text_property (make_number (glyph->charpos),
6316 Qhelp_echo, glyph->object);
6317 if (STRINGP (help))
6318 help_echo = help;
6319
6320 /* Change the mouse pointer according to what is under X/Y. */
6321 map = Fget_text_property (make_number (glyph->charpos),
6322 Qlocal_map, glyph->object);
6323 if (!NILP (Fkeymapp (map)))
6324 cursor = f->output_data.x->nontext_cursor;
6325 }
6326 }
6327
6328 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6329}
6330
6331
6332/* Take proper action when the mouse has moved to position X, Y on
6333 frame F as regards highlighting characters that have mouse-face
6334 properties. Also de-highlighting chars where the mouse was before.
27f338af 6335 X and Y can be negative or out of range. */
b8009dd1
RS
6336
6337static void
6338note_mouse_highlight (f, x, y)
06a2c219 6339 struct frame *f;
c32cdd9a 6340 int x, y;
b8009dd1 6341{
06a2c219
GM
6342 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6343 int portion;
b8009dd1
RS
6344 Lisp_Object window;
6345 struct window *w;
6346
06a2c219
GM
6347 /* When a menu is active, don't highlight because this looks odd. */
6348#ifdef USE_X_TOOLKIT
6349 if (popup_activated ())
6350 return;
6351#endif
6352
04fff9c0
GM
6353 if (disable_mouse_highlight
6354 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6355 return;
6356
06a2c219
GM
6357 dpyinfo->mouse_face_mouse_x = x;
6358 dpyinfo->mouse_face_mouse_y = y;
6359 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6360
06a2c219 6361 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6362 return;
6363
514e4681
RS
6364 if (gc_in_progress)
6365 {
06a2c219 6366 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6367 return;
6368 }
6369
b8009dd1 6370 /* Which window is that in? */
06a2c219 6371 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6372
6373 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6374 if (! EQ (window, dpyinfo->mouse_face_window))
6375 clear_mouse_face (dpyinfo);
6376
6377 /* Not on a window -> return. */
6378 if (!WINDOWP (window))
6379 return;
6380
6381 /* Convert to window-relative pixel coordinates. */
6382 w = XWINDOW (window);
6383 frame_to_window_pixel_xy (w, &x, &y);
6384
9ea173e8 6385 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6386 buffer. */
9ea173e8 6387 if (EQ (window, f->tool_bar_window))
06a2c219 6388 {
9ea173e8 6389 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6390 return;
6391 }
6392
6393 if (portion == 1 || portion == 3)
6394 {
6395 /* Mouse is on the mode or top line. */
6396 note_mode_line_highlight (w, x, portion == 1);
6397 return;
6398 }
6399 else
6400 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6401 f->output_data.x->text_cursor);
b8009dd1 6402
0cdd0c9f
RS
6403 /* Are we in a window whose display is up to date?
6404 And verify the buffer's text has not changed. */
06a2c219
GM
6405 if (/* Within text portion of the window. */
6406 portion == 0
0cdd0c9f 6407 && EQ (w->window_end_valid, w->buffer)
26459b28
KH
6408 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
6409 && (XFASTINT (w->last_overlay_modified)
6410 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
b8009dd1 6411 {
06a2c219
GM
6412 int hpos, vpos, pos, i, area;
6413 struct glyph *glyph;
b8009dd1 6414
06a2c219
GM
6415 /* Find the glyph under X/Y. */
6416 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
6417
6418 /* Clear mouse face if X/Y not over text. */
6419 if (glyph == NULL
6420 || area != TEXT_AREA
6421 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6422 {
06a2c219
GM
6423 clear_mouse_face (dpyinfo);
6424 return;
6425 }
6426
6427 pos = glyph->charpos;
6428 xassert (w->pseudo_window_p || BUFFERP (glyph->object));
6429
6430 /* Check for mouse-face and help-echo. */
6431 {
6432 Lisp_Object mouse_face, overlay, position;
6433 Lisp_Object *overlay_vec;
6434 int len, noverlays;
6435 struct buffer *obuf;
6436 int obegv, ozv;
6437
6438 /* If we get an out-of-range value, return now; avoid an error. */
6439 if (pos > BUF_Z (XBUFFER (w->buffer)))
6440 return;
6441
6442 /* Make the window's buffer temporarily current for
6443 overlays_at and compute_char_face. */
6444 obuf = current_buffer;
6445 current_buffer = XBUFFER (w->buffer);
6446 obegv = BEGV;
6447 ozv = ZV;
6448 BEGV = BEG;
6449 ZV = Z;
6450
6451 /* Is this char mouse-active or does it have help-echo? */
6452 XSETINT (position, pos);
6453
6454 /* Put all the overlays we want in a vector in overlay_vec.
6455 Store the length in len. If there are more than 10, make
6456 enough space for all, and try again. */
6457 len = 10;
6458 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6459 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6460 if (noverlays > len)
6461 {
6462 len = noverlays;
6463 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6464 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
6465 }
6466
6467 noverlays = sort_overlays (overlay_vec, noverlays, w);
6468
6469 /* Check mouse-face highlighting. */
6470 if (! (EQ (window, dpyinfo->mouse_face_window)
6471 && vpos >= dpyinfo->mouse_face_beg_row
6472 && vpos <= dpyinfo->mouse_face_end_row
6473 && (vpos > dpyinfo->mouse_face_beg_row
6474 || hpos >= dpyinfo->mouse_face_beg_col)
6475 && (vpos < dpyinfo->mouse_face_end_row
6476 || hpos < dpyinfo->mouse_face_end_col
6477 || dpyinfo->mouse_face_past_end)))
6478 {
6479 /* Clear the display of the old active region, if any. */
6480 clear_mouse_face (dpyinfo);
6481
6482 /* Find the highest priority overlay that has a mouse-face prop. */
6483 overlay = Qnil;
6484 for (i = 0; i < noverlays; i++)
6485 {
6486 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6487 if (!NILP (mouse_face))
6488 {
6489 overlay = overlay_vec[i];
6490 break;
6491 }
6492 }
6493
6494 /* If no overlay applies, get a text property. */
6495 if (NILP (overlay))
6496 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6497
6498 /* Handle the overlay case. */
6499 if (! NILP (overlay))
6500 {
6501 /* Find the range of text around this char that
6502 should be active. */
6503 Lisp_Object before, after;
6504 int ignore;
6505
6506 before = Foverlay_start (overlay);
6507 after = Foverlay_end (overlay);
6508 /* Record this as the current active region. */
6509 fast_find_position (w, XFASTINT (before),
6510 &dpyinfo->mouse_face_beg_col,
6511 &dpyinfo->mouse_face_beg_row,
6512 &dpyinfo->mouse_face_beg_x,
6513 &dpyinfo->mouse_face_beg_y);
6514 dpyinfo->mouse_face_past_end
6515 = !fast_find_position (w, XFASTINT (after),
6516 &dpyinfo->mouse_face_end_col,
6517 &dpyinfo->mouse_face_end_row,
6518 &dpyinfo->mouse_face_end_x,
6519 &dpyinfo->mouse_face_end_y);
6520 dpyinfo->mouse_face_window = window;
6521 dpyinfo->mouse_face_face_id
6522 = face_at_buffer_position (w, pos, 0, 0,
6523 &ignore, pos + 1, 1);
6524
6525 /* Display it as active. */
6526 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6527 }
6528 /* Handle the text property case. */
6529 else if (! NILP (mouse_face))
6530 {
6531 /* Find the range of text around this char that
6532 should be active. */
6533 Lisp_Object before, after, beginning, end;
6534 int ignore;
6535
6536 beginning = Fmarker_position (w->start);
6537 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
6538 - XFASTINT (w->window_end_pos)));
6539 before
6540 = Fprevious_single_property_change (make_number (pos + 1),
6541 Qmouse_face,
6542 w->buffer, beginning);
6543 after
6544 = Fnext_single_property_change (position, Qmouse_face,
6545 w->buffer, end);
6546 /* Record this as the current active region. */
6547 fast_find_position (w, XFASTINT (before),
6548 &dpyinfo->mouse_face_beg_col,
6549 &dpyinfo->mouse_face_beg_row,
6550 &dpyinfo->mouse_face_beg_x,
6551 &dpyinfo->mouse_face_beg_y);
6552 dpyinfo->mouse_face_past_end
6553 = !fast_find_position (w, XFASTINT (after),
6554 &dpyinfo->mouse_face_end_col,
6555 &dpyinfo->mouse_face_end_row,
6556 &dpyinfo->mouse_face_end_x,
6557 &dpyinfo->mouse_face_end_y);
6558 dpyinfo->mouse_face_window = window;
6559 dpyinfo->mouse_face_face_id
6560 = face_at_buffer_position (w, pos, 0, 0,
6561 &ignore, pos + 1, 1);
6562
6563 /* Display it as active. */
6564 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6565 }
6566 }
6567
6568 /* Look for a `help-echo' property. */
6569 {
6570 Lisp_Object help;
6571
6572 /* Check overlays first. */
6573 help = Qnil;
6574 for (i = 0; i < noverlays && !STRINGP (help); ++i)
6575 help = Foverlay_get (overlay_vec[i], Qhelp_echo);
6576
6577 /* Try text properties. */
6578 if (!STRINGP (help)
6579 && ((STRINGP (glyph->object)
6580 && glyph->charpos >= 0
6581 && glyph->charpos < XSTRING (glyph->object)->size)
6582 || (BUFFERP (glyph->object)
6583 && glyph->charpos >= BEGV
6584 && glyph->charpos < ZV)))
6585 help = Fget_text_property (make_number (glyph->charpos),
6586 Qhelp_echo, glyph->object);
6587
6588 if (STRINGP (help))
6589 help_echo = help;
6590 }
6591
6592 BEGV = obegv;
6593 ZV = ozv;
6594 current_buffer = obuf;
6595 }
6596 }
6597}
6598
6599static void
6600redo_mouse_highlight ()
6601{
6602 if (!NILP (last_mouse_motion_frame)
6603 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
6604 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
6605 last_mouse_motion_event.x,
6606 last_mouse_motion_event.y);
6607}
6608
6609
6610\f
6611/***********************************************************************
9ea173e8 6612 Tool-bars
06a2c219
GM
6613 ***********************************************************************/
6614
9ea173e8
GM
6615static int x_tool_bar_item P_ ((struct frame *, int, int,
6616 struct glyph **, int *, int *, int *));
06a2c219 6617
9ea173e8 6618/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
6619 or -1. */
6620
9ea173e8 6621static int last_tool_bar_item;
06a2c219
GM
6622
6623
9ea173e8
GM
6624/* Get information about the tool-bar item at position X/Y on frame F.
6625 Return in *GLYPH a pointer to the glyph of the tool-bar item in
6626 the current matrix of the tool-bar window of F, or NULL if not
6627 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
6628 item in F->current_tool_bar_items. Value is
06a2c219 6629
9ea173e8 6630 -1 if X/Y is not on a tool-bar item
06a2c219
GM
6631 0 if X/Y is on the same item that was highlighted before.
6632 1 otherwise. */
6633
6634static int
9ea173e8 6635x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
6636 struct frame *f;
6637 int x, y;
6638 struct glyph **glyph;
6639 int *hpos, *vpos, *prop_idx;
6640{
6641 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6642 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6643 int area;
6644
6645 /* Find the glyph under X/Y. */
6646 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
6647 if (*glyph == NULL)
6648 return -1;
6649
9ea173e8
GM
6650 /* Get the start of this tool-bar item's properties in
6651 f->current_tool_bar_items. */
6652 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
6653 return -1;
6654
6655 /* Is mouse on the highlighted item? */
9ea173e8 6656 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
6657 && *vpos >= dpyinfo->mouse_face_beg_row
6658 && *vpos <= dpyinfo->mouse_face_end_row
6659 && (*vpos > dpyinfo->mouse_face_beg_row
6660 || *hpos >= dpyinfo->mouse_face_beg_col)
6661 && (*vpos < dpyinfo->mouse_face_end_row
6662 || *hpos < dpyinfo->mouse_face_end_col
6663 || dpyinfo->mouse_face_past_end))
6664 return 0;
6665
6666 return 1;
6667}
6668
6669
9ea173e8 6670/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
6671 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
6672 or ButtonRelase. */
6673
6674static void
9ea173e8 6675x_handle_tool_bar_click (f, button_event)
06a2c219
GM
6676 struct frame *f;
6677 XButtonEvent *button_event;
6678{
6679 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6680 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6681 int hpos, vpos, prop_idx;
6682 struct glyph *glyph;
6683 Lisp_Object enabled_p;
6684 int x = button_event->x;
6685 int y = button_event->y;
6686
9ea173e8 6687 /* If not on the highlighted tool-bar item, return. */
06a2c219 6688 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 6689 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
6690 return;
6691
6692 /* If item is disabled, do nothing. */
9ea173e8
GM
6693 enabled_p = (XVECTOR (f->current_tool_bar_items)
6694 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6695 if (NILP (enabled_p))
6696 return;
6697
6698 if (button_event->type == ButtonPress)
6699 {
6700 /* Show item in pressed state. */
6701 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
6702 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 6703 last_tool_bar_item = prop_idx;
06a2c219
GM
6704 }
6705 else
6706 {
6707 Lisp_Object key, frame;
6708 struct input_event event;
6709
6710 /* Show item in released state. */
6711 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
6712 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
6713
9ea173e8
GM
6714 key = (XVECTOR (f->current_tool_bar_items)
6715 ->contents[prop_idx + TOOL_BAR_ITEM_KEY]);
06a2c219
GM
6716
6717 XSETFRAME (frame, f);
9ea173e8
GM
6718 event.kind = TOOL_BAR_EVENT;
6719 event.frame_or_window = Fcons (frame, Fcons (Qtool_bar, Qnil));
06a2c219
GM
6720 kbd_buffer_store_event (&event);
6721
9ea173e8 6722 event.kind = TOOL_BAR_EVENT;
06a2c219
GM
6723 event.frame_or_window = Fcons (frame, key);
6724 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6725 button_event->state);
6726 kbd_buffer_store_event (&event);
9ea173e8 6727 last_tool_bar_item = -1;
06a2c219
GM
6728 }
6729}
6730
6731
9ea173e8
GM
6732/* Possibly highlight a tool-bar item on frame F when mouse moves to
6733 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
6734 note_mouse_highlight. */
6735
6736static void
9ea173e8 6737note_tool_bar_highlight (f, x, y)
06a2c219
GM
6738 struct frame *f;
6739 int x, y;
6740{
9ea173e8 6741 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
6742 struct window *w = XWINDOW (window);
6743 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6744 int hpos, vpos;
6745 struct glyph *glyph;
6746 struct glyph_row *row;
5c187dee 6747 int i;
06a2c219
GM
6748 Lisp_Object enabled_p;
6749 int prop_idx;
6750 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
5c187dee 6751 int mouse_down_p, rc;
06a2c219
GM
6752
6753 /* Function note_mouse_highlight is called with negative x(y
6754 values when mouse moves outside of the frame. */
6755 if (x <= 0 || y <= 0)
6756 {
6757 clear_mouse_face (dpyinfo);
6758 return;
6759 }
6760
9ea173e8 6761 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
6762 if (rc < 0)
6763 {
9ea173e8 6764 /* Not on tool-bar item. */
06a2c219
GM
6765 clear_mouse_face (dpyinfo);
6766 return;
6767 }
6768 else if (rc == 0)
9ea173e8 6769 /* On same tool-bar item as before. */
06a2c219 6770 goto set_help_echo;
b8009dd1 6771
06a2c219
GM
6772 clear_mouse_face (dpyinfo);
6773
9ea173e8 6774 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
6775 mouse_down_p = (dpyinfo->grabbed
6776 && f == last_mouse_frame
6777 && FRAME_LIVE_P (f));
6778 if (mouse_down_p
9ea173e8 6779 && last_tool_bar_item != prop_idx)
06a2c219
GM
6780 return;
6781
6782 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
6783 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
6784
9ea173e8
GM
6785 /* If tool-bar item is not enabled, don't highlight it. */
6786 enabled_p = (XVECTOR (f->current_tool_bar_items)
6787 ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
06a2c219
GM
6788 if (!NILP (enabled_p))
6789 {
6790 /* Compute the x-position of the glyph. In front and past the
6791 image is a space. We include this is the highlighted area. */
6792 row = MATRIX_ROW (w->current_matrix, vpos);
6793 for (i = x = 0; i < hpos; ++i)
6794 x += row->glyphs[TEXT_AREA][i].pixel_width;
6795
6796 /* Record this as the current active region. */
6797 dpyinfo->mouse_face_beg_col = hpos;
6798 dpyinfo->mouse_face_beg_row = vpos;
6799 dpyinfo->mouse_face_beg_x = x;
6800 dpyinfo->mouse_face_beg_y = row->y;
6801 dpyinfo->mouse_face_past_end = 0;
6802
6803 dpyinfo->mouse_face_end_col = hpos + 1;
6804 dpyinfo->mouse_face_end_row = vpos;
6805 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
6806 dpyinfo->mouse_face_end_y = row->y;
6807 dpyinfo->mouse_face_window = window;
9ea173e8 6808 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
6809
6810 /* Display it as active. */
6811 show_mouse_face (dpyinfo, draw);
6812 dpyinfo->mouse_face_image_state = draw;
b8009dd1 6813 }
06a2c219
GM
6814
6815 set_help_echo:
6816
9ea173e8 6817 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 6818 XTread_socket does the rest. */
9ea173e8
GM
6819 help_echo = (XVECTOR (f->current_tool_bar_items)
6820 ->contents[prop_idx + TOOL_BAR_ITEM_HELP]);
06a2c219 6821 if (!STRINGP (help_echo))
9ea173e8
GM
6822 help_echo = (XVECTOR (f->current_tool_bar_items)
6823 ->contents[prop_idx + TOOL_BAR_ITEM_CAPTION]);
b8009dd1 6824}
4d73d038 6825
06a2c219
GM
6826
6827\f
6828/* Find the glyph matrix position of buffer position POS in window W.
6829 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
6830 current glyphs must be up to date. If POS is above window start
6831 return (0, 0, 0, 0). If POS is after end of W, return end of
6832 last line in W. */
b8009dd1
RS
6833
6834static int
06a2c219
GM
6835fast_find_position (w, pos, hpos, vpos, x, y)
6836 struct window *w;
b8009dd1 6837 int pos;
06a2c219 6838 int *hpos, *vpos, *x, *y;
b8009dd1 6839{
b8009dd1 6840 int i;
bf1c0ba1 6841 int lastcol;
06a2c219
GM
6842 int maybe_next_line_p = 0;
6843 int line_start_position;
6844 int yb = window_text_bottom_y (w);
6845 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
6846 struct glyph_row *best_row = row;
6847 int row_vpos = 0, best_row_vpos = 0;
6848 int current_x;
6849
6850 while (row->y < yb)
b8009dd1 6851 {
06a2c219
GM
6852 if (row->used[TEXT_AREA])
6853 line_start_position = row->glyphs[TEXT_AREA]->charpos;
6854 else
6855 line_start_position = 0;
6856
6857 if (line_start_position > pos)
b8009dd1 6858 break;
77b68646
RS
6859 /* If the position sought is the end of the buffer,
6860 don't include the blank lines at the bottom of the window. */
06a2c219
GM
6861 else if (line_start_position == pos
6862 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 6863 {
06a2c219 6864 maybe_next_line_p = 1;
77b68646
RS
6865 break;
6866 }
06a2c219
GM
6867 else if (line_start_position > 0)
6868 {
6869 best_row = row;
6870 best_row_vpos = row_vpos;
6871 }
4b0bb6f3
GM
6872
6873 if (row->y + row->height >= yb)
6874 break;
06a2c219
GM
6875
6876 ++row;
6877 ++row_vpos;
b8009dd1 6878 }
06a2c219
GM
6879
6880 /* Find the right column within BEST_ROW. */
6881 lastcol = 0;
6882 current_x = best_row->x;
6883 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 6884 {
06a2c219
GM
6885 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
6886 int charpos;
6887
6888 charpos = glyph->charpos;
6889 if (charpos == pos)
bf1c0ba1 6890 {
06a2c219
GM
6891 *hpos = i;
6892 *vpos = best_row_vpos;
6893 *x = current_x;
6894 *y = best_row->y;
bf1c0ba1
RS
6895 return 1;
6896 }
06a2c219 6897 else if (charpos > pos)
4d73d038 6898 break;
06a2c219
GM
6899 else if (charpos > 0)
6900 lastcol = i;
6901
6902 current_x += glyph->pixel_width;
bf1c0ba1 6903 }
b8009dd1 6904
77b68646
RS
6905 /* If we're looking for the end of the buffer,
6906 and we didn't find it in the line we scanned,
6907 use the start of the following line. */
06a2c219 6908 if (maybe_next_line_p)
77b68646 6909 {
06a2c219
GM
6910 ++best_row;
6911 ++best_row_vpos;
6912 lastcol = 0;
6913 current_x = best_row->x;
77b68646
RS
6914 }
6915
06a2c219
GM
6916 *vpos = best_row_vpos;
6917 *hpos = lastcol + 1;
6918 *x = current_x;
6919 *y = best_row->y;
b8009dd1
RS
6920 return 0;
6921}
6922
06a2c219 6923
b8009dd1
RS
6924/* Display the active region described by mouse_face_*
6925 in its mouse-face if HL > 0, in its normal face if HL = 0. */
6926
6927static void
06a2c219 6928show_mouse_face (dpyinfo, draw)
7a13e894 6929 struct x_display_info *dpyinfo;
06a2c219 6930 enum draw_glyphs_face draw;
b8009dd1 6931{
7a13e894 6932 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 6933 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 6934 int i;
06a2c219
GM
6935 int cursor_off_p = 0;
6936 struct cursor_pos saved_cursor;
6937
6938 saved_cursor = output_cursor;
6939
6940 /* If window is in the process of being destroyed, don't bother
6941 to do anything. */
6942 if (w->current_matrix == NULL)
6943 goto set_x_cursor;
6944
6945 /* Recognize when we are called to operate on rows that don't exist
6946 anymore. This can happen when a window is split. */
6947 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
6948 goto set_x_cursor;
6949
6950 set_output_cursor (&w->phys_cursor);
6951
6952 /* Note that mouse_face_beg_row etc. are window relative. */
6953 for (i = dpyinfo->mouse_face_beg_row;
6954 i <= dpyinfo->mouse_face_end_row;
6955 i++)
6956 {
6957 int start_hpos, end_hpos, start_x;
6958 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
6959
6960 /* Don't do anything if row doesn't have valid contents. */
6961 if (!row->enabled_p)
6962 continue;
6963
6964 /* For all but the first row, the highlight starts at column 0. */
6965 if (i == dpyinfo->mouse_face_beg_row)
6966 {
6967 start_hpos = dpyinfo->mouse_face_beg_col;
6968 start_x = dpyinfo->mouse_face_beg_x;
6969 }
6970 else
6971 {
6972 start_hpos = 0;
6973 start_x = 0;
6974 }
6975
6976 if (i == dpyinfo->mouse_face_end_row)
6977 end_hpos = dpyinfo->mouse_face_end_col;
6978 else
6979 end_hpos = row->used[TEXT_AREA];
6980
6981 /* If the cursor's in the text we are about to rewrite, turn the
6982 cursor off. */
6983 if (!w->pseudo_window_p
6984 && i == output_cursor.vpos
6985 && output_cursor.hpos >= start_hpos - 1
6986 && output_cursor.hpos <= end_hpos)
514e4681 6987 {
06a2c219
GM
6988 x_update_window_cursor (w, 0);
6989 cursor_off_p = 1;
514e4681 6990 }
b8009dd1 6991
06a2c219 6992 if (end_hpos > start_hpos)
54a91a0f 6993 x_draw_glyphs (w, start_x, row, TEXT_AREA,
66ac4b0e 6994 start_hpos, end_hpos, draw, NULL, NULL, 0);
b8009dd1
RS
6995 }
6996
514e4681 6997 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
6998 if (cursor_off_p)
6999 x_display_cursor (w, 1,
7000 output_cursor.hpos, output_cursor.vpos,
7001 output_cursor.x, output_cursor.y);
2729a2b5 7002
06a2c219 7003 output_cursor = saved_cursor;
fb3b7de5 7004
06a2c219
GM
7005 set_x_cursor:
7006
7007 /* Change the mouse cursor. */
7008 if (draw == DRAW_NORMAL_TEXT)
7009 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7010 f->output_data.x->text_cursor);
7011 else if (draw == DRAW_MOUSE_FACE)
334208b7 7012 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7013 f->output_data.x->cross_cursor);
27ead1d5 7014 else
334208b7 7015 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7016 f->output_data.x->nontext_cursor);
b8009dd1
RS
7017}
7018
7019/* Clear out the mouse-highlighted active region.
06a2c219 7020 Redraw it un-highlighted first. */
b8009dd1 7021
06a2c219 7022void
7a13e894
RS
7023clear_mouse_face (dpyinfo)
7024 struct x_display_info *dpyinfo;
b8009dd1 7025{
06a2c219
GM
7026 if (tip_frame)
7027 return;
7028
7a13e894 7029 if (! NILP (dpyinfo->mouse_face_window))
06a2c219 7030 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
b8009dd1 7031
7a13e894
RS
7032 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7033 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7034 dpyinfo->mouse_face_window = Qnil;
b8009dd1 7035}
e687d06e
RS
7036
7037/* Just discard the mouse face information for frame F, if any.
7038 This is used when the size of F is changed. */
7039
dfcf069d 7040void
e687d06e
RS
7041cancel_mouse_face (f)
7042 FRAME_PTR f;
7043{
7044 Lisp_Object window;
7045 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7046
7047 window = dpyinfo->mouse_face_window;
7048 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7049 {
7050 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7051 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7052 dpyinfo->mouse_face_window = Qnil;
7053 }
7054}
b8009dd1 7055\f
ab648270
JB
7056static struct scroll_bar *x_window_to_scroll_bar ();
7057static void x_scroll_bar_report_motion ();
12ba150f 7058
90e65f07 7059/* Return the current position of the mouse.
2d7fc7e8 7060 *fp should be a frame which indicates which display to ask about.
90e65f07 7061
2d7fc7e8 7062 If the mouse movement started in a scroll bar, set *fp, *bar_window,
ab648270 7063 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 7064 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 7065 position on the scroll bar.
12ba150f 7066
2d7fc7e8 7067 If the mouse movement started elsewhere, set *fp to the frame the
12ba150f
JB
7068 mouse is on, *bar_window to nil, and *x and *y to the character cell
7069 the mouse is over.
7070
06a2c219 7071 Set *time to the server time-stamp for the time at which the mouse
12ba150f
JB
7072 was at this position.
7073
a135645a
RS
7074 Don't store anything if we don't have a valid set of values to report.
7075
90e65f07 7076 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7077 movement. */
90e65f07
JB
7078
7079static void
1cf412ec 7080XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7081 FRAME_PTR *fp;
1cf412ec 7082 int insist;
12ba150f 7083 Lisp_Object *bar_window;
ab648270 7084 enum scroll_bar_part *part;
90e65f07 7085 Lisp_Object *x, *y;
e5d77022 7086 unsigned long *time;
90e65f07 7087{
a135645a
RS
7088 FRAME_PTR f1;
7089
90e65f07
JB
7090 BLOCK_INPUT;
7091
8bcee03e 7092 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7093 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7094 else
7095 {
12ba150f
JB
7096 Window root;
7097 int root_x, root_y;
90e65f07 7098
12ba150f
JB
7099 Window dummy_window;
7100 int dummy;
7101
39d8bb4d
KH
7102 Lisp_Object frame, tail;
7103
7104 /* Clear the mouse-moved flag for every frame on this display. */
7105 FOR_EACH_FRAME (tail, frame)
7106 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7107 XFRAME (frame)->mouse_moved = 0;
7108
ab648270 7109 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7110
7111 /* Figure out which root window we're on. */
334208b7
RS
7112 XQueryPointer (FRAME_X_DISPLAY (*fp),
7113 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7114
7115 /* The root window which contains the pointer. */
7116 &root,
7117
7118 /* Trash which we can't trust if the pointer is on
7119 a different screen. */
7120 &dummy_window,
7121
7122 /* The position on that root window. */
58769bee 7123 &root_x, &root_y,
12ba150f
JB
7124
7125 /* More trash we can't trust. */
7126 &dummy, &dummy,
7127
7128 /* Modifier keys and pointer buttons, about which
7129 we don't care. */
7130 (unsigned int *) &dummy);
7131
7132 /* Now we have a position on the root; find the innermost window
7133 containing the pointer. */
7134 {
7135 Window win, child;
7136 int win_x, win_y;
06a2c219 7137 int parent_x = 0, parent_y = 0;
e99db5a1 7138 int count;
12ba150f
JB
7139
7140 win = root;
69388238 7141
2d7fc7e8
RS
7142 /* XTranslateCoordinates can get errors if the window
7143 structure is changing at the same time this function
7144 is running. So at least we must not crash from them. */
7145
e99db5a1 7146 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 7147
334208b7 7148 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 7149 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 7150 {
69388238
RS
7151 /* If mouse was grabbed on a frame, give coords for that frame
7152 even if the mouse is now outside it. */
334208b7 7153 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 7154
12ba150f 7155 /* From-window, to-window. */
69388238 7156 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
7157
7158 /* From-position, to-position. */
7159 root_x, root_y, &win_x, &win_y,
7160
7161 /* Child of win. */
7162 &child);
69388238
RS
7163 f1 = last_mouse_frame;
7164 }
7165 else
7166 {
7167 while (1)
7168 {
334208b7 7169 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 7170
69388238
RS
7171 /* From-window, to-window. */
7172 root, win,
12ba150f 7173
69388238
RS
7174 /* From-position, to-position. */
7175 root_x, root_y, &win_x, &win_y,
7176
7177 /* Child of win. */
7178 &child);
7179
9af3143a 7180 if (child == None || child == win)
69388238
RS
7181 break;
7182
7183 win = child;
7184 parent_x = win_x;
7185 parent_y = win_y;
7186 }
12ba150f 7187
69388238
RS
7188 /* Now we know that:
7189 win is the innermost window containing the pointer
7190 (XTC says it has no child containing the pointer),
7191 win_x and win_y are the pointer's position in it
7192 (XTC did this the last time through), and
7193 parent_x and parent_y are the pointer's position in win's parent.
7194 (They are what win_x and win_y were when win was child.
7195 If win is the root window, it has no parent, and
7196 parent_{x,y} are invalid, but that's okay, because we'll
7197 never use them in that case.) */
7198
7199 /* Is win one of our frames? */
19126e11 7200 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
69388238 7201 }
58769bee 7202
2d7fc7e8
RS
7203 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
7204 f1 = 0;
7205
e99db5a1 7206 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 7207
ab648270 7208 /* If not, is it one of our scroll bars? */
a135645a 7209 if (! f1)
12ba150f 7210 {
ab648270 7211 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
7212
7213 if (bar)
7214 {
a135645a 7215 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
7216 win_x = parent_x;
7217 win_y = parent_y;
7218 }
7219 }
90e65f07 7220
8bcee03e 7221 if (f1 == 0 && insist > 0)
b86bd3dd 7222 f1 = SELECTED_FRAME ();
1cf412ec 7223
a135645a 7224 if (f1)
12ba150f 7225 {
06a2c219
GM
7226 /* Ok, we found a frame. Store all the values.
7227 last_mouse_glyph is a rectangle used to reduce the
7228 generation of mouse events. To not miss any motion
7229 events, we must divide the frame into rectangles of the
7230 size of the smallest character that could be displayed
7231 on it, i.e. into the same rectangles that matrices on
7232 the frame are divided into. */
7233
7234#if OLD_REDISPLAY_CODE
2b5c9e71 7235 int ignore1, ignore2;
2b5c9e71 7236 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
334208b7 7237 &last_mouse_glyph,
1cf412ec
RS
7238 FRAME_X_DISPLAY_INFO (f1)->grabbed
7239 || insist);
06a2c219
GM
7240#else
7241 {
7242 int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
7243 int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
7244 int x = win_x;
7245 int y = win_y;
7246
7247 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
7248 round down even for negative values. */
7249 if (x < 0)
7250 x -= width - 1;
7251 if (y < 0)
7252 y -= height - 1;
7253
7254 last_mouse_glyph.width = width;
7255 last_mouse_glyph.height = height;
7256 last_mouse_glyph.x = (x + width - 1) / width * width;
7257 last_mouse_glyph.y = (y + height - 1) / height * height;
7258 }
7259#endif
12ba150f
JB
7260
7261 *bar_window = Qnil;
7262 *part = 0;
334208b7 7263 *fp = f1;
e0c1aef2
KH
7264 XSETINT (*x, win_x);
7265 XSETINT (*y, win_y);
12ba150f
JB
7266 *time = last_mouse_movement_time;
7267 }
7268 }
7269 }
90e65f07
JB
7270
7271 UNBLOCK_INPUT;
7272}
f451eb13 7273
06a2c219 7274
06a2c219 7275#ifdef USE_X_TOOLKIT
bffcfca9
GM
7276
7277/* Atimer callback function for TIMER. Called every 0.1s to process
7278 Xt timeouts, if needed. We must avoid calling XtAppPending as
7279 much as possible because that function does an implicit XFlush
7280 that slows us down. */
7281
7282static void
7283x_process_timeouts (timer)
7284 struct atimer *timer;
7285{
7286 if (toolkit_scroll_bar_interaction || popup_activated_flag)
7287 {
7288 BLOCK_INPUT;
7289 while (XtAppPending (Xt_app_con) & XtIMTimer)
7290 XtAppProcessEvent (Xt_app_con, XtIMTimer);
7291 UNBLOCK_INPUT;
7292 }
06a2c219
GM
7293}
7294
bffcfca9 7295#endif /* USE_X_TOOLKIT */
06a2c219
GM
7296
7297\f
7298/* Scroll bar support. */
7299
7300/* Given an X window ID, find the struct scroll_bar which manages it.
7301 This can be called in GC, so we have to make sure to strip off mark
7302 bits. */
bffcfca9 7303
06a2c219
GM
7304static struct scroll_bar *
7305x_window_to_scroll_bar (window_id)
7306 Window window_id;
7307{
7308 Lisp_Object tail;
7309
7310 for (tail = Vframe_list;
7311 XGCTYPE (tail) == Lisp_Cons;
8e713be6 7312 tail = XCDR (tail))
06a2c219
GM
7313 {
7314 Lisp_Object frame, bar, condemned;
7315
8e713be6 7316 frame = XCAR (tail);
06a2c219
GM
7317 /* All elements of Vframe_list should be frames. */
7318 if (! GC_FRAMEP (frame))
7319 abort ();
7320
7321 /* Scan this frame's scroll bar list for a scroll bar with the
7322 right window ID. */
7323 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
7324 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
7325 /* This trick allows us to search both the ordinary and
7326 condemned scroll bar lists with one loop. */
7327 ! GC_NILP (bar) || (bar = condemned,
7328 condemned = Qnil,
7329 ! GC_NILP (bar));
7330 bar = XSCROLL_BAR (bar)->next)
7331 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
7332 return XSCROLL_BAR (bar);
7333 }
7334
7335 return 0;
7336}
7337
7338
7339\f
7340/************************************************************************
7341 Toolkit scroll bars
7342 ************************************************************************/
7343
7344#if USE_TOOLKIT_SCROLL_BARS
7345
7346static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
7347static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
7348static void x_create_toolkit_scroll_bar P_ ((struct frame *,
7349 struct scroll_bar *));
7350static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
7351 int, int, int));
7352
7353
7354/* Id of action hook installed for scroll bars. */
7355
7356static XtActionHookId action_hook_id;
7357
7358/* Lisp window being scrolled. Set when starting to interact with
7359 a toolkit scroll bar, reset to nil when ending the interaction. */
7360
7361static Lisp_Object window_being_scrolled;
7362
7363/* Last scroll bar part sent in xm_scroll_callback. */
7364
7365static int last_scroll_bar_part;
7366
ec18280f
SM
7367/* Whether this is an Xaw with arrow-scrollbars. This should imply
7368 that movements of 1/20 of the screen size are mapped to up/down. */
7369
7370static Boolean xaw3d_arrow_scroll;
7371
7372/* Whether the drag scrolling maintains the mouse at the top of the
7373 thumb. If not, resizing the thumb needs to be done more carefully
7374 to avoid jerkyness. */
7375
7376static Boolean xaw3d_pick_top;
7377
06a2c219
GM
7378
7379/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 7380 bars are used.. The hook is responsible for detecting when
06a2c219
GM
7381 the user ends an interaction with the scroll bar, and generates
7382 a `end-scroll' scroll_bar_click' event if so. */
7383
7384static void
7385xt_action_hook (widget, client_data, action_name, event, params,
7386 num_params)
7387 Widget widget;
7388 XtPointer client_data;
7389 String action_name;
7390 XEvent *event;
7391 String *params;
7392 Cardinal *num_params;
7393{
7394 int scroll_bar_p;
7395 char *end_action;
7396
7397#ifdef USE_MOTIF
7398 scroll_bar_p = XmIsScrollBar (widget);
7399 end_action = "Release";
ec18280f 7400#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7401 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
7402 end_action = "EndScroll";
ec18280f 7403#endif /* USE_MOTIF */
06a2c219 7404
06a2c219
GM
7405 if (scroll_bar_p
7406 && strcmp (action_name, end_action) == 0
7407 && WINDOWP (window_being_scrolled))
7408 {
7409 struct window *w;
7410
7411 x_send_scroll_bar_event (window_being_scrolled,
7412 scroll_bar_end_scroll, 0, 0);
7413 w = XWINDOW (window_being_scrolled);
7414 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
7415 window_being_scrolled = Qnil;
7416 last_scroll_bar_part = -1;
bffcfca9
GM
7417
7418 /* Xt timeouts no longer needed. */
7419 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
7420 }
7421}
7422
7423
7424/* Send a client message with message type Xatom_Scrollbar for a
7425 scroll action to the frame of WINDOW. PART is a value identifying
7426 the part of the scroll bar that was clicked on. PORTION is the
7427 amount to scroll of a whole of WHOLE. */
7428
7429static void
7430x_send_scroll_bar_event (window, part, portion, whole)
7431 Lisp_Object window;
7432 int part, portion, whole;
7433{
7434 XEvent event;
7435 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
7436 struct frame *f = XFRAME (XWINDOW (window)->frame);
7437
7438 /* Construct a ClientMessage event to send to the frame. */
7439 ev->type = ClientMessage;
7440 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
7441 ev->display = FRAME_X_DISPLAY (f);
7442 ev->window = FRAME_X_WINDOW (f);
7443 ev->format = 32;
52e386c2 7444 ev->data.l[0] = (long) XFASTINT (window);
06a2c219
GM
7445 ev->data.l[1] = (long) part;
7446 ev->data.l[2] = (long) 0;
7447 ev->data.l[3] = (long) portion;
7448 ev->data.l[4] = (long) whole;
7449
bffcfca9
GM
7450 /* Make Xt timeouts work while the scroll bar is active. */
7451 toolkit_scroll_bar_interaction = 1;
7452
06a2c219
GM
7453 /* Setting the event mask to zero means that the message will
7454 be sent to the client that created the window, and if that
7455 window no longer exists, no event will be sent. */
7456 BLOCK_INPUT;
7457 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
7458 UNBLOCK_INPUT;
7459}
7460
7461
7462/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
7463 in *IEVENT. */
7464
7465static void
7466x_scroll_bar_to_input_event (event, ievent)
7467 XEvent *event;
7468 struct input_event *ievent;
7469{
7470 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
7471 Lisp_Object window;
7472 struct frame *f;
7473
7474 XSETFASTINT (window, ev->data.l[0]);
7475 f = XFRAME (XWINDOW (window)->frame);
06a2c219
GM
7476
7477 ievent->kind = scroll_bar_click;
7478 ievent->frame_or_window = window;
7479 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
7480 ievent->part = ev->data.l[1];
7481 ievent->code = ev->data.l[2];
7482 ievent->x = make_number ((int) ev->data.l[3]);
7483 ievent->y = make_number ((int) ev->data.l[4]);
7484 ievent->modifiers = 0;
7485}
7486
7487
7488#ifdef USE_MOTIF
7489
7490/* Minimum and maximum values used for Motif scroll bars. */
7491
7492#define XM_SB_MIN 1
7493#define XM_SB_MAX 10000000
7494#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
7495
7496
7497/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
7498 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
7499 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
7500
7501static void
7502xm_scroll_callback (widget, client_data, call_data)
7503 Widget widget;
7504 XtPointer client_data, call_data;
7505{
7506 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7507 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
7508 double percent;
7509 int part = -1, whole = 0, portion = 0;
7510
7511 switch (cs->reason)
7512 {
7513 case XmCR_DECREMENT:
7514 bar->dragging = Qnil;
7515 part = scroll_bar_up_arrow;
7516 break;
7517
7518 case XmCR_INCREMENT:
7519 bar->dragging = Qnil;
7520 part = scroll_bar_down_arrow;
7521 break;
7522
7523 case XmCR_PAGE_DECREMENT:
7524 bar->dragging = Qnil;
7525 part = scroll_bar_above_handle;
7526 break;
7527
7528 case XmCR_PAGE_INCREMENT:
7529 bar->dragging = Qnil;
7530 part = scroll_bar_below_handle;
7531 break;
7532
7533 case XmCR_TO_TOP:
7534 bar->dragging = Qnil;
7535 part = scroll_bar_to_top;
7536 break;
7537
7538 case XmCR_TO_BOTTOM:
7539 bar->dragging = Qnil;
7540 part = scroll_bar_to_bottom;
7541 break;
7542
7543 case XmCR_DRAG:
7544 {
7545 int slider_size;
7546 int dragging_down_p = (INTEGERP (bar->dragging)
7547 && XINT (bar->dragging) <= cs->value);
7548
7549 /* Get the slider size. */
7550 BLOCK_INPUT;
7551 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
7552 UNBLOCK_INPUT;
7553
7554 /* At the max position of the scroll bar, do a line-wise
7555 movement. Without doing anything, the LessTif scroll bar
7556 calls us with the same cs->value again and again. If we
7557 want to make sure that we can reach the end of the buffer,
7558 we have to do something.
7559
7560 Implementation note: setting bar->dragging always to
7561 cs->value gives a smoother movement at the max position.
7562 Setting it to nil when doing line-wise movement gives
7563 a better slider behavior. */
7564
7565 if (cs->value + slider_size == XM_SB_MAX
7566 || (dragging_down_p
7567 && last_scroll_bar_part == scroll_bar_down_arrow))
7568 {
7569 part = scroll_bar_down_arrow;
7570 bar->dragging = Qnil;
7571 }
7572 else
7573 {
7574 whole = XM_SB_RANGE;
7575 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
7576 part = scroll_bar_handle;
7577 bar->dragging = make_number (cs->value);
7578 }
7579 }
7580 break;
7581
7582 case XmCR_VALUE_CHANGED:
7583 break;
7584 };
7585
7586 if (part >= 0)
7587 {
7588 window_being_scrolled = bar->window;
7589 last_scroll_bar_part = part;
7590 x_send_scroll_bar_event (bar->window, part, portion, whole);
7591 }
7592}
7593
7594
ec18280f 7595#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
7596
7597
ec18280f 7598/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
7599 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
7600 scroll bar struct. CALL_DATA is a pointer to a float saying where
7601 the thumb is. */
7602
7603static void
ec18280f 7604xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
7605 Widget widget;
7606 XtPointer client_data, call_data;
7607{
7608 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7609 float top = *(float *) call_data;
7610 float shown;
ec18280f
SM
7611 int whole, portion, height;
7612 int part;
06a2c219
GM
7613
7614 /* Get the size of the thumb, a value between 0 and 1. */
7615 BLOCK_INPUT;
ec18280f 7616 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
7617 UNBLOCK_INPUT;
7618
7619 whole = 10000000;
7620 portion = shown < 1 ? top * whole : 0;
06a2c219 7621
ec18280f
SM
7622 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
7623 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
7624 the bottom, so we force the scrolling whenever we see that we're
7625 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
7626 we try to ensure that we always stay two pixels away from the
7627 bottom). */
06a2c219
GM
7628 part = scroll_bar_down_arrow;
7629 else
7630 part = scroll_bar_handle;
7631
7632 window_being_scrolled = bar->window;
7633 bar->dragging = make_number (portion);
7634 last_scroll_bar_part = part;
7635 x_send_scroll_bar_event (bar->window, part, portion, whole);
7636}
7637
7638
ec18280f
SM
7639/* Xaw scroll bar callback. Invoked for incremental scrolling.,
7640 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
7641 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
7642 the scroll bar. CALL_DATA is an integer specifying the action that
7643 has taken place. It's magnitude is in the range 0..height of the
7644 scroll bar. Negative values mean scroll towards buffer start.
7645 Values < height of scroll bar mean line-wise movement. */
7646
7647static void
ec18280f 7648xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
7649 Widget widget;
7650 XtPointer client_data, call_data;
7651{
7652 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7653 int position = (int) call_data;
7654 Dimension height;
7655 int part;
7656
7657 /* Get the height of the scroll bar. */
7658 BLOCK_INPUT;
7659 XtVaGetValues (widget, XtNheight, &height, NULL);
7660 UNBLOCK_INPUT;
7661
ec18280f
SM
7662 if (abs (position) >= height)
7663 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
7664
7665 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
7666 it maps line-movement to call_data = max(5, height/20). */
7667 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
7668 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 7669 else
ec18280f 7670 part = scroll_bar_move_ratio;
06a2c219
GM
7671
7672 window_being_scrolled = bar->window;
7673 bar->dragging = Qnil;
7674 last_scroll_bar_part = part;
ec18280f 7675 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
7676}
7677
7678
7679#endif /* not USE_MOTIF */
7680
7681
7682/* Create the widget for scroll bar BAR on frame F. Record the widget
7683 and X window of the scroll bar in BAR. */
7684
7685static void
7686x_create_toolkit_scroll_bar (f, bar)
7687 struct frame *f;
7688 struct scroll_bar *bar;
7689{
7690 Window xwindow;
7691 Widget widget;
7692 Arg av[20];
7693 int ac = 0;
7694 char *scroll_bar_name = "verticalScrollBar";
7695 unsigned long pixel;
7696
7697 BLOCK_INPUT;
7698
7699#ifdef USE_MOTIF
7700 /* LessTif 0.85, problems:
7701
7702 1. When the mouse if over the scroll bar, the scroll bar will
7703 get keyboard events. I didn't find a way to turn this off.
7704
7705 2. Do we have to explicitly set the cursor to get an arrow
7706 cursor (see below)? */
7707
7708 /* Set resources. Create the widget. */
7709 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7710 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
7711 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
7712 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
7713 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
7714 XtSetArg (av[ac], XmNincrement, 1); ++ac;
7715 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
7716
7717 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7718 if (pixel != -1)
7719 {
7720 XtSetArg (av[ac], XmNforeground, pixel);
7721 ++ac;
7722 }
7723
7724 pixel = f->output_data.x->scroll_bar_background_pixel;
7725 if (pixel != -1)
7726 {
7727 XtSetArg (av[ac], XmNbackground, pixel);
7728 ++ac;
7729 }
7730
7731 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
7732 scroll_bar_name, av, ac);
7733
7734 /* Add one callback for everything that can happen. */
7735 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
7736 (XtPointer) bar);
7737 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
7738 (XtPointer) bar);
7739 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
7740 (XtPointer) bar);
7741 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
7742 (XtPointer) bar);
7743 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
7744 (XtPointer) bar);
7745 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
7746 (XtPointer) bar);
7747 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
7748 (XtPointer) bar);
7749
7750 /* Realize the widget. Only after that is the X window created. */
7751 XtRealizeWidget (widget);
7752
7753 /* Set the cursor to an arrow. I didn't find a resource to do that.
7754 And I'm wondering why it hasn't an arrow cursor by default. */
7755 XDefineCursor (XtDisplay (widget), XtWindow (widget),
7756 f->output_data.x->nontext_cursor);
7757
ec18280f 7758#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7759
7760 /* Set resources. Create the widget. The background of the
7761 Xaw3d scroll bar widget is a little bit light for my taste.
7762 We don't alter it here to let users change it according
7763 to their taste with `emacs*verticalScrollBar.background: xxx'. */
7764 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
7765 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
7766 /* For smoother scrolling with Xaw3d -sm */
7767 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
7768 /* XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac; */
06a2c219
GM
7769
7770 pixel = f->output_data.x->scroll_bar_foreground_pixel;
7771 if (pixel != -1)
7772 {
7773 XtSetArg (av[ac], XtNforeground, pixel);
7774 ++ac;
7775 }
7776
7777 pixel = f->output_data.x->scroll_bar_background_pixel;
7778 if (pixel != -1)
7779 {
7780 XtSetArg (av[ac], XtNbackground, pixel);
7781 ++ac;
7782 }
7783
7784 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
7785 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
7786
7787 {
7788 char *initial = "";
7789 char *val = initial;
7790 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
7791 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
7792 if (val == initial)
7793 { /* ARROW_SCROLL */
7794 xaw3d_arrow_scroll = True;
7795 /* Isn't that just a personal preference ? -sm */
7796 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
7797 }
7798 }
06a2c219
GM
7799
7800 /* Define callbacks. */
ec18280f
SM
7801 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
7802 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
7803 (XtPointer) bar);
7804
7805 /* Realize the widget. Only after that is the X window created. */
7806 XtRealizeWidget (widget);
7807
ec18280f 7808#endif /* !USE_MOTIF */
06a2c219
GM
7809
7810 /* Install an action hook that let's us detect when the user
7811 finishes interacting with a scroll bar. */
7812 if (action_hook_id == 0)
7813 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
7814
7815 /* Remember X window and widget in the scroll bar vector. */
7816 SET_SCROLL_BAR_X_WIDGET (bar, widget);
7817 xwindow = XtWindow (widget);
7818 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
7819
7820 UNBLOCK_INPUT;
7821}
7822
7823
7824/* Set the thumb size and position of scroll bar BAR. We are currently
7825 displaying PORTION out of a whole WHOLE, and our position POSITION. */
7826
7827static void
7828x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
7829 struct scroll_bar *bar;
7830 int portion, position, whole;
f451eb13 7831{
06a2c219 7832 float top, shown;
06a2c219 7833 Widget widget = SCROLL_BAR_X_WIDGET (bar);
f451eb13 7834
06a2c219
GM
7835 if (whole == 0)
7836 top = 0, shown = 1;
7837 else
f451eb13 7838 {
06a2c219
GM
7839 top = (float) position / whole;
7840 shown = (float) portion / whole;
7841 }
f451eb13 7842
06a2c219 7843 BLOCK_INPUT;
f451eb13 7844
06a2c219
GM
7845#ifdef USE_MOTIF
7846 {
7847 int size, value;
7848 Boolean arrow1_selected, arrow2_selected;
7849 unsigned char flags;
7850 XmScrollBarWidget sb;
7851
ec18280f 7852 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
7853 is the scroll bar's maximum and MIN is the scroll bar's minimum
7854 value. */
7855 size = shown * XM_SB_RANGE;
7856 size = min (size, XM_SB_RANGE);
7857 size = max (size, 1);
7858
7859 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
7860 value = top * XM_SB_RANGE;
7861 value = min (value, XM_SB_MAX - size);
7862 value = max (value, XM_SB_MIN);
7863
7864 /* LessTif: Calling XmScrollBarSetValues after an increment or
7865 decrement turns off auto-repeat LessTif-internally. This can
7866 be seen in ScrollBar.c which resets Arrow1Selected and
7867 Arrow2Selected. It also sets internal flags so that LessTif
7868 believes the mouse is in the slider. We either have to change
7869 our code, or work around that by accessing private data. */
7870
7871 sb = (XmScrollBarWidget) widget;
7872 arrow1_selected = sb->scrollBar.arrow1_selected;
7873 arrow2_selected = sb->scrollBar.arrow2_selected;
7874 flags = sb->scrollBar.flags;
7875
7876 if (NILP (bar->dragging))
7877 XmScrollBarSetValues (widget, value, size, 0, 0, False);
7878 else if (last_scroll_bar_part == scroll_bar_down_arrow)
7879 /* This has the negative side effect that the slider value is
ec18280f 7880 not what it would be if we scrolled here using line-wise or
06a2c219
GM
7881 page-wise movement. */
7882 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
7883 else
7884 {
7885 /* If currently dragging, only update the slider size.
7886 This reduces flicker effects. */
7887 int old_value, old_size, increment, page_increment;
7888
7889 XmScrollBarGetValues (widget, &old_value, &old_size,
7890 &increment, &page_increment);
7891 XmScrollBarSetValues (widget, old_value,
7892 min (size, XM_SB_RANGE - old_value),
7893 0, 0, False);
7894 }
7895
7896 sb->scrollBar.arrow1_selected = arrow1_selected;
7897 sb->scrollBar.arrow2_selected = arrow2_selected;
7898 sb->scrollBar.flags = flags;
7899 }
ec18280f 7900#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 7901 {
ec18280f
SM
7902 float old_top, old_shown;
7903 Dimension height;
7904 XtVaGetValues (widget,
7905 XtNtopOfThumb, &old_top,
7906 XtNshown, &old_shown,
7907 XtNheight, &height,
7908 NULL);
7909
7910 /* Massage the top+shown values. */
7911 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
7912 top = max (0, min (1, top));
7913 else
7914 top = old_top;
7915 /* Keep two pixels available for moving the thumb down. */
7916 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
7917
7918 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
7919 check that your system's configuration file contains a define
7920 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 7921 if (top != old_top || shown != old_shown)
eb393530 7922 {
ec18280f 7923 if (NILP (bar->dragging))
eb393530 7924 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
7925 else
7926 {
ec18280f
SM
7927#ifdef HAVE_XAW3D
7928 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 7929 int scroll_mode = 0;
ec18280f
SM
7930
7931 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
7932 if (xaw3d_arrow_scroll)
7933 {
7934 /* Xaw3d stupidly ignores resize requests while dragging
7935 so we have to make it believe it's not in dragging mode. */
7936 scroll_mode = sb->scrollbar.scroll_mode;
7937 if (scroll_mode == 2)
7938 sb->scrollbar.scroll_mode = 0;
7939 }
7940#endif
7941 /* Try to make the scrolling a tad smoother. */
7942 if (!xaw3d_pick_top)
7943 shown = min (shown, old_shown);
7944
7945 XawScrollbarSetThumb (widget, top, shown);
7946
7947#ifdef HAVE_XAW3D
7948 if (xaw3d_arrow_scroll && scroll_mode == 2)
7949 sb->scrollbar.scroll_mode = scroll_mode;
7950#endif
06a2c219 7951 }
06a2c219
GM
7952 }
7953 }
ec18280f 7954#endif /* !USE_MOTIF */
06a2c219
GM
7955
7956 UNBLOCK_INPUT;
f451eb13
JB
7957}
7958
06a2c219
GM
7959#endif /* USE_TOOLKIT_SCROLL_BARS */
7960
7961
7962\f
7963/************************************************************************
7964 Scroll bars, general
7965 ************************************************************************/
7966
7967/* Create a scroll bar and return the scroll bar vector for it. W is
7968 the Emacs window on which to create the scroll bar. TOP, LEFT,
7969 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
7970 scroll bar. */
7971
ab648270 7972static struct scroll_bar *
06a2c219
GM
7973x_scroll_bar_create (w, top, left, width, height)
7974 struct window *w;
f451eb13
JB
7975 int top, left, width, height;
7976{
06a2c219 7977 struct frame *f = XFRAME (w->frame);
334208b7
RS
7978 struct scroll_bar *bar
7979 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
7980
7981 BLOCK_INPUT;
7982
06a2c219
GM
7983#if USE_TOOLKIT_SCROLL_BARS
7984 x_create_toolkit_scroll_bar (f, bar);
7985#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
7986 {
7987 XSetWindowAttributes a;
7988 unsigned long mask;
5c187dee 7989 Window window;
06a2c219
GM
7990
7991 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
7992 if (a.background_pixel == -1)
7993 a.background_pixel = f->output_data.x->background_pixel;
7994
12ba150f 7995 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 7996 | ButtonMotionMask | PointerMotionHintMask
12ba150f 7997 | ExposureMask);
7a13e894 7998 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 7999
dbc4e1c1 8000 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8001
06a2c219
GM
8002 /* Clear the area of W that will serve as a scroll bar. This is
8003 for the case that a window has been split horizontally. In
8004 this case, no clear_frame is generated to reduce flickering. */
8005 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8006 left, top, width,
8007 window_box_height (w), False);
8008
8009 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8010 /* Position and size of scroll bar. */
8011 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8012 top,
8013 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8014 height,
8015 /* Border width, depth, class, and visual. */
8016 0,
8017 CopyFromParent,
8018 CopyFromParent,
8019 CopyFromParent,
8020 /* Attributes. */
8021 mask, &a);
8022 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8023 }
06a2c219 8024#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8025
06a2c219 8026 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8027 XSETINT (bar->top, top);
8028 XSETINT (bar->left, left);
8029 XSETINT (bar->width, width);
8030 XSETINT (bar->height, height);
8031 XSETINT (bar->start, 0);
8032 XSETINT (bar->end, 0);
12ba150f 8033 bar->dragging = Qnil;
f451eb13
JB
8034
8035 /* Add bar to its frame's list of scroll bars. */
334208b7 8036 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8037 bar->prev = Qnil;
334208b7 8038 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 8039 if (!NILP (bar->next))
e0c1aef2 8040 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 8041
06a2c219
GM
8042 /* Map the window/widget. */
8043#if USE_TOOLKIT_SCROLL_BARS
8044 XtMapWidget (SCROLL_BAR_X_WIDGET (bar));
8045 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
8046 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8047 top,
8048 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8049 height, 0);
8050#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 8051 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 8052#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8053
8054 UNBLOCK_INPUT;
12ba150f 8055 return bar;
f451eb13
JB
8056}
8057
06a2c219 8058
12ba150f 8059/* Draw BAR's handle in the proper position.
06a2c219 8060
12ba150f
JB
8061 If the handle is already drawn from START to END, don't bother
8062 redrawing it, unless REBUILD is non-zero; in that case, always
8063 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 8064 events.)
12ba150f
JB
8065
8066 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
8067 fit inside its rectangle, but if the user is dragging the scroll
8068 bar handle, we want to let them drag it down all the way, so that
8069 the bar's top is as far down as it goes; otherwise, there's no way
8070 to move to the very end of the buffer. */
8071
5c187dee
GM
8072#ifndef USE_TOOLKIT_SCROLL_BARS
8073
f451eb13 8074static void
ab648270
JB
8075x_scroll_bar_set_handle (bar, start, end, rebuild)
8076 struct scroll_bar *bar;
f451eb13 8077 int start, end;
12ba150f 8078 int rebuild;
f451eb13 8079{
12ba150f 8080 int dragging = ! NILP (bar->dragging);
ab648270 8081 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8082 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8083 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
8084
8085 /* If the display is already accurate, do nothing. */
8086 if (! rebuild
8087 && start == XINT (bar->start)
8088 && end == XINT (bar->end))
8089 return;
8090
f451eb13
JB
8091 BLOCK_INPUT;
8092
8093 {
d9cdbb3d
RS
8094 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
8095 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
8096 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
8097
8098 /* Make sure the values are reasonable, and try to preserve
8099 the distance between start and end. */
12ba150f
JB
8100 {
8101 int length = end - start;
8102
8103 if (start < 0)
8104 start = 0;
8105 else if (start > top_range)
8106 start = top_range;
8107 end = start + length;
8108
8109 if (end < start)
8110 end = start;
8111 else if (end > top_range && ! dragging)
8112 end = top_range;
8113 }
f451eb13 8114
ab648270 8115 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
8116 XSETINT (bar->start, start);
8117 XSETINT (bar->end, end);
f451eb13 8118
12ba150f
JB
8119 /* Clip the end position, just for display. */
8120 if (end > top_range)
8121 end = top_range;
f451eb13 8122
ab648270 8123 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
8124 below top positions, to make sure the handle is always at least
8125 that many pixels tall. */
ab648270 8126 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 8127
12ba150f
JB
8128 /* Draw the empty space above the handle. Note that we can't clear
8129 zero-height areas; that means "clear to end of window." */
8130 if (0 < start)
334208b7 8131 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8132
12ba150f 8133 /* x, y, width, height, and exposures. */
ab648270
JB
8134 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8135 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
8136 inside_width, start,
8137 False);
f451eb13 8138
06a2c219
GM
8139 /* Change to proper foreground color if one is specified. */
8140 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8141 XSetForeground (FRAME_X_DISPLAY (f), gc,
8142 f->output_data.x->scroll_bar_foreground_pixel);
8143
12ba150f 8144 /* Draw the handle itself. */
334208b7 8145 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 8146
12ba150f 8147 /* x, y, width, height */
ab648270
JB
8148 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8149 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 8150 inside_width, end - start);
f451eb13 8151
06a2c219
GM
8152 /* Restore the foreground color of the GC if we changed it above. */
8153 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8154 XSetForeground (FRAME_X_DISPLAY (f), gc,
8155 f->output_data.x->foreground_pixel);
f451eb13 8156
12ba150f
JB
8157 /* Draw the empty space below the handle. Note that we can't
8158 clear zero-height areas; that means "clear to end of window." */
8159 if (end < inside_height)
334208b7 8160 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 8161
12ba150f 8162 /* x, y, width, height, and exposures. */
ab648270
JB
8163 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8164 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
8165 inside_width, inside_height - end,
8166 False);
f451eb13 8167
f451eb13
JB
8168 }
8169
f451eb13
JB
8170 UNBLOCK_INPUT;
8171}
8172
5c187dee 8173#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 8174
06a2c219
GM
8175/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
8176 nil. */
58769bee 8177
12ba150f 8178static void
ab648270
JB
8179x_scroll_bar_remove (bar)
8180 struct scroll_bar *bar;
12ba150f 8181{
12ba150f
JB
8182 BLOCK_INPUT;
8183
06a2c219
GM
8184#if USE_TOOLKIT_SCROLL_BARS
8185 XtDestroyWidget (SCROLL_BAR_X_WIDGET (bar));
8186#else /* not USE_TOOLKIT_SCROLL_BARS */
5c187dee
GM
8187 {
8188 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8189 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
8190 }
06a2c219
GM
8191#endif /* not USE_TOOLKIT_SCROLL_BARS */
8192
ab648270
JB
8193 /* Disassociate this scroll bar from its window. */
8194 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
8195
8196 UNBLOCK_INPUT;
8197}
8198
06a2c219 8199
12ba150f
JB
8200/* Set the handle of the vertical scroll bar for WINDOW to indicate
8201 that we are displaying PORTION characters out of a total of WHOLE
ab648270 8202 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 8203 create one. */
06a2c219 8204
12ba150f 8205static void
06a2c219
GM
8206XTset_vertical_scroll_bar (w, portion, whole, position)
8207 struct window *w;
f451eb13
JB
8208 int portion, whole, position;
8209{
06a2c219 8210 struct frame *f = XFRAME (w->frame);
ab648270 8211 struct scroll_bar *bar;
3c6ede7b 8212 int top, height, left, sb_left, width, sb_width;
06a2c219 8213 int window_x, window_y, window_width, window_height;
06a2c219 8214
3c6ede7b 8215 /* Get window dimensions. */
06a2c219 8216 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
8217 top = window_y;
8218 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
8219 height = window_height;
06a2c219 8220
3c6ede7b 8221 /* Compute the left edge of the scroll bar area. */
06a2c219 8222 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
8223 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
8224 else
8225 left = XFASTINT (w->left);
8226 left *= CANON_X_UNIT (f);
8227 left += FRAME_INTERNAL_BORDER_WIDTH (f);
8228
8229 /* Compute the width of the scroll bar which might be less than
8230 the width of the area reserved for the scroll bar. */
8231 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
8232 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 8233 else
3c6ede7b 8234 sb_width = width;
12ba150f 8235
3c6ede7b
GM
8236 /* Compute the left edge of the scroll bar. */
8237#ifdef USE_TOOLKIT_SCROLL_BARS
8238 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8239 sb_left = left + width - sb_width - (width - sb_width) / 2;
8240 else
8241 sb_left = left + (width - sb_width) / 2;
8242#else
8243 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8244 sb_left = left + width - sb_width;
8245 else
8246 sb_left = left;
8247#endif
8248
ab648270 8249 /* Does the scroll bar exist yet? */
06a2c219 8250 if (NILP (w->vertical_scroll_bar))
3c6ede7b 8251 {
80c32bcc 8252 BLOCK_INPUT;
3c6ede7b
GM
8253 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8254 left, top, width, height, False);
80c32bcc 8255 UNBLOCK_INPUT;
3c6ede7b
GM
8256 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
8257 }
f451eb13 8258 else
12ba150f
JB
8259 {
8260 /* It may just need to be moved and resized. */
06a2c219
GM
8261 unsigned int mask = 0;
8262
8263 bar = XSCROLL_BAR (w->vertical_scroll_bar);
8264
8265 BLOCK_INPUT;
8266
3c6ede7b 8267 if (sb_left != XINT (bar->left))
06a2c219 8268 mask |= CWX;
3c6ede7b 8269 if (top != XINT (bar->top))
06a2c219 8270 mask |= CWY;
3c6ede7b 8271 if (sb_width != XINT (bar->width))
06a2c219 8272 mask |= CWWidth;
3c6ede7b 8273 if (height != XINT (bar->height))
06a2c219
GM
8274 mask |= CWHeight;
8275
8276#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
8277
8278 /* Since toolkit scroll bars are smaller than the space reserved
8279 for them on the frame, we have to clear "under" them. */
8280 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3c6ede7b 8281 left, top, width, height, False);
06a2c219
GM
8282
8283 /* Move/size the scroll bar widget. */
8284 if (mask)
8285 XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
3c6ede7b
GM
8286 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8287 top,
8288 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8289 height, 0);
06a2c219
GM
8290
8291#else /* not USE_TOOLKIT_SCROLL_BARS */
8292
e1f6572f
RS
8293 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
8294 {
8295 /* Clear areas not covered by the scroll bar. This makes sure a
8296 previous mode line display is cleared after C-x 2 C-x 1, for
8297 example. Non-toolkit scroll bars are as wide as the area
8298 reserved for scroll bars - trim at both sides. */
8299 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8300 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8301 height, False);
8302 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8303 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8304 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8305 height, False);
8306 }
06a2c219
GM
8307
8308 /* Move/size the scroll bar window. */
8309 if (mask)
8310 {
8311 XWindowChanges wc;
8312
3c6ede7b
GM
8313 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
8314 wc.y = top;
8315 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
8316 wc.height = height;
06a2c219
GM
8317 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
8318 mask, &wc);
8319 }
8320
8321#endif /* not USE_TOOLKIT_SCROLL_BARS */
8322
8323 /* Remember new settings. */
3c6ede7b
GM
8324 XSETINT (bar->left, sb_left);
8325 XSETINT (bar->top, top);
8326 XSETINT (bar->width, sb_width);
8327 XSETINT (bar->height, height);
06a2c219
GM
8328
8329 UNBLOCK_INPUT;
12ba150f 8330 }
f451eb13 8331
06a2c219
GM
8332#if USE_TOOLKIT_SCROLL_BARS
8333 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
8334#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 8335 /* Set the scroll bar's current state, unless we're currently being
f451eb13 8336 dragged. */
12ba150f 8337 if (NILP (bar->dragging))
f451eb13 8338 {
92857db0 8339 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 8340
12ba150f 8341 if (whole == 0)
ab648270 8342 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
8343 else
8344 {
43f868f5
JB
8345 int start = ((double) position * top_range) / whole;
8346 int end = ((double) (position + portion) * top_range) / whole;
ab648270 8347 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 8348 }
f451eb13 8349 }
06a2c219 8350#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8351
06a2c219 8352 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
8353}
8354
12ba150f 8355
f451eb13 8356/* The following three hooks are used when we're doing a thorough
ab648270 8357 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 8358 are going to be deleted, because keeping track of when windows go
12ba150f
JB
8359 away is a real pain - "Can you say set-window-configuration, boys
8360 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 8361 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 8362 from the fiery pit when we actually redisplay its window. */
f451eb13 8363
ab648270
JB
8364/* Arrange for all scroll bars on FRAME to be removed at the next call
8365 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
8366 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
8367
58769bee 8368static void
ab648270 8369XTcondemn_scroll_bars (frame)
f451eb13
JB
8370 FRAME_PTR frame;
8371{
f9e24cb9
RS
8372 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
8373 while (! NILP (FRAME_SCROLL_BARS (frame)))
8374 {
8375 Lisp_Object bar;
8376 bar = FRAME_SCROLL_BARS (frame);
8377 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
8378 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
8379 XSCROLL_BAR (bar)->prev = Qnil;
8380 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
8381 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
8382 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
8383 }
f451eb13
JB
8384}
8385
06a2c219 8386/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 8387 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 8388static void
ab648270 8389XTredeem_scroll_bar (window)
12ba150f 8390 struct window *window;
f451eb13 8391{
ab648270 8392 struct scroll_bar *bar;
12ba150f 8393
ab648270
JB
8394 /* We can't redeem this window's scroll bar if it doesn't have one. */
8395 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
8396 abort ();
8397
ab648270 8398 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
8399
8400 /* Unlink it from the condemned list. */
8401 {
8402 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
8403
8404 if (NILP (bar->prev))
8405 {
8406 /* If the prev pointer is nil, it must be the first in one of
8407 the lists. */
ab648270 8408 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
8409 /* It's not condemned. Everything's fine. */
8410 return;
ab648270
JB
8411 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
8412 window->vertical_scroll_bar))
8413 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
8414 else
8415 /* If its prev pointer is nil, it must be at the front of
8416 one or the other! */
8417 abort ();
8418 }
8419 else
ab648270 8420 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
8421
8422 if (! NILP (bar->next))
ab648270 8423 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 8424
ab648270 8425 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8426 bar->prev = Qnil;
e0c1aef2 8427 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 8428 if (! NILP (bar->next))
e0c1aef2 8429 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
12ba150f 8430 }
f451eb13
JB
8431}
8432
ab648270
JB
8433/* Remove all scroll bars on FRAME that haven't been saved since the
8434 last call to `*condemn_scroll_bars_hook'. */
06a2c219 8435
f451eb13 8436static void
ab648270 8437XTjudge_scroll_bars (f)
12ba150f 8438 FRAME_PTR f;
f451eb13 8439{
12ba150f 8440 Lisp_Object bar, next;
f451eb13 8441
ab648270 8442 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
8443
8444 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
8445 more events on the hapless scroll bars. */
8446 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
8447
8448 for (; ! NILP (bar); bar = next)
f451eb13 8449 {
ab648270 8450 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 8451
ab648270 8452 x_scroll_bar_remove (b);
12ba150f
JB
8453
8454 next = b->next;
8455 b->next = b->prev = Qnil;
f451eb13 8456 }
12ba150f 8457
ab648270 8458 /* Now there should be no references to the condemned scroll bars,
12ba150f 8459 and they should get garbage-collected. */
f451eb13
JB
8460}
8461
8462
06a2c219
GM
8463/* Handle an Expose or GraphicsExpose event on a scroll bar. This
8464 is a no-op when using toolkit scroll bars.
ab648270
JB
8465
8466 This may be called from a signal handler, so we have to ignore GC
8467 mark bits. */
06a2c219 8468
f451eb13 8469static void
ab648270
JB
8470x_scroll_bar_expose (bar, event)
8471 struct scroll_bar *bar;
f451eb13
JB
8472 XEvent *event;
8473{
06a2c219
GM
8474#ifndef USE_TOOLKIT_SCROLL_BARS
8475
ab648270 8476 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8477 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8478 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 8479 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 8480
f451eb13
JB
8481 BLOCK_INPUT;
8482
ab648270 8483 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 8484
06a2c219 8485 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 8486 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
8487
8488 /* x, y, width, height */
d9cdbb3d 8489 0, 0,
3cbd2e0b 8490 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
8491 XINT (bar->height) - 1);
8492
f451eb13 8493 UNBLOCK_INPUT;
06a2c219
GM
8494
8495#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8496}
8497
ab648270
JB
8498/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8499 is set to something other than no_event, it is enqueued.
8500
8501 This may be called from a signal handler, so we have to ignore GC
8502 mark bits. */
06a2c219 8503
5c187dee
GM
8504#ifndef USE_TOOLKIT_SCROLL_BARS
8505
f451eb13 8506static void
ab648270
JB
8507x_scroll_bar_handle_click (bar, event, emacs_event)
8508 struct scroll_bar *bar;
f451eb13
JB
8509 XEvent *event;
8510 struct input_event *emacs_event;
8511{
0299d313 8512 if (! GC_WINDOWP (bar->window))
12ba150f
JB
8513 abort ();
8514
ab648270 8515 emacs_event->kind = scroll_bar_click;
69388238 8516 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
8517 emacs_event->modifiers
8518 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
8519 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
8520 event->xbutton.state)
8521 | (event->type == ButtonRelease
8522 ? up_modifier
8523 : down_modifier));
12ba150f 8524 emacs_event->frame_or_window = bar->window;
f451eb13 8525 emacs_event->timestamp = event->xbutton.time;
12ba150f 8526 {
06a2c219 8527#if 0
d9cdbb3d 8528 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 8529 int internal_height
d9cdbb3d 8530 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8531#endif
0299d313 8532 int top_range
d9cdbb3d 8533 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 8534 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
8535
8536 if (y < 0) y = 0;
8537 if (y > top_range) y = top_range;
8538
8539 if (y < XINT (bar->start))
ab648270
JB
8540 emacs_event->part = scroll_bar_above_handle;
8541 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8542 emacs_event->part = scroll_bar_handle;
12ba150f 8543 else
ab648270 8544 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
8545
8546 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
8547 they want to drag it. Lisp code needs to be able to decide
8548 whether or not we're dragging. */
929787e1 8549#if 0
12ba150f
JB
8550 /* If the user has just clicked on the handle, record where they're
8551 holding it. */
8552 if (event->type == ButtonPress
ab648270 8553 && emacs_event->part == scroll_bar_handle)
e0c1aef2 8554 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 8555#endif
12ba150f
JB
8556
8557 /* If the user has released the handle, set it to its final position. */
8558 if (event->type == ButtonRelease
8559 && ! NILP (bar->dragging))
8560 {
8561 int new_start = y - XINT (bar->dragging);
8562 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 8563
ab648270 8564 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
8565 bar->dragging = Qnil;
8566 }
f451eb13 8567
5116f055
JB
8568 /* Same deal here as the other #if 0. */
8569#if 0
58769bee 8570 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 8571 the handle. */
ab648270 8572 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
8573 emacs_event->x = bar->start;
8574 else
e0c1aef2 8575 XSETINT (emacs_event->x, y);
5116f055 8576#else
e0c1aef2 8577 XSETINT (emacs_event->x, y);
5116f055 8578#endif
f451eb13 8579
e0c1aef2 8580 XSETINT (emacs_event->y, top_range);
12ba150f
JB
8581 }
8582}
f451eb13 8583
ab648270
JB
8584/* Handle some mouse motion while someone is dragging the scroll bar.
8585
8586 This may be called from a signal handler, so we have to ignore GC
8587 mark bits. */
06a2c219 8588
f451eb13 8589static void
ab648270
JB
8590x_scroll_bar_note_movement (bar, event)
8591 struct scroll_bar *bar;
f451eb13
JB
8592 XEvent *event;
8593{
39d8bb4d
KH
8594 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
8595
f451eb13
JB
8596 last_mouse_movement_time = event->xmotion.time;
8597
39d8bb4d 8598 f->mouse_moved = 1;
e0c1aef2 8599 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
8600
8601 /* If we're dragging the bar, display it. */
ab648270 8602 if (! GC_NILP (bar->dragging))
f451eb13
JB
8603 {
8604 /* Where should the handle be now? */
12ba150f 8605 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 8606
12ba150f 8607 if (new_start != XINT (bar->start))
f451eb13 8608 {
12ba150f 8609 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 8610
ab648270 8611 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
8612 }
8613 }
f451eb13
JB
8614}
8615
5c187dee
GM
8616#endif /* !USE_TOOLKIT_SCROLL_BARS */
8617
12ba150f 8618/* Return information to the user about the current position of the mouse
ab648270 8619 on the scroll bar. */
06a2c219 8620
12ba150f 8621static void
334208b7
RS
8622x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
8623 FRAME_PTR *fp;
12ba150f 8624 Lisp_Object *bar_window;
ab648270 8625 enum scroll_bar_part *part;
12ba150f
JB
8626 Lisp_Object *x, *y;
8627 unsigned long *time;
8628{
ab648270 8629 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
8630 Window w = SCROLL_BAR_X_WINDOW (bar);
8631 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 8632 int win_x, win_y;
559cb2fb
JB
8633 Window dummy_window;
8634 int dummy_coord;
8635 unsigned int dummy_mask;
12ba150f 8636
cf7cb199
JB
8637 BLOCK_INPUT;
8638
ab648270 8639 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 8640 report that. */
334208b7 8641 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 8642
559cb2fb
JB
8643 /* Root, child, root x and root y. */
8644 &dummy_window, &dummy_window,
8645 &dummy_coord, &dummy_coord,
12ba150f 8646
559cb2fb
JB
8647 /* Position relative to scroll bar. */
8648 &win_x, &win_y,
12ba150f 8649
559cb2fb
JB
8650 /* Mouse buttons and modifier keys. */
8651 &dummy_mask))
7a13e894 8652 ;
559cb2fb
JB
8653 else
8654 {
06a2c219 8655#if 0
559cb2fb 8656 int inside_height
d9cdbb3d 8657 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8658#endif
559cb2fb 8659 int top_range
d9cdbb3d 8660 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
8661
8662 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
8663
8664 if (! NILP (bar->dragging))
8665 win_y -= XINT (bar->dragging);
8666
8667 if (win_y < 0)
8668 win_y = 0;
8669 if (win_y > top_range)
8670 win_y = top_range;
8671
334208b7 8672 *fp = f;
7a13e894 8673 *bar_window = bar->window;
559cb2fb
JB
8674
8675 if (! NILP (bar->dragging))
8676 *part = scroll_bar_handle;
8677 else if (win_y < XINT (bar->start))
8678 *part = scroll_bar_above_handle;
8679 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8680 *part = scroll_bar_handle;
8681 else
8682 *part = scroll_bar_below_handle;
12ba150f 8683
e0c1aef2
KH
8684 XSETINT (*x, win_y);
8685 XSETINT (*y, top_range);
12ba150f 8686
39d8bb4d 8687 f->mouse_moved = 0;
559cb2fb
JB
8688 last_mouse_scroll_bar = Qnil;
8689 }
12ba150f 8690
559cb2fb 8691 *time = last_mouse_movement_time;
cf7cb199 8692
cf7cb199 8693 UNBLOCK_INPUT;
12ba150f
JB
8694}
8695
f451eb13 8696
dbc4e1c1 8697/* The screen has been cleared so we may have changed foreground or
ab648270
JB
8698 background colors, and the scroll bars may need to be redrawn.
8699 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
8700 redraw them. */
8701
dfcf069d 8702void
ab648270 8703x_scroll_bar_clear (f)
dbc4e1c1
JB
8704 FRAME_PTR f;
8705{
06a2c219 8706#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
8707 Lisp_Object bar;
8708
b80c363e
RS
8709 /* We can have scroll bars even if this is 0,
8710 if we just turned off scroll bar mode.
8711 But in that case we should not clear them. */
8712 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
8713 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
8714 bar = XSCROLL_BAR (bar)->next)
8715 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
8716 0, 0, 0, 0, True);
06a2c219 8717#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
8718}
8719
06a2c219 8720/* This processes Expose events from the menu-bar specific X event
19126e11 8721 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 8722 when handling menu-bar or pop-up items. */
3afe33e7 8723
06a2c219 8724int
3afe33e7
RS
8725process_expose_from_menu (event)
8726 XEvent event;
8727{
8728 FRAME_PTR f;
19126e11 8729 struct x_display_info *dpyinfo;
06a2c219 8730 int frame_exposed_p = 0;
3afe33e7 8731
f94397b5
KH
8732 BLOCK_INPUT;
8733
19126e11
KH
8734 dpyinfo = x_display_info_for_display (event.xexpose.display);
8735 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
8736 if (f)
8737 {
8738 if (f->async_visible == 0)
8739 {
8740 f->async_visible = 1;
8741 f->async_iconified = 0;
06c488fd 8742 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
8743 SET_FRAME_GARBAGED (f);
8744 }
8745 else
8746 {
06a2c219
GM
8747 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
8748 event.xexpose.x, event.xexpose.y,
8749 event.xexpose.width, event.xexpose.height);
8750 frame_exposed_p = 1;
3afe33e7
RS
8751 }
8752 }
8753 else
8754 {
8755 struct scroll_bar *bar
8756 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 8757
3afe33e7
RS
8758 if (bar)
8759 x_scroll_bar_expose (bar, &event);
8760 }
f94397b5
KH
8761
8762 UNBLOCK_INPUT;
06a2c219 8763 return frame_exposed_p;
3afe33e7 8764}
09756a85
RS
8765\f
8766/* Define a queue to save up SelectionRequest events for later handling. */
8767
8768struct selection_event_queue
8769 {
8770 XEvent event;
8771 struct selection_event_queue *next;
8772 };
8773
8774static struct selection_event_queue *queue;
8775
8776/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 8777
09756a85
RS
8778static int x_queue_selection_requests;
8779
8780/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 8781
09756a85 8782static void
334208b7
RS
8783x_queue_event (f, event)
8784 FRAME_PTR f;
09756a85
RS
8785 XEvent *event;
8786{
8787 struct selection_event_queue *queue_tmp
06a2c219 8788 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 8789
58769bee 8790 if (queue_tmp != NULL)
09756a85
RS
8791 {
8792 queue_tmp->event = *event;
8793 queue_tmp->next = queue;
8794 queue = queue_tmp;
8795 }
8796}
8797
8798/* Take all the queued events and put them back
8799 so that they get processed afresh. */
8800
8801static void
db3906fd
RS
8802x_unqueue_events (display)
8803 Display *display;
09756a85 8804{
58769bee 8805 while (queue != NULL)
09756a85
RS
8806 {
8807 struct selection_event_queue *queue_tmp = queue;
db3906fd 8808 XPutBackEvent (display, &queue_tmp->event);
09756a85 8809 queue = queue_tmp->next;
06a2c219 8810 xfree ((char *)queue_tmp);
09756a85
RS
8811 }
8812}
8813
8814/* Start queuing SelectionRequest events. */
8815
8816void
db3906fd
RS
8817x_start_queuing_selection_requests (display)
8818 Display *display;
09756a85
RS
8819{
8820 x_queue_selection_requests++;
8821}
8822
8823/* Stop queuing SelectionRequest events. */
8824
8825void
db3906fd
RS
8826x_stop_queuing_selection_requests (display)
8827 Display *display;
09756a85
RS
8828{
8829 x_queue_selection_requests--;
db3906fd 8830 x_unqueue_events (display);
09756a85 8831}
f451eb13
JB
8832\f
8833/* The main X event-reading loop - XTread_socket. */
dc6f92b8 8834
06a2c219 8835/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
8836 but we have to put it out here, since static variables within functions
8837 sometimes don't work. */
06a2c219 8838
dc6f92b8
JB
8839static Time enter_timestamp;
8840
11edeb03 8841/* This holds the state XLookupString needs to implement dead keys
58769bee 8842 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
8843 says that a portable program can't use this, but Stephen Gildea assures
8844 me that letting the compiler initialize it to zeros will work okay.
8845
8846 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
8847 given for enter_time stamp, above. */
8848
11edeb03
JB
8849static XComposeStatus compose_status;
8850
10e6549c
RS
8851/* Record the last 100 characters stored
8852 to help debug the loss-of-chars-during-GC problem. */
06a2c219 8853
2224b905
RS
8854static int temp_index;
8855static short temp_buffer[100];
10e6549c 8856
7a13e894
RS
8857/* Set this to nonzero to fake an "X I/O error"
8858 on a particular display. */
06a2c219 8859
7a13e894
RS
8860struct x_display_info *XTread_socket_fake_io_error;
8861
2224b905
RS
8862/* When we find no input here, we occasionally do a no-op command
8863 to verify that the X server is still running and we can still talk with it.
8864 We try all the open displays, one by one.
8865 This variable is used for cycling thru the displays. */
06a2c219 8866
2224b905
RS
8867static struct x_display_info *next_noop_dpyinfo;
8868
06a2c219
GM
8869#define SET_SAVED_MENU_EVENT(size) \
8870 do \
8871 { \
8872 if (f->output_data.x->saved_menu_event == 0) \
8873 f->output_data.x->saved_menu_event \
8874 = (XEvent *) xmalloc (sizeof (XEvent)); \
8875 bcopy (&event, f->output_data.x->saved_menu_event, size); \
8876 if (numchars >= 1) \
8877 { \
8878 bufp->kind = menu_bar_activate_event; \
8879 XSETFRAME (bufp->frame_or_window, f); \
8880 bufp++; \
8881 count++; \
8882 numchars--; \
8883 } \
8884 } \
8885 while (0)
8886
8805890a 8887#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 8888#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 8889
dc6f92b8
JB
8890/* Read events coming from the X server.
8891 This routine is called by the SIGIO handler.
8892 We return as soon as there are no more events to be read.
8893
8894 Events representing keys are stored in buffer BUFP,
8895 which can hold up to NUMCHARS characters.
8896 We return the number of characters stored into the buffer,
8897 thus pretending to be `read'.
8898
dc6f92b8
JB
8899 EXPECTED is nonzero if the caller knows input is available. */
8900
7c5283e4 8901int
f66868ba 8902XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 8903 register int sd;
8805890a
KH
8904 /* register */ struct input_event *bufp;
8905 /* register */ int numchars;
dc6f92b8
JB
8906 int expected;
8907{
8908 int count = 0;
8909 int nbytes = 0;
dc6f92b8 8910 XEvent event;
f676886a 8911 struct frame *f;
66f55a9d 8912 int event_found = 0;
334208b7 8913 struct x_display_info *dpyinfo;
dc6f92b8 8914
9ac0d9e0 8915 if (interrupt_input_blocked)
dc6f92b8 8916 {
9ac0d9e0 8917 interrupt_input_pending = 1;
dc6f92b8
JB
8918 return -1;
8919 }
8920
9ac0d9e0 8921 interrupt_input_pending = 0;
dc6f92b8 8922 BLOCK_INPUT;
c0a04927
RS
8923
8924 /* So people can tell when we have read the available input. */
8925 input_signal_count++;
8926
dc6f92b8 8927 if (numchars <= 0)
06a2c219 8928 abort (); /* Don't think this happens. */
dc6f92b8 8929
7a13e894
RS
8930 /* Find the display we are supposed to read input for.
8931 It's the one communicating on descriptor SD. */
8932 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
8933 {
8934#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 8935#ifdef FIOSNBIO
7a13e894
RS
8936 /* If available, Xlib uses FIOSNBIO to make the socket
8937 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 8938 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 8939 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 8940 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 8941#endif /* ! defined (FIOSNBIO) */
7a13e894 8942#endif
dc6f92b8 8943
7a13e894
RS
8944#if 0 /* This code can't be made to work, with multiple displays,
8945 and appears not to be used on any system any more.
8946 Also keyboard.c doesn't turn O_NDELAY on and off
8947 for X connections. */
dc6f92b8
JB
8948#ifndef SIGIO
8949#ifndef HAVE_SELECT
7a13e894
RS
8950 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
8951 {
8952 extern int read_alarm_should_throw;
8953 read_alarm_should_throw = 1;
8954 XPeekEvent (dpyinfo->display, &event);
8955 read_alarm_should_throw = 0;
8956 }
c118dd06
JB
8957#endif /* HAVE_SELECT */
8958#endif /* SIGIO */
7a13e894 8959#endif
dc6f92b8 8960
7a13e894
RS
8961 /* For debugging, this gives a way to fake an I/O error. */
8962 if (dpyinfo == XTread_socket_fake_io_error)
8963 {
8964 XTread_socket_fake_io_error = 0;
8965 x_io_error_quitter (dpyinfo->display);
8966 }
dc6f92b8 8967
06a2c219 8968 while (XPending (dpyinfo->display))
dc6f92b8 8969 {
7a13e894 8970 XNextEvent (dpyinfo->display, &event);
06a2c219 8971
531483fb 8972#ifdef HAVE_X_I18N
d1bc4182 8973 {
f2be1146
GM
8974 /* Filter events for the current X input method.
8975 XFilterEvent returns non-zero if the input method has
8976 consumed the event. We pass the frame's X window to
8977 XFilterEvent because that's the one for which the IC
8978 was created. */
f5d11644
GM
8979 struct frame *f1 = x_any_window_to_frame (dpyinfo,
8980 event.xclient.window);
8981 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
8982 break;
8983 }
0cd6403b 8984#endif
7a13e894
RS
8985 event_found = 1;
8986
8987 switch (event.type)
8988 {
8989 case ClientMessage:
c047688c 8990 {
7a13e894
RS
8991 if (event.xclient.message_type
8992 == dpyinfo->Xatom_wm_protocols
8993 && event.xclient.format == 32)
c047688c 8994 {
7a13e894
RS
8995 if (event.xclient.data.l[0]
8996 == dpyinfo->Xatom_wm_take_focus)
c047688c 8997 {
8c1a6a84
RS
8998 /* Use x_any_window_to_frame because this
8999 could be the shell widget window
9000 if the frame has no title bar. */
9001 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
9002#ifdef HAVE_X_I18N
9003 /* Not quite sure this is needed -pd */
8c1a6a84 9004 if (f && FRAME_XIC (f))
6c183ba5
RS
9005 XSetICFocus (FRAME_XIC (f));
9006#endif
f1da8f06
GM
9007#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
9008 instructs the WM to set the input focus automatically for
9009 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
9010 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
9011 it has set the focus. So, XSetInputFocus below is not
9012 needed.
9013
9014 The call to XSetInputFocus below has also caused trouble. In
9015 cases where the XSetInputFocus done by the WM and the one
9016 below are temporally close (on a fast machine), the call
9017 below can generate additional FocusIn events which confuse
9018 Emacs. */
9019
bf7253f4
RS
9020 /* Since we set WM_TAKE_FOCUS, we must call
9021 XSetInputFocus explicitly. But not if f is null,
9022 since that might be an event for a deleted frame. */
7a13e894 9023 if (f)
bf7253f4
RS
9024 {
9025 Display *d = event.xclient.display;
9026 /* Catch and ignore errors, in case window has been
9027 iconified by a window manager such as GWM. */
9028 int count = x_catch_errors (d);
9029 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
9030 /* The ICCCM says this is
9031 the only valid choice. */
9032 RevertToParent,
bf7253f4
RS
9033 event.xclient.data.l[1]);
9034 /* This is needed to detect the error
9035 if there is an error. */
9036 XSync (d, False);
9037 x_uncatch_errors (d, count);
9038 }
7a13e894 9039 /* Not certain about handling scroll bars here */
f1da8f06 9040#endif /* 0 */
c047688c 9041 }
7a13e894
RS
9042 else if (event.xclient.data.l[0]
9043 == dpyinfo->Xatom_wm_save_yourself)
9044 {
9045 /* Save state modify the WM_COMMAND property to
06a2c219 9046 something which can reinstate us. This notifies
7a13e894
RS
9047 the session manager, who's looking for such a
9048 PropertyNotify. Can restart processing when
06a2c219 9049 a keyboard or mouse event arrives. */
7a13e894
RS
9050 if (numchars > 0)
9051 {
19126e11
KH
9052 f = x_top_window_to_frame (dpyinfo,
9053 event.xclient.window);
7a13e894
RS
9054
9055 /* This is just so we only give real data once
9056 for a single Emacs process. */
b86bd3dd 9057 if (f == SELECTED_FRAME ())
7a13e894
RS
9058 XSetCommand (FRAME_X_DISPLAY (f),
9059 event.xclient.window,
9060 initial_argv, initial_argc);
f000f5c5 9061 else if (f)
7a13e894
RS
9062 XSetCommand (FRAME_X_DISPLAY (f),
9063 event.xclient.window,
9064 0, 0);
9065 }
9066 }
9067 else if (event.xclient.data.l[0]
9068 == dpyinfo->Xatom_wm_delete_window)
1fb20991 9069 {
19126e11
KH
9070 struct frame *f
9071 = x_any_window_to_frame (dpyinfo,
9072 event.xclient.window);
1fb20991 9073
7a13e894
RS
9074 if (f)
9075 {
9076 if (numchars == 0)
9077 abort ();
1fb20991 9078
7a13e894
RS
9079 bufp->kind = delete_window_event;
9080 XSETFRAME (bufp->frame_or_window, f);
9081 bufp++;
9082
9083 count += 1;
9084 numchars -= 1;
9085 }
1fb20991 9086 }
c047688c 9087 }
7a13e894
RS
9088 else if (event.xclient.message_type
9089 == dpyinfo->Xatom_wm_configure_denied)
9090 {
9091 }
9092 else if (event.xclient.message_type
9093 == dpyinfo->Xatom_wm_window_moved)
9094 {
9095 int new_x, new_y;
19126e11
KH
9096 struct frame *f
9097 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 9098
7a13e894
RS
9099 new_x = event.xclient.data.s[0];
9100 new_y = event.xclient.data.s[1];
1fb20991 9101
7a13e894
RS
9102 if (f)
9103 {
7556890b
RS
9104 f->output_data.x->left_pos = new_x;
9105 f->output_data.x->top_pos = new_y;
7a13e894 9106 }
1fb20991 9107 }
0fdff6bb 9108#ifdef HACK_EDITRES
7a13e894
RS
9109 else if (event.xclient.message_type
9110 == dpyinfo->Xatom_editres)
9111 {
19126e11
KH
9112 struct frame *f
9113 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 9114 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 9115 &event, NULL);
7a13e894 9116 }
0fdff6bb 9117#endif /* HACK_EDITRES */
06a2c219
GM
9118 else if ((event.xclient.message_type
9119 == dpyinfo->Xatom_DONE)
9120 || (event.xclient.message_type
9121 == dpyinfo->Xatom_PAGE))
9122 {
9123 /* Ghostview job completed. Kill it. We could
9124 reply with "Next" if we received "Page", but we
9125 currently never do because we are interested in
9126 images, only, which should have 1 page. */
06a2c219
GM
9127 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
9128 struct frame *f
9129 = x_window_to_frame (dpyinfo, event.xclient.window);
9130 x_kill_gs_process (pixmap, f);
9131 expose_frame (f, 0, 0, 0, 0);
9132 }
9133#ifdef USE_TOOLKIT_SCROLL_BARS
9134 /* Scroll bar callbacks send a ClientMessage from which
9135 we construct an input_event. */
9136 else if (event.xclient.message_type
9137 == dpyinfo->Xatom_Scrollbar)
9138 {
9139 x_scroll_bar_to_input_event (&event, bufp);
9140 ++bufp, ++count, --numchars;
9141 goto out;
9142 }
9143#endif /* USE_TOOLKIT_SCROLL_BARS */
9144 else
9145 goto OTHER;
7a13e894
RS
9146 }
9147 break;
dc6f92b8 9148
7a13e894 9149 case SelectionNotify:
3afe33e7 9150#ifdef USE_X_TOOLKIT
19126e11 9151 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 9152 goto OTHER;
3afe33e7 9153#endif /* not USE_X_TOOLKIT */
dfcf069d 9154 x_handle_selection_notify (&event.xselection);
7a13e894 9155 break;
d56a553a 9156
06a2c219 9157 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 9158#ifdef USE_X_TOOLKIT
19126e11 9159 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 9160 goto OTHER;
3afe33e7 9161#endif /* USE_X_TOOLKIT */
7a13e894
RS
9162 {
9163 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 9164
7a13e894
RS
9165 if (numchars == 0)
9166 abort ();
d56a553a 9167
7a13e894
RS
9168 bufp->kind = selection_clear_event;
9169 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9170 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9171 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9172 bufp->frame_or_window = Qnil;
7a13e894 9173 bufp++;
d56a553a 9174
7a13e894
RS
9175 count += 1;
9176 numchars -= 1;
9177 }
9178 break;
dc6f92b8 9179
06a2c219 9180 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 9181#ifdef USE_X_TOOLKIT
19126e11 9182 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 9183 goto OTHER;
3afe33e7 9184#endif /* USE_X_TOOLKIT */
7a13e894 9185 if (x_queue_selection_requests)
19126e11 9186 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
9187 &event);
9188 else
9189 {
9190 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 9191
7a13e894
RS
9192 if (numchars == 0)
9193 abort ();
9194
9195 bufp->kind = selection_request_event;
9196 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9197 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
9198 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9199 SELECTION_EVENT_TARGET (bufp) = eventp->target;
9200 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
9201 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9202 bufp->frame_or_window = Qnil;
7a13e894
RS
9203 bufp++;
9204
9205 count += 1;
9206 numchars -= 1;
9207 }
9208 break;
9209
9210 case PropertyNotify:
3afe33e7 9211#ifdef USE_X_TOOLKIT
19126e11 9212 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 9213 goto OTHER;
3afe33e7 9214#endif /* not USE_X_TOOLKIT */
dfcf069d 9215 x_handle_property_notify (&event.xproperty);
7a13e894 9216 break;
dc6f92b8 9217
7a13e894 9218 case ReparentNotify:
19126e11 9219 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
9220 if (f)
9221 {
9222 int x, y;
7556890b 9223 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 9224 x_real_positions (f, &x, &y);
7556890b
RS
9225 f->output_data.x->left_pos = x;
9226 f->output_data.x->top_pos = y;
7a13e894
RS
9227 }
9228 break;
3bd330d4 9229
7a13e894 9230 case Expose:
19126e11 9231 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 9232 if (f)
dc6f92b8 9233 {
7a13e894
RS
9234 if (f->async_visible == 0)
9235 {
9236 f->async_visible = 1;
9237 f->async_iconified = 0;
06c488fd 9238 f->output_data.x->has_been_visible = 1;
7a13e894
RS
9239 SET_FRAME_GARBAGED (f);
9240 }
9241 else
06a2c219
GM
9242 expose_frame (x_window_to_frame (dpyinfo,
9243 event.xexpose.window),
9244 event.xexpose.x, event.xexpose.y,
9245 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
9246 }
9247 else
7a13e894 9248 {
06a2c219
GM
9249#ifdef USE_TOOLKIT_SCROLL_BARS
9250 /* Dispatch event to the widget. */
9251 goto OTHER;
9252#else /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9253 struct scroll_bar *bar
9254 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9255
7a13e894
RS
9256 if (bar)
9257 x_scroll_bar_expose (bar, &event);
3afe33e7 9258#ifdef USE_X_TOOLKIT
7a13e894
RS
9259 else
9260 goto OTHER;
3afe33e7 9261#endif /* USE_X_TOOLKIT */
06a2c219 9262#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9263 }
9264 break;
dc6f92b8 9265
7a13e894
RS
9266 case GraphicsExpose: /* This occurs when an XCopyArea's
9267 source area was obscured or not
9268 available.*/
19126e11 9269 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
9270 if (f)
9271 {
06a2c219
GM
9272 expose_frame (f,
9273 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
9274 event.xgraphicsexpose.width,
9275 event.xgraphicsexpose.height);
7a13e894 9276 }
3afe33e7 9277#ifdef USE_X_TOOLKIT
7a13e894
RS
9278 else
9279 goto OTHER;
3afe33e7 9280#endif /* USE_X_TOOLKIT */
7a13e894 9281 break;
dc6f92b8 9282
7a13e894 9283 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
9284 source area was completely
9285 available */
7a13e894 9286 break;
dc6f92b8 9287
7a13e894 9288 case UnmapNotify:
06a2c219
GM
9289 /* Redo the mouse-highlight after the tooltip has gone. */
9290 if (event.xmap.window == tip_window)
9291 {
9292 tip_window = 0;
9293 redo_mouse_highlight ();
9294 }
9295
91ea2a7a 9296 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
9297 if (f) /* F may no longer exist if
9298 the frame was deleted. */
9299 {
9300 /* While a frame is unmapped, display generation is
9301 disabled; you don't want to spend time updating a
9302 display that won't ever be seen. */
9303 f->async_visible = 0;
9304 /* We can't distinguish, from the event, whether the window
9305 has become iconified or invisible. So assume, if it
9306 was previously visible, than now it is iconified.
1aa6072f
RS
9307 But x_make_frame_invisible clears both
9308 the visible flag and the iconified flag;
9309 and that way, we know the window is not iconified now. */
7a13e894 9310 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
9311 {
9312 f->async_iconified = 1;
bddd097c 9313
1aa6072f
RS
9314 bufp->kind = iconify_event;
9315 XSETFRAME (bufp->frame_or_window, f);
9316 bufp++;
9317 count++;
9318 numchars--;
9319 }
7a13e894 9320 }
7a13e894 9321 goto OTHER;
dc6f92b8 9322
7a13e894 9323 case MapNotify:
06a2c219
GM
9324 if (event.xmap.window == tip_window)
9325 /* The tooltip has been drawn already. Avoid
9326 the SET_FRAME_GARBAGED below. */
9327 goto OTHER;
9328
9329 /* We use x_top_window_to_frame because map events can
9330 come for sub-windows and they don't mean that the
9331 frame is visible. */
19126e11 9332 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
9333 if (f)
9334 {
9335 f->async_visible = 1;
9336 f->async_iconified = 0;
06c488fd 9337 f->output_data.x->has_been_visible = 1;
dc6f92b8 9338
7a13e894
RS
9339 /* wait_reading_process_input will notice this and update
9340 the frame's display structures. */
9341 SET_FRAME_GARBAGED (f);
bddd097c 9342
d806e720
RS
9343 if (f->iconified)
9344 {
9345 bufp->kind = deiconify_event;
9346 XSETFRAME (bufp->frame_or_window, f);
9347 bufp++;
9348 count++;
9349 numchars--;
9350 }
e73ec6fa 9351 else if (! NILP (Vframe_list)
8e713be6 9352 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
9353 /* Force a redisplay sooner or later
9354 to update the frame titles
9355 in case this is the second frame. */
9356 record_asynch_buffer_change ();
7a13e894 9357 }
7a13e894 9358 goto OTHER;
dc6f92b8 9359
7a13e894 9360 case KeyPress:
19126e11 9361 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 9362
06a2c219
GM
9363#ifdef USE_MOTIF
9364 /* I couldn't find a way to prevent LessTif scroll bars
9365 from consuming key events. */
9366 if (f == 0)
9367 {
9368 Widget widget = XtWindowToWidget (dpyinfo->display,
9369 event.xkey.window);
9370 if (widget && XmIsScrollBar (widget))
9371 {
9372 widget = XtParent (widget);
9373 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
9374 }
9375 }
9376#endif /* USE_MOTIF */
9377
7a13e894
RS
9378 if (f != 0)
9379 {
9380 KeySym keysym, orig_keysym;
9381 /* al%imercury@uunet.uu.net says that making this 81 instead of
9382 80 fixed a bug whereby meta chars made his Emacs hang. */
9383 unsigned char copy_buffer[81];
9384 int modifiers;
64bb1782 9385
7a13e894
RS
9386 event.xkey.state
9387 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
9388 extra_keyboard_modifiers);
9389 modifiers = event.xkey.state;
3a2712f9 9390
7a13e894 9391 /* This will have to go some day... */
752a043f 9392
7a13e894
RS
9393 /* make_lispy_event turns chars into control chars.
9394 Don't do it here because XLookupString is too eager. */
9395 event.xkey.state &= ~ControlMask;
5d46f928
RS
9396 event.xkey.state &= ~(dpyinfo->meta_mod_mask
9397 | dpyinfo->super_mod_mask
9398 | dpyinfo->hyper_mod_mask
9399 | dpyinfo->alt_mod_mask);
9400
1cf4a0d1
RS
9401 /* In case Meta is ComposeCharacter,
9402 clear its status. According to Markus Ehrnsperger
9403 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
9404 this enables ComposeCharacter to work whether or
9405 not it is combined with Meta. */
9406 if (modifiers & dpyinfo->meta_mod_mask)
9407 bzero (&compose_status, sizeof (compose_status));
9408
6c183ba5
RS
9409#ifdef HAVE_X_I18N
9410 if (FRAME_XIC (f))
9411 {
f5d11644
GM
9412 unsigned char *copy_bufptr = copy_buffer;
9413 int copy_bufsiz = sizeof (copy_buffer);
9414 Status status_return;
9415
6c183ba5 9416 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
9417 &event.xkey, copy_bufptr,
9418 copy_bufsiz, &keysym,
6c183ba5 9419 &status_return);
f5d11644
GM
9420 if (status_return == XBufferOverflow)
9421 {
9422 copy_bufsiz = nbytes + 1;
9423 copy_bufptr = (char *) alloca (copy_bufsiz);
9424 nbytes = XmbLookupString (FRAME_XIC (f),
9425 &event.xkey, copy_bufptr,
9426 copy_bufsiz, &keysym,
9427 &status_return);
9428 }
9429
1decb680
PE
9430 if (status_return == XLookupNone)
9431 break;
9432 else if (status_return == XLookupChars)
fdd9d55e
GM
9433 {
9434 keysym = NoSymbol;
9435 modifiers = 0;
9436 }
1decb680
PE
9437 else if (status_return != XLookupKeySym
9438 && status_return != XLookupBoth)
9439 abort ();
6c183ba5
RS
9440 }
9441 else
9442 nbytes = XLookupString (&event.xkey, copy_buffer,
9443 80, &keysym, &compose_status);
9444#else
0299d313
RS
9445 nbytes = XLookupString (&event.xkey, copy_buffer,
9446 80, &keysym, &compose_status);
6c183ba5 9447#endif
dc6f92b8 9448
7a13e894 9449 orig_keysym = keysym;
55123275 9450
7a13e894
RS
9451 if (numchars > 1)
9452 {
9453 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
9454 || keysym == XK_Delete
1097aea0 9455#ifdef XK_ISO_Left_Tab
441affdb 9456 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 9457#endif
852bff8f 9458 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
9459 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
9460 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 9461#ifdef HPUX
7a13e894
RS
9462 /* This recognizes the "extended function keys".
9463 It seems there's no cleaner way.
9464 Test IsModifierKey to avoid handling mode_switch
9465 incorrectly. */
9466 || ((unsigned) (keysym) >= XK_Select
9467 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
9468#endif
9469#ifdef XK_dead_circumflex
7a13e894 9470 || orig_keysym == XK_dead_circumflex
69388238
RS
9471#endif
9472#ifdef XK_dead_grave
7a13e894 9473 || orig_keysym == XK_dead_grave
69388238
RS
9474#endif
9475#ifdef XK_dead_tilde
7a13e894 9476 || orig_keysym == XK_dead_tilde
69388238
RS
9477#endif
9478#ifdef XK_dead_diaeresis
7a13e894 9479 || orig_keysym == XK_dead_diaeresis
69388238
RS
9480#endif
9481#ifdef XK_dead_macron
7a13e894 9482 || orig_keysym == XK_dead_macron
69388238
RS
9483#endif
9484#ifdef XK_dead_degree
7a13e894 9485 || orig_keysym == XK_dead_degree
69388238
RS
9486#endif
9487#ifdef XK_dead_acute
7a13e894 9488 || orig_keysym == XK_dead_acute
69388238
RS
9489#endif
9490#ifdef XK_dead_cedilla
7a13e894 9491 || orig_keysym == XK_dead_cedilla
69388238
RS
9492#endif
9493#ifdef XK_dead_breve
7a13e894 9494 || orig_keysym == XK_dead_breve
69388238
RS
9495#endif
9496#ifdef XK_dead_ogonek
7a13e894 9497 || orig_keysym == XK_dead_ogonek
69388238
RS
9498#endif
9499#ifdef XK_dead_caron
7a13e894 9500 || orig_keysym == XK_dead_caron
69388238
RS
9501#endif
9502#ifdef XK_dead_doubleacute
7a13e894 9503 || orig_keysym == XK_dead_doubleacute
69388238
RS
9504#endif
9505#ifdef XK_dead_abovedot
7a13e894 9506 || orig_keysym == XK_dead_abovedot
c34790e0 9507#endif
7a13e894
RS
9508 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
9509 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
9510 /* Any "vendor-specific" key is ok. */
9511 || (orig_keysym & (1 << 28)))
9512 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
9513#ifndef HAVE_X11R5
9514#ifdef XK_Mode_switch
7a13e894 9515 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
9516#endif
9517#ifdef XK_Num_Lock
7a13e894 9518 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
9519#endif
9520#endif /* not HAVE_X11R5 */
7a13e894 9521 ))
dc6f92b8 9522 {
10e6549c
RS
9523 if (temp_index == sizeof temp_buffer / sizeof (short))
9524 temp_index = 0;
7a13e894
RS
9525 temp_buffer[temp_index++] = keysym;
9526 bufp->kind = non_ascii_keystroke;
9527 bufp->code = keysym;
e0c1aef2 9528 XSETFRAME (bufp->frame_or_window, f);
334208b7
RS
9529 bufp->modifiers
9530 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9531 modifiers);
1113d9db 9532 bufp->timestamp = event.xkey.time;
dc6f92b8 9533 bufp++;
7a13e894
RS
9534 count++;
9535 numchars--;
dc6f92b8 9536 }
7a13e894
RS
9537 else if (numchars > nbytes)
9538 {
9539 register int i;
9540
9541 for (i = 0; i < nbytes; i++)
9542 {
9543 if (temp_index == sizeof temp_buffer / sizeof (short))
9544 temp_index = 0;
9545 temp_buffer[temp_index++] = copy_buffer[i];
9546 bufp->kind = ascii_keystroke;
9547 bufp->code = copy_buffer[i];
9548 XSETFRAME (bufp->frame_or_window, f);
9549 bufp->modifiers
9550 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9551 modifiers);
9552 bufp->timestamp = event.xkey.time;
9553 bufp++;
9554 }
9555
9556 count += nbytes;
9557 numchars -= nbytes;
1decb680
PE
9558
9559 if (keysym == NoSymbol)
9560 break;
7a13e894
RS
9561 }
9562 else
9563 abort ();
dc6f92b8 9564 }
10e6549c
RS
9565 else
9566 abort ();
dc6f92b8 9567 }
59ddecde
GM
9568#ifdef HAVE_X_I18N
9569 /* Don't dispatch this event since XtDispatchEvent calls
9570 XFilterEvent, and two calls in a row may freeze the
9571 client. */
9572 break;
9573#else
717ca130 9574 goto OTHER;
59ddecde 9575#endif
f451eb13 9576
f5d11644 9577 case KeyRelease:
59ddecde
GM
9578#ifdef HAVE_X_I18N
9579 /* Don't dispatch this event since XtDispatchEvent calls
9580 XFilterEvent, and two calls in a row may freeze the
9581 client. */
9582 break;
9583#else
f5d11644 9584 goto OTHER;
59ddecde 9585#endif
f5d11644 9586
7a13e894 9587 /* Here's a possible interpretation of the whole
06a2c219
GM
9588 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
9589 you get a FocusIn event, you have to get a FocusOut
9590 event before you relinquish the focus. If you
9591 haven't received a FocusIn event, then a mere
9592 LeaveNotify is enough to free you. */
f451eb13 9593
7a13e894 9594 case EnterNotify:
06a2c219
GM
9595 {
9596 int from_menu_bar_p = 0;
9597
9598 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
9599
9600#ifdef LESSTIF_VERSION
9601 /* When clicking outside of a menu bar popup to close
9602 it, we get a FocusIn/ EnterNotify sequence of
9603 events. The flag event.xcrossing.focus is not set
9604 in the EnterNotify event of that sequence because
9605 the focus is in the menu bar,
9606 event.xcrossing.window is the frame's X window.
9607 Unconditionally setting the focus frame to null in
9608 this case is not the right thing, because no event
9609 follows that could set the focus frame to the right
9610 value.
9611
9612 This could be a LessTif bug, but I wasn't able to
9613 reproduce the behavior in a simple test program.
9614
9615 (gerd, LessTif 0.88.1). */
9616
9617 if (!event.xcrossing.focus
9618 && f
9619 && f->output_data.x->menubar_widget)
9620 {
9621 Window focus;
9622 int revert;
9623
9624 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9625 if (focus == XtWindow (f->output_data.x->menubar_widget))
9626 from_menu_bar_p = 1;
9627 }
9628#endif /* LESSTIF_VERSION */
6d4238f3 9629
06a2c219
GM
9630 if (event.xcrossing.focus || from_menu_bar_p)
9631 {
9632 /* Avoid nasty pop/raise loops. */
9633 if (f && (!(f->auto_raise)
9634 || !(f->auto_lower)
9635 || (event.xcrossing.time - enter_timestamp) > 500))
9636 {
9637 x_new_focus_frame (dpyinfo, f);
9638 enter_timestamp = event.xcrossing.time;
9639 }
9640 }
9641 else if (f == dpyinfo->x_focus_frame)
9642 x_new_focus_frame (dpyinfo, 0);
9643
9644 /* EnterNotify counts as mouse movement,
9645 so update things that depend on mouse position. */
9646 if (f && !f->output_data.x->busy_p)
9647 note_mouse_movement (f, &event.xmotion);
9648 goto OTHER;
9649 }
dc6f92b8 9650
7a13e894 9651 case FocusIn:
19126e11 9652 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9653 if (event.xfocus.detail != NotifyPointer)
0f941935 9654 dpyinfo->x_focus_event_frame = f;
7a13e894 9655 if (f)
eb72635f
GM
9656 {
9657 x_new_focus_frame (dpyinfo, f);
9658
9659 /* Don't stop displaying the initial startup message
9660 for a switch-frame event we don't need. */
9661 if (GC_NILP (Vterminal_frame)
9662 && GC_CONSP (Vframe_list)
9663 && !GC_NILP (XCDR (Vframe_list)))
9664 {
9665 bufp->kind = FOCUS_IN_EVENT;
9666 XSETFRAME (bufp->frame_or_window, f);
9667 ++bufp, ++count, --numchars;
9668 }
9669 }
f9e24cb9 9670
6c183ba5
RS
9671#ifdef HAVE_X_I18N
9672 if (f && FRAME_XIC (f))
9673 XSetICFocus (FRAME_XIC (f));
9674#endif
9675
7a13e894 9676 goto OTHER;
10c5e63d 9677
7a13e894 9678 case LeaveNotify:
19126e11 9679 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 9680 if (f)
10c5e63d 9681 {
06a2c219
GM
9682 Lisp_Object frame;
9683 int from_menu_bar_p = 0;
9684
7a13e894 9685 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
9686 {
9687 /* If we move outside the frame, then we're
9688 certainly no longer on any text in the frame. */
9689 clear_mouse_face (dpyinfo);
9690 dpyinfo->mouse_face_mouse_frame = 0;
9691 }
9692
9693 /* Generate a nil HELP_EVENT to cancel a help-echo.
9694 Do it only if there's something to cancel.
9695 Otherwise, the startup message is cleared when
9696 the mouse leaves the frame. */
9697 if (any_help_event_p)
9698 {
9699 XSETFRAME (frame, f);
9700 bufp->kind = HELP_EVENT;
9701 bufp->frame_or_window = Fcons (frame, Qnil);
9702 ++bufp, ++count, --numchars;
9703 }
7a13e894 9704
06a2c219
GM
9705#ifdef LESSTIF_VERSION
9706 /* Please see the comment at the start of the
9707 EnterNotify case. */
9708 if (!event.xcrossing.focus
9709 && f->output_data.x->menubar_widget)
9710 {
9711 Window focus;
9712 int revert;
9713 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
9714 if (focus == XtWindow (f->output_data.x->menubar_widget))
9715 from_menu_bar_p = 1;
9716 }
9717#endif /* LESSTIF_VERSION */
9718
9719 if (event.xcrossing.focus || from_menu_bar_p)
0f941935 9720 x_mouse_leave (dpyinfo);
10c5e63d 9721 else
7a13e894 9722 {
0f941935
KH
9723 if (f == dpyinfo->x_focus_event_frame)
9724 dpyinfo->x_focus_event_frame = 0;
9725 if (f == dpyinfo->x_focus_frame)
9726 x_new_focus_frame (dpyinfo, 0);
7a13e894 9727 }
10c5e63d 9728 }
7a13e894 9729 goto OTHER;
dc6f92b8 9730
7a13e894 9731 case FocusOut:
19126e11 9732 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 9733 if (event.xfocus.detail != NotifyPointer
0f941935
KH
9734 && f == dpyinfo->x_focus_event_frame)
9735 dpyinfo->x_focus_event_frame = 0;
9736 if (f && f == dpyinfo->x_focus_frame)
9737 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 9738
6c183ba5
RS
9739#ifdef HAVE_X_I18N
9740 if (f && FRAME_XIC (f))
9741 XUnsetICFocus (FRAME_XIC (f));
9742#endif
9743
7a13e894 9744 goto OTHER;
dc6f92b8 9745
7a13e894 9746 case MotionNotify:
dc6f92b8 9747 {
06a2c219
GM
9748 previous_help_echo = help_echo;
9749 help_echo = Qnil;
9750
7a13e894
RS
9751 if (dpyinfo->grabbed && last_mouse_frame
9752 && FRAME_LIVE_P (last_mouse_frame))
9753 f = last_mouse_frame;
9754 else
19126e11 9755 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 9756
7a13e894
RS
9757 if (f)
9758 note_mouse_movement (f, &event.xmotion);
9759 else
9760 {
e88b3c50 9761#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
9762 struct scroll_bar *bar
9763 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 9764
7a13e894
RS
9765 if (bar)
9766 x_scroll_bar_note_movement (bar, &event);
e88b3c50 9767#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 9768
06a2c219
GM
9769 /* If we move outside the frame, then we're
9770 certainly no longer on any text in the frame. */
7a13e894
RS
9771 clear_mouse_face (dpyinfo);
9772 }
06a2c219
GM
9773
9774 /* If the contents of the global variable help_echo
9775 has changed, generate a HELP_EVENT. */
9776 if (STRINGP (help_echo)
9777 || STRINGP (previous_help_echo))
9778 {
9779 Lisp_Object frame;
9780
9781 if (f)
9782 XSETFRAME (frame, f);
9783 else
9784 frame = Qnil;
9785
9786 any_help_event_p = 1;
9787 bufp->kind = HELP_EVENT;
9788 bufp->frame_or_window = Fcons (frame, help_echo);
9789 ++bufp, ++count, --numchars;
9790 }
9791
9792 goto OTHER;
dc6f92b8 9793 }
dc6f92b8 9794
7a13e894 9795 case ConfigureNotify:
9829ddba
RS
9796 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
9797 if (f)
af395ec1 9798 {
5c187dee 9799#ifndef USE_X_TOOLKIT
bf1b7b30
KH
9800 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
9801 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 9802
2d7fc7e8
RS
9803 /* In the toolkit version, change_frame_size
9804 is called by the code that handles resizing
9805 of the EmacsFrame widget. */
7a13e894 9806
7a13e894
RS
9807 /* Even if the number of character rows and columns has
9808 not changed, the font size may have changed, so we need
9809 to check the pixel dimensions as well. */
9810 if (columns != f->width
9811 || rows != f->height
7556890b
RS
9812 || event.xconfigure.width != f->output_data.x->pixel_width
9813 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 9814 {
7d1e984f 9815 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 9816 SET_FRAME_GARBAGED (f);
e687d06e 9817 cancel_mouse_face (f);
7a13e894 9818 }
2d7fc7e8 9819#endif
af395ec1 9820
7556890b
RS
9821 f->output_data.x->pixel_width = event.xconfigure.width;
9822 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
9823
9824 /* What we have now is the position of Emacs's own window.
9825 Convert that to the position of the window manager window. */
dcb07ae9
RS
9826 x_real_positions (f, &f->output_data.x->left_pos,
9827 &f->output_data.x->top_pos);
9828
f5d11644
GM
9829#ifdef HAVE_X_I18N
9830 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
9831 xic_set_statusarea (f);
9832#endif
9833
dcb07ae9
RS
9834 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
9835 {
9836 /* Since the WM decorations come below top_pos now,
9837 we must put them below top_pos in the future. */
9838 f->output_data.x->win_gravity = NorthWestGravity;
9839 x_wm_set_size_hint (f, (long) 0, 0);
9840 }
8f08dc93
KH
9841#ifdef USE_MOTIF
9842 /* Some window managers pass (0,0) as the location of
9843 the window, and the Motif event handler stores it
9844 in the emacs widget, which messes up Motif menus. */
9845 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
9846 {
9847 event.xconfigure.x = f->output_data.x->widget->core.x;
9848 event.xconfigure.y = f->output_data.x->widget->core.y;
9849 }
06a2c219 9850#endif /* USE_MOTIF */
7a13e894 9851 }
2d7fc7e8 9852 goto OTHER;
dc6f92b8 9853
7a13e894
RS
9854 case ButtonPress:
9855 case ButtonRelease:
9856 {
9857 /* If we decide we want to generate an event to be seen
9858 by the rest of Emacs, we put it here. */
9859 struct input_event emacs_event;
9ea173e8 9860 int tool_bar_p = 0;
06a2c219 9861
7a13e894 9862 emacs_event.kind = no_event;
7a13e894 9863 bzero (&compose_status, sizeof (compose_status));
9b07615b 9864
06a2c219
GM
9865 if (dpyinfo->grabbed
9866 && last_mouse_frame
9f67f20b
RS
9867 && FRAME_LIVE_P (last_mouse_frame))
9868 f = last_mouse_frame;
9869 else
2224b905 9870 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 9871
06a2c219
GM
9872 if (f)
9873 {
9ea173e8
GM
9874 /* Is this in the tool-bar? */
9875 if (WINDOWP (f->tool_bar_window)
9876 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
9877 {
9878 Lisp_Object window;
9879 int p, x, y;
9880
9881 x = event.xbutton.x;
9882 y = event.xbutton.y;
9883
9884 /* Set x and y. */
9885 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 9886 if (EQ (window, f->tool_bar_window))
06a2c219 9887 {
9ea173e8
GM
9888 x_handle_tool_bar_click (f, &event.xbutton);
9889 tool_bar_p = 1;
06a2c219
GM
9890 }
9891 }
9892
9ea173e8 9893 if (!tool_bar_p)
06a2c219
GM
9894 if (!dpyinfo->x_focus_frame
9895 || f == dpyinfo->x_focus_frame)
9896 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
9897 }
9898 else
9899 {
06a2c219 9900#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
9901 struct scroll_bar *bar
9902 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 9903
7a13e894
RS
9904 if (bar)
9905 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 9906#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9907 }
9908
9909 if (event.type == ButtonPress)
9910 {
9911 dpyinfo->grabbed |= (1 << event.xbutton.button);
9912 last_mouse_frame = f;
edad46f6
KH
9913 /* Ignore any mouse motion that happened
9914 before this event; any subsequent mouse-movement
9915 Emacs events should reflect only motion after
9916 the ButtonPress. */
a00e91cd
KH
9917 if (f != 0)
9918 f->mouse_moved = 0;
06a2c219 9919
9ea173e8
GM
9920 if (!tool_bar_p)
9921 last_tool_bar_item = -1;
7a13e894 9922 }
3afe33e7
RS
9923 else
9924 {
7a13e894 9925 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 9926 }
23faf38f 9927
7a13e894
RS
9928 if (numchars >= 1 && emacs_event.kind != no_event)
9929 {
9930 bcopy (&emacs_event, bufp, sizeof (struct input_event));
9931 bufp++;
9932 count++;
9933 numchars--;
9934 }
3afe33e7
RS
9935
9936#ifdef USE_X_TOOLKIT
2224b905
RS
9937 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
9938 /* For a down-event in the menu bar,
9939 don't pass it to Xt right now.
9940 Instead, save it away
9941 and we will pass it to Xt from kbd_buffer_get_event.
9942 That way, we can run some Lisp code first. */
91375f8f
RS
9943 if (f && event.type == ButtonPress
9944 /* Verify the event is really within the menu bar
9945 and not just sent to it due to grabbing. */
9946 && event.xbutton.x >= 0
9947 && event.xbutton.x < f->output_data.x->pixel_width
9948 && event.xbutton.y >= 0
9949 && event.xbutton.y < f->output_data.x->menubar_height
9950 && event.xbutton.same_screen)
2224b905 9951 {
8805890a 9952 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
9953 XSETFRAME (last_mouse_press_frame, f);
9954 }
9955 else if (event.type == ButtonPress)
9956 {
9957 last_mouse_press_frame = Qnil;
30e671c3 9958 goto OTHER;
ce89ef46 9959 }
06a2c219 9960
2237cac9
RS
9961#ifdef USE_MOTIF /* This should do not harm for Lucid,
9962 but I am trying to be cautious. */
ce89ef46
RS
9963 else if (event.type == ButtonRelease)
9964 {
2237cac9 9965 if (!NILP (last_mouse_press_frame))
f10ded1c 9966 {
2237cac9
RS
9967 f = XFRAME (last_mouse_press_frame);
9968 if (f->output_data.x)
06a2c219 9969 SET_SAVED_BUTTON_EVENT;
f10ded1c 9970 }
06a2c219 9971 else
30e671c3 9972 goto OTHER;
2224b905 9973 }
2237cac9 9974#endif /* USE_MOTIF */
2224b905
RS
9975 else
9976 goto OTHER;
3afe33e7 9977#endif /* USE_X_TOOLKIT */
7a13e894
RS
9978 }
9979 break;
dc6f92b8 9980
7a13e894 9981 case CirculateNotify:
06a2c219
GM
9982 goto OTHER;
9983
7a13e894 9984 case CirculateRequest:
06a2c219
GM
9985 goto OTHER;
9986
9987 case VisibilityNotify:
9988 goto OTHER;
dc6f92b8 9989
7a13e894
RS
9990 case MappingNotify:
9991 /* Someone has changed the keyboard mapping - update the
9992 local cache. */
9993 switch (event.xmapping.request)
9994 {
9995 case MappingModifier:
9996 x_find_modifier_meanings (dpyinfo);
9997 /* This is meant to fall through. */
9998 case MappingKeyboard:
9999 XRefreshKeyboardMapping (&event.xmapping);
10000 }
7a13e894 10001 goto OTHER;
dc6f92b8 10002
7a13e894 10003 default:
7a13e894 10004 OTHER:
717ca130 10005#ifdef USE_X_TOOLKIT
7a13e894
RS
10006 BLOCK_INPUT;
10007 XtDispatchEvent (&event);
10008 UNBLOCK_INPUT;
3afe33e7 10009#endif /* USE_X_TOOLKIT */
7a13e894
RS
10010 break;
10011 }
dc6f92b8
JB
10012 }
10013 }
10014
06a2c219
GM
10015 out:;
10016
9a5196d0
RS
10017 /* On some systems, an X bug causes Emacs to get no more events
10018 when the window is destroyed. Detect that. (1994.) */
58769bee 10019 if (! event_found)
ef2a22d0 10020 {
ef2a22d0
RS
10021 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
10022 One XNOOP in 100 loops will make Emacs terminate.
10023 B. Bretthauer, 1994 */
10024 x_noop_count++;
58769bee 10025 if (x_noop_count >= 100)
ef2a22d0
RS
10026 {
10027 x_noop_count=0;
2224b905
RS
10028
10029 if (next_noop_dpyinfo == 0)
10030 next_noop_dpyinfo = x_display_list;
10031
10032 XNoOp (next_noop_dpyinfo->display);
10033
10034 /* Each time we get here, cycle through the displays now open. */
10035 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
10036 }
10037 }
502add23 10038
06a2c219 10039 /* If the focus was just given to an auto-raising frame,
0134a210 10040 raise it now. */
7a13e894 10041 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
10042 if (pending_autoraise_frame)
10043 {
10044 x_raise_frame (pending_autoraise_frame);
10045 pending_autoraise_frame = 0;
10046 }
0134a210 10047
dc6f92b8
JB
10048 UNBLOCK_INPUT;
10049 return count;
10050}
06a2c219
GM
10051
10052
10053
dc6f92b8 10054\f
06a2c219
GM
10055/***********************************************************************
10056 Text Cursor
10057 ***********************************************************************/
10058
10059/* Note if the text cursor of window W has been overwritten by a
10060 drawing operation that outputs N glyphs starting at HPOS in the
10061 line given by output_cursor.vpos. N < 0 means all the rest of the
10062 line after HPOS has been written. */
10063
10064static void
10065note_overwritten_text_cursor (w, hpos, n)
10066 struct window *w;
10067 int hpos, n;
10068{
10069 if (updated_area == TEXT_AREA
10070 && output_cursor.vpos == w->phys_cursor.vpos
10071 && hpos <= w->phys_cursor.hpos
10072 && (n < 0
10073 || hpos + n > w->phys_cursor.hpos))
10074 w->phys_cursor_on_p = 0;
10075}
f451eb13
JB
10076
10077
06a2c219
GM
10078/* Set clipping for output in glyph row ROW. W is the window in which
10079 we operate. GC is the graphics context to set clipping in.
10080 WHOLE_LINE_P non-zero means include the areas used for truncation
10081 mark display and alike in the clipping rectangle.
10082
10083 ROW may be a text row or, e.g., a mode line. Text rows must be
10084 clipped to the interior of the window dedicated to text display,
10085 mode lines must be clipped to the whole window. */
dc6f92b8
JB
10086
10087static void
06a2c219
GM
10088x_clip_to_row (w, row, gc, whole_line_p)
10089 struct window *w;
10090 struct glyph_row *row;
10091 GC gc;
10092 int whole_line_p;
dc6f92b8 10093{
06a2c219
GM
10094 struct frame *f = XFRAME (WINDOW_FRAME (w));
10095 XRectangle clip_rect;
10096 int window_x, window_y, window_width, window_height;
dc6f92b8 10097
06a2c219 10098 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 10099
06a2c219
GM
10100 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
10101 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
10102 clip_rect.y = max (clip_rect.y, window_y);
10103 clip_rect.width = window_width;
10104 clip_rect.height = row->visible_height;
5c1aae96 10105
06a2c219
GM
10106 /* If clipping to the whole line, including trunc marks, extend
10107 the rectangle to the left and increase its width. */
10108 if (whole_line_p)
10109 {
110859fc
GM
10110 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
10111 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 10112 }
5c1aae96 10113
06a2c219 10114 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
10115}
10116
06a2c219
GM
10117
10118/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
10119
10120static void
06a2c219
GM
10121x_draw_hollow_cursor (w, row)
10122 struct window *w;
10123 struct glyph_row *row;
dc6f92b8 10124{
06a2c219
GM
10125 struct frame *f = XFRAME (WINDOW_FRAME (w));
10126 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10127 Display *dpy = FRAME_X_DISPLAY (f);
10128 int x, y, wd, h;
10129 XGCValues xgcv;
10130 struct glyph *cursor_glyph;
10131 GC gc;
10132
10133 /* Compute frame-relative coordinates from window-relative
10134 coordinates. */
10135 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10136 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
10137 + row->ascent - w->phys_cursor_ascent);
10138 h = row->height - 1;
10139
10140 /* Get the glyph the cursor is on. If we can't tell because
10141 the current matrix is invalid or such, give up. */
10142 cursor_glyph = get_phys_cursor_glyph (w);
10143 if (cursor_glyph == NULL)
dc6f92b8
JB
10144 return;
10145
06a2c219
GM
10146 /* Compute the width of the rectangle to draw. If on a stretch
10147 glyph, and `x-stretch-block-cursor' is nil, don't draw a
10148 rectangle as wide as the glyph, but use a canonical character
10149 width instead. */
10150 wd = cursor_glyph->pixel_width - 1;
10151 if (cursor_glyph->type == STRETCH_GLYPH
10152 && !x_stretch_cursor_p)
10153 wd = min (CANON_X_UNIT (f), wd);
10154
10155 /* The foreground of cursor_gc is typically the same as the normal
10156 background color, which can cause the cursor box to be invisible. */
10157 xgcv.foreground = f->output_data.x->cursor_pixel;
10158 if (dpyinfo->scratch_cursor_gc)
10159 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
10160 else
10161 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
10162 GCForeground, &xgcv);
10163 gc = dpyinfo->scratch_cursor_gc;
10164
10165 /* Set clipping, draw the rectangle, and reset clipping again. */
10166 x_clip_to_row (w, row, gc, 0);
10167 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
10168 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
10169}
10170
06a2c219
GM
10171
10172/* Draw a bar cursor on window W in glyph row ROW.
10173
10174 Implementation note: One would like to draw a bar cursor with an
10175 angle equal to the one given by the font property XA_ITALIC_ANGLE.
10176 Unfortunately, I didn't find a font yet that has this property set.
10177 --gerd. */
dc6f92b8
JB
10178
10179static void
f02d8aa0 10180x_draw_bar_cursor (w, row, width)
06a2c219
GM
10181 struct window *w;
10182 struct glyph_row *row;
f02d8aa0 10183 int width;
dc6f92b8 10184{
06a2c219
GM
10185 /* If cursor hpos is out of bounds, don't draw garbage. This can
10186 happen in mini-buffer windows when switching between echo area
10187 glyphs and mini-buffer. */
10188 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
10189 {
10190 struct frame *f = XFRAME (w->frame);
10191 struct glyph *cursor_glyph;
10192 GC gc;
10193 int x;
10194 unsigned long mask;
10195 XGCValues xgcv;
10196 Display *dpy;
10197 Window window;
10198
10199 cursor_glyph = get_phys_cursor_glyph (w);
10200 if (cursor_glyph == NULL)
10201 return;
10202
10203 xgcv.background = f->output_data.x->cursor_pixel;
10204 xgcv.foreground = f->output_data.x->cursor_pixel;
10205 xgcv.graphics_exposures = 0;
10206 mask = GCForeground | GCBackground | GCGraphicsExposures;
10207 dpy = FRAME_X_DISPLAY (f);
10208 window = FRAME_X_WINDOW (f);
10209 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
10210
10211 if (gc)
10212 XChangeGC (dpy, gc, mask, &xgcv);
10213 else
10214 {
10215 gc = XCreateGC (dpy, window, mask, &xgcv);
10216 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
10217 }
10218
f02d8aa0
GM
10219 if (width < 0)
10220 width = f->output_data.x->cursor_width;
10221
06a2c219
GM
10222 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10223 x_clip_to_row (w, row, gc, 0);
10224 XFillRectangle (dpy, window, gc,
10225 x,
10226 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 10227 min (cursor_glyph->pixel_width, width),
06a2c219
GM
10228 row->height);
10229 XSetClipMask (dpy, gc, None);
10230 }
dc6f92b8
JB
10231}
10232
06a2c219
GM
10233
10234/* Clear the cursor of window W to background color, and mark the
10235 cursor as not shown. This is used when the text where the cursor
10236 is is about to be rewritten. */
10237
dc6f92b8 10238static void
06a2c219
GM
10239x_clear_cursor (w)
10240 struct window *w;
dc6f92b8 10241{
06a2c219
GM
10242 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
10243 x_update_window_cursor (w, 0);
10244}
90e65f07 10245
dbc4e1c1 10246
06a2c219
GM
10247/* Draw the cursor glyph of window W in glyph row ROW. See the
10248 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 10249
06a2c219
GM
10250static void
10251x_draw_phys_cursor_glyph (w, row, hl)
10252 struct window *w;
10253 struct glyph_row *row;
10254 enum draw_glyphs_face hl;
10255{
10256 /* If cursor hpos is out of bounds, don't draw garbage. This can
10257 happen in mini-buffer windows when switching between echo area
10258 glyphs and mini-buffer. */
10259 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
10260 {
10261 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
10262 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
10263 hl, 0, 0, 0);
10264
10265 /* When we erase the cursor, and ROW is overlapped by other
10266 rows, make sure that these overlapping parts of other rows
10267 are redrawn. */
10268 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
10269 {
10270 if (row > w->current_matrix->rows
10271 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
10272 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
10273
10274 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
10275 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
10276 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
10277 }
10278 }
06a2c219 10279}
dbc4e1c1 10280
eea6af04 10281
06a2c219 10282/* Erase the image of a cursor of window W from the screen. */
eea6af04 10283
06a2c219
GM
10284static void
10285x_erase_phys_cursor (w)
10286 struct window *w;
10287{
10288 struct frame *f = XFRAME (w->frame);
10289 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10290 int hpos = w->phys_cursor.hpos;
10291 int vpos = w->phys_cursor.vpos;
10292 int mouse_face_here_p = 0;
10293 struct glyph_matrix *active_glyphs = w->current_matrix;
10294 struct glyph_row *cursor_row;
10295 struct glyph *cursor_glyph;
10296 enum draw_glyphs_face hl;
10297
10298 /* No cursor displayed or row invalidated => nothing to do on the
10299 screen. */
10300 if (w->phys_cursor_type == NO_CURSOR)
10301 goto mark_cursor_off;
10302
10303 /* VPOS >= active_glyphs->nrows means that window has been resized.
10304 Don't bother to erase the cursor. */
10305 if (vpos >= active_glyphs->nrows)
10306 goto mark_cursor_off;
10307
10308 /* If row containing cursor is marked invalid, there is nothing we
10309 can do. */
10310 cursor_row = MATRIX_ROW (active_glyphs, vpos);
10311 if (!cursor_row->enabled_p)
10312 goto mark_cursor_off;
10313
10314 /* This can happen when the new row is shorter than the old one.
10315 In this case, either x_draw_glyphs or clear_end_of_line
10316 should have cleared the cursor. Note that we wouldn't be
10317 able to erase the cursor in this case because we don't have a
10318 cursor glyph at hand. */
10319 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
10320 goto mark_cursor_off;
10321
10322 /* If the cursor is in the mouse face area, redisplay that when
10323 we clear the cursor. */
8801a864
KR
10324 if (! NILP (dpyinfo->mouse_face_window)
10325 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
10326 && (vpos > dpyinfo->mouse_face_beg_row
10327 || (vpos == dpyinfo->mouse_face_beg_row
10328 && hpos >= dpyinfo->mouse_face_beg_col))
10329 && (vpos < dpyinfo->mouse_face_end_row
10330 || (vpos == dpyinfo->mouse_face_end_row
10331 && hpos < dpyinfo->mouse_face_end_col))
10332 /* Don't redraw the cursor's spot in mouse face if it is at the
10333 end of a line (on a newline). The cursor appears there, but
10334 mouse highlighting does not. */
10335 && cursor_row->used[TEXT_AREA] > hpos)
10336 mouse_face_here_p = 1;
10337
10338 /* Maybe clear the display under the cursor. */
10339 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
10340 {
10341 int x;
045dee35 10342 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 10343
06a2c219
GM
10344 cursor_glyph = get_phys_cursor_glyph (w);
10345 if (cursor_glyph == NULL)
10346 goto mark_cursor_off;
dbc4e1c1 10347
06a2c219
GM
10348 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
10349
10350 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10351 x,
045dee35 10352 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219
GM
10353 cursor_row->y)),
10354 cursor_glyph->pixel_width,
10355 cursor_row->visible_height,
10356 False);
dbc4e1c1 10357 }
06a2c219
GM
10358
10359 /* Erase the cursor by redrawing the character underneath it. */
10360 if (mouse_face_here_p)
10361 hl = DRAW_MOUSE_FACE;
10362 else if (cursor_row->inverse_p)
10363 hl = DRAW_INVERSE_VIDEO;
10364 else
10365 hl = DRAW_NORMAL_TEXT;
10366 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 10367
06a2c219
GM
10368 mark_cursor_off:
10369 w->phys_cursor_on_p = 0;
10370 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
10371}
10372
10373
06a2c219
GM
10374/* Display or clear cursor of window W. If ON is zero, clear the
10375 cursor. If it is non-zero, display the cursor. If ON is nonzero,
10376 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 10377
06a2c219
GM
10378void
10379x_display_and_set_cursor (w, on, hpos, vpos, x, y)
10380 struct window *w;
10381 int on, hpos, vpos, x, y;
dbc4e1c1 10382{
06a2c219
GM
10383 struct frame *f = XFRAME (w->frame);
10384 int new_cursor_type;
f02d8aa0 10385 int new_cursor_width;
06a2c219
GM
10386 struct glyph_matrix *current_glyphs;
10387 struct glyph_row *glyph_row;
10388 struct glyph *glyph;
dbc4e1c1 10389
49d838ea 10390 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
10391 windows and frames; in the latter case, the frame or window may
10392 be in the midst of changing its size, and x and y may be off the
10393 window. */
10394 if (! FRAME_VISIBLE_P (f)
10395 || FRAME_GARBAGED_P (f)
10396 || vpos >= w->current_matrix->nrows
10397 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
10398 return;
10399
10400 /* If cursor is off and we want it off, return quickly. */
06a2c219 10401 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
10402 return;
10403
06a2c219
GM
10404 current_glyphs = w->current_matrix;
10405 glyph_row = MATRIX_ROW (current_glyphs, vpos);
10406 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
10407
10408 /* If cursor row is not enabled, we don't really know where to
10409 display the cursor. */
10410 if (!glyph_row->enabled_p)
10411 {
10412 w->phys_cursor_on_p = 0;
10413 return;
10414 }
10415
10416 xassert (interrupt_input_blocked);
10417
10418 /* Set new_cursor_type to the cursor we want to be displayed. In a
10419 mini-buffer window, we want the cursor only to appear if we are
10420 reading input from this window. For the selected window, we want
10421 the cursor type given by the frame parameter. If explicitly
10422 marked off, draw no cursor. In all other cases, we want a hollow
10423 box cursor. */
f02d8aa0 10424 new_cursor_width = -1;
9b4a7047
GM
10425 if (cursor_in_echo_area
10426 && FRAME_HAS_MINIBUF_P (f)
10427 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 10428 {
9b4a7047
GM
10429 if (w == XWINDOW (echo_area_window))
10430 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
10431 else
10432 new_cursor_type = HOLLOW_BOX_CURSOR;
10433 }
06a2c219 10434 else
9b4a7047
GM
10435 {
10436 if (w != XWINDOW (selected_window)
10437 || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
10438 {
e55a0b79
GM
10439 extern int cursor_in_non_selected_windows;
10440
10441 if (MINI_WINDOW_P (w) || !cursor_in_non_selected_windows)
9b4a7047
GM
10442 new_cursor_type = NO_CURSOR;
10443 else
10444 new_cursor_type = HOLLOW_BOX_CURSOR;
10445 }
10446 else if (w->cursor_off_p)
10447 new_cursor_type = NO_CURSOR;
10448 else
f02d8aa0
GM
10449 {
10450 struct buffer *b = XBUFFER (w->buffer);
10451
10452 if (EQ (b->cursor_type, Qt))
10453 new_cursor_type = FRAME_DESIRED_CURSOR (f);
10454 else
10455 new_cursor_type = x_specified_cursor_type (b->cursor_type,
10456 &new_cursor_width);
10457 }
9b4a7047 10458 }
06a2c219
GM
10459
10460 /* If cursor is currently being shown and we don't want it to be or
10461 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 10462 erase it. */
06a2c219 10463 if (w->phys_cursor_on_p
dc6f92b8 10464 && (!on
06a2c219
GM
10465 || w->phys_cursor.x != x
10466 || w->phys_cursor.y != y
10467 || new_cursor_type != w->phys_cursor_type))
10468 x_erase_phys_cursor (w);
10469
10470 /* If the cursor is now invisible and we want it to be visible,
10471 display it. */
10472 if (on && !w->phys_cursor_on_p)
10473 {
10474 w->phys_cursor_ascent = glyph_row->ascent;
10475 w->phys_cursor_height = glyph_row->height;
10476
10477 /* Set phys_cursor_.* before x_draw_.* is called because some
10478 of them may need the information. */
10479 w->phys_cursor.x = x;
10480 w->phys_cursor.y = glyph_row->y;
10481 w->phys_cursor.hpos = hpos;
10482 w->phys_cursor.vpos = vpos;
10483 w->phys_cursor_type = new_cursor_type;
10484 w->phys_cursor_on_p = 1;
10485
10486 switch (new_cursor_type)
dc6f92b8 10487 {
06a2c219
GM
10488 case HOLLOW_BOX_CURSOR:
10489 x_draw_hollow_cursor (w, glyph_row);
10490 break;
10491
10492 case FILLED_BOX_CURSOR:
10493 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
10494 break;
10495
10496 case BAR_CURSOR:
f02d8aa0 10497 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
10498 break;
10499
10500 case NO_CURSOR:
10501 break;
dc6f92b8 10502
06a2c219
GM
10503 default:
10504 abort ();
10505 }
59ddecde
GM
10506
10507#ifdef HAVE_X_I18N
10508 if (w == XWINDOW (f->selected_window))
10509 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
10510 xic_set_preeditarea (w, x, y);
10511#endif
dc6f92b8
JB
10512 }
10513
06a2c219 10514#ifndef XFlush
f676886a 10515 if (updating_frame != f)
334208b7 10516 XFlush (FRAME_X_DISPLAY (f));
06a2c219 10517#endif
dc6f92b8
JB
10518}
10519
06a2c219
GM
10520
10521/* Display the cursor on window W, or clear it. X and Y are window
10522 relative pixel coordinates. HPOS and VPOS are glyph matrix
10523 positions. If W is not the selected window, display a hollow
10524 cursor. ON non-zero means display the cursor at X, Y which
10525 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 10526
dfcf069d 10527void
06a2c219
GM
10528x_display_cursor (w, on, hpos, vpos, x, y)
10529 struct window *w;
10530 int on, hpos, vpos, x, y;
dc6f92b8 10531{
f94397b5 10532 BLOCK_INPUT;
06a2c219 10533 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
10534 UNBLOCK_INPUT;
10535}
10536
06a2c219
GM
10537
10538/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
10539 Don't change the cursor's position. */
10540
dfcf069d 10541void
06a2c219 10542x_update_cursor (f, on_p)
5d46f928 10543 struct frame *f;
5d46f928 10544{
06a2c219
GM
10545 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
10546}
10547
10548
10549/* Call x_update_window_cursor with parameter ON_P on all leaf windows
10550 in the window tree rooted at W. */
10551
10552static void
10553x_update_cursor_in_window_tree (w, on_p)
10554 struct window *w;
10555 int on_p;
10556{
10557 while (w)
10558 {
10559 if (!NILP (w->hchild))
10560 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
10561 else if (!NILP (w->vchild))
10562 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
10563 else
10564 x_update_window_cursor (w, on_p);
10565
10566 w = NILP (w->next) ? 0 : XWINDOW (w->next);
10567 }
10568}
5d46f928 10569
f94397b5 10570
06a2c219
GM
10571/* Switch the display of W's cursor on or off, according to the value
10572 of ON. */
10573
10574static void
10575x_update_window_cursor (w, on)
10576 struct window *w;
10577 int on;
10578{
16b5d424
GM
10579 /* Don't update cursor in windows whose frame is in the process
10580 of being deleted. */
10581 if (w->current_matrix)
10582 {
10583 BLOCK_INPUT;
10584 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
10585 w->phys_cursor.x, w->phys_cursor.y);
10586 UNBLOCK_INPUT;
10587 }
dc6f92b8 10588}
06a2c219
GM
10589
10590
10591
dc6f92b8
JB
10592\f
10593/* Icons. */
10594
f676886a 10595/* Refresh bitmap kitchen sink icon for frame F
06a2c219 10596 when we get an expose event for it. */
dc6f92b8 10597
dfcf069d 10598void
f676886a
JB
10599refreshicon (f)
10600 struct frame *f;
dc6f92b8 10601{
06a2c219 10602 /* Normally, the window manager handles this function. */
dc6f92b8
JB
10603}
10604
dbc4e1c1 10605/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
10606
10607int
990ba854 10608x_bitmap_icon (f, file)
f676886a 10609 struct frame *f;
990ba854 10610 Lisp_Object file;
dc6f92b8 10611{
06a2c219 10612 int bitmap_id;
dc6f92b8 10613
c118dd06 10614 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10615 return 1;
10616
990ba854 10617 /* Free up our existing icon bitmap if any. */
7556890b
RS
10618 if (f->output_data.x->icon_bitmap > 0)
10619 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10620 f->output_data.x->icon_bitmap = 0;
990ba854
RS
10621
10622 if (STRINGP (file))
7f2ae036
RS
10623 bitmap_id = x_create_bitmap_from_file (f, file);
10624 else
10625 {
990ba854 10626 /* Create the GNU bitmap if necessary. */
5bf01b68 10627 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
10628 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
10629 = x_create_bitmap_from_data (f, gnu_bits,
10630 gnu_width, gnu_height);
990ba854
RS
10631
10632 /* The first time we create the GNU bitmap,
06a2c219 10633 this increments the ref-count one extra time.
990ba854
RS
10634 As a result, the GNU bitmap is never freed.
10635 That way, we don't have to worry about allocating it again. */
334208b7 10636 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 10637
334208b7 10638 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
10639 }
10640
10641 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 10642 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
10643
10644 return 0;
10645}
10646
10647
1be2d067
KH
10648/* Make the x-window of frame F use a rectangle with text.
10649 Use ICON_NAME as the text. */
dc6f92b8
JB
10650
10651int
f676886a
JB
10652x_text_icon (f, icon_name)
10653 struct frame *f;
dc6f92b8
JB
10654 char *icon_name;
10655{
c118dd06 10656 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
10657 return 1;
10658
1be2d067
KH
10659#ifdef HAVE_X11R4
10660 {
10661 XTextProperty text;
10662 text.value = (unsigned char *) icon_name;
10663 text.encoding = XA_STRING;
10664 text.format = 8;
10665 text.nitems = strlen (icon_name);
10666#ifdef USE_X_TOOLKIT
7556890b 10667 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
10668 &text);
10669#else /* not USE_X_TOOLKIT */
10670 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
10671#endif /* not USE_X_TOOLKIT */
10672 }
10673#else /* not HAVE_X11R4 */
10674 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
10675#endif /* not HAVE_X11R4 */
58769bee 10676
7556890b
RS
10677 if (f->output_data.x->icon_bitmap > 0)
10678 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
10679 f->output_data.x->icon_bitmap = 0;
b1c884c3 10680 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
10681
10682 return 0;
10683}
10684\f
e99db5a1
RS
10685#define X_ERROR_MESSAGE_SIZE 200
10686
10687/* If non-nil, this should be a string.
10688 It means catch X errors and store the error message in this string. */
10689
10690static Lisp_Object x_error_message_string;
10691
10692/* An X error handler which stores the error message in
10693 x_error_message_string. This is called from x_error_handler if
10694 x_catch_errors is in effect. */
10695
06a2c219 10696static void
e99db5a1
RS
10697x_error_catcher (display, error)
10698 Display *display;
10699 XErrorEvent *error;
10700{
10701 XGetErrorText (display, error->error_code,
10702 XSTRING (x_error_message_string)->data,
10703 X_ERROR_MESSAGE_SIZE);
10704}
10705
10706/* Begin trapping X errors for display DPY. Actually we trap X errors
10707 for all displays, but DPY should be the display you are actually
10708 operating on.
10709
10710 After calling this function, X protocol errors no longer cause
10711 Emacs to exit; instead, they are recorded in the string
10712 stored in x_error_message_string.
10713
10714 Calling x_check_errors signals an Emacs error if an X error has
10715 occurred since the last call to x_catch_errors or x_check_errors.
10716
10717 Calling x_uncatch_errors resumes the normal error handling. */
10718
10719void x_check_errors ();
10720static Lisp_Object x_catch_errors_unwind ();
10721
10722int
10723x_catch_errors (dpy)
10724 Display *dpy;
10725{
10726 int count = specpdl_ptr - specpdl;
10727
10728 /* Make sure any errors from previous requests have been dealt with. */
10729 XSync (dpy, False);
10730
10731 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
10732
10733 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
10734 XSTRING (x_error_message_string)->data[0] = 0;
10735
10736 return count;
10737}
10738
10739/* Unbind the binding that we made to check for X errors. */
10740
10741static Lisp_Object
10742x_catch_errors_unwind (old_val)
10743 Lisp_Object old_val;
10744{
10745 x_error_message_string = old_val;
10746 return Qnil;
10747}
10748
10749/* If any X protocol errors have arrived since the last call to
10750 x_catch_errors or x_check_errors, signal an Emacs error using
10751 sprintf (a buffer, FORMAT, the x error message text) as the text. */
10752
10753void
10754x_check_errors (dpy, format)
10755 Display *dpy;
10756 char *format;
10757{
10758 /* Make sure to catch any errors incurred so far. */
10759 XSync (dpy, False);
10760
10761 if (XSTRING (x_error_message_string)->data[0])
10762 error (format, XSTRING (x_error_message_string)->data);
10763}
10764
9829ddba
RS
10765/* Nonzero if we had any X protocol errors
10766 since we did x_catch_errors on DPY. */
e99db5a1
RS
10767
10768int
10769x_had_errors_p (dpy)
10770 Display *dpy;
10771{
10772 /* Make sure to catch any errors incurred so far. */
10773 XSync (dpy, False);
10774
10775 return XSTRING (x_error_message_string)->data[0] != 0;
10776}
10777
9829ddba
RS
10778/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
10779
06a2c219 10780void
9829ddba
RS
10781x_clear_errors (dpy)
10782 Display *dpy;
10783{
10784 XSTRING (x_error_message_string)->data[0] = 0;
10785}
10786
e99db5a1
RS
10787/* Stop catching X protocol errors and let them make Emacs die.
10788 DPY should be the display that was passed to x_catch_errors.
10789 COUNT should be the value that was returned by
10790 the corresponding call to x_catch_errors. */
10791
10792void
10793x_uncatch_errors (dpy, count)
10794 Display *dpy;
10795 int count;
10796{
10797 unbind_to (count, Qnil);
10798}
10799
10800#if 0
10801static unsigned int x_wire_count;
10802x_trace_wire ()
10803{
10804 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
10805}
10806#endif /* ! 0 */
10807
10808\f
10809/* Handle SIGPIPE, which can happen when the connection to a server
10810 simply goes away. SIGPIPE is handled by x_connection_signal.
10811 Don't need to do anything, because the write which caused the
10812 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 10813 which will do the appropriate cleanup for us. */
e99db5a1
RS
10814
10815static SIGTYPE
10816x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 10817 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
10818{
10819#ifdef USG
10820 /* USG systems forget handlers when they are used;
10821 must reestablish each time */
10822 signal (signalnum, x_connection_signal);
10823#endif /* USG */
10824}
10825\f
4746118a
JB
10826/* Handling X errors. */
10827
7a13e894 10828/* Handle the loss of connection to display DISPLAY. */
16bd92ea 10829
4746118a 10830static SIGTYPE
7a13e894
RS
10831x_connection_closed (display, error_message)
10832 Display *display;
10833 char *error_message;
4746118a 10834{
7a13e894
RS
10835 struct x_display_info *dpyinfo = x_display_info_for_display (display);
10836 Lisp_Object frame, tail;
10837
6186a4a0
RS
10838 /* Indicate that this display is dead. */
10839
2e465cdd 10840#if 0 /* Closing the display caused a bus error on OpenWindows. */
f613a4c8 10841#ifdef USE_X_TOOLKIT
adabc3a9 10842 XtCloseDisplay (display);
2e465cdd 10843#endif
f613a4c8 10844#endif
adabc3a9 10845
9e80b57d
KR
10846 if (dpyinfo)
10847 dpyinfo->display = 0;
6186a4a0 10848
06a2c219 10849 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
10850 that are on the dead display. */
10851 FOR_EACH_FRAME (tail, frame)
10852 {
10853 Lisp_Object minibuf_frame;
10854 minibuf_frame
10855 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
10856 if (FRAME_X_P (XFRAME (frame))
10857 && FRAME_X_P (XFRAME (minibuf_frame))
10858 && ! EQ (frame, minibuf_frame)
10859 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
10860 Fdelete_frame (frame, Qt);
10861 }
10862
10863 /* Now delete all remaining frames on the dead display.
06a2c219 10864 We are now sure none of these is used as the mini-buffer
7a13e894
RS
10865 for another frame that we need to delete. */
10866 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
10867 if (FRAME_X_P (XFRAME (frame))
10868 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
10869 {
10870 /* Set this to t so that Fdelete_frame won't get confused
10871 trying to find a replacement. */
10872 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
10873 Fdelete_frame (frame, Qt);
10874 }
7a13e894 10875
482a1bd2
KH
10876 if (dpyinfo)
10877 x_delete_display (dpyinfo);
7a13e894
RS
10878
10879 if (x_display_list == 0)
10880 {
f8d07b62 10881 fprintf (stderr, "%s\n", error_message);
7a13e894
RS
10882 shut_down_emacs (0, 0, Qnil);
10883 exit (70);
10884 }
12ba150f 10885
7a13e894
RS
10886 /* Ordinary stack unwind doesn't deal with these. */
10887#ifdef SIGIO
10888 sigunblock (sigmask (SIGIO));
10889#endif
10890 sigunblock (sigmask (SIGALRM));
10891 TOTALLY_UNBLOCK_INPUT;
10892
aa4d9a9e 10893 clear_waiting_for_input ();
7a13e894 10894 error ("%s", error_message);
4746118a
JB
10895}
10896
7a13e894
RS
10897/* This is the usual handler for X protocol errors.
10898 It kills all frames on the display that we got the error for.
10899 If that was the only one, it prints an error message and kills Emacs. */
10900
06a2c219 10901static void
c118dd06
JB
10902x_error_quitter (display, error)
10903 Display *display;
10904 XErrorEvent *error;
10905{
7a13e894 10906 char buf[256], buf1[356];
dc6f92b8 10907
58769bee 10908 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 10909 original error handler. */
dc6f92b8 10910
c118dd06 10911 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 10912 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 10913 buf, error->request_code);
7a13e894 10914 x_connection_closed (display, buf1);
dc6f92b8
JB
10915}
10916
e99db5a1
RS
10917/* This is the first-level handler for X protocol errors.
10918 It calls x_error_quitter or x_error_catcher. */
7a13e894 10919
8922af5f 10920static int
e99db5a1 10921x_error_handler (display, error)
8922af5f 10922 Display *display;
e99db5a1 10923 XErrorEvent *error;
8922af5f 10924{
e99db5a1
RS
10925 if (! NILP (x_error_message_string))
10926 x_error_catcher (display, error);
10927 else
10928 x_error_quitter (display, error);
06a2c219 10929 return 0;
f9e24cb9 10930}
c118dd06 10931
e99db5a1
RS
10932/* This is the handler for X IO errors, always.
10933 It kills all frames on the display that we lost touch with.
10934 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 10935
c118dd06 10936static int
e99db5a1 10937x_io_error_quitter (display)
c118dd06 10938 Display *display;
c118dd06 10939{
e99db5a1 10940 char buf[256];
dc6f92b8 10941
e99db5a1
RS
10942 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
10943 x_connection_closed (display, buf);
06a2c219 10944 return 0;
dc6f92b8 10945}
dc6f92b8 10946\f
f451eb13
JB
10947/* Changing the font of the frame. */
10948
76bcdf39
RS
10949/* Give frame F the font named FONTNAME as its default font, and
10950 return the full name of that font. FONTNAME may be a wildcard
10951 pattern; in that case, we choose some font that fits the pattern.
10952 The return value shows which font we chose. */
10953
b5cf7a0e 10954Lisp_Object
f676886a
JB
10955x_new_font (f, fontname)
10956 struct frame *f;
dc6f92b8
JB
10957 register char *fontname;
10958{
dc43ef94 10959 struct font_info *fontp
ee569018 10960 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 10961
dc43ef94
KH
10962 if (!fontp)
10963 return Qnil;
2224a5fc 10964
dc43ef94 10965 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 10966 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
10967 f->output_data.x->fontset = -1;
10968
b2cad826
KH
10969 /* Compute the scroll bar width in character columns. */
10970 if (f->scroll_bar_pixel_width > 0)
10971 {
7556890b 10972 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
10973 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
10974 }
10975 else
4e61bddf
RS
10976 {
10977 int wid = FONT_WIDTH (f->output_data.x->font);
10978 f->scroll_bar_cols = (14 + wid - 1) / wid;
10979 }
b2cad826 10980
f676886a 10981 /* Now make the frame display the given font. */
c118dd06 10982 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 10983 {
7556890b
RS
10984 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
10985 f->output_data.x->font->fid);
10986 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
10987 f->output_data.x->font->fid);
10988 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
10989 f->output_data.x->font->fid);
f676886a 10990
a27f9f86 10991 frame_update_line_height (f);
0134a210 10992 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 10993 }
a27f9f86
RS
10994 else
10995 /* If we are setting a new frame's font for the first time,
10996 there are no faces yet, so this font's height is the line height. */
7556890b 10997 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 10998
dc43ef94
KH
10999 return build_string (fontp->full_name);
11000}
11001
11002/* Give frame F the fontset named FONTSETNAME as its default font, and
11003 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
11004 pattern; in that case, we choose some fontset that fits the pattern.
11005 The return value shows which fontset we chose. */
b5cf7a0e 11006
dc43ef94
KH
11007Lisp_Object
11008x_new_fontset (f, fontsetname)
11009 struct frame *f;
11010 char *fontsetname;
11011{
ee569018 11012 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 11013 Lisp_Object result;
b5cf7a0e 11014
dc43ef94
KH
11015 if (fontset < 0)
11016 return Qnil;
b5cf7a0e 11017
2da424f1
KH
11018 if (f->output_data.x->fontset == fontset)
11019 /* This fontset is already set in frame F. There's nothing more
11020 to do. */
ee569018 11021 return fontset_name (fontset);
dc43ef94 11022
ee569018 11023 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
11024
11025 if (!STRINGP (result))
11026 /* Can't load ASCII font. */
11027 return Qnil;
11028
11029 /* Since x_new_font doesn't update any fontset information, do it now. */
11030 f->output_data.x->fontset = fontset;
dc43ef94 11031
f5d11644
GM
11032#ifdef HAVE_X_I18N
11033 if (FRAME_XIC (f)
11034 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 11035 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
11036#endif
11037
dc43ef94 11038 return build_string (fontsetname);
dc6f92b8 11039}
f5d11644
GM
11040
11041\f
11042/***********************************************************************
11043 X Input Methods
11044 ***********************************************************************/
11045
11046#ifdef HAVE_X_I18N
11047
11048#ifdef HAVE_X11R6
11049
11050/* XIM destroy callback function, which is called whenever the
11051 connection to input method XIM dies. CLIENT_DATA contains a
11052 pointer to the x_display_info structure corresponding to XIM. */
11053
11054static void
11055xim_destroy_callback (xim, client_data, call_data)
11056 XIM xim;
11057 XPointer client_data;
11058 XPointer call_data;
11059{
11060 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
11061 Lisp_Object frame, tail;
11062
11063 BLOCK_INPUT;
11064
11065 /* No need to call XDestroyIC.. */
11066 FOR_EACH_FRAME (tail, frame)
11067 {
11068 struct frame *f = XFRAME (frame);
11069 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
11070 {
11071 FRAME_XIC (f) = NULL;
11072 if (FRAME_XIC_FONTSET (f))
11073 {
11074 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
11075 FRAME_XIC_FONTSET (f) = NULL;
11076 }
11077 }
11078 }
11079
11080 /* No need to call XCloseIM. */
11081 dpyinfo->xim = NULL;
11082 XFree (dpyinfo->xim_styles);
11083 UNBLOCK_INPUT;
11084}
11085
11086#endif /* HAVE_X11R6 */
11087
11088/* Open the connection to the XIM server on display DPYINFO.
11089 RESOURCE_NAME is the resource name Emacs uses. */
11090
11091static void
11092xim_open_dpy (dpyinfo, resource_name)
11093 struct x_display_info *dpyinfo;
11094 char *resource_name;
11095{
287f7dd6 11096#ifdef USE_XIM
f5d11644
GM
11097 XIM xim;
11098
11099 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
11100 dpyinfo->xim = xim;
11101
11102 if (xim)
11103 {
f5d11644
GM
11104#ifdef HAVE_X11R6
11105 XIMCallback destroy;
11106#endif
11107
11108 /* Get supported styles and XIM values. */
11109 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
11110
11111#ifdef HAVE_X11R6
11112 destroy.callback = xim_destroy_callback;
11113 destroy.client_data = (XPointer)dpyinfo;
68642df6 11114 /* This isn't prptotyped in OSF 5.0. */
f5d11644
GM
11115 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
11116#endif
11117 }
287f7dd6
GM
11118
11119#else /* not USE_XIM */
11120 dpyinfo->xim = NULL;
11121#endif /* not USE_XIM */
f5d11644
GM
11122}
11123
11124
b9de836c 11125#ifdef HAVE_X11R6_XIM
f5d11644
GM
11126
11127struct xim_inst_t
11128{
11129 struct x_display_info *dpyinfo;
11130 char *resource_name;
11131};
11132
11133/* XIM instantiate callback function, which is called whenever an XIM
11134 server is available. DISPLAY is teh display of the XIM.
11135 CLIENT_DATA contains a pointer to an xim_inst_t structure created
11136 when the callback was registered. */
11137
11138static void
11139xim_instantiate_callback (display, client_data, call_data)
11140 Display *display;
11141 XPointer client_data;
11142 XPointer call_data;
11143{
11144 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
11145 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
11146
11147 /* We don't support multiple XIM connections. */
11148 if (dpyinfo->xim)
11149 return;
11150
11151 xim_open_dpy (dpyinfo, xim_inst->resource_name);
11152
11153 /* Create XIC for the existing frames on the same display, as long
11154 as they have no XIC. */
11155 if (dpyinfo->xim && dpyinfo->reference_count > 0)
11156 {
11157 Lisp_Object tail, frame;
11158
11159 BLOCK_INPUT;
11160 FOR_EACH_FRAME (tail, frame)
11161 {
11162 struct frame *f = XFRAME (frame);
11163
11164 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
11165 if (FRAME_XIC (f) == NULL)
11166 {
11167 create_frame_xic (f);
11168 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
11169 xic_set_statusarea (f);
11170 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
11171 {
11172 struct window *w = XWINDOW (f->selected_window);
11173 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
11174 }
11175 }
11176 }
11177
11178 UNBLOCK_INPUT;
11179 }
11180}
11181
b9de836c 11182#endif /* HAVE_X11R6_XIM */
f5d11644
GM
11183
11184
11185/* Open a connection to the XIM server on display DPYINFO.
11186 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
11187 connection only at the first time. On X11R6, open the connection
11188 in the XIM instantiate callback function. */
11189
11190static void
11191xim_initialize (dpyinfo, resource_name)
11192 struct x_display_info *dpyinfo;
11193 char *resource_name;
11194{
287f7dd6 11195#ifdef USE_XIM
b9de836c 11196#ifdef HAVE_X11R6_XIM
f5d11644
GM
11197 struct xim_inst_t *xim_inst;
11198 int len;
11199
11200 dpyinfo->xim = NULL;
11201 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
11202 xim_inst->dpyinfo = dpyinfo;
11203 len = strlen (resource_name);
11204 xim_inst->resource_name = (char *) xmalloc (len + 1);
11205 bcopy (resource_name, xim_inst->resource_name, len + 1);
11206 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11207 resource_name, EMACS_CLASS,
11208 xim_instantiate_callback,
2ebb2f8b
DL
11209 /* Fixme: This is XPointer in
11210 XFree86 but (XPointer *) on
11211 Tru64, at least. */
11212 (XPointer) xim_inst);
b9de836c 11213#else /* not HAVE_X11R6_XIM */
f5d11644
GM
11214 dpyinfo->xim = NULL;
11215 xim_open_dpy (dpyinfo, resource_name);
b9de836c 11216#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
11217
11218#else /* not USE_XIM */
11219 dpyinfo->xim = NULL;
11220#endif /* not USE_XIM */
f5d11644
GM
11221}
11222
11223
11224/* Close the connection to the XIM server on display DPYINFO. */
11225
11226static void
11227xim_close_dpy (dpyinfo)
11228 struct x_display_info *dpyinfo;
11229{
287f7dd6 11230#ifdef USE_XIM
b9de836c 11231#ifdef HAVE_X11R6_XIM
f5d11644
GM
11232 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11233 NULL, EMACS_CLASS,
11234 xim_instantiate_callback, NULL);
b9de836c 11235#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11236 XCloseIM (dpyinfo->xim);
11237 dpyinfo->xim = NULL;
11238 XFree (dpyinfo->xim_styles);
287f7dd6 11239#endif /* USE_XIM */
f5d11644
GM
11240}
11241
b9de836c 11242#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11243
11244
dc6f92b8 11245\f
2e365682
RS
11246/* Calculate the absolute position in frame F
11247 from its current recorded position values and gravity. */
11248
dfcf069d 11249void
43bca5d5 11250x_calc_absolute_position (f)
f676886a 11251 struct frame *f;
dc6f92b8 11252{
06a2c219 11253 Window child;
6dba1858 11254 int win_x = 0, win_y = 0;
7556890b 11255 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
11256 int this_window;
11257
9829ddba
RS
11258 /* We have nothing to do if the current position
11259 is already for the top-left corner. */
11260 if (! ((flags & XNegative) || (flags & YNegative)))
11261 return;
11262
c81412a0 11263#ifdef USE_X_TOOLKIT
7556890b 11264 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
11265#else
11266 this_window = FRAME_X_WINDOW (f);
11267#endif
6dba1858
RS
11268
11269 /* Find the position of the outside upper-left corner of
9829ddba
RS
11270 the inner window, with respect to the outer window.
11271 But do this only if we will need the results. */
7556890b 11272 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 11273 {
9829ddba
RS
11274 int count;
11275
6dba1858 11276 BLOCK_INPUT;
9829ddba
RS
11277 count = x_catch_errors (FRAME_X_DISPLAY (f));
11278 while (1)
11279 {
11280 x_clear_errors (FRAME_X_DISPLAY (f));
11281 XTranslateCoordinates (FRAME_X_DISPLAY (f),
11282
11283 /* From-window, to-window. */
11284 this_window,
11285 f->output_data.x->parent_desc,
11286
11287 /* From-position, to-position. */
11288 0, 0, &win_x, &win_y,
11289
11290 /* Child of win. */
11291 &child);
11292 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
11293 {
11294 Window newroot, newparent = 0xdeadbeef;
11295 Window *newchildren;
2ebb2f8b 11296 unsigned int nchildren;
9829ddba
RS
11297
11298 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
11299 &newparent, &newchildren, &nchildren))
11300 break;
58769bee 11301
7c3c78a3 11302 XFree ((char *) newchildren);
6dba1858 11303
9829ddba
RS
11304 f->output_data.x->parent_desc = newparent;
11305 }
11306 else
11307 break;
11308 }
6dba1858 11309
9829ddba 11310 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
11311 UNBLOCK_INPUT;
11312 }
11313
11314 /* Treat negative positions as relative to the leftmost bottommost
11315 position that fits on the screen. */
20f55f9a 11316 if (flags & XNegative)
7556890b 11317 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
11318 - 2 * f->output_data.x->border_width - win_x
11319 - PIXEL_WIDTH (f)
11320 + f->output_data.x->left_pos);
dc6f92b8 11321
20f55f9a 11322 if (flags & YNegative)
06a2c219
GM
11323 {
11324 int menubar_height = 0;
11325
11326#ifdef USE_X_TOOLKIT
11327 if (f->output_data.x->menubar_widget)
11328 menubar_height
11329 = (f->output_data.x->menubar_widget->core.height
11330 + f->output_data.x->menubar_widget->core.border_width);
11331#endif
11332
11333 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
11334 - 2 * f->output_data.x->border_width
11335 - win_y
11336 - PIXEL_HEIGHT (f)
11337 - menubar_height
11338 + f->output_data.x->top_pos);
11339 }
2e365682 11340
3a35ab44
RS
11341 /* The left_pos and top_pos
11342 are now relative to the top and left screen edges,
11343 so the flags should correspond. */
7556890b 11344 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
11345}
11346
3a35ab44
RS
11347/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
11348 to really change the position, and 0 when calling from
11349 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
11350 position values). It is -1 when calling from x_set_frame_parameters,
11351 which means, do adjust for borders but don't change the gravity. */
3a35ab44 11352
dfcf069d 11353void
dc05a16b 11354x_set_offset (f, xoff, yoff, change_gravity)
f676886a 11355 struct frame *f;
dc6f92b8 11356 register int xoff, yoff;
dc05a16b 11357 int change_gravity;
dc6f92b8 11358{
4a4cbdd5
KH
11359 int modified_top, modified_left;
11360
aa3ff7c9 11361 if (change_gravity > 0)
3a35ab44 11362 {
7556890b
RS
11363 f->output_data.x->top_pos = yoff;
11364 f->output_data.x->left_pos = xoff;
11365 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 11366 if (xoff < 0)
7556890b 11367 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 11368 if (yoff < 0)
7556890b
RS
11369 f->output_data.x->size_hint_flags |= YNegative;
11370 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 11371 }
43bca5d5 11372 x_calc_absolute_position (f);
dc6f92b8
JB
11373
11374 BLOCK_INPUT;
c32cdd9a 11375 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 11376
7556890b
RS
11377 modified_left = f->output_data.x->left_pos;
11378 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
11379#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
11380 this seems to be unnecessary and incorrect. rms, 4/17/97. */
11381 /* It is a mystery why we need to add the border_width here
11382 when the frame is already visible, but experiment says we do. */
aa3ff7c9 11383 if (change_gravity != 0)
4a4cbdd5 11384 {
7556890b
RS
11385 modified_left += f->output_data.x->border_width;
11386 modified_top += f->output_data.x->border_width;
4a4cbdd5 11387 }
e73ec6fa 11388#endif
4a4cbdd5 11389
3afe33e7 11390#ifdef USE_X_TOOLKIT
7556890b 11391 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 11392 modified_left, modified_top);
3afe33e7 11393#else /* not USE_X_TOOLKIT */
334208b7 11394 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 11395 modified_left, modified_top);
3afe33e7 11396#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11397 UNBLOCK_INPUT;
11398}
11399
bc20ebbf
FP
11400/* Call this to change the size of frame F's x-window.
11401 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
11402 for this size change and subsequent size changes.
11403 Otherwise we leave the window gravity unchanged. */
dc6f92b8 11404
dfcf069d 11405void
bc20ebbf 11406x_set_window_size (f, change_gravity, cols, rows)
f676886a 11407 struct frame *f;
bc20ebbf 11408 int change_gravity;
b1c884c3 11409 int cols, rows;
dc6f92b8 11410{
06a2c219 11411#ifndef USE_X_TOOLKIT
dc6f92b8 11412 int pixelwidth, pixelheight;
06a2c219 11413#endif
dc6f92b8 11414
80fd1fe2 11415 BLOCK_INPUT;
aee9a898
RS
11416
11417#ifdef USE_X_TOOLKIT
3a20653d
RS
11418 {
11419 /* The x and y position of the widget is clobbered by the
11420 call to XtSetValues within EmacsFrameSetCharSize.
11421 This is a real kludge, but I don't understand Xt so I can't
11422 figure out a correct fix. Can anyone else tell me? -- rms. */
7556890b
RS
11423 int xpos = f->output_data.x->widget->core.x;
11424 int ypos = f->output_data.x->widget->core.y;
11425 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
11426 f->output_data.x->widget->core.x = xpos;
11427 f->output_data.x->widget->core.y = ypos;
3a20653d 11428 }
80fd1fe2
FP
11429
11430#else /* not USE_X_TOOLKIT */
11431
b1c884c3 11432 check_frame_size (f, &rows, &cols);
7556890b 11433 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
11434 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
11435 ? 0
11436 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 11437 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 11438 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 11439 f->output_data.x->flags_areas_extra
110859fc 11440 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
11441 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
11442 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 11443
7556890b 11444 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 11445 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 11446
334208b7
RS
11447 XSync (FRAME_X_DISPLAY (f), False);
11448 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11449 pixelwidth, pixelheight);
b1c884c3
JB
11450
11451 /* Now, strictly speaking, we can't be sure that this is accurate,
11452 but the window manager will get around to dealing with the size
11453 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
11454 ConfigureNotify event gets here.
11455
11456 We could just not bother storing any of this information here,
11457 and let the ConfigureNotify event set everything up, but that
fddd5ceb 11458 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 11459 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
11460 point in the future when the ConfigureNotify event arrives.
11461
11462 We pass 1 for DELAY since we can't run Lisp code inside of
11463 a BLOCK_INPUT. */
7d1e984f 11464 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
11465 PIXEL_WIDTH (f) = pixelwidth;
11466 PIXEL_HEIGHT (f) = pixelheight;
11467
aee9a898
RS
11468 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
11469 receive in the ConfigureNotify event; if we get what we asked
11470 for, then the event won't cause the screen to become garbaged, so
11471 we have to make sure to do it here. */
11472 SET_FRAME_GARBAGED (f);
11473
11474 XFlush (FRAME_X_DISPLAY (f));
11475
11476#endif /* not USE_X_TOOLKIT */
11477
4d73d038 11478 /* If cursor was outside the new size, mark it as off. */
06a2c219 11479 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 11480
aee9a898
RS
11481 /* Clear out any recollection of where the mouse highlighting was,
11482 since it might be in a place that's outside the new frame size.
11483 Actually checking whether it is outside is a pain in the neck,
11484 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 11485 cancel_mouse_face (f);
dbc4e1c1 11486
dc6f92b8
JB
11487 UNBLOCK_INPUT;
11488}
dc6f92b8 11489\f
d047c4eb 11490/* Mouse warping. */
dc6f92b8 11491
9b378208 11492void
f676886a
JB
11493x_set_mouse_position (f, x, y)
11494 struct frame *f;
dc6f92b8
JB
11495 int x, y;
11496{
11497 int pix_x, pix_y;
11498
7556890b
RS
11499 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
11500 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
11501
11502 if (pix_x < 0) pix_x = 0;
11503 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
11504
11505 if (pix_y < 0) pix_y = 0;
11506 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
11507
11508 BLOCK_INPUT;
dc6f92b8 11509
334208b7
RS
11510 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11511 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
11512 UNBLOCK_INPUT;
11513}
11514
9b378208
RS
11515/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
11516
11517void
11518x_set_mouse_pixel_position (f, pix_x, pix_y)
11519 struct frame *f;
11520 int pix_x, pix_y;
11521{
11522 BLOCK_INPUT;
11523
334208b7
RS
11524 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11525 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
11526 UNBLOCK_INPUT;
11527}
d047c4eb
KH
11528\f
11529/* focus shifting, raising and lowering. */
9b378208 11530
dfcf069d 11531void
f676886a
JB
11532x_focus_on_frame (f)
11533 struct frame *f;
dc6f92b8 11534{
1fb20991 11535#if 0 /* This proves to be unpleasant. */
f676886a 11536 x_raise_frame (f);
1fb20991 11537#endif
6d4238f3
JB
11538#if 0
11539 /* I don't think that the ICCCM allows programs to do things like this
11540 without the interaction of the window manager. Whatever you end up
f676886a 11541 doing with this code, do it to x_unfocus_frame too. */
334208b7 11542 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 11543 RevertToPointerRoot, CurrentTime);
c118dd06 11544#endif /* ! 0 */
dc6f92b8
JB
11545}
11546
dfcf069d 11547void
f676886a
JB
11548x_unfocus_frame (f)
11549 struct frame *f;
dc6f92b8 11550{
6d4238f3 11551#if 0
f676886a 11552 /* Look at the remarks in x_focus_on_frame. */
0f941935 11553 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 11554 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 11555 RevertToPointerRoot, CurrentTime);
c118dd06 11556#endif /* ! 0 */
dc6f92b8
JB
11557}
11558
f676886a 11559/* Raise frame F. */
dc6f92b8 11560
dfcf069d 11561void
f676886a
JB
11562x_raise_frame (f)
11563 struct frame *f;
dc6f92b8 11564{
3a88c238 11565 if (f->async_visible)
dc6f92b8
JB
11566 {
11567 BLOCK_INPUT;
3afe33e7 11568#ifdef USE_X_TOOLKIT
7556890b 11569 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11570#else /* not USE_X_TOOLKIT */
334208b7 11571 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11572#endif /* not USE_X_TOOLKIT */
334208b7 11573 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11574 UNBLOCK_INPUT;
11575 }
11576}
11577
f676886a 11578/* Lower frame F. */
dc6f92b8 11579
dfcf069d 11580void
f676886a
JB
11581x_lower_frame (f)
11582 struct frame *f;
dc6f92b8 11583{
3a88c238 11584 if (f->async_visible)
dc6f92b8
JB
11585 {
11586 BLOCK_INPUT;
3afe33e7 11587#ifdef USE_X_TOOLKIT
7556890b 11588 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 11589#else /* not USE_X_TOOLKIT */
334208b7 11590 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11591#endif /* not USE_X_TOOLKIT */
334208b7 11592 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
11593 UNBLOCK_INPUT;
11594 }
11595}
11596
dbc4e1c1 11597static void
6b0442dc 11598XTframe_raise_lower (f, raise_flag)
dbc4e1c1 11599 FRAME_PTR f;
6b0442dc 11600 int raise_flag;
dbc4e1c1 11601{
6b0442dc 11602 if (raise_flag)
dbc4e1c1
JB
11603 x_raise_frame (f);
11604 else
11605 x_lower_frame (f);
11606}
d047c4eb
KH
11607\f
11608/* Change of visibility. */
dc6f92b8 11609
9382638d
KH
11610/* This tries to wait until the frame is really visible.
11611 However, if the window manager asks the user where to position
11612 the frame, this will return before the user finishes doing that.
11613 The frame will not actually be visible at that time,
11614 but it will become visible later when the window manager
11615 finishes with it. */
11616
dfcf069d 11617void
f676886a
JB
11618x_make_frame_visible (f)
11619 struct frame *f;
dc6f92b8 11620{
990ba854 11621 Lisp_Object type;
1aa6072f 11622 int original_top, original_left;
dc6f92b8 11623
dc6f92b8 11624 BLOCK_INPUT;
dc6f92b8 11625
990ba854
RS
11626 type = x_icon_type (f);
11627 if (!NILP (type))
11628 x_bitmap_icon (f, type);
bdcd49ba 11629
f676886a 11630 if (! FRAME_VISIBLE_P (f))
90e65f07 11631 {
1aa6072f
RS
11632 /* We test FRAME_GARBAGED_P here to make sure we don't
11633 call x_set_offset a second time
11634 if we get to x_make_frame_visible a second time
11635 before the window gets really visible. */
11636 if (! FRAME_ICONIFIED_P (f)
11637 && ! f->output_data.x->asked_for_visible)
11638 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
11639
11640 f->output_data.x->asked_for_visible = 1;
11641
90e65f07 11642 if (! EQ (Vx_no_window_manager, Qt))
f676886a 11643 x_wm_set_window_state (f, NormalState);
3afe33e7 11644#ifdef USE_X_TOOLKIT
d7a38a2e 11645 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11646 XtMapWidget (f->output_data.x->widget);
3afe33e7 11647#else /* not USE_X_TOOLKIT */
7f9c7f94 11648 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 11649#endif /* not USE_X_TOOLKIT */
0134a210
RS
11650#if 0 /* This seems to bring back scroll bars in the wrong places
11651 if the window configuration has changed. They seem
11652 to come back ok without this. */
ab648270 11653 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 11654 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 11655#endif
90e65f07 11656 }
dc6f92b8 11657
334208b7 11658 XFlush (FRAME_X_DISPLAY (f));
90e65f07 11659
0dacf791
RS
11660 /* Synchronize to ensure Emacs knows the frame is visible
11661 before we do anything else. We do this loop with input not blocked
11662 so that incoming events are handled. */
11663 {
11664 Lisp_Object frame;
12ce2351 11665 int count;
28c01ffe
RS
11666 /* This must be before UNBLOCK_INPUT
11667 since events that arrive in response to the actions above
11668 will set it when they are handled. */
11669 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
11670
11671 original_left = f->output_data.x->left_pos;
11672 original_top = f->output_data.x->top_pos;
c0a04927
RS
11673
11674 /* This must come after we set COUNT. */
11675 UNBLOCK_INPUT;
11676
2745e6c4 11677 /* We unblock here so that arriving X events are processed. */
1aa6072f 11678
dcb07ae9
RS
11679 /* Now move the window back to where it was "supposed to be".
11680 But don't do it if the gravity is negative.
11681 When the gravity is negative, this uses a position
28c01ffe
RS
11682 that is 3 pixels too low. Perhaps that's really the border width.
11683
11684 Don't do this if the window has never been visible before,
11685 because the window manager may choose the position
11686 and we don't want to override it. */
1aa6072f 11687
4d3f5d9a 11688 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 11689 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 11690 && previously_visible)
1aa6072f 11691 {
2745e6c4
RS
11692 Drawable rootw;
11693 int x, y;
11694 unsigned int width, height, border, depth;
06a2c219 11695
1aa6072f 11696 BLOCK_INPUT;
9829ddba 11697
06a2c219
GM
11698 /* On some window managers (such as FVWM) moving an existing
11699 window, even to the same place, causes the window manager
11700 to introduce an offset. This can cause the window to move
11701 to an unexpected location. Check the geometry (a little
11702 slow here) and then verify that the window is in the right
11703 place. If the window is not in the right place, move it
11704 there, and take the potential window manager hit. */
2745e6c4
RS
11705 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11706 &rootw, &x, &y, &width, &height, &border, &depth);
11707
11708 if (original_left != x || original_top != y)
11709 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11710 original_left, original_top);
11711
1aa6072f
RS
11712 UNBLOCK_INPUT;
11713 }
9829ddba 11714
e0c1aef2 11715 XSETFRAME (frame, f);
c0a04927 11716
12ce2351
GM
11717 /* Wait until the frame is visible. Process X events until a
11718 MapNotify event has been seen, or until we think we won't get a
11719 MapNotify at all.. */
11720 for (count = input_signal_count + 10;
11721 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 11722 {
12ce2351 11723 /* Force processing of queued events. */
334208b7 11724 x_sync (f);
12ce2351
GM
11725
11726 /* Machines that do polling rather than SIGIO have been
11727 observed to go into a busy-wait here. So we'll fake an
11728 alarm signal to let the handler know that there's something
11729 to be read. We used to raise a real alarm, but it seems
11730 that the handler isn't always enabled here. This is
11731 probably a bug. */
8b2f8d4e 11732 if (input_polling_used ())
3b2fa4e6 11733 {
12ce2351
GM
11734 /* It could be confusing if a real alarm arrives while
11735 processing the fake one. Turn it off and let the
11736 handler reset it. */
3e71d8f2 11737 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
11738 int old_poll_suppress_count = poll_suppress_count;
11739 poll_suppress_count = 1;
11740 poll_for_input_1 ();
11741 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 11742 }
12ce2351
GM
11743
11744 /* See if a MapNotify event has been processed. */
11745 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 11746 }
0dacf791 11747 }
dc6f92b8
JB
11748}
11749
06a2c219 11750/* Change from mapped state to withdrawn state. */
dc6f92b8 11751
d047c4eb
KH
11752/* Make the frame visible (mapped and not iconified). */
11753
dfcf069d 11754void
f676886a
JB
11755x_make_frame_invisible (f)
11756 struct frame *f;
dc6f92b8 11757{
546e6d5b
RS
11758 Window window;
11759
11760#ifdef USE_X_TOOLKIT
11761 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 11762 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
11763#else /* not USE_X_TOOLKIT */
11764 window = FRAME_X_WINDOW (f);
11765#endif /* not USE_X_TOOLKIT */
dc6f92b8 11766
9319ae23 11767 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11768 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11769 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11770
5627c40e 11771#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 11772 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 11773 return;
5627c40e 11774#endif
dc6f92b8
JB
11775
11776 BLOCK_INPUT;
c118dd06 11777
af31d76f
RS
11778 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
11779 that the current position of the window is user-specified, rather than
11780 program-specified, so that when the window is mapped again, it will be
11781 placed at the same location, without forcing the user to position it
11782 by hand again (they have already done that once for this window.) */
c32cdd9a 11783 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 11784
c118dd06
JB
11785#ifdef HAVE_X11R4
11786
334208b7
RS
11787 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
11788 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
11789 {
11790 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11791 error ("Can't notify window manager of window withdrawal");
c118dd06 11792 }
c118dd06 11793#else /* ! defined (HAVE_X11R4) */
16bd92ea 11794
c118dd06 11795 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
11796 if (! EQ (Vx_no_window_manager, Qt))
11797 {
16bd92ea 11798 XEvent unmap;
dc6f92b8 11799
16bd92ea 11800 unmap.xunmap.type = UnmapNotify;
546e6d5b 11801 unmap.xunmap.window = window;
334208b7 11802 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 11803 unmap.xunmap.from_configure = False;
334208b7
RS
11804 if (! XSendEvent (FRAME_X_DISPLAY (f),
11805 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 11806 False,
06a2c219 11807 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
11808 &unmap))
11809 {
11810 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11811 error ("Can't notify window manager of withdrawal");
16bd92ea 11812 }
dc6f92b8
JB
11813 }
11814
16bd92ea 11815 /* Unmap the window ourselves. Cheeky! */
334208b7 11816 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 11817#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 11818
5627c40e
RS
11819 /* We can't distinguish this from iconification
11820 just by the event that we get from the server.
11821 So we can't win using the usual strategy of letting
11822 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
11823 and synchronize with the server to make sure we agree. */
11824 f->visible = 0;
11825 FRAME_ICONIFIED_P (f) = 0;
11826 f->async_visible = 0;
11827 f->async_iconified = 0;
11828
334208b7 11829 x_sync (f);
5627c40e 11830
dc6f92b8
JB
11831 UNBLOCK_INPUT;
11832}
11833
06a2c219 11834/* Change window state from mapped to iconified. */
dc6f92b8 11835
dfcf069d 11836void
f676886a
JB
11837x_iconify_frame (f)
11838 struct frame *f;
dc6f92b8 11839{
3afe33e7 11840 int result;
990ba854 11841 Lisp_Object type;
dc6f92b8 11842
9319ae23 11843 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
11844 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
11845 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 11846
3a88c238 11847 if (f->async_iconified)
dc6f92b8
JB
11848 return;
11849
3afe33e7 11850 BLOCK_INPUT;
546e6d5b 11851
9af3143a
RS
11852 FRAME_SAMPLE_VISIBILITY (f);
11853
990ba854
RS
11854 type = x_icon_type (f);
11855 if (!NILP (type))
11856 x_bitmap_icon (f, type);
bdcd49ba
RS
11857
11858#ifdef USE_X_TOOLKIT
11859
546e6d5b
RS
11860 if (! FRAME_VISIBLE_P (f))
11861 {
11862 if (! EQ (Vx_no_window_manager, Qt))
11863 x_wm_set_window_state (f, IconicState);
11864 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 11865 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
11866 /* The server won't give us any event to indicate
11867 that an invisible frame was changed to an icon,
11868 so we have to record it here. */
11869 f->iconified = 1;
1e6bc770 11870 f->visible = 1;
9cf30a30 11871 f->async_iconified = 1;
1e6bc770 11872 f->async_visible = 0;
546e6d5b
RS
11873 UNBLOCK_INPUT;
11874 return;
11875 }
11876
334208b7 11877 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 11878 XtWindow (f->output_data.x->widget),
334208b7 11879 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
11880 UNBLOCK_INPUT;
11881
11882 if (!result)
546e6d5b 11883 error ("Can't notify window manager of iconification");
3afe33e7
RS
11884
11885 f->async_iconified = 1;
1e6bc770
RS
11886 f->async_visible = 0;
11887
8c002a25
KH
11888
11889 BLOCK_INPUT;
334208b7 11890 XFlush (FRAME_X_DISPLAY (f));
8c002a25 11891 UNBLOCK_INPUT;
3afe33e7
RS
11892#else /* not USE_X_TOOLKIT */
11893
fd13dbb2
RS
11894 /* Make sure the X server knows where the window should be positioned,
11895 in case the user deiconifies with the window manager. */
11896 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 11897 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 11898
16bd92ea
JB
11899 /* Since we don't know which revision of X we're running, we'll use both
11900 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
11901
11902 /* X11R4: send a ClientMessage to the window manager using the
11903 WM_CHANGE_STATE type. */
11904 {
11905 XEvent message;
58769bee 11906
c118dd06 11907 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 11908 message.xclient.type = ClientMessage;
334208b7 11909 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
11910 message.xclient.format = 32;
11911 message.xclient.data.l[0] = IconicState;
11912
334208b7
RS
11913 if (! XSendEvent (FRAME_X_DISPLAY (f),
11914 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
11915 False,
11916 SubstructureRedirectMask | SubstructureNotifyMask,
11917 &message))
dc6f92b8
JB
11918 {
11919 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 11920 error ("Can't notify window manager of iconification");
dc6f92b8 11921 }
16bd92ea 11922 }
dc6f92b8 11923
58769bee 11924 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
11925 IconicState. */
11926 x_wm_set_window_state (f, IconicState);
dc6f92b8 11927
a9c00105
RS
11928 if (!FRAME_VISIBLE_P (f))
11929 {
11930 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 11931 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
11932 }
11933
3a88c238 11934 f->async_iconified = 1;
1e6bc770 11935 f->async_visible = 0;
dc6f92b8 11936
334208b7 11937 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 11938 UNBLOCK_INPUT;
8c002a25 11939#endif /* not USE_X_TOOLKIT */
dc6f92b8 11940}
d047c4eb 11941\f
c0ff3fab 11942/* Destroy the X window of frame F. */
dc6f92b8 11943
dfcf069d 11944void
c0ff3fab 11945x_destroy_window (f)
f676886a 11946 struct frame *f;
dc6f92b8 11947{
7f9c7f94
RS
11948 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11949
dc6f92b8 11950 BLOCK_INPUT;
c0ff3fab 11951
6186a4a0
RS
11952 /* If a display connection is dead, don't try sending more
11953 commands to the X server. */
11954 if (dpyinfo->display != 0)
11955 {
11956 if (f->output_data.x->icon_desc != 0)
11957 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
31f41daf 11958#ifdef HAVE_X_I18N
f5d11644
GM
11959 if (FRAME_XIC (f))
11960 free_frame_xic (f);
31f41daf 11961#endif
6186a4a0 11962 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->window_desc);
3afe33e7 11963#ifdef USE_X_TOOLKIT
06a2c219
GM
11964 if (f->output_data.x->widget)
11965 XtDestroyWidget (f->output_data.x->widget);
6186a4a0 11966 free_frame_menubar (f);
3afe33e7
RS
11967#endif /* USE_X_TOOLKIT */
11968
3e71d8f2
GM
11969 unload_color (f, f->output_data.x->foreground_pixel);
11970 unload_color (f, f->output_data.x->background_pixel);
11971 unload_color (f, f->output_data.x->cursor_pixel);
11972 unload_color (f, f->output_data.x->cursor_foreground_pixel);
11973 unload_color (f, f->output_data.x->border_pixel);
11974 unload_color (f, f->output_data.x->mouse_pixel);
11975 if (f->output_data.x->scroll_bar_background_pixel != -1)
11976 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
11977 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
11978 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
11979 if (f->output_data.x->white_relief.allocated_p)
11980 unload_color (f, f->output_data.x->white_relief.pixel);
11981 if (f->output_data.x->black_relief.allocated_p)
11982 unload_color (f, f->output_data.x->black_relief.pixel);
11983
6186a4a0
RS
11984 free_frame_faces (f);
11985 XFlush (FRAME_X_DISPLAY (f));
11986 }
dc6f92b8 11987
df89d8a4 11988 if (f->output_data.x->saved_menu_event)
06a2c219 11989 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 11990
7556890b
RS
11991 xfree (f->output_data.x);
11992 f->output_data.x = 0;
0f941935
KH
11993 if (f == dpyinfo->x_focus_frame)
11994 dpyinfo->x_focus_frame = 0;
11995 if (f == dpyinfo->x_focus_event_frame)
11996 dpyinfo->x_focus_event_frame = 0;
11997 if (f == dpyinfo->x_highlight_frame)
11998 dpyinfo->x_highlight_frame = 0;
c0ff3fab 11999
7f9c7f94
RS
12000 dpyinfo->reference_count--;
12001
12002 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 12003 {
7f9c7f94
RS
12004 dpyinfo->mouse_face_beg_row
12005 = dpyinfo->mouse_face_beg_col = -1;
12006 dpyinfo->mouse_face_end_row
12007 = dpyinfo->mouse_face_end_col = -1;
12008 dpyinfo->mouse_face_window = Qnil;
21323706
RS
12009 dpyinfo->mouse_face_deferred_gc = 0;
12010 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 12011 }
0134a210 12012
c0ff3fab 12013 UNBLOCK_INPUT;
dc6f92b8
JB
12014}
12015\f
f451eb13
JB
12016/* Setting window manager hints. */
12017
af31d76f
RS
12018/* Set the normal size hints for the window manager, for frame F.
12019 FLAGS is the flags word to use--or 0 meaning preserve the flags
12020 that the window now has.
12021 If USER_POSITION is nonzero, we set the USPosition
12022 flag (this is useful when FLAGS is 0). */
6dba1858 12023
dfcf069d 12024void
af31d76f 12025x_wm_set_size_hint (f, flags, user_position)
f676886a 12026 struct frame *f;
af31d76f
RS
12027 long flags;
12028 int user_position;
dc6f92b8
JB
12029{
12030 XSizeHints size_hints;
3afe33e7
RS
12031
12032#ifdef USE_X_TOOLKIT
7e4f2521
FP
12033 Arg al[2];
12034 int ac = 0;
12035 Dimension widget_width, widget_height;
7556890b 12036 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 12037#else /* not USE_X_TOOLKIT */
c118dd06 12038 Window window = FRAME_X_WINDOW (f);
3afe33e7 12039#endif /* not USE_X_TOOLKIT */
dc6f92b8 12040
b72a58fd
RS
12041 /* Setting PMaxSize caused various problems. */
12042 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 12043
7556890b
RS
12044 size_hints.x = f->output_data.x->left_pos;
12045 size_hints.y = f->output_data.x->top_pos;
7553a6b7 12046
7e4f2521
FP
12047#ifdef USE_X_TOOLKIT
12048 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
12049 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 12050 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
12051 size_hints.height = widget_height;
12052 size_hints.width = widget_width;
12053#else /* not USE_X_TOOLKIT */
f676886a
JB
12054 size_hints.height = PIXEL_HEIGHT (f);
12055 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 12056#endif /* not USE_X_TOOLKIT */
7553a6b7 12057
7556890b
RS
12058 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
12059 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
12060 size_hints.max_width
12061 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
12062 size_hints.max_height
12063 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 12064
d067ea8b
KH
12065 /* Calculate the base and minimum sizes.
12066
12067 (When we use the X toolkit, we don't do it here.
12068 Instead we copy the values that the widgets are using, below.) */
12069#ifndef USE_X_TOOLKIT
b1c884c3 12070 {
b0342f17 12071 int base_width, base_height;
0134a210 12072 int min_rows = 0, min_cols = 0;
b0342f17 12073
f451eb13
JB
12074 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
12075 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 12076
0134a210 12077 check_frame_size (f, &min_rows, &min_cols);
b0342f17 12078
0134a210
RS
12079 /* The window manager uses the base width hints to calculate the
12080 current number of rows and columns in the frame while
12081 resizing; min_width and min_height aren't useful for this
12082 purpose, since they might not give the dimensions for a
12083 zero-row, zero-column frame.
58769bee 12084
0134a210
RS
12085 We use the base_width and base_height members if we have
12086 them; otherwise, we set the min_width and min_height members
12087 to the size for a zero x zero frame. */
b0342f17
JB
12088
12089#ifdef HAVE_X11R4
0134a210
RS
12090 size_hints.flags |= PBaseSize;
12091 size_hints.base_width = base_width;
12092 size_hints.base_height = base_height;
12093 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
12094 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 12095#else
0134a210
RS
12096 size_hints.min_width = base_width;
12097 size_hints.min_height = base_height;
b0342f17 12098#endif
b1c884c3 12099 }
dc6f92b8 12100
d067ea8b 12101 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 12102 if (flags)
dc6f92b8 12103 {
d067ea8b
KH
12104 size_hints.flags |= flags;
12105 goto no_read;
12106 }
12107#endif /* not USE_X_TOOLKIT */
12108
12109 {
12110 XSizeHints hints; /* Sometimes I hate X Windows... */
12111 long supplied_return;
12112 int value;
af31d76f
RS
12113
12114#ifdef HAVE_X11R4
d067ea8b
KH
12115 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
12116 &supplied_return);
af31d76f 12117#else
d067ea8b 12118 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 12119#endif
58769bee 12120
d067ea8b
KH
12121#ifdef USE_X_TOOLKIT
12122 size_hints.base_height = hints.base_height;
12123 size_hints.base_width = hints.base_width;
12124 size_hints.min_height = hints.min_height;
12125 size_hints.min_width = hints.min_width;
12126#endif
12127
12128 if (flags)
12129 size_hints.flags |= flags;
12130 else
12131 {
12132 if (value == 0)
12133 hints.flags = 0;
12134 if (hints.flags & PSize)
12135 size_hints.flags |= PSize;
12136 if (hints.flags & PPosition)
12137 size_hints.flags |= PPosition;
12138 if (hints.flags & USPosition)
12139 size_hints.flags |= USPosition;
12140 if (hints.flags & USSize)
12141 size_hints.flags |= USSize;
12142 }
12143 }
12144
06a2c219 12145#ifndef USE_X_TOOLKIT
d067ea8b 12146 no_read:
06a2c219 12147#endif
0134a210 12148
af31d76f 12149#ifdef PWinGravity
7556890b 12150 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 12151 size_hints.flags |= PWinGravity;
dc05a16b 12152
af31d76f 12153 if (user_position)
6dba1858 12154 {
af31d76f
RS
12155 size_hints.flags &= ~ PPosition;
12156 size_hints.flags |= USPosition;
6dba1858 12157 }
2554751d 12158#endif /* PWinGravity */
6dba1858 12159
b0342f17 12160#ifdef HAVE_X11R4
334208b7 12161 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12162#else
334208b7 12163 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12164#endif
dc6f92b8
JB
12165}
12166
12167/* Used for IconicState or NormalState */
06a2c219 12168
dfcf069d 12169void
f676886a
JB
12170x_wm_set_window_state (f, state)
12171 struct frame *f;
dc6f92b8
JB
12172 int state;
12173{
3afe33e7 12174#ifdef USE_X_TOOLKIT
546e6d5b
RS
12175 Arg al[1];
12176
12177 XtSetArg (al[0], XtNinitialState, state);
7556890b 12178 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 12179#else /* not USE_X_TOOLKIT */
c118dd06 12180 Window window = FRAME_X_WINDOW (f);
dc6f92b8 12181
7556890b
RS
12182 f->output_data.x->wm_hints.flags |= StateHint;
12183 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 12184
7556890b 12185 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 12186#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12187}
12188
dfcf069d 12189void
7f2ae036 12190x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 12191 struct frame *f;
7f2ae036 12192 int pixmap_id;
dc6f92b8 12193{
d2bd6bc4
RS
12194 Pixmap icon_pixmap;
12195
06a2c219 12196#ifndef USE_X_TOOLKIT
c118dd06 12197 Window window = FRAME_X_WINDOW (f);
75231bad 12198#endif
dc6f92b8 12199
7f2ae036 12200 if (pixmap_id > 0)
dbc4e1c1 12201 {
d2bd6bc4 12202 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 12203 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
12204 }
12205 else
68568555
RS
12206 {
12207 /* It seems there is no way to turn off use of an icon pixmap.
12208 The following line does it, only if no icon has yet been created,
12209 for some window managers. But with mwm it crashes.
12210 Some people say it should clear the IconPixmapHint bit in this case,
12211 but that doesn't work, and the X consortium said it isn't the
12212 right thing at all. Since there is no way to win,
12213 best to explicitly give up. */
12214#if 0
12215 f->output_data.x->wm_hints.icon_pixmap = None;
12216#else
12217 return;
12218#endif
12219 }
b1c884c3 12220
d2bd6bc4
RS
12221#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
12222
12223 {
12224 Arg al[1];
12225 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
12226 XtSetValues (f->output_data.x->widget, al, 1);
12227 }
12228
12229#else /* not USE_X_TOOLKIT */
12230
7556890b
RS
12231 f->output_data.x->wm_hints.flags |= IconPixmapHint;
12232 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
12233
12234#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12235}
12236
dfcf069d 12237void
f676886a
JB
12238x_wm_set_icon_position (f, icon_x, icon_y)
12239 struct frame *f;
dc6f92b8
JB
12240 int icon_x, icon_y;
12241{
75231bad 12242#ifdef USE_X_TOOLKIT
7556890b 12243 Window window = XtWindow (f->output_data.x->widget);
75231bad 12244#else
c118dd06 12245 Window window = FRAME_X_WINDOW (f);
75231bad 12246#endif
dc6f92b8 12247
7556890b
RS
12248 f->output_data.x->wm_hints.flags |= IconPositionHint;
12249 f->output_data.x->wm_hints.icon_x = icon_x;
12250 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 12251
7556890b 12252 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
12253}
12254
12255\f
06a2c219
GM
12256/***********************************************************************
12257 Fonts
12258 ***********************************************************************/
dc43ef94
KH
12259
12260/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 12261
dc43ef94
KH
12262struct font_info *
12263x_get_font_info (f, font_idx)
12264 FRAME_PTR f;
12265 int font_idx;
12266{
12267 return (FRAME_X_FONT_TABLE (f) + font_idx);
12268}
12269
12270
12271/* Return a list of names of available fonts matching PATTERN on frame
12272 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
12273 to be listed. Frame F NULL means we have not yet created any
12274 frame on X, and consult the first display in x_display_list.
12275 MAXNAMES sets a limit on how many fonts to match. */
12276
12277Lisp_Object
12278x_list_fonts (f, pattern, size, maxnames)
12279 FRAME_PTR f;
12280 Lisp_Object pattern;
12281 int size;
12282 int maxnames;
12283{
06a2c219
GM
12284 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
12285 Lisp_Object tem, second_best;
dc43ef94 12286 Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
09c6077f 12287 int try_XLoadQueryFont = 0;
53ca4657 12288 int count;
dc43ef94 12289
6b0efe73 12290 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
12291 if (NILP (patterns))
12292 patterns = Fcons (pattern, Qnil);
81ba44e5 12293
09c6077f
KH
12294 if (maxnames == 1 && !size)
12295 /* We can return any single font matching PATTERN. */
12296 try_XLoadQueryFont = 1;
9a32686f 12297
8e713be6 12298 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 12299 {
dc43ef94 12300 int num_fonts;
3e71d8f2 12301 char **names = NULL;
dc43ef94 12302
8e713be6 12303 pattern = XCAR (patterns);
536f4067
RS
12304 /* See if we cached the result for this particular query.
12305 The cache is an alist of the form:
12306 (((PATTERN . MAXNAMES) (FONTNAME . WIDTH) ...) ...)
12307 */
8e713be6 12308 if (f && (tem = XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element),
b5210ea7
KH
12309 key = Fcons (pattern, make_number (maxnames)),
12310 !NILP (list = Fassoc (key, tem))))
12311 {
12312 list = Fcdr_safe (list);
12313 /* We have a cashed list. Don't have to get the list again. */
12314 goto label_cached;
12315 }
12316
12317 /* At first, put PATTERN in the cache. */
09c6077f 12318
dc43ef94 12319 BLOCK_INPUT;
17d85edc
KH
12320 count = x_catch_errors (dpy);
12321
09c6077f
KH
12322 if (try_XLoadQueryFont)
12323 {
12324 XFontStruct *font;
12325 unsigned long value;
12326
12327 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
12328 if (x_had_errors_p (dpy))
12329 {
12330 /* This error is perhaps due to insufficient memory on X
12331 server. Let's just ignore it. */
12332 font = NULL;
12333 x_clear_errors (dpy);
12334 }
12335
09c6077f
KH
12336 if (font
12337 && XGetFontProperty (font, XA_FONT, &value))
12338 {
12339 char *name = (char *) XGetAtomName (dpy, (Atom) value);
12340 int len = strlen (name);
01c752b5 12341 char *tmp;
09c6077f 12342
6f6512e8
KH
12343 /* If DXPC (a Differential X Protocol Compressor)
12344 Ver.3.7 is running, XGetAtomName will return null
12345 string. We must avoid such a name. */
12346 if (len == 0)
12347 try_XLoadQueryFont = 0;
12348 else
12349 {
12350 num_fonts = 1;
12351 names = (char **) alloca (sizeof (char *));
12352 /* Some systems only allow alloca assigned to a
12353 simple var. */
12354 tmp = (char *) alloca (len + 1); names[0] = tmp;
12355 bcopy (name, names[0], len + 1);
12356 XFree (name);
12357 }
09c6077f
KH
12358 }
12359 else
12360 try_XLoadQueryFont = 0;
a083fd23
RS
12361
12362 if (font)
12363 XFreeFont (dpy, font);
09c6077f
KH
12364 }
12365
12366 if (!try_XLoadQueryFont)
17d85edc
KH
12367 {
12368 /* We try at least 10 fonts because XListFonts will return
12369 auto-scaled fonts at the head. */
12370 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
12371 &num_fonts);
12372 if (x_had_errors_p (dpy))
12373 {
12374 /* This error is perhaps due to insufficient memory on X
12375 server. Let's just ignore it. */
12376 names = NULL;
12377 x_clear_errors (dpy);
12378 }
12379 }
12380
12381 x_uncatch_errors (dpy, count);
dc43ef94
KH
12382 UNBLOCK_INPUT;
12383
12384 if (names)
12385 {
12386 int i;
dc43ef94
KH
12387
12388 /* Make a list of all the fonts we got back.
12389 Store that in the font cache for the display. */
12390 for (i = 0; i < num_fonts; i++)
12391 {
06a2c219 12392 int width = 0;
dc43ef94 12393 char *p = names[i];
06a2c219
GM
12394 int average_width = -1, dashes = 0;
12395
dc43ef94 12396 /* Count the number of dashes in NAMES[I]. If there are
b5210ea7
KH
12397 14 dashes, and the field value following 12th dash
12398 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
12399 is usually too ugly to be used for editing. Let's
12400 ignore it. */
dc43ef94
KH
12401 while (*p)
12402 if (*p++ == '-')
12403 {
12404 dashes++;
12405 if (dashes == 7) /* PIXEL_SIZE field */
12406 width = atoi (p);
12407 else if (dashes == 12) /* AVERAGE_WIDTH field */
12408 average_width = atoi (p);
12409 }
12410 if (dashes < 14 || average_width != 0)
12411 {
12412 tem = build_string (names[i]);
12413 if (NILP (Fassoc (tem, list)))
12414 {
12415 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
12416 && ((fast_c_string_match_ignore_case
12417 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
12418 >= 0))
12419 /* We can set the value of PIXEL_SIZE to the
b5210ea7 12420 width of this font. */
dc43ef94
KH
12421 list = Fcons (Fcons (tem, make_number (width)), list);
12422 else
12423 /* For the moment, width is not known. */
12424 list = Fcons (Fcons (tem, Qnil), list);
12425 }
12426 }
12427 }
09c6077f
KH
12428 if (!try_XLoadQueryFont)
12429 XFreeFontNames (names);
dc43ef94
KH
12430 }
12431
b5210ea7 12432 /* Now store the result in the cache. */
dc43ef94 12433 if (f != NULL)
8e713be6 12434 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element)
dc43ef94 12435 = Fcons (Fcons (key, list),
8e713be6 12436 XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
dc43ef94 12437
b5210ea7
KH
12438 label_cached:
12439 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 12440
b5210ea7
KH
12441 newlist = second_best = Qnil;
12442 /* Make a list of the fonts that have the right width. */
8e713be6 12443 for (; CONSP (list); list = XCDR (list))
b5210ea7 12444 {
536f4067
RS
12445 int found_size;
12446
8e713be6 12447 tem = XCAR (list);
dc43ef94 12448
8e713be6 12449 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
12450 continue;
12451 if (!size)
12452 {
8e713be6 12453 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
12454 continue;
12455 }
dc43ef94 12456
8e713be6 12457 if (!INTEGERP (XCDR (tem)))
dc43ef94 12458 {
b5210ea7
KH
12459 /* Since we have not yet known the size of this font, we
12460 must try slow function call XLoadQueryFont. */
dc43ef94
KH
12461 XFontStruct *thisinfo;
12462
12463 BLOCK_INPUT;
17d85edc 12464 count = x_catch_errors (dpy);
dc43ef94 12465 thisinfo = XLoadQueryFont (dpy,
8e713be6 12466 XSTRING (XCAR (tem))->data);
17d85edc
KH
12467 if (x_had_errors_p (dpy))
12468 {
12469 /* This error is perhaps due to insufficient memory on X
12470 server. Let's just ignore it. */
12471 thisinfo = NULL;
12472 x_clear_errors (dpy);
12473 }
12474 x_uncatch_errors (dpy, count);
dc43ef94
KH
12475 UNBLOCK_INPUT;
12476
12477 if (thisinfo)
12478 {
8e713be6 12479 XCDR (tem)
536f4067
RS
12480 = (thisinfo->min_bounds.width == 0
12481 ? make_number (0)
12482 : make_number (thisinfo->max_bounds.width));
dc43ef94
KH
12483 XFreeFont (dpy, thisinfo);
12484 }
12485 else
b5210ea7 12486 /* For unknown reason, the previous call of XListFont had
06a2c219 12487 returned a font which can't be opened. Record the size
b5210ea7 12488 as 0 not to try to open it again. */
8e713be6 12489 XCDR (tem) = make_number (0);
dc43ef94 12490 }
536f4067 12491
8e713be6 12492 found_size = XINT (XCDR (tem));
536f4067 12493 if (found_size == size)
8e713be6 12494 newlist = Fcons (XCAR (tem), newlist);
536f4067 12495 else if (found_size > 0)
b5210ea7 12496 {
536f4067 12497 if (NILP (second_best))
b5210ea7 12498 second_best = tem;
536f4067
RS
12499 else if (found_size < size)
12500 {
8e713be6
KR
12501 if (XINT (XCDR (second_best)) > size
12502 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
12503 second_best = tem;
12504 }
12505 else
12506 {
8e713be6
KR
12507 if (XINT (XCDR (second_best)) > size
12508 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
12509 second_best = tem;
12510 }
b5210ea7
KH
12511 }
12512 }
12513 if (!NILP (newlist))
12514 break;
12515 else if (!NILP (second_best))
12516 {
8e713be6 12517 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 12518 break;
dc43ef94 12519 }
dc43ef94
KH
12520 }
12521
12522 return newlist;
12523}
12524
06a2c219
GM
12525
12526#if GLYPH_DEBUG
12527
12528/* Check that FONT is valid on frame F. It is if it can be found in F's
12529 font table. */
12530
12531static void
12532x_check_font (f, font)
12533 struct frame *f;
12534 XFontStruct *font;
12535{
12536 int i;
12537 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12538
12539 xassert (font != NULL);
12540
12541 for (i = 0; i < dpyinfo->n_fonts; i++)
12542 if (dpyinfo->font_table[i].name
12543 && font == dpyinfo->font_table[i].font)
12544 break;
12545
12546 xassert (i < dpyinfo->n_fonts);
12547}
12548
12549#endif /* GLYPH_DEBUG != 0 */
12550
12551/* Set *W to the minimum width, *H to the minimum font height of FONT.
12552 Note: There are (broken) X fonts out there with invalid XFontStruct
12553 min_bounds contents. For example, handa@etl.go.jp reports that
12554 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
12555 have font->min_bounds.width == 0. */
12556
12557static INLINE void
12558x_font_min_bounds (font, w, h)
12559 XFontStruct *font;
12560 int *w, *h;
12561{
12562 *h = FONT_HEIGHT (font);
12563 *w = font->min_bounds.width;
12564
12565 /* Try to handle the case where FONT->min_bounds has invalid
12566 contents. Since the only font known to have invalid min_bounds
12567 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
12568 if (*w <= 0)
12569 *w = font->max_bounds.width;
12570}
12571
12572
12573/* Compute the smallest character width and smallest font height over
12574 all fonts available on frame F. Set the members smallest_char_width
12575 and smallest_font_height in F's x_display_info structure to
12576 the values computed. Value is non-zero if smallest_font_height or
12577 smallest_char_width become smaller than they were before. */
12578
12579static int
12580x_compute_min_glyph_bounds (f)
12581 struct frame *f;
12582{
12583 int i;
12584 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12585 XFontStruct *font;
12586 int old_width = dpyinfo->smallest_char_width;
12587 int old_height = dpyinfo->smallest_font_height;
12588
12589 dpyinfo->smallest_font_height = 100000;
12590 dpyinfo->smallest_char_width = 100000;
12591
12592 for (i = 0; i < dpyinfo->n_fonts; ++i)
12593 if (dpyinfo->font_table[i].name)
12594 {
12595 struct font_info *fontp = dpyinfo->font_table + i;
12596 int w, h;
12597
12598 font = (XFontStruct *) fontp->font;
12599 xassert (font != (XFontStruct *) ~0);
12600 x_font_min_bounds (font, &w, &h);
12601
12602 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
12603 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
12604 }
12605
12606 xassert (dpyinfo->smallest_char_width > 0
12607 && dpyinfo->smallest_font_height > 0);
12608
12609 return (dpyinfo->n_fonts == 1
12610 || dpyinfo->smallest_char_width < old_width
12611 || dpyinfo->smallest_font_height < old_height);
12612}
12613
12614
dc43ef94
KH
12615/* Load font named FONTNAME of the size SIZE for frame F, and return a
12616 pointer to the structure font_info while allocating it dynamically.
12617 If SIZE is 0, load any size of font.
12618 If loading is failed, return NULL. */
12619
12620struct font_info *
12621x_load_font (f, fontname, size)
12622 struct frame *f;
12623 register char *fontname;
12624 int size;
12625{
12626 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12627 Lisp_Object font_names;
d645aaa4 12628 int count;
dc43ef94
KH
12629
12630 /* Get a list of all the fonts that match this name. Once we
12631 have a list of matching fonts, we compare them against the fonts
12632 we already have by comparing names. */
09c6077f 12633 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
12634
12635 if (!NILP (font_names))
12636 {
12637 Lisp_Object tail;
12638 int i;
12639
12640 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 12641 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
12642 if (dpyinfo->font_table[i].name
12643 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 12644 XSTRING (XCAR (tail))->data)
06a2c219 12645 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 12646 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
12647 return (dpyinfo->font_table + i);
12648 }
12649
12650 /* Load the font and add it to the table. */
12651 {
12652 char *full_name;
12653 XFontStruct *font;
12654 struct font_info *fontp;
12655 unsigned long value;
06a2c219 12656 int i;
dc43ef94 12657
2da424f1
KH
12658 /* If we have found fonts by x_list_font, load one of them. If
12659 not, we still try to load a font by the name given as FONTNAME
12660 because XListFonts (called in x_list_font) of some X server has
12661 a bug of not finding a font even if the font surely exists and
12662 is loadable by XLoadQueryFont. */
e1d6d5b9 12663 if (size > 0 && !NILP (font_names))
8e713be6 12664 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
12665
12666 BLOCK_INPUT;
d645aaa4 12667 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 12668 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
12669 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12670 {
12671 /* This error is perhaps due to insufficient memory on X
12672 server. Let's just ignore it. */
12673 font = NULL;
12674 x_clear_errors (FRAME_X_DISPLAY (f));
12675 }
12676 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 12677 UNBLOCK_INPUT;
b5210ea7 12678 if (!font)
dc43ef94
KH
12679 return NULL;
12680
06a2c219
GM
12681 /* Find a free slot in the font table. */
12682 for (i = 0; i < dpyinfo->n_fonts; ++i)
12683 if (dpyinfo->font_table[i].name == NULL)
12684 break;
12685
12686 /* If no free slot found, maybe enlarge the font table. */
12687 if (i == dpyinfo->n_fonts
12688 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 12689 {
06a2c219
GM
12690 int sz;
12691 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
12692 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 12693 dpyinfo->font_table
06a2c219 12694 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
12695 }
12696
06a2c219
GM
12697 fontp = dpyinfo->font_table + i;
12698 if (i == dpyinfo->n_fonts)
12699 ++dpyinfo->n_fonts;
dc43ef94
KH
12700
12701 /* Now fill in the slots of *FONTP. */
12702 BLOCK_INPUT;
12703 fontp->font = font;
06a2c219 12704 fontp->font_idx = i;
dc43ef94
KH
12705 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
12706 bcopy (fontname, fontp->name, strlen (fontname) + 1);
12707
12708 /* Try to get the full name of FONT. Put it in FULL_NAME. */
12709 full_name = 0;
12710 if (XGetFontProperty (font, XA_FONT, &value))
12711 {
12712 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
12713 char *p = name;
12714 int dashes = 0;
12715
12716 /* Count the number of dashes in the "full name".
12717 If it is too few, this isn't really the font's full name,
12718 so don't use it.
12719 In X11R4, the fonts did not come with their canonical names
12720 stored in them. */
12721 while (*p)
12722 {
12723 if (*p == '-')
12724 dashes++;
12725 p++;
12726 }
12727
12728 if (dashes >= 13)
12729 {
12730 full_name = (char *) xmalloc (p - name + 1);
12731 bcopy (name, full_name, p - name + 1);
12732 }
12733
12734 XFree (name);
12735 }
12736
12737 if (full_name != 0)
12738 fontp->full_name = full_name;
12739 else
12740 fontp->full_name = fontp->name;
12741
12742 fontp->size = font->max_bounds.width;
d5749adb
KH
12743 fontp->height = FONT_HEIGHT (font);
12744 {
12745 /* For some font, ascent and descent in max_bounds field is
12746 larger than the above value. */
12747 int max_height = font->max_bounds.ascent + font->max_bounds.descent;
12748 if (max_height > fontp->height)
74848a96 12749 fontp->height = max_height;
d5749adb 12750 }
dc43ef94 12751
2da424f1
KH
12752 if (NILP (font_names))
12753 {
12754 /* We come here because of a bug of XListFonts mentioned at
12755 the head of this block. Let's store this information in
12756 the cache for x_list_fonts. */
12757 Lisp_Object lispy_name = build_string (fontname);
12758 Lisp_Object lispy_full_name = build_string (fontp->full_name);
12759
8e713be6 12760 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12761 = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
12762 Fcons (Fcons (lispy_full_name,
12763 make_number (fontp->size)),
12764 Qnil)),
8e713be6 12765 XCDR (dpyinfo->name_list_element));
2da424f1 12766 if (full_name)
8e713be6 12767 XCDR (dpyinfo->name_list_element)
2da424f1
KH
12768 = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
12769 Fcons (Fcons (lispy_full_name,
12770 make_number (fontp->size)),
12771 Qnil)),
8e713be6 12772 XCDR (dpyinfo->name_list_element));
2da424f1
KH
12773 }
12774
dc43ef94
KH
12775 /* The slot `encoding' specifies how to map a character
12776 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
12777 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
12778 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 12779 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 12780 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
12781 which is never used by any charset. If mapping can't be
12782 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
12783 fontp->encoding[1]
12784 = (font->max_byte1 == 0
12785 /* 1-byte font */
12786 ? (font->min_char_or_byte2 < 0x80
12787 ? (font->max_char_or_byte2 < 0x80
12788 ? 0 /* 0x20..0x7F */
8ff102bd 12789 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
12790 : 1) /* 0xA0..0xFF */
12791 /* 2-byte font */
12792 : (font->min_byte1 < 0x80
12793 ? (font->max_byte1 < 0x80
12794 ? (font->min_char_or_byte2 < 0x80
12795 ? (font->max_char_or_byte2 < 0x80
12796 ? 0 /* 0x2020..0x7F7F */
8ff102bd 12797 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 12798 : 3) /* 0x20A0..0x7FFF */
8ff102bd 12799 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
12800 : (font->min_char_or_byte2 < 0x80
12801 ? (font->max_char_or_byte2 < 0x80
12802 ? 2 /* 0xA020..0xFF7F */
8ff102bd 12803 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
12804 : 1))); /* 0xA0A0..0xFFFF */
12805
12806 fontp->baseline_offset
12807 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
12808 ? (long) value : 0);
12809 fontp->relative_compose
12810 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
12811 ? (long) value : 0);
f78798df
KH
12812 fontp->default_ascent
12813 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
12814 ? (long) value : 0);
dc43ef94 12815
06a2c219
GM
12816 /* Set global flag fonts_changed_p to non-zero if the font loaded
12817 has a character with a smaller width than any other character
12818 before, or if the font loaded has a smalle>r height than any
12819 other font loaded before. If this happens, it will make a
12820 glyph matrix reallocation necessary. */
12821 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 12822 UNBLOCK_INPUT;
dc43ef94
KH
12823 return fontp;
12824 }
12825}
12826
06a2c219
GM
12827
12828/* Return a pointer to struct font_info of a font named FONTNAME for
12829 frame F. If no such font is loaded, return NULL. */
12830
dc43ef94
KH
12831struct font_info *
12832x_query_font (f, fontname)
12833 struct frame *f;
12834 register char *fontname;
12835{
12836 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12837 int i;
12838
12839 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
12840 if (dpyinfo->font_table[i].name
12841 && (!strcmp (dpyinfo->font_table[i].name, fontname)
12842 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
12843 return (dpyinfo->font_table + i);
12844 return NULL;
12845}
12846
06a2c219
GM
12847
12848/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
12849 `encoder' of the structure. */
12850
12851void
12852x_find_ccl_program (fontp)
12853 struct font_info *fontp;
12854{
a42f54e6 12855 Lisp_Object list, elt;
a6582676 12856
8e713be6 12857 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 12858 {
8e713be6 12859 elt = XCAR (list);
a6582676 12860 if (CONSP (elt)
8e713be6
KR
12861 && STRINGP (XCAR (elt))
12862 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
a6582676 12863 >= 0))
a42f54e6
KH
12864 break;
12865 }
12866 if (! NILP (list))
12867 {
d27f8ca7
KH
12868 struct ccl_program *ccl
12869 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 12870
8e713be6 12871 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
12872 xfree (ccl);
12873 else
12874 fontp->font_encoder = ccl;
a6582676
KH
12875 }
12876}
12877
06a2c219 12878
dc43ef94 12879\f
06a2c219
GM
12880/***********************************************************************
12881 Initialization
12882 ***********************************************************************/
f451eb13 12883
3afe33e7
RS
12884#ifdef USE_X_TOOLKIT
12885static XrmOptionDescRec emacs_options[] = {
12886 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
12887 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
12888
12889 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
12890 XrmoptionSepArg, NULL},
12891 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
12892
12893 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12894 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12895 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
12896 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
12897 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
12898 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
12899 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
12900};
12901#endif /* USE_X_TOOLKIT */
12902
7a13e894
RS
12903static int x_initialized;
12904
29b38361
KH
12905#ifdef MULTI_KBOARD
12906/* Test whether two display-name strings agree up to the dot that separates
12907 the screen number from the server number. */
12908static int
12909same_x_server (name1, name2)
12910 char *name1, *name2;
12911{
12912 int seen_colon = 0;
cf591cc1
RS
12913 unsigned char *system_name = XSTRING (Vsystem_name)->data;
12914 int system_name_length = strlen (system_name);
12915 int length_until_period = 0;
12916
12917 while (system_name[length_until_period] != 0
12918 && system_name[length_until_period] != '.')
12919 length_until_period++;
12920
12921 /* Treat `unix' like an empty host name. */
12922 if (! strncmp (name1, "unix:", 5))
12923 name1 += 4;
12924 if (! strncmp (name2, "unix:", 5))
12925 name2 += 4;
12926 /* Treat this host's name like an empty host name. */
12927 if (! strncmp (name1, system_name, system_name_length)
12928 && name1[system_name_length] == ':')
12929 name1 += system_name_length;
12930 if (! strncmp (name2, system_name, system_name_length)
12931 && name2[system_name_length] == ':')
12932 name2 += system_name_length;
12933 /* Treat this host's domainless name like an empty host name. */
12934 if (! strncmp (name1, system_name, length_until_period)
12935 && name1[length_until_period] == ':')
12936 name1 += length_until_period;
12937 if (! strncmp (name2, system_name, length_until_period)
12938 && name2[length_until_period] == ':')
12939 name2 += length_until_period;
12940
29b38361
KH
12941 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
12942 {
12943 if (*name1 == ':')
12944 seen_colon++;
12945 if (seen_colon && *name1 == '.')
12946 return 1;
12947 }
12948 return (seen_colon
12949 && (*name1 == '.' || *name1 == '\0')
12950 && (*name2 == '.' || *name2 == '\0'));
12951}
12952#endif
12953
334208b7 12954struct x_display_info *
1f8255f2 12955x_term_init (display_name, xrm_option, resource_name)
334208b7 12956 Lisp_Object display_name;
1f8255f2
RS
12957 char *xrm_option;
12958 char *resource_name;
dc6f92b8 12959{
334208b7 12960 int connection;
7a13e894 12961 Display *dpy;
334208b7
RS
12962 struct x_display_info *dpyinfo;
12963 XrmDatabase xrdb;
12964
60439948
KH
12965 BLOCK_INPUT;
12966
7a13e894
RS
12967 if (!x_initialized)
12968 {
12969 x_initialize ();
12970 x_initialized = 1;
12971 }
dc6f92b8 12972
3afe33e7 12973#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
12974 /* weiner@footloose.sps.mot.com reports that this causes
12975 errors with X11R5:
12976 X protocol error: BadAtom (invalid Atom parameter)
12977 on protocol request 18skiloaf.
12978 So let's not use it until R6. */
12979#ifdef HAVE_X11XTR6
bdcd49ba
RS
12980 XtSetLanguageProc (NULL, NULL, NULL);
12981#endif
12982
7f9c7f94
RS
12983 {
12984 int argc = 0;
12985 char *argv[3];
12986
12987 argv[0] = "";
12988 argc = 1;
12989 if (xrm_option)
12990 {
12991 argv[argc++] = "-xrm";
12992 argv[argc++] = xrm_option;
12993 }
12994 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
12995 resource_name, EMACS_CLASS,
12996 emacs_options, XtNumber (emacs_options),
12997 &argc, argv);
39d8bb4d
KH
12998
12999#ifdef HAVE_X11XTR6
10537cb1 13000 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 13001 fixup_locale ();
39d8bb4d 13002#endif
7f9c7f94 13003 }
3afe33e7
RS
13004
13005#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
13006#ifdef HAVE_X11R5
13007 XSetLocaleModifiers ("");
13008#endif
7a13e894 13009 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 13010#endif /* not USE_X_TOOLKIT */
334208b7 13011
7a13e894
RS
13012 /* Detect failure. */
13013 if (dpy == 0)
60439948
KH
13014 {
13015 UNBLOCK_INPUT;
13016 return 0;
13017 }
7a13e894
RS
13018
13019 /* We have definitely succeeded. Record the new connection. */
13020
13021 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
13022
29b38361
KH
13023#ifdef MULTI_KBOARD
13024 {
13025 struct x_display_info *share;
13026 Lisp_Object tail;
13027
13028 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
13029 share = share->next, tail = XCDR (tail))
13030 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
13031 XSTRING (display_name)->data))
13032 break;
13033 if (share)
13034 dpyinfo->kboard = share->kboard;
13035 else
13036 {
13037 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13038 init_kboard (dpyinfo->kboard);
59e755be
KH
13039 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
13040 {
13041 char *vendor = ServerVendor (dpy);
9b6ed9f3 13042 UNBLOCK_INPUT;
59e755be
KH
13043 dpyinfo->kboard->Vsystem_key_alist
13044 = call1 (Qvendor_specific_keysyms,
13045 build_string (vendor ? vendor : ""));
9b6ed9f3 13046 BLOCK_INPUT;
59e755be
KH
13047 }
13048
29b38361
KH
13049 dpyinfo->kboard->next_kboard = all_kboards;
13050 all_kboards = dpyinfo->kboard;
0ad5446c
KH
13051 /* Don't let the initial kboard remain current longer than necessary.
13052 That would cause problems if a file loaded on startup tries to
06a2c219 13053 prompt in the mini-buffer. */
0ad5446c
KH
13054 if (current_kboard == initial_kboard)
13055 current_kboard = dpyinfo->kboard;
29b38361
KH
13056 }
13057 dpyinfo->kboard->reference_count++;
13058 }
b9737ad3
KH
13059#endif
13060
7a13e894
RS
13061 /* Put this display on the chain. */
13062 dpyinfo->next = x_display_list;
13063 x_display_list = dpyinfo;
13064
13065 /* Put it on x_display_name_list as well, to keep them parallel. */
13066 x_display_name_list = Fcons (Fcons (display_name, Qnil),
13067 x_display_name_list);
8e713be6 13068 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
13069
13070 dpyinfo->display = dpy;
dc6f92b8 13071
dc6f92b8 13072#if 0
7a13e894 13073 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 13074#endif /* ! 0 */
7a13e894
RS
13075
13076 dpyinfo->x_id_name
fc932ac6
RS
13077 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
13078 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
13079 + 2);
13080 sprintf (dpyinfo->x_id_name, "%s@%s",
13081 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
13082
13083 /* Figure out which modifier bits mean what. */
334208b7 13084 x_find_modifier_meanings (dpyinfo);
f451eb13 13085
ab648270 13086 /* Get the scroll bar cursor. */
7a13e894 13087 dpyinfo->vertical_scroll_bar_cursor
334208b7 13088 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 13089
334208b7
RS
13090 xrdb = x_load_resources (dpyinfo->display, xrm_option,
13091 resource_name, EMACS_CLASS);
13092#ifdef HAVE_XRMSETDATABASE
13093 XrmSetDatabase (dpyinfo->display, xrdb);
13094#else
13095 dpyinfo->display->db = xrdb;
13096#endif
547d9db8 13097 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
13098 all versions. */
13099 dpyinfo->xrdb = xrdb;
334208b7
RS
13100
13101 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
13102 DefaultScreen (dpyinfo->display));
5ff67d81 13103 select_visual (dpyinfo);
43bd1b2b 13104 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
13105 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
13106 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
13107 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
13108 dpyinfo->grabbed = 0;
13109 dpyinfo->reference_count = 0;
13110 dpyinfo->icon_bitmap_id = -1;
06a2c219 13111 dpyinfo->font_table = NULL;
7a13e894
RS
13112 dpyinfo->n_fonts = 0;
13113 dpyinfo->font_table_size = 0;
13114 dpyinfo->bitmaps = 0;
13115 dpyinfo->bitmaps_size = 0;
13116 dpyinfo->bitmaps_last = 0;
13117 dpyinfo->scratch_cursor_gc = 0;
13118 dpyinfo->mouse_face_mouse_frame = 0;
13119 dpyinfo->mouse_face_deferred_gc = 0;
13120 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
13121 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 13122 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894
RS
13123 dpyinfo->mouse_face_window = Qnil;
13124 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
13125 dpyinfo->mouse_face_defer = 0;
0f941935
KH
13126 dpyinfo->x_focus_frame = 0;
13127 dpyinfo->x_focus_event_frame = 0;
13128 dpyinfo->x_highlight_frame = 0;
06a2c219 13129 dpyinfo->image_cache = make_image_cache ();
334208b7 13130
43bd1b2b 13131 /* See if a private colormap is requested. */
5ff67d81
GM
13132 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
13133 {
13134 if (dpyinfo->visual->class == PseudoColor)
13135 {
13136 Lisp_Object value;
13137 value = display_x_get_resource (dpyinfo,
13138 build_string ("privateColormap"),
13139 build_string ("PrivateColormap"),
13140 Qnil, Qnil);
13141 if (STRINGP (value)
13142 && (!strcmp (XSTRING (value)->data, "true")
13143 || !strcmp (XSTRING (value)->data, "on")))
13144 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
13145 }
43bd1b2b 13146 }
5ff67d81
GM
13147 else
13148 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
13149 dpyinfo->visual, AllocNone);
43bd1b2b 13150
06a2c219
GM
13151 {
13152 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
13153 double pixels = DisplayHeight (dpyinfo->display, screen_number);
13154 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
13155 dpyinfo->resy = pixels * 25.4 / mm;
13156 pixels = DisplayWidth (dpyinfo->display, screen_number);
13157 mm = DisplayWidthMM (dpyinfo->display, screen_number);
13158 dpyinfo->resx = pixels * 25.4 / mm;
13159 }
13160
334208b7
RS
13161 dpyinfo->Xatom_wm_protocols
13162 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
13163 dpyinfo->Xatom_wm_take_focus
13164 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
13165 dpyinfo->Xatom_wm_save_yourself
13166 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
13167 dpyinfo->Xatom_wm_delete_window
13168 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
13169 dpyinfo->Xatom_wm_change_state
13170 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
13171 dpyinfo->Xatom_wm_configure_denied
13172 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
13173 dpyinfo->Xatom_wm_window_moved
13174 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
13175 dpyinfo->Xatom_editres
13176 = XInternAtom (dpyinfo->display, "Editres", False);
13177 dpyinfo->Xatom_CLIPBOARD
13178 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
13179 dpyinfo->Xatom_TIMESTAMP
13180 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
13181 dpyinfo->Xatom_TEXT
13182 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
13183 dpyinfo->Xatom_COMPOUND_TEXT
13184 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
13185 dpyinfo->Xatom_DELETE
13186 = XInternAtom (dpyinfo->display, "DELETE", False);
13187 dpyinfo->Xatom_MULTIPLE
13188 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
13189 dpyinfo->Xatom_INCR
13190 = XInternAtom (dpyinfo->display, "INCR", False);
13191 dpyinfo->Xatom_EMACS_TMP
13192 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
13193 dpyinfo->Xatom_TARGETS
13194 = XInternAtom (dpyinfo->display, "TARGETS", False);
13195 dpyinfo->Xatom_NULL
13196 = XInternAtom (dpyinfo->display, "NULL", False);
13197 dpyinfo->Xatom_ATOM_PAIR
13198 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
13199 /* For properties of font. */
13200 dpyinfo->Xatom_PIXEL_SIZE
13201 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
13202 dpyinfo->Xatom_MULE_BASELINE_OFFSET
13203 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
13204 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
13205 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
13206 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
13207 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 13208
06a2c219
GM
13209 /* Ghostscript support. */
13210 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
13211 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
13212
13213 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
13214 False);
13215
547d9db8
KH
13216 dpyinfo->cut_buffers_initialized = 0;
13217
334208b7
RS
13218 connection = ConnectionNumber (dpyinfo->display);
13219 dpyinfo->connection = connection;
13220
dc43ef94 13221 {
5d7cc324
RS
13222 char null_bits[1];
13223
13224 null_bits[0] = 0x00;
dc43ef94
KH
13225
13226 dpyinfo->null_pixel
13227 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13228 null_bits, 1, 1, (long) 0, (long) 0,
13229 1);
13230 }
13231
06a2c219
GM
13232 {
13233 extern int gray_bitmap_width, gray_bitmap_height;
13234 extern unsigned char *gray_bitmap_bits;
13235 dpyinfo->gray
13236 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13237 gray_bitmap_bits,
13238 gray_bitmap_width, gray_bitmap_height,
13239 (unsigned long) 1, (unsigned long) 0, 1);
13240 }
13241
f5d11644
GM
13242#ifdef HAVE_X_I18N
13243 xim_initialize (dpyinfo, resource_name);
13244#endif
13245
87485d6f
MW
13246#ifdef subprocesses
13247 /* This is only needed for distinguishing keyboard and process input. */
334208b7 13248 if (connection != 0)
7a13e894 13249 add_keyboard_wait_descriptor (connection);
87485d6f 13250#endif
6d4238f3 13251
041b69ac 13252#ifndef F_SETOWN_BUG
dc6f92b8 13253#ifdef F_SETOWN
dc6f92b8 13254#ifdef F_SETOWN_SOCK_NEG
61c3ce62 13255 /* stdin is a socket here */
334208b7 13256 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 13257#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 13258 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
13259#endif /* ! defined (F_SETOWN_SOCK_NEG) */
13260#endif /* ! defined (F_SETOWN) */
041b69ac 13261#endif /* F_SETOWN_BUG */
dc6f92b8
JB
13262
13263#ifdef SIGIO
eee20f6a
KH
13264 if (interrupt_input)
13265 init_sigio (connection);
c118dd06 13266#endif /* ! defined (SIGIO) */
dc6f92b8 13267
51b592fb 13268#ifdef USE_LUCID
f8c39f51 13269#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
13270 /* Make sure that we have a valid font for dialog boxes
13271 so that Xt does not crash. */
13272 {
13273 Display *dpy = dpyinfo->display;
13274 XrmValue d, fr, to;
13275 Font font;
e99db5a1 13276 int count;
51b592fb
RS
13277
13278 d.addr = (XPointer)&dpy;
13279 d.size = sizeof (Display *);
13280 fr.addr = XtDefaultFont;
13281 fr.size = sizeof (XtDefaultFont);
13282 to.size = sizeof (Font *);
13283 to.addr = (XPointer)&font;
e99db5a1 13284 count = x_catch_errors (dpy);
51b592fb
RS
13285 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
13286 abort ();
13287 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
13288 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 13289 x_uncatch_errors (dpy, count);
51b592fb
RS
13290 }
13291#endif
f8c39f51 13292#endif
51b592fb 13293
34e23e5a
GM
13294 /* See if we should run in synchronous mode. This is useful
13295 for debugging X code. */
13296 {
13297 Lisp_Object value;
13298 value = display_x_get_resource (dpyinfo,
13299 build_string ("synchronous"),
13300 build_string ("Synchronous"),
13301 Qnil, Qnil);
13302 if (STRINGP (value)
13303 && (!strcmp (XSTRING (value)->data, "true")
13304 || !strcmp (XSTRING (value)->data, "on")))
13305 XSynchronize (dpyinfo->display, True);
13306 }
13307
60439948
KH
13308 UNBLOCK_INPUT;
13309
7a13e894
RS
13310 return dpyinfo;
13311}
13312\f
13313/* Get rid of display DPYINFO, assuming all frames are already gone,
13314 and without sending any more commands to the X server. */
dc6f92b8 13315
7a13e894
RS
13316void
13317x_delete_display (dpyinfo)
13318 struct x_display_info *dpyinfo;
13319{
13320 delete_keyboard_wait_descriptor (dpyinfo->connection);
13321
13322 /* Discard this display from x_display_name_list and x_display_list.
13323 We can't use Fdelq because that can quit. */
13324 if (! NILP (x_display_name_list)
8e713be6
KR
13325 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
13326 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
13327 else
13328 {
13329 Lisp_Object tail;
13330
13331 tail = x_display_name_list;
8e713be6 13332 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 13333 {
bffcfca9 13334 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 13335 {
8e713be6 13336 XCDR (tail) = XCDR (XCDR (tail));
7a13e894
RS
13337 break;
13338 }
8e713be6 13339 tail = XCDR (tail);
7a13e894
RS
13340 }
13341 }
13342
9bda743f
GM
13343 if (next_noop_dpyinfo == dpyinfo)
13344 next_noop_dpyinfo = dpyinfo->next;
13345
7a13e894
RS
13346 if (x_display_list == dpyinfo)
13347 x_display_list = dpyinfo->next;
7f9c7f94
RS
13348 else
13349 {
13350 struct x_display_info *tail;
7a13e894 13351
7f9c7f94
RS
13352 for (tail = x_display_list; tail; tail = tail->next)
13353 if (tail->next == dpyinfo)
13354 tail->next = tail->next->next;
13355 }
7a13e894 13356
0d777288
RS
13357#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
13358#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
13359 XrmDestroyDatabase (dpyinfo->xrdb);
13360#endif
0d777288 13361#endif
29b38361
KH
13362#ifdef MULTI_KBOARD
13363 if (--dpyinfo->kboard->reference_count == 0)
39f79001 13364 delete_kboard (dpyinfo->kboard);
b9737ad3 13365#endif
f5d11644
GM
13366#ifdef HAVE_X_I18N
13367 if (dpyinfo->xim)
13368 xim_close_dpy (dpyinfo);
13369#endif
13370
b9737ad3
KH
13371 xfree (dpyinfo->font_table);
13372 xfree (dpyinfo->x_id_name);
13373 xfree (dpyinfo);
7a13e894
RS
13374}
13375\f
13376/* Set up use of X before we make the first connection. */
13377
06a2c219
GM
13378static struct redisplay_interface x_redisplay_interface =
13379{
13380 x_produce_glyphs,
13381 x_write_glyphs,
13382 x_insert_glyphs,
13383 x_clear_end_of_line,
13384 x_scroll_run,
13385 x_after_update_window_line,
13386 x_update_window_begin,
13387 x_update_window_end,
13388 XTcursor_to,
13389 x_flush,
66ac4b0e
GM
13390 x_get_glyph_overhangs,
13391 x_fix_overlapping_area
06a2c219
GM
13392};
13393
dfcf069d 13394void
7a13e894
RS
13395x_initialize ()
13396{
06a2c219
GM
13397 rif = &x_redisplay_interface;
13398
13399 clear_frame_hook = x_clear_frame;
13400 ins_del_lines_hook = x_ins_del_lines;
13401 change_line_highlight_hook = x_change_line_highlight;
13402 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
13403 ring_bell_hook = XTring_bell;
13404 reset_terminal_modes_hook = XTreset_terminal_modes;
13405 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
13406 update_begin_hook = x_update_begin;
13407 update_end_hook = x_update_end;
dc6f92b8
JB
13408 set_terminal_window_hook = XTset_terminal_window;
13409 read_socket_hook = XTread_socket;
b8009dd1 13410 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 13411 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 13412 mouse_position_hook = XTmouse_position;
f451eb13 13413 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 13414 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
13415 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13416 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13417 redeem_scroll_bar_hook = XTredeem_scroll_bar;
13418 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 13419 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 13420
f676886a 13421 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
13422 char_ins_del_ok = 0; /* just as fast to write the line */
13423 line_ins_del_ok = 1; /* we'll just blt 'em */
13424 fast_clear_end_of_line = 1; /* X does this well */
58769bee 13425 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
13426 off the bottom */
13427 baud_rate = 19200;
13428
7a13e894 13429 x_noop_count = 0;
9ea173e8 13430 last_tool_bar_item = -1;
06a2c219
GM
13431 any_help_event_p = 0;
13432
b30b24cb
RS
13433 /* Try to use interrupt input; if we can't, then start polling. */
13434 Fset_input_mode (Qt, Qnil, Qt, Qnil);
13435
7f9c7f94
RS
13436#ifdef USE_X_TOOLKIT
13437 XtToolkitInitialize ();
13438 Xt_app_con = XtCreateApplicationContext ();
665881ad 13439 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
13440
13441 /* Install an asynchronous timer that processes Xt timeout events
13442 every 0.1s. This is necessary because some widget sets use
13443 timeouts internally, for example the LessTif menu bar, or the
13444 Xaw3d scroll bar. When Xt timouts aren't processed, these
13445 widgets don't behave normally. */
13446 {
13447 EMACS_TIME interval;
13448 EMACS_SET_SECS_USECS (interval, 0, 100000);
13449 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
13450 }
db74249b 13451#endif
bffcfca9 13452
db74249b 13453#if USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
13454 xaw3d_arrow_scroll = False;
13455 xaw3d_pick_top = True;
7f9c7f94
RS
13456#endif
13457
58769bee 13458 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 13459 original error handler. */
e99db5a1 13460 XSetErrorHandler (x_error_handler);
334208b7 13461 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 13462
06a2c219 13463 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
13464#ifdef SIGWINCH
13465 signal (SIGWINCH, SIG_DFL);
c118dd06 13466#endif /* ! defined (SIGWINCH) */
dc6f92b8 13467
92e2441b 13468 signal (SIGPIPE, x_connection_signal);
dc6f92b8 13469}
55123275 13470
06a2c219 13471
55123275
JB
13472void
13473syms_of_xterm ()
13474{
e99db5a1
RS
13475 staticpro (&x_error_message_string);
13476 x_error_message_string = Qnil;
13477
7a13e894
RS
13478 staticpro (&x_display_name_list);
13479 x_display_name_list = Qnil;
334208b7 13480
ab648270 13481 staticpro (&last_mouse_scroll_bar);
e53cb100 13482 last_mouse_scroll_bar = Qnil;
59e755be
KH
13483
13484 staticpro (&Qvendor_specific_keysyms);
13485 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
13486
13487 staticpro (&last_mouse_press_frame);
13488 last_mouse_press_frame = Qnil;
06a2c219
GM
13489
13490 staticpro (&help_echo);
13491 help_echo = Qnil;
13492 staticpro (&previous_help_echo);
13493 previous_help_echo = Qnil;
13494
13495 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
13496 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
13497For example, if a block cursor is over a tab, it will be drawn as\n\
13498wide as that tab on the display.");
13499 x_stretch_cursor_p = 0;
13500
13501 DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
13502 "If not nil, Emacs uses toolkit scroll bars.");
13503#if USE_TOOLKIT_SCROLL_BARS
13504 x_toolkit_scroll_bars_p = 1;
13505#else
13506 x_toolkit_scroll_bars_p = 0;
13507#endif
13508
06a2c219
GM
13509 staticpro (&last_mouse_motion_frame);
13510 last_mouse_motion_frame = Qnil;
55123275 13511}
6cf0ae86
RS
13512
13513#endif /* not HAVE_X_WINDOWS */
06a2c219 13514