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