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