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