(update_menu_bar): Pass 0 to set_frame_menubar.
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
b8009dd1 2 Copyright (C) 1989, 1993, 1994 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
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20/* Serious problems:
21
22 Kludge: dup2 is used to put the X-connection socket into desc # 0
23 so that wait_reading_process_input will wait for it in place of
24 actual terminal input.
25
26*/
27
3afe33e7
RS
28/* Xt features made by Fred Pierresteguy. */
29
d56a553a
RS
30#define NEW_SELECTIONS
31
039440c4
RS
32/* On 4.3 these lose if they come after xterm.h. */
33/* On HP-UX 8.0 signal.h loses if it comes after config.h. */
34/* Putting these at the beginning seems to be standard for other .c files. */
35#include <stdio.h>
36#include <signal.h>
37
18160b98 38#include <config.h>
dc6f92b8 39
3afe33e7 40/* Need syssignal.h for various externs and definitions that may be required
bc20ebbf 41 by some configurations for calls to signal later in this source file. */
3afe33e7
RS
42#include "syssignal.h"
43
dc6f92b8
JB
44#ifdef HAVE_X_WINDOWS
45
46#include "lisp.h"
9ac0d9e0 47#include "blockinput.h"
dc6f92b8 48
dc6f92b8
JB
49/* This may include sys/types.h, and that somehow loses
50 if this is not done before the other system files. */
51#include "xterm.h"
f451eb13 52#include <X11/cursorfont.h>
dc6f92b8 53
16bd92ea 54#ifndef USG
dc6f92b8
JB
55/* Load sys/types.h if not already loaded.
56 In some systems loading it twice is suicidal. */
57#ifndef makedev
58#include <sys/types.h>
c118dd06
JB
59#endif /* makedev */
60#endif /* USG */
dc6f92b8
JB
61
62#ifdef BSD
63#include <sys/ioctl.h>
64#include <strings.h>
c118dd06 65#else /* ! defined (BSD) */
febf25d5 66#ifndef VMS
dc6f92b8 67#include <string.h>
febf25d5 68#endif
c118dd06 69#endif /* ! defined (BSD) */
dc6f92b8 70
2d368234 71#include "systty.h"
3a2712f9 72#include "systime.h"
dc6f92b8 73
b8009dd1 74#ifndef INCLUDED_FCNTL
dc6f92b8 75#include <fcntl.h>
b8009dd1 76#endif
dc6f92b8
JB
77#include <ctype.h>
78#include <errno.h>
79#include <setjmp.h>
80#include <sys/stat.h>
81#include <sys/param.h>
82
83#include "dispextern.h"
84#include "termhooks.h"
85#include "termopts.h"
86#include "termchar.h"
87#if 0
88#include "sink.h"
89#include "sinkmask.h"
c118dd06 90#endif /* ! 0 */
dc6f92b8 91#include "gnu.h"
f676886a 92#include "frame.h"
dc6f92b8 93#include "disptab.h"
dc6f92b8 94#include "buffer.h"
f451eb13 95#include "window.h"
dc6f92b8 96
3afe33e7
RS
97#ifdef USE_X_TOOLKIT
98extern XtAppContext Xt_app_con;
99extern Widget Xt_app_shell;
9d7e2e3e 100extern void free_frame_menubar ();
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
105#endif
106
dc6f92b8
JB
107#ifdef HAVE_X11
108#define XMapWindow XMapRaised /* Raise them when mapping. */
c118dd06 109#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
110#include <X/Xkeyboard.h>
111/*#include <X/Xproto.h> */
c118dd06 112#endif /* ! defined (HAVE_X11) */
dc6f92b8 113
c34efc6c
JB
114#ifdef FD_SET
115/* We could get this from param.h, but better not to depend on finding that.
116 And better not to risk that it might define other symbols used in this
117 file. */
118#ifdef FD_SETSIZE
119#define MAXDESC FD_SETSIZE
120#else
121#define MAXDESC 64
122#endif
123#define SELECT_TYPE fd_set
124#else /* no FD_SET */
125#define MAXDESC 32
126#define SELECT_TYPE int
127
128/* Define the macros to access a single-int bitmap of descriptors. */
129#define FD_SET(n, p) (*(p) |= (1 << (n)))
130#define FD_CLR(n, p) (*(p) &= ~(1 << (n)))
131#define FD_ISSET(n, p) (*(p) & (1 << (n)))
132#define FD_ZERO(p) (*(p) = 0)
133#endif /* no FD_SET */
134
dc6f92b8
JB
135/* For sending Meta-characters. Do we need this? */
136#define METABIT 0200
137
138#define min(a,b) ((a)<(b) ? (a) : (b))
139#define max(a,b) ((a)>(b) ? (a) : (b))
69388238 140\f
dc6f92b8
JB
141/* Nonzero means we must reprint all windows
142 because 1) we received an ExposeWindow event
f451eb13 143 or 2) we received too many ExposeRegion events to record.
dc6f92b8 144
f451eb13 145 This is never needed under X11. */
dc6f92b8
JB
146static int expose_all_windows;
147
148/* Nonzero means we must reprint all icon windows. */
149
150static int expose_all_icons;
151
152#ifndef HAVE_X11
153/* ExposeRegion events, when received, are copied into this queue
154 for later processing. */
155
156static struct event_queue x_expose_queue;
157
69388238 158/* ButtonPress and ButtonReleased events, when received,
dc6f92b8
JB
159 are copied into this queue for later processing. */
160
161struct event_queue x_mouse_queue;
c118dd06 162#endif /* HAVE_X11 */
dc6f92b8 163
dc6f92b8
JB
164#if defined (SIGIO) && defined (FIONREAD)
165int BLOCK_INPUT_mask;
c118dd06 166#endif /* ! defined (SIGIO) && defined (FIONREAD) */
dc6f92b8 167
dc6f92b8
JB
168/* The id of a bitmap used for icon windows.
169 One such map is shared by all Emacs icon windows.
170 This is zero if we have not yet had a need to create the bitmap. */
171
172static Bitmap icon_bitmap;
173
174/* Font used for text icons. */
175
176static FONT_TYPE *icon_font_info;
177
178/* Stuff for dealing with the main icon title. */
179
180extern Lisp_Object Vcommand_line_args;
60fb3ee1 181char *hostname, *x_id_name;
dc6f92b8
JB
182
183/* This is the X connection that we are using. */
184
185Display *x_current_display;
186
ab648270
JB
187/* The cursor to use for vertical scroll bars on x_current_display. */
188static Cursor x_vertical_scroll_bar_cursor;
f451eb13 189
987d2ad1 190/* Frame being updated by update_frame. This is declared in term.c.
d0386f2a 191 This is set by update_begin and looked at by all the
dc6f92b8 192 XT functions. It is zero while not inside an update.
f676886a
JB
193 In that case, the XT functions assume that `selected_frame'
194 is the frame to apply to. */
d0386f2a 195extern struct frame *updating_frame;
dc6f92b8 196
f676886a 197/* The frame (if any) which has the X window that has keyboard focus.
f451eb13
JB
198 Zero if none. This is examined by Ffocus_frame in frame.c. Note
199 that a mere EnterNotify event can set this; if you need to know the
200 last frame specified in a FocusIn or FocusOut event, use
201 x_focus_event_frame. */
f676886a 202struct frame *x_focus_frame;
dc6f92b8 203
f451eb13
JB
204/* The last frame mentioned in a FocusIn or FocusOut event. This is
205 separate from x_focus_frame, because whether or not LeaveNotify
206 events cause us to lose focus depends on whether or not we have
207 received a FocusIn event for it. */
208struct frame *x_focus_event_frame;
209
f676886a
JB
210/* The frame which currently has the visual highlight, and should get
211 keyboard input (other sorts of input have the frame encoded in the
212 event). It points to the X focus frame's selected window's
213 frame. It differs from x_focus_frame when we're using a global
6d4238f3 214 minibuffer. */
f676886a 215static struct frame *x_highlight_frame;
6d4238f3 216
dc6f92b8 217/* From .Xdefaults, the value of "emacs.WarpMouse". If non-zero,
f676886a 218 mouse is moved to inside of frame when frame is de-iconified. */
dc6f92b8
JB
219
220static int warp_mouse_on_deiconify;
221
222/* During an update, maximum vpos for ins/del line operations to affect. */
223
224static int flexlines;
225
226/* During an update, nonzero if chars output now should be highlighted. */
227
228static int highlight;
229
230/* Nominal cursor position -- where to draw output.
231 During an update, these are different from the cursor-box position. */
232
233static int curs_x;
234static int curs_y;
235
69388238
RS
236/* Mouse movement.
237
238 In order to avoid asking for motion events and then throwing most
239 of them away or busy-polling the server for mouse positions, we ask
240 the server for pointer motion hints. This means that we get only
241 one event per group of mouse movements. "Groups" are delimited by
242 other kinds of events (focus changes and button clicks, for
243 example), or by XQueryPointer calls; when one of these happens, we
244 get another MotionNotify event the next time the mouse moves. This
245 is at least as efficient as getting motion events when mouse
246 tracking is on, and I suspect only negligibly worse when tracking
247 is off.
248
249 The silly O'Reilly & Associates Nutshell guides barely document
250 pointer motion hints at all (I think you have to infer how they
251 work from an example), and the description of XQueryPointer doesn't
252 mention that calling it causes you to get another motion hint from
253 the server, which is very important. */
254
255/* Where the mouse was last time we reported a mouse event. */
256static FRAME_PTR last_mouse_frame;
257static XRectangle last_mouse_glyph;
258
259/* The scroll bar in which the last X motion event occurred.
260
261 If the last X motion event occurred in a scroll bar, we set this
262 so XTmouse_position can know whether to report a scroll bar motion or
263 an ordinary motion.
264
265 If the last X motion event didn't occur in a scroll bar, we set this
266 to Qnil, to tell XTmouse_position to return an ordinary motion event. */
267static Lisp_Object last_mouse_scroll_bar;
268
269/* Record which buttons are currently pressed. */
270unsigned int x_mouse_grabbed;
271
272/* This is a hack. We would really prefer that XTmouse_position would
273 return the time associated with the position it returns, but there
274 doesn't seem to be any way to wrest the timestamp from the server
275 along with the position query. So, we just keep track of the time
276 of the last movement we received, and return that in hopes that
277 it's somewhat accurate. */
278static Time last_mouse_movement_time;
279
b8009dd1
RS
280/* These variables describe the range of text currently shown
281 in its mouse-face, together with the window they apply to.
282 As long as the mouse stays within this range, we need not
283 redraw anything on its account. */
284static int mouse_face_beg, mouse_face_end;
285static Lisp_Object mouse_face_window;
286static int mouse_face_face_id;
287
288/* FRAME and X, Y position of mouse when last checked for highlighting. */
289static FRAME_PTR mouse_face_mouse_frame;
290static int mouse_face_mouse_x, mouse_face_mouse_y;
291
292/* Nonzero means defer mouse-motion highlighting. */
293static int mouse_face_defer;
294
dc6f92b8
JB
295#ifdef HAVE_X11
296/* `t' if a mouse button is depressed. */
297
298extern Lisp_Object Vmouse_depressed;
299
300/* Tells if a window manager is present or not. */
301
302extern Lisp_Object Vx_no_window_manager;
303
304/* Timestamp that we requested selection data was made. */
305extern Time requestor_time;
306
307/* ID of the window requesting selection data. */
308extern Window requestor_window;
309
310/* Nonzero enables some debugging for the X interface code. */
311extern int _Xdebug;
312
b8009dd1
RS
313extern Qface, Qmouse_face;
314
c118dd06 315#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
316
317/* Bit patterns for the mouse cursor. */
318
319short MouseCursor[] = {
320 0x0000, 0x0008, 0x0018, 0x0038,
321 0x0078, 0x00f8, 0x01f8, 0x03f8,
322 0x07f8, 0x00f8, 0x00d8, 0x0188,
323 0x0180, 0x0300, 0x0300, 0x0000};
324
325short MouseMask[] = {
326 0x000c, 0x001c, 0x003c, 0x007c,
327 0x00fc, 0x01fc, 0x03fc, 0x07fc,
328 0x0ffc, 0x0ffc, 0x01fc, 0x03dc,
329 0x03cc, 0x0780, 0x0780, 0x0300};
330
331static short grey_bits[] = {
332 0x0005, 0x000a, 0x0005, 0x000a};
333
334static Pixmap GreyPixmap = 0;
c118dd06 335#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
336
337/* From time to time we get info on an Emacs window, here. */
338
339static WINDOWINFO_TYPE windowinfo;
340
341extern int errno;
342
dfeccd2d 343/* A mask of extra modifier bits to put into every keyboard char. */
64bb1782
RS
344extern int extra_keyboard_modifiers;
345
dc6f92b8
JB
346extern Display *XOpenDisplay ();
347extern Window XCreateWindow ();
348
349extern Cursor XCreateCursor ();
350extern FONT_TYPE *XOpenFont ();
351
352static void flashback ();
c83febd7 353static void redraw_previous_char ();
3afe33e7 354static unsigned int x_x_to_emacs_modifiers ();
dc6f92b8 355
b8009dd1
RS
356static void note_mouse_highlight ();
357static void clear_mouse_face ();
358static void show_mouse_face ();
359
dc6f92b8
JB
360#ifndef HAVE_X11
361static void dumpqueue ();
c118dd06 362#endif /* HAVE_X11 */
dc6f92b8
JB
363
364void dumpborder ();
4746118a
JB
365static int XTcursor_to ();
366static int XTclear_end_of_line ();
16bd92ea
JB
367
368\f
f451eb13
JB
369/* Starting and ending updates.
370
371 These hooks are called by update_frame at the beginning and end
f676886a
JB
372 of a frame update. We record in `updating_frame' the identity
373 of the frame being updated, so that the XT... functions do not
374 need to take a frame as argument. Most of the XT... functions
dc6f92b8 375 should never be called except during an update, the only exceptions
c83febd7 376 being XTcursor_to, XTwrite_glyphs and XTreassert_line_highlight. */
dc6f92b8
JB
377
378extern int mouse_track_top, mouse_track_left, mouse_track_width;
379
380static
f676886a
JB
381XTupdate_begin (f)
382 struct frame *f;
dc6f92b8
JB
383{
384 int mask;
385
f676886a 386 if (f == 0)
dc6f92b8
JB
387 abort ();
388
f676886a 389 flexlines = f->height;
dc6f92b8
JB
390 highlight = 0;
391
dc6f92b8 392 BLOCK_INPUT;
b8009dd1
RS
393
394 if (f == mouse_face_mouse_frame)
395 {
396 mouse_face_defer = 1;
397 if (!NILP (mouse_face_window))
398 clear_mouse_face ();
399 }
dc6f92b8
JB
400#ifndef HAVE_X11
401 dumpqueue ();
c118dd06 402#endif /* HAVE_X11 */
dc6f92b8
JB
403 UNBLOCK_INPUT;
404}
405
f451eb13 406#ifndef HAVE_X11
dc6f92b8 407static void x_do_pending_expose ();
f451eb13 408#endif
dc6f92b8
JB
409
410static
f676886a
JB
411XTupdate_end (f)
412 struct frame *f;
dc6f92b8
JB
413{
414 int mask;
415
dc6f92b8
JB
416 BLOCK_INPUT;
417#ifndef HAVE_X11
418 dumpqueue ();
dc6f92b8 419 x_do_pending_expose ();
f451eb13 420#endif /* HAVE_X11 */
dc6f92b8 421
f676886a 422 x_display_cursor (f, 1);
dc6f92b8 423
b8009dd1
RS
424 if (f == mouse_face_mouse_frame)
425 mouse_face_defer = 0;
426#if 0
427 /* This fails in the case of having updated only the echo area
428 if we have switched buffers. In that case, FRAME_CURRENT_GLYPHS
429 has no relation to the current contents, and its charstarts
430 have no relation to the contents of the window-buffer.
431 I don't know a clean way to check
432 for that case. window_end_valid isn't set up yet. */
433 if (f == mouse_face_mouse_frame)
434 note_mouse_highlight (f, mouse_face_mouse_x, mouse_face_mouse_y);
435#endif
436
dc6f92b8
JB
437 XFlushQueue ();
438 UNBLOCK_INPUT;
439}
b8009dd1
RS
440
441/* This is called when all windows on frame F are now up to date. */
442
443static
444XTframe_up_to_date (f)
445 FRAME_PTR f;
446{
447 if (f == mouse_face_mouse_frame)
448 note_mouse_highlight (f, mouse_face_mouse_x, mouse_face_mouse_y);
449}
dc6f92b8
JB
450\f
451/* External interface to control of standout mode.
452 Call this when about to modify line at position VPOS
453 and not change whether it is highlighted. */
454
455XTreassert_line_highlight (new, vpos)
456 int new, vpos;
457{
458 highlight = new;
459}
460
461/* Call this when about to modify line at position VPOS
462 and change whether it is highlighted. */
463
464static
465XTchange_line_highlight (new_highlight, vpos, first_unused_hpos)
466 int new_highlight, vpos, first_unused_hpos;
467{
468 highlight = new_highlight;
469 XTcursor_to (vpos, 0);
f676886a 470 XTclear_end_of_line (updating_frame->width);
dc6f92b8
JB
471}
472
473/* This is used when starting Emacs and when restarting after suspend.
474 When starting Emacs, no X window is mapped. And nothing must be done
475 to Emacs's own window if it is suspended (though that rarely happens). */
476
477static
478XTset_terminal_modes ()
479{
480}
481
482/* This is called when exiting or suspending Emacs.
483 Exiting will make the X-windows go away, and suspending
484 requires no action. */
485
486static
487XTreset_terminal_modes ()
488{
f676886a 489/* XTclear_frame (); */
dc6f92b8
JB
490}
491\f
f451eb13
JB
492/* Set the nominal cursor position of the frame.
493 This is where display update commands will take effect.
dc6f92b8
JB
494 This does not affect the place where the cursor-box is displayed. */
495
4746118a 496static int
dc6f92b8
JB
497XTcursor_to (row, col)
498 register int row, col;
499{
500 int mask;
501 int orow = row;
502
503 curs_x = col;
504 curs_y = row;
505
f676886a 506 if (updating_frame == 0)
dc6f92b8
JB
507 {
508 BLOCK_INPUT;
f676886a 509 x_display_cursor (selected_frame, 1);
dc6f92b8
JB
510 XFlushQueue ();
511 UNBLOCK_INPUT;
512 }
513}
514\f
515/* Display a sequence of N glyphs found at GP.
516 WINDOW is the x-window to output to. LEFT and TOP are starting coords.
b8009dd1
RS
517 HL is 1 if this text is highlighted, 2 if the cursor is on it,
518 3 if should appear in its mouse-face.
dc6f92b8 519
07e34cb0 520 FONT is the default font to use (for glyphs whose font-code is 0).
dc6f92b8 521
07e34cb0
JB
522 Since the display generation code is responsible for calling
523 compute_char_face and compute_glyph_face on everything it puts in
524 the display structure, we can assume that the face code on each
28f72798 525 glyph is a valid index into FRAME_COMPUTED_FACES (f), and the one
f94397b5
KH
526 to which we can actually apply intern_face.
527 Call this function with input blocked. */
dc6f92b8 528
07e34cb0
JB
529#if 1
530/* This is the multi-face code. */
dc6f92b8 531
dc6f92b8 532static void
07e34cb0 533dumpglyphs (f, left, top, gp, n, hl)
f676886a 534 struct frame *f;
dc6f92b8
JB
535 int left, top;
536 register GLYPH *gp; /* Points to first GLYPH. */
537 register int n; /* Number of glyphs to display. */
538 int hl;
dc6f92b8 539{
07e34cb0
JB
540 /* Holds characters to be displayed. */
541 char *buf = (char *) alloca (f->width * sizeof (*buf));
dc6f92b8
JB
542 register char *cp; /* Steps through buf[]. */
543 register int tlen = GLYPH_TABLE_LENGTH;
544 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
c118dd06 545 Window window = FRAME_X_WINDOW (f);
dc6f92b8 546
07e34cb0 547 while (n > 0)
dc6f92b8
JB
548 {
549 /* Get the face-code of the next GLYPH. */
550 int cf, len;
551 int g = *gp;
552
07e34cb0 553 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
6f63ba79 554 cf = FAST_GLYPH_FACE (g);
dc6f92b8
JB
555
556 /* Find the run of consecutive glyphs with the same face-code.
557 Extract their character codes into BUF. */
558 cp = buf;
559 while (n > 0)
560 {
561 g = *gp;
07e34cb0 562 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
6f63ba79 563 if (FAST_GLYPH_FACE (g) != cf)
dc6f92b8
JB
564 break;
565
6f63ba79 566 *cp++ = FAST_GLYPH_CHAR (g);
dc6f92b8
JB
567 --n;
568 ++gp;
569 }
570
571 /* LEN gets the length of the run. */
572 len = cp - buf;
573
574 /* Now output this run of chars, with the font and pixel values
575 determined by the face code CF. */
07e34cb0
JB
576 {
577 struct face *face = FRAME_DEFAULT_FACE (f);
578 FONT_TYPE *font = FACE_FONT (face);
579 GC gc = FACE_GC (face);
b73b6aaf
RS
580 int defaulted = 1;
581 int gc_temporary = 0;
07e34cb0 582
b8009dd1
RS
583 /* HL = 3 means use a mouse face previously chosen. */
584 if (hl == 3)
585 cf = mouse_face_face_id;
586
b73b6aaf
RS
587 /* First look at the face of the text itself. */
588 if (cf != 0)
07e34cb0 589 {
a07d4bc5
RS
590 /* It's possible for the display table to specify
591 a face code that is out of range. Use 0 in that case. */
28f72798
JB
592 if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f)
593 || FRAME_COMPUTED_FACES (f) [cf] == 0)
a07d4bc5 594 cf = 0;
07e34cb0
JB
595
596 if (cf == 1)
597 face = FRAME_MODE_LINE_FACE (f);
598 else
28f72798 599 face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
07e34cb0
JB
600 font = FACE_FONT (face);
601 gc = FACE_GC (face);
b73b6aaf 602 defaulted = 0;
07e34cb0 603 }
4a4dc352
JB
604
605 /* Then comes the distinction between modeline and normal text. */
07e34cb0
JB
606 else if (hl == 0)
607 ;
608 else if (hl == 1)
609 {
610 face = FRAME_MODE_LINE_FACE (f);
611 font = FACE_FONT (face);
612 gc = FACE_GC (face);
b73b6aaf
RS
613 defaulted = 0;
614 }
615
616#define FACE_DEFAULT (~0)
617
618 /* Now override that if the cursor's on this character. */
b5cf7a0e 619 if (hl == 2)
b73b6aaf 620 {
b5cf7a0e
JB
621 if (defaulted
622 || !face->font
623 || (int) face->font == FACE_DEFAULT)
624 {
625 gc = f->display.x->cursor_gc;
626 }
627 /* Cursor on non-default face: must merge. */
628 else
629 {
630 XGCValues xgcv;
631 unsigned long mask;
632
633 xgcv.background = f->display.x->cursor_pixel;
df5a440b
RS
634 if (face == FRAME_DEFAULT_FACE (f))
635 xgcv.foreground = f->display.x->cursor_foreground_pixel;
636 else
637 xgcv.foreground = face->foreground;
638 /* If the glyph would be invisible,
639 try a different foreground. */
640 if (xgcv.foreground == xgcv.background)
641 xgcv.foreground = face->background;
642 if (xgcv.foreground == xgcv.background)
643 xgcv.foreground = f->display.x->cursor_foreground_pixel;
644 if (xgcv.foreground == xgcv.background)
645 xgcv.foreground = face->foreground;
646 /* Make sure the cursor is distinct from text in this face. */
647 if (xgcv.background == face->background
648 && xgcv.foreground == face->foreground)
649 {
650 xgcv.background = face->foreground;
651 xgcv.foreground = face->background;
652 }
b5cf7a0e
JB
653 xgcv.font = face->font->fid;
654 xgcv.graphics_exposures = 0;
655 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
656 gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
657 mask, &xgcv);
b73b6aaf 658#if 0
b5cf7a0e
JB
659 if (face->stipple && face->stipple != FACE_DEFAULT)
660 XSetStipple (x_current_display, gc, face->stipple);
b73b6aaf 661#endif
b5cf7a0e
JB
662 gc_temporary = 1;
663 }
07e34cb0 664 }
07e34cb0 665
b5cf7a0e
JB
666 if ((int) font == FACE_DEFAULT)
667 font = f->display.x->font;
668
07e34cb0
JB
669 XDrawImageString (x_current_display, window, gc,
670 left, top + FONT_BASE (font), buf, len);
07e34cb0 671
b73b6aaf
RS
672 if (gc_temporary)
673 XFreeGC (x_current_display, gc);
674
07e34cb0
JB
675 /* We should probably check for XA_UNDERLINE_POSITION and
676 XA_UNDERLINE_THICKNESS properties on the font, but let's
677 just get the thing working, and come back to that. */
dc6f92b8 678 {
4a4dc352 679 int underline_position = 1;
07e34cb0 680
4a4dc352
JB
681 if (font->descent <= underline_position)
682 underline_position = font->descent - 1;
07e34cb0
JB
683
684 if (face->underline)
685 XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
686 FACE_GC (face),
687 left, (top
688 + FONT_BASE (font)
689 + underline_position),
690 len * FONT_WIDTH (font), 1);
dc6f92b8 691 }
07e34cb0
JB
692
693 left += len * FONT_WIDTH (font);
694 }
dc6f92b8
JB
695 }
696}
07e34cb0
JB
697#endif /* 1 */
698
699#if 0
700/* This is the old single-face code. */
701
702static void
703dumpglyphs (f, left, top, gp, n, hl, font)
704 struct frame *f;
705 int left, top;
706 register GLYPH *gp; /* Points to first GLYPH. */
707 register int n; /* Number of glyphs to display. */
708 int hl;
709 FONT_TYPE *font;
710{
711 register int len;
712 Window window = FRAME_X_WINDOW (f);
713 GC drawing_gc = (hl == 2 ? f->display.x->cursor_gc
714 : (hl ? f->display.x->reverse_gc
715 : f->display.x->normal_gc));
716
717 if (sizeof (GLYPH) == sizeof (XChar2b))
718 XDrawImageString16 (x_current_display, window, drawing_gc,
719 left, top + FONT_BASE (font), (XChar2b *) gp, n);
720 else if (sizeof (GLYPH) == sizeof (unsigned char))
721 XDrawImageString (x_current_display, window, drawing_gc,
722 left, top + FONT_BASE (font), (char *) gp, n);
723 else
724 /* What size of glyph ARE you using? And does X have a function to
725 draw them? */
726 abort ();
727}
728#endif
dc6f92b8 729\f
f451eb13
JB
730/* Output some text at the nominal frame cursor position.
731 Advance the cursor over the text.
dc6f92b8
JB
732 Output LEN glyphs at START.
733
734 `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight,
735 controls the pixel values used for foreground and background. */
736
737static
738XTwrite_glyphs (start, len)
739 register GLYPH *start;
740 int len;
741{
742 register int temp_length;
743 int mask;
f676886a 744 struct frame *f;
dc6f92b8
JB
745
746 BLOCK_INPUT;
747
f676886a
JB
748 f = updating_frame;
749 if (f == 0)
dc6f92b8 750 {
f676886a 751 f = selected_frame;
dc6f92b8 752 /* If not within an update,
f676886a
JB
753 output at the frame's visible cursor. */
754 curs_x = f->cursor_x;
755 curs_y = f->cursor_y;
dc6f92b8
JB
756 }
757
f676886a 758 dumpglyphs (f,
12ba150f
JB
759 CHAR_TO_PIXEL_COL (f, curs_x),
760 CHAR_TO_PIXEL_ROW (f, curs_y),
07e34cb0 761 start, len, highlight);
90e65f07
JB
762
763 /* If we drew on top of the cursor, note that it is turned off. */
f676886a
JB
764 if (curs_y == f->phys_cursor_y
765 && curs_x <= f->phys_cursor_x
766 && curs_x + len > f->phys_cursor_x)
767 f->phys_cursor_x = -1;
dc6f92b8 768
f676886a 769 if (updating_frame == 0)
dc6f92b8 770 {
f676886a
JB
771 f->cursor_x += len;
772 x_display_cursor (f, 1);
773 f->cursor_x -= len;
dc6f92b8
JB
774 }
775 else
776 curs_x += len;
777
778 UNBLOCK_INPUT;
779}
780\f
f451eb13
JB
781/* Clear to the end of the line.
782 Erase the current text line from the nominal cursor position (inclusive)
dc6f92b8
JB
783 to column FIRST_UNUSED (exclusive). The idea is that everything
784 from FIRST_UNUSED onward is already erased. */
785
4746118a 786static int
dc6f92b8
JB
787XTclear_end_of_line (first_unused)
788 register int first_unused;
789{
f676886a 790 struct frame *f = updating_frame;
dc6f92b8
JB
791 int mask;
792
f676886a 793 if (f == 0)
dc6f92b8
JB
794 abort ();
795
f676886a 796 if (curs_y < 0 || curs_y >= f->height)
dc6f92b8
JB
797 return;
798 if (first_unused <= 0)
799 return;
800
f676886a
JB
801 if (first_unused >= f->width)
802 first_unused = f->width;
dc6f92b8
JB
803
804 BLOCK_INPUT;
805
90e65f07 806 /* Notice if the cursor will be cleared by this operation. */
f676886a
JB
807 if (curs_y == f->phys_cursor_y
808 && curs_x <= f->phys_cursor_x
809 && f->phys_cursor_x < first_unused)
810 f->phys_cursor_x = -1;
dc6f92b8
JB
811
812#ifdef HAVE_X11
c118dd06 813 XClearArea (x_current_display, FRAME_X_WINDOW (f),
12ba150f
JB
814 CHAR_TO_PIXEL_COL (f, curs_x),
815 CHAR_TO_PIXEL_ROW (f, curs_y),
f676886a
JB
816 FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
817 FONT_HEIGHT (f->display.x->font), False);
c83febd7
RS
818#if 0
819 redraw_previous_char (f, curs_x, curs_y);
820#endif
c118dd06
JB
821#else /* ! defined (HAVE_X11) */
822 XPixSet (FRAME_X_WINDOW (f),
12ba150f
JB
823 CHAR_TO_PIXEL_COL (f, curs_x),
824 CHAR_TO_PIXEL_ROW (f, curs_y),
f676886a
JB
825 FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
826 FONT_HEIGHT (f->display.x->font),
827 f->display.x->background_pixel);
c118dd06 828#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
829
830 UNBLOCK_INPUT;
831}
832
c83febd7
RS
833/* Erase the character (if any) at the position just before X, Y in frame F,
834 then redraw it and the character before it.
835 This is necessary when we erase starting at X,
f94397b5
KH
836 in case the character after X overlaps into the one before X.
837 Call this function with input blocked. */
c83febd7
RS
838
839static void
840redraw_previous_char (f, x, y)
841 FRAME_PTR f;
842 int x, y;
843{
844 /* Erase the character before the new ones, in case
845 what was here before overlaps it.
846 Reoutput that character, and the previous character
847 (in case the previous character overlaps it). */
848 if (x > 0)
849 {
850 int start_x = x - 2;
851 if (start_x < 0)
852 start_x = 0;
853 XClearArea (x_current_display, FRAME_X_WINDOW (f),
854 CHAR_TO_PIXEL_COL (f, x - 1),
855 CHAR_TO_PIXEL_ROW (f, y),
856 FONT_WIDTH (f->display.x->font),
857 FONT_HEIGHT (f->display.x->font), False);
858
859 dumpglyphs (f, CHAR_TO_PIXEL_COL (f, start_x),
860 CHAR_TO_PIXEL_ROW (f, y),
861 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][start_x],
862 x - start_x, highlight);
863 }
864}
865
dc6f92b8 866static
f676886a 867XTclear_frame ()
dc6f92b8
JB
868{
869 int mask;
f676886a 870 struct frame *f = updating_frame;
dc6f92b8 871
f676886a
JB
872 if (f == 0)
873 f = selected_frame;
dc6f92b8 874
f676886a 875 f->phys_cursor_x = -1; /* Cursor not visible. */
dc6f92b8
JB
876 curs_x = 0; /* Nominal cursor position is top left. */
877 curs_y = 0;
878
879 BLOCK_INPUT;
dbc4e1c1 880
c118dd06 881 XClear (FRAME_X_WINDOW (f));
dbc4e1c1 882
ab648270 883 /* We have to clear the scroll bars, too. If we have changed
dbc4e1c1 884 colors or something like that, then they should be notified. */
ab648270 885 x_scroll_bar_clear (f);
dbc4e1c1 886
dc6f92b8 887#ifndef HAVE_X11
f676886a 888 dumpborder (f, 0);
c118dd06 889#endif /* HAVE_X11 */
dbc4e1c1 890
dc6f92b8
JB
891 XFlushQueue ();
892 UNBLOCK_INPUT;
893}
894\f
dbc4e1c1
JB
895/* Invert the middle quarter of the frame for .15 sec. */
896
897/* We use the select system call to do the waiting, so we have to make sure
eb8c3be9 898 it's available. If it isn't, we just won't do visual bells. */
dbc4e1c1
JB
899#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
900
901/* Subtract the `struct timeval' values X and Y,
902 storing the result in RESULT.
903 Return 1 if the difference is negative, otherwise 0. */
904
905static int
906timeval_subtract (result, x, y)
907 struct timeval *result, x, y;
908{
909 /* Perform the carry for the later subtraction by updating y.
910 This is safer because on some systems
911 the tv_sec member is unsigned. */
912 if (x.tv_usec < y.tv_usec)
913 {
914 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
915 y.tv_usec -= 1000000 * nsec;
916 y.tv_sec += nsec;
917 }
918 if (x.tv_usec - y.tv_usec > 1000000)
919 {
920 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
921 y.tv_usec += 1000000 * nsec;
922 y.tv_sec -= nsec;
923 }
924
925 /* Compute the time remaining to wait. tv_usec is certainly positive. */
926 result->tv_sec = x.tv_sec - y.tv_sec;
927 result->tv_usec = x.tv_usec - y.tv_usec;
928
929 /* Return indication of whether the result should be considered negative. */
930 return x.tv_sec < y.tv_sec;
931}
dc6f92b8 932
f676886a
JB
933XTflash (f)
934 struct frame *f;
dc6f92b8 935{
dbc4e1c1 936 BLOCK_INPUT;
dc6f92b8 937
dbc4e1c1
JB
938 {
939 GC gc;
dc6f92b8 940
dbc4e1c1
JB
941 /* Create a GC that will use the GXxor function to flip foreground pixels
942 into background pixels. */
943 {
944 XGCValues values;
dc6f92b8 945
dbc4e1c1
JB
946 values.function = GXxor;
947 values.foreground = (f->display.x->foreground_pixel
948 ^ f->display.x->background_pixel);
949
950 gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
951 GCFunction | GCForeground, &values);
952 }
dc6f92b8 953
dbc4e1c1
JB
954 {
955 int width = PIXEL_WIDTH (f);
956 int height = PIXEL_HEIGHT (f);
dc6f92b8 957
dbc4e1c1
JB
958 XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc,
959 width/4, height/4, width/2, height/2);
960 XFlush (x_current_display);
dc6f92b8 961
dbc4e1c1
JB
962 {
963 struct timeval wakeup, now;
dc6f92b8 964
66c30ea1 965 EMACS_GET_TIME (wakeup);
dc6f92b8 966
dbc4e1c1
JB
967 /* Compute time to wait until, propagating carry from usecs. */
968 wakeup.tv_usec += 150000;
969 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
970 wakeup.tv_usec %= 1000000;
971
972 /* Keep waiting until past the time wakeup. */
973 while (1)
974 {
975 struct timeval timeout;
976
66c30ea1 977 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
978
979 /* In effect, timeout = wakeup - timeout.
980 Break if result would be negative. */
981 if (timeval_subtract (&timeout, wakeup, timeout))
982 break;
983
984 /* Try to wait that long--but we might wake up sooner. */
985 select (0, 0, 0, 0, &timeout);
986 }
987 }
988
989 XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc,
990 width/4, height/4, width/2, height/2);
991 XFreeGC (x_current_display, gc);
992 XFlush (x_current_display);
dc6f92b8 993 }
dbc4e1c1
JB
994 }
995
996 UNBLOCK_INPUT;
dc6f92b8
JB
997}
998
dbc4e1c1
JB
999#endif
1000
1001
dc6f92b8
JB
1002/* Make audible bell. */
1003
1004#ifdef HAVE_X11
bc20ebbf 1005#define XRINGBELL XBell (x_current_display, 0)
c118dd06 1006#else /* ! defined (HAVE_X11) */
bc20ebbf 1007#define XRINGBELL XFeep (0);
c118dd06 1008#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
1009
1010XTring_bell ()
1011{
5a6ef893
RS
1012 if (x_current_display == 0)
1013 return;
1014
dbc4e1c1 1015#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
dc6f92b8 1016 if (visible_bell)
f676886a 1017 XTflash (selected_frame);
dc6f92b8 1018 else
dbc4e1c1 1019#endif
dc6f92b8
JB
1020 {
1021 BLOCK_INPUT;
1022 XRINGBELL;
1023 XFlushQueue ();
1024 UNBLOCK_INPUT;
1025 }
1026}
1027\f
f451eb13
JB
1028/* Insert and delete character.
1029 These are not supposed to be used because we are supposed to turn
1030 off the feature of using them. */
dc6f92b8
JB
1031
1032static
1033XTinsert_glyphs (start, len)
1034 register char *start;
1035 register int len;
1036{
1037 abort ();
1038}
1039
1040static
1041XTdelete_glyphs (n)
1042 register int n;
1043{
1044 abort ();
1045}
1046\f
1047/* Specify how many text lines, from the top of the window,
1048 should be affected by insert-lines and delete-lines operations.
1049 This, and those operations, are used only within an update
1050 that is bounded by calls to XTupdate_begin and XTupdate_end. */
1051
1052static
1053XTset_terminal_window (n)
1054 register int n;
1055{
f676886a 1056 if (updating_frame == 0)
dc6f92b8
JB
1057 abort ();
1058
f676886a
JB
1059 if ((n <= 0) || (n > updating_frame->height))
1060 flexlines = updating_frame->height;
dc6f92b8
JB
1061 else
1062 flexlines = n;
1063}
1064\f
f451eb13
JB
1065/* Perform an insert-lines operation.
1066 Insert N lines at a vertical position curs_y. */
dc6f92b8
JB
1067
1068static void
1069stufflines (n)
1070 register int n;
1071{
1072 register int topregion, bottomregion;
1073 register int length, newtop, mask;
f676886a
JB
1074 register struct frame *f = updating_frame;
1075 int intborder = f->display.x->internal_border_width;
dc6f92b8
JB
1076
1077 if (curs_y >= flexlines)
1078 return;
1079
1080 topregion = curs_y;
1081 bottomregion = flexlines - (n + 1);
1082 newtop = topregion + n;
1083 length = (bottomregion - topregion) + 1;
1084
1085#ifndef HAVE_X11
1086 dumpqueue ();
c118dd06 1087#endif /* HAVE_X11 */
dc6f92b8
JB
1088
1089 if ((length > 0) && (newtop <= flexlines))
1090 {
1091#ifdef HAVE_X11
c118dd06
JB
1092 XCopyArea (x_current_display, FRAME_X_WINDOW (f),
1093 FRAME_X_WINDOW (f), f->display.x->normal_gc,
12ba150f 1094 intborder, CHAR_TO_PIXEL_ROW (f, topregion),
f676886a
JB
1095 f->width * FONT_WIDTH (f->display.x->font),
1096 length * FONT_HEIGHT (f->display.x->font), intborder,
12ba150f 1097 CHAR_TO_PIXEL_ROW (f, newtop));
c118dd06
JB
1098#else /* ! defined (HAVE_X11) */
1099 XMoveArea (FRAME_X_WINDOW (f),
12ba150f
JB
1100 intborder, CHAR_TO_PIXEL_ROW (f, topregion),
1101 intborder, CHAR_TO_PIXEL_ROW (f, newtop),
f676886a
JB
1102 f->width * FONT_WIDTH (f->display.x->font),
1103 length * FONT_HEIGHT (f->display.x->font));
dc6f92b8
JB
1104 /* Now we must process any ExposeRegion events that occur
1105 if the area being copied from is obscured.
1106 We can't let it wait because further i/d operations
1107 may want to copy this area to another area. */
1108 x_read_exposes ();
c118dd06 1109#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
1110 }
1111
1112 newtop = min (newtop, (flexlines - 1));
1113 length = newtop - topregion;
1114 if (length > 0)
1115 {
1116#ifdef HAVE_X11
c118dd06 1117 XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder,
12ba150f 1118 CHAR_TO_PIXEL_ROW (f, topregion),
f676886a
JB
1119 f->width * FONT_WIDTH (f->display.x->font),
1120 n * FONT_HEIGHT (f->display.x->font), False);
c118dd06
JB
1121#else /* ! defined (HAVE_X11) */
1122 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 1123 intborder,
12ba150f 1124 CHAR_TO_PIXEL_ROW (f, topregion),
f676886a
JB
1125 f->width * FONT_WIDTH (f->display.x->font),
1126 n * FONT_HEIGHT (f->display.x->font),
1127 f->display.x->background_pixel);
c118dd06 1128#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
1129 }
1130}
1131
1132/* Perform a delete-lines operation, deleting N lines
1133 at a vertical position curs_y. */
1134
1135static void
1136scraplines (n)
1137 register int n;
1138{
1139 int mask;
f676886a
JB
1140 register struct frame *f = updating_frame;
1141 int intborder = f->display.x->internal_border_width;
dc6f92b8
JB
1142
1143 if (curs_y >= flexlines)
1144 return;
1145
1146#ifndef HAVE_X11
1147 dumpqueue ();
c118dd06 1148#endif /* HAVE_X11 */
dc6f92b8
JB
1149
1150 if ((curs_y + n) >= flexlines)
1151 {
1152 if (flexlines >= (curs_y + 1))
1153 {
1154#ifdef HAVE_X11
c118dd06 1155 XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder,
12ba150f 1156 CHAR_TO_PIXEL_ROW (f, curs_y),
f676886a
JB
1157 f->width * FONT_WIDTH (f->display.x->font),
1158 (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font), False);
c118dd06
JB
1159#else /* ! defined (HAVE_X11) */
1160 XPixSet (FRAME_X_WINDOW (f),
12ba150f 1161 intborder, CHAR_TO_PIXEL_ROW (f, curs_y),
f676886a
JB
1162 f->width * FONT_WIDTH (f->display.x->font),
1163 (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font),
1164 f->display.x->background_pixel);
c118dd06 1165#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
1166 }
1167 }
1168 else
1169 {
1170#ifdef HAVE_X11
c118dd06
JB
1171 XCopyArea (x_current_display, FRAME_X_WINDOW (f),
1172 FRAME_X_WINDOW (f), f->display.x->normal_gc,
dc6f92b8 1173 intborder,
12ba150f 1174 CHAR_TO_PIXEL_ROW (f, curs_y + n),
f676886a
JB
1175 f->width * FONT_WIDTH (f->display.x->font),
1176 (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font),
12ba150f 1177 intborder, CHAR_TO_PIXEL_ROW (f, curs_y));
c118dd06 1178 XClearArea (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8 1179 intborder,
12ba150f 1180 CHAR_TO_PIXEL_ROW (f, flexlines - n),
f676886a
JB
1181 f->width * FONT_WIDTH (f->display.x->font),
1182 n * FONT_HEIGHT (f->display.x->font), False);
c118dd06
JB
1183#else /* ! defined (HAVE_X11) */
1184 XMoveArea (FRAME_X_WINDOW (f),
dc6f92b8 1185 intborder,
12ba150f
JB
1186 CHAR_TO_PIXEL_ROW (f, curs_y + n),
1187 intborder, CHAR_TO_PIXEL_ROW (f, curs_y),
f676886a
JB
1188 f->width * FONT_WIDTH (f->display.x->font),
1189 (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font));
dc6f92b8
JB
1190 /* Now we must process any ExposeRegion events that occur
1191 if the area being copied from is obscured.
1192 We can't let it wait because further i/d operations
1193 may want to copy this area to another area. */
1194 x_read_exposes ();
c118dd06 1195 XPixSet (FRAME_X_WINDOW (f), intborder,
12ba150f 1196 CHAR_TO_PIXEL_ROW (f, flexlines - n),
f676886a
JB
1197 f->width * FONT_WIDTH (f->display.x->font),
1198 n * FONT_HEIGHT (f->display.x->font), f->display.x->background_pixel);
c118dd06 1199#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
1200 }
1201}
1202
1203/* Perform an insert-lines or delete-lines operation,
1204 inserting N lines or deleting -N lines at vertical position VPOS. */
1205
1206XTins_del_lines (vpos, n)
1207 int vpos, n;
1208{
f676886a 1209 if (updating_frame == 0)
dc6f92b8
JB
1210 abort ();
1211
90e65f07 1212 /* Hide the cursor. */
f676886a 1213 x_display_cursor (updating_frame, 0);
dc6f92b8
JB
1214
1215 XTcursor_to (vpos, 0);
1216
1217 BLOCK_INPUT;
1218 if (n >= 0)
1219 stufflines (n);
1220 else
1221 scraplines (-n);
1222 XFlushQueue ();
1223 UNBLOCK_INPUT;
1224}
1225\f
f451eb13 1226/* Support routines for exposure events. */
dc6f92b8
JB
1227static void clear_cursor ();
1228
f676886a
JB
1229/* Output into a rectangle of an X-window (for frame F)
1230 the characters in f->phys_lines that overlap that rectangle.
dc6f92b8 1231 TOP and LEFT are the position of the upper left corner of the rectangle.
f94397b5
KH
1232 ROWS and COLS are the size of the rectangle.
1233 Call this function with input blocked. */
dc6f92b8
JB
1234
1235static void
f676886a
JB
1236dumprectangle (f, left, top, cols, rows)
1237 struct frame *f;
dc6f92b8
JB
1238 register int left, top, cols, rows;
1239{
f676886a 1240 register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
dc6f92b8
JB
1241 int cursor_cleared = 0;
1242 int bottom, right;
1243 register int y;
1244
f676886a 1245 if (FRAME_GARBAGED_P (f))
dc6f92b8
JB
1246 return;
1247
dc6f92b8
JB
1248 /* Express rectangle as four edges, instead of position-and-size. */
1249 bottom = top + rows;
1250 right = left + cols;
1251
1252#ifndef HAVE_X11 /* Window manger does this for X11. */
12ba150f
JB
1253 {
1254 int intborder = f->display.x->internal_border_width;
1255
1256 /* If the rectangle includes any of the internal border area,
1257 redisplay the border emphasis. */
1258 if (top < intborder || left < intborder
1259 || bottom > intborder + f->height * FONT_HEIGHT (f->display.x->font)
1260 || right > intborder + f->width * FONT_WIDTH (f->display.x->font))
1261 dumpborder (f, 0);
1262 }
b8009dd1 1263#endif /* not HAVE_X11 Window manger does this for X11. */
dc6f92b8
JB
1264
1265 /* Convert rectangle edges in pixels to edges in chars.
1266 Round down for left and top, up for right and bottom. */
12ba150f
JB
1267 top = PIXEL_TO_CHAR_ROW (f, top);
1268 left = PIXEL_TO_CHAR_COL (f, left);
f676886a
JB
1269 bottom += (FONT_HEIGHT (f->display.x->font) - 1);
1270 right += (FONT_WIDTH (f->display.x->font) - 1);
12ba150f
JB
1271 bottom = PIXEL_TO_CHAR_ROW (f, bottom);
1272 right = PIXEL_TO_CHAR_COL (f, right);
dc6f92b8
JB
1273
1274 /* Clip the rectangle to what can be visible. */
1275 if (left < 0)
1276 left = 0;
1277 if (top < 0)
1278 top = 0;
f676886a
JB
1279 if (right > f->width)
1280 right = f->width;
1281 if (bottom > f->height)
1282 bottom = f->height;
dc6f92b8
JB
1283
1284 /* Get size in chars of the rectangle. */
1285 cols = right - left;
1286 rows = bottom - top;
1287
1288 /* If rectangle has zero area, return. */
1289 if (rows <= 0) return;
1290 if (cols <= 0) return;
1291
1292 /* Turn off the cursor if it is in the rectangle.
1293 We will turn it back on afterward. */
f676886a
JB
1294 if ((f->phys_cursor_x >= left) && (f->phys_cursor_x < right)
1295 && (f->phys_cursor_y >= top) && (f->phys_cursor_y < bottom))
dc6f92b8 1296 {
f676886a 1297 clear_cursor (f);
dc6f92b8
JB
1298 cursor_cleared = 1;
1299 }
1300
1301 /* Display the text in the rectangle, one text line at a time. */
1302
1303 for (y = top; y < bottom; y++)
1304 {
f676886a 1305 GLYPH *line = &active_frame->glyphs[y][left];
dc6f92b8 1306
f676886a 1307 if (! active_frame->enable[y] || left > active_frame->used[y])
dc6f92b8
JB
1308 continue;
1309
f676886a 1310 dumpglyphs (f,
12ba150f
JB
1311 CHAR_TO_PIXEL_COL (f, left),
1312 CHAR_TO_PIXEL_ROW (f, y),
1313 line, min (cols, active_frame->used[y] - left),
07e34cb0 1314 active_frame->highlight[y]);
dc6f92b8
JB
1315 }
1316
1317 /* Turn the cursor on if we turned it off. */
1318
1319 if (cursor_cleared)
f676886a 1320 x_display_cursor (f, 1);
dc6f92b8
JB
1321}
1322
1323#ifndef HAVE_X11
1324/* Process all queued ExposeRegion events. */
1325
1326static void
1327dumpqueue ()
1328{
1329 register int i;
1330 XExposeRegionEvent r;
1331
1332 while (dequeue_event (&r, &x_expose_queue))
1333 {
f676886a
JB
1334 struct frame *f = x_window_to_frame (r.window);
1335 if (f->display.x->icon_desc == r.window)
1336 refreshicon (f);
dc6f92b8 1337 else
f676886a 1338 dumprectangle (f, r.x, r.y, r.width, r.height);
dc6f92b8
JB
1339 }
1340 XFlushQueue ();
1341}
c118dd06 1342#endif /* HAVE_X11 */
dc6f92b8 1343\f
f451eb13 1344/* Process all expose events that are pending, for X10.
f676886a
JB
1345 Redraws the cursor if necessary on any frame that
1346 is not in the process of being updated with update_frame. */
dc6f92b8 1347
f451eb13 1348#ifndef HAVE_X11
dc6f92b8
JB
1349static void
1350x_do_pending_expose ()
1351{
1352 int mask;
f676886a
JB
1353 struct frame *f;
1354 Lisp_Object tail, frame;
dc6f92b8
JB
1355
1356 if (expose_all_windows)
1357 {
1358 expose_all_windows = 0;
f676886a 1359 for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
dc6f92b8
JB
1360 {
1361 register int temp_width, temp_height;
1362 int intborder;
1363
f676886a 1364 frame = XCONS (tail)->car;
ab648270 1365 if (XGCTYPE (frame) != Lisp_Frame)
dc6f92b8 1366 continue;
f676886a 1367 f = XFRAME (frame);
b1c884c3 1368 if (! FRAME_X_P (f))
dc6f92b8 1369 continue;
3a88c238 1370 if (!f->async_visible)
dc6f92b8 1371 continue;
f676886a 1372 if (!f->display.x->needs_exposure)
dc6f92b8
JB
1373 continue;
1374
f676886a 1375 intborder = f->display.x->internal_border_width;
dc6f92b8 1376
f676886a 1377 clear_cursor (f);
c118dd06 1378 XGetWindowInfo (FRAME_X_WINDOW (f), &windowinfo);
dc6f92b8 1379 temp_width = ((windowinfo.width - 2 * intborder
ab648270 1380 - f->display.x->v_scroll_bar_width)
f676886a 1381 / FONT_WIDTH (f->display.x->font));
dc6f92b8 1382 temp_height = ((windowinfo.height- 2 * intborder
ab648270 1383 - f->display.x->h_scroll_bar_height)
f676886a
JB
1384 / FONT_HEIGHT (f->display.x->font));
1385 if (temp_width != f->width || temp_height != f->height)
dc6f92b8 1386 {
f676886a 1387 change_frame_size (f, max (1, temp_height),
b1c884c3 1388 max (1, temp_width), 0, 1);
ab648270 1389 x_resize_scroll_bars (f);
dc6f92b8 1390 }
f676886a
JB
1391 f->display.x->left_pos = windowinfo.x;
1392 f->display.x->top_pos = windowinfo.y;
1393 dumprectangle (f, 0, 0, PIXEL_WIDTH (f), PIXEL_HEIGHT (f));
dc6f92b8 1394#if 0
f676886a 1395 dumpborder (f, 0);
c118dd06 1396#endif /* ! 0 */
f676886a
JB
1397 f->display.x->needs_exposure = 0;
1398 if (updating_frame != f)
1399 x_display_cursor (f, 1);
dc6f92b8
JB
1400 XFlushQueue ();
1401 }
1402 }
1403 else
1404 /* Handle any individual-rectangle expose events queued
1405 for various windows. */
1406#ifdef HAVE_X11
1407 ;
c118dd06 1408#else /* ! defined (HAVE_X11) */
dc6f92b8 1409 dumpqueue ();
c118dd06 1410#endif /* ! defined (HAVE_X11) */
dc6f92b8 1411}
f451eb13 1412#endif
dc6f92b8
JB
1413
1414#ifdef HAVE_X11
1415static void
f676886a
JB
1416frame_highlight (frame)
1417 struct frame *frame;
dc6f92b8 1418{
b3e1e05c
JB
1419 /* We used to only do this if Vx_no_window_manager was non-nil, but
1420 the ICCCM (section 4.1.6) says that the window's border pixmap
1421 and border pixel are window attributes which are "private to the
1422 client", so we can always change it to whatever we want. */
1423 BLOCK_INPUT;
1424 XSetWindowBorder (x_current_display, FRAME_X_WINDOW (frame),
1425 frame->display.x->border_pixel);
1426 UNBLOCK_INPUT;
f676886a 1427 x_display_cursor (frame, 1);
dc6f92b8
JB
1428}
1429
1430static void
f676886a
JB
1431frame_unhighlight (frame)
1432 struct frame *frame;
dc6f92b8 1433{
b3e1e05c
JB
1434 /* We used to only do this if Vx_no_window_manager was non-nil, but
1435 the ICCCM (section 4.1.6) says that the window's border pixmap
1436 and border pixel are window attributes which are "private to the
1437 client", so we can always change it to whatever we want. */
1438 BLOCK_INPUT;
1439 XSetWindowBorderPixmap (x_current_display, FRAME_X_WINDOW (frame),
1440 frame->display.x->border_tile);
1441 UNBLOCK_INPUT;
f676886a 1442 x_display_cursor (frame, 1);
dc6f92b8 1443}
c118dd06 1444#else /* ! defined (HAVE_X11) */
f676886a
JB
1445/* Dump the border-emphasis of frame F.
1446 If F is selected, this is a lining of the same color as the border,
dc6f92b8 1447 just within the border, occupying a portion of the internal border.
f676886a 1448 If F is not selected, it is background in the same place.
dc6f92b8
JB
1449 If ALWAYS is 0, don't bother explicitly drawing if it's background.
1450
f676886a 1451 ALWAYS = 1 is used when a frame becomes selected or deselected.
dc6f92b8
JB
1452 In that case, we also turn the cursor off and on again
1453 so it will appear in the proper shape (solid if selected; else hollow.) */
1454
1455static void
f676886a
JB
1456dumpborder (f, always)
1457 struct frame *f;
dc6f92b8
JB
1458 int always;
1459{
f676886a
JB
1460 int thickness = f->display.x->internal_border_width / 2;
1461 int width = PIXEL_WIDTH (f);
1462 int height = PIXEL_HEIGHT (f);
dc6f92b8
JB
1463 int pixel;
1464
f676886a 1465 if (f != selected_frame)
dc6f92b8
JB
1466 {
1467 if (!always)
1468 return;
1469
f676886a 1470 pixel = f->display.x->background_pixel;
dc6f92b8
JB
1471 }
1472 else
1473 {
f676886a 1474 pixel = f->display.x->border_pixel;
dc6f92b8
JB
1475 }
1476
c118dd06
JB
1477 XPixSet (FRAME_X_WINDOW (f), 0, 0, width, thickness, pixel);
1478 XPixSet (FRAME_X_WINDOW (f), 0, 0, thickness, height, pixel);
1479 XPixSet (FRAME_X_WINDOW (f), 0, height - thickness, width,
dc6f92b8 1480 thickness, pixel);
c118dd06 1481 XPixSet (FRAME_X_WINDOW (f), width - thickness, 0, thickness,
dc6f92b8
JB
1482 height, pixel);
1483
1484 if (always)
f676886a 1485 x_display_cursor (f, 1);
dc6f92b8 1486}
c118dd06 1487#endif /* ! defined (HAVE_X11) */
dc6f92b8 1488
f676886a 1489static void XTframe_rehighlight ();
6d4238f3 1490
f676886a
JB
1491/* The focus has changed. Update the frames as necessary to reflect
1492 the new situation. Note that we can't change the selected frame
dc6f92b8 1493 here, because the lisp code we are interrupting might become confused.
eb8c3be9 1494 Each event gets marked with the frame in which it occurred, so the
6d4238f3 1495 lisp code can tell when the switch took place by examining the events. */
dc6f92b8 1496
6d4238f3 1497static void
f676886a
JB
1498x_new_focus_frame (frame)
1499 struct frame *frame;
dc6f92b8 1500{
f676886a 1501 struct frame *old_focus = x_focus_frame;
dc6f92b8
JB
1502 int events_enqueued = 0;
1503
f676886a 1504 if (frame != x_focus_frame)
dc6f92b8 1505 {
6d4238f3 1506 /* Set this before calling other routines, so that they see
f676886a
JB
1507 the correct value of x_focus_frame. */
1508 x_focus_frame = frame;
6d4238f3
JB
1509
1510 if (old_focus && old_focus->auto_lower)
f676886a 1511 x_lower_frame (old_focus);
dc6f92b8
JB
1512
1513#if 0
f676886a
JB
1514 selected_frame = frame;
1515 XSET (XWINDOW (selected_frame->selected_window)->frame,
1516 Lisp_Frame, selected_frame);
1517 Fselect_window (selected_frame->selected_window);
1518 choose_minibuf_frame ();
c118dd06 1519#endif /* ! 0 */
dc6f92b8 1520
f676886a
JB
1521 if (x_focus_frame && x_focus_frame->auto_raise)
1522 x_raise_frame (x_focus_frame);
6d4238f3 1523 }
dc6f92b8 1524
f676886a 1525 XTframe_rehighlight ();
6d4238f3
JB
1526}
1527
1528
f451eb13
JB
1529/* The focus has changed, or we have redirected a frame's focus to
1530 another frame (this happens when a frame uses a surrogate
1531 minibuffer frame). Shift the highlight as appropriate. */
6d4238f3 1532static void
f676886a 1533XTframe_rehighlight ()
6d4238f3 1534{
f676886a 1535 struct frame *old_highlight = x_highlight_frame;
6d4238f3 1536
f676886a 1537 if (x_focus_frame)
6d4238f3 1538 {
f451eb13 1539 x_highlight_frame =
ab648270 1540 ((XGCTYPE (FRAME_FOCUS_FRAME (x_focus_frame)) == Lisp_Frame)
f451eb13
JB
1541 ? XFRAME (FRAME_FOCUS_FRAME (x_focus_frame))
1542 : x_focus_frame);
1543 if (! FRAME_LIVE_P (x_highlight_frame))
1544 {
1545 FRAME_FOCUS_FRAME (x_focus_frame) = Qnil;
1546 x_highlight_frame = x_focus_frame;
1547 }
dc6f92b8 1548 }
6d4238f3 1549 else
f676886a 1550 x_highlight_frame = 0;
dc6f92b8 1551
f676886a 1552 if (x_highlight_frame != old_highlight)
6d4238f3
JB
1553 {
1554 if (old_highlight)
f676886a
JB
1555 frame_unhighlight (old_highlight);
1556 if (x_highlight_frame)
1557 frame_highlight (x_highlight_frame);
6d4238f3 1558 }
dc6f92b8
JB
1559}
1560\f
e4571a43 1561/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 1562
28430d3c
JB
1563/* Which modifier keys are on which modifier bits?
1564
1565 With each keystroke, X returns eight bits indicating which modifier
11edeb03
JB
1566 keys were held down when the key was pressed. The interpretation
1567 of the top five modifier bits depends on what keys are attached
28430d3c
JB
1568 to them. If the Meta_L and Meta_R keysyms are on mod5, then mod5
1569 is the meta bit.
1570
1571 x_meta_mod_mask is a mask containing the bits used for the meta key.
1572 It may have more than one bit set, if more than one modifier bit
1573 has meta keys on it. Basically, if EVENT is a KeyPress event,
11edeb03
JB
1574 the meta key is pressed if (EVENT.state & x_meta_mod_mask) != 0.
1575
1576 x_shift_lock_mask is LockMask if the XK_Shift_Lock keysym is on the
1577 lock modifier bit, or zero otherwise. Non-alphabetic keys should
1578 only be affected by the lock modifier bit if XK_Shift_Lock is in
1579 use; XK_Caps_Lock should only affect alphabetic keys. With this
1580 arrangement, the lock modifier should shift the character if
1581 (EVENT.state & x_shift_lock_mask) != 0. */
1582static int x_meta_mod_mask, x_shift_lock_mask;
28430d3c 1583
a3c44b14
RS
1584/* These are like x_meta_mod_mask, but for different modifiers. */
1585static int x_alt_mod_mask, x_super_mod_mask, x_hyper_mod_mask;
1586
28430d3c
JB
1587/* Initialize mode_switch_bit and modifier_meaning. */
1588static void
1589x_find_modifier_meanings ()
1590{
f689eb05 1591 int min_code, max_code;
28430d3c
JB
1592 KeySym *syms;
1593 int syms_per_code;
1594 XModifierKeymap *mods;
1595
1596 x_meta_mod_mask = 0;
11edeb03 1597 x_shift_lock_mask = 0;
a3c44b14
RS
1598 x_alt_mod_mask = 0;
1599 x_super_mod_mask = 0;
1600 x_hyper_mod_mask = 0;
28430d3c 1601
9658a521 1602#ifdef HAVE_X11R4
28430d3c 1603 XDisplayKeycodes (x_current_display, &min_code, &max_code);
9658a521
JB
1604#else
1605 min_code = x_current_display->min_keycode;
1606 max_code = x_current_display->max_keycode;
1607#endif
1608
28430d3c
JB
1609 syms = XGetKeyboardMapping (x_current_display,
1610 min_code, max_code - min_code + 1,
1611 &syms_per_code);
1612 mods = XGetModifierMapping (x_current_display);
1613
11edeb03
JB
1614 /* Scan the modifier table to see which modifier bits the Meta and
1615 Alt keysyms are on. */
28430d3c
JB
1616 {
1617 int row, col; /* The row and column in the modifier table. */
1618
1619 for (row = 3; row < 8; row++)
1620 for (col = 0; col < mods->max_keypermod; col++)
1621 {
1622 KeyCode code =
1623 mods->modifiermap[(row * mods->max_keypermod) + col];
1624
af92970c
KH
1625 /* Zeroes are used for filler. Skip them. */
1626 if (code == 0)
1627 continue;
1628
28430d3c
JB
1629 /* Are any of this keycode's keysyms a meta key? */
1630 {
1631 int code_col;
1632
1633 for (code_col = 0; code_col < syms_per_code; code_col++)
1634 {
f689eb05 1635 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 1636
f689eb05 1637 switch (sym)
28430d3c 1638 {
f689eb05
JB
1639 case XK_Meta_L:
1640 case XK_Meta_R:
28430d3c
JB
1641 x_meta_mod_mask |= (1 << row);
1642 break;
f689eb05
JB
1643
1644 case XK_Alt_L:
1645 case XK_Alt_R:
a3c44b14
RS
1646 x_alt_mod_mask |= (1 << row);
1647 break;
1648
1649 case XK_Hyper_L:
1650 case XK_Hyper_R:
1651 x_hyper_mod_mask |= (1 << row);
1652 break;
1653
1654 case XK_Super_L:
1655 case XK_Super_R:
1656 x_super_mod_mask |= (1 << row);
f689eb05 1657 break;
11edeb03
JB
1658
1659 case XK_Shift_Lock:
1660 /* Ignore this if it's not on the lock modifier. */
1661 if ((1 << row) == LockMask)
1662 x_shift_lock_mask = LockMask;
1663 break;
28430d3c
JB
1664 }
1665 }
1666 }
1667 }
1668 }
1669
f689eb05
JB
1670 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
1671 if (! x_meta_mod_mask)
a3c44b14
RS
1672 {
1673 x_meta_mod_mask = x_alt_mod_mask;
1674 x_alt_mod_mask = 0;
1675 }
f689eb05 1676
148c4b70
RS
1677 /* If some keys are both alt and meta,
1678 make them just meta, not alt. */
1679 if (x_alt_mod_mask & x_meta_mod_mask)
1680 {
1681 x_alt_mod_mask &= ~x_meta_mod_mask;
1682 }
1683
28430d3c 1684 XFree ((char *) syms);
f689eb05 1685 XFreeModifiermap (mods);
28430d3c
JB
1686}
1687
dfeccd2d
JB
1688/* Convert between the modifier bits X uses and the modifier bits
1689 Emacs uses. */
7c5283e4 1690static unsigned int
dfeccd2d 1691x_x_to_emacs_modifiers (state)
dc6f92b8
JB
1692 unsigned int state;
1693{
11edeb03
JB
1694 return ( ((state & (ShiftMask | x_shift_lock_mask)) ? shift_modifier : 0)
1695 | ((state & ControlMask) ? ctrl_modifier : 0)
a3c44b14
RS
1696 | ((state & x_meta_mod_mask) ? meta_modifier : 0)
1697 | ((state & x_alt_mod_mask) ? alt_modifier : 0)
1698 | ((state & x_super_mod_mask) ? super_modifier : 0)
1699 | ((state & x_hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
1700}
1701
dfeccd2d
JB
1702static unsigned int
1703x_emacs_to_x_modifiers (state)
1704 unsigned int state;
1705{
1706 return ( ((state & alt_modifier) ? x_alt_mod_mask : 0)
1707 | ((state & super_modifier) ? x_super_mod_mask : 0)
1708 | ((state & hyper_modifier) ? x_hyper_mod_mask : 0)
1709 | ((state & shift_modifier) ? ShiftMask : 0)
1710 | ((state & ctrl_modifier) ? ControlMask : 0)
1711 | ((state & meta_modifier) ? x_meta_mod_mask : 0));
1712}
1713
e4571a43
JB
1714/* Return true iff KEYSYM is a vendor-specific keysym that we should
1715 return as a function key. If you add a keysym to this, you should
1716 make sure that the tables make_lispy_event uses contain a suitable
1717 name for it. */
1718static int
1719x_is_vendor_fkey (sym)
1720 KeySym sym;
1721{
1722 return 0
1723#ifdef DXK_Remove
1724 || (sym == DXK_Remove)
1725#endif
1726 ;
1727}
1728
1729\f
1730/* Mouse clicks and mouse movement. Rah. */
1731#ifdef HAVE_X11
1732
1733/* Given a pixel position (PIX_X, PIX_Y) on the frame F, return
1734 glyph co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle
69388238
RS
1735 that the glyph at X, Y occupies, if BOUNDS != 0.
1736 If NOCLIP is nonzero, do not force the value into range. */
1737
c8dba240 1738void
69388238 1739pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 1740 FRAME_PTR f;
69388238 1741 register int pix_x, pix_y;
e4571a43
JB
1742 register int *x, *y;
1743 XRectangle *bounds;
69388238 1744 int noclip;
e4571a43 1745{
69388238
RS
1746 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
1747 even for negative values. */
1748 if (pix_x < 0)
1749 pix_x -= FONT_WIDTH ((f)->display.x->font) - 1;
1750 if (pix_y < 0)
1751 pix_y -= FONT_HEIGHT ((f)->display.x->font) - 1;
1752
e4571a43
JB
1753 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
1754 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
1755
1756 if (bounds)
1757 {
1758 bounds->width = FONT_WIDTH (f->display.x->font);
1759 bounds->height = FONT_HEIGHT (f->display.x->font);
1760 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
1761 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
1762 }
1763
69388238
RS
1764 if (!noclip)
1765 {
1766 if (pix_x < 0)
1767 pix_x = 0;
1768 else if (pix_x > f->width)
1769 pix_x = f->width;
1770
1771 if (pix_y < 0)
1772 pix_y = 0;
1773 else if (pix_y > f->height)
1774 pix_y = f->height;
1775 }
e4571a43
JB
1776
1777 *x = pix_x;
1778 *y = pix_y;
1779}
1780
2b5c9e71
RS
1781void
1782glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1783 FRAME_PTR f;
1784 register int x, y;
1785 register int *pix_x, *pix_y;
1786{
1787 *pix_x = CHAR_TO_PIXEL_COL (f, x);
1788 *pix_y = CHAR_TO_PIXEL_ROW (f, y);
1789}
1790
dc6f92b8
JB
1791/* Prepare a mouse-event in *RESULT for placement in the input queue.
1792
1793 If the event is a button press, then note that we have grabbed
f451eb13 1794 the mouse. */
dc6f92b8
JB
1795
1796static Lisp_Object
f451eb13 1797construct_mouse_click (result, event, f)
dc6f92b8
JB
1798 struct input_event *result;
1799 XButtonEvent *event;
f676886a 1800 struct frame *f;
dc6f92b8 1801{
f451eb13 1802 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 1803 otherwise. */
f451eb13 1804 result->kind = mouse_click;
69388238 1805 result->code = event->button - Button1;
1113d9db 1806 result->timestamp = event->time;
dfeccd2d 1807 result->modifiers = (x_x_to_emacs_modifiers (event->state)
f689eb05
JB
1808 | (event->type == ButtonRelease
1809 ? up_modifier
1810 : down_modifier));
dc6f92b8
JB
1811
1812 /* Notice if the mouse is still grabbed. */
1813 if (event->type == ButtonPress)
1814 {
1815 if (! x_mouse_grabbed)
1816 Vmouse_depressed = Qt;
90e65f07 1817 x_mouse_grabbed |= (1 << event->button);
69388238 1818 last_mouse_frame = f;
dc6f92b8
JB
1819 }
1820 else if (event->type == ButtonRelease)
1821 {
90e65f07 1822 x_mouse_grabbed &= ~(1 << event->button);
dc6f92b8
JB
1823 if (!x_mouse_grabbed)
1824 Vmouse_depressed = Qnil;
1825 }
1826
f451eb13
JB
1827 {
1828 int row, column;
dc6f92b8 1829
2b5c9e71 1830#if 0
69388238 1831 pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL, 0);
f451eb13
JB
1832 XFASTINT (result->x) = column;
1833 XFASTINT (result->y) = row;
2b5c9e71 1834#endif
09fe4c31
RS
1835 XSET (result->x, Lisp_Int, event->x);
1836 XSET (result->y, Lisp_Int, event->y);
12ba150f 1837 XSET (result->frame_or_window, Lisp_Frame, f);
f451eb13 1838 }
dc6f92b8 1839}
b849c413
RS
1840
1841/* Prepare a menu-event in *RESULT for placement in the input queue. */
1842
1843static Lisp_Object
1844construct_menu_click (result, event, f)
1845 struct input_event *result;
1846 XButtonEvent *event;
1847 struct frame *f;
1848{
1849 /* Make the event type no_event; we'll change that when we decide
1850 otherwise. */
1851 result->kind = mouse_click;
1852 XSET (result->code, Lisp_Int, event->button - Button1);
1853 result->timestamp = event->time;
1854 result->modifiers = (x_x_to_emacs_modifiers (event->state)
1855 | (event->type == ButtonRelease
1856 ? up_modifier
1857 : down_modifier));
1858
09fe4c31
RS
1859 XSET (result->x, Lisp_Int, event->x);
1860 XSET (result->y, Lisp_Int, -1);
c8dba240 1861 XSET (result->frame_or_window, Lisp_Frame, f);
b849c413 1862}
69388238 1863\f
90e65f07
JB
1864/* Function to report a mouse movement to the mainstream Emacs code.
1865 The input handler calls this.
1866
1867 We have received a mouse movement event, which is given in *event.
1868 If the mouse is over a different glyph than it was last time, tell
1869 the mainstream emacs code by setting mouse_moved. If not, ask for
1870 another motion event, so we can check again the next time it moves. */
b8009dd1 1871
90e65f07 1872static void
12ba150f 1873note_mouse_movement (frame, event)
f676886a 1874 FRAME_PTR frame;
90e65f07
JB
1875 XMotionEvent *event;
1876
1877{
e5d77022
JB
1878 last_mouse_movement_time = event->time;
1879
90e65f07
JB
1880 /* Has the mouse moved off the glyph it was on at the last sighting? */
1881 if (event->x < last_mouse_glyph.x
1882 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
1883 || event->y < last_mouse_glyph.y
1884 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f
JB
1885 {
1886 mouse_moved = 1;
ab648270 1887 last_mouse_scroll_bar = Qnil;
b8009dd1
RS
1888
1889 note_mouse_highlight (frame, event->x, event->y);
1890
1891 /* Ask for another mouse motion event. */
1892 {
1893 int dummy;
1894
1895 XQueryPointer (event->display, event->window,
1896 (Window *) &dummy, (Window *) &dummy,
1897 &dummy, &dummy, &dummy, &dummy,
1898 (unsigned int *) &dummy);
1899 }
12ba150f 1900 }
90e65f07
JB
1901 else
1902 {
1903 /* It's on the same glyph. Call XQueryPointer so we'll get an
1904 event the next time the mouse moves and we can see if it's
1905 *still* on the same glyph. */
1906 int dummy;
1907
1908 XQueryPointer (event->display, event->window,
1909 (Window *) &dummy, (Window *) &dummy,
1910 &dummy, &dummy, &dummy, &dummy,
1911 (unsigned int *) &dummy);
1912 }
1913}
1914
b8009dd1
RS
1915/* Take proper action when the mouse has moved to position X, Y on frame F
1916 as regards highlighting characters that have mouse-face properties.
1917 Also dehighlighting chars where the mouse was before. */
1918
1919static void
1920note_mouse_highlight (f, x, y)
1921 FRAME_PTR f;
1922{
1923 int row, column, portion;
1924 XRectangle new_glyph;
1925 Lisp_Object window;
1926 struct window *w;
1927
1928 mouse_face_mouse_x = x;
1929 mouse_face_mouse_y = y;
1930 mouse_face_mouse_frame = f;
1931
1932 if (mouse_face_defer)
1933 return;
1934
1935 /* Find out which glyph the mouse is on. */
1936 pixel_to_glyph_coords (f, x, y, &column, &row,
1937 &new_glyph, x_mouse_grabbed);
1938
1939 /* Which window is that in? */
1940 window = window_from_coordinates (f, column, row, &portion);
1941 w = XWINDOW (window);
1942
1943 /* If we were displaying active text in another window, clear that. */
1944 if (! EQ (window, mouse_face_window))
1945 clear_mouse_face ();
1946
1947 /* Are we in a window whose display is up to date? */
1948 if (WINDOWP (window) && portion == 0
1949 && EQ (w->window_end_valid, Qt))
1950 {
1951 int *ptr = FRAME_CURRENT_GLYPHS (f)->charstarts[row];
1952 int i, pos;
1953
1954 /* Find which buffer position the mouse corresponds to. */
1955 for (i = column; i >= 0; i--)
1956 if (ptr[i] > 0)
1957 break;
1958 pos = ptr[i];
1959 /* Is it outside the displayed active region (if any)? */
1960 if (pos > 0
1961 && ! (EQ (window, mouse_face_window)
1962 && pos >= mouse_face_beg && pos < mouse_face_end))
1963 {
1964 Lisp_Object mouse_face, overlay, position;
1965 Lisp_Object *overlay_vec;
1966 int len, noverlays, ignor1;
1967
09fe4c31
RS
1968 /* Make the window's buffer temporarily current for
1969 overlays_at and compute_char_face. */
1970 struct buffer *obuf = current_buffer;
1971 current_buffer = XBUFFER (w->buffer);
1972
b8009dd1
RS
1973 /* Yes. Clear the display of the old active region, if any. */
1974 clear_mouse_face ();
1975
1976 /* Is this char mouse-active? */
1977 XSET (position, Lisp_Int, pos);
1978
1979 len = 10;
1980 overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
1981
1982 /* Put all the overlays we want in a vector in overlay_vec.
1983 Store the length in len. */
1984 noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len, &ignor1);
09fe4c31 1985 noverlays = sort_overlays (overlay_vec, noverlays, w);
b8009dd1
RS
1986
1987 /* Find the highest priority overlay that has a mouse-face prop. */
1988 overlay = Qnil;
1989 for (i = 0; i < noverlays; i++)
1990 {
1991 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1992 if (!NILP (mouse_face))
1993 {
1994 overlay = overlay_vec[i];
1995 break;
1996 }
1997 }
1998 free (overlay_vec);
1999 /* If no overlay applies, get a text property. */
2000 if (NILP (overlay))
2001 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
2002
2003 /* Handle the overlay case. */
2004 if (! NILP (overlay))
2005 {
2006 /* Find the range of text around this char that
2007 should be active. */
2008 Lisp_Object before, after;
2009 int ignore;
2010
2011 before = Foverlay_start (overlay);
2012 after = Foverlay_end (overlay);
2013 /* Record this as the current active region. */
2014 mouse_face_beg = XFASTINT (before);
2015 mouse_face_end = XFASTINT (after);
2016 mouse_face_window = window;
2017 mouse_face_face_id = compute_char_face (f, w, pos, 0, 0,
2018 &ignore, pos + 1, 1);
2019
2020 /* Display it as active. */
2021 show_mouse_face (1);
2022 }
2023 /* Handle the text property case. */
2024 else if (! NILP (mouse_face))
2025 {
2026 /* Find the range of text around this char that
2027 should be active. */
2028 Lisp_Object before, after, beginning, end;
2029 int ignore;
2030
2031 beginning = Fmarker_position (w->start);
2032 XSET (end, Lisp_Int,
09fe4c31 2033 (BUF_Z (XBUFFER (w->buffer))
b8009dd1
RS
2034 - XFASTINT (w->window_end_pos)));
2035 before
2036 = Fprevious_single_property_change (make_number (pos + 1),
2037 Qmouse_face,
2038 w->buffer, beginning);
2039 after
2040 = Fnext_single_property_change (position, Qmouse_face,
2041 w->buffer, end);
2042 /* Record this as the current active region. */
2043 mouse_face_beg = XFASTINT (before);
2044 mouse_face_end = XFASTINT (after);
2045 mouse_face_window = window;
2046 mouse_face_face_id
2047 = compute_char_face (f, w, pos, 0, 0,
2048 &ignore, pos + 1, 1);
2049
2050 /* Display it as active. */
2051 show_mouse_face (1);
2052 }
09fe4c31 2053 current_buffer = obuf;
b8009dd1
RS
2054 }
2055 else if (pos <= 0)
2056 clear_mouse_face ();
2057 }
2058}
2059\f
2060/* Find the row and column of position POS in window WINDOW.
2061 Store them in *COLUMNP and *ROWP.
2062 This assumes display in WINDOW is up to date. */
2063
2064static int
2065fast_find_position (window, pos, columnp, rowp)
2066 Lisp_Object window;
2067 int pos;
2068 int *columnp, *rowp;
2069{
2070 struct window *w = XWINDOW (window);
2071 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2072 int i;
2073 int row;
2074 int left = w->left;
2075 int top = w->top;
2076 int height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
2077 int width = window_internal_width (w);
2078 int *charstarts;
2079
2080 for (i = 0;
2081 i < height;
2082 i++)
2083 {
2084 int linestart = FRAME_CURRENT_GLYPHS (f)->charstarts[top + i][left];
2085 if (linestart > pos)
2086 break;
2087 if (linestart > 0)
2088 row = i;
2089 }
2090
2091 charstarts = FRAME_CURRENT_GLYPHS (f)->charstarts[top + row];
2092 for (i = 0; i < width; i++)
2093 if (charstarts[left + i] == pos)
2094 {
2095 *rowp = row + top;
2096 *columnp = i + left;
2097 return 1;
2098 }
2099
2100 return 0;
2101}
2102
2103/* Display the active region described by mouse_face_*
2104 in its mouse-face if HL > 0, in its normal face if HL = 0. */
2105
2106static void
2107show_mouse_face (hl)
2108 int hl;
2109{
2110 int begcol, begrow, endcol, endrow;
2111 struct window *w = XWINDOW (mouse_face_window);
2112 int width = window_internal_width (w);
2113 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2114 int i;
2115
2116 fast_find_position (mouse_face_window, mouse_face_beg,
2117 &begcol, &begrow);
2118 fast_find_position (mouse_face_window, mouse_face_end,
2119 &endcol, &endrow);
2120
2121 x_display_cursor (f, 0);
2122
2123 for (i = begrow; i <= endrow; i++)
2124 {
2125 int column = (i == begrow ? begcol : w->left);
2126 int endcolumn = (i == endrow ? endcol : w->left + width);
2127 endcolumn = min (endcolumn, FRAME_CURRENT_GLYPHS (f)->used[i] - w->left),
2128
2129 dumpglyphs (f,
2130 CHAR_TO_PIXEL_COL (f, column),
2131 CHAR_TO_PIXEL_ROW (f, i),
2132 FRAME_CURRENT_GLYPHS (f)->glyphs[i] + column,
2133 endcolumn - column,
2134 /* Highlight with mouse face if hl > 0. */
2135 hl > 0 ? 3 : 0);
2136 }
2137
2138 x_display_cursor (f, 1);
2139}
2140
2141/* Clear out the mouse-highlighted active region.
2142 Redraw it unhighlighted first. */
2143
2144static void
2145clear_mouse_face ()
2146{
2147 if (! NILP (mouse_face_window))
2148 show_mouse_face (0);
2149
2150 mouse_face_beg = -1;
2151 mouse_face_end = -1;
2152 mouse_face_window = Qnil;
2153}
2154\f
ab648270
JB
2155static struct scroll_bar *x_window_to_scroll_bar ();
2156static void x_scroll_bar_report_motion ();
12ba150f 2157
90e65f07
JB
2158/* Return the current position of the mouse.
2159
ab648270
JB
2160 If the mouse movement started in a scroll bar, set *f, *bar_window,
2161 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 2162 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 2163 position on the scroll bar.
12ba150f
JB
2164
2165 If the mouse movement started elsewhere, set *f to the frame the
2166 mouse is on, *bar_window to nil, and *x and *y to the character cell
2167 the mouse is over.
2168
2169 Set *time to the server timestamp for the time at which the mouse
2170 was at this position.
2171
a135645a
RS
2172 Don't store anything if we don't have a valid set of values to report.
2173
90e65f07 2174 This clears the mouse_moved flag, so we can wait for the next mouse
12ba150f
JB
2175 movement. This also calls XQueryPointer, which will cause the
2176 server to give us another MotionNotify when the mouse moves
2177 again. */
90e65f07
JB
2178
2179static void
12ba150f 2180XTmouse_position (f, bar_window, part, x, y, time)
472895ad 2181 FRAME_PTR *f;
12ba150f 2182 Lisp_Object *bar_window;
ab648270 2183 enum scroll_bar_part *part;
90e65f07 2184 Lisp_Object *x, *y;
e5d77022 2185 unsigned long *time;
90e65f07 2186{
a135645a
RS
2187 FRAME_PTR f1;
2188
90e65f07
JB
2189 BLOCK_INPUT;
2190
ab648270
JB
2191 if (! NILP (last_mouse_scroll_bar))
2192 x_scroll_bar_report_motion (f, bar_window, part, x, y, time);
90e65f07
JB
2193 else
2194 {
12ba150f
JB
2195 Window root;
2196 int root_x, root_y;
90e65f07 2197
12ba150f
JB
2198 Window dummy_window;
2199 int dummy;
2200
2201 mouse_moved = 0;
ab648270 2202 last_mouse_scroll_bar = Qnil;
12ba150f
JB
2203
2204 /* Figure out which root window we're on. */
2205 XQueryPointer (x_current_display,
2206 DefaultRootWindow (x_current_display),
2207
2208 /* The root window which contains the pointer. */
2209 &root,
2210
2211 /* Trash which we can't trust if the pointer is on
2212 a different screen. */
2213 &dummy_window,
2214
2215 /* The position on that root window. */
2216 &root_x, &root_y,
2217
2218 /* More trash we can't trust. */
2219 &dummy, &dummy,
2220
2221 /* Modifier keys and pointer buttons, about which
2222 we don't care. */
2223 (unsigned int *) &dummy);
2224
2225 /* Now we have a position on the root; find the innermost window
2226 containing the pointer. */
2227 {
2228 Window win, child;
2229 int win_x, win_y;
2230 int parent_x, parent_y;
2231
2232 win = root;
69388238
RS
2233
2234 if (x_mouse_grabbed)
12ba150f 2235 {
69388238
RS
2236 /* If mouse was grabbed on a frame, give coords for that frame
2237 even if the mouse is now outside it. */
12ba150f 2238 XTranslateCoordinates (x_current_display,
69388238 2239
12ba150f 2240 /* From-window, to-window. */
69388238 2241 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
2242
2243 /* From-position, to-position. */
2244 root_x, root_y, &win_x, &win_y,
2245
2246 /* Child of win. */
2247 &child);
69388238
RS
2248 f1 = last_mouse_frame;
2249 }
2250 else
2251 {
2252 while (1)
2253 {
2254 XTranslateCoordinates (x_current_display,
12ba150f 2255
69388238
RS
2256 /* From-window, to-window. */
2257 root, win,
12ba150f 2258
69388238
RS
2259 /* From-position, to-position. */
2260 root_x, root_y, &win_x, &win_y,
2261
2262 /* Child of win. */
2263 &child);
2264
2265 if (child == None)
2266 break;
2267
2268 win = child;
2269 parent_x = win_x;
2270 parent_y = win_y;
2271 }
12ba150f 2272
69388238
RS
2273 /* Now we know that:
2274 win is the innermost window containing the pointer
2275 (XTC says it has no child containing the pointer),
2276 win_x and win_y are the pointer's position in it
2277 (XTC did this the last time through), and
2278 parent_x and parent_y are the pointer's position in win's parent.
2279 (They are what win_x and win_y were when win was child.
2280 If win is the root window, it has no parent, and
2281 parent_{x,y} are invalid, but that's okay, because we'll
2282 never use them in that case.) */
2283
2284 /* Is win one of our frames? */
2b5c9e71 2285 f1 = x_any_window_to_frame (win);
69388238 2286 }
12ba150f 2287
ab648270 2288 /* If not, is it one of our scroll bars? */
a135645a 2289 if (! f1)
12ba150f 2290 {
ab648270 2291 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
2292
2293 if (bar)
2294 {
a135645a 2295 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
2296 win_x = parent_x;
2297 win_y = parent_y;
2298 }
2299 }
90e65f07 2300
a135645a 2301 if (f1)
12ba150f 2302 {
2b5c9e71
RS
2303 int ignore1, ignore2;
2304
2305 /* Ok, we found a frame. Store all the values. */
a135645a 2306
2b5c9e71 2307 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
69388238 2308 &last_mouse_glyph, x_mouse_grabbed);
12ba150f
JB
2309
2310 *bar_window = Qnil;
2311 *part = 0;
a135645a 2312 *f = f1;
12ba150f
JB
2313 XSET (*x, Lisp_Int, win_x);
2314 XSET (*y, Lisp_Int, win_y);
2315 *time = last_mouse_movement_time;
2316 }
2317 }
2318 }
90e65f07
JB
2319
2320 UNBLOCK_INPUT;
2321}
2322
c118dd06 2323#else /* ! defined (HAVE_X11) */
dc6f92b8 2324#define XEvent XKeyPressedEvent
c118dd06
JB
2325#endif /* ! defined (HAVE_X11) */
2326\f
ab648270 2327/* Scroll bar support. */
f451eb13 2328
ab648270
JB
2329/* Given an X window ID, find the struct scroll_bar which manages it.
2330 This can be called in GC, so we have to make sure to strip off mark
2331 bits. */
2332static struct scroll_bar *
2333x_window_to_scroll_bar (window_id)
f451eb13
JB
2334 Window window_id;
2335{
2336 Lisp_Object tail, frame;
f451eb13 2337
ab648270
JB
2338 for (tail = Vframe_list;
2339 XGCTYPE (tail) == Lisp_Cons;
2340 tail = XCONS (tail)->cdr)
f451eb13 2341 {
abdda982 2342 Lisp_Object frame, bar, condemned;
f451eb13 2343
abdda982 2344 frame = XCONS (tail)->car;
f451eb13 2345 /* All elements of Vframe_list should be frames. */
ab648270 2346 if (XGCTYPE (frame) != Lisp_Frame)
f451eb13
JB
2347 abort ();
2348
ab648270 2349 /* Scan this frame's scroll bar list for a scroll bar with the
f451eb13 2350 right window ID. */
ab648270
JB
2351 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
2352 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
cf7cb199 2353 /* This trick allows us to search both the ordinary and
ab648270
JB
2354 condemned scroll bar lists with one loop. */
2355 ! GC_NILP (bar) || (bar = condemned,
2356 condemned = Qnil,
2357 ! GC_NILP (bar));
bc20ebbf 2358 bar = XSCROLL_BAR (bar)->next)
ab648270
JB
2359 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
2360 return XSCROLL_BAR (bar);
f451eb13
JB
2361 }
2362
2363 return 0;
2364}
2365
ab648270
JB
2366/* Open a new X window to serve as a scroll bar, and return the
2367 scroll bar vector for it. */
2368static struct scroll_bar *
2369x_scroll_bar_create (window, top, left, width, height)
12ba150f 2370 struct window *window;
f451eb13
JB
2371 int top, left, width, height;
2372{
12ba150f 2373 FRAME_PTR frame = XFRAME (WINDOW_FRAME (window));
ab648270
JB
2374 struct scroll_bar *bar =
2375 XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
2376
2377 BLOCK_INPUT;
2378
2379 {
2380 XSetWindowAttributes a;
2381 unsigned long mask;
12ba150f
JB
2382 a.background_pixel = frame->display.x->background_pixel;
2383 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 2384 | ButtonMotionMask | PointerMotionHintMask
12ba150f 2385 | ExposureMask);
ab648270 2386 a.cursor = x_vertical_scroll_bar_cursor;
f451eb13 2387
dbc4e1c1 2388 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 2389
3afe33e7
RS
2390#if 0
2391
2392 ac = 0;
2393 XtSetArg (al[ac], XtNx, left); ac++;
2394 XtSetArg (al[ac], XtNy, top); ac++;
2395 XtSetArg (al[ac], XtNwidth, width); ac++;
2396 XtSetArg (al[ac], XtNheight, height); ac++;
2397 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
2398 sb_widget = XtCreateManagedWidget ("box",
7246d1d3
KH
2399 boxWidgetClass,
2400 frame->display.x->edit_widget, al, ac);
2401 SET_SCROLL_BAR_X_WINDOW
3afe33e7
RS
2402 (bar, sb_widget->core.window);
2403#endif
7246d1d3 2404 SET_SCROLL_BAR_X_WINDOW
12ba150f
JB
2405 (bar,
2406 XCreateWindow (x_current_display, FRAME_X_WINDOW (frame),
f451eb13 2407
ab648270 2408 /* Position and size of scroll bar. */
12ba150f 2409 left, top, width, height,
f451eb13 2410
12ba150f
JB
2411 /* Border width, depth, class, and visual. */
2412 0, CopyFromParent, CopyFromParent, CopyFromParent,
f451eb13 2413
12ba150f
JB
2414 /* Attributes. */
2415 mask, &a));
f451eb13
JB
2416 }
2417
12ba150f
JB
2418 XSET (bar->window, Lisp_Window, window);
2419 XSET (bar->top, Lisp_Int, top);
2420 XSET (bar->left, Lisp_Int, left);
2421 XSET (bar->width, Lisp_Int, width);
2422 XSET (bar->height, Lisp_Int, height);
2423 XSET (bar->start, Lisp_Int, 0);
2424 XSET (bar->end, Lisp_Int, 0);
2425 bar->dragging = Qnil;
f451eb13
JB
2426
2427 /* Add bar to its frame's list of scroll bars. */
ab648270 2428 bar->next = FRAME_SCROLL_BARS (frame);
12ba150f 2429 bar->prev = Qnil;
ab648270 2430 XSET (FRAME_SCROLL_BARS (frame), Lisp_Vector, bar);
12ba150f 2431 if (! NILP (bar->next))
ab648270 2432 XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
f451eb13 2433
ab648270 2434 XMapWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
f451eb13
JB
2435
2436 UNBLOCK_INPUT;
12ba150f
JB
2437
2438 return bar;
f451eb13
JB
2439}
2440
12ba150f
JB
2441/* Draw BAR's handle in the proper position.
2442 If the handle is already drawn from START to END, don't bother
2443 redrawing it, unless REBUILD is non-zero; in that case, always
2444 redraw it. (REBUILD is handy for drawing the handle after expose
2445 events.)
2446
2447 Normally, we want to constrain the start and end of the handle to
ab648270 2448 fit inside its rectangle, but if the user is dragging the scroll bar
12ba150f
JB
2449 handle, we want to let them drag it down all the way, so that the
2450 bar's top is as far down as it goes; otherwise, there's no way to
2451 move to the very end of the buffer. */
f451eb13 2452static void
ab648270
JB
2453x_scroll_bar_set_handle (bar, start, end, rebuild)
2454 struct scroll_bar *bar;
f451eb13 2455 int start, end;
12ba150f 2456 int rebuild;
f451eb13 2457{
12ba150f 2458 int dragging = ! NILP (bar->dragging);
ab648270 2459 Window w = SCROLL_BAR_X_WINDOW (bar);
12ba150f
JB
2460 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
2461
2462 /* If the display is already accurate, do nothing. */
2463 if (! rebuild
2464 && start == XINT (bar->start)
2465 && end == XINT (bar->end))
2466 return;
2467
f451eb13
JB
2468 BLOCK_INPUT;
2469
2470 {
ab648270
JB
2471 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (XINT (bar->width));
2472 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2473 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
f451eb13
JB
2474
2475 /* Make sure the values are reasonable, and try to preserve
2476 the distance between start and end. */
12ba150f
JB
2477 {
2478 int length = end - start;
2479
2480 if (start < 0)
2481 start = 0;
2482 else if (start > top_range)
2483 start = top_range;
2484 end = start + length;
2485
2486 if (end < start)
2487 end = start;
2488 else if (end > top_range && ! dragging)
2489 end = top_range;
2490 }
f451eb13 2491
ab648270 2492 /* Store the adjusted setting in the scroll bar. */
12ba150f
JB
2493 XSET (bar->start, Lisp_Int, start);
2494 XSET (bar->end, Lisp_Int, end);
f451eb13 2495
12ba150f
JB
2496 /* Clip the end position, just for display. */
2497 if (end > top_range)
2498 end = top_range;
f451eb13 2499
ab648270 2500 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
2501 below top positions, to make sure the handle is always at least
2502 that many pixels tall. */
ab648270 2503 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 2504
12ba150f
JB
2505 /* Draw the empty space above the handle. Note that we can't clear
2506 zero-height areas; that means "clear to end of window." */
2507 if (0 < start)
2508 XClearArea (x_current_display, w,
f451eb13 2509
12ba150f 2510 /* x, y, width, height, and exposures. */
ab648270
JB
2511 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2512 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
2513 inside_width, start,
2514 False);
f451eb13 2515
12ba150f
JB
2516 /* Draw the handle itself. */
2517 XFillRectangle (x_current_display, w, gc,
f451eb13 2518
12ba150f 2519 /* x, y, width, height */
ab648270
JB
2520 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2521 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 2522 inside_width, end - start);
f451eb13 2523
f451eb13 2524
12ba150f
JB
2525 /* Draw the empty space below the handle. Note that we can't
2526 clear zero-height areas; that means "clear to end of window." */
2527 if (end < inside_height)
2528 XClearArea (x_current_display, w,
f451eb13 2529
12ba150f 2530 /* x, y, width, height, and exposures. */
ab648270
JB
2531 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2532 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
2533 inside_width, inside_height - end,
2534 False);
f451eb13 2535
f451eb13
JB
2536 }
2537
f451eb13
JB
2538 UNBLOCK_INPUT;
2539}
2540
eb8c3be9 2541/* Move a scroll bar around on the screen, to accommodate changing
12ba150f 2542 window configurations. */
f451eb13 2543static void
ab648270
JB
2544x_scroll_bar_move (bar, top, left, width, height)
2545 struct scroll_bar *bar;
f451eb13
JB
2546 int top, left, width, height;
2547{
2548 BLOCK_INPUT;
2549
2550 {
2551 XWindowChanges wc;
2552 unsigned int mask = 0;
2553
2554 wc.x = left;
2555 wc.y = top;
2556 wc.width = width;
2557 wc.height = height;
2558
12ba150f
JB
2559 if (left != XINT (bar->left)) mask |= CWX;
2560 if (top != XINT (bar->top)) mask |= CWY;
2561 if (width != XINT (bar->width)) mask |= CWWidth;
2562 if (height != XINT (bar->height)) mask |= CWHeight;
2563
2564 if (mask)
ab648270 2565 XConfigureWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar),
12ba150f 2566 mask, &wc);
f451eb13
JB
2567 }
2568
12ba150f
JB
2569 XSET (bar->left, Lisp_Int, left);
2570 XSET (bar->top, Lisp_Int, top);
2571 XSET (bar->width, Lisp_Int, width);
2572 XSET (bar->height, Lisp_Int, height);
2573
f451eb13
JB
2574 UNBLOCK_INPUT;
2575}
2576
ab648270 2577/* Destroy the X window for BAR, and set its Emacs window's scroll bar
12ba150f
JB
2578 to nil. */
2579static void
ab648270
JB
2580x_scroll_bar_remove (bar)
2581 struct scroll_bar *bar;
12ba150f
JB
2582{
2583 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2584
2585 BLOCK_INPUT;
2586
2587 /* Destroy the window. */
ab648270 2588 XDestroyWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
12ba150f 2589
ab648270
JB
2590 /* Disassociate this scroll bar from its window. */
2591 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
2592
2593 UNBLOCK_INPUT;
2594}
2595
2596/* Set the handle of the vertical scroll bar for WINDOW to indicate
2597 that we are displaying PORTION characters out of a total of WHOLE
ab648270 2598 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f
JB
2599 create one. */
2600static void
ab648270 2601XTset_vertical_scroll_bar (window, portion, whole, position)
f451eb13
JB
2602 struct window *window;
2603 int portion, whole, position;
2604{
2605 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
f451eb13 2606 int top = XINT (window->top);
ab648270
JB
2607 int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
2608 int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
f451eb13 2609
ab648270 2610 /* Where should this scroll bar be, pixelwise? */
12ba150f
JB
2611 int pixel_top = CHAR_TO_PIXEL_ROW (f, top);
2612 int pixel_left = CHAR_TO_PIXEL_COL (f, left);
ab648270
JB
2613 int pixel_width = VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f);
2614 int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
f451eb13 2615
ab648270 2616 struct scroll_bar *bar;
12ba150f 2617
ab648270
JB
2618 /* Does the scroll bar exist yet? */
2619 if (NILP (window->vertical_scroll_bar))
2620 bar = x_scroll_bar_create (window,
f451eb13
JB
2621 pixel_top, pixel_left,
2622 pixel_width, pixel_height);
2623 else
12ba150f
JB
2624 {
2625 /* It may just need to be moved and resized. */
ab648270
JB
2626 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2627 x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
12ba150f 2628 }
f451eb13 2629
ab648270 2630 /* Set the scroll bar's current state, unless we're currently being
f451eb13 2631 dragged. */
12ba150f 2632 if (NILP (bar->dragging))
f451eb13 2633 {
12ba150f 2634 int top_range =
ab648270 2635 VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
f451eb13 2636
12ba150f 2637 if (whole == 0)
ab648270 2638 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
2639 else
2640 {
43f868f5
JB
2641 int start = ((double) position * top_range) / whole;
2642 int end = ((double) (position + portion) * top_range) / whole;
12ba150f 2643
ab648270 2644 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 2645 }
f451eb13
JB
2646 }
2647
ab648270 2648 XSET (window->vertical_scroll_bar, Lisp_Vector, bar);
f451eb13
JB
2649}
2650
12ba150f 2651
f451eb13 2652/* The following three hooks are used when we're doing a thorough
ab648270 2653 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 2654 are going to be deleted, because keeping track of when windows go
12ba150f
JB
2655 away is a real pain - "Can you say set-window-configuration, boys
2656 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 2657 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 2658 from the fiery pit when we actually redisplay its window. */
f451eb13 2659
ab648270
JB
2660/* Arrange for all scroll bars on FRAME to be removed at the next call
2661 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
2662 `*redeem_scroll_bar_hook' is applied to its window before the judgement. */
f451eb13 2663static void
ab648270 2664XTcondemn_scroll_bars (frame)
f451eb13
JB
2665 FRAME_PTR frame;
2666{
12ba150f
JB
2667 /* The condemned list should be empty at this point; if it's not,
2668 then the rest of Emacs isn't using the condemn/redeem/judge
2669 protocol correctly. */
ab648270 2670 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
12ba150f
JB
2671 abort ();
2672
2673 /* Move them all to the "condemned" list. */
ab648270
JB
2674 FRAME_CONDEMNED_SCROLL_BARS (frame) = FRAME_SCROLL_BARS (frame);
2675 FRAME_SCROLL_BARS (frame) = Qnil;
f451eb13
JB
2676}
2677
ab648270 2678/* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
12ba150f 2679 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 2680static void
ab648270 2681XTredeem_scroll_bar (window)
12ba150f 2682 struct window *window;
f451eb13 2683{
ab648270 2684 struct scroll_bar *bar;
12ba150f 2685
ab648270
JB
2686 /* We can't redeem this window's scroll bar if it doesn't have one. */
2687 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
2688 abort ();
2689
ab648270 2690 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
2691
2692 /* Unlink it from the condemned list. */
2693 {
2694 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2695
2696 if (NILP (bar->prev))
2697 {
2698 /* If the prev pointer is nil, it must be the first in one of
2699 the lists. */
ab648270 2700 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
2701 /* It's not condemned. Everything's fine. */
2702 return;
ab648270
JB
2703 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
2704 window->vertical_scroll_bar))
2705 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
2706 else
2707 /* If its prev pointer is nil, it must be at the front of
2708 one or the other! */
2709 abort ();
2710 }
2711 else
ab648270 2712 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
2713
2714 if (! NILP (bar->next))
ab648270 2715 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 2716
ab648270 2717 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 2718 bar->prev = Qnil;
ab648270 2719 XSET (FRAME_SCROLL_BARS (f), Lisp_Vector, bar);
12ba150f 2720 if (! NILP (bar->next))
ab648270 2721 XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
12ba150f 2722 }
f451eb13
JB
2723}
2724
ab648270
JB
2725/* Remove all scroll bars on FRAME that haven't been saved since the
2726 last call to `*condemn_scroll_bars_hook'. */
f451eb13 2727static void
ab648270 2728XTjudge_scroll_bars (f)
12ba150f 2729 FRAME_PTR f;
f451eb13 2730{
12ba150f 2731 Lisp_Object bar, next;
f451eb13 2732
ab648270 2733 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
2734
2735 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
2736 more events on the hapless scroll bars. */
2737 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
2738
2739 for (; ! NILP (bar); bar = next)
f451eb13 2740 {
ab648270 2741 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 2742
ab648270 2743 x_scroll_bar_remove (b);
12ba150f
JB
2744
2745 next = b->next;
2746 b->next = b->prev = Qnil;
f451eb13 2747 }
12ba150f 2748
ab648270 2749 /* Now there should be no references to the condemned scroll bars,
12ba150f 2750 and they should get garbage-collected. */
f451eb13
JB
2751}
2752
2753
ab648270
JB
2754/* Handle an Expose or GraphicsExpose event on a scroll bar.
2755
2756 This may be called from a signal handler, so we have to ignore GC
2757 mark bits. */
f451eb13 2758static void
ab648270
JB
2759x_scroll_bar_expose (bar, event)
2760 struct scroll_bar *bar;
f451eb13
JB
2761 XEvent *event;
2762{
ab648270 2763 Window w = SCROLL_BAR_X_WINDOW (bar);
12ba150f
JB
2764 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
2765
f451eb13
JB
2766 BLOCK_INPUT;
2767
ab648270 2768 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 2769
ab648270 2770 /* Draw a one-pixel border just inside the edges of the scroll bar. */
12ba150f 2771 XDrawRectangle (x_current_display, w, gc,
f451eb13
JB
2772
2773 /* x, y, width, height */
12ba150f 2774 0, 0, XINT (bar->width) - 1, XINT (bar->height) - 1);
f451eb13 2775
f451eb13
JB
2776 UNBLOCK_INPUT;
2777}
2778
ab648270
JB
2779/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2780 is set to something other than no_event, it is enqueued.
2781
2782 This may be called from a signal handler, so we have to ignore GC
2783 mark bits. */
f451eb13 2784static void
ab648270
JB
2785x_scroll_bar_handle_click (bar, event, emacs_event)
2786 struct scroll_bar *bar;
f451eb13
JB
2787 XEvent *event;
2788 struct input_event *emacs_event;
2789{
ab648270 2790 if (XGCTYPE (bar->window) != Lisp_Window)
12ba150f
JB
2791 abort ();
2792
ab648270 2793 emacs_event->kind = scroll_bar_click;
69388238 2794 emacs_event->code = event->xbutton.button - Button1;
f451eb13 2795 emacs_event->modifiers =
dfeccd2d 2796 (x_x_to_emacs_modifiers (event->xbutton.state)
f451eb13
JB
2797 | (event->type == ButtonRelease
2798 ? up_modifier
2799 : down_modifier));
12ba150f 2800 emacs_event->frame_or_window = bar->window;
f451eb13 2801 emacs_event->timestamp = event->xbutton.time;
12ba150f
JB
2802 {
2803 int internal_height =
ab648270 2804 VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
12ba150f 2805 int top_range =
ab648270
JB
2806 VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2807 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
2808
2809 if (y < 0) y = 0;
2810 if (y > top_range) y = top_range;
2811
2812 if (y < XINT (bar->start))
ab648270
JB
2813 emacs_event->part = scroll_bar_above_handle;
2814 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2815 emacs_event->part = scroll_bar_handle;
12ba150f 2816 else
ab648270 2817 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
2818
2819 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
2820 they want to drag it. Lisp code needs to be able to decide
2821 whether or not we're dragging. */
929787e1 2822#if 0
12ba150f
JB
2823 /* If the user has just clicked on the handle, record where they're
2824 holding it. */
2825 if (event->type == ButtonPress
ab648270 2826 && emacs_event->part == scroll_bar_handle)
12ba150f 2827 XSET (bar->dragging, Lisp_Int, y - XINT (bar->start));
929787e1 2828#endif
12ba150f
JB
2829
2830 /* If the user has released the handle, set it to its final position. */
2831 if (event->type == ButtonRelease
2832 && ! NILP (bar->dragging))
2833 {
2834 int new_start = y - XINT (bar->dragging);
2835 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 2836
ab648270 2837 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
2838 bar->dragging = Qnil;
2839 }
f451eb13 2840
5116f055
JB
2841 /* Same deal here as the other #if 0. */
2842#if 0
eb8c3be9 2843 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 2844 the handle. */
ab648270 2845 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
2846 emacs_event->x = bar->start;
2847 else
2848 XSET (emacs_event->x, Lisp_Int, y);
5116f055
JB
2849#else
2850 XSET (emacs_event->x, Lisp_Int, y);
2851#endif
f451eb13 2852
12ba150f
JB
2853 XSET (emacs_event->y, Lisp_Int, top_range);
2854 }
2855}
f451eb13 2856
ab648270
JB
2857/* Handle some mouse motion while someone is dragging the scroll bar.
2858
2859 This may be called from a signal handler, so we have to ignore GC
2860 mark bits. */
f451eb13 2861static void
ab648270
JB
2862x_scroll_bar_note_movement (bar, event)
2863 struct scroll_bar *bar;
f451eb13
JB
2864 XEvent *event;
2865{
2866 last_mouse_movement_time = event->xmotion.time;
2867
2868 mouse_moved = 1;
ab648270 2869 XSET (last_mouse_scroll_bar, Lisp_Vector, bar);
f451eb13
JB
2870
2871 /* If we're dragging the bar, display it. */
ab648270 2872 if (! GC_NILP (bar->dragging))
f451eb13
JB
2873 {
2874 /* Where should the handle be now? */
12ba150f 2875 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 2876
12ba150f 2877 if (new_start != XINT (bar->start))
f451eb13 2878 {
12ba150f 2879 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 2880
ab648270 2881 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
2882 }
2883 }
2884
2885 /* Call XQueryPointer so we'll get an event the next time the mouse
2886 moves and we can see *still* on the same position. */
2887 {
2888 int dummy;
2889
2890 XQueryPointer (event->xmotion.display, event->xmotion.window,
2891 (Window *) &dummy, (Window *) &dummy,
2892 &dummy, &dummy, &dummy, &dummy,
2893 (unsigned int *) &dummy);
2894 }
2895}
2896
12ba150f 2897/* Return information to the user about the current position of the mouse
ab648270 2898 on the scroll bar. */
12ba150f 2899static void
ab648270 2900x_scroll_bar_report_motion (f, bar_window, part, x, y, time)
12ba150f
JB
2901 FRAME_PTR *f;
2902 Lisp_Object *bar_window;
ab648270 2903 enum scroll_bar_part *part;
12ba150f
JB
2904 Lisp_Object *x, *y;
2905 unsigned long *time;
2906{
ab648270 2907 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
12ba150f 2908 int win_x, win_y;
559cb2fb
JB
2909 Window dummy_window;
2910 int dummy_coord;
2911 unsigned int dummy_mask;
12ba150f 2912
cf7cb199
JB
2913 BLOCK_INPUT;
2914
ab648270 2915 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 2916 report that. */
559cb2fb
JB
2917 if (! XQueryPointer (x_current_display,
2918 SCROLL_BAR_X_WINDOW (bar),
12ba150f 2919
559cb2fb
JB
2920 /* Root, child, root x and root y. */
2921 &dummy_window, &dummy_window,
2922 &dummy_coord, &dummy_coord,
12ba150f 2923
559cb2fb
JB
2924 /* Position relative to scroll bar. */
2925 &win_x, &win_y,
12ba150f 2926
559cb2fb
JB
2927 /* Mouse buttons and modifier keys. */
2928 &dummy_mask))
2929 *f = 0;
2930 else
2931 {
2932 int inside_height
2933 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2934 int top_range
2935 = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2936
2937 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2938
2939 if (! NILP (bar->dragging))
2940 win_y -= XINT (bar->dragging);
2941
2942 if (win_y < 0)
2943 win_y = 0;
2944 if (win_y > top_range)
2945 win_y = top_range;
2946
2947 *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2948 *bar_window = bar->window;
2949
2950 if (! NILP (bar->dragging))
2951 *part = scroll_bar_handle;
2952 else if (win_y < XINT (bar->start))
2953 *part = scroll_bar_above_handle;
2954 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2955 *part = scroll_bar_handle;
2956 else
2957 *part = scroll_bar_below_handle;
12ba150f 2958
559cb2fb
JB
2959 XSET (*x, Lisp_Int, win_y);
2960 XSET (*y, Lisp_Int, top_range);
12ba150f 2961
559cb2fb
JB
2962 mouse_moved = 0;
2963 last_mouse_scroll_bar = Qnil;
2964 }
12ba150f 2965
559cb2fb 2966 *time = last_mouse_movement_time;
cf7cb199 2967
cf7cb199 2968 UNBLOCK_INPUT;
12ba150f
JB
2969}
2970
f451eb13 2971
dbc4e1c1 2972/* The screen has been cleared so we may have changed foreground or
ab648270
JB
2973 background colors, and the scroll bars may need to be redrawn.
2974 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
2975 redraw them. */
2976
ab648270 2977x_scroll_bar_clear (f)
dbc4e1c1
JB
2978 FRAME_PTR f;
2979{
2980 Lisp_Object bar;
2981
ab648270 2982 for (bar = FRAME_SCROLL_BARS (f);
dbc4e1c1 2983 XTYPE (bar) == Lisp_Vector;
ab648270
JB
2984 bar = XSCROLL_BAR (bar)->next)
2985 XClearArea (x_current_display, SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
dbc4e1c1
JB
2986 0, 0, 0, 0, True);
2987}
2988
3afe33e7
RS
2989/* This processes Expose events from the menubar specific X event
2990 loop in menubar.c. This allows to redisplay the frame if necessary
2991 when handling menubar or popup items. */
2992
2993void
2994process_expose_from_menu (event)
2995 XEvent event;
2996{
2997 FRAME_PTR f;
2998
f94397b5
KH
2999 BLOCK_INPUT;
3000
3afe33e7
RS
3001 f = x_window_to_frame (event.xexpose.window);
3002 if (f)
3003 {
3004 if (f->async_visible == 0)
3005 {
3006 f->async_visible = 1;
3007 f->async_iconified = 0;
3008 SET_FRAME_GARBAGED (f);
3009 }
3010 else
3011 {
3012 dumprectangle (x_window_to_frame (event.xexpose.window),
3013 event.xexpose.x, event.xexpose.y,
3014 event.xexpose.width, event.xexpose.height);
3015 }
3016 }
3017 else
3018 {
3019 struct scroll_bar *bar
3020 = x_window_to_scroll_bar (event.xexpose.window);
3021
3022 if (bar)
3023 x_scroll_bar_expose (bar, &event);
3024 }
f94397b5
KH
3025
3026 UNBLOCK_INPUT;
3afe33e7 3027}
dbc4e1c1 3028
f451eb13
JB
3029\f
3030/* The main X event-reading loop - XTread_socket. */
dc6f92b8 3031
dc6f92b8
JB
3032/* Timestamp of enter window event. This is only used by XTread_socket,
3033 but we have to put it out here, since static variables within functions
3034 sometimes don't work. */
3035static Time enter_timestamp;
3036
11edeb03
JB
3037/* This holds the state XLookupString needs to implement dead keys
3038 and other tricks known as "compose processing". _X Window System_
3039 says that a portable program can't use this, but Stephen Gildea assures
3040 me that letting the compiler initialize it to zeros will work okay.
3041
3042 This must be defined outside of XTread_socket, for the same reasons
3043 given for enter_timestamp, above. */
3044static XComposeStatus compose_status;
3045
c047688c
JA
3046/* Communication with window managers. */
3047Atom Xatom_wm_protocols;
3048
3049/* Kinds of protocol things we may receive. */
3050Atom Xatom_wm_take_focus;
3051Atom Xatom_wm_save_yourself;
3052Atom Xatom_wm_delete_window;
3053
3054/* Other WM communication */
3055Atom Xatom_wm_configure_denied; /* When our config request is denied */
3056Atom Xatom_wm_window_moved; /* When the WM moves us. */
3057
d56a553a
RS
3058/* Window manager communication. */
3059Atom Xatom_wm_change_state;
3060
10e6549c
RS
3061/* Record the last 100 characters stored
3062 to help debug the loss-of-chars-during-GC problem. */
3063int temp_index;
3064short temp_buffer[100];
3065
dc6f92b8
JB
3066/* Read events coming from the X server.
3067 This routine is called by the SIGIO handler.
3068 We return as soon as there are no more events to be read.
3069
3070 Events representing keys are stored in buffer BUFP,
3071 which can hold up to NUMCHARS characters.
3072 We return the number of characters stored into the buffer,
3073 thus pretending to be `read'.
3074
3075 WAITP is nonzero if we should block until input arrives.
3076 EXPECTED is nonzero if the caller knows input is available. */
3077
7c5283e4 3078int
dc6f92b8
JB
3079XTread_socket (sd, bufp, numchars, waitp, expected)
3080 register int sd;
3081 register struct input_event *bufp;
3082 register int numchars;
3083 int waitp;
3084 int expected;
3085{
3086 int count = 0;
3087 int nbytes = 0;
3088 int mask;
3089 int items_pending; /* How many items are in the X queue. */
3090 XEvent event;
f676886a 3091 struct frame *f;
66f55a9d 3092 int event_found = 0;
dc6f92b8
JB
3093 int prefix;
3094 Lisp_Object part;
3095
9ac0d9e0 3096 if (interrupt_input_blocked)
dc6f92b8 3097 {
9ac0d9e0 3098 interrupt_input_pending = 1;
dc6f92b8
JB
3099 return -1;
3100 }
3101
9ac0d9e0 3102 interrupt_input_pending = 0;
dc6f92b8
JB
3103 BLOCK_INPUT;
3104
3105 if (numchars <= 0)
3106 abort (); /* Don't think this happens. */
3107
3108#ifdef FIOSNBIO
3109 /* If available, Xlib uses FIOSNBIO to make the socket
3110 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
3111 FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK,
3112 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
3113 fcntl (fileno (stdin), F_SETFL, 0);
c118dd06 3114#endif /* ! defined (FIOSNBIO) */
dc6f92b8
JB
3115
3116#ifndef SIGIO
3117#ifndef HAVE_SELECT
3118 if (! (fcntl (fileno (stdin), F_GETFL, 0) & O_NDELAY))
3119 {
3120 extern int read_alarm_should_throw;
3121 read_alarm_should_throw = 1;
3122 XPeekEvent (XDISPLAY &event);
3123 read_alarm_should_throw = 0;
3124 }
c118dd06
JB
3125#endif /* HAVE_SELECT */
3126#endif /* SIGIO */
dc6f92b8
JB
3127
3128 while (XStuffPending () != 0)
3129 {
3130 XNextEvent (XDISPLAY &event);
3131 event_found = 1;
3132
3133 switch (event.type)
3134 {
3135#ifdef HAVE_X11
c047688c
JA
3136 case ClientMessage:
3137 {
3138 if (event.xclient.message_type == Xatom_wm_protocols
3139 && event.xclient.format == 32)
3140 {
3141 if (event.xclient.data.l[0] == Xatom_wm_take_focus)
3142 {
3afe33e7
RS
3143#ifdef USE_X_TOOLKIT
3144 /* f = x_any_window_to_frame (event.xclient.window); */
f676886a 3145 f = x_window_to_frame (event.xclient.window);
3afe33e7
RS
3146#else
3147 f = x_window_to_frame (event.xclient.window);
3148#endif
f676886a
JB
3149 if (f)
3150 x_focus_on_frame (f);
ab648270 3151 /* Not certain about handling scroll bars here */
c047688c
JA
3152 }
3153 else if (event.xclient.data.l[0] == Xatom_wm_save_yourself)
3154 {
3155 /* Save state modify the WM_COMMAND property to
3156 something which can reinstate us. This notifies
3157 the session manager, who's looking for such a
3158 PropertyNotify. Can restart processing when
3159 a keyboard or mouse event arrives. */
3160 if (numchars > 0)
3161 {
3162 }
3163 }
3164 else if (event.xclient.data.l[0] == Xatom_wm_delete_window)
3165 {
82aebaf4 3166 struct frame *f = x_any_window_to_frame (event.xclient.window);
c047688c 3167
f676886a 3168 if (f)
1fb20991
RS
3169 {
3170 if (numchars == 0)
3171 abort ();
3172
3173 bufp->kind = delete_window_event;
3174 XSET (bufp->frame_or_window, Lisp_Frame, f);
3175 bufp++;
3176
3177 count += 1;
3178 numchars -= 1;
3179 }
c047688c
JA
3180 }
3181 }
3182 else if (event.xclient.message_type == Xatom_wm_configure_denied)
3183 {
3184 }
3185 else if (event.xclient.message_type == Xatom_wm_window_moved)
3186 {
3187 int new_x, new_y;
1fb20991
RS
3188 struct frame *f = x_window_to_frame (event.xclient.window);
3189
4357eba7
JB
3190 new_x = event.xclient.data.s[0];
3191 new_y = event.xclient.data.s[1];
1fb20991
RS
3192
3193 if (f)
3194 {
3195 f->display.x->left_pos = new_x;
3196 f->display.x->top_pos = new_y;
3197 }
c047688c
JA
3198 }
3199 }
3200 break;
dc6f92b8 3201
d56a553a
RS
3202#ifdef NEW_SELECTIONS
3203 case SelectionNotify:
3afe33e7
RS
3204#ifdef USE_X_TOOLKIT
3205 if (x_window_to_frame (event.xselection.requestor))
3206 x_handle_selection_notify (&event);
3207 else
3208 goto OTHER;
3209#else /* not USE_X_TOOLKIT */
d56a553a 3210 x_handle_selection_notify (&event);
3afe33e7 3211#endif /* not USE_X_TOOLKIT */
d56a553a 3212 break;
3afe33e7 3213#endif /* NEW_SELECTIONS */
d56a553a 3214
dc6f92b8 3215 case SelectionClear: /* Someone has grabbed ownership. */
d56a553a
RS
3216#ifdef NEW_SELECTIONS
3217 {
3afe33e7
RS
3218#ifdef USE_X_TOOLKIT
3219 if (x_window_to_frame (event.xselectionclear.window))
3220 {
3221#endif /* USE_X_TOOLKIT */
d56a553a
RS
3222 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
3223
3224 if (numchars == 0)
3225 abort ();
3226
3227 bufp->kind = selection_clear_event;
3228 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3229 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3230 SELECTION_EVENT_TIME (bufp) = eventp->time;
3231 bufp++;
3232
3233 count += 1;
3234 numchars -= 1;
3afe33e7 3235#ifdef USE_X_TOOLKIT
d56a553a 3236 }
3afe33e7
RS
3237 else
3238 goto OTHER;
3239#endif /* USE_X_TOOLKIT */
3240 }
3241#else /* not NEW_SELECTIONS */
dc6f92b8
JB
3242 x_disown_selection (event.xselectionclear.window,
3243 event.xselectionclear.selection,
3244 event.xselectionclear.time);
3afe33e7 3245#endif /* not NEW_SELECTIONS */
dc6f92b8
JB
3246 break;
3247
3248 case SelectionRequest: /* Someone wants our selection. */
d56a553a
RS
3249#ifdef NEW_SELECTIONS
3250 {
3afe33e7
RS
3251#ifdef USE_X_TOOLKIT
3252 if (x_window_to_frame (event.xselectionrequest.owner))
3253 {
3254#endif /* USE_X_TOOLKIT */
d56a553a
RS
3255 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
3256
3257 if (numchars == 0)
3258 abort ();
3259
3260 bufp->kind = selection_request_event;
3261 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3262 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
3263 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3264 SELECTION_EVENT_TARGET (bufp) = eventp->target;
3265 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
3266 SELECTION_EVENT_TIME (bufp) = eventp->time;
3267 bufp++;
3268
3269 count += 1;
3270 numchars -= 1;
3afe33e7 3271#ifdef USE_X_TOOLKIT
d56a553a 3272 }
3afe33e7
RS
3273 else
3274 goto OTHER;
3275#endif /* USE_X_TOOLKIT */
3276 }
3277#else /* not NEW_SELECTIONS */
dc6f92b8 3278 x_answer_selection_request (event);
3afe33e7 3279#endif /* not NEW_SELECTIONS */
dc6f92b8
JB
3280 break;
3281
3282 case PropertyNotify:
d56a553a 3283#ifdef NEW_SELECTIONS
3afe33e7
RS
3284#ifdef USE_X_TOOLKIT
3285 if (x_any_window_to_frame (event.xproperty.window))
3286 x_handle_property_notify (&event);
3287 else
3288 goto OTHER;
3289#else /* not USE_X_TOOLKIT */
d56a553a 3290 x_handle_property_notify (&event);
3afe33e7
RS
3291#endif /* not USE_X_TOOLKIT */
3292#else /* not NEW_SELECTIONS */
28430d3c
JB
3293 /* If we're being told about a root window property, then it's
3294 a cut buffer change. */
3295 if (event.xproperty.window == ROOT_WINDOW)
3296 x_invalidate_cut_buffer_cache (&event.xproperty);
3297
3298 /* Otherwise, we're probably handling an incremental
3299 selection transmission. */
3300 else
3301 {
3302 /* If we were to do this synchronously, there'd be no worry
3303 about re-selecting. */
3304 x_send_incremental (event);
3305 }
3afe33e7 3306#endif /* not NEW_SELECTIONS */
dc6f92b8
JB
3307 break;
3308
3bd330d4
RS
3309 case ReparentNotify:
3310 f = x_window_to_frame (event.xreparent.window);
3311 if (f)
3312 f->display.x->parent_desc = event.xreparent.parent;
3313 break;
3314
dc6f92b8 3315 case Expose:
f676886a
JB
3316 f = x_window_to_frame (event.xexpose.window);
3317 if (f)
dc6f92b8 3318 {
3a88c238 3319 if (f->async_visible == 0)
dc6f92b8 3320 {
3a88c238
JB
3321 f->async_visible = 1;
3322 f->async_iconified = 0;
f676886a 3323 SET_FRAME_GARBAGED (f);
dc6f92b8
JB
3324 }
3325 else
f451eb13
JB
3326 {
3327 dumprectangle (x_window_to_frame (event.xexpose.window),
3328 event.xexpose.x, event.xexpose.y,
3329 event.xexpose.width, event.xexpose.height);
f451eb13
JB
3330 }
3331 }
3332 else
3333 {
ab648270
JB
3334 struct scroll_bar *bar
3335 = x_window_to_scroll_bar (event.xexpose.window);
3afe33e7 3336
f451eb13 3337 if (bar)
3afe33e7
RS
3338 x_scroll_bar_expose (bar, &event);
3339#ifdef USE_X_TOOLKIT
3340 else
3341 goto OTHER;
3342#endif /* USE_X_TOOLKIT */
dc6f92b8
JB
3343 }
3344 break;
3345
3346 case GraphicsExpose: /* This occurs when an XCopyArea's
3347 source area was obscured or not
3348 available.*/
f451eb13
JB
3349 f = x_window_to_frame (event.xgraphicsexpose.drawable);
3350 if (f)
3351 {
3352 dumprectangle (f,
3353 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
3354 event.xgraphicsexpose.width,
3355 event.xgraphicsexpose.height);
f451eb13 3356 }
3afe33e7
RS
3357#ifdef USE_X_TOOLKIT
3358 else
3359 goto OTHER;
3360#endif /* USE_X_TOOLKIT */
dc6f92b8
JB
3361 break;
3362
3363 case NoExpose: /* This occurs when an XCopyArea's
3364 source area was completely
3365 available */
3366 break;
c118dd06 3367#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3368 case ExposeWindow:
3369 if (event.subwindow != 0)
3370 break; /* duplicate event */
f676886a
JB
3371 f = x_window_to_frame (event.window);
3372 if (event.window == f->display.x->icon_desc)
dc6f92b8 3373 {
f676886a 3374 refreshicon (f);
3a88c238 3375 f->async_iconified = 1;
dc6f92b8 3376 }
c118dd06 3377 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8
JB
3378 {
3379 /* Say must check all windows' needs_exposure flags. */
3380 expose_all_windows = 1;
f676886a 3381 f->display.x->needs_exposure = 1;
3a88c238 3382 f->async_visible = 1;
dc6f92b8
JB
3383 }
3384 break;
3385
3386 case ExposeRegion:
3387 if (event.subwindow != 0)
3388 break; /* duplicate event */
f676886a
JB
3389 f = x_window_to_frame (event.window);
3390 if (event.window == f->display.x->icon_desc)
dc6f92b8 3391 {
f676886a 3392 refreshicon (f);
dc6f92b8
JB
3393 break;
3394 }
3395 /* If window already needs full redraw, ignore this rectangle. */
f676886a 3396 if (expose_all_windows && f->display.x->needs_exposure)
dc6f92b8
JB
3397 break;
3398 /* Put the event on the queue of rectangles to redraw. */
3399 if (enqueue_event (&event, &x_expose_queue))
3400 /* If it is full, we can't record the rectangle,
3401 so redraw this entire window. */
3402 {
3403 /* Say must check all windows' needs_exposure flags. */
3404 expose_all_windows = 1;
f676886a 3405 f->display.x->needs_exposure = 1;
dc6f92b8
JB
3406 }
3407 break;
3408
3409 case ExposeCopy:
3410 /* This should happen only when we are expecting it,
3411 in x_read_exposes. */
3412 abort ();
c118dd06 3413#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3414
3415#ifdef HAVE_X11
3416 case UnmapNotify:
f451eb13
JB
3417 f = x_window_to_frame (event.xunmap.window);
3418 if (f) /* F may no longer exist if
f676886a 3419 the frame was deleted. */
f451eb13
JB
3420 {
3421 /* While a frame is unmapped, display generation is
3422 disabled; you don't want to spend time updating a
3423 display that won't ever be seen. */
3424 f->async_visible = 0;
9319ae23
RS
3425 /* The window manager never makes a window invisible
3426 ("withdrawn"); all it does is switch between visible
3427 and iconified. Frames get into the invisible state
041b69ac 3428 only through x_make_frame_invisible. */
9319ae23
RS
3429 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
3430 f->async_iconified = 1;
f451eb13 3431 }
3afe33e7
RS
3432#ifdef USE_X_TOOLKIT
3433 goto OTHER;
3434#endif /* USE_X_TOOLKIT */
dc6f92b8
JB
3435 break;
3436
3437 case MapNotify:
3afe33e7
RS
3438#ifdef USE_X_TOOLKIT
3439 f = x_any_window_to_frame (event.xmap.window);
3440#else /* not USE_X_TOOLKIT */
f676886a 3441 f = x_window_to_frame (event.xmap.window);
3afe33e7 3442#endif /* not USE_X_TOOLKIT */
f676886a 3443 if (f)
dc6f92b8 3444 {
3a88c238
JB
3445 f->async_visible = 1;
3446 f->async_iconified = 0;
dc6f92b8
JB
3447
3448 /* wait_reading_process_input will notice this and update
f676886a
JB
3449 the frame's display structures. */
3450 SET_FRAME_GARBAGED (f);
dc6f92b8 3451 }
3afe33e7
RS
3452#ifdef USE_X_TOOLKIT
3453 goto OTHER;
3454#endif /* USE_X_TOOLKIT */
3455 break;
dc6f92b8
JB
3456
3457 /* Turn off processing if we become fully obscured. */
3458 case VisibilityNotify:
3459 break;
3460
c118dd06 3461#else /* ! defined (HAVE_X11) */
dc6f92b8 3462 case UnmapWindow:
f676886a
JB
3463 f = x_window_to_frame (event.window);
3464 if (event.window == f->display.x->icon_desc)
3a88c238 3465 f->async_iconified = 0;
c118dd06 3466 if (event.window == FRAME_X_WINDOW (f))
3a88c238 3467 f->async_visible = 0;
dc6f92b8 3468 break;
c118dd06 3469#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3470
3471#ifdef HAVE_X11
3472 case KeyPress:
1dea5a83 3473 f = x_any_window_to_frame (event.xkey.window);
f451eb13 3474
f676886a 3475 if (f != 0)
dc6f92b8 3476 {
2d368234 3477 KeySym keysym, orig_keysym;
bf6d8fb9
RS
3478 /* al%imercury@uunet.uu.net says that making this 81 instead of
3479 80 fixed a bug whereby meta chars made his Emacs hang. */
3480 unsigned char copy_buffer[81];
64bb1782
RS
3481 int modifiers;
3482
dfeccd2d
JB
3483 event.xkey.state
3484 |= x_emacs_to_x_modifiers (extra_keyboard_modifiers);
64bb1782 3485 modifiers = event.xkey.state;
3a2712f9 3486
11edeb03 3487 /* This will have to go some day... */
752a043f
JB
3488
3489 /* make_lispy_event turns chars into control chars.
3490 Don't do it here because XLookupString is too eager. */
3491 event.xkey.state &= ~ControlMask;
11edeb03
JB
3492 nbytes =
3493 XLookupString (&event.xkey, copy_buffer, 80, &keysym,
3494 &compose_status);
dc6f92b8 3495
55123275
JB
3496 /* Strip off the vendor-specific keysym bit, and take a shot
3497 at recognizing the codes. HP servers have extra keysyms
3498 that fit into the MiscFunctionKey category. */
2d368234 3499 orig_keysym = keysym;
55123275
JB
3500 keysym &= ~(1<<28);
3501
dc6f92b8
JB
3502 if (numchars > 1)
3503 {
64a07219
JB
3504 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
3505 || keysym == XK_Delete
3506 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
3507 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 3508#ifdef HPUX
64a07219
JB
3509 /* This recognizes the "extended function keys".
3510 It seems there's no cleaner way.
3511 Test IsModifierKey to avoid handling mode_switch
3512 incorrectly. */
3513 || ((unsigned) (keysym) >= XK_Select
3514 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
3515#endif
3516#ifdef XK_dead_circumflex
3517 || orig_keysym == XK_dead_circumflex
3518#endif
3519#ifdef XK_dead_grave
3520 || orig_keysym == XK_dead_grave
3521#endif
3522#ifdef XK_dead_tilde
3523 || orig_keysym == XK_dead_tilde
3524#endif
3525#ifdef XK_dead_diaeresis
3526 || orig_keysym == XK_dead_diaeresis
3527#endif
3528#ifdef XK_dead_macron
3529 || orig_keysym == XK_dead_macron
3530#endif
3531#ifdef XK_dead_degree
3532 || orig_keysym == XK_dead_degree
3533#endif
3534#ifdef XK_dead_acute
3535 || orig_keysym == XK_dead_acute
3536#endif
3537#ifdef XK_dead_cedilla
3538 || orig_keysym == XK_dead_cedilla
3539#endif
3540#ifdef XK_dead_breve
3541 || orig_keysym == XK_dead_breve
3542#endif
3543#ifdef XK_dead_ogonek
3544 || orig_keysym == XK_dead_ogonek
3545#endif
3546#ifdef XK_dead_caron
3547 || orig_keysym == XK_dead_caron
3548#endif
3549#ifdef XK_dead_doubleacute
3550 || orig_keysym == XK_dead_doubleacute
3551#endif
3552#ifdef XK_dead_abovedot
3553 || orig_keysym == XK_dead_abovedot
c34790e0 3554#endif
64a07219
JB
3555 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
3556 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
3557 || x_is_vendor_fkey (orig_keysym))
7719aa06
RS
3558 && ! (IsModifierKey (orig_keysym)
3559#ifndef HAVE_X11R5
3560#ifdef XK_Mode_switch
3561 || ((unsigned)(orig_keysym) == XK_Mode_switch)
3562#endif
3563#ifdef XK_Num_Lock
3564 || ((unsigned)(orig_keysym) == XK_Num_Lock)
3565#endif
3566#endif /* not HAVE_X11R5 */
3567 ))
dc6f92b8 3568 {
10e6549c
RS
3569 if (temp_index == sizeof temp_buffer / sizeof (short))
3570 temp_index = 0;
3571 temp_buffer[temp_index++] = keysym;
dc6f92b8 3572 bufp->kind = non_ascii_keystroke;
69388238 3573 bufp->code = keysym;
12ba150f 3574 XSET (bufp->frame_or_window, Lisp_Frame, f);
dfeccd2d 3575 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
1113d9db 3576 bufp->timestamp = event.xkey.time;
dc6f92b8
JB
3577 bufp++;
3578 count++;
3579 numchars--;
3580 }
3581 else if (numchars > nbytes)
3582 {
3583 register int i;
3584
10e6549c 3585 for (i = 0; i < nbytes; i++)
dc6f92b8 3586 {
10e6549c
RS
3587 if (temp_index == sizeof temp_buffer / sizeof (short))
3588 temp_index = 0;
3589 temp_buffer[temp_index++] = copy_buffer[i];
dc6f92b8 3590 bufp->kind = ascii_keystroke;
69388238 3591 bufp->code = copy_buffer[i];
12ba150f 3592 XSET (bufp->frame_or_window, Lisp_Frame, f);
dfeccd2d 3593 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
1113d9db 3594 bufp->timestamp = event.xkey.time;
dc6f92b8
JB
3595 bufp++;
3596 }
dc6f92b8
JB
3597
3598 count += nbytes;
3599 numchars -= nbytes;
3600 }
10e6549c
RS
3601 else
3602 abort ();
dc6f92b8 3603 }
10e6549c
RS
3604 else
3605 abort ();
dc6f92b8
JB
3606 }
3607 break;
c118dd06 3608#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3609 case KeyPressed:
3610 {
3611 register char *where_mapping;
3612
f676886a 3613 f = x_window_to_frame (event.window);
dc6f92b8 3614 /* Ignore keys typed on icon windows. */
f676886a 3615 if (f != 0 && event.window == f->display.x->icon_desc)
dc6f92b8
JB
3616 break;
3617 where_mapping = XLookupMapping (&event, &nbytes);
3618 /* Nasty fix for arrow keys */
3619 if (!nbytes && IsCursorKey (event.detail & 0xff))
3620 {
3621 switch (event.detail & 0xff)
3622 {
3623 case KC_CURSOR_LEFT:
3624 where_mapping = "\002";
3625 break;
3626 case KC_CURSOR_RIGHT:
3627 where_mapping = "\006";
3628 break;
3629 case KC_CURSOR_UP:
3630 where_mapping = "\020";
3631 break;
3632 case KC_CURSOR_DOWN:
3633 where_mapping = "\016";
3634 break;
3635 }
3636 nbytes = 1;
3637 }
3638 if (numchars - nbytes > 0)
3639 {
3640 register int i;
3641
3642 for (i = 0; i < nbytes; i++)
3643 {
3644 bufp->kind = ascii_keystroke;
69388238 3645 bufp->code = where_mapping[i];
90e65f07 3646 XSET (bufp->time, Lisp_Int, event.xkey.time);
12ba150f 3647 XSET (bufp->frame_or_window, Lisp_Frame, f);
dc6f92b8
JB
3648 bufp++;
3649 }
3650 count += nbytes;
3651 numchars -= nbytes;
3652 }
3653 }
3654 break;
c118dd06 3655#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3656
3657#ifdef HAVE_X11
f451eb13
JB
3658
3659 /* Here's a possible interpretation of the whole
3660 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
3661 FocusIn event, you have to get a FocusOut event before you
3662 relinquish the focus. If you haven't received a FocusIn event,
3663 then a mere LeaveNotify is enough to free you. */
3664
dc6f92b8 3665 case EnterNotify:
1dea5a83 3666 f = x_any_window_to_frame (event.xcrossing.window);
6d4238f3 3667
f451eb13 3668 if (event.xcrossing.focus) /* Entered Window */
dc6f92b8 3669 {
dc6f92b8 3670 /* Avoid nasty pop/raise loops. */
f676886a
JB
3671 if (f && (!(f->auto_raise)
3672 || !(f->auto_lower)
dc6f92b8
JB
3673 || (event.xcrossing.time - enter_timestamp) > 500))
3674 {
f676886a 3675 x_new_focus_frame (f);
dc6f92b8
JB
3676 enter_timestamp = event.xcrossing.time;
3677 }
dc6f92b8 3678 }
f676886a
JB
3679 else if (f == x_focus_frame)
3680 x_new_focus_frame (0);
3afe33e7
RS
3681#ifdef USE_X_TOOLKIT
3682 goto OTHER;
3683#endif /* USE_X_TOOLKIT */
dc6f92b8
JB
3684 break;
3685
3686 case FocusIn:
1dea5a83 3687 f = x_any_window_to_frame (event.xfocus.window);
f451eb13
JB
3688 if (event.xfocus.detail != NotifyPointer)
3689 x_focus_event_frame = f;
f676886a
JB
3690 if (f)
3691 x_new_focus_frame (f);
3afe33e7
RS
3692#ifdef USE_X_TOOLKIT
3693 goto OTHER;
3694#endif /* USE_X_TOOLKIT */
dc6f92b8
JB
3695 break;
3696
f451eb13 3697
dc6f92b8 3698 case LeaveNotify:
1dea5a83 3699 f = x_any_window_to_frame (event.xcrossing.window);
b1c884c3 3700
b8009dd1
RS
3701 if (f == mouse_face_mouse_frame)
3702 /* If we move outside the frame,
3703 then we're certainly no longer on any text in the frame. */
3704 clear_mouse_face ();
3705
f451eb13
JB
3706 if (event.xcrossing.focus)
3707 {
3708 if (! x_focus_event_frame)
3709 x_new_focus_frame (0);
3710 else
f676886a 3711 x_new_focus_frame (f);
f451eb13
JB
3712 }
3713 else
3714 {
3715 if (f == x_focus_event_frame)
3716 x_focus_event_frame = 0;
3717 if (f == x_focus_frame)
f676886a 3718 x_new_focus_frame (0);
dc6f92b8 3719 }
3afe33e7
RS
3720#ifdef USE_X_TOOLKIT
3721 goto OTHER;
3722#endif /* USE_X_TOOLKIT */
dc6f92b8
JB
3723 break;
3724
3725 case FocusOut:
1dea5a83 3726 f = x_any_window_to_frame (event.xfocus.window);
f451eb13
JB
3727 if (event.xfocus.detail != NotifyPointer
3728 && f == x_focus_event_frame)
3729 x_focus_event_frame = 0;
f676886a
JB
3730 if (f && f == x_focus_frame)
3731 x_new_focus_frame (0);
3afe33e7
RS
3732#ifdef USE_X_TOOLKIT
3733 goto OTHER;
3734#endif /* USE_X_TOOLKIT */
dc6f92b8
JB
3735 break;
3736
c118dd06 3737#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3738
3739 case EnterWindow:
3740 if ((event.detail & 0xFF) == 1)
3741 break; /* Coming from our own subwindow */
3742 if (event.subwindow != 0)
3743 break; /* Entering our own subwindow. */
3744
3745 {
f676886a
JB
3746 f = x_window_to_frame (event.window);
3747 x_mouse_frame = f;
dc6f92b8 3748
f676886a 3749 x_new_focus_frame (f);
dc6f92b8
JB
3750 }
3751 break;
3752
3753 case LeaveWindow:
3754 if ((event.detail & 0xFF) == 1)
3755 break; /* Entering our own subwindow */
3756 if (event.subwindow != 0)
3757 break; /* Leaving our own subwindow. */
3758
f676886a
JB
3759 x_mouse_frame = 0;
3760 if (x_focus_frame == 0
3761 && x_input_frame != 0
3762 && x_input_frame == x_window_to_frame (event.window)
c118dd06 3763 && event.window == FRAME_X_WINDOW (x_input_frame))
dc6f92b8 3764 {
f676886a
JB
3765 f = x_input_frame;
3766 x_input_frame = 0;
3767 if (f)
3768 frame_unhighlight (f);
dc6f92b8
JB
3769 }
3770 break;
c118dd06 3771#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3772
3773#ifdef HAVE_X11
3774 case MotionNotify:
3775 {
69388238
RS
3776 if (x_mouse_grabbed)
3777 f = last_mouse_frame;
3778 else
3779 f = x_window_to_frame (event.xmotion.window);
f676886a 3780 if (f)
12ba150f 3781 note_mouse_movement (f, &event.xmotion);
f451eb13 3782 else
dc6f92b8 3783 {
69388238
RS
3784 struct scroll_bar *bar
3785 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13
JB
3786
3787 if (bar)
ab648270 3788 x_scroll_bar_note_movement (bar, &event);
b8009dd1
RS
3789
3790 /* If we move outside the frame,
3791 then we're certainly no longer on any text in the frame. */
3792 clear_mouse_face ();
dc6f92b8 3793 }
dc6f92b8 3794 }
3afe33e7
RS
3795#ifdef USE_X_TOOLKIT
3796 goto OTHER;
3797#endif /* USE_X_TOOLKIT */
dc6f92b8
JB
3798 break;
3799
3800 case ConfigureNotify:
13ce2d73 3801 f = x_any_window_to_frame (event.xconfigure.window);
3afe33e7 3802#ifdef USE_X_TOOLKIT
13ce2d73
FP
3803 if (f
3804 && ! event.xconfigure.send_event
3805 && (event.xconfigure.window == XtWindow (f->display.x->widget)))
3806 {
3807 Window win, child;
3808 int win_x, win_y;
3809
3810 /* Find the position of the outside upper-left corner of
3811 the window, in the root coordinate system. Don't
3812 refer to the parent window here; we may be processing
3813 this event after the window manager has changed our
3814 parent, but before we have reached the ReparentNotify. */
3815 XTranslateCoordinates (x_current_display,
3816
3817 /* From-window, to-window. */
3818 XtWindow (f->display.x->widget),
3819 ROOT_WINDOW,
3820
3821 /* From-position, to-position. */
3822 -event.xconfigure.border_width,
3823 -event.xconfigure.border_width,
3824 &win_x, &win_y,
3825
3826 /* Child of win. */
3827 &child);
3828 event.xconfigure.x = win_x;
3829 event.xconfigure.y = win_y;
3830
3831 f->display.x->pixel_width = event.xconfigure.width;
3832 f->display.x->pixel_height = event.xconfigure.height;
3833 f->display.x->left_pos = event.xconfigure.x;
3834 f->display.x->top_pos = event.xconfigure.y;
3835 }
3836 goto OTHER;
3afe33e7 3837#else /* not USE_X_TOOLKIT */
dbc4e1c1
JB
3838 if (f)
3839 {
3840 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
3841 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
3842
3843 /* Even if the number of character rows and columns has
3844 not changed, the font size may have changed, so we need
3845 to check the pixel dimensions as well. */
3846 if (columns != f->width
3847 || rows != f->height
3848 || event.xconfigure.width != f->display.x->pixel_width
3849 || event.xconfigure.height != f->display.x->pixel_height)
3850 {
3851 change_frame_size (f, rows, columns, 0, 1);
3852 SET_FRAME_GARBAGED (f);
3853 }
dc6f92b8 3854
3bd330d4 3855 if (! event.xconfigure.send_event)
af395ec1
RS
3856 {
3857 Window win, child;
3858 int win_x, win_y;
3859
6cc35d86
JB
3860 /* Find the position of the outside upper-left corner of
3861 the window, in the root coordinate system. Don't
3862 refer to the parent window here; we may be processing
3863 this event after the window manager has changed our
3864 parent, but before we have reached the ReparentNotify. */
af395ec1
RS
3865 XTranslateCoordinates (x_current_display,
3866
3867 /* From-window, to-window. */
6cc35d86 3868 f->display.x->window_desc,
3bd330d4 3869 ROOT_WINDOW,
af395ec1
RS
3870
3871 /* From-position, to-position. */
6cc35d86
JB
3872 -event.xconfigure.border_width,
3873 -event.xconfigure.border_width,
af395ec1
RS
3874 &win_x, &win_y,
3875
3876 /* Child of win. */
3877 &child);
3878 event.xconfigure.x = win_x;
3879 event.xconfigure.y = win_y;
3880 }
3881
dbc4e1c1
JB
3882 f->display.x->pixel_width = event.xconfigure.width;
3883 f->display.x->pixel_height = event.xconfigure.height;
3884 f->display.x->left_pos = event.xconfigure.x;
3885 f->display.x->top_pos = event.xconfigure.y;
3886 }
3afe33e7 3887#endif /* not USE_X_TOOLKIT */
dbc4e1c1 3888 break;
dc6f92b8
JB
3889
3890 case ButtonPress:
3891 case ButtonRelease:
3892 {
3893 /* If we decide we want to generate an event to be seen
3894 by the rest of Emacs, we put it here. */
3895 struct input_event emacs_event;
3896 emacs_event.kind = no_event;
3897
f676886a
JB
3898 f = x_window_to_frame (event.xbutton.window);
3899 if (f)
f451eb13
JB
3900 {
3901 if (!x_focus_frame || (f == x_focus_frame))
69388238 3902 construct_mouse_click (&emacs_event, &event, f);
f451eb13 3903 }
dc6f92b8 3904 else
f451eb13 3905 {
ab648270
JB
3906 struct scroll_bar *bar =
3907 x_window_to_scroll_bar (event.xbutton.window);
f451eb13
JB
3908
3909 if (bar)
ab648270 3910 x_scroll_bar_handle_click (bar, &event, &emacs_event);
3afe33e7
RS
3911#ifdef USE_X_TOOLKIT
3912 else
3913 {
3914 f = x_any_window_to_frame (event.xbutton.window);
3915 if (f && event.type == ButtonPress)
3916 construct_menu_click (&emacs_event,
3917 &event, f);
3918 }
3919#endif /* USE_X_TOOLKIT */
f451eb13 3920 }
dc6f92b8
JB
3921
3922 if (numchars >= 1 && emacs_event.kind != no_event)
3923 {
3924 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3925 bufp++;
3926 count++;
3927 numchars--;
3928 }
3afe33e7
RS
3929
3930#ifdef USE_X_TOOLKIT
3931 goto OTHER;
3932#endif /* USE_X_TOOLKIT */
dc6f92b8
JB
3933 }
3934 break;
3935
c118dd06 3936#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3937 case ButtonPressed:
3938 case ButtonReleased:
f676886a
JB
3939 f = x_window_to_frame (event.window);
3940 if (f)
dc6f92b8 3941 {
f676886a 3942 if (event.window == f->display.x->icon_desc)
dc6f92b8 3943 {
f676886a 3944 x_make_frame_visible (f);
dc6f92b8
JB
3945
3946 if (warp_mouse_on_deiconify)
c118dd06 3947 XWarpMouse (FRAME_X_WINDOW (f), 10, 10);
dc6f92b8
JB
3948 break;
3949 }
c118dd06 3950 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8 3951 {
f676886a
JB
3952 if (f->auto_raise)
3953 x_raise_frame (f);
dc6f92b8
JB
3954 }
3955 }
3956 enqueue_event (&event, &x_mouse_queue);
3957 if (numchars >= 2)
3958 {
3959 bufp->kind = ascii_keystroke;
69388238 3960 bufp->code = 'X' & 037; /* C-x */
12ba150f 3961 XSET (bufp->frame_or_window, Lisp_Frame, f);
90e65f07 3962 XSET (bufp->time, Lisp_Int, event.xkey.time);
dc6f92b8
JB
3963 bufp++;
3964
3965 bufp->kind = ascii_keystroke;
69388238 3966 bufp->code = 0; /* C-@ */
12ba150f 3967 XSET (bufp->frame_or_window, Lisp_Frame, f);
90e65f07 3968 XSET (bufp->time, Lisp_Int, event.xkey.time);
dc6f92b8
JB
3969 bufp++;
3970
3971 count += 2;
3972 numchars -= 2;
3973 }
3974 break;
c118dd06 3975#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3976
3977#ifdef HAVE_X11
3978
3979 case CirculateNotify:
3980 break;
3981 case CirculateRequest:
3982 break;
3983
c118dd06 3984#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3985
3986 case MappingNotify:
11edeb03
JB
3987 /* Someone has changed the keyboard mapping - update the
3988 local cache. */
3989 switch (event.xmapping.request)
3990 {
3991 case MappingModifier:
3992 x_find_modifier_meanings ();
3993 /* This is meant to fall through. */
3994 case MappingKeyboard:
3995 XRefreshKeyboardMapping (&event.xmapping);
3996 }
3afe33e7
RS
3997#ifdef USE_X_TOOLKIT
3998 goto OTHER;
3999#endif /* USE_X_TOOLKIT */
dc6f92b8
JB
4000 break;
4001
4002 default:
3afe33e7
RS
4003#ifdef USE_X_TOOLKIT
4004 OTHER:
4005 BLOCK_INPUT;
4006 XtDispatchEvent (&event);
4007 UNBLOCK_INPUT;
4008#endif /* USE_X_TOOLKIT */
dc6f92b8
JB
4009 break;
4010 }
4011 }
4012
502add23
RS
4013#ifdef X_IO_BUG
4014 if (! event_found)
4015 /* On some systems, an X bug causes Emacs to get no more events
7071e5dd 4016 when the window is destroyed. Detect that. (1994.) */
502add23
RS
4017 XNoOp (x_current_display);
4018#endif /* X_IO_BUG */
4019
7071e5dd
RS
4020#if 0 /* This fails for serial-line connections to the X server,
4021 because the characters arrive one by one, and a partial
4022 command makes select return but gives nothing to read.
4023 We'll have to hope that the bug that this tried to fix
4024 in 1988 has been fixed in Xlib or the X server. */
dc6f92b8
JB
4025#ifdef HAVE_SELECT
4026 if (expected && ! event_found)
4027 {
4028 /* AOJ 880406: if select returns true but XPending doesn't, it means that
4029 there is an EOF condition; in other words, that X has died.
4030 Act as if there had been a hangup. */
dc6f92b8 4031 int fd = ConnectionNumber (x_current_display);
307feb1f 4032 SELECT_TYPE mask, junk1, junk2;
66f55a9d 4033 EMACS_TIME timeout;
dc6f92b8 4034
61c3ce62
RS
4035 FD_ZERO (&mask);
4036 FD_SET (fd, &mask);
66f55a9d 4037 EMACS_SET_SECS_USECS (timeout, 0, 0);
307feb1f
RS
4038 FD_ZERO (&junk1);
4039 FD_ZERO (&junk2);
4040 if (0 != select (fd + 1, &mask, &junk1, &junk2, &timeout)
dc6f92b8
JB
4041 && !XStuffPending ())
4042 kill (getpid (), SIGHUP);
4043 }
61c3ce62 4044#endif /* HAVE_SELECT */
7071e5dd 4045#endif /* 0 */
dc6f92b8 4046
f451eb13 4047#ifndef HAVE_X11
f676886a 4048 if (updating_frame == 0)
dc6f92b8 4049 x_do_pending_expose ();
f451eb13 4050#endif
dc6f92b8
JB
4051
4052 UNBLOCK_INPUT;
4053 return count;
4054}
4055
4056#ifndef HAVE_X11
4057/* Read and process only Expose events
4058 until we get an ExposeCopy event; then return.
4059 This is used in insert/delete line.
4060 We assume input is already blocked. */
4061
4062static void
4063x_read_exposes ()
4064{
f676886a 4065 struct frame *f;
dc6f92b8
JB
4066 XKeyPressedEvent event;
4067
4068 while (1)
4069 {
4070 /* while there are more events*/
4071 XMaskEvent (ExposeWindow | ExposeRegion | ExposeCopy, &event);
4072 switch (event.type)
4073 {
4074 case ExposeWindow:
4075 if (event.subwindow != 0)
4076 break; /* duplicate event */
f676886a
JB
4077 f = x_window_to_frame (event.window);
4078 if (event.window == f->display.x->icon_desc)
dc6f92b8 4079 {
f676886a 4080 refreshicon (f);
dc6f92b8
JB
4081 break;
4082 }
c118dd06 4083 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8
JB
4084 {
4085 expose_all_windows = 1;
f676886a 4086 f->display.x->needs_exposure = 1;
dc6f92b8
JB
4087 break;
4088 }
4089 break;
4090
4091 case ExposeRegion:
4092 if (event.subwindow != 0)
4093 break; /* duplicate event */
f676886a
JB
4094 f = x_window_to_frame (event.window);
4095 if (event.window == f->display.x->icon_desc)
dc6f92b8 4096 {
f676886a 4097 refreshicon (f);
dc6f92b8
JB
4098 break;
4099 }
4100 /* If window already needs full redraw, ignore this rectangle. */
f676886a 4101 if (expose_all_windows && f->display.x->needs_exposure)
dc6f92b8
JB
4102 break;
4103 /* Put the event on the queue of rectangles to redraw. */
4104 if (enqueue_event (&event, &x_expose_queue))
4105 /* If it is full, we can't record the rectangle,
4106 so redraw this entire window. */
4107 {
4108 /* Say must check all windows' needs_exposure flags. */
4109 expose_all_windows = 1;
f676886a 4110 f->display.x->needs_exposure = 1;
dc6f92b8
JB
4111 }
4112 break;
4113
4114 case ExposeCopy:
4115 return;
4116 }
4117 }
4118}
4119#endif /* HAVE_X11 */
4120
dc6f92b8 4121\f
f451eb13
JB
4122/* Drawing the cursor. */
4123
4124
dc6f92b8
JB
4125/* Draw a hollow box cursor. Don't change the inside of the box. */
4126
4127static void
f676886a
JB
4128x_draw_box (f)
4129 struct frame *f;
dc6f92b8 4130{
12ba150f
JB
4131 int left = CHAR_TO_PIXEL_COL (f, f->cursor_x);
4132 int top = CHAR_TO_PIXEL_ROW (f, f->cursor_y);
f676886a
JB
4133 int width = FONT_WIDTH (f->display.x->font);
4134 int height = FONT_HEIGHT (f->display.x->font);
dc6f92b8
JB
4135
4136#ifdef HAVE_X11
c118dd06 4137 XDrawRectangle (x_current_display, FRAME_X_WINDOW (f),
f676886a 4138 f->display.x->cursor_gc,
dc6f92b8 4139 left, top, width - 1, height - 1);
c118dd06
JB
4140#else /* ! defined (HAVE_X11) */
4141 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 4142 left, top, width, 1,
f676886a 4143 f->display.x->cursor_pixel);
dc6f92b8 4144
c118dd06 4145 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 4146 left, top, 1, height,
f676886a 4147 f->display.x->cursor_pixel);
dc6f92b8 4148
c118dd06 4149 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 4150 left+width-1, top, 1, height,
f676886a 4151 f->display.x->cursor_pixel);
dc6f92b8 4152
c118dd06 4153 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 4154 left, top+height-1, width, 1,
f676886a 4155 f->display.x->cursor_pixel);
c118dd06 4156#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4157}
4158
f676886a 4159/* Clear the cursor of frame F to background color,
dc6f92b8
JB
4160 and mark the cursor as not shown.
4161 This is used when the text where the cursor is
4162 is about to be rewritten. */
4163
4164static void
f676886a
JB
4165clear_cursor (f)
4166 struct frame *f;
dc6f92b8
JB
4167{
4168 int mask;
4169
f451eb13 4170 if (! FRAME_VISIBLE_P (f)
f676886a 4171 || f->phys_cursor_x < 0)
dc6f92b8
JB
4172 return;
4173
4174#ifdef HAVE_X11
f676886a 4175 x_display_cursor (f, 0);
c118dd06
JB
4176#else /* ! defined (HAVE_X11) */
4177 XPixSet (FRAME_X_WINDOW (f),
12ba150f
JB
4178 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
4179 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
f676886a
JB
4180 FONT_WIDTH (f->display.x->font), FONT_HEIGHT (f->display.x->font),
4181 f->display.x->background_pixel);
c118dd06 4182#endif /* ! defined (HAVE_X11) */
f676886a 4183 f->phys_cursor_x = -1;
dc6f92b8
JB
4184}
4185
f676886a 4186/* Redraw the glyph at ROW, COLUMN on frame F, in the style
90e65f07
JB
4187 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
4188 glyph drawn. */
dc6f92b8
JB
4189
4190static void
f676886a
JB
4191x_draw_single_glyph (f, row, column, glyph, highlight)
4192 struct frame *f;
dc6f92b8 4193 int row, column;
90e65f07 4194 GLYPH glyph;
dc6f92b8
JB
4195 int highlight;
4196{
f676886a 4197 dumpglyphs (f,
12ba150f
JB
4198 CHAR_TO_PIXEL_COL (f, column),
4199 CHAR_TO_PIXEL_ROW (f, row),
07e34cb0 4200 &glyph, 1, highlight);
dc6f92b8
JB
4201}
4202
dc6f92b8 4203static void
dbc4e1c1 4204x_display_bar_cursor (f, on)
f676886a 4205 struct frame *f;
dc6f92b8
JB
4206 int on;
4207{
f676886a 4208 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
90e65f07 4209
49d838ea
JB
4210 /* This is pointless on invisible frames, and dangerous on garbaged
4211 frames; in the latter case, the frame may be in the midst of
4212 changing its size, and curs_x and curs_y may be off the frame. */
4213 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dbc4e1c1
JB
4214 return;
4215
4216 if (! on && f->phys_cursor_x < 0)
4217 return;
4218
f676886a 4219 /* If we're not updating, then we want to use the current frame's
1113d9db 4220 cursor position, not our local idea of where the cursor ought to be. */
f676886a 4221 if (f != updating_frame)
1113d9db 4222 {
f676886a
JB
4223 curs_x = FRAME_CURSOR_X (f);
4224 curs_y = FRAME_CURSOR_Y (f);
1113d9db
JB
4225 }
4226
dbc4e1c1
JB
4227 /* If there is anything wrong with the current cursor state, remove it. */
4228 if (f->phys_cursor_x >= 0
4229 && (!on
4230 || f->phys_cursor_x != curs_x
4231 || f->phys_cursor_y != curs_y
4232 || f->display.x->current_cursor != bar_cursor))
4233 {
4234 /* Erase the cursor by redrawing the character underneath it. */
4235 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4236 f->phys_cursor_glyph,
4237 current_glyphs->highlight[f->phys_cursor_y]);
4238 f->phys_cursor_x = -1;
4239 }
4240
4241 /* If we now need a cursor in the new place or in the new form, do it so. */
4242 if (on
4243 && (f->phys_cursor_x < 0
4244 || (f->display.x->current_cursor != bar_cursor)))
4245 {
4246 f->phys_cursor_glyph
4247 = ((current_glyphs->enable[curs_y]
4248 && curs_x < current_glyphs->used[curs_y])
4249 ? current_glyphs->glyphs[curs_y][curs_x]
4250 : SPACEGLYPH);
4251 XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
4252 f->display.x->cursor_gc,
4253 CHAR_TO_PIXEL_COL (f, curs_x),
4254 CHAR_TO_PIXEL_ROW (f, curs_y),
4255 1, FONT_HEIGHT (f->display.x->font));
4256
4257 f->phys_cursor_x = curs_x;
4258 f->phys_cursor_y = curs_y;
4259
4260 f->display.x->current_cursor = bar_cursor;
4261 }
4262
4263 if (updating_frame != f)
4264 XFlushQueue ();
4265}
4266
4267
4268/* Turn the displayed cursor of frame F on or off according to ON.
4269 If ON is nonzero, where to put the cursor is specified
4270 by F->cursor_x and F->cursor_y. */
4271
4272static void
4273x_display_box_cursor (f, on)
4274 struct frame *f;
4275 int on;
4276{
4277 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4278
49d838ea
JB
4279 /* This is pointless on invisible frames, and dangerous on garbaged
4280 frames; in the latter case, the frame may be in the midst of
4281 changing its size, and curs_x and curs_y may be off the frame. */
4282 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dc6f92b8
JB
4283 return;
4284
4285 /* If cursor is off and we want it off, return quickly. */
f676886a 4286 if (!on && f->phys_cursor_x < 0)
dc6f92b8
JB
4287 return;
4288
dbc4e1c1
JB
4289 /* If we're not updating, then we want to use the current frame's
4290 cursor position, not our local idea of where the cursor ought to be. */
4291 if (f != updating_frame)
4292 {
4293 curs_x = FRAME_CURSOR_X (f);
4294 curs_y = FRAME_CURSOR_Y (f);
4295 }
4296
dc6f92b8
JB
4297 /* If cursor is currently being shown and we don't want it to be
4298 or it is in the wrong place,
4299 or we want a hollow box and it's not so, (pout!)
4300 erase it. */
f676886a 4301 if (f->phys_cursor_x >= 0
dc6f92b8 4302 && (!on
f676886a
JB
4303 || f->phys_cursor_x != curs_x
4304 || f->phys_cursor_y != curs_y
dbc4e1c1 4305 || (f->display.x->current_cursor != hollow_box_cursor
f676886a 4306 && (f != x_highlight_frame))))
dc6f92b8
JB
4307 {
4308 /* Erase the cursor by redrawing the character underneath it. */
f676886a
JB
4309 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4310 f->phys_cursor_glyph,
4311 current_glyphs->highlight[f->phys_cursor_y]);
4312 f->phys_cursor_x = -1;
dc6f92b8
JB
4313 }
4314
4315 /* If we want to show a cursor,
4316 or we want a box cursor and it's not so,
4317 write it in the right place. */
4318 if (on
f676886a 4319 && (f->phys_cursor_x < 0
dbc4e1c1 4320 || (f->display.x->current_cursor != filled_box_cursor
f676886a 4321 && f == x_highlight_frame)))
dc6f92b8 4322 {
f676886a 4323 f->phys_cursor_glyph
1113d9db
JB
4324 = ((current_glyphs->enable[curs_y]
4325 && curs_x < current_glyphs->used[curs_y])
4326 ? current_glyphs->glyphs[curs_y][curs_x]
90e65f07 4327 : SPACEGLYPH);
f676886a 4328 if (f != x_highlight_frame)
dc6f92b8 4329 {
f676886a 4330 x_draw_box (f);
dbc4e1c1 4331 f->display.x->current_cursor = hollow_box_cursor;
dc6f92b8
JB
4332 }
4333 else
4334 {
f676886a
JB
4335 x_draw_single_glyph (f, curs_y, curs_x,
4336 f->phys_cursor_glyph, 2);
dbc4e1c1 4337 f->display.x->current_cursor = filled_box_cursor;
dc6f92b8
JB
4338 }
4339
f676886a
JB
4340 f->phys_cursor_x = curs_x;
4341 f->phys_cursor_y = curs_y;
dc6f92b8
JB
4342 }
4343
f676886a 4344 if (updating_frame != f)
dc6f92b8
JB
4345 XFlushQueue ();
4346}
4347
f676886a
JB
4348x_display_cursor (f, on)
4349 struct frame *f;
dc6f92b8
JB
4350 int on;
4351{
f94397b5
KH
4352 BLOCK_INPUT;
4353
dbc4e1c1 4354 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
f676886a 4355 x_display_box_cursor (f, on);
dbc4e1c1 4356 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
f676886a 4357 x_display_bar_cursor (f, on);
dbc4e1c1
JB
4358 else
4359 /* Those are the only two we have implemented! */
4360 abort ();
f94397b5
KH
4361
4362 UNBLOCK_INPUT;
dc6f92b8
JB
4363}
4364\f
4365/* Icons. */
4366
f676886a 4367/* Refresh bitmap kitchen sink icon for frame F
dc6f92b8
JB
4368 when we get an expose event for it. */
4369
f676886a
JB
4370refreshicon (f)
4371 struct frame *f;
dc6f92b8
JB
4372{
4373#ifdef HAVE_X11
4374 /* Normally, the window manager handles this function. */
c118dd06 4375#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
4376 int mask;
4377
f676886a
JB
4378 if (f->display.x->icon_bitmap_flag)
4379 XBitmapBitsPut (f->display.x->icon_desc, 0, 0, sink_width, sink_height,
dc6f92b8
JB
4380 sink_bits, BlackPixel, WHITE_PIX_DEFAULT,
4381 icon_bitmap, GXcopy, AllPlanes);
4382 else
4383 {
f676886a 4384 extern struct frame *selected_frame;
dc6f92b8
JB
4385 struct Lisp_String *str;
4386 unsigned char *string;
4387
4388 string
f676886a 4389 = XSTRING (XBUFFER (XWINDOW (f->selected_window)->buffer)->name)->data;
dc6f92b8 4390
f676886a 4391 if (f->display.x->icon_label != string)
dc6f92b8 4392 {
f676886a
JB
4393 f->display.x->icon_label = string;
4394 XChangeWindow (f->display.x->icon_desc,
dc6f92b8
JB
4395 XQueryWidth (string, icon_font_info->id) + 10,
4396 icon_font_info->height + 10);
4397 }
4398
f676886a 4399 XText (f->display.x->icon_desc, 5, 5, string,
dc6f92b8
JB
4400 str->size, icon_font_info->id,
4401 BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT);
4402 }
4403 XFlushQueue ();
c118dd06 4404#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4405}
4406
dbc4e1c1 4407/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
4408
4409int
f676886a
JB
4410x_bitmap_icon (f)
4411 struct frame *f;
dc6f92b8
JB
4412{
4413 int mask;
4414 Window icon_window;
4415
c118dd06 4416 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
4417 return 1;
4418
4419#ifdef HAVE_X11
8583db58
RS
4420 if (! icon_bitmap)
4421 icon_bitmap =
4422 XCreateBitmapFromData (x_current_display, FRAME_X_WINDOW (f),
4423 gnu_bits, gnu_width, gnu_height);
f676886a
JB
4424 x_wm_set_icon_pixmap (f, icon_bitmap);
4425 f->display.x->icon_bitmap_flag = 1;
c118dd06 4426#else /* ! defined (HAVE_X11) */
f676886a 4427 if (f->display.x->icon_desc)
dc6f92b8 4428 {
c118dd06 4429 XClearIconWindow (FRAME_X_WINDOW (f));
f676886a 4430 XDestroyWindow (f->display.x->icon_desc);
dc6f92b8
JB
4431 }
4432
f676886a 4433 icon_window = XCreateWindow (f->display.x->parent_desc,
dc6f92b8
JB
4434 0, 0, sink_width, sink_height,
4435 2, WhitePixmap, (Pixmap) NULL);
4436
4437 if (icon_window == 0)
4438 return 1;
4439
c118dd06 4440 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
dc6f92b8
JB
4441 XSelectInput (icon_window, ExposeWindow | UnmapWindow);
4442
f676886a
JB
4443 f->display.x->icon_desc = icon_window;
4444 f->display.x->icon_bitmap_flag = 1;
dc6f92b8
JB
4445
4446 if (icon_bitmap == 0)
4447 icon_bitmap
4448 = XStoreBitmap (sink_mask_width, sink_mask_height, sink_mask_bits);
c118dd06 4449#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4450
4451 return 0;
4452}
4453
4454
f676886a 4455/* Make the x-window of frame F use a rectangle with text. */
dc6f92b8
JB
4456
4457int
f676886a
JB
4458x_text_icon (f, icon_name)
4459 struct frame *f;
dc6f92b8
JB
4460 char *icon_name;
4461{
4462#ifndef HAVE_X11
4463 int mask;
4464 int width;
4465 Window icon_window;
4466 char *X_DefaultValue;
4467 Bitmap b1;
4468
dc6f92b8
JB
4469#ifndef WhitePixel
4470#define WhitePixel 1
c118dd06 4471#endif /* WhitePixel */
dc6f92b8
JB
4472
4473#ifndef BlackPixel
4474#define BlackPixel 0
c118dd06
JB
4475#endif /* BlackPixel */
4476#endif /* HAVE_X11 */
dc6f92b8 4477
c118dd06 4478 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
4479 return 1;
4480
dc6f92b8
JB
4481#ifdef HAVE_X11
4482 if (icon_name)
f676886a 4483 f->display.x->icon_label = icon_name;
dc6f92b8 4484 else
f676886a
JB
4485 if (! f->display.x->icon_label)
4486 f->display.x->icon_label = " *emacs* ";
dc6f92b8 4487
dfeccd2d 4488#if 0
c118dd06 4489 XSetIconName (x_current_display, FRAME_X_WINDOW (f),
f676886a 4490 (char *) f->display.x->icon_label);
dfeccd2d 4491#endif
dc6f92b8 4492
f676886a 4493 f->display.x->icon_bitmap_flag = 0;
b1c884c3 4494 x_wm_set_icon_pixmap (f, 0);
c118dd06 4495#else /* ! defined (HAVE_X11) */
dbc4e1c1
JB
4496 if (icon_font_info == 0)
4497 icon_font_info
4498 = XGetFont (XGetDefault (XDISPLAY
59653951 4499 (char *) XSTRING (Vinvocation_name)->data,
dbc4e1c1
JB
4500 "BodyFont"));
4501
f676886a 4502 if (f->display.x->icon_desc)
dc6f92b8 4503 {
c118dd06 4504 XClearIconWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a 4505 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
dc6f92b8
JB
4506 }
4507
4508 if (icon_name)
f676886a 4509 f->display.x->icon_label = (unsigned char *) icon_name;
dc6f92b8 4510 else
f676886a
JB
4511 if (! f->display.x->icon_label)
4512 f->display.x->icon_label = XSTRING (f->name)->data;
dc6f92b8 4513
f676886a
JB
4514 width = XStringWidth (f->display.x->icon_label, icon_font_info, 0, 0);
4515 icon_window = XCreateWindow (f->display.x->parent_desc,
4516 f->display.x->left_pos,
4517 f->display.x->top_pos,
dc6f92b8
JB
4518 width + 10, icon_font_info->height + 10,
4519 2, BlackPixmap, WhitePixmap);
4520
4521 if (icon_window == 0)
4522 return 1;
4523
c118dd06 4524 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
dc6f92b8
JB
4525 XSelectInput (icon_window, ExposeWindow | ExposeRegion | UnmapWindow | ButtonPressed);
4526
f676886a
JB
4527 f->display.x->icon_desc = icon_window;
4528 f->display.x->icon_bitmap_flag = 0;
4529 f->display.x->icon_label = 0;
c118dd06 4530#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4531
4532 return 0;
4533}
4534\f
4746118a
JB
4535/* Handling X errors. */
4536
12ba150f
JB
4537/* Shut down Emacs in an orderly fashion, because of a SIGPIPE on the
4538 X server's connection, or an error reported via the X protocol. */
16bd92ea 4539
4746118a 4540static SIGTYPE
c118dd06 4541x_connection_closed ()
4746118a
JB
4542{
4543 if (_Xdebug)
4544 abort ();
12ba150f 4545
1cd2d6d4 4546 shut_down_emacs (0, 1, Qnil);
12ba150f
JB
4547
4548 exit (70);
4746118a
JB
4549}
4550
8922af5f
JB
4551/* An X error handler which prints an error message and then kills
4552 Emacs. This is what's normally installed as Xlib's handler for
4553 protocol errors. */
c118dd06
JB
4554static int
4555x_error_quitter (display, error)
4556 Display *display;
4557 XErrorEvent *error;
4558{
4559 char buf[256];
dc6f92b8 4560
c118dd06
JB
4561 /* Note that there is no real way portable across R3/R4 to get the
4562 original error handler. */
dc6f92b8 4563
c118dd06
JB
4564 XGetErrorText (display, error->error_code, buf, sizeof (buf));
4565 fprintf (stderr, "X protocol error: %s on protocol request %d\n",
4566 buf, error->request_code);
dc6f92b8 4567
e09f9351 4568#if 0
12ba150f
JB
4569 /* While we're testing Emacs 19, we'll just dump core whenever we
4570 get an X error, so we can figure out why it happened. */
4571 abort ();
e09f9351 4572#endif
12ba150f 4573
c118dd06 4574 x_connection_closed ();
dc6f92b8
JB
4575}
4576
8922af5f
JB
4577/* A handler for X IO errors which prints an error message and then
4578 kills Emacs. This is what is always installed as Xlib's handler
4579 for I/O errors. */
4580static int
4581x_io_error_quitter (display)
4582 Display *display;
4583{
4584 fprintf (stderr, "Connection to X server %s lost.\n",
4585 XDisplayName (DisplayString (display)));
4586
e09f9351 4587#if 0
8922af5f
JB
4588 /* While we're testing Emacs 19, we'll just dump core whenever we
4589 get an X error, so we can figure out why it happened. */
4590 abort ();
e09f9351 4591#endif
8922af5f
JB
4592
4593 x_connection_closed ();
4594}
4595
c118dd06 4596/* A buffer for storing X error messages. */
cef13e55
RS
4597static char *x_caught_error_message;
4598#define X_CAUGHT_ERROR_MESSAGE_SIZE 200
c118dd06
JB
4599
4600/* An X error handler which stores the error message in
4601 x_caught_error_message. This is what's installed when
4602 x_catch_errors is in effect. */
4603static int
4604x_error_catcher (display, error)
4605 Display *display;
4606 XErrorEvent *error;
4607{
4608 XGetErrorText (display, error->error_code,
cef13e55 4609 x_caught_error_message, X_CAUGHT_ERROR_MESSAGE_SIZE);
c118dd06
JB
4610}
4611
4612
4613/* Begin trapping X errors.
dc6f92b8 4614
c118dd06
JB
4615 After calling this function, X protocol errors no longer cause
4616 Emacs to exit; instead, they are recorded in x_cfc_error_message.
dc6f92b8 4617
c118dd06
JB
4618 Calling x_check_errors signals an Emacs error if an X error has
4619 occurred since the last call to x_catch_errors or x_check_errors.
4620
4621 Calling x_uncatch_errors resumes the normal error handling. */
4622
bc20ebbf 4623void x_catch_errors (), x_check_errors (), x_uncatch_errors ();
c118dd06
JB
4624
4625void
4626x_catch_errors ()
dc6f92b8 4627{
c118dd06
JB
4628 /* Make sure any errors from previous requests have been dealt with. */
4629 XSync (x_current_display, False);
dc6f92b8 4630
c118dd06 4631 /* Set up the error buffer. */
60f9aad3 4632 x_caught_error_message
cef13e55
RS
4633 = (char*) xmalloc (X_CAUGHT_ERROR_MESSAGE_SIZE);
4634 x_caught_error_message[0] = '\0';
16bd92ea 4635
c118dd06
JB
4636 /* Install our little error handler. */
4637 XHandleError (x_error_catcher);
4638}
16bd92ea 4639
c118dd06
JB
4640/* If any X protocol errors have arrived since the last call to
4641 x_catch_errors or x_check_errors, signal an Emacs error using
4642 sprintf (a buffer, FORMAT, the x error message text) as the text. */
812361a1 4643
c118dd06
JB
4644void
4645x_check_errors (format)
4646 char *format;
4647{
4648 /* Make sure to catch any errors incurred so far. */
4649 XSync (x_current_display, False);
16bd92ea 4650
cef13e55 4651 if (x_caught_error_message[0])
c118dd06 4652 {
cef13e55 4653 char buf[X_CAUGHT_ERROR_MESSAGE_SIZE + 56];
dc6f92b8 4654
cef13e55 4655 sprintf (buf, format, x_caught_error_message);
c118dd06
JB
4656 x_uncatch_errors ();
4657 error (buf);
4658 }
4659}
4660
b849c413
RS
4661/* Nonzero if we had any X protocol errors since we did x_catch_errors. */
4662
4663int
4664x_had_errors_p ()
4665{
4666 /* Make sure to catch any errors incurred so far. */
4667 XSync (x_current_display, False);
4668
4669 return x_caught_error_message[0] != 0;
4670}
4671
812361a1
RS
4672/* Stop catching X protocol errors and let them make Emacs die. */
4673
c118dd06
JB
4674void
4675x_uncatch_errors ()
4676{
9ac0d9e0 4677 xfree (x_caught_error_message);
cef13e55 4678 x_caught_error_message = 0;
c118dd06 4679 XHandleError (x_error_quitter);
dc6f92b8
JB
4680}
4681
dc6f92b8
JB
4682#if 0
4683static unsigned int x_wire_count;
4684x_trace_wire ()
4685{
4686 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
4687}
c118dd06 4688#endif /* ! 0 */
dc6f92b8
JB
4689
4690\f
f451eb13
JB
4691/* Changing the font of the frame. */
4692
f676886a 4693/* Set the font of the x-window specified by frame F
dc6f92b8 4694 to the font named NEWNAME. This is safe to use
f676886a 4695 even before F has an actual x-window. */
dc6f92b8
JB
4696
4697#ifdef HAVE_X11
4698
2224a5fc
RS
4699struct font_info
4700{
4701 XFontStruct *font;
4702 char *name;
4703};
4704
dc6f92b8 4705/* A table of all the fonts we have already loaded. */
2224a5fc 4706static struct font_info *x_font_table;
dc6f92b8
JB
4707
4708/* The current capacity of x_font_table. */
4709static int x_font_table_size;
4710
4711/* The number of fonts actually stored in x_font_table.
4712 x_font_table[n] is used and valid iff 0 <= n < n_fonts.
4713 0 <= n_fonts <= x_font_table_size. */
4714static int n_fonts;
4715
b5cf7a0e 4716Lisp_Object
f676886a
JB
4717x_new_font (f, fontname)
4718 struct frame *f;
dc6f92b8
JB
4719 register char *fontname;
4720{
dc6f92b8
JB
4721 int already_loaded;
4722 int n_matching_fonts;
4723 XFontStruct *font_info;
4724 char **font_names;
4725
4726 /* Get a list of all the fonts that match this name. Once we
4727 have a list of matching fonts, we compare them against the fonts
4728 we already have by comparing font ids. */
2224a5fc
RS
4729 font_names = (char **) XListFonts (x_current_display, fontname,
4730 1024, &n_matching_fonts);
0c94f6ee
JB
4731 /* Apparently it doesn't set n_matching_fonts to zero when it can't
4732 find any matches; font_names == 0 is the only clue. */
4733 if (! font_names)
4734 n_matching_fonts = 0;
4735
5835f860
RS
4736 /* Don't just give up if n_matching_fonts is 0.
4737 Apparently there's a bug on Suns: XListFontsWithInfo can
4738 fail to find a font, but XLoadQueryFont may still find it. */
dc6f92b8 4739
90e65f07 4740 /* See if we've already loaded a matching font. */
5835f860
RS
4741 already_loaded = -1;
4742 if (n_matching_fonts != 0)
4743 {
4744 int i, j;
dc6f92b8 4745
5835f860
RS
4746 for (i = 0; i < n_fonts; i++)
4747 for (j = 0; j < n_matching_fonts; j++)
2224a5fc 4748 if (!strcmp (x_font_table[i].name, font_names[j]))
5835f860
RS
4749 {
4750 already_loaded = i;
4751 fontname = font_names[j];
4752 goto found_font;
4753 }
4754 }
dc6f92b8
JB
4755 found_font:
4756
4757 /* If we have, just return it from the table. */
2224a5fc
RS
4758 if (already_loaded >= 0)
4759 f->display.x->font = x_font_table[already_loaded].font;
90e65f07 4760
dc6f92b8
JB
4761 /* Otherwise, load the font and add it to the table. */
4762 else
4763 {
9696f58b 4764 int i;
dc6f92b8
JB
4765 XFontStruct *font;
4766
9696f58b 4767 /* Try to find a character-cell font in the list. */
f126bd67
JB
4768#if 0
4769 /* A laudable goal, but this isn't how to do it. */
9696f58b
JB
4770 for (i = 0; i < n_matching_fonts; i++)
4771 if (! font_info[i].per_char)
4772 break;
f126bd67
JB
4773#else
4774 i = 0;
4775#endif
9696f58b 4776
5835f860
RS
4777 /* See comment above. */
4778 if (n_matching_fonts != 0)
9696f58b
JB
4779 fontname = font_names[i];
4780
dc6f92b8
JB
4781 font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname);
4782 if (! font)
5835f860 4783 {
2224a5fc 4784 /* Free the information from XListFonts. */
5835f860 4785 if (n_matching_fonts)
2224a5fc 4786 XFreeFontNames (font_names);
5835f860
RS
4787 return Qnil;
4788 }
dc6f92b8
JB
4789
4790 /* Do we need to create the table? */
4791 if (x_font_table_size == 0)
4792 {
4793 x_font_table_size = 16;
4794 x_font_table
2224a5fc
RS
4795 = (struct font_info *) xmalloc (x_font_table_size
4796 * sizeof (x_font_table[0]));
dc6f92b8
JB
4797 }
4798 /* Do we need to grow the table? */
4799 else if (n_fonts >= x_font_table_size)
4800 {
90e65f07 4801 x_font_table_size *= 2;
dc6f92b8 4802 x_font_table
2224a5fc
RS
4803 = (struct font_info *) xrealloc (x_font_table,
4804 (x_font_table_size
4805 * sizeof (x_font_table[0])));
dc6f92b8
JB
4806 }
4807
dff815ef 4808 x_font_table[n_fonts].name = (char *) xmalloc (strlen (fontname) + 1);
2224a5fc
RS
4809 bcopy (fontname, x_font_table[n_fonts].name, strlen (fontname) + 1);
4810 f->display.x->font = x_font_table[n_fonts++].font = font;
dc6f92b8 4811 }
2224a5fc 4812
f676886a 4813 /* Now make the frame display the given font. */
c118dd06 4814 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 4815 {
f676886a
JB
4816 XSetFont (x_current_display, f->display.x->normal_gc,
4817 f->display.x->font->fid);
4818 XSetFont (x_current_display, f->display.x->reverse_gc,
4819 f->display.x->font->fid);
4820 XSetFont (x_current_display, f->display.x->cursor_gc,
4821 f->display.x->font->fid);
4822
bc20ebbf 4823 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8
JB
4824 }
4825
b5cf7a0e 4826 {
abdda982 4827 Lisp_Object lispy_name;
b5cf7a0e 4828
abdda982 4829 lispy_name = build_string (fontname);
b5cf7a0e 4830
2224a5fc 4831 /* Free the information from XListFonts. The data
b5cf7a0e 4832 we actually retain comes from XLoadQueryFont. */
2224a5fc 4833 XFreeFontNames (font_names);
b5cf7a0e
JB
4834
4835 return lispy_name;
4836 }
dc6f92b8 4837}
c118dd06 4838#else /* ! defined (HAVE_X11) */
f676886a
JB
4839x_new_font (f, newname)
4840 struct frame *f;
dc6f92b8
JB
4841 register char *newname;
4842{
4843 FONT_TYPE *temp;
4844 int mask;
4845
4846 temp = XGetFont (newname);
4847 if (temp == (FONT_TYPE *) 0)
4848 return 1;
4849
f676886a
JB
4850 if (f->display.x->font)
4851 XLoseFont (f->display.x->font);
dc6f92b8 4852
f676886a 4853 f->display.x->font = temp;
dc6f92b8 4854
c118dd06 4855 if (FRAME_X_WINDOW (f) != 0)
bc20ebbf 4856 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8
JB
4857
4858 return 0;
4859}
c118dd06 4860#endif /* ! defined (HAVE_X11) */
dc6f92b8 4861\f
f676886a
JB
4862x_calc_absolute_position (f)
4863 struct frame *f;
dc6f92b8
JB
4864{
4865#ifdef HAVE_X11
6dba1858
RS
4866 Window win, child;
4867 int win_x = 0, win_y = 0;
4868
4869 /* Find the position of the outside upper-left corner of
4870 the inner window, with respect to the outer window. */
4871 if (f->display.x->parent_desc != ROOT_WINDOW)
4872 {
4873 BLOCK_INPUT;
4874 XTranslateCoordinates (x_current_display,
4875
4876 /* From-window, to-window. */
4877 f->display.x->window_desc,
4878 f->display.x->parent_desc,
4879
4880 /* From-position, to-position. */
4881 0, 0, &win_x, &win_y,
4882
4883 /* Child of win. */
4884 &child);
4885 UNBLOCK_INPUT;
4886 }
4887
4888 /* Treat negative positions as relative to the leftmost bottommost
4889 position that fits on the screen. */
f676886a 4890 if (f->display.x->left_pos < 0)
31ea78fd 4891 f->display.x->left_pos = (x_screen_width
69388238 4892 - 2 * f->display.x->border_width - win_x
31ea78fd
JB
4893 - PIXEL_WIDTH (f)
4894 + f->display.x->left_pos);
dc6f92b8 4895
f676886a 4896 if (f->display.x->top_pos < 0)
31ea78fd 4897 f->display.x->top_pos = (x_screen_height
69388238 4898 - 2 * f->display.x->border_width - win_y
31ea78fd
JB
4899 - PIXEL_HEIGHT (f)
4900 + f->display.x->top_pos);
6dba1858 4901
c118dd06 4902#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
4903 WINDOWINFO_TYPE parentinfo;
4904
c118dd06 4905 XGetWindowInfo (FRAME_X_WINDOW (f), &parentinfo);
dc6f92b8 4906
f676886a
JB
4907 if (f->display.x->left_pos < 0)
4908 f->display.x->left_pos = parentinfo.width + (f->display.x->left_pos + 1)
4909 - PIXEL_WIDTH (f) - 2 * f->display.x->internal_border_width;
dc6f92b8 4910
f676886a
JB
4911 if (f->display.x->top_pos < 0)
4912 f->display.x->top_pos = parentinfo.height + (f->display.x->top_pos + 1)
4913 - PIXEL_HEIGHT (f) - 2 * f->display.x->internal_border_width;
c118dd06 4914#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4915}
4916
f676886a
JB
4917x_set_offset (f, xoff, yoff)
4918 struct frame *f;
dc6f92b8
JB
4919 register int xoff, yoff;
4920{
f676886a
JB
4921 f->display.x->top_pos = yoff;
4922 f->display.x->left_pos = xoff;
4923 x_calc_absolute_position (f);
dc6f92b8
JB
4924
4925 BLOCK_INPUT;
3afe33e7
RS
4926#ifdef USE_X_TOOLKIT
4927 XMoveWindow (XDISPLAY XtWindow (f->display.x->widget),
4928 f->display.x->left_pos, f->display.x->top_pos);
4929#else /* not USE_X_TOOLKIT */
c118dd06 4930 XMoveWindow (XDISPLAY FRAME_X_WINDOW (f),
f676886a 4931 f->display.x->left_pos, f->display.x->top_pos);
3afe33e7 4932#endif /* not USE_X_TOOLKIT */
dc6f92b8 4933#ifdef HAVE_X11
bc20ebbf 4934 x_wm_set_size_hint (f, 0, 1, xoff, yoff);
c118dd06 4935#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4936 UNBLOCK_INPUT;
4937}
4938
bc20ebbf
FP
4939/* Call this to change the size of frame F's x-window.
4940 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
4941 for this size change and subsequent size changes.
4942 Otherwise we leave the window gravity unchanged. */
dc6f92b8 4943
bc20ebbf 4944x_set_window_size (f, change_gravity, cols, rows)
f676886a 4945 struct frame *f;
bc20ebbf 4946 int change_gravity;
b1c884c3 4947 int cols, rows;
dc6f92b8
JB
4948{
4949 int pixelwidth, pixelheight;
4950 int mask;
dc6f92b8 4951
80fd1fe2
FP
4952#ifdef USE_X_TOOLKIT
4953 BLOCK_INPUT;
4954 EmacsFrameSetCharSize (f->display.x->edit_widget, cols, rows);
4955 UNBLOCK_INPUT;
4956
4957#else /* not USE_X_TOOLKIT */
4958
dc6f92b8
JB
4959 BLOCK_INPUT;
4960
b1c884c3 4961 check_frame_size (f, &rows, &cols);
6dba1858
RS
4962 f->display.x->vertical_scroll_bar_extra
4963 = (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4964 ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f)
4965 : 0);
f451eb13
JB
4966 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4967 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8
JB
4968
4969#ifdef HAVE_X11
bc20ebbf 4970 x_wm_set_size_hint (f, 0, change_gravity, 0, 0);
c118dd06
JB
4971#endif /* ! defined (HAVE_X11) */
4972 XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight);
b1c884c3
JB
4973
4974 /* Now, strictly speaking, we can't be sure that this is accurate,
4975 but the window manager will get around to dealing with the size
4976 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
4977 ConfigureNotify event gets here.
4978
4979 We could just not bother storing any of this information here,
4980 and let the ConfigureNotify event set everything up, but that
4981 might be kind of confusing to the lisp code, since size changes
4982 wouldn't be reported in the frame parameters until some random
4983 point in the future when the ConfigureNotify event arrives. */
8922af5f 4984 change_frame_size (f, rows, cols, 0, 0);
b1c884c3
JB
4985 PIXEL_WIDTH (f) = pixelwidth;
4986 PIXEL_HEIGHT (f) = pixelheight;
4987
dbc4e1c1
JB
4988 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4989 receive in the ConfigureNotify event; if we get what we asked
4990 for, then the event won't cause the screen to become garbaged, so
4991 we have to make sure to do it here. */
4992 SET_FRAME_GARBAGED (f);
4993
dc6f92b8
JB
4994 XFlushQueue ();
4995 UNBLOCK_INPUT;
80fd1fe2 4996#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
4997}
4998
4999#ifndef HAVE_X11
f676886a
JB
5000x_set_resize_hint (f)
5001 struct frame *f;
dc6f92b8 5002{
12ba150f
JB
5003 XSetResizeHint (FRAME_X_WINDOW (f),
5004 2 * f->display.x->internal_border_width,
f676886a 5005 2 * f->display.x->internal_border_width,
12ba150f
JB
5006 FONT_WIDTH (f->display.x->font),
5007 FONT_HEIGHT (f->display.x->font));
dc6f92b8 5008}
c118dd06 5009#endif /* HAVE_X11 */
dc6f92b8 5010\f
f451eb13 5011/* Mouse warping, focus shifting, raising and lowering. */
dc6f92b8 5012
f676886a
JB
5013x_set_mouse_position (f, x, y)
5014 struct frame *f;
dc6f92b8
JB
5015 int x, y;
5016{
5017 int pix_x, pix_y;
5018
4466efa5 5019#if 0 /* Let the user ask for this if he wants it. */
f676886a 5020 x_raise_frame (f);
4466efa5 5021#endif
dc6f92b8 5022
12ba150f
JB
5023 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
5024 pix_y = CHAR_TO_PIXEL_ROW (f, y) + FONT_HEIGHT (f->display.x->font) / 2;
f451eb13
JB
5025
5026 if (pix_x < 0) pix_x = 0;
5027 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
5028
5029 if (pix_y < 0) pix_y = 0;
5030 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
5031
5032 BLOCK_INPUT;
dc6f92b8 5033
c118dd06 5034 XWarpMousePointer (FRAME_X_WINDOW (f), pix_x, pix_y);
dc6f92b8
JB
5035 UNBLOCK_INPUT;
5036}
5037
5038#ifdef HAVE_X11
f676886a
JB
5039x_focus_on_frame (f)
5040 struct frame *f;
dc6f92b8 5041{
1fb20991 5042#if 0 /* This proves to be unpleasant. */
f676886a 5043 x_raise_frame (f);
1fb20991 5044#endif
6d4238f3
JB
5045#if 0
5046 /* I don't think that the ICCCM allows programs to do things like this
5047 without the interaction of the window manager. Whatever you end up
f676886a 5048 doing with this code, do it to x_unfocus_frame too. */
c118dd06 5049 XSetInputFocus (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8 5050 RevertToPointerRoot, CurrentTime);
c118dd06 5051#endif /* ! 0 */
dc6f92b8
JB
5052}
5053
f676886a
JB
5054x_unfocus_frame (f)
5055 struct frame *f;
dc6f92b8 5056{
6d4238f3 5057#if 0
f676886a
JB
5058 /* Look at the remarks in x_focus_on_frame. */
5059 if (x_focus_frame == f)
dc6f92b8
JB
5060 XSetInputFocus (x_current_display, PointerRoot,
5061 RevertToPointerRoot, CurrentTime);
c118dd06 5062#endif /* ! 0 */
dc6f92b8
JB
5063}
5064
c118dd06 5065#endif /* ! defined (HAVE_X11) */
dc6f92b8 5066
f676886a 5067/* Raise frame F. */
dc6f92b8 5068
f676886a
JB
5069x_raise_frame (f)
5070 struct frame *f;
dc6f92b8 5071{
3a88c238 5072 if (f->async_visible)
dc6f92b8
JB
5073 {
5074 BLOCK_INPUT;
3afe33e7
RS
5075#ifdef USE_X_TOOLKIT
5076 XRaiseWindow (XDISPLAY XtWindow (f->display.x->widget));
5077#else /* not USE_X_TOOLKIT */
c118dd06 5078 XRaiseWindow (XDISPLAY FRAME_X_WINDOW (f));
3afe33e7 5079#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5080 XFlushQueue ();
5081 UNBLOCK_INPUT;
5082 }
5083}
5084
f676886a 5085/* Lower frame F. */
dc6f92b8 5086
f676886a
JB
5087x_lower_frame (f)
5088 struct frame *f;
dc6f92b8 5089{
3a88c238 5090 if (f->async_visible)
dc6f92b8
JB
5091 {
5092 BLOCK_INPUT;
3afe33e7
RS
5093#ifdef USE_X_TOOLKIT
5094 XLowerWindow (XDISPLAY XtWindow (f->display.x->widget));
5095#else /* not USE_X_TOOLKIT */
c118dd06 5096 XLowerWindow (XDISPLAY FRAME_X_WINDOW (f));
3afe33e7 5097#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5098 XFlushQueue ();
5099 UNBLOCK_INPUT;
5100 }
5101}
5102
dbc4e1c1
JB
5103static void
5104XTframe_raise_lower (f, raise)
5105 FRAME_PTR f;
5106 int raise;
5107{
5108 if (raise)
5109 x_raise_frame (f);
5110 else
5111 x_lower_frame (f);
5112}
5113
5114
dc6f92b8
JB
5115/* Change from withdrawn state to mapped state. */
5116
f676886a
JB
5117x_make_frame_visible (f)
5118 struct frame *f;
dc6f92b8
JB
5119{
5120 int mask;
5121
dc6f92b8 5122 BLOCK_INPUT;
dc6f92b8 5123
f676886a 5124 if (! FRAME_VISIBLE_P (f))
90e65f07
JB
5125 {
5126#ifdef HAVE_X11
5127 if (! EQ (Vx_no_window_manager, Qt))
f676886a 5128 x_wm_set_window_state (f, NormalState);
3afe33e7
RS
5129#ifdef USE_X_TOOLKIT
5130 XtPopup (f->display.x->widget, XtGrabNone);
5131#else /* not USE_X_TOOLKIT */
c118dd06 5132 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
3afe33e7 5133#endif /* not USE_X_TOOLKIT */
ab648270 5134 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
c118dd06
JB
5135 XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
5136#else /* ! defined (HAVE_X11) */
5137 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a
JB
5138 if (f->display.x->icon_desc != 0)
5139 XUnmapWindow (f->display.x->icon_desc);
dc6f92b8 5140
90e65f07 5141 /* Handled by the MapNotify event for X11 */
3a88c238
JB
5142 f->async_visible = 1;
5143 f->async_iconified = 0;
dc6f92b8 5144
f676886a 5145 /* NOTE: this may cause problems for the first frame. */
90e65f07 5146 XTcursor_to (0, 0);
c118dd06 5147#endif /* ! defined (HAVE_X11) */
90e65f07 5148 }
dc6f92b8 5149
dc6f92b8 5150 XFlushQueue ();
90e65f07 5151
dc6f92b8
JB
5152 UNBLOCK_INPUT;
5153}
5154
5155/* Change from mapped state to withdrawn state. */
5156
f676886a
JB
5157x_make_frame_invisible (f)
5158 struct frame *f;
dc6f92b8
JB
5159{
5160 int mask;
5161
9319ae23
RS
5162 /* Don't keep the highlight on an invisible frame. */
5163 if (x_highlight_frame == f)
5164 x_highlight_frame = 0;
5165
5166 if (! f->async_visible && ! f->async_iconified)
dc6f92b8
JB
5167 return;
5168
5169 BLOCK_INPUT;
c118dd06
JB
5170
5171#ifdef HAVE_X11R4
5172
bc20ebbf
FP
5173#ifdef USE_X_TOOLKIT
5174 if (! XWithdrawWindow (x_current_display, XtWindow (f->display.x->widget),
5175 DefaultScreen (x_current_display)))
5176#else /* not USE_X_TOOLKIT */
c118dd06
JB
5177 if (! XWithdrawWindow (x_current_display, FRAME_X_WINDOW (f),
5178 DefaultScreen (x_current_display)))
bc20ebbf 5179#endif /* not USE_X_TOOLKIT */
c118dd06
JB
5180 {
5181 UNBLOCK_INPUT_RESIGNAL;
eb8c3be9 5182 error ("can't notify window manager of window withdrawal");
c118dd06
JB
5183 }
5184
5185#else /* ! defined (HAVE_X11R4) */
dc6f92b8 5186#ifdef HAVE_X11
16bd92ea 5187
c118dd06 5188 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
5189 if (! EQ (Vx_no_window_manager, Qt))
5190 {
16bd92ea 5191 XEvent unmap;
dc6f92b8 5192
16bd92ea 5193 unmap.xunmap.type = UnmapNotify;
bc20ebbf
FP
5194#ifdef USE_X_TOOLKIT
5195 unmap.xunmap.window = XtWindow (f->display.x->widget);
5196#else /* not USE_X_TOOLKIT */
c118dd06 5197 unmap.xunmap.window = FRAME_X_WINDOW (f);
bc20ebbf 5198#endif /* not USE_X_TOOLKIT */
16bd92ea
JB
5199 unmap.xunmap.event = DefaultRootWindow (x_current_display);
5200 unmap.xunmap.from_configure = False;
5201 if (! XSendEvent (x_current_display,
5202 DefaultRootWindow (x_current_display),
5203 False,
5204 SubstructureRedirectMask|SubstructureNotifyMask,
5205 &unmap))
5206 {
5207 UNBLOCK_INPUT_RESIGNAL;
5208 error ("can't notify window manager of withdrawal");
5209 }
dc6f92b8
JB
5210 }
5211
16bd92ea 5212 /* Unmap the window ourselves. Cheeky! */
bc20ebbf
FP
5213#ifdef USE_X_TOOLKIT
5214 XUnmapWindow (x_current_display, XtWindow (f->display.x->widget));
5215#else /* not USE_X_TOOLKIT */
c118dd06 5216 XUnmapWindow (x_current_display, FRAME_X_WINDOW (f));
bc20ebbf 5217#endif /* not USE_X_TOOLKIT */
c118dd06 5218#else /* ! defined (HAVE_X11) */
dc6f92b8 5219
c118dd06 5220 XUnmapWindow (FRAME_X_WINDOW (f));
3a88c238 5221 f->async_visible = 0; /* Handled by the UnMap event for X11 */
f676886a 5222 if (f->display.x->icon_desc != 0)
c118dd06
JB
5223 XUnmapWindow (f->display.x->icon_desc);
5224
5225#endif /* ! defined (HAVE_X11) */
5226#endif /* ! defined (HAVE_X11R4) */
dc6f92b8
JB
5227
5228 XFlushQueue ();
5229 UNBLOCK_INPUT;
5230}
5231
dc6f92b8
JB
5232/* Change window state from mapped to iconified. */
5233
f676886a
JB
5234x_iconify_frame (f)
5235 struct frame *f;
dc6f92b8
JB
5236{
5237 int mask;
3afe33e7 5238 int result;
dc6f92b8 5239
9319ae23
RS
5240 /* Don't keep the highlight on an invisible frame. */
5241 if (x_highlight_frame == f)
5242 x_highlight_frame = 0;
5243
3a88c238 5244 if (f->async_iconified)
dc6f92b8
JB
5245 return;
5246
3afe33e7
RS
5247#ifdef USE_X_TOOLKIT
5248 BLOCK_INPUT;
5249 result = XIconifyWindow (x_current_display,
bc20ebbf 5250 XtWindow (f->display.x->widget),
3afe33e7
RS
5251 DefaultScreen (x_current_display));
5252 UNBLOCK_INPUT;
5253
5254 if (!result)
5255 error ("Can't notify window manager of iconification.");
5256
5257 f->async_iconified = 1;
8c002a25
KH
5258
5259 BLOCK_INPUT;
5260 XFlushQueue ();
5261 UNBLOCK_INPUT;
3afe33e7
RS
5262#else /* not USE_X_TOOLKIT */
5263
dc6f92b8
JB
5264 BLOCK_INPUT;
5265
5266#ifdef HAVE_X11
16bd92ea
JB
5267 /* Since we don't know which revision of X we're running, we'll use both
5268 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
5269
5270 /* X11R4: send a ClientMessage to the window manager using the
5271 WM_CHANGE_STATE type. */
5272 {
5273 XEvent message;
5274
c118dd06 5275 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea
JB
5276 message.xclient.type = ClientMessage;
5277 message.xclient.message_type = Xatom_wm_change_state;
5278 message.xclient.format = 32;
5279 message.xclient.data.l[0] = IconicState;
5280
5281 if (! XSendEvent (x_current_display,
5282 DefaultRootWindow (x_current_display),
5283 False,
5284 SubstructureRedirectMask | SubstructureNotifyMask,
5285 &message))
dc6f92b8
JB
5286 {
5287 UNBLOCK_INPUT_RESIGNAL;
5288 error ("Can't notify window manager of iconification.");
5289 }
16bd92ea 5290 }
dc6f92b8 5291
16bd92ea
JB
5292 /* X11R3: set the initial_state field of the window manager hints to
5293 IconicState. */
5294 x_wm_set_window_state (f, IconicState);
dc6f92b8 5295
a9c00105
RS
5296 if (!FRAME_VISIBLE_P (f))
5297 {
5298 /* If the frame was withdrawn, before, we must map it. */
5299 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
5300 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5301 XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
5302 }
5303
3a88c238 5304 f->async_iconified = 1;
c118dd06
JB
5305#else /* ! defined (HAVE_X11) */
5306 XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8 5307
3a88c238 5308 f->async_visible = 0; /* Handled in the UnMap event for X11. */
f676886a 5309 if (f->display.x->icon_desc != 0)
dc6f92b8 5310 {
f676886a
JB
5311 XMapWindow (XDISPLAY f->display.x->icon_desc);
5312 refreshicon (f);
dc6f92b8 5313 }
c118dd06 5314#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
5315
5316 XFlushQueue ();
5317 UNBLOCK_INPUT;
8c002a25 5318#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5319}
5320
c0ff3fab 5321/* Destroy the X window of frame F. */
dc6f92b8 5322
c0ff3fab 5323x_destroy_window (f)
f676886a 5324 struct frame *f;
dc6f92b8 5325{
dc6f92b8 5326 BLOCK_INPUT;
c0ff3fab
JB
5327
5328 if (f->display.x->icon_desc != 0)
5329 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
5330 XDestroyWindow (XDISPLAY f->display.x->window_desc);
3afe33e7
RS
5331#ifdef USE_X_TOOLKIT
5332 XtDestroyWidget (f->display.x->widget);
9d7e2e3e 5333 free_frame_menubar (f);
3afe33e7
RS
5334#endif /* USE_X_TOOLKIT */
5335
07e34cb0 5336 free_frame_faces (f);
dc6f92b8 5337 XFlushQueue ();
dc6f92b8 5338
9ac0d9e0 5339 xfree (f->display.x);
c0ff3fab 5340 f->display.x = 0;
f676886a
JB
5341 if (f == x_focus_frame)
5342 x_focus_frame = 0;
5343 if (f == x_highlight_frame)
5344 x_highlight_frame = 0;
c0ff3fab
JB
5345
5346 UNBLOCK_INPUT;
dc6f92b8
JB
5347}
5348\f
f451eb13
JB
5349/* Manage event queues for X10. */
5350
dc6f92b8
JB
5351#ifndef HAVE_X11
5352
5353/* Manage event queues.
5354
5355 This code is only used by the X10 support.
5356
5357 We cannot leave events in the X queue and get them when we are ready
5358 because X does not provide a subroutine to get only a certain kind
5359 of event but not block if there are no queued events of that kind.
5360
5361 Therefore, we must examine events as they come in and copy events
5362 of certain kinds into our private queues.
5363
5364 All ExposeRegion events are put in x_expose_queue.
69388238 5365 All ButtonPress and ButtonRelease events are put in x_mouse_queue. */
dc6f92b8
JB
5366
5367
5368/* Write the event *P_XREP into the event queue *QUEUE.
5369 If the queue is full, do nothing, but return nonzero. */
5370
5371int
5372enqueue_event (p_xrep, queue)
5373 register XEvent *p_xrep;
5374 register struct event_queue *queue;
5375{
5376 int newindex = queue->windex + 1;
5377 if (newindex == EVENT_BUFFER_SIZE)
5378 newindex = 0;
5379 if (newindex == queue->rindex)
5380 return -1;
5381 queue->xrep[queue->windex] = *p_xrep;
5382 queue->windex = newindex;
5383 return 0;
5384}
5385
5386/* Fetch the next event from queue *QUEUE and store it in *P_XREP.
5387 If *QUEUE is empty, do nothing and return 0. */
5388
5389int
5390dequeue_event (p_xrep, queue)
5391 register XEvent *p_xrep;
5392 register struct event_queue *queue;
5393{
5394 if (queue->windex == queue->rindex)
5395 return 0;
5396 *p_xrep = queue->xrep[queue->rindex++];
5397 if (queue->rindex == EVENT_BUFFER_SIZE)
5398 queue->rindex = 0;
5399 return 1;
5400}
5401
5402/* Return the number of events buffered in *QUEUE. */
5403
5404int
5405queue_event_count (queue)
5406 register struct event_queue *queue;
5407{
5408 int tem = queue->windex - queue->rindex;
5409 if (tem >= 0)
5410 return tem;
5411 return EVENT_BUFFER_SIZE + tem;
5412}
5413
5414/* Return nonzero if mouse input is pending. */
5415
5416int
5417mouse_event_pending_p ()
5418{
5419 return queue_event_count (&x_mouse_queue);
5420}
c118dd06 5421#endif /* HAVE_X11 */
dc6f92b8 5422\f
f451eb13
JB
5423/* Setting window manager hints. */
5424
dc6f92b8
JB
5425#ifdef HAVE_X11
5426
bc20ebbf
FP
5427/* Record the gravity used previously, in case CHANGE_GRAVITY is 0. */
5428static int previous_gravity;
5429
6dba1858 5430/* SPEC_X and SPEC_Y are the specified positions.
bc20ebbf
FP
5431 We look only at their sign, to decide the gravity.
5432 If CHANGE_GRAVITY is 0, we ignore SPEC_X and SPEC_Y
5433 and leave the gravity unchanged. */
6dba1858 5434
bc20ebbf 5435x_wm_set_size_hint (f, prompting, change_gravity, spec_x, spec_y)
f676886a 5436 struct frame *f;
dc6f92b8 5437 long prompting;
bc20ebbf 5438 int change_gravity;
6dba1858 5439 int spec_x, spec_y;
dc6f92b8
JB
5440{
5441 XSizeHints size_hints;
3afe33e7
RS
5442
5443#ifdef USE_X_TOOLKIT
bc20ebbf 5444 Window window = XtWindow (f->display.x->widget);
3afe33e7 5445#else /* not USE_X_TOOLKIT */
c118dd06 5446 Window window = FRAME_X_WINDOW (f);
3afe33e7 5447#endif /* not USE_X_TOOLKIT */
dc6f92b8 5448
f7f79491 5449 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 5450
f676886a
JB
5451 flexlines = f->height;
5452
5453 size_hints.x = f->display.x->left_pos;
5454 size_hints.y = f->display.x->top_pos;
5455 size_hints.height = PIXEL_HEIGHT (f);
5456 size_hints.width = PIXEL_WIDTH (f);
5457 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
5458 size_hints.height_inc = FONT_HEIGHT (f->display.x->font);
f7f79491 5459#if 0
12ba150f
JB
5460 size_hints.max_width = x_screen_width - CHAR_TO_PIXEL_WIDTH (f, 0);
5461 size_hints.max_height = x_screen_height - CHAR_TO_PIXEL_HEIGHT (f, 0);
f7f79491 5462#endif
b1c884c3 5463 {
b0342f17
JB
5464 int base_width, base_height;
5465
f451eb13
JB
5466 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
5467 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17
JB
5468
5469 {
5470 int min_rows = 0, min_cols = 0;
5471 check_frame_size (f, &min_rows, &min_cols);
5472
5473 /* The window manager uses the base width hints to calculate the
5474 current number of rows and columns in the frame while
5475 resizing; min_width and min_height aren't useful for this
5476 purpose, since they might not give the dimensions for a
5477 zero-row, zero-column frame.
5478
5479 We use the base_width and base_height members if we have
5480 them; otherwise, we set the min_width and min_height members
5481 to the size for a zero x zero frame. */
5482
5483#ifdef HAVE_X11R4
5484 size_hints.flags |= PBaseSize;
5485 size_hints.base_width = base_width;
5486 size_hints.base_height = base_height;
5487 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
5488 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
5489#else
5490 size_hints.min_width = base_width;
5491 size_hints.min_height = base_height;
5492#endif
5493 }
b1c884c3 5494
b1c884c3 5495 }
dc6f92b8
JB
5496
5497 if (prompting)
5498 size_hints.flags |= prompting;
5499 else
5500 {
5501 XSizeHints hints; /* Sometimes I hate X Windows... */
5502
82ee0df4
RS
5503 if (XGetNormalHints (x_current_display, window, &hints) == 0)
5504 hints.flags = 0;
dc6f92b8
JB
5505 if (hints.flags & PSize)
5506 size_hints.flags |= PSize;
5507 if (hints.flags & PPosition)
5508 size_hints.flags |= PPosition;
5509 if (hints.flags & USPosition)
5510 size_hints.flags |= USPosition;
5511 if (hints.flags & USSize)
5512 size_hints.flags |= USSize;
5513 }
2554751d 5514#if defined (PWinGravity)
bc20ebbf 5515 if (change_gravity)
6dba1858 5516 {
bc20ebbf
FP
5517 switch (((spec_x < 0) << 1) + (spec_y < 0))
5518 {
5519 case 0:
5520 size_hints.win_gravity = NorthWestGravity;
5521 break;
5522 case 1:
5523 size_hints.win_gravity = NorthEastGravity;
5524 break;
5525 case 2:
5526 size_hints.win_gravity = SouthWestGravity;
5527 break;
5528 case 3:
5529 size_hints.win_gravity = SouthEastGravity;
5530 break;
5531 }
5532 previous_gravity = size_hints.win_gravity;
6dba1858 5533 }
bc20ebbf
FP
5534 else
5535 size_hints.win_gravity = previous_gravity;
5536
6dba1858 5537 size_hints.flags |= PWinGravity;
2554751d 5538#endif /* PWinGravity */
6dba1858 5539
b0342f17
JB
5540#ifdef HAVE_X11R4
5541 XSetWMNormalHints (x_current_display, window, &size_hints);
5542#else
dc6f92b8 5543 XSetNormalHints (x_current_display, window, &size_hints);
b0342f17 5544#endif
dc6f92b8
JB
5545}
5546
5547/* Used for IconicState or NormalState */
f676886a
JB
5548x_wm_set_window_state (f, state)
5549 struct frame *f;
dc6f92b8
JB
5550 int state;
5551{
3afe33e7 5552#ifdef USE_X_TOOLKIT
bc20ebbf 5553 Window window = XtWindow (f->display.x->widget);
3afe33e7 5554#else /* not USE_X_TOOLKIT */
c118dd06 5555 Window window = FRAME_X_WINDOW (f);
3afe33e7 5556#endif /* not USE_X_TOOLKIT */
dc6f92b8 5557
16bd92ea
JB
5558 f->display.x->wm_hints.flags |= StateHint;
5559 f->display.x->wm_hints.initial_state = state;
b1c884c3 5560
16bd92ea 5561 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
5562}
5563
f676886a
JB
5564x_wm_set_icon_pixmap (f, icon_pixmap)
5565 struct frame *f;
dc6f92b8
JB
5566 Pixmap icon_pixmap;
5567{
c118dd06 5568 Window window = FRAME_X_WINDOW (f);
dc6f92b8 5569
dbc4e1c1
JB
5570 if (icon_pixmap)
5571 {
5572 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
5573 f->display.x->wm_hints.flags |= IconPixmapHint;
5574 }
5575 else
5576 f->display.x->wm_hints.flags &= ~IconPixmapHint;
b1c884c3 5577
16bd92ea 5578 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
5579}
5580
f676886a
JB
5581x_wm_set_icon_position (f, icon_x, icon_y)
5582 struct frame *f;
dc6f92b8
JB
5583 int icon_x, icon_y;
5584{
c118dd06 5585 Window window = FRAME_X_WINDOW (f);
dc6f92b8 5586
16bd92ea
JB
5587 f->display.x->wm_hints.flags |= IconPositionHint;
5588 f->display.x->wm_hints.icon_x = icon_x;
5589 f->display.x->wm_hints.icon_y = icon_y;
b1c884c3 5590
16bd92ea 5591 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
5592}
5593
5594\f
f451eb13
JB
5595/* Initialization. */
5596
3afe33e7
RS
5597#ifdef USE_X_TOOLKIT
5598static XrmOptionDescRec emacs_options[] = {
5599 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
5600 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
5601
5602 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
5603 XrmoptionSepArg, NULL},
5604 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
5605
5606 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5607 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5608 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5609 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5610 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5611 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
5612 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
5613};
5614#endif /* USE_X_TOOLKIT */
5615
dc6f92b8
JB
5616void
5617x_term_init (display_name)
5618 char *display_name;
5619{
f676886a 5620 Lisp_Object frame;
dc6f92b8 5621 char *defaultvalue;
3afe33e7
RS
5622 int argc = 0;
5623 char** argv = 0;
041b69ac 5624#ifndef F_SETOWN_BUG
dc6f92b8
JB
5625#ifdef F_SETOWN
5626 extern int old_fcntl_owner;
c118dd06 5627#endif /* ! defined (F_SETOWN) */
041b69ac 5628#endif /* F_SETOWN_BUG */
6d4238f3 5629
f676886a 5630 x_focus_frame = x_highlight_frame = 0;
dc6f92b8 5631
3afe33e7 5632#ifdef USE_X_TOOLKIT
5c94b90b 5633 argv = (char **) XtMalloc (3 * sizeof (char *));
3afe33e7
RS
5634 argv [0] = "";
5635 argv [1] = "-display";
5636 argv [2] = display_name;
5637 argc = 3;
5638 Xt_app_shell = XtAppInitialize (&Xt_app_con, "Emacs",
bc20ebbf 5639 emacs_options, XtNumber (emacs_options),
3afe33e7
RS
5640 &argc, argv,
5641 NULL, NULL, 0);
5642 XtFree (argv);
5643 x_current_display = XtDisplay (Xt_app_shell);
5644
5645#else /* not USE_X_TOOLKIT */
dc6f92b8 5646 x_current_display = XOpenDisplay (display_name);
3afe33e7 5647#endif /* not USE_X_TOOLKIT */
dc6f92b8 5648 if (x_current_display == 0)
041b69ac
JB
5649 fatal ("X server %s not responding.\n\
5650Check the DISPLAY environment variable or use \"-d\"\n",
dc6f92b8
JB
5651 display_name);
5652
5653#ifdef HAVE_X11
5654 {
dc6f92b8
JB
5655#if 0
5656 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 5657#endif /* ! 0 */
8c86eccd 5658 hostname = get_system_name ();
59653951 5659 x_id_name = (char *) xmalloc (XSTRING (Vinvocation_name)->size
60fb3ee1
JB
5660 + strlen (hostname)
5661 + 2);
59653951 5662 sprintf (x_id_name, "%s@%s", XSTRING (Vinvocation_name)->data, hostname);
dc6f92b8 5663 }
28430d3c
JB
5664
5665 /* Figure out which modifier bits mean what. */
5666 x_find_modifier_meanings ();
f451eb13 5667
ab648270 5668 /* Get the scroll bar cursor. */
d56a553a
RS
5669 x_vertical_scroll_bar_cursor
5670 = XCreateFontCursor (x_current_display, XC_sb_v_double_arrow);
f451eb13 5671
d56a553a 5672#if 0
28430d3c
JB
5673 /* Watch for PropertyNotify events on the root window; we use them
5674 to figure out when to invalidate our cache of the cut buffers. */
5675 x_watch_cut_buffer_cache ();
d56a553a 5676#endif
28430d3c 5677
a4fc7360 5678 if (ConnectionNumber (x_current_display) != 0)
61c3ce62
RS
5679 change_keyboard_wait_descriptor (ConnectionNumber (x_current_display));
5680 change_input_fd (ConnectionNumber (x_current_display));
6d4238f3 5681
c118dd06 5682#endif /* ! defined (HAVE_X11) */
dc6f92b8 5683
041b69ac 5684#ifndef F_SETOWN_BUG
dc6f92b8 5685#ifdef F_SETOWN
61c3ce62 5686 old_fcntl_owner = fcntl (ConnectionNumber (x_current_display), F_GETOWN, 0);
dc6f92b8 5687#ifdef F_SETOWN_SOCK_NEG
61c3ce62
RS
5688 /* stdin is a socket here */
5689 fcntl (ConnectionNumber (x_current_display), F_SETOWN, -getpid ());
c118dd06 5690#else /* ! defined (F_SETOWN_SOCK_NEG) */
61c3ce62 5691 fcntl (ConnectionNumber (x_current_display), F_SETOWN, getpid ());
c118dd06
JB
5692#endif /* ! defined (F_SETOWN_SOCK_NEG) */
5693#endif /* ! defined (F_SETOWN) */
041b69ac 5694#endif /* F_SETOWN_BUG */
dc6f92b8
JB
5695
5696#ifdef SIGIO
5697 init_sigio ();
c118dd06 5698#endif /* ! defined (SIGIO) */
dc6f92b8 5699
dc6f92b8
JB
5700 expose_all_windows = 0;
5701
f676886a 5702 clear_frame_hook = XTclear_frame;
dc6f92b8
JB
5703 clear_end_of_line_hook = XTclear_end_of_line;
5704 ins_del_lines_hook = XTins_del_lines;
5705 change_line_highlight_hook = XTchange_line_highlight;
5706 insert_glyphs_hook = XTinsert_glyphs;
5707 write_glyphs_hook = XTwrite_glyphs;
5708 delete_glyphs_hook = XTdelete_glyphs;
5709 ring_bell_hook = XTring_bell;
5710 reset_terminal_modes_hook = XTreset_terminal_modes;
5711 set_terminal_modes_hook = XTset_terminal_modes;
5712 update_begin_hook = XTupdate_begin;
5713 update_end_hook = XTupdate_end;
5714 set_terminal_window_hook = XTset_terminal_window;
5715 read_socket_hook = XTread_socket;
b8009dd1 5716 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8
JB
5717 cursor_to_hook = XTcursor_to;
5718 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 5719 mouse_position_hook = XTmouse_position;
f451eb13 5720 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 5721 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
5722 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
5723 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
5724 redeem_scroll_bar_hook = XTredeem_scroll_bar;
5725 judge_scroll_bars_hook = XTjudge_scroll_bars;
dc6f92b8 5726
f676886a 5727 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
5728 char_ins_del_ok = 0; /* just as fast to write the line */
5729 line_ins_del_ok = 1; /* we'll just blt 'em */
5730 fast_clear_end_of_line = 1; /* X does this well */
f676886a 5731 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
5732 off the bottom */
5733 baud_rate = 19200;
5734
b30b24cb
RS
5735 /* Try to use interrupt input; if we can't, then start polling. */
5736 Fset_input_mode (Qt, Qnil, Qt, Qnil);
5737
c118dd06
JB
5738 /* Note that there is no real way portable across R3/R4 to get the
5739 original error handler. */
5740 XHandleError (x_error_quitter);
8922af5f 5741 XHandleIOError (x_io_error_quitter);
dc6f92b8
JB
5742
5743 /* Disable Window Change signals; they are handled by X events. */
5744#ifdef SIGWINCH
5745 signal (SIGWINCH, SIG_DFL);
c118dd06 5746#endif /* ! defined (SIGWINCH) */
dc6f92b8 5747
c118dd06 5748 signal (SIGPIPE, x_connection_closed);
dc6f92b8 5749}
55123275
JB
5750
5751void
5752syms_of_xterm ()
5753{
ab648270 5754 staticpro (&last_mouse_scroll_bar);
e53cb100 5755 last_mouse_scroll_bar = Qnil;
b8009dd1
RS
5756 staticpro (&mouse_face_window);
5757 mouse_face_window = Qnil;
55123275 5758}
c118dd06
JB
5759#endif /* ! defined (HAVE_X11) */
5760#endif /* ! defined (HAVE_X_WINDOWS) */