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