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