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