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