(texinfo-no-refill-regexp): Add "direntry".
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
2e365682 2 Copyright (C) 1989, 93, 94, 95, 1996 Free Software Foundation, Inc.
dc6f92b8
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
4746118a 8the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
dc6f92b8 20
3afe33e7
RS
21/* Xt features made by Fred Pierresteguy. */
22
039440c4
RS
23/* On 4.3 these lose if they come after xterm.h. */
24/* On HP-UX 8.0 signal.h loses if it comes after config.h. */
25/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
26#include <signal.h>
27
18160b98 28#include <config.h>
dc6f92b8 29
4846819e
RS
30#include <stdio.h>
31
3afe33e7 32/* Need syssignal.h for various externs and definitions that may be required
bc20ebbf 33 by some configurations for calls to signal later in this source file. */
3afe33e7
RS
34#include "syssignal.h"
35
dc6f92b8
JB
36#ifdef HAVE_X_WINDOWS
37
38#include "lisp.h"
9ac0d9e0 39#include "blockinput.h"
dc6f92b8 40
dc6f92b8
JB
41/* This may include sys/types.h, and that somehow loses
42 if this is not done before the other system files. */
43#include "xterm.h"
f451eb13 44#include <X11/cursorfont.h>
dc6f92b8 45
16bd92ea 46#ifndef USG
dc6f92b8
JB
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
JB
51#endif /* makedev */
52#endif /* USG */
dc6f92b8 53
6df54671 54#ifdef BSD_SYSTEM
dc6f92b8 55#include <sys/ioctl.h>
6df54671 56#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 57
2d368234 58#include "systty.h"
3a2712f9 59#include "systime.h"
dc6f92b8 60
b8009dd1 61#ifndef INCLUDED_FCNTL
dc6f92b8 62#include <fcntl.h>
b8009dd1 63#endif
dc6f92b8
JB
64#include <ctype.h>
65#include <errno.h>
66#include <setjmp.h>
67#include <sys/stat.h>
a0a7635f
RS
68/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
69/* #include <sys/param.h> */
dc6f92b8 70
dc43ef94
KH
71#include "charset.h"
72#include "ccl.h"
73#include "fontset.h"
7a13e894 74#include "frame.h"
dc6f92b8
JB
75#include "dispextern.h"
76#include "termhooks.h"
77#include "termopts.h"
78#include "termchar.h"
79#if 0
80#include "sink.h"
81#include "sinkmask.h"
c118dd06 82#endif /* ! 0 */
dc6f92b8 83#include "gnu.h"
dc6f92b8 84#include "disptab.h"
dc6f92b8 85#include "buffer.h"
f451eb13 86#include "window.h"
3b2fa4e6 87#include "keyboard.h"
bde7c500 88#include "intervals.h"
dc6f92b8 89
d2bd6bc4
RS
90#ifdef USE_X_TOOLKIT
91#include <X11/Shell.h>
92#endif
93
3afe33e7 94#ifdef USE_X_TOOLKIT
9d7e2e3e 95extern void free_frame_menubar ();
2224b905 96extern FRAME_PTR x_menubar_window_to_frame ();
0fdff6bb
RS
97#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
98#define HACK_EDITRES
99extern void _XEditResCheckMessages ();
100#endif /* not NO_EDITRES */
3afe33e7
RS
101#endif /* USE_X_TOOLKIT */
102
b849c413
RS
103#ifndef USE_X_TOOLKIT
104#define x_any_window_to_frame x_window_to_frame
5627c40e 105#define x_top_window_to_frame x_window_to_frame
b849c413
RS
106#endif
107
546e6d5b 108#ifdef USE_X_TOOLKIT
d067ea8b 109#include "widget.h"
546e6d5b
RS
110#ifndef XtNinitialState
111#define XtNinitialState "initialState"
112#endif
113#endif
114
10537cb1 115#ifdef HAVE_SETLOCALE
39d8bb4d
KH
116/* So we can do setlocale. */
117#include <locale.h>
118#endif
119
80528801
KH
120#ifdef SOLARIS2
121/* memmove will be defined as a macro in Xfuncs.h unless
122 <string.h> is included beforehand. The declaration for memmove in
123 <string.h> will cause a syntax error when Xfuncs.h later includes it. */
124#include <string.h>
125#endif
126
e4b68333 127#ifndef min
dc6f92b8 128#define min(a,b) ((a)<(b) ? (a) : (b))
e4b68333
RS
129#endif
130#ifndef max
dc6f92b8 131#define max(a,b) ((a)>(b) ? (a) : (b))
e4b68333 132#endif
69388238 133\f
334208b7
RS
134/* This is a chain of structures for all the X displays currently in use. */
135struct x_display_info *x_display_list;
dc6f92b8 136
7a13e894
RS
137/* This is a list of cons cells, each of the form (NAME . FONT-LIST-CACHE),
138 one for each element of x_display_list and in the same order.
139 NAME is the name of the frame.
140 FONT-LIST-CACHE records previous values returned by x-list-fonts. */
141Lisp_Object x_display_name_list;
f451eb13 142
987d2ad1 143/* Frame being updated by update_frame. This is declared in term.c.
d0386f2a 144 This is set by update_begin and looked at by all the
dc6f92b8 145 XT functions. It is zero while not inside an update.
f676886a
JB
146 In that case, the XT functions assume that `selected_frame'
147 is the frame to apply to. */
d0386f2a 148extern struct frame *updating_frame;
dc6f92b8 149
0e81d8cd
RS
150extern waiting_for_input;
151
0134a210
RS
152/* This is a frame waiting to be autoraised, within XTread_socket. */
153struct frame *pending_autoraise_frame;
154
7f9c7f94
RS
155#ifdef USE_X_TOOLKIT
156/* The application context for Xt use. */
157XtAppContext Xt_app_con;
665881ad
RS
158
159static String Xt_default_resources[] =
160{
161 0
162};
7f9c7f94
RS
163#endif
164
dc6f92b8
JB
165/* During an update, maximum vpos for ins/del line operations to affect. */
166
167static int flexlines;
168
169/* During an update, nonzero if chars output now should be highlighted. */
170
171static int highlight;
172
173/* Nominal cursor position -- where to draw output.
174 During an update, these are different from the cursor-box position. */
175
176static int curs_x;
177static int curs_y;
178
69388238
RS
179/* Mouse movement.
180
f5bb65ec
RS
181 Formerly, we used PointerMotionHintMask (in STANDARD_EVENT_MASK)
182 so that we would have to call XQueryPointer after each MotionNotify
183 event to ask for another such event. However, this made mouse tracking
184 slow, and there was a bug that made it eventually stop.
185
186 Simply asking for MotionNotify all the time seems to work better.
187
69388238
RS
188 In order to avoid asking for motion events and then throwing most
189 of them away or busy-polling the server for mouse positions, we ask
190 the server for pointer motion hints. This means that we get only
191 one event per group of mouse movements. "Groups" are delimited by
192 other kinds of events (focus changes and button clicks, for
193 example), or by XQueryPointer calls; when one of these happens, we
194 get another MotionNotify event the next time the mouse moves. This
195 is at least as efficient as getting motion events when mouse
196 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 197 is off. */
69388238
RS
198
199/* Where the mouse was last time we reported a mouse event. */
200static FRAME_PTR last_mouse_frame;
201static XRectangle last_mouse_glyph;
202
2237cac9
RS
203static Lisp_Object last_mouse_press_frame;
204
69388238
RS
205/* The scroll bar in which the last X motion event occurred.
206
207 If the last X motion event occurred in a scroll bar, we set this
208 so XTmouse_position can know whether to report a scroll bar motion or
209 an ordinary motion.
210
211 If the last X motion event didn't occur in a scroll bar, we set this
212 to Qnil, to tell XTmouse_position to return an ordinary motion event. */
213static Lisp_Object last_mouse_scroll_bar;
214
69388238
RS
215/* This is a hack. We would really prefer that XTmouse_position would
216 return the time associated with the position it returns, but there
217 doesn't seem to be any way to wrest the timestamp from the server
218 along with the position query. So, we just keep track of the time
219 of the last movement we received, and return that in hopes that
220 it's somewhat accurate. */
221static Time last_mouse_movement_time;
222
c0a04927
RS
223/* Incremented by XTread_socket whenever it really tries to read events. */
224#ifdef __STDC__
225static int volatile input_signal_count;
226#else
227static int input_signal_count;
228#endif
229
7a13e894
RS
230/* Used locally within XTread_socket. */
231static int x_noop_count;
dc6f92b8 232
7a13e894
RS
233/* Initial values of argv and argc. */
234extern char **initial_argv;
235extern int initial_argc;
dc6f92b8 236
7a13e894 237extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 238
7a13e894
RS
239/* Tells if a window manager is present or not. */
240
241extern Lisp_Object Vx_no_window_manager;
dc6f92b8 242
c2df547c 243extern Lisp_Object Qface, Qmouse_face;
b8009dd1 244
dc6f92b8
JB
245extern int errno;
246
dfeccd2d 247/* A mask of extra modifier bits to put into every keyboard char. */
64bb1782
RS
248extern int extra_keyboard_modifiers;
249
59e755be
KH
250static Lisp_Object Qvendor_specific_keysyms;
251
334208b7 252extern XrmDatabase x_load_resources ();
dc6f92b8 253
c32cdd9a
KH
254extern Lisp_Object x_icon_type ();
255
7a13e894
RS
256void x_delete_display ();
257
c83febd7 258static void redraw_previous_char ();
0cdd0c9f 259static void redraw_following_char ();
3afe33e7 260static unsigned int x_x_to_emacs_modifiers ();
dc6f92b8 261
55836b73 262static int fast_find_position ();
b8009dd1
RS
263static void note_mouse_highlight ();
264static void clear_mouse_face ();
265static void show_mouse_face ();
58769bee 266static void do_line_dance ();
b8009dd1 267
4746118a
JB
268static int XTcursor_to ();
269static int XTclear_end_of_line ();
7a13e894 270static int x_io_error_quitter ();
e99db5a1 271int x_catch_errors ();
2d7fc7e8 272void x_uncatch_errors ();
334208b7 273\f
9382638d
KH
274#if 0
275/* This is a function useful for recording debugging information
276 about the sequence of occurrences in this file. */
277
278struct record
279{
280 char *locus;
281 int type;
282};
283
284struct record event_record[100];
285
286int event_record_index;
287
288record_event (locus, type)
289 char *locus;
290 int type;
291{
292 if (event_record_index == sizeof (event_record) / sizeof (struct record))
293 event_record_index = 0;
294
295 event_record[event_record_index].locus = locus;
296 event_record[event_record_index].type = type;
297 event_record_index++;
298}
299
300#endif /* 0 */
301\f
334208b7
RS
302/* Return the struct x_display_info corresponding to DPY. */
303
304struct x_display_info *
305x_display_info_for_display (dpy)
306 Display *dpy;
307{
308 struct x_display_info *dpyinfo;
309
310 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
311 if (dpyinfo->display == dpy)
312 return dpyinfo;
16bd92ea 313
334208b7
RS
314 return 0;
315}
16bd92ea 316\f
58769bee 317/* Starting and ending updates.
f451eb13
JB
318
319 These hooks are called by update_frame at the beginning and end
f676886a
JB
320 of a frame update. We record in `updating_frame' the identity
321 of the frame being updated, so that the XT... functions do not
322 need to take a frame as argument. Most of the XT... functions
dc6f92b8 323 should never be called except during an update, the only exceptions
c83febd7 324 being XTcursor_to, XTwrite_glyphs and XTreassert_line_highlight. */
dc6f92b8 325
dc6f92b8 326static
f676886a
JB
327XTupdate_begin (f)
328 struct frame *f;
58769bee 329{
dc6f92b8
JB
330 int mask;
331
f676886a 332 if (f == 0)
dc6f92b8
JB
333 abort ();
334
f676886a 335 flexlines = f->height;
dc6f92b8
JB
336 highlight = 0;
337
dc6f92b8 338 BLOCK_INPUT;
b8009dd1 339
d1bc4182
RS
340 curs_x = FRAME_CURSOR_X (f);
341 curs_y = FRAME_CURSOR_Y (f);
342
7a13e894 343 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
b8009dd1 344 {
514e4681 345 /* Don't do highlighting for mouse motion during the update. */
7a13e894 346 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 1;
37c2c98b
RS
347
348 /* If the frame needs to be redrawn,
349 simply forget about any prior mouse highlighting. */
9f67f20b 350 if (FRAME_GARBAGED_P (f))
37c2c98b
RS
351 FRAME_X_DISPLAY_INFO (f)->mouse_face_window = Qnil;
352
7a13e894 353 if (!NILP (FRAME_X_DISPLAY_INFO (f)->mouse_face_window))
514e4681
RS
354 {
355 int firstline, lastline, i;
7a13e894 356 struct window *w = XWINDOW (FRAME_X_DISPLAY_INFO (f)->mouse_face_window);
514e4681
RS
357
358 /* Find the first, and the last+1, lines affected by redisplay. */
359 for (firstline = 0; firstline < f->height; firstline++)
360 if (FRAME_DESIRED_GLYPHS (f)->enable[firstline])
361 break;
362
363 lastline = f->height;
364 for (i = f->height - 1; i >= 0; i--)
365 {
366 if (FRAME_DESIRED_GLYPHS (f)->enable[i])
367 break;
368 else
369 lastline = i;
370 }
371
372 /* Can we tell that this update does not affect the window
37c2c98b
RS
373 where the mouse highlight is? If so, no need to turn off.
374 Likewise, don't do anything if the frame is garbaged;
375 in that case, the FRAME_CURRENT_GLYPHS that we would use
376 are all wrong, and we will redisplay that line anyway. */
514e4681
RS
377 if (! (firstline > (XFASTINT (w->top) + window_internal_height (w))
378 || lastline < XFASTINT (w->top)))
7a13e894 379 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
514e4681 380 }
b8009dd1 381 }
6ccf47d1 382
dc6f92b8
JB
383 UNBLOCK_INPUT;
384}
385
dc6f92b8 386static
f676886a
JB
387XTupdate_end (f)
388 struct frame *f;
58769bee 389{
dc6f92b8
JB
390 int mask;
391
dc6f92b8 392 BLOCK_INPUT;
dc6f92b8 393
58769bee 394 do_line_dance ();
d1bc4182 395 x_display_cursor (f, 1, curs_x, curs_y);
dc6f92b8 396
aa8bff2e 397 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1
RS
398#if 0
399 /* This fails in the case of having updated only the echo area
400 if we have switched buffers. In that case, FRAME_CURRENT_GLYPHS
401 has no relation to the current contents, and its charstarts
402 have no relation to the contents of the window-buffer.
403 I don't know a clean way to check
404 for that case. window_end_valid isn't set up yet. */
7a13e894
RS
405 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
406 note_mouse_highlight (f, FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x,
407 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y);
b8009dd1
RS
408#endif
409
334208b7 410 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
411 UNBLOCK_INPUT;
412}
b8009dd1 413
514e4681 414/* This is called after a redisplay on frame F. */
b8009dd1
RS
415
416static
417XTframe_up_to_date (f)
418 FRAME_PTR f;
419{
cbe24f60 420 BLOCK_INPUT;
7a13e894
RS
421 if (FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc
422 || f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
514e4681 423 {
7a13e894
RS
424 note_mouse_highlight (FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame,
425 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x,
426 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y);
427 FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc = 0;
514e4681 428 }
cbe24f60 429 UNBLOCK_INPUT;
b8009dd1 430}
dc6f92b8
JB
431\f
432/* External interface to control of standout mode.
433 Call this when about to modify line at position VPOS
434 and not change whether it is highlighted. */
435
436XTreassert_line_highlight (new, vpos)
437 int new, vpos;
438{
439 highlight = new;
440}
441
442/* Call this when about to modify line at position VPOS
443 and change whether it is highlighted. */
444
445static
446XTchange_line_highlight (new_highlight, vpos, first_unused_hpos)
447 int new_highlight, vpos, first_unused_hpos;
448{
449 highlight = new_highlight;
450 XTcursor_to (vpos, 0);
3cbd2e0b 451 XTclear_end_of_line (FRAME_WINDOW_WIDTH (updating_frame));
dc6f92b8
JB
452}
453
454/* This is used when starting Emacs and when restarting after suspend.
455 When starting Emacs, no X window is mapped. And nothing must be done
456 to Emacs's own window if it is suspended (though that rarely happens). */
457
458static
459XTset_terminal_modes ()
460{
461}
462
463/* This is called when exiting or suspending Emacs.
464 Exiting will make the X-windows go away, and suspending
465 requires no action. */
466
467static
468XTreset_terminal_modes ()
469{
f676886a 470/* XTclear_frame (); */
dc6f92b8
JB
471}
472\f
f451eb13
JB
473/* Set the nominal cursor position of the frame.
474 This is where display update commands will take effect.
dc6f92b8
JB
475 This does not affect the place where the cursor-box is displayed. */
476
4746118a 477static int
dc6f92b8
JB
478XTcursor_to (row, col)
479 register int row, col;
480{
481 int mask;
482 int orow = row;
483
484 curs_x = col;
485 curs_y = row;
486
f676886a 487 if (updating_frame == 0)
dc6f92b8
JB
488 {
489 BLOCK_INPUT;
d1bc4182 490 x_display_cursor (selected_frame, 1, curs_x, curs_y);
334208b7 491 XFlush (FRAME_X_DISPLAY (selected_frame));
dc6f92b8
JB
492 UNBLOCK_INPUT;
493 }
494}
495\f
dc43ef94
KH
496
497/* Return a pointer to per char metric information in FONT of a
498 character pointed by B (*XChar2b). */
499
500#define PER_CHAR_METRIC(font, b) \
501 ((font)->per_char \
502 ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \
503 + (((font)->min_byte1 || (font)->max_byte1) \
504 ? (((b)->byte1 - (font)->min_byte1) \
505 * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \
506 : 0)) \
507 : &((font)->max_bounds))
508
dc6f92b8
JB
509/* Display a sequence of N glyphs found at GP.
510 WINDOW is the x-window to output to. LEFT and TOP are starting coords.
b8009dd1
RS
511 HL is 1 if this text is highlighted, 2 if the cursor is on it,
512 3 if should appear in its mouse-face.
0cdd0c9f
RS
513 JUST_FOREGROUND if 1 means draw only the foreground;
514 don't alter the background.
dc6f92b8 515
dc43ef94
KH
516 CMPCHARP if non NULL is a pointer to the struct cmpchar_info, which
517 means drawing glyphs on the same column. This is set to non NULL
518 only when recursively called within dumpglyphs to draw a composite
519 character specified by CMPCHAR.
520
07e34cb0 521 FONT is the default font to use (for glyphs whose font-code is 0).
dc6f92b8 522
07e34cb0
JB
523 Since the display generation code is responsible for calling
524 compute_char_face and compute_glyph_face on everything it puts in
525 the display structure, we can assume that the face code on each
28f72798 526 glyph is a valid index into FRAME_COMPUTED_FACES (f), and the one
f94397b5 527 to which we can actually apply intern_face.
dc43ef94
KH
528 Call this function with input blocked.
529
530 Return overall pixel width of the drawn glyphs. */
dc6f92b8 531
07e34cb0
JB
532#if 1
533/* This is the multi-face code. */
dc6f92b8 534
dc43ef94
KH
535static int
536dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
f676886a 537 struct frame *f;
dc6f92b8
JB
538 int left, top;
539 register GLYPH *gp; /* Points to first GLYPH. */
540 register int n; /* Number of glyphs to display. */
541 int hl;
0cdd0c9f 542 int just_foreground;
dc43ef94 543 struct cmpchar_info *cmpcharp;
dc6f92b8 544{
07e34cb0 545 /* Holds characters to be displayed. */
dc43ef94
KH
546 XChar2b *buf = (XChar2b *) alloca (FRAME_WINDOW_WIDTH (f) * sizeof (*buf));
547 register XChar2b *cp; /* Steps through buf[]. */
dc6f92b8
JB
548 register int tlen = GLYPH_TABLE_LENGTH;
549 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
c118dd06 550 Window window = FRAME_X_WINDOW (f);
0cdd0c9f 551 int orig_left = left;
dc43ef94 552 int gidx = 0;
b5210ea7 553 int i;
dc6f92b8 554
07e34cb0 555 while (n > 0)
dc6f92b8
JB
556 {
557 /* Get the face-code of the next GLYPH. */
558 int cf, len;
eefe9096 559 GLYPH g = *gp;
b264791c
RS
560 int ch, charset;
561 Lisp_Object first_ch;
dc43ef94
KH
562 /* HIGHEST and LOWEST are used while drawing a composite
563 character. The meanings are described later. */
564 int highest, lowest;
dc6f92b8 565
07e34cb0 566 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
dc43ef94
KH
567 cf = (cmpcharp ? cmpcharp->face_work : FAST_GLYPH_FACE (g));
568 ch = FAST_GLYPH_CHAR (g);
b264791c 569 if (gidx == 0) XSETFASTINT (first_ch, ch);
dc43ef94
KH
570 charset = CHAR_CHARSET (ch);
571 if (charset == CHARSET_COMPOSITION)
572 {
573 /* We must draw components of the composite character on the
574 same column. */
575 cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (ch)];
576
577 /* Set the face in the slot for work. */
578 cmpcharp->face_work = cf;
579
580 /* We don't need the return value ... */
581 dumpglyphs (f, left, top, cmpcharp->glyph, cmpcharp->glyph_len,
582 hl, just_foreground, cmpcharp);
583 /* ... because the width of just drawn text can be
584 calculated as follows. */
585 left += FONT_WIDTH (f->output_data.x->font) * cmpcharp->width;
586
587 ++gp, --n;
588 while (gp && (*gp & GLYPH_MASK_PADDING)) ++gp, --n;
589 cmpcharp = NULL;
590 continue;
591 }
dc6f92b8 592
dc43ef94
KH
593 /* Find the run of consecutive glyphs which can be drawn with
594 the same GC (i.e. the same charset and the same face-code).
595 Extract their character codes into BUF.
596 If CMPCHARP is not NULL, face-code is not checked because we
597 use only the face specified in `cmpcharp->face_work'. */
dc6f92b8
JB
598 cp = buf;
599 while (n > 0)
600 {
dc43ef94
KH
601 int this_charset, c1, c2;
602
dc6f92b8 603 g = *gp;
07e34cb0 604 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
dc43ef94
KH
605 ch = FAST_GLYPH_CHAR (g);
606 SPLIT_CHAR (ch, this_charset, c1, c2);
607 if (this_charset != charset
608 || (cmpcharp == NULL && FAST_GLYPH_FACE (g) != cf))
dc6f92b8
JB
609 break;
610
57b03282 611 if (c2 > 0)
dc43ef94
KH
612 cp->byte1 = c1, cp->byte2 = c2;
613 else
614 cp->byte1 = 0, cp->byte2 = c1;
615 ++cp;
616 ++gp, --n;
617 while (gp && (*gp & GLYPH_MASK_PADDING))
618 ++gp, --n;
dc6f92b8
JB
619 }
620
621 /* LEN gets the length of the run. */
622 len = cp - buf;
dc6f92b8
JB
623 /* Now output this run of chars, with the font and pixel values
624 determined by the face code CF. */
07e34cb0
JB
625 {
626 struct face *face = FRAME_DEFAULT_FACE (f);
dc43ef94
KH
627 XFontStruct *font = NULL;
628 GC gc;
990ba854 629 int stippled = 0;
b5210ea7
KH
630 int line_height = f->output_data.x->line_height;
631 /* Pixel width of each glyph in this run. */
632 int glyph_width
57b03282
KH
633 = (FONT_WIDTH (f->output_data.x->font)
634 * (cmpcharp ? cmpcharp->width : CHARSET_WIDTH (charset)));
b5210ea7
KH
635 /* Overall pixel width of this run. */
636 int run_width
637 = (FONT_WIDTH (f->output_data.x->font)
638 * (cmpcharp ? cmpcharp->width : len * CHARSET_WIDTH (charset)));
dc43ef94
KH
639 /* A flag to tell if we have already filled background. We
640 fill background in advance in the following cases:
641 1) A face has stipple.
b5210ea7 642 2) A height of font is shorter than LINE_HEIGHT.
dc43ef94 643 3) Drawing a composite character.
f78798df 644 4) Font has non-zero _MULE_BASELINE_OFFSET property.
dc43ef94
KH
645 After filling background, we draw glyphs by XDrawString16. */
646 int background_filled;
647 /* Baseline position of a character, offset from TOP. */
648 int baseline;
f78798df
KH
649 /* The property value of `_MULE_RELATIVE_COMPOSE' and
650 `_MULE_DEFAULT_ASCENT'. */
651 int relative_compose = 0, default_ascent = 0;
b5210ea7
KH
652 /* 1 if we find no font or a font of inappropriate size. */
653 int require_clipping;
07e34cb0 654
b8009dd1
RS
655 /* HL = 3 means use a mouse face previously chosen. */
656 if (hl == 3)
7a13e894 657 cf = FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id;
b8009dd1 658
b73b6aaf
RS
659 /* First look at the face of the text itself. */
660 if (cf != 0)
07e34cb0 661 {
a07d4bc5
RS
662 /* It's possible for the display table to specify
663 a face code that is out of range. Use 0 in that case. */
28f72798
JB
664 if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f)
665 || FRAME_COMPUTED_FACES (f) [cf] == 0)
a07d4bc5 666 cf = 0;
07e34cb0
JB
667
668 if (cf == 1)
669 face = FRAME_MODE_LINE_FACE (f);
670 else
28f72798 671 face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
990ba854
RS
672 if (FACE_STIPPLE (face))
673 stippled = 1;
07e34cb0 674 }
4a4dc352
JB
675
676 /* Then comes the distinction between modeline and normal text. */
07e34cb0
JB
677 else if (hl == 0)
678 ;
679 else if (hl == 1)
680 {
681 face = FRAME_MODE_LINE_FACE (f);
990ba854
RS
682 if (FACE_STIPPLE (face))
683 stippled = 1;
b73b6aaf
RS
684 }
685
57b03282
KH
686#define FACE_DEFAULT (~0)
687
dc43ef94
KH
688 /* Setting appropriate font and gc for this charset. */
689 if (charset != CHARSET_ASCII)
690 {
691 int font_id;
692 int fontset = FACE_FONTSET (face);
693 struct font_info *fontp;
694
695 if ((fontset < 0 && (fontset = FRAME_FONTSET (f)) < 0)
2da424f1 696 || !(fontp = FS_LOAD_FONT (f, FRAME_X_FONT_TABLE (f),
dc43ef94
KH
697 charset, NULL, fontset)))
698 goto font_not_found;
699
700 font = (XFontStruct *) (fontp->font);
701 gc = FACE_NON_ASCII_GC (face);
702 XSetFont (FRAME_X_DISPLAY (f), gc, font->fid);
b5210ea7
KH
703 baseline
704 = (font->max_byte1 != 0
705 ? (line_height + font->ascent - font->descent) / 2
706 : f->output_data.x->font_baseline - fontp->baseline_offset);
97210f4e
KH
707 if (FONT_HEIGHT (font) <= line_height
708 && (font->ascent > baseline
709 || font->descent > line_height - baseline))
710 /* Adjust baseline for this font to show the whole
711 glyphs in a line. */
712 baseline = line_height - font->descent;
713
dc43ef94 714 if (cmpcharp && cmpcharp->cmp_rule == NULL)
f78798df
KH
715 {
716 relative_compose = fontp->relative_compose;
717 default_ascent = fontp->default_ascent;
718 }
dc43ef94
KH
719
720 /* We have to change code points in the following cases. */
721 if (fontp->font_encoder)
722 {
723 /* This font requires CCL program to calculate code
724 point of characters. */
725 struct ccl_program *ccl = fontp->font_encoder;
726
727 if (CHARSET_DIMENSION (charset) == 1)
728 for (cp = buf; cp < buf + len; cp++)
729 {
730 ccl->reg[0] = charset;
731 ccl->reg[1] = cp->byte2;
732 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
733 cp->byte2 = ccl->reg[1];
734 }
735 else
736 for (cp = buf; cp < buf + len; cp++)
737 {
738 ccl->reg[0] = charset;
739 ccl->reg[1] = cp->byte1, ccl->reg[2] = cp->byte2;
740 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
741 cp->byte1 = ccl->reg[1], cp->byte2 = ccl->reg[2];
742 }
743 }
744 else if (fontp->encoding[charset])
745 {
746 int enc = fontp->encoding[charset];
747
748 if ((enc == 1 || enc == 2) && CHARSET_DIMENSION (charset) == 2)
749 for (cp = buf; cp < buf + len; cp++)
750 cp->byte1 |= 0x80;
751 if (enc == 1 || enc == 3)
752 for (cp = buf; cp < buf + len; cp++)
753 cp->byte2 |= 0x80;
754 }
755 }
756 else
757 {
dc43ef94 758 font_not_found:
34910d41
KH
759 if (charset == CHARSET_ASCII || charset == charset_latin_iso8859_1)
760 {
761 font = FACE_FONT (face);
762 if (font == (XFontStruct *) FACE_DEFAULT)
763 font = f->output_data.x->font;
fe27f88d 764 baseline = FONT_BASE (f->output_data.x->font);
34910d41
KH
765 if (charset == charset_latin_iso8859_1)
766 {
767 if (font->max_char_or_byte2 < 0x80)
768 /* This font can't display Latin1 characters. */
769 font = NULL;
770 else
771 {
772 for (cp = buf; cp < buf + len; cp++)
773 cp->byte2 |= 0x80;
774 }
775 }
776 }
777 gc = FACE_GC (face);
dc43ef94
KH
778 }
779
b73b6aaf 780 /* Now override that if the cursor's on this character. */
b5cf7a0e 781 if (hl == 2)
b73b6aaf 782 {
990ba854
RS
783 /* The cursor overrides stippling. */
784 stippled = 0;
785
57b03282 786 if (font == f->output_data.x->font
7556890b 787 && face->background == f->output_data.x->background_pixel
34910d41
KH
788 && face->foreground == f->output_data.x->foreground_pixel
789 && !cmpcharp)
b5cf7a0e 790 {
7556890b 791 gc = f->output_data.x->cursor_gc;
b5cf7a0e
JB
792 }
793 /* Cursor on non-default face: must merge. */
794 else
795 {
796 XGCValues xgcv;
797 unsigned long mask;
798
7556890b 799 xgcv.background = f->output_data.x->cursor_pixel;
11dd3d61 800 xgcv.foreground = face->background;
df5a440b
RS
801 /* If the glyph would be invisible,
802 try a different foreground. */
803 if (xgcv.foreground == xgcv.background)
da893f1f 804 xgcv.foreground = face->foreground;
df5a440b 805 if (xgcv.foreground == xgcv.background)
7556890b 806 xgcv.foreground = f->output_data.x->cursor_foreground_pixel;
df5a440b
RS
807 if (xgcv.foreground == xgcv.background)
808 xgcv.foreground = face->foreground;
809 /* Make sure the cursor is distinct from text in this face. */
810 if (xgcv.background == face->background
811 && xgcv.foreground == face->foreground)
812 {
813 xgcv.background = face->foreground;
814 xgcv.foreground = face->background;
815 }
dc43ef94
KH
816 if (font)
817 xgcv.font = font->fid;
818 else
819 xgcv.font = FACE_FONT (face)->fid;
b5cf7a0e
JB
820 xgcv.graphics_exposures = 0;
821 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
7a13e894
RS
822 if (FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc)
823 XChangeGC (FRAME_X_DISPLAY (f),
824 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc,
825 mask, &xgcv);
11dd3d61 826 else
7a13e894 827 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc
334208b7 828 = XCreateGC (FRAME_X_DISPLAY (f), window, mask, &xgcv);
7a13e894 829 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
b73b6aaf 830#if 0
11dd3d61
RS
831/* If this code is restored, it must also reset to the default stipple
832 if necessary. */
b5cf7a0e 833 if (face->stipple && face->stipple != FACE_DEFAULT)
334208b7 834 XSetStipple (FRAME_X_DISPLAY (f), gc, face->stipple);
b73b6aaf 835#endif
b5cf7a0e 836 }
07e34cb0 837 }
07e34cb0 838
b5210ea7 839 if (font)
57b03282
KH
840 require_clipping = (!NILP (Vclip_large_size_font)
841 && (font->ascent > baseline
842 || font->descent > line_height - baseline
843 || (!cmpcharp
844 && FONT_WIDTH (font) > glyph_width)));
b5210ea7 845
dc43ef94
KH
846 if (font && (just_foreground || (cmpcharp && gidx > 0)))
847 background_filled = 1;
b5210ea7 848 else if (stippled)
dc43ef94 849 {
dc43ef94
KH
850 /* Turn stipple on. */
851 XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillOpaqueStippled);
852
853 /* Draw stipple or background color on background. */
854 XFillRectangle (FRAME_X_DISPLAY (f), window, gc,
b5210ea7 855 left, top, run_width, line_height);
dc43ef94
KH
856
857 /* Turn stipple off. */
858 XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillSolid);
859
b5210ea7
KH
860 background_filled = 1;
861 }
862 else if (!font
863 || FONT_HEIGHT (font) < line_height
864 || FONT_WIDTH (font) < glyph_width
b5210ea7
KH
865 || cmpcharp)
866 {
867 /* Fill a area for the current run in background pixle of GC. */
868 XGCValues xgcv;
fe27f88d 869 unsigned long mask = GCForeground | GCBackground | GCFillStyle;
b5210ea7 870
34910d41
KH
871 /* The current code at first set foreground to background,
872 fill the area, then recover the original foreground.
97210f4e 873 Aren't there any smarter ways? */
b5210ea7
KH
874
875 XGetGCValues (FRAME_X_DISPLAY (f), gc, mask, &xgcv);
34910d41 876 XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.background);
fe27f88d 877 XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillSolid);
b5210ea7
KH
878 XFillRectangle (FRAME_X_DISPLAY (f), window, gc,
879 left, top, run_width, line_height);
34910d41 880 XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.foreground);
b5210ea7 881
dc43ef94
KH
882 background_filled = 1;
883 if (cmpcharp)
884 /* To assure not to fill background while drawing
885 remaining components. */
886 just_foreground = 1;
887 }
0cdd0c9f 888 else
dc43ef94
KH
889 background_filled = 0;
890
891 if (font)
0cdd0c9f 892 {
b5210ea7
KH
893 if (require_clipping)
894 {
895 Region region; /* Region used for setting clip mask to GC. */
896 XPoint x[4]; /* Data used for creating REGION. */
897
898 x[0].x = x[3].x = left, x[1].x = x[2].x = left + glyph_width;
899 x[0].y = x[1].y = top, x[2].y = x[3].y = top + line_height;
900 region = XPolygonRegion (x, 4, EvenOddRule);
901 XSetRegion (FRAME_X_DISPLAY (f), gc, region);
902 XDestroyRegion (region);
903 }
904
905 if (!cmpcharp)
906 {
f613a4c8 907 if (require_clipping || FONT_WIDTH (font) != glyph_width)
b5210ea7
KH
908 for (i = 0; i < len; i++)
909 {
f613a4c8 910 if (require_clipping && i > 0)
b5210ea7
KH
911 XSetClipOrigin (FRAME_X_DISPLAY (f), gc,
912 glyph_width * i, 0);
913 if (background_filled)
914 XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
915 left + glyph_width * i,
916 top + baseline, buf + i, 1);
917 else
918 XDrawImageString16 (FRAME_X_DISPLAY (f), window, gc,
919 left + glyph_width * i,
920 top + baseline, buf + i, 1);
921 }
922 else
923 {
924 if (background_filled)
925 XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
926 left, top + baseline, buf, len);
927 else
928 XDrawImageString16 (FRAME_X_DISPLAY (f), window, gc,
929 left, top + baseline, buf, len);
930 }
931 }
932 else
990ba854 933 {
dc43ef94 934 XCharStruct *pcm; /* Pointer to per char metric info. */
990ba854 935
dc43ef94
KH
936 if ((cmpcharp->cmp_rule || relative_compose)
937 && gidx == 0)
938 {
939 /* This is the first character. Initialize variables.
940 HIGHEST is the highest position of glyphs ever
941 written, LOWEST the lowest position. */
942 int x_offset = 0;
943
f78798df
KH
944 if (default_ascent
945 && CHAR_TABLE_P (Vuse_default_ascent)
946 && !NILP (Faref (Vuse_default_ascent, first_ch)))
947 {
948 highest = default_ascent;
949 lowest = 0;
950 }
951 else
952 {
953 pcm = PER_CHAR_METRIC (font, buf);
954 highest = pcm->ascent + 1;
955 lowest = - pcm->descent;
956 }
dc43ef94
KH
957
958 if (cmpcharp->cmp_rule)
959 x_offset = (cmpcharp->col_offset[0]
960 * FONT_WIDTH (f->output_data.x->font));
961 /* Draw the first character at the normal position. */
962 XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
963 left + x_offset, top + baseline, buf, 1);
964 i = 1;
965 gidx++;
966 }
967 else
968 i = 0;
990ba854 969
dc43ef94
KH
970 for (; i < len; i++, gidx++)
971 {
972 int x_offset = 0, y_offset = 0;
990ba854 973
dc43ef94
KH
974 if (relative_compose)
975 {
976 pcm = PER_CHAR_METRIC (font, buf + i);
977 if (- pcm->descent >= relative_compose)
978 {
979 /* Draw above the current glyphs. */
980 y_offset = highest + pcm->descent;
981 highest += pcm->ascent + pcm->descent;
982 }
983 else if (pcm->ascent <= 0)
984 {
985 /* Draw beneath the current glyphs. */
986 y_offset = lowest - pcm->ascent;
987 lowest -= pcm->ascent + pcm->descent;
988 }
989 }
990 else if (cmpcharp->cmp_rule)
991 {
992 int gref = (cmpcharp->cmp_rule[gidx] - 0xA0) / 9;
993 int nref = (cmpcharp->cmp_rule[gidx] - 0xA0) % 9;
994 int bottom, top;
995
996 /* Re-encode GREF and NREF so that they specify
997 only Y-axis information:
998 0:top, 1:base, 2:bottom, 3:center */
999 gref = gref / 3 + (gref == 4) * 2;
1000 nref = nref / 3 + (nref == 4) * 2;
1001
1002 pcm = PER_CHAR_METRIC (font, buf + i);
1003 bottom = ((gref == 0 ? highest : gref == 1 ? 0
1004 : gref == 2 ? lowest
1005 : (highest + lowest) / 2)
1006 - (nref == 0 ? pcm->ascent + pcm->descent
1007 : nref == 1 ? pcm->descent : nref == 2 ? 0
1008 : (pcm->ascent + pcm->descent) / 2));
1009 top = bottom + (pcm->ascent + pcm->descent);
1010 if (top > highest)
1011 highest = top;
1012 if (bottom < lowest)
1013 lowest = bottom;
1014 y_offset = bottom + pcm->descent;
1015 x_offset = (cmpcharp->col_offset[gidx]
1016 * FONT_WIDTH (f->output_data.x->font));
1017 }
1018 XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
1019 left + x_offset, top + baseline - y_offset,
1020 buf + i, 1);
1021 }
990ba854 1022 }
b5210ea7
KH
1023 if (require_clipping)
1024 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
0cdd0c9f
RS
1025
1026#if 0 /* Doesn't work, because it uses FRAME_CURRENT_GLYPHS,
1027 which often is not up to date yet. */
dc43ef94
KH
1028 if (!just_foreground)
1029 {
1030 if (left == orig_left)
1031 redraw_previous_char (f, PIXEL_TO_CHAR_COL (f, left),
1032 PIXEL_TO_CHAR_ROW (f, top), hl == 1);
1033 if (n == 0)
1034 redraw_following_char (f, PIXEL_TO_CHAR_COL (f, left + len * FONT_WIDTH (font)),
1035 PIXEL_TO_CHAR_ROW (f, top), hl == 1);
1036 }
1037#endif
1038 }
97210f4e 1039 if (!font)
0cdd0c9f 1040 {
97210f4e
KH
1041 /* Show rectangles to indicate that we found no font. */
1042 int limit = cmpcharp ? 1 : len;
dc43ef94 1043
97210f4e
KH
1044 for (i = 0; i < limit; i++)
1045 XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
1046 left + glyph_width * i, top,
1047 glyph_width - 1, line_height - 1);
1048 }
1049 else if (require_clipping && !NILP (Vhighlight_wrong_size_font))
1050 {
1051 /* Show ??? to indicate that we found a font of
1052 inappropriate size. */
1053 int limit = cmpcharp ? 1 : len;
1054
1055 for (i = 0; i < limit; i++)
1056 {
1057 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
1058 left + glyph_width * i, top + line_height - 1,
1059 left + glyph_width * i + 1, top + line_height - 1);
1060 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
1061 left + glyph_width * i, top + line_height - 3,
1062 left + glyph_width * i, top + line_height - 1);
1063 }
0cdd0c9f 1064 }
97210f4e 1065
07e34cb0
JB
1066 /* We should probably check for XA_UNDERLINE_POSITION and
1067 XA_UNDERLINE_THICKNESS properties on the font, but let's
1068 just get the thing working, and come back to that. */
dc6f92b8 1069 {
dc43ef94
KH
1070 /* Setting underline position based on the metric of the
1071 current font results in shaky underline if it strides
1072 over different fonts. So, we set the position based only
1073 on the default font of this frame. */
1074 int underline_position = f->output_data.x->font_baseline + 1;
07e34cb0 1075
b5210ea7
KH
1076 if (underline_position >= line_height)
1077 underline_position = line_height - 1;
07e34cb0
JB
1078
1079 if (face->underline)
334208b7 1080 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
07e34cb0 1081 FACE_GC (face),
b5210ea7 1082 left, top + underline_position, run_width, 1);
dc6f92b8 1083 }
07e34cb0 1084
dc43ef94 1085 if (!cmpcharp)
b5210ea7 1086 left += run_width;
07e34cb0 1087 }
dc6f92b8 1088 }
dc43ef94
KH
1089
1090 return (left - orig_left);
dc6f92b8 1091}
07e34cb0
JB
1092#endif /* 1 */
1093
1094#if 0
1095/* This is the old single-face code. */
1096
1097static void
1098dumpglyphs (f, left, top, gp, n, hl, font)
1099 struct frame *f;
1100 int left, top;
1101 register GLYPH *gp; /* Points to first GLYPH. */
1102 register int n; /* Number of glyphs to display. */
1103 int hl;
334208b7 1104 XFontStruct *font;
07e34cb0
JB
1105{
1106 register int len;
1107 Window window = FRAME_X_WINDOW (f);
7556890b
RS
1108 GC drawing_gc = (hl == 2 ? f->output_data.x->cursor_gc
1109 : (hl ? f->output_data.x->reverse_gc
1110 : f->output_data.x->normal_gc));
07e34cb0
JB
1111
1112 if (sizeof (GLYPH) == sizeof (XChar2b))
334208b7 1113 XDrawImageString16 (FRAME_X_DISPLAY (f), window, drawing_gc,
07e34cb0
JB
1114 left, top + FONT_BASE (font), (XChar2b *) gp, n);
1115 else if (sizeof (GLYPH) == sizeof (unsigned char))
334208b7 1116 XDrawImageString (FRAME_X_DISPLAY (f), window, drawing_gc,
07e34cb0
JB
1117 left, top + FONT_BASE (font), (char *) gp, n);
1118 else
1119 /* What size of glyph ARE you using? And does X have a function to
1120 draw them? */
1121 abort ();
1122}
1123#endif
dc6f92b8 1124\f
f451eb13
JB
1125/* Output some text at the nominal frame cursor position.
1126 Advance the cursor over the text.
dc6f92b8
JB
1127 Output LEN glyphs at START.
1128
1129 `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight,
1130 controls the pixel values used for foreground and background. */
1131
1132static
1133XTwrite_glyphs (start, len)
1134 register GLYPH *start;
1135 int len;
1136{
1137 register int temp_length;
1138 int mask;
f676886a 1139 struct frame *f;
dc6f92b8
JB
1140
1141 BLOCK_INPUT;
1142
58769bee 1143 do_line_dance ();
f676886a
JB
1144 f = updating_frame;
1145 if (f == 0)
dc6f92b8 1146 {
f676886a 1147 f = selected_frame;
dc6f92b8 1148 /* If not within an update,
f676886a
JB
1149 output at the frame's visible cursor. */
1150 curs_x = f->cursor_x;
1151 curs_y = f->cursor_y;
dc6f92b8
JB
1152 }
1153
f676886a 1154 dumpglyphs (f,
12ba150f
JB
1155 CHAR_TO_PIXEL_COL (f, curs_x),
1156 CHAR_TO_PIXEL_ROW (f, curs_y),
dc43ef94 1157 start, len, highlight, 0, NULL);
90e65f07
JB
1158
1159 /* If we drew on top of the cursor, note that it is turned off. */
f676886a
JB
1160 if (curs_y == f->phys_cursor_y
1161 && curs_x <= f->phys_cursor_x
1162 && curs_x + len > f->phys_cursor_x)
549b29ac 1163 f->phys_cursor_on = 0;
58769bee 1164
f676886a 1165 if (updating_frame == 0)
d1bc4182 1166 x_display_cursor (f, 1, FRAME_CURSOR_X (f) + len, FRAME_CURSOR_Y (f));
dc6f92b8
JB
1167 else
1168 curs_x += len;
1169
1170 UNBLOCK_INPUT;
1171}
1172\f
f451eb13
JB
1173/* Clear to the end of the line.
1174 Erase the current text line from the nominal cursor position (inclusive)
dc6f92b8
JB
1175 to column FIRST_UNUSED (exclusive). The idea is that everything
1176 from FIRST_UNUSED onward is already erased. */
58769bee 1177
c32cdd9a 1178static
dc6f92b8
JB
1179XTclear_end_of_line (first_unused)
1180 register int first_unused;
1181{
f676886a 1182 struct frame *f = updating_frame;
dc6f92b8
JB
1183 int mask;
1184
f676886a 1185 if (f == 0)
dc6f92b8
JB
1186 abort ();
1187
f676886a 1188 if (curs_y < 0 || curs_y >= f->height)
dc6f92b8
JB
1189 return;
1190 if (first_unused <= 0)
1191 return;
1192
3cbd2e0b
RS
1193 if (first_unused >= FRAME_WINDOW_WIDTH (f))
1194 first_unused = FRAME_WINDOW_WIDTH (f);
dc6f92b8 1195
d9cdbb3d
RS
1196 first_unused += FRAME_LEFT_SCROLL_BAR_WIDTH (f);
1197
dc6f92b8
JB
1198 BLOCK_INPUT;
1199
b30ec466
KH
1200 do_line_dance ();
1201
90e65f07 1202 /* Notice if the cursor will be cleared by this operation. */
f676886a
JB
1203 if (curs_y == f->phys_cursor_y
1204 && curs_x <= f->phys_cursor_x
1205 && f->phys_cursor_x < first_unused)
549b29ac 1206 f->phys_cursor_on = 0;
dc6f92b8 1207
334208b7 1208 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12ba150f
JB
1209 CHAR_TO_PIXEL_COL (f, curs_x),
1210 CHAR_TO_PIXEL_ROW (f, curs_y),
7556890b
RS
1211 FONT_WIDTH (f->output_data.x->font) * (first_unused - curs_x),
1212 f->output_data.x->line_height, False);
c83febd7 1213#if 0
0cdd0c9f 1214 redraw_previous_char (f, curs_x, curs_y, highlight);
c83febd7 1215#endif
dc6f92b8
JB
1216
1217 UNBLOCK_INPUT;
1218}
1219
0cdd0c9f
RS
1220static
1221XTclear_frame ()
1222{
1223 int mask;
1224 struct frame *f = updating_frame;
1225
1226 if (f == 0)
1227 f = selected_frame;
1228
549b29ac 1229 f->phys_cursor_on = 0; /* Cursor not visible. */
0cdd0c9f
RS
1230 curs_x = 0; /* Nominal cursor position is top left. */
1231 curs_y = 0;
58769bee 1232
0cdd0c9f
RS
1233 BLOCK_INPUT;
1234
334208b7 1235 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0cdd0c9f
RS
1236
1237 /* We have to clear the scroll bars, too. If we have changed
1238 colors or something like that, then they should be notified. */
1239 x_scroll_bar_clear (f);
1240
334208b7 1241 XFlush (FRAME_X_DISPLAY (f));
0cdd0c9f
RS
1242 UNBLOCK_INPUT;
1243}
1244\f
1245#if 0
1246/* This currently does not work because FRAME_CURRENT_GLYPHS doesn't
1247 always contain the right glyphs to use.
1248
1249 It also needs to be changed to look at the details of the font and
1250 see whether there is really overlap, and do nothing when there is
1251 not. This can use font_char_overlap_left and font_char_overlap_right,
1252 but just how to use them is not clear. */
1253
c83febd7
RS
1254/* Erase the character (if any) at the position just before X, Y in frame F,
1255 then redraw it and the character before it.
1256 This is necessary when we erase starting at X,
f94397b5
KH
1257 in case the character after X overlaps into the one before X.
1258 Call this function with input blocked. */
c83febd7
RS
1259
1260static void
0cdd0c9f 1261redraw_previous_char (f, x, y, highlight_flag)
c83febd7
RS
1262 FRAME_PTR f;
1263 int x, y;
0cdd0c9f 1264 int highlight_flag;
c83febd7
RS
1265{
1266 /* Erase the character before the new ones, in case
1267 what was here before overlaps it.
1268 Reoutput that character, and the previous character
1269 (in case the previous character overlaps it). */
1270 if (x > 0)
1271 {
1272 int start_x = x - 2;
1273 if (start_x < 0)
1274 start_x = 0;
334208b7 1275 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
c83febd7
RS
1276 CHAR_TO_PIXEL_COL (f, x - 1),
1277 CHAR_TO_PIXEL_ROW (f, y),
7556890b
RS
1278 FONT_WIDTH (f->output_data.x->font),
1279 f->output_data.x->line_height, False);
c83febd7
RS
1280
1281 dumpglyphs (f, CHAR_TO_PIXEL_COL (f, start_x),
1282 CHAR_TO_PIXEL_ROW (f, y),
1283 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][start_x],
dc43ef94 1284 x - start_x, highlight_flag, 1, NULL);
c83febd7
RS
1285 }
1286}
1287
0cdd0c9f
RS
1288/* Erase the character (if any) at the position X, Y in frame F,
1289 then redraw it and the character after it.
1290 This is necessary when we erase endng at X,
1291 in case the character after X overlaps into the one before X.
1292 Call this function with input blocked. */
1293
1294static void
1295redraw_following_char (f, x, y, highlight_flag)
1296 FRAME_PTR f;
1297 int x, y;
1298 int highlight_flag;
dc6f92b8 1299{
0cdd0c9f
RS
1300 int limit = FRAME_CURRENT_GLYPHS (f)->used[y];
1301 /* Erase the character after the new ones, in case
1302 what was here before overlaps it.
1303 Reoutput that character, and the following character
1304 (in case the following character overlaps it). */
1305 if (x < limit
1306 && FRAME_CURRENT_GLYPHS (f)->glyphs[y][x] != SPACEGLYPH)
1307 {
1308 int end_x = x + 2;
1309 if (end_x > limit)
1310 end_x = limit;
334208b7 1311 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
0cdd0c9f
RS
1312 CHAR_TO_PIXEL_COL (f, x),
1313 CHAR_TO_PIXEL_ROW (f, y),
7556890b
RS
1314 FONT_WIDTH (f->output_data.x->font),
1315 f->output_data.x->line_height, False);
dc6f92b8 1316
0cdd0c9f
RS
1317 dumpglyphs (f, CHAR_TO_PIXEL_COL (f, x),
1318 CHAR_TO_PIXEL_ROW (f, y),
1319 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][x],
dc43ef94 1320 end_x - x, highlight_flag, 1, NULL);
0cdd0c9f
RS
1321 }
1322}
1323#endif /* 0 */
1324\f
1325#if 0 /* Not in use yet */
dc6f92b8 1326
0cdd0c9f 1327/* Return 1 if character C in font F extends past its left edge. */
dbc4e1c1 1328
0cdd0c9f
RS
1329static int
1330font_char_overlap_left (font, c)
1331 XFontStruct *font;
1332 int c;
1333{
1334 XCharStruct *s;
dbc4e1c1 1335
0cdd0c9f
RS
1336 /* Find the bounding-box info for C. */
1337 if (font->per_char == 0)
1338 s = &font->max_bounds;
1339 else
1340 {
1341 int rowlen = font->max_char_or_byte2 - font->min_char_or_byte2 + 1;
1342 int row, within;
58769bee 1343
0cdd0c9f
RS
1344 /* Decode char into row number (byte 1) and code within row (byte 2). */
1345 row = c >> 8;
1346 within = c & 0177;
1347 if (!(within >= font->min_char_or_byte2
1348 && within <= font->max_char_or_byte2
1349 && row >= font->min_byte1
1350 && row <= font->max_byte1))
1351 {
1352 /* If char is out of range, try the font's default char instead. */
1353 c = font->default_char;
68be917d 1354 row = c >> (BITS_PER_INT - 8);
0cdd0c9f
RS
1355 within = c & 0177;
1356 }
1357 if (!(within >= font->min_char_or_byte2
1358 && within <= font->max_char_or_byte2
1359 && row >= font->min_byte1
1360 && row <= font->max_byte1))
1361 /* Still out of range means this char does not overlap. */
1362 return 0;
1363 else
1364 /* We found the info for this char. */
1365 s = (font->per_char + (within - font->min_char_or_byte2)
1366 + row * rowlen);
1367 }
dbc4e1c1 1368
0cdd0c9f
RS
1369 return (s && s->lbearing < 0);
1370}
dbc4e1c1 1371
0cdd0c9f
RS
1372/* Return 1 if character C in font F extends past its right edge. */
1373
1374static int
1375font_char_overlap_right (font, c)
1376 XFontStruct *font;
1377 int c;
1378{
1379 XCharStruct *s;
1380
1381 /* Find the bounding-box info for C. */
1382 if (font->per_char == 0)
1383 s = &font->max_bounds;
1384 else
1385 {
1386 int rowlen = font->max_char_or_byte2 - font->min_char_or_byte2 + 1;
1387 int row, within;
58769bee 1388
0cdd0c9f
RS
1389 /* Decode char into row number (byte 1) and code within row (byte 2). */
1390 row = c >> 8;
1391 within = c & 0177;
1392 if (!(within >= font->min_char_or_byte2
1393 && within <= font->max_char_or_byte2
1394 && row >= font->min_byte1
1395 && row <= font->max_byte1))
1396 {
1397 /* If char is out of range, try the font's default char instead. */
1398 c = font->default_char;
68be917d 1399 row = c >> (BITS_PER_INT - 8);
0cdd0c9f
RS
1400 within = c & 0177;
1401 }
1402 if (!(within >= font->min_char_or_byte2
1403 && within <= font->max_char_or_byte2
1404 && row >= font->min_byte1
1405 && row <= font->max_byte1))
1406 /* Still out of range means this char does not overlap. */
1407 return 0;
1408 else
1409 /* We found the info for this char. */
1410 s = (font->per_char + (within - font->min_char_or_byte2)
1411 + row * rowlen);
1412 }
1413
1414 return (s && s->rbearing >= s->width);
dc6f92b8 1415}
0cdd0c9f 1416#endif /* 0 */
dc6f92b8 1417\f
dbc4e1c1
JB
1418/* Invert the middle quarter of the frame for .15 sec. */
1419
1420/* We use the select system call to do the waiting, so we have to make sure
eb8c3be9 1421 it's available. If it isn't, we just won't do visual bells. */
dbc4e1c1
JB
1422#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
1423
1424/* Subtract the `struct timeval' values X and Y,
1425 storing the result in RESULT.
1426 Return 1 if the difference is negative, otherwise 0. */
1427
1428static int
1429timeval_subtract (result, x, y)
1430 struct timeval *result, x, y;
1431{
1432 /* Perform the carry for the later subtraction by updating y.
1433 This is safer because on some systems
1434 the tv_sec member is unsigned. */
1435 if (x.tv_usec < y.tv_usec)
1436 {
1437 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
1438 y.tv_usec -= 1000000 * nsec;
1439 y.tv_sec += nsec;
1440 }
1441 if (x.tv_usec - y.tv_usec > 1000000)
1442 {
1443 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
1444 y.tv_usec += 1000000 * nsec;
1445 y.tv_sec -= nsec;
1446 }
1447
1448 /* Compute the time remaining to wait. tv_usec is certainly positive. */
1449 result->tv_sec = x.tv_sec - y.tv_sec;
1450 result->tv_usec = x.tv_usec - y.tv_usec;
1451
1452 /* Return indication of whether the result should be considered negative. */
1453 return x.tv_sec < y.tv_sec;
1454}
dc6f92b8 1455
f676886a
JB
1456XTflash (f)
1457 struct frame *f;
dc6f92b8 1458{
dbc4e1c1 1459 BLOCK_INPUT;
dc6f92b8 1460
dbc4e1c1
JB
1461 {
1462 GC gc;
dc6f92b8 1463
dbc4e1c1
JB
1464 /* Create a GC that will use the GXxor function to flip foreground pixels
1465 into background pixels. */
1466 {
1467 XGCValues values;
dc6f92b8 1468
dbc4e1c1 1469 values.function = GXxor;
7556890b
RS
1470 values.foreground = (f->output_data.x->foreground_pixel
1471 ^ f->output_data.x->background_pixel);
58769bee 1472
334208b7 1473 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
1474 GCFunction | GCForeground, &values);
1475 }
dc6f92b8 1476
dbc4e1c1 1477 {
e84e14c3
RS
1478 /* Get the height not including a menu bar widget. */
1479 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
1480 /* Height of each line to flash. */
1481 int flash_height = FRAME_LINE_HEIGHT (f);
1482 /* These will be the left and right margins of the rectangles. */
1483 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
1484 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
1485
1486 int width;
1487
1488 /* Don't flash the area between a scroll bar and the frame
1489 edge it is next to. */
1490 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
1491 {
1492 case vertical_scroll_bar_left:
1493 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
1494 break;
1495
1496 case vertical_scroll_bar_right:
1497 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
1498 break;
1499 }
1500
1501 width = flash_right - flash_left;
1502
1503 /* If window is tall, flash top and bottom line. */
1504 if (height > 3 * FRAME_LINE_HEIGHT (f))
1505 {
1506 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
1507 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
1508 width, flash_height);
1509 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
1510 flash_left,
1511 (height - flash_height
1512 - FRAME_INTERNAL_BORDER_WIDTH (f)),
1513 width, flash_height);
1514 }
1515 else
1516 /* If it is short, flash it all. */
1517 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
1518 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
1519 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 1520
334208b7 1521 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 1522
dbc4e1c1
JB
1523 {
1524 struct timeval wakeup, now;
dc6f92b8 1525
66c30ea1 1526 EMACS_GET_TIME (wakeup);
dc6f92b8 1527
dbc4e1c1
JB
1528 /* Compute time to wait until, propagating carry from usecs. */
1529 wakeup.tv_usec += 150000;
1530 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
1531 wakeup.tv_usec %= 1000000;
1532
1533 /* Keep waiting until past the time wakeup. */
1534 while (1)
1535 {
1536 struct timeval timeout;
1537
66c30ea1 1538 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
1539
1540 /* In effect, timeout = wakeup - timeout.
1541 Break if result would be negative. */
1542 if (timeval_subtract (&timeout, wakeup, timeout))
1543 break;
1544
1545 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 1546 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
1547 }
1548 }
58769bee 1549
e84e14c3
RS
1550 /* If window is tall, flash top and bottom line. */
1551 if (height > 3 * FRAME_LINE_HEIGHT (f))
1552 {
1553 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
1554 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
1555 width, flash_height);
1556 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
1557 flash_left,
1558 (height - flash_height
1559 - FRAME_INTERNAL_BORDER_WIDTH (f)),
1560 width, flash_height);
1561 }
1562 else
1563 /* If it is short, flash it all. */
1564 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
1565 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
1566 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
1567
334208b7
RS
1568 XFreeGC (FRAME_X_DISPLAY (f), gc);
1569 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 1570 }
dbc4e1c1
JB
1571 }
1572
1573 UNBLOCK_INPUT;
dc6f92b8
JB
1574}
1575
dbc4e1c1
JB
1576#endif
1577
1578
dc6f92b8
JB
1579/* Make audible bell. */
1580
334208b7 1581#define XRINGBELL XBell (FRAME_X_DISPLAY (selected_frame), 0)
dc6f92b8
JB
1582
1583XTring_bell ()
1584{
334208b7 1585 if (FRAME_X_DISPLAY (selected_frame) == 0)
5a6ef893
RS
1586 return;
1587
dbc4e1c1 1588#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
dc6f92b8 1589 if (visible_bell)
f676886a 1590 XTflash (selected_frame);
dc6f92b8 1591 else
dbc4e1c1 1592#endif
dc6f92b8
JB
1593 {
1594 BLOCK_INPUT;
1595 XRINGBELL;
334208b7 1596 XFlush (FRAME_X_DISPLAY (selected_frame));
dc6f92b8
JB
1597 UNBLOCK_INPUT;
1598 }
1599}
1600\f
f451eb13
JB
1601/* Insert and delete character.
1602 These are not supposed to be used because we are supposed to turn
1603 off the feature of using them. */
dc6f92b8 1604
58769bee 1605static
dc6f92b8
JB
1606XTinsert_glyphs (start, len)
1607 register char *start;
1608 register int len;
1609{
1610 abort ();
1611}
1612
58769bee 1613static
dc6f92b8
JB
1614XTdelete_glyphs (n)
1615 register int n;
1616{
1617 abort ();
1618}
1619\f
1620/* Specify how many text lines, from the top of the window,
1621 should be affected by insert-lines and delete-lines operations.
1622 This, and those operations, are used only within an update
1623 that is bounded by calls to XTupdate_begin and XTupdate_end. */
1624
1625static
1626XTset_terminal_window (n)
1627 register int n;
1628{
f676886a 1629 if (updating_frame == 0)
dc6f92b8
JB
1630 abort ();
1631
f676886a
JB
1632 if ((n <= 0) || (n > updating_frame->height))
1633 flexlines = updating_frame->height;
dc6f92b8
JB
1634 else
1635 flexlines = n;
1636}
1637\f
7a13e894
RS
1638/* These variables need not be per frame
1639 because redisplay is done on a frame-by-frame basis
1640 and the line dance for one frame is finished before
1641 anything is done for anoter frame. */
1642
58769bee
KH
1643/* Array of line numbers from cached insert/delete operations.
1644 line_dance[i] is the old position of the line that we want
1645 to move to line i, or -1 if we want a blank line there. */
1646static int *line_dance;
dc6f92b8 1647
58769bee
KH
1648/* Allocated length of that array. */
1649static int line_dance_len;
dc6f92b8 1650
58769bee
KH
1651/* Flag indicating whether we've done any work. */
1652static int line_dance_in_progress;
dc6f92b8 1653
58769bee
KH
1654/* Perform an insert-lines or delete-lines operation,
1655 inserting N lines or deleting -N lines at vertical position VPOS. */
1656XTins_del_lines (vpos, n)
1657 int vpos, n;
dc6f92b8 1658{
58769bee 1659 register int fence, i;
dc6f92b8 1660
58769bee 1661 if (vpos >= flexlines)
dc6f92b8
JB
1662 return;
1663
58769bee 1664 if (!line_dance_in_progress)
dc6f92b8 1665 {
58769bee
KH
1666 int ht = updating_frame->height;
1667 if (ht > line_dance_len)
1668 {
1669 line_dance = (int *)xrealloc (line_dance, ht * sizeof (int));
1670 line_dance_len = ht;
1671 }
1672 for (i = 0; i < ht; ++i) line_dance[i] = i;
1673 line_dance_in_progress = 1;
1674 }
1675 if (n >= 0)
1676 {
1677 if (n > flexlines - vpos)
1678 n = flexlines - vpos;
1679 fence = vpos + n;
1680 for (i = flexlines; --i >= fence;)
1681 line_dance[i] = line_dance[i-n];
1682 for (i = fence; --i >= vpos;)
1683 line_dance[i] = -1;
dc6f92b8
JB
1684 }
1685 else
1686 {
58769bee
KH
1687 n = -n;
1688 if (n > flexlines - vpos)
1689 n = flexlines - vpos;
1690 fence = flexlines - n;
1691 for (i = vpos; i < fence; ++i)
1692 line_dance[i] = line_dance[i + n];
1693 for (i = fence; i < flexlines; ++i)
1694 line_dance[i] = -1;
dc6f92b8
JB
1695 }
1696}
1697
58769bee
KH
1698/* Here's where we actually move the pixels around.
1699 Must be called with input blocked. */
1700static void
1701do_line_dance ()
dc6f92b8 1702{
58769bee
KH
1703 register int i, j, distance;
1704 register struct frame *f;
1705 int ht;
1706 int intborder;
1707
1708 /* Must check this flag first. If it's not set, then not only is the
1709 array uninitialized, but we might not even have a frame. */
1710 if (!line_dance_in_progress)
1711 return;
1712
1713 f = updating_frame;
1714 if (f == 0)
dc6f92b8
JB
1715 abort ();
1716
58769bee 1717 ht = f->height;
d9cdbb3d 1718 intborder = CHAR_TO_PIXEL_COL (f, FRAME_LEFT_SCROLL_BAR_WIDTH (f));
58769bee 1719
d1bc4182 1720 x_update_cursor (updating_frame, 0);
dc6f92b8 1721
58769bee
KH
1722 for (i = 0; i < ht; ++i)
1723 if (line_dance[i] != -1 && (distance = line_dance[i]-i) > 0)
1724 {
1725 for (j = i; (j < ht && line_dance[j] != -1
1726 && line_dance[j]-j == distance); ++j);
1727 /* Copy [i,j) upward from [i+distance,j+distance) */
334208b7 1728 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 1729 FRAME_X_WINDOW (f), f->output_data.x->normal_gc,
58769bee 1730 intborder, CHAR_TO_PIXEL_ROW (f, i+distance),
3cbd2e0b 1731 FRAME_WINDOW_WIDTH (f) * FONT_WIDTH (f->output_data.x->font),
7556890b 1732 (j-i) * f->output_data.x->line_height,
58769bee
KH
1733 intborder, CHAR_TO_PIXEL_ROW (f, i));
1734 i = j-1;
1735 }
dc6f92b8 1736
58769bee
KH
1737 for (i = ht; --i >=0; )
1738 if (line_dance[i] != -1 && (distance = line_dance[i]-i) < 0)
1739 {
1740 for (j = i; (--j >= 0 && line_dance[j] != -1
0ccf5d73 1741 && line_dance[j]-j == distance););
58769bee 1742 /* Copy (j,i] downward from (j+distance, i+distance] */
334208b7 1743 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 1744 FRAME_X_WINDOW (f), f->output_data.x->normal_gc,
58769bee 1745 intborder, CHAR_TO_PIXEL_ROW (f, j+1+distance),
3cbd2e0b 1746 FRAME_WINDOW_WIDTH (f) * FONT_WIDTH (f->output_data.x->font),
7556890b 1747 (i-j) * f->output_data.x->line_height,
58769bee
KH
1748 intborder, CHAR_TO_PIXEL_ROW (f, j+1));
1749 i = j+1;
1750 }
1751
1752 for (i = 0; i < ht; ++i)
1753 if (line_dance[i] == -1)
1754 {
1755 for (j = i; j < ht && line_dance[j] == -1; ++j);
1756 /* Clear [i,j) */
334208b7 1757 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
58769bee 1758 intborder, CHAR_TO_PIXEL_ROW (f, i),
3cbd2e0b 1759 FRAME_WINDOW_WIDTH (f) * FONT_WIDTH (f->output_data.x->font),
7556890b 1760 (j-i) * f->output_data.x->line_height, False);
58769bee
KH
1761 i = j-1;
1762 }
1763 line_dance_in_progress = 0;
dc6f92b8
JB
1764}
1765\f
f451eb13 1766/* Support routines for exposure events. */
dc6f92b8
JB
1767static void clear_cursor ();
1768
f676886a
JB
1769/* Output into a rectangle of an X-window (for frame F)
1770 the characters in f->phys_lines that overlap that rectangle.
dc6f92b8 1771 TOP and LEFT are the position of the upper left corner of the rectangle.
f94397b5
KH
1772 ROWS and COLS are the size of the rectangle.
1773 Call this function with input blocked. */
dc6f92b8
JB
1774
1775static void
f676886a
JB
1776dumprectangle (f, left, top, cols, rows)
1777 struct frame *f;
dc6f92b8
JB
1778 register int left, top, cols, rows;
1779{
f676886a 1780 register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
dc6f92b8
JB
1781 int cursor_cleared = 0;
1782 int bottom, right;
1783 register int y;
1784
f676886a 1785 if (FRAME_GARBAGED_P (f))
dc6f92b8
JB
1786 return;
1787
dc6f92b8
JB
1788 /* Express rectangle as four edges, instead of position-and-size. */
1789 bottom = top + rows;
1790 right = left + cols;
58769bee 1791
dc6f92b8
JB
1792 /* Convert rectangle edges in pixels to edges in chars.
1793 Round down for left and top, up for right and bottom. */
12ba150f
JB
1794 top = PIXEL_TO_CHAR_ROW (f, top);
1795 left = PIXEL_TO_CHAR_COL (f, left);
7556890b
RS
1796 bottom += (f->output_data.x->line_height - 1);
1797 right += (FONT_WIDTH (f->output_data.x->font) - 1);
12ba150f
JB
1798 bottom = PIXEL_TO_CHAR_ROW (f, bottom);
1799 right = PIXEL_TO_CHAR_COL (f, right);
dc6f92b8
JB
1800
1801 /* Clip the rectangle to what can be visible. */
1802 if (left < 0)
1803 left = 0;
1804 if (top < 0)
1805 top = 0;
d9cdbb3d
RS
1806 if (right > FRAME_WINDOW_WIDTH (f))
1807 right = FRAME_WINDOW_WIDTH (f);
f676886a
JB
1808 if (bottom > f->height)
1809 bottom = f->height;
dc6f92b8
JB
1810
1811 /* Get size in chars of the rectangle. */
1812 cols = right - left;
1813 rows = bottom - top;
1814
1815 /* If rectangle has zero area, return. */
1816 if (rows <= 0) return;
1817 if (cols <= 0) return;
1818
1819 /* Turn off the cursor if it is in the rectangle.
1820 We will turn it back on afterward. */
f676886a
JB
1821 if ((f->phys_cursor_x >= left) && (f->phys_cursor_x < right)
1822 && (f->phys_cursor_y >= top) && (f->phys_cursor_y < bottom))
dc6f92b8 1823 {
f676886a 1824 clear_cursor (f);
dc6f92b8
JB
1825 cursor_cleared = 1;
1826 }
1827
1828 /* Display the text in the rectangle, one text line at a time. */
1829
1830 for (y = top; y < bottom; y++)
1831 {
f676886a 1832 GLYPH *line = &active_frame->glyphs[y][left];
dc6f92b8 1833
f676886a 1834 if (! active_frame->enable[y] || left > active_frame->used[y])
dc6f92b8
JB
1835 continue;
1836
dc43ef94
KH
1837 while (*line & GLYPH_MASK_PADDING)
1838 {
1839 /* We must display the whole glyph of a wide-column
1840 character. */
1841 left--;
1842 line--;
1843 cols++;
1844 }
f676886a 1845 dumpglyphs (f,
12ba150f
JB
1846 CHAR_TO_PIXEL_COL (f, left),
1847 CHAR_TO_PIXEL_ROW (f, y),
1848 line, min (cols, active_frame->used[y] - left),
dc43ef94 1849 active_frame->highlight[y], 0, NULL);
dc6f92b8
JB
1850 }
1851
1852 /* Turn the cursor on if we turned it off. */
1853
1854 if (cursor_cleared)
d1bc4182 1855 x_update_cursor (f, 1);
dc6f92b8 1856}
dc6f92b8 1857\f
dc6f92b8 1858static void
334208b7
RS
1859frame_highlight (f)
1860 struct frame *f;
dc6f92b8 1861{
b3e1e05c
JB
1862 /* We used to only do this if Vx_no_window_manager was non-nil, but
1863 the ICCCM (section 4.1.6) says that the window's border pixmap
1864 and border pixel are window attributes which are "private to the
1865 client", so we can always change it to whatever we want. */
1866 BLOCK_INPUT;
334208b7 1867 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 1868 f->output_data.x->border_pixel);
b3e1e05c 1869 UNBLOCK_INPUT;
5d46f928 1870 x_update_cursor (f, 1);
dc6f92b8
JB
1871}
1872
1873static void
334208b7
RS
1874frame_unhighlight (f)
1875 struct frame *f;
dc6f92b8 1876{
b3e1e05c
JB
1877 /* We used to only do this if Vx_no_window_manager was non-nil, but
1878 the ICCCM (section 4.1.6) says that the window's border pixmap
1879 and border pixel are window attributes which are "private to the
1880 client", so we can always change it to whatever we want. */
1881 BLOCK_INPUT;
334208b7 1882 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 1883 f->output_data.x->border_tile);
b3e1e05c 1884 UNBLOCK_INPUT;
5d46f928 1885 x_update_cursor (f, 1);
dc6f92b8 1886}
dc6f92b8 1887
f676886a 1888static void XTframe_rehighlight ();
0f941935 1889static void x_frame_rehighlight ();
6d4238f3 1890
f676886a
JB
1891/* The focus has changed. Update the frames as necessary to reflect
1892 the new situation. Note that we can't change the selected frame
c5acd733 1893 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 1894 Each event gets marked with the frame in which it occurred, so the
c5acd733 1895 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 1896
6d4238f3 1897static void
0f941935
KH
1898x_new_focus_frame (dpyinfo, frame)
1899 struct x_display_info *dpyinfo;
f676886a 1900 struct frame *frame;
dc6f92b8 1901{
0f941935 1902 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8
JB
1903 int events_enqueued = 0;
1904
0f941935 1905 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 1906 {
58769bee 1907 /* Set this before calling other routines, so that they see
f676886a 1908 the correct value of x_focus_frame. */
0f941935 1909 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
1910
1911 if (old_focus && old_focus->auto_lower)
f676886a 1912 x_lower_frame (old_focus);
dc6f92b8
JB
1913
1914#if 0
f676886a 1915 selected_frame = frame;
e0c1aef2
KH
1916 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
1917 selected_frame);
f676886a
JB
1918 Fselect_window (selected_frame->selected_window);
1919 choose_minibuf_frame ();
c118dd06 1920#endif /* ! 0 */
dc6f92b8 1921
0f941935
KH
1922 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
1923 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
1924 else
1925 pending_autoraise_frame = 0;
6d4238f3 1926 }
dc6f92b8 1927
0f941935 1928 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
1929}
1930
37c2c98b
RS
1931/* Handle an event saying the mouse has moved out of an Emacs frame. */
1932
1933void
0f941935
KH
1934x_mouse_leave (dpyinfo)
1935 struct x_display_info *dpyinfo;
37c2c98b 1936{
0f941935 1937 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 1938}
6d4238f3 1939
f451eb13
JB
1940/* The focus has changed, or we have redirected a frame's focus to
1941 another frame (this happens when a frame uses a surrogate
0f941935
KH
1942 minibuffer frame). Shift the highlight as appropriate.
1943
1944 The FRAME argument doesn't necessarily have anything to do with which
1945 frame is being highlighted or unhighlighted; we only use it to find
1946 the appropriate X display info. */
6d4238f3 1947static void
0f941935
KH
1948XTframe_rehighlight (frame)
1949 struct frame *frame;
6d4238f3 1950{
0f941935
KH
1951 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
1952}
6d4238f3 1953
0f941935
KH
1954static void
1955x_frame_rehighlight (dpyinfo)
1956 struct x_display_info *dpyinfo;
1957{
1958 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1959
1960 if (dpyinfo->x_focus_frame)
6d4238f3 1961 {
0f941935
KH
1962 dpyinfo->x_highlight_frame
1963 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
1964 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1965 : dpyinfo->x_focus_frame);
1966 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 1967 {
0f941935
KH
1968 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
1969 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 1970 }
dc6f92b8 1971 }
6d4238f3 1972 else
0f941935 1973 dpyinfo->x_highlight_frame = 0;
dc6f92b8 1974
0f941935 1975 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
1976 {
1977 if (old_highlight)
f676886a 1978 frame_unhighlight (old_highlight);
0f941935
KH
1979 if (dpyinfo->x_highlight_frame)
1980 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 1981 }
dc6f92b8
JB
1982}
1983\f
e4571a43 1984/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 1985
28430d3c
JB
1986/* Initialize mode_switch_bit and modifier_meaning. */
1987static void
334208b7
RS
1988x_find_modifier_meanings (dpyinfo)
1989 struct x_display_info *dpyinfo;
28430d3c 1990{
f689eb05 1991 int min_code, max_code;
28430d3c
JB
1992 KeySym *syms;
1993 int syms_per_code;
1994 XModifierKeymap *mods;
1995
334208b7
RS
1996 dpyinfo->meta_mod_mask = 0;
1997 dpyinfo->shift_lock_mask = 0;
1998 dpyinfo->alt_mod_mask = 0;
1999 dpyinfo->super_mod_mask = 0;
2000 dpyinfo->hyper_mod_mask = 0;
58769bee 2001
9658a521 2002#ifdef HAVE_X11R4
334208b7 2003 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 2004#else
4a60f8c5
RS
2005 min_code = dpyinfo->display->min_keycode;
2006 max_code = dpyinfo->display->max_keycode;
9658a521
JB
2007#endif
2008
334208b7 2009 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
2010 min_code, max_code - min_code + 1,
2011 &syms_per_code);
334208b7 2012 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 2013
58769bee 2014 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 2015 Alt keysyms are on. */
28430d3c
JB
2016 {
2017 int row, col; /* The row and column in the modifier table. */
2018
2019 for (row = 3; row < 8; row++)
2020 for (col = 0; col < mods->max_keypermod; col++)
2021 {
0299d313
RS
2022 KeyCode code
2023 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 2024
af92970c
KH
2025 /* Zeroes are used for filler. Skip them. */
2026 if (code == 0)
2027 continue;
2028
28430d3c
JB
2029 /* Are any of this keycode's keysyms a meta key? */
2030 {
2031 int code_col;
2032
2033 for (code_col = 0; code_col < syms_per_code; code_col++)
2034 {
f689eb05 2035 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 2036
f689eb05 2037 switch (sym)
28430d3c 2038 {
f689eb05
JB
2039 case XK_Meta_L:
2040 case XK_Meta_R:
334208b7 2041 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 2042 break;
f689eb05
JB
2043
2044 case XK_Alt_L:
2045 case XK_Alt_R:
334208b7 2046 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
2047 break;
2048
2049 case XK_Hyper_L:
2050 case XK_Hyper_R:
334208b7 2051 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
2052 break;
2053
2054 case XK_Super_L:
2055 case XK_Super_R:
334208b7 2056 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 2057 break;
11edeb03
JB
2058
2059 case XK_Shift_Lock:
2060 /* Ignore this if it's not on the lock modifier. */
2061 if ((1 << row) == LockMask)
334208b7 2062 dpyinfo->shift_lock_mask = LockMask;
11edeb03 2063 break;
28430d3c
JB
2064 }
2065 }
2066 }
2067 }
2068 }
2069
f689eb05 2070 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 2071 if (! dpyinfo->meta_mod_mask)
a3c44b14 2072 {
334208b7
RS
2073 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
2074 dpyinfo->alt_mod_mask = 0;
a3c44b14 2075 }
f689eb05 2076
148c4b70
RS
2077 /* If some keys are both alt and meta,
2078 make them just meta, not alt. */
334208b7 2079 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 2080 {
334208b7 2081 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 2082 }
58769bee 2083
28430d3c 2084 XFree ((char *) syms);
f689eb05 2085 XFreeModifiermap (mods);
28430d3c
JB
2086}
2087
dfeccd2d
JB
2088/* Convert between the modifier bits X uses and the modifier bits
2089 Emacs uses. */
7c5283e4 2090static unsigned int
334208b7
RS
2091x_x_to_emacs_modifiers (dpyinfo, state)
2092 struct x_display_info *dpyinfo;
dc6f92b8
JB
2093 unsigned int state;
2094{
334208b7
RS
2095 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
2096 | ((state & ControlMask) ? ctrl_modifier : 0)
2097 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
2098 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
2099 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
2100 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
2101}
2102
dfeccd2d 2103static unsigned int
334208b7
RS
2104x_emacs_to_x_modifiers (dpyinfo, state)
2105 struct x_display_info *dpyinfo;
dfeccd2d
JB
2106 unsigned int state;
2107{
334208b7
RS
2108 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
2109 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
2110 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
2111 | ((state & shift_modifier) ? ShiftMask : 0)
2112 | ((state & ctrl_modifier) ? ControlMask : 0)
2113 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 2114}
d047c4eb
KH
2115
2116/* Convert a keysym to its name. */
2117
2118char *
2119x_get_keysym_name (keysym)
2120 KeySym keysym;
2121{
2122 char *value;
2123
2124 BLOCK_INPUT;
2125 value = XKeysymToString (keysym);
2126 UNBLOCK_INPUT;
2127
2128 return value;
2129}
e4571a43
JB
2130\f
2131/* Mouse clicks and mouse movement. Rah. */
e4571a43
JB
2132
2133/* Given a pixel position (PIX_X, PIX_Y) on the frame F, return
2134 glyph co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle
69388238
RS
2135 that the glyph at X, Y occupies, if BOUNDS != 0.
2136 If NOCLIP is nonzero, do not force the value into range. */
2137
c8dba240 2138void
69388238 2139pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 2140 FRAME_PTR f;
69388238 2141 register int pix_x, pix_y;
e4571a43
JB
2142 register int *x, *y;
2143 XRectangle *bounds;
69388238 2144 int noclip;
e4571a43 2145{
69388238
RS
2146 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
2147 even for negative values. */
2148 if (pix_x < 0)
7556890b 2149 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 2150 if (pix_y < 0)
7556890b 2151 pix_y -= (f)->output_data.x->line_height - 1;
69388238 2152
e4571a43
JB
2153 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
2154 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
2155
2156 if (bounds)
2157 {
7556890b
RS
2158 bounds->width = FONT_WIDTH (f->output_data.x->font);
2159 bounds->height = f->output_data.x->line_height;
e4571a43
JB
2160 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
2161 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
2162 }
2163
69388238
RS
2164 if (!noclip)
2165 {
2166 if (pix_x < 0)
2167 pix_x = 0;
3cbd2e0b
RS
2168 else if (pix_x > FRAME_WINDOW_WIDTH (f))
2169 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
2170
2171 if (pix_y < 0)
2172 pix_y = 0;
2173 else if (pix_y > f->height)
2174 pix_y = f->height;
2175 }
e4571a43
JB
2176
2177 *x = pix_x;
2178 *y = pix_y;
2179}
2180
2b5c9e71
RS
2181void
2182glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
2183 FRAME_PTR f;
2184 register int x, y;
2185 register int *pix_x, *pix_y;
2186{
2187 *pix_x = CHAR_TO_PIXEL_COL (f, x);
2188 *pix_y = CHAR_TO_PIXEL_ROW (f, y);
2189}
2190
dc6f92b8
JB
2191/* Prepare a mouse-event in *RESULT for placement in the input queue.
2192
2193 If the event is a button press, then note that we have grabbed
f451eb13 2194 the mouse. */
dc6f92b8
JB
2195
2196static Lisp_Object
f451eb13 2197construct_mouse_click (result, event, f)
dc6f92b8
JB
2198 struct input_event *result;
2199 XButtonEvent *event;
f676886a 2200 struct frame *f;
dc6f92b8 2201{
f451eb13 2202 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 2203 otherwise. */
f451eb13 2204 result->kind = mouse_click;
69388238 2205 result->code = event->button - Button1;
1113d9db 2206 result->timestamp = event->time;
334208b7
RS
2207 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
2208 event->state)
f689eb05 2209 | (event->type == ButtonRelease
58769bee 2210 ? up_modifier
f689eb05 2211 : down_modifier));
dc6f92b8 2212
f451eb13
JB
2213 {
2214 int row, column;
dc6f92b8 2215
2b5c9e71 2216#if 0
69388238 2217 pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL, 0);
90e1eb6f
KH
2218 XSETFASTINT (result->x, column);
2219 XSETFASTINT (result->y, row);
2b5c9e71 2220#endif
e0c1aef2
KH
2221 XSETINT (result->x, event->x);
2222 XSETINT (result->y, event->y);
2223 XSETFRAME (result->frame_or_window, f);
f451eb13 2224 }
dc6f92b8 2225}
b849c413
RS
2226
2227/* Prepare a menu-event in *RESULT for placement in the input queue. */
2228
2229static Lisp_Object
2230construct_menu_click (result, event, f)
2231 struct input_event *result;
2232 XButtonEvent *event;
2233 struct frame *f;
2234{
2235 /* Make the event type no_event; we'll change that when we decide
2236 otherwise. */
2237 result->kind = mouse_click;
26459b28 2238 result->code = event->button - Button1;
b849c413 2239 result->timestamp = event->time;
334208b7
RS
2240 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
2241 event->state)
b849c413 2242 | (event->type == ButtonRelease
58769bee 2243 ? up_modifier
b849c413
RS
2244 : down_modifier));
2245
e0c1aef2
KH
2246 XSETINT (result->x, event->x);
2247 XSETINT (result->y, -1);
2248 XSETFRAME (result->frame_or_window, f);
b849c413 2249}
69388238 2250\f
90e65f07
JB
2251/* Function to report a mouse movement to the mainstream Emacs code.
2252 The input handler calls this.
2253
2254 We have received a mouse movement event, which is given in *event.
2255 If the mouse is over a different glyph than it was last time, tell
2256 the mainstream emacs code by setting mouse_moved. If not, ask for
2257 another motion event, so we can check again the next time it moves. */
b8009dd1 2258
90e65f07 2259static void
12ba150f 2260note_mouse_movement (frame, event)
f676886a 2261 FRAME_PTR frame;
90e65f07 2262 XMotionEvent *event;
90e65f07 2263{
e5d77022
JB
2264 last_mouse_movement_time = event->time;
2265
27f338af
RS
2266 if (event->window != FRAME_X_WINDOW (frame))
2267 {
39d8bb4d 2268 frame->mouse_moved = 1;
27f338af
RS
2269 last_mouse_scroll_bar = Qnil;
2270
2271 note_mouse_highlight (frame, -1, -1);
27f338af
RS
2272 }
2273
90e65f07 2274 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
2275 else if (event->x < last_mouse_glyph.x
2276 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
2277 || event->y < last_mouse_glyph.y
2278 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 2279 {
39d8bb4d 2280 frame->mouse_moved = 1;
ab648270 2281 last_mouse_scroll_bar = Qnil;
b8009dd1
RS
2282
2283 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
2284 }
2285}
2286
bf1c0ba1
RS
2287/* This is used for debugging, to turn off note_mouse_highlight. */
2288static int disable_mouse_highlight;
2289
b8009dd1
RS
2290/* Take proper action when the mouse has moved to position X, Y on frame F
2291 as regards highlighting characters that have mouse-face properties.
27f338af
RS
2292 Also dehighlighting chars where the mouse was before.
2293 X and Y can be negative or out of range. */
b8009dd1
RS
2294
2295static void
2296note_mouse_highlight (f, x, y)
2297 FRAME_PTR f;
c32cdd9a 2298 int x, y;
b8009dd1
RS
2299{
2300 int row, column, portion;
2301 XRectangle new_glyph;
2302 Lisp_Object window;
2303 struct window *w;
2304
bf1c0ba1
RS
2305 if (disable_mouse_highlight)
2306 return;
2307
7a13e894
RS
2308 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x = x;
2309 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y = y;
2310 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame = f;
b8009dd1 2311
7a13e894 2312 if (FRAME_X_DISPLAY_INFO (f)->mouse_face_defer)
b8009dd1
RS
2313 return;
2314
514e4681
RS
2315 if (gc_in_progress)
2316 {
7a13e894 2317 FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc = 1;
514e4681
RS
2318 return;
2319 }
2320
b8009dd1
RS
2321 /* Find out which glyph the mouse is on. */
2322 pixel_to_glyph_coords (f, x, y, &column, &row,
334208b7 2323 &new_glyph, FRAME_X_DISPLAY_INFO (f)->grabbed);
b8009dd1
RS
2324
2325 /* Which window is that in? */
2326 window = window_from_coordinates (f, column, row, &portion);
2327 w = XWINDOW (window);
2328
2329 /* If we were displaying active text in another window, clear that. */
7a13e894
RS
2330 if (! EQ (window, FRAME_X_DISPLAY_INFO (f)->mouse_face_window))
2331 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
b8009dd1 2332
0cdd0c9f
RS
2333 /* Are we in a window whose display is up to date?
2334 And verify the buffer's text has not changed. */
27f338af
RS
2335 if (WINDOWP (window) && portion == 0 && row >= 0 && column >= 0
2336 && row < FRAME_HEIGHT (f) && column < FRAME_WIDTH (f)
0cdd0c9f 2337 && EQ (w->window_end_valid, w->buffer)
26459b28
KH
2338 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
2339 && (XFASTINT (w->last_overlay_modified)
2340 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
b8009dd1
RS
2341 {
2342 int *ptr = FRAME_CURRENT_GLYPHS (f)->charstarts[row];
2343 int i, pos;
2344
2345 /* Find which buffer position the mouse corresponds to. */
2346 for (i = column; i >= 0; i--)
2347 if (ptr[i] > 0)
2348 break;
2349 pos = ptr[i];
2350 /* Is it outside the displayed active region (if any)? */
55836b73 2351 if (pos <= 0)
7a13e894
RS
2352 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
2353 else if (! (EQ (window, FRAME_X_DISPLAY_INFO (f)->mouse_face_window)
2354 && row >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
2355 && row <= FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
2356 && (row > FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
2357 || column >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col)
2358 && (row < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
2359 || column < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col
2360 || FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end)))
b8009dd1
RS
2361 {
2362 Lisp_Object mouse_face, overlay, position;
2363 Lisp_Object *overlay_vec;
2364 int len, noverlays, ignor1;
f8bdb8e6 2365 struct buffer *obuf;
e444162e 2366 int obegv, ozv;
f8bdb8e6 2367
e444162e
RS
2368 /* If we get an out-of-range value, return now; avoid an error. */
2369 if (pos > BUF_Z (XBUFFER (w->buffer)))
f8bdb8e6 2370 return;
b8009dd1 2371
09fe4c31
RS
2372 /* Make the window's buffer temporarily current for
2373 overlays_at and compute_char_face. */
f8bdb8e6 2374 obuf = current_buffer;
09fe4c31 2375 current_buffer = XBUFFER (w->buffer);
e444162e
RS
2376 obegv = BEGV;
2377 ozv = ZV;
2378 BEGV = BEG;
2379 ZV = Z;
09fe4c31 2380
b8009dd1 2381 /* Yes. Clear the display of the old active region, if any. */
7a13e894 2382 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
b8009dd1
RS
2383
2384 /* Is this char mouse-active? */
e0c1aef2 2385 XSETINT (position, pos);
b8009dd1
RS
2386
2387 len = 10;
2388 overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
2389
2390 /* Put all the overlays we want in a vector in overlay_vec.
2391 Store the length in len. */
26459b28 2392 noverlays = overlays_at (pos, 1, &overlay_vec, &len,
7965883b 2393 NULL, NULL);
09fe4c31 2394 noverlays = sort_overlays (overlay_vec, noverlays, w);
b8009dd1
RS
2395
2396 /* Find the highest priority overlay that has a mouse-face prop. */
2397 overlay = Qnil;
2398 for (i = 0; i < noverlays; i++)
2399 {
2400 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
2401 if (!NILP (mouse_face))
2402 {
2403 overlay = overlay_vec[i];
2404 break;
2405 }
2406 }
2407 free (overlay_vec);
2408 /* If no overlay applies, get a text property. */
2409 if (NILP (overlay))
2410 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
2411
2412 /* Handle the overlay case. */
2413 if (! NILP (overlay))
2414 {
2415 /* Find the range of text around this char that
2416 should be active. */
2417 Lisp_Object before, after;
2418 int ignore;
2419
2420 before = Foverlay_start (overlay);
2421 after = Foverlay_end (overlay);
2422 /* Record this as the current active region. */
2ef60670 2423 fast_find_position (window, XFASTINT (before),
7a13e894
RS
2424 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col,
2425 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row);
2426 FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end
2ef60670 2427 = !fast_find_position (window, XFASTINT (after),
7a13e894
RS
2428 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col,
2429 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row);
2430 FRAME_X_DISPLAY_INFO (f)->mouse_face_window = window;
2431 FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id
2432 = compute_char_face (f, w, pos, 0, 0,
2433 &ignore, pos + 1, 1);
b8009dd1
RS
2434
2435 /* Display it as active. */
7a13e894 2436 show_mouse_face (FRAME_X_DISPLAY_INFO (f), 1);
b8009dd1
RS
2437 }
2438 /* Handle the text property case. */
2439 else if (! NILP (mouse_face))
2440 {
2441 /* Find the range of text around this char that
2442 should be active. */
2443 Lisp_Object before, after, beginning, end;
2444 int ignore;
2445
2446 beginning = Fmarker_position (w->start);
e0c1aef2
KH
2447 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
2448 - XFASTINT (w->window_end_pos)));
b8009dd1
RS
2449 before
2450 = Fprevious_single_property_change (make_number (pos + 1),
2451 Qmouse_face,
2452 w->buffer, beginning);
2453 after
2454 = Fnext_single_property_change (position, Qmouse_face,
2455 w->buffer, end);
2456 /* Record this as the current active region. */
2ef60670 2457 fast_find_position (window, XFASTINT (before),
7a13e894
RS
2458 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col,
2459 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row);
2460 FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end
2ef60670 2461 = !fast_find_position (window, XFASTINT (after),
7a13e894
RS
2462 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col,
2463 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row);
2464 FRAME_X_DISPLAY_INFO (f)->mouse_face_window = window;
2465 FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id
b8009dd1
RS
2466 = compute_char_face (f, w, pos, 0, 0,
2467 &ignore, pos + 1, 1);
2468
2469 /* Display it as active. */
7a13e894 2470 show_mouse_face (FRAME_X_DISPLAY_INFO (f), 1);
b8009dd1 2471 }
e444162e
RS
2472 BEGV = obegv;
2473 ZV = ozv;
09fe4c31 2474 current_buffer = obuf;
b8009dd1 2475 }
b8009dd1
RS
2476 }
2477}
2478\f
2479/* Find the row and column of position POS in window WINDOW.
2480 Store them in *COLUMNP and *ROWP.
bf1c0ba1
RS
2481 This assumes display in WINDOW is up to date.
2482 If POS is above start of WINDOW, return coords
2483 of start of first screen line.
4d73d038
RS
2484 If POS is after end of WINDOW, return coords of end of last screen line.
2485
2486 Value is 1 if POS is in range, 0 if it was off screen. */
b8009dd1
RS
2487
2488static int
2489fast_find_position (window, pos, columnp, rowp)
2490 Lisp_Object window;
2491 int pos;
2492 int *columnp, *rowp;
2493{
2494 struct window *w = XWINDOW (window);
2495 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2496 int i;
4d73d038 2497 int row = 0;
d9cdbb3d 2498 int left = WINDOW_LEFT_MARGIN (w);
26459b28 2499 int top = XFASTINT (w->top);
b8009dd1
RS
2500 int height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
2501 int width = window_internal_width (w);
2502 int *charstarts;
bf1c0ba1 2503 int lastcol;
77b68646 2504 int maybe_next_line = 0;
b8009dd1 2505
4d73d038 2506 /* Find the right row. */
b8009dd1
RS
2507 for (i = 0;
2508 i < height;
2509 i++)
2510 {
2511 int linestart = FRAME_CURRENT_GLYPHS (f)->charstarts[top + i][left];
2512 if (linestart > pos)
2513 break;
77b68646
RS
2514 /* If the position sought is the end of the buffer,
2515 don't include the blank lines at the bottom of the window. */
2516 if (linestart == pos && pos == BUF_ZV (XBUFFER (w->buffer)))
2517 {
2518 maybe_next_line = 1;
2519 break;
2520 }
b8009dd1
RS
2521 if (linestart > 0)
2522 row = i;
2523 }
2524
4d73d038 2525 /* Find the right column with in it. */
b8009dd1 2526 charstarts = FRAME_CURRENT_GLYPHS (f)->charstarts[top + row];
bf1c0ba1 2527 lastcol = left;
b8009dd1 2528 for (i = 0; i < width; i++)
bf1c0ba1
RS
2529 {
2530 if (charstarts[left + i] == pos)
2531 {
2532 *rowp = row + top;
2533 *columnp = i + left;
2534 return 1;
2535 }
2536 else if (charstarts[left + i] > pos)
4d73d038
RS
2537 break;
2538 else if (charstarts[left + i] > 0)
bf1c0ba1
RS
2539 lastcol = left + i;
2540 }
b8009dd1 2541
77b68646
RS
2542 /* If we're looking for the end of the buffer,
2543 and we didn't find it in the line we scanned,
2544 use the start of the following line. */
2545 if (maybe_next_line)
2546 {
2547 row++;
e932d73d 2548 lastcol = left;
77b68646
RS
2549 }
2550
bf1c0ba1
RS
2551 *rowp = row + top;
2552 *columnp = lastcol;
b8009dd1
RS
2553 return 0;
2554}
2555
2556/* Display the active region described by mouse_face_*
2557 in its mouse-face if HL > 0, in its normal face if HL = 0. */
2558
2559static void
7a13e894
RS
2560show_mouse_face (dpyinfo, hl)
2561 struct x_display_info *dpyinfo;
b8009dd1
RS
2562 int hl;
2563{
7a13e894 2564 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
b8009dd1
RS
2565 int width = window_internal_width (w);
2566 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2567 int i;
514e4681 2568 int cursor_off = 0;
2729a2b5
RS
2569 int old_curs_x = curs_x;
2570 int old_curs_y = curs_y;
2571
2572 /* Set these variables temporarily
2573 so that if we have to turn the cursor off and on again
2574 we will put it back at the same place. */
2575 curs_x = f->phys_cursor_x;
2576 curs_y = f->phys_cursor_y;
7a13e894
RS
2577 for (i = FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row;
2578 i <= FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row; i++)
b8009dd1 2579 {
7a13e894
RS
2580 int column = (i == FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
2581 ? FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col
d9cdbb3d 2582 : WINDOW_LEFT_MARGIN (w));
7a13e894
RS
2583 int endcolumn = (i == FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
2584 ? FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col
d9cdbb3d 2585 : WINDOW_LEFT_MARGIN (w) + width);
6f4c2453 2586 endcolumn = min (endcolumn, FRAME_CURRENT_GLYPHS (f)->used[i]);
514e4681
RS
2587
2588 /* If the cursor's in the text we are about to rewrite,
2589 turn the cursor off. */
2590 if (i == curs_y
0d43a5d9
RS
2591 && curs_x >= column - 1
2592 && curs_x <= endcolumn)
514e4681 2593 {
d1bc4182 2594 x_update_cursor (f, 0);
514e4681
RS
2595 cursor_off = 1;
2596 }
b8009dd1
RS
2597
2598 dumpglyphs (f,
2599 CHAR_TO_PIXEL_COL (f, column),
2600 CHAR_TO_PIXEL_ROW (f, i),
2601 FRAME_CURRENT_GLYPHS (f)->glyphs[i] + column,
2602 endcolumn - column,
2603 /* Highlight with mouse face if hl > 0. */
dc43ef94 2604 hl > 0 ? 3 : 0, 0, NULL);
b8009dd1
RS
2605 }
2606
514e4681
RS
2607 /* If we turned the cursor off, turn it back on. */
2608 if (cursor_off)
2729a2b5
RS
2609 x_display_cursor (f, 1, curs_x, curs_y);
2610
2611 curs_x = old_curs_x;
2612 curs_y = old_curs_y;
fb3b7de5 2613
27ead1d5
FP
2614 /* Change the mouse cursor according to the value of HL. */
2615 if (hl > 0)
334208b7 2616 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 2617 f->output_data.x->cross_cursor);
27ead1d5 2618 else
334208b7 2619 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 2620 f->output_data.x->text_cursor);
b8009dd1
RS
2621}
2622
2623/* Clear out the mouse-highlighted active region.
2624 Redraw it unhighlighted first. */
2625
2626static void
7a13e894
RS
2627clear_mouse_face (dpyinfo)
2628 struct x_display_info *dpyinfo;
b8009dd1 2629{
7a13e894
RS
2630 if (! NILP (dpyinfo->mouse_face_window))
2631 show_mouse_face (dpyinfo, 0);
b8009dd1 2632
7a13e894
RS
2633 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2634 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2635 dpyinfo->mouse_face_window = Qnil;
b8009dd1 2636}
e687d06e
RS
2637
2638/* Just discard the mouse face information for frame F, if any.
2639 This is used when the size of F is changed. */
2640
2641cancel_mouse_face (f)
2642 FRAME_PTR f;
2643{
2644 Lisp_Object window;
2645 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
2646
2647 window = dpyinfo->mouse_face_window;
2648 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
2649 {
2650 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2651 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2652 dpyinfo->mouse_face_window = Qnil;
2653 }
2654}
b8009dd1 2655\f
ab648270
JB
2656static struct scroll_bar *x_window_to_scroll_bar ();
2657static void x_scroll_bar_report_motion ();
12ba150f 2658
90e65f07 2659/* Return the current position of the mouse.
2d7fc7e8 2660 *fp should be a frame which indicates which display to ask about.
90e65f07 2661
2d7fc7e8 2662 If the mouse movement started in a scroll bar, set *fp, *bar_window,
ab648270 2663 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 2664 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 2665 position on the scroll bar.
12ba150f 2666
2d7fc7e8 2667 If the mouse movement started elsewhere, set *fp to the frame the
12ba150f
JB
2668 mouse is on, *bar_window to nil, and *x and *y to the character cell
2669 the mouse is over.
2670
2671 Set *time to the server timestamp for the time at which the mouse
2672 was at this position.
2673
a135645a
RS
2674 Don't store anything if we don't have a valid set of values to report.
2675
90e65f07 2676 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 2677 movement. */
90e65f07
JB
2678
2679static void
1cf412ec 2680XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 2681 FRAME_PTR *fp;
1cf412ec 2682 int insist;
12ba150f 2683 Lisp_Object *bar_window;
ab648270 2684 enum scroll_bar_part *part;
90e65f07 2685 Lisp_Object *x, *y;
e5d77022 2686 unsigned long *time;
90e65f07 2687{
a135645a
RS
2688 FRAME_PTR f1;
2689
90e65f07
JB
2690 BLOCK_INPUT;
2691
ab648270 2692 if (! NILP (last_mouse_scroll_bar))
334208b7 2693 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
2694 else
2695 {
12ba150f
JB
2696 Window root;
2697 int root_x, root_y;
90e65f07 2698
12ba150f
JB
2699 Window dummy_window;
2700 int dummy;
2701
39d8bb4d
KH
2702 Lisp_Object frame, tail;
2703
2704 /* Clear the mouse-moved flag for every frame on this display. */
2705 FOR_EACH_FRAME (tail, frame)
2706 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
2707 XFRAME (frame)->mouse_moved = 0;
2708
ab648270 2709 last_mouse_scroll_bar = Qnil;
12ba150f
JB
2710
2711 /* Figure out which root window we're on. */
334208b7
RS
2712 XQueryPointer (FRAME_X_DISPLAY (*fp),
2713 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
2714
2715 /* The root window which contains the pointer. */
2716 &root,
2717
2718 /* Trash which we can't trust if the pointer is on
2719 a different screen. */
2720 &dummy_window,
2721
2722 /* The position on that root window. */
58769bee 2723 &root_x, &root_y,
12ba150f
JB
2724
2725 /* More trash we can't trust. */
2726 &dummy, &dummy,
2727
2728 /* Modifier keys and pointer buttons, about which
2729 we don't care. */
2730 (unsigned int *) &dummy);
2731
2732 /* Now we have a position on the root; find the innermost window
2733 containing the pointer. */
2734 {
2735 Window win, child;
2736 int win_x, win_y;
2737 int parent_x, parent_y;
e99db5a1 2738 int count;
12ba150f
JB
2739
2740 win = root;
69388238 2741
2d7fc7e8
RS
2742 /* XTranslateCoordinates can get errors if the window
2743 structure is changing at the same time this function
2744 is running. So at least we must not crash from them. */
2745
e99db5a1 2746 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 2747
334208b7 2748 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 2749 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 2750 {
69388238
RS
2751 /* If mouse was grabbed on a frame, give coords for that frame
2752 even if the mouse is now outside it. */
334208b7 2753 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 2754
12ba150f 2755 /* From-window, to-window. */
69388238 2756 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
2757
2758 /* From-position, to-position. */
2759 root_x, root_y, &win_x, &win_y,
2760
2761 /* Child of win. */
2762 &child);
69388238
RS
2763 f1 = last_mouse_frame;
2764 }
2765 else
2766 {
2767 while (1)
2768 {
334208b7 2769 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 2770
69388238
RS
2771 /* From-window, to-window. */
2772 root, win,
12ba150f 2773
69388238
RS
2774 /* From-position, to-position. */
2775 root_x, root_y, &win_x, &win_y,
2776
2777 /* Child of win. */
2778 &child);
2779
9af3143a 2780 if (child == None || child == win)
69388238
RS
2781 break;
2782
2783 win = child;
2784 parent_x = win_x;
2785 parent_y = win_y;
2786 }
12ba150f 2787
69388238
RS
2788 /* Now we know that:
2789 win is the innermost window containing the pointer
2790 (XTC says it has no child containing the pointer),
2791 win_x and win_y are the pointer's position in it
2792 (XTC did this the last time through), and
2793 parent_x and parent_y are the pointer's position in win's parent.
2794 (They are what win_x and win_y were when win was child.
2795 If win is the root window, it has no parent, and
2796 parent_{x,y} are invalid, but that's okay, because we'll
2797 never use them in that case.) */
2798
2799 /* Is win one of our frames? */
19126e11 2800 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
69388238 2801 }
58769bee 2802
2d7fc7e8
RS
2803 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
2804 f1 = 0;
2805
e99db5a1 2806 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 2807
ab648270 2808 /* If not, is it one of our scroll bars? */
a135645a 2809 if (! f1)
12ba150f 2810 {
ab648270 2811 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
2812
2813 if (bar)
2814 {
a135645a 2815 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
2816 win_x = parent_x;
2817 win_y = parent_y;
2818 }
2819 }
90e65f07 2820
1cf412ec
RS
2821 if (f1 == 0 && insist)
2822 f1 = selected_frame;
2823
a135645a 2824 if (f1)
12ba150f 2825 {
2b5c9e71
RS
2826 int ignore1, ignore2;
2827
2828 /* Ok, we found a frame. Store all the values. */
a135645a 2829
2b5c9e71 2830 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
334208b7 2831 &last_mouse_glyph,
1cf412ec
RS
2832 FRAME_X_DISPLAY_INFO (f1)->grabbed
2833 || insist);
12ba150f
JB
2834
2835 *bar_window = Qnil;
2836 *part = 0;
334208b7 2837 *fp = f1;
e0c1aef2
KH
2838 XSETINT (*x, win_x);
2839 XSETINT (*y, win_y);
12ba150f
JB
2840 *time = last_mouse_movement_time;
2841 }
2842 }
2843 }
90e65f07
JB
2844
2845 UNBLOCK_INPUT;
2846}
c118dd06 2847\f
ab648270 2848/* Scroll bar support. */
f451eb13 2849
ab648270
JB
2850/* Given an X window ID, find the struct scroll_bar which manages it.
2851 This can be called in GC, so we have to make sure to strip off mark
2852 bits. */
2853static struct scroll_bar *
2854x_window_to_scroll_bar (window_id)
f451eb13
JB
2855 Window window_id;
2856{
2857 Lisp_Object tail, frame;
f451eb13 2858
ab648270
JB
2859 for (tail = Vframe_list;
2860 XGCTYPE (tail) == Lisp_Cons;
2861 tail = XCONS (tail)->cdr)
f451eb13 2862 {
abdda982 2863 Lisp_Object frame, bar, condemned;
f451eb13 2864
abdda982 2865 frame = XCONS (tail)->car;
f451eb13 2866 /* All elements of Vframe_list should be frames. */
0299d313 2867 if (! GC_FRAMEP (frame))
f451eb13
JB
2868 abort ();
2869
ab648270 2870 /* Scan this frame's scroll bar list for a scroll bar with the
f451eb13 2871 right window ID. */
ab648270
JB
2872 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
2873 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
cf7cb199 2874 /* This trick allows us to search both the ordinary and
ab648270
JB
2875 condemned scroll bar lists with one loop. */
2876 ! GC_NILP (bar) || (bar = condemned,
2877 condemned = Qnil,
2878 ! GC_NILP (bar));
bc20ebbf 2879 bar = XSCROLL_BAR (bar)->next)
ab648270
JB
2880 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
2881 return XSCROLL_BAR (bar);
f451eb13
JB
2882 }
2883
2884 return 0;
2885}
2886
ab648270
JB
2887/* Open a new X window to serve as a scroll bar, and return the
2888 scroll bar vector for it. */
2889static struct scroll_bar *
2890x_scroll_bar_create (window, top, left, width, height)
12ba150f 2891 struct window *window;
f451eb13
JB
2892 int top, left, width, height;
2893{
334208b7
RS
2894 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2895 struct scroll_bar *bar
2896 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
2897
2898 BLOCK_INPUT;
2899
2900 {
2901 XSetWindowAttributes a;
2902 unsigned long mask;
7556890b 2903 a.background_pixel = f->output_data.x->background_pixel;
12ba150f 2904 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 2905 | ButtonMotionMask | PointerMotionHintMask
12ba150f 2906 | ExposureMask);
7a13e894 2907 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 2908
dbc4e1c1 2909 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 2910
3afe33e7
RS
2911#if 0
2912
2913 ac = 0;
2914 XtSetArg (al[ac], XtNx, left); ac++;
2915 XtSetArg (al[ac], XtNy, top); ac++;
2916 XtSetArg (al[ac], XtNwidth, width); ac++;
2917 XtSetArg (al[ac], XtNheight, height); ac++;
2918 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
2919 sb_widget = XtCreateManagedWidget ("box",
7246d1d3 2920 boxWidgetClass,
7556890b 2921 f->output_data.x->edit_widget, al, ac);
7246d1d3 2922 SET_SCROLL_BAR_X_WINDOW
3afe33e7 2923 (bar, sb_widget->core.window);
58769bee 2924#endif
7246d1d3 2925 SET_SCROLL_BAR_X_WINDOW
58769bee 2926 (bar,
334208b7 2927 XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f451eb13 2928
ab648270 2929 /* Position and size of scroll bar. */
3cbd2e0b
RS
2930 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, top,
2931 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, height,
f451eb13 2932
12ba150f
JB
2933 /* Border width, depth, class, and visual. */
2934 0, CopyFromParent, CopyFromParent, CopyFromParent,
f451eb13 2935
12ba150f
JB
2936 /* Attributes. */
2937 mask, &a));
f451eb13
JB
2938 }
2939
e0c1aef2
KH
2940 XSETWINDOW (bar->window, window);
2941 XSETINT (bar->top, top);
2942 XSETINT (bar->left, left);
2943 XSETINT (bar->width, width);
2944 XSETINT (bar->height, height);
2945 XSETINT (bar->start, 0);
2946 XSETINT (bar->end, 0);
12ba150f 2947 bar->dragging = Qnil;
f451eb13
JB
2948
2949 /* Add bar to its frame's list of scroll bars. */
334208b7 2950 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 2951 bar->prev = Qnil;
334208b7 2952 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 2953 if (! NILP (bar->next))
e0c1aef2 2954 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 2955
7f9c7f94 2956 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
f451eb13
JB
2957
2958 UNBLOCK_INPUT;
12ba150f
JB
2959
2960 return bar;
f451eb13
JB
2961}
2962
12ba150f
JB
2963/* Draw BAR's handle in the proper position.
2964 If the handle is already drawn from START to END, don't bother
2965 redrawing it, unless REBUILD is non-zero; in that case, always
2966 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 2967 events.)
12ba150f
JB
2968
2969 Normally, we want to constrain the start and end of the handle to
ab648270 2970 fit inside its rectangle, but if the user is dragging the scroll bar
12ba150f
JB
2971 handle, we want to let them drag it down all the way, so that the
2972 bar's top is as far down as it goes; otherwise, there's no way to
2973 move to the very end of the buffer. */
f451eb13 2974static void
ab648270
JB
2975x_scroll_bar_set_handle (bar, start, end, rebuild)
2976 struct scroll_bar *bar;
f451eb13 2977 int start, end;
12ba150f 2978 int rebuild;
f451eb13 2979{
12ba150f 2980 int dragging = ! NILP (bar->dragging);
ab648270 2981 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 2982 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 2983 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
2984
2985 /* If the display is already accurate, do nothing. */
2986 if (! rebuild
2987 && start == XINT (bar->start)
2988 && end == XINT (bar->end))
2989 return;
2990
f451eb13
JB
2991 BLOCK_INPUT;
2992
2993 {
d9cdbb3d
RS
2994 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
2995 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
2996 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
2997
2998 /* Make sure the values are reasonable, and try to preserve
2999 the distance between start and end. */
12ba150f
JB
3000 {
3001 int length = end - start;
3002
3003 if (start < 0)
3004 start = 0;
3005 else if (start > top_range)
3006 start = top_range;
3007 end = start + length;
3008
3009 if (end < start)
3010 end = start;
3011 else if (end > top_range && ! dragging)
3012 end = top_range;
3013 }
f451eb13 3014
ab648270 3015 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
3016 XSETINT (bar->start, start);
3017 XSETINT (bar->end, end);
f451eb13 3018
12ba150f
JB
3019 /* Clip the end position, just for display. */
3020 if (end > top_range)
3021 end = top_range;
f451eb13 3022
ab648270 3023 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
3024 below top positions, to make sure the handle is always at least
3025 that many pixels tall. */
ab648270 3026 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 3027
12ba150f
JB
3028 /* Draw the empty space above the handle. Note that we can't clear
3029 zero-height areas; that means "clear to end of window." */
3030 if (0 < start)
334208b7 3031 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 3032
12ba150f 3033 /* x, y, width, height, and exposures. */
ab648270
JB
3034 VERTICAL_SCROLL_BAR_LEFT_BORDER,
3035 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
3036 inside_width, start,
3037 False);
f451eb13 3038
12ba150f 3039 /* Draw the handle itself. */
334208b7 3040 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 3041
12ba150f 3042 /* x, y, width, height */
ab648270
JB
3043 VERTICAL_SCROLL_BAR_LEFT_BORDER,
3044 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 3045 inside_width, end - start);
f451eb13 3046
f451eb13 3047
12ba150f
JB
3048 /* Draw the empty space below the handle. Note that we can't
3049 clear zero-height areas; that means "clear to end of window." */
3050 if (end < inside_height)
334208b7 3051 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 3052
12ba150f 3053 /* x, y, width, height, and exposures. */
ab648270
JB
3054 VERTICAL_SCROLL_BAR_LEFT_BORDER,
3055 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
3056 inside_width, inside_height - end,
3057 False);
f451eb13 3058
f451eb13
JB
3059 }
3060
f451eb13
JB
3061 UNBLOCK_INPUT;
3062}
3063
eb8c3be9 3064/* Move a scroll bar around on the screen, to accommodate changing
12ba150f 3065 window configurations. */
f451eb13 3066static void
ab648270
JB
3067x_scroll_bar_move (bar, top, left, width, height)
3068 struct scroll_bar *bar;
f451eb13
JB
3069 int top, left, width, height;
3070{
334208b7
RS
3071 Window w = SCROLL_BAR_X_WINDOW (bar);
3072 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3073
f451eb13
JB
3074 BLOCK_INPUT;
3075
3076 {
3077 XWindowChanges wc;
3078 unsigned int mask = 0;
3079
3cbd2e0b 3080 wc.x = left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
f451eb13 3081 wc.y = top;
3cbd2e0b
RS
3082
3083 wc.width = width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
f451eb13
JB
3084 wc.height = height;
3085
12ba150f
JB
3086 if (left != XINT (bar->left)) mask |= CWX;
3087 if (top != XINT (bar->top)) mask |= CWY;
3088 if (width != XINT (bar->width)) mask |= CWWidth;
3089 if (height != XINT (bar->height)) mask |= CWHeight;
58769bee 3090
12ba150f 3091 if (mask)
334208b7 3092 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
12ba150f 3093 mask, &wc);
f451eb13
JB
3094 }
3095
e0c1aef2
KH
3096 XSETINT (bar->left, left);
3097 XSETINT (bar->top, top);
3098 XSETINT (bar->width, width);
3099 XSETINT (bar->height, height);
12ba150f 3100
f451eb13
JB
3101 UNBLOCK_INPUT;
3102}
3103
ab648270 3104/* Destroy the X window for BAR, and set its Emacs window's scroll bar
12ba150f
JB
3105 to nil. */
3106static void
ab648270
JB
3107x_scroll_bar_remove (bar)
3108 struct scroll_bar *bar;
12ba150f
JB
3109{
3110 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
3111
3112 BLOCK_INPUT;
3113
3114 /* Destroy the window. */
334208b7 3115 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
12ba150f 3116
ab648270
JB
3117 /* Disassociate this scroll bar from its window. */
3118 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
3119
3120 UNBLOCK_INPUT;
3121}
3122
3123/* Set the handle of the vertical scroll bar for WINDOW to indicate
3124 that we are displaying PORTION characters out of a total of WHOLE
ab648270 3125 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f
JB
3126 create one. */
3127static void
ab648270 3128XTset_vertical_scroll_bar (window, portion, whole, position)
f451eb13
JB
3129 struct window *window;
3130 int portion, whole, position;
3131{
3132 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
f451eb13 3133 int top = XINT (window->top);
ab648270
JB
3134 int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
3135 int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
f451eb13 3136
ab648270 3137 /* Where should this scroll bar be, pixelwise? */
12ba150f
JB
3138 int pixel_top = CHAR_TO_PIXEL_ROW (f, top);
3139 int pixel_left = CHAR_TO_PIXEL_COL (f, left);
b2cad826
KH
3140 int pixel_width
3141 = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3142 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 3143 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
ab648270 3144 int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
f451eb13 3145
ab648270 3146 struct scroll_bar *bar;
12ba150f 3147
ab648270
JB
3148 /* Does the scroll bar exist yet? */
3149 if (NILP (window->vertical_scroll_bar))
3150 bar = x_scroll_bar_create (window,
f451eb13
JB
3151 pixel_top, pixel_left,
3152 pixel_width, pixel_height);
3153 else
12ba150f
JB
3154 {
3155 /* It may just need to be moved and resized. */
ab648270
JB
3156 bar = XSCROLL_BAR (window->vertical_scroll_bar);
3157 x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
12ba150f 3158 }
f451eb13 3159
ab648270 3160 /* Set the scroll bar's current state, unless we're currently being
f451eb13 3161 dragged. */
12ba150f 3162 if (NILP (bar->dragging))
f451eb13 3163 {
d9cdbb3d 3164 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, pixel_height);
f451eb13 3165
12ba150f 3166 if (whole == 0)
ab648270 3167 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
3168 else
3169 {
43f868f5
JB
3170 int start = ((double) position * top_range) / whole;
3171 int end = ((double) (position + portion) * top_range) / whole;
12ba150f 3172
ab648270 3173 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 3174 }
f451eb13
JB
3175 }
3176
e0c1aef2 3177 XSETVECTOR (window->vertical_scroll_bar, bar);
f451eb13
JB
3178}
3179
12ba150f 3180
f451eb13 3181/* The following three hooks are used when we're doing a thorough
ab648270 3182 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 3183 are going to be deleted, because keeping track of when windows go
12ba150f
JB
3184 away is a real pain - "Can you say set-window-configuration, boys
3185 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 3186 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 3187 from the fiery pit when we actually redisplay its window. */
f451eb13 3188
ab648270
JB
3189/* Arrange for all scroll bars on FRAME to be removed at the next call
3190 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
3191 `*redeem_scroll_bar_hook' is applied to its window before the judgement. */
58769bee 3192static void
ab648270 3193XTcondemn_scroll_bars (frame)
f451eb13
JB
3194 FRAME_PTR frame;
3195{
f9e24cb9
RS
3196 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
3197 while (! NILP (FRAME_SCROLL_BARS (frame)))
3198 {
3199 Lisp_Object bar;
3200 bar = FRAME_SCROLL_BARS (frame);
3201 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
3202 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
3203 XSCROLL_BAR (bar)->prev = Qnil;
3204 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
3205 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
3206 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
3207 }
f451eb13
JB
3208}
3209
ab648270 3210/* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
12ba150f 3211 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 3212static void
ab648270 3213XTredeem_scroll_bar (window)
12ba150f 3214 struct window *window;
f451eb13 3215{
ab648270 3216 struct scroll_bar *bar;
12ba150f 3217
ab648270
JB
3218 /* We can't redeem this window's scroll bar if it doesn't have one. */
3219 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
3220 abort ();
3221
ab648270 3222 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
3223
3224 /* Unlink it from the condemned list. */
3225 {
3226 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
3227
3228 if (NILP (bar->prev))
3229 {
3230 /* If the prev pointer is nil, it must be the first in one of
3231 the lists. */
ab648270 3232 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
3233 /* It's not condemned. Everything's fine. */
3234 return;
ab648270
JB
3235 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
3236 window->vertical_scroll_bar))
3237 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
3238 else
3239 /* If its prev pointer is nil, it must be at the front of
3240 one or the other! */
3241 abort ();
3242 }
3243 else
ab648270 3244 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
3245
3246 if (! NILP (bar->next))
ab648270 3247 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 3248
ab648270 3249 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 3250 bar->prev = Qnil;
e0c1aef2 3251 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 3252 if (! NILP (bar->next))
e0c1aef2 3253 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
12ba150f 3254 }
f451eb13
JB
3255}
3256
ab648270
JB
3257/* Remove all scroll bars on FRAME that haven't been saved since the
3258 last call to `*condemn_scroll_bars_hook'. */
f451eb13 3259static void
ab648270 3260XTjudge_scroll_bars (f)
12ba150f 3261 FRAME_PTR f;
f451eb13 3262{
12ba150f 3263 Lisp_Object bar, next;
f451eb13 3264
ab648270 3265 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
3266
3267 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
3268 more events on the hapless scroll bars. */
3269 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
3270
3271 for (; ! NILP (bar); bar = next)
f451eb13 3272 {
ab648270 3273 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 3274
ab648270 3275 x_scroll_bar_remove (b);
12ba150f
JB
3276
3277 next = b->next;
3278 b->next = b->prev = Qnil;
f451eb13 3279 }
12ba150f 3280
ab648270 3281 /* Now there should be no references to the condemned scroll bars,
12ba150f 3282 and they should get garbage-collected. */
f451eb13
JB
3283}
3284
3285
ab648270
JB
3286/* Handle an Expose or GraphicsExpose event on a scroll bar.
3287
3288 This may be called from a signal handler, so we have to ignore GC
3289 mark bits. */
f451eb13 3290static void
ab648270
JB
3291x_scroll_bar_expose (bar, event)
3292 struct scroll_bar *bar;
f451eb13
JB
3293 XEvent *event;
3294{
ab648270 3295 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 3296 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 3297 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 3298 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 3299
f451eb13
JB
3300 BLOCK_INPUT;
3301
ab648270 3302 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 3303
ab648270 3304 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 3305 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
3306
3307 /* x, y, width, height */
d9cdbb3d 3308 0, 0,
3cbd2e0b 3309 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
3310 XINT (bar->height) - 1);
3311
f451eb13
JB
3312 UNBLOCK_INPUT;
3313}
3314
ab648270
JB
3315/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
3316 is set to something other than no_event, it is enqueued.
3317
3318 This may be called from a signal handler, so we have to ignore GC
3319 mark bits. */
f451eb13 3320static void
ab648270
JB
3321x_scroll_bar_handle_click (bar, event, emacs_event)
3322 struct scroll_bar *bar;
f451eb13
JB
3323 XEvent *event;
3324 struct input_event *emacs_event;
3325{
0299d313 3326 if (! GC_WINDOWP (bar->window))
12ba150f
JB
3327 abort ();
3328
ab648270 3329 emacs_event->kind = scroll_bar_click;
69388238 3330 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
3331 emacs_event->modifiers
3332 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
3333 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
3334 event->xbutton.state)
3335 | (event->type == ButtonRelease
3336 ? up_modifier
3337 : down_modifier));
12ba150f 3338 emacs_event->frame_or_window = bar->window;
f451eb13 3339 emacs_event->timestamp = event->xbutton.time;
12ba150f 3340 {
d9cdbb3d 3341 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 3342 int internal_height
d9cdbb3d 3343 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
0299d313 3344 int top_range
d9cdbb3d 3345 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 3346 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
3347
3348 if (y < 0) y = 0;
3349 if (y > top_range) y = top_range;
3350
3351 if (y < XINT (bar->start))
ab648270
JB
3352 emacs_event->part = scroll_bar_above_handle;
3353 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
3354 emacs_event->part = scroll_bar_handle;
12ba150f 3355 else
ab648270 3356 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
3357
3358 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
3359 they want to drag it. Lisp code needs to be able to decide
3360 whether or not we're dragging. */
929787e1 3361#if 0
12ba150f
JB
3362 /* If the user has just clicked on the handle, record where they're
3363 holding it. */
3364 if (event->type == ButtonPress
ab648270 3365 && emacs_event->part == scroll_bar_handle)
e0c1aef2 3366 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 3367#endif
12ba150f
JB
3368
3369 /* If the user has released the handle, set it to its final position. */
3370 if (event->type == ButtonRelease
3371 && ! NILP (bar->dragging))
3372 {
3373 int new_start = y - XINT (bar->dragging);
3374 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 3375
ab648270 3376 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
3377 bar->dragging = Qnil;
3378 }
f451eb13 3379
5116f055
JB
3380 /* Same deal here as the other #if 0. */
3381#if 0
58769bee 3382 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 3383 the handle. */
ab648270 3384 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
3385 emacs_event->x = bar->start;
3386 else
e0c1aef2 3387 XSETINT (emacs_event->x, y);
5116f055 3388#else
e0c1aef2 3389 XSETINT (emacs_event->x, y);
5116f055 3390#endif
f451eb13 3391
e0c1aef2 3392 XSETINT (emacs_event->y, top_range);
12ba150f
JB
3393 }
3394}
f451eb13 3395
ab648270
JB
3396/* Handle some mouse motion while someone is dragging the scroll bar.
3397
3398 This may be called from a signal handler, so we have to ignore GC
3399 mark bits. */
f451eb13 3400static void
ab648270
JB
3401x_scroll_bar_note_movement (bar, event)
3402 struct scroll_bar *bar;
f451eb13
JB
3403 XEvent *event;
3404{
39d8bb4d
KH
3405 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
3406
f451eb13
JB
3407 last_mouse_movement_time = event->xmotion.time;
3408
39d8bb4d 3409 f->mouse_moved = 1;
e0c1aef2 3410 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
3411
3412 /* If we're dragging the bar, display it. */
ab648270 3413 if (! GC_NILP (bar->dragging))
f451eb13
JB
3414 {
3415 /* Where should the handle be now? */
12ba150f 3416 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 3417
12ba150f 3418 if (new_start != XINT (bar->start))
f451eb13 3419 {
12ba150f 3420 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 3421
ab648270 3422 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
3423 }
3424 }
f451eb13
JB
3425}
3426
12ba150f 3427/* Return information to the user about the current position of the mouse
ab648270 3428 on the scroll bar. */
12ba150f 3429static void
334208b7
RS
3430x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
3431 FRAME_PTR *fp;
12ba150f 3432 Lisp_Object *bar_window;
ab648270 3433 enum scroll_bar_part *part;
12ba150f
JB
3434 Lisp_Object *x, *y;
3435 unsigned long *time;
3436{
ab648270 3437 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
3438 Window w = SCROLL_BAR_X_WINDOW (bar);
3439 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 3440 int win_x, win_y;
559cb2fb
JB
3441 Window dummy_window;
3442 int dummy_coord;
3443 unsigned int dummy_mask;
12ba150f 3444
cf7cb199
JB
3445 BLOCK_INPUT;
3446
ab648270 3447 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 3448 report that. */
334208b7 3449 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 3450
559cb2fb
JB
3451 /* Root, child, root x and root y. */
3452 &dummy_window, &dummy_window,
3453 &dummy_coord, &dummy_coord,
12ba150f 3454
559cb2fb
JB
3455 /* Position relative to scroll bar. */
3456 &win_x, &win_y,
12ba150f 3457
559cb2fb
JB
3458 /* Mouse buttons and modifier keys. */
3459 &dummy_mask))
7a13e894 3460 ;
559cb2fb
JB
3461 else
3462 {
3463 int inside_height
d9cdbb3d 3464 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
559cb2fb 3465 int top_range
d9cdbb3d 3466 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
3467
3468 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
3469
3470 if (! NILP (bar->dragging))
3471 win_y -= XINT (bar->dragging);
3472
3473 if (win_y < 0)
3474 win_y = 0;
3475 if (win_y > top_range)
3476 win_y = top_range;
3477
334208b7 3478 *fp = f;
7a13e894 3479 *bar_window = bar->window;
559cb2fb
JB
3480
3481 if (! NILP (bar->dragging))
3482 *part = scroll_bar_handle;
3483 else if (win_y < XINT (bar->start))
3484 *part = scroll_bar_above_handle;
3485 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
3486 *part = scroll_bar_handle;
3487 else
3488 *part = scroll_bar_below_handle;
12ba150f 3489
e0c1aef2
KH
3490 XSETINT (*x, win_y);
3491 XSETINT (*y, top_range);
12ba150f 3492
39d8bb4d 3493 f->mouse_moved = 0;
559cb2fb
JB
3494 last_mouse_scroll_bar = Qnil;
3495 }
12ba150f 3496
559cb2fb 3497 *time = last_mouse_movement_time;
cf7cb199 3498
cf7cb199 3499 UNBLOCK_INPUT;
12ba150f
JB
3500}
3501
f451eb13 3502
dbc4e1c1 3503/* The screen has been cleared so we may have changed foreground or
ab648270
JB
3504 background colors, and the scroll bars may need to be redrawn.
3505 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
3506 redraw them. */
3507
ab648270 3508x_scroll_bar_clear (f)
dbc4e1c1
JB
3509 FRAME_PTR f;
3510{
3511 Lisp_Object bar;
3512
b80c363e
RS
3513 /* We can have scroll bars even if this is 0,
3514 if we just turned off scroll bar mode.
3515 But in that case we should not clear them. */
3516 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
3517 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
3518 bar = XSCROLL_BAR (bar)->next)
3519 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
3520 0, 0, 0, 0, True);
dbc4e1c1
JB
3521}
3522
3afe33e7 3523/* This processes Expose events from the menubar specific X event
19126e11 3524 loop in xmenu.c. This allows to redisplay the frame if necessary
3afe33e7
RS
3525 when handling menubar or popup items. */
3526
3527void
3528process_expose_from_menu (event)
3529 XEvent event;
3530{
3531 FRAME_PTR f;
19126e11 3532 struct x_display_info *dpyinfo;
3afe33e7 3533
f94397b5
KH
3534 BLOCK_INPUT;
3535
19126e11
KH
3536 dpyinfo = x_display_info_for_display (event.xexpose.display);
3537 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
3538 if (f)
3539 {
3540 if (f->async_visible == 0)
3541 {
3542 f->async_visible = 1;
3543 f->async_iconified = 0;
06c488fd 3544 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
3545 SET_FRAME_GARBAGED (f);
3546 }
3547 else
3548 {
19126e11 3549 dumprectangle (x_window_to_frame (dpyinfo, event.xexpose.window),
3afe33e7
RS
3550 event.xexpose.x, event.xexpose.y,
3551 event.xexpose.width, event.xexpose.height);
3552 }
3553 }
3554 else
3555 {
3556 struct scroll_bar *bar
3557 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 3558
3afe33e7
RS
3559 if (bar)
3560 x_scroll_bar_expose (bar, &event);
3561 }
f94397b5
KH
3562
3563 UNBLOCK_INPUT;
3afe33e7 3564}
09756a85
RS
3565\f
3566/* Define a queue to save up SelectionRequest events for later handling. */
3567
3568struct selection_event_queue
3569 {
3570 XEvent event;
3571 struct selection_event_queue *next;
3572 };
3573
3574static struct selection_event_queue *queue;
3575
3576/* Nonzero means queue up certain events--don't process them yet. */
3577static int x_queue_selection_requests;
3578
3579/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 3580
09756a85 3581static void
334208b7
RS
3582x_queue_event (f, event)
3583 FRAME_PTR f;
09756a85
RS
3584 XEvent *event;
3585{
3586 struct selection_event_queue *queue_tmp
3587 = (struct selection_event_queue *) malloc (sizeof (struct selection_event_queue));
3588
58769bee 3589 if (queue_tmp != NULL)
09756a85
RS
3590 {
3591 queue_tmp->event = *event;
3592 queue_tmp->next = queue;
3593 queue = queue_tmp;
3594 }
3595}
3596
3597/* Take all the queued events and put them back
3598 so that they get processed afresh. */
3599
3600static void
db3906fd
RS
3601x_unqueue_events (display)
3602 Display *display;
09756a85 3603{
58769bee 3604 while (queue != NULL)
09756a85
RS
3605 {
3606 struct selection_event_queue *queue_tmp = queue;
db3906fd 3607 XPutBackEvent (display, &queue_tmp->event);
09756a85
RS
3608 queue = queue_tmp->next;
3609 free ((char *)queue_tmp);
3610 }
3611}
3612
3613/* Start queuing SelectionRequest events. */
3614
3615void
db3906fd
RS
3616x_start_queuing_selection_requests (display)
3617 Display *display;
09756a85
RS
3618{
3619 x_queue_selection_requests++;
3620}
3621
3622/* Stop queuing SelectionRequest events. */
3623
3624void
db3906fd
RS
3625x_stop_queuing_selection_requests (display)
3626 Display *display;
09756a85
RS
3627{
3628 x_queue_selection_requests--;
db3906fd 3629 x_unqueue_events (display);
09756a85 3630}
f451eb13
JB
3631\f
3632/* The main X event-reading loop - XTread_socket. */
dc6f92b8 3633
dc6f92b8
JB
3634/* Timestamp of enter window event. This is only used by XTread_socket,
3635 but we have to put it out here, since static variables within functions
3636 sometimes don't work. */
3637static Time enter_timestamp;
3638
11edeb03 3639/* This holds the state XLookupString needs to implement dead keys
58769bee 3640 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
3641 says that a portable program can't use this, but Stephen Gildea assures
3642 me that letting the compiler initialize it to zeros will work okay.
3643
3644 This must be defined outside of XTread_socket, for the same reasons
3645 given for enter_timestamp, above. */
3646static XComposeStatus compose_status;
3647
10e6549c
RS
3648/* Record the last 100 characters stored
3649 to help debug the loss-of-chars-during-GC problem. */
2224b905
RS
3650static int temp_index;
3651static short temp_buffer[100];
10e6549c 3652
7a13e894
RS
3653/* Set this to nonzero to fake an "X I/O error"
3654 on a particular display. */
3655struct x_display_info *XTread_socket_fake_io_error;
3656
2224b905
RS
3657/* When we find no input here, we occasionally do a no-op command
3658 to verify that the X server is still running and we can still talk with it.
3659 We try all the open displays, one by one.
3660 This variable is used for cycling thru the displays. */
3661static struct x_display_info *next_noop_dpyinfo;
3662
8805890a
KH
3663#define SET_SAVED_MENU_EVENT(size) { \
3664 if (f->output_data.x->saved_menu_event == 0) \
3665 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent)); \
3666 bcopy (&event, f->output_data.x->saved_menu_event, size); \
3667 if (numchars >= 1) \
3668 { \
3669 bufp->kind = menu_bar_activate_event; \
3670 XSETFRAME (bufp->frame_or_window, f); \
3671 bufp++; \
3672 count++; \
3673 numchars--; \
3674 } \
3675 }
3676#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
3677#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
3678
dc6f92b8
JB
3679/* Read events coming from the X server.
3680 This routine is called by the SIGIO handler.
3681 We return as soon as there are no more events to be read.
3682
3683 Events representing keys are stored in buffer BUFP,
3684 which can hold up to NUMCHARS characters.
3685 We return the number of characters stored into the buffer,
3686 thus pretending to be `read'.
3687
dc6f92b8
JB
3688 EXPECTED is nonzero if the caller knows input is available. */
3689
7c5283e4 3690int
f66868ba 3691XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 3692 register int sd;
8805890a
KH
3693 /* register */ struct input_event *bufp;
3694 /* register */ int numchars;
dc6f92b8
JB
3695 int expected;
3696{
3697 int count = 0;
3698 int nbytes = 0;
3699 int mask;
3700 int items_pending; /* How many items are in the X queue. */
3701 XEvent event;
f676886a 3702 struct frame *f;
66f55a9d 3703 int event_found = 0;
dc6f92b8
JB
3704 int prefix;
3705 Lisp_Object part;
334208b7 3706 struct x_display_info *dpyinfo;
6c183ba5
RS
3707#ifdef HAVE_X_I18N
3708 Status status_return;
3709#endif
dc6f92b8 3710
9ac0d9e0 3711 if (interrupt_input_blocked)
dc6f92b8 3712 {
9ac0d9e0 3713 interrupt_input_pending = 1;
dc6f92b8
JB
3714 return -1;
3715 }
3716
9ac0d9e0 3717 interrupt_input_pending = 0;
dc6f92b8 3718 BLOCK_INPUT;
c0a04927
RS
3719
3720 /* So people can tell when we have read the available input. */
3721 input_signal_count++;
3722
dc6f92b8
JB
3723 if (numchars <= 0)
3724 abort (); /* Don't think this happens. */
3725
7a13e894
RS
3726 /* Find the display we are supposed to read input for.
3727 It's the one communicating on descriptor SD. */
3728 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
3729 {
3730#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 3731#ifdef FIOSNBIO
7a13e894
RS
3732 /* If available, Xlib uses FIOSNBIO to make the socket
3733 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 3734 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
7a13e894
RS
3735 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
3736 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 3737#endif /* ! defined (FIOSNBIO) */
7a13e894 3738#endif
dc6f92b8 3739
7a13e894
RS
3740#if 0 /* This code can't be made to work, with multiple displays,
3741 and appears not to be used on any system any more.
3742 Also keyboard.c doesn't turn O_NDELAY on and off
3743 for X connections. */
dc6f92b8
JB
3744#ifndef SIGIO
3745#ifndef HAVE_SELECT
7a13e894
RS
3746 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
3747 {
3748 extern int read_alarm_should_throw;
3749 read_alarm_should_throw = 1;
3750 XPeekEvent (dpyinfo->display, &event);
3751 read_alarm_should_throw = 0;
3752 }
c118dd06
JB
3753#endif /* HAVE_SELECT */
3754#endif /* SIGIO */
7a13e894 3755#endif
dc6f92b8 3756
7a13e894
RS
3757 /* For debugging, this gives a way to fake an I/O error. */
3758 if (dpyinfo == XTread_socket_fake_io_error)
3759 {
3760 XTread_socket_fake_io_error = 0;
3761 x_io_error_quitter (dpyinfo->display);
3762 }
dc6f92b8 3763
7a13e894 3764 while (XPending (dpyinfo->display) != 0)
dc6f92b8 3765 {
0cd6403b
RS
3766#ifdef USE_X_TOOLKIT
3767 /* needed to raise Motif submenus */
3768 XtAppNextEvent (Xt_app_con, &event);
3769#else
7a13e894 3770 XNextEvent (dpyinfo->display, &event);
531483fb
RS
3771#endif
3772#ifdef HAVE_X_I18N
d1bc4182
RS
3773 {
3774 struct frame *f1 = x_any_window_to_frame (dpyinfo,
3775 &event.xclient.window);
3776 /* The necessity of the following line took me
3777 a full work-day to decipher from the docs!! */
3778 if (f1 != 0 && FRAME_XIC (f1) && XFilterEvent (&event, None))
3779 break;
3780 }
0cd6403b 3781#endif
7a13e894
RS
3782 event_found = 1;
3783
3784 switch (event.type)
3785 {
3786 case ClientMessage:
c047688c 3787 {
7a13e894
RS
3788 if (event.xclient.message_type
3789 == dpyinfo->Xatom_wm_protocols
3790 && event.xclient.format == 32)
c047688c 3791 {
7a13e894
RS
3792 if (event.xclient.data.l[0]
3793 == dpyinfo->Xatom_wm_take_focus)
c047688c 3794 {
19126e11 3795 f = x_window_to_frame (dpyinfo, event.xclient.window);
7a13e894
RS
3796 /* Since we set WM_TAKE_FOCUS, we must call
3797 XSetInputFocus explicitly. But not if f is null,
3798 since that might be an event for a deleted frame. */
6c183ba5
RS
3799#ifdef HAVE_X_I18N
3800 /* Not quite sure this is needed -pd */
3801 if (f)
3802 XSetICFocus (FRAME_XIC (f));
3803#endif
7a13e894
RS
3804 if (f)
3805 XSetInputFocus (event.xclient.display,
3806 event.xclient.window,
3807 RevertToPointerRoot,
3808 event.xclient.data.l[1]);
3809 /* Not certain about handling scroll bars here */
c047688c 3810 }
7a13e894
RS
3811 else if (event.xclient.data.l[0]
3812 == dpyinfo->Xatom_wm_save_yourself)
3813 {
3814 /* Save state modify the WM_COMMAND property to
3815 something which can reinstate us. This notifies
3816 the session manager, who's looking for such a
3817 PropertyNotify. Can restart processing when
3818 a keyboard or mouse event arrives. */
3819 if (numchars > 0)
3820 {
19126e11
KH
3821 f = x_top_window_to_frame (dpyinfo,
3822 event.xclient.window);
7a13e894
RS
3823
3824 /* This is just so we only give real data once
3825 for a single Emacs process. */
3826 if (f == selected_frame)
3827 XSetCommand (FRAME_X_DISPLAY (f),
3828 event.xclient.window,
3829 initial_argv, initial_argc);
f000f5c5 3830 else if (f)
7a13e894
RS
3831 XSetCommand (FRAME_X_DISPLAY (f),
3832 event.xclient.window,
3833 0, 0);
3834 }
3835 }
3836 else if (event.xclient.data.l[0]
3837 == dpyinfo->Xatom_wm_delete_window)
1fb20991 3838 {
19126e11
KH
3839 struct frame *f
3840 = x_any_window_to_frame (dpyinfo,
3841 event.xclient.window);
1fb20991 3842
7a13e894
RS
3843 if (f)
3844 {
3845 if (numchars == 0)
3846 abort ();
1fb20991 3847
7a13e894
RS
3848 bufp->kind = delete_window_event;
3849 XSETFRAME (bufp->frame_or_window, f);
3850 bufp++;
3851
3852 count += 1;
3853 numchars -= 1;
3854 }
1fb20991 3855 }
c047688c 3856 }
7a13e894
RS
3857 else if (event.xclient.message_type
3858 == dpyinfo->Xatom_wm_configure_denied)
3859 {
3860 }
3861 else if (event.xclient.message_type
3862 == dpyinfo->Xatom_wm_window_moved)
3863 {
3864 int new_x, new_y;
19126e11
KH
3865 struct frame *f
3866 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 3867
7a13e894
RS
3868 new_x = event.xclient.data.s[0];
3869 new_y = event.xclient.data.s[1];
1fb20991 3870
7a13e894
RS
3871 if (f)
3872 {
7556890b
RS
3873 f->output_data.x->left_pos = new_x;
3874 f->output_data.x->top_pos = new_y;
7a13e894 3875 }
1fb20991 3876 }
0fdff6bb 3877#ifdef HACK_EDITRES
7a13e894
RS
3878 else if (event.xclient.message_type
3879 == dpyinfo->Xatom_editres)
3880 {
19126e11
KH
3881 struct frame *f
3882 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 3883 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 3884 &event, NULL);
7a13e894 3885 }
0fdff6bb 3886#endif /* HACK_EDITRES */
7a13e894
RS
3887 }
3888 break;
dc6f92b8 3889
7a13e894 3890 case SelectionNotify:
3afe33e7 3891#ifdef USE_X_TOOLKIT
19126e11 3892 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 3893 goto OTHER;
3afe33e7 3894#endif /* not USE_X_TOOLKIT */
7a13e894
RS
3895 x_handle_selection_notify (&event);
3896 break;
d56a553a 3897
7a13e894 3898 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 3899#ifdef USE_X_TOOLKIT
19126e11 3900 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 3901 goto OTHER;
3afe33e7 3902#endif /* USE_X_TOOLKIT */
7a13e894
RS
3903 {
3904 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 3905
7a13e894
RS
3906 if (numchars == 0)
3907 abort ();
d56a553a 3908
7a13e894
RS
3909 bufp->kind = selection_clear_event;
3910 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3911 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3912 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 3913 bufp->frame_or_window = Qnil;
7a13e894 3914 bufp++;
d56a553a 3915
7a13e894
RS
3916 count += 1;
3917 numchars -= 1;
3918 }
3919 break;
dc6f92b8 3920
7a13e894 3921 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 3922#ifdef USE_X_TOOLKIT
19126e11 3923 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 3924 goto OTHER;
3afe33e7 3925#endif /* USE_X_TOOLKIT */
7a13e894 3926 if (x_queue_selection_requests)
19126e11 3927 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
3928 &event);
3929 else
3930 {
3931 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 3932
7a13e894
RS
3933 if (numchars == 0)
3934 abort ();
3935
3936 bufp->kind = selection_request_event;
3937 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3938 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
3939 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3940 SELECTION_EVENT_TARGET (bufp) = eventp->target;
3941 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
3942 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 3943 bufp->frame_or_window = Qnil;
7a13e894
RS
3944 bufp++;
3945
3946 count += 1;
3947 numchars -= 1;
3948 }
3949 break;
3950
3951 case PropertyNotify:
3afe33e7 3952#ifdef USE_X_TOOLKIT
19126e11 3953 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 3954 goto OTHER;
3afe33e7 3955#endif /* not USE_X_TOOLKIT */
7a13e894
RS
3956 x_handle_property_notify (&event);
3957 break;
dc6f92b8 3958
7a13e894 3959 case ReparentNotify:
19126e11 3960 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
3961 if (f)
3962 {
3963 int x, y;
7556890b 3964 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 3965 x_real_positions (f, &x, &y);
7556890b
RS
3966 f->output_data.x->left_pos = x;
3967 f->output_data.x->top_pos = y;
7a13e894
RS
3968 }
3969 break;
3bd330d4 3970
7a13e894 3971 case Expose:
19126e11 3972 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 3973 if (f)
dc6f92b8 3974 {
7a13e894
RS
3975 if (f->async_visible == 0)
3976 {
3977 f->async_visible = 1;
3978 f->async_iconified = 0;
06c488fd 3979 f->output_data.x->has_been_visible = 1;
7a13e894
RS
3980 SET_FRAME_GARBAGED (f);
3981 }
3982 else
19126e11
KH
3983 dumprectangle (x_window_to_frame (dpyinfo,
3984 event.xexpose.window),
7a13e894
RS
3985 event.xexpose.x, event.xexpose.y,
3986 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
3987 }
3988 else
7a13e894
RS
3989 {
3990 struct scroll_bar *bar
3991 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 3992
7a13e894
RS
3993 if (bar)
3994 x_scroll_bar_expose (bar, &event);
3afe33e7 3995#ifdef USE_X_TOOLKIT
7a13e894
RS
3996 else
3997 goto OTHER;
3afe33e7 3998#endif /* USE_X_TOOLKIT */
7a13e894
RS
3999 }
4000 break;
dc6f92b8 4001
7a13e894
RS
4002 case GraphicsExpose: /* This occurs when an XCopyArea's
4003 source area was obscured or not
4004 available.*/
19126e11 4005 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
4006 if (f)
4007 {
4008 dumprectangle (f,
4009 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
4010 event.xgraphicsexpose.width,
4011 event.xgraphicsexpose.height);
4012 }
3afe33e7 4013#ifdef USE_X_TOOLKIT
7a13e894
RS
4014 else
4015 goto OTHER;
3afe33e7 4016#endif /* USE_X_TOOLKIT */
7a13e894 4017 break;
dc6f92b8 4018
7a13e894
RS
4019 case NoExpose: /* This occurs when an XCopyArea's
4020 source area was completely
4021 available */
4022 break;
dc6f92b8 4023
7a13e894 4024 case UnmapNotify:
91ea2a7a 4025 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
4026 if (f) /* F may no longer exist if
4027 the frame was deleted. */
4028 {
4029 /* While a frame is unmapped, display generation is
4030 disabled; you don't want to spend time updating a
4031 display that won't ever be seen. */
4032 f->async_visible = 0;
4033 /* We can't distinguish, from the event, whether the window
4034 has become iconified or invisible. So assume, if it
4035 was previously visible, than now it is iconified.
1aa6072f
RS
4036 But x_make_frame_invisible clears both
4037 the visible flag and the iconified flag;
4038 and that way, we know the window is not iconified now. */
7a13e894 4039 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
4040 {
4041 f->async_iconified = 1;
bddd097c 4042
1aa6072f
RS
4043 bufp->kind = iconify_event;
4044 XSETFRAME (bufp->frame_or_window, f);
4045 bufp++;
4046 count++;
4047 numchars--;
4048 }
7a13e894 4049 }
7a13e894 4050 goto OTHER;
dc6f92b8 4051
7a13e894
RS
4052 case MapNotify:
4053 /* We use x_top_window_to_frame because map events can come
4054 for subwindows and they don't mean that the frame is visible. */
19126e11 4055 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
4056 if (f)
4057 {
4058 f->async_visible = 1;
4059 f->async_iconified = 0;
06c488fd 4060 f->output_data.x->has_been_visible = 1;
dc6f92b8 4061
7a13e894
RS
4062 /* wait_reading_process_input will notice this and update
4063 the frame's display structures. */
4064 SET_FRAME_GARBAGED (f);
bddd097c 4065
d806e720
RS
4066 if (f->iconified)
4067 {
4068 bufp->kind = deiconify_event;
4069 XSETFRAME (bufp->frame_or_window, f);
4070 bufp++;
4071 count++;
4072 numchars--;
4073 }
e73ec6fa 4074 else if (! NILP (Vframe_list)
8c29f6bf 4075 && ! NILP (XCONS (Vframe_list)->cdr))
78aa2ba5
KH
4076 /* Force a redisplay sooner or later
4077 to update the frame titles
4078 in case this is the second frame. */
4079 record_asynch_buffer_change ();
7a13e894 4080 }
7a13e894 4081 goto OTHER;
dc6f92b8 4082
7a13e894
RS
4083 /* Turn off processing if we become fully obscured. */
4084 case VisibilityNotify:
4085 break;
dc6f92b8 4086
7a13e894 4087 case KeyPress:
19126e11 4088 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 4089
7a13e894
RS
4090 if (f != 0)
4091 {
4092 KeySym keysym, orig_keysym;
4093 /* al%imercury@uunet.uu.net says that making this 81 instead of
4094 80 fixed a bug whereby meta chars made his Emacs hang. */
4095 unsigned char copy_buffer[81];
4096 int modifiers;
64bb1782 4097
0a43f75b
RS
4098#if 0 /* This was how we made f10 work in Motif.
4099 The drawback is, you can't type at Emacs when the
4100 the mouse is in the menu bar. So it is better to
4101 turn off f10 in Motif and let Emacs handle it. */
2237cac9 4102#ifdef USE_MOTIF
aaca4aca
KH
4103 if (lw_window_is_in_menubar (event.xkey.window,
4104 f->output_data.x->menubar_widget
4105 ))
4106 {
8805890a 4107 SET_SAVED_KEY_EVENT;
aaca4aca
KH
4108 break;
4109 }
2237cac9 4110#endif /* USE_MOTIF */
0a43f75b 4111#endif /* 0 */
7723570d 4112
7a13e894
RS
4113 event.xkey.state
4114 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
4115 extra_keyboard_modifiers);
4116 modifiers = event.xkey.state;
3a2712f9 4117
7a13e894 4118 /* This will have to go some day... */
752a043f 4119
7a13e894
RS
4120 /* make_lispy_event turns chars into control chars.
4121 Don't do it here because XLookupString is too eager. */
4122 event.xkey.state &= ~ControlMask;
5d46f928
RS
4123 event.xkey.state &= ~(dpyinfo->meta_mod_mask
4124 | dpyinfo->super_mod_mask
4125 | dpyinfo->hyper_mod_mask
4126 | dpyinfo->alt_mod_mask);
4127
1cf4a0d1
RS
4128 /* In case Meta is ComposeCharacter,
4129 clear its status. According to Markus Ehrnsperger
4130 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
4131 this enables ComposeCharacter to work whether or
4132 not it is combined with Meta. */
4133 if (modifiers & dpyinfo->meta_mod_mask)
4134 bzero (&compose_status, sizeof (compose_status));
4135
6c183ba5
RS
4136#ifdef HAVE_X_I18N
4137 if (FRAME_XIC (f))
4138 {
5d7cc324
RS
4139 /* The necessity of the following line took me
4140 a full work-day to decipher from the docs!! */
4141 if (XFilterEvent (&event, None))
4142 break;
6c183ba5
RS
4143 nbytes = XmbLookupString (FRAME_XIC (f),
4144 &event.xkey, copy_buffer,
4145 80, &keysym,
4146 &status_return);
4147 }
4148 else
4149 nbytes = XLookupString (&event.xkey, copy_buffer,
4150 80, &keysym, &compose_status);
4151#else
0299d313
RS
4152 nbytes = XLookupString (&event.xkey, copy_buffer,
4153 80, &keysym, &compose_status);
6c183ba5 4154#endif
dc6f92b8 4155
7a13e894 4156 orig_keysym = keysym;
55123275 4157
7a13e894
RS
4158 if (numchars > 1)
4159 {
4160 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
4161 || keysym == XK_Delete
1097aea0 4162#ifdef XK_ISO_Left_Tab
441affdb 4163 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 4164#endif
7a13e894
RS
4165 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
4166 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 4167#ifdef HPUX
7a13e894
RS
4168 /* This recognizes the "extended function keys".
4169 It seems there's no cleaner way.
4170 Test IsModifierKey to avoid handling mode_switch
4171 incorrectly. */
4172 || ((unsigned) (keysym) >= XK_Select
4173 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
4174#endif
4175#ifdef XK_dead_circumflex
7a13e894 4176 || orig_keysym == XK_dead_circumflex
69388238
RS
4177#endif
4178#ifdef XK_dead_grave
7a13e894 4179 || orig_keysym == XK_dead_grave
69388238
RS
4180#endif
4181#ifdef XK_dead_tilde
7a13e894 4182 || orig_keysym == XK_dead_tilde
69388238
RS
4183#endif
4184#ifdef XK_dead_diaeresis
7a13e894 4185 || orig_keysym == XK_dead_diaeresis
69388238
RS
4186#endif
4187#ifdef XK_dead_macron
7a13e894 4188 || orig_keysym == XK_dead_macron
69388238
RS
4189#endif
4190#ifdef XK_dead_degree
7a13e894 4191 || orig_keysym == XK_dead_degree
69388238
RS
4192#endif
4193#ifdef XK_dead_acute
7a13e894 4194 || orig_keysym == XK_dead_acute
69388238
RS
4195#endif
4196#ifdef XK_dead_cedilla
7a13e894 4197 || orig_keysym == XK_dead_cedilla
69388238
RS
4198#endif
4199#ifdef XK_dead_breve
7a13e894 4200 || orig_keysym == XK_dead_breve
69388238
RS
4201#endif
4202#ifdef XK_dead_ogonek
7a13e894 4203 || orig_keysym == XK_dead_ogonek
69388238
RS
4204#endif
4205#ifdef XK_dead_caron
7a13e894 4206 || orig_keysym == XK_dead_caron
69388238
RS
4207#endif
4208#ifdef XK_dead_doubleacute
7a13e894 4209 || orig_keysym == XK_dead_doubleacute
69388238
RS
4210#endif
4211#ifdef XK_dead_abovedot
7a13e894 4212 || orig_keysym == XK_dead_abovedot
c34790e0 4213#endif
7a13e894
RS
4214 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
4215 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
4216 /* Any "vendor-specific" key is ok. */
4217 || (orig_keysym & (1 << 28)))
4218 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
4219#ifndef HAVE_X11R5
4220#ifdef XK_Mode_switch
7a13e894 4221 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
4222#endif
4223#ifdef XK_Num_Lock
7a13e894 4224 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
4225#endif
4226#endif /* not HAVE_X11R5 */
7a13e894 4227 ))
dc6f92b8 4228 {
10e6549c
RS
4229 if (temp_index == sizeof temp_buffer / sizeof (short))
4230 temp_index = 0;
7a13e894
RS
4231 temp_buffer[temp_index++] = keysym;
4232 bufp->kind = non_ascii_keystroke;
4233 bufp->code = keysym;
e0c1aef2 4234 XSETFRAME (bufp->frame_or_window, f);
334208b7
RS
4235 bufp->modifiers
4236 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
4237 modifiers);
1113d9db 4238 bufp->timestamp = event.xkey.time;
dc6f92b8 4239 bufp++;
7a13e894
RS
4240 count++;
4241 numchars--;
dc6f92b8 4242 }
7a13e894
RS
4243 else if (numchars > nbytes)
4244 {
4245 register int i;
4246
4247 for (i = 0; i < nbytes; i++)
4248 {
4249 if (temp_index == sizeof temp_buffer / sizeof (short))
4250 temp_index = 0;
4251 temp_buffer[temp_index++] = copy_buffer[i];
4252 bufp->kind = ascii_keystroke;
4253 bufp->code = copy_buffer[i];
4254 XSETFRAME (bufp->frame_or_window, f);
4255 bufp->modifiers
4256 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
4257 modifiers);
4258 bufp->timestamp = event.xkey.time;
4259 bufp++;
4260 }
4261
4262 count += nbytes;
4263 numchars -= nbytes;
4264 }
4265 else
4266 abort ();
dc6f92b8 4267 }
10e6549c
RS
4268 else
4269 abort ();
dc6f92b8 4270 }
717ca130 4271 goto OTHER;
f451eb13 4272
7a13e894
RS
4273 /* Here's a possible interpretation of the whole
4274 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
4275 FocusIn event, you have to get a FocusOut event before you
4276 relinquish the focus. If you haven't received a FocusIn event,
4277 then a mere LeaveNotify is enough to free you. */
f451eb13 4278
7a13e894 4279 case EnterNotify:
19126e11 4280 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
6d4238f3 4281
7a13e894 4282 if (event.xcrossing.focus) /* Entered Window */
dc6f92b8 4283 {
7a13e894
RS
4284 /* Avoid nasty pop/raise loops. */
4285 if (f && (!(f->auto_raise)
4286 || !(f->auto_lower)
4287 || (event.xcrossing.time - enter_timestamp) > 500))
4288 {
0f941935 4289 x_new_focus_frame (dpyinfo, f);
7a13e894
RS
4290 enter_timestamp = event.xcrossing.time;
4291 }
dc6f92b8 4292 }
0f941935
KH
4293 else if (f == dpyinfo->x_focus_frame)
4294 x_new_focus_frame (dpyinfo, 0);
7a13e894
RS
4295 /* EnterNotify counts as mouse movement,
4296 so update things that depend on mouse position. */
4297 if (f)
4298 note_mouse_movement (f, &event.xmotion);
7a13e894 4299 goto OTHER;
dc6f92b8 4300
7a13e894 4301 case FocusIn:
19126e11 4302 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 4303 if (event.xfocus.detail != NotifyPointer)
0f941935 4304 dpyinfo->x_focus_event_frame = f;
7a13e894 4305 if (f)
0f941935 4306 x_new_focus_frame (dpyinfo, f);
f9e24cb9 4307
6c183ba5
RS
4308#ifdef HAVE_X_I18N
4309 if (f && FRAME_XIC (f))
4310 XSetICFocus (FRAME_XIC (f));
4311#endif
4312
7a13e894 4313 goto OTHER;
10c5e63d 4314
7a13e894 4315 case LeaveNotify:
19126e11 4316 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 4317 if (f)
10c5e63d 4318 {
7a13e894
RS
4319 if (f == dpyinfo->mouse_face_mouse_frame)
4320 /* If we move outside the frame,
4321 then we're certainly no longer on any text in the frame. */
4322 clear_mouse_face (dpyinfo);
4323
4324 if (event.xcrossing.focus)
0f941935 4325 x_mouse_leave (dpyinfo);
10c5e63d 4326 else
7a13e894 4327 {
0f941935
KH
4328 if (f == dpyinfo->x_focus_event_frame)
4329 dpyinfo->x_focus_event_frame = 0;
4330 if (f == dpyinfo->x_focus_frame)
4331 x_new_focus_frame (dpyinfo, 0);
7a13e894 4332 }
10c5e63d 4333 }
7a13e894 4334 goto OTHER;
dc6f92b8 4335
7a13e894 4336 case FocusOut:
19126e11 4337 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 4338 if (event.xfocus.detail != NotifyPointer
0f941935
KH
4339 && f == dpyinfo->x_focus_event_frame)
4340 dpyinfo->x_focus_event_frame = 0;
4341 if (f && f == dpyinfo->x_focus_frame)
4342 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 4343
6c183ba5
RS
4344#ifdef HAVE_X_I18N
4345 if (f && FRAME_XIC (f))
4346 XUnsetICFocus (FRAME_XIC (f));
4347#endif
4348
7a13e894 4349 goto OTHER;
dc6f92b8 4350
7a13e894 4351 case MotionNotify:
dc6f92b8 4352 {
7a13e894
RS
4353 if (dpyinfo->grabbed && last_mouse_frame
4354 && FRAME_LIVE_P (last_mouse_frame))
4355 f = last_mouse_frame;
4356 else
19126e11 4357 f = x_window_to_frame (dpyinfo, event.xmotion.window);
7a13e894
RS
4358 if (f)
4359 note_mouse_movement (f, &event.xmotion);
4360 else
4361 {
4362 struct scroll_bar *bar
4363 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 4364
7a13e894
RS
4365 if (bar)
4366 x_scroll_bar_note_movement (bar, &event);
b8009dd1 4367
7a13e894
RS
4368 /* If we move outside the frame,
4369 then we're certainly no longer on any text in the frame. */
4370 clear_mouse_face (dpyinfo);
4371 }
dc6f92b8 4372 }
7a13e894 4373 goto OTHER;
dc6f92b8 4374
7a13e894 4375 case ConfigureNotify:
9829ddba
RS
4376 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
4377 if (f)
af395ec1 4378 {
2d7fc7e8
RS
4379#ifndef USE_X_TOOLKIT
4380 /* In the toolkit version, change_frame_size
4381 is called by the code that handles resizing
4382 of the EmacsFrame widget. */
7a13e894 4383
7a13e894
RS
4384 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
4385 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
4386
4387 /* Even if the number of character rows and columns has
4388 not changed, the font size may have changed, so we need
4389 to check the pixel dimensions as well. */
4390 if (columns != f->width
4391 || rows != f->height
7556890b
RS
4392 || event.xconfigure.width != f->output_data.x->pixel_width
4393 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894
RS
4394 {
4395 change_frame_size (f, rows, columns, 0, 1);
4396 SET_FRAME_GARBAGED (f);
e687d06e 4397 cancel_mouse_face (f);
7a13e894 4398 }
2d7fc7e8 4399#endif
af395ec1 4400
7556890b
RS
4401 f->output_data.x->pixel_width = event.xconfigure.width;
4402 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
4403
4404 /* What we have now is the position of Emacs's own window.
4405 Convert that to the position of the window manager window. */
dcb07ae9
RS
4406 x_real_positions (f, &f->output_data.x->left_pos,
4407 &f->output_data.x->top_pos);
4408
4409 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
4410 {
4411 /* Since the WM decorations come below top_pos now,
4412 we must put them below top_pos in the future. */
4413 f->output_data.x->win_gravity = NorthWestGravity;
4414 x_wm_set_size_hint (f, (long) 0, 0);
4415 }
7a13e894 4416 }
2d7fc7e8 4417 goto OTHER;
dc6f92b8 4418
7a13e894
RS
4419 case ButtonPress:
4420 case ButtonRelease:
4421 {
4422 /* If we decide we want to generate an event to be seen
4423 by the rest of Emacs, we put it here. */
4424 struct input_event emacs_event;
4425 emacs_event.kind = no_event;
dc6f92b8 4426
7a13e894 4427 bzero (&compose_status, sizeof (compose_status));
9b07615b 4428
9f67f20b
RS
4429 if (dpyinfo->grabbed && last_mouse_frame
4430 && FRAME_LIVE_P (last_mouse_frame))
4431 f = last_mouse_frame;
4432 else
2224b905 4433 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 4434
7a13e894
RS
4435 if (f)
4436 {
0f941935 4437 if (!dpyinfo->x_focus_frame || f == dpyinfo->x_focus_frame)
7a13e894
RS
4438 construct_mouse_click (&emacs_event, &event, f);
4439 }
4440 else
4441 {
4442 struct scroll_bar *bar
4443 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 4444
7a13e894
RS
4445 if (bar)
4446 x_scroll_bar_handle_click (bar, &event, &emacs_event);
7a13e894
RS
4447 }
4448
4449 if (event.type == ButtonPress)
4450 {
4451 dpyinfo->grabbed |= (1 << event.xbutton.button);
4452 last_mouse_frame = f;
4453 }
3afe33e7
RS
4454 else
4455 {
7a13e894 4456 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 4457 }
23faf38f 4458
7a13e894
RS
4459 if (numchars >= 1 && emacs_event.kind != no_event)
4460 {
4461 bcopy (&emacs_event, bufp, sizeof (struct input_event));
4462 bufp++;
4463 count++;
4464 numchars--;
4465 }
3afe33e7
RS
4466
4467#ifdef USE_X_TOOLKIT
2224b905
RS
4468 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
4469 /* For a down-event in the menu bar,
4470 don't pass it to Xt right now.
4471 Instead, save it away
4472 and we will pass it to Xt from kbd_buffer_get_event.
4473 That way, we can run some Lisp code first. */
91375f8f
RS
4474 if (f && event.type == ButtonPress
4475 /* Verify the event is really within the menu bar
4476 and not just sent to it due to grabbing. */
4477 && event.xbutton.x >= 0
4478 && event.xbutton.x < f->output_data.x->pixel_width
4479 && event.xbutton.y >= 0
4480 && event.xbutton.y < f->output_data.x->menubar_height
4481 && event.xbutton.same_screen)
2224b905 4482 {
8805890a 4483 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
4484 XSETFRAME (last_mouse_press_frame, f);
4485 }
4486 else if (event.type == ButtonPress)
4487 {
4488 last_mouse_press_frame = Qnil;
30e671c3 4489 goto OTHER;
ce89ef46 4490 }
2237cac9
RS
4491#ifdef USE_MOTIF /* This should do not harm for Lucid,
4492 but I am trying to be cautious. */
ce89ef46
RS
4493 else if (event.type == ButtonRelease)
4494 {
2237cac9 4495 if (!NILP (last_mouse_press_frame))
f10ded1c 4496 {
2237cac9
RS
4497 f = XFRAME (last_mouse_press_frame);
4498 if (f->output_data.x)
4499 {
4500 SET_SAVED_BUTTON_EVENT;
4501 }
f10ded1c 4502 }
30e671c3
RS
4503 else
4504 goto OTHER;
2224b905 4505 }
2237cac9 4506#endif /* USE_MOTIF */
2224b905
RS
4507 else
4508 goto OTHER;
3afe33e7 4509#endif /* USE_X_TOOLKIT */
7a13e894
RS
4510 }
4511 break;
dc6f92b8 4512
7a13e894
RS
4513 case CirculateNotify:
4514 break;
4515 case CirculateRequest:
4516 break;
dc6f92b8 4517
7a13e894
RS
4518 case MappingNotify:
4519 /* Someone has changed the keyboard mapping - update the
4520 local cache. */
4521 switch (event.xmapping.request)
4522 {
4523 case MappingModifier:
4524 x_find_modifier_meanings (dpyinfo);
4525 /* This is meant to fall through. */
4526 case MappingKeyboard:
4527 XRefreshKeyboardMapping (&event.xmapping);
4528 }
7a13e894 4529 goto OTHER;
dc6f92b8 4530
7a13e894 4531 default:
7a13e894 4532 OTHER:
717ca130 4533#ifdef USE_X_TOOLKIT
7a13e894
RS
4534 BLOCK_INPUT;
4535 XtDispatchEvent (&event);
4536 UNBLOCK_INPUT;
3afe33e7 4537#endif /* USE_X_TOOLKIT */
7a13e894
RS
4538 break;
4539 }
dc6f92b8
JB
4540 }
4541 }
4542
9a5196d0
RS
4543 /* On some systems, an X bug causes Emacs to get no more events
4544 when the window is destroyed. Detect that. (1994.) */
58769bee 4545 if (! event_found)
ef2a22d0 4546 {
ef2a22d0
RS
4547 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
4548 One XNOOP in 100 loops will make Emacs terminate.
4549 B. Bretthauer, 1994 */
4550 x_noop_count++;
58769bee 4551 if (x_noop_count >= 100)
ef2a22d0
RS
4552 {
4553 x_noop_count=0;
2224b905
RS
4554
4555 if (next_noop_dpyinfo == 0)
4556 next_noop_dpyinfo = x_display_list;
4557
4558 XNoOp (next_noop_dpyinfo->display);
4559
4560 /* Each time we get here, cycle through the displays now open. */
4561 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
4562 }
4563 }
502add23 4564
0134a210
RS
4565 /* If the focus was just given to an autoraising frame,
4566 raise it now. */
7a13e894 4567 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
4568 if (pending_autoraise_frame)
4569 {
4570 x_raise_frame (pending_autoraise_frame);
4571 pending_autoraise_frame = 0;
4572 }
0134a210 4573
dc6f92b8
JB
4574 UNBLOCK_INPUT;
4575 return count;
4576}
dc6f92b8 4577\f
f451eb13
JB
4578/* Drawing the cursor. */
4579
4580
39d8bb4d
KH
4581/* Draw a hollow box cursor on frame F at X, Y.
4582 Don't change the inside of the box. */
dc6f92b8
JB
4583
4584static void
39d8bb4d 4585x_draw_box (f, x, y)
f676886a 4586 struct frame *f;
39d8bb4d 4587 int x, y;
dc6f92b8 4588{
39d8bb4d
KH
4589 int left = CHAR_TO_PIXEL_COL (f, x);
4590 int top = CHAR_TO_PIXEL_ROW (f, y);
7556890b
RS
4591 int width = FONT_WIDTH (f->output_data.x->font);
4592 int height = f->output_data.x->line_height;
dc43ef94
KH
4593 int c = FAST_GLYPH_CHAR (f->phys_cursor_glyph);
4594 int charset = CHAR_CHARSET (c);
dc6f92b8 4595
5c1aae96
RS
4596 XGCValues xgcv;
4597 unsigned long mask = GCForeground;
4598
4599 xgcv.foreground = f->output_data.x->cursor_pixel;
4600
4601 /* cursor_gc's foreground color is typically the same as the normal
4602 background color, which can cause the cursor box to be invisible. */
4603 if (FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc)
4604 XChangeGC (FRAME_X_DISPLAY (f),
4605 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc,
4606 mask, &xgcv);
4607 else
4608 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc
4609 = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), mask, &xgcv);
4610
dc43ef94
KH
4611 /* If cursor is on a multi-column character, multiply WIDTH by columns. */
4612 width *= (charset == CHARSET_COMPOSITION
4613 ? cmpchar_table[COMPOSITE_CHAR_ID (c)]->width
4614 : CHARSET_WIDTH (charset));
334208b7 4615 XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5c1aae96 4616 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc,
dc6f92b8 4617 left, top, width - 1, height - 1);
dc6f92b8
JB
4618}
4619
f676886a 4620/* Clear the cursor of frame F to background color,
dc6f92b8
JB
4621 and mark the cursor as not shown.
4622 This is used when the text where the cursor is
4623 is about to be rewritten. */
4624
4625static void
f676886a
JB
4626clear_cursor (f)
4627 struct frame *f;
dc6f92b8
JB
4628{
4629 int mask;
4630
f451eb13 4631 if (! FRAME_VISIBLE_P (f)
549b29ac 4632 || ! f->phys_cursor_on)
dc6f92b8
JB
4633 return;
4634
d1bc4182 4635 x_update_cursor (f, 0);
549b29ac 4636 f->phys_cursor_on = 0;
dc6f92b8
JB
4637}
4638
f676886a 4639/* Redraw the glyph at ROW, COLUMN on frame F, in the style
90e65f07
JB
4640 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
4641 glyph drawn. */
dc6f92b8
JB
4642
4643static void
f676886a
JB
4644x_draw_single_glyph (f, row, column, glyph, highlight)
4645 struct frame *f;
dc6f92b8 4646 int row, column;
90e65f07 4647 GLYPH glyph;
dc6f92b8
JB
4648 int highlight;
4649{
f676886a 4650 dumpglyphs (f,
12ba150f
JB
4651 CHAR_TO_PIXEL_COL (f, column),
4652 CHAR_TO_PIXEL_ROW (f, row),
dc43ef94 4653 &glyph, 1, highlight, 0, NULL);
dc6f92b8
JB
4654}
4655
dc6f92b8 4656static void
39d8bb4d 4657x_display_bar_cursor (f, on, x, y)
f676886a 4658 struct frame *f;
dc6f92b8 4659 int on;
39d8bb4d 4660 int x, y;
dc6f92b8 4661{
f676886a 4662 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
90e65f07 4663
49d838ea
JB
4664 /* This is pointless on invisible frames, and dangerous on garbaged
4665 frames; in the latter case, the frame may be in the midst of
39d8bb4d 4666 changing its size, and x and y may be off the frame. */
49d838ea 4667 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dbc4e1c1
JB
4668 return;
4669
549b29ac 4670 if (! on && ! f->phys_cursor_on)
dbc4e1c1
JB
4671 return;
4672
dbc4e1c1 4673 /* If there is anything wrong with the current cursor state, remove it. */
549b29ac 4674 if (f->phys_cursor_on
dbc4e1c1 4675 && (!on
39d8bb4d
KH
4676 || f->phys_cursor_x != x
4677 || f->phys_cursor_y != y
7556890b 4678 || f->output_data.x->current_cursor != bar_cursor))
dbc4e1c1
JB
4679 {
4680 /* Erase the cursor by redrawing the character underneath it. */
4681 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4682 f->phys_cursor_glyph,
4683 current_glyphs->highlight[f->phys_cursor_y]);
549b29ac 4684 f->phys_cursor_on = 0;
dbc4e1c1
JB
4685 }
4686
4687 /* If we now need a cursor in the new place or in the new form, do it so. */
4688 if (on
549b29ac 4689 && (! f->phys_cursor_on
7556890b 4690 || (f->output_data.x->current_cursor != bar_cursor)))
dbc4e1c1
JB
4691 {
4692 f->phys_cursor_glyph
39d8bb4d
KH
4693 = ((current_glyphs->enable[y]
4694 && x < current_glyphs->used[y])
4695 ? current_glyphs->glyphs[y][x]
dbc4e1c1 4696 : SPACEGLYPH);
334208b7 4697 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 4698 f->output_data.x->cursor_gc,
39d8bb4d
KH
4699 CHAR_TO_PIXEL_COL (f, x),
4700 CHAR_TO_PIXEL_ROW (f, y),
7556890b
RS
4701 max (f->output_data.x->cursor_width, 1),
4702 f->output_data.x->line_height);
dbc4e1c1 4703
39d8bb4d
KH
4704 f->phys_cursor_x = x;
4705 f->phys_cursor_y = y;
549b29ac 4706 f->phys_cursor_on = 1;
dbc4e1c1 4707
7556890b 4708 f->output_data.x->current_cursor = bar_cursor;
dbc4e1c1
JB
4709 }
4710
4711 if (updating_frame != f)
334208b7 4712 XFlush (FRAME_X_DISPLAY (f));
dbc4e1c1
JB
4713}
4714
4715
4716/* Turn the displayed cursor of frame F on or off according to ON.
39d8bb4d 4717 If ON is nonzero, where to put the cursor is specified by X and Y. */
dbc4e1c1
JB
4718
4719static void
39d8bb4d 4720x_display_box_cursor (f, on, x, y)
dbc4e1c1
JB
4721 struct frame *f;
4722 int on;
39d8bb4d 4723 int x, y;
dbc4e1c1
JB
4724{
4725 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4726
49d838ea
JB
4727 /* This is pointless on invisible frames, and dangerous on garbaged
4728 frames; in the latter case, the frame may be in the midst of
39d8bb4d 4729 changing its size, and x and y may be off the frame. */
49d838ea 4730 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dc6f92b8
JB
4731 return;
4732
4733 /* If cursor is off and we want it off, return quickly. */
549b29ac 4734 if (!on && ! f->phys_cursor_on)
dc6f92b8
JB
4735 return;
4736
4737 /* If cursor is currently being shown and we don't want it to be
4738 or it is in the wrong place,
4739 or we want a hollow box and it's not so, (pout!)
4740 erase it. */
549b29ac 4741 if (f->phys_cursor_on
dc6f92b8 4742 && (!on
39d8bb4d
KH
4743 || f->phys_cursor_x != x
4744 || f->phys_cursor_y != y
7556890b 4745 || (f->output_data.x->current_cursor != hollow_box_cursor
0f941935 4746 && (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame))))
dc6f92b8 4747 {
79cf7456 4748 int mouse_face_here = 0;
9f67f20b 4749 struct frame_glyphs *active_glyphs = FRAME_CURRENT_GLYPHS (f);
79cf7456
RS
4750
4751 /* If the cursor is in the mouse face area, redisplay that when
4752 we clear the cursor. */
7a13e894 4753 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame
79cf7456 4754 &&
7a13e894
RS
4755 (f->phys_cursor_y > FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4756 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4757 && f->phys_cursor_x >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col))
79cf7456 4758 &&
7a13e894
RS
4759 (f->phys_cursor_y < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
4760 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
9f67f20b
RS
4761 && f->phys_cursor_x < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col))
4762 /* Don't redraw the cursor's spot in mouse face
4763 if it is at the end of a line (on a newline).
4764 The cursor appears there, but mouse highlighting does not. */
4765 && active_glyphs->used[f->phys_cursor_y] > f->phys_cursor_x)
79cf7456
RS
4766 mouse_face_here = 1;
4767
0cdd0c9f
RS
4768 /* If the font is not as tall as a whole line,
4769 we must explicitly clear the line's whole height. */
7556890b 4770 if (FONT_HEIGHT (f->output_data.x->font) != f->output_data.x->line_height)
334208b7 4771 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
0cdd0c9f
RS
4772 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
4773 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
7556890b
RS
4774 FONT_WIDTH (f->output_data.x->font),
4775 f->output_data.x->line_height, False);
dc6f92b8 4776 /* Erase the cursor by redrawing the character underneath it. */
f676886a
JB
4777 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4778 f->phys_cursor_glyph,
79cf7456
RS
4779 (mouse_face_here
4780 ? 3
4781 : current_glyphs->highlight[f->phys_cursor_y]));
549b29ac 4782 f->phys_cursor_on = 0;
dc6f92b8
JB
4783 }
4784
4785 /* If we want to show a cursor,
4786 or we want a box cursor and it's not so,
4787 write it in the right place. */
4788 if (on
549b29ac 4789 && (! f->phys_cursor_on
7556890b 4790 || (f->output_data.x->current_cursor != filled_box_cursor
0f941935 4791 && f == FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)))
dc6f92b8 4792 {
f676886a 4793 f->phys_cursor_glyph
39d8bb4d
KH
4794 = ((current_glyphs->enable[y]
4795 && x < current_glyphs->used[y])
4796 ? current_glyphs->glyphs[y][x]
90e65f07 4797 : SPACEGLYPH);
0f941935 4798 if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
dc6f92b8 4799 {
39d8bb4d 4800 x_draw_box (f, x, y);
7556890b 4801 f->output_data.x->current_cursor = hollow_box_cursor;
dc6f92b8
JB
4802 }
4803 else
4804 {
39d8bb4d 4805 x_draw_single_glyph (f, y, x,
f676886a 4806 f->phys_cursor_glyph, 2);
7556890b 4807 f->output_data.x->current_cursor = filled_box_cursor;
dc6f92b8
JB
4808 }
4809
39d8bb4d
KH
4810 f->phys_cursor_x = x;
4811 f->phys_cursor_y = y;
549b29ac 4812 f->phys_cursor_on = 1;
dc6f92b8
JB
4813 }
4814
f676886a 4815 if (updating_frame != f)
334208b7 4816 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
4817}
4818
5d46f928 4819/* Display the cursor on frame F, or clear it, according to ON.
d1bc4182 4820 Also set the frame's cursor position to X and Y. */
5d46f928 4821
d1bc4182 4822x_display_cursor (f, on, x, y)
f676886a 4823 struct frame *f;
dc6f92b8 4824 int on;
d1bc4182 4825 int x, y;
dc6f92b8 4826{
f94397b5
KH
4827 BLOCK_INPUT;
4828
5d46f928 4829 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
d1bc4182 4830 x_display_box_cursor (f, on, x, y);
5d46f928 4831 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
d1bc4182 4832 x_display_bar_cursor (f, on, x, y);
5d46f928
RS
4833 else
4834 /* Those are the only two we have implemented! */
4835 abort ();
4836
4837 UNBLOCK_INPUT;
4838}
4839
4840/* Display the cursor on frame F, or clear it, according to ON.
4841 Don't change the cursor's position. */
4842
4843x_update_cursor (f, on)
4844 struct frame *f;
4845 int on;
4846{
4847 BLOCK_INPUT;
4848
dbc4e1c1 4849 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
39d8bb4d 4850 x_display_box_cursor (f, on, f->phys_cursor_x, f->phys_cursor_y);
dbc4e1c1 4851 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
39d8bb4d 4852 x_display_bar_cursor (f, on, f->phys_cursor_x, f->phys_cursor_y);
dbc4e1c1
JB
4853 else
4854 /* Those are the only two we have implemented! */
4855 abort ();
f94397b5
KH
4856
4857 UNBLOCK_INPUT;
dc6f92b8
JB
4858}
4859\f
4860/* Icons. */
4861
f676886a 4862/* Refresh bitmap kitchen sink icon for frame F
dc6f92b8
JB
4863 when we get an expose event for it. */
4864
f676886a
JB
4865refreshicon (f)
4866 struct frame *f;
dc6f92b8 4867{
dc6f92b8 4868 /* Normally, the window manager handles this function. */
dc6f92b8
JB
4869}
4870
dbc4e1c1 4871/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
4872
4873int
990ba854 4874x_bitmap_icon (f, file)
f676886a 4875 struct frame *f;
990ba854 4876 Lisp_Object file;
dc6f92b8 4877{
7f2ae036 4878 int mask, bitmap_id;
dc6f92b8
JB
4879 Window icon_window;
4880
c118dd06 4881 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
4882 return 1;
4883
990ba854 4884 /* Free up our existing icon bitmap if any. */
7556890b
RS
4885 if (f->output_data.x->icon_bitmap > 0)
4886 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
4887 f->output_data.x->icon_bitmap = 0;
990ba854
RS
4888
4889 if (STRINGP (file))
7f2ae036
RS
4890 bitmap_id = x_create_bitmap_from_file (f, file);
4891 else
4892 {
990ba854 4893 /* Create the GNU bitmap if necessary. */
5bf01b68 4894 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
4895 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
4896 = x_create_bitmap_from_data (f, gnu_bits,
4897 gnu_width, gnu_height);
990ba854
RS
4898
4899 /* The first time we create the GNU bitmap,
4900 this increments the refcount one extra time.
4901 As a result, the GNU bitmap is never freed.
4902 That way, we don't have to worry about allocating it again. */
334208b7 4903 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 4904
334208b7 4905 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
4906 }
4907
4908 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 4909 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
4910
4911 return 0;
4912}
4913
4914
1be2d067
KH
4915/* Make the x-window of frame F use a rectangle with text.
4916 Use ICON_NAME as the text. */
dc6f92b8
JB
4917
4918int
f676886a
JB
4919x_text_icon (f, icon_name)
4920 struct frame *f;
dc6f92b8
JB
4921 char *icon_name;
4922{
c118dd06 4923 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
4924 return 1;
4925
1be2d067
KH
4926#ifdef HAVE_X11R4
4927 {
4928 XTextProperty text;
4929 text.value = (unsigned char *) icon_name;
4930 text.encoding = XA_STRING;
4931 text.format = 8;
4932 text.nitems = strlen (icon_name);
4933#ifdef USE_X_TOOLKIT
7556890b 4934 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
4935 &text);
4936#else /* not USE_X_TOOLKIT */
4937 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
4938#endif /* not USE_X_TOOLKIT */
4939 }
4940#else /* not HAVE_X11R4 */
4941 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
4942#endif /* not HAVE_X11R4 */
58769bee 4943
7556890b
RS
4944 if (f->output_data.x->icon_bitmap > 0)
4945 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
4946 f->output_data.x->icon_bitmap = 0;
b1c884c3 4947 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
4948
4949 return 0;
4950}
4951\f
e99db5a1
RS
4952#define X_ERROR_MESSAGE_SIZE 200
4953
4954/* If non-nil, this should be a string.
4955 It means catch X errors and store the error message in this string. */
4956
4957static Lisp_Object x_error_message_string;
4958
4959/* An X error handler which stores the error message in
4960 x_error_message_string. This is called from x_error_handler if
4961 x_catch_errors is in effect. */
4962
4963static int
4964x_error_catcher (display, error)
4965 Display *display;
4966 XErrorEvent *error;
4967{
4968 XGetErrorText (display, error->error_code,
4969 XSTRING (x_error_message_string)->data,
4970 X_ERROR_MESSAGE_SIZE);
4971}
4972
4973/* Begin trapping X errors for display DPY. Actually we trap X errors
4974 for all displays, but DPY should be the display you are actually
4975 operating on.
4976
4977 After calling this function, X protocol errors no longer cause
4978 Emacs to exit; instead, they are recorded in the string
4979 stored in x_error_message_string.
4980
4981 Calling x_check_errors signals an Emacs error if an X error has
4982 occurred since the last call to x_catch_errors or x_check_errors.
4983
4984 Calling x_uncatch_errors resumes the normal error handling. */
4985
4986void x_check_errors ();
4987static Lisp_Object x_catch_errors_unwind ();
4988
4989int
4990x_catch_errors (dpy)
4991 Display *dpy;
4992{
4993 int count = specpdl_ptr - specpdl;
4994
4995 /* Make sure any errors from previous requests have been dealt with. */
4996 XSync (dpy, False);
4997
4998 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
4999
5000 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
5001 XSTRING (x_error_message_string)->data[0] = 0;
5002
5003 return count;
5004}
5005
5006/* Unbind the binding that we made to check for X errors. */
5007
5008static Lisp_Object
5009x_catch_errors_unwind (old_val)
5010 Lisp_Object old_val;
5011{
5012 x_error_message_string = old_val;
5013 return Qnil;
5014}
5015
5016/* If any X protocol errors have arrived since the last call to
5017 x_catch_errors or x_check_errors, signal an Emacs error using
5018 sprintf (a buffer, FORMAT, the x error message text) as the text. */
5019
5020void
5021x_check_errors (dpy, format)
5022 Display *dpy;
5023 char *format;
5024{
5025 /* Make sure to catch any errors incurred so far. */
5026 XSync (dpy, False);
5027
5028 if (XSTRING (x_error_message_string)->data[0])
5029 error (format, XSTRING (x_error_message_string)->data);
5030}
5031
9829ddba
RS
5032/* Nonzero if we had any X protocol errors
5033 since we did x_catch_errors on DPY. */
e99db5a1
RS
5034
5035int
5036x_had_errors_p (dpy)
5037 Display *dpy;
5038{
5039 /* Make sure to catch any errors incurred so far. */
5040 XSync (dpy, False);
5041
5042 return XSTRING (x_error_message_string)->data[0] != 0;
5043}
5044
9829ddba
RS
5045/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
5046
5047int
5048x_clear_errors (dpy)
5049 Display *dpy;
5050{
5051 XSTRING (x_error_message_string)->data[0] = 0;
5052}
5053
e99db5a1
RS
5054/* Stop catching X protocol errors and let them make Emacs die.
5055 DPY should be the display that was passed to x_catch_errors.
5056 COUNT should be the value that was returned by
5057 the corresponding call to x_catch_errors. */
5058
5059void
5060x_uncatch_errors (dpy, count)
5061 Display *dpy;
5062 int count;
5063{
5064 unbind_to (count, Qnil);
5065}
5066
5067#if 0
5068static unsigned int x_wire_count;
5069x_trace_wire ()
5070{
5071 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
5072}
5073#endif /* ! 0 */
5074
5075\f
5076/* Handle SIGPIPE, which can happen when the connection to a server
5077 simply goes away. SIGPIPE is handled by x_connection_signal.
5078 Don't need to do anything, because the write which caused the
5079 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
5080 which will do the appropriate cleanup for us. */
5081
5082static SIGTYPE
5083x_connection_signal (signalnum) /* If we don't have an argument, */
5084 int signalnum; /* some compilers complain in signal calls. */
5085{
5086#ifdef USG
5087 /* USG systems forget handlers when they are used;
5088 must reestablish each time */
5089 signal (signalnum, x_connection_signal);
5090#endif /* USG */
5091}
5092\f
4746118a
JB
5093/* Handling X errors. */
5094
7a13e894 5095/* Handle the loss of connection to display DISPLAY. */
16bd92ea 5096
4746118a 5097static SIGTYPE
7a13e894
RS
5098x_connection_closed (display, error_message)
5099 Display *display;
5100 char *error_message;
4746118a 5101{
7a13e894
RS
5102 struct x_display_info *dpyinfo = x_display_info_for_display (display);
5103 Lisp_Object frame, tail;
5104
6186a4a0
RS
5105 /* Indicate that this display is dead. */
5106
f613a4c8 5107#ifdef USE_X_TOOLKIT
adabc3a9 5108 XtCloseDisplay (display);
f613a4c8 5109#endif
adabc3a9 5110
6186a4a0
RS
5111 dpyinfo->display = 0;
5112
7a13e894
RS
5113 /* First delete frames whose minibuffers are on frames
5114 that are on the dead display. */
5115 FOR_EACH_FRAME (tail, frame)
5116 {
5117 Lisp_Object minibuf_frame;
5118 minibuf_frame
5119 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
5120 if (FRAME_X_P (XFRAME (frame))
5121 && FRAME_X_P (XFRAME (minibuf_frame))
5122 && ! EQ (frame, minibuf_frame)
5123 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
5124 Fdelete_frame (frame, Qt);
5125 }
5126
5127 /* Now delete all remaining frames on the dead display.
5128 We are now sure none of these is used as the minibuffer
5129 for another frame that we need to delete. */
5130 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
5131 if (FRAME_X_P (XFRAME (frame))
5132 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
5133 {
5134 /* Set this to t so that Fdelete_frame won't get confused
5135 trying to find a replacement. */
5136 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
5137 Fdelete_frame (frame, Qt);
5138 }
7a13e894 5139
482a1bd2
KH
5140 if (dpyinfo)
5141 x_delete_display (dpyinfo);
7a13e894
RS
5142
5143 if (x_display_list == 0)
5144 {
f8d07b62 5145 fprintf (stderr, "%s\n", error_message);
7a13e894
RS
5146 shut_down_emacs (0, 0, Qnil);
5147 exit (70);
5148 }
12ba150f 5149
7a13e894
RS
5150 /* Ordinary stack unwind doesn't deal with these. */
5151#ifdef SIGIO
5152 sigunblock (sigmask (SIGIO));
5153#endif
5154 sigunblock (sigmask (SIGALRM));
5155 TOTALLY_UNBLOCK_INPUT;
5156
aa4d9a9e 5157 clear_waiting_for_input ();
7a13e894 5158 error ("%s", error_message);
4746118a
JB
5159}
5160
7a13e894
RS
5161/* This is the usual handler for X protocol errors.
5162 It kills all frames on the display that we got the error for.
5163 If that was the only one, it prints an error message and kills Emacs. */
5164
c118dd06
JB
5165static int
5166x_error_quitter (display, error)
5167 Display *display;
5168 XErrorEvent *error;
5169{
7a13e894 5170 char buf[256], buf1[356];
dc6f92b8 5171
58769bee 5172 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 5173 original error handler. */
dc6f92b8 5174
c118dd06 5175 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 5176 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 5177 buf, error->request_code);
7a13e894 5178 x_connection_closed (display, buf1);
dc6f92b8
JB
5179}
5180
e99db5a1
RS
5181/* This is the first-level handler for X protocol errors.
5182 It calls x_error_quitter or x_error_catcher. */
7a13e894 5183
8922af5f 5184static int
e99db5a1 5185x_error_handler (display, error)
8922af5f 5186 Display *display;
e99db5a1 5187 XErrorEvent *error;
8922af5f 5188{
e99db5a1 5189 char buf[256], buf1[356];
8922af5f 5190
e99db5a1
RS
5191 if (! NILP (x_error_message_string))
5192 x_error_catcher (display, error);
5193 else
5194 x_error_quitter (display, error);
f9e24cb9 5195}
c118dd06 5196
e99db5a1
RS
5197/* This is the handler for X IO errors, always.
5198 It kills all frames on the display that we lost touch with.
5199 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 5200
c118dd06 5201static int
e99db5a1 5202x_io_error_quitter (display)
c118dd06 5203 Display *display;
c118dd06 5204{
e99db5a1 5205 char buf[256];
dc6f92b8 5206
e99db5a1
RS
5207 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
5208 x_connection_closed (display, buf);
dc6f92b8 5209}
dc6f92b8 5210\f
f451eb13
JB
5211/* Changing the font of the frame. */
5212
76bcdf39
RS
5213/* Give frame F the font named FONTNAME as its default font, and
5214 return the full name of that font. FONTNAME may be a wildcard
5215 pattern; in that case, we choose some font that fits the pattern.
5216 The return value shows which font we chose. */
5217
b5cf7a0e 5218Lisp_Object
f676886a
JB
5219x_new_font (f, fontname)
5220 struct frame *f;
dc6f92b8
JB
5221 register char *fontname;
5222{
dc43ef94
KH
5223 struct font_info *fontp
5224 = fs_load_font (f, FRAME_X_FONT_TABLE (f), CHARSET_ASCII, fontname, -1);
dc6f92b8 5225
dc43ef94
KH
5226 if (!fontp)
5227 return Qnil;
2224a5fc 5228
dc43ef94
KH
5229 f->output_data.x->font = (XFontStruct *) (fontp->font);
5230 f->output_data.x->font_baseline
5231 = (f->output_data.x->font->ascent + fontp->baseline_offset);
5232 f->output_data.x->fontset = -1;
5233
b2cad826
KH
5234 /* Compute the scroll bar width in character columns. */
5235 if (f->scroll_bar_pixel_width > 0)
5236 {
7556890b 5237 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
5238 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
5239 }
5240 else
5241 f->scroll_bar_cols = 2;
5242
f676886a 5243 /* Now make the frame display the given font. */
c118dd06 5244 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 5245 {
7556890b
RS
5246 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
5247 f->output_data.x->font->fid);
5248 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
5249 f->output_data.x->font->fid);
5250 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
5251 f->output_data.x->font->fid);
f676886a 5252
a27f9f86 5253 frame_update_line_height (f);
0134a210 5254 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 5255 }
a27f9f86
RS
5256 else
5257 /* If we are setting a new frame's font for the first time,
5258 there are no faces yet, so this font's height is the line height. */
7556890b 5259 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 5260
dc43ef94
KH
5261 return build_string (fontp->full_name);
5262}
5263
5264/* Give frame F the fontset named FONTSETNAME as its default font, and
5265 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
5266 pattern; in that case, we choose some fontset that fits the pattern.
5267 The return value shows which fontset we chose. */
b5cf7a0e 5268
dc43ef94
KH
5269Lisp_Object
5270x_new_fontset (f, fontsetname)
5271 struct frame *f;
5272 char *fontsetname;
5273{
5274 int fontset = fs_query_fontset (f, fontsetname);
5275 struct fontset_info *fontsetp;
5276 Lisp_Object result;
b5cf7a0e 5277
dc43ef94
KH
5278 if (fontset < 0)
5279 return Qnil;
b5cf7a0e 5280
2da424f1
KH
5281 if (f->output_data.x->fontset == fontset)
5282 /* This fontset is already set in frame F. There's nothing more
5283 to do. */
5284 return build_string (fontsetname);
5285
dc43ef94
KH
5286 fontsetp = FRAME_FONTSET_DATA (f)->fontset_table[fontset];
5287
5288 if (!fontsetp->fontname[CHARSET_ASCII])
5289 /* This fontset doesn't contain ASCII font. */
5290 return Qnil;
5291
5292 result = x_new_font (f, fontsetp->fontname[CHARSET_ASCII]);
5293
5294 if (!STRINGP (result))
5295 /* Can't load ASCII font. */
5296 return Qnil;
5297
5298 /* Since x_new_font doesn't update any fontset information, do it now. */
5299 f->output_data.x->fontset = fontset;
2da424f1 5300 FS_LOAD_FONT (f, FRAME_X_FONT_TABLE (f),
dc43ef94
KH
5301 CHARSET_ASCII, XSTRING (result)->data, fontset);
5302
5303 return build_string (fontsetname);
dc6f92b8 5304}
dc6f92b8 5305\f
2e365682
RS
5306/* Calculate the absolute position in frame F
5307 from its current recorded position values and gravity. */
5308
43bca5d5 5309x_calc_absolute_position (f)
f676886a 5310 struct frame *f;
dc6f92b8 5311{
6dba1858
RS
5312 Window win, child;
5313 int win_x = 0, win_y = 0;
7556890b 5314 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
5315 int this_window;
5316
9829ddba
RS
5317 /* We have nothing to do if the current position
5318 is already for the top-left corner. */
5319 if (! ((flags & XNegative) || (flags & YNegative)))
5320 return;
5321
c81412a0 5322#ifdef USE_X_TOOLKIT
7556890b 5323 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
5324#else
5325 this_window = FRAME_X_WINDOW (f);
5326#endif
6dba1858
RS
5327
5328 /* Find the position of the outside upper-left corner of
9829ddba
RS
5329 the inner window, with respect to the outer window.
5330 But do this only if we will need the results. */
7556890b 5331 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 5332 {
9829ddba
RS
5333 int count;
5334
6dba1858 5335 BLOCK_INPUT;
9829ddba
RS
5336 count = x_catch_errors (FRAME_X_DISPLAY (f));
5337 while (1)
5338 {
5339 x_clear_errors (FRAME_X_DISPLAY (f));
5340 XTranslateCoordinates (FRAME_X_DISPLAY (f),
5341
5342 /* From-window, to-window. */
5343 this_window,
5344 f->output_data.x->parent_desc,
5345
5346 /* From-position, to-position. */
5347 0, 0, &win_x, &win_y,
5348
5349 /* Child of win. */
5350 &child);
5351 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
5352 {
5353 Window newroot, newparent = 0xdeadbeef;
5354 Window *newchildren;
5355 int nchildren;
5356
5357 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
5358 &newparent, &newchildren, &nchildren))
5359 break;
58769bee 5360
9829ddba 5361 XFree (newchildren);
6dba1858 5362
9829ddba
RS
5363 f->output_data.x->parent_desc = newparent;
5364 }
5365 else
5366 break;
5367 }
6dba1858 5368
9829ddba 5369 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
5370 UNBLOCK_INPUT;
5371 }
5372
5373 /* Treat negative positions as relative to the leftmost bottommost
5374 position that fits on the screen. */
20f55f9a 5375 if (flags & XNegative)
7556890b 5376 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
5377 - 2 * f->output_data.x->border_width - win_x
5378 - PIXEL_WIDTH (f)
5379 + f->output_data.x->left_pos);
dc6f92b8 5380
20f55f9a 5381 if (flags & YNegative)
b983e34e
RS
5382 /* We used to subtract f->output_data.x->menubar_height here
5383 in the toolkit case, but PIXEL_HEIGHT already includes that. */
7556890b 5384 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
2e365682
RS
5385 - 2 * f->output_data.x->border_width - win_y
5386 - PIXEL_HEIGHT (f)
5387 + f->output_data.x->top_pos);
5388
3a35ab44
RS
5389 /* The left_pos and top_pos
5390 are now relative to the top and left screen edges,
5391 so the flags should correspond. */
7556890b 5392 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
5393}
5394
3a35ab44
RS
5395/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
5396 to really change the position, and 0 when calling from
5397 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
5398 position values). It is -1 when calling from x_set_frame_parameters,
5399 which means, do adjust for borders but don't change the gravity. */
3a35ab44 5400
dc05a16b 5401x_set_offset (f, xoff, yoff, change_gravity)
f676886a 5402 struct frame *f;
dc6f92b8 5403 register int xoff, yoff;
dc05a16b 5404 int change_gravity;
dc6f92b8 5405{
4a4cbdd5
KH
5406 int modified_top, modified_left;
5407
aa3ff7c9 5408 if (change_gravity > 0)
3a35ab44 5409 {
7556890b
RS
5410 f->output_data.x->top_pos = yoff;
5411 f->output_data.x->left_pos = xoff;
5412 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 5413 if (xoff < 0)
7556890b 5414 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 5415 if (yoff < 0)
7556890b
RS
5416 f->output_data.x->size_hint_flags |= YNegative;
5417 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 5418 }
43bca5d5 5419 x_calc_absolute_position (f);
dc6f92b8
JB
5420
5421 BLOCK_INPUT;
c32cdd9a 5422 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 5423
7556890b
RS
5424 modified_left = f->output_data.x->left_pos;
5425 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
5426#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
5427 this seems to be unnecessary and incorrect. rms, 4/17/97. */
5428 /* It is a mystery why we need to add the border_width here
5429 when the frame is already visible, but experiment says we do. */
aa3ff7c9 5430 if (change_gravity != 0)
4a4cbdd5 5431 {
7556890b
RS
5432 modified_left += f->output_data.x->border_width;
5433 modified_top += f->output_data.x->border_width;
4a4cbdd5 5434 }
e73ec6fa 5435#endif
4a4cbdd5 5436
3afe33e7 5437#ifdef USE_X_TOOLKIT
7556890b 5438 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 5439 modified_left, modified_top);
3afe33e7 5440#else /* not USE_X_TOOLKIT */
334208b7 5441 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 5442 modified_left, modified_top);
3afe33e7 5443#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5444 UNBLOCK_INPUT;
5445}
5446
bc20ebbf
FP
5447/* Call this to change the size of frame F's x-window.
5448 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
5449 for this size change and subsequent size changes.
5450 Otherwise we leave the window gravity unchanged. */
dc6f92b8 5451
bc20ebbf 5452x_set_window_size (f, change_gravity, cols, rows)
f676886a 5453 struct frame *f;
bc20ebbf 5454 int change_gravity;
b1c884c3 5455 int cols, rows;
dc6f92b8
JB
5456{
5457 int pixelwidth, pixelheight;
5458 int mask;
aee9a898 5459 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
dc6f92b8 5460
80fd1fe2 5461 BLOCK_INPUT;
aee9a898
RS
5462
5463#ifdef USE_X_TOOLKIT
3a20653d
RS
5464 {
5465 /* The x and y position of the widget is clobbered by the
5466 call to XtSetValues within EmacsFrameSetCharSize.
5467 This is a real kludge, but I don't understand Xt so I can't
5468 figure out a correct fix. Can anyone else tell me? -- rms. */
7556890b
RS
5469 int xpos = f->output_data.x->widget->core.x;
5470 int ypos = f->output_data.x->widget->core.y;
5471 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
5472 f->output_data.x->widget->core.x = xpos;
5473 f->output_data.x->widget->core.y = ypos;
3a20653d 5474 }
80fd1fe2
FP
5475
5476#else /* not USE_X_TOOLKIT */
5477
b1c884c3 5478 check_frame_size (f, &rows, &cols);
7556890b 5479 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
5480 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5481 ? 0
5482 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 5483 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 5484 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
f451eb13
JB
5485 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
5486 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 5487
7556890b 5488 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 5489 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 5490
334208b7
RS
5491 XSync (FRAME_X_DISPLAY (f), False);
5492 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5493 pixelwidth, pixelheight);
b1c884c3
JB
5494
5495 /* Now, strictly speaking, we can't be sure that this is accurate,
5496 but the window manager will get around to dealing with the size
5497 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
5498 ConfigureNotify event gets here.
5499
5500 We could just not bother storing any of this information here,
5501 and let the ConfigureNotify event set everything up, but that
5502 might be kind of confusing to the lisp code, since size changes
5503 wouldn't be reported in the frame parameters until some random
5504 point in the future when the ConfigureNotify event arrives. */
8922af5f 5505 change_frame_size (f, rows, cols, 0, 0);
b1c884c3
JB
5506 PIXEL_WIDTH (f) = pixelwidth;
5507 PIXEL_HEIGHT (f) = pixelheight;
5508
aee9a898
RS
5509 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
5510 receive in the ConfigureNotify event; if we get what we asked
5511 for, then the event won't cause the screen to become garbaged, so
5512 we have to make sure to do it here. */
5513 SET_FRAME_GARBAGED (f);
5514
5515 XFlush (FRAME_X_DISPLAY (f));
5516
5517#endif /* not USE_X_TOOLKIT */
5518
4d73d038
RS
5519 /* If cursor was outside the new size, mark it as off. */
5520 if (f->phys_cursor_y >= rows
5521 || f->phys_cursor_x >= cols)
5522 {
549b29ac
RS
5523 f->phys_cursor_x = 0;
5524 f->phys_cursor_y = 0;
5525 f->phys_cursor_on = 0;
4d73d038
RS
5526 }
5527
aee9a898
RS
5528 /* Clear out any recollection of where the mouse highlighting was,
5529 since it might be in a place that's outside the new frame size.
5530 Actually checking whether it is outside is a pain in the neck,
5531 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 5532 cancel_mouse_face (f);
dbc4e1c1 5533
dc6f92b8
JB
5534 UNBLOCK_INPUT;
5535}
dc6f92b8 5536\f
d047c4eb 5537/* Mouse warping. */
dc6f92b8 5538
9b378208 5539void
f676886a
JB
5540x_set_mouse_position (f, x, y)
5541 struct frame *f;
dc6f92b8
JB
5542 int x, y;
5543{
5544 int pix_x, pix_y;
5545
7556890b
RS
5546 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
5547 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
5548
5549 if (pix_x < 0) pix_x = 0;
5550 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
5551
5552 if (pix_y < 0) pix_y = 0;
5553 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
5554
5555 BLOCK_INPUT;
dc6f92b8 5556
334208b7
RS
5557 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
5558 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
5559 UNBLOCK_INPUT;
5560}
5561
9b378208
RS
5562/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
5563
5564void
5565x_set_mouse_pixel_position (f, pix_x, pix_y)
5566 struct frame *f;
5567 int pix_x, pix_y;
5568{
5569 BLOCK_INPUT;
5570
334208b7
RS
5571 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
5572 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
5573 UNBLOCK_INPUT;
5574}
d047c4eb
KH
5575\f
5576/* focus shifting, raising and lowering. */
9b378208 5577
f676886a
JB
5578x_focus_on_frame (f)
5579 struct frame *f;
dc6f92b8 5580{
1fb20991 5581#if 0 /* This proves to be unpleasant. */
f676886a 5582 x_raise_frame (f);
1fb20991 5583#endif
6d4238f3
JB
5584#if 0
5585 /* I don't think that the ICCCM allows programs to do things like this
5586 without the interaction of the window manager. Whatever you end up
f676886a 5587 doing with this code, do it to x_unfocus_frame too. */
334208b7 5588 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 5589 RevertToPointerRoot, CurrentTime);
c118dd06 5590#endif /* ! 0 */
dc6f92b8
JB
5591}
5592
f676886a
JB
5593x_unfocus_frame (f)
5594 struct frame *f;
dc6f92b8 5595{
6d4238f3 5596#if 0
f676886a 5597 /* Look at the remarks in x_focus_on_frame. */
0f941935 5598 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 5599 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 5600 RevertToPointerRoot, CurrentTime);
c118dd06 5601#endif /* ! 0 */
dc6f92b8
JB
5602}
5603
f676886a 5604/* Raise frame F. */
dc6f92b8 5605
f676886a
JB
5606x_raise_frame (f)
5607 struct frame *f;
dc6f92b8 5608{
3a88c238 5609 if (f->async_visible)
dc6f92b8
JB
5610 {
5611 BLOCK_INPUT;
3afe33e7 5612#ifdef USE_X_TOOLKIT
7556890b 5613 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 5614#else /* not USE_X_TOOLKIT */
334208b7 5615 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 5616#endif /* not USE_X_TOOLKIT */
334208b7 5617 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
5618 UNBLOCK_INPUT;
5619 }
5620}
5621
f676886a 5622/* Lower frame F. */
dc6f92b8 5623
f676886a
JB
5624x_lower_frame (f)
5625 struct frame *f;
dc6f92b8 5626{
3a88c238 5627 if (f->async_visible)
dc6f92b8
JB
5628 {
5629 BLOCK_INPUT;
3afe33e7 5630#ifdef USE_X_TOOLKIT
7556890b 5631 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 5632#else /* not USE_X_TOOLKIT */
334208b7 5633 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 5634#endif /* not USE_X_TOOLKIT */
334208b7 5635 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
5636 UNBLOCK_INPUT;
5637 }
5638}
5639
dbc4e1c1 5640static void
6b0442dc 5641XTframe_raise_lower (f, raise_flag)
dbc4e1c1 5642 FRAME_PTR f;
6b0442dc 5643 int raise_flag;
dbc4e1c1 5644{
6b0442dc 5645 if (raise_flag)
dbc4e1c1
JB
5646 x_raise_frame (f);
5647 else
5648 x_lower_frame (f);
5649}
d047c4eb
KH
5650\f
5651/* Change of visibility. */
dc6f92b8 5652
9382638d
KH
5653/* This tries to wait until the frame is really visible.
5654 However, if the window manager asks the user where to position
5655 the frame, this will return before the user finishes doing that.
5656 The frame will not actually be visible at that time,
5657 but it will become visible later when the window manager
5658 finishes with it. */
5659
f676886a
JB
5660x_make_frame_visible (f)
5661 struct frame *f;
dc6f92b8
JB
5662{
5663 int mask;
990ba854 5664 Lisp_Object type;
1aa6072f
RS
5665 int starting_flags = f->output_data.x->size_hint_flags;
5666 int original_top, original_left;
dc6f92b8 5667
dc6f92b8 5668 BLOCK_INPUT;
dc6f92b8 5669
990ba854
RS
5670 type = x_icon_type (f);
5671 if (!NILP (type))
5672 x_bitmap_icon (f, type);
bdcd49ba 5673
f676886a 5674 if (! FRAME_VISIBLE_P (f))
90e65f07 5675 {
1aa6072f
RS
5676 /* We test FRAME_GARBAGED_P here to make sure we don't
5677 call x_set_offset a second time
5678 if we get to x_make_frame_visible a second time
5679 before the window gets really visible. */
5680 if (! FRAME_ICONIFIED_P (f)
5681 && ! f->output_data.x->asked_for_visible)
5682 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
5683
5684 f->output_data.x->asked_for_visible = 1;
5685
90e65f07 5686 if (! EQ (Vx_no_window_manager, Qt))
f676886a 5687 x_wm_set_window_state (f, NormalState);
3afe33e7 5688#ifdef USE_X_TOOLKIT
d7a38a2e 5689 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 5690 XtMapWidget (f->output_data.x->widget);
3afe33e7 5691#else /* not USE_X_TOOLKIT */
7f9c7f94 5692 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 5693#endif /* not USE_X_TOOLKIT */
0134a210
RS
5694#if 0 /* This seems to bring back scroll bars in the wrong places
5695 if the window configuration has changed. They seem
5696 to come back ok without this. */
ab648270 5697 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 5698 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 5699#endif
90e65f07 5700 }
dc6f92b8 5701
334208b7 5702 XFlush (FRAME_X_DISPLAY (f));
90e65f07 5703
0dacf791
RS
5704 /* Synchronize to ensure Emacs knows the frame is visible
5705 before we do anything else. We do this loop with input not blocked
5706 so that incoming events are handled. */
5707 {
5708 Lisp_Object frame;
c0a04927 5709 int count = input_signal_count;
28c01ffe
RS
5710 /* This must be before UNBLOCK_INPUT
5711 since events that arrive in response to the actions above
5712 will set it when they are handled. */
5713 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
5714
5715 original_left = f->output_data.x->left_pos;
5716 original_top = f->output_data.x->top_pos;
c0a04927
RS
5717
5718 /* This must come after we set COUNT. */
5719 UNBLOCK_INPUT;
5720
1aa6072f
RS
5721 /* Arriving X events are processed here. */
5722
dcb07ae9
RS
5723 /* Now move the window back to where it was "supposed to be".
5724 But don't do it if the gravity is negative.
5725 When the gravity is negative, this uses a position
28c01ffe
RS
5726 that is 3 pixels too low. Perhaps that's really the border width.
5727
5728 Don't do this if the window has never been visible before,
5729 because the window manager may choose the position
5730 and we don't want to override it. */
1aa6072f 5731
4d3f5d9a 5732 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 5733 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 5734 && previously_visible)
1aa6072f
RS
5735 {
5736 BLOCK_INPUT;
9829ddba 5737
1aa6072f
RS
5738#ifdef USE_X_TOOLKIT
5739 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
5740 original_left, original_top);
5741#else /* not USE_X_TOOLKIT */
5742 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5743 original_left, original_top);
5744#endif /* not USE_X_TOOLKIT */
5745 UNBLOCK_INPUT;
5746 }
9829ddba 5747
e0c1aef2 5748 XSETFRAME (frame, f);
c0a04927
RS
5749
5750 while (1)
2a6cf806 5751 {
334208b7 5752 x_sync (f);
c0a04927
RS
5753 /* Once we have handled input events,
5754 we should have received the MapNotify if one is coming.
5755 So if we have not got it yet, stop looping.
5756 Some window managers make their own decisions
5757 about visibility. */
5758 if (input_signal_count != count)
5759 break;
c12a7cbd 5760 /* Machines that do polling rather than SIGIO have been observed
23cf7c60
KH
5761 to go into a busy-wait here. So we'll fake an alarm signal
5762 to let the handler know that there's something to be read.
5763 We used to raise a real alarm, but it seems that the handler
5764 isn't always enabled here. This is probably a bug. */
8b2f8d4e 5765 if (input_polling_used ())
3b2fa4e6
RS
5766 {
5767 /* It could be confusing if a real alarm arrives while processing
5768 the fake one. Turn it off and let the handler reset it. */
5769 alarm (0);
5770 input_poll_signal ();
5771 }
c0a04927
RS
5772 /* Once we have handled input events,
5773 we should have received the MapNotify if one is coming.
5774 So if we have not got it yet, stop looping.
5775 Some window managers make their own decisions
5776 about visibility. */
5777 if (input_signal_count != count)
5778 break;
2a6cf806 5779 }
0dacf791
RS
5780 FRAME_SAMPLE_VISIBILITY (f);
5781 }
dc6f92b8
JB
5782}
5783
5784/* Change from mapped state to withdrawn state. */
5785
d047c4eb
KH
5786/* Make the frame visible (mapped and not iconified). */
5787
f676886a
JB
5788x_make_frame_invisible (f)
5789 struct frame *f;
dc6f92b8
JB
5790{
5791 int mask;
546e6d5b
RS
5792 Window window;
5793
5794#ifdef USE_X_TOOLKIT
5795 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 5796 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
5797#else /* not USE_X_TOOLKIT */
5798 window = FRAME_X_WINDOW (f);
5799#endif /* not USE_X_TOOLKIT */
dc6f92b8 5800
9319ae23 5801 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
5802 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
5803 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 5804
5627c40e 5805#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 5806 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 5807 return;
5627c40e 5808#endif
dc6f92b8
JB
5809
5810 BLOCK_INPUT;
c118dd06 5811
af31d76f
RS
5812 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
5813 that the current position of the window is user-specified, rather than
5814 program-specified, so that when the window is mapped again, it will be
5815 placed at the same location, without forcing the user to position it
5816 by hand again (they have already done that once for this window.) */
c32cdd9a 5817 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 5818
c118dd06
JB
5819#ifdef HAVE_X11R4
5820
334208b7
RS
5821 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
5822 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
5823 {
5824 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5825 error ("Can't notify window manager of window withdrawal");
c118dd06 5826 }
c118dd06 5827#else /* ! defined (HAVE_X11R4) */
16bd92ea 5828
c118dd06 5829 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
5830 if (! EQ (Vx_no_window_manager, Qt))
5831 {
16bd92ea 5832 XEvent unmap;
dc6f92b8 5833
16bd92ea 5834 unmap.xunmap.type = UnmapNotify;
546e6d5b 5835 unmap.xunmap.window = window;
334208b7 5836 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 5837 unmap.xunmap.from_configure = False;
334208b7
RS
5838 if (! XSendEvent (FRAME_X_DISPLAY (f),
5839 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
5840 False,
5841 SubstructureRedirectMask|SubstructureNotifyMask,
5842 &unmap))
5843 {
5844 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5845 error ("Can't notify window manager of withdrawal");
16bd92ea 5846 }
dc6f92b8
JB
5847 }
5848
16bd92ea 5849 /* Unmap the window ourselves. Cheeky! */
334208b7 5850 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 5851#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 5852
5627c40e
RS
5853 /* We can't distinguish this from iconification
5854 just by the event that we get from the server.
5855 So we can't win using the usual strategy of letting
5856 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
5857 and synchronize with the server to make sure we agree. */
5858 f->visible = 0;
5859 FRAME_ICONIFIED_P (f) = 0;
5860 f->async_visible = 0;
5861 f->async_iconified = 0;
5862
334208b7 5863 x_sync (f);
5627c40e 5864
dc6f92b8
JB
5865 UNBLOCK_INPUT;
5866}
5867
dc6f92b8
JB
5868/* Change window state from mapped to iconified. */
5869
f676886a
JB
5870x_iconify_frame (f)
5871 struct frame *f;
dc6f92b8
JB
5872{
5873 int mask;
3afe33e7 5874 int result;
990ba854 5875 Lisp_Object type;
dc6f92b8 5876
9319ae23 5877 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
5878 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
5879 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 5880
3a88c238 5881 if (f->async_iconified)
dc6f92b8
JB
5882 return;
5883
3afe33e7 5884 BLOCK_INPUT;
546e6d5b 5885
9af3143a
RS
5886 FRAME_SAMPLE_VISIBILITY (f);
5887
990ba854
RS
5888 type = x_icon_type (f);
5889 if (!NILP (type))
5890 x_bitmap_icon (f, type);
bdcd49ba
RS
5891
5892#ifdef USE_X_TOOLKIT
5893
546e6d5b
RS
5894 if (! FRAME_VISIBLE_P (f))
5895 {
5896 if (! EQ (Vx_no_window_manager, Qt))
5897 x_wm_set_window_state (f, IconicState);
5898 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 5899 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
5900 /* The server won't give us any event to indicate
5901 that an invisible frame was changed to an icon,
5902 so we have to record it here. */
5903 f->iconified = 1;
1e6bc770 5904 f->visible = 1;
9cf30a30 5905 f->async_iconified = 1;
1e6bc770 5906 f->async_visible = 0;
546e6d5b
RS
5907 UNBLOCK_INPUT;
5908 return;
5909 }
5910
334208b7 5911 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 5912 XtWindow (f->output_data.x->widget),
334208b7 5913 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
5914 UNBLOCK_INPUT;
5915
5916 if (!result)
546e6d5b 5917 error ("Can't notify window manager of iconification");
3afe33e7
RS
5918
5919 f->async_iconified = 1;
1e6bc770
RS
5920 f->async_visible = 0;
5921
8c002a25
KH
5922
5923 BLOCK_INPUT;
334208b7 5924 XFlush (FRAME_X_DISPLAY (f));
8c002a25 5925 UNBLOCK_INPUT;
3afe33e7
RS
5926#else /* not USE_X_TOOLKIT */
5927
fd13dbb2
RS
5928 /* Make sure the X server knows where the window should be positioned,
5929 in case the user deiconifies with the window manager. */
5930 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 5931 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 5932
16bd92ea
JB
5933 /* Since we don't know which revision of X we're running, we'll use both
5934 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
5935
5936 /* X11R4: send a ClientMessage to the window manager using the
5937 WM_CHANGE_STATE type. */
5938 {
5939 XEvent message;
58769bee 5940
c118dd06 5941 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 5942 message.xclient.type = ClientMessage;
334208b7 5943 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
5944 message.xclient.format = 32;
5945 message.xclient.data.l[0] = IconicState;
5946
334208b7
RS
5947 if (! XSendEvent (FRAME_X_DISPLAY (f),
5948 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
5949 False,
5950 SubstructureRedirectMask | SubstructureNotifyMask,
5951 &message))
dc6f92b8
JB
5952 {
5953 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5954 error ("Can't notify window manager of iconification");
dc6f92b8 5955 }
16bd92ea 5956 }
dc6f92b8 5957
58769bee 5958 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
5959 IconicState. */
5960 x_wm_set_window_state (f, IconicState);
dc6f92b8 5961
a9c00105
RS
5962 if (!FRAME_VISIBLE_P (f))
5963 {
5964 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 5965 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
5966 }
5967
3a88c238 5968 f->async_iconified = 1;
1e6bc770 5969 f->async_visible = 0;
dc6f92b8 5970
334208b7 5971 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 5972 UNBLOCK_INPUT;
8c002a25 5973#endif /* not USE_X_TOOLKIT */
dc6f92b8 5974}
d047c4eb 5975\f
c0ff3fab 5976/* Destroy the X window of frame F. */
dc6f92b8 5977
c0ff3fab 5978x_destroy_window (f)
f676886a 5979 struct frame *f;
dc6f92b8 5980{
7f9c7f94
RS
5981 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5982
dc6f92b8 5983 BLOCK_INPUT;
c0ff3fab 5984
6186a4a0
RS
5985 /* If a display connection is dead, don't try sending more
5986 commands to the X server. */
5987 if (dpyinfo->display != 0)
5988 {
5989 if (f->output_data.x->icon_desc != 0)
5990 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
31f41daf
RS
5991#ifdef HAVE_X_I18N
5992 if (FRAME_XIM (f))
5993 {
5994 XDestroyIC (FRAME_XIC (f));
408be661
RS
5995#if ! defined (SOLARIS2) || defined (HAVE_X11R6)
5996 /* This line causes crashes on Solaris with Openwin,
5997 due to an apparent bug in XCloseIM.
5998 X11R6 seems not to have the bug. */
31f41daf 5999 XCloseIM (FRAME_XIM (f));
a9978dd8 6000#endif
31f41daf
RS
6001 }
6002#endif
6186a4a0 6003 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->window_desc);
3afe33e7 6004#ifdef USE_X_TOOLKIT
6186a4a0
RS
6005 XtDestroyWidget (f->output_data.x->widget);
6006 free_frame_menubar (f);
3afe33e7
RS
6007#endif /* USE_X_TOOLKIT */
6008
6186a4a0
RS
6009 free_frame_faces (f);
6010 XFlush (FRAME_X_DISPLAY (f));
6011 }
dc6f92b8 6012
df89d8a4
RS
6013 if (f->output_data.x->saved_menu_event)
6014 free (f->output_data.x->saved_menu_event);
0c49ce2f 6015
7556890b
RS
6016 xfree (f->output_data.x);
6017 f->output_data.x = 0;
0f941935
KH
6018 if (f == dpyinfo->x_focus_frame)
6019 dpyinfo->x_focus_frame = 0;
6020 if (f == dpyinfo->x_focus_event_frame)
6021 dpyinfo->x_focus_event_frame = 0;
6022 if (f == dpyinfo->x_highlight_frame)
6023 dpyinfo->x_highlight_frame = 0;
c0ff3fab 6024
7f9c7f94
RS
6025 dpyinfo->reference_count--;
6026
6027 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 6028 {
7f9c7f94
RS
6029 dpyinfo->mouse_face_beg_row
6030 = dpyinfo->mouse_face_beg_col = -1;
6031 dpyinfo->mouse_face_end_row
6032 = dpyinfo->mouse_face_end_col = -1;
6033 dpyinfo->mouse_face_window = Qnil;
dc05a16b 6034 }
0134a210 6035
c0ff3fab 6036 UNBLOCK_INPUT;
dc6f92b8
JB
6037}
6038\f
f451eb13
JB
6039/* Setting window manager hints. */
6040
af31d76f
RS
6041/* Set the normal size hints for the window manager, for frame F.
6042 FLAGS is the flags word to use--or 0 meaning preserve the flags
6043 that the window now has.
6044 If USER_POSITION is nonzero, we set the USPosition
6045 flag (this is useful when FLAGS is 0). */
6dba1858 6046
af31d76f 6047x_wm_set_size_hint (f, flags, user_position)
f676886a 6048 struct frame *f;
af31d76f
RS
6049 long flags;
6050 int user_position;
dc6f92b8
JB
6051{
6052 XSizeHints size_hints;
3afe33e7
RS
6053
6054#ifdef USE_X_TOOLKIT
7e4f2521
FP
6055 Arg al[2];
6056 int ac = 0;
6057 Dimension widget_width, widget_height;
7556890b 6058 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 6059#else /* not USE_X_TOOLKIT */
c118dd06 6060 Window window = FRAME_X_WINDOW (f);
3afe33e7 6061#endif /* not USE_X_TOOLKIT */
dc6f92b8 6062
b72a58fd
RS
6063 /* Setting PMaxSize caused various problems. */
6064 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 6065
f676886a
JB
6066 flexlines = f->height;
6067
7556890b
RS
6068 size_hints.x = f->output_data.x->left_pos;
6069 size_hints.y = f->output_data.x->top_pos;
7553a6b7 6070
7e4f2521
FP
6071#ifdef USE_X_TOOLKIT
6072 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
6073 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 6074 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
6075 size_hints.height = widget_height;
6076 size_hints.width = widget_width;
6077#else /* not USE_X_TOOLKIT */
f676886a
JB
6078 size_hints.height = PIXEL_HEIGHT (f);
6079 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 6080#endif /* not USE_X_TOOLKIT */
7553a6b7 6081
7556890b
RS
6082 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
6083 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
6084 size_hints.max_width
6085 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
6086 size_hints.max_height
6087 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 6088
d067ea8b
KH
6089 /* Calculate the base and minimum sizes.
6090
6091 (When we use the X toolkit, we don't do it here.
6092 Instead we copy the values that the widgets are using, below.) */
6093#ifndef USE_X_TOOLKIT
b1c884c3 6094 {
b0342f17 6095 int base_width, base_height;
0134a210 6096 int min_rows = 0, min_cols = 0;
b0342f17 6097
f451eb13
JB
6098 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
6099 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 6100
0134a210 6101 check_frame_size (f, &min_rows, &min_cols);
b0342f17 6102
0134a210
RS
6103 /* The window manager uses the base width hints to calculate the
6104 current number of rows and columns in the frame while
6105 resizing; min_width and min_height aren't useful for this
6106 purpose, since they might not give the dimensions for a
6107 zero-row, zero-column frame.
58769bee 6108
0134a210
RS
6109 We use the base_width and base_height members if we have
6110 them; otherwise, we set the min_width and min_height members
6111 to the size for a zero x zero frame. */
b0342f17
JB
6112
6113#ifdef HAVE_X11R4
0134a210
RS
6114 size_hints.flags |= PBaseSize;
6115 size_hints.base_width = base_width;
6116 size_hints.base_height = base_height;
6117 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
6118 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 6119#else
0134a210
RS
6120 size_hints.min_width = base_width;
6121 size_hints.min_height = base_height;
b0342f17 6122#endif
b1c884c3 6123 }
dc6f92b8 6124
d067ea8b 6125 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 6126 if (flags)
dc6f92b8 6127 {
d067ea8b
KH
6128 size_hints.flags |= flags;
6129 goto no_read;
6130 }
6131#endif /* not USE_X_TOOLKIT */
6132
6133 {
6134 XSizeHints hints; /* Sometimes I hate X Windows... */
6135 long supplied_return;
6136 int value;
af31d76f
RS
6137
6138#ifdef HAVE_X11R4
d067ea8b
KH
6139 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
6140 &supplied_return);
af31d76f 6141#else
d067ea8b 6142 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 6143#endif
58769bee 6144
d067ea8b
KH
6145#ifdef USE_X_TOOLKIT
6146 size_hints.base_height = hints.base_height;
6147 size_hints.base_width = hints.base_width;
6148 size_hints.min_height = hints.min_height;
6149 size_hints.min_width = hints.min_width;
6150#endif
6151
6152 if (flags)
6153 size_hints.flags |= flags;
6154 else
6155 {
6156 if (value == 0)
6157 hints.flags = 0;
6158 if (hints.flags & PSize)
6159 size_hints.flags |= PSize;
6160 if (hints.flags & PPosition)
6161 size_hints.flags |= PPosition;
6162 if (hints.flags & USPosition)
6163 size_hints.flags |= USPosition;
6164 if (hints.flags & USSize)
6165 size_hints.flags |= USSize;
6166 }
6167 }
6168
6169 no_read:
0134a210 6170
af31d76f 6171#ifdef PWinGravity
7556890b 6172 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 6173 size_hints.flags |= PWinGravity;
dc05a16b 6174
af31d76f 6175 if (user_position)
6dba1858 6176 {
af31d76f
RS
6177 size_hints.flags &= ~ PPosition;
6178 size_hints.flags |= USPosition;
6dba1858 6179 }
2554751d 6180#endif /* PWinGravity */
6dba1858 6181
b0342f17 6182#ifdef HAVE_X11R4
334208b7 6183 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 6184#else
334208b7 6185 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 6186#endif
dc6f92b8
JB
6187}
6188
6189/* Used for IconicState or NormalState */
f676886a
JB
6190x_wm_set_window_state (f, state)
6191 struct frame *f;
dc6f92b8
JB
6192 int state;
6193{
3afe33e7 6194#ifdef USE_X_TOOLKIT
546e6d5b
RS
6195 Arg al[1];
6196
6197 XtSetArg (al[0], XtNinitialState, state);
7556890b 6198 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 6199#else /* not USE_X_TOOLKIT */
c118dd06 6200 Window window = FRAME_X_WINDOW (f);
dc6f92b8 6201
7556890b
RS
6202 f->output_data.x->wm_hints.flags |= StateHint;
6203 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 6204
7556890b 6205 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 6206#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
6207}
6208
7f2ae036 6209x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 6210 struct frame *f;
7f2ae036 6211 int pixmap_id;
dc6f92b8 6212{
d2bd6bc4
RS
6213 Pixmap icon_pixmap;
6214
75231bad 6215#ifdef USE_X_TOOLKIT
7556890b 6216 Window window = XtWindow (f->output_data.x->widget);
75231bad 6217#else
c118dd06 6218 Window window = FRAME_X_WINDOW (f);
75231bad 6219#endif
dc6f92b8 6220
7f2ae036 6221 if (pixmap_id > 0)
dbc4e1c1 6222 {
d2bd6bc4 6223 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 6224 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
6225 }
6226 else
68568555
RS
6227 {
6228 /* It seems there is no way to turn off use of an icon pixmap.
6229 The following line does it, only if no icon has yet been created,
6230 for some window managers. But with mwm it crashes.
6231 Some people say it should clear the IconPixmapHint bit in this case,
6232 but that doesn't work, and the X consortium said it isn't the
6233 right thing at all. Since there is no way to win,
6234 best to explicitly give up. */
6235#if 0
6236 f->output_data.x->wm_hints.icon_pixmap = None;
6237#else
6238 return;
6239#endif
6240 }
b1c884c3 6241
d2bd6bc4
RS
6242#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
6243
6244 {
6245 Arg al[1];
6246 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
6247 XtSetValues (f->output_data.x->widget, al, 1);
6248 }
6249
6250#else /* not USE_X_TOOLKIT */
6251
7556890b
RS
6252 f->output_data.x->wm_hints.flags |= IconPixmapHint;
6253 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
6254
6255#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
6256}
6257
f676886a
JB
6258x_wm_set_icon_position (f, icon_x, icon_y)
6259 struct frame *f;
dc6f92b8
JB
6260 int icon_x, icon_y;
6261{
75231bad 6262#ifdef USE_X_TOOLKIT
7556890b 6263 Window window = XtWindow (f->output_data.x->widget);
75231bad 6264#else
c118dd06 6265 Window window = FRAME_X_WINDOW (f);
75231bad 6266#endif
dc6f92b8 6267
7556890b
RS
6268 f->output_data.x->wm_hints.flags |= IconPositionHint;
6269 f->output_data.x->wm_hints.icon_x = icon_x;
6270 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 6271
7556890b 6272 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
6273}
6274
6275\f
dc43ef94
KH
6276/* Interface to fontset handler. */
6277
6278/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6279struct font_info *
6280x_get_font_info (f, font_idx)
6281 FRAME_PTR f;
6282 int font_idx;
6283{
6284 return (FRAME_X_FONT_TABLE (f) + font_idx);
6285}
6286
6287
6288/* Return a list of names of available fonts matching PATTERN on frame
6289 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6290 to be listed. Frame F NULL means we have not yet created any
6291 frame on X, and consult the first display in x_display_list.
6292 MAXNAMES sets a limit on how many fonts to match. */
6293
6294Lisp_Object
6295x_list_fonts (f, pattern, size, maxnames)
6296 FRAME_PTR f;
6297 Lisp_Object pattern;
6298 int size;
6299 int maxnames;
6300{
1348f1a4 6301 Lisp_Object list = Qnil, patterns, newlist = Qnil, key, tem, second_best;
dc43ef94
KH
6302 Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
6303
2da424f1
KH
6304 patterns = Fassoc (pattern, Valternative_fontname_alist);
6305 if (NILP (patterns))
6306 patterns = Fcons (pattern, Qnil);
81ba44e5 6307
2da424f1 6308 for (; CONSP (patterns); patterns = XCONS (patterns)->cdr)
dc43ef94 6309 {
dc43ef94
KH
6310 int num_fonts;
6311 char **names;
6312
2da424f1 6313 pattern = XCONS (patterns)->car;
b5210ea7
KH
6314 /* See if we cached the result for this particular query. */
6315 if (f && (tem = XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr,
6316 key = Fcons (pattern, make_number (maxnames)),
6317 !NILP (list = Fassoc (key, tem))))
6318 {
6319 list = Fcdr_safe (list);
6320 /* We have a cashed list. Don't have to get the list again. */
6321 goto label_cached;
6322 }
6323
6324 /* At first, put PATTERN in the cache. */
dc43ef94
KH
6325 BLOCK_INPUT;
6326 names = XListFonts (dpy, XSTRING (pattern)->data, maxnames, &num_fonts);
6327 UNBLOCK_INPUT;
6328
6329 if (names)
6330 {
6331 int i;
dc43ef94
KH
6332
6333 /* Make a list of all the fonts we got back.
6334 Store that in the font cache for the display. */
6335 for (i = 0; i < num_fonts; i++)
6336 {
6337 char *p = names[i];
6338 int average_width = -1, dashes = 0, width = 0;
6339
6340 /* Count the number of dashes in NAMES[I]. If there are
b5210ea7
KH
6341 14 dashes, and the field value following 12th dash
6342 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
6343 is usually too ugly to be used for editing. Let's
6344 ignore it. */
dc43ef94
KH
6345 while (*p)
6346 if (*p++ == '-')
6347 {
6348 dashes++;
6349 if (dashes == 7) /* PIXEL_SIZE field */
6350 width = atoi (p);
6351 else if (dashes == 12) /* AVERAGE_WIDTH field */
6352 average_width = atoi (p);
6353 }
6354 if (dashes < 14 || average_width != 0)
6355 {
6356 tem = build_string (names[i]);
6357 if (NILP (Fassoc (tem, list)))
6358 {
6359 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
6360 && ((fast_c_string_match_ignore_case
6361 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
6362 >= 0))
6363 /* We can set the value of PIXEL_SIZE to the
b5210ea7 6364 width of this font. */
dc43ef94
KH
6365 list = Fcons (Fcons (tem, make_number (width)), list);
6366 else
6367 /* For the moment, width is not known. */
6368 list = Fcons (Fcons (tem, Qnil), list);
6369 }
6370 }
6371 }
6372 XFreeFontNames (names);
6373 }
6374
b5210ea7 6375 /* Now store the result in the cache. */
dc43ef94
KH
6376 if (f != NULL)
6377 XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr
6378 = Fcons (Fcons (key, list),
6379 XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr);
dc43ef94 6380
b5210ea7
KH
6381 label_cached:
6382 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 6383
b5210ea7
KH
6384 newlist = second_best = Qnil;
6385 /* Make a list of the fonts that have the right width. */
6386 for (; CONSP (list); list = XCONS (list)->cdr)
6387 {
6388 tem = XCONS (list)->car;
dc43ef94 6389
b5210ea7
KH
6390 if (!CONSP (tem) || NILP (XCONS (tem)->car))
6391 continue;
6392 if (!size)
6393 {
6394 newlist = Fcons (XCONS (tem)->car, newlist);
6395 continue;
6396 }
dc43ef94 6397
dc43ef94
KH
6398 if (!INTEGERP (XCONS (tem)->cdr))
6399 {
b5210ea7
KH
6400 /* Since we have not yet known the size of this font, we
6401 must try slow function call XLoadQueryFont. */
dc43ef94
KH
6402 XFontStruct *thisinfo;
6403
6404 BLOCK_INPUT;
6405 thisinfo = XLoadQueryFont (dpy,
6406 XSTRING (XCONS (tem)->car)->data);
6407 UNBLOCK_INPUT;
6408
6409 if (thisinfo)
6410 {
6411 XCONS (tem)->cdr = make_number (thisinfo->max_bounds.width);
6412 XFreeFont (dpy, thisinfo);
6413 }
6414 else
b5210ea7
KH
6415 /* For unknown reason, the previous call of XListFont had
6416 retruned a font which can't be opened. Record the size
6417 as 0 not to try to open it again. */
dc43ef94
KH
6418 XCONS (tem)->cdr = make_number (0);
6419 }
b5210ea7
KH
6420 if (XINT (XCONS (tem)->cdr) == size)
6421 newlist = Fcons (XCONS (tem)->car, newlist);
6422 else if (NILP (second_best))
6423 second_best = tem;
6424 else if (XINT (XCONS (tem)->cdr) < size)
6425 {
6426 if (XINT (XCONS (second_best)->cdr) > size
6427 || XINT (XCONS (second_best)->cdr) < XINT (XCONS (tem)->cdr))
6428 second_best = tem;
6429 }
6430 else
6431 {
6432 if (XINT (XCONS (second_best)->cdr) > size
6433 && XINT (XCONS (second_best)->cdr) > XINT (XCONS (tem)->cdr))
6434 second_best = tem;
6435 }
6436 }
6437 if (!NILP (newlist))
6438 break;
6439 else if (!NILP (second_best))
6440 {
6441 newlist = Fcons (XCONS (second_best)->car, Qnil);
6442 break;
dc43ef94 6443 }
dc43ef94
KH
6444 }
6445
6446 return newlist;
6447}
6448
6449/* Load font named FONTNAME of the size SIZE for frame F, and return a
6450 pointer to the structure font_info while allocating it dynamically.
6451 If SIZE is 0, load any size of font.
6452 If loading is failed, return NULL. */
6453
6454struct font_info *
6455x_load_font (f, fontname, size)
6456 struct frame *f;
6457 register char *fontname;
6458 int size;
6459{
6460 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6461 Lisp_Object font_names;
6462
6463 /* Get a list of all the fonts that match this name. Once we
6464 have a list of matching fonts, we compare them against the fonts
6465 we already have by comparing names. */
6466 font_names = x_list_fonts (f, build_string (fontname), size, 256);
6467
6468 if (!NILP (font_names))
6469 {
6470 Lisp_Object tail;
6471 int i;
6472
6473 for (i = 0; i < dpyinfo->n_fonts; i++)
6474 for (tail = font_names; CONSP (tail); tail = XCONS (tail)->cdr)
6475 if (!strcmp (dpyinfo->font_table[i].name,
6476 XSTRING (XCONS (tail)->car)->data)
6477 || !strcmp (dpyinfo->font_table[i].full_name,
6478 XSTRING (XCONS (tail)->car)->data))
6479 return (dpyinfo->font_table + i);
6480 }
6481
6482 /* Load the font and add it to the table. */
6483 {
6484 char *full_name;
6485 XFontStruct *font;
6486 struct font_info *fontp;
6487 unsigned long value;
6488
2da424f1
KH
6489 /* If we have found fonts by x_list_font, load one of them. If
6490 not, we still try to load a font by the name given as FONTNAME
6491 because XListFonts (called in x_list_font) of some X server has
6492 a bug of not finding a font even if the font surely exists and
6493 is loadable by XLoadQueryFont. */
dc43ef94 6494 if (!NILP (font_names))
f613a4c8 6495 fontname = (char *) XSTRING (XCONS (font_names)->car)->data;
dc43ef94
KH
6496
6497 BLOCK_INPUT;
6498 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
6499 UNBLOCK_INPUT;
b5210ea7 6500 if (!font)
dc43ef94
KH
6501 return NULL;
6502
6503 /* Do we need to create the table? */
6504 if (dpyinfo->font_table_size == 0)
6505 {
6506 dpyinfo->font_table_size = 16;
6507 dpyinfo->font_table
6508 = (struct font_info *) xmalloc (dpyinfo->font_table_size
6509 * sizeof (struct font_info));
6510 }
6511 /* Do we need to grow the table? */
6512 else if (dpyinfo->n_fonts
6513 >= dpyinfo->font_table_size)
6514 {
6515 dpyinfo->font_table_size *= 2;
6516 dpyinfo->font_table
6517 = (struct font_info *) xrealloc (dpyinfo->font_table,
6518 (dpyinfo->font_table_size
6519 * sizeof (struct font_info)));
6520 }
6521
6522 fontp = dpyinfo->font_table + dpyinfo->n_fonts;
6523
6524 /* Now fill in the slots of *FONTP. */
6525 BLOCK_INPUT;
6526 fontp->font = font;
6527 fontp->font_idx = dpyinfo->n_fonts;
6528 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
6529 bcopy (fontname, fontp->name, strlen (fontname) + 1);
6530
6531 /* Try to get the full name of FONT. Put it in FULL_NAME. */
6532 full_name = 0;
6533 if (XGetFontProperty (font, XA_FONT, &value))
6534 {
6535 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
6536 char *p = name;
6537 int dashes = 0;
6538
6539 /* Count the number of dashes in the "full name".
6540 If it is too few, this isn't really the font's full name,
6541 so don't use it.
6542 In X11R4, the fonts did not come with their canonical names
6543 stored in them. */
6544 while (*p)
6545 {
6546 if (*p == '-')
6547 dashes++;
6548 p++;
6549 }
6550
6551 if (dashes >= 13)
6552 {
6553 full_name = (char *) xmalloc (p - name + 1);
6554 bcopy (name, full_name, p - name + 1);
6555 }
6556
6557 XFree (name);
6558 }
6559
6560 if (full_name != 0)
6561 fontp->full_name = full_name;
6562 else
6563 fontp->full_name = fontp->name;
6564
6565 fontp->size = font->max_bounds.width;
fe27f88d 6566 fontp->height = font->max_bounds.ascent + font->max_bounds.descent;
dc43ef94 6567
2da424f1
KH
6568 if (NILP (font_names))
6569 {
6570 /* We come here because of a bug of XListFonts mentioned at
6571 the head of this block. Let's store this information in
6572 the cache for x_list_fonts. */
6573 Lisp_Object lispy_name = build_string (fontname);
6574 Lisp_Object lispy_full_name = build_string (fontp->full_name);
6575
6576 XCONS (dpyinfo->name_list_element)->cdr
6577 = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
6578 Fcons (Fcons (lispy_full_name,
6579 make_number (fontp->size)),
6580 Qnil)),
6581 XCONS (dpyinfo->name_list_element)->cdr);
6582 if (full_name)
6583 XCONS (dpyinfo->name_list_element)->cdr
6584 = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
6585 Fcons (Fcons (lispy_full_name,
6586 make_number (fontp->size)),
6587 Qnil)),
6588 XCONS (dpyinfo->name_list_element)->cdr);
6589 }
6590
dc43ef94
KH
6591 /* The slot `encoding' specifies how to map a character
6592 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ce667c3e 6593 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
8ff102bd
RS
6594 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
6595 0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
6596 2:0xA020..0xFF7F). For the moment, we don't know which charset
6597 uses this font. So, we set informatoin in fontp->encoding[1]
6598 which is never used by any charset. If mapping can't be
6599 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
6600 fontp->encoding[1]
6601 = (font->max_byte1 == 0
6602 /* 1-byte font */
6603 ? (font->min_char_or_byte2 < 0x80
6604 ? (font->max_char_or_byte2 < 0x80
6605 ? 0 /* 0x20..0x7F */
8ff102bd 6606 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
6607 : 1) /* 0xA0..0xFF */
6608 /* 2-byte font */
6609 : (font->min_byte1 < 0x80
6610 ? (font->max_byte1 < 0x80
6611 ? (font->min_char_or_byte2 < 0x80
6612 ? (font->max_char_or_byte2 < 0x80
6613 ? 0 /* 0x2020..0x7F7F */
8ff102bd 6614 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 6615 : 3) /* 0x20A0..0x7FFF */
8ff102bd 6616 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
6617 : (font->min_char_or_byte2 < 0x80
6618 ? (font->max_char_or_byte2 < 0x80
6619 ? 2 /* 0xA020..0xFF7F */
8ff102bd 6620 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
6621 : 1))); /* 0xA0A0..0xFFFF */
6622
6623 fontp->baseline_offset
6624 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
6625 ? (long) value : 0);
6626 fontp->relative_compose
6627 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
6628 ? (long) value : 0);
f78798df
KH
6629 fontp->default_ascent
6630 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
6631 ? (long) value : 0);
dc43ef94
KH
6632
6633 UNBLOCK_INPUT;
6634 dpyinfo->n_fonts++;
6635
6636 return fontp;
6637 }
6638}
6639
6640/* Return a pointer to struct font_info of a font named FONTNAME for frame F.
6641 If no such font is loaded, return NULL. */
6642struct font_info *
6643x_query_font (f, fontname)
6644 struct frame *f;
6645 register char *fontname;
6646{
6647 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6648 int i;
6649
6650 for (i = 0; i < dpyinfo->n_fonts; i++)
6651 if (!strcmp (dpyinfo->font_table[i].name, fontname)
6652 || !strcmp (dpyinfo->font_table[i].full_name, fontname))
6653 return (dpyinfo->font_table + i);
6654 return NULL;
6655}
6656
6657\f
f451eb13
JB
6658/* Initialization. */
6659
3afe33e7
RS
6660#ifdef USE_X_TOOLKIT
6661static XrmOptionDescRec emacs_options[] = {
6662 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
6663 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
6664
6665 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
6666 XrmoptionSepArg, NULL},
6667 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
6668
6669 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
6670 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
6671 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
6672 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
6673 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
6674 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
6675 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
6676};
6677#endif /* USE_X_TOOLKIT */
6678
7a13e894
RS
6679static int x_initialized;
6680
29b38361
KH
6681#ifdef MULTI_KBOARD
6682/* Test whether two display-name strings agree up to the dot that separates
6683 the screen number from the server number. */
6684static int
6685same_x_server (name1, name2)
6686 char *name1, *name2;
6687{
6688 int seen_colon = 0;
6689 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
6690 {
6691 if (*name1 == ':')
6692 seen_colon++;
6693 if (seen_colon && *name1 == '.')
6694 return 1;
6695 }
6696 return (seen_colon
6697 && (*name1 == '.' || *name1 == '\0')
6698 && (*name2 == '.' || *name2 == '\0'));
6699}
6700#endif
6701
334208b7 6702struct x_display_info *
1f8255f2 6703x_term_init (display_name, xrm_option, resource_name)
334208b7 6704 Lisp_Object display_name;
1f8255f2
RS
6705 char *xrm_option;
6706 char *resource_name;
dc6f92b8 6707{
f676886a 6708 Lisp_Object frame;
dc6f92b8 6709 char *defaultvalue;
334208b7 6710 int connection;
7a13e894 6711 Display *dpy;
334208b7
RS
6712 struct x_display_info *dpyinfo;
6713 XrmDatabase xrdb;
6714
60439948
KH
6715 BLOCK_INPUT;
6716
7a13e894
RS
6717 if (!x_initialized)
6718 {
6719 x_initialize ();
6720 x_initialized = 1;
6721 }
dc6f92b8 6722
6c183ba5 6723#ifdef HAVE_X_I18N
6186a4a0 6724 setlocale (LC_ALL, "");
333bc6d0
RS
6725 /* In case we just overrode what init_lread did, redo it. */
6726 setlocale (LC_NUMERIC, "C");
10537cb1 6727 setlocale (LC_TIME, "C");
6c183ba5
RS
6728#endif
6729
3afe33e7 6730#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
6731 /* weiner@footloose.sps.mot.com reports that this causes
6732 errors with X11R5:
6733 X protocol error: BadAtom (invalid Atom parameter)
6734 on protocol request 18skiloaf.
6735 So let's not use it until R6. */
6736#ifdef HAVE_X11XTR6
bdcd49ba
RS
6737 XtSetLanguageProc (NULL, NULL, NULL);
6738#endif
6739
7f9c7f94
RS
6740 {
6741 int argc = 0;
6742 char *argv[3];
6743
6744 argv[0] = "";
6745 argc = 1;
6746 if (xrm_option)
6747 {
6748 argv[argc++] = "-xrm";
6749 argv[argc++] = xrm_option;
6750 }
6751 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
6752 resource_name, EMACS_CLASS,
6753 emacs_options, XtNumber (emacs_options),
6754 &argc, argv);
39d8bb4d
KH
6755
6756#ifdef HAVE_X11XTR6
10537cb1 6757 /* I think this is to compensate for XtSetLanguageProc. */
39d8bb4d
KH
6758 setlocale (LC_NUMERIC, "C");
6759 setlocale (LC_TIME, "C");
6760#endif
7f9c7f94 6761 }
3afe33e7
RS
6762
6763#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
6764#ifdef HAVE_X11R5
6765 XSetLocaleModifiers ("");
6766#endif
7a13e894 6767 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 6768#endif /* not USE_X_TOOLKIT */
334208b7 6769
7a13e894
RS
6770 /* Detect failure. */
6771 if (dpy == 0)
60439948
KH
6772 {
6773 UNBLOCK_INPUT;
6774 return 0;
6775 }
7a13e894
RS
6776
6777 /* We have definitely succeeded. Record the new connection. */
6778
6779 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
6780
29b38361
KH
6781#ifdef MULTI_KBOARD
6782 {
6783 struct x_display_info *share;
6784 Lisp_Object tail;
6785
6786 for (share = x_display_list, tail = x_display_name_list; share;
6787 share = share->next, tail = XCONS (tail)->cdr)
6788 if (same_x_server (XSTRING (XCONS (XCONS (tail)->car)->car)->data,
6789 XSTRING (display_name)->data))
6790 break;
6791 if (share)
6792 dpyinfo->kboard = share->kboard;
6793 else
6794 {
6795 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
6796 init_kboard (dpyinfo->kboard);
59e755be
KH
6797 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
6798 {
6799 char *vendor = ServerVendor (dpy);
6800 dpyinfo->kboard->Vsystem_key_alist
6801 = call1 (Qvendor_specific_keysyms,
6802 build_string (vendor ? vendor : ""));
6803 }
6804
29b38361
KH
6805 dpyinfo->kboard->next_kboard = all_kboards;
6806 all_kboards = dpyinfo->kboard;
0ad5446c
KH
6807 /* Don't let the initial kboard remain current longer than necessary.
6808 That would cause problems if a file loaded on startup tries to
6809 prompt in the minibuffer. */
6810 if (current_kboard == initial_kboard)
6811 current_kboard = dpyinfo->kboard;
29b38361
KH
6812 }
6813 dpyinfo->kboard->reference_count++;
6814 }
b9737ad3
KH
6815#endif
6816
7a13e894
RS
6817 /* Put this display on the chain. */
6818 dpyinfo->next = x_display_list;
6819 x_display_list = dpyinfo;
6820
6821 /* Put it on x_display_name_list as well, to keep them parallel. */
6822 x_display_name_list = Fcons (Fcons (display_name, Qnil),
6823 x_display_name_list);
6824 dpyinfo->name_list_element = XCONS (x_display_name_list)->car;
6825
6826 dpyinfo->display = dpy;
dc6f92b8 6827
dc6f92b8 6828#if 0
7a13e894 6829 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 6830#endif /* ! 0 */
7a13e894
RS
6831
6832 dpyinfo->x_id_name
6833 = (char *) xmalloc (XSTRING (Vinvocation_name)->size
6834 + XSTRING (Vsystem_name)->size
6835 + 2);
6836 sprintf (dpyinfo->x_id_name, "%s@%s",
6837 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
6838
6839 /* Figure out which modifier bits mean what. */
334208b7 6840 x_find_modifier_meanings (dpyinfo);
f451eb13 6841
ab648270 6842 /* Get the scroll bar cursor. */
7a13e894 6843 dpyinfo->vertical_scroll_bar_cursor
334208b7 6844 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 6845
334208b7
RS
6846 xrdb = x_load_resources (dpyinfo->display, xrm_option,
6847 resource_name, EMACS_CLASS);
6848#ifdef HAVE_XRMSETDATABASE
6849 XrmSetDatabase (dpyinfo->display, xrdb);
6850#else
6851 dpyinfo->display->db = xrdb;
6852#endif
547d9db8 6853 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
6854 all versions. */
6855 dpyinfo->xrdb = xrdb;
334208b7
RS
6856
6857 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
6858 DefaultScreen (dpyinfo->display));
6859 dpyinfo->visual = select_visual (dpyinfo->display, dpyinfo->screen,
6860 &dpyinfo->n_planes);
6861 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
6862 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
6863 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
6864 dpyinfo->grabbed = 0;
6865 dpyinfo->reference_count = 0;
6866 dpyinfo->icon_bitmap_id = -1;
7a13e894
RS
6867 dpyinfo->n_fonts = 0;
6868 dpyinfo->font_table_size = 0;
6869 dpyinfo->bitmaps = 0;
6870 dpyinfo->bitmaps_size = 0;
6871 dpyinfo->bitmaps_last = 0;
6872 dpyinfo->scratch_cursor_gc = 0;
6873 dpyinfo->mouse_face_mouse_frame = 0;
6874 dpyinfo->mouse_face_deferred_gc = 0;
6875 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
6876 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
6877 dpyinfo->mouse_face_face_id = 0;
6878 dpyinfo->mouse_face_window = Qnil;
6879 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
6880 dpyinfo->mouse_face_defer = 0;
0f941935
KH
6881 dpyinfo->x_focus_frame = 0;
6882 dpyinfo->x_focus_event_frame = 0;
6883 dpyinfo->x_highlight_frame = 0;
334208b7
RS
6884
6885 dpyinfo->Xatom_wm_protocols
6886 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
6887 dpyinfo->Xatom_wm_take_focus
6888 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
6889 dpyinfo->Xatom_wm_save_yourself
6890 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
6891 dpyinfo->Xatom_wm_delete_window
6892 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
6893 dpyinfo->Xatom_wm_change_state
6894 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
6895 dpyinfo->Xatom_wm_configure_denied
6896 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
6897 dpyinfo->Xatom_wm_window_moved
6898 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
6899 dpyinfo->Xatom_editres
6900 = XInternAtom (dpyinfo->display, "Editres", False);
6901 dpyinfo->Xatom_CLIPBOARD
6902 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
6903 dpyinfo->Xatom_TIMESTAMP
6904 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
6905 dpyinfo->Xatom_TEXT
6906 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
6907 dpyinfo->Xatom_COMPOUND_TEXT
6908 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
6909 dpyinfo->Xatom_DELETE
6910 = XInternAtom (dpyinfo->display, "DELETE", False);
6911 dpyinfo->Xatom_MULTIPLE
6912 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
6913 dpyinfo->Xatom_INCR
6914 = XInternAtom (dpyinfo->display, "INCR", False);
6915 dpyinfo->Xatom_EMACS_TMP
6916 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
6917 dpyinfo->Xatom_TARGETS
6918 = XInternAtom (dpyinfo->display, "TARGETS", False);
6919 dpyinfo->Xatom_NULL
6920 = XInternAtom (dpyinfo->display, "NULL", False);
6921 dpyinfo->Xatom_ATOM_PAIR
6922 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
6923 /* For properties of font. */
6924 dpyinfo->Xatom_PIXEL_SIZE
6925 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
6926 dpyinfo->Xatom_MULE_BASELINE_OFFSET
6927 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
6928 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
6929 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
6930 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
6931 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 6932
547d9db8
KH
6933 dpyinfo->cut_buffers_initialized = 0;
6934
334208b7
RS
6935 connection = ConnectionNumber (dpyinfo->display);
6936 dpyinfo->connection = connection;
6937
dc43ef94 6938 {
5d7cc324
RS
6939 char null_bits[1];
6940
6941 null_bits[0] = 0x00;
dc43ef94
KH
6942
6943 dpyinfo->null_pixel
6944 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
6945 null_bits, 1, 1, (long) 0, (long) 0,
6946 1);
6947 }
6948
87485d6f
MW
6949#ifdef subprocesses
6950 /* This is only needed for distinguishing keyboard and process input. */
334208b7 6951 if (connection != 0)
7a13e894 6952 add_keyboard_wait_descriptor (connection);
87485d6f 6953#endif
6d4238f3 6954
041b69ac 6955#ifndef F_SETOWN_BUG
dc6f92b8 6956#ifdef F_SETOWN
dc6f92b8 6957#ifdef F_SETOWN_SOCK_NEG
61c3ce62 6958 /* stdin is a socket here */
334208b7 6959 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 6960#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 6961 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
6962#endif /* ! defined (F_SETOWN_SOCK_NEG) */
6963#endif /* ! defined (F_SETOWN) */
041b69ac 6964#endif /* F_SETOWN_BUG */
dc6f92b8
JB
6965
6966#ifdef SIGIO
eee20f6a
KH
6967 if (interrupt_input)
6968 init_sigio (connection);
c118dd06 6969#endif /* ! defined (SIGIO) */
dc6f92b8 6970
51b592fb
RS
6971#ifdef USE_LUCID
6972 /* Make sure that we have a valid font for dialog boxes
6973 so that Xt does not crash. */
6974 {
6975 Display *dpy = dpyinfo->display;
6976 XrmValue d, fr, to;
6977 Font font;
e99db5a1 6978 int count;
51b592fb
RS
6979
6980 d.addr = (XPointer)&dpy;
6981 d.size = sizeof (Display *);
6982 fr.addr = XtDefaultFont;
6983 fr.size = sizeof (XtDefaultFont);
6984 to.size = sizeof (Font *);
6985 to.addr = (XPointer)&font;
e99db5a1 6986 count = x_catch_errors (dpy);
51b592fb
RS
6987 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
6988 abort ();
6989 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
6990 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 6991 x_uncatch_errors (dpy, count);
51b592fb
RS
6992 }
6993#endif
6994
6995
60439948
KH
6996 UNBLOCK_INPUT;
6997
7a13e894
RS
6998 return dpyinfo;
6999}
7000\f
7001/* Get rid of display DPYINFO, assuming all frames are already gone,
7002 and without sending any more commands to the X server. */
dc6f92b8 7003
7a13e894
RS
7004void
7005x_delete_display (dpyinfo)
7006 struct x_display_info *dpyinfo;
7007{
7008 delete_keyboard_wait_descriptor (dpyinfo->connection);
7009
7010 /* Discard this display from x_display_name_list and x_display_list.
7011 We can't use Fdelq because that can quit. */
7012 if (! NILP (x_display_name_list)
7013 && EQ (XCONS (x_display_name_list)->car, dpyinfo->name_list_element))
7014 x_display_name_list = XCONS (x_display_name_list)->cdr;
7015 else
7016 {
7017 Lisp_Object tail;
7018
7019 tail = x_display_name_list;
7020 while (CONSP (tail) && CONSP (XCONS (tail)->cdr))
7021 {
7022 if (EQ (XCONS (XCONS (tail)->cdr)->car,
7023 dpyinfo->name_list_element))
7024 {
7025 XCONS (tail)->cdr = XCONS (XCONS (tail)->cdr)->cdr;
7026 break;
7027 }
7028 tail = XCONS (tail)->cdr;
7029 }
7030 }
7031
7032 if (x_display_list == dpyinfo)
7033 x_display_list = dpyinfo->next;
7f9c7f94
RS
7034 else
7035 {
7036 struct x_display_info *tail;
7a13e894 7037
7f9c7f94
RS
7038 for (tail = x_display_list; tail; tail = tail->next)
7039 if (tail->next == dpyinfo)
7040 tail->next = tail->next->next;
7041 }
7a13e894 7042
0d777288
RS
7043#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
7044#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
7045 XrmDestroyDatabase (dpyinfo->xrdb);
7046#endif
0d777288 7047#endif
29b38361
KH
7048#ifdef MULTI_KBOARD
7049 if (--dpyinfo->kboard->reference_count == 0)
39f79001 7050 delete_kboard (dpyinfo->kboard);
b9737ad3
KH
7051#endif
7052 xfree (dpyinfo->font_table);
7053 xfree (dpyinfo->x_id_name);
7054 xfree (dpyinfo);
7a13e894
RS
7055}
7056\f
7057/* Set up use of X before we make the first connection. */
7058
7059x_initialize ()
7060{
f676886a 7061 clear_frame_hook = XTclear_frame;
dc6f92b8
JB
7062 clear_end_of_line_hook = XTclear_end_of_line;
7063 ins_del_lines_hook = XTins_del_lines;
7064 change_line_highlight_hook = XTchange_line_highlight;
7065 insert_glyphs_hook = XTinsert_glyphs;
7066 write_glyphs_hook = XTwrite_glyphs;
7067 delete_glyphs_hook = XTdelete_glyphs;
7068 ring_bell_hook = XTring_bell;
7069 reset_terminal_modes_hook = XTreset_terminal_modes;
7070 set_terminal_modes_hook = XTset_terminal_modes;
7071 update_begin_hook = XTupdate_begin;
7072 update_end_hook = XTupdate_end;
7073 set_terminal_window_hook = XTset_terminal_window;
7074 read_socket_hook = XTread_socket;
b8009dd1 7075 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8
JB
7076 cursor_to_hook = XTcursor_to;
7077 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 7078 mouse_position_hook = XTmouse_position;
f451eb13 7079 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 7080 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
7081 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
7082 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
7083 redeem_scroll_bar_hook = XTredeem_scroll_bar;
7084 judge_scroll_bars_hook = XTjudge_scroll_bars;
58769bee 7085
f676886a 7086 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
7087 char_ins_del_ok = 0; /* just as fast to write the line */
7088 line_ins_del_ok = 1; /* we'll just blt 'em */
7089 fast_clear_end_of_line = 1; /* X does this well */
58769bee 7090 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
7091 off the bottom */
7092 baud_rate = 19200;
7093
7a13e894
RS
7094 x_noop_count = 0;
7095
b30b24cb
RS
7096 /* Try to use interrupt input; if we can't, then start polling. */
7097 Fset_input_mode (Qt, Qnil, Qt, Qnil);
7098
7f9c7f94
RS
7099#ifdef USE_X_TOOLKIT
7100 XtToolkitInitialize ();
7101 Xt_app_con = XtCreateApplicationContext ();
665881ad 7102 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
7f9c7f94
RS
7103#endif
7104
58769bee 7105 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 7106 original error handler. */
e99db5a1 7107 XSetErrorHandler (x_error_handler);
334208b7 7108 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8
JB
7109
7110 /* Disable Window Change signals; they are handled by X events. */
7111#ifdef SIGWINCH
7112 signal (SIGWINCH, SIG_DFL);
c118dd06 7113#endif /* ! defined (SIGWINCH) */
dc6f92b8 7114
92e2441b 7115 signal (SIGPIPE, x_connection_signal);
dc6f92b8 7116}
55123275
JB
7117
7118void
7119syms_of_xterm ()
7120{
e99db5a1
RS
7121 staticpro (&x_error_message_string);
7122 x_error_message_string = Qnil;
7123
7a13e894
RS
7124 staticpro (&x_display_name_list);
7125 x_display_name_list = Qnil;
334208b7 7126
ab648270 7127 staticpro (&last_mouse_scroll_bar);
e53cb100 7128 last_mouse_scroll_bar = Qnil;
59e755be
KH
7129
7130 staticpro (&Qvendor_specific_keysyms);
7131 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
7132
7133 staticpro (&last_mouse_press_frame);
7134 last_mouse_press_frame = Qnil;
55123275 7135}
6cf0ae86
RS
7136
7137#endif /* not HAVE_X_WINDOWS */