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