(Fdelete_window): Handle deleting a parent of the selected window.
[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
eb8c3be9 706 it's available. If it isn't, we just won't do visual bells. */
dbc4e1c1
JB
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.
eb8c3be9 1291 Each event gets marked with the frame in which it occurred, 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
eb8c3be9 1632 If the last X motion event occurred in a scroll bar, we set this
ab648270 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
a135645a
RS
1703 Don't store anything if we don't have a valid set of values to report.
1704
90e65f07 1705 This clears the mouse_moved flag, so we can wait for the next mouse
12ba150f
JB
1706 movement. This also calls XQueryPointer, which will cause the
1707 server to give us another MotionNotify when the mouse moves
1708 again. */
90e65f07
JB
1709
1710static void
12ba150f 1711XTmouse_position (f, bar_window, part, x, y, time)
f676886a 1712 FRAME_PTR *f;
12ba150f 1713 Lisp_Object *bar_window;
ab648270 1714 enum scroll_bar_part *part;
90e65f07 1715 Lisp_Object *x, *y;
e5d77022 1716 unsigned long *time;
90e65f07 1717{
a135645a
RS
1718 FRAME_PTR f1;
1719
90e65f07
JB
1720 BLOCK_INPUT;
1721
ab648270
JB
1722 if (! NILP (last_mouse_scroll_bar))
1723 x_scroll_bar_report_motion (f, bar_window, part, x, y, time);
90e65f07
JB
1724 else
1725 {
12ba150f
JB
1726 Window root;
1727 int root_x, root_y;
90e65f07 1728
12ba150f
JB
1729 Window dummy_window;
1730 int dummy;
1731
1732 mouse_moved = 0;
ab648270 1733 last_mouse_scroll_bar = Qnil;
12ba150f
JB
1734
1735 /* Figure out which root window we're on. */
1736 XQueryPointer (x_current_display,
1737 DefaultRootWindow (x_current_display),
1738
1739 /* The root window which contains the pointer. */
1740 &root,
1741
1742 /* Trash which we can't trust if the pointer is on
1743 a different screen. */
1744 &dummy_window,
1745
1746 /* The position on that root window. */
1747 &root_x, &root_y,
1748
1749 /* More trash we can't trust. */
1750 &dummy, &dummy,
1751
1752 /* Modifier keys and pointer buttons, about which
1753 we don't care. */
1754 (unsigned int *) &dummy);
1755
1756 /* Now we have a position on the root; find the innermost window
1757 containing the pointer. */
1758 {
1759 Window win, child;
1760 int win_x, win_y;
1761 int parent_x, parent_y;
1762
1763 win = root;
1764 for (;;)
1765 {
1766 XTranslateCoordinates (x_current_display,
1767
1768 /* From-window, to-window. */
1769 root, win,
1770
1771 /* From-position, to-position. */
1772 root_x, root_y, &win_x, &win_y,
1773
1774 /* Child of win. */
1775 &child);
1776
1777 if (child == None)
1778 break;
1779
1780 win = child;
1781 parent_x = win_x;
1782 parent_y = win_y;
1783 }
1784
1785 /* Now we know that:
1786 win is the innermost window containing the pointer
1787 (XTC says it has no child containing the pointer),
1788 win_x and win_y are the pointer's position in it
1789 (XTC did this the last time through), and
1790 parent_x and parent_y are the pointer's position in win's parent.
1791 (They are what win_x and win_y were when win was child.
1792 If win is the root window, it has no parent, and
1793 parent_{x,y} are invalid, but that's okay, because we'll
1794 never use them in that case.) */
1795
1796 /* Is win one of our frames? */
a135645a 1797 f1 = x_window_to_frame (win);
12ba150f 1798
ab648270 1799 /* If not, is it one of our scroll bars? */
a135645a 1800 if (! f1)
12ba150f 1801 {
ab648270 1802 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
1803
1804 if (bar)
1805 {
a135645a 1806 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
1807 win_x = parent_x;
1808 win_y = parent_y;
1809 }
1810 }
90e65f07 1811
a135645a 1812 if (f1)
12ba150f 1813 {
a135645a
RS
1814 /* Ok, we found a frame. Convert from pixels to characters
1815 and store all the values. */
1816
1817 pixel_to_glyph_coords (f1, win_x, win_y, &win_x, &win_y,
12ba150f
JB
1818 &last_mouse_glyph);
1819
1820 *bar_window = Qnil;
1821 *part = 0;
a135645a 1822 *f = f1;
12ba150f
JB
1823 XSET (*x, Lisp_Int, win_x);
1824 XSET (*y, Lisp_Int, win_y);
1825 *time = last_mouse_movement_time;
1826 }
1827 }
1828 }
90e65f07
JB
1829
1830 UNBLOCK_INPUT;
1831}
1832
c118dd06 1833#else /* ! defined (HAVE_X11) */
dc6f92b8 1834#define XEvent XKeyPressedEvent
c118dd06
JB
1835#endif /* ! defined (HAVE_X11) */
1836\f
ab648270 1837/* Scroll bar support. */
f451eb13 1838
ab648270
JB
1839/* Given an X window ID, find the struct scroll_bar which manages it.
1840 This can be called in GC, so we have to make sure to strip off mark
1841 bits. */
1842static struct scroll_bar *
1843x_window_to_scroll_bar (window_id)
f451eb13
JB
1844 Window window_id;
1845{
1846 Lisp_Object tail, frame;
f451eb13 1847
ab648270
JB
1848 for (tail = Vframe_list;
1849 XGCTYPE (tail) == Lisp_Cons;
1850 tail = XCONS (tail)->cdr)
f451eb13 1851 {
f451eb13 1852 Lisp_Object frame = XCONS (tail)->car;
cf7cb199 1853 Lisp_Object bar, condemned;
f451eb13
JB
1854
1855 /* All elements of Vframe_list should be frames. */
ab648270 1856 if (XGCTYPE (frame) != Lisp_Frame)
f451eb13
JB
1857 abort ();
1858
ab648270 1859 /* Scan this frame's scroll bar list for a scroll bar with the
f451eb13 1860 right window ID. */
ab648270
JB
1861 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
1862 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
cf7cb199 1863 /* This trick allows us to search both the ordinary and
ab648270
JB
1864 condemned scroll bar lists with one loop. */
1865 ! GC_NILP (bar) || (bar = condemned,
1866 condemned = Qnil,
1867 ! GC_NILP (bar));
1868 bar = XSCROLL_BAR(bar)->next)
1869 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
1870 return XSCROLL_BAR (bar);
f451eb13
JB
1871 }
1872
1873 return 0;
1874}
1875
ab648270
JB
1876/* Open a new X window to serve as a scroll bar, and return the
1877 scroll bar vector for it. */
1878static struct scroll_bar *
1879x_scroll_bar_create (window, top, left, width, height)
12ba150f 1880 struct window *window;
f451eb13
JB
1881 int top, left, width, height;
1882{
12ba150f 1883 FRAME_PTR frame = XFRAME (WINDOW_FRAME (window));
ab648270
JB
1884 struct scroll_bar *bar =
1885 XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
1886
1887 BLOCK_INPUT;
1888
1889 {
1890 XSetWindowAttributes a;
1891 unsigned long mask;
1892
12ba150f
JB
1893 a.background_pixel = frame->display.x->background_pixel;
1894 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 1895 | ButtonMotionMask | PointerMotionHintMask
12ba150f 1896 | ExposureMask);
ab648270 1897 a.cursor = x_vertical_scroll_bar_cursor;
f451eb13 1898
dbc4e1c1 1899 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 1900
ab648270 1901 SET_SCROLL_BAR_X_WINDOW
12ba150f
JB
1902 (bar,
1903 XCreateWindow (x_current_display, FRAME_X_WINDOW (frame),
f451eb13 1904
ab648270 1905 /* Position and size of scroll bar. */
12ba150f 1906 left, top, width, height,
f451eb13 1907
12ba150f
JB
1908 /* Border width, depth, class, and visual. */
1909 0, CopyFromParent, CopyFromParent, CopyFromParent,
f451eb13 1910
12ba150f
JB
1911 /* Attributes. */
1912 mask, &a));
f451eb13
JB
1913 }
1914
12ba150f
JB
1915 XSET (bar->window, Lisp_Window, window);
1916 XSET (bar->top, Lisp_Int, top);
1917 XSET (bar->left, Lisp_Int, left);
1918 XSET (bar->width, Lisp_Int, width);
1919 XSET (bar->height, Lisp_Int, height);
1920 XSET (bar->start, Lisp_Int, 0);
1921 XSET (bar->end, Lisp_Int, 0);
1922 bar->dragging = Qnil;
f451eb13
JB
1923
1924 /* Add bar to its frame's list of scroll bars. */
ab648270 1925 bar->next = FRAME_SCROLL_BARS (frame);
12ba150f 1926 bar->prev = Qnil;
ab648270 1927 XSET (FRAME_SCROLL_BARS (frame), Lisp_Vector, bar);
12ba150f 1928 if (! NILP (bar->next))
ab648270 1929 XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
f451eb13 1930
ab648270 1931 XMapWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
f451eb13
JB
1932
1933 UNBLOCK_INPUT;
12ba150f
JB
1934
1935 return bar;
f451eb13
JB
1936}
1937
12ba150f
JB
1938/* Draw BAR's handle in the proper position.
1939 If the handle is already drawn from START to END, don't bother
1940 redrawing it, unless REBUILD is non-zero; in that case, always
1941 redraw it. (REBUILD is handy for drawing the handle after expose
1942 events.)
1943
1944 Normally, we want to constrain the start and end of the handle to
ab648270 1945 fit inside its rectangle, but if the user is dragging the scroll bar
12ba150f
JB
1946 handle, we want to let them drag it down all the way, so that the
1947 bar's top is as far down as it goes; otherwise, there's no way to
1948 move to the very end of the buffer. */
f451eb13 1949static void
ab648270
JB
1950x_scroll_bar_set_handle (bar, start, end, rebuild)
1951 struct scroll_bar *bar;
f451eb13 1952 int start, end;
12ba150f 1953 int rebuild;
f451eb13 1954{
12ba150f 1955 int dragging = ! NILP (bar->dragging);
ab648270 1956 Window w = SCROLL_BAR_X_WINDOW (bar);
12ba150f
JB
1957 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
1958
1959 /* If the display is already accurate, do nothing. */
1960 if (! rebuild
1961 && start == XINT (bar->start)
1962 && end == XINT (bar->end))
1963 return;
1964
f451eb13
JB
1965 BLOCK_INPUT;
1966
1967 {
ab648270
JB
1968 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (XINT (bar->width));
1969 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
1970 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
f451eb13
JB
1971
1972 /* Make sure the values are reasonable, and try to preserve
1973 the distance between start and end. */
12ba150f
JB
1974 {
1975 int length = end - start;
1976
1977 if (start < 0)
1978 start = 0;
1979 else if (start > top_range)
1980 start = top_range;
1981 end = start + length;
1982
1983 if (end < start)
1984 end = start;
1985 else if (end > top_range && ! dragging)
1986 end = top_range;
1987 }
f451eb13 1988
ab648270 1989 /* Store the adjusted setting in the scroll bar. */
12ba150f
JB
1990 XSET (bar->start, Lisp_Int, start);
1991 XSET (bar->end, Lisp_Int, end);
f451eb13 1992
12ba150f
JB
1993 /* Clip the end position, just for display. */
1994 if (end > top_range)
1995 end = top_range;
f451eb13 1996
ab648270 1997 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
1998 below top positions, to make sure the handle is always at least
1999 that many pixels tall. */
ab648270 2000 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 2001
12ba150f
JB
2002 /* Draw the empty space above the handle. Note that we can't clear
2003 zero-height areas; that means "clear to end of window." */
2004 if (0 < start)
2005 XClearArea (x_current_display, w,
f451eb13 2006
12ba150f 2007 /* x, y, width, height, and exposures. */
ab648270
JB
2008 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2009 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
2010 inside_width, start,
2011 False);
f451eb13 2012
12ba150f
JB
2013 /* Draw the handle itself. */
2014 XFillRectangle (x_current_display, w, gc,
f451eb13 2015
12ba150f 2016 /* x, y, width, height */
ab648270
JB
2017 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2018 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 2019 inside_width, end - start);
f451eb13 2020
f451eb13 2021
12ba150f
JB
2022 /* Draw the empty space below the handle. Note that we can't
2023 clear zero-height areas; that means "clear to end of window." */
2024 if (end < inside_height)
2025 XClearArea (x_current_display, w,
f451eb13 2026
12ba150f 2027 /* x, y, width, height, and exposures. */
ab648270
JB
2028 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2029 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
2030 inside_width, inside_height - end,
2031 False);
f451eb13 2032
f451eb13
JB
2033 }
2034
f451eb13
JB
2035 UNBLOCK_INPUT;
2036}
2037
eb8c3be9 2038/* Move a scroll bar around on the screen, to accommodate changing
12ba150f 2039 window configurations. */
f451eb13 2040static void
ab648270
JB
2041x_scroll_bar_move (bar, top, left, width, height)
2042 struct scroll_bar *bar;
f451eb13
JB
2043 int top, left, width, height;
2044{
2045 BLOCK_INPUT;
2046
2047 {
2048 XWindowChanges wc;
2049 unsigned int mask = 0;
2050
2051 wc.x = left;
2052 wc.y = top;
2053 wc.width = width;
2054 wc.height = height;
2055
12ba150f
JB
2056 if (left != XINT (bar->left)) mask |= CWX;
2057 if (top != XINT (bar->top)) mask |= CWY;
2058 if (width != XINT (bar->width)) mask |= CWWidth;
2059 if (height != XINT (bar->height)) mask |= CWHeight;
2060
2061 if (mask)
ab648270 2062 XConfigureWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar),
12ba150f 2063 mask, &wc);
f451eb13
JB
2064 }
2065
12ba150f
JB
2066 XSET (bar->left, Lisp_Int, left);
2067 XSET (bar->top, Lisp_Int, top);
2068 XSET (bar->width, Lisp_Int, width);
2069 XSET (bar->height, Lisp_Int, height);
2070
f451eb13
JB
2071 UNBLOCK_INPUT;
2072}
2073
ab648270 2074/* Destroy the X window for BAR, and set its Emacs window's scroll bar
12ba150f
JB
2075 to nil. */
2076static void
ab648270
JB
2077x_scroll_bar_remove (bar)
2078 struct scroll_bar *bar;
12ba150f
JB
2079{
2080 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2081
2082 BLOCK_INPUT;
2083
2084 /* Destroy the window. */
ab648270 2085 XDestroyWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
12ba150f 2086
ab648270
JB
2087 /* Disassociate this scroll bar from its window. */
2088 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
2089
2090 UNBLOCK_INPUT;
2091}
2092
2093/* Set the handle of the vertical scroll bar for WINDOW to indicate
2094 that we are displaying PORTION characters out of a total of WHOLE
ab648270 2095 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f
JB
2096 create one. */
2097static void
ab648270 2098XTset_vertical_scroll_bar (window, portion, whole, position)
f451eb13
JB
2099 struct window *window;
2100 int portion, whole, position;
2101{
2102 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
f451eb13 2103 int top = XINT (window->top);
ab648270
JB
2104 int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
2105 int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
f451eb13 2106
ab648270 2107 /* Where should this scroll bar be, pixelwise? */
12ba150f
JB
2108 int pixel_top = CHAR_TO_PIXEL_ROW (f, top);
2109 int pixel_left = CHAR_TO_PIXEL_COL (f, left);
ab648270
JB
2110 int pixel_width = VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f);
2111 int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
f451eb13 2112
ab648270 2113 struct scroll_bar *bar;
12ba150f 2114
ab648270
JB
2115 /* Does the scroll bar exist yet? */
2116 if (NILP (window->vertical_scroll_bar))
2117 bar = x_scroll_bar_create (window,
f451eb13
JB
2118 pixel_top, pixel_left,
2119 pixel_width, pixel_height);
2120 else
12ba150f
JB
2121 {
2122 /* It may just need to be moved and resized. */
ab648270
JB
2123 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2124 x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
12ba150f 2125 }
f451eb13 2126
ab648270 2127 /* Set the scroll bar's current state, unless we're currently being
f451eb13 2128 dragged. */
12ba150f 2129 if (NILP (bar->dragging))
f451eb13 2130 {
12ba150f 2131 int top_range =
ab648270 2132 VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
f451eb13 2133
12ba150f 2134 if (whole == 0)
ab648270 2135 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
2136 else
2137 {
43f868f5
JB
2138 int start = ((double) position * top_range) / whole;
2139 int end = ((double) (position + portion) * top_range) / whole;
12ba150f 2140
ab648270 2141 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 2142 }
f451eb13
JB
2143 }
2144
ab648270 2145 XSET (window->vertical_scroll_bar, Lisp_Vector, bar);
f451eb13
JB
2146}
2147
12ba150f 2148
f451eb13 2149/* The following three hooks are used when we're doing a thorough
ab648270 2150 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 2151 are going to be deleted, because keeping track of when windows go
12ba150f
JB
2152 away is a real pain - "Can you say set-window-configuration, boys
2153 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 2154 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 2155 from the fiery pit when we actually redisplay its window. */
f451eb13 2156
ab648270
JB
2157/* Arrange for all scroll bars on FRAME to be removed at the next call
2158 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
2159 `*redeem_scroll_bar_hook' is applied to its window before the judgement. */
f451eb13 2160static void
ab648270 2161XTcondemn_scroll_bars (frame)
f451eb13
JB
2162 FRAME_PTR frame;
2163{
12ba150f
JB
2164 /* The condemned list should be empty at this point; if it's not,
2165 then the rest of Emacs isn't using the condemn/redeem/judge
2166 protocol correctly. */
ab648270 2167 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
12ba150f
JB
2168 abort ();
2169
2170 /* Move them all to the "condemned" list. */
ab648270
JB
2171 FRAME_CONDEMNED_SCROLL_BARS (frame) = FRAME_SCROLL_BARS (frame);
2172 FRAME_SCROLL_BARS (frame) = Qnil;
f451eb13
JB
2173}
2174
ab648270 2175/* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
12ba150f 2176 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 2177static void
ab648270 2178XTredeem_scroll_bar (window)
12ba150f 2179 struct window *window;
f451eb13 2180{
ab648270 2181 struct scroll_bar *bar;
12ba150f 2182
ab648270
JB
2183 /* We can't redeem this window's scroll bar if it doesn't have one. */
2184 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
2185 abort ();
2186
ab648270 2187 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
2188
2189 /* Unlink it from the condemned list. */
2190 {
2191 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2192
2193 if (NILP (bar->prev))
2194 {
2195 /* If the prev pointer is nil, it must be the first in one of
2196 the lists. */
ab648270 2197 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
2198 /* It's not condemned. Everything's fine. */
2199 return;
ab648270
JB
2200 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
2201 window->vertical_scroll_bar))
2202 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
2203 else
2204 /* If its prev pointer is nil, it must be at the front of
2205 one or the other! */
2206 abort ();
2207 }
2208 else
ab648270 2209 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
2210
2211 if (! NILP (bar->next))
ab648270 2212 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 2213
ab648270 2214 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 2215 bar->prev = Qnil;
ab648270 2216 XSET (FRAME_SCROLL_BARS (f), Lisp_Vector, bar);
12ba150f 2217 if (! NILP (bar->next))
ab648270 2218 XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
12ba150f 2219 }
f451eb13
JB
2220}
2221
ab648270
JB
2222/* Remove all scroll bars on FRAME that haven't been saved since the
2223 last call to `*condemn_scroll_bars_hook'. */
f451eb13 2224static void
ab648270 2225XTjudge_scroll_bars (f)
12ba150f 2226 FRAME_PTR f;
f451eb13 2227{
12ba150f 2228 Lisp_Object bar, next;
f451eb13 2229
ab648270 2230 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
2231
2232 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
2233 more events on the hapless scroll bars. */
2234 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
2235
2236 for (; ! NILP (bar); bar = next)
f451eb13 2237 {
ab648270 2238 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 2239
ab648270 2240 x_scroll_bar_remove (b);
12ba150f
JB
2241
2242 next = b->next;
2243 b->next = b->prev = Qnil;
f451eb13 2244 }
12ba150f 2245
ab648270 2246 /* Now there should be no references to the condemned scroll bars,
12ba150f 2247 and they should get garbage-collected. */
f451eb13
JB
2248}
2249
2250
ab648270
JB
2251/* Handle an Expose or GraphicsExpose event on a scroll bar.
2252
2253 This may be called from a signal handler, so we have to ignore GC
2254 mark bits. */
f451eb13 2255static void
ab648270
JB
2256x_scroll_bar_expose (bar, event)
2257 struct scroll_bar *bar;
f451eb13
JB
2258 XEvent *event;
2259{
ab648270 2260 Window w = SCROLL_BAR_X_WINDOW (bar);
12ba150f
JB
2261 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
2262
f451eb13
JB
2263 BLOCK_INPUT;
2264
ab648270 2265 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 2266
ab648270 2267 /* Draw a one-pixel border just inside the edges of the scroll bar. */
12ba150f 2268 XDrawRectangle (x_current_display, w, gc,
f451eb13
JB
2269
2270 /* x, y, width, height */
12ba150f 2271 0, 0, XINT (bar->width) - 1, XINT (bar->height) - 1);
f451eb13 2272
12ba150f
JB
2273 /* Draw another line to make the extra-thick border on the right. */
2274 XFillRectangle (x_current_display, w, gc,
f451eb13 2275
12ba150f
JB
2276 /* x, y, width, height */
2277 XINT (bar->width) - 2, 1, 1, XINT (bar->height) - 2);
f451eb13
JB
2278
2279 UNBLOCK_INPUT;
2280}
2281
ab648270
JB
2282/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2283 is set to something other than no_event, it is enqueued.
2284
2285 This may be called from a signal handler, so we have to ignore GC
2286 mark bits. */
f451eb13 2287static void
ab648270
JB
2288x_scroll_bar_handle_click (bar, event, emacs_event)
2289 struct scroll_bar *bar;
f451eb13
JB
2290 XEvent *event;
2291 struct input_event *emacs_event;
2292{
ab648270 2293 if (XGCTYPE (bar->window) != Lisp_Window)
12ba150f
JB
2294 abort ();
2295
ab648270 2296 emacs_event->kind = scroll_bar_click;
12ba150f 2297 XSET (emacs_event->code, Lisp_Int, event->xbutton.button - Button1);
f451eb13 2298 emacs_event->modifiers =
dfeccd2d 2299 (x_x_to_emacs_modifiers (event->xbutton.state)
f451eb13
JB
2300 | (event->type == ButtonRelease
2301 ? up_modifier
2302 : down_modifier));
12ba150f 2303 emacs_event->frame_or_window = bar->window;
f451eb13 2304 emacs_event->timestamp = event->xbutton.time;
12ba150f
JB
2305 {
2306 int internal_height =
ab648270 2307 VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
12ba150f 2308 int top_range =
ab648270
JB
2309 VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2310 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
2311
2312 if (y < 0) y = 0;
2313 if (y > top_range) y = top_range;
2314
2315 if (y < XINT (bar->start))
ab648270
JB
2316 emacs_event->part = scroll_bar_above_handle;
2317 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2318 emacs_event->part = scroll_bar_handle;
12ba150f 2319 else
ab648270 2320 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
2321
2322 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
2323 they want to drag it. Lisp code needs to be able to decide
2324 whether or not we're dragging. */
929787e1 2325#if 0
12ba150f
JB
2326 /* If the user has just clicked on the handle, record where they're
2327 holding it. */
2328 if (event->type == ButtonPress
ab648270 2329 && emacs_event->part == scroll_bar_handle)
12ba150f 2330 XSET (bar->dragging, Lisp_Int, y - XINT (bar->start));
929787e1 2331#endif
12ba150f
JB
2332
2333 /* If the user has released the handle, set it to its final position. */
2334 if (event->type == ButtonRelease
2335 && ! NILP (bar->dragging))
2336 {
2337 int new_start = y - XINT (bar->dragging);
2338 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 2339
ab648270 2340 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
2341 bar->dragging = Qnil;
2342 }
f451eb13 2343
5116f055
JB
2344 /* Same deal here as the other #if 0. */
2345#if 0
eb8c3be9 2346 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 2347 the handle. */
ab648270 2348 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
2349 emacs_event->x = bar->start;
2350 else
2351 XSET (emacs_event->x, Lisp_Int, y);
5116f055
JB
2352#else
2353 XSET (emacs_event->x, Lisp_Int, y);
2354#endif
f451eb13 2355
12ba150f
JB
2356 XSET (emacs_event->y, Lisp_Int, top_range);
2357 }
2358}
f451eb13 2359
ab648270
JB
2360/* Handle some mouse motion while someone is dragging the scroll bar.
2361
2362 This may be called from a signal handler, so we have to ignore GC
2363 mark bits. */
f451eb13 2364static void
ab648270
JB
2365x_scroll_bar_note_movement (bar, event)
2366 struct scroll_bar *bar;
f451eb13
JB
2367 XEvent *event;
2368{
2369 last_mouse_movement_time = event->xmotion.time;
2370
2371 mouse_moved = 1;
ab648270 2372 XSET (last_mouse_scroll_bar, Lisp_Vector, bar);
f451eb13
JB
2373
2374 /* If we're dragging the bar, display it. */
ab648270 2375 if (! GC_NILP (bar->dragging))
f451eb13
JB
2376 {
2377 /* Where should the handle be now? */
12ba150f 2378 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 2379
12ba150f 2380 if (new_start != XINT (bar->start))
f451eb13 2381 {
12ba150f 2382 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 2383
ab648270 2384 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
2385 }
2386 }
2387
2388 /* Call XQueryPointer so we'll get an event the next time the mouse
2389 moves and we can see *still* on the same position. */
2390 {
2391 int dummy;
2392
2393 XQueryPointer (event->xmotion.display, event->xmotion.window,
2394 (Window *) &dummy, (Window *) &dummy,
2395 &dummy, &dummy, &dummy, &dummy,
2396 (unsigned int *) &dummy);
2397 }
2398}
2399
12ba150f 2400/* Return information to the user about the current position of the mouse
ab648270 2401 on the scroll bar. */
12ba150f 2402static void
ab648270 2403x_scroll_bar_report_motion (f, bar_window, part, x, y, time)
12ba150f
JB
2404 FRAME_PTR *f;
2405 Lisp_Object *bar_window;
ab648270 2406 enum scroll_bar_part *part;
12ba150f
JB
2407 Lisp_Object *x, *y;
2408 unsigned long *time;
2409{
ab648270 2410 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
12ba150f 2411 int win_x, win_y;
559cb2fb
JB
2412 Window dummy_window;
2413 int dummy_coord;
2414 unsigned int dummy_mask;
12ba150f 2415
cf7cb199
JB
2416 BLOCK_INPUT;
2417
ab648270 2418 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 2419 report that. */
559cb2fb
JB
2420 if (! XQueryPointer (x_current_display,
2421 SCROLL_BAR_X_WINDOW (bar),
12ba150f 2422
559cb2fb
JB
2423 /* Root, child, root x and root y. */
2424 &dummy_window, &dummy_window,
2425 &dummy_coord, &dummy_coord,
12ba150f 2426
559cb2fb
JB
2427 /* Position relative to scroll bar. */
2428 &win_x, &win_y,
12ba150f 2429
559cb2fb
JB
2430 /* Mouse buttons and modifier keys. */
2431 &dummy_mask))
2432 *f = 0;
2433 else
2434 {
2435 int inside_height
2436 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2437 int top_range
2438 = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2439
2440 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2441
2442 if (! NILP (bar->dragging))
2443 win_y -= XINT (bar->dragging);
2444
2445 if (win_y < 0)
2446 win_y = 0;
2447 if (win_y > top_range)
2448 win_y = top_range;
2449
2450 *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2451 *bar_window = bar->window;
2452
2453 if (! NILP (bar->dragging))
2454 *part = scroll_bar_handle;
2455 else if (win_y < XINT (bar->start))
2456 *part = scroll_bar_above_handle;
2457 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2458 *part = scroll_bar_handle;
2459 else
2460 *part = scroll_bar_below_handle;
12ba150f 2461
559cb2fb
JB
2462 XSET (*x, Lisp_Int, win_y);
2463 XSET (*y, Lisp_Int, top_range);
12ba150f 2464
559cb2fb
JB
2465 mouse_moved = 0;
2466 last_mouse_scroll_bar = Qnil;
2467 }
12ba150f 2468
559cb2fb 2469 *time = last_mouse_movement_time;
cf7cb199 2470
cf7cb199 2471 UNBLOCK_INPUT;
12ba150f
JB
2472}
2473
f451eb13 2474
dbc4e1c1 2475/* The screen has been cleared so we may have changed foreground or
ab648270
JB
2476 background colors, and the scroll bars may need to be redrawn.
2477 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
2478 redraw them. */
2479
ab648270 2480x_scroll_bar_clear (f)
dbc4e1c1
JB
2481 FRAME_PTR f;
2482{
2483 Lisp_Object bar;
2484
ab648270 2485 for (bar = FRAME_SCROLL_BARS (f);
dbc4e1c1 2486 XTYPE (bar) == Lisp_Vector;
ab648270
JB
2487 bar = XSCROLL_BAR (bar)->next)
2488 XClearArea (x_current_display, SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
dbc4e1c1
JB
2489 0, 0, 0, 0, True);
2490}
2491
2492
f451eb13
JB
2493\f
2494/* The main X event-reading loop - XTread_socket. */
dc6f92b8 2495
dc6f92b8
JB
2496/* Timestamp of enter window event. This is only used by XTread_socket,
2497 but we have to put it out here, since static variables within functions
2498 sometimes don't work. */
2499static Time enter_timestamp;
2500
11edeb03
JB
2501/* This holds the state XLookupString needs to implement dead keys
2502 and other tricks known as "compose processing". _X Window System_
2503 says that a portable program can't use this, but Stephen Gildea assures
2504 me that letting the compiler initialize it to zeros will work okay.
2505
2506 This must be defined outside of XTread_socket, for the same reasons
2507 given for enter_timestamp, above. */
2508static XComposeStatus compose_status;
2509
c047688c
JA
2510/* Communication with window managers. */
2511Atom Xatom_wm_protocols;
2512
2513/* Kinds of protocol things we may receive. */
2514Atom Xatom_wm_take_focus;
2515Atom Xatom_wm_save_yourself;
2516Atom Xatom_wm_delete_window;
2517
2518/* Other WM communication */
2519Atom Xatom_wm_configure_denied; /* When our config request is denied */
2520Atom Xatom_wm_window_moved; /* When the WM moves us. */
2521
d56a553a
RS
2522/* Window manager communication. */
2523Atom Xatom_wm_change_state;
2524
10e6549c
RS
2525/* Record the last 100 characters stored
2526 to help debug the loss-of-chars-during-GC problem. */
2527int temp_index;
2528short temp_buffer[100];
2529
dc6f92b8
JB
2530/* Read events coming from the X server.
2531 This routine is called by the SIGIO handler.
2532 We return as soon as there are no more events to be read.
2533
2534 Events representing keys are stored in buffer BUFP,
2535 which can hold up to NUMCHARS characters.
2536 We return the number of characters stored into the buffer,
2537 thus pretending to be `read'.
2538
2539 WAITP is nonzero if we should block until input arrives.
2540 EXPECTED is nonzero if the caller knows input is available. */
2541
7c5283e4 2542int
dc6f92b8
JB
2543XTread_socket (sd, bufp, numchars, waitp, expected)
2544 register int sd;
2545 register struct input_event *bufp;
2546 register int numchars;
2547 int waitp;
2548 int expected;
2549{
2550 int count = 0;
2551 int nbytes = 0;
2552 int mask;
2553 int items_pending; /* How many items are in the X queue. */
2554 XEvent event;
f676886a 2555 struct frame *f;
dc6f92b8
JB
2556 int event_found;
2557 int prefix;
2558 Lisp_Object part;
2559
9ac0d9e0 2560 if (interrupt_input_blocked)
dc6f92b8 2561 {
9ac0d9e0 2562 interrupt_input_pending = 1;
dc6f92b8
JB
2563 return -1;
2564 }
2565
9ac0d9e0 2566 interrupt_input_pending = 0;
dc6f92b8
JB
2567 BLOCK_INPUT;
2568
2569 if (numchars <= 0)
2570 abort (); /* Don't think this happens. */
2571
2572#ifdef FIOSNBIO
2573 /* If available, Xlib uses FIOSNBIO to make the socket
2574 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
2575 FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK,
2576 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
2577 fcntl (fileno (stdin), F_SETFL, 0);
c118dd06 2578#endif /* ! defined (FIOSNBIO) */
dc6f92b8
JB
2579
2580#ifndef SIGIO
2581#ifndef HAVE_SELECT
2582 if (! (fcntl (fileno (stdin), F_GETFL, 0) & O_NDELAY))
2583 {
2584 extern int read_alarm_should_throw;
2585 read_alarm_should_throw = 1;
2586 XPeekEvent (XDISPLAY &event);
2587 read_alarm_should_throw = 0;
2588 }
c118dd06
JB
2589#endif /* HAVE_SELECT */
2590#endif /* SIGIO */
dc6f92b8
JB
2591
2592 while (XStuffPending () != 0)
2593 {
2594 XNextEvent (XDISPLAY &event);
2595 event_found = 1;
2596
2597 switch (event.type)
2598 {
2599#ifdef HAVE_X11
c047688c
JA
2600 case ClientMessage:
2601 {
2602 if (event.xclient.message_type == Xatom_wm_protocols
2603 && event.xclient.format == 32)
2604 {
2605 if (event.xclient.data.l[0] == Xatom_wm_take_focus)
2606 {
f676886a
JB
2607 f = x_window_to_frame (event.xclient.window);
2608 if (f)
2609 x_focus_on_frame (f);
ab648270 2610 /* Not certain about handling scroll bars here */
c047688c
JA
2611 }
2612 else if (event.xclient.data.l[0] == Xatom_wm_save_yourself)
2613 {
2614 /* Save state modify the WM_COMMAND property to
2615 something which can reinstate us. This notifies
2616 the session manager, who's looking for such a
2617 PropertyNotify. Can restart processing when
2618 a keyboard or mouse event arrives. */
2619 if (numchars > 0)
2620 {
2621 }
2622 }
2623 else if (event.xclient.data.l[0] == Xatom_wm_delete_window)
2624 {
f676886a 2625 struct frame *f = x_window_to_frame (event.xclient.window);
c047688c 2626
f676886a 2627 if (f)
c047688c
JA
2628 if (numchars > 0)
2629 {
2630 }
2631 }
2632 }
2633 else if (event.xclient.message_type == Xatom_wm_configure_denied)
2634 {
2635 }
2636 else if (event.xclient.message_type == Xatom_wm_window_moved)
2637 {
2638 int new_x, new_y;
2639
4357eba7
JB
2640 new_x = event.xclient.data.s[0];
2641 new_y = event.xclient.data.s[1];
c047688c
JA
2642 }
2643 }
2644 break;
dc6f92b8 2645
d56a553a
RS
2646#ifdef NEW_SELECTIONS
2647 case SelectionNotify:
2648 x_handle_selection_notify (&event);
2649 break;
2650#endif
2651
dc6f92b8 2652 case SelectionClear: /* Someone has grabbed ownership. */
d56a553a
RS
2653#ifdef NEW_SELECTIONS
2654 {
2655 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
2656
2657 if (numchars == 0)
2658 abort ();
2659
2660 bufp->kind = selection_clear_event;
2661 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
2662 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
2663 SELECTION_EVENT_TIME (bufp) = eventp->time;
2664 bufp++;
2665
2666 count += 1;
2667 numchars -= 1;
2668 }
2669#else
dc6f92b8
JB
2670 x_disown_selection (event.xselectionclear.window,
2671 event.xselectionclear.selection,
2672 event.xselectionclear.time);
d56a553a 2673#endif
dc6f92b8
JB
2674 break;
2675
2676 case SelectionRequest: /* Someone wants our selection. */
d56a553a
RS
2677#ifdef NEW_SELECTIONS
2678 {
2679 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
2680
2681 if (numchars == 0)
2682 abort ();
2683
2684 bufp->kind = selection_request_event;
2685 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
2686 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
2687 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
2688 SELECTION_EVENT_TARGET (bufp) = eventp->target;
2689 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
2690 SELECTION_EVENT_TIME (bufp) = eventp->time;
2691 bufp++;
2692
2693 count += 1;
2694 numchars -= 1;
2695 }
2696#else
dc6f92b8 2697 x_answer_selection_request (event);
d56a553a 2698#endif
dc6f92b8
JB
2699 break;
2700
2701 case PropertyNotify:
d56a553a
RS
2702#ifdef NEW_SELECTIONS
2703 x_handle_property_notify (&event);
2704#else
28430d3c
JB
2705 /* If we're being told about a root window property, then it's
2706 a cut buffer change. */
2707 if (event.xproperty.window == ROOT_WINDOW)
2708 x_invalidate_cut_buffer_cache (&event.xproperty);
2709
2710 /* Otherwise, we're probably handling an incremental
2711 selection transmission. */
2712 else
2713 {
2714 /* If we were to do this synchronously, there'd be no worry
2715 about re-selecting. */
2716 x_send_incremental (event);
2717 }
d56a553a 2718#endif
dc6f92b8
JB
2719 break;
2720
3bd330d4
RS
2721 case ReparentNotify:
2722 f = x_window_to_frame (event.xreparent.window);
2723 if (f)
2724 f->display.x->parent_desc = event.xreparent.parent;
2725 break;
2726
dc6f92b8 2727 case Expose:
f676886a
JB
2728 f = x_window_to_frame (event.xexpose.window);
2729 if (f)
dc6f92b8 2730 {
3a88c238 2731 if (f->async_visible == 0)
dc6f92b8 2732 {
3a88c238
JB
2733 f->async_visible = 1;
2734 f->async_iconified = 0;
f676886a 2735 SET_FRAME_GARBAGED (f);
dc6f92b8
JB
2736 }
2737 else
f451eb13
JB
2738 {
2739 dumprectangle (x_window_to_frame (event.xexpose.window),
2740 event.xexpose.x, event.xexpose.y,
2741 event.xexpose.width, event.xexpose.height);
f451eb13
JB
2742 }
2743 }
2744 else
2745 {
ab648270
JB
2746 struct scroll_bar *bar
2747 = x_window_to_scroll_bar (event.xexpose.window);
f451eb13
JB
2748
2749 if (bar)
ab648270 2750 x_scroll_bar_expose (bar, &event);
dc6f92b8
JB
2751 }
2752 break;
2753
2754 case GraphicsExpose: /* This occurs when an XCopyArea's
2755 source area was obscured or not
2756 available.*/
f451eb13
JB
2757 f = x_window_to_frame (event.xgraphicsexpose.drawable);
2758 if (f)
2759 {
2760 dumprectangle (f,
2761 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
2762 event.xgraphicsexpose.width,
2763 event.xgraphicsexpose.height);
f451eb13 2764 }
dc6f92b8
JB
2765 break;
2766
2767 case NoExpose: /* This occurs when an XCopyArea's
2768 source area was completely
2769 available */
2770 break;
c118dd06 2771#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
2772 case ExposeWindow:
2773 if (event.subwindow != 0)
2774 break; /* duplicate event */
f676886a
JB
2775 f = x_window_to_frame (event.window);
2776 if (event.window == f->display.x->icon_desc)
dc6f92b8 2777 {
f676886a 2778 refreshicon (f);
3a88c238 2779 f->async_iconified = 1;
dc6f92b8 2780 }
c118dd06 2781 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8
JB
2782 {
2783 /* Say must check all windows' needs_exposure flags. */
2784 expose_all_windows = 1;
f676886a 2785 f->display.x->needs_exposure = 1;
3a88c238 2786 f->async_visible = 1;
dc6f92b8
JB
2787 }
2788 break;
2789
2790 case ExposeRegion:
2791 if (event.subwindow != 0)
2792 break; /* duplicate event */
f676886a
JB
2793 f = x_window_to_frame (event.window);
2794 if (event.window == f->display.x->icon_desc)
dc6f92b8 2795 {
f676886a 2796 refreshicon (f);
dc6f92b8
JB
2797 break;
2798 }
2799 /* If window already needs full redraw, ignore this rectangle. */
f676886a 2800 if (expose_all_windows && f->display.x->needs_exposure)
dc6f92b8
JB
2801 break;
2802 /* Put the event on the queue of rectangles to redraw. */
2803 if (enqueue_event (&event, &x_expose_queue))
2804 /* If it is full, we can't record the rectangle,
2805 so redraw this entire window. */
2806 {
2807 /* Say must check all windows' needs_exposure flags. */
2808 expose_all_windows = 1;
f676886a 2809 f->display.x->needs_exposure = 1;
dc6f92b8
JB
2810 }
2811 break;
2812
2813 case ExposeCopy:
2814 /* This should happen only when we are expecting it,
2815 in x_read_exposes. */
2816 abort ();
c118dd06 2817#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2818
2819#ifdef HAVE_X11
2820 case UnmapNotify:
f451eb13
JB
2821 f = x_window_to_frame (event.xunmap.window);
2822 if (f) /* F may no longer exist if
f676886a 2823 the frame was deleted. */
f451eb13
JB
2824 {
2825 /* While a frame is unmapped, display generation is
2826 disabled; you don't want to spend time updating a
2827 display that won't ever be seen. */
2828 f->async_visible = 0;
9319ae23
RS
2829 /* The window manager never makes a window invisible
2830 ("withdrawn"); all it does is switch between visible
2831 and iconified. Frames get into the invisible state
2832 only through x_make_frame_invisible.
2833 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
2834 f->async_iconified = 1;
f451eb13 2835 }
dc6f92b8
JB
2836 break;
2837
2838 case MapNotify:
f676886a
JB
2839 f = x_window_to_frame (event.xmap.window);
2840 if (f)
dc6f92b8 2841 {
3a88c238
JB
2842 f->async_visible = 1;
2843 f->async_iconified = 0;
dc6f92b8
JB
2844
2845 /* wait_reading_process_input will notice this and update
f676886a
JB
2846 the frame's display structures. */
2847 SET_FRAME_GARBAGED (f);
dc6f92b8
JB
2848 }
2849 break;
2850
2851 /* Turn off processing if we become fully obscured. */
2852 case VisibilityNotify:
2853 break;
2854
c118dd06 2855#else /* ! defined (HAVE_X11) */
dc6f92b8 2856 case UnmapWindow:
f676886a
JB
2857 f = x_window_to_frame (event.window);
2858 if (event.window == f->display.x->icon_desc)
3a88c238 2859 f->async_iconified = 0;
c118dd06 2860 if (event.window == FRAME_X_WINDOW (f))
3a88c238 2861 f->async_visible = 0;
dc6f92b8 2862 break;
c118dd06 2863#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2864
2865#ifdef HAVE_X11
2866 case KeyPress:
f676886a 2867 f = x_window_to_frame (event.xkey.window);
f451eb13 2868
f676886a 2869 if (f != 0)
dc6f92b8 2870 {
2d368234 2871 KeySym keysym, orig_keysym;
dc6f92b8 2872 char copy_buffer[80];
64bb1782
RS
2873 int modifiers;
2874
dfeccd2d
JB
2875 event.xkey.state
2876 |= x_emacs_to_x_modifiers (extra_keyboard_modifiers);
64bb1782 2877 modifiers = event.xkey.state;
3a2712f9 2878
11edeb03 2879 /* This will have to go some day... */
752a043f
JB
2880
2881 /* make_lispy_event turns chars into control chars.
2882 Don't do it here because XLookupString is too eager. */
2883 event.xkey.state &= ~ControlMask;
11edeb03
JB
2884 nbytes =
2885 XLookupString (&event.xkey, copy_buffer, 80, &keysym,
2886 &compose_status);
dc6f92b8 2887
55123275
JB
2888 /* Strip off the vendor-specific keysym bit, and take a shot
2889 at recognizing the codes. HP servers have extra keysyms
2890 that fit into the MiscFunctionKey category. */
2d368234 2891 orig_keysym = keysym;
55123275
JB
2892 keysym &= ~(1<<28);
2893
dc6f92b8
JB
2894 if (numchars > 1)
2895 {
a3c44b14
RS
2896 if ((keysym >= XK_BackSpace && keysym <= XK_Escape)
2897 || keysym == XK_Delete
2898 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
465791da 2899 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0
RS
2900#ifdef HPUX
2901 /* This recognizes the "extended function keys".
2d368234
RS
2902 It seems there's no cleaner way.
2903 Test IsModifierKey to avoid handling mode_switch
2904 incorrectly. */
2905 || (!IsModifierKey (orig_keysym)
2906 && (unsigned) (keysym) >= XK_Select
c34790e0
RS
2907 && (unsigned)(keysym) < XK_KP_Space)
2908#endif
55123275 2909 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
e4571a43
JB
2910 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
2911 || x_is_vendor_fkey (orig_keysym)) /* wherever */
dc6f92b8 2912 {
10e6549c
RS
2913 if (temp_index == sizeof temp_buffer / sizeof (short))
2914 temp_index = 0;
2915 temp_buffer[temp_index++] = keysym;
dc6f92b8 2916 bufp->kind = non_ascii_keystroke;
a3c44b14 2917 XSET (bufp->code, Lisp_Int, (unsigned) keysym - 0xff00);
12ba150f 2918 XSET (bufp->frame_or_window, Lisp_Frame, f);
dfeccd2d 2919 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
1113d9db 2920 bufp->timestamp = event.xkey.time;
dc6f92b8
JB
2921 bufp++;
2922 count++;
2923 numchars--;
2924 }
2925 else if (numchars > nbytes)
2926 {
2927 register int i;
2928
10e6549c 2929 for (i = 0; i < nbytes; i++)
dc6f92b8 2930 {
10e6549c
RS
2931 if (temp_index == sizeof temp_buffer / sizeof (short))
2932 temp_index = 0;
2933 temp_buffer[temp_index++] = copy_buffer[i];
dc6f92b8 2934 bufp->kind = ascii_keystroke;
10e6549c 2935 XSET (bufp->code, Lisp_Int, copy_buffer[i]);
12ba150f 2936 XSET (bufp->frame_or_window, Lisp_Frame, f);
dfeccd2d 2937 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
1113d9db 2938 bufp->timestamp = event.xkey.time;
dc6f92b8
JB
2939 bufp++;
2940 }
dc6f92b8
JB
2941
2942 count += nbytes;
2943 numchars -= nbytes;
2944 }
10e6549c
RS
2945 else
2946 abort ();
dc6f92b8 2947 }
10e6549c
RS
2948 else
2949 abort ();
dc6f92b8
JB
2950 }
2951 break;
c118dd06 2952#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
2953 case KeyPressed:
2954 {
2955 register char *where_mapping;
2956
f676886a 2957 f = x_window_to_frame (event.window);
dc6f92b8 2958 /* Ignore keys typed on icon windows. */
f676886a 2959 if (f != 0 && event.window == f->display.x->icon_desc)
dc6f92b8
JB
2960 break;
2961 where_mapping = XLookupMapping (&event, &nbytes);
2962 /* Nasty fix for arrow keys */
2963 if (!nbytes && IsCursorKey (event.detail & 0xff))
2964 {
2965 switch (event.detail & 0xff)
2966 {
2967 case KC_CURSOR_LEFT:
2968 where_mapping = "\002";
2969 break;
2970 case KC_CURSOR_RIGHT:
2971 where_mapping = "\006";
2972 break;
2973 case KC_CURSOR_UP:
2974 where_mapping = "\020";
2975 break;
2976 case KC_CURSOR_DOWN:
2977 where_mapping = "\016";
2978 break;
2979 }
2980 nbytes = 1;
2981 }
2982 if (numchars - nbytes > 0)
2983 {
2984 register int i;
2985
2986 for (i = 0; i < nbytes; i++)
2987 {
2988 bufp->kind = ascii_keystroke;
2989 XSET (bufp->code, Lisp_Int, where_mapping[i]);
90e65f07 2990 XSET (bufp->time, Lisp_Int, event.xkey.time);
12ba150f 2991 XSET (bufp->frame_or_window, Lisp_Frame, f);
dc6f92b8
JB
2992 bufp++;
2993 }
2994 count += nbytes;
2995 numchars -= nbytes;
2996 }
2997 }
2998 break;
c118dd06 2999#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3000
3001#ifdef HAVE_X11
f451eb13
JB
3002
3003 /* Here's a possible interpretation of the whole
3004 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
3005 FocusIn event, you have to get a FocusOut event before you
3006 relinquish the focus. If you haven't received a FocusIn event,
3007 then a mere LeaveNotify is enough to free you. */
3008
dc6f92b8 3009 case EnterNotify:
f676886a 3010 f = x_window_to_frame (event.xcrossing.window);
6d4238f3 3011
f451eb13 3012 if (event.xcrossing.focus) /* Entered Window */
dc6f92b8 3013 {
dc6f92b8 3014 /* Avoid nasty pop/raise loops. */
f676886a
JB
3015 if (f && (!(f->auto_raise)
3016 || !(f->auto_lower)
dc6f92b8
JB
3017 || (event.xcrossing.time - enter_timestamp) > 500))
3018 {
f676886a 3019 x_new_focus_frame (f);
dc6f92b8
JB
3020 enter_timestamp = event.xcrossing.time;
3021 }
dc6f92b8 3022 }
f676886a
JB
3023 else if (f == x_focus_frame)
3024 x_new_focus_frame (0);
dc6f92b8
JB
3025
3026 break;
3027
3028 case FocusIn:
f676886a 3029 f = x_window_to_frame (event.xfocus.window);
f451eb13
JB
3030 if (event.xfocus.detail != NotifyPointer)
3031 x_focus_event_frame = f;
f676886a
JB
3032 if (f)
3033 x_new_focus_frame (f);
dc6f92b8
JB
3034 break;
3035
f451eb13 3036
dc6f92b8 3037 case LeaveNotify:
f451eb13 3038 f = x_window_to_frame (event.xcrossing.window);
b1c884c3 3039
f451eb13
JB
3040 if (event.xcrossing.focus)
3041 {
3042 if (! x_focus_event_frame)
3043 x_new_focus_frame (0);
3044 else
f676886a 3045 x_new_focus_frame (f);
f451eb13
JB
3046 }
3047 else
3048 {
3049 if (f == x_focus_event_frame)
3050 x_focus_event_frame = 0;
3051 if (f == x_focus_frame)
f676886a 3052 x_new_focus_frame (0);
dc6f92b8
JB
3053 }
3054 break;
3055
3056 case FocusOut:
f676886a 3057 f = x_window_to_frame (event.xfocus.window);
f451eb13
JB
3058 if (event.xfocus.detail != NotifyPointer
3059 && f == x_focus_event_frame)
3060 x_focus_event_frame = 0;
f676886a
JB
3061 if (f && f == x_focus_frame)
3062 x_new_focus_frame (0);
dc6f92b8
JB
3063 break;
3064
c118dd06 3065#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3066
3067 case EnterWindow:
3068 if ((event.detail & 0xFF) == 1)
3069 break; /* Coming from our own subwindow */
3070 if (event.subwindow != 0)
3071 break; /* Entering our own subwindow. */
3072
3073 {
f676886a
JB
3074 f = x_window_to_frame (event.window);
3075 x_mouse_frame = f;
dc6f92b8 3076
f676886a 3077 x_new_focus_frame (f);
dc6f92b8
JB
3078 }
3079 break;
3080
3081 case LeaveWindow:
3082 if ((event.detail & 0xFF) == 1)
3083 break; /* Entering our own subwindow */
3084 if (event.subwindow != 0)
3085 break; /* Leaving our own subwindow. */
3086
f676886a
JB
3087 x_mouse_frame = 0;
3088 if (x_focus_frame == 0
3089 && x_input_frame != 0
3090 && x_input_frame == x_window_to_frame (event.window)
c118dd06 3091 && event.window == FRAME_X_WINDOW (x_input_frame))
dc6f92b8 3092 {
f676886a
JB
3093 f = x_input_frame;
3094 x_input_frame = 0;
3095 if (f)
3096 frame_unhighlight (f);
dc6f92b8
JB
3097 }
3098 break;
c118dd06 3099#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3100
3101#ifdef HAVE_X11
3102 case MotionNotify:
3103 {
f676886a
JB
3104 f = x_window_to_frame (event.xmotion.window);
3105 if (f)
12ba150f 3106 note_mouse_movement (f, &event.xmotion);
f451eb13 3107 else
dc6f92b8 3108 {
ab648270
JB
3109 struct scroll_bar *bar =
3110 x_window_to_scroll_bar (event.xmotion.window);
f451eb13
JB
3111
3112 if (bar)
ab648270 3113 x_scroll_bar_note_movement (bar, &event);
dc6f92b8 3114 }
dc6f92b8
JB
3115 }
3116 break;
3117
3118 case ConfigureNotify:
dbc4e1c1
JB
3119 f = x_window_to_frame (event.xconfigure.window);
3120 if (f)
3121 {
3122 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
3123 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
3124
3125 /* Even if the number of character rows and columns has
3126 not changed, the font size may have changed, so we need
3127 to check the pixel dimensions as well. */
3128 if (columns != f->width
3129 || rows != f->height
3130 || event.xconfigure.width != f->display.x->pixel_width
3131 || event.xconfigure.height != f->display.x->pixel_height)
3132 {
3133 change_frame_size (f, rows, columns, 0, 1);
3134 SET_FRAME_GARBAGED (f);
3135 }
dc6f92b8 3136
3bd330d4 3137 if (! event.xconfigure.send_event)
af395ec1
RS
3138 {
3139 Window win, child;
3140 int win_x, win_y;
3141
3bd330d4
RS
3142 /* Coords are relative to the parent.
3143 Convert them to root-relative. */
af395ec1
RS
3144 XTranslateCoordinates (x_current_display,
3145
3146 /* From-window, to-window. */
3bd330d4
RS
3147 f->display.x->parent_desc,
3148 ROOT_WINDOW,
af395ec1
RS
3149
3150 /* From-position, to-position. */
3151 event.xconfigure.x,
3152 event.xconfigure.y,
3153 &win_x, &win_y,
3154
3155 /* Child of win. */
3156 &child);
3157 event.xconfigure.x = win_x;
3158 event.xconfigure.y = win_y;
3159 }
3160
dbc4e1c1
JB
3161 f->display.x->pixel_width = event.xconfigure.width;
3162 f->display.x->pixel_height = event.xconfigure.height;
3163 f->display.x->left_pos = event.xconfigure.x;
3164 f->display.x->top_pos = event.xconfigure.y;
3165 }
3166 break;
dc6f92b8
JB
3167
3168 case ButtonPress:
3169 case ButtonRelease:
3170 {
3171 /* If we decide we want to generate an event to be seen
3172 by the rest of Emacs, we put it here. */
3173 struct input_event emacs_event;
3174 emacs_event.kind = no_event;
3175
f676886a
JB
3176 f = x_window_to_frame (event.xbutton.window);
3177 if (f)
f451eb13
JB
3178 {
3179 if (!x_focus_frame || (f == x_focus_frame))
3180 construct_mouse_click (&emacs_event,
b10fd412 3181 &event, f);
f451eb13 3182 }
dc6f92b8 3183 else
f451eb13 3184 {
ab648270
JB
3185 struct scroll_bar *bar =
3186 x_window_to_scroll_bar (event.xbutton.window);
f451eb13
JB
3187
3188 if (bar)
ab648270 3189 x_scroll_bar_handle_click (bar, &event, &emacs_event);
f451eb13 3190 }
dc6f92b8
JB
3191
3192 if (numchars >= 1 && emacs_event.kind != no_event)
3193 {
3194 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3195 bufp++;
3196 count++;
3197 numchars--;
3198 }
3199 }
3200 break;
3201
c118dd06 3202#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3203 case ButtonPressed:
3204 case ButtonReleased:
f676886a
JB
3205 f = x_window_to_frame (event.window);
3206 if (f)
dc6f92b8 3207 {
f676886a 3208 if (event.window == f->display.x->icon_desc)
dc6f92b8 3209 {
f676886a 3210 x_make_frame_visible (f);
dc6f92b8
JB
3211
3212 if (warp_mouse_on_deiconify)
c118dd06 3213 XWarpMouse (FRAME_X_WINDOW (f), 10, 10);
dc6f92b8
JB
3214 break;
3215 }
c118dd06 3216 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8 3217 {
f676886a
JB
3218 if (f->auto_raise)
3219 x_raise_frame (f);
dc6f92b8
JB
3220 }
3221 }
3222 enqueue_event (&event, &x_mouse_queue);
3223 if (numchars >= 2)
3224 {
3225 bufp->kind = ascii_keystroke;
3226 bufp->code = (char) 'X' & 037; /* C-x */
12ba150f 3227 XSET (bufp->frame_or_window, Lisp_Frame, f);
90e65f07 3228 XSET (bufp->time, Lisp_Int, event.xkey.time);
dc6f92b8
JB
3229 bufp++;
3230
3231 bufp->kind = ascii_keystroke;
3232 bufp->code = (char) 0; /* C-@ */
12ba150f 3233 XSET (bufp->frame_or_window, Lisp_Frame, f);
90e65f07 3234 XSET (bufp->time, Lisp_Int, event.xkey.time);
dc6f92b8
JB
3235 bufp++;
3236
3237 count += 2;
3238 numchars -= 2;
3239 }
3240 break;
c118dd06 3241#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3242
3243#ifdef HAVE_X11
3244
3245 case CirculateNotify:
3246 break;
3247 case CirculateRequest:
3248 break;
3249
c118dd06 3250#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3251
3252 case MappingNotify:
11edeb03
JB
3253 /* Someone has changed the keyboard mapping - update the
3254 local cache. */
3255 switch (event.xmapping.request)
3256 {
3257 case MappingModifier:
3258 x_find_modifier_meanings ();
3259 /* This is meant to fall through. */
3260 case MappingKeyboard:
3261 XRefreshKeyboardMapping (&event.xmapping);
3262 }
dc6f92b8
JB
3263 break;
3264
3265 default:
3266 break;
3267 }
3268 }
3269
3270#if 0
3271#ifdef HAVE_SELECT
3272 if (expected && ! event_found)
3273 {
3274 /* AOJ 880406: if select returns true but XPending doesn't, it means that
3275 there is an EOF condition; in other words, that X has died.
3276 Act as if there had been a hangup. */
3277
3278 int fd = ConnectionNumber (x_current_display);
3279 int mask = 1 << fd;
3280
3281 if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0,
3a2712f9 3282 (EMACS_TIME) 0)
dc6f92b8
JB
3283 && !XStuffPending ())
3284 kill (getpid (), SIGHUP);
3285 }
c118dd06
JB
3286#endif /* ! defined (HAVE_SELECT) */
3287#endif /* ! 0 */
dc6f92b8 3288
f451eb13 3289#ifndef HAVE_X11
f676886a 3290 if (updating_frame == 0)
dc6f92b8 3291 x_do_pending_expose ();
f451eb13 3292#endif
dc6f92b8
JB
3293
3294 UNBLOCK_INPUT;
3295 return count;
3296}
3297
3298#ifndef HAVE_X11
3299/* Read and process only Expose events
3300 until we get an ExposeCopy event; then return.
3301 This is used in insert/delete line.
3302 We assume input is already blocked. */
3303
3304static void
3305x_read_exposes ()
3306{
f676886a 3307 struct frame *f;
dc6f92b8
JB
3308 XKeyPressedEvent event;
3309
3310 while (1)
3311 {
3312 /* while there are more events*/
3313 XMaskEvent (ExposeWindow | ExposeRegion | ExposeCopy, &event);
3314 switch (event.type)
3315 {
3316 case ExposeWindow:
3317 if (event.subwindow != 0)
3318 break; /* duplicate event */
f676886a
JB
3319 f = x_window_to_frame (event.window);
3320 if (event.window == f->display.x->icon_desc)
dc6f92b8 3321 {
f676886a 3322 refreshicon (f);
dc6f92b8
JB
3323 break;
3324 }
c118dd06 3325 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8
JB
3326 {
3327 expose_all_windows = 1;
f676886a 3328 f->display.x->needs_exposure = 1;
dc6f92b8
JB
3329 break;
3330 }
3331 break;
3332
3333 case ExposeRegion:
3334 if (event.subwindow != 0)
3335 break; /* duplicate event */
f676886a
JB
3336 f = x_window_to_frame (event.window);
3337 if (event.window == f->display.x->icon_desc)
dc6f92b8 3338 {
f676886a 3339 refreshicon (f);
dc6f92b8
JB
3340 break;
3341 }
3342 /* If window already needs full redraw, ignore this rectangle. */
f676886a 3343 if (expose_all_windows && f->display.x->needs_exposure)
dc6f92b8
JB
3344 break;
3345 /* Put the event on the queue of rectangles to redraw. */
3346 if (enqueue_event (&event, &x_expose_queue))
3347 /* If it is full, we can't record the rectangle,
3348 so redraw this entire window. */
3349 {
3350 /* Say must check all windows' needs_exposure flags. */
3351 expose_all_windows = 1;
f676886a 3352 f->display.x->needs_exposure = 1;
dc6f92b8
JB
3353 }
3354 break;
3355
3356 case ExposeCopy:
3357 return;
3358 }
3359 }
3360}
3361#endif /* HAVE_X11 */
3362
dc6f92b8 3363\f
f451eb13
JB
3364/* Drawing the cursor. */
3365
3366
dc6f92b8
JB
3367/* Draw a hollow box cursor. Don't change the inside of the box. */
3368
3369static void
f676886a
JB
3370x_draw_box (f)
3371 struct frame *f;
dc6f92b8 3372{
12ba150f
JB
3373 int left = CHAR_TO_PIXEL_COL (f, f->cursor_x);
3374 int top = CHAR_TO_PIXEL_ROW (f, f->cursor_y);
f676886a
JB
3375 int width = FONT_WIDTH (f->display.x->font);
3376 int height = FONT_HEIGHT (f->display.x->font);
dc6f92b8
JB
3377
3378#ifdef HAVE_X11
c118dd06 3379 XDrawRectangle (x_current_display, FRAME_X_WINDOW (f),
f676886a 3380 f->display.x->cursor_gc,
dc6f92b8 3381 left, top, width - 1, height - 1);
c118dd06
JB
3382#else /* ! defined (HAVE_X11) */
3383 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3384 left, top, width, 1,
f676886a 3385 f->display.x->cursor_pixel);
dc6f92b8 3386
c118dd06 3387 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3388 left, top, 1, height,
f676886a 3389 f->display.x->cursor_pixel);
dc6f92b8 3390
c118dd06 3391 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3392 left+width-1, top, 1, height,
f676886a 3393 f->display.x->cursor_pixel);
dc6f92b8 3394
c118dd06 3395 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3396 left, top+height-1, width, 1,
f676886a 3397 f->display.x->cursor_pixel);
c118dd06 3398#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3399}
3400
f676886a 3401/* Clear the cursor of frame F to background color,
dc6f92b8
JB
3402 and mark the cursor as not shown.
3403 This is used when the text where the cursor is
3404 is about to be rewritten. */
3405
3406static void
f676886a
JB
3407clear_cursor (f)
3408 struct frame *f;
dc6f92b8
JB
3409{
3410 int mask;
3411
f451eb13 3412 if (! FRAME_VISIBLE_P (f)
f676886a 3413 || f->phys_cursor_x < 0)
dc6f92b8
JB
3414 return;
3415
3416#ifdef HAVE_X11
f676886a 3417 x_display_cursor (f, 0);
c118dd06
JB
3418#else /* ! defined (HAVE_X11) */
3419 XPixSet (FRAME_X_WINDOW (f),
12ba150f
JB
3420 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
3421 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
f676886a
JB
3422 FONT_WIDTH (f->display.x->font), FONT_HEIGHT (f->display.x->font),
3423 f->display.x->background_pixel);
c118dd06 3424#endif /* ! defined (HAVE_X11) */
f676886a 3425 f->phys_cursor_x = -1;
dc6f92b8
JB
3426}
3427
f676886a 3428/* Redraw the glyph at ROW, COLUMN on frame F, in the style
90e65f07
JB
3429 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
3430 glyph drawn. */
dc6f92b8
JB
3431
3432static void
f676886a
JB
3433x_draw_single_glyph (f, row, column, glyph, highlight)
3434 struct frame *f;
dc6f92b8 3435 int row, column;
90e65f07 3436 GLYPH glyph;
dc6f92b8
JB
3437 int highlight;
3438{
f676886a 3439 dumpglyphs (f,
12ba150f
JB
3440 CHAR_TO_PIXEL_COL (f, column),
3441 CHAR_TO_PIXEL_ROW (f, row),
07e34cb0 3442 &glyph, 1, highlight);
dc6f92b8
JB
3443}
3444
dc6f92b8 3445static void
dbc4e1c1 3446x_display_bar_cursor (f, on)
f676886a 3447 struct frame *f;
dc6f92b8
JB
3448 int on;
3449{
f676886a 3450 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
90e65f07 3451
49d838ea
JB
3452 /* This is pointless on invisible frames, and dangerous on garbaged
3453 frames; in the latter case, the frame may be in the midst of
3454 changing its size, and curs_x and curs_y may be off the frame. */
3455 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dbc4e1c1
JB
3456 return;
3457
3458 if (! on && f->phys_cursor_x < 0)
3459 return;
3460
f676886a 3461 /* If we're not updating, then we want to use the current frame's
1113d9db 3462 cursor position, not our local idea of where the cursor ought to be. */
f676886a 3463 if (f != updating_frame)
1113d9db 3464 {
f676886a
JB
3465 curs_x = FRAME_CURSOR_X (f);
3466 curs_y = FRAME_CURSOR_Y (f);
1113d9db
JB
3467 }
3468
dbc4e1c1
JB
3469 /* If there is anything wrong with the current cursor state, remove it. */
3470 if (f->phys_cursor_x >= 0
3471 && (!on
3472 || f->phys_cursor_x != curs_x
3473 || f->phys_cursor_y != curs_y
3474 || f->display.x->current_cursor != bar_cursor))
3475 {
3476 /* Erase the cursor by redrawing the character underneath it. */
3477 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
3478 f->phys_cursor_glyph,
3479 current_glyphs->highlight[f->phys_cursor_y]);
3480 f->phys_cursor_x = -1;
3481 }
3482
3483 /* If we now need a cursor in the new place or in the new form, do it so. */
3484 if (on
3485 && (f->phys_cursor_x < 0
3486 || (f->display.x->current_cursor != bar_cursor)))
3487 {
3488 f->phys_cursor_glyph
3489 = ((current_glyphs->enable[curs_y]
3490 && curs_x < current_glyphs->used[curs_y])
3491 ? current_glyphs->glyphs[curs_y][curs_x]
3492 : SPACEGLYPH);
3493 XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
3494 f->display.x->cursor_gc,
3495 CHAR_TO_PIXEL_COL (f, curs_x),
3496 CHAR_TO_PIXEL_ROW (f, curs_y),
3497 1, FONT_HEIGHT (f->display.x->font));
3498
3499 f->phys_cursor_x = curs_x;
3500 f->phys_cursor_y = curs_y;
3501
3502 f->display.x->current_cursor = bar_cursor;
3503 }
3504
3505 if (updating_frame != f)
3506 XFlushQueue ();
3507}
3508
3509
3510/* Turn the displayed cursor of frame F on or off according to ON.
3511 If ON is nonzero, where to put the cursor is specified
3512 by F->cursor_x and F->cursor_y. */
3513
3514static void
3515x_display_box_cursor (f, on)
3516 struct frame *f;
3517 int on;
3518{
3519 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
3520
49d838ea
JB
3521 /* This is pointless on invisible frames, and dangerous on garbaged
3522 frames; in the latter case, the frame may be in the midst of
3523 changing its size, and curs_x and curs_y may be off the frame. */
3524 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dc6f92b8
JB
3525 return;
3526
3527 /* If cursor is off and we want it off, return quickly. */
f676886a 3528 if (!on && f->phys_cursor_x < 0)
dc6f92b8
JB
3529 return;
3530
dbc4e1c1
JB
3531 /* If we're not updating, then we want to use the current frame's
3532 cursor position, not our local idea of where the cursor ought to be. */
3533 if (f != updating_frame)
3534 {
3535 curs_x = FRAME_CURSOR_X (f);
3536 curs_y = FRAME_CURSOR_Y (f);
3537 }
3538
dc6f92b8
JB
3539 /* If cursor is currently being shown and we don't want it to be
3540 or it is in the wrong place,
3541 or we want a hollow box and it's not so, (pout!)
3542 erase it. */
f676886a 3543 if (f->phys_cursor_x >= 0
dc6f92b8 3544 && (!on
f676886a
JB
3545 || f->phys_cursor_x != curs_x
3546 || f->phys_cursor_y != curs_y
dbc4e1c1 3547 || (f->display.x->current_cursor != hollow_box_cursor
f676886a 3548 && (f != x_highlight_frame))))
dc6f92b8
JB
3549 {
3550 /* Erase the cursor by redrawing the character underneath it. */
f676886a
JB
3551 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
3552 f->phys_cursor_glyph,
3553 current_glyphs->highlight[f->phys_cursor_y]);
3554 f->phys_cursor_x = -1;
dc6f92b8
JB
3555 }
3556
3557 /* If we want to show a cursor,
3558 or we want a box cursor and it's not so,
3559 write it in the right place. */
3560 if (on
f676886a 3561 && (f->phys_cursor_x < 0
dbc4e1c1 3562 || (f->display.x->current_cursor != filled_box_cursor
f676886a 3563 && f == x_highlight_frame)))
dc6f92b8 3564 {
f676886a 3565 f->phys_cursor_glyph
1113d9db
JB
3566 = ((current_glyphs->enable[curs_y]
3567 && curs_x < current_glyphs->used[curs_y])
3568 ? current_glyphs->glyphs[curs_y][curs_x]
90e65f07 3569 : SPACEGLYPH);
f676886a 3570 if (f != x_highlight_frame)
dc6f92b8 3571 {
f676886a 3572 x_draw_box (f);
dbc4e1c1 3573 f->display.x->current_cursor = hollow_box_cursor;
dc6f92b8
JB
3574 }
3575 else
3576 {
f676886a
JB
3577 x_draw_single_glyph (f, curs_y, curs_x,
3578 f->phys_cursor_glyph, 2);
dbc4e1c1 3579 f->display.x->current_cursor = filled_box_cursor;
dc6f92b8
JB
3580 }
3581
f676886a
JB
3582 f->phys_cursor_x = curs_x;
3583 f->phys_cursor_y = curs_y;
dc6f92b8
JB
3584 }
3585
f676886a 3586 if (updating_frame != f)
dc6f92b8
JB
3587 XFlushQueue ();
3588}
3589
f676886a
JB
3590x_display_cursor (f, on)
3591 struct frame *f;
dc6f92b8
JB
3592 int on;
3593{
dbc4e1c1 3594 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
f676886a 3595 x_display_box_cursor (f, on);
dbc4e1c1 3596 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
f676886a 3597 x_display_bar_cursor (f, on);
dbc4e1c1
JB
3598 else
3599 /* Those are the only two we have implemented! */
3600 abort ();
dc6f92b8
JB
3601}
3602\f
3603/* Icons. */
3604
f676886a 3605/* Refresh bitmap kitchen sink icon for frame F
dc6f92b8
JB
3606 when we get an expose event for it. */
3607
f676886a
JB
3608refreshicon (f)
3609 struct frame *f;
dc6f92b8
JB
3610{
3611#ifdef HAVE_X11
3612 /* Normally, the window manager handles this function. */
c118dd06 3613#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3614 int mask;
3615
f676886a
JB
3616 if (f->display.x->icon_bitmap_flag)
3617 XBitmapBitsPut (f->display.x->icon_desc, 0, 0, sink_width, sink_height,
dc6f92b8
JB
3618 sink_bits, BlackPixel, WHITE_PIX_DEFAULT,
3619 icon_bitmap, GXcopy, AllPlanes);
3620 else
3621 {
f676886a 3622 extern struct frame *selected_frame;
dc6f92b8
JB
3623 struct Lisp_String *str;
3624 unsigned char *string;
3625
3626 string
f676886a 3627 = XSTRING (XBUFFER (XWINDOW (f->selected_window)->buffer)->name)->data;
dc6f92b8 3628
f676886a 3629 if (f->display.x->icon_label != string)
dc6f92b8 3630 {
f676886a
JB
3631 f->display.x->icon_label = string;
3632 XChangeWindow (f->display.x->icon_desc,
dc6f92b8
JB
3633 XQueryWidth (string, icon_font_info->id) + 10,
3634 icon_font_info->height + 10);
3635 }
3636
f676886a 3637 XText (f->display.x->icon_desc, 5, 5, string,
dc6f92b8
JB
3638 str->size, icon_font_info->id,
3639 BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT);
3640 }
3641 XFlushQueue ();
c118dd06 3642#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3643}
3644
dbc4e1c1 3645/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
3646
3647int
f676886a
JB
3648x_bitmap_icon (f)
3649 struct frame *f;
dc6f92b8
JB
3650{
3651 int mask;
3652 Window icon_window;
3653
c118dd06 3654 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
3655 return 1;
3656
3657#ifdef HAVE_X11
8583db58
RS
3658 if (! icon_bitmap)
3659 icon_bitmap =
3660 XCreateBitmapFromData (x_current_display, FRAME_X_WINDOW (f),
3661 gnu_bits, gnu_width, gnu_height);
f676886a
JB
3662 x_wm_set_icon_pixmap (f, icon_bitmap);
3663 f->display.x->icon_bitmap_flag = 1;
c118dd06 3664#else /* ! defined (HAVE_X11) */
f676886a 3665 if (f->display.x->icon_desc)
dc6f92b8 3666 {
c118dd06 3667 XClearIconWindow (FRAME_X_WINDOW (f));
f676886a 3668 XDestroyWindow (f->display.x->icon_desc);
dc6f92b8
JB
3669 }
3670
f676886a 3671 icon_window = XCreateWindow (f->display.x->parent_desc,
dc6f92b8
JB
3672 0, 0, sink_width, sink_height,
3673 2, WhitePixmap, (Pixmap) NULL);
3674
3675 if (icon_window == 0)
3676 return 1;
3677
c118dd06 3678 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
dc6f92b8
JB
3679 XSelectInput (icon_window, ExposeWindow | UnmapWindow);
3680
f676886a
JB
3681 f->display.x->icon_desc = icon_window;
3682 f->display.x->icon_bitmap_flag = 1;
dc6f92b8
JB
3683
3684 if (icon_bitmap == 0)
3685 icon_bitmap
3686 = XStoreBitmap (sink_mask_width, sink_mask_height, sink_mask_bits);
c118dd06 3687#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3688
3689 return 0;
3690}
3691
3692
f676886a 3693/* Make the x-window of frame F use a rectangle with text. */
dc6f92b8
JB
3694
3695int
f676886a
JB
3696x_text_icon (f, icon_name)
3697 struct frame *f;
dc6f92b8
JB
3698 char *icon_name;
3699{
3700#ifndef HAVE_X11
3701 int mask;
3702 int width;
3703 Window icon_window;
3704 char *X_DefaultValue;
3705 Bitmap b1;
3706
dc6f92b8
JB
3707#ifndef WhitePixel
3708#define WhitePixel 1
c118dd06 3709#endif /* WhitePixel */
dc6f92b8
JB
3710
3711#ifndef BlackPixel
3712#define BlackPixel 0
c118dd06
JB
3713#endif /* BlackPixel */
3714#endif /* HAVE_X11 */
dc6f92b8 3715
c118dd06 3716 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
3717 return 1;
3718
dc6f92b8
JB
3719#ifdef HAVE_X11
3720 if (icon_name)
f676886a 3721 f->display.x->icon_label = icon_name;
dc6f92b8 3722 else
f676886a
JB
3723 if (! f->display.x->icon_label)
3724 f->display.x->icon_label = " *emacs* ";
dc6f92b8 3725
dfeccd2d 3726#if 0
c118dd06 3727 XSetIconName (x_current_display, FRAME_X_WINDOW (f),
f676886a 3728 (char *) f->display.x->icon_label);
dfeccd2d 3729#endif
dc6f92b8 3730
f676886a 3731 f->display.x->icon_bitmap_flag = 0;
b1c884c3 3732 x_wm_set_icon_pixmap (f, 0);
c118dd06 3733#else /* ! defined (HAVE_X11) */
dbc4e1c1
JB
3734 if (icon_font_info == 0)
3735 icon_font_info
3736 = XGetFont (XGetDefault (XDISPLAY
59653951 3737 (char *) XSTRING (Vinvocation_name)->data,
dbc4e1c1
JB
3738 "BodyFont"));
3739
f676886a 3740 if (f->display.x->icon_desc)
dc6f92b8 3741 {
c118dd06 3742 XClearIconWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a 3743 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
dc6f92b8
JB
3744 }
3745
3746 if (icon_name)
f676886a 3747 f->display.x->icon_label = (unsigned char *) icon_name;
dc6f92b8 3748 else
f676886a
JB
3749 if (! f->display.x->icon_label)
3750 f->display.x->icon_label = XSTRING (f->name)->data;
dc6f92b8 3751
f676886a
JB
3752 width = XStringWidth (f->display.x->icon_label, icon_font_info, 0, 0);
3753 icon_window = XCreateWindow (f->display.x->parent_desc,
3754 f->display.x->left_pos,
3755 f->display.x->top_pos,
dc6f92b8
JB
3756 width + 10, icon_font_info->height + 10,
3757 2, BlackPixmap, WhitePixmap);
3758
3759 if (icon_window == 0)
3760 return 1;
3761
c118dd06 3762 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
dc6f92b8
JB
3763 XSelectInput (icon_window, ExposeWindow | ExposeRegion | UnmapWindow | ButtonPressed);
3764
f676886a
JB
3765 f->display.x->icon_desc = icon_window;
3766 f->display.x->icon_bitmap_flag = 0;
3767 f->display.x->icon_label = 0;
c118dd06 3768#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3769
3770 return 0;
3771}
3772\f
4746118a
JB
3773/* Handling X errors. */
3774
12ba150f
JB
3775/* Shut down Emacs in an orderly fashion, because of a SIGPIPE on the
3776 X server's connection, or an error reported via the X protocol. */
16bd92ea 3777
4746118a 3778static SIGTYPE
c118dd06 3779x_connection_closed ()
4746118a
JB
3780{
3781 if (_Xdebug)
3782 abort ();
12ba150f 3783
1cd2d6d4 3784 shut_down_emacs (0, 1, Qnil);
12ba150f
JB
3785
3786 exit (70);
4746118a
JB
3787}
3788
8922af5f
JB
3789/* An X error handler which prints an error message and then kills
3790 Emacs. This is what's normally installed as Xlib's handler for
3791 protocol errors. */
c118dd06
JB
3792static int
3793x_error_quitter (display, error)
3794 Display *display;
3795 XErrorEvent *error;
3796{
3797 char buf[256];
dc6f92b8 3798
c118dd06
JB
3799 /* Note that there is no real way portable across R3/R4 to get the
3800 original error handler. */
dc6f92b8 3801
c118dd06
JB
3802 XGetErrorText (display, error->error_code, buf, sizeof (buf));
3803 fprintf (stderr, "X protocol error: %s on protocol request %d\n",
3804 buf, error->request_code);
dc6f92b8 3805
e09f9351 3806#if 0
12ba150f
JB
3807 /* While we're testing Emacs 19, we'll just dump core whenever we
3808 get an X error, so we can figure out why it happened. */
3809 abort ();
e09f9351 3810#endif
12ba150f 3811
c118dd06 3812 x_connection_closed ();
dc6f92b8
JB
3813}
3814
8922af5f
JB
3815/* A handler for X IO errors which prints an error message and then
3816 kills Emacs. This is what is always installed as Xlib's handler
3817 for I/O errors. */
3818static int
3819x_io_error_quitter (display)
3820 Display *display;
3821{
3822 fprintf (stderr, "Connection to X server %s lost.\n",
3823 XDisplayName (DisplayString (display)));
3824
e09f9351 3825#if 0
8922af5f
JB
3826 /* While we're testing Emacs 19, we'll just dump core whenever we
3827 get an X error, so we can figure out why it happened. */
3828 abort ();
e09f9351 3829#endif
8922af5f
JB
3830
3831 x_connection_closed ();
3832}
3833
c118dd06 3834/* A buffer for storing X error messages. */
cef13e55
RS
3835static char *x_caught_error_message;
3836#define X_CAUGHT_ERROR_MESSAGE_SIZE 200
c118dd06
JB
3837
3838/* An X error handler which stores the error message in
3839 x_caught_error_message. This is what's installed when
3840 x_catch_errors is in effect. */
3841static int
3842x_error_catcher (display, error)
3843 Display *display;
3844 XErrorEvent *error;
3845{
3846 XGetErrorText (display, error->error_code,
cef13e55 3847 x_caught_error_message, X_CAUGHT_ERROR_MESSAGE_SIZE);
c118dd06
JB
3848}
3849
3850
3851/* Begin trapping X errors.
dc6f92b8 3852
c118dd06
JB
3853 After calling this function, X protocol errors no longer cause
3854 Emacs to exit; instead, they are recorded in x_cfc_error_message.
dc6f92b8 3855
c118dd06
JB
3856 Calling x_check_errors signals an Emacs error if an X error has
3857 occurred since the last call to x_catch_errors or x_check_errors.
3858
3859 Calling x_uncatch_errors resumes the normal error handling. */
3860
3861void x_catch_errors(), x_check_errors (), x_uncatch_errors ();
3862
3863void
3864x_catch_errors ()
dc6f92b8 3865{
c118dd06
JB
3866 /* Make sure any errors from previous requests have been dealt with. */
3867 XSync (x_current_display, False);
dc6f92b8 3868
c118dd06 3869 /* Set up the error buffer. */
60f9aad3 3870 x_caught_error_message
cef13e55
RS
3871 = (char*) xmalloc (X_CAUGHT_ERROR_MESSAGE_SIZE);
3872 x_caught_error_message[0] = '\0';
16bd92ea 3873
c118dd06
JB
3874 /* Install our little error handler. */
3875 XHandleError (x_error_catcher);
3876}
16bd92ea 3877
c118dd06
JB
3878/* If any X protocol errors have arrived since the last call to
3879 x_catch_errors or x_check_errors, signal an Emacs error using
3880 sprintf (a buffer, FORMAT, the x error message text) as the text. */
3881void
3882x_check_errors (format)
3883 char *format;
3884{
3885 /* Make sure to catch any errors incurred so far. */
3886 XSync (x_current_display, False);
16bd92ea 3887
cef13e55 3888 if (x_caught_error_message[0])
c118dd06 3889 {
cef13e55 3890 char buf[X_CAUGHT_ERROR_MESSAGE_SIZE + 56];
dc6f92b8 3891
cef13e55 3892 sprintf (buf, format, x_caught_error_message);
c118dd06
JB
3893 x_uncatch_errors ();
3894 error (buf);
3895 }
3896}
3897
3898void
3899x_uncatch_errors ()
3900{
9ac0d9e0 3901 xfree (x_caught_error_message);
cef13e55 3902 x_caught_error_message = 0;
c118dd06 3903 XHandleError (x_error_quitter);
dc6f92b8
JB
3904}
3905
dc6f92b8
JB
3906#if 0
3907static unsigned int x_wire_count;
3908x_trace_wire ()
3909{
3910 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
3911}
c118dd06 3912#endif /* ! 0 */
dc6f92b8
JB
3913
3914\f
f451eb13
JB
3915/* Changing the font of the frame. */
3916
f676886a 3917/* Set the font of the x-window specified by frame F
dc6f92b8 3918 to the font named NEWNAME. This is safe to use
f676886a 3919 even before F has an actual x-window. */
dc6f92b8
JB
3920
3921#ifdef HAVE_X11
3922
3923/* A table of all the fonts we have already loaded. */
3924static XFontStruct **x_font_table;
3925
3926/* The current capacity of x_font_table. */
3927static int x_font_table_size;
3928
3929/* The number of fonts actually stored in x_font_table.
3930 x_font_table[n] is used and valid iff 0 <= n < n_fonts.
3931 0 <= n_fonts <= x_font_table_size. */
3932static int n_fonts;
3933
b5cf7a0e 3934Lisp_Object
f676886a
JB
3935x_new_font (f, fontname)
3936 struct frame *f;
dc6f92b8
JB
3937 register char *fontname;
3938{
dc6f92b8
JB
3939 int already_loaded;
3940 int n_matching_fonts;
3941 XFontStruct *font_info;
3942 char **font_names;
3943
3944 /* Get a list of all the fonts that match this name. Once we
3945 have a list of matching fonts, we compare them against the fonts
3946 we already have by comparing font ids. */
3947 font_names = (char **) XListFontsWithInfo (x_current_display, fontname,
3948 1024, &n_matching_fonts,
3949 &font_info);
0c94f6ee
JB
3950 /* Apparently it doesn't set n_matching_fonts to zero when it can't
3951 find any matches; font_names == 0 is the only clue. */
3952 if (! font_names)
3953 n_matching_fonts = 0;
3954
5835f860
RS
3955 /* Don't just give up if n_matching_fonts is 0.
3956 Apparently there's a bug on Suns: XListFontsWithInfo can
3957 fail to find a font, but XLoadQueryFont may still find it. */
dc6f92b8 3958
90e65f07 3959 /* See if we've already loaded a matching font. */
5835f860
RS
3960 already_loaded = -1;
3961 if (n_matching_fonts != 0)
3962 {
3963 int i, j;
dc6f92b8 3964
5835f860
RS
3965 for (i = 0; i < n_fonts; i++)
3966 for (j = 0; j < n_matching_fonts; j++)
3967 if (x_font_table[i]->fid == font_info[j].fid)
3968 {
3969 already_loaded = i;
3970 fontname = font_names[j];
3971 goto found_font;
3972 }
3973 }
dc6f92b8
JB
3974 found_font:
3975
3976 /* If we have, just return it from the table. */
5835f860 3977 if (already_loaded > 0)
f676886a 3978 f->display.x->font = x_font_table[already_loaded];
90e65f07 3979
dc6f92b8
JB
3980 /* Otherwise, load the font and add it to the table. */
3981 else
3982 {
9696f58b 3983 int i;
dc6f92b8
JB
3984 XFontStruct *font;
3985
9696f58b 3986 /* Try to find a character-cell font in the list. */
f126bd67
JB
3987#if 0
3988 /* A laudable goal, but this isn't how to do it. */
9696f58b
JB
3989 for (i = 0; i < n_matching_fonts; i++)
3990 if (! font_info[i].per_char)
3991 break;
f126bd67
JB
3992#else
3993 i = 0;
3994#endif
9696f58b 3995
5835f860
RS
3996 /* See comment above. */
3997 if (n_matching_fonts != 0)
9696f58b
JB
3998 fontname = font_names[i];
3999
dc6f92b8
JB
4000 font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname);
4001 if (! font)
5835f860
RS
4002 {
4003 /* Free the information from XListFontsWithInfo. */
4004 if (n_matching_fonts)
4005 XFreeFontInfo (font_names, font_info, n_matching_fonts);
4006 return Qnil;
4007 }
dc6f92b8
JB
4008
4009 /* Do we need to create the table? */
4010 if (x_font_table_size == 0)
4011 {
4012 x_font_table_size = 16;
4013 x_font_table
4014 = (XFontStruct **) xmalloc (x_font_table_size
4015 * sizeof (x_font_table[0]));
4016 }
4017 /* Do we need to grow the table? */
4018 else if (n_fonts >= x_font_table_size)
4019 {
90e65f07 4020 x_font_table_size *= 2;
dc6f92b8
JB
4021 x_font_table
4022 = (XFontStruct **) xrealloc (x_font_table,
4023 (x_font_table_size
4024 * sizeof (x_font_table[0])));
4025 }
4026
f676886a 4027 f->display.x->font = x_font_table[n_fonts++] = font;
dc6f92b8
JB
4028 }
4029
f676886a 4030 /* Now make the frame display the given font. */
c118dd06 4031 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 4032 {
f676886a
JB
4033 XSetFont (x_current_display, f->display.x->normal_gc,
4034 f->display.x->font->fid);
4035 XSetFont (x_current_display, f->display.x->reverse_gc,
4036 f->display.x->font->fid);
4037 XSetFont (x_current_display, f->display.x->cursor_gc,
4038 f->display.x->font->fid);
4039
4040 x_set_window_size (f, f->width, f->height);
dc6f92b8
JB
4041 }
4042
b5cf7a0e
JB
4043 {
4044 Lisp_Object lispy_name = build_string (fontname);
4045
4046
4047 /* Free the information from XListFontsWithInfo. The data
4048 we actually retain comes from XLoadQueryFont. */
4049 XFreeFontInfo (font_names, font_info, n_matching_fonts);
4050
4051 return lispy_name;
4052 }
dc6f92b8 4053}
c118dd06 4054#else /* ! defined (HAVE_X11) */
f676886a
JB
4055x_new_font (f, newname)
4056 struct frame *f;
dc6f92b8
JB
4057 register char *newname;
4058{
4059 FONT_TYPE *temp;
4060 int mask;
4061
4062 temp = XGetFont (newname);
4063 if (temp == (FONT_TYPE *) 0)
4064 return 1;
4065
f676886a
JB
4066 if (f->display.x->font)
4067 XLoseFont (f->display.x->font);
dc6f92b8 4068
f676886a 4069 f->display.x->font = temp;
dc6f92b8 4070
c118dd06 4071 if (FRAME_X_WINDOW (f) != 0)
f676886a 4072 x_set_window_size (f, f->width, f->height);
dc6f92b8
JB
4073
4074 return 0;
4075}
c118dd06 4076#endif /* ! defined (HAVE_X11) */
dc6f92b8 4077\f
f451eb13
JB
4078/* X Window sizes and positions. */
4079
f676886a
JB
4080x_calc_absolute_position (f)
4081 struct frame *f;
dc6f92b8
JB
4082{
4083#ifdef HAVE_X11
f676886a
JB
4084 if (f->display.x->left_pos < 0)
4085 f->display.x->left_pos
7c5283e4 4086 = x_screen_width - PIXEL_WIDTH (f) + f->display.x->left_pos;
dc6f92b8 4087
f676886a
JB
4088 if (f->display.x->top_pos < 0)
4089 f->display.x->top_pos
7c5283e4 4090 = x_screen_height - PIXEL_HEIGHT (f) + f->display.x->top_pos;
c118dd06 4091#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
4092 WINDOWINFO_TYPE parentinfo;
4093
c118dd06 4094 XGetWindowInfo (FRAME_X_WINDOW (f), &parentinfo);
dc6f92b8 4095
f676886a
JB
4096 if (f->display.x->left_pos < 0)
4097 f->display.x->left_pos = parentinfo.width + (f->display.x->left_pos + 1)
4098 - PIXEL_WIDTH (f) - 2 * f->display.x->internal_border_width;
dc6f92b8 4099
f676886a
JB
4100 if (f->display.x->top_pos < 0)
4101 f->display.x->top_pos = parentinfo.height + (f->display.x->top_pos + 1)
4102 - PIXEL_HEIGHT (f) - 2 * f->display.x->internal_border_width;
c118dd06 4103#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4104}
4105
f676886a
JB
4106x_set_offset (f, xoff, yoff)
4107 struct frame *f;
dc6f92b8
JB
4108 register int xoff, yoff;
4109{
f676886a
JB
4110 f->display.x->top_pos = yoff;
4111 f->display.x->left_pos = xoff;
4112 x_calc_absolute_position (f);
dc6f92b8
JB
4113
4114 BLOCK_INPUT;
c118dd06 4115 XMoveWindow (XDISPLAY FRAME_X_WINDOW (f),
f676886a 4116 f->display.x->left_pos, f->display.x->top_pos);
dc6f92b8 4117#ifdef HAVE_X11
f676886a 4118 x_wm_set_size_hint (f, 0);
c118dd06 4119#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4120 UNBLOCK_INPUT;
4121}
4122
f676886a 4123/* Call this to change the size of frame F's x-window. */
dc6f92b8 4124
f676886a
JB
4125x_set_window_size (f, cols, rows)
4126 struct frame *f;
b1c884c3 4127 int cols, rows;
dc6f92b8
JB
4128{
4129 int pixelwidth, pixelheight;
4130 int mask;
dc6f92b8
JB
4131
4132 BLOCK_INPUT;
4133
b1c884c3 4134 check_frame_size (f, &rows, &cols);
ab648270
JB
4135 f->display.x->vertical_scroll_bar_extra =
4136 (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4137 ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f)
f451eb13
JB
4138 : 0);
4139 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4140 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8
JB
4141
4142#ifdef HAVE_X11
f676886a 4143 x_wm_set_size_hint (f, 0);
c118dd06
JB
4144#endif /* ! defined (HAVE_X11) */
4145 XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight);
b1c884c3
JB
4146
4147 /* Now, strictly speaking, we can't be sure that this is accurate,
4148 but the window manager will get around to dealing with the size
4149 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
4150 ConfigureNotify event gets here.
4151
4152 We could just not bother storing any of this information here,
4153 and let the ConfigureNotify event set everything up, but that
4154 might be kind of confusing to the lisp code, since size changes
4155 wouldn't be reported in the frame parameters until some random
4156 point in the future when the ConfigureNotify event arrives. */
8922af5f 4157 change_frame_size (f, rows, cols, 0, 0);
b1c884c3
JB
4158 PIXEL_WIDTH (f) = pixelwidth;
4159 PIXEL_HEIGHT (f) = pixelheight;
4160
dbc4e1c1
JB
4161 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4162 receive in the ConfigureNotify event; if we get what we asked
4163 for, then the event won't cause the screen to become garbaged, so
4164 we have to make sure to do it here. */
4165 SET_FRAME_GARBAGED (f);
4166
dc6f92b8
JB
4167 XFlushQueue ();
4168 UNBLOCK_INPUT;
4169}
4170
4171#ifndef HAVE_X11
f676886a
JB
4172x_set_resize_hint (f)
4173 struct frame *f;
dc6f92b8 4174{
12ba150f
JB
4175 XSetResizeHint (FRAME_X_WINDOW (f),
4176 2 * f->display.x->internal_border_width,
f676886a 4177 2 * f->display.x->internal_border_width,
12ba150f
JB
4178 FONT_WIDTH (f->display.x->font),
4179 FONT_HEIGHT (f->display.x->font));
dc6f92b8 4180}
c118dd06 4181#endif /* HAVE_X11 */
dc6f92b8 4182\f
f451eb13 4183/* Mouse warping, focus shifting, raising and lowering. */
dc6f92b8 4184
f676886a
JB
4185x_set_mouse_position (f, x, y)
4186 struct frame *f;
dc6f92b8
JB
4187 int x, y;
4188{
4189 int pix_x, pix_y;
4190
f676886a 4191 x_raise_frame (f);
dc6f92b8 4192
12ba150f
JB
4193 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
4194 pix_y = CHAR_TO_PIXEL_ROW (f, y) + FONT_HEIGHT (f->display.x->font) / 2;
f451eb13
JB
4195
4196 if (pix_x < 0) pix_x = 0;
4197 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4198
4199 if (pix_y < 0) pix_y = 0;
4200 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
4201
4202 BLOCK_INPUT;
dc6f92b8 4203
c118dd06 4204 XWarpMousePointer (FRAME_X_WINDOW (f), pix_x, pix_y);
dc6f92b8
JB
4205 UNBLOCK_INPUT;
4206}
4207
4208#ifdef HAVE_X11
f676886a
JB
4209x_focus_on_frame (f)
4210 struct frame *f;
dc6f92b8 4211{
f676886a 4212 x_raise_frame (f);
6d4238f3
JB
4213#if 0
4214 /* I don't think that the ICCCM allows programs to do things like this
4215 without the interaction of the window manager. Whatever you end up
f676886a 4216 doing with this code, do it to x_unfocus_frame too. */
c118dd06 4217 XSetInputFocus (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8 4218 RevertToPointerRoot, CurrentTime);
c118dd06 4219#endif /* ! 0 */
dc6f92b8
JB
4220}
4221
f676886a
JB
4222x_unfocus_frame (f)
4223 struct frame *f;
dc6f92b8 4224{
6d4238f3 4225#if 0
f676886a
JB
4226 /* Look at the remarks in x_focus_on_frame. */
4227 if (x_focus_frame == f)
dc6f92b8
JB
4228 XSetInputFocus (x_current_display, PointerRoot,
4229 RevertToPointerRoot, CurrentTime);
c118dd06 4230#endif /* ! 0 */
dc6f92b8
JB
4231}
4232
c118dd06 4233#endif /* ! defined (HAVE_X11) */
dc6f92b8 4234
f676886a 4235/* Raise frame F. */
dc6f92b8 4236
f676886a
JB
4237x_raise_frame (f)
4238 struct frame *f;
dc6f92b8 4239{
3a88c238 4240 if (f->async_visible)
dc6f92b8
JB
4241 {
4242 BLOCK_INPUT;
c118dd06 4243 XRaiseWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8
JB
4244 XFlushQueue ();
4245 UNBLOCK_INPUT;
4246 }
4247}
4248
f676886a 4249/* Lower frame F. */
dc6f92b8 4250
f676886a
JB
4251x_lower_frame (f)
4252 struct frame *f;
dc6f92b8 4253{
3a88c238 4254 if (f->async_visible)
dc6f92b8
JB
4255 {
4256 BLOCK_INPUT;
c118dd06 4257 XLowerWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8
JB
4258 XFlushQueue ();
4259 UNBLOCK_INPUT;
4260 }
4261}
4262
dbc4e1c1
JB
4263static void
4264XTframe_raise_lower (f, raise)
4265 FRAME_PTR f;
4266 int raise;
4267{
4268 if (raise)
4269 x_raise_frame (f);
4270 else
4271 x_lower_frame (f);
4272}
4273
4274
dc6f92b8
JB
4275/* Change from withdrawn state to mapped state. */
4276
f676886a
JB
4277x_make_frame_visible (f)
4278 struct frame *f;
dc6f92b8
JB
4279{
4280 int mask;
4281
dc6f92b8 4282 BLOCK_INPUT;
dc6f92b8 4283
f676886a 4284 if (! FRAME_VISIBLE_P (f))
90e65f07
JB
4285 {
4286#ifdef HAVE_X11
4287 if (! EQ (Vx_no_window_manager, Qt))
f676886a 4288 x_wm_set_window_state (f, NormalState);
dc6f92b8 4289
c118dd06 4290 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
ab648270 4291 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
c118dd06
JB
4292 XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
4293#else /* ! defined (HAVE_X11) */
4294 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a
JB
4295 if (f->display.x->icon_desc != 0)
4296 XUnmapWindow (f->display.x->icon_desc);
dc6f92b8 4297
90e65f07 4298 /* Handled by the MapNotify event for X11 */
3a88c238
JB
4299 f->async_visible = 1;
4300 f->async_iconified = 0;
dc6f92b8 4301
f676886a 4302 /* NOTE: this may cause problems for the first frame. */
90e65f07 4303 XTcursor_to (0, 0);
c118dd06 4304#endif /* ! defined (HAVE_X11) */
90e65f07 4305 }
dc6f92b8 4306
dc6f92b8 4307 XFlushQueue ();
90e65f07 4308
dc6f92b8
JB
4309 UNBLOCK_INPUT;
4310}
4311
4312/* Change from mapped state to withdrawn state. */
4313
f676886a
JB
4314x_make_frame_invisible (f)
4315 struct frame *f;
dc6f92b8
JB
4316{
4317 int mask;
4318
9319ae23
RS
4319 /* Don't keep the highlight on an invisible frame. */
4320 if (x_highlight_frame == f)
4321 x_highlight_frame = 0;
4322
4323 if (! f->async_visible && ! f->async_iconified)
dc6f92b8
JB
4324 return;
4325
4326 BLOCK_INPUT;
c118dd06
JB
4327
4328#ifdef HAVE_X11R4
4329
4330 if (! XWithdrawWindow (x_current_display, FRAME_X_WINDOW (f),
4331 DefaultScreen (x_current_display)))
4332 {
4333 UNBLOCK_INPUT_RESIGNAL;
eb8c3be9 4334 error ("can't notify window manager of window withdrawal");
c118dd06
JB
4335 }
4336
4337#else /* ! defined (HAVE_X11R4) */
dc6f92b8 4338#ifdef HAVE_X11
16bd92ea 4339
c118dd06 4340 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
4341 if (! EQ (Vx_no_window_manager, Qt))
4342 {
16bd92ea 4343 XEvent unmap;
dc6f92b8 4344
16bd92ea 4345 unmap.xunmap.type = UnmapNotify;
c118dd06 4346 unmap.xunmap.window = FRAME_X_WINDOW (f);
16bd92ea
JB
4347 unmap.xunmap.event = DefaultRootWindow (x_current_display);
4348 unmap.xunmap.from_configure = False;
4349 if (! XSendEvent (x_current_display,
4350 DefaultRootWindow (x_current_display),
4351 False,
4352 SubstructureRedirectMask|SubstructureNotifyMask,
4353 &unmap))
4354 {
4355 UNBLOCK_INPUT_RESIGNAL;
4356 error ("can't notify window manager of withdrawal");
4357 }
dc6f92b8
JB
4358 }
4359
16bd92ea 4360 /* Unmap the window ourselves. Cheeky! */
c118dd06
JB
4361 XUnmapWindow (x_current_display, FRAME_X_WINDOW (f));
4362
4363#else /* ! defined (HAVE_X11) */
dc6f92b8 4364
c118dd06 4365 XUnmapWindow (FRAME_X_WINDOW (f));
3a88c238 4366 f->async_visible = 0; /* Handled by the UnMap event for X11 */
f676886a 4367 if (f->display.x->icon_desc != 0)
c118dd06
JB
4368 XUnmapWindow (f->display.x->icon_desc);
4369
4370#endif /* ! defined (HAVE_X11) */
4371#endif /* ! defined (HAVE_X11R4) */
dc6f92b8
JB
4372
4373 XFlushQueue ();
4374 UNBLOCK_INPUT;
4375}
4376
dc6f92b8
JB
4377/* Change window state from mapped to iconified. */
4378
f676886a
JB
4379x_iconify_frame (f)
4380 struct frame *f;
dc6f92b8
JB
4381{
4382 int mask;
4383
9319ae23
RS
4384 /* Don't keep the highlight on an invisible frame. */
4385 if (x_highlight_frame == f)
4386 x_highlight_frame = 0;
4387
3a88c238 4388 if (f->async_iconified)
dc6f92b8
JB
4389 return;
4390
4391 BLOCK_INPUT;
4392
4393#ifdef HAVE_X11
16bd92ea
JB
4394 /* Since we don't know which revision of X we're running, we'll use both
4395 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
4396
4397 /* X11R4: send a ClientMessage to the window manager using the
4398 WM_CHANGE_STATE type. */
4399 {
4400 XEvent message;
4401
c118dd06 4402 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea
JB
4403 message.xclient.type = ClientMessage;
4404 message.xclient.message_type = Xatom_wm_change_state;
4405 message.xclient.format = 32;
4406 message.xclient.data.l[0] = IconicState;
4407
4408 if (! XSendEvent (x_current_display,
4409 DefaultRootWindow (x_current_display),
4410 False,
4411 SubstructureRedirectMask | SubstructureNotifyMask,
4412 &message))
dc6f92b8
JB
4413 {
4414 UNBLOCK_INPUT_RESIGNAL;
4415 error ("Can't notify window manager of iconification.");
4416 }
16bd92ea 4417 }
dc6f92b8 4418
16bd92ea
JB
4419 /* X11R3: set the initial_state field of the window manager hints to
4420 IconicState. */
4421 x_wm_set_window_state (f, IconicState);
dc6f92b8 4422
3a88c238 4423 f->async_iconified = 1;
c118dd06
JB
4424#else /* ! defined (HAVE_X11) */
4425 XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8 4426
3a88c238 4427 f->async_visible = 0; /* Handled in the UnMap event for X11. */
f676886a 4428 if (f->display.x->icon_desc != 0)
dc6f92b8 4429 {
f676886a
JB
4430 XMapWindow (XDISPLAY f->display.x->icon_desc);
4431 refreshicon (f);
dc6f92b8 4432 }
c118dd06 4433#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4434
4435 XFlushQueue ();
4436 UNBLOCK_INPUT;
4437}
4438
c0ff3fab 4439/* Destroy the X window of frame F. */
dc6f92b8 4440
c0ff3fab 4441x_destroy_window (f)
f676886a 4442 struct frame *f;
dc6f92b8 4443{
dc6f92b8 4444 BLOCK_INPUT;
c0ff3fab
JB
4445
4446 if (f->display.x->icon_desc != 0)
4447 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
4448 XDestroyWindow (XDISPLAY f->display.x->window_desc);
07e34cb0 4449 free_frame_faces (f);
dc6f92b8 4450 XFlushQueue ();
dc6f92b8 4451
9ac0d9e0 4452 xfree (f->display.x);
c0ff3fab 4453 f->display.x = 0;
f676886a
JB
4454 if (f == x_focus_frame)
4455 x_focus_frame = 0;
4456 if (f == x_highlight_frame)
4457 x_highlight_frame = 0;
c0ff3fab
JB
4458
4459 UNBLOCK_INPUT;
dc6f92b8
JB
4460}
4461\f
f451eb13
JB
4462/* Manage event queues for X10. */
4463
dc6f92b8
JB
4464#ifndef HAVE_X11
4465
4466/* Manage event queues.
4467
4468 This code is only used by the X10 support.
4469
4470 We cannot leave events in the X queue and get them when we are ready
4471 because X does not provide a subroutine to get only a certain kind
4472 of event but not block if there are no queued events of that kind.
4473
4474 Therefore, we must examine events as they come in and copy events
4475 of certain kinds into our private queues.
4476
4477 All ExposeRegion events are put in x_expose_queue.
4478 All ButtonPressed and ButtonReleased events are put in x_mouse_queue. */
4479
4480
4481/* Write the event *P_XREP into the event queue *QUEUE.
4482 If the queue is full, do nothing, but return nonzero. */
4483
4484int
4485enqueue_event (p_xrep, queue)
4486 register XEvent *p_xrep;
4487 register struct event_queue *queue;
4488{
4489 int newindex = queue->windex + 1;
4490 if (newindex == EVENT_BUFFER_SIZE)
4491 newindex = 0;
4492 if (newindex == queue->rindex)
4493 return -1;
4494 queue->xrep[queue->windex] = *p_xrep;
4495 queue->windex = newindex;
4496 return 0;
4497}
4498
4499/* Fetch the next event from queue *QUEUE and store it in *P_XREP.
4500 If *QUEUE is empty, do nothing and return 0. */
4501
4502int
4503dequeue_event (p_xrep, queue)
4504 register XEvent *p_xrep;
4505 register struct event_queue *queue;
4506{
4507 if (queue->windex == queue->rindex)
4508 return 0;
4509 *p_xrep = queue->xrep[queue->rindex++];
4510 if (queue->rindex == EVENT_BUFFER_SIZE)
4511 queue->rindex = 0;
4512 return 1;
4513}
4514
4515/* Return the number of events buffered in *QUEUE. */
4516
4517int
4518queue_event_count (queue)
4519 register struct event_queue *queue;
4520{
4521 int tem = queue->windex - queue->rindex;
4522 if (tem >= 0)
4523 return tem;
4524 return EVENT_BUFFER_SIZE + tem;
4525}
4526
4527/* Return nonzero if mouse input is pending. */
4528
4529int
4530mouse_event_pending_p ()
4531{
4532 return queue_event_count (&x_mouse_queue);
4533}
c118dd06 4534#endif /* HAVE_X11 */
dc6f92b8 4535\f
f451eb13
JB
4536/* Setting window manager hints. */
4537
dc6f92b8
JB
4538#ifdef HAVE_X11
4539
f676886a
JB
4540x_wm_set_size_hint (f, prompting)
4541 struct frame *f;
dc6f92b8
JB
4542 long prompting;
4543{
4544 XSizeHints size_hints;
c118dd06 4545 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4546
f7f79491 4547 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 4548
f676886a
JB
4549 flexlines = f->height;
4550
4551 size_hints.x = f->display.x->left_pos;
4552 size_hints.y = f->display.x->top_pos;
4553 size_hints.height = PIXEL_HEIGHT (f);
4554 size_hints.width = PIXEL_WIDTH (f);
4555 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
4556 size_hints.height_inc = FONT_HEIGHT (f->display.x->font);
f7f79491 4557#if 0
12ba150f
JB
4558 size_hints.max_width = x_screen_width - CHAR_TO_PIXEL_WIDTH (f, 0);
4559 size_hints.max_height = x_screen_height - CHAR_TO_PIXEL_HEIGHT (f, 0);
f7f79491 4560#endif
b1c884c3 4561 {
b0342f17
JB
4562 int base_width, base_height;
4563
f451eb13
JB
4564 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
4565 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17
JB
4566
4567 {
4568 int min_rows = 0, min_cols = 0;
4569 check_frame_size (f, &min_rows, &min_cols);
4570
4571 /* The window manager uses the base width hints to calculate the
4572 current number of rows and columns in the frame while
4573 resizing; min_width and min_height aren't useful for this
4574 purpose, since they might not give the dimensions for a
4575 zero-row, zero-column frame.
4576
4577 We use the base_width and base_height members if we have
4578 them; otherwise, we set the min_width and min_height members
4579 to the size for a zero x zero frame. */
4580
4581#ifdef HAVE_X11R4
4582 size_hints.flags |= PBaseSize;
4583 size_hints.base_width = base_width;
4584 size_hints.base_height = base_height;
4585 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
4586 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
4587#else
4588 size_hints.min_width = base_width;
4589 size_hints.min_height = base_height;
4590#endif
4591 }
b1c884c3 4592
b1c884c3 4593 }
dc6f92b8
JB
4594
4595 if (prompting)
4596 size_hints.flags |= prompting;
4597 else
4598 {
4599 XSizeHints hints; /* Sometimes I hate X Windows... */
4600
82ee0df4
RS
4601 if (XGetNormalHints (x_current_display, window, &hints) == 0)
4602 hints.flags = 0;
dc6f92b8
JB
4603 if (hints.flags & PSize)
4604 size_hints.flags |= PSize;
4605 if (hints.flags & PPosition)
4606 size_hints.flags |= PPosition;
4607 if (hints.flags & USPosition)
4608 size_hints.flags |= USPosition;
4609 if (hints.flags & USSize)
4610 size_hints.flags |= USSize;
4611 }
16bd92ea 4612
b0342f17
JB
4613#ifdef HAVE_X11R4
4614 XSetWMNormalHints (x_current_display, window, &size_hints);
4615#else
dc6f92b8 4616 XSetNormalHints (x_current_display, window, &size_hints);
b0342f17 4617#endif
dc6f92b8
JB
4618}
4619
4620/* Used for IconicState or NormalState */
f676886a
JB
4621x_wm_set_window_state (f, state)
4622 struct frame *f;
dc6f92b8
JB
4623 int state;
4624{
c118dd06 4625 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4626
16bd92ea
JB
4627 f->display.x->wm_hints.flags |= StateHint;
4628 f->display.x->wm_hints.initial_state = state;
b1c884c3 4629
16bd92ea 4630 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4631}
4632
f676886a
JB
4633x_wm_set_icon_pixmap (f, icon_pixmap)
4634 struct frame *f;
dc6f92b8
JB
4635 Pixmap icon_pixmap;
4636{
c118dd06 4637 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4638
dbc4e1c1
JB
4639 if (icon_pixmap)
4640 {
4641 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
4642 f->display.x->wm_hints.flags |= IconPixmapHint;
4643 }
4644 else
4645 f->display.x->wm_hints.flags &= ~IconPixmapHint;
b1c884c3 4646
16bd92ea 4647 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4648}
4649
f676886a
JB
4650x_wm_set_icon_position (f, icon_x, icon_y)
4651 struct frame *f;
dc6f92b8
JB
4652 int icon_x, icon_y;
4653{
c118dd06 4654 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4655
16bd92ea
JB
4656 f->display.x->wm_hints.flags |= IconPositionHint;
4657 f->display.x->wm_hints.icon_x = icon_x;
4658 f->display.x->wm_hints.icon_y = icon_y;
b1c884c3 4659
16bd92ea 4660 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4661}
4662
4663\f
f451eb13
JB
4664/* Initialization. */
4665
dc6f92b8
JB
4666void
4667x_term_init (display_name)
4668 char *display_name;
4669{
f676886a 4670 Lisp_Object frame;
dc6f92b8
JB
4671 char *defaultvalue;
4672#ifdef F_SETOWN
4673 extern int old_fcntl_owner;
c118dd06 4674#endif /* ! defined (F_SETOWN) */
6d4238f3 4675
f676886a 4676 x_focus_frame = x_highlight_frame = 0;
dc6f92b8
JB
4677
4678 x_current_display = XOpenDisplay (display_name);
4679 if (x_current_display == 0)
4680 fatal ("X server %s not responding; check the DISPLAY environment variable or use \"-d\"\n",
4681 display_name);
4682
4683#ifdef HAVE_X11
4684 {
16bd92ea 4685 int hostname_size = 256;
60fb3ee1
JB
4686
4687 hostname = (char *) xmalloc (hostname_size);
4688
dc6f92b8
JB
4689#if 0
4690 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 4691#endif /* ! 0 */
dc6f92b8 4692
60fb3ee1
JB
4693 /* Try to get the host name; if the buffer is too short, try
4694 again. Apparently, the only indication gethostname gives of
4695 whether the buffer was large enough is the presence or absence
4696 of a '\0' in the string. Eech. */
4697 for (;;)
4698 {
4699 gethostname (hostname, hostname_size - 1);
4700 hostname[hostname_size - 1] = '\0';
4701
4702 /* Was the buffer large enough for gethostname to store the '\0'? */
4703 if (strlen (hostname) < hostname_size - 1)
4704 break;
4705
4706 hostname_size <<= 1;
4707 hostname = (char *) xrealloc (hostname, hostname_size);
4708 }
59653951 4709 x_id_name = (char *) xmalloc (XSTRING (Vinvocation_name)->size
60fb3ee1
JB
4710 + strlen (hostname)
4711 + 2);
59653951 4712 sprintf (x_id_name, "%s@%s", XSTRING (Vinvocation_name)->data, hostname);
dc6f92b8 4713 }
28430d3c
JB
4714
4715 /* Figure out which modifier bits mean what. */
4716 x_find_modifier_meanings ();
f451eb13 4717
ab648270 4718 /* Get the scroll bar cursor. */
d56a553a
RS
4719 x_vertical_scroll_bar_cursor
4720 = XCreateFontCursor (x_current_display, XC_sb_v_double_arrow);
f451eb13 4721
d56a553a 4722#if 0
28430d3c
JB
4723 /* Watch for PropertyNotify events on the root window; we use them
4724 to figure out when to invalidate our cache of the cut buffers. */
4725 x_watch_cut_buffer_cache ();
d56a553a 4726#endif
28430d3c 4727
a4fc7360
JB
4728 if (ConnectionNumber (x_current_display) != 0)
4729 {
4730 dup2 (ConnectionNumber (x_current_display), 0);
6d4238f3
JB
4731
4732#ifndef SYSV_STREAMS
a4fc7360
JB
4733 /* Streams somehow keeps track of which descriptor number
4734 is being used to talk to X. So it is not safe to substitute
4735 descriptor 0. But it is safe to make descriptor 0 a copy of it. */
4736 close (ConnectionNumber (x_current_display));
4737 ConnectionNumber (x_current_display) = 0; /* Looks a little strange?
6d4238f3
JB
4738 * check the def of the macro;
4739 * it is a genuine lvalue */
c118dd06 4740#endif /* SYSV_STREAMS */
a4fc7360 4741 }
6d4238f3 4742
c118dd06 4743#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4744
4745#ifdef F_SETOWN
4746 old_fcntl_owner = fcntl (0, F_GETOWN, 0);
4747#ifdef F_SETOWN_SOCK_NEG
4748 fcntl (0, F_SETOWN, -getpid ()); /* stdin is a socket here */
c118dd06 4749#else /* ! defined (F_SETOWN_SOCK_NEG) */
dc6f92b8 4750 fcntl (0, F_SETOWN, getpid ());
c118dd06
JB
4751#endif /* ! defined (F_SETOWN_SOCK_NEG) */
4752#endif /* ! defined (F_SETOWN) */
dc6f92b8
JB
4753
4754#ifdef SIGIO
4755 init_sigio ();
c118dd06 4756#endif /* ! defined (SIGIO) */
dc6f92b8
JB
4757
4758 /* Must use interrupt input because we cannot otherwise
4759 arrange for C-g to be noticed immediately.
4760 We cannot connect it to SIGINT. */
4761 Fset_input_mode (Qt, Qnil, Qt, Qnil);
4762
4763 expose_all_windows = 0;
4764
f676886a 4765 clear_frame_hook = XTclear_frame;
dc6f92b8
JB
4766 clear_end_of_line_hook = XTclear_end_of_line;
4767 ins_del_lines_hook = XTins_del_lines;
4768 change_line_highlight_hook = XTchange_line_highlight;
4769 insert_glyphs_hook = XTinsert_glyphs;
4770 write_glyphs_hook = XTwrite_glyphs;
4771 delete_glyphs_hook = XTdelete_glyphs;
4772 ring_bell_hook = XTring_bell;
4773 reset_terminal_modes_hook = XTreset_terminal_modes;
4774 set_terminal_modes_hook = XTset_terminal_modes;
4775 update_begin_hook = XTupdate_begin;
4776 update_end_hook = XTupdate_end;
4777 set_terminal_window_hook = XTset_terminal_window;
4778 read_socket_hook = XTread_socket;
4779 cursor_to_hook = XTcursor_to;
4780 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 4781 mouse_position_hook = XTmouse_position;
f451eb13 4782 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 4783 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
4784 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
4785 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
4786 redeem_scroll_bar_hook = XTredeem_scroll_bar;
4787 judge_scroll_bars_hook = XTjudge_scroll_bars;
dc6f92b8 4788
f676886a 4789 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
4790 char_ins_del_ok = 0; /* just as fast to write the line */
4791 line_ins_del_ok = 1; /* we'll just blt 'em */
4792 fast_clear_end_of_line = 1; /* X does this well */
f676886a 4793 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
4794 off the bottom */
4795 baud_rate = 19200;
4796
c118dd06
JB
4797 /* Note that there is no real way portable across R3/R4 to get the
4798 original error handler. */
4799 XHandleError (x_error_quitter);
8922af5f 4800 XHandleIOError (x_io_error_quitter);
dc6f92b8
JB
4801
4802 /* Disable Window Change signals; they are handled by X events. */
4803#ifdef SIGWINCH
4804 signal (SIGWINCH, SIG_DFL);
c118dd06 4805#endif /* ! defined (SIGWINCH) */
dc6f92b8 4806
c118dd06 4807 signal (SIGPIPE, x_connection_closed);
dc6f92b8 4808}
55123275
JB
4809
4810void
4811syms_of_xterm ()
4812{
ab648270 4813 staticpro (&last_mouse_scroll_bar);
55123275 4814}
c118dd06
JB
4815#endif /* ! defined (HAVE_X11) */
4816#endif /* ! defined (HAVE_X_WINDOWS) */