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