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