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