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