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