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