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