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