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