(VALBITS, GCTYPEBITS): Deleted; default is better.
[bpt/emacs.git] / src / xterm.c
1 /* X Communication module for terminals which understand the X protocol.
2 Copyright (C) 1989, 1993, 1994 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 /* Xt features made by Fred Pierresteguy. */
21
22 /* On 4.3 these lose if they come after xterm.h. */
23 /* On HP-UX 8.0 signal.h loses if it comes after config.h. */
24 /* Putting these at the beginning seems to be standard for other .c files. */
25 #include <signal.h>
26
27 #include <config.h>
28
29 #include <stdio.h>
30
31 /* Need syssignal.h for various externs and definitions that may be required
32 by some configurations for calls to signal later in this source file. */
33 #include "syssignal.h"
34
35 #ifdef HAVE_X_WINDOWS
36
37 #include "lisp.h"
38 #include "blockinput.h"
39
40 /* This may include sys/types.h, and that somehow loses
41 if this is not done before the other system files. */
42 #include "xterm.h"
43 #include <X11/cursorfont.h>
44
45 #ifndef USG
46 /* Load sys/types.h if not already loaded.
47 In some systems loading it twice is suicidal. */
48 #ifndef makedev
49 #include <sys/types.h>
50 #endif /* makedev */
51 #endif /* USG */
52
53 #ifdef BSD
54 #include <sys/ioctl.h>
55 #endif /* ! defined (BSD) */
56
57 #include "systty.h"
58 #include "systime.h"
59
60 #ifndef INCLUDED_FCNTL
61 #include <fcntl.h>
62 #endif
63 #include <ctype.h>
64 #include <errno.h>
65 #include <setjmp.h>
66 #include <sys/stat.h>
67 #include <sys/param.h>
68
69 #include "frame.h"
70 #include "dispextern.h"
71 #include "termhooks.h"
72 #include "termopts.h"
73 #include "termchar.h"
74 #if 0
75 #include "sink.h"
76 #include "sinkmask.h"
77 #endif /* ! 0 */
78 #include "gnu.h"
79 #include "disptab.h"
80 #include "buffer.h"
81 #include "window.h"
82 #include "keyboard.h"
83 #include "intervals.h"
84
85 #ifdef USE_X_TOOLKIT
86 extern void free_frame_menubar ();
87 extern void _XEditResCheckMessages ();
88 #endif /* USE_X_TOOLKIT */
89
90 #ifndef USE_X_TOOLKIT
91 #define x_any_window_to_frame x_window_to_frame
92 #define x_top_window_to_frame x_window_to_frame
93 #endif
94
95 #ifdef USE_X_TOOLKIT
96 #ifndef XtNinitialState
97 #define XtNinitialState "initialState"
98 #endif
99 #endif
100
101 #define min(a,b) ((a)<(b) ? (a) : (b))
102 #define max(a,b) ((a)>(b) ? (a) : (b))
103 \f
104 /* This is a chain of structures for all the X displays currently in use. */
105 struct x_display_info *x_display_list;
106
107 /* This is a list of cons cells, each of the form (NAME . FONT-LIST-CACHE),
108 one for each element of x_display_list and in the same order.
109 NAME is the name of the frame.
110 FONT-LIST-CACHE records previous values returned by x-list-fonts. */
111 Lisp_Object x_display_name_list;
112
113 /* Frame being updated by update_frame. This is declared in term.c.
114 This is set by update_begin and looked at by all the
115 XT functions. It is zero while not inside an update.
116 In that case, the XT functions assume that `selected_frame'
117 is the frame to apply to. */
118 extern struct frame *updating_frame;
119
120 /* The frame (if any) which has the X window that has keyboard focus.
121 Zero if none. This is examined by Ffocus_frame in frame.c. Note
122 that a mere EnterNotify event can set this; if you need to know the
123 last frame specified in a FocusIn or FocusOut event, use
124 x_focus_event_frame. */
125 struct frame *x_focus_frame;
126
127 /* This is a frame waiting to be autoraised, within XTread_socket. */
128 struct frame *pending_autoraise_frame;
129
130 /* The last frame mentioned in a FocusIn or FocusOut event. This is
131 separate from x_focus_frame, because whether or not LeaveNotify
132 events cause us to lose focus depends on whether or not we have
133 received a FocusIn event for it. */
134 struct frame *x_focus_event_frame;
135
136 /* The frame which currently has the visual highlight, and should get
137 keyboard input (other sorts of input have the frame encoded in the
138 event). It points to the X focus frame's selected window's
139 frame. It differs from x_focus_frame when we're using a global
140 minibuffer. */
141 static struct frame *x_highlight_frame;
142
143 #ifdef USE_X_TOOLKIT
144 /* The application context for Xt use. */
145 XtAppContext Xt_app_con;
146 #endif
147
148 /* During an update, maximum vpos for ins/del line operations to affect. */
149
150 static int flexlines;
151
152 /* During an update, nonzero if chars output now should be highlighted. */
153
154 static int highlight;
155
156 /* Nominal cursor position -- where to draw output.
157 During an update, these are different from the cursor-box position. */
158
159 static int curs_x;
160 static int curs_y;
161
162 /* Mouse movement.
163
164 In order to avoid asking for motion events and then throwing most
165 of them away or busy-polling the server for mouse positions, we ask
166 the server for pointer motion hints. This means that we get only
167 one event per group of mouse movements. "Groups" are delimited by
168 other kinds of events (focus changes and button clicks, for
169 example), or by XQueryPointer calls; when one of these happens, we
170 get another MotionNotify event the next time the mouse moves. This
171 is at least as efficient as getting motion events when mouse
172 tracking is on, and I suspect only negligibly worse when tracking
173 is off.
174
175 The silly O'Reilly & Associates Nutshell guides barely document
176 pointer motion hints at all (I think you have to infer how they
177 work from an example), and the description of XQueryPointer doesn't
178 mention that calling it causes you to get another motion hint from
179 the server, which is very important. */
180
181 /* Where the mouse was last time we reported a mouse event. */
182 static FRAME_PTR last_mouse_frame;
183 static XRectangle last_mouse_glyph;
184
185 /* The scroll bar in which the last X motion event occurred.
186
187 If the last X motion event occurred in a scroll bar, we set this
188 so XTmouse_position can know whether to report a scroll bar motion or
189 an ordinary motion.
190
191 If the last X motion event didn't occur in a scroll bar, we set this
192 to Qnil, to tell XTmouse_position to return an ordinary motion event. */
193 static Lisp_Object last_mouse_scroll_bar;
194
195 /* This is a hack. We would really prefer that XTmouse_position would
196 return the time associated with the position it returns, but there
197 doesn't seem to be any way to wrest the timestamp from the server
198 along with the position query. So, we just keep track of the time
199 of the last movement we received, and return that in hopes that
200 it's somewhat accurate. */
201 static Time last_mouse_movement_time;
202
203 /* Incremented by XTread_socket whenever it really tries to read events. */
204 #ifdef __STDC__
205 static int volatile input_signal_count;
206 #else
207 static int input_signal_count;
208 #endif
209
210 /* Used locally within XTread_socket. */
211 static int x_noop_count;
212
213 /* Initial values of argv and argc. */
214 extern char **initial_argv;
215 extern int initial_argc;
216
217 extern Lisp_Object Vcommand_line_args, Vsystem_name;
218
219 /* Tells if a window manager is present or not. */
220
221 extern Lisp_Object Vx_no_window_manager;
222
223 /* Nonzero enables some debugging for the X interface code. */
224 extern int _Xdebug;
225
226 extern Lisp_Object Qface, Qmouse_face;
227
228 extern int errno;
229
230 /* A mask of extra modifier bits to put into every keyboard char. */
231 extern int extra_keyboard_modifiers;
232
233 extern XrmDatabase x_load_resources ();
234
235 void x_delete_display ();
236
237 static void flashback ();
238 static void redraw_previous_char ();
239 static void redraw_following_char ();
240 static unsigned int x_x_to_emacs_modifiers ();
241
242 static int fast_find_position ();
243 static void note_mouse_highlight ();
244 static void clear_mouse_face ();
245 static void show_mouse_face ();
246 static void do_line_dance ();
247
248 static int XTcursor_to ();
249 static int XTclear_end_of_line ();
250 static int x_io_error_quitter ();
251 \f
252 /* Return the struct x_display_info corresponding to DPY. */
253
254 struct x_display_info *
255 x_display_info_for_display (dpy)
256 Display *dpy;
257 {
258 struct x_display_info *dpyinfo;
259
260 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
261 if (dpyinfo->display == dpy)
262 return dpyinfo;
263
264 return 0;
265 }
266 \f
267 /* Starting and ending updates.
268
269 These hooks are called by update_frame at the beginning and end
270 of a frame update. We record in `updating_frame' the identity
271 of the frame being updated, so that the XT... functions do not
272 need to take a frame as argument. Most of the XT... functions
273 should never be called except during an update, the only exceptions
274 being XTcursor_to, XTwrite_glyphs and XTreassert_line_highlight. */
275
276 static
277 XTupdate_begin (f)
278 struct frame *f;
279 {
280 int mask;
281
282 if (f == 0)
283 abort ();
284
285 flexlines = f->height;
286 highlight = 0;
287
288 BLOCK_INPUT;
289
290 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
291 {
292 /* Don't do highlighting for mouse motion during the update. */
293 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 1;
294
295 /* If the frame needs to be redrawn,
296 simply forget about any prior mouse highlighting. */
297 if (FRAME_GARBAGED_P (f))
298 FRAME_X_DISPLAY_INFO (f)->mouse_face_window = Qnil;
299
300 if (!NILP (FRAME_X_DISPLAY_INFO (f)->mouse_face_window))
301 {
302 int firstline, lastline, i;
303 struct window *w = XWINDOW (FRAME_X_DISPLAY_INFO (f)->mouse_face_window);
304
305 /* Find the first, and the last+1, lines affected by redisplay. */
306 for (firstline = 0; firstline < f->height; firstline++)
307 if (FRAME_DESIRED_GLYPHS (f)->enable[firstline])
308 break;
309
310 lastline = f->height;
311 for (i = f->height - 1; i >= 0; i--)
312 {
313 if (FRAME_DESIRED_GLYPHS (f)->enable[i])
314 break;
315 else
316 lastline = i;
317 }
318
319 /* Can we tell that this update does not affect the window
320 where the mouse highlight is? If so, no need to turn off.
321 Likewise, don't do anything if the frame is garbaged;
322 in that case, the FRAME_CURRENT_GLYPHS that we would use
323 are all wrong, and we will redisplay that line anyway. */
324 if (! (firstline > (XFASTINT (w->top) + window_internal_height (w))
325 || lastline < XFASTINT (w->top)))
326 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
327 }
328 }
329
330 UNBLOCK_INPUT;
331 }
332
333 static
334 XTupdate_end (f)
335 struct frame *f;
336 {
337 int mask;
338
339 BLOCK_INPUT;
340
341 do_line_dance ();
342 x_display_cursor (f, 1);
343
344 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
345 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
346 #if 0
347 /* This fails in the case of having updated only the echo area
348 if we have switched buffers. In that case, FRAME_CURRENT_GLYPHS
349 has no relation to the current contents, and its charstarts
350 have no relation to the contents of the window-buffer.
351 I don't know a clean way to check
352 for that case. window_end_valid isn't set up yet. */
353 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
354 note_mouse_highlight (f, FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x,
355 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y);
356 #endif
357
358 XFlush (FRAME_X_DISPLAY (f));
359 UNBLOCK_INPUT;
360 }
361
362 /* This is called after a redisplay on frame F. */
363
364 static
365 XTframe_up_to_date (f)
366 FRAME_PTR f;
367 {
368 if (FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc
369 || f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
370 {
371 note_mouse_highlight (FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame,
372 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x,
373 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y);
374 FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc = 0;
375 }
376 }
377 \f
378 /* External interface to control of standout mode.
379 Call this when about to modify line at position VPOS
380 and not change whether it is highlighted. */
381
382 XTreassert_line_highlight (new, vpos)
383 int new, vpos;
384 {
385 highlight = new;
386 }
387
388 /* Call this when about to modify line at position VPOS
389 and change whether it is highlighted. */
390
391 static
392 XTchange_line_highlight (new_highlight, vpos, first_unused_hpos)
393 int new_highlight, vpos, first_unused_hpos;
394 {
395 highlight = new_highlight;
396 XTcursor_to (vpos, 0);
397 XTclear_end_of_line (updating_frame->width);
398 }
399
400 /* This is used when starting Emacs and when restarting after suspend.
401 When starting Emacs, no X window is mapped. And nothing must be done
402 to Emacs's own window if it is suspended (though that rarely happens). */
403
404 static
405 XTset_terminal_modes ()
406 {
407 }
408
409 /* This is called when exiting or suspending Emacs.
410 Exiting will make the X-windows go away, and suspending
411 requires no action. */
412
413 static
414 XTreset_terminal_modes ()
415 {
416 /* XTclear_frame (); */
417 }
418 \f
419 /* Set the nominal cursor position of the frame.
420 This is where display update commands will take effect.
421 This does not affect the place where the cursor-box is displayed. */
422
423 static int
424 XTcursor_to (row, col)
425 register int row, col;
426 {
427 int mask;
428 int orow = row;
429
430 curs_x = col;
431 curs_y = row;
432
433 if (updating_frame == 0)
434 {
435 BLOCK_INPUT;
436 x_display_cursor (selected_frame, 1);
437 XFlush (FRAME_X_DISPLAY (selected_frame));
438 UNBLOCK_INPUT;
439 }
440 }
441 \f
442 /* Display a sequence of N glyphs found at GP.
443 WINDOW is the x-window to output to. LEFT and TOP are starting coords.
444 HL is 1 if this text is highlighted, 2 if the cursor is on it,
445 3 if should appear in its mouse-face.
446 JUST_FOREGROUND if 1 means draw only the foreground;
447 don't alter the background.
448
449 FONT is the default font to use (for glyphs whose font-code is 0).
450
451 Since the display generation code is responsible for calling
452 compute_char_face and compute_glyph_face on everything it puts in
453 the display structure, we can assume that the face code on each
454 glyph is a valid index into FRAME_COMPUTED_FACES (f), and the one
455 to which we can actually apply intern_face.
456 Call this function with input blocked. */
457
458 #if 1
459 /* This is the multi-face code. */
460
461 static void
462 dumpglyphs (f, left, top, gp, n, hl, just_foreground)
463 struct frame *f;
464 int left, top;
465 register GLYPH *gp; /* Points to first GLYPH. */
466 register int n; /* Number of glyphs to display. */
467 int hl;
468 int just_foreground;
469 {
470 /* Holds characters to be displayed. */
471 char *buf = (char *) alloca (f->width * sizeof (*buf));
472 register char *cp; /* Steps through buf[]. */
473 register int tlen = GLYPH_TABLE_LENGTH;
474 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
475 Window window = FRAME_X_WINDOW (f);
476 int orig_left = left;
477
478 while (n > 0)
479 {
480 /* Get the face-code of the next GLYPH. */
481 int cf, len;
482 int g = *gp;
483
484 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
485 cf = FAST_GLYPH_FACE (g);
486
487 /* Find the run of consecutive glyphs with the same face-code.
488 Extract their character codes into BUF. */
489 cp = buf;
490 while (n > 0)
491 {
492 g = *gp;
493 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
494 if (FAST_GLYPH_FACE (g) != cf)
495 break;
496
497 *cp++ = FAST_GLYPH_CHAR (g);
498 --n;
499 ++gp;
500 }
501
502 /* LEN gets the length of the run. */
503 len = cp - buf;
504
505 /* Now output this run of chars, with the font and pixel values
506 determined by the face code CF. */
507 {
508 struct face *face = FRAME_DEFAULT_FACE (f);
509 XFontStruct *font = FACE_FONT (face);
510 GC gc = FACE_GC (face);
511 int stippled = 0;
512
513 /* HL = 3 means use a mouse face previously chosen. */
514 if (hl == 3)
515 cf = FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id;
516
517 /* First look at the face of the text itself. */
518 if (cf != 0)
519 {
520 /* It's possible for the display table to specify
521 a face code that is out of range. Use 0 in that case. */
522 if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f)
523 || FRAME_COMPUTED_FACES (f) [cf] == 0)
524 cf = 0;
525
526 if (cf == 1)
527 face = FRAME_MODE_LINE_FACE (f);
528 else
529 face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
530 font = FACE_FONT (face);
531 gc = FACE_GC (face);
532 if (FACE_STIPPLE (face))
533 stippled = 1;
534 }
535
536 /* Then comes the distinction between modeline and normal text. */
537 else if (hl == 0)
538 ;
539 else if (hl == 1)
540 {
541 face = FRAME_MODE_LINE_FACE (f);
542 font = FACE_FONT (face);
543 gc = FACE_GC (face);
544 if (FACE_STIPPLE (face))
545 stippled = 1;
546 }
547
548 #define FACE_DEFAULT (~0)
549
550 /* Now override that if the cursor's on this character. */
551 if (hl == 2)
552 {
553 /* The cursor overrides stippling. */
554 stippled = 0;
555
556 if ((!face->font
557 || (int) face->font == FACE_DEFAULT
558 || face->font == f->display.x->font)
559 && face->background == f->display.x->background_pixel
560 && face->foreground == f->display.x->foreground_pixel)
561 {
562 gc = f->display.x->cursor_gc;
563 }
564 /* Cursor on non-default face: must merge. */
565 else
566 {
567 XGCValues xgcv;
568 unsigned long mask;
569
570 xgcv.background = f->display.x->cursor_pixel;
571 xgcv.foreground = face->background;
572 /* If the glyph would be invisible,
573 try a different foreground. */
574 if (xgcv.foreground == xgcv.background)
575 xgcv.foreground = face->foreground;
576 if (xgcv.foreground == xgcv.background)
577 xgcv.foreground = f->display.x->cursor_foreground_pixel;
578 if (xgcv.foreground == xgcv.background)
579 xgcv.foreground = face->foreground;
580 /* Make sure the cursor is distinct from text in this face. */
581 if (xgcv.background == face->background
582 && xgcv.foreground == face->foreground)
583 {
584 xgcv.background = face->foreground;
585 xgcv.foreground = face->background;
586 }
587 xgcv.font = face->font->fid;
588 xgcv.graphics_exposures = 0;
589 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
590 if (FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc)
591 XChangeGC (FRAME_X_DISPLAY (f),
592 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc,
593 mask, &xgcv);
594 else
595 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc
596 = XCreateGC (FRAME_X_DISPLAY (f), window, mask, &xgcv);
597 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
598 #if 0
599 /* If this code is restored, it must also reset to the default stipple
600 if necessary. */
601 if (face->stipple && face->stipple != FACE_DEFAULT)
602 XSetStipple (FRAME_X_DISPLAY (f), gc, face->stipple);
603 #endif
604 }
605 }
606
607 if ((int) font == FACE_DEFAULT)
608 font = f->display.x->font;
609
610 if (just_foreground)
611 XDrawString (FRAME_X_DISPLAY (f), window, gc,
612 left, top + FONT_BASE (font), buf, len);
613 else
614 {
615 if (stippled)
616 {
617 /* Turn stipple on. */
618 XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillOpaqueStippled);
619
620 /* Draw stipple on background. */
621 XFillRectangle (FRAME_X_DISPLAY (f), window, gc,
622 left, top,
623 FONT_WIDTH (font) * len,
624 FONT_HEIGHT (font));
625
626 /* Turn stipple off. */
627 XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillSolid);
628
629 /* Draw the text, solidly, onto the stipple pattern. */
630 XDrawString (FRAME_X_DISPLAY (f), window, gc,
631 left, top + FONT_BASE (font), buf, len);
632 }
633 else
634 XDrawImageString (FRAME_X_DISPLAY (f), window, gc,
635 left, top + FONT_BASE (font), buf, len);
636
637 /* Clear the rest of the line's height. */
638 if (f->display.x->line_height != FONT_HEIGHT (font))
639 XClearArea (FRAME_X_DISPLAY (f), window, left,
640 top + FONT_HEIGHT (font),
641 FONT_WIDTH (font) * len,
642 /* This is how many pixels of height
643 we have to clear. */
644 f->display.x->line_height - FONT_HEIGHT (font),
645 False);
646 }
647
648 #if 0 /* Doesn't work, because it uses FRAME_CURRENT_GLYPHS,
649 which often is not up to date yet. */
650 if (!just_foreground)
651 {
652 if (left == orig_left)
653 redraw_previous_char (f, PIXEL_TO_CHAR_COL (f, left),
654 PIXEL_TO_CHAR_ROW (f, top), hl == 1);
655 if (n == 0)
656 redraw_following_char (f, PIXEL_TO_CHAR_COL (f, left + len * FONT_WIDTH (font)),
657 PIXEL_TO_CHAR_ROW (f, top), hl == 1);
658 }
659 #endif
660
661 /* We should probably check for XA_UNDERLINE_POSITION and
662 XA_UNDERLINE_THICKNESS properties on the font, but let's
663 just get the thing working, and come back to that. */
664 {
665 int underline_position = 1;
666
667 if (font->descent <= underline_position)
668 underline_position = font->descent - 1;
669
670 if (face->underline)
671 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
672 FACE_GC (face),
673 left, (top
674 + FONT_BASE (font)
675 + underline_position),
676 len * FONT_WIDTH (font), 1);
677 }
678
679 left += len * FONT_WIDTH (font);
680 }
681 }
682 }
683 #endif /* 1 */
684
685 #if 0
686 /* This is the old single-face code. */
687
688 static void
689 dumpglyphs (f, left, top, gp, n, hl, font)
690 struct frame *f;
691 int left, top;
692 register GLYPH *gp; /* Points to first GLYPH. */
693 register int n; /* Number of glyphs to display. */
694 int hl;
695 XFontStruct *font;
696 {
697 register int len;
698 Window window = FRAME_X_WINDOW (f);
699 GC drawing_gc = (hl == 2 ? f->display.x->cursor_gc
700 : (hl ? f->display.x->reverse_gc
701 : f->display.x->normal_gc));
702
703 if (sizeof (GLYPH) == sizeof (XChar2b))
704 XDrawImageString16 (FRAME_X_DISPLAY (f), window, drawing_gc,
705 left, top + FONT_BASE (font), (XChar2b *) gp, n);
706 else if (sizeof (GLYPH) == sizeof (unsigned char))
707 XDrawImageString (FRAME_X_DISPLAY (f), window, drawing_gc,
708 left, top + FONT_BASE (font), (char *) gp, n);
709 else
710 /* What size of glyph ARE you using? And does X have a function to
711 draw them? */
712 abort ();
713 }
714 #endif
715 \f
716 /* Output some text at the nominal frame cursor position.
717 Advance the cursor over the text.
718 Output LEN glyphs at START.
719
720 `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight,
721 controls the pixel values used for foreground and background. */
722
723 static
724 XTwrite_glyphs (start, len)
725 register GLYPH *start;
726 int len;
727 {
728 register int temp_length;
729 int mask;
730 struct frame *f;
731
732 BLOCK_INPUT;
733
734 do_line_dance ();
735 f = updating_frame;
736 if (f == 0)
737 {
738 f = selected_frame;
739 /* If not within an update,
740 output at the frame's visible cursor. */
741 curs_x = f->cursor_x;
742 curs_y = f->cursor_y;
743 }
744
745 dumpglyphs (f,
746 CHAR_TO_PIXEL_COL (f, curs_x),
747 CHAR_TO_PIXEL_ROW (f, curs_y),
748 start, len, highlight, 0);
749
750 /* If we drew on top of the cursor, note that it is turned off. */
751 if (curs_y == f->phys_cursor_y
752 && curs_x <= f->phys_cursor_x
753 && curs_x + len > f->phys_cursor_x)
754 f->phys_cursor_x = -1;
755
756 if (updating_frame == 0)
757 {
758 f->cursor_x += len;
759 x_display_cursor (f, 1);
760 f->cursor_x -= len;
761 }
762 else
763 curs_x += len;
764
765 UNBLOCK_INPUT;
766 }
767 \f
768 /* Clear to the end of the line.
769 Erase the current text line from the nominal cursor position (inclusive)
770 to column FIRST_UNUSED (exclusive). The idea is that everything
771 from FIRST_UNUSED onward is already erased. */
772
773 static int
774 XTclear_end_of_line (first_unused)
775 register int first_unused;
776 {
777 struct frame *f = updating_frame;
778 int mask;
779
780 if (f == 0)
781 abort ();
782
783 if (curs_y < 0 || curs_y >= f->height)
784 return;
785 if (first_unused <= 0)
786 return;
787
788 if (first_unused >= f->width)
789 first_unused = f->width;
790
791 BLOCK_INPUT;
792
793 do_line_dance ();
794
795 /* Notice if the cursor will be cleared by this operation. */
796 if (curs_y == f->phys_cursor_y
797 && curs_x <= f->phys_cursor_x
798 && f->phys_cursor_x < first_unused)
799 f->phys_cursor_x = -1;
800
801 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
802 CHAR_TO_PIXEL_COL (f, curs_x),
803 CHAR_TO_PIXEL_ROW (f, curs_y),
804 FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
805 f->display.x->line_height, False);
806 #if 0
807 redraw_previous_char (f, curs_x, curs_y, highlight);
808 #endif
809
810 UNBLOCK_INPUT;
811 }
812
813 static
814 XTclear_frame ()
815 {
816 int mask;
817 struct frame *f = updating_frame;
818
819 if (f == 0)
820 f = selected_frame;
821
822 f->phys_cursor_x = -1; /* Cursor not visible. */
823 curs_x = 0; /* Nominal cursor position is top left. */
824 curs_y = 0;
825
826 BLOCK_INPUT;
827
828 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
829
830 /* We have to clear the scroll bars, too. If we have changed
831 colors or something like that, then they should be notified. */
832 x_scroll_bar_clear (f);
833
834 XFlush (FRAME_X_DISPLAY (f));
835 UNBLOCK_INPUT;
836 }
837 \f
838 #if 0
839 /* This currently does not work because FRAME_CURRENT_GLYPHS doesn't
840 always contain the right glyphs to use.
841
842 It also needs to be changed to look at the details of the font and
843 see whether there is really overlap, and do nothing when there is
844 not. This can use font_char_overlap_left and font_char_overlap_right,
845 but just how to use them is not clear. */
846
847 /* Erase the character (if any) at the position just before X, Y in frame F,
848 then redraw it and the character before it.
849 This is necessary when we erase starting at X,
850 in case the character after X overlaps into the one before X.
851 Call this function with input blocked. */
852
853 static void
854 redraw_previous_char (f, x, y, highlight_flag)
855 FRAME_PTR f;
856 int x, y;
857 int highlight_flag;
858 {
859 /* Erase the character before the new ones, in case
860 what was here before overlaps it.
861 Reoutput that character, and the previous character
862 (in case the previous character overlaps it). */
863 if (x > 0)
864 {
865 int start_x = x - 2;
866 if (start_x < 0)
867 start_x = 0;
868 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
869 CHAR_TO_PIXEL_COL (f, x - 1),
870 CHAR_TO_PIXEL_ROW (f, y),
871 FONT_WIDTH (f->display.x->font),
872 f->display.x->line_height, False);
873
874 dumpglyphs (f, CHAR_TO_PIXEL_COL (f, start_x),
875 CHAR_TO_PIXEL_ROW (f, y),
876 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][start_x],
877 x - start_x, highlight_flag, 1);
878 }
879 }
880
881 /* Erase the character (if any) at the position X, Y in frame F,
882 then redraw it and the character after it.
883 This is necessary when we erase endng at X,
884 in case the character after X overlaps into the one before X.
885 Call this function with input blocked. */
886
887 static void
888 redraw_following_char (f, x, y, highlight_flag)
889 FRAME_PTR f;
890 int x, y;
891 int highlight_flag;
892 {
893 int limit = FRAME_CURRENT_GLYPHS (f)->used[y];
894 /* Erase the character after the new ones, in case
895 what was here before overlaps it.
896 Reoutput that character, and the following character
897 (in case the following character overlaps it). */
898 if (x < limit
899 && FRAME_CURRENT_GLYPHS (f)->glyphs[y][x] != SPACEGLYPH)
900 {
901 int end_x = x + 2;
902 if (end_x > limit)
903 end_x = limit;
904 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
905 CHAR_TO_PIXEL_COL (f, x),
906 CHAR_TO_PIXEL_ROW (f, y),
907 FONT_WIDTH (f->display.x->font),
908 f->display.x->line_height, False);
909
910 dumpglyphs (f, CHAR_TO_PIXEL_COL (f, x),
911 CHAR_TO_PIXEL_ROW (f, y),
912 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][x],
913 end_x - x, highlight_flag, 1);
914 }
915 }
916 #endif /* 0 */
917 \f
918 #if 0 /* Not in use yet */
919
920 /* Return 1 if character C in font F extends past its left edge. */
921
922 static int
923 font_char_overlap_left (font, c)
924 XFontStruct *font;
925 int c;
926 {
927 XCharStruct *s;
928
929 /* Find the bounding-box info for C. */
930 if (font->per_char == 0)
931 s = &font->max_bounds;
932 else
933 {
934 int rowlen = font->max_char_or_byte2 - font->min_char_or_byte2 + 1;
935 int row, within;
936
937 /* Decode char into row number (byte 1) and code within row (byte 2). */
938 row = c >> 8;
939 within = c & 0177;
940 if (!(within >= font->min_char_or_byte2
941 && within <= font->max_char_or_byte2
942 && row >= font->min_byte1
943 && row <= font->max_byte1))
944 {
945 /* If char is out of range, try the font's default char instead. */
946 c = font->default_char;
947 row = c >> (INTBITS - 8);
948 within = c & 0177;
949 }
950 if (!(within >= font->min_char_or_byte2
951 && within <= font->max_char_or_byte2
952 && row >= font->min_byte1
953 && row <= font->max_byte1))
954 /* Still out of range means this char does not overlap. */
955 return 0;
956 else
957 /* We found the info for this char. */
958 s = (font->per_char + (within - font->min_char_or_byte2)
959 + row * rowlen);
960 }
961
962 return (s && s->lbearing < 0);
963 }
964
965 /* Return 1 if character C in font F extends past its right edge. */
966
967 static int
968 font_char_overlap_right (font, c)
969 XFontStruct *font;
970 int c;
971 {
972 XCharStruct *s;
973
974 /* Find the bounding-box info for C. */
975 if (font->per_char == 0)
976 s = &font->max_bounds;
977 else
978 {
979 int rowlen = font->max_char_or_byte2 - font->min_char_or_byte2 + 1;
980 int row, within;
981
982 /* Decode char into row number (byte 1) and code within row (byte 2). */
983 row = c >> 8;
984 within = c & 0177;
985 if (!(within >= font->min_char_or_byte2
986 && within <= font->max_char_or_byte2
987 && row >= font->min_byte1
988 && row <= font->max_byte1))
989 {
990 /* If char is out of range, try the font's default char instead. */
991 c = font->default_char;
992 row = c >> (INTBITS - 8);
993 within = c & 0177;
994 }
995 if (!(within >= font->min_char_or_byte2
996 && within <= font->max_char_or_byte2
997 && row >= font->min_byte1
998 && row <= font->max_byte1))
999 /* Still out of range means this char does not overlap. */
1000 return 0;
1001 else
1002 /* We found the info for this char. */
1003 s = (font->per_char + (within - font->min_char_or_byte2)
1004 + row * rowlen);
1005 }
1006
1007 return (s && s->rbearing >= s->width);
1008 }
1009 #endif /* 0 */
1010 \f
1011 /* Invert the middle quarter of the frame for .15 sec. */
1012
1013 /* We use the select system call to do the waiting, so we have to make sure
1014 it's available. If it isn't, we just won't do visual bells. */
1015 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
1016
1017 /* Subtract the `struct timeval' values X and Y,
1018 storing the result in RESULT.
1019 Return 1 if the difference is negative, otherwise 0. */
1020
1021 static int
1022 timeval_subtract (result, x, y)
1023 struct timeval *result, x, y;
1024 {
1025 /* Perform the carry for the later subtraction by updating y.
1026 This is safer because on some systems
1027 the tv_sec member is unsigned. */
1028 if (x.tv_usec < y.tv_usec)
1029 {
1030 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
1031 y.tv_usec -= 1000000 * nsec;
1032 y.tv_sec += nsec;
1033 }
1034 if (x.tv_usec - y.tv_usec > 1000000)
1035 {
1036 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
1037 y.tv_usec += 1000000 * nsec;
1038 y.tv_sec -= nsec;
1039 }
1040
1041 /* Compute the time remaining to wait. tv_usec is certainly positive. */
1042 result->tv_sec = x.tv_sec - y.tv_sec;
1043 result->tv_usec = x.tv_usec - y.tv_usec;
1044
1045 /* Return indication of whether the result should be considered negative. */
1046 return x.tv_sec < y.tv_sec;
1047 }
1048
1049 XTflash (f)
1050 struct frame *f;
1051 {
1052 BLOCK_INPUT;
1053
1054 {
1055 GC gc;
1056
1057 /* Create a GC that will use the GXxor function to flip foreground pixels
1058 into background pixels. */
1059 {
1060 XGCValues values;
1061
1062 values.function = GXxor;
1063 values.foreground = (f->display.x->foreground_pixel
1064 ^ f->display.x->background_pixel);
1065
1066 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1067 GCFunction | GCForeground, &values);
1068 }
1069
1070 {
1071 int width = PIXEL_WIDTH (f);
1072 int height = PIXEL_HEIGHT (f);
1073
1074 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
1075 width/4, height/4, width/2, height/2);
1076 XFlush (FRAME_X_DISPLAY (f));
1077
1078 {
1079 struct timeval wakeup, now;
1080
1081 EMACS_GET_TIME (wakeup);
1082
1083 /* Compute time to wait until, propagating carry from usecs. */
1084 wakeup.tv_usec += 150000;
1085 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
1086 wakeup.tv_usec %= 1000000;
1087
1088 /* Keep waiting until past the time wakeup. */
1089 while (1)
1090 {
1091 struct timeval timeout;
1092
1093 EMACS_GET_TIME (timeout);
1094
1095 /* In effect, timeout = wakeup - timeout.
1096 Break if result would be negative. */
1097 if (timeval_subtract (&timeout, wakeup, timeout))
1098 break;
1099
1100 /* Try to wait that long--but we might wake up sooner. */
1101 select (0, 0, 0, 0, &timeout);
1102 }
1103 }
1104
1105 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
1106 width/4, height/4, width/2, height/2);
1107 XFreeGC (FRAME_X_DISPLAY (f), gc);
1108 XFlush (FRAME_X_DISPLAY (f));
1109 }
1110 }
1111
1112 UNBLOCK_INPUT;
1113 }
1114
1115 #endif
1116
1117
1118 /* Make audible bell. */
1119
1120 #define XRINGBELL XBell (FRAME_X_DISPLAY (selected_frame), 0)
1121
1122 XTring_bell ()
1123 {
1124 if (FRAME_X_DISPLAY (selected_frame) == 0)
1125 return;
1126
1127 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
1128 if (visible_bell)
1129 XTflash (selected_frame);
1130 else
1131 #endif
1132 {
1133 BLOCK_INPUT;
1134 XRINGBELL;
1135 XFlush (FRAME_X_DISPLAY (selected_frame));
1136 UNBLOCK_INPUT;
1137 }
1138 }
1139 \f
1140 /* Insert and delete character.
1141 These are not supposed to be used because we are supposed to turn
1142 off the feature of using them. */
1143
1144 static
1145 XTinsert_glyphs (start, len)
1146 register char *start;
1147 register int len;
1148 {
1149 abort ();
1150 }
1151
1152 static
1153 XTdelete_glyphs (n)
1154 register int n;
1155 {
1156 abort ();
1157 }
1158 \f
1159 /* Specify how many text lines, from the top of the window,
1160 should be affected by insert-lines and delete-lines operations.
1161 This, and those operations, are used only within an update
1162 that is bounded by calls to XTupdate_begin and XTupdate_end. */
1163
1164 static
1165 XTset_terminal_window (n)
1166 register int n;
1167 {
1168 if (updating_frame == 0)
1169 abort ();
1170
1171 if ((n <= 0) || (n > updating_frame->height))
1172 flexlines = updating_frame->height;
1173 else
1174 flexlines = n;
1175 }
1176 \f
1177 /* These variables need not be per frame
1178 because redisplay is done on a frame-by-frame basis
1179 and the line dance for one frame is finished before
1180 anything is done for anoter frame. */
1181
1182 /* Array of line numbers from cached insert/delete operations.
1183 line_dance[i] is the old position of the line that we want
1184 to move to line i, or -1 if we want a blank line there. */
1185 static int *line_dance;
1186
1187 /* Allocated length of that array. */
1188 static int line_dance_len;
1189
1190 /* Flag indicating whether we've done any work. */
1191 static int line_dance_in_progress;
1192
1193 /* Perform an insert-lines or delete-lines operation,
1194 inserting N lines or deleting -N lines at vertical position VPOS. */
1195 XTins_del_lines (vpos, n)
1196 int vpos, n;
1197 {
1198 register int fence, i;
1199
1200 if (vpos >= flexlines)
1201 return;
1202
1203 if (!line_dance_in_progress)
1204 {
1205 int ht = updating_frame->height;
1206 if (ht > line_dance_len)
1207 {
1208 line_dance = (int *)xrealloc (line_dance, ht * sizeof (int));
1209 line_dance_len = ht;
1210 }
1211 for (i = 0; i < ht; ++i) line_dance[i] = i;
1212 line_dance_in_progress = 1;
1213 }
1214 if (n >= 0)
1215 {
1216 if (n > flexlines - vpos)
1217 n = flexlines - vpos;
1218 fence = vpos + n;
1219 for (i = flexlines; --i >= fence;)
1220 line_dance[i] = line_dance[i-n];
1221 for (i = fence; --i >= vpos;)
1222 line_dance[i] = -1;
1223 }
1224 else
1225 {
1226 n = -n;
1227 if (n > flexlines - vpos)
1228 n = flexlines - vpos;
1229 fence = flexlines - n;
1230 for (i = vpos; i < fence; ++i)
1231 line_dance[i] = line_dance[i + n];
1232 for (i = fence; i < flexlines; ++i)
1233 line_dance[i] = -1;
1234 }
1235 }
1236
1237 /* Here's where we actually move the pixels around.
1238 Must be called with input blocked. */
1239 static void
1240 do_line_dance ()
1241 {
1242 register int i, j, distance;
1243 register struct frame *f;
1244 int ht;
1245 int intborder;
1246
1247 /* Must check this flag first. If it's not set, then not only is the
1248 array uninitialized, but we might not even have a frame. */
1249 if (!line_dance_in_progress)
1250 return;
1251
1252 f = updating_frame;
1253 if (f == 0)
1254 abort ();
1255
1256 ht = f->height;
1257 intborder = f->display.x->internal_border_width;
1258
1259 x_display_cursor (updating_frame, 0);
1260
1261 for (i = 0; i < ht; ++i)
1262 if (line_dance[i] != -1 && (distance = line_dance[i]-i) > 0)
1263 {
1264 for (j = i; (j < ht && line_dance[j] != -1
1265 && line_dance[j]-j == distance); ++j);
1266 /* Copy [i,j) upward from [i+distance,j+distance) */
1267 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1268 FRAME_X_WINDOW (f), f->display.x->normal_gc,
1269 intborder, CHAR_TO_PIXEL_ROW (f, i+distance),
1270 f->width * FONT_WIDTH (f->display.x->font),
1271 (j-i) * f->display.x->line_height,
1272 intborder, CHAR_TO_PIXEL_ROW (f, i));
1273 i = j-1;
1274 }
1275
1276 for (i = ht; --i >=0; )
1277 if (line_dance[i] != -1 && (distance = line_dance[i]-i) < 0)
1278 {
1279 for (j = i; (--j >= 0 && line_dance[j] != -1
1280 && line_dance[j]-j == distance););
1281 /* Copy (j,i] downward from (j+distance, i+distance] */
1282 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1283 FRAME_X_WINDOW (f), f->display.x->normal_gc,
1284 intborder, CHAR_TO_PIXEL_ROW (f, j+1+distance),
1285 f->width * FONT_WIDTH (f->display.x->font),
1286 (i-j) * f->display.x->line_height,
1287 intborder, CHAR_TO_PIXEL_ROW (f, j+1));
1288 i = j+1;
1289 }
1290
1291 for (i = 0; i < ht; ++i)
1292 if (line_dance[i] == -1)
1293 {
1294 for (j = i; j < ht && line_dance[j] == -1; ++j);
1295 /* Clear [i,j) */
1296 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1297 intborder, CHAR_TO_PIXEL_ROW (f, i),
1298 f->width * FONT_WIDTH (f->display.x->font),
1299 (j-i) * f->display.x->line_height, False);
1300 i = j-1;
1301 }
1302 line_dance_in_progress = 0;
1303 }
1304 \f
1305 /* Support routines for exposure events. */
1306 static void clear_cursor ();
1307
1308 /* Output into a rectangle of an X-window (for frame F)
1309 the characters in f->phys_lines that overlap that rectangle.
1310 TOP and LEFT are the position of the upper left corner of the rectangle.
1311 ROWS and COLS are the size of the rectangle.
1312 Call this function with input blocked. */
1313
1314 static void
1315 dumprectangle (f, left, top, cols, rows)
1316 struct frame *f;
1317 register int left, top, cols, rows;
1318 {
1319 register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
1320 int cursor_cleared = 0;
1321 int bottom, right;
1322 register int y;
1323
1324 if (FRAME_GARBAGED_P (f))
1325 return;
1326
1327 /* Express rectangle as four edges, instead of position-and-size. */
1328 bottom = top + rows;
1329 right = left + cols;
1330
1331 /* Convert rectangle edges in pixels to edges in chars.
1332 Round down for left and top, up for right and bottom. */
1333 top = PIXEL_TO_CHAR_ROW (f, top);
1334 left = PIXEL_TO_CHAR_COL (f, left);
1335 bottom += (f->display.x->line_height - 1);
1336 right += (FONT_WIDTH (f->display.x->font) - 1);
1337 bottom = PIXEL_TO_CHAR_ROW (f, bottom);
1338 right = PIXEL_TO_CHAR_COL (f, right);
1339
1340 /* Clip the rectangle to what can be visible. */
1341 if (left < 0)
1342 left = 0;
1343 if (top < 0)
1344 top = 0;
1345 if (right > f->width)
1346 right = f->width;
1347 if (bottom > f->height)
1348 bottom = f->height;
1349
1350 /* Get size in chars of the rectangle. */
1351 cols = right - left;
1352 rows = bottom - top;
1353
1354 /* If rectangle has zero area, return. */
1355 if (rows <= 0) return;
1356 if (cols <= 0) return;
1357
1358 /* Turn off the cursor if it is in the rectangle.
1359 We will turn it back on afterward. */
1360 if ((f->phys_cursor_x >= left) && (f->phys_cursor_x < right)
1361 && (f->phys_cursor_y >= top) && (f->phys_cursor_y < bottom))
1362 {
1363 clear_cursor (f);
1364 cursor_cleared = 1;
1365 }
1366
1367 /* Display the text in the rectangle, one text line at a time. */
1368
1369 for (y = top; y < bottom; y++)
1370 {
1371 GLYPH *line = &active_frame->glyphs[y][left];
1372
1373 if (! active_frame->enable[y] || left > active_frame->used[y])
1374 continue;
1375
1376 dumpglyphs (f,
1377 CHAR_TO_PIXEL_COL (f, left),
1378 CHAR_TO_PIXEL_ROW (f, y),
1379 line, min (cols, active_frame->used[y] - left),
1380 active_frame->highlight[y], 0);
1381 }
1382
1383 /* Turn the cursor on if we turned it off. */
1384
1385 if (cursor_cleared)
1386 x_display_cursor (f, 1);
1387 }
1388 \f
1389 static void
1390 frame_highlight (f)
1391 struct frame *f;
1392 {
1393 /* We used to only do this if Vx_no_window_manager was non-nil, but
1394 the ICCCM (section 4.1.6) says that the window's border pixmap
1395 and border pixel are window attributes which are "private to the
1396 client", so we can always change it to whatever we want. */
1397 BLOCK_INPUT;
1398 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1399 f->display.x->border_pixel);
1400 UNBLOCK_INPUT;
1401 x_display_cursor (f, 1);
1402 }
1403
1404 static void
1405 frame_unhighlight (f)
1406 struct frame *f;
1407 {
1408 /* We used to only do this if Vx_no_window_manager was non-nil, but
1409 the ICCCM (section 4.1.6) says that the window's border pixmap
1410 and border pixel are window attributes which are "private to the
1411 client", so we can always change it to whatever we want. */
1412 BLOCK_INPUT;
1413 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1414 f->display.x->border_tile);
1415 UNBLOCK_INPUT;
1416 x_display_cursor (f, 1);
1417 }
1418
1419 static void XTframe_rehighlight ();
1420
1421 /* The focus has changed. Update the frames as necessary to reflect
1422 the new situation. Note that we can't change the selected frame
1423 here, because the lisp code we are interrupting might become confused.
1424 Each event gets marked with the frame in which it occurred, so the
1425 lisp code can tell when the switch took place by examining the events. */
1426
1427 static void
1428 x_new_focus_frame (frame)
1429 struct frame *frame;
1430 {
1431 struct frame *old_focus = x_focus_frame;
1432 int events_enqueued = 0;
1433
1434 if (frame != x_focus_frame)
1435 {
1436 /* Set this before calling other routines, so that they see
1437 the correct value of x_focus_frame. */
1438 x_focus_frame = frame;
1439
1440 if (old_focus && old_focus->auto_lower)
1441 x_lower_frame (old_focus);
1442
1443 #if 0
1444 selected_frame = frame;
1445 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
1446 selected_frame);
1447 Fselect_window (selected_frame->selected_window);
1448 choose_minibuf_frame ();
1449 #endif /* ! 0 */
1450
1451 if (x_focus_frame && x_focus_frame->auto_raise)
1452 pending_autoraise_frame = x_focus_frame;
1453 else
1454 pending_autoraise_frame = 0;
1455 }
1456
1457 XTframe_rehighlight ();
1458 }
1459
1460 /* Handle an event saying the mouse has moved out of an Emacs frame. */
1461
1462 void
1463 x_mouse_leave ()
1464 {
1465 if (! x_focus_event_frame)
1466 x_new_focus_frame (NULL);
1467 else
1468 x_new_focus_frame (x_focus_event_frame); /* Was f, but that seems wrong. */
1469 }
1470
1471 /* The focus has changed, or we have redirected a frame's focus to
1472 another frame (this happens when a frame uses a surrogate
1473 minibuffer frame). Shift the highlight as appropriate. */
1474 static void
1475 XTframe_rehighlight ()
1476 {
1477 struct frame *old_highlight = x_highlight_frame;
1478
1479 if (x_focus_frame)
1480 {
1481 x_highlight_frame
1482 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (x_focus_frame)))
1483 ? XFRAME (FRAME_FOCUS_FRAME (x_focus_frame))
1484 : x_focus_frame);
1485 if (! FRAME_LIVE_P (x_highlight_frame))
1486 {
1487 FRAME_FOCUS_FRAME (x_focus_frame) = Qnil;
1488 x_highlight_frame = x_focus_frame;
1489 }
1490 }
1491 else
1492 x_highlight_frame = 0;
1493
1494 if (x_highlight_frame != old_highlight)
1495 {
1496 if (old_highlight)
1497 frame_unhighlight (old_highlight);
1498 if (x_highlight_frame)
1499 frame_highlight (x_highlight_frame);
1500 }
1501 }
1502 \f
1503 /* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
1504
1505 /* Initialize mode_switch_bit and modifier_meaning. */
1506 static void
1507 x_find_modifier_meanings (dpyinfo)
1508 struct x_display_info *dpyinfo;
1509 {
1510 int min_code, max_code;
1511 KeySym *syms;
1512 int syms_per_code;
1513 XModifierKeymap *mods;
1514
1515 dpyinfo->meta_mod_mask = 0;
1516 dpyinfo->shift_lock_mask = 0;
1517 dpyinfo->alt_mod_mask = 0;
1518 dpyinfo->super_mod_mask = 0;
1519 dpyinfo->hyper_mod_mask = 0;
1520
1521 #ifdef HAVE_X11R4
1522 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
1523 #else
1524 min_code = display->min_keycode;
1525 max_code = display->max_keycode;
1526 #endif
1527
1528 syms = XGetKeyboardMapping (dpyinfo->display,
1529 min_code, max_code - min_code + 1,
1530 &syms_per_code);
1531 mods = XGetModifierMapping (dpyinfo->display);
1532
1533 /* Scan the modifier table to see which modifier bits the Meta and
1534 Alt keysyms are on. */
1535 {
1536 int row, col; /* The row and column in the modifier table. */
1537
1538 for (row = 3; row < 8; row++)
1539 for (col = 0; col < mods->max_keypermod; col++)
1540 {
1541 KeyCode code
1542 = mods->modifiermap[(row * mods->max_keypermod) + col];
1543
1544 /* Zeroes are used for filler. Skip them. */
1545 if (code == 0)
1546 continue;
1547
1548 /* Are any of this keycode's keysyms a meta key? */
1549 {
1550 int code_col;
1551
1552 for (code_col = 0; code_col < syms_per_code; code_col++)
1553 {
1554 int sym = syms[((code - min_code) * syms_per_code) + code_col];
1555
1556 switch (sym)
1557 {
1558 case XK_Meta_L:
1559 case XK_Meta_R:
1560 dpyinfo->meta_mod_mask |= (1 << row);
1561 break;
1562
1563 case XK_Alt_L:
1564 case XK_Alt_R:
1565 dpyinfo->alt_mod_mask |= (1 << row);
1566 break;
1567
1568 case XK_Hyper_L:
1569 case XK_Hyper_R:
1570 dpyinfo->hyper_mod_mask |= (1 << row);
1571 break;
1572
1573 case XK_Super_L:
1574 case XK_Super_R:
1575 dpyinfo->super_mod_mask |= (1 << row);
1576 break;
1577
1578 case XK_Shift_Lock:
1579 /* Ignore this if it's not on the lock modifier. */
1580 if ((1 << row) == LockMask)
1581 dpyinfo->shift_lock_mask = LockMask;
1582 break;
1583 }
1584 }
1585 }
1586 }
1587 }
1588
1589 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
1590 if (! dpyinfo->meta_mod_mask)
1591 {
1592 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
1593 dpyinfo->alt_mod_mask = 0;
1594 }
1595
1596 /* If some keys are both alt and meta,
1597 make them just meta, not alt. */
1598 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
1599 {
1600 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
1601 }
1602
1603 XFree ((char *) syms);
1604 XFreeModifiermap (mods);
1605 }
1606
1607 /* Convert between the modifier bits X uses and the modifier bits
1608 Emacs uses. */
1609 static unsigned int
1610 x_x_to_emacs_modifiers (dpyinfo, state)
1611 struct x_display_info *dpyinfo;
1612 unsigned int state;
1613 {
1614 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
1615 | ((state & ControlMask) ? ctrl_modifier : 0)
1616 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
1617 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
1618 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
1619 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
1620 }
1621
1622 static unsigned int
1623 x_emacs_to_x_modifiers (dpyinfo, state)
1624 struct x_display_info *dpyinfo;
1625 unsigned int state;
1626 {
1627 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
1628 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
1629 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
1630 | ((state & shift_modifier) ? ShiftMask : 0)
1631 | ((state & ctrl_modifier) ? ControlMask : 0)
1632 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
1633 }
1634 \f
1635 /* Mouse clicks and mouse movement. Rah. */
1636
1637 /* Given a pixel position (PIX_X, PIX_Y) on the frame F, return
1638 glyph co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle
1639 that the glyph at X, Y occupies, if BOUNDS != 0.
1640 If NOCLIP is nonzero, do not force the value into range. */
1641
1642 void
1643 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1644 FRAME_PTR f;
1645 register int pix_x, pix_y;
1646 register int *x, *y;
1647 XRectangle *bounds;
1648 int noclip;
1649 {
1650 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
1651 even for negative values. */
1652 if (pix_x < 0)
1653 pix_x -= FONT_WIDTH ((f)->display.x->font) - 1;
1654 if (pix_y < 0)
1655 pix_y -= (f)->display.x->line_height - 1;
1656
1657 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
1658 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
1659
1660 if (bounds)
1661 {
1662 bounds->width = FONT_WIDTH (f->display.x->font);
1663 bounds->height = f->display.x->line_height;
1664 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
1665 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
1666 }
1667
1668 if (!noclip)
1669 {
1670 if (pix_x < 0)
1671 pix_x = 0;
1672 else if (pix_x > f->width)
1673 pix_x = f->width;
1674
1675 if (pix_y < 0)
1676 pix_y = 0;
1677 else if (pix_y > f->height)
1678 pix_y = f->height;
1679 }
1680
1681 *x = pix_x;
1682 *y = pix_y;
1683 }
1684
1685 void
1686 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1687 FRAME_PTR f;
1688 register int x, y;
1689 register int *pix_x, *pix_y;
1690 {
1691 *pix_x = CHAR_TO_PIXEL_COL (f, x);
1692 *pix_y = CHAR_TO_PIXEL_ROW (f, y);
1693 }
1694
1695 /* Prepare a mouse-event in *RESULT for placement in the input queue.
1696
1697 If the event is a button press, then note that we have grabbed
1698 the mouse. */
1699
1700 static Lisp_Object
1701 construct_mouse_click (result, event, f)
1702 struct input_event *result;
1703 XButtonEvent *event;
1704 struct frame *f;
1705 {
1706 /* Make the event type no_event; we'll change that when we decide
1707 otherwise. */
1708 result->kind = mouse_click;
1709 result->code = event->button - Button1;
1710 result->timestamp = event->time;
1711 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
1712 event->state)
1713 | (event->type == ButtonRelease
1714 ? up_modifier
1715 : down_modifier));
1716
1717 {
1718 int row, column;
1719
1720 #if 0
1721 pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL, 0);
1722 XSETFASTINT (result->x, column);
1723 XSETFASTINT (result->y, row);
1724 #endif
1725 XSETINT (result->x, event->x);
1726 XSETINT (result->y, event->y);
1727 XSETFRAME (result->frame_or_window, f);
1728 }
1729 }
1730
1731 /* Prepare a menu-event in *RESULT for placement in the input queue. */
1732
1733 static Lisp_Object
1734 construct_menu_click (result, event, f)
1735 struct input_event *result;
1736 XButtonEvent *event;
1737 struct frame *f;
1738 {
1739 /* Make the event type no_event; we'll change that when we decide
1740 otherwise. */
1741 result->kind = mouse_click;
1742 XSETINT (result->code, event->button - Button1);
1743 result->timestamp = event->time;
1744 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
1745 event->state)
1746 | (event->type == ButtonRelease
1747 ? up_modifier
1748 : down_modifier));
1749
1750 XSETINT (result->x, event->x);
1751 XSETINT (result->y, -1);
1752 XSETFRAME (result->frame_or_window, f);
1753 }
1754 \f
1755 /* Function to report a mouse movement to the mainstream Emacs code.
1756 The input handler calls this.
1757
1758 We have received a mouse movement event, which is given in *event.
1759 If the mouse is over a different glyph than it was last time, tell
1760 the mainstream emacs code by setting mouse_moved. If not, ask for
1761 another motion event, so we can check again the next time it moves. */
1762
1763 static void
1764 note_mouse_movement (frame, event)
1765 FRAME_PTR frame;
1766 XMotionEvent *event;
1767
1768 {
1769 last_mouse_movement_time = event->time;
1770
1771 if (event->window != FRAME_X_WINDOW (frame))
1772 {
1773 mouse_moved = 1;
1774 last_mouse_scroll_bar = Qnil;
1775
1776 note_mouse_highlight (frame, -1, -1);
1777
1778 /* Ask for another mouse motion event. */
1779 {
1780 int dummy;
1781 Window dummy_window;
1782
1783 XQueryPointer (event->display, FRAME_X_WINDOW (frame),
1784 &dummy_window, &dummy_window,
1785 &dummy, &dummy, &dummy, &dummy,
1786 (unsigned int *) &dummy);
1787 }
1788 }
1789
1790 /* Has the mouse moved off the glyph it was on at the last sighting? */
1791 else if (event->x < last_mouse_glyph.x
1792 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
1793 || event->y < last_mouse_glyph.y
1794 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
1795 {
1796 mouse_moved = 1;
1797 last_mouse_scroll_bar = Qnil;
1798
1799 note_mouse_highlight (frame, event->x, event->y);
1800
1801 /* Ask for another mouse motion event. */
1802 {
1803 int dummy;
1804 Window dummy_window;
1805
1806 XQueryPointer (event->display, FRAME_X_WINDOW (frame),
1807 &dummy_window, &dummy_window,
1808 &dummy, &dummy, &dummy, &dummy,
1809 (unsigned int *) &dummy);
1810 }
1811 }
1812 else
1813 {
1814 /* It's on the same glyph. Call XQueryPointer so we'll get an
1815 event the next time the mouse moves and we can see if it's
1816 *still* on the same glyph. */
1817 int dummy;
1818 Window dummy_window;
1819
1820 XQueryPointer (event->display, FRAME_X_WINDOW (frame),
1821 &dummy_window, &dummy_window,
1822 &dummy, &dummy, &dummy, &dummy,
1823 (unsigned int *) &dummy);
1824 }
1825 }
1826
1827 /* This is used for debugging, to turn off note_mouse_highlight. */
1828 static int disable_mouse_highlight;
1829
1830 /* Take proper action when the mouse has moved to position X, Y on frame F
1831 as regards highlighting characters that have mouse-face properties.
1832 Also dehighlighting chars where the mouse was before.
1833 X and Y can be negative or out of range. */
1834
1835 static void
1836 note_mouse_highlight (f, x, y)
1837 FRAME_PTR f;
1838 {
1839 int row, column, portion;
1840 XRectangle new_glyph;
1841 Lisp_Object window;
1842 struct window *w;
1843
1844 if (disable_mouse_highlight)
1845 return;
1846
1847 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x = x;
1848 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y = y;
1849 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame = f;
1850
1851 if (FRAME_X_DISPLAY_INFO (f)->mouse_face_defer)
1852 return;
1853
1854 if (gc_in_progress)
1855 {
1856 FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc = 1;
1857 return;
1858 }
1859
1860 /* Find out which glyph the mouse is on. */
1861 pixel_to_glyph_coords (f, x, y, &column, &row,
1862 &new_glyph, FRAME_X_DISPLAY_INFO (f)->grabbed);
1863
1864 /* Which window is that in? */
1865 window = window_from_coordinates (f, column, row, &portion);
1866 w = XWINDOW (window);
1867
1868 /* If we were displaying active text in another window, clear that. */
1869 if (! EQ (window, FRAME_X_DISPLAY_INFO (f)->mouse_face_window))
1870 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
1871
1872 /* Are we in a window whose display is up to date?
1873 And verify the buffer's text has not changed. */
1874 if (WINDOWP (window) && portion == 0 && row >= 0 && column >= 0
1875 && row < FRAME_HEIGHT (f) && column < FRAME_WIDTH (f)
1876 && EQ (w->window_end_valid, w->buffer)
1877 && w->last_modified == BUF_MODIFF (XBUFFER (w->buffer)))
1878 {
1879 int *ptr = FRAME_CURRENT_GLYPHS (f)->charstarts[row];
1880 int i, pos;
1881
1882 /* Find which buffer position the mouse corresponds to. */
1883 for (i = column; i >= 0; i--)
1884 if (ptr[i] > 0)
1885 break;
1886 pos = ptr[i];
1887 /* Is it outside the displayed active region (if any)? */
1888 if (pos <= 0)
1889 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
1890 else if (! (EQ (window, FRAME_X_DISPLAY_INFO (f)->mouse_face_window)
1891 && row >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
1892 && row <= FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
1893 && (row > FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
1894 || column >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col)
1895 && (row < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
1896 || column < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col
1897 || FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end)))
1898 {
1899 Lisp_Object mouse_face, overlay, position;
1900 Lisp_Object *overlay_vec;
1901 int len, noverlays, ignor1;
1902 struct buffer *obuf;
1903 int obegv, ozv;
1904
1905 /* If we get an out-of-range value, return now; avoid an error. */
1906 if (pos > BUF_Z (XBUFFER (w->buffer)))
1907 return;
1908
1909 /* Make the window's buffer temporarily current for
1910 overlays_at and compute_char_face. */
1911 obuf = current_buffer;
1912 current_buffer = XBUFFER (w->buffer);
1913 obegv = BEGV;
1914 ozv = ZV;
1915 BEGV = BEG;
1916 ZV = Z;
1917
1918 /* Yes. Clear the display of the old active region, if any. */
1919 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
1920
1921 /* Is this char mouse-active? */
1922 XSETINT (position, pos);
1923
1924 len = 10;
1925 overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
1926
1927 /* Put all the overlays we want in a vector in overlay_vec.
1928 Store the length in len. */
1929 noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
1930 NULL, NULL);
1931 noverlays = sort_overlays (overlay_vec, noverlays, w);
1932
1933 /* Find the highest priority overlay that has a mouse-face prop. */
1934 overlay = Qnil;
1935 for (i = 0; i < noverlays; i++)
1936 {
1937 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1938 if (!NILP (mouse_face))
1939 {
1940 overlay = overlay_vec[i];
1941 break;
1942 }
1943 }
1944 free (overlay_vec);
1945 /* If no overlay applies, get a text property. */
1946 if (NILP (overlay))
1947 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
1948
1949 /* Handle the overlay case. */
1950 if (! NILP (overlay))
1951 {
1952 /* Find the range of text around this char that
1953 should be active. */
1954 Lisp_Object before, after;
1955 int ignore;
1956
1957 before = Foverlay_start (overlay);
1958 after = Foverlay_end (overlay);
1959 /* Record this as the current active region. */
1960 fast_find_position (window, before,
1961 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col,
1962 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row);
1963 FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end
1964 = !fast_find_position (window, after,
1965 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col,
1966 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row);
1967 FRAME_X_DISPLAY_INFO (f)->mouse_face_window = window;
1968 FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id
1969 = compute_char_face (f, w, pos, 0, 0,
1970 &ignore, pos + 1, 1);
1971
1972 /* Display it as active. */
1973 show_mouse_face (FRAME_X_DISPLAY_INFO (f), 1);
1974 }
1975 /* Handle the text property case. */
1976 else if (! NILP (mouse_face))
1977 {
1978 /* Find the range of text around this char that
1979 should be active. */
1980 Lisp_Object before, after, beginning, end;
1981 int ignore;
1982
1983 beginning = Fmarker_position (w->start);
1984 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1985 - XFASTINT (w->window_end_pos)));
1986 before
1987 = Fprevious_single_property_change (make_number (pos + 1),
1988 Qmouse_face,
1989 w->buffer, beginning);
1990 after
1991 = Fnext_single_property_change (position, Qmouse_face,
1992 w->buffer, end);
1993 /* Record this as the current active region. */
1994 fast_find_position (window, before,
1995 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col,
1996 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row);
1997 FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end
1998 = !fast_find_position (window, after,
1999 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col,
2000 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row);
2001 FRAME_X_DISPLAY_INFO (f)->mouse_face_window = window;
2002 FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id
2003 = compute_char_face (f, w, pos, 0, 0,
2004 &ignore, pos + 1, 1);
2005
2006 /* Display it as active. */
2007 show_mouse_face (FRAME_X_DISPLAY_INFO (f), 1);
2008 }
2009 BEGV = obegv;
2010 ZV = ozv;
2011 current_buffer = obuf;
2012 }
2013 }
2014 }
2015 \f
2016 /* Find the row and column of position POS in window WINDOW.
2017 Store them in *COLUMNP and *ROWP.
2018 This assumes display in WINDOW is up to date.
2019 If POS is above start of WINDOW, return coords
2020 of start of first screen line.
2021 If POS is after end of WINDOW, return coords of end of last screen line.
2022
2023 Value is 1 if POS is in range, 0 if it was off screen. */
2024
2025 static int
2026 fast_find_position (window, pos, columnp, rowp)
2027 Lisp_Object window;
2028 int pos;
2029 int *columnp, *rowp;
2030 {
2031 struct window *w = XWINDOW (window);
2032 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2033 int i;
2034 int row = 0;
2035 int left = w->left;
2036 int top = w->top;
2037 int height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
2038 int width = window_internal_width (w);
2039 int *charstarts;
2040 int lastcol;
2041 int maybe_next_line = 0;
2042
2043 /* Find the right row. */
2044 for (i = 0;
2045 i < height;
2046 i++)
2047 {
2048 int linestart = FRAME_CURRENT_GLYPHS (f)->charstarts[top + i][left];
2049 if (linestart > pos)
2050 break;
2051 /* If the position sought is the end of the buffer,
2052 don't include the blank lines at the bottom of the window. */
2053 if (linestart == pos && pos == BUF_ZV (XBUFFER (w->buffer)))
2054 {
2055 maybe_next_line = 1;
2056 break;
2057 }
2058 if (linestart > 0)
2059 row = i;
2060 }
2061
2062 /* Find the right column with in it. */
2063 charstarts = FRAME_CURRENT_GLYPHS (f)->charstarts[top + row];
2064 lastcol = left;
2065 for (i = 0; i < width; i++)
2066 {
2067 if (charstarts[left + i] == pos)
2068 {
2069 *rowp = row + top;
2070 *columnp = i + left;
2071 return 1;
2072 }
2073 else if (charstarts[left + i] > pos)
2074 break;
2075 else if (charstarts[left + i] > 0)
2076 lastcol = left + i;
2077 }
2078
2079 /* If we're looking for the end of the buffer,
2080 and we didn't find it in the line we scanned,
2081 use the start of the following line. */
2082 if (maybe_next_line)
2083 {
2084 row++;
2085 i = 0;
2086 }
2087
2088 *rowp = row + top;
2089 *columnp = lastcol;
2090 return 0;
2091 }
2092
2093 /* Display the active region described by mouse_face_*
2094 in its mouse-face if HL > 0, in its normal face if HL = 0. */
2095
2096 static void
2097 show_mouse_face (dpyinfo, hl)
2098 struct x_display_info *dpyinfo;
2099 int hl;
2100 {
2101 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
2102 int width = window_internal_width (w);
2103 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2104 int i;
2105 int cursor_off = 0;
2106 int old_curs_x = curs_x;
2107 int old_curs_y = curs_y;
2108
2109 /* Set these variables temporarily
2110 so that if we have to turn the cursor off and on again
2111 we will put it back at the same place. */
2112 curs_x = f->phys_cursor_x;
2113 curs_y = f->phys_cursor_y;
2114
2115 for (i = FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row;
2116 i <= FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row; i++)
2117 {
2118 int column = (i == FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
2119 ? FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col
2120 : w->left);
2121 int endcolumn = (i == FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
2122 ? FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col
2123 : w->left + width);
2124 endcolumn = min (endcolumn, FRAME_CURRENT_GLYPHS (f)->used[i]);
2125
2126 /* If the cursor's in the text we are about to rewrite,
2127 turn the cursor off. */
2128 if (i == curs_y
2129 && curs_x >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col - 1
2130 && curs_x <= FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col)
2131 {
2132 x_display_cursor (f, 0);
2133 cursor_off = 1;
2134 }
2135
2136 dumpglyphs (f,
2137 CHAR_TO_PIXEL_COL (f, column),
2138 CHAR_TO_PIXEL_ROW (f, i),
2139 FRAME_CURRENT_GLYPHS (f)->glyphs[i] + column,
2140 endcolumn - column,
2141 /* Highlight with mouse face if hl > 0. */
2142 hl > 0 ? 3 : 0, 0);
2143 }
2144
2145 /* If we turned the cursor off, turn it back on. */
2146 if (cursor_off)
2147 x_display_cursor (f, 1);
2148
2149 curs_x = old_curs_x;
2150 curs_y = old_curs_y;
2151
2152 /* Change the mouse cursor according to the value of HL. */
2153 if (hl > 0)
2154 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2155 f->display.x->cross_cursor);
2156 else
2157 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2158 f->display.x->text_cursor);
2159 }
2160
2161 /* Clear out the mouse-highlighted active region.
2162 Redraw it unhighlighted first. */
2163
2164 static void
2165 clear_mouse_face (dpyinfo)
2166 struct x_display_info *dpyinfo;
2167 {
2168 if (! NILP (dpyinfo->mouse_face_window))
2169 show_mouse_face (dpyinfo, 0);
2170
2171 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2172 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2173 dpyinfo->mouse_face_window = Qnil;
2174 }
2175 \f
2176 static struct scroll_bar *x_window_to_scroll_bar ();
2177 static void x_scroll_bar_report_motion ();
2178
2179 /* Return the current position of the mouse.
2180
2181 If the mouse movement started in a scroll bar, set *f, *bar_window,
2182 and *part to the frame, window, and scroll bar part that the mouse
2183 is over. Set *x and *y to the portion and whole of the mouse's
2184 position on the scroll bar.
2185
2186 If the mouse movement started elsewhere, set *f to the frame the
2187 mouse is on, *bar_window to nil, and *x and *y to the character cell
2188 the mouse is over.
2189
2190 Set *time to the server timestamp for the time at which the mouse
2191 was at this position.
2192
2193 Don't store anything if we don't have a valid set of values to report.
2194
2195 This clears the mouse_moved flag, so we can wait for the next mouse
2196 movement. This also calls XQueryPointer, which will cause the
2197 server to give us another MotionNotify when the mouse moves
2198 again. */
2199
2200 static void
2201 XTmouse_position (fp, bar_window, part, x, y, time)
2202 FRAME_PTR *fp;
2203 Lisp_Object *bar_window;
2204 enum scroll_bar_part *part;
2205 Lisp_Object *x, *y;
2206 unsigned long *time;
2207 {
2208 FRAME_PTR f1;
2209
2210 BLOCK_INPUT;
2211
2212 if (! NILP (last_mouse_scroll_bar))
2213 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
2214 else
2215 {
2216 Window root;
2217 int root_x, root_y;
2218
2219 Window dummy_window;
2220 int dummy;
2221
2222 mouse_moved = 0;
2223 last_mouse_scroll_bar = Qnil;
2224
2225 /* Figure out which root window we're on. */
2226 XQueryPointer (FRAME_X_DISPLAY (*fp),
2227 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
2228
2229 /* The root window which contains the pointer. */
2230 &root,
2231
2232 /* Trash which we can't trust if the pointer is on
2233 a different screen. */
2234 &dummy_window,
2235
2236 /* The position on that root window. */
2237 &root_x, &root_y,
2238
2239 /* More trash we can't trust. */
2240 &dummy, &dummy,
2241
2242 /* Modifier keys and pointer buttons, about which
2243 we don't care. */
2244 (unsigned int *) &dummy);
2245
2246 /* Now we have a position on the root; find the innermost window
2247 containing the pointer. */
2248 {
2249 Window win, child;
2250 int win_x, win_y;
2251 int parent_x, parent_y;
2252
2253 win = root;
2254
2255 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
2256 && FRAME_LIVE_P (last_mouse_frame))
2257 {
2258 /* If mouse was grabbed on a frame, give coords for that frame
2259 even if the mouse is now outside it. */
2260 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
2261
2262 /* From-window, to-window. */
2263 root, FRAME_X_WINDOW (last_mouse_frame),
2264
2265 /* From-position, to-position. */
2266 root_x, root_y, &win_x, &win_y,
2267
2268 /* Child of win. */
2269 &child);
2270 f1 = last_mouse_frame;
2271 }
2272 else
2273 {
2274 while (1)
2275 {
2276 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
2277
2278 /* From-window, to-window. */
2279 root, win,
2280
2281 /* From-position, to-position. */
2282 root_x, root_y, &win_x, &win_y,
2283
2284 /* Child of win. */
2285 &child);
2286
2287 if (child == None)
2288 break;
2289
2290 win = child;
2291 parent_x = win_x;
2292 parent_y = win_y;
2293 }
2294
2295 /* Now we know that:
2296 win is the innermost window containing the pointer
2297 (XTC says it has no child containing the pointer),
2298 win_x and win_y are the pointer's position in it
2299 (XTC did this the last time through), and
2300 parent_x and parent_y are the pointer's position in win's parent.
2301 (They are what win_x and win_y were when win was child.
2302 If win is the root window, it has no parent, and
2303 parent_{x,y} are invalid, but that's okay, because we'll
2304 never use them in that case.) */
2305
2306 /* Is win one of our frames? */
2307 f1 = x_any_window_to_frame (win);
2308 }
2309
2310 /* If not, is it one of our scroll bars? */
2311 if (! f1)
2312 {
2313 struct scroll_bar *bar = x_window_to_scroll_bar (win);
2314
2315 if (bar)
2316 {
2317 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2318 win_x = parent_x;
2319 win_y = parent_y;
2320 }
2321 }
2322
2323 if (f1)
2324 {
2325 int ignore1, ignore2;
2326
2327 /* Ok, we found a frame. Store all the values. */
2328
2329 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
2330 &last_mouse_glyph,
2331 FRAME_X_DISPLAY_INFO (f1)->grabbed);
2332
2333 *bar_window = Qnil;
2334 *part = 0;
2335 *fp = f1;
2336 XSETINT (*x, win_x);
2337 XSETINT (*y, win_y);
2338 *time = last_mouse_movement_time;
2339 }
2340 }
2341 }
2342
2343 UNBLOCK_INPUT;
2344 }
2345 \f
2346 /* Scroll bar support. */
2347
2348 /* Given an X window ID, find the struct scroll_bar which manages it.
2349 This can be called in GC, so we have to make sure to strip off mark
2350 bits. */
2351 static struct scroll_bar *
2352 x_window_to_scroll_bar (window_id)
2353 Window window_id;
2354 {
2355 Lisp_Object tail, frame;
2356
2357 for (tail = Vframe_list;
2358 XGCTYPE (tail) == Lisp_Cons;
2359 tail = XCONS (tail)->cdr)
2360 {
2361 Lisp_Object frame, bar, condemned;
2362
2363 frame = XCONS (tail)->car;
2364 /* All elements of Vframe_list should be frames. */
2365 if (! GC_FRAMEP (frame))
2366 abort ();
2367
2368 /* Scan this frame's scroll bar list for a scroll bar with the
2369 right window ID. */
2370 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
2371 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
2372 /* This trick allows us to search both the ordinary and
2373 condemned scroll bar lists with one loop. */
2374 ! GC_NILP (bar) || (bar = condemned,
2375 condemned = Qnil,
2376 ! GC_NILP (bar));
2377 bar = XSCROLL_BAR (bar)->next)
2378 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
2379 return XSCROLL_BAR (bar);
2380 }
2381
2382 return 0;
2383 }
2384
2385 /* Open a new X window to serve as a scroll bar, and return the
2386 scroll bar vector for it. */
2387 static struct scroll_bar *
2388 x_scroll_bar_create (window, top, left, width, height)
2389 struct window *window;
2390 int top, left, width, height;
2391 {
2392 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2393 struct scroll_bar *bar
2394 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
2395
2396 BLOCK_INPUT;
2397
2398 {
2399 XSetWindowAttributes a;
2400 unsigned long mask;
2401 a.background_pixel = f->display.x->background_pixel;
2402 a.event_mask = (ButtonPressMask | ButtonReleaseMask
2403 | ButtonMotionMask | PointerMotionHintMask
2404 | ExposureMask);
2405 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
2406
2407 mask = (CWBackPixel | CWEventMask | CWCursor);
2408
2409 #if 0
2410
2411 ac = 0;
2412 XtSetArg (al[ac], XtNx, left); ac++;
2413 XtSetArg (al[ac], XtNy, top); ac++;
2414 XtSetArg (al[ac], XtNwidth, width); ac++;
2415 XtSetArg (al[ac], XtNheight, height); ac++;
2416 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
2417 sb_widget = XtCreateManagedWidget ("box",
2418 boxWidgetClass,
2419 f->display.x->edit_widget, al, ac);
2420 SET_SCROLL_BAR_X_WINDOW
2421 (bar, sb_widget->core.window);
2422 #endif
2423 SET_SCROLL_BAR_X_WINDOW
2424 (bar,
2425 XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2426
2427 /* Position and size of scroll bar. */
2428 left, top, width, height,
2429
2430 /* Border width, depth, class, and visual. */
2431 0, CopyFromParent, CopyFromParent, CopyFromParent,
2432
2433 /* Attributes. */
2434 mask, &a));
2435 }
2436
2437 XSETWINDOW (bar->window, window);
2438 XSETINT (bar->top, top);
2439 XSETINT (bar->left, left);
2440 XSETINT (bar->width, width);
2441 XSETINT (bar->height, height);
2442 XSETINT (bar->start, 0);
2443 XSETINT (bar->end, 0);
2444 bar->dragging = Qnil;
2445
2446 /* Add bar to its frame's list of scroll bars. */
2447 bar->next = FRAME_SCROLL_BARS (f);
2448 bar->prev = Qnil;
2449 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
2450 if (! NILP (bar->next))
2451 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
2452
2453 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
2454
2455 UNBLOCK_INPUT;
2456
2457 return bar;
2458 }
2459
2460 /* Draw BAR's handle in the proper position.
2461 If the handle is already drawn from START to END, don't bother
2462 redrawing it, unless REBUILD is non-zero; in that case, always
2463 redraw it. (REBUILD is handy for drawing the handle after expose
2464 events.)
2465
2466 Normally, we want to constrain the start and end of the handle to
2467 fit inside its rectangle, but if the user is dragging the scroll bar
2468 handle, we want to let them drag it down all the way, so that the
2469 bar's top is as far down as it goes; otherwise, there's no way to
2470 move to the very end of the buffer. */
2471 static void
2472 x_scroll_bar_set_handle (bar, start, end, rebuild)
2473 struct scroll_bar *bar;
2474 int start, end;
2475 int rebuild;
2476 {
2477 int dragging = ! NILP (bar->dragging);
2478 Window w = SCROLL_BAR_X_WINDOW (bar);
2479 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2480 GC gc = f->display.x->normal_gc;
2481
2482 /* If the display is already accurate, do nothing. */
2483 if (! rebuild
2484 && start == XINT (bar->start)
2485 && end == XINT (bar->end))
2486 return;
2487
2488 BLOCK_INPUT;
2489
2490 {
2491 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (XINT (bar->width));
2492 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2493 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2494
2495 /* Make sure the values are reasonable, and try to preserve
2496 the distance between start and end. */
2497 {
2498 int length = end - start;
2499
2500 if (start < 0)
2501 start = 0;
2502 else if (start > top_range)
2503 start = top_range;
2504 end = start + length;
2505
2506 if (end < start)
2507 end = start;
2508 else if (end > top_range && ! dragging)
2509 end = top_range;
2510 }
2511
2512 /* Store the adjusted setting in the scroll bar. */
2513 XSETINT (bar->start, start);
2514 XSETINT (bar->end, end);
2515
2516 /* Clip the end position, just for display. */
2517 if (end > top_range)
2518 end = top_range;
2519
2520 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
2521 below top positions, to make sure the handle is always at least
2522 that many pixels tall. */
2523 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
2524
2525 /* Draw the empty space above the handle. Note that we can't clear
2526 zero-height areas; that means "clear to end of window." */
2527 if (0 < start)
2528 XClearArea (FRAME_X_DISPLAY (f), w,
2529
2530 /* x, y, width, height, and exposures. */
2531 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2532 VERTICAL_SCROLL_BAR_TOP_BORDER,
2533 inside_width, start,
2534 False);
2535
2536 /* Draw the handle itself. */
2537 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
2538
2539 /* x, y, width, height */
2540 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2541 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
2542 inside_width, end - start);
2543
2544
2545 /* Draw the empty space below the handle. Note that we can't
2546 clear zero-height areas; that means "clear to end of window." */
2547 if (end < inside_height)
2548 XClearArea (FRAME_X_DISPLAY (f), w,
2549
2550 /* x, y, width, height, and exposures. */
2551 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2552 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
2553 inside_width, inside_height - end,
2554 False);
2555
2556 }
2557
2558 UNBLOCK_INPUT;
2559 }
2560
2561 /* Move a scroll bar around on the screen, to accommodate changing
2562 window configurations. */
2563 static void
2564 x_scroll_bar_move (bar, top, left, width, height)
2565 struct scroll_bar *bar;
2566 int top, left, width, height;
2567 {
2568 Window w = SCROLL_BAR_X_WINDOW (bar);
2569 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2570
2571 BLOCK_INPUT;
2572
2573 {
2574 XWindowChanges wc;
2575 unsigned int mask = 0;
2576
2577 wc.x = left;
2578 wc.y = top;
2579 wc.width = width;
2580 wc.height = height;
2581
2582 if (left != XINT (bar->left)) mask |= CWX;
2583 if (top != XINT (bar->top)) mask |= CWY;
2584 if (width != XINT (bar->width)) mask |= CWWidth;
2585 if (height != XINT (bar->height)) mask |= CWHeight;
2586
2587 if (mask)
2588 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
2589 mask, &wc);
2590 }
2591
2592 XSETINT (bar->left, left);
2593 XSETINT (bar->top, top);
2594 XSETINT (bar->width, width);
2595 XSETINT (bar->height, height);
2596
2597 UNBLOCK_INPUT;
2598 }
2599
2600 /* Destroy the X window for BAR, and set its Emacs window's scroll bar
2601 to nil. */
2602 static void
2603 x_scroll_bar_remove (bar)
2604 struct scroll_bar *bar;
2605 {
2606 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2607
2608 BLOCK_INPUT;
2609
2610 /* Destroy the window. */
2611 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
2612
2613 /* Disassociate this scroll bar from its window. */
2614 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
2615
2616 UNBLOCK_INPUT;
2617 }
2618
2619 /* Set the handle of the vertical scroll bar for WINDOW to indicate
2620 that we are displaying PORTION characters out of a total of WHOLE
2621 characters, starting at POSITION. If WINDOW has no scroll bar,
2622 create one. */
2623 static void
2624 XTset_vertical_scroll_bar (window, portion, whole, position)
2625 struct window *window;
2626 int portion, whole, position;
2627 {
2628 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2629 int top = XINT (window->top);
2630 int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
2631 int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
2632
2633 /* Where should this scroll bar be, pixelwise? */
2634 int pixel_top = CHAR_TO_PIXEL_ROW (f, top);
2635 int pixel_left = CHAR_TO_PIXEL_COL (f, left);
2636 int pixel_width
2637 = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
2638 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2639 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->display.x->font)));
2640 int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
2641
2642 struct scroll_bar *bar;
2643
2644 /* Does the scroll bar exist yet? */
2645 if (NILP (window->vertical_scroll_bar))
2646 bar = x_scroll_bar_create (window,
2647 pixel_top, pixel_left,
2648 pixel_width, pixel_height);
2649 else
2650 {
2651 /* It may just need to be moved and resized. */
2652 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2653 x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
2654 }
2655
2656 /* Set the scroll bar's current state, unless we're currently being
2657 dragged. */
2658 if (NILP (bar->dragging))
2659 {
2660 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
2661
2662 if (whole == 0)
2663 x_scroll_bar_set_handle (bar, 0, top_range, 0);
2664 else
2665 {
2666 int start = ((double) position * top_range) / whole;
2667 int end = ((double) (position + portion) * top_range) / whole;
2668
2669 x_scroll_bar_set_handle (bar, start, end, 0);
2670 }
2671 }
2672
2673 XSETVECTOR (window->vertical_scroll_bar, bar);
2674 }
2675
2676
2677 /* The following three hooks are used when we're doing a thorough
2678 redisplay of the frame. We don't explicitly know which scroll bars
2679 are going to be deleted, because keeping track of when windows go
2680 away is a real pain - "Can you say set-window-configuration, boys
2681 and girls?" Instead, we just assert at the beginning of redisplay
2682 that *all* scroll bars are to be removed, and then save a scroll bar
2683 from the fiery pit when we actually redisplay its window. */
2684
2685 /* Arrange for all scroll bars on FRAME to be removed at the next call
2686 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
2687 `*redeem_scroll_bar_hook' is applied to its window before the judgement. */
2688 static void
2689 XTcondemn_scroll_bars (frame)
2690 FRAME_PTR frame;
2691 {
2692 /* The condemned list should be empty at this point; if it's not,
2693 then the rest of Emacs isn't using the condemn/redeem/judge
2694 protocol correctly. */
2695 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
2696 abort ();
2697
2698 /* Move them all to the "condemned" list. */
2699 FRAME_CONDEMNED_SCROLL_BARS (frame) = FRAME_SCROLL_BARS (frame);
2700 FRAME_SCROLL_BARS (frame) = Qnil;
2701 }
2702
2703 /* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
2704 Note that WINDOW isn't necessarily condemned at all. */
2705 static void
2706 XTredeem_scroll_bar (window)
2707 struct window *window;
2708 {
2709 struct scroll_bar *bar;
2710
2711 /* We can't redeem this window's scroll bar if it doesn't have one. */
2712 if (NILP (window->vertical_scroll_bar))
2713 abort ();
2714
2715 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2716
2717 /* Unlink it from the condemned list. */
2718 {
2719 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2720
2721 if (NILP (bar->prev))
2722 {
2723 /* If the prev pointer is nil, it must be the first in one of
2724 the lists. */
2725 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
2726 /* It's not condemned. Everything's fine. */
2727 return;
2728 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
2729 window->vertical_scroll_bar))
2730 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
2731 else
2732 /* If its prev pointer is nil, it must be at the front of
2733 one or the other! */
2734 abort ();
2735 }
2736 else
2737 XSCROLL_BAR (bar->prev)->next = bar->next;
2738
2739 if (! NILP (bar->next))
2740 XSCROLL_BAR (bar->next)->prev = bar->prev;
2741
2742 bar->next = FRAME_SCROLL_BARS (f);
2743 bar->prev = Qnil;
2744 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
2745 if (! NILP (bar->next))
2746 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
2747 }
2748 }
2749
2750 /* Remove all scroll bars on FRAME that haven't been saved since the
2751 last call to `*condemn_scroll_bars_hook'. */
2752 static void
2753 XTjudge_scroll_bars (f)
2754 FRAME_PTR f;
2755 {
2756 Lisp_Object bar, next;
2757
2758 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
2759
2760 /* Clear out the condemned list now so we won't try to process any
2761 more events on the hapless scroll bars. */
2762 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
2763
2764 for (; ! NILP (bar); bar = next)
2765 {
2766 struct scroll_bar *b = XSCROLL_BAR (bar);
2767
2768 x_scroll_bar_remove (b);
2769
2770 next = b->next;
2771 b->next = b->prev = Qnil;
2772 }
2773
2774 /* Now there should be no references to the condemned scroll bars,
2775 and they should get garbage-collected. */
2776 }
2777
2778
2779 /* Handle an Expose or GraphicsExpose event on a scroll bar.
2780
2781 This may be called from a signal handler, so we have to ignore GC
2782 mark bits. */
2783 static void
2784 x_scroll_bar_expose (bar, event)
2785 struct scroll_bar *bar;
2786 XEvent *event;
2787 {
2788 Window w = SCROLL_BAR_X_WINDOW (bar);
2789 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2790 GC gc = f->display.x->normal_gc;
2791
2792 BLOCK_INPUT;
2793
2794 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
2795
2796 /* Draw a one-pixel border just inside the edges of the scroll bar. */
2797 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
2798
2799 /* x, y, width, height */
2800 0, 0, XINT (bar->width) - 1, XINT (bar->height) - 1);
2801
2802 UNBLOCK_INPUT;
2803 }
2804
2805 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2806 is set to something other than no_event, it is enqueued.
2807
2808 This may be called from a signal handler, so we have to ignore GC
2809 mark bits. */
2810 static void
2811 x_scroll_bar_handle_click (bar, event, emacs_event)
2812 struct scroll_bar *bar;
2813 XEvent *event;
2814 struct input_event *emacs_event;
2815 {
2816 if (! GC_WINDOWP (bar->window))
2817 abort ();
2818
2819 emacs_event->kind = scroll_bar_click;
2820 emacs_event->code = event->xbutton.button - Button1;
2821 emacs_event->modifiers
2822 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
2823 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
2824 event->xbutton.state)
2825 | (event->type == ButtonRelease
2826 ? up_modifier
2827 : down_modifier));
2828 emacs_event->frame_or_window = bar->window;
2829 emacs_event->timestamp = event->xbutton.time;
2830 {
2831 int internal_height
2832 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2833 int top_range
2834 = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2835 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
2836
2837 if (y < 0) y = 0;
2838 if (y > top_range) y = top_range;
2839
2840 if (y < XINT (bar->start))
2841 emacs_event->part = scroll_bar_above_handle;
2842 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2843 emacs_event->part = scroll_bar_handle;
2844 else
2845 emacs_event->part = scroll_bar_below_handle;
2846
2847 /* Just because the user has clicked on the handle doesn't mean
2848 they want to drag it. Lisp code needs to be able to decide
2849 whether or not we're dragging. */
2850 #if 0
2851 /* If the user has just clicked on the handle, record where they're
2852 holding it. */
2853 if (event->type == ButtonPress
2854 && emacs_event->part == scroll_bar_handle)
2855 XSETINT (bar->dragging, y - XINT (bar->start));
2856 #endif
2857
2858 /* If the user has released the handle, set it to its final position. */
2859 if (event->type == ButtonRelease
2860 && ! NILP (bar->dragging))
2861 {
2862 int new_start = y - XINT (bar->dragging);
2863 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2864
2865 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2866 bar->dragging = Qnil;
2867 }
2868
2869 /* Same deal here as the other #if 0. */
2870 #if 0
2871 /* Clicks on the handle are always reported as occurring at the top of
2872 the handle. */
2873 if (emacs_event->part == scroll_bar_handle)
2874 emacs_event->x = bar->start;
2875 else
2876 XSETINT (emacs_event->x, y);
2877 #else
2878 XSETINT (emacs_event->x, y);
2879 #endif
2880
2881 XSETINT (emacs_event->y, top_range);
2882 }
2883 }
2884
2885 /* Handle some mouse motion while someone is dragging the scroll bar.
2886
2887 This may be called from a signal handler, so we have to ignore GC
2888 mark bits. */
2889 static void
2890 x_scroll_bar_note_movement (bar, event)
2891 struct scroll_bar *bar;
2892 XEvent *event;
2893 {
2894 last_mouse_movement_time = event->xmotion.time;
2895
2896 mouse_moved = 1;
2897 XSETVECTOR (last_mouse_scroll_bar, bar);
2898
2899 /* If we're dragging the bar, display it. */
2900 if (! GC_NILP (bar->dragging))
2901 {
2902 /* Where should the handle be now? */
2903 int new_start = event->xmotion.y - XINT (bar->dragging);
2904
2905 if (new_start != XINT (bar->start))
2906 {
2907 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2908
2909 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2910 }
2911 }
2912
2913 /* Call XQueryPointer so we'll get an event the next time the mouse
2914 moves and we can see *still* on the same position. */
2915 {
2916 int dummy;
2917 Window dummy_window;
2918
2919 XQueryPointer (event->xmotion.display, event->xmotion.window,
2920 &dummy_window, &dummy_window,
2921 &dummy, &dummy, &dummy, &dummy,
2922 (unsigned int *) &dummy);
2923 }
2924 }
2925
2926 /* Return information to the user about the current position of the mouse
2927 on the scroll bar. */
2928 static void
2929 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
2930 FRAME_PTR *fp;
2931 Lisp_Object *bar_window;
2932 enum scroll_bar_part *part;
2933 Lisp_Object *x, *y;
2934 unsigned long *time;
2935 {
2936 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
2937 Window w = SCROLL_BAR_X_WINDOW (bar);
2938 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2939 int win_x, win_y;
2940 Window dummy_window;
2941 int dummy_coord;
2942 unsigned int dummy_mask;
2943
2944 BLOCK_INPUT;
2945
2946 /* Get the mouse's position relative to the scroll bar window, and
2947 report that. */
2948 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
2949
2950 /* Root, child, root x and root y. */
2951 &dummy_window, &dummy_window,
2952 &dummy_coord, &dummy_coord,
2953
2954 /* Position relative to scroll bar. */
2955 &win_x, &win_y,
2956
2957 /* Mouse buttons and modifier keys. */
2958 &dummy_mask))
2959 ;
2960 else
2961 {
2962 int inside_height
2963 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2964 int top_range
2965 = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2966
2967 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2968
2969 if (! NILP (bar->dragging))
2970 win_y -= XINT (bar->dragging);
2971
2972 if (win_y < 0)
2973 win_y = 0;
2974 if (win_y > top_range)
2975 win_y = top_range;
2976
2977 *fp = f;
2978 *bar_window = bar->window;
2979
2980 if (! NILP (bar->dragging))
2981 *part = scroll_bar_handle;
2982 else if (win_y < XINT (bar->start))
2983 *part = scroll_bar_above_handle;
2984 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2985 *part = scroll_bar_handle;
2986 else
2987 *part = scroll_bar_below_handle;
2988
2989 XSETINT (*x, win_y);
2990 XSETINT (*y, top_range);
2991
2992 mouse_moved = 0;
2993 last_mouse_scroll_bar = Qnil;
2994 }
2995
2996 *time = last_mouse_movement_time;
2997
2998 UNBLOCK_INPUT;
2999 }
3000
3001
3002 /* The screen has been cleared so we may have changed foreground or
3003 background colors, and the scroll bars may need to be redrawn.
3004 Clear out the scroll bars, and ask for expose events, so we can
3005 redraw them. */
3006
3007 x_scroll_bar_clear (f)
3008 FRAME_PTR f;
3009 {
3010 Lisp_Object bar;
3011
3012 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
3013 bar = XSCROLL_BAR (bar)->next)
3014 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
3015 0, 0, 0, 0, True);
3016 }
3017
3018 /* This processes Expose events from the menubar specific X event
3019 loop in menubar.c. This allows to redisplay the frame if necessary
3020 when handling menubar or popup items. */
3021
3022 void
3023 process_expose_from_menu (event)
3024 XEvent event;
3025 {
3026 FRAME_PTR f;
3027
3028 BLOCK_INPUT;
3029
3030 f = x_window_to_frame (event.xexpose.window);
3031 if (f)
3032 {
3033 if (f->async_visible == 0)
3034 {
3035 f->async_visible = 1;
3036 f->async_iconified = 0;
3037 SET_FRAME_GARBAGED (f);
3038 }
3039 else
3040 {
3041 dumprectangle (x_window_to_frame (event.xexpose.window),
3042 event.xexpose.x, event.xexpose.y,
3043 event.xexpose.width, event.xexpose.height);
3044 }
3045 }
3046 else
3047 {
3048 struct scroll_bar *bar
3049 = x_window_to_scroll_bar (event.xexpose.window);
3050
3051 if (bar)
3052 x_scroll_bar_expose (bar, &event);
3053 }
3054
3055 UNBLOCK_INPUT;
3056 }
3057 \f
3058 /* Define a queue to save up SelectionRequest events for later handling. */
3059
3060 struct selection_event_queue
3061 {
3062 XEvent event;
3063 struct selection_event_queue *next;
3064 };
3065
3066 static struct selection_event_queue *queue;
3067
3068 /* Nonzero means queue up certain events--don't process them yet. */
3069 static int x_queue_selection_requests;
3070
3071 /* Queue up an X event *EVENT, to be processed later. */
3072
3073 static void
3074 x_queue_event (f, event)
3075 FRAME_PTR f;
3076 XEvent *event;
3077 {
3078 struct selection_event_queue *queue_tmp
3079 = (struct selection_event_queue *) malloc (sizeof (struct selection_event_queue));
3080
3081 if (queue_tmp != NULL)
3082 {
3083 queue_tmp->event = *event;
3084 queue_tmp->next = queue;
3085 queue = queue_tmp;
3086 }
3087 }
3088
3089 /* Take all the queued events and put them back
3090 so that they get processed afresh. */
3091
3092 static void
3093 x_unqueue_events (f)
3094 FRAME_PTR f;
3095 {
3096 while (queue != NULL)
3097 {
3098 struct selection_event_queue *queue_tmp = queue;
3099 XPutBackEvent (FRAME_X_DISPLAY (f), &queue_tmp->event);
3100 queue = queue_tmp->next;
3101 free ((char *)queue_tmp);
3102 }
3103 }
3104
3105 /* Start queuing SelectionRequest events. */
3106
3107 void
3108 x_start_queuing_selection_requests (f)
3109 FRAME_PTR f;
3110 {
3111 x_queue_selection_requests++;
3112 }
3113
3114 /* Stop queuing SelectionRequest events. */
3115
3116 void
3117 x_stop_queuing_selection_requests (f)
3118 FRAME_PTR f;
3119 {
3120 x_queue_selection_requests--;
3121 x_unqueue_events (f);
3122 }
3123 \f
3124 /* The main X event-reading loop - XTread_socket. */
3125
3126 /* Timestamp of enter window event. This is only used by XTread_socket,
3127 but we have to put it out here, since static variables within functions
3128 sometimes don't work. */
3129 static Time enter_timestamp;
3130
3131 /* This holds the state XLookupString needs to implement dead keys
3132 and other tricks known as "compose processing". _X Window System_
3133 says that a portable program can't use this, but Stephen Gildea assures
3134 me that letting the compiler initialize it to zeros will work okay.
3135
3136 This must be defined outside of XTread_socket, for the same reasons
3137 given for enter_timestamp, above. */
3138 static XComposeStatus compose_status;
3139
3140 /* Record the last 100 characters stored
3141 to help debug the loss-of-chars-during-GC problem. */
3142 int temp_index;
3143 short temp_buffer[100];
3144
3145 /* Set this to nonzero to fake an "X I/O error"
3146 on a particular display. */
3147 struct x_display_info *XTread_socket_fake_io_error;
3148
3149 /* Read events coming from the X server.
3150 This routine is called by the SIGIO handler.
3151 We return as soon as there are no more events to be read.
3152
3153 Events representing keys are stored in buffer BUFP,
3154 which can hold up to NUMCHARS characters.
3155 We return the number of characters stored into the buffer,
3156 thus pretending to be `read'.
3157
3158 WAITP is nonzero if we should block until input arrives.
3159 EXPECTED is nonzero if the caller knows input is available. */
3160
3161 int
3162 XTread_socket (sd, bufp, numchars, waitp, expected)
3163 register int sd;
3164 register struct input_event *bufp;
3165 register int numchars;
3166 int waitp;
3167 int expected;
3168 {
3169 int count = 0;
3170 int nbytes = 0;
3171 int mask;
3172 int items_pending; /* How many items are in the X queue. */
3173 XEvent event;
3174 struct frame *f;
3175 int event_found = 0;
3176 int prefix;
3177 Lisp_Object part;
3178 struct x_display_info *dpyinfo;
3179
3180 if (interrupt_input_blocked)
3181 {
3182 interrupt_input_pending = 1;
3183 return -1;
3184 }
3185
3186 interrupt_input_pending = 0;
3187 BLOCK_INPUT;
3188
3189 /* So people can tell when we have read the available input. */
3190 input_signal_count++;
3191
3192 if (numchars <= 0)
3193 abort (); /* Don't think this happens. */
3194
3195 /* Find the display we are supposed to read input for.
3196 It's the one communicating on descriptor SD. */
3197 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
3198 {
3199 #if 0 /* This ought to be unnecessary; let's verify it. */
3200 #ifdef FIOSNBIO
3201 /* If available, Xlib uses FIOSNBIO to make the socket
3202 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
3203 FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK,
3204 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
3205 fcntl (dpyinfo->connection, F_SETFL, 0);
3206 #endif /* ! defined (FIOSNBIO) */
3207 #endif
3208
3209 #if 0 /* This code can't be made to work, with multiple displays,
3210 and appears not to be used on any system any more.
3211 Also keyboard.c doesn't turn O_NDELAY on and off
3212 for X connections. */
3213 #ifndef SIGIO
3214 #ifndef HAVE_SELECT
3215 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
3216 {
3217 extern int read_alarm_should_throw;
3218 read_alarm_should_throw = 1;
3219 XPeekEvent (dpyinfo->display, &event);
3220 read_alarm_should_throw = 0;
3221 }
3222 #endif /* HAVE_SELECT */
3223 #endif /* SIGIO */
3224 #endif
3225
3226 /* For debugging, this gives a way to fake an I/O error. */
3227 if (dpyinfo == XTread_socket_fake_io_error)
3228 {
3229 XTread_socket_fake_io_error = 0;
3230 x_io_error_quitter (dpyinfo->display);
3231 }
3232
3233 while (XPending (dpyinfo->display) != 0)
3234 {
3235 XNextEvent (dpyinfo->display, &event);
3236 event_found = 1;
3237
3238 switch (event.type)
3239 {
3240 case ClientMessage:
3241 {
3242 if (event.xclient.message_type
3243 == dpyinfo->Xatom_wm_protocols
3244 && event.xclient.format == 32)
3245 {
3246 if (event.xclient.data.l[0]
3247 == dpyinfo->Xatom_wm_take_focus)
3248 {
3249 f = x_window_to_frame (event.xclient.window);
3250 /* Since we set WM_TAKE_FOCUS, we must call
3251 XSetInputFocus explicitly. But not if f is null,
3252 since that might be an event for a deleted frame. */
3253 if (f)
3254 XSetInputFocus (event.xclient.display,
3255 event.xclient.window,
3256 RevertToPointerRoot,
3257 event.xclient.data.l[1]);
3258 /* Not certain about handling scroll bars here */
3259 }
3260 else if (event.xclient.data.l[0]
3261 == dpyinfo->Xatom_wm_save_yourself)
3262 {
3263 /* Save state modify the WM_COMMAND property to
3264 something which can reinstate us. This notifies
3265 the session manager, who's looking for such a
3266 PropertyNotify. Can restart processing when
3267 a keyboard or mouse event arrives. */
3268 if (numchars > 0)
3269 {
3270 f = x_top_window_to_frame (event.xclient.window);
3271
3272 /* This is just so we only give real data once
3273 for a single Emacs process. */
3274 if (f == selected_frame)
3275 XSetCommand (FRAME_X_DISPLAY (f),
3276 event.xclient.window,
3277 initial_argv, initial_argc);
3278 else
3279 XSetCommand (FRAME_X_DISPLAY (f),
3280 event.xclient.window,
3281 0, 0);
3282 }
3283 }
3284 else if (event.xclient.data.l[0]
3285 == dpyinfo->Xatom_wm_delete_window)
3286 {
3287 struct frame *f = x_any_window_to_frame (event.xclient.window);
3288
3289 if (f)
3290 {
3291 if (numchars == 0)
3292 abort ();
3293
3294 bufp->kind = delete_window_event;
3295 XSETFRAME (bufp->frame_or_window, f);
3296 bufp++;
3297
3298 count += 1;
3299 numchars -= 1;
3300 }
3301 }
3302 }
3303 else if (event.xclient.message_type
3304 == dpyinfo->Xatom_wm_configure_denied)
3305 {
3306 }
3307 else if (event.xclient.message_type
3308 == dpyinfo->Xatom_wm_window_moved)
3309 {
3310 int new_x, new_y;
3311 struct frame *f = x_window_to_frame (event.xclient.window);
3312
3313 new_x = event.xclient.data.s[0];
3314 new_y = event.xclient.data.s[1];
3315
3316 if (f)
3317 {
3318 f->display.x->left_pos = new_x;
3319 f->display.x->top_pos = new_y;
3320 }
3321 }
3322 #if defined (USE_X_TOOLKIT) && defined (HAVE_X11R5)
3323 else if (event.xclient.message_type
3324 == dpyinfo->Xatom_editres)
3325 {
3326 struct frame *f = x_any_window_to_frame (event.xclient.window);
3327 _XEditResCheckMessages (f->display.x->widget, NULL, &event, NULL);
3328 }
3329 #endif /* USE_X_TOOLKIT and HAVE_X11R5 */
3330 }
3331 break;
3332
3333 case SelectionNotify:
3334 #ifdef USE_X_TOOLKIT
3335 if (! x_window_to_frame (event.xselection.requestor))
3336 goto OTHER;
3337 #endif /* not USE_X_TOOLKIT */
3338 x_handle_selection_notify (&event);
3339 break;
3340
3341 case SelectionClear: /* Someone has grabbed ownership. */
3342 #ifdef USE_X_TOOLKIT
3343 if (! x_window_to_frame (event.xselectionclear.window))
3344 goto OTHER;
3345 #endif /* USE_X_TOOLKIT */
3346 {
3347 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
3348
3349 if (numchars == 0)
3350 abort ();
3351
3352 bufp->kind = selection_clear_event;
3353 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3354 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3355 SELECTION_EVENT_TIME (bufp) = eventp->time;
3356 bufp++;
3357
3358 count += 1;
3359 numchars -= 1;
3360 }
3361 break;
3362
3363 case SelectionRequest: /* Someone wants our selection. */
3364 #ifdef USE_X_TOOLKIT
3365 if (!x_window_to_frame (event.xselectionrequest.owner))
3366 goto OTHER;
3367 #endif /* USE_X_TOOLKIT */
3368 if (x_queue_selection_requests)
3369 x_queue_event (x_window_to_frame (event.xselectionrequest.owner),
3370 &event);
3371 else
3372 {
3373 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
3374
3375 if (numchars == 0)
3376 abort ();
3377
3378 bufp->kind = selection_request_event;
3379 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3380 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
3381 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3382 SELECTION_EVENT_TARGET (bufp) = eventp->target;
3383 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
3384 SELECTION_EVENT_TIME (bufp) = eventp->time;
3385 bufp++;
3386
3387 count += 1;
3388 numchars -= 1;
3389 }
3390 break;
3391
3392 case PropertyNotify:
3393 #ifdef USE_X_TOOLKIT
3394 if (!x_any_window_to_frame (event.xproperty.window))
3395 goto OTHER;
3396 #endif /* not USE_X_TOOLKIT */
3397 x_handle_property_notify (&event);
3398 break;
3399
3400 case ReparentNotify:
3401 f = x_top_window_to_frame (event.xreparent.window);
3402 if (f)
3403 {
3404 int x, y;
3405 f->display.x->parent_desc = event.xreparent.parent;
3406 x_real_positions (f, &x, &y);
3407 f->display.x->left_pos = x;
3408 f->display.x->top_pos = y;
3409 }
3410 break;
3411
3412 case Expose:
3413 f = x_window_to_frame (event.xexpose.window);
3414 if (f)
3415 {
3416 if (f->async_visible == 0)
3417 {
3418 f->async_visible = 1;
3419 f->async_iconified = 0;
3420 SET_FRAME_GARBAGED (f);
3421 }
3422 else
3423 dumprectangle (x_window_to_frame (event.xexpose.window),
3424 event.xexpose.x, event.xexpose.y,
3425 event.xexpose.width, event.xexpose.height);
3426 }
3427 else
3428 {
3429 struct scroll_bar *bar
3430 = x_window_to_scroll_bar (event.xexpose.window);
3431
3432 if (bar)
3433 x_scroll_bar_expose (bar, &event);
3434 #ifdef USE_X_TOOLKIT
3435 else
3436 goto OTHER;
3437 #endif /* USE_X_TOOLKIT */
3438 }
3439 break;
3440
3441 case GraphicsExpose: /* This occurs when an XCopyArea's
3442 source area was obscured or not
3443 available.*/
3444 f = x_window_to_frame (event.xgraphicsexpose.drawable);
3445 if (f)
3446 {
3447 dumprectangle (f,
3448 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
3449 event.xgraphicsexpose.width,
3450 event.xgraphicsexpose.height);
3451 }
3452 #ifdef USE_X_TOOLKIT
3453 else
3454 goto OTHER;
3455 #endif /* USE_X_TOOLKIT */
3456 break;
3457
3458 case NoExpose: /* This occurs when an XCopyArea's
3459 source area was completely
3460 available */
3461 break;
3462
3463 case UnmapNotify:
3464 f = x_any_window_to_frame (event.xunmap.window);
3465 if (f) /* F may no longer exist if
3466 the frame was deleted. */
3467 {
3468 /* While a frame is unmapped, display generation is
3469 disabled; you don't want to spend time updating a
3470 display that won't ever be seen. */
3471 f->async_visible = 0;
3472 /* We can't distinguish, from the event, whether the window
3473 has become iconified or invisible. So assume, if it
3474 was previously visible, than now it is iconified.
3475 We depend on x_make_frame_invisible to mark it iconified. */
3476 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
3477 f->async_iconified = 1;
3478
3479 bufp->kind = iconify_event;
3480 XSETFRAME (bufp->frame_or_window, f);
3481 bufp++;
3482 count++;
3483 numchars--;
3484 }
3485 #ifdef USE_X_TOOLKIT
3486 goto OTHER;
3487 #endif /* USE_X_TOOLKIT */
3488 break;
3489
3490 case MapNotify:
3491 /* We use x_top_window_to_frame because map events can come
3492 for subwindows and they don't mean that the frame is visible. */
3493 f = x_top_window_to_frame (event.xmap.window);
3494 if (f)
3495 {
3496 f->async_visible = 1;
3497 f->async_iconified = 0;
3498
3499 /* wait_reading_process_input will notice this and update
3500 the frame's display structures. */
3501 SET_FRAME_GARBAGED (f);
3502
3503 bufp->kind = deiconify_event;
3504 XSETFRAME (bufp->frame_or_window, f);
3505 bufp++;
3506 count++;
3507 numchars--;
3508 }
3509 #ifdef USE_X_TOOLKIT
3510 goto OTHER;
3511 #endif /* USE_X_TOOLKIT */
3512 break;
3513
3514 /* Turn off processing if we become fully obscured. */
3515 case VisibilityNotify:
3516 break;
3517
3518 case KeyPress:
3519 f = x_any_window_to_frame (event.xkey.window);
3520
3521 if (f != 0)
3522 {
3523 KeySym keysym, orig_keysym;
3524 /* al%imercury@uunet.uu.net says that making this 81 instead of
3525 80 fixed a bug whereby meta chars made his Emacs hang. */
3526 unsigned char copy_buffer[81];
3527 int modifiers;
3528
3529 event.xkey.state
3530 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
3531 extra_keyboard_modifiers);
3532 modifiers = event.xkey.state;
3533
3534 /* This will have to go some day... */
3535
3536 /* make_lispy_event turns chars into control chars.
3537 Don't do it here because XLookupString is too eager. */
3538 event.xkey.state &= ~ControlMask;
3539 nbytes = XLookupString (&event.xkey, copy_buffer,
3540 80, &keysym, &compose_status);
3541
3542 orig_keysym = keysym;
3543
3544 if (numchars > 1)
3545 {
3546 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
3547 || keysym == XK_Delete
3548 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
3549 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
3550 #ifdef HPUX
3551 /* This recognizes the "extended function keys".
3552 It seems there's no cleaner way.
3553 Test IsModifierKey to avoid handling mode_switch
3554 incorrectly. */
3555 || ((unsigned) (keysym) >= XK_Select
3556 && (unsigned)(keysym) < XK_KP_Space)
3557 #endif
3558 #ifdef XK_dead_circumflex
3559 || orig_keysym == XK_dead_circumflex
3560 #endif
3561 #ifdef XK_dead_grave
3562 || orig_keysym == XK_dead_grave
3563 #endif
3564 #ifdef XK_dead_tilde
3565 || orig_keysym == XK_dead_tilde
3566 #endif
3567 #ifdef XK_dead_diaeresis
3568 || orig_keysym == XK_dead_diaeresis
3569 #endif
3570 #ifdef XK_dead_macron
3571 || orig_keysym == XK_dead_macron
3572 #endif
3573 #ifdef XK_dead_degree
3574 || orig_keysym == XK_dead_degree
3575 #endif
3576 #ifdef XK_dead_acute
3577 || orig_keysym == XK_dead_acute
3578 #endif
3579 #ifdef XK_dead_cedilla
3580 || orig_keysym == XK_dead_cedilla
3581 #endif
3582 #ifdef XK_dead_breve
3583 || orig_keysym == XK_dead_breve
3584 #endif
3585 #ifdef XK_dead_ogonek
3586 || orig_keysym == XK_dead_ogonek
3587 #endif
3588 #ifdef XK_dead_caron
3589 || orig_keysym == XK_dead_caron
3590 #endif
3591 #ifdef XK_dead_doubleacute
3592 || orig_keysym == XK_dead_doubleacute
3593 #endif
3594 #ifdef XK_dead_abovedot
3595 || orig_keysym == XK_dead_abovedot
3596 #endif
3597 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
3598 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
3599 /* Any "vendor-specific" key is ok. */
3600 || (orig_keysym & (1 << 28)))
3601 && ! (IsModifierKey (orig_keysym)
3602 #ifndef HAVE_X11R5
3603 #ifdef XK_Mode_switch
3604 || ((unsigned)(orig_keysym) == XK_Mode_switch)
3605 #endif
3606 #ifdef XK_Num_Lock
3607 || ((unsigned)(orig_keysym) == XK_Num_Lock)
3608 #endif
3609 #endif /* not HAVE_X11R5 */
3610 ))
3611 {
3612 if (temp_index == sizeof temp_buffer / sizeof (short))
3613 temp_index = 0;
3614 temp_buffer[temp_index++] = keysym;
3615 bufp->kind = non_ascii_keystroke;
3616 bufp->code = keysym;
3617 XSETFRAME (bufp->frame_or_window, f);
3618 bufp->modifiers
3619 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
3620 modifiers);
3621 bufp->timestamp = event.xkey.time;
3622 bufp++;
3623 count++;
3624 numchars--;
3625 }
3626 else if (numchars > nbytes)
3627 {
3628 register int i;
3629
3630 for (i = 0; i < nbytes; i++)
3631 {
3632 if (temp_index == sizeof temp_buffer / sizeof (short))
3633 temp_index = 0;
3634 temp_buffer[temp_index++] = copy_buffer[i];
3635 bufp->kind = ascii_keystroke;
3636 bufp->code = copy_buffer[i];
3637 XSETFRAME (bufp->frame_or_window, f);
3638 bufp->modifiers
3639 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
3640 modifiers);
3641 bufp->timestamp = event.xkey.time;
3642 bufp++;
3643 }
3644
3645 count += nbytes;
3646 numchars -= nbytes;
3647 }
3648 else
3649 abort ();
3650 }
3651 else
3652 abort ();
3653 }
3654 break;
3655
3656 /* Here's a possible interpretation of the whole
3657 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
3658 FocusIn event, you have to get a FocusOut event before you
3659 relinquish the focus. If you haven't received a FocusIn event,
3660 then a mere LeaveNotify is enough to free you. */
3661
3662 case EnterNotify:
3663 f = x_any_window_to_frame (event.xcrossing.window);
3664
3665 if (event.xcrossing.focus) /* Entered Window */
3666 {
3667 /* Avoid nasty pop/raise loops. */
3668 if (f && (!(f->auto_raise)
3669 || !(f->auto_lower)
3670 || (event.xcrossing.time - enter_timestamp) > 500))
3671 {
3672 x_new_focus_frame (f);
3673 enter_timestamp = event.xcrossing.time;
3674 }
3675 }
3676 else if (f == x_focus_frame)
3677 x_new_focus_frame (0);
3678 /* EnterNotify counts as mouse movement,
3679 so update things that depend on mouse position. */
3680 if (f)
3681 note_mouse_movement (f, &event.xmotion);
3682 #ifdef USE_X_TOOLKIT
3683 goto OTHER;
3684 #endif /* USE_X_TOOLKIT */
3685 break;
3686
3687 case FocusIn:
3688 f = x_any_window_to_frame (event.xfocus.window);
3689 if (event.xfocus.detail != NotifyPointer)
3690 x_focus_event_frame = f;
3691 if (f)
3692 x_new_focus_frame (f);
3693 #ifdef USE_X_TOOLKIT
3694 goto OTHER;
3695 #endif /* USE_X_TOOLKIT */
3696 break;
3697
3698
3699 case LeaveNotify:
3700 f = x_top_window_to_frame (event.xcrossing.window);
3701 if (f)
3702 {
3703 if (f == dpyinfo->mouse_face_mouse_frame)
3704 /* If we move outside the frame,
3705 then we're certainly no longer on any text in the frame. */
3706 clear_mouse_face (dpyinfo);
3707
3708 if (event.xcrossing.focus)
3709 x_mouse_leave ();
3710 else
3711 {
3712 if (f == x_focus_event_frame)
3713 x_focus_event_frame = 0;
3714 if (f == x_focus_frame)
3715 x_new_focus_frame (0);
3716 }
3717 }
3718 #ifdef USE_X_TOOLKIT
3719 goto OTHER;
3720 #endif /* USE_X_TOOLKIT */
3721 break;
3722
3723 case FocusOut:
3724 f = x_any_window_to_frame (event.xfocus.window);
3725 if (event.xfocus.detail != NotifyPointer
3726 && f == x_focus_event_frame)
3727 x_focus_event_frame = 0;
3728 if (f && f == x_focus_frame)
3729 x_new_focus_frame (0);
3730 #ifdef USE_X_TOOLKIT
3731 goto OTHER;
3732 #endif /* USE_X_TOOLKIT */
3733 break;
3734
3735 case MotionNotify:
3736 {
3737 if (dpyinfo->grabbed && last_mouse_frame
3738 && FRAME_LIVE_P (last_mouse_frame))
3739 f = last_mouse_frame;
3740 else
3741 f = x_window_to_frame (event.xmotion.window);
3742 if (f)
3743 note_mouse_movement (f, &event.xmotion);
3744 else
3745 {
3746 struct scroll_bar *bar
3747 = x_window_to_scroll_bar (event.xmotion.window);
3748
3749 if (bar)
3750 x_scroll_bar_note_movement (bar, &event);
3751
3752 /* If we move outside the frame,
3753 then we're certainly no longer on any text in the frame. */
3754 clear_mouse_face (dpyinfo);
3755 }
3756 }
3757 #if 0 /* This should be unnecessary, since the toolkit has no use
3758 for motion events that happen outside of the menu event loop,
3759 and it seems to cause the bug that mouse events stop coming
3760 after a while. */
3761 #ifdef USE_X_TOOLKIT
3762 goto OTHER;
3763 #endif /* USE_X_TOOLKIT */
3764 #endif
3765 break;
3766
3767 case ConfigureNotify:
3768 f = x_any_window_to_frame (event.xconfigure.window);
3769 #ifdef USE_X_TOOLKIT
3770 if (f
3771 #if 0
3772 && ! event.xconfigure.send_event
3773 #endif
3774 && (event.xconfigure.window == XtWindow (f->display.x->widget)))
3775 {
3776 Window win, child;
3777 int win_x, win_y;
3778
3779 /* Find the position of the outside upper-left corner of
3780 the window, in the root coordinate system. Don't
3781 refer to the parent window here; we may be processing
3782 this event after the window manager has changed our
3783 parent, but before we have reached the ReparentNotify. */
3784 XTranslateCoordinates (FRAME_X_DISPLAY (f),
3785
3786 /* From-window, to-window. */
3787 XtWindow (f->display.x->widget),
3788 FRAME_X_DISPLAY_INFO (f)->root_window,
3789
3790 /* From-position, to-position. */
3791 -event.xconfigure.border_width,
3792 -event.xconfigure.border_width,
3793 &win_x, &win_y,
3794
3795 /* Child of win. */
3796 &child);
3797 event.xconfigure.x = win_x;
3798 event.xconfigure.y = win_y;
3799
3800 f->display.x->pixel_width = event.xconfigure.width;
3801 f->display.x->pixel_height = event.xconfigure.height;
3802 f->display.x->left_pos = event.xconfigure.x;
3803 f->display.x->top_pos = event.xconfigure.y;
3804
3805 /* What we have now is the position of Emacs's own window.
3806 Convert that to the position of the window manager window. */
3807 {
3808 int x, y;
3809 x_real_positions (f, &x, &y);
3810 f->display.x->left_pos = x;
3811 f->display.x->top_pos = y;
3812 }
3813 }
3814 goto OTHER;
3815 #else /* not USE_X_TOOLKIT */
3816 if (f)
3817 {
3818 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
3819 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
3820
3821 /* Even if the number of character rows and columns has
3822 not changed, the font size may have changed, so we need
3823 to check the pixel dimensions as well. */
3824 if (columns != f->width
3825 || rows != f->height
3826 || event.xconfigure.width != f->display.x->pixel_width
3827 || event.xconfigure.height != f->display.x->pixel_height)
3828 {
3829 change_frame_size (f, rows, columns, 0, 1);
3830 SET_FRAME_GARBAGED (f);
3831 }
3832
3833 if (! event.xconfigure.send_event)
3834 {
3835 Window win, child;
3836 int win_x, win_y;
3837
3838 /* Find the position of the outside upper-left corner of
3839 the window, in the root coordinate system. Don't
3840 refer to the parent window here; we may be processing
3841 this event after the window manager has changed our
3842 parent, but before we have reached the ReparentNotify. */
3843 XTranslateCoordinates (FRAME_X_DISPLAY (f),
3844
3845 /* From-window, to-window. */
3846 f->display.x->window_desc,
3847 FRAME_X_DISPLAY_INFO (f)->root_window,
3848
3849 /* From-position, to-position. */
3850 -event.xconfigure.border_width,
3851 -event.xconfigure.border_width,
3852 &win_x, &win_y,
3853
3854 /* Child of win. */
3855 &child);
3856 event.xconfigure.x = win_x;
3857 event.xconfigure.y = win_y;
3858 }
3859
3860 f->display.x->pixel_width = event.xconfigure.width;
3861 f->display.x->pixel_height = event.xconfigure.height;
3862 f->display.x->left_pos = event.xconfigure.x;
3863 f->display.x->top_pos = event.xconfigure.y;
3864
3865 /* What we have now is the position of Emacs's own window.
3866 Convert that to the position of the window manager window. */
3867 {
3868 int x, y;
3869 x_real_positions (f, &x, &y);
3870 f->display.x->left_pos = x;
3871 f->display.x->top_pos = y;
3872 if (y != event.xconfigure.y)
3873 {
3874 /* Since the WM decorations come below top_pos now,
3875 we must put them below top_pos in the future. */
3876 f->display.x->win_gravity = NorthWestGravity;
3877 x_wm_set_size_hint (f, 0, 0);
3878 }
3879 }
3880 }
3881 #endif /* not USE_X_TOOLKIT */
3882 break;
3883
3884 case ButtonPress:
3885 case ButtonRelease:
3886 {
3887 /* If we decide we want to generate an event to be seen
3888 by the rest of Emacs, we put it here. */
3889 struct input_event emacs_event;
3890 emacs_event.kind = no_event;
3891
3892 bzero (&compose_status, sizeof (compose_status));
3893
3894 if (dpyinfo->grabbed && last_mouse_frame
3895 && FRAME_LIVE_P (last_mouse_frame))
3896 f = last_mouse_frame;
3897 else
3898 f = x_window_to_frame (event.xmotion.window);
3899
3900 if (f)
3901 {
3902 if (!x_focus_frame || (f == x_focus_frame))
3903 construct_mouse_click (&emacs_event, &event, f);
3904 }
3905 else
3906 {
3907 struct scroll_bar *bar
3908 = x_window_to_scroll_bar (event.xbutton.window);
3909
3910 if (bar)
3911 x_scroll_bar_handle_click (bar, &event, &emacs_event);
3912 #ifdef USE_X_TOOLKIT
3913 else
3914 {
3915 /* Assume we have a menubar button press. A bad
3916 assumption should behave benignly. */
3917 popup_get_selection (&event);
3918 break;
3919 }
3920 #endif /* USE_X_TOOLKIT */
3921 }
3922
3923 if (event.type == ButtonPress)
3924 {
3925 dpyinfo->grabbed |= (1 << event.xbutton.button);
3926 last_mouse_frame = f;
3927 }
3928 else
3929 {
3930 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3931 }
3932
3933 if (numchars >= 1 && emacs_event.kind != no_event)
3934 {
3935 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3936 bufp++;
3937 count++;
3938 numchars--;
3939 }
3940
3941 #ifdef USE_X_TOOLKIT
3942 goto OTHER;
3943 #endif /* USE_X_TOOLKIT */
3944 }
3945 break;
3946
3947 case CirculateNotify:
3948 break;
3949 case CirculateRequest:
3950 break;
3951
3952 case MappingNotify:
3953 /* Someone has changed the keyboard mapping - update the
3954 local cache. */
3955 switch (event.xmapping.request)
3956 {
3957 case MappingModifier:
3958 x_find_modifier_meanings (dpyinfo);
3959 /* This is meant to fall through. */
3960 case MappingKeyboard:
3961 XRefreshKeyboardMapping (&event.xmapping);
3962 }
3963 #ifdef USE_X_TOOLKIT
3964 goto OTHER;
3965 #endif /* USE_X_TOOLKIT */
3966 break;
3967
3968 default:
3969 #ifdef USE_X_TOOLKIT
3970 OTHER:
3971 BLOCK_INPUT;
3972 XtDispatchEvent (&event);
3973 UNBLOCK_INPUT;
3974 #endif /* USE_X_TOOLKIT */
3975 break;
3976 }
3977 }
3978 }
3979
3980 /* On some systems, an X bug causes Emacs to get no more events
3981 when the window is destroyed. Detect that. (1994.) */
3982 if (! event_found)
3983 {
3984 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
3985 One XNOOP in 100 loops will make Emacs terminate.
3986 B. Bretthauer, 1994 */
3987 x_noop_count++;
3988 if (x_noop_count >= 100)
3989 {
3990 x_noop_count=0;
3991 /* Use the first display in the list. Why not? */
3992 XNoOp (x_display_list->display);
3993 }
3994 }
3995
3996 /* If the focus was just given to an autoraising frame,
3997 raise it now. */
3998 /* ??? This ought to be able to handle more than one such frame. */
3999 if (pending_autoraise_frame)
4000 {
4001 x_raise_frame (pending_autoraise_frame);
4002 pending_autoraise_frame = 0;
4003 }
4004
4005 UNBLOCK_INPUT;
4006 return count;
4007 }
4008 \f
4009 /* Drawing the cursor. */
4010
4011
4012 /* Draw a hollow box cursor. Don't change the inside of the box. */
4013
4014 static void
4015 x_draw_box (f)
4016 struct frame *f;
4017 {
4018 int left = CHAR_TO_PIXEL_COL (f, curs_x);
4019 int top = CHAR_TO_PIXEL_ROW (f, curs_y);
4020 int width = FONT_WIDTH (f->display.x->font);
4021 int height = f->display.x->line_height;
4022
4023 XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4024 f->display.x->cursor_gc,
4025 left, top, width - 1, height - 1);
4026 }
4027
4028 /* Clear the cursor of frame F to background color,
4029 and mark the cursor as not shown.
4030 This is used when the text where the cursor is
4031 is about to be rewritten. */
4032
4033 static void
4034 clear_cursor (f)
4035 struct frame *f;
4036 {
4037 int mask;
4038
4039 if (! FRAME_VISIBLE_P (f)
4040 || f->phys_cursor_x < 0)
4041 return;
4042
4043 x_display_cursor (f, 0);
4044 f->phys_cursor_x = -1;
4045 }
4046
4047 /* Redraw the glyph at ROW, COLUMN on frame F, in the style
4048 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
4049 glyph drawn. */
4050
4051 static void
4052 x_draw_single_glyph (f, row, column, glyph, highlight)
4053 struct frame *f;
4054 int row, column;
4055 GLYPH glyph;
4056 int highlight;
4057 {
4058 dumpglyphs (f,
4059 CHAR_TO_PIXEL_COL (f, column),
4060 CHAR_TO_PIXEL_ROW (f, row),
4061 &glyph, 1, highlight, 0);
4062 }
4063
4064 static void
4065 x_display_bar_cursor (f, on)
4066 struct frame *f;
4067 int on;
4068 {
4069 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4070
4071 /* This is pointless on invisible frames, and dangerous on garbaged
4072 frames; in the latter case, the frame may be in the midst of
4073 changing its size, and curs_x and curs_y may be off the frame. */
4074 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
4075 return;
4076
4077 if (! on && f->phys_cursor_x < 0)
4078 return;
4079
4080 /* If we're not updating, then we want to use the current frame's
4081 cursor position, not our local idea of where the cursor ought to be. */
4082 if (f != updating_frame)
4083 {
4084 curs_x = FRAME_CURSOR_X (f);
4085 curs_y = FRAME_CURSOR_Y (f);
4086 }
4087
4088 /* If there is anything wrong with the current cursor state, remove it. */
4089 if (f->phys_cursor_x >= 0
4090 && (!on
4091 || f->phys_cursor_x != curs_x
4092 || f->phys_cursor_y != curs_y
4093 || f->display.x->current_cursor != bar_cursor))
4094 {
4095 /* Erase the cursor by redrawing the character underneath it. */
4096 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4097 f->phys_cursor_glyph,
4098 current_glyphs->highlight[f->phys_cursor_y]);
4099 f->phys_cursor_x = -1;
4100 }
4101
4102 /* If we now need a cursor in the new place or in the new form, do it so. */
4103 if (on
4104 && (f->phys_cursor_x < 0
4105 || (f->display.x->current_cursor != bar_cursor)))
4106 {
4107 f->phys_cursor_glyph
4108 = ((current_glyphs->enable[curs_y]
4109 && curs_x < current_glyphs->used[curs_y])
4110 ? current_glyphs->glyphs[curs_y][curs_x]
4111 : SPACEGLYPH);
4112 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4113 f->display.x->cursor_gc,
4114 CHAR_TO_PIXEL_COL (f, curs_x),
4115 CHAR_TO_PIXEL_ROW (f, curs_y),
4116 1, f->display.x->line_height);
4117
4118 f->phys_cursor_x = curs_x;
4119 f->phys_cursor_y = curs_y;
4120
4121 f->display.x->current_cursor = bar_cursor;
4122 }
4123
4124 if (updating_frame != f)
4125 XFlush (FRAME_X_DISPLAY (f));
4126 }
4127
4128
4129 /* Turn the displayed cursor of frame F on or off according to ON.
4130 If ON is nonzero, where to put the cursor is specified
4131 by F->cursor_x and F->cursor_y. */
4132
4133 static void
4134 x_display_box_cursor (f, on)
4135 struct frame *f;
4136 int on;
4137 {
4138 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4139
4140 /* This is pointless on invisible frames, and dangerous on garbaged
4141 frames; in the latter case, the frame may be in the midst of
4142 changing its size, and curs_x and curs_y may be off the frame. */
4143 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
4144 return;
4145
4146 /* If cursor is off and we want it off, return quickly. */
4147 if (!on && f->phys_cursor_x < 0)
4148 return;
4149
4150 /* If we're not updating, then we want to use the current frame's
4151 cursor position, not our local idea of where the cursor ought to be. */
4152 if (f != updating_frame)
4153 {
4154 curs_x = FRAME_CURSOR_X (f);
4155 curs_y = FRAME_CURSOR_Y (f);
4156 }
4157
4158 /* If cursor is currently being shown and we don't want it to be
4159 or it is in the wrong place,
4160 or we want a hollow box and it's not so, (pout!)
4161 erase it. */
4162 if (f->phys_cursor_x >= 0
4163 && (!on
4164 || f->phys_cursor_x != curs_x
4165 || f->phys_cursor_y != curs_y
4166 || (f->display.x->current_cursor != hollow_box_cursor
4167 && (f != x_highlight_frame))))
4168 {
4169 int mouse_face_here = 0;
4170 struct frame_glyphs *active_glyphs = FRAME_CURRENT_GLYPHS (f);
4171
4172 /* If the cursor is in the mouse face area, redisplay that when
4173 we clear the cursor. */
4174 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame
4175 &&
4176 (f->phys_cursor_y > FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4177 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4178 && f->phys_cursor_x >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col))
4179 &&
4180 (f->phys_cursor_y < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
4181 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
4182 && f->phys_cursor_x < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col))
4183 /* Don't redraw the cursor's spot in mouse face
4184 if it is at the end of a line (on a newline).
4185 The cursor appears there, but mouse highlighting does not. */
4186 && active_glyphs->used[f->phys_cursor_y] > f->phys_cursor_x)
4187 mouse_face_here = 1;
4188
4189 /* If the font is not as tall as a whole line,
4190 we must explicitly clear the line's whole height. */
4191 if (FONT_HEIGHT (f->display.x->font) != f->display.x->line_height)
4192 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4193 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
4194 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
4195 FONT_WIDTH (f->display.x->font),
4196 f->display.x->line_height, False);
4197 /* Erase the cursor by redrawing the character underneath it. */
4198 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4199 f->phys_cursor_glyph,
4200 (mouse_face_here
4201 ? 3
4202 : current_glyphs->highlight[f->phys_cursor_y]));
4203 f->phys_cursor_x = -1;
4204 }
4205
4206 /* If we want to show a cursor,
4207 or we want a box cursor and it's not so,
4208 write it in the right place. */
4209 if (on
4210 && (f->phys_cursor_x < 0
4211 || (f->display.x->current_cursor != filled_box_cursor
4212 && f == x_highlight_frame)))
4213 {
4214 f->phys_cursor_glyph
4215 = ((current_glyphs->enable[curs_y]
4216 && curs_x < current_glyphs->used[curs_y])
4217 ? current_glyphs->glyphs[curs_y][curs_x]
4218 : SPACEGLYPH);
4219 if (f != x_highlight_frame)
4220 {
4221 x_draw_box (f);
4222 f->display.x->current_cursor = hollow_box_cursor;
4223 }
4224 else
4225 {
4226 x_draw_single_glyph (f, curs_y, curs_x,
4227 f->phys_cursor_glyph, 2);
4228 f->display.x->current_cursor = filled_box_cursor;
4229 }
4230
4231 f->phys_cursor_x = curs_x;
4232 f->phys_cursor_y = curs_y;
4233 }
4234
4235 if (updating_frame != f)
4236 XFlush (FRAME_X_DISPLAY (f));
4237 }
4238
4239 x_display_cursor (f, on)
4240 struct frame *f;
4241 int on;
4242 {
4243 BLOCK_INPUT;
4244
4245 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
4246 x_display_box_cursor (f, on);
4247 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
4248 x_display_bar_cursor (f, on);
4249 else
4250 /* Those are the only two we have implemented! */
4251 abort ();
4252
4253 UNBLOCK_INPUT;
4254 }
4255 \f
4256 /* Icons. */
4257
4258 /* Refresh bitmap kitchen sink icon for frame F
4259 when we get an expose event for it. */
4260
4261 refreshicon (f)
4262 struct frame *f;
4263 {
4264 /* Normally, the window manager handles this function. */
4265 }
4266
4267 /* Make the x-window of frame F use the gnu icon bitmap. */
4268
4269 int
4270 x_bitmap_icon (f, file)
4271 struct frame *f;
4272 Lisp_Object file;
4273 {
4274 int mask, bitmap_id;
4275 Window icon_window;
4276
4277 if (FRAME_X_WINDOW (f) == 0)
4278 return 1;
4279
4280 /* Free up our existing icon bitmap if any. */
4281 if (f->display.x->icon_bitmap > 0)
4282 x_destroy_bitmap (f, f->display.x->icon_bitmap);
4283 f->display.x->icon_bitmap = 0;
4284
4285 if (STRINGP (file))
4286 bitmap_id = x_create_bitmap_from_file (f, file);
4287 else
4288 {
4289 /* Create the GNU bitmap if necessary. */
4290 if (!FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
4291 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
4292 = x_create_bitmap_from_data (f, gnu_bits,
4293 gnu_width, gnu_height);
4294
4295 /* The first time we create the GNU bitmap,
4296 this increments the refcount one extra time.
4297 As a result, the GNU bitmap is never freed.
4298 That way, we don't have to worry about allocating it again. */
4299 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
4300
4301 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
4302 }
4303
4304 x_wm_set_icon_pixmap (f, bitmap_id);
4305 f->display.x->icon_bitmap = bitmap_id;
4306
4307 return 0;
4308 }
4309
4310
4311 /* Make the x-window of frame F use a rectangle with text. */
4312
4313 int
4314 x_text_icon (f, icon_name)
4315 struct frame *f;
4316 char *icon_name;
4317 {
4318 if (FRAME_X_WINDOW (f) == 0)
4319 return 1;
4320
4321 if (icon_name)
4322 f->display.x->icon_label = icon_name;
4323 else
4324 if (! f->display.x->icon_label)
4325 f->display.x->icon_label = " *emacs* ";
4326
4327 #if 0
4328 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4329 (char *) f->display.x->icon_label);
4330 #endif
4331
4332 if (f->display.x->icon_bitmap > 0)
4333 x_destroy_bitmap (f, f->display.x->icon_bitmap);
4334 f->display.x->icon_bitmap = 0;
4335 x_wm_set_icon_pixmap (f, 0);
4336
4337 return 0;
4338 }
4339 \f
4340 /* Handling X errors. */
4341
4342 /* Handle the loss of connection to display DISPLAY. */
4343
4344 static SIGTYPE
4345 x_connection_closed (display, error_message)
4346 Display *display;
4347 char *error_message;
4348 {
4349 struct x_display_info *dpyinfo = x_display_info_for_display (display);
4350 Lisp_Object frame, tail;
4351
4352 if (_Xdebug)
4353 abort ();
4354
4355 /* First delete frames whose minibuffers are on frames
4356 that are on the dead display. */
4357 FOR_EACH_FRAME (tail, frame)
4358 {
4359 Lisp_Object minibuf_frame;
4360 minibuf_frame
4361 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
4362 if (! EQ (frame, minibuf_frame)
4363 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
4364 Fdelete_frame (frame, Qt);
4365 }
4366
4367 /* Now delete all remaining frames on the dead display.
4368 We are now sure none of these is used as the minibuffer
4369 for another frame that we need to delete. */
4370 FOR_EACH_FRAME (tail, frame)
4371 if (FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
4372 Fdelete_frame (frame, Qt);
4373
4374 x_delete_display (dpyinfo);
4375
4376 if (x_display_list == 0)
4377 {
4378 fprintf (stderr, "%s", error_message);
4379 shut_down_emacs (0, 0, Qnil);
4380 exit (70);
4381 }
4382
4383 /* Ordinary stack unwind doesn't deal with these. */
4384 #ifdef SIGIO
4385 sigunblock (sigmask (SIGIO));
4386 #endif
4387 sigunblock (sigmask (SIGALRM));
4388 TOTALLY_UNBLOCK_INPUT;
4389
4390 error ("%s", error_message);
4391 }
4392
4393 /* This is the usual handler for X protocol errors.
4394 It kills all frames on the display that we got the error for.
4395 If that was the only one, it prints an error message and kills Emacs. */
4396
4397 static int
4398 x_error_quitter (display, error)
4399 Display *display;
4400 XErrorEvent *error;
4401 {
4402 char buf[256], buf1[356];
4403
4404 /* Note that there is no real way portable across R3/R4 to get the
4405 original error handler. */
4406
4407 XGetErrorText (display, error->error_code, buf, sizeof (buf));
4408 sprintf (buf1, "X protocol error: %s on protocol request %d",
4409 buf, error->request_code);
4410 x_connection_closed (display, buf1);
4411 }
4412
4413 /* This is the handler for X IO errors, always.
4414 It kills all frames on the display that we lost touch with.
4415 If that was the only one, it prints an error message and kills Emacs. */
4416
4417 static int
4418 x_io_error_quitter (display)
4419 Display *display;
4420 {
4421 char buf[256];
4422
4423 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
4424 x_connection_closed (display, buf);
4425 }
4426 \f
4427 /* A buffer for storing X error messages. */
4428 static char *x_caught_error_message;
4429 #define X_CAUGHT_ERROR_MESSAGE_SIZE 200
4430
4431 /* An X error handler which stores the error message in
4432 x_caught_error_message. This is what's installed when
4433 x_catch_errors is in effect. */
4434
4435 static int
4436 x_error_catcher (display, error)
4437 Display *display;
4438 XErrorEvent *error;
4439 {
4440 XGetErrorText (display, error->error_code,
4441 x_caught_error_message, X_CAUGHT_ERROR_MESSAGE_SIZE);
4442 }
4443
4444
4445 /* Begin trapping X errors for display DPY. Actually we trap X errors
4446 for all displays, but DPY should be the display you are actually
4447 operating on.
4448
4449 After calling this function, X protocol errors no longer cause
4450 Emacs to exit; instead, they are recorded in x_cfc_error_message.
4451
4452 Calling x_check_errors signals an Emacs error if an X error has
4453 occurred since the last call to x_catch_errors or x_check_errors.
4454
4455 Calling x_uncatch_errors resumes the normal error handling. */
4456
4457 void x_catch_errors (), x_check_errors (), x_uncatch_errors ();
4458
4459 void
4460 x_catch_errors (dpy)
4461 Display *dpy;
4462 {
4463 /* Make sure any errors from previous requests have been dealt with. */
4464 XSync (dpy, False);
4465
4466 /* Set up the error buffer. */
4467 x_caught_error_message
4468 = (char*) xmalloc (X_CAUGHT_ERROR_MESSAGE_SIZE);
4469 x_caught_error_message[0] = '\0';
4470
4471 /* Install our little error handler. */
4472 XSetErrorHandler (x_error_catcher);
4473 }
4474
4475 /* If any X protocol errors have arrived since the last call to
4476 x_catch_errors or x_check_errors, signal an Emacs error using
4477 sprintf (a buffer, FORMAT, the x error message text) as the text. */
4478
4479 void
4480 x_check_errors (dpy, format)
4481 Display *dpy;
4482 char *format;
4483 {
4484 /* Make sure to catch any errors incurred so far. */
4485 XSync (dpy, False);
4486
4487 if (x_caught_error_message[0])
4488 {
4489 char buf[X_CAUGHT_ERROR_MESSAGE_SIZE + 56];
4490
4491 sprintf (buf, format, x_caught_error_message);
4492 x_uncatch_errors (dpy);
4493 error (buf);
4494 }
4495 }
4496
4497 /* Nonzero if we had any X protocol errors since we did x_catch_errors. */
4498
4499 int
4500 x_had_errors_p (dpy)
4501 Display *dpy;
4502 {
4503 /* Make sure to catch any errors incurred so far. */
4504 XSync (dpy, False);
4505
4506 return x_caught_error_message[0] != 0;
4507 }
4508
4509 /* Stop catching X protocol errors and let them make Emacs die. */
4510
4511 void
4512 x_uncatch_errors (dpy)
4513 Display *dpy;
4514 {
4515 xfree (x_caught_error_message);
4516 x_caught_error_message = 0;
4517 XSetErrorHandler (x_error_quitter);
4518 }
4519
4520 #if 0
4521 static unsigned int x_wire_count;
4522 x_trace_wire ()
4523 {
4524 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
4525 }
4526 #endif /* ! 0 */
4527
4528 \f
4529 /* Changing the font of the frame. */
4530
4531 /* Give frame F the font named FONTNAME as its default font, and
4532 return the full name of that font. FONTNAME may be a wildcard
4533 pattern; in that case, we choose some font that fits the pattern.
4534 The return value shows which font we chose. */
4535
4536 Lisp_Object
4537 x_new_font (f, fontname)
4538 struct frame *f;
4539 register char *fontname;
4540 {
4541 int already_loaded;
4542 int n_matching_fonts;
4543 XFontStruct *font_info;
4544 char **font_names;
4545
4546 /* Get a list of all the fonts that match this name. Once we
4547 have a list of matching fonts, we compare them against the fonts
4548 we already have by comparing font ids. */
4549 font_names = (char **) XListFonts (FRAME_X_DISPLAY (f), fontname,
4550 1024, &n_matching_fonts);
4551 /* Apparently it doesn't set n_matching_fonts to zero when it can't
4552 find any matches; font_names == 0 is the only clue. */
4553 if (! font_names)
4554 n_matching_fonts = 0;
4555
4556 /* Don't just give up if n_matching_fonts is 0.
4557 Apparently there's a bug on Suns: XListFontsWithInfo can
4558 fail to find a font, but XLoadQueryFont may still find it. */
4559
4560 /* See if we've already loaded a matching font. */
4561 already_loaded = -1;
4562 if (n_matching_fonts != 0)
4563 {
4564 int i, j;
4565
4566 for (i = 0; i < FRAME_X_DISPLAY_INFO (f)->n_fonts; i++)
4567 for (j = 0; j < n_matching_fonts; j++)
4568 if (!strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].name, font_names[j])
4569 || !strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name, font_names[j]))
4570 {
4571 already_loaded = i;
4572 fontname = FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name;
4573 goto found_font;
4574 }
4575 }
4576 found_font:
4577
4578 /* If we have, just return it from the table. */
4579 if (already_loaded >= 0)
4580 f->display.x->font = FRAME_X_DISPLAY_INFO (f)->font_table[already_loaded].font;
4581 /* Otherwise, load the font and add it to the table. */
4582 else
4583 {
4584 int i;
4585 char *full_name;
4586 XFontStruct *font;
4587 int n_fonts;
4588
4589 /* Try to find a character-cell font in the list. */
4590 #if 0
4591 /* A laudable goal, but this isn't how to do it. */
4592 for (i = 0; i < n_matching_fonts; i++)
4593 if (! font_info[i].per_char)
4594 break;
4595 #else
4596 i = 0;
4597 #endif
4598
4599 /* See comment above. */
4600 if (n_matching_fonts != 0)
4601 fontname = font_names[i];
4602
4603 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
4604 if (! font)
4605 {
4606 /* Free the information from XListFonts. */
4607 if (n_matching_fonts)
4608 XFreeFontNames (font_names);
4609 return Qnil;
4610 }
4611
4612 /* Do we need to create the table? */
4613 if (FRAME_X_DISPLAY_INFO (f)->font_table_size == 0)
4614 {
4615 FRAME_X_DISPLAY_INFO (f)->font_table_size = 16;
4616 FRAME_X_DISPLAY_INFO (f)->font_table
4617 = (struct font_info *) xmalloc (FRAME_X_DISPLAY_INFO (f)->font_table_size
4618 * sizeof (struct font_info));
4619 }
4620 /* Do we need to grow the table? */
4621 else if (FRAME_X_DISPLAY_INFO (f)->n_fonts
4622 >= FRAME_X_DISPLAY_INFO (f)->font_table_size)
4623 {
4624 FRAME_X_DISPLAY_INFO (f)->font_table_size *= 2;
4625 FRAME_X_DISPLAY_INFO (f)->font_table
4626 = (struct font_info *) xrealloc (FRAME_X_DISPLAY_INFO (f)->font_table,
4627 (FRAME_X_DISPLAY_INFO (f)->font_table_size
4628 * sizeof (struct font_info)));
4629 }
4630
4631 /* Try to get the full name of FONT. Put it in full_name. */
4632 full_name = 0;
4633 for (i = 0; i < font->n_properties; i++)
4634 {
4635 char *atom
4636 = XGetAtomName (FRAME_X_DISPLAY (f), font->properties[i].name);
4637 if (!strcmp (atom, "FONT"))
4638 {
4639 char *name = XGetAtomName (FRAME_X_DISPLAY (f),
4640 (Atom) (font->properties[i].card32));
4641 char *p = name;
4642 int dashes = 0;
4643
4644 /* Count the number of dashes in the "full name".
4645 If it is too few, this isn't really the font's full name,
4646 so don't use it.
4647 In X11R4, the fonts did not come with their canonical names
4648 stored in them. */
4649 while (*p)
4650 {
4651 if (*p == '-')
4652 dashes++;
4653 p++;
4654 }
4655
4656 if (dashes >= 13)
4657 full_name = name;
4658
4659 break;
4660 }
4661
4662 XFree (atom);
4663 }
4664
4665 n_fonts = FRAME_X_DISPLAY_INFO (f)->n_fonts;
4666 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name = (char *) xmalloc (strlen (fontname) + 1);
4667 bcopy (fontname, FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name, strlen (fontname) + 1);
4668 if (full_name != 0)
4669 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].full_name = full_name;
4670 else
4671 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].full_name = FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name;
4672 f->display.x->font = FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].font = font;
4673 FRAME_X_DISPLAY_INFO (f)->n_fonts++;
4674
4675 if (full_name)
4676 fontname = full_name;
4677 }
4678
4679 /* Compute the scroll bar width in character columns. */
4680 if (f->scroll_bar_pixel_width > 0)
4681 {
4682 int wid = FONT_WIDTH (f->display.x->font);
4683 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
4684 }
4685 else
4686 f->scroll_bar_cols = 2;
4687
4688 /* Now make the frame display the given font. */
4689 if (FRAME_X_WINDOW (f) != 0)
4690 {
4691 XSetFont (FRAME_X_DISPLAY (f), f->display.x->normal_gc,
4692 f->display.x->font->fid);
4693 XSetFont (FRAME_X_DISPLAY (f), f->display.x->reverse_gc,
4694 f->display.x->font->fid);
4695 XSetFont (FRAME_X_DISPLAY (f), f->display.x->cursor_gc,
4696 f->display.x->font->fid);
4697
4698 frame_update_line_height (f);
4699 x_set_window_size (f, 0, f->width, f->height);
4700 }
4701 else
4702 /* If we are setting a new frame's font for the first time,
4703 there are no faces yet, so this font's height is the line height. */
4704 f->display.x->line_height = FONT_HEIGHT (f->display.x->font);
4705
4706 {
4707 Lisp_Object lispy_name;
4708
4709 lispy_name = build_string (fontname);
4710
4711 /* Free the information from XListFonts. The data
4712 we actually retain comes from XLoadQueryFont. */
4713 XFreeFontNames (font_names);
4714
4715 return lispy_name;
4716 }
4717 }
4718 \f
4719 x_calc_absolute_position (f)
4720 struct frame *f;
4721 {
4722 Window win, child;
4723 int win_x = 0, win_y = 0;
4724 int flags = f->display.x->size_hint_flags;
4725
4726 /* Find the position of the outside upper-left corner of
4727 the inner window, with respect to the outer window. */
4728 if (f->display.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
4729 {
4730 BLOCK_INPUT;
4731 XTranslateCoordinates (FRAME_X_DISPLAY (f),
4732
4733 /* From-window, to-window. */
4734 f->display.x->window_desc,
4735 f->display.x->parent_desc,
4736
4737 /* From-position, to-position. */
4738 0, 0, &win_x, &win_y,
4739
4740 /* Child of win. */
4741 &child);
4742 UNBLOCK_INPUT;
4743 }
4744
4745 /* Treat negative positions as relative to the leftmost bottommost
4746 position that fits on the screen. */
4747 if (flags & XNegative)
4748 f->display.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
4749 - 2 * f->display.x->border_width - win_x
4750 - PIXEL_WIDTH (f)
4751 + f->display.x->left_pos);
4752
4753 if (flags & YNegative)
4754 f->display.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
4755 - 2 * f->display.x->border_width - win_y
4756 - PIXEL_HEIGHT (f)
4757 + f->display.x->top_pos);
4758 /* The left_pos and top_pos
4759 are now relative to the top and left screen edges,
4760 so the flags should correspond. */
4761 f->display.x->size_hint_flags &= ~ (XNegative | YNegative);
4762 }
4763
4764 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
4765 to really change the position, and 0 when calling from
4766 x_make_frame_visible (in that case, XOFF and YOFF are the current
4767 position values). */
4768
4769 x_set_offset (f, xoff, yoff, change_gravity)
4770 struct frame *f;
4771 register int xoff, yoff;
4772 int change_gravity;
4773 {
4774 if (change_gravity)
4775 {
4776 f->display.x->top_pos = yoff;
4777 f->display.x->left_pos = xoff;
4778 f->display.x->size_hint_flags &= ~ (XNegative | YNegative);
4779 if (xoff < 0)
4780 f->display.x->size_hint_flags |= XNegative;
4781 if (yoff < 0)
4782 f->display.x->size_hint_flags |= YNegative;
4783 f->display.x->win_gravity = NorthWestGravity;
4784 }
4785 x_calc_absolute_position (f);
4786
4787 BLOCK_INPUT;
4788 x_wm_set_size_hint (f, 0, 0);
4789
4790 #ifdef USE_X_TOOLKIT
4791 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget),
4792 f->display.x->left_pos, f->display.x->top_pos);
4793 #else /* not USE_X_TOOLKIT */
4794 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4795 f->display.x->left_pos, f->display.x->top_pos);
4796 #endif /* not USE_X_TOOLKIT */
4797 UNBLOCK_INPUT;
4798 }
4799
4800 /* Call this to change the size of frame F's x-window.
4801 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
4802 for this size change and subsequent size changes.
4803 Otherwise we leave the window gravity unchanged. */
4804
4805 x_set_window_size (f, change_gravity, cols, rows)
4806 struct frame *f;
4807 int change_gravity;
4808 int cols, rows;
4809 {
4810 int pixelwidth, pixelheight;
4811 int mask;
4812
4813 #ifdef USE_X_TOOLKIT
4814 BLOCK_INPUT;
4815 {
4816 /* The x and y position of the widget is clobbered by the
4817 call to XtSetValues within EmacsFrameSetCharSize.
4818 This is a real kludge, but I don't understand Xt so I can't
4819 figure out a correct fix. Can anyone else tell me? -- rms. */
4820 int xpos = f->display.x->widget->core.x;
4821 int ypos = f->display.x->widget->core.y;
4822 EmacsFrameSetCharSize (f->display.x->edit_widget, cols, rows);
4823 f->display.x->widget->core.x = xpos;
4824 f->display.x->widget->core.y = ypos;
4825 }
4826 UNBLOCK_INPUT;
4827
4828 #else /* not USE_X_TOOLKIT */
4829
4830 BLOCK_INPUT;
4831
4832 check_frame_size (f, &rows, &cols);
4833 f->display.x->vertical_scroll_bar_extra
4834 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4835 ? 0
4836 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
4837 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
4838 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->display.x->font)));
4839 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4840 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
4841
4842 f->display.x->win_gravity = NorthWestGravity;
4843 x_wm_set_size_hint (f, 0, 0);
4844
4845 XSync (FRAME_X_DISPLAY (f), False);
4846 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4847 pixelwidth, pixelheight);
4848
4849 /* Now, strictly speaking, we can't be sure that this is accurate,
4850 but the window manager will get around to dealing with the size
4851 change request eventually, and we'll hear how it went when the
4852 ConfigureNotify event gets here.
4853
4854 We could just not bother storing any of this information here,
4855 and let the ConfigureNotify event set everything up, but that
4856 might be kind of confusing to the lisp code, since size changes
4857 wouldn't be reported in the frame parameters until some random
4858 point in the future when the ConfigureNotify event arrives. */
4859 change_frame_size (f, rows, cols, 0, 0);
4860 PIXEL_WIDTH (f) = pixelwidth;
4861 PIXEL_HEIGHT (f) = pixelheight;
4862
4863 /* If cursor was outside the new size, mark it as off. */
4864 if (f->phys_cursor_y >= rows
4865 || f->phys_cursor_x >= cols)
4866 {
4867 f->phys_cursor_x = -1;
4868 f->phys_cursor_y = -1;
4869 }
4870
4871 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4872 receive in the ConfigureNotify event; if we get what we asked
4873 for, then the event won't cause the screen to become garbaged, so
4874 we have to make sure to do it here. */
4875 SET_FRAME_GARBAGED (f);
4876
4877 XFlush (FRAME_X_DISPLAY (f));
4878 UNBLOCK_INPUT;
4879 #endif /* not USE_X_TOOLKIT */
4880 }
4881 \f
4882 /* Mouse warping, focus shifting, raising and lowering. */
4883
4884 void
4885 x_set_mouse_position (f, x, y)
4886 struct frame *f;
4887 int x, y;
4888 {
4889 int pix_x, pix_y;
4890
4891 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
4892 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->display.x->line_height / 2;
4893
4894 if (pix_x < 0) pix_x = 0;
4895 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4896
4897 if (pix_y < 0) pix_y = 0;
4898 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
4899
4900 BLOCK_INPUT;
4901
4902 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
4903 0, 0, 0, 0, pix_x, pix_y);
4904 UNBLOCK_INPUT;
4905 }
4906
4907 /* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
4908
4909 void
4910 x_set_mouse_pixel_position (f, pix_x, pix_y)
4911 struct frame *f;
4912 int pix_x, pix_y;
4913 {
4914 BLOCK_INPUT;
4915
4916 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
4917 0, 0, 0, 0, pix_x, pix_y);
4918 UNBLOCK_INPUT;
4919 }
4920
4921 x_focus_on_frame (f)
4922 struct frame *f;
4923 {
4924 #if 0 /* This proves to be unpleasant. */
4925 x_raise_frame (f);
4926 #endif
4927 #if 0
4928 /* I don't think that the ICCCM allows programs to do things like this
4929 without the interaction of the window manager. Whatever you end up
4930 doing with this code, do it to x_unfocus_frame too. */
4931 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4932 RevertToPointerRoot, CurrentTime);
4933 #endif /* ! 0 */
4934 }
4935
4936 x_unfocus_frame (f)
4937 struct frame *f;
4938 {
4939 #if 0
4940 /* Look at the remarks in x_focus_on_frame. */
4941 if (x_focus_frame == f)
4942 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
4943 RevertToPointerRoot, CurrentTime);
4944 #endif /* ! 0 */
4945 }
4946
4947 /* Raise frame F. */
4948
4949 x_raise_frame (f)
4950 struct frame *f;
4951 {
4952 if (f->async_visible)
4953 {
4954 BLOCK_INPUT;
4955 #ifdef USE_X_TOOLKIT
4956 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget));
4957 #else /* not USE_X_TOOLKIT */
4958 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
4959 #endif /* not USE_X_TOOLKIT */
4960 XFlush (FRAME_X_DISPLAY (f));
4961 UNBLOCK_INPUT;
4962 }
4963 }
4964
4965 /* Lower frame F. */
4966
4967 x_lower_frame (f)
4968 struct frame *f;
4969 {
4970 if (f->async_visible)
4971 {
4972 BLOCK_INPUT;
4973 #ifdef USE_X_TOOLKIT
4974 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget));
4975 #else /* not USE_X_TOOLKIT */
4976 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
4977 #endif /* not USE_X_TOOLKIT */
4978 XFlush (FRAME_X_DISPLAY (f));
4979 UNBLOCK_INPUT;
4980 }
4981 }
4982
4983 static void
4984 XTframe_raise_lower (f, raise)
4985 FRAME_PTR f;
4986 int raise;
4987 {
4988 if (raise)
4989 x_raise_frame (f);
4990 else
4991 x_lower_frame (f);
4992 }
4993
4994 /* Change from withdrawn state to mapped state,
4995 or deiconify. */
4996
4997 x_make_frame_visible (f)
4998 struct frame *f;
4999 {
5000 int mask;
5001 Lisp_Object type;
5002
5003 BLOCK_INPUT;
5004
5005 type = x_icon_type (f);
5006 if (!NILP (type))
5007 x_bitmap_icon (f, type);
5008
5009 if (! FRAME_VISIBLE_P (f))
5010 {
5011 #ifndef USE_X_TOOLKIT
5012 if (! FRAME_ICONIFIED_P (f))
5013 x_set_offset (f, f->display.x->left_pos, f->display.x->top_pos, 0);
5014 #endif
5015
5016 if (! EQ (Vx_no_window_manager, Qt))
5017 x_wm_set_window_state (f, NormalState);
5018 #ifdef USE_X_TOOLKIT
5019 /* This was XtPopup, but that did nothing for an iconified frame. */
5020 XtMapWidget (f->display.x->widget);
5021 #else /* not USE_X_TOOLKIT */
5022 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5023 #endif /* not USE_X_TOOLKIT */
5024 #if 0 /* This seems to bring back scroll bars in the wrong places
5025 if the window configuration has changed. They seem
5026 to come back ok without this. */
5027 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5028 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5029 #endif
5030 }
5031
5032 XFlush (FRAME_X_DISPLAY (f));
5033
5034 /* Synchronize to ensure Emacs knows the frame is visible
5035 before we do anything else. We do this loop with input not blocked
5036 so that incoming events are handled. */
5037 {
5038 Lisp_Object frame;
5039 int count = input_signal_count;
5040
5041 /* This must come after we set COUNT. */
5042 UNBLOCK_INPUT;
5043
5044 XSETFRAME (frame, f);
5045
5046 while (1)
5047 {
5048 x_sync (f);
5049 /* Once we have handled input events,
5050 we should have received the MapNotify if one is coming.
5051 So if we have not got it yet, stop looping.
5052 Some window managers make their own decisions
5053 about visibility. */
5054 if (input_signal_count != count)
5055 break;
5056 /* Machines that do polling rather than SIGIO have been observed
5057 to go into a busy-wait here. So we'll fake an alarm signal
5058 to let the handler know that there's something to be read.
5059 We used to raise a real alarm, but it seems that the handler
5060 isn't always enabled here. This is probably a bug. */
5061 if (input_polling_used ())
5062 {
5063 /* It could be confusing if a real alarm arrives while processing
5064 the fake one. Turn it off and let the handler reset it. */
5065 alarm (0);
5066 input_poll_signal ();
5067 }
5068 /* Once we have handled input events,
5069 we should have received the MapNotify if one is coming.
5070 So if we have not got it yet, stop looping.
5071 Some window managers make their own decisions
5072 about visibility. */
5073 if (input_signal_count != count)
5074 break;
5075 }
5076 FRAME_SAMPLE_VISIBILITY (f);
5077 }
5078 }
5079
5080 /* Change from mapped state to withdrawn state. */
5081
5082 x_make_frame_invisible (f)
5083 struct frame *f;
5084 {
5085 int mask;
5086 Window window;
5087
5088 #ifdef USE_X_TOOLKIT
5089 /* Use the frame's outermost window, not the one we normally draw on. */
5090 window = XtWindow (f->display.x->widget);
5091 #else /* not USE_X_TOOLKIT */
5092 window = FRAME_X_WINDOW (f);
5093 #endif /* not USE_X_TOOLKIT */
5094
5095 /* Don't keep the highlight on an invisible frame. */
5096 if (x_highlight_frame == f)
5097 x_highlight_frame = 0;
5098
5099 #if 0/* This might add unreliability; I don't trust it -- rms. */
5100 if (! f->async_visible && ! f->async_iconified)
5101 return;
5102 #endif
5103
5104 BLOCK_INPUT;
5105
5106 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
5107 that the current position of the window is user-specified, rather than
5108 program-specified, so that when the window is mapped again, it will be
5109 placed at the same location, without forcing the user to position it
5110 by hand again (they have already done that once for this window.) */
5111 x_wm_set_size_hint (f, 0, 1);
5112
5113 #ifdef HAVE_X11R4
5114
5115 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
5116 DefaultScreen (FRAME_X_DISPLAY (f))))
5117 {
5118 UNBLOCK_INPUT_RESIGNAL;
5119 error ("Can't notify window manager of window withdrawal");
5120 }
5121 #else /* ! defined (HAVE_X11R4) */
5122
5123 /* Tell the window manager what we're going to do. */
5124 if (! EQ (Vx_no_window_manager, Qt))
5125 {
5126 XEvent unmap;
5127
5128 unmap.xunmap.type = UnmapNotify;
5129 unmap.xunmap.window = window;
5130 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
5131 unmap.xunmap.from_configure = False;
5132 if (! XSendEvent (FRAME_X_DISPLAY (f),
5133 DefaultRootWindow (FRAME_X_DISPLAY (f)),
5134 False,
5135 SubstructureRedirectMask|SubstructureNotifyMask,
5136 &unmap))
5137 {
5138 UNBLOCK_INPUT_RESIGNAL;
5139 error ("Can't notify window manager of withdrawal");
5140 }
5141 }
5142
5143 /* Unmap the window ourselves. Cheeky! */
5144 XUnmapWindow (FRAME_X_DISPLAY (f), window);
5145 #endif /* ! defined (HAVE_X11R4) */
5146
5147 /* We can't distinguish this from iconification
5148 just by the event that we get from the server.
5149 So we can't win using the usual strategy of letting
5150 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
5151 and synchronize with the server to make sure we agree. */
5152 f->visible = 0;
5153 FRAME_ICONIFIED_P (f) = 0;
5154 f->async_visible = 0;
5155 f->async_iconified = 0;
5156
5157 x_sync (f);
5158
5159 UNBLOCK_INPUT;
5160 }
5161
5162 /* Change window state from mapped to iconified. */
5163
5164 x_iconify_frame (f)
5165 struct frame *f;
5166 {
5167 int mask;
5168 int result;
5169 Lisp_Object type;
5170
5171 /* Don't keep the highlight on an invisible frame. */
5172 if (x_highlight_frame == f)
5173 x_highlight_frame = 0;
5174
5175 if (f->async_iconified)
5176 return;
5177
5178 BLOCK_INPUT;
5179
5180 type = x_icon_type (f);
5181 if (!NILP (type))
5182 x_bitmap_icon (f, type);
5183
5184 #ifdef USE_X_TOOLKIT
5185
5186 if (! FRAME_VISIBLE_P (f))
5187 {
5188 if (! EQ (Vx_no_window_manager, Qt))
5189 x_wm_set_window_state (f, IconicState);
5190 /* This was XtPopup, but that did nothing for an iconified frame. */
5191 XtMapWidget (f->display.x->widget);
5192 UNBLOCK_INPUT;
5193 return;
5194 }
5195
5196 result = XIconifyWindow (FRAME_X_DISPLAY (f),
5197 XtWindow (f->display.x->widget),
5198 DefaultScreen (FRAME_X_DISPLAY (f)));
5199 UNBLOCK_INPUT;
5200
5201 if (!result)
5202 error ("Can't notify window manager of iconification");
5203
5204 f->async_iconified = 1;
5205
5206 BLOCK_INPUT;
5207 XFlush (FRAME_X_DISPLAY (f));
5208 UNBLOCK_INPUT;
5209 #else /* not USE_X_TOOLKIT */
5210
5211 /* Make sure the X server knows where the window should be positioned,
5212 in case the user deiconifies with the window manager. */
5213 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
5214 x_set_offset (f, f->display.x->left_pos, f->display.x->top_pos, 0);
5215
5216 /* Since we don't know which revision of X we're running, we'll use both
5217 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
5218
5219 /* X11R4: send a ClientMessage to the window manager using the
5220 WM_CHANGE_STATE type. */
5221 {
5222 XEvent message;
5223
5224 message.xclient.window = FRAME_X_WINDOW (f);
5225 message.xclient.type = ClientMessage;
5226 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
5227 message.xclient.format = 32;
5228 message.xclient.data.l[0] = IconicState;
5229
5230 if (! XSendEvent (FRAME_X_DISPLAY (f),
5231 DefaultRootWindow (FRAME_X_DISPLAY (f)),
5232 False,
5233 SubstructureRedirectMask | SubstructureNotifyMask,
5234 &message))
5235 {
5236 UNBLOCK_INPUT_RESIGNAL;
5237 error ("Can't notify window manager of iconification");
5238 }
5239 }
5240
5241 /* X11R3: set the initial_state field of the window manager hints to
5242 IconicState. */
5243 x_wm_set_window_state (f, IconicState);
5244
5245 if (!FRAME_VISIBLE_P (f))
5246 {
5247 /* If the frame was withdrawn, before, we must map it. */
5248 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5249 }
5250
5251 f->async_iconified = 1;
5252
5253 XFlush (FRAME_X_DISPLAY (f));
5254 UNBLOCK_INPUT;
5255 #endif /* not USE_X_TOOLKIT */
5256 }
5257
5258 /* Destroy the X window of frame F. */
5259
5260 x_destroy_window (f)
5261 struct frame *f;
5262 {
5263 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5264
5265 BLOCK_INPUT;
5266
5267 if (f->display.x->icon_desc != 0)
5268 XDestroyWindow (FRAME_X_DISPLAY (f), f->display.x->icon_desc);
5269 XDestroyWindow (FRAME_X_DISPLAY (f), f->display.x->window_desc);
5270 #ifdef USE_X_TOOLKIT
5271 XtDestroyWidget (f->display.x->widget);
5272 free_frame_menubar (f);
5273 #endif /* USE_X_TOOLKIT */
5274
5275 free_frame_faces (f);
5276 XFlush (FRAME_X_DISPLAY (f));
5277
5278 xfree (f->display.x);
5279 f->display.x = 0;
5280 if (f == x_focus_frame)
5281 x_focus_frame = 0;
5282 if (f == x_highlight_frame)
5283 x_highlight_frame = 0;
5284
5285 dpyinfo->reference_count--;
5286
5287 if (f == dpyinfo->mouse_face_mouse_frame)
5288 {
5289 dpyinfo->mouse_face_beg_row
5290 = dpyinfo->mouse_face_beg_col = -1;
5291 dpyinfo->mouse_face_end_row
5292 = dpyinfo->mouse_face_end_col = -1;
5293 dpyinfo->mouse_face_window = Qnil;
5294 }
5295
5296 UNBLOCK_INPUT;
5297 }
5298 \f
5299 /* Setting window manager hints. */
5300
5301 /* Set the normal size hints for the window manager, for frame F.
5302 FLAGS is the flags word to use--or 0 meaning preserve the flags
5303 that the window now has.
5304 If USER_POSITION is nonzero, we set the USPosition
5305 flag (this is useful when FLAGS is 0). */
5306
5307 x_wm_set_size_hint (f, flags, user_position)
5308 struct frame *f;
5309 long flags;
5310 int user_position;
5311 {
5312 XSizeHints size_hints;
5313
5314 #ifdef USE_X_TOOLKIT
5315 Arg al[2];
5316 int ac = 0;
5317 Dimension widget_width, widget_height;
5318 Window window = XtWindow (f->display.x->widget);
5319 #else /* not USE_X_TOOLKIT */
5320 Window window = FRAME_X_WINDOW (f);
5321 #endif /* not USE_X_TOOLKIT */
5322
5323 /* Setting PMaxSize caused various problems. */
5324 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
5325
5326 flexlines = f->height;
5327
5328 size_hints.x = f->display.x->left_pos;
5329 size_hints.y = f->display.x->top_pos;
5330
5331 #ifdef USE_X_TOOLKIT
5332 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
5333 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
5334 XtGetValues (f->display.x->column_widget, al, ac);
5335 size_hints.height = widget_height;
5336 size_hints.width = widget_width;
5337 #else /* not USE_X_TOOLKIT */
5338 size_hints.height = PIXEL_HEIGHT (f);
5339 size_hints.width = PIXEL_WIDTH (f);
5340 #endif /* not USE_X_TOOLKIT */
5341
5342 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
5343 size_hints.height_inc = f->display.x->line_height;
5344 size_hints.max_width
5345 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
5346 size_hints.max_height
5347 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
5348
5349 {
5350 int base_width, base_height;
5351 int min_rows = 0, min_cols = 0;
5352
5353 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
5354 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
5355
5356 check_frame_size (f, &min_rows, &min_cols);
5357
5358 /* The window manager uses the base width hints to calculate the
5359 current number of rows and columns in the frame while
5360 resizing; min_width and min_height aren't useful for this
5361 purpose, since they might not give the dimensions for a
5362 zero-row, zero-column frame.
5363
5364 We use the base_width and base_height members if we have
5365 them; otherwise, we set the min_width and min_height members
5366 to the size for a zero x zero frame. */
5367
5368 #ifdef HAVE_X11R4
5369 size_hints.flags |= PBaseSize;
5370 size_hints.base_width = base_width;
5371 size_hints.base_height = base_height;
5372 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
5373 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
5374 #else
5375 size_hints.min_width = base_width;
5376 size_hints.min_height = base_height;
5377 #endif
5378 }
5379
5380 if (flags)
5381 size_hints.flags |= flags;
5382 else
5383 {
5384 XSizeHints hints; /* Sometimes I hate X Windows... */
5385 long supplied_return;
5386 int value;
5387
5388 #ifdef HAVE_X11R4
5389 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
5390 &supplied_return);
5391 #else
5392 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
5393 #endif
5394
5395 if (value == 0)
5396 hints.flags = 0;
5397 if (hints.flags & PSize)
5398 size_hints.flags |= PSize;
5399 if (hints.flags & PPosition)
5400 size_hints.flags |= PPosition;
5401 if (hints.flags & USPosition)
5402 size_hints.flags |= USPosition;
5403 if (hints.flags & USSize)
5404 size_hints.flags |= USSize;
5405 }
5406
5407 #ifdef PWinGravity
5408 size_hints.win_gravity = f->display.x->win_gravity;
5409 size_hints.flags |= PWinGravity;
5410
5411 if (user_position)
5412 {
5413 size_hints.flags &= ~ PPosition;
5414 size_hints.flags |= USPosition;
5415 }
5416 #endif /* PWinGravity */
5417
5418 #ifdef HAVE_X11R4
5419 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
5420 #else
5421 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
5422 #endif
5423 }
5424
5425 /* Used for IconicState or NormalState */
5426 x_wm_set_window_state (f, state)
5427 struct frame *f;
5428 int state;
5429 {
5430 #ifdef USE_X_TOOLKIT
5431 Arg al[1];
5432
5433 XtSetArg (al[0], XtNinitialState, state);
5434 XtSetValues (f->display.x->widget, al, 1);
5435 #else /* not USE_X_TOOLKIT */
5436 Window window = FRAME_X_WINDOW (f);
5437
5438 f->display.x->wm_hints.flags |= StateHint;
5439 f->display.x->wm_hints.initial_state = state;
5440
5441 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
5442 #endif /* not USE_X_TOOLKIT */
5443 }
5444
5445 x_wm_set_icon_pixmap (f, pixmap_id)
5446 struct frame *f;
5447 int pixmap_id;
5448 {
5449 #ifdef USE_X_TOOLKIT
5450 Window window = XtWindow (f->display.x->widget);
5451 #else
5452 Window window = FRAME_X_WINDOW (f);
5453 #endif
5454
5455 if (pixmap_id > 0)
5456 {
5457 Pixmap icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
5458 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
5459 f->display.x->wm_hints.flags |= IconPixmapHint;
5460 }
5461 else
5462 {
5463 f->display.x->wm_hints.icon_pixmap = None;
5464 f->display.x->wm_hints.flags &= ~IconPixmapHint;
5465 }
5466
5467 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
5468 }
5469
5470 x_wm_set_icon_position (f, icon_x, icon_y)
5471 struct frame *f;
5472 int icon_x, icon_y;
5473 {
5474 #ifdef USE_X_TOOLKIT
5475 Window window = XtWindow (f->display.x->widget);
5476 #else
5477 Window window = FRAME_X_WINDOW (f);
5478 #endif
5479
5480 f->display.x->wm_hints.flags |= IconPositionHint;
5481 f->display.x->wm_hints.icon_x = icon_x;
5482 f->display.x->wm_hints.icon_y = icon_y;
5483
5484 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
5485 }
5486
5487 \f
5488 /* Initialization. */
5489
5490 #ifdef USE_X_TOOLKIT
5491 static XrmOptionDescRec emacs_options[] = {
5492 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
5493 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
5494
5495 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
5496 XrmoptionSepArg, NULL},
5497 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
5498
5499 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5500 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5501 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5502 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5503 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5504 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
5505 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
5506 };
5507 #endif /* USE_X_TOOLKIT */
5508
5509 static int x_initialized;
5510
5511 struct x_display_info *
5512 x_term_init (display_name, xrm_option, resource_name)
5513 Lisp_Object display_name;
5514 char *xrm_option;
5515 char *resource_name;
5516 {
5517 Lisp_Object frame;
5518 char *defaultvalue;
5519 int connection;
5520 Display *dpy;
5521 struct x_display_info *dpyinfo;
5522 XrmDatabase xrdb;
5523
5524 if (!x_initialized)
5525 {
5526 x_initialize ();
5527 x_initialized = 1;
5528 }
5529
5530 #ifdef USE_X_TOOLKIT
5531 #ifdef HAVE_X11R5
5532 XtSetLanguageProc (NULL, NULL, NULL);
5533 #endif
5534
5535 {
5536 int argc = 0;
5537 char *argv[3];
5538
5539 argv[0] = "";
5540 argc = 1;
5541 if (xrm_option)
5542 {
5543 argv[argc++] = "-xrm";
5544 argv[argc++] = xrm_option;
5545 }
5546 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
5547 resource_name, EMACS_CLASS,
5548 emacs_options, XtNumber (emacs_options),
5549 &argc, argv);
5550 }
5551
5552 #else /* not USE_X_TOOLKIT */
5553 #ifdef HAVE_X11R5
5554 XSetLocaleModifiers ("");
5555 #endif
5556 dpy = XOpenDisplay (XSTRING (display_name)->data);
5557 #endif /* not USE_X_TOOLKIT */
5558
5559 /* Detect failure. */
5560 if (dpy == 0)
5561 return 0;
5562
5563 /* We have definitely succeeded. Record the new connection. */
5564
5565 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
5566
5567 /* Put this display on the chain. */
5568 dpyinfo->next = x_display_list;
5569 x_display_list = dpyinfo;
5570
5571 /* Put it on x_display_name_list as well, to keep them parallel. */
5572 x_display_name_list = Fcons (Fcons (display_name, Qnil),
5573 x_display_name_list);
5574 dpyinfo->name_list_element = XCONS (x_display_name_list)->car;
5575
5576 dpyinfo->display = dpy;
5577
5578 #if 0
5579 XSetAfterFunction (x_current_display, x_trace_wire);
5580 #endif /* ! 0 */
5581
5582 dpyinfo->x_id_name
5583 = (char *) xmalloc (XSTRING (Vinvocation_name)->size
5584 + XSTRING (Vsystem_name)->size
5585 + 2);
5586 sprintf (dpyinfo->x_id_name, "%s@%s",
5587 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
5588
5589 /* Figure out which modifier bits mean what. */
5590 x_find_modifier_meanings (dpyinfo);
5591
5592 /* Get the scroll bar cursor. */
5593 dpyinfo->vertical_scroll_bar_cursor
5594 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
5595
5596 xrdb = x_load_resources (dpyinfo->display, xrm_option,
5597 resource_name, EMACS_CLASS);
5598 #ifdef HAVE_XRMSETDATABASE
5599 XrmSetDatabase (dpyinfo->display, xrdb);
5600 #else
5601 dpyinfo->display->db = xrdb;
5602 #endif
5603 /* Put thr rdb where we can find it in a way that works on
5604 all versions. */
5605 dpyinfo->xrdb = xrdb;
5606
5607 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
5608 DefaultScreen (dpyinfo->display));
5609 dpyinfo->visual = select_visual (dpyinfo->display, dpyinfo->screen,
5610 &dpyinfo->n_planes);
5611 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
5612 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
5613 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
5614 dpyinfo->grabbed = 0;
5615 dpyinfo->reference_count = 0;
5616 dpyinfo->icon_bitmap_id = -1;
5617 dpyinfo->n_fonts = 0;
5618 dpyinfo->font_table_size = 0;
5619 dpyinfo->bitmaps = 0;
5620 dpyinfo->bitmaps_size = 0;
5621 dpyinfo->bitmaps_last = 0;
5622 dpyinfo->scratch_cursor_gc = 0;
5623 dpyinfo->mouse_face_mouse_frame = 0;
5624 dpyinfo->mouse_face_deferred_gc = 0;
5625 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
5626 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
5627 dpyinfo->mouse_face_face_id = 0;
5628 dpyinfo->mouse_face_window = Qnil;
5629 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
5630 dpyinfo->mouse_face_defer = 0;
5631
5632 dpyinfo->Xatom_wm_protocols
5633 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
5634 dpyinfo->Xatom_wm_take_focus
5635 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
5636 dpyinfo->Xatom_wm_save_yourself
5637 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
5638 dpyinfo->Xatom_wm_delete_window
5639 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
5640 dpyinfo->Xatom_wm_change_state
5641 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
5642 dpyinfo->Xatom_wm_configure_denied
5643 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
5644 dpyinfo->Xatom_wm_window_moved
5645 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
5646 dpyinfo->Xatom_editres
5647 = XInternAtom (dpyinfo->display, "Editres", False);
5648 dpyinfo->Xatom_CLIPBOARD
5649 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
5650 dpyinfo->Xatom_TIMESTAMP
5651 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
5652 dpyinfo->Xatom_TEXT
5653 = XInternAtom (dpyinfo->display, "TEXT", False);
5654 dpyinfo->Xatom_DELETE
5655 = XInternAtom (dpyinfo->display, "DELETE", False);
5656 dpyinfo->Xatom_MULTIPLE
5657 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
5658 dpyinfo->Xatom_INCR
5659 = XInternAtom (dpyinfo->display, "INCR", False);
5660 dpyinfo->Xatom_EMACS_TMP
5661 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
5662 dpyinfo->Xatom_TARGETS
5663 = XInternAtom (dpyinfo->display, "TARGETS", False);
5664 dpyinfo->Xatom_NULL
5665 = XInternAtom (dpyinfo->display, "NULL", False);
5666 dpyinfo->Xatom_ATOM_PAIR
5667 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
5668
5669 connection = ConnectionNumber (dpyinfo->display);
5670 dpyinfo->connection = connection;
5671
5672 #ifdef subprocesses
5673 /* This is only needed for distinguishing keyboard and process input. */
5674 if (connection != 0)
5675 add_keyboard_wait_descriptor (connection);
5676 #endif
5677
5678 #ifndef F_SETOWN_BUG
5679 #ifdef F_SETOWN
5680 #ifdef F_SETOWN_SOCK_NEG
5681 /* stdin is a socket here */
5682 fcntl (connection, F_SETOWN, -getpid ());
5683 #else /* ! defined (F_SETOWN_SOCK_NEG) */
5684 fcntl (connection, F_SETOWN, getpid ());
5685 #endif /* ! defined (F_SETOWN_SOCK_NEG) */
5686 #endif /* ! defined (F_SETOWN) */
5687 #endif /* F_SETOWN_BUG */
5688
5689 #ifdef SIGIO
5690 init_sigio (connection);
5691 #endif /* ! defined (SIGIO) */
5692
5693 return dpyinfo;
5694 }
5695 \f
5696 /* Get rid of display DPYINFO, assuming all frames are already gone,
5697 and without sending any more commands to the X server. */
5698
5699 void
5700 x_delete_display (dpyinfo)
5701 struct x_display_info *dpyinfo;
5702 {
5703 delete_keyboard_wait_descriptor (dpyinfo->connection);
5704
5705 /* Discard this display from x_display_name_list and x_display_list.
5706 We can't use Fdelq because that can quit. */
5707 if (! NILP (x_display_name_list)
5708 && EQ (XCONS (x_display_name_list)->car, dpyinfo->name_list_element))
5709 x_display_name_list = XCONS (x_display_name_list)->cdr;
5710 else
5711 {
5712 Lisp_Object tail;
5713
5714 tail = x_display_name_list;
5715 while (CONSP (tail) && CONSP (XCONS (tail)->cdr))
5716 {
5717 if (EQ (XCONS (XCONS (tail)->cdr)->car,
5718 dpyinfo->name_list_element))
5719 {
5720 XCONS (tail)->cdr = XCONS (XCONS (tail)->cdr)->cdr;
5721 break;
5722 }
5723 tail = XCONS (tail)->cdr;
5724 }
5725 }
5726
5727 if (x_display_list == dpyinfo)
5728 x_display_list = dpyinfo->next;
5729 else
5730 {
5731 struct x_display_info *tail;
5732
5733 for (tail = x_display_list; tail; tail = tail->next)
5734 if (tail->next == dpyinfo)
5735 tail->next = tail->next->next;
5736 }
5737
5738 #ifndef USE_X_TOOLKIT
5739 /* I'm told Xt does this itself. */
5740 XrmDestroyDatabase (dpyinfo->xrdb);
5741 #endif
5742 free (dpyinfo->font_table);
5743 free (dpyinfo->x_id_name);
5744 free (dpyinfo);
5745 }
5746 \f
5747 /* Set up use of X before we make the first connection. */
5748
5749 x_initialize ()
5750 {
5751 clear_frame_hook = XTclear_frame;
5752 clear_end_of_line_hook = XTclear_end_of_line;
5753 ins_del_lines_hook = XTins_del_lines;
5754 change_line_highlight_hook = XTchange_line_highlight;
5755 insert_glyphs_hook = XTinsert_glyphs;
5756 write_glyphs_hook = XTwrite_glyphs;
5757 delete_glyphs_hook = XTdelete_glyphs;
5758 ring_bell_hook = XTring_bell;
5759 reset_terminal_modes_hook = XTreset_terminal_modes;
5760 set_terminal_modes_hook = XTset_terminal_modes;
5761 update_begin_hook = XTupdate_begin;
5762 update_end_hook = XTupdate_end;
5763 set_terminal_window_hook = XTset_terminal_window;
5764 read_socket_hook = XTread_socket;
5765 frame_up_to_date_hook = XTframe_up_to_date;
5766 cursor_to_hook = XTcursor_to;
5767 reassert_line_highlight_hook = XTreassert_line_highlight;
5768 mouse_position_hook = XTmouse_position;
5769 frame_rehighlight_hook = XTframe_rehighlight;
5770 frame_raise_lower_hook = XTframe_raise_lower;
5771 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
5772 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
5773 redeem_scroll_bar_hook = XTredeem_scroll_bar;
5774 judge_scroll_bars_hook = XTjudge_scroll_bars;
5775
5776 scroll_region_ok = 1; /* we'll scroll partial frames */
5777 char_ins_del_ok = 0; /* just as fast to write the line */
5778 line_ins_del_ok = 1; /* we'll just blt 'em */
5779 fast_clear_end_of_line = 1; /* X does this well */
5780 memory_below_frame = 0; /* we don't remember what scrolls
5781 off the bottom */
5782 baud_rate = 19200;
5783
5784 x_noop_count = 0;
5785
5786 x_focus_frame = x_highlight_frame = 0;
5787
5788 /* Try to use interrupt input; if we can't, then start polling. */
5789 Fset_input_mode (Qt, Qnil, Qt, Qnil);
5790
5791 #ifdef USE_X_TOOLKIT
5792 XtToolkitInitialize ();
5793 Xt_app_con = XtCreateApplicationContext ();
5794 #endif
5795
5796 /* Note that there is no real way portable across R3/R4 to get the
5797 original error handler. */
5798 XSetErrorHandler (x_error_quitter);
5799 XSetIOErrorHandler (x_io_error_quitter);
5800
5801 /* Disable Window Change signals; they are handled by X events. */
5802 #ifdef SIGWINCH
5803 signal (SIGWINCH, SIG_DFL);
5804 #endif /* ! defined (SIGWINCH) */
5805
5806 signal (SIGPIPE, x_connection_closed);
5807 }
5808
5809 void
5810 syms_of_xterm ()
5811 {
5812 staticpro (&x_display_name_list);
5813 x_display_name_list = Qnil;
5814
5815 staticpro (&last_mouse_scroll_bar);
5816 last_mouse_scroll_bar = Qnil;
5817 }
5818 #endif /* ! defined (HAVE_X_WINDOWS) */