1 /* X Communication module for terminals which understand the X protocol.
2
3 Copyright (C) 1989, 1993-2021 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20 /* New display code by Gerd Moellmann <gerd@gnu.org>. */
21 /* Xt features made by Fred Pierresteguy. */
22
23 #include <config.h>
24 #include <stdlib.h>
25 #include <math.h>
26
27 #include "lisp.h"
28 #include "blockinput.h"
29 #include "sysstdio.h"
30
31 /* This may include sys/types.h, and that somehow loses
32 if this is not done before the other system files. */
33 #include "xterm.h"
34 #include <X11/cursorfont.h>
35
36 /* If we have Xfixes extension, use it for pointer blanking. */
37 #ifdef HAVE_XFIXES
38 #include <X11/extensions/Xfixes.h>
39 #endif
40
41 #ifdef HAVE_XDBE
42 #include <X11/extensions/Xdbe.h>
43 #endif
44
45 /* Load sys/types.h if not already loaded.
46 In some systems loading it twice is suicidal. */
47 #ifndef makedev
48 #include <sys/types.h>
49 #endif /* makedev */
50
51 #include <sys/ioctl.h>
52
53 #include "systime.h"
54
55 #include <fcntl.h>
56 #include <errno.h>
57 #include <sys/stat.h>
58 #include "character.h"
59 #include "coding.h"
60 #include "composite.h"
61 #include "frame.h"
62 #include "dispextern.h"
63 #include "xwidget.h"
64 #include "fontset.h"
65 #include "termhooks.h"
66 #include "termopts.h"
67 #include "termchar.h"
68 #include "emacs-icon.h"
69 #include "buffer.h"
70 #include "window.h"
71 #include "keyboard.h"
72 #include "atimer.h"
73 #include "font.h"
74 #include "xsettings.h"
75 #include "sysselect.h"
76 #include "menu.h"
77 #include "pdumper.h"
78
79 #ifdef USE_X_TOOLKIT
80 #include <X11/Shell.h>
81 #endif
82
83 #include <unistd.h>
84
85 #ifdef USE_GTK
86 #include "gtkutil.h"
87 #ifdef HAVE_GTK3
88 #include <X11/Xproto.h>
89 #endif
90 #endif
91
92 #if defined (USE_LUCID) || defined (USE_MOTIF)
93 #include "../lwlib/xlwmenu.h"
94 #endif
95
96 #ifdef USE_X_TOOLKIT
97
98 /* Include toolkit specific headers for the scroll bar widget. */
99
100 #ifdef USE_TOOLKIT_SCROLL_BARS
101 #if defined USE_MOTIF
102 #include <Xm/Xm.h> /* For LESSTIF_VERSION */
103 #include <Xm/ScrollBar.h>
104 #else /* !USE_MOTIF i.e. use Xaw */
105
106 #ifdef HAVE_XAW3D
107 #include <X11/Xaw3d/Simple.h>
108 #include <X11/Xaw3d/Scrollbar.h>
109 #include <X11/Xaw3d/ThreeD.h>
110 #else /* !HAVE_XAW3D */
111 #include <X11/Xaw/Simple.h>
112 #include <X11/Xaw/Scrollbar.h>
113 #endif /* !HAVE_XAW3D */
114 #ifndef XtNpickTop
115 #define XtNpickTop "pickTop"
116 #endif /* !XtNpickTop */
117 #endif /* !USE_MOTIF */
118 #endif /* USE_TOOLKIT_SCROLL_BARS */
119
120 #endif /* USE_X_TOOLKIT */
121
122 #ifdef USE_X_TOOLKIT
123 #include "widget.h"
124 #ifndef XtNinitialState
125 #define XtNinitialState "initialState"
126 #endif
127 #endif
128
129 #include "bitmaps/gray.xbm"
130
131 #ifdef HAVE_XKB
132 #include <X11/XKBlib.h>
133 #endif
134
135 /* Default to using XIM if available. */
136 #ifdef USE_XIM
137 bool use_xim = true;
138 #else
139 bool use_xim = false; /* configure --without-xim */
140 #endif
141
142 /* Non-zero means that a HELP_EVENT has been generated since Emacs
143 start. */
144
145 static bool any_help_event_p;
146
147 /* This is a chain of structures for all the X displays currently in
148 use. */
149
150 struct x_display_info *x_display_list;
151
152 #ifdef USE_X_TOOLKIT
153
154 /* The application context for Xt use. */
155 XtAppContext Xt_app_con;
156 static String Xt_default_resources[] = {0};
157
158 /* Non-zero means user is interacting with a toolkit scroll bar. */
159 static bool toolkit_scroll_bar_interaction;
160
161 #endif /* USE_X_TOOLKIT */
162
163 /* Non-zero timeout value means ignore next mouse click if it arrives
164 before that timeout elapses (i.e. as part of the same sequence of
165 events resulting from clicking on a frame to select it). */
166
167 static Time ignore_next_mouse_click_timeout;
168
169 /* Used locally within XTread_socket. */
170
171 static int x_noop_count;
172
173 #ifdef USE_GTK
174 /* The name of the Emacs icon file. */
175 static Lisp_Object xg_default_icon_file;
176 #endif
177
178 /* Some functions take this as char *, not const char *. */
179 static char emacs_class[] = EMACS_CLASS;
180
181 enum xembed_info
182 {
183 XEMBED_MAPPED = 1 << 0
184 };
185
186 enum xembed_message
187 {
188 XEMBED_EMBEDDED_NOTIFY = 0,
189 XEMBED_WINDOW_ACTIVATE = 1,
190 XEMBED_WINDOW_DEACTIVATE = 2,
191 XEMBED_REQUEST_FOCUS = 3,
192 XEMBED_FOCUS_IN = 4,
193 XEMBED_FOCUS_OUT = 5,
194 XEMBED_FOCUS_NEXT = 6,
195 XEMBED_FOCUS_PREV = 7,
196
197 XEMBED_MODALITY_ON = 10,
198 XEMBED_MODALITY_OFF = 11,
199 XEMBED_REGISTER_ACCELERATOR = 12,
200 XEMBED_UNREGISTER_ACCELERATOR = 13,
201 XEMBED_ACTIVATE_ACCELERATOR = 14
202 };
203
204 static bool x_alloc_nearest_color_1 (Display *, Colormap, XColor *);
205 static void x_raise_frame (struct frame *);
206 static void x_lower_frame (struct frame *);
207 static int x_io_error_quitter (Display *);
208 static struct terminal *x_create_terminal (struct x_display_info *);
209 static void x_frame_rehighlight (struct x_display_info *);
210
211 static void x_clip_to_row (struct window *, struct glyph_row *,
212 enum glyph_row_area, GC);
213 static struct scroll_bar *x_window_to_scroll_bar (Display *, Window, int);
214 static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *,
215 enum scroll_bar_part *,
216 Lisp_Object *, Lisp_Object *,
217 Time *);
218 static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object *,
219 enum scroll_bar_part *,
220 Lisp_Object *, Lisp_Object *,
221 Time *);
222 static bool x_handle_net_wm_state (struct frame *, const XPropertyEvent *);
223 static void x_check_fullscreen (struct frame *);
224 static void x_check_expected_move (struct frame *, int, int);
225 static void x_sync_with_move (struct frame *, int, int, bool);
226 static int handle_one_xevent (struct x_display_info *,
227 const XEvent *, int *,
228 struct input_event *);
229 #if ! (defined USE_X_TOOLKIT || defined USE_MOTIF) && defined USE_GTK
230 static int x_dispatch_event (XEvent *, Display *);
231 #endif
232 static void x_wm_set_window_state (struct frame *, int);
233 static void x_wm_set_icon_pixmap (struct frame *, ptrdiff_t);
234 static void x_initialize (void);
235
236 static bool x_get_current_wm_state (struct frame *, Window, int *, bool *);
237
238 /* Flush display of frame F. */
239
240 static void
x_flush(struct frame * f)241 x_flush (struct frame *f)
242 {
243 eassert (f && FRAME_X_P (f));
244 /* Don't call XFlush when it is not safe to redisplay; the X
245 connection may be broken. */
246 if (!NILP (Vinhibit_redisplay))
247 return;
248
249 block_input ();
250 XFlush (FRAME_X_DISPLAY (f));
251 unblock_input ();
252 }
253
254
255 /* Remove calls to XFlush by defining XFlush to an empty replacement.
256 Calls to XFlush should be unnecessary because the X output buffer
257 is flushed automatically as needed by calls to XPending,
258 XNextEvent, or XWindowEvent according to the XFlush man page.
259 XTread_socket calls XPending. Removing XFlush improves
260 performance. */
261
262 #define XFlush(DISPLAY) (void) 0
263
264
265 /***********************************************************************
266 Debugging
267 ***********************************************************************/
268
269 #if false
270
271 /* This is a function useful for recording debugging information about
272 the sequence of occurrences in this file. */
273
274 struct record
275 {
276 char *locus;
277 int type;
278 };
279
280 struct record event_record[100];
281
282 int event_record_index;
283
284 void
record_event(char * locus,int type)285 record_event (char *locus, int type)
286 {
287 if (event_record_index == ARRAYELTS (event_record))
288 event_record_index = 0;
289
290 event_record[event_record_index].locus = locus;
291 event_record[event_record_index].type = type;
292 event_record_index++;
293 }
294
295 #endif
296
297 #ifdef USE_CAIRO
298
299 #define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context)
300 #define FRAME_CR_SURFACE_DESIRED_WIDTH(f) \
301 ((f)->output_data.x->cr_surface_desired_width)
302 #define FRAME_CR_SURFACE_DESIRED_HEIGHT(f) \
303 ((f)->output_data.x->cr_surface_desired_height)
304
305 static struct x_gc_ext_data *
x_gc_get_ext_data(struct frame * f,GC gc,int create_if_not_found_p)306 x_gc_get_ext_data (struct frame *f, GC gc, int create_if_not_found_p)
307 {
308 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
309 XEDataObject object;
310 XExtData **head, *ext_data;
311
312 object.gc = gc;
313 head = XEHeadOfExtensionList (object);
314 ext_data = XFindOnExtensionList (head, dpyinfo->ext_codes->extension);
315 if (ext_data == NULL)
316 {
317 if (!create_if_not_found_p)
318 return NULL;
319 else
320 {
321 ext_data = xzalloc (sizeof (*ext_data));
322 ext_data->number = dpyinfo->ext_codes->extension;
323 ext_data->private_data = xzalloc (sizeof (struct x_gc_ext_data));
324 XAddToExtensionList (head, ext_data);
325 }
326 }
327 return (struct x_gc_ext_data *) ext_data->private_data;
328 }
329
330 static void
x_extension_initialize(struct x_display_info * dpyinfo)331 x_extension_initialize (struct x_display_info *dpyinfo)
332 {
333 XExtCodes *ext_codes = XAddExtension (dpyinfo->display);
334
335 dpyinfo->ext_codes = ext_codes;
336 }
337
338 void
x_cr_destroy_frame_context(struct frame * f)339 x_cr_destroy_frame_context (struct frame *f)
340 {
341 if (FRAME_CR_CONTEXT (f))
342 {
343 cairo_destroy (FRAME_CR_CONTEXT (f));
344 FRAME_CR_CONTEXT (f) = NULL;
345 }
346 }
347
348 void
x_cr_update_surface_desired_size(struct frame * f,int width,int height)349 x_cr_update_surface_desired_size (struct frame *f, int width, int height)
350 {
351 if (FRAME_CR_SURFACE_DESIRED_WIDTH (f) != width
352 || FRAME_CR_SURFACE_DESIRED_HEIGHT (f) != height)
353 {
354 x_cr_destroy_frame_context (f);
355 FRAME_CR_SURFACE_DESIRED_WIDTH (f) = width;
356 FRAME_CR_SURFACE_DESIRED_HEIGHT (f) = height;
357 }
358 }
359
360 static void
x_cr_gc_clip(cairo_t * cr,struct frame * f,GC gc)361 x_cr_gc_clip (cairo_t *cr, struct frame *f, GC gc)
362 {
363 if (gc)
364 {
365 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
366
367 if (gc_ext && gc_ext->n_clip_rects)
368 {
369 for (int i = 0; i < gc_ext->n_clip_rects; i++)
370 cairo_rectangle (cr, gc_ext->clip_rects[i].x,
371 gc_ext->clip_rects[i].y,
372 gc_ext->clip_rects[i].width,
373 gc_ext->clip_rects[i].height);
374 cairo_clip (cr);
375 }
376 }
377 }
378
379 cairo_t *
x_begin_cr_clip(struct frame * f,GC gc)380 x_begin_cr_clip (struct frame *f, GC gc)
381 {
382 cairo_t *cr = FRAME_CR_CONTEXT (f);
383
384 if (!cr)
385 {
386 int width = FRAME_CR_SURFACE_DESIRED_WIDTH (f);
387 int height = FRAME_CR_SURFACE_DESIRED_HEIGHT (f);
388 cairo_surface_t *surface
389 = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
390 FRAME_X_RAW_DRAWABLE (f),
391 FRAME_X_VISUAL (f),
392 width, height);
393
394 cr = FRAME_CR_CONTEXT (f) = cairo_create (surface);
395 cairo_surface_destroy (surface);
396 }
397 cairo_save (cr);
398 x_cr_gc_clip (cr, f, gc);
399
400 return cr;
401 }
402
403 void
x_end_cr_clip(struct frame * f)404 x_end_cr_clip (struct frame *f)
405 {
406 cairo_restore (FRAME_CR_CONTEXT (f));
407 if (FRAME_X_DOUBLE_BUFFERED_P (f))
408 x_mark_frame_dirty (f);
409 }
410
411 void
x_set_cr_source_with_gc_foreground(struct frame * f,GC gc)412 x_set_cr_source_with_gc_foreground (struct frame *f, GC gc)
413 {
414 XGCValues xgcv;
415 XColor color;
416
417 XGetGCValues (FRAME_X_DISPLAY (f), gc, GCForeground, &xgcv);
418 color.pixel = xgcv.foreground;
419 x_query_colors (f, &color, 1);
420 cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
421 color.green / 65535.0, color.blue / 65535.0);
422 }
423
424 void
x_set_cr_source_with_gc_background(struct frame * f,GC gc)425 x_set_cr_source_with_gc_background (struct frame *f, GC gc)
426 {
427 XGCValues xgcv;
428 XColor color;
429
430 XGetGCValues (FRAME_X_DISPLAY (f), gc, GCBackground, &xgcv);
431 color.pixel = xgcv.background;
432 x_query_colors (f, &color, 1);
433 cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
434 color.green / 65535.0, color.blue / 65535.0);
435 }
436
437 static const cairo_user_data_key_t xlib_surface_key, saved_drawable_key;
438
439 static void
x_cr_destroy_xlib_surface(cairo_surface_t * xlib_surface)440 x_cr_destroy_xlib_surface (cairo_surface_t *xlib_surface)
441 {
442 if (xlib_surface)
443 {
444 XFreePixmap (cairo_xlib_surface_get_display (xlib_surface),
445 cairo_xlib_surface_get_drawable (xlib_surface));
446 cairo_surface_destroy (xlib_surface);
447 }
448 }
449
450 static bool
x_try_cr_xlib_drawable(struct frame * f,GC gc)451 x_try_cr_xlib_drawable (struct frame *f, GC gc)
452 {
453 cairo_t *cr = FRAME_CR_CONTEXT (f);
454 if (!cr)
455 return true;
456
457 cairo_surface_t *surface = cairo_get_target (cr);
458 switch (cairo_surface_get_type (surface))
459 {
460 case CAIRO_SURFACE_TYPE_XLIB:
461 cairo_surface_flush (surface);
462 return true;
463
464 case CAIRO_SURFACE_TYPE_IMAGE:
465 break;
466
467 default:
468 return false;
469 }
470
471 /* FRAME_CR_CONTEXT (f) is an image surface we can not draw into
472 directly with Xlib. Set up a Pixmap so we can copy back the
473 result later in x_end_cr_xlib_drawable. */
474 cairo_surface_t *xlib_surface = cairo_get_user_data (cr, &xlib_surface_key);
475 int width = FRAME_CR_SURFACE_DESIRED_WIDTH (f);
476 int height = FRAME_CR_SURFACE_DESIRED_HEIGHT (f);
477 Pixmap pixmap;
478 if (xlib_surface
479 && cairo_xlib_surface_get_width (xlib_surface) == width
480 && cairo_xlib_surface_get_height (xlib_surface) == height)
481 pixmap = cairo_xlib_surface_get_drawable (xlib_surface);
482 else
483 {
484 pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_RAW_DRAWABLE (f),
485 width, height,
486 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
487 xlib_surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
488 pixmap, FRAME_X_VISUAL (f),
489 width, height);
490 cairo_set_user_data (cr, &xlib_surface_key, xlib_surface,
491 (cairo_destroy_func_t) x_cr_destroy_xlib_surface);
492 }
493
494 cairo_t *buf = cairo_create (xlib_surface);
495 cairo_set_source_surface (buf, surface, 0, 0);
496 cairo_matrix_t matrix;
497 cairo_get_matrix (cr, &matrix);
498 cairo_pattern_set_matrix (cairo_get_source (cr), &matrix);
499 cairo_set_operator (buf, CAIRO_OPERATOR_SOURCE);
500 x_cr_gc_clip (buf, f, gc);
501 cairo_paint (buf);
502 cairo_destroy (buf);
503
504 cairo_set_user_data (cr, &saved_drawable_key,
505 (void *) (uintptr_t) FRAME_X_RAW_DRAWABLE (f), NULL);
506 FRAME_X_RAW_DRAWABLE (f) = pixmap;
507 cairo_surface_flush (xlib_surface);
508
509 return true;
510 }
511
512 static void
x_end_cr_xlib_drawable(struct frame * f,GC gc)513 x_end_cr_xlib_drawable (struct frame *f, GC gc)
514 {
515 cairo_t *cr = FRAME_CR_CONTEXT (f);
516 if (!cr)
517 return;
518
519 Drawable saved_drawable
520 = (uintptr_t) cairo_get_user_data (cr, &saved_drawable_key);
521 cairo_surface_t *surface = (saved_drawable
522 ? cairo_get_user_data (cr, &xlib_surface_key)
523 : cairo_get_target (cr));
524 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
525 if (gc_ext && gc_ext->n_clip_rects)
526 for (int i = 0; i < gc_ext->n_clip_rects; i++)
527 cairo_surface_mark_dirty_rectangle (surface, gc_ext->clip_rects[i].x,
528 gc_ext->clip_rects[i].y,
529 gc_ext->clip_rects[i].width,
530 gc_ext->clip_rects[i].height);
531 else
532 cairo_surface_mark_dirty (surface);
533 if (!saved_drawable)
534 return;
535
536 cairo_save (cr);
537 cairo_set_source_surface (cr, surface, 0, 0);
538 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
539 x_cr_gc_clip (cr, f, gc);
540 cairo_paint (cr);
541 cairo_restore (cr);
542
543 FRAME_X_RAW_DRAWABLE (f) = saved_drawable;
544 cairo_set_user_data (cr, &saved_drawable_key, NULL, NULL);
545 }
546
547 /* Fringe bitmaps. */
548
549 static int max_fringe_bmp = 0;
550 static cairo_pattern_t **fringe_bmp = 0;
551
552 static void
x_cr_define_fringe_bitmap(int which,unsigned short * bits,int h,int wd)553 x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
554 {
555 int i, stride;
556 cairo_surface_t *surface;
557 cairo_pattern_t *pattern;
558 unsigned char *data;
559
560 if (which >= max_fringe_bmp)
561 {
562 i = max_fringe_bmp;
563 max_fringe_bmp = which + 20;
564 fringe_bmp = xrealloc (fringe_bmp, max_fringe_bmp * sizeof (*fringe_bmp));
565 while (i < max_fringe_bmp)
566 fringe_bmp[i++] = 0;
567 }
568
569 block_input ();
570
571 surface = cairo_image_surface_create (CAIRO_FORMAT_A1, wd, h);
572 stride = cairo_image_surface_get_stride (surface);
573 data = cairo_image_surface_get_data (surface);
574
575 for (i = 0; i < h; i++)
576 {
577 *((unsigned short *) data) = bits[i];
578 data += stride;
579 }
580
581 cairo_surface_mark_dirty (surface);
582 pattern = cairo_pattern_create_for_surface (surface);
583 cairo_surface_destroy (surface);
584
585 unblock_input ();
586
587 fringe_bmp[which] = pattern;
588 }
589
590 static void
x_cr_destroy_fringe_bitmap(int which)591 x_cr_destroy_fringe_bitmap (int which)
592 {
593 if (which >= max_fringe_bmp)
594 return;
595
596 if (fringe_bmp[which])
597 {
598 block_input ();
599 cairo_pattern_destroy (fringe_bmp[which]);
600 unblock_input ();
601 }
602 fringe_bmp[which] = 0;
603 }
604
605 static void
x_cr_draw_image(struct frame * f,GC gc,cairo_pattern_t * image,int src_x,int src_y,int width,int height,int dest_x,int dest_y,bool overlay_p)606 x_cr_draw_image (struct frame *f, GC gc, cairo_pattern_t *image,
607 int src_x, int src_y, int width, int height,
608 int dest_x, int dest_y, bool overlay_p)
609 {
610 cairo_t *cr = x_begin_cr_clip (f, gc);
611
612 if (overlay_p)
613 cairo_rectangle (cr, dest_x, dest_y, width, height);
614 else
615 {
616 x_set_cr_source_with_gc_background (f, gc);
617 cairo_rectangle (cr, dest_x, dest_y, width, height);
618 cairo_fill_preserve (cr);
619 }
620
621 cairo_translate (cr, dest_x - src_x, dest_y - src_y);
622
623 cairo_surface_t *surface;
624 cairo_pattern_get_surface (image, &surface);
625 cairo_format_t format = cairo_image_surface_get_format (surface);
626 if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1)
627 {
628 cairo_set_source (cr, image);
629 cairo_fill (cr);
630 }
631 else
632 {
633 x_set_cr_source_with_gc_foreground (f, gc);
634 cairo_clip (cr);
635 cairo_mask (cr, image);
636 }
637
638 x_end_cr_clip (f);
639 }
640
641 void
x_cr_draw_frame(cairo_t * cr,struct frame * f)642 x_cr_draw_frame (cairo_t *cr, struct frame *f)
643 {
644 int width, height;
645
646 width = FRAME_PIXEL_WIDTH (f);
647 height = FRAME_PIXEL_HEIGHT (f);
648
649 cairo_t *saved_cr = FRAME_CR_CONTEXT (f);
650 FRAME_CR_CONTEXT (f) = cr;
651 x_clear_area (f, 0, 0, width, height);
652 expose_frame (f, 0, 0, width, height);
653 FRAME_CR_CONTEXT (f) = saved_cr;
654 }
655
656 static cairo_status_t
x_cr_accumulate_data(void * closure,const unsigned char * data,unsigned int length)657 x_cr_accumulate_data (void *closure, const unsigned char *data,
658 unsigned int length)
659 {
660 Lisp_Object *acc = (Lisp_Object *) closure;
661
662 *acc = Fcons (make_unibyte_string ((char const *) data, length), *acc);
663
664 return CAIRO_STATUS_SUCCESS;
665 }
666
667 static void
x_cr_destroy(void * cr)668 x_cr_destroy (void *cr)
669 {
670 block_input ();
671 cairo_destroy (cr);
672 unblock_input ();
673 }
674
675 Lisp_Object
x_cr_export_frames(Lisp_Object frames,cairo_surface_type_t surface_type)676 x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
677 {
678 struct frame *f;
679 cairo_surface_t *surface;
680 cairo_t *cr;
681 int width, height;
682 void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL;
683 Lisp_Object acc = Qnil;
684 ptrdiff_t count = SPECPDL_INDEX ();
685
686 specbind (Qredisplay_dont_pause, Qt);
687 redisplay_preserve_echo_area (31);
688
689 f = XFRAME (XCAR (frames));
690 frames = XCDR (frames);
691 width = FRAME_PIXEL_WIDTH (f);
692 height = FRAME_PIXEL_HEIGHT (f);
693
694 block_input ();
695 #ifdef CAIRO_HAS_PDF_SURFACE
696 if (surface_type == CAIRO_SURFACE_TYPE_PDF)
697 {
698 surface = cairo_pdf_surface_create_for_stream (x_cr_accumulate_data, &acc,
699 width, height);
700 surface_set_size_func = cairo_pdf_surface_set_size;
701 }
702 else
703 #endif
704 #ifdef CAIRO_HAS_PNG_FUNCTIONS
705 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
706 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
707 else
708 #endif
709 #ifdef CAIRO_HAS_PS_SURFACE
710 if (surface_type == CAIRO_SURFACE_TYPE_PS)
711 {
712 surface = cairo_ps_surface_create_for_stream (x_cr_accumulate_data, &acc,
713 width, height);
714 surface_set_size_func = cairo_ps_surface_set_size;
715 }
716 else
717 #endif
718 #ifdef CAIRO_HAS_SVG_SURFACE
719 if (surface_type == CAIRO_SURFACE_TYPE_SVG)
720 surface = cairo_svg_surface_create_for_stream (x_cr_accumulate_data, &acc,
721 width, height);
722 else
723 #endif
724 abort ();
725
726 cr = cairo_create (surface);
727 cairo_surface_destroy (surface);
728 record_unwind_protect_ptr (x_cr_destroy, cr);
729
730 while (1)
731 {
732 cairo_t *saved_cr = FRAME_CR_CONTEXT (f);
733 FRAME_CR_CONTEXT (f) = cr;
734 x_clear_area (f, 0, 0, width, height);
735 expose_frame (f, 0, 0, width, height);
736 FRAME_CR_CONTEXT (f) = saved_cr;
737
738 if (NILP (frames))
739 break;
740
741 cairo_surface_show_page (surface);
742 f = XFRAME (XCAR (frames));
743 frames = XCDR (frames);
744 width = FRAME_PIXEL_WIDTH (f);
745 height = FRAME_PIXEL_HEIGHT (f);
746 if (surface_set_size_func)
747 (*surface_set_size_func) (surface, width, height);
748
749 unblock_input ();
750 maybe_quit ();
751 block_input ();
752 }
753
754 #ifdef CAIRO_HAS_PNG_FUNCTIONS
755 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
756 {
757 cairo_surface_flush (surface);
758 cairo_surface_write_to_png_stream (surface, x_cr_accumulate_data, &acc);
759 }
760 #endif
761 unblock_input ();
762
763 unbind_to (count, Qnil);
764
765 return CALLN (Fapply, intern ("concat"), Fnreverse (acc));
766 }
767
768 #endif /* USE_CAIRO */
769
770 static void
x_set_clip_rectangles(struct frame * f,GC gc,XRectangle * rectangles,int n)771 x_set_clip_rectangles (struct frame *f, GC gc, XRectangle *rectangles, int n)
772 {
773 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, rectangles, n, Unsorted);
774 #ifdef USE_CAIRO
775 eassert (n >= 0 && n <= MAX_CLIP_RECTS);
776
777 {
778 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 1);
779
780 gc_ext->n_clip_rects = n;
781 memcpy (gc_ext->clip_rects, rectangles, sizeof (XRectangle) * n);
782 }
783 #endif
784 }
785
786 static void
x_reset_clip_rectangles(struct frame * f,GC gc)787 x_reset_clip_rectangles (struct frame *f, GC gc)
788 {
789 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
790 #ifdef USE_CAIRO
791 {
792 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
793
794 if (gc_ext)
795 gc_ext->n_clip_rects = 0;
796 }
797 #endif
798 }
799
800 static void
x_fill_rectangle(struct frame * f,GC gc,int x,int y,int width,int height)801 x_fill_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
802 {
803 #ifdef USE_CAIRO
804 Display *dpy = FRAME_X_DISPLAY (f);
805 cairo_t *cr;
806 XGCValues xgcv;
807
808 cr = x_begin_cr_clip (f, gc);
809 XGetGCValues (dpy, gc, GCFillStyle | GCStipple, &xgcv);
810 if (xgcv.fill_style == FillSolid
811 /* Invalid resource ID (one or more of the three most
812 significant bits set to 1) is obtained if the GCStipple
813 component has never been explicitly set. It should be
814 regarded as Pixmap of unspecified size filled with ones. */
815 || (xgcv.stipple & ((Pixmap) 7 << (sizeof (Pixmap) * CHAR_BIT - 3))))
816 {
817 x_set_cr_source_with_gc_foreground (f, gc);
818 cairo_rectangle (cr, x, y, width, height);
819 cairo_fill (cr);
820 }
821 else
822 {
823 eassert (xgcv.fill_style == FillOpaqueStippled);
824 eassert (xgcv.stipple != None);
825 x_set_cr_source_with_gc_background (f, gc);
826 cairo_rectangle (cr, x, y, width, height);
827 cairo_fill_preserve (cr);
828
829 cairo_pattern_t *pattern = x_bitmap_stipple (f, xgcv.stipple);
830 if (pattern)
831 {
832 x_set_cr_source_with_gc_foreground (f, gc);
833 cairo_clip (cr);
834 cairo_mask (cr, pattern);
835 }
836 }
837 x_end_cr_clip (f);
838 #else
839 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
840 gc, x, y, width, height);
841 #endif
842 }
843
844 static void
x_draw_rectangle(struct frame * f,GC gc,int x,int y,int width,int height)845 x_draw_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
846 {
847 #ifdef USE_CAIRO
848 cairo_t *cr;
849
850 cr = x_begin_cr_clip (f, gc);
851 x_set_cr_source_with_gc_foreground (f, gc);
852 cairo_rectangle (cr, x + 0.5, y + 0.5, width, height);
853 cairo_set_line_width (cr, 1);
854 cairo_stroke (cr);
855 x_end_cr_clip (f);
856 #else
857 XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
858 gc, x, y, width, height);
859 #endif
860 }
861
862 static void
x_clear_window(struct frame * f)863 x_clear_window (struct frame *f)
864 {
865 #ifdef USE_CAIRO
866 cairo_t *cr;
867
868 cr = x_begin_cr_clip (f, NULL);
869 x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
870 cairo_paint (cr);
871 x_end_cr_clip (f);
872 #else
873 if (FRAME_X_DOUBLE_BUFFERED_P (f))
874 x_clear_area (f, 0, 0, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
875 else
876 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
877 #endif
878 }
879
880 #ifdef USE_CAIRO
881 static void
x_fill_trapezoid_for_relief(struct frame * f,GC gc,int x,int y,int width,int height,int top_p)882 x_fill_trapezoid_for_relief (struct frame *f, GC gc, int x, int y,
883 int width, int height, int top_p)
884 {
885 cairo_t *cr;
886
887 cr = x_begin_cr_clip (f, gc);
888 x_set_cr_source_with_gc_foreground (f, gc);
889 cairo_move_to (cr, top_p ? x : x + height, y);
890 cairo_line_to (cr, x, y + height);
891 cairo_line_to (cr, top_p ? x + width - height : x + width, y + height);
892 cairo_line_to (cr, x + width, y);
893 cairo_fill (cr);
894 x_end_cr_clip (f);
895 }
896
897 enum corners
898 {
899 CORNER_BOTTOM_RIGHT, /* 0 -> pi/2 */
900 CORNER_BOTTOM_LEFT, /* pi/2 -> pi */
901 CORNER_TOP_LEFT, /* pi -> 3pi/2 */
902 CORNER_TOP_RIGHT, /* 3pi/2 -> 2pi */
903 CORNER_LAST
904 };
905
906 static void
x_erase_corners_for_relief(struct frame * f,GC gc,int x,int y,int width,int height,double radius,double margin,int corners)907 x_erase_corners_for_relief (struct frame *f, GC gc, int x, int y,
908 int width, int height,
909 double radius, double margin, int corners)
910 {
911 cairo_t *cr;
912 int i;
913
914 cr = x_begin_cr_clip (f, gc);
915 x_set_cr_source_with_gc_background (f, gc);
916 for (i = 0; i < CORNER_LAST; i++)
917 if (corners & (1 << i))
918 {
919 double xm, ym, xc, yc;
920
921 if (i == CORNER_TOP_LEFT || i == CORNER_BOTTOM_LEFT)
922 xm = x - margin, xc = xm + radius;
923 else
924 xm = x + width + margin, xc = xm - radius;
925 if (i == CORNER_TOP_LEFT || i == CORNER_TOP_RIGHT)
926 ym = y - margin, yc = ym + radius;
927 else
928 ym = y + height + margin, yc = ym - radius;
929
930 cairo_move_to (cr, xm, ym);
931 cairo_arc (cr, xc, yc, radius, i * M_PI_2, (i + 1) * M_PI_2);
932 }
933 cairo_clip (cr);
934 cairo_rectangle (cr, x, y, width, height);
935 cairo_fill (cr);
936 x_end_cr_clip (f);
937 }
938
939 static void
x_draw_horizontal_wave(struct frame * f,GC gc,int x,int y,int width,int height,int wave_length)940 x_draw_horizontal_wave (struct frame *f, GC gc, int x, int y,
941 int width, int height, int wave_length)
942 {
943 cairo_t *cr;
944 double dx = wave_length, dy = height - 1;
945 int xoffset, n;
946
947 cr = x_begin_cr_clip (f, gc);
948 x_set_cr_source_with_gc_foreground (f, gc);
949 cairo_rectangle (cr, x, y, width, height);
950 cairo_clip (cr);
951
952 if (x >= 0)
953 {
954 xoffset = x % (wave_length * 2);
955 if (xoffset == 0)
956 xoffset = wave_length * 2;
957 }
958 else
959 xoffset = x % (wave_length * 2) + wave_length * 2;
960 n = (width + xoffset) / wave_length + 1;
961 if (xoffset > wave_length)
962 {
963 xoffset -= wave_length;
964 --n;
965 y += height - 1;
966 dy = -dy;
967 }
968
969 cairo_move_to (cr, x - xoffset + 0.5, y + 0.5);
970 while (--n >= 0)
971 {
972 cairo_rel_line_to (cr, dx, dy);
973 dy = -dy;
974 }
975 cairo_set_line_width (cr, 1);
976 cairo_stroke (cr);
977 x_end_cr_clip (f);
978 }
979 #endif
980
981
982 /* Return the struct x_display_info corresponding to DPY. */
983
984 struct x_display_info *
x_display_info_for_display(Display * dpy)985 x_display_info_for_display (Display *dpy)
986 {
987 struct x_display_info *dpyinfo;
988
989 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
990 if (dpyinfo->display == dpy)
991 return dpyinfo;
992
993 return 0;
994 }
995
996 static Window
x_find_topmost_parent(struct frame * f)997 x_find_topmost_parent (struct frame *f)
998 {
999 struct x_output *x = f->output_data.x;
1000 Window win = None, wi = x->parent_desc;
1001 Display *dpy = FRAME_X_DISPLAY (f);
1002
1003 while (wi != FRAME_DISPLAY_INFO (f)->root_window)
1004 {
1005 Window root;
1006 Window *children;
1007 unsigned int nchildren;
1008
1009 win = wi;
1010 if (XQueryTree (dpy, win, &root, &wi, &children, &nchildren))
1011 XFree (children);
1012 else
1013 break;
1014 }
1015
1016 return win;
1017 }
1018
1019 #define OPAQUE 0xffffffff
1020
1021 static void
x_set_frame_alpha(struct frame * f)1022 x_set_frame_alpha (struct frame *f)
1023 {
1024 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1025 Display *dpy = FRAME_X_DISPLAY (f);
1026 Window win = FRAME_OUTER_WINDOW (f);
1027 double alpha = 1.0;
1028 double alpha_min = 1.0;
1029 unsigned long opac;
1030 Window parent;
1031
1032 if (dpyinfo->highlight_frame == f)
1033 alpha = f->alpha[0];
1034 else
1035 alpha = f->alpha[1];
1036
1037 if (alpha < 0.0)
1038 return;
1039
1040 if (FLOATP (Vframe_alpha_lower_limit))
1041 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1042 else if (FIXNUMP (Vframe_alpha_lower_limit))
1043 alpha_min = (XFIXNUM (Vframe_alpha_lower_limit)) / 100.0;
1044
1045 if (alpha > 1.0)
1046 alpha = 1.0;
1047 else if (alpha < alpha_min && alpha_min <= 1.0)
1048 alpha = alpha_min;
1049
1050 opac = alpha * OPAQUE;
1051
1052 x_catch_errors (dpy);
1053
1054 /* If there is a parent from the window manager, put the property there
1055 also, to work around broken window managers that fail to do that.
1056 Do this unconditionally as this function is called on reparent when
1057 alpha has not changed on the frame. */
1058
1059 if (!FRAME_PARENT_FRAME (f))
1060 {
1061 parent = x_find_topmost_parent (f);
1062 if (parent != None)
1063 XChangeProperty (dpy, parent, dpyinfo->Xatom_net_wm_window_opacity,
1064 XA_CARDINAL, 32, PropModeReplace,
1065 (unsigned char *) &opac, 1);
1066 }
1067
1068 /* return unless necessary */
1069 {
1070 unsigned char *data;
1071 Atom actual;
1072 int rc, format;
1073 unsigned long n, left;
1074
1075 rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
1076 0, 1, False, XA_CARDINAL,
1077 &actual, &format, &n, &left,
1078 &data);
1079
1080 if (rc == Success && actual != None)
1081 {
1082 unsigned long value = *(unsigned long *)data;
1083 XFree (data);
1084 if (value == opac)
1085 {
1086 x_uncatch_errors ();
1087 return;
1088 }
1089 }
1090 }
1091
1092 XChangeProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
1093 XA_CARDINAL, 32, PropModeReplace,
1094 (unsigned char *) &opac, 1);
1095 x_uncatch_errors ();
1096 }
1097
1098 /***********************************************************************
1099 Starting and ending an update
1100 ***********************************************************************/
1101
1102 /* Start an update of frame F. This function is installed as a hook
1103 for update_begin, i.e. it is called when update_begin is called.
1104 This function is called prior to calls to gui_update_window_begin for
1105 each window being updated. Currently, there is nothing to do here
1106 because all interesting stuff is done on a window basis. */
1107
1108 static void
x_update_begin(struct frame * f)1109 x_update_begin (struct frame *f)
1110 {
1111 /* Nothing to do. */
1112 }
1113
1114 /* Draw a vertical window border from (x,y0) to (x,y1) */
1115
1116 static void
x_draw_vertical_window_border(struct window * w,int x,int y0,int y1)1117 x_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
1118 {
1119 struct frame *f = XFRAME (WINDOW_FRAME (w));
1120 struct face *face;
1121
1122 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
1123 if (face)
1124 XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
1125 face->foreground);
1126
1127 #ifdef USE_CAIRO
1128 x_fill_rectangle (f, f->output_data.x->normal_gc, x, y0, 1, y1 - y0);
1129 #else
1130 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
1131 f->output_data.x->normal_gc, x, y0, x, y1);
1132 #endif
1133 }
1134
1135 /* Draw a window divider from (x0,y0) to (x1,y1) */
1136
1137 static void
x_draw_window_divider(struct window * w,int x0,int x1,int y0,int y1)1138 x_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
1139 {
1140 struct frame *f = XFRAME (WINDOW_FRAME (w));
1141 struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
1142 struct face *face_first
1143 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
1144 struct face *face_last
1145 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
1146 unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
1147 unsigned long color_first = (face_first
1148 ? face_first->foreground
1149 : FRAME_FOREGROUND_PIXEL (f));
1150 unsigned long color_last = (face_last
1151 ? face_last->foreground
1152 : FRAME_FOREGROUND_PIXEL (f));
1153 Display *display = FRAME_X_DISPLAY (f);
1154
1155 if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
1156 /* A vertical divider, at least three pixels wide: Draw first and
1157 last pixels differently. */
1158 {
1159 XSetForeground (display, f->output_data.x->normal_gc, color_first);
1160 x_fill_rectangle (f, f->output_data.x->normal_gc,
1161 x0, y0, 1, y1 - y0);
1162 XSetForeground (display, f->output_data.x->normal_gc, color);
1163 x_fill_rectangle (f, f->output_data.x->normal_gc,
1164 x0 + 1, y0, x1 - x0 - 2, y1 - y0);
1165 XSetForeground (display, f->output_data.x->normal_gc, color_last);
1166 x_fill_rectangle (f, f->output_data.x->normal_gc,
1167 x1 - 1, y0, 1, y1 - y0);
1168 }
1169 else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
1170 /* A horizontal divider, at least three pixels high: Draw first and
1171 last pixels differently. */
1172 {
1173 XSetForeground (display, f->output_data.x->normal_gc, color_first);
1174 x_fill_rectangle (f, f->output_data.x->normal_gc,
1175 x0, y0, x1 - x0, 1);
1176 XSetForeground (display, f->output_data.x->normal_gc, color);
1177 x_fill_rectangle (f, f->output_data.x->normal_gc,
1178 x0, y0 + 1, x1 - x0, y1 - y0 - 2);
1179 XSetForeground (display, f->output_data.x->normal_gc, color_last);
1180 x_fill_rectangle (f, f->output_data.x->normal_gc,
1181 x0, y1 - 1, x1 - x0, 1);
1182 }
1183 else
1184 {
1185 /* In any other case do not draw the first and last pixels
1186 differently. */
1187 XSetForeground (display, f->output_data.x->normal_gc, color);
1188 x_fill_rectangle (f, f->output_data.x->normal_gc,
1189 x0, y0, x1 - x0, y1 - y0);
1190 }
1191 }
1192
1193 /* Show the frame back buffer. If frame is double-buffered,
1194 atomically publish to the user's screen graphics updates made since
1195 the last call to show_back_buffer. */
1196 static void
show_back_buffer(struct frame * f)1197 show_back_buffer (struct frame *f)
1198 {
1199 block_input ();
1200 if (FRAME_X_DOUBLE_BUFFERED_P (f))
1201 {
1202 #ifdef HAVE_XDBE
1203 #ifdef USE_CAIRO
1204 cairo_t *cr = FRAME_CR_CONTEXT (f);
1205 if (cr)
1206 cairo_surface_flush (cairo_get_target (cr));
1207 #endif
1208 XdbeSwapInfo swap_info;
1209 memset (&swap_info, 0, sizeof (swap_info));
1210 swap_info.swap_window = FRAME_X_WINDOW (f);
1211 swap_info.swap_action = XdbeCopied;
1212 XdbeSwapBuffers (FRAME_X_DISPLAY (f), &swap_info, 1);
1213 #else
1214 eassert (!"should have back-buffer only with XDBE");
1215 #endif
1216 }
1217 FRAME_X_NEED_BUFFER_FLIP (f) = false;
1218 unblock_input ();
1219 }
1220
1221 /* Updates back buffer and flushes changes to display. Called from
1222 minibuf read code. Note that we display the back buffer even if
1223 buffer flipping is blocked. */
1224 static void
x_flip_and_flush(struct frame * f)1225 x_flip_and_flush (struct frame *f)
1226 {
1227 block_input ();
1228 if (FRAME_X_NEED_BUFFER_FLIP (f))
1229 show_back_buffer (f);
1230 x_flush (f);
1231 unblock_input ();
1232 }
1233
1234 /* End update of frame F. This function is installed as a hook in
1235 update_end. */
1236
1237 static void
x_update_end(struct frame * f)1238 x_update_end (struct frame *f)
1239 {
1240 /* Mouse highlight may be displayed again. */
1241 MOUSE_HL_INFO (f)->mouse_face_defer = false;
1242
1243 #ifdef USE_CAIRO
1244 if (!FRAME_X_DOUBLE_BUFFERED_P (f) && FRAME_CR_CONTEXT (f))
1245 {
1246 block_input ();
1247 cairo_surface_flush (cairo_get_target (FRAME_CR_CONTEXT (f)));
1248 unblock_input ();
1249 }
1250 #endif
1251
1252 #ifndef XFlush
1253 block_input ();
1254 XFlush (FRAME_X_DISPLAY (f));
1255 unblock_input ();
1256 #endif
1257 }
1258
1259 /* This function is called from various places in xdisp.c
1260 whenever a complete update has been performed. */
1261
1262 static void
XTframe_up_to_date(struct frame * f)1263 XTframe_up_to_date (struct frame *f)
1264 {
1265 eassert (FRAME_X_P (f));
1266 block_input ();
1267 FRAME_MOUSE_UPDATE (f);
1268 if (!buffer_flipping_blocked_p () && FRAME_X_NEED_BUFFER_FLIP (f))
1269 show_back_buffer (f);
1270 unblock_input ();
1271 }
1272
1273 static void
XTbuffer_flipping_unblocked_hook(struct frame * f)1274 XTbuffer_flipping_unblocked_hook (struct frame *f)
1275 {
1276 if (FRAME_X_NEED_BUFFER_FLIP (f))
1277 show_back_buffer (f);
1278 }
1279
1280 /**
1281 * x_clear_under_internal_border:
1282 *
1283 * Clear area of frame F's internal border. If the internal border face
1284 * of F has been specified (is not null), fill the area with that face.
1285 */
1286 void
x_clear_under_internal_border(struct frame * f)1287 x_clear_under_internal_border (struct frame *f)
1288 {
1289 if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
1290 {
1291 int border = FRAME_INTERNAL_BORDER_WIDTH (f);
1292 int width = FRAME_PIXEL_WIDTH (f);
1293 int height = FRAME_PIXEL_HEIGHT (f);
1294 int margin = FRAME_TOP_MARGIN_HEIGHT (f);
1295 int face_id =
1296 !NILP (Vface_remapping_alist)
1297 ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID)
1298 : INTERNAL_BORDER_FACE_ID;
1299 struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
1300
1301 block_input ();
1302
1303 if (face)
1304 {
1305 unsigned long color = face->background;
1306 Display *display = FRAME_X_DISPLAY (f);
1307 GC gc = f->output_data.x->normal_gc;
1308
1309 XSetForeground (display, gc, color);
1310 x_fill_rectangle (f, gc, 0, margin, width, border);
1311 x_fill_rectangle (f, gc, 0, 0, border, height);
1312 x_fill_rectangle (f, gc, width - border, 0, border, height);
1313 x_fill_rectangle (f, gc, 0, height - border, width, border);
1314 XSetForeground (display, gc, FRAME_FOREGROUND_PIXEL (f));
1315 }
1316 else
1317 {
1318 x_clear_area (f, 0, 0, border, height);
1319 x_clear_area (f, 0, margin, width, border);
1320 x_clear_area (f, width - border, 0, border, height);
1321 x_clear_area (f, 0, height - border, width, border);
1322 }
1323
1324 unblock_input ();
1325 }
1326 }
1327
1328 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
1329 arrow bitmaps, or clear the fringes if no bitmaps are required
1330 before DESIRED_ROW is made current. This function is called from
1331 update_window_line only if it is known that there are differences
1332 between bitmaps to be drawn between current row and DESIRED_ROW. */
1333
1334 static void
x_after_update_window_line(struct window * w,struct glyph_row * desired_row)1335 x_after_update_window_line (struct window *w, struct glyph_row *desired_row)
1336 {
1337 eassert (w);
1338
1339 if (!desired_row->mode_line_p && !w->pseudo_window_p)
1340 desired_row->redraw_fringe_bitmaps_p = true;
1341
1342 #ifdef USE_X_TOOLKIT
1343 /* When a window has disappeared, make sure that no rest of
1344 full-width rows stays visible in the internal border. Could
1345 check here if updated window is the leftmost/rightmost window,
1346 but I guess it's not worth doing since vertically split windows
1347 are almost never used, internal border is rarely set, and the
1348 overhead is very small. */
1349 {
1350 struct frame *f;
1351 int width, height;
1352
1353 if (windows_or_buffers_changed
1354 && desired_row->full_width_p
1355 && (f = XFRAME (w->frame),
1356 width = FRAME_INTERNAL_BORDER_WIDTH (f),
1357 width != 0)
1358 && (height = desired_row->visible_height,
1359 height > 0))
1360 {
1361 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
1362 int face_id =
1363 !NILP (Vface_remapping_alist)
1364 ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID)
1365 : INTERNAL_BORDER_FACE_ID;
1366 struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
1367
1368 block_input ();
1369 if (face)
1370 {
1371 unsigned long color = face->background;
1372 Display *display = FRAME_X_DISPLAY (f);
1373 GC gc = f->output_data.x->normal_gc;
1374
1375 XSetForeground (display, gc, color);
1376 x_fill_rectangle (f, gc, 0, y, width, height);
1377 x_fill_rectangle (f, gc, FRAME_PIXEL_WIDTH (f) - width, y,
1378 width, height);
1379 XSetForeground (display, gc, FRAME_FOREGROUND_PIXEL (f));
1380 }
1381 else
1382 {
1383 x_clear_area (f, 0, y, width, height);
1384 x_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
1385 }
1386 unblock_input ();
1387 }
1388 }
1389 #endif
1390 }
1391
1392 static void
x_draw_fringe_bitmap(struct window * w,struct glyph_row * row,struct draw_fringe_bitmap_params * p)1393 x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fringe_bitmap_params *p)
1394 {
1395 struct frame *f = XFRAME (WINDOW_FRAME (w));
1396 Display *display = FRAME_X_DISPLAY (f);
1397 GC gc = f->output_data.x->normal_gc;
1398 struct face *face = p->face;
1399
1400 /* Must clip because of partially visible lines. */
1401 x_clip_to_row (w, row, ANY_AREA, gc);
1402
1403 if (p->bx >= 0 && !p->overlay_p)
1404 {
1405 /* In case the same realized face is used for fringes and
1406 for something displayed in the text (e.g. face `region' on
1407 mono-displays, the fill style may have been changed to
1408 FillSolid in x_draw_glyph_string_background. */
1409 if (face->stipple)
1410 XSetFillStyle (display, face->gc, FillOpaqueStippled);
1411 else
1412 XSetForeground (display, face->gc, face->background);
1413
1414 x_fill_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
1415
1416 if (!face->stipple)
1417 XSetForeground (display, face->gc, face->foreground);
1418 }
1419
1420 #ifdef USE_CAIRO
1421 if (p->which && p->which < max_fringe_bmp)
1422 {
1423 XGCValues gcv;
1424
1425 XGetGCValues (display, gc, GCForeground | GCBackground, &gcv);
1426 XSetForeground (display, gc, (p->cursor_p
1427 ? (p->overlay_p ? face->background
1428 : f->output_data.x->cursor_pixel)
1429 : face->foreground));
1430 XSetBackground (display, gc, face->background);
1431 x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, p->dh,
1432 p->wd, p->h, p->x, p->y, p->overlay_p);
1433 XSetForeground (display, gc, gcv.foreground);
1434 XSetBackground (display, gc, gcv.background);
1435 }
1436 #else /* not USE_CAIRO */
1437 if (p->which)
1438 {
1439 Drawable drawable = FRAME_X_DRAWABLE (f);
1440 char *bits;
1441 Pixmap pixmap, clipmask = (Pixmap) 0;
1442 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
1443 XGCValues gcv;
1444
1445 if (p->wd > 8)
1446 bits = (char *) (p->bits + p->dh);
1447 else
1448 bits = (char *) p->bits + p->dh;
1449
1450 /* Draw the bitmap. I believe these small pixmaps can be cached
1451 by the server. */
1452 pixmap = XCreatePixmapFromBitmapData (display, drawable, bits, p->wd, p->h,
1453 (p->cursor_p
1454 ? (p->overlay_p ? face->background
1455 : f->output_data.x->cursor_pixel)
1456 : face->foreground),
1457 face->background, depth);
1458
1459 if (p->overlay_p)
1460 {
1461 clipmask = XCreatePixmapFromBitmapData (display,
1462 FRAME_DISPLAY_INFO (f)->root_window,
1463 bits, p->wd, p->h,
1464 1, 0, 1);
1465 gcv.clip_mask = clipmask;
1466 gcv.clip_x_origin = p->x;
1467 gcv.clip_y_origin = p->y;
1468 XChangeGC (display, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
1469 }
1470
1471 XCopyArea (display, pixmap, drawable, gc, 0, 0,
1472 p->wd, p->h, p->x, p->y);
1473 XFreePixmap (display, pixmap);
1474
1475 if (p->overlay_p)
1476 {
1477 gcv.clip_mask = (Pixmap) 0;
1478 XChangeGC (display, gc, GCClipMask, &gcv);
1479 XFreePixmap (display, clipmask);
1480 }
1481 }
1482 #endif /* not USE_CAIRO */
1483
1484 x_reset_clip_rectangles (f, gc);
1485 }
1486
1487 /***********************************************************************
1488 Glyph display
1489 ***********************************************************************/
1490
1491 static bool x_alloc_lighter_color (struct frame *, Display *, Colormap,
1492 unsigned long *, double, int);
1493 static void x_scroll_bar_clear (struct frame *);
1494
1495 #ifdef GLYPH_DEBUG
1496 static void x_check_font (struct frame *, struct font *);
1497 #endif
1498
1499
1500 /* Set S->gc to a suitable GC for drawing glyph string S in cursor
1501 face. */
1502
1503 static void
x_set_cursor_gc(struct glyph_string * s)1504 x_set_cursor_gc (struct glyph_string *s)
1505 {
1506 if (s->font == FRAME_FONT (s->f)
1507 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
1508 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
1509 && !s->cmp)
1510 s->gc = s->f->output_data.x->cursor_gc;
1511 else
1512 {
1513 /* Cursor on non-default face: must merge. */
1514 XGCValues xgcv;
1515 unsigned long mask;
1516 Display *display = FRAME_X_DISPLAY (s->f);
1517
1518 xgcv.background = s->f->output_data.x->cursor_pixel;
1519 xgcv.foreground = s->face->background;
1520
1521 /* If the glyph would be invisible, try a different foreground. */
1522 if (xgcv.foreground == xgcv.background)
1523 xgcv.foreground = s->face->foreground;
1524 if (xgcv.foreground == xgcv.background)
1525 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
1526 if (xgcv.foreground == xgcv.background)
1527 xgcv.foreground = s->face->foreground;
1528
1529 /* Make sure the cursor is distinct from text in this face. */
1530 if (xgcv.background == s->face->background
1531 && xgcv.foreground == s->face->foreground)
1532 {
1533 xgcv.background = s->face->foreground;
1534 xgcv.foreground = s->face->background;
1535 }
1536
1537 IF_DEBUG (x_check_font (s->f, s->font));
1538 xgcv.graphics_exposures = False;
1539 mask = GCForeground | GCBackground | GCGraphicsExposures;
1540
1541 if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1542 XChangeGC (display, FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1543 mask, &xgcv);
1544 else
1545 FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
1546 = XCreateGC (display, FRAME_X_DRAWABLE (s->f), mask, &xgcv);
1547
1548 s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1549 }
1550 }
1551
1552
1553 /* Set up S->gc of glyph string S for drawing text in mouse face. */
1554
1555 static void
x_set_mouse_face_gc(struct glyph_string * s)1556 x_set_mouse_face_gc (struct glyph_string *s)
1557 {
1558 int face_id;
1559 struct face *face;
1560
1561 /* What face has to be used last for the mouse face? */
1562 face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
1563 face = FACE_FROM_ID_OR_NULL (s->f, face_id);
1564 if (face == NULL)
1565 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1566
1567 if (s->first_glyph->type == CHAR_GLYPH)
1568 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
1569 else
1570 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
1571 s->face = FACE_FROM_ID (s->f, face_id);
1572 prepare_face_for_display (s->f, s->face);
1573
1574 if (s->font == s->face->font)
1575 s->gc = s->face->gc;
1576 else
1577 {
1578 /* Otherwise construct scratch_cursor_gc with values from FACE
1579 except for FONT. */
1580 XGCValues xgcv;
1581 unsigned long mask;
1582 Display *display = FRAME_X_DISPLAY (s->f);
1583
1584 xgcv.background = s->face->background;
1585 xgcv.foreground = s->face->foreground;
1586 xgcv.graphics_exposures = False;
1587 mask = GCForeground | GCBackground | GCGraphicsExposures;
1588
1589 if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1590 XChangeGC (display, FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1591 mask, &xgcv);
1592 else
1593 FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
1594 = XCreateGC (display, FRAME_X_DRAWABLE (s->f), mask, &xgcv);
1595
1596 s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1597
1598 }
1599 eassert (s->gc != 0);
1600 }
1601
1602
1603 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
1604 Faces to use in the mode line have already been computed when the
1605 matrix was built, so there isn't much to do, here. */
1606
1607 static void
x_set_mode_line_face_gc(struct glyph_string * s)1608 x_set_mode_line_face_gc (struct glyph_string *s)
1609 {
1610 s->gc = s->face->gc;
1611 }
1612
1613
1614 /* Set S->gc of glyph string S for drawing that glyph string. Set
1615 S->stippled_p to a non-zero value if the face of S has a stipple
1616 pattern. */
1617
1618 static void
x_set_glyph_string_gc(struct glyph_string * s)1619 x_set_glyph_string_gc (struct glyph_string *s)
1620 {
1621 prepare_face_for_display (s->f, s->face);
1622
1623 if (s->hl == DRAW_NORMAL_TEXT)
1624 {
1625 s->gc = s->face->gc;
1626 s->stippled_p = s->face->stipple != 0;
1627 }
1628 else if (s->hl == DRAW_INVERSE_VIDEO)
1629 {
1630 x_set_mode_line_face_gc (s);
1631 s->stippled_p = s->face->stipple != 0;
1632 }
1633 else if (s->hl == DRAW_CURSOR)
1634 {
1635 x_set_cursor_gc (s);
1636 s->stippled_p = false;
1637 }
1638 else if (s->hl == DRAW_MOUSE_FACE)
1639 {
1640 x_set_mouse_face_gc (s);
1641 s->stippled_p = s->face->stipple != 0;
1642 }
1643 else if (s->hl == DRAW_IMAGE_RAISED
1644 || s->hl == DRAW_IMAGE_SUNKEN)
1645 {
1646 s->gc = s->face->gc;
1647 s->stippled_p = s->face->stipple != 0;
1648 }
1649 else
1650 emacs_abort ();
1651
1652 /* GC must have been set. */
1653 eassert (s->gc != 0);
1654 }
1655
1656
1657 /* Set clipping for output of glyph string S. S may be part of a mode
1658 line or menu if we don't have X toolkit support. */
1659
1660 static void
x_set_glyph_string_clipping(struct glyph_string * s)1661 x_set_glyph_string_clipping (struct glyph_string *s)
1662 {
1663 XRectangle *r = s->clip;
1664 int n = get_glyph_string_clip_rects (s, r, 2);
1665
1666 if (n > 0)
1667 x_set_clip_rectangles (s->f, s->gc, r, n);
1668 s->num_clips = n;
1669 }
1670
1671
1672 /* Set SRC's clipping for output of glyph string DST. This is called
1673 when we are drawing DST's left_overhang or right_overhang only in
1674 the area of SRC. */
1675
1676 static void
x_set_glyph_string_clipping_exactly(struct glyph_string * src,struct glyph_string * dst)1677 x_set_glyph_string_clipping_exactly (struct glyph_string *src, struct glyph_string *dst)
1678 {
1679 XRectangle r;
1680
1681 r.x = src->x;
1682 r.width = src->width;
1683 r.y = src->y;
1684 r.height = src->height;
1685 dst->clip[0] = r;
1686 dst->num_clips = 1;
1687 x_set_clip_rectangles (dst->f, dst->gc, &r, 1);
1688 }
1689
1690
1691 /* RIF:
1692 Compute left and right overhang of glyph string S. */
1693
1694 static void
x_compute_glyph_string_overhangs(struct glyph_string * s)1695 x_compute_glyph_string_overhangs (struct glyph_string *s)
1696 {
1697 if (s->cmp == NULL
1698 && (s->first_glyph->type == CHAR_GLYPH
1699 || s->first_glyph->type == COMPOSITE_GLYPH))
1700 {
1701 struct font_metrics metrics;
1702
1703 if (s->first_glyph->type == CHAR_GLYPH)
1704 {
1705 struct font *font = s->font;
1706 font->driver->text_extents (font, s->char2b, s->nchars, &metrics);
1707 }
1708 else
1709 {
1710 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1711
1712 composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics);
1713 }
1714 s->right_overhang = (metrics.rbearing > metrics.width
1715 ? metrics.rbearing - metrics.width : 0);
1716 s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0;
1717 }
1718 else if (s->cmp)
1719 {
1720 s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
1721 s->left_overhang = - s->cmp->lbearing;
1722 }
1723 }
1724
1725
1726 /* Fill rectangle X, Y, W, H with background color of glyph string S. */
1727
1728 static void
x_clear_glyph_string_rect(struct glyph_string * s,int x,int y,int w,int h)1729 x_clear_glyph_string_rect (struct glyph_string *s, int x, int y, int w, int h)
1730 {
1731 Display *display = FRAME_X_DISPLAY (s->f);
1732 XGCValues xgcv;
1733 XGetGCValues (display, s->gc, GCForeground | GCBackground, &xgcv);
1734 XSetForeground (display, s->gc, xgcv.background);
1735 x_fill_rectangle (s->f, s->gc, x, y, w, h);
1736 XSetForeground (display, s->gc, xgcv.foreground);
1737 }
1738
1739
1740 /* Draw the background of glyph_string S. If S->background_filled_p
1741 is non-zero don't draw it. FORCE_P non-zero means draw the
1742 background even if it wouldn't be drawn normally. This is used
1743 when a string preceding S draws into the background of S, or S
1744 contains the first component of a composition. */
1745
1746 static void
x_draw_glyph_string_background(struct glyph_string * s,bool force_p)1747 x_draw_glyph_string_background (struct glyph_string *s, bool force_p)
1748 {
1749 /* Nothing to do if background has already been drawn or if it
1750 shouldn't be drawn in the first place. */
1751 if (!s->background_filled_p)
1752 {
1753 int box_line_width = max (s->face->box_line_width, 0);
1754
1755 if (s->stippled_p)
1756 {
1757 Display *display = FRAME_X_DISPLAY (s->f);
1758
1759 /* Fill background with a stipple pattern. */
1760 XSetFillStyle (display, s->gc, FillOpaqueStippled);
1761 x_fill_rectangle (s->f, s->gc, s->x,
1762 s->y + box_line_width,
1763 s->background_width,
1764 s->height - 2 * box_line_width);
1765 XSetFillStyle (display, s->gc, FillSolid);
1766 s->background_filled_p = true;
1767 }
1768 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
1769 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust
1770 font dimensions, since the actual glyphs might be
1771 much smaller. So in that case we always clear the
1772 rectangle with background color. */
1773 || FONT_TOO_HIGH (s->font)
1774 || s->font_not_found_p
1775 || s->extends_to_end_of_line_p
1776 || force_p)
1777 {
1778 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
1779 s->background_width,
1780 s->height - 2 * box_line_width);
1781 s->background_filled_p = true;
1782 }
1783 }
1784 }
1785
1786
1787 /* Draw the foreground of glyph string S. */
1788
1789 static void
x_draw_glyph_string_foreground(struct glyph_string * s)1790 x_draw_glyph_string_foreground (struct glyph_string *s)
1791 {
1792 int i, x;
1793
1794 /* If first glyph of S has a left box line, start drawing the text
1795 of S to the right of that box line. */
1796 if (s->face->box != FACE_NO_BOX
1797 && s->first_glyph->left_box_line_p)
1798 x = s->x + eabs (s->face->box_line_width);
1799 else
1800 x = s->x;
1801
1802 /* Draw characters of S as rectangles if S's font could not be
1803 loaded. */
1804 if (s->font_not_found_p)
1805 {
1806 for (i = 0; i < s->nchars; ++i)
1807 {
1808 struct glyph *g = s->first_glyph + i;
1809 x_draw_rectangle (s->f,
1810 s->gc, x, s->y, g->pixel_width - 1,
1811 s->height - 1);
1812 x += g->pixel_width;
1813 }
1814 }
1815 else
1816 {
1817 struct font *font = s->font;
1818 #ifdef USE_CAIRO
1819 if (!EQ (font->driver->type, Qx)
1820 || x_try_cr_xlib_drawable (s->f, s->gc))
1821 {
1822 #endif /* USE_CAIRO */
1823 int boff = font->baseline_offset;
1824 int y;
1825
1826 if (font->vertical_centering)
1827 boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff;
1828
1829 y = s->ybase - boff;
1830 if (s->for_overlaps
1831 || (s->background_filled_p && s->hl != DRAW_CURSOR))
1832 font->driver->draw (s, 0, s->nchars, x, y, false);
1833 else
1834 font->driver->draw (s, 0, s->nchars, x, y, true);
1835 if (s->face->overstrike)
1836 font->driver->draw (s, 0, s->nchars, x + 1, y, false);
1837 #ifdef USE_CAIRO
1838 if (EQ (font->driver->type, Qx))
1839 x_end_cr_xlib_drawable (s->f, s->gc);
1840 }
1841 else
1842 {
1843 /* Fallback for the case that no Xlib Drawable is available
1844 for drawing text with X core fonts. */
1845 if (!(s->for_overlaps
1846 || (s->background_filled_p && s->hl != DRAW_CURSOR)))
1847 {
1848 int box_line_width = max (s->face->box_line_width, 0);
1849
1850 if (s->stippled_p)
1851 {
1852 Display *display = FRAME_X_DISPLAY (s->f);
1853
1854 /* Fill background with a stipple pattern. */
1855 XSetFillStyle (display, s->gc, FillOpaqueStippled);
1856 x_fill_rectangle (s->f, s->gc, s->x,
1857 s->y + box_line_width,
1858 s->background_width,
1859 s->height - 2 * box_line_width);
1860 XSetFillStyle (display, s->gc, FillSolid);
1861 }
1862 else
1863 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
1864 s->background_width,
1865 s->height - 2 * box_line_width);
1866 }
1867 for (i = 0; i < s->nchars; ++i)
1868 {
1869 struct glyph *g = s->first_glyph + i;
1870 x_draw_rectangle (s->f,
1871 s->gc, x, s->y, g->pixel_width - 1,
1872 s->height - 1);
1873 x += g->pixel_width;
1874 }
1875 }
1876 #endif /* USE_CAIRO */
1877 }
1878 }
1879
1880 /* Draw the foreground of composite glyph string S. */
1881
1882 static void
x_draw_composite_glyph_string_foreground(struct glyph_string * s)1883 x_draw_composite_glyph_string_foreground (struct glyph_string *s)
1884 {
1885 int i, j, x;
1886 struct font *font = s->font;
1887
1888 /* If first glyph of S has a left box line, start drawing the text
1889 of S to the right of that box line. */
1890 if (s->face && s->face->box != FACE_NO_BOX
1891 && s->first_glyph->left_box_line_p)
1892 x = s->x + eabs (s->face->box_line_width);
1893 else
1894 x = s->x;
1895
1896 /* S is a glyph string for a composition. S->cmp_from is the index
1897 of the first character drawn for glyphs of this composition.
1898 S->cmp_from == 0 means we are drawing the very first character of
1899 this composition. */
1900
1901 /* Draw a rectangle for the composition if the font for the very
1902 first character of the composition could not be loaded. */
1903 if (s->font_not_found_p)
1904 {
1905 if (s->cmp_from == 0)
1906 x_draw_rectangle (s->f, s->gc, x, s->y,
1907 s->width - 1, s->height - 1);
1908 }
1909 else
1910 #ifdef USE_CAIRO
1911 if (!EQ (font->driver->type, Qx)
1912 || x_try_cr_xlib_drawable (s->f, s->gc))
1913 {
1914 #endif /* USE_CAIRO */
1915 if (! s->first_glyph->u.cmp.automatic)
1916 {
1917 int y = s->ybase;
1918
1919 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
1920 /* TAB in a composition means display glyphs with
1921 padding space on the left or right. */
1922 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
1923 {
1924 int xx = x + s->cmp->offsets[j * 2];
1925 int yy = y - s->cmp->offsets[j * 2 + 1];
1926
1927 font->driver->draw (s, j, j + 1, xx, yy, false);
1928 if (s->face->overstrike)
1929 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
1930 }
1931 }
1932 else
1933 {
1934 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1935 Lisp_Object glyph;
1936 int y = s->ybase;
1937 int width = 0;
1938
1939 for (i = j = s->cmp_from; i < s->cmp_to; i++)
1940 {
1941 glyph = LGSTRING_GLYPH (gstring, i);
1942 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1943 width += LGLYPH_WIDTH (glyph);
1944 else
1945 {
1946 int xoff, yoff, wadjust;
1947
1948 if (j < i)
1949 {
1950 font->driver->draw (s, j, i, x, y, false);
1951 if (s->face->overstrike)
1952 font->driver->draw (s, j, i, x + 1, y, false);
1953 x += width;
1954 }
1955 xoff = LGLYPH_XOFF (glyph);
1956 yoff = LGLYPH_YOFF (glyph);
1957 wadjust = LGLYPH_WADJUST (glyph);
1958 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
1959 if (s->face->overstrike)
1960 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
1961 false);
1962 x += wadjust;
1963 j = i + 1;
1964 width = 0;
1965 }
1966 }
1967 if (j < i)
1968 {
1969 font->driver->draw (s, j, i, x, y, false);
1970 if (s->face->overstrike)
1971 font->driver->draw (s, j, i, x + 1, y, false);
1972 }
1973 }
1974 #ifdef USE_CAIRO
1975 if (EQ (font->driver->type, Qx))
1976 x_end_cr_xlib_drawable (s->f, s->gc);
1977 }
1978 else
1979 {
1980 /* Fallback for the case that no Xlib Drawable is available
1981 for drawing text with X core fonts. */
1982 if (s->cmp_from == 0)
1983 x_draw_rectangle (s->f, s->gc, x, s->y,
1984 s->width - 1, s->height - 1);
1985 }
1986 #endif /* USE_CAIRO */
1987 }
1988
1989
1990 /* Draw the foreground of glyph string S for glyphless characters. */
1991
1992 static void
x_draw_glyphless_glyph_string_foreground(struct glyph_string * s)1993 x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
1994 {
1995 struct glyph *glyph = s->first_glyph;
1996 unsigned char2b[8];
1997 int x, i, j;
1998
1999 /* If first glyph of S has a left box line, start drawing the text
2000 of S to the right of that box line. */
2001 if (s->face && s->face->box != FACE_NO_BOX
2002 && s->first_glyph->left_box_line_p)
2003 x = s->x + eabs (s->face->box_line_width);
2004 else
2005 x = s->x;
2006
2007 s->char2b = char2b;
2008
2009 for (i = 0; i < s->nchars; i++, glyph++)
2010 {
2011 #ifdef GCC_LINT
2012 enum { PACIFY_GCC_BUG_81401 = 1 };
2013 #else
2014 enum { PACIFY_GCC_BUG_81401 = 0 };
2015 #endif
2016 char buf[7 + PACIFY_GCC_BUG_81401];
2017 char *str = NULL;
2018 int len = glyph->u.glyphless.len;
2019
2020 if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
2021 {
2022 if (len > 0
2023 && CHAR_TABLE_P (Vglyphless_char_display)
2024 && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
2025 >= 1))
2026 {
2027 Lisp_Object acronym
2028 = (! glyph->u.glyphless.for_no_font
2029 ? CHAR_TABLE_REF (Vglyphless_char_display,
2030 glyph->u.glyphless.ch)
2031 : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
2032 if (STRINGP (acronym))
2033 str = SSDATA (acronym);
2034 }
2035 }
2036 else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE)
2037 {
2038 unsigned int ch = glyph->u.glyphless.ch;
2039 eassume (ch <= MAX_CHAR);
2040 sprintf (buf, "%0*X", ch < 0x10000 ? 4 : 6, ch);
2041 str = buf;
2042 }
2043
2044 if (str)
2045 {
2046 int upper_len = (len + 1) / 2;
2047
2048 /* It is assured that all LEN characters in STR is ASCII. */
2049 for (j = 0; j < len; j++)
2050 char2b[j] = s->font->driver->encode_char (s->font, str[j]) & 0xFFFF;
2051 s->font->driver->draw (s, 0, upper_len,
2052 x + glyph->slice.glyphless.upper_xoff,
2053 s->ybase + glyph->slice.glyphless.upper_yoff,
2054 false);
2055 s->font->driver->draw (s, upper_len, len,
2056 x + glyph->slice.glyphless.lower_xoff,
2057 s->ybase + glyph->slice.glyphless.lower_yoff,
2058 false);
2059 }
2060 if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
2061 x_draw_rectangle (s->f, s->gc,
2062 x, s->ybase - glyph->ascent,
2063 glyph->pixel_width - 1,
2064 glyph->ascent + glyph->descent - 1);
2065 x += glyph->pixel_width;
2066 }
2067 }
2068
2069 #ifdef USE_X_TOOLKIT
2070
2071 #ifdef USE_LUCID
2072
2073 /* Return the frame on which widget WIDGET is used.. Abort if frame
2074 cannot be determined. */
2075
2076 static struct frame *
x_frame_of_widget(Widget widget)2077 x_frame_of_widget (Widget widget)
2078 {
2079 struct x_display_info *dpyinfo;
2080 Lisp_Object tail, frame;
2081 struct frame *f;
2082
2083 dpyinfo = x_display_info_for_display (XtDisplay (widget));
2084
2085 /* Find the top-level shell of the widget. Note that this function
2086 can be called when the widget is not yet realized, so XtWindow
2087 (widget) == 0. That's the reason we can't simply use
2088 x_any_window_to_frame. */
2089 while (!XtIsTopLevelShell (widget))
2090 widget = XtParent (widget);
2091
2092 /* Look for a frame with that top-level widget. Allocate the color
2093 on that frame to get the right gamma correction value. */
2094 FOR_EACH_FRAME (tail, frame)
2095 {
2096 f = XFRAME (frame);
2097 if (FRAME_X_P (f)
2098 && FRAME_DISPLAY_INFO (f) == dpyinfo
2099 && f->output_data.x->widget == widget)
2100 return f;
2101 }
2102 emacs_abort ();
2103 }
2104
2105 /* Allocate a color which is lighter or darker than *PIXEL by FACTOR
2106 or DELTA. Try a color with RGB values multiplied by FACTOR first.
2107 If this produces the same color as PIXEL, try a color where all RGB
2108 values have DELTA added. Return the allocated color in *PIXEL.
2109 DISPLAY is the X display, CMAP is the colormap to operate on.
2110 Value is true if successful. */
2111
2112 bool
x_alloc_lighter_color_for_widget(Widget widget,Display * display,Colormap cmap,unsigned long * pixel,double factor,int delta)2113 x_alloc_lighter_color_for_widget (Widget widget, Display *display, Colormap cmap,
2114 unsigned long *pixel, double factor, int delta)
2115 {
2116 struct frame *f = x_frame_of_widget (widget);
2117 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
2118 }
2119
2120 #endif /* USE_LUCID */
2121
2122
2123 /* Structure specifying which arguments should be passed by Xt to
2124 cvt_string_to_pixel. We want the widget's screen and colormap. */
2125
2126 static XtConvertArgRec cvt_string_to_pixel_args[] =
2127 {
2128 {XtWidgetBaseOffset, (XtPointer) offsetof (WidgetRec, core.screen),
2129 sizeof (Screen *)},
2130 {XtWidgetBaseOffset, (XtPointer) offsetof (WidgetRec, core.colormap),
2131 sizeof (Colormap)}
2132 };
2133
2134
2135 /* The address of this variable is returned by
2136 cvt_string_to_pixel. */
2137
2138 static Pixel cvt_string_to_pixel_value;
2139
2140
2141 /* Convert a color name to a pixel color.
2142
2143 DPY is the display we are working on.
2144
2145 ARGS is an array of *NARGS XrmValue structures holding additional
2146 information about the widget for which the conversion takes place.
2147 The contents of this array are determined by the specification
2148 in cvt_string_to_pixel_args.
2149
2150 FROM is a pointer to an XrmValue which points to the color name to
2151 convert. TO is an XrmValue in which to return the pixel color.
2152
2153 CLOSURE_RET is a pointer to user-data, in which we record if
2154 we allocated the color or not.
2155
2156 Value is True if successful, False otherwise. */
2157
2158 static Boolean
cvt_string_to_pixel(Display * dpy,XrmValue * args,Cardinal * nargs,XrmValue * from,XrmValue * to,XtPointer * closure_ret)2159 cvt_string_to_pixel (Display *dpy, XrmValue *args, Cardinal *nargs,
2160 XrmValue *from, XrmValue *to,
2161 XtPointer *closure_ret)
2162 {
2163 Screen *screen;
2164 Colormap cmap;
2165 Pixel pixel;
2166 String color_name;
2167 XColor color;
2168
2169 if (*nargs != 2)
2170 {
2171 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
2172 "wrongParameters", "cvt_string_to_pixel",
2173 "XtToolkitError",
2174 "Screen and colormap args required", NULL, NULL);
2175 return False;
2176 }
2177
2178 screen = *(Screen **) args[0].addr;
2179 cmap = *(Colormap *) args[1].addr;
2180 color_name = (String) from->addr;
2181
2182 if (strcmp (color_name, XtDefaultBackground) == 0)
2183 {
2184 *closure_ret = (XtPointer) False;
2185 pixel = WhitePixelOfScreen (screen);
2186 }
2187 else if (strcmp (color_name, XtDefaultForeground) == 0)
2188 {
2189 *closure_ret = (XtPointer) False;
2190 pixel = BlackPixelOfScreen (screen);
2191 }
2192 else if (XParseColor (dpy, cmap, color_name, &color)
2193 && x_alloc_nearest_color_1 (dpy, cmap, &color))
2194 {
2195 pixel = color.pixel;
2196 *closure_ret = (XtPointer) True;
2197 }
2198 else
2199 {
2200 String params[1];
2201 Cardinal nparams = 1;
2202
2203 params[0] = color_name;
2204 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
2205 "badValue", "cvt_string_to_pixel",
2206 "XtToolkitError", "Invalid color '%s'",
2207 params, &nparams);
2208 return False;
2209 }
2210
2211 if (to->addr != NULL)
2212 {
2213 if (to->size < sizeof (Pixel))
2214 {
2215 to->size = sizeof (Pixel);
2216 return False;
2217 }
2218
2219 *(Pixel *) to->addr = pixel;
2220 }
2221 else
2222 {
2223 cvt_string_to_pixel_value = pixel;
2224 to->addr = (XtPointer) &cvt_string_to_pixel_value;
2225 }
2226
2227 to->size = sizeof (Pixel);
2228 return True;
2229 }
2230
2231
2232 /* Free a pixel color which was previously allocated via
2233 cvt_string_to_pixel. This is registered as the destructor
2234 for this type of resource via XtSetTypeConverter.
2235
2236 APP is the application context in which we work.
2237
2238 TO is a pointer to an XrmValue holding the color to free.
2239 CLOSURE is the value we stored in CLOSURE_RET for this color
2240 in cvt_string_to_pixel.
2241
2242 ARGS and NARGS are like for cvt_string_to_pixel. */
2243
2244 static void
cvt_pixel_dtor(XtAppContext app,XrmValuePtr to,XtPointer closure,XrmValuePtr args,Cardinal * nargs)2245 cvt_pixel_dtor (XtAppContext app, XrmValuePtr to, XtPointer closure, XrmValuePtr args,
2246 Cardinal *nargs)
2247 {
2248 if (*nargs != 2)
2249 {
2250 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
2251 "XtToolkitError",
2252 "Screen and colormap arguments required",
2253 NULL, NULL);
2254 }
2255 else if (closure != NULL)
2256 {
2257 /* We did allocate the pixel, so free it. */
2258 Screen *screen = *(Screen **) args[0].addr;
2259 Colormap cmap = *(Colormap *) args[1].addr;
2260 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
2261 (Pixel *) to->addr, 1);
2262 }
2263 }
2264
2265
2266 #endif /* USE_X_TOOLKIT */
2267
2268
2269 /* Value is an array of XColor structures for the contents of the
2270 color map of display DPY. Set *NCELLS to the size of the array.
2271 Note that this probably shouldn't be called for large color maps,
2272 say a 24-bit TrueColor map. */
2273
2274 static const XColor *
x_color_cells(Display * dpy,int * ncells)2275 x_color_cells (Display *dpy, int *ncells)
2276 {
2277 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
2278 eassume (dpyinfo);
2279
2280 if (dpyinfo->color_cells == NULL)
2281 {
2282 Screen *screen = dpyinfo->screen;
2283 int ncolor_cells = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
2284 int i;
2285
2286 dpyinfo->color_cells = xnmalloc (ncolor_cells,
2287 sizeof *dpyinfo->color_cells);
2288 dpyinfo->ncolor_cells = ncolor_cells;
2289
2290 for (i = 0; i < ncolor_cells; ++i)
2291 dpyinfo->color_cells[i].pixel = i;
2292
2293 XQueryColors (dpy, dpyinfo->cmap,
2294 dpyinfo->color_cells, ncolor_cells);
2295 }
2296
2297 *ncells = dpyinfo->ncolor_cells;
2298 return dpyinfo->color_cells;
2299 }
2300
2301
2302 /* On frame F, translate pixel colors to RGB values for the NCOLORS
2303 colors in COLORS. Use cached information, if available. */
2304
2305 void
x_query_colors(struct frame * f,XColor * colors,int ncolors)2306 x_query_colors (struct frame *f, XColor *colors, int ncolors)
2307 {
2308 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2309
2310 if (dpyinfo->red_bits > 0)
2311 {
2312 /* For TrueColor displays, we can decompose the RGB value
2313 directly. */
2314 int i;
2315 unsigned int rmult, gmult, bmult;
2316 unsigned int rmask, gmask, bmask;
2317
2318 rmask = (1 << dpyinfo->red_bits) - 1;
2319 gmask = (1 << dpyinfo->green_bits) - 1;
2320 bmask = (1 << dpyinfo->blue_bits) - 1;
2321 /* If we're widening, for example, 8 bits in the pixel value to
2322 16 bits for the separate-color representation, we want to
2323 extrapolate the lower bits based on those bits available --
2324 in other words, we'd like 0xff to become 0xffff instead of
2325 the 0xff00 we'd get by just zero-filling the lower bits.
2326
2327 We generate a 32-bit scaled-up value and shift it, in case
2328 the bit count doesn't divide 16 evenly (e.g., when dealing
2329 with a 3-3-2 bit RGB display), to get more of the lower bits
2330 correct.
2331
2332 Should we cache the multipliers in dpyinfo? Maybe
2333 special-case the 8-8-8 common case? */
2334 rmult = 0xffffffff / rmask;
2335 gmult = 0xffffffff / gmask;
2336 bmult = 0xffffffff / bmask;
2337
2338 for (i = 0; i < ncolors; ++i)
2339 {
2340 unsigned int r, g, b;
2341 unsigned long pixel = colors[i].pixel;
2342
2343 r = (pixel >> dpyinfo->red_offset) & rmask;
2344 g = (pixel >> dpyinfo->green_offset) & gmask;
2345 b = (pixel >> dpyinfo->blue_offset) & bmask;
2346
2347 colors[i].red = (r * rmult) >> 16;
2348 colors[i].green = (g * gmult) >> 16;
2349 colors[i].blue = (b * bmult) >> 16;
2350 }
2351 return;
2352 }
2353
2354 if (dpyinfo->color_cells)
2355 {
2356 int i;
2357 for (i = 0; i < ncolors; ++i)
2358 {
2359 unsigned long pixel = colors[i].pixel;
2360 eassert (pixel < dpyinfo->ncolor_cells);
2361 eassert (dpyinfo->color_cells[pixel].pixel == pixel);
2362 colors[i] = dpyinfo->color_cells[pixel];
2363 }
2364 return;
2365 }
2366
2367 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
2368 }
2369
2370 /* Store F's background color into *BGCOLOR. */
2371
2372 static void
x_query_frame_background_color(struct frame * f,XColor * bgcolor)2373 x_query_frame_background_color (struct frame *f, XColor *bgcolor)
2374 {
2375 bgcolor->pixel = FRAME_BACKGROUND_PIXEL (f);
2376 x_query_colors (f, bgcolor, 1);
2377 }
2378
2379 #define HEX_COLOR_NAME_LENGTH 32
2380
2381 /* On frame F, translate the color name to RGB values. Use cached
2382 information, if possible.
2383
2384 Note that there is currently no way to clean old entries out of the
2385 cache. However, it is limited to names in the server's database,
2386 and names we've actually looked up; list-colors-display is probably
2387 the most color-intensive case we're likely to hit. */
2388
x_parse_color(struct frame * f,const char * color_name,XColor * color)2389 Status x_parse_color (struct frame *f, const char *color_name,
2390 XColor *color)
2391 {
2392 Display *dpy = FRAME_X_DISPLAY (f);
2393 Colormap cmap = FRAME_X_COLORMAP (f);
2394 struct color_name_cache_entry *cache_entry;
2395
2396 if (color_name[0] == '#')
2397 {
2398 /* Don't pass #RGB strings directly to XParseColor, because that
2399 follows the X convention of zero-extending each channel
2400 value: #f00 means #f00000. We want the convention of scaling
2401 channel values, so #f00 means #ff0000, just as it does for
2402 HTML, SVG, and CSS.
2403
2404 So we translate #f00 to rgb:f/0/0, which X handles
2405 differently. */
2406 char rgb_color_name[HEX_COLOR_NAME_LENGTH];
2407 int len = strlen (color_name);
2408 int digits_per_channel;
2409 if (len == 4)
2410 digits_per_channel = 1;
2411 else if (len == 7)
2412 digits_per_channel = 2;
2413 else if (len == 10)
2414 digits_per_channel = 3;
2415 else if (len == 13)
2416 digits_per_channel = 4;
2417 else
2418 return 0;
2419
2420 snprintf (rgb_color_name, sizeof rgb_color_name, "rgb:%.*s/%.*s/%.*s",
2421 digits_per_channel, color_name + 1,
2422 digits_per_channel, color_name + digits_per_channel + 1,
2423 digits_per_channel, color_name + 2 * digits_per_channel + 1);
2424
2425 /* The rgb form is parsed directly by XParseColor without
2426 talking to the X server. No need for caching. */
2427 return XParseColor (dpy, cmap, rgb_color_name, color);
2428 }
2429
2430 for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names; cache_entry;
2431 cache_entry = cache_entry->next)
2432 {
2433 if (!xstrcasecmp(cache_entry->name, color_name))
2434 {
2435 *color = cache_entry->rgb;
2436 return 1;
2437 }
2438 }
2439
2440 if (XParseColor (dpy, cmap, color_name, color) == 0)
2441 /* No caching of negative results, currently. */
2442 return 0;
2443
2444 cache_entry = xzalloc (sizeof *cache_entry);
2445 cache_entry->rgb = *color;
2446 cache_entry->name = xstrdup (color_name);
2447 cache_entry->next = FRAME_DISPLAY_INFO (f)->color_names;
2448 FRAME_DISPLAY_INFO (f)->color_names = cache_entry;
2449 return 1;
2450 }
2451
2452
2453 /* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
2454 exact match can't be allocated, try the nearest color available.
2455 Value is true if successful. Set *COLOR to the color
2456 allocated. */
2457
2458 static bool
x_alloc_nearest_color_1(Display * dpy,Colormap cmap,XColor * color)2459 x_alloc_nearest_color_1 (Display *dpy, Colormap cmap, XColor *color)
2460 {
2461 bool rc;
2462
2463 rc = XAllocColor (dpy, cmap, color) != 0;
2464 if (rc == 0)
2465 {
2466 /* If we got to this point, the colormap is full, so we're going
2467 to try to get the next closest color. The algorithm used is
2468 a least-squares matching, which is what X uses for closest
2469 color matching with StaticColor visuals. */
2470 int nearest, i;
2471 int max_color_delta = 255;
2472 int max_delta = 3 * max_color_delta;
2473 int nearest_delta = max_delta + 1;
2474 int ncells;
2475 const XColor *cells = x_color_cells (dpy, &ncells);
2476
2477 for (nearest = i = 0; i < ncells; ++i)
2478 {
2479 int dred = (color->red >> 8) - (cells[i].red >> 8);
2480 int dgreen = (color->green >> 8) - (cells[i].green >> 8);
2481 int dblue = (color->blue >> 8) - (cells[i].blue >> 8);
2482 int delta = dred * dred + dgreen * dgreen + dblue * dblue;
2483
2484 if (delta < nearest_delta)
2485 {
2486 nearest = i;
2487 nearest_delta = delta;
2488 }
2489 }
2490
2491 color->red = cells[nearest].red;
2492 color->green = cells[nearest].green;
2493 color->blue = cells[nearest].blue;
2494 rc = XAllocColor (dpy, cmap, color) != 0;
2495 }
2496 else
2497 {
2498 /* If allocation succeeded, and the allocated pixel color is not
2499 equal to a cached pixel color recorded earlier, there was a
2500 change in the colormap, so clear the color cache. */
2501 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
2502 eassume (dpyinfo);
2503
2504 if (dpyinfo->color_cells)
2505 {
2506 XColor *cached_color = &dpyinfo->color_cells[color->pixel];
2507 if (cached_color->red != color->red
2508 || cached_color->blue != color->blue
2509 || cached_color->green != color->green)
2510 {
2511 xfree (dpyinfo->color_cells);
2512 dpyinfo->color_cells = NULL;
2513 dpyinfo->ncolor_cells = 0;
2514 }
2515 }
2516 }
2517
2518 #ifdef DEBUG_X_COLORS
2519 if (rc)
2520 register_color (color->pixel);
2521 #endif /* DEBUG_X_COLORS */
2522
2523 return rc;
2524 }
2525
2526
2527 /* Allocate the color COLOR->pixel on frame F, colormap CMAP, after
2528 gamma correction. If an exact match can't be allocated, try the
2529 nearest color available. Value is true if successful. Set *COLOR
2530 to the color allocated. */
2531
2532 bool
x_alloc_nearest_color(struct frame * f,Colormap cmap,XColor * color)2533 x_alloc_nearest_color (struct frame *f, Colormap cmap, XColor *color)
2534 {
2535 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2536
2537 gamma_correct (f, color);
2538
2539 if (dpyinfo->red_bits > 0)
2540 {
2541 color->pixel = x_make_truecolor_pixel (dpyinfo,
2542 color->red,
2543 color->green,
2544 color->blue);
2545 return true;
2546 }
2547
2548 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
2549 }
2550
2551
2552 /* Allocate color PIXEL on frame F. PIXEL must already be allocated.
2553 It's necessary to do this instead of just using PIXEL directly to
2554 get color reference counts right. */
2555
2556 unsigned long
x_copy_color(struct frame * f,unsigned long pixel)2557 x_copy_color (struct frame *f, unsigned long pixel)
2558 {
2559 XColor color;
2560
2561 /* If display has an immutable color map, freeing colors is not
2562 necessary and some servers don't allow it. Since we won't free a
2563 color once we've allocated it, we don't need to re-allocate it to
2564 maintain the server's reference count. */
2565 if (!x_mutable_colormap (FRAME_X_VISUAL (f)))
2566 return pixel;
2567
2568 color.pixel = pixel;
2569 block_input ();
2570 /* The color could still be found in the color_cells array. */
2571 x_query_colors (f, &color, 1);
2572 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
2573 unblock_input ();
2574 #ifdef DEBUG_X_COLORS
2575 register_color (pixel);
2576 #endif
2577 return color.pixel;
2578 }
2579
2580
2581 /* Brightness beyond which a color won't have its highlight brightness
2582 boosted.
2583
2584 Nominally, highlight colors for `3d' faces are calculated by
2585 brightening an object's color by a constant scale factor, but this
2586 doesn't yield good results for dark colors, so for colors who's
2587 brightness is less than this value (on a scale of 0-65535) have an
2588 use an additional additive factor.
2589
2590 The value here is set so that the default menu-bar/mode-line color
2591 (grey75) will not have its highlights changed at all. */
2592 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
2593
2594
2595 /* Allocate a color which is lighter or darker than *PIXEL by FACTOR
2596 or DELTA. Try a color with RGB values multiplied by FACTOR first.
2597 If this produces the same color as PIXEL, try a color where all RGB
2598 values have DELTA added. Return the allocated color in *PIXEL.
2599 DISPLAY is the X display, CMAP is the colormap to operate on.
2600 Value is non-zero if successful. */
2601
2602 static bool
x_alloc_lighter_color(struct frame * f,Display * display,Colormap cmap,unsigned long * pixel,double factor,int delta)2603 x_alloc_lighter_color (struct frame *f, Display *display, Colormap cmap,
2604 unsigned long *pixel, double factor, int delta)
2605 {
2606 XColor color, new;
2607 long bright;
2608 bool success_p;
2609
2610 /* Get RGB color values. */
2611 color.pixel = *pixel;
2612 x_query_colors (f, &color, 1);
2613
2614 /* Change RGB values by specified FACTOR. Avoid overflow! */
2615 eassert (factor >= 0);
2616 new.red = min (0xffff, factor * color.red);
2617 new.green = min (0xffff, factor * color.green);
2618 new.blue = min (0xffff, factor * color.blue);
2619
2620 /* Calculate brightness of COLOR. */
2621 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
2622
2623 /* We only boost colors that are darker than
2624 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
2625 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
2626 /* Make an additive adjustment to NEW, because it's dark enough so
2627 that scaling by FACTOR alone isn't enough. */
2628 {
2629 /* How far below the limit this color is (0 - 1, 1 being darker). */
2630 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
2631 /* The additive adjustment. */
2632 int min_delta = delta * dimness * factor / 2;
2633
2634 if (factor < 1)
2635 {
2636 new.red = max (0, new.red - min_delta);
2637 new.green = max (0, new.green - min_delta);
2638 new.blue = max (0, new.blue - min_delta);
2639 }
2640 else
2641 {
2642 new.red = min (0xffff, min_delta + new.red);
2643 new.green = min (0xffff, min_delta + new.green);
2644 new.blue = min (0xffff, min_delta + new.blue);
2645 }
2646 }
2647
2648 /* Try to allocate the color. */
2649 success_p = x_alloc_nearest_color (f, cmap, &new);
2650 if (success_p)
2651 {
2652 if (new.pixel == *pixel)
2653 {
2654 /* If we end up with the same color as before, try adding
2655 delta to the RGB values. */
2656 x_free_colors (f, &new.pixel, 1);
2657
2658 new.red = min (0xffff, delta + color.red);
2659 new.green = min (0xffff, delta + color.green);
2660 new.blue = min (0xffff, delta + color.blue);
2661 success_p = x_alloc_nearest_color (f, cmap, &new);
2662 }
2663 else
2664 success_p = true;
2665 *pixel = new.pixel;
2666 }
2667
2668 return success_p;
2669 }
2670
2671
2672 /* Set up the foreground color for drawing relief lines of glyph
2673 string S. RELIEF is a pointer to a struct relief containing the GC
2674 with which lines will be drawn. Use a color that is FACTOR or
2675 DELTA lighter or darker than the relief's background which is found
2676 in S->f->output_data.x->relief_background. If such a color cannot
2677 be allocated, use DEFAULT_PIXEL, instead. */
2678
2679 static void
x_setup_relief_color(struct frame * f,struct relief * relief,double factor,int delta,unsigned long default_pixel)2680 x_setup_relief_color (struct frame *f, struct relief *relief, double factor,
2681 int delta, unsigned long default_pixel)
2682 {
2683 XGCValues xgcv;
2684 struct x_output *di = f->output_data.x;
2685 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
2686 unsigned long pixel;
2687 unsigned long background = di->relief_background;
2688 Colormap cmap = FRAME_X_COLORMAP (f);
2689 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2690 Display *dpy = FRAME_X_DISPLAY (f);
2691
2692 xgcv.graphics_exposures = False;
2693 xgcv.line_width = 1;
2694
2695 /* Free previously allocated color. The color cell will be reused
2696 when it has been freed as many times as it was allocated, so this
2697 doesn't affect faces using the same colors. */
2698 if (relief->gc && relief->pixel != -1)
2699 {
2700 x_free_colors (f, &relief->pixel, 1);
2701 relief->pixel = -1;
2702 }
2703
2704 /* Allocate new color. */
2705 xgcv.foreground = default_pixel;
2706 pixel = background;
2707 if (dpyinfo->n_planes != 1
2708 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
2709 xgcv.foreground = relief->pixel = pixel;
2710
2711 if (relief->gc == 0)
2712 {
2713 xgcv.stipple = dpyinfo->gray;
2714 mask |= GCStipple;
2715 relief->gc = XCreateGC (dpy, FRAME_X_DRAWABLE (f), mask, &xgcv);
2716 }
2717 else
2718 XChangeGC (dpy, relief->gc, mask, &xgcv);
2719 }
2720
2721
2722 /* Set up colors for the relief lines around glyph string S. */
2723
2724 static void
x_setup_relief_colors(struct glyph_string * s)2725 x_setup_relief_colors (struct glyph_string *s)
2726 {
2727 struct x_output *di = s->f->output_data.x;
2728 unsigned long color;
2729
2730 if (s->face->use_box_color_for_shadows_p)
2731 color = s->face->box_color;
2732 else if (s->first_glyph->type == IMAGE_GLYPH
2733 && s->img->pixmap
2734 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2735 color = IMAGE_BACKGROUND (s->img, s->f, 0);
2736 else
2737 {
2738 XGCValues xgcv;
2739
2740 /* Get the background color of the face. */
2741 XGetGCValues (FRAME_X_DISPLAY (s->f), s->gc, GCBackground, &xgcv);
2742 color = xgcv.background;
2743 }
2744
2745 if (di->white_relief.gc == 0
2746 || color != di->relief_background)
2747 {
2748 di->relief_background = color;
2749 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
2750 WHITE_PIX_DEFAULT (s->f));
2751 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
2752 BLACK_PIX_DEFAULT (s->f));
2753 }
2754 }
2755
2756
2757 /* Draw a relief on frame F inside the rectangle given by LEFT_X,
2758 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
2759 to draw, it must be >= 0. RAISED_P means draw a raised
2760 relief. LEFT_P means draw a relief on the left side of
2761 the rectangle. RIGHT_P means draw a relief on the right
2762 side of the rectangle. CLIP_RECT is the clipping rectangle to use
2763 when drawing. */
2764
2765 static void
x_draw_relief_rect(struct frame * f,int left_x,int top_y,int right_x,int bottom_y,int width,bool raised_p,bool top_p,bool bot_p,bool left_p,bool right_p,XRectangle * clip_rect)2766 x_draw_relief_rect (struct frame *f,
2767 int left_x, int top_y, int right_x, int bottom_y,
2768 int width, bool raised_p, bool top_p, bool bot_p,
2769 bool left_p, bool right_p,
2770 XRectangle *clip_rect)
2771 {
2772 #ifdef USE_CAIRO
2773 GC top_left_gc, bottom_right_gc;
2774 int corners = 0;
2775
2776 if (raised_p)
2777 {
2778 top_left_gc = f->output_data.x->white_relief.gc;
2779 bottom_right_gc = f->output_data.x->black_relief.gc;
2780 }
2781 else
2782 {
2783 top_left_gc = f->output_data.x->black_relief.gc;
2784 bottom_right_gc = f->output_data.x->white_relief.gc;
2785 }
2786
2787 x_set_clip_rectangles (f, top_left_gc, clip_rect, 1);
2788 x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1);
2789
2790 if (left_p)
2791 {
2792 x_fill_rectangle (f, top_left_gc, left_x, top_y,
2793 width, bottom_y + 1 - top_y);
2794 if (top_p)
2795 corners |= 1 << CORNER_TOP_LEFT;
2796 if (bot_p)
2797 corners |= 1 << CORNER_BOTTOM_LEFT;
2798 }
2799 if (right_p)
2800 {
2801 x_fill_rectangle (f, bottom_right_gc, right_x + 1 - width, top_y,
2802 width, bottom_y + 1 - top_y);
2803 if (top_p)
2804 corners |= 1 << CORNER_TOP_RIGHT;
2805 if (bot_p)
2806 corners |= 1 << CORNER_BOTTOM_RIGHT;
2807 }
2808 if (top_p)
2809 {
2810 if (!right_p)
2811 x_fill_rectangle (f, top_left_gc, left_x, top_y,
2812 right_x + 1 - left_x, width);
2813 else
2814 x_fill_trapezoid_for_relief (f, top_left_gc, left_x, top_y,
2815 right_x + 1 - left_x, width, 1);
2816 }
2817 if (bot_p)
2818 {
2819 if (!left_p)
2820 x_fill_rectangle (f, bottom_right_gc, left_x, bottom_y + 1 - width,
2821 right_x + 1 - left_x, width);
2822 else
2823 x_fill_trapezoid_for_relief (f, bottom_right_gc,
2824 left_x, bottom_y + 1 - width,
2825 right_x + 1 - left_x, width, 0);
2826 }
2827 if (left_p && width != 1)
2828 x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
2829 1, bottom_y + 1 - top_y);
2830 if (top_p && width != 1)
2831 x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
2832 right_x + 1 - left_x, 1);
2833 if (corners)
2834 {
2835 XSetBackground (FRAME_X_DISPLAY (f), top_left_gc,
2836 FRAME_BACKGROUND_PIXEL (f));
2837 x_erase_corners_for_relief (f, top_left_gc, left_x, top_y,
2838 right_x - left_x + 1, bottom_y - top_y + 1,
2839 6, 1, corners);
2840 }
2841
2842 x_reset_clip_rectangles (f, top_left_gc);
2843 x_reset_clip_rectangles (f, bottom_right_gc);
2844 #else
2845 Display *dpy = FRAME_X_DISPLAY (f);
2846 Drawable drawable = FRAME_X_DRAWABLE (f);
2847 int i;
2848 GC gc;
2849
2850 if (raised_p)
2851 gc = f->output_data.x->white_relief.gc;
2852 else
2853 gc = f->output_data.x->black_relief.gc;
2854 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
2855
2856 /* This code is more complicated than it has to be, because of two
2857 minor hacks to make the boxes look nicer: (i) if width > 1, draw
2858 the outermost line using the black relief. (ii) Omit the four
2859 corner pixels. */
2860
2861 /* Top. */
2862 if (top_p)
2863 {
2864 if (width == 1)
2865 XDrawLine (dpy, drawable, gc,
2866 left_x + left_p, top_y,
2867 right_x + !right_p, top_y);
2868
2869 for (i = 1; i < width; ++i)
2870 XDrawLine (dpy, drawable, gc,
2871 left_x + i * left_p, top_y + i,
2872 right_x + 1 - i * right_p, top_y + i);
2873 }
2874
2875 /* Left. */
2876 if (left_p)
2877 {
2878 if (width == 1)
2879 XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y);
2880
2881 x_clear_area(f, left_x, top_y, 1, 1);
2882 x_clear_area(f, left_x, bottom_y, 1, 1);
2883
2884 for (i = (width > 1 ? 1 : 0); i < width; ++i)
2885 XDrawLine (dpy, drawable, gc,
2886 left_x + i, top_y + (i + 1) * top_p,
2887 left_x + i, bottom_y + 1 - (i + 1) * bot_p);
2888 }
2889
2890 XSetClipMask (dpy, gc, None);
2891 if (raised_p)
2892 gc = f->output_data.x->black_relief.gc;
2893 else
2894 gc = f->output_data.x->white_relief.gc;
2895 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
2896
2897 if (width > 1)
2898 {
2899 /* Outermost top line. */
2900 if (top_p)
2901 XDrawLine (dpy, drawable, gc,
2902 left_x + left_p, top_y,
2903 right_x + !right_p, top_y);
2904
2905 /* Outermost left line. */
2906 if (left_p)
2907 XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y);
2908 }
2909
2910 /* Bottom. */
2911 if (bot_p)
2912 {
2913 XDrawLine (dpy, drawable, gc,
2914 left_x + left_p, bottom_y,
2915 right_x + !right_p, bottom_y);
2916 for (i = 1; i < width; ++i)
2917 XDrawLine (dpy, drawable, gc,
2918 left_x + i * left_p, bottom_y - i,
2919 right_x + 1 - i * right_p, bottom_y - i);
2920 }
2921
2922 /* Right. */
2923 if (right_p)
2924 {
2925 x_clear_area(f, right_x, top_y, 1, 1);
2926 x_clear_area(f, right_x, bottom_y, 1, 1);
2927 for (i = 0; i < width; ++i)
2928 XDrawLine (dpy, drawable, gc,
2929 right_x - i, top_y + (i + 1) * top_p,
2930 right_x - i, bottom_y + 1 - (i + 1) * bot_p);
2931 }
2932
2933 x_reset_clip_rectangles (f, gc);
2934
2935 #endif
2936 }
2937
2938
2939 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
2940 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
2941 draw, it must be >= 0. LEFT_P means draw a line on the
2942 left side of the rectangle. RIGHT_P means draw a line
2943 on the right side of the rectangle. CLIP_RECT is the clipping
2944 rectangle to use when drawing. */
2945
2946 static void
x_draw_box_rect(struct glyph_string * s,int left_x,int top_y,int right_x,int bottom_y,int width,bool left_p,bool right_p,XRectangle * clip_rect)2947 x_draw_box_rect (struct glyph_string *s,
2948 int left_x, int top_y, int right_x, int bottom_y, int width,
2949 bool left_p, bool right_p, XRectangle *clip_rect)
2950 {
2951 Display *display = FRAME_X_DISPLAY (s->f);
2952 XGCValues xgcv;
2953
2954 XGetGCValues (display, s->gc, GCForeground, &xgcv);
2955 XSetForeground (display, s->gc, s->face->box_color);
2956 x_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
2957
2958 /* Top. */
2959 x_fill_rectangle (s->f, s->gc,
2960 left_x, top_y, right_x - left_x + 1, width);
2961
2962 /* Left. */
2963 if (left_p)
2964 x_fill_rectangle (s->f, s->gc,
2965 left_x, top_y, width, bottom_y - top_y + 1);
2966
2967 /* Bottom. */
2968 x_fill_rectangle (s->f, s->gc,
2969 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
2970
2971 /* Right. */
2972 if (right_p)
2973 x_fill_rectangle (s->f, s->gc,
2974 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
2975
2976 XSetForeground (display, s->gc, xgcv.foreground);
2977 x_reset_clip_rectangles (s->f, s->gc);
2978 }
2979
2980
2981 /* Draw a box around glyph string S. */
2982
2983 static void
x_draw_glyph_string_box(struct glyph_string * s)2984 x_draw_glyph_string_box (struct glyph_string *s)
2985 {
2986 int width, left_x, right_x, top_y, bottom_y, last_x;
2987 bool raised_p, left_p, right_p;
2988 struct glyph *last_glyph;
2989 XRectangle clip_rect;
2990
2991 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2992 ? WINDOW_RIGHT_EDGE_X (s->w)
2993 : window_box_right (s->w, s->area));
2994
2995 /* The glyph that may have a right box line. */
2996 last_glyph = (s->cmp || s->img
2997 ? s->first_glyph
2998 : s->first_glyph + s->nchars - 1);
2999
3000 width = eabs (s->face->box_line_width);
3001 raised_p = s->face->box == FACE_RAISED_BOX;
3002 left_x = s->x;
3003 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3004 ? last_x - 1
3005 : min (last_x, s->x + s->background_width) - 1);
3006 top_y = s->y;
3007 bottom_y = top_y + s->height - 1;
3008
3009 left_p = (s->first_glyph->left_box_line_p
3010 || (s->hl == DRAW_MOUSE_FACE
3011 && (s->prev == NULL
3012 || s->prev->hl != s->hl)));
3013 right_p = (last_glyph->right_box_line_p
3014 || (s->hl == DRAW_MOUSE_FACE
3015 && (s->next == NULL
3016 || s->next->hl != s->hl)));
3017
3018 get_glyph_string_clip_rect (s, &clip_rect);
3019
3020 if (s->face->box == FACE_SIMPLE_BOX)
3021 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3022 left_p, right_p, &clip_rect);
3023 else
3024 {
3025 x_setup_relief_colors (s);
3026 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3027 width, raised_p, true, true, left_p, right_p,
3028 &clip_rect);
3029 }
3030 }
3031
3032
3033 #ifndef USE_CAIRO
3034 static void
x_composite_image(struct glyph_string * s,Pixmap dest,int srcX,int srcY,int dstX,int dstY,int width,int height)3035 x_composite_image (struct glyph_string *s, Pixmap dest,
3036 int srcX, int srcY, int dstX, int dstY,
3037 int width, int height)
3038 {
3039 Display *display = FRAME_X_DISPLAY (s->f);
3040 #ifdef HAVE_XRENDER
3041 if (s->img->picture)
3042 {
3043 Picture destination;
3044 XRenderPictFormat *default_format;
3045 XRenderPictureAttributes attr;
3046
3047 default_format = XRenderFindVisualFormat (display,
3048 DefaultVisual (display, 0));
3049 destination = XRenderCreatePicture (display, dest,
3050 default_format, 0, &attr);
3051
3052 XRenderComposite (display, s->img->mask_picture ? PictOpOver : PictOpSrc,
3053 s->img->picture, s->img->mask_picture, destination,
3054 srcX, srcY,
3055 srcX, srcY,
3056 dstX, dstY,
3057 width, height);
3058
3059 XRenderFreePicture (display, destination);
3060 return;
3061 }
3062 #endif
3063
3064 XCopyArea (display, s->img->pixmap,
3065 dest, s->gc,
3066 srcX, srcY,
3067 width, height, dstX, dstY);
3068 }
3069 #endif /* !USE_CAIRO */
3070
3071
3072 /* Draw foreground of image glyph string S. */
3073
3074 static void
x_draw_image_foreground(struct glyph_string * s)3075 x_draw_image_foreground (struct glyph_string *s)
3076 {
3077 int x = s->x;
3078 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3079
3080 /* If first glyph of S has a left box line, start drawing it to the
3081 right of that line. */
3082 if (s->face->box != FACE_NO_BOX
3083 && s->first_glyph->left_box_line_p
3084 && s->slice.x == 0)
3085 x += eabs (s->face->box_line_width);
3086
3087 /* If there is a margin around the image, adjust x- and y-position
3088 by that margin. */
3089 if (s->slice.x == 0)
3090 x += s->img->hmargin;
3091 if (s->slice.y == 0)
3092 y += s->img->vmargin;
3093
3094 #ifdef USE_CAIRO
3095 if (s->img->cr_data)
3096 {
3097 x_set_glyph_string_clipping (s);
3098 x_cr_draw_image (s->f, s->gc, s->img->cr_data,
3099 s->slice.x, s->slice.y, s->slice.width, s->slice.height,
3100 x, y, true);
3101 if (!s->img->mask)
3102 {
3103 /* When the image has a mask, we can expect that at
3104 least part of a mouse highlight or a block cursor will
3105 be visible. If the image doesn't have a mask, make
3106 a block cursor visible by drawing a rectangle around
3107 the image. I believe it's looking better if we do
3108 nothing here for mouse-face. */
3109 if (s->hl == DRAW_CURSOR)
3110 {
3111 int relief = eabs (s->img->relief);
3112 x_draw_rectangle (s->f, s->gc, x - relief, y - relief,
3113 s->slice.width + relief*2 - 1,
3114 s->slice.height + relief*2 - 1);
3115 }
3116 }
3117 }
3118 #else /* ! USE_CAIRO */
3119 if (s->img->pixmap)
3120 {
3121 if (s->img->mask)
3122 {
3123 /* We can't set both a clip mask and use XSetClipRectangles
3124 because the latter also sets a clip mask. We also can't
3125 trust on the shape extension to be available
3126 (XShapeCombineRegion). So, compute the rectangle to draw
3127 manually. */
3128 /* FIXME: Do we need to do this when using XRender compositing? */
3129 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3130 | GCFunction);
3131 XGCValues xgcv;
3132 XRectangle clip_rect, image_rect, r;
3133
3134 xgcv.clip_mask = s->img->mask;
3135 xgcv.clip_x_origin = x;
3136 xgcv.clip_y_origin = y;
3137 xgcv.function = GXcopy;
3138 XChangeGC (FRAME_X_DISPLAY (s->f), s->gc, mask, &xgcv);
3139
3140 get_glyph_string_clip_rect (s, &clip_rect);
3141 image_rect.x = x;
3142 image_rect.y = y;
3143 image_rect.width = s->slice.width;
3144 image_rect.height = s->slice.height;
3145 if (gui_intersect_rectangles (&clip_rect, &image_rect, &r))
3146 x_composite_image (s, FRAME_X_DRAWABLE (s->f),
3147 s->slice.x + r.x - x, s->slice.y + r.y - y,
3148 r.x, r.y, r.width, r.height);
3149 }
3150 else
3151 {
3152 XRectangle clip_rect, image_rect, r;
3153
3154 get_glyph_string_clip_rect (s, &clip_rect);
3155 image_rect.x = x;
3156 image_rect.y = y;
3157 image_rect.width = s->slice.width;
3158 image_rect.height = s->slice.height;
3159 if (gui_intersect_rectangles (&clip_rect, &image_rect, &r))
3160 x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - x, s->slice.y + r.y - y,
3161 r.x, r.y, r.width, r.height);
3162
3163 /* When the image has a mask, we can expect that at
3164 least part of a mouse highlight or a block cursor will
3165 be visible. If the image doesn't have a mask, make
3166 a block cursor visible by drawing a rectangle around
3167 the image. I believe it's looking better if we do
3168 nothing here for mouse-face. */
3169 if (s->hl == DRAW_CURSOR)
3170 {
3171 int relief = eabs (s->img->relief);
3172 x_draw_rectangle (s->f, s->gc,
3173 x - relief, y - relief,
3174 s->slice.width + relief*2 - 1,
3175 s->slice.height + relief*2 - 1);
3176 }
3177 }
3178 }
3179 #endif /* ! USE_CAIRO */
3180 else
3181 /* Draw a rectangle if image could not be loaded. */
3182 x_draw_rectangle (s->f, s->gc, x, y,
3183 s->slice.width - 1, s->slice.height - 1);
3184 }
3185
3186
3187 /* Draw a relief around the image glyph string S. */
3188
3189 static void
x_draw_image_relief(struct glyph_string * s)3190 x_draw_image_relief (struct glyph_string *s)
3191 {
3192 int x1, y1, thick;
3193 bool raised_p, top_p, bot_p, left_p, right_p;
3194 int extra_x, extra_y;
3195 XRectangle r;
3196 int x = s->x;
3197 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3198
3199 /* If first glyph of S has a left box line, start drawing it to the
3200 right of that line. */
3201 if (s->face->box != FACE_NO_BOX
3202 && s->first_glyph->left_box_line_p
3203 && s->slice.x == 0)
3204 x += eabs (s->face->box_line_width);
3205
3206 /* If there is a margin around the image, adjust x- and y-position
3207 by that margin. */
3208 if (s->slice.x == 0)
3209 x += s->img->hmargin;
3210 if (s->slice.y == 0)
3211 y += s->img->vmargin;
3212
3213 if (s->hl == DRAW_IMAGE_SUNKEN
3214 || s->hl == DRAW_IMAGE_RAISED)
3215 {
3216 thick = (tab_bar_button_relief < 0
3217 ? DEFAULT_TAB_BAR_BUTTON_RELIEF
3218 : (tool_bar_button_relief < 0
3219 ? DEFAULT_TOOL_BAR_BUTTON_RELIEF
3220 : min (tool_bar_button_relief, 1000000)));
3221 raised_p = s->hl == DRAW_IMAGE_RAISED;
3222 }
3223 else
3224 {
3225 thick = eabs (s->img->relief);
3226 raised_p = s->img->relief > 0;
3227 }
3228
3229 x1 = x + s->slice.width - 1;
3230 y1 = y + s->slice.height - 1;
3231
3232 extra_x = extra_y = 0;
3233 if (s->face->id == TAB_BAR_FACE_ID)
3234 {
3235 if (CONSP (Vtab_bar_button_margin)
3236 && FIXNUMP (XCAR (Vtab_bar_button_margin))
3237 && FIXNUMP (XCDR (Vtab_bar_button_margin)))
3238 {
3239 extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin));
3240 extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin));
3241 }
3242 else if (FIXNUMP (Vtab_bar_button_margin))
3243 extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin);
3244 }
3245
3246 if (s->face->id == TOOL_BAR_FACE_ID)
3247 {
3248 if (CONSP (Vtool_bar_button_margin)
3249 && FIXNUMP (XCAR (Vtool_bar_button_margin))
3250 && FIXNUMP (XCDR (Vtool_bar_button_margin)))
3251 {
3252 extra_x = XFIXNUM (XCAR (Vtool_bar_button_margin));
3253 extra_y = XFIXNUM (XCDR (Vtool_bar_button_margin));
3254 }
3255 else if (FIXNUMP (Vtool_bar_button_margin))
3256 extra_x = extra_y = XFIXNUM (Vtool_bar_button_margin);
3257 }
3258
3259 top_p = bot_p = left_p = right_p = false;
3260
3261 if (s->slice.x == 0)
3262 x -= thick + extra_x, left_p = true;
3263 if (s->slice.y == 0)
3264 y -= thick + extra_y, top_p = true;
3265 if (s->slice.x + s->slice.width == s->img->width)
3266 x1 += thick + extra_x, right_p = true;
3267 if (s->slice.y + s->slice.height == s->img->height)
3268 y1 += thick + extra_y, bot_p = true;
3269
3270 x_setup_relief_colors (s);
3271 get_glyph_string_clip_rect (s, &r);
3272 x_draw_relief_rect (s->f, x, y, x1, y1, thick, raised_p,
3273 top_p, bot_p, left_p, right_p, &r);
3274 }
3275
3276
3277 #ifndef USE_CAIRO
3278 /* Draw the foreground of image glyph string S to PIXMAP. */
3279
3280 static void
x_draw_image_foreground_1(struct glyph_string * s,Pixmap pixmap)3281 x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap)
3282 {
3283 int x = 0;
3284 int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice);
3285
3286 /* If first glyph of S has a left box line, start drawing it to the
3287 right of that line. */
3288 if (s->face->box != FACE_NO_BOX
3289 && s->first_glyph->left_box_line_p
3290 && s->slice.x == 0)
3291 x += eabs (s->face->box_line_width);
3292
3293 /* If there is a margin around the image, adjust x- and y-position
3294 by that margin. */
3295 if (s->slice.x == 0)
3296 x += s->img->hmargin;
3297 if (s->slice.y == 0)
3298 y += s->img->vmargin;
3299
3300 if (s->img->pixmap)
3301 {
3302 Display *display = FRAME_X_DISPLAY (s->f);
3303
3304 if (s->img->mask)
3305 {
3306 /* We can't set both a clip mask and use XSetClipRectangles
3307 because the latter also sets a clip mask. We also can't
3308 trust on the shape extension to be available
3309 (XShapeCombineRegion). So, compute the rectangle to draw
3310 manually. */
3311 /* FIXME: Do we need to do this when using XRender compositing? */
3312 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3313 | GCFunction);
3314 XGCValues xgcv;
3315
3316 xgcv.clip_mask = s->img->mask;
3317 xgcv.clip_x_origin = x - s->slice.x;
3318 xgcv.clip_y_origin = y - s->slice.y;
3319 xgcv.function = GXcopy;
3320 XChangeGC (display, s->gc, mask, &xgcv);
3321
3322 x_composite_image (s, pixmap,
3323 s->slice.x, s->slice.y,
3324 x, y, s->slice.width, s->slice.height);
3325 XSetClipMask (display, s->gc, None);
3326 }
3327 else
3328 {
3329 XCopyArea (display, s->img->pixmap, pixmap, s->gc,
3330 s->slice.x, s->slice.y,
3331 s->slice.width, s->slice.height, x, y);
3332
3333 /* When the image has a mask, we can expect that at
3334 least part of a mouse highlight or a block cursor will
3335 be visible. If the image doesn't have a mask, make
3336 a block cursor visible by drawing a rectangle around
3337 the image. I believe it's looking better if we do
3338 nothing here for mouse-face. */
3339 if (s->hl == DRAW_CURSOR)
3340 {
3341 int r = eabs (s->img->relief);
3342 x_draw_rectangle (s->f, s->gc, x - r, y - r,
3343 s->slice.width + r*2 - 1,
3344 s->slice.height + r*2 - 1);
3345 }
3346 }
3347 }
3348 else
3349 /* Draw a rectangle if image could not be loaded. */
3350 x_draw_rectangle (s->f, s->gc, x, y,
3351 s->slice.width - 1, s->slice.height - 1);
3352 }
3353 #endif /* ! USE_CAIRO */
3354
3355
3356 /* Draw part of the background of glyph string S. X, Y, W, and H
3357 give the rectangle to draw. */
3358
3359 static void
x_draw_glyph_string_bg_rect(struct glyph_string * s,int x,int y,int w,int h)3360 x_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, int w, int h)
3361 {
3362 if (s->stippled_p)
3363 {
3364 Display *display = FRAME_X_DISPLAY (s->f);
3365
3366 /* Fill background with a stipple pattern. */
3367 XSetFillStyle (display, s->gc, FillOpaqueStippled);
3368 x_fill_rectangle (s->f, s->gc, x, y, w, h);
3369 XSetFillStyle (display, s->gc, FillSolid);
3370 }
3371 else
3372 x_clear_glyph_string_rect (s, x, y, w, h);
3373 }
3374
3375
3376 /* Draw image glyph string S.
3377
3378 s->y
3379 s->x +-------------------------
3380 | s->face->box
3381 |
3382 | +-------------------------
3383 | | s->img->margin
3384 | |
3385 | | +-------------------
3386 | | | the image
3387
3388 */
3389
3390 static void
x_draw_image_glyph_string(struct glyph_string * s)3391 x_draw_image_glyph_string (struct glyph_string *s)
3392 {
3393 int box_line_hwidth = eabs (s->face->box_line_width);
3394 int box_line_vwidth = max (s->face->box_line_width, 0);
3395 int height;
3396 #ifndef USE_CAIRO
3397 Display *display = FRAME_X_DISPLAY (s->f);
3398 Pixmap pixmap = None;
3399 #endif
3400
3401 height = s->height;
3402 if (s->slice.y == 0)
3403 height -= box_line_vwidth;
3404 if (s->slice.y + s->slice.height >= s->img->height)
3405 height -= box_line_vwidth;
3406
3407 /* Fill background with face under the image. Do it only if row is
3408 taller than image or if image has a clip mask to reduce
3409 flickering. */
3410 s->stippled_p = s->face->stipple != 0;
3411 if (height > s->slice.height
3412 || s->img->hmargin
3413 || s->img->vmargin
3414 || s->img->mask
3415 || s->img->pixmap == 0
3416 || s->width != s->background_width)
3417 {
3418 #ifndef USE_CAIRO
3419 if (s->img->mask)
3420 {
3421 /* Create a pixmap as large as the glyph string. Fill it
3422 with the background color. Copy the image to it, using
3423 its mask. Copy the temporary pixmap to the display. */
3424 Screen *screen = FRAME_X_SCREEN (s->f);
3425 int depth = DefaultDepthOfScreen (screen);
3426
3427 /* Create a pixmap as large as the glyph string. */
3428 pixmap = XCreatePixmap (display, FRAME_X_DRAWABLE (s->f),
3429 s->background_width,
3430 s->height, depth);
3431
3432 /* Don't clip in the following because we're working on the
3433 pixmap. */
3434 XSetClipMask (display, s->gc, None);
3435
3436 /* Fill the pixmap with the background color/stipple. */
3437 if (s->stippled_p)
3438 {
3439 /* Fill background with a stipple pattern. */
3440 XSetFillStyle (display, s->gc, FillOpaqueStippled);
3441 XSetTSOrigin (display, s->gc, - s->x, - s->y);
3442 XFillRectangle (display, pixmap, s->gc,
3443 0, 0, s->background_width, s->height);
3444 XSetFillStyle (display, s->gc, FillSolid);
3445 XSetTSOrigin (display, s->gc, 0, 0);
3446 }
3447 else
3448 {
3449 XGCValues xgcv;
3450 XGetGCValues (display, s->gc, GCForeground | GCBackground,
3451 &xgcv);
3452 XSetForeground (display, s->gc, xgcv.background);
3453 XFillRectangle (display, pixmap, s->gc,
3454 0, 0, s->background_width, s->height);
3455 XSetForeground (display, s->gc, xgcv.foreground);
3456 }
3457 }
3458 else
3459 #endif /* ! USE_CAIRO */
3460 {
3461 int x = s->x;
3462 int y = s->y;
3463 int width = s->background_width;
3464
3465 if (s->first_glyph->left_box_line_p
3466 && s->slice.x == 0)
3467 {
3468 x += box_line_hwidth;
3469 width -= box_line_hwidth;
3470 }
3471
3472 if (s->slice.y == 0)
3473 y += box_line_vwidth;
3474
3475 x_draw_glyph_string_bg_rect (s, x, y, width, height);
3476 }
3477
3478 s->background_filled_p = true;
3479 }
3480
3481 /* Draw the foreground. */
3482 #ifndef USE_CAIRO
3483 if (pixmap != None)
3484 {
3485 x_draw_image_foreground_1 (s, pixmap);
3486 x_set_glyph_string_clipping (s);
3487 XCopyArea (display, pixmap, FRAME_X_DRAWABLE (s->f), s->gc,
3488 0, 0, s->background_width, s->height, s->x, s->y);
3489 XFreePixmap (display, pixmap);
3490 }
3491 else
3492 #endif /* ! USE_CAIRO */
3493 x_draw_image_foreground (s);
3494
3495 /* If we must draw a relief around the image, do it. */
3496 if (s->img->relief
3497 || s->hl == DRAW_IMAGE_RAISED
3498 || s->hl == DRAW_IMAGE_SUNKEN)
3499 x_draw_image_relief (s);
3500 }
3501
3502
3503 /* Draw stretch glyph string S. */
3504
3505 static void
x_draw_stretch_glyph_string(struct glyph_string * s)3506 x_draw_stretch_glyph_string (struct glyph_string *s)
3507 {
3508 eassert (s->first_glyph->type == STRETCH_GLYPH);
3509
3510 if (s->hl == DRAW_CURSOR
3511 && !x_stretch_cursor_p)
3512 {
3513 /* If `x-stretch-cursor' is nil, don't draw a block cursor as
3514 wide as the stretch glyph. */
3515 int width, background_width = s->background_width;
3516 int x = s->x;
3517
3518 if (!s->row->reversed_p)
3519 {
3520 int left_x = window_box_left_offset (s->w, TEXT_AREA);
3521
3522 if (x < left_x)
3523 {
3524 background_width -= left_x - x;
3525 x = left_x;
3526 }
3527 }
3528 else
3529 {
3530 /* In R2L rows, draw the cursor on the right edge of the
3531 stretch glyph. */
3532 int right_x = window_box_right (s->w, TEXT_AREA);
3533
3534 if (x + background_width > right_x)
3535 background_width -= x - right_x;
3536 x += background_width;
3537 }
3538 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
3539 if (s->row->reversed_p)
3540 x -= width;
3541
3542 /* Draw cursor. */
3543 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
3544
3545 /* Clear rest using the GC of the original non-cursor face. */
3546 if (width < background_width)
3547 {
3548 int y = s->y;
3549 int w = background_width - width, h = s->height;
3550 Display *display = FRAME_X_DISPLAY (s->f);
3551 XRectangle r;
3552 GC gc;
3553
3554 if (!s->row->reversed_p)
3555 x += width;
3556 else
3557 x = s->x;
3558 if (s->row->mouse_face_p
3559 && cursor_in_mouse_face_p (s->w))
3560 {
3561 x_set_mouse_face_gc (s);
3562 gc = s->gc;
3563 }
3564 else
3565 gc = s->face->gc;
3566
3567 get_glyph_string_clip_rect (s, &r);
3568 x_set_clip_rectangles (s->f, gc, &r, 1);
3569
3570 if (s->face->stipple)
3571 {
3572 /* Fill background with a stipple pattern. */
3573 XSetFillStyle (display, gc, FillOpaqueStippled);
3574 x_fill_rectangle (s->f, gc, x, y, w, h);
3575 XSetFillStyle (display, gc, FillSolid);
3576 }
3577 else
3578 {
3579 XGCValues xgcv;
3580 XGetGCValues (display, gc, GCForeground | GCBackground, &xgcv);
3581 XSetForeground (display, gc, xgcv.background);
3582 x_fill_rectangle (s->f, gc, x, y, w, h);
3583 XSetForeground (display, gc, xgcv.foreground);
3584 }
3585
3586 x_reset_clip_rectangles (s->f, gc);
3587 }
3588 }
3589 else if (!s->background_filled_p)
3590 {
3591 int background_width = s->background_width;
3592 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3593
3594 /* Don't draw into left margin, fringe or scrollbar area
3595 except for header line and mode line. */
3596 if (x < left_x && !s->row->mode_line_p)
3597 {
3598 background_width -= left_x - x;
3599 x = left_x;
3600 }
3601 if (background_width > 0)
3602 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
3603 }
3604
3605 s->background_filled_p = true;
3606 }
3607
3608 static void
x_get_scale_factor(Display * disp,int * scale_x,int * scale_y)3609 x_get_scale_factor(Display *disp, int *scale_x, int *scale_y)
3610 {
3611 const int base_res = 96;
3612 struct x_display_info * dpyinfo = x_display_info_for_display (disp);
3613
3614 *scale_x = *scale_y = 1;
3615
3616 if (dpyinfo)
3617 {
3618 if (dpyinfo->resx > base_res)
3619 *scale_x = floor (dpyinfo->resx / base_res);
3620 if (dpyinfo->resy > base_res)
3621 *scale_y = floor (dpyinfo->resy / base_res);
3622 }
3623 }
3624
3625 /*
3626 Draw a wavy line under S. The wave fills wave_height pixels from y0.
3627
3628 x0 wave_length = 2
3629 --
3630 y0 * * * * *
3631 |* * * * * * * * *
3632 wave_height = 3 | * * * *
3633
3634 */
3635 static void
x_draw_underwave(struct glyph_string * s)3636 x_draw_underwave (struct glyph_string *s)
3637 {
3638 Display *display = FRAME_X_DISPLAY (s->f);
3639
3640 /* Adjust for scale/HiDPI. */
3641 int scale_x, scale_y;
3642
3643 x_get_scale_factor (display, &scale_x, &scale_y);
3644
3645 int wave_height = 3 * scale_y, wave_length = 2 * scale_x;
3646
3647 #ifdef USE_CAIRO
3648 x_draw_horizontal_wave (s->f, s->gc, s->x, s->ybase - wave_height + 3,
3649 s->width, wave_height, wave_length);
3650 #else /* not USE_CAIRO */
3651 int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax, thickness = scale_y;;
3652 bool odd;
3653 XRectangle wave_clip, string_clip, final_clip;
3654
3655 dx = wave_length;
3656 dy = wave_height - 1;
3657 x0 = s->x;
3658 y0 = s->ybase + wave_height / 2 - scale_y;
3659 width = s->width;
3660 xmax = x0 + width;
3661
3662 /* Find and set clipping rectangle */
3663
3664 wave_clip.x = x0;
3665 wave_clip.y = y0;
3666 wave_clip.width = width;
3667 wave_clip.height = wave_height;
3668 get_glyph_string_clip_rect (s, &string_clip);
3669
3670 if (!gui_intersect_rectangles (&wave_clip, &string_clip, &final_clip))
3671 return;
3672
3673 XSetClipRectangles (display, s->gc, 0, 0, &final_clip, 1, Unsorted);
3674
3675 /* Draw the waves */
3676
3677 x1 = x0 - (x0 % dx);
3678 x2 = x1 + dx;
3679 odd = (x1 / dx) & 1;
3680 y1 = y2 = y0;
3681
3682 if (odd)
3683 y1 += dy;
3684 else
3685 y2 += dy;
3686
3687 if (INT_MAX - dx < xmax)
3688 emacs_abort ();
3689
3690 while (x1 <= xmax)
3691 {
3692 XSetLineAttributes (display, s->gc, thickness, LineSolid, CapButt,
3693 JoinRound);
3694 XDrawLine (display, FRAME_X_DRAWABLE (s->f), s->gc, x1, y1, x2, y2);
3695 x1 = x2, y1 = y2;
3696 x2 += dx, y2 = y0 + odd*dy;
3697 odd = !odd;
3698 }
3699
3700 /* Restore previous clipping rectangle(s) */
3701 XSetClipRectangles (display, s->gc, 0, 0, s->clip, s->num_clips, Unsorted);
3702 #endif /* not USE_CAIRO */
3703 }
3704
3705
3706 /* Draw glyph string S. */
3707
3708 static void
x_draw_glyph_string(struct glyph_string * s)3709 x_draw_glyph_string (struct glyph_string *s)
3710 {
3711 bool relief_drawn_p = false;
3712
3713 /* If S draws into the background of its successors, draw the
3714 background of the successors first so that S can draw into it.
3715 This makes S->next use XDrawString instead of XDrawImageString. */
3716 if (s->next && s->right_overhang && !s->for_overlaps)
3717 {
3718 int width;
3719 struct glyph_string *next;
3720
3721 for (width = 0, next = s->next;
3722 next && width < s->right_overhang;
3723 width += next->width, next = next->next)
3724 if (next->first_glyph->type != IMAGE_GLYPH)
3725 {
3726 x_set_glyph_string_gc (next);
3727 x_set_glyph_string_clipping (next);
3728 if (next->first_glyph->type == STRETCH_GLYPH)
3729 x_draw_stretch_glyph_string (next);
3730 else
3731 x_draw_glyph_string_background (next, true);
3732 next->num_clips = 0;
3733 }
3734 }
3735
3736 /* Set up S->gc, set clipping and draw S. */
3737 x_set_glyph_string_gc (s);
3738
3739 /* Draw relief (if any) in advance for char/composition so that the
3740 glyph string can be drawn over it. */
3741 if (!s->for_overlaps
3742 && s->face->box != FACE_NO_BOX
3743 && (s->first_glyph->type == CHAR_GLYPH
3744 || s->first_glyph->type == COMPOSITE_GLYPH))
3745
3746 {
3747 x_set_glyph_string_clipping (s);
3748 x_draw_glyph_string_background (s, true);
3749 x_draw_glyph_string_box (s);
3750 x_set_glyph_string_clipping (s);
3751 relief_drawn_p = true;
3752 }
3753 else if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */
3754 && !s->clip_tail
3755 && ((s->prev && s->prev->hl != s->hl && s->left_overhang)
3756 || (s->next && s->next->hl != s->hl && s->right_overhang)))
3757 /* We must clip just this glyph. left_overhang part has already
3758 drawn when s->prev was drawn, and right_overhang part will be
3759 drawn later when s->next is drawn. */
3760 x_set_glyph_string_clipping_exactly (s, s);
3761 else
3762 x_set_glyph_string_clipping (s);
3763
3764 switch (s->first_glyph->type)
3765 {
3766 case IMAGE_GLYPH:
3767 x_draw_image_glyph_string (s);
3768 break;
3769
3770 case XWIDGET_GLYPH:
3771 x_draw_xwidget_glyph_string (s);
3772 break;
3773
3774 case STRETCH_GLYPH:
3775 x_draw_stretch_glyph_string (s);
3776 break;
3777
3778 case CHAR_GLYPH:
3779 if (s->for_overlaps)
3780 s->background_filled_p = true;
3781 else
3782 x_draw_glyph_string_background (s, false);
3783 x_draw_glyph_string_foreground (s);
3784 break;
3785
3786 case COMPOSITE_GLYPH:
3787 if (s->for_overlaps || (s->cmp_from > 0
3788 && ! s->first_glyph->u.cmp.automatic))
3789 s->background_filled_p = true;
3790 else
3791 x_draw_glyph_string_background (s, true);
3792 x_draw_composite_glyph_string_foreground (s);
3793 break;
3794
3795 case GLYPHLESS_GLYPH:
3796 if (s->for_overlaps)
3797 s->background_filled_p = true;
3798 else
3799 x_draw_glyph_string_background (s, true);
3800 x_draw_glyphless_glyph_string_foreground (s);
3801 break;
3802
3803 default:
3804 emacs_abort ();
3805 }
3806
3807 if (!s->for_overlaps)
3808 {
3809 /* Draw underline. */
3810 if (s->face->underline)
3811 {
3812 if (s->face->underline == FACE_UNDER_WAVE)
3813 {
3814 if (s->face->underline_defaulted_p)
3815 x_draw_underwave (s);
3816 else
3817 {
3818 Display *display = FRAME_X_DISPLAY (s->f);
3819 XGCValues xgcv;
3820 XGetGCValues (display, s->gc, GCForeground, &xgcv);
3821 XSetForeground (display, s->gc, s->face->underline_color);
3822 x_draw_underwave (s);
3823 XSetForeground (display, s->gc, xgcv.foreground);
3824 }
3825 }
3826 else if (s->face->underline == FACE_UNDER_LINE)
3827 {
3828 unsigned long thickness, position;
3829 int y;
3830
3831 if (s->prev &&
3832 s->prev->face->underline == FACE_UNDER_LINE)
3833 {
3834 /* We use the same underline style as the previous one. */
3835 thickness = s->prev->underline_thickness;
3836 position = s->prev->underline_position;
3837 }
3838 else
3839 {
3840 struct font *font = font_for_underline_metrics (s);
3841 unsigned long minimum_offset;
3842 bool underline_at_descent_line;
3843 bool use_underline_position_properties;
3844 Lisp_Object val = (WINDOW_BUFFER_LOCAL_VALUE
3845 (Qunderline_minimum_offset, s->w));
3846
3847 if (FIXNUMP (val))
3848 minimum_offset = max (0, XFIXNUM (val));
3849 else
3850 minimum_offset = 1;
3851
3852 val = (WINDOW_BUFFER_LOCAL_VALUE
3853 (Qx_underline_at_descent_line, s->w));
3854 underline_at_descent_line
3855 = !(NILP (val) || EQ (val, Qunbound));
3856
3857 val = (WINDOW_BUFFER_LOCAL_VALUE
3858 (Qx_use_underline_position_properties, s->w));
3859 use_underline_position_properties
3860 = !(NILP (val) || EQ (val, Qunbound));
3861
3862 /* Get the underline thickness. Default is 1 pixel. */
3863 if (font && font->underline_thickness > 0)
3864 thickness = font->underline_thickness;
3865 else
3866 thickness = 1;
3867 if (underline_at_descent_line)
3868 position = (s->height - thickness) - (s->ybase - s->y);
3869 else
3870 {
3871 /* Get the underline position. This is the
3872 recommended vertical offset in pixels from
3873 the baseline to the top of the underline.
3874 This is a signed value according to the
3875 specs, and its default is
3876
3877 ROUND ((maximum descent) / 2), with
3878 ROUND(x) = floor (x + 0.5) */
3879
3880 if (use_underline_position_properties
3881 && font && font->underline_position >= 0)
3882 position = font->underline_position;
3883 else if (font)
3884 position = (font->descent + 1) / 2;
3885 else
3886 position = minimum_offset;
3887 }
3888 position = max (position, minimum_offset);
3889 }
3890 /* Check the sanity of thickness and position. We should
3891 avoid drawing underline out of the current line area. */
3892 if (s->y + s->height <= s->ybase + position)
3893 position = (s->height - 1) - (s->ybase - s->y);
3894 if (s->y + s->height < s->ybase + position + thickness)
3895 thickness = (s->y + s->height) - (s->ybase + position);
3896 s->underline_thickness = thickness;
3897 s->underline_position = position;
3898 y = s->ybase + position;
3899 if (s->face->underline_defaulted_p)
3900 x_fill_rectangle (s->f, s->gc,
3901 s->x, y, s->width, thickness);
3902 else
3903 {
3904 Display *display = FRAME_X_DISPLAY (s->f);
3905 XGCValues xgcv;
3906 XGetGCValues (display, s->gc, GCForeground, &xgcv);
3907 XSetForeground (display, s->gc, s->face->underline_color);
3908 x_fill_rectangle (s->f, s->gc,
3909 s->x, y, s->width, thickness);
3910 XSetForeground (display, s->gc, xgcv.foreground);
3911 }
3912 }
3913 }
3914 /* Draw overline. */
3915 if (s->face->overline_p)
3916 {
3917 unsigned long dy = 0, h = 1;
3918
3919 if (s->face->overline_color_defaulted_p)
3920 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3921 s->width, h);
3922 else
3923 {
3924 Display *display = FRAME_X_DISPLAY (s->f);
3925 XGCValues xgcv;
3926 XGetGCValues (display, s->gc, GCForeground, &xgcv);
3927 XSetForeground (display, s->gc, s->face->overline_color);
3928 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3929 s->width, h);
3930 XSetForeground (display, s->gc, xgcv.foreground);
3931 }
3932 }
3933
3934 /* Draw strike-through. */
3935 if (s->face->strike_through_p)
3936 {
3937 /* Y-coordinate and height of the glyph string's first
3938 glyph. We cannot use s->y and s->height because those
3939 could be larger if there are taller display elements
3940 (e.g., characters displayed with a larger font) in the
3941 same glyph row. */
3942 int glyph_y = s->ybase - s->first_glyph->ascent;
3943 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3944 /* Strike-through width and offset from the glyph string's
3945 top edge. */
3946 unsigned long h = 1;
3947 unsigned long dy = (glyph_height - h) / 2;
3948
3949 if (s->face->strike_through_color_defaulted_p)
3950 x_fill_rectangle (s->f, s->gc, s->x, glyph_y + dy,
3951 s->width, h);
3952 else
3953 {
3954 Display *display = FRAME_X_DISPLAY (s->f);
3955 XGCValues xgcv;
3956 XGetGCValues (display, s->gc, GCForeground, &xgcv);
3957 XSetForeground (display, s->gc, s->face->strike_through_color);
3958 x_fill_rectangle (s->f, s->gc, s->x, glyph_y + dy,
3959 s->width, h);
3960 XSetForeground (display, s->gc, xgcv.foreground);
3961 }
3962 }
3963
3964 /* Draw relief if not yet drawn. */
3965 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
3966 x_draw_glyph_string_box (s);
3967
3968 if (s->prev)
3969 {
3970 struct glyph_string *prev;
3971
3972 for (prev = s->prev; prev; prev = prev->prev)
3973 if (prev->hl != s->hl
3974 && prev->x + prev->width + prev->right_overhang > s->x)
3975 {
3976 /* As prev was drawn while clipped to its own area, we
3977 must draw the right_overhang part using s->hl now. */
3978 enum draw_glyphs_face save = prev->hl;
3979
3980 prev->hl = s->hl;
3981 x_set_glyph_string_gc (prev);
3982 x_set_glyph_string_clipping_exactly (s, prev);
3983 if (prev->first_glyph->type == CHAR_GLYPH)
3984 x_draw_glyph_string_foreground (prev);
3985 else
3986 x_draw_composite_glyph_string_foreground (prev);
3987 x_reset_clip_rectangles (prev->f, prev->gc);
3988 prev->hl = save;
3989 prev->num_clips = 0;
3990 }
3991 }
3992
3993 if (s->next)
3994 {
3995 struct glyph_string *next;
3996
3997 for (next = s->next; next; next = next->next)
3998 if (next->hl != s->hl
3999 && next->x - next->left_overhang < s->x + s->width)
4000 {
4001 /* As next will be drawn while clipped to its own area,
4002 we must draw the left_overhang part using s->hl now. */
4003 enum draw_glyphs_face save = next->hl;
4004
4005 next->hl = s->hl;
4006 x_set_glyph_string_gc (next);
4007 x_set_glyph_string_clipping_exactly (s, next);
4008 if (next->first_glyph->type == CHAR_GLYPH)
4009 x_draw_glyph_string_foreground (next);
4010 else
4011 x_draw_composite_glyph_string_foreground (next);
4012 x_reset_clip_rectangles (next->f, next->gc);
4013 next->hl = save;
4014 next->num_clips = 0;
4015 next->clip_head = s->next;
4016 }
4017 }
4018 }
4019
4020 /* Reset clipping. */
4021 x_reset_clip_rectangles (s->f, s->gc);
4022 s->num_clips = 0;
4023 }
4024
4025 /* Shift display to make room for inserted glyphs. */
4026
4027 static void
x_shift_glyphs_for_insert(struct frame * f,int x,int y,int width,int height,int shift_by)4028 x_shift_glyphs_for_insert (struct frame *f, int x, int y, int width, int height, int shift_by)
4029 {
4030 /* Never called on a GUI frame, see
4031 https://lists.gnu.org/r/emacs-devel/2015-05/msg00456.html
4032 */
4033 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f),
4034 f->output_data.x->normal_gc,
4035 x, y, width, height,
4036 x + shift_by, y);
4037 }
4038
4039 /* Delete N glyphs at the nominal cursor position. Not implemented
4040 for X frames. */
4041
4042 static void
x_delete_glyphs(struct frame * f,int n)4043 x_delete_glyphs (struct frame *f, int n)
4044 {
4045 emacs_abort ();
4046 }
4047
4048
4049 /* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
4050 If they are <= 0, this is probably an error. */
4051
4052 static ATTRIBUTE_UNUSED void
x_clear_area1(Display * dpy,Window window,int x,int y,int width,int height,int exposures)4053 x_clear_area1 (Display *dpy, Window window,
4054 int x, int y, int width, int height, int exposures)
4055 {
4056 eassert (width > 0 && height > 0);
4057 XClearArea (dpy, window, x, y, width, height, exposures);
4058 }
4059
4060 void
x_clear_area(struct frame * f,int x,int y,int width,int height)4061 x_clear_area (struct frame *f, int x, int y, int width, int height)
4062 {
4063 #ifdef USE_CAIRO
4064 cairo_t *cr;
4065
4066 eassert (width > 0 && height > 0);
4067
4068 cr = x_begin_cr_clip (f, NULL);
4069 x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
4070 cairo_rectangle (cr, x, y, width, height);
4071 cairo_fill (cr);
4072 x_end_cr_clip (f);
4073 #else
4074 if (FRAME_X_DOUBLE_BUFFERED_P (f))
4075 XFillRectangle (FRAME_X_DISPLAY (f),
4076 FRAME_X_DRAWABLE (f),
4077 f->output_data.x->reverse_gc,
4078 x, y, width, height);
4079 else
4080 x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4081 x, y, width, height, False);
4082 #endif
4083 }
4084
4085
4086 /* Clear an entire frame. */
4087
4088 static void
x_clear_frame(struct frame * f)4089 x_clear_frame (struct frame *f)
4090 {
4091 /* Clearing the frame will erase any cursor, so mark them all as no
4092 longer visible. */
4093 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
4094
4095 block_input ();
4096
4097 font_drop_xrender_surfaces (f);
4098 x_clear_window (f);
4099
4100 /* We have to clear the scroll bars. If we have changed colors or
4101 something like that, then they should be notified. */
4102 x_scroll_bar_clear (f);
4103
4104 XFlush (FRAME_X_DISPLAY (f));
4105
4106 unblock_input ();
4107 }
4108
4109 /* RIF: Show hourglass cursor on frame F. */
4110
4111 static void
x_show_hourglass(struct frame * f)4112 x_show_hourglass (struct frame *f)
4113 {
4114 Display *dpy = FRAME_X_DISPLAY (f);
4115
4116 if (dpy)
4117 {
4118 struct x_output *x = FRAME_X_OUTPUT (f);
4119 #ifdef USE_X_TOOLKIT
4120 if (x->widget)
4121 #else
4122 if (FRAME_OUTER_WINDOW (f))
4123 #endif
4124 {
4125 x->hourglass_p = true;
4126
4127 if (!x->hourglass_window)
4128 {
4129 unsigned long mask = CWCursor;
4130 XSetWindowAttributes attrs;
4131 #ifdef USE_GTK
4132 Window parent = FRAME_X_WINDOW (f);
4133 #else
4134 Window parent = FRAME_OUTER_WINDOW (f);
4135 #endif
4136 attrs.cursor = x->hourglass_cursor;
4137
4138 x->hourglass_window = XCreateWindow
4139 (dpy, parent, 0, 0, 32000, 32000, 0, 0,
4140 InputOnly, CopyFromParent, mask, &attrs);
4141 }
4142
4143 XMapRaised (dpy, x->hourglass_window);
4144 XFlush (dpy);
4145 }
4146 }
4147 }
4148
4149 /* RIF: Cancel hourglass cursor on frame F. */
4150
4151 static void
x_hide_hourglass(struct frame * f)4152 x_hide_hourglass (struct frame *f)
4153 {
4154 struct x_output *x = FRAME_X_OUTPUT (f);
4155
4156 /* Watch out for newly created frames. */
4157 if (x->hourglass_window)
4158 {
4159 XUnmapWindow (FRAME_X_DISPLAY (f), x->hourglass_window);
4160 /* Sync here because XTread_socket looks at the
4161 hourglass_p flag that is reset to zero below. */
4162 XSync (FRAME_X_DISPLAY (f), False);
4163 x->hourglass_p = false;
4164 }
4165 }
4166
4167 /* Invert the middle quarter of the frame for .15 sec. */
4168
4169 static void
XTflash(struct frame * f)4170 XTflash (struct frame *f)
4171 {
4172 block_input ();
4173
4174 {
4175 #ifdef USE_GTK
4176 /* Use Gdk routines to draw. This way, we won't draw over scroll bars
4177 when the scroll bars and the edit widget share the same X window. */
4178 GdkWindow *window = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
4179 #ifdef HAVE_GTK3
4180 #if GTK_CHECK_VERSION (3, 22, 0)
4181 cairo_region_t *region = gdk_window_get_visible_region (window);
4182 GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
4183 cairo_t *cr = gdk_drawing_context_get_cairo_context (context);
4184 #else
4185 cairo_t *cr = gdk_cairo_create (window);
4186 #endif
4187 cairo_set_source_rgb (cr, 1, 1, 1);
4188 cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
4189 #define XFillRectangle(d, win, gc, x, y, w, h) \
4190 do { \
4191 cairo_rectangle (cr, x, y, w, h); \
4192 cairo_fill (cr); \
4193 } \
4194 while (false)
4195 #else /* ! HAVE_GTK3 */
4196 GdkGCValues vals;
4197 GdkGC *gc;
4198 vals.foreground.pixel = (FRAME_FOREGROUND_PIXEL (f)
4199 ^ FRAME_BACKGROUND_PIXEL (f));
4200 vals.function = GDK_XOR;
4201 gc = gdk_gc_new_with_values (window,
4202 &vals, GDK_GC_FUNCTION | GDK_GC_FOREGROUND);
4203 #define XFillRectangle(d, win, gc, x, y, w, h) \
4204 gdk_draw_rectangle (window, gc, true, x, y, w, h)
4205 #endif /* ! HAVE_GTK3 */
4206 #else /* ! USE_GTK */
4207 GC gc;
4208
4209 /* Create a GC that will use the GXxor function to flip foreground
4210 pixels into background pixels. */
4211 {
4212 XGCValues values;
4213
4214 values.function = GXxor;
4215 values.foreground = (FRAME_FOREGROUND_PIXEL (f)
4216 ^ FRAME_BACKGROUND_PIXEL (f));
4217
4218 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4219 GCFunction | GCForeground, &values);
4220 }
4221 #endif
4222 {
4223 /* Get the height not including a menu bar widget. */
4224 int height = FRAME_PIXEL_HEIGHT (f);
4225 /* Height of each line to flash. */
4226 int flash_height = FRAME_LINE_HEIGHT (f);
4227 /* These will be the left and right margins of the rectangles. */
4228 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
4229 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
4230 int width = flash_right - flash_left;
4231
4232 /* If window is tall, flash top and bottom line. */
4233 if (height > 3 * FRAME_LINE_HEIGHT (f))
4234 {
4235 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4236 flash_left,
4237 (FRAME_INTERNAL_BORDER_WIDTH (f)
4238 + FRAME_TOP_MARGIN_HEIGHT (f)),
4239 width, flash_height);
4240 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4241 flash_left,
4242 (height - flash_height
4243 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4244 width, flash_height);
4245
4246 }
4247 else
4248 /* If it is short, flash it all. */
4249 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4250 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4251 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4252
4253 x_flush (f);
4254
4255 {
4256 struct timespec delay = make_timespec (0, 150 * 1000 * 1000);
4257 struct timespec wakeup = timespec_add (current_timespec (), delay);
4258
4259 /* Keep waiting until past the time wakeup or any input gets
4260 available. */
4261 while (! detect_input_pending ())
4262 {
4263 struct timespec current = current_timespec ();
4264 struct timespec timeout;
4265
4266 /* Break if result would not be positive. */
4267 if (timespec_cmp (wakeup, current) <= 0)
4268 break;
4269
4270 /* How long `select' should wait. */
4271 timeout = make_timespec (0, 10 * 1000 * 1000);
4272
4273 /* Try to wait that long--but we might wake up sooner. */
4274 pselect (0, NULL, NULL, NULL, &timeout, NULL);
4275 }
4276 }
4277
4278 /* If window is tall, flash top and bottom line. */
4279 if (height > 3 * FRAME_LINE_HEIGHT (f))
4280 {
4281 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4282 flash_left,
4283 (FRAME_INTERNAL_BORDER_WIDTH (f)
4284 + FRAME_TOP_MARGIN_HEIGHT (f)),
4285 width, flash_height);
4286 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4287 flash_left,
4288 (height - flash_height
4289 - FRAME_INTERNAL_BORDER_WIDTH (f)),
4290 width, flash_height);
4291 }
4292 else
4293 /* If it is short, flash it all. */
4294 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4295 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4296 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4297
4298 #ifdef USE_GTK
4299 #ifdef HAVE_GTK3
4300 #if GTK_CHECK_VERSION (3, 22, 0)
4301 gdk_window_end_draw_frame (window, context);
4302 cairo_region_destroy (region);
4303 #else
4304 cairo_destroy (cr);
4305 #endif
4306 #else
4307 g_object_unref (G_OBJECT (gc));
4308 #endif
4309 #undef XFillRectangle
4310 #else
4311 XFreeGC (FRAME_X_DISPLAY (f), gc);
4312 #endif
4313 x_flush (f);
4314 }
4315 }
4316
4317 unblock_input ();
4318 }
4319
4320
4321 static void
XTtoggle_invisible_pointer(struct frame * f,bool invisible)4322 XTtoggle_invisible_pointer (struct frame *f, bool invisible)
4323 {
4324 block_input ();
4325 FRAME_DISPLAY_INFO (f)->toggle_visible_pointer (f, invisible);
4326 unblock_input ();
4327 }
4328
4329
4330 /* Make audible bell. */
4331
4332 static void
XTring_bell(struct frame * f)4333 XTring_bell (struct frame *f)
4334 {
4335 if (FRAME_X_DISPLAY (f))
4336 {
4337 if (visible_bell)
4338 XTflash (f);
4339 else
4340 {
4341 block_input ();
4342 #ifdef HAVE_XKB
4343 XkbBell (FRAME_X_DISPLAY (f), None, 0, None);
4344 #else
4345 XBell (FRAME_X_DISPLAY (f), 0);
4346 #endif
4347 XFlush (FRAME_X_DISPLAY (f));
4348 unblock_input ();
4349 }
4350 }
4351 }
4352
4353 /***********************************************************************
4354 Line Dance
4355 ***********************************************************************/
4356
4357 /* Perform an insert-lines or delete-lines operation, inserting N
4358 lines or deleting -N lines at vertical position VPOS. */
4359
4360 static void
x_ins_del_lines(struct frame * f,int vpos,int n)4361 x_ins_del_lines (struct frame *f, int vpos, int n)
4362 {
4363 emacs_abort ();
4364 }
4365
4366
4367 /* Scroll part of the display as described by RUN. */
4368
4369 static void
x_scroll_run(struct window * w,struct run * run)4370 x_scroll_run (struct window *w, struct run *run)
4371 {
4372 struct frame *f = XFRAME (w->frame);
4373 int x, y, width, height, from_y, to_y, bottom_y;
4374
4375 /* Get frame-relative bounding box of the text display area of W,
4376 without mode lines. Include in this box the left and right
4377 fringe of W. */
4378 window_box (w, ANY_AREA, &x, &y, &width, &height);
4379
4380 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4381 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4382 bottom_y = y + height;
4383
4384 if (to_y < from_y)
4385 {
4386 /* Scrolling up. Make sure we don't copy part of the mode
4387 line at the bottom. */
4388 if (from_y + run->height > bottom_y)
4389 height = bottom_y - from_y;
4390 else
4391 height = run->height;
4392 }
4393 else
4394 {
4395 /* Scrolling down. Make sure we don't copy over the mode line.
4396 at the bottom. */
4397 if (to_y + run->height > bottom_y)
4398 height = bottom_y - to_y;
4399 else
4400 height = run->height;
4401 }
4402
4403 block_input ();
4404
4405 /* Cursor off. Will be switched on again in gui_update_window_end. */
4406 gui_clear_cursor (w);
4407
4408 #ifdef USE_CAIRO
4409 if (FRAME_CR_CONTEXT (f))
4410 {
4411 cairo_surface_t *surface = cairo_get_target (FRAME_CR_CONTEXT (f));
4412 if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
4413 {
4414 eassert (cairo_xlib_surface_get_display (surface)
4415 == FRAME_X_DISPLAY (f));
4416 eassert (cairo_xlib_surface_get_drawable (surface)
4417 == FRAME_X_RAW_DRAWABLE (f));
4418 cairo_surface_flush (surface);
4419 XCopyArea (FRAME_X_DISPLAY (f),
4420 FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f),
4421 f->output_data.x->normal_gc,
4422 x, from_y,
4423 width, height,
4424 x, to_y);
4425 cairo_surface_mark_dirty_rectangle (surface, x, to_y, width, height);
4426 }
4427 else
4428 {
4429 cairo_surface_t *s
4430 = cairo_surface_create_similar (surface,
4431 cairo_surface_get_content (surface),
4432 width, height);
4433 cairo_t *cr = cairo_create (s);
4434 cairo_set_source_surface (cr, surface, -x, -from_y);
4435 cairo_paint (cr);
4436 cairo_destroy (cr);
4437
4438 cr = FRAME_CR_CONTEXT (f);
4439 cairo_save (cr);
4440 cairo_set_source_surface (cr, s, x, to_y);
4441 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
4442 cairo_rectangle (cr, x, to_y, width, height);
4443 cairo_fill (cr);
4444 cairo_restore (cr);
4445 cairo_surface_destroy (s);
4446 }
4447 }
4448 else
4449 #endif /* USE_CAIRO */
4450 XCopyArea (FRAME_X_DISPLAY (f),
4451 FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f),
4452 f->output_data.x->normal_gc,
4453 x, from_y,
4454 width, height,
4455 x, to_y);
4456
4457 unblock_input ();
4458 }
4459
4460
4461
4462 /***********************************************************************
4463 Exposure Events
4464 ***********************************************************************/
4465
4466
4467 static void
x_frame_highlight(struct frame * f)4468 x_frame_highlight (struct frame *f)
4469 {
4470 /* We used to only do this if Vx_no_window_manager was non-nil, but
4471 the ICCCM (section 4.1.6) says that the window's border pixmap
4472 and border pixel are window attributes which are "private to the
4473 client", so we can always change it to whatever we want. */
4474 block_input ();
4475 /* I recently started to get errors in this XSetWindowBorder, depending on
4476 the window-manager in use, tho something more is at play since I've been
4477 using that same window-manager binary for ever. Let's not crash just
4478 because of this (bug#9310). */
4479 x_catch_errors (FRAME_X_DISPLAY (f));
4480 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4481 f->output_data.x->border_pixel);
4482 x_uncatch_errors ();
4483 unblock_input ();
4484 gui_update_cursor (f, true);
4485 x_set_frame_alpha (f);
4486 }
4487
4488 static void
x_frame_unhighlight(struct frame * f)4489 x_frame_unhighlight (struct frame *f)
4490 {
4491 /* We used to only do this if Vx_no_window_manager was non-nil, but
4492 the ICCCM (section 4.1.6) says that the window's border pixmap
4493 and border pixel are window attributes which are "private to the
4494 client", so we can always change it to whatever we want. */
4495 block_input ();
4496 /* Same as above for XSetWindowBorder (bug#9310). */
4497 x_catch_errors (FRAME_X_DISPLAY (f));
4498 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4499 f->output_data.x->border_tile);
4500 x_uncatch_errors ();
4501 unblock_input ();
4502 gui_update_cursor (f, true);
4503 x_set_frame_alpha (f);
4504 }
4505
4506 /* The focus has changed. Update the frames as necessary to reflect
4507 the new situation. Note that we can't change the selected frame
4508 here, because the Lisp code we are interrupting might become confused.
4509 Each event gets marked with the frame in which it occurred, so the
4510 Lisp code can tell when the switch took place by examining the events. */
4511
4512 static void
x_new_focus_frame(struct x_display_info * dpyinfo,struct frame * frame)4513 x_new_focus_frame (struct x_display_info *dpyinfo, struct frame *frame)
4514 {
4515 struct frame *old_focus = dpyinfo->x_focus_frame;
4516
4517 if (frame != dpyinfo->x_focus_frame)
4518 {
4519 /* Set this before calling other routines, so that they see
4520 the correct value of x_focus_frame. */
4521 dpyinfo->x_focus_frame = frame;
4522
4523 if (old_focus && old_focus->auto_lower)
4524 x_lower_frame (old_focus);
4525
4526 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4527 dpyinfo->x_pending_autoraise_frame = dpyinfo->x_focus_frame;
4528 else
4529 dpyinfo->x_pending_autoraise_frame = NULL;
4530 }
4531
4532 x_frame_rehighlight (dpyinfo);
4533 }
4534
4535 /* Handle FocusIn and FocusOut state changes for FRAME.
4536 If FRAME has focus and there exists more than one frame, puts
4537 a FOCUS_IN_EVENT into *BUFP. */
4538
4539 static void
x_focus_changed(int type,int state,struct x_display_info * dpyinfo,struct frame * frame,struct input_event * bufp)4540 x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct frame *frame, struct input_event *bufp)
4541 {
4542 if (type == FocusIn)
4543 {
4544 if (dpyinfo->x_focus_event_frame != frame)
4545 {
4546 x_new_focus_frame (dpyinfo, frame);
4547 dpyinfo->x_focus_event_frame = frame;
4548 bufp->kind = FOCUS_IN_EVENT;
4549 XSETFRAME (bufp->frame_or_window, frame);
4550 }
4551
4552 frame->output_data.x->focus_state |= state;
4553
4554 #ifdef HAVE_X_I18N
4555 if (FRAME_XIC (frame))
4556 XSetICFocus (FRAME_XIC (frame));
4557 #endif
4558 }
4559 else if (type == FocusOut)
4560 {
4561 frame->output_data.x->focus_state &= ~state;
4562
4563 if (dpyinfo->x_focus_event_frame == frame)
4564 {
4565 dpyinfo->x_focus_event_frame = 0;
4566 x_new_focus_frame (dpyinfo, 0);
4567
4568 bufp->kind = FOCUS_OUT_EVENT;
4569 XSETFRAME (bufp->frame_or_window, frame);
4570 }
4571
4572 #ifdef HAVE_X_I18N
4573 if (FRAME_XIC (frame))
4574 XUnsetICFocus (FRAME_XIC (frame));
4575 #endif
4576 if (frame->pointer_invisible)
4577 XTtoggle_invisible_pointer (frame, false);
4578 }
4579 }
4580
4581 /* Return the Emacs frame-object corresponding to an X window.
4582 It could be the frame's main window or an icon window. */
4583
4584 static struct frame *
x_window_to_frame(struct x_display_info * dpyinfo,int wdesc)4585 x_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4586 {
4587 Lisp_Object tail, frame;
4588 struct frame *f;
4589
4590 if (wdesc == None)
4591 return NULL;
4592
4593 FOR_EACH_FRAME (tail, frame)
4594 {
4595 f = XFRAME (frame);
4596 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4597 continue;
4598 if (f->output_data.x->hourglass_window == wdesc)
4599 return f;
4600 #ifdef USE_X_TOOLKIT
4601 if ((f->output_data.x->edit_widget
4602 && XtWindow (f->output_data.x->edit_widget) == wdesc)
4603 /* A tooltip frame? */
4604 || (!f->output_data.x->edit_widget
4605 && FRAME_X_WINDOW (f) == wdesc)
4606 || f->output_data.x->icon_desc == wdesc)
4607 return f;
4608 #else /* not USE_X_TOOLKIT */
4609 #ifdef USE_GTK
4610 if (f->output_data.x->edit_widget)
4611 {
4612 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4613 struct x_output *x = f->output_data.x;
4614 if (gwdesc != 0 && gwdesc == x->edit_widget)
4615 return f;
4616 }
4617 #endif /* USE_GTK */
4618 if (FRAME_X_WINDOW (f) == wdesc
4619 || f->output_data.x->icon_desc == wdesc)
4620 return f;
4621 #endif /* not USE_X_TOOLKIT */
4622 }
4623 return 0;
4624 }
4625
4626 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
4627
4628 /* Like x_window_to_frame but also compares the window with the widget's
4629 windows. */
4630
4631 static struct frame *
x_any_window_to_frame(struct x_display_info * dpyinfo,int wdesc)4632 x_any_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4633 {
4634 Lisp_Object tail, frame;
4635 struct frame *f, *found = NULL;
4636 struct x_output *x;
4637
4638 if (wdesc == None)
4639 return NULL;
4640
4641 FOR_EACH_FRAME (tail, frame)
4642 {
4643 if (found)
4644 break;
4645 f = XFRAME (frame);
4646 if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo)
4647 {
4648 /* This frame matches if the window is any of its widgets. */
4649 x = f->output_data.x;
4650 if (x->hourglass_window == wdesc)
4651 found = f;
4652 else if (x->widget)
4653 {
4654 #ifdef USE_GTK
4655 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4656 if (gwdesc != 0
4657 && gtk_widget_get_toplevel (gwdesc) == x->widget)
4658 found = f;
4659 #else
4660 if (wdesc == XtWindow (x->widget)
4661 || wdesc == XtWindow (x->column_widget)
4662 || wdesc == XtWindow (x->edit_widget))
4663 found = f;
4664 /* Match if the window is this frame's menubar. */
4665 else if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
4666 found = f;
4667 #endif
4668 }
4669 else if (FRAME_X_WINDOW (f) == wdesc)
4670 /* A tooltip frame. */
4671 found = f;
4672 }
4673 }
4674
4675 return found;
4676 }
4677
4678 /* Likewise, but consider only the menu bar widget. */
4679
4680 static struct frame *
x_menubar_window_to_frame(struct x_display_info * dpyinfo,const XEvent * event)4681 x_menubar_window_to_frame (struct x_display_info *dpyinfo,
4682 const XEvent *event)
4683 {
4684 Window wdesc = event->xany.window;
4685 Lisp_Object tail, frame;
4686 struct frame *f;
4687 struct x_output *x;
4688
4689 if (wdesc == None)
4690 return NULL;
4691
4692 FOR_EACH_FRAME (tail, frame)
4693 {
4694 f = XFRAME (frame);
4695 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4696 continue;
4697 x = f->output_data.x;
4698 #ifdef USE_GTK
4699 if (x->menubar_widget && xg_event_is_for_menubar (f, event))
4700 return f;
4701 #else
4702 /* Match if the window is this frame's menubar. */
4703 if (x->menubar_widget
4704 && lw_window_is_in_menubar (wdesc, x->menubar_widget))
4705 return f;
4706 #endif
4707 }
4708 return 0;
4709 }
4710
4711 /* Return the frame whose principal (outermost) window is WDESC.
4712 If WDESC is some other (smaller) window, we return 0. */
4713
4714 struct frame *
x_top_window_to_frame(struct x_display_info * dpyinfo,int wdesc)4715 x_top_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4716 {
4717 Lisp_Object tail, frame;
4718 struct frame *f;
4719 struct x_output *x;
4720
4721 if (wdesc == None)
4722 return NULL;
4723
4724 FOR_EACH_FRAME (tail, frame)
4725 {
4726 f = XFRAME (frame);
4727 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4728 continue;
4729 x = f->output_data.x;
4730
4731 if (x->widget)
4732 {
4733 /* This frame matches if the window is its topmost widget. */
4734 #ifdef USE_GTK
4735 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4736 if (gwdesc == x->widget)
4737 return f;
4738 #else
4739 if (wdesc == XtWindow (x->widget))
4740 return f;
4741 #endif
4742 }
4743 else if (FRAME_X_WINDOW (f) == wdesc)
4744 /* Tooltip frame. */
4745 return f;
4746 }
4747 return 0;
4748 }
4749
4750 #else /* !USE_X_TOOLKIT && !USE_GTK */
4751
4752 #define x_any_window_to_frame(d, i) x_window_to_frame (d, i)
4753 #define x_top_window_to_frame(d, i) x_window_to_frame (d, i)
4754
4755 #endif /* USE_X_TOOLKIT || USE_GTK */
4756
4757 /* The focus may have changed. Figure out if it is a real focus change,
4758 by checking both FocusIn/Out and Enter/LeaveNotify events.
4759
4760 Returns FOCUS_IN_EVENT event in *BUFP. */
4761
4762 static void
x_detect_focus_change(struct x_display_info * dpyinfo,struct frame * frame,const XEvent * event,struct input_event * bufp)4763 x_detect_focus_change (struct x_display_info *dpyinfo, struct frame *frame,
4764 const XEvent *event, struct input_event *bufp)
4765 {
4766 if (!frame)
4767 return;
4768
4769 switch (event->type)
4770 {
4771 case EnterNotify:
4772 case LeaveNotify:
4773 {
4774 struct frame *focus_frame = dpyinfo->x_focus_event_frame;
4775 int focus_state
4776 = focus_frame ? focus_frame->output_data.x->focus_state : 0;
4777
4778 if (event->xcrossing.detail != NotifyInferior
4779 && event->xcrossing.focus
4780 && ! (focus_state & FOCUS_EXPLICIT))
4781 x_focus_changed ((event->type == EnterNotify ? FocusIn : FocusOut),
4782 FOCUS_IMPLICIT,
4783 dpyinfo, frame, bufp);
4784 }
4785 break;
4786
4787 case FocusIn:
4788 case FocusOut:
4789 x_focus_changed (event->type,
4790 (event->xfocus.detail == NotifyPointer ?
4791 FOCUS_IMPLICIT : FOCUS_EXPLICIT),
4792 dpyinfo, frame, bufp);
4793 break;
4794
4795 case ClientMessage:
4796 if (event->xclient.message_type == dpyinfo->Xatom_XEMBED)
4797 {
4798 enum xembed_message msg = event->xclient.data.l[1];
4799 x_focus_changed ((msg == XEMBED_FOCUS_IN ? FocusIn : FocusOut),
4800 FOCUS_EXPLICIT, dpyinfo, frame, bufp);
4801 }
4802 break;
4803 }
4804 }
4805
4806
4807 #if !defined USE_X_TOOLKIT && !defined USE_GTK
4808 /* Handle an event saying the mouse has moved out of an Emacs frame. */
4809
4810 void
x_mouse_leave(struct x_display_info * dpyinfo)4811 x_mouse_leave (struct x_display_info *dpyinfo)
4812 {
4813 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
4814 }
4815 #endif
4816
4817 /* The focus has changed, or we have redirected a frame's focus to
4818 another frame (this happens when a frame uses a surrogate
4819 mini-buffer frame). Shift the highlight as appropriate.
4820
4821 The FRAME argument doesn't necessarily have anything to do with which
4822 frame is being highlighted or un-highlighted; we only use it to find
4823 the appropriate X display info. */
4824
4825 static void
XTframe_rehighlight(struct frame * frame)4826 XTframe_rehighlight (struct frame *frame)
4827 {
4828 x_frame_rehighlight (FRAME_DISPLAY_INFO (frame));
4829 }
4830
4831 static void
x_frame_rehighlight(struct x_display_info * dpyinfo)4832 x_frame_rehighlight (struct x_display_info *dpyinfo)
4833 {
4834 struct frame *old_highlight = dpyinfo->highlight_frame;
4835
4836 if (dpyinfo->x_focus_frame)
4837 {
4838 dpyinfo->highlight_frame
4839 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4840 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4841 : dpyinfo->x_focus_frame);
4842 if (! FRAME_LIVE_P (dpyinfo->highlight_frame))
4843 {
4844 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
4845 dpyinfo->highlight_frame = dpyinfo->x_focus_frame;
4846 }
4847 }
4848 else
4849 dpyinfo->highlight_frame = 0;
4850
4851 if (dpyinfo->highlight_frame != old_highlight)
4852 {
4853 if (old_highlight)
4854 x_frame_unhighlight (old_highlight);
4855 if (dpyinfo->highlight_frame)
4856 x_frame_highlight (dpyinfo->highlight_frame);
4857 }
4858 }
4859
4860
4861
4862 /* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
4863
4864 /* Initialize mode_switch_bit and modifier_meaning. */
4865 static void
x_find_modifier_meanings(struct x_display_info * dpyinfo)4866 x_find_modifier_meanings (struct x_display_info *dpyinfo)
4867 {
4868 int min_code, max_code;
4869 KeySym *syms;
4870 int syms_per_code;
4871 XModifierKeymap *mods;
4872
4873 dpyinfo->meta_mod_mask = 0;
4874 dpyinfo->shift_lock_mask = 0;
4875 dpyinfo->alt_mod_mask = 0;
4876 dpyinfo->super_mod_mask = 0;
4877 dpyinfo->hyper_mod_mask = 0;
4878
4879 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
4880
4881 syms = XGetKeyboardMapping (dpyinfo->display,
4882 min_code, max_code - min_code + 1,
4883 &syms_per_code);
4884 mods = XGetModifierMapping (dpyinfo->display);
4885
4886 /* Scan the modifier table to see which modifier bits the Meta and
4887 Alt keysyms are on. */
4888 {
4889 int row, col; /* The row and column in the modifier table. */
4890 bool found_alt_or_meta;
4891
4892 for (row = 3; row < 8; row++)
4893 {
4894 found_alt_or_meta = false;
4895 for (col = 0; col < mods->max_keypermod; col++)
4896 {
4897 KeyCode code = mods->modifiermap[(row * mods->max_keypermod) + col];
4898
4899 /* Zeroes are used for filler. Skip them. */
4900 if (code == 0)
4901 continue;
4902
4903 /* Are any of this keycode's keysyms a meta key? */
4904 {
4905 int code_col;
4906
4907 for (code_col = 0; code_col < syms_per_code; code_col++)
4908 {
4909 int sym = syms[((code - min_code) * syms_per_code) + code_col];
4910
4911 switch (sym)
4912 {
4913 case XK_Meta_L:
4914 case XK_Meta_R:
4915 found_alt_or_meta = true;
4916 dpyinfo->meta_mod_mask |= (1 << row);
4917 break;
4918
4919 case XK_Alt_L:
4920 case XK_Alt_R:
4921 found_alt_or_meta = true;
4922 dpyinfo->alt_mod_mask |= (1 << row);
4923 break;
4924
4925 case XK_Hyper_L:
4926 case XK_Hyper_R:
4927 if (!found_alt_or_meta)
4928 dpyinfo->hyper_mod_mask |= (1 << row);
4929 code_col = syms_per_code;
4930 col = mods->max_keypermod;
4931 break;
4932
4933 case XK_Super_L:
4934 case XK_Super_R:
4935 if (!found_alt_or_meta)
4936 dpyinfo->super_mod_mask |= (1 << row);
4937 code_col = syms_per_code;
4938 col = mods->max_keypermod;
4939 break;
4940
4941 case XK_Shift_Lock:
4942 /* Ignore this if it's not on the lock modifier. */
4943 if (!found_alt_or_meta && ((1 << row) == LockMask))
4944 dpyinfo->shift_lock_mask = LockMask;
4945 code_col = syms_per_code;
4946 col = mods->max_keypermod;
4947 break;
4948 }
4949 }
4950 }
4951 }
4952 }
4953 }
4954
4955 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
4956 if (! dpyinfo->meta_mod_mask)
4957 {
4958 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
4959 dpyinfo->alt_mod_mask = 0;
4960 }
4961
4962 /* If some keys are both alt and meta,
4963 make them just meta, not alt. */
4964 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
4965 {
4966 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
4967 }
4968
4969 XFree (syms);
4970 XFreeModifiermap (mods);
4971 }
4972
4973 /* Convert between the modifier bits X uses and the modifier bits
4974 Emacs uses. */
4975
4976 int
x_x_to_emacs_modifiers(struct x_display_info * dpyinfo,int state)4977 x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state)
4978 {
4979 int mod_ctrl = ctrl_modifier;
4980 int mod_meta = meta_modifier;
4981 int mod_alt = alt_modifier;
4982 int mod_hyper = hyper_modifier;
4983 int mod_super = super_modifier;
4984 Lisp_Object tem;
4985
4986 tem = Fget (Vx_ctrl_keysym, Qmodifier_value);
4987 if (FIXNUMP (tem)) mod_ctrl = XFIXNUM (tem) & INT_MAX;
4988 tem = Fget (Vx_alt_keysym, Qmodifier_value);
4989 if (FIXNUMP (tem)) mod_alt = XFIXNUM (tem) & INT_MAX;
4990 tem = Fget (Vx_meta_keysym, Qmodifier_value);
4991 if (FIXNUMP (tem)) mod_meta = XFIXNUM (tem) & INT_MAX;
4992 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
4993 if (FIXNUMP (tem)) mod_hyper = XFIXNUM (tem) & INT_MAX;
4994 tem = Fget (Vx_super_keysym, Qmodifier_value);
4995 if (FIXNUMP (tem)) mod_super = XFIXNUM (tem) & INT_MAX;
4996
4997 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
4998 | ((state & ControlMask) ? mod_ctrl : 0)
4999 | ((state & dpyinfo->meta_mod_mask) ? mod_meta : 0)
5000 | ((state & dpyinfo->alt_mod_mask) ? mod_alt : 0)
5001 | ((state & dpyinfo->super_mod_mask) ? mod_super : 0)
5002 | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0));
5003 }
5004
5005 static int
x_emacs_to_x_modifiers(struct x_display_info * dpyinfo,intmax_t state)5006 x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, intmax_t state)
5007 {
5008 EMACS_INT mod_ctrl = ctrl_modifier;
5009 EMACS_INT mod_meta = meta_modifier;
5010 EMACS_INT mod_alt = alt_modifier;
5011 EMACS_INT mod_hyper = hyper_modifier;
5012 EMACS_INT mod_super = super_modifier;
5013
5014 Lisp_Object tem;
5015
5016 tem = Fget (Vx_ctrl_keysym, Qmodifier_value);
5017 if (FIXNUMP (tem)) mod_ctrl = XFIXNUM (tem);
5018 tem = Fget (Vx_alt_keysym, Qmodifier_value);
5019 if (FIXNUMP (tem)) mod_alt = XFIXNUM (tem);
5020 tem = Fget (Vx_meta_keysym, Qmodifier_value);
5021 if (FIXNUMP (tem)) mod_meta = XFIXNUM (tem);
5022 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
5023 if (FIXNUMP (tem)) mod_hyper = XFIXNUM (tem);
5024 tem = Fget (Vx_super_keysym, Qmodifier_value);
5025 if (FIXNUMP (tem)) mod_super = XFIXNUM (tem);
5026
5027
5028 return ( ((state & mod_alt) ? dpyinfo->alt_mod_mask : 0)
5029 | ((state & mod_super) ? dpyinfo->super_mod_mask : 0)
5030 | ((state & mod_hyper) ? dpyinfo->hyper_mod_mask : 0)
5031 | ((state & shift_modifier) ? ShiftMask : 0)
5032 | ((state & mod_ctrl) ? ControlMask : 0)
5033 | ((state & mod_meta) ? dpyinfo->meta_mod_mask : 0));
5034 }
5035
5036 /* Convert a keysym to its name. */
5037
5038 char *
get_keysym_name(int keysym)5039 get_keysym_name (int keysym)
5040 {
5041 char *value;
5042
5043 block_input ();
5044 value = XKeysymToString (keysym);
5045 unblock_input ();
5046
5047 return value;
5048 }
5049
5050 /* Mouse clicks and mouse movement. Rah.
5051
5052 Formerly, we used PointerMotionHintMask (in standard_event_mask)
5053 so that we would have to call XQueryPointer after each MotionNotify
5054 event to ask for another such event. However, this made mouse tracking
5055 slow, and there was a bug that made it eventually stop.
5056
5057 Simply asking for MotionNotify all the time seems to work better.
5058
5059 In order to avoid asking for motion events and then throwing most
5060 of them away or busy-polling the server for mouse positions, we ask
5061 the server for pointer motion hints. This means that we get only
5062 one event per group of mouse movements. "Groups" are delimited by
5063 other kinds of events (focus changes and button clicks, for
5064 example), or by XQueryPointer calls; when one of these happens, we
5065 get another MotionNotify event the next time the mouse moves. This
5066 is at least as efficient as getting motion events when mouse
5067 tracking is on, and I suspect only negligibly worse when tracking
5068 is off. */
5069
5070 /* Prepare a mouse-event in *RESULT for placement in the input queue.
5071
5072 If the event is a button press, then note that we have grabbed
5073 the mouse. */
5074
5075 static Lisp_Object
x_construct_mouse_click(struct input_event * result,const XButtonEvent * event,struct frame * f)5076 x_construct_mouse_click (struct input_event *result,
5077 const XButtonEvent *event,
5078 struct frame *f)
5079 {
5080 /* Make the event type NO_EVENT; we'll change that when we decide
5081 otherwise. */
5082 result->kind = MOUSE_CLICK_EVENT;
5083 result->code = event->button - Button1;
5084 result->timestamp = event->time;
5085 result->modifiers = (x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f),
5086 event->state)
5087 | (event->type == ButtonRelease
5088 ? up_modifier
5089 : down_modifier));
5090
5091 XSETINT (result->x, event->x);
5092 XSETINT (result->y, event->y);
5093 XSETFRAME (result->frame_or_window, f);
5094 result->arg = Qnil;
5095 return Qnil;
5096 }
5097
5098 /* Function to report a mouse movement to the mainstream Emacs code.
5099 The input handler calls this.
5100
5101 We have received a mouse movement event, which is given in *event.
5102 If the mouse is over a different glyph than it was last time, tell
5103 the mainstream emacs code by setting mouse_moved. If not, ask for
5104 another motion event, so we can check again the next time it moves. */
5105
5106 static bool
x_note_mouse_movement(struct frame * frame,const XMotionEvent * event)5107 x_note_mouse_movement (struct frame *frame, const XMotionEvent *event)
5108 {
5109 XRectangle *r;
5110 struct x_display_info *dpyinfo;
5111
5112 if (!FRAME_X_OUTPUT (frame))
5113 return false;
5114
5115 dpyinfo = FRAME_DISPLAY_INFO (frame);
5116 dpyinfo->last_mouse_movement_time = event->time;
5117 dpyinfo->last_mouse_motion_frame = frame;
5118 dpyinfo->last_mouse_motion_x = event->x;
5119 dpyinfo->last_mouse_motion_y = event->y;
5120
5121 if (event->window != FRAME_X_WINDOW (frame))
5122 {
5123 frame->mouse_moved = true;
5124 dpyinfo->last_mouse_scroll_bar = NULL;
5125 note_mouse_highlight (frame, -1, -1);
5126 dpyinfo->last_mouse_glyph_frame = NULL;
5127 return true;
5128 }
5129
5130
5131 /* Has the mouse moved off the glyph it was on at the last sighting? */
5132 r = &dpyinfo->last_mouse_glyph;
5133 if (frame != dpyinfo->last_mouse_glyph_frame
5134 || event->x < r->x || event->x >= r->x + r->width
5135 || event->y < r->y || event->y >= r->y + r->height)
5136 {
5137 frame->mouse_moved = true;
5138 dpyinfo->last_mouse_scroll_bar = NULL;
5139 note_mouse_highlight (frame, event->x, event->y);
5140 /* Remember which glyph we're now on. */
5141 remember_mouse_glyph (frame, event->x, event->y, r);
5142 dpyinfo->last_mouse_glyph_frame = frame;
5143 return true;
5144 }
5145
5146 return false;
5147 }
5148
5149 /* Return the current position of the mouse.
5150 *FP should be a frame which indicates which display to ask about.
5151
5152 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
5153 and *PART to the frame, window, and scroll bar part that the mouse
5154 is over. Set *X and *Y to the portion and whole of the mouse's
5155 position on the scroll bar.
5156
5157 If the mouse movement started elsewhere, set *FP to the frame the
5158 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
5159 the mouse is over.
5160
5161 Set *TIMESTAMP to the server time-stamp for the time at which the mouse
5162 was at this position.
5163
5164 Don't store anything if we don't have a valid set of values to report.
5165
5166 This clears the mouse_moved flag, so we can wait for the next mouse
5167 movement. */
5168
5169 static void
XTmouse_position(struct frame ** fp,int insist,Lisp_Object * bar_window,enum scroll_bar_part * part,Lisp_Object * x,Lisp_Object * y,Time * timestamp)5170 XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
5171 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
5172 Time *timestamp)
5173 {
5174 struct frame *f1;
5175 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
5176
5177 block_input ();
5178
5179 if (dpyinfo->last_mouse_scroll_bar && insist == 0)
5180 {
5181 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
5182
5183 if (bar->horizontal)
5184 x_horizontal_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp);
5185 else
5186 x_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp);
5187 }
5188 else
5189 {
5190 Window root;
5191 int root_x, root_y;
5192
5193 Window dummy_window;
5194 int dummy;
5195
5196 Lisp_Object frame, tail;
5197
5198 /* Clear the mouse-moved flag for every frame on this display. */
5199 FOR_EACH_FRAME (tail, frame)
5200 if (FRAME_X_P (XFRAME (frame))
5201 && FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
5202 XFRAME (frame)->mouse_moved = false;
5203
5204 dpyinfo->last_mouse_scroll_bar = NULL;
5205
5206 /* Figure out which root window we're on. */
5207 XQueryPointer (FRAME_X_DISPLAY (*fp),
5208 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
5209 /* The root window which contains the pointer. */
5210 &root,
5211 /* Trash which we can't trust if the pointer is on
5212 a different screen. */
5213 &dummy_window,
5214 /* The position on that root window. */
5215 &root_x, &root_y,
5216 /* More trash we can't trust. */
5217 &dummy, &dummy,
5218 /* Modifier keys and pointer buttons, about which
5219 we don't care. */
5220 (unsigned int *) &dummy);
5221
5222 /* Now we have a position on the root; find the innermost window
5223 containing the pointer. */
5224 {
5225 Window win, child;
5226 #ifdef USE_GTK
5227 Window first_win = 0;
5228 #endif
5229 int win_x, win_y;
5230 int parent_x = 0, parent_y = 0;
5231
5232 win = root;
5233
5234 /* XTranslateCoordinates can get errors if the window
5235 structure is changing at the same time this function
5236 is running. So at least we must not crash from them. */
5237
5238 x_catch_errors (FRAME_X_DISPLAY (*fp));
5239
5240 if (gui_mouse_grabbed (dpyinfo) && !EQ (track_mouse, Qdropping))
5241 {
5242 /* If mouse was grabbed on a frame, give coords for that frame
5243 even if the mouse is now outside it. */
5244 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
5245 /* From-window. */
5246 root,
5247 /* To-window. */
5248 FRAME_X_WINDOW (dpyinfo->last_mouse_frame),
5249 /* From-position, to-position. */
5250 root_x, root_y, &win_x, &win_y,
5251 /* Child of win. */
5252 &child);
5253 f1 = dpyinfo->last_mouse_frame;
5254 }
5255 else
5256 {
5257 while (true)
5258 {
5259 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
5260 /* From-window, to-window. */
5261 root, win,
5262 /* From-position, to-position. */
5263 root_x, root_y, &win_x, &win_y,
5264 /* Child of win. */
5265 &child);
5266 if (child == None || child == win)
5267 {
5268 #ifdef USE_GTK
5269 /* On GTK we have not inspected WIN yet. If it has
5270 a frame and that frame has a parent, use it. */
5271 struct frame *f = x_window_to_frame (dpyinfo, win);
5272
5273 if (f && FRAME_PARENT_FRAME (f))
5274 first_win = win;
5275 #endif
5276 break;
5277 }
5278 #ifdef USE_GTK
5279 /* We don't wan't to know the innermost window. We
5280 want the edit window. For non-Gtk+ the innermost
5281 window is the edit window. For Gtk+ it might not
5282 be. It might be the tool bar for example. */
5283 if (x_window_to_frame (dpyinfo, win))
5284 /* But don't hurry. We might find a child frame
5285 beneath. */
5286 first_win = win;
5287 #endif
5288 win = child;
5289 parent_x = win_x;
5290 parent_y = win_y;
5291 }
5292
5293 #ifdef USE_GTK
5294 if (first_win)
5295 win = first_win;
5296 #endif
5297
5298 /* Now we know that:
5299 win is the innermost window containing the pointer
5300 (XTC says it has no child containing the pointer),
5301 win_x and win_y are the pointer's position in it
5302 (XTC did this the last time through), and
5303 parent_x and parent_y are the pointer's position in win's parent.
5304 (They are what win_x and win_y were when win was child.
5305 If win is the root window, it has no parent, and
5306 parent_{x,y} are invalid, but that's okay, because we'll
5307 never use them in that case.) */
5308
5309 #ifdef USE_GTK
5310 /* We don't wan't to know the innermost window. We
5311 want the edit window. */
5312 f1 = x_window_to_frame (dpyinfo, win);
5313 #else
5314 /* Is win one of our frames? */
5315 f1 = x_any_window_to_frame (dpyinfo, win);
5316 #endif
5317
5318 #ifdef USE_X_TOOLKIT
5319 /* If we end up with the menu bar window, say it's not
5320 on the frame. */
5321 if (f1 != NULL
5322 && f1->output_data.x->menubar_widget
5323 && win == XtWindow (f1->output_data.x->menubar_widget))
5324 f1 = NULL;
5325 #endif /* USE_X_TOOLKIT */
5326 }
5327
5328 if ((!f1 || FRAME_TOOLTIP_P (f1))
5329 && EQ (track_mouse, Qdropping)
5330 && gui_mouse_grabbed (dpyinfo))
5331 {
5332 /* When dropping then if we didn't get a frame or only a
5333 tooltip frame and the mouse was grabbed on a frame,
5334 give coords for that frame even if the mouse is now
5335 outside it. */
5336 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
5337 /* From-window. */
5338 root,
5339 /* To-window. */
5340 FRAME_X_WINDOW (dpyinfo->last_mouse_frame),
5341 /* From-position, to-position. */
5342 root_x, root_y, &win_x, &win_y,
5343 /* Child of win. */
5344 &child);
5345 f1 = dpyinfo->last_mouse_frame;
5346 }
5347 else if (f1 && FRAME_TOOLTIP_P (f1))
5348 f1 = NULL;
5349
5350 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
5351 f1 = NULL;
5352
5353 x_uncatch_errors_after_check ();
5354
5355 /* If not, is it one of our scroll bars? */
5356 if (!f1)
5357 {
5358 struct scroll_bar *bar;
5359
5360 bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win, 2);
5361
5362 if (bar)
5363 {
5364 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5365 win_x = parent_x;
5366 win_y = parent_y;
5367 }
5368 }
5369
5370 if (!f1 && insist > 0)
5371 f1 = SELECTED_FRAME ();
5372
5373 if (f1)
5374 {
5375 /* Ok, we found a frame. Store all the values.
5376 last_mouse_glyph is a rectangle used to reduce the
5377 generation of mouse events. To not miss any motion
5378 events, we must divide the frame into rectangles of the
5379 size of the smallest character that could be displayed
5380 on it, i.e. into the same rectangles that matrices on
5381 the frame are divided into. */
5382
5383 /* FIXME: what if F1 is not an X frame? */
5384 dpyinfo = FRAME_DISPLAY_INFO (f1);
5385 remember_mouse_glyph (f1, win_x, win_y, &dpyinfo->last_mouse_glyph);
5386 dpyinfo->last_mouse_glyph_frame = f1;
5387
5388 *bar_window = Qnil;
5389 *part = 0;
5390 *fp = f1;
5391 XSETINT (*x, win_x);
5392 XSETINT (*y, win_y);
5393 *timestamp = dpyinfo->last_mouse_movement_time;
5394 }
5395 }
5396 }
5397
5398 unblock_input ();
5399 }
5400
5401
5402
5403 /***********************************************************************
5404 Scroll bars
5405 ***********************************************************************/
5406
5407 /* Scroll bar support. */
5408
5409 /* Given an X window ID and a DISPLAY, find the struct scroll_bar which
5410 manages it.
5411 This can be called in GC, so we have to make sure to strip off mark
5412 bits. */
5413
5414 static struct scroll_bar *
x_window_to_scroll_bar(Display * display,Window window_id,int type)5415 x_window_to_scroll_bar (Display *display, Window window_id, int type)
5416 {
5417 Lisp_Object tail, frame;
5418
5419 #if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
5420 window_id = (Window) xg_get_scroll_id_for_window (display, window_id);
5421 #endif /* USE_GTK && USE_TOOLKIT_SCROLL_BARS */
5422
5423 FOR_EACH_FRAME (tail, frame)
5424 {
5425 Lisp_Object bar, condemned;
5426
5427 if (! FRAME_X_P (XFRAME (frame)))
5428 continue;
5429
5430 /* Scan this frame's scroll bar list for a scroll bar with the
5431 right window ID. */
5432 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
5433 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
5434 /* This trick allows us to search both the ordinary and
5435 condemned scroll bar lists with one loop. */
5436 ! NILP (bar) || (bar = condemned,
5437 condemned = Qnil,
5438 ! NILP (bar));
5439 bar = XSCROLL_BAR (bar)->next)
5440 if (XSCROLL_BAR (bar)->x_window == window_id
5441 && FRAME_X_DISPLAY (XFRAME (frame)) == display
5442 && (type == 2
5443 || (type == 1 && XSCROLL_BAR (bar)->horizontal)
5444 || (type == 0 && !XSCROLL_BAR (bar)->horizontal)))
5445 return XSCROLL_BAR (bar);
5446 }
5447
5448 return NULL;
5449 }
5450
5451
5452 #if defined USE_LUCID
5453
5454 /* Return the Lucid menu bar WINDOW is part of. Return null
5455 if WINDOW is not part of a menu bar. */
5456
5457 static Widget
x_window_to_menu_bar(Window window)5458 x_window_to_menu_bar (Window window)
5459 {
5460 Lisp_Object tail, frame;
5461
5462 FOR_EACH_FRAME (tail, frame)
5463 if (FRAME_X_P (XFRAME (frame)))
5464 {
5465 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
5466
5467 if (menu_bar && xlwmenu_window_p (menu_bar, window))
5468 return menu_bar;
5469 }
5470 return NULL;
5471 }
5472
5473 #endif /* USE_LUCID */
5474
5475
5476 /************************************************************************
5477 Toolkit scroll bars
5478 ************************************************************************/
5479
5480 #ifdef USE_TOOLKIT_SCROLL_BARS
5481
5482 static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part,
5483 int, int, bool);
5484
5485 /* Lisp window being scrolled. Set when starting to interact with
5486 a toolkit scroll bar, reset to nil when ending the interaction. */
5487
5488 static Lisp_Object window_being_scrolled;
5489
5490 /* Whether this is an Xaw with arrow-scrollbars. This should imply
5491 that movements of 1/20 of the screen size are mapped to up/down. */
5492
5493 #ifndef USE_GTK
5494 /* Id of action hook installed for scroll bars. */
5495
5496 static XtActionHookId action_hook_id;
5497 static XtActionHookId horizontal_action_hook_id;
5498
5499 static Boolean xaw3d_arrow_scroll;
5500
5501 /* Whether the drag scrolling maintains the mouse at the top of the
5502 thumb. If not, resizing the thumb needs to be done more carefully
5503 to avoid jerkiness. */
5504
5505 static Boolean xaw3d_pick_top;
5506
5507 /* Action hook installed via XtAppAddActionHook when toolkit scroll
5508 bars are used.. The hook is responsible for detecting when
5509 the user ends an interaction with the scroll bar, and generates
5510 a `end-scroll' SCROLL_BAR_CLICK_EVENT' event if so. */
5511
5512 static void
xt_action_hook(Widget widget,XtPointer client_data,String action_name,XEvent * event,String * params,Cardinal * num_params)5513 xt_action_hook (Widget widget, XtPointer client_data, String action_name,
5514 XEvent *event, String *params, Cardinal *num_params)
5515 {
5516 bool scroll_bar_p;
5517 const char *end_action;
5518
5519 #ifdef USE_MOTIF
5520 scroll_bar_p = XmIsScrollBar (widget);
5521 end_action = "Release";
5522 #else /* !USE_MOTIF i.e. use Xaw */
5523 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
5524 end_action = "EndScroll";
5525 #endif /* USE_MOTIF */
5526
5527 if (scroll_bar_p
5528 && strcmp (action_name, end_action) == 0
5529 && WINDOWP (window_being_scrolled))
5530 {
5531 struct window *w;
5532 struct scroll_bar *bar;
5533
5534 x_send_scroll_bar_event (window_being_scrolled,
5535 scroll_bar_end_scroll, 0, 0, false);
5536 w = XWINDOW (window_being_scrolled);
5537 bar = XSCROLL_BAR (w->vertical_scroll_bar);
5538
5539 if (bar->dragging != -1)
5540 {
5541 bar->dragging = -1;
5542 /* The thumb size is incorrect while dragging: fix it. */
5543 set_vertical_scroll_bar (w);
5544 }
5545 window_being_scrolled = Qnil;
5546 #if defined (USE_LUCID)
5547 bar->last_seen_part = scroll_bar_nowhere;
5548 #endif
5549 /* Xt timeouts no longer needed. */
5550 toolkit_scroll_bar_interaction = false;
5551 }
5552 }
5553
5554
5555 static void
xt_horizontal_action_hook(Widget widget,XtPointer client_data,String action_name,XEvent * event,String * params,Cardinal * num_params)5556 xt_horizontal_action_hook (Widget widget, XtPointer client_data, String action_name,
5557 XEvent *event, String *params, Cardinal *num_params)
5558 {
5559 bool scroll_bar_p;
5560 const char *end_action;
5561
5562 #ifdef USE_MOTIF
5563 scroll_bar_p = XmIsScrollBar (widget);
5564 end_action = "Release";
5565 #else /* !USE_MOTIF i.e. use Xaw */
5566 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
5567 end_action = "EndScroll";
5568 #endif /* USE_MOTIF */
5569
5570 if (scroll_bar_p
5571 && strcmp (action_name, end_action) == 0
5572 && WINDOWP (window_being_scrolled))
5573 {
5574 struct window *w;
5575 struct scroll_bar *bar;
5576
5577 x_send_scroll_bar_event (window_being_scrolled,
5578 scroll_bar_end_scroll, 0, 0, true);
5579 w = XWINDOW (window_being_scrolled);
5580 if (!NILP (w->horizontal_scroll_bar))
5581 {
5582 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
5583 if (bar->dragging != -1)
5584 {
5585 bar->dragging = -1;
5586 /* The thumb size is incorrect while dragging: fix it. */
5587 set_horizontal_scroll_bar (w);
5588 }
5589 window_being_scrolled = Qnil;
5590 #if defined (USE_LUCID)
5591 bar->last_seen_part = scroll_bar_nowhere;
5592 #endif
5593 /* Xt timeouts no longer needed. */
5594 toolkit_scroll_bar_interaction = false;
5595 }
5596 }
5597 }
5598 #endif /* not USE_GTK */
5599
5600 /* Send a client message with message type Xatom_Scrollbar for a
5601 scroll action to the frame of WINDOW. PART is a value identifying
5602 the part of the scroll bar that was clicked on. PORTION is the
5603 amount to scroll of a whole of WHOLE. */
5604
5605 static void
x_send_scroll_bar_event(Lisp_Object window,enum scroll_bar_part part,int portion,int whole,bool horizontal)5606 x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part,
5607 int portion, int whole, bool horizontal)
5608 {
5609 XEvent event;
5610 XClientMessageEvent *ev = &event.xclient;
5611 struct window *w = XWINDOW (window);
5612 struct frame *f = XFRAME (w->frame);
5613 intptr_t iw = (intptr_t) w;
5614 verify (INTPTR_WIDTH <= 64);
5615 int sign_shift = INTPTR_WIDTH - 32;
5616
5617 block_input ();
5618
5619 /* Construct a ClientMessage event to send to the frame. */
5620 ev->type = ClientMessage;
5621 ev->message_type = (horizontal
5622 ? FRAME_DISPLAY_INFO (f)->Xatom_Horizontal_Scrollbar
5623 : FRAME_DISPLAY_INFO (f)->Xatom_Scrollbar);
5624 ev->display = FRAME_X_DISPLAY (f);
5625 ev->window = FRAME_X_WINDOW (f);
5626 ev->format = 32;
5627
5628 /* A 32-bit X client on a 64-bit X server can pass a window pointer
5629 as-is. A 64-bit client on a 32-bit X server is in trouble
5630 because a pointer does not fit and would be truncated while
5631 passing through the server. So use two slots and hope that X12
5632 will resolve such issues someday. */
5633 ev->data.l[0] = iw >> 31 >> 1;
5634 ev->data.l[1] = sign_shift <= 0 ? iw : iw << sign_shift >> sign_shift;
5635 ev->data.l[2] = part;
5636 ev->data.l[3] = portion;
5637 ev->data.l[4] = whole;
5638
5639 /* Make Xt timeouts work while the scroll bar is active. */
5640 #ifdef USE_X_TOOLKIT
5641 toolkit_scroll_bar_interaction = true;
5642 x_activate_timeout_atimer ();
5643 #endif
5644
5645 /* Setting the event mask to zero means that the message will
5646 be sent to the client that created the window, and if that
5647 window no longer exists, no event will be sent. */
5648 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
5649 unblock_input ();
5650 }
5651
5652
5653 /* Transform a scroll bar ClientMessage EVENT to an Emacs input event
5654 in *IEVENT. */
5655
5656 static void
x_scroll_bar_to_input_event(const XEvent * event,struct input_event * ievent)5657 x_scroll_bar_to_input_event (const XEvent *event,
5658 struct input_event *ievent)
5659 {
5660 const XClientMessageEvent *ev = &event->xclient;
5661 Lisp_Object window;
5662 struct window *w;
5663
5664 /* See the comment in the function above. */
5665 intptr_t iw0 = ev->data.l[0];
5666 intptr_t iw1 = ev->data.l[1];
5667 intptr_t iw = (iw0 << 31 << 1) + (iw1 & 0xffffffffu);
5668 w = (struct window *) iw;
5669
5670 XSETWINDOW (window, w);
5671
5672 ievent->kind = SCROLL_BAR_CLICK_EVENT;
5673 ievent->frame_or_window = window;
5674 ievent->arg = Qnil;
5675 #ifdef USE_GTK
5676 ievent->timestamp = CurrentTime;
5677 #else
5678 ievent->timestamp =
5679 XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame)));
5680 #endif
5681 ievent->code = 0;
5682 ievent->part = ev->data.l[2];
5683 ievent->x = make_fixnum (ev->data.l[3]);
5684 ievent->y = make_fixnum (ev->data.l[4]);
5685 ievent->modifiers = 0;
5686 }
5687
5688 /* Transform a horizontal scroll bar ClientMessage EVENT to an Emacs
5689 input event in *IEVENT. */
5690
5691 static void
x_horizontal_scroll_bar_to_input_event(const XEvent * event,struct input_event * ievent)5692 x_horizontal_scroll_bar_to_input_event (const XEvent *event,
5693 struct input_event *ievent)
5694 {
5695 const XClientMessageEvent *ev = &event->xclient;
5696 Lisp_Object window;
5697 struct window *w;
5698
5699 /* See the comment in the function above. */
5700 intptr_t iw0 = ev->data.l[0];
5701 intptr_t iw1 = ev->data.l[1];
5702 intptr_t iw = (iw0 << 31 << 1) + (iw1 & 0xffffffffu);
5703 w = (struct window *) iw;
5704
5705 XSETWINDOW (window, w);
5706
5707 ievent->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
5708 ievent->frame_or_window = window;
5709 ievent->arg = Qnil;
5710 #ifdef USE_GTK
5711 ievent->timestamp = CurrentTime;
5712 #else
5713 ievent->timestamp =
5714 XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame)));
5715 #endif
5716 ievent->code = 0;
5717 ievent->part = ev->data.l[2];
5718 ievent->x = make_fixnum (ev->data.l[3]);
5719 ievent->y = make_fixnum (ev->data.l[4]);
5720 ievent->modifiers = 0;
5721 }
5722
5723
5724 #ifdef USE_MOTIF
5725
5726 /* Minimum and maximum values used for Motif scroll bars. */
5727
5728 #define XM_SB_MAX 10000000
5729
5730 /* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
5731 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
5732 CALL_DATA is a pointer to a XmScrollBarCallbackStruct. */
5733
5734 static void
xm_scroll_callback(Widget widget,XtPointer client_data,XtPointer call_data)5735 xm_scroll_callback (Widget widget, XtPointer client_data, XtPointer call_data)
5736 {
5737 struct scroll_bar *bar = client_data;
5738 XmScrollBarCallbackStruct *cs = call_data;
5739 enum scroll_bar_part part = scroll_bar_nowhere;
5740 bool horizontal = bar->horizontal;
5741 int whole = 0, portion = 0;
5742
5743 switch (cs->reason)
5744 {
5745 case XmCR_DECREMENT:
5746 bar->dragging = -1;
5747 part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow;
5748 break;
5749
5750 case XmCR_INCREMENT:
5751 bar->dragging = -1;
5752 part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow;
5753 break;
5754
5755 case XmCR_PAGE_DECREMENT:
5756 bar->dragging = -1;
5757 part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle;
5758 break;
5759
5760 case XmCR_PAGE_INCREMENT:
5761 bar->dragging = -1;
5762 part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle;
5763 break;
5764
5765 case XmCR_TO_TOP:
5766 bar->dragging = -1;
5767 part = horizontal ? scroll_bar_to_leftmost : scroll_bar_to_top;
5768 break;
5769
5770 case XmCR_TO_BOTTOM:
5771 bar->dragging = -1;
5772 part = horizontal ? scroll_bar_to_rightmost : scroll_bar_to_bottom;
5773 break;
5774
5775 case XmCR_DRAG:
5776 {
5777 int slider_size;
5778
5779 block_input ();
5780 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
5781 unblock_input ();
5782
5783 if (horizontal)
5784 {
5785 portion = bar->whole * ((float)cs->value / XM_SB_MAX);
5786 whole = bar->whole * ((float)(XM_SB_MAX - slider_size) / XM_SB_MAX);
5787 portion = min (portion, whole);
5788 part = scroll_bar_horizontal_handle;
5789 }
5790 else
5791 {
5792 whole = XM_SB_MAX - slider_size;
5793 portion = min (cs->value, whole);
5794 part = scroll_bar_handle;
5795 }
5796
5797 bar->dragging = cs->value;
5798 }
5799 break;
5800
5801 case XmCR_VALUE_CHANGED:
5802 break;
5803 };
5804
5805 if (part != scroll_bar_nowhere)
5806 {
5807 window_being_scrolled = bar->window;
5808 x_send_scroll_bar_event (bar->window, part, portion, whole,
5809 bar->horizontal);
5810 }
5811 }
5812
5813 #elif defined USE_GTK
5814
5815 /* Scroll bar callback for GTK scroll bars. WIDGET is the scroll
5816 bar widget. DATA is a pointer to the scroll_bar structure. */
5817
5818 static gboolean
xg_scroll_callback(GtkRange * range,GtkScrollType scroll,gdouble value,gpointer user_data)5819 xg_scroll_callback (GtkRange *range,
5820 GtkScrollType scroll,
5821 gdouble value,
5822 gpointer user_data)
5823 {
5824 int whole = 0, portion = 0;
5825 struct scroll_bar *bar = user_data;
5826 enum scroll_bar_part part = scroll_bar_nowhere;
5827 GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
5828 struct frame *f = g_object_get_data (G_OBJECT (range), XG_FRAME_DATA);
5829
5830 if (xg_ignore_gtk_scrollbar) return false;
5831
5832 switch (scroll)
5833 {
5834 case GTK_SCROLL_JUMP:
5835 /* Buttons 1 2 or 3 must be grabbed. */
5836 if (FRAME_DISPLAY_INFO (f)->grabbed != 0
5837 && FRAME_DISPLAY_INFO (f)->grabbed < (1 << 4))
5838 {
5839 if (bar->horizontal)
5840 {
5841 part = scroll_bar_horizontal_handle;
5842 whole = (int)(gtk_adjustment_get_upper (adj) -
5843 gtk_adjustment_get_page_size (adj));
5844 portion = min ((int)value, whole);
5845 bar->dragging = portion;
5846 }
5847 else
5848 {
5849 part = scroll_bar_handle;
5850 whole = gtk_adjustment_get_upper (adj) -
5851 gtk_adjustment_get_page_size (adj);
5852 portion = min ((int)value, whole);
5853 bar->dragging = portion;
5854 }
5855 }
5856 break;
5857 case GTK_SCROLL_STEP_BACKWARD:
5858 part = (bar->horizontal
5859 ? scroll_bar_left_arrow : scroll_bar_up_arrow);
5860 bar->dragging = -1;
5861 break;
5862 case GTK_SCROLL_STEP_FORWARD:
5863 part = (bar->horizontal
5864 ? scroll_bar_right_arrow : scroll_bar_down_arrow);
5865 bar->dragging = -1;
5866 break;
5867 case GTK_SCROLL_PAGE_BACKWARD:
5868 part = (bar->horizontal
5869 ? scroll_bar_before_handle : scroll_bar_above_handle);
5870 bar->dragging = -1;
5871 break;
5872 case GTK_SCROLL_PAGE_FORWARD:
5873 part = (bar->horizontal
5874 ? scroll_bar_after_handle : scroll_bar_below_handle);
5875 bar->dragging = -1;
5876 break;
5877 default:
5878 break;
5879 }
5880
5881 if (part != scroll_bar_nowhere)
5882 {
5883 window_being_scrolled = bar->window;
5884 x_send_scroll_bar_event (bar->window, part, portion, whole,
5885 bar->horizontal);
5886 }
5887
5888 return false;
5889 }
5890
5891 /* Callback for button release. Sets dragging to -1 when dragging is done. */
5892
5893 static gboolean
xg_end_scroll_callback(GtkWidget * widget,GdkEventButton * event,gpointer user_data)5894 xg_end_scroll_callback (GtkWidget *widget,
5895 GdkEventButton *event,
5896 gpointer user_data)
5897 {
5898 struct scroll_bar *bar = user_data;
5899 bar->dragging = -1;
5900 if (WINDOWP (window_being_scrolled))
5901 {
5902 x_send_scroll_bar_event (window_being_scrolled,
5903 scroll_bar_end_scroll, 0, 0, bar->horizontal);
5904 window_being_scrolled = Qnil;
5905 }
5906
5907 return false;
5908 }
5909
5910
5911 #else /* not USE_GTK and not USE_MOTIF */
5912
5913 /* Xaw scroll bar callback. Invoked when the thumb is dragged.
5914 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
5915 scroll bar struct. CALL_DATA is a pointer to a float saying where
5916 the thumb is. */
5917
5918 static void
xaw_jump_callback(Widget widget,XtPointer client_data,XtPointer call_data)5919 xaw_jump_callback (Widget widget, XtPointer client_data, XtPointer call_data)
5920 {
5921 struct scroll_bar *bar = client_data;
5922 float *top_addr = call_data;
5923 float top = *top_addr;
5924 float shown;
5925 int whole, portion, height, width;
5926 enum scroll_bar_part part;
5927 bool horizontal = bar->horizontal;
5928
5929 if (horizontal)
5930 {
5931 /* Get the size of the thumb, a value between 0 and 1. */
5932 block_input ();
5933 XtVaGetValues (widget, XtNshown, &shown, XtNwidth, &width, NULL);
5934 unblock_input ();
5935
5936 if (shown < 1)
5937 {
5938 whole = bar->whole - (shown * bar->whole);
5939 portion = min (top * bar->whole, whole);
5940 }
5941 else
5942 {
5943 whole = bar->whole;
5944 portion = 0;
5945 }
5946
5947 part = scroll_bar_horizontal_handle;
5948 }
5949 else
5950 {
5951 /* Get the size of the thumb, a value between 0 and 1. */
5952 block_input ();
5953 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
5954 unblock_input ();
5955
5956 whole = 10000000;
5957 portion = shown < 1 ? top * whole : 0;
5958
5959 if (shown < 1 && (eabs (top + shown - 1) < 1.0f / height))
5960 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
5961 the bottom, so we force the scrolling whenever we see that we're
5962 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
5963 we try to ensure that we always stay two pixels away from the
5964 bottom). */
5965 part = scroll_bar_down_arrow;
5966 else
5967 part = scroll_bar_handle;
5968 }
5969
5970 window_being_scrolled = bar->window;
5971 bar->dragging = portion;
5972 bar->last_seen_part = part;
5973 x_send_scroll_bar_event (bar->window, part, portion, whole, bar->horizontal);
5974 }
5975
5976
5977 /* Xaw scroll bar callback. Invoked for incremental scrolling.,
5978 i.e. line or page up or down. WIDGET is the Xaw scroll bar
5979 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
5980 the scroll bar. CALL_DATA is an integer specifying the action that
5981 has taken place. Its magnitude is in the range 0..height of the
5982 scroll bar. Negative values mean scroll towards buffer start.
5983 Values < height of scroll bar mean line-wise movement. */
5984
5985 static void
xaw_scroll_callback(Widget widget,XtPointer client_data,XtPointer call_data)5986 xaw_scroll_callback (Widget widget, XtPointer client_data, XtPointer call_data)
5987 {
5988 struct scroll_bar *bar = client_data;
5989 /* The position really is stored cast to a pointer. */
5990 int position = (intptr_t) call_data;
5991 Dimension height, width;
5992 enum scroll_bar_part part;
5993
5994 if (bar->horizontal)
5995 {
5996 /* Get the width of the scroll bar. */
5997 block_input ();
5998 XtVaGetValues (widget, XtNwidth, &width, NULL);
5999 unblock_input ();
6000
6001 if (eabs (position) >= width)
6002 part = (position < 0) ? scroll_bar_before_handle : scroll_bar_after_handle;
6003
6004 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
6005 it maps line-movement to call_data = max(5, height/20). */
6006 else if (xaw3d_arrow_scroll && eabs (position) <= max (5, width / 20))
6007 part = (position < 0) ? scroll_bar_left_arrow : scroll_bar_right_arrow;
6008 else
6009 part = scroll_bar_move_ratio;
6010
6011 window_being_scrolled = bar->window;
6012 bar->dragging = -1;
6013 bar->last_seen_part = part;
6014 x_send_scroll_bar_event (bar->window, part, position, width,
6015 bar->horizontal);
6016 }
6017 else
6018 {
6019
6020 /* Get the height of the scroll bar. */
6021 block_input ();
6022 XtVaGetValues (widget, XtNheight, &height, NULL);
6023 unblock_input ();
6024
6025 if (eabs (position) >= height)
6026 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
6027
6028 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
6029 it maps line-movement to call_data = max(5, height/20). */
6030 else if (xaw3d_arrow_scroll && eabs (position) <= max (5, height / 20))
6031 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
6032 else
6033 part = scroll_bar_move_ratio;
6034
6035 window_being_scrolled = bar->window;
6036 bar->dragging = -1;
6037 bar->last_seen_part = part;
6038 x_send_scroll_bar_event (bar->window, part, position, height,
6039 bar->horizontal);
6040 }
6041 }
6042
6043 #endif /* not USE_GTK and not USE_MOTIF */
6044
6045 #define SCROLL_BAR_NAME "verticalScrollBar"
6046 #define SCROLL_BAR_HORIZONTAL_NAME "horizontalScrollBar"
6047
6048 /* Create the widget for scroll bar BAR on frame F. Record the widget
6049 and X window of the scroll bar in BAR. */
6050
6051 #ifdef USE_GTK
6052 static void
x_create_toolkit_scroll_bar(struct frame * f,struct scroll_bar * bar)6053 x_create_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
6054 {
6055 const char *scroll_bar_name = SCROLL_BAR_NAME;
6056
6057 block_input ();
6058 xg_create_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
6059 G_CALLBACK (xg_end_scroll_callback),
6060 scroll_bar_name);
6061 unblock_input ();
6062 }
6063
6064 static void
x_create_horizontal_toolkit_scroll_bar(struct frame * f,struct scroll_bar * bar)6065 x_create_horizontal_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
6066 {
6067 const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME;
6068
6069 block_input ();
6070 xg_create_horizontal_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
6071 G_CALLBACK (xg_end_scroll_callback),
6072 scroll_bar_name);
6073 unblock_input ();
6074 }
6075
6076 #else /* not USE_GTK */
6077
6078 static void
x_create_toolkit_scroll_bar(struct frame * f,struct scroll_bar * bar)6079 x_create_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
6080 {
6081 Window xwindow;
6082 Widget widget;
6083 Arg av[20];
6084 int ac = 0;
6085 const char *scroll_bar_name = SCROLL_BAR_NAME;
6086 unsigned long pixel;
6087
6088 block_input ();
6089
6090 #ifdef USE_MOTIF
6091 /* Set resources. Create the widget. */
6092 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
6093 XtSetArg (av[ac], XmNminimum, 0); ++ac;
6094 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
6095 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
6096 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
6097 XtSetArg (av[ac], XmNincrement, 1); ++ac;
6098 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
6099
6100 /* Note: "background" is the thumb color, and "trough" is the color behind
6101 everything. */
6102 pixel = f->output_data.x->scroll_bar_foreground_pixel;
6103 if (pixel != -1)
6104 {
6105 XtSetArg (av[ac], XmNbackground, pixel);
6106 ++ac;
6107 }
6108
6109 pixel = f->output_data.x->scroll_bar_background_pixel;
6110 if (pixel != -1)
6111 {
6112 XtSetArg (av[ac], XmNtroughColor, pixel);
6113 ++ac;
6114 }
6115
6116 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
6117 (char *) scroll_bar_name, av, ac);
6118
6119 /* Add one callback for everything that can happen. */
6120 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
6121 (XtPointer) bar);
6122 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
6123 (XtPointer) bar);
6124 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
6125 (XtPointer) bar);
6126 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
6127 (XtPointer) bar);
6128 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
6129 (XtPointer) bar);
6130 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
6131 (XtPointer) bar);
6132 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
6133 (XtPointer) bar);
6134
6135 /* Realize the widget. Only after that is the X window created. */
6136 XtRealizeWidget (widget);
6137
6138 /* Set the cursor to an arrow. I didn't find a resource to do that.
6139 And I'm wondering why it hasn't an arrow cursor by default. */
6140 XDefineCursor (XtDisplay (widget), XtWindow (widget),
6141 f->output_data.x->nontext_cursor);
6142
6143 #else /* !USE_MOTIF i.e. use Xaw */
6144
6145 /* Set resources. Create the widget. The background of the
6146 Xaw3d scroll bar widget is a little bit light for my taste.
6147 We don't alter it here to let users change it according
6148 to their taste with `emacs*verticalScrollBar.background: xxx'. */
6149 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
6150 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
6151 /* For smoother scrolling with Xaw3d -sm */
6152 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
6153
6154 pixel = f->output_data.x->scroll_bar_foreground_pixel;
6155 if (pixel != -1)
6156 {
6157 XtSetArg (av[ac], XtNforeground, pixel);
6158 ++ac;
6159 }
6160
6161 pixel = f->output_data.x->scroll_bar_background_pixel;
6162 if (pixel != -1)
6163 {
6164 XtSetArg (av[ac], XtNbackground, pixel);
6165 ++ac;
6166 }
6167
6168 /* Top/bottom shadow colors. */
6169
6170 /* Allocate them, if necessary. */
6171 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
6172 {
6173 pixel = f->output_data.x->scroll_bar_background_pixel;
6174 if (pixel != -1)
6175 {
6176 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
6177 FRAME_X_COLORMAP (f),
6178 &pixel, 1.2, 0x8000))
6179 pixel = -1;
6180 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
6181 }
6182 }
6183 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
6184 {
6185 pixel = f->output_data.x->scroll_bar_background_pixel;
6186 if (pixel != -1)
6187 {
6188 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
6189 FRAME_X_COLORMAP (f),
6190 &pixel, 0.6, 0x4000))
6191 pixel = -1;
6192 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
6193 }
6194 }
6195
6196 #ifdef XtNbeNiceToColormap
6197 /* Tell the toolkit about them. */
6198 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
6199 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
6200 /* We tried to allocate a color for the top/bottom shadow, and
6201 failed, so tell Xaw3d to use dithering instead. */
6202 /* But only if we have a small colormap. Xaw3d can allocate nice
6203 colors itself. */
6204 {
6205 XtSetArg (av[ac], XtNbeNiceToColormap,
6206 DefaultDepthOfScreen (FRAME_X_SCREEN (f)) < 16);
6207 ++ac;
6208 }
6209 else
6210 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
6211 be more consistent with other emacs 3d colors, and since Xaw3d is
6212 not good at dealing with allocation failure. */
6213 {
6214 /* This tells Xaw3d to use real colors instead of dithering for
6215 the shadows. */
6216 XtSetArg (av[ac], XtNbeNiceToColormap, False);
6217 ++ac;
6218
6219 /* Specify the colors. */
6220 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
6221 if (pixel != -1)
6222 {
6223 XtSetArg (av[ac], XtNtopShadowPixel, pixel);
6224 ++ac;
6225 }
6226 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
6227 if (pixel != -1)
6228 {
6229 XtSetArg (av[ac], XtNbottomShadowPixel, pixel);
6230 ++ac;
6231 }
6232 }
6233 #endif
6234
6235 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
6236 f->output_data.x->edit_widget, av, ac);
6237
6238 {
6239 char const *initial = "";
6240 char const *val = initial;
6241 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
6242 #ifdef XtNarrowScrollbars
6243 XtNarrowScrollbars, (XtPointer) &xaw3d_arrow_scroll,
6244 #endif
6245 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
6246 if (xaw3d_arrow_scroll || val == initial)
6247 { /* ARROW_SCROLL */
6248 xaw3d_arrow_scroll = True;
6249 /* Isn't that just a personal preference ? --Stef */
6250 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
6251 }
6252 }
6253
6254 /* Define callbacks. */
6255 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
6256 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
6257 (XtPointer) bar);
6258
6259 /* Realize the widget. Only after that is the X window created. */
6260 XtRealizeWidget (widget);
6261
6262 #endif /* !USE_MOTIF */
6263
6264 /* Install an action hook that lets us detect when the user
6265 finishes interacting with a scroll bar. */
6266 if (action_hook_id == 0)
6267 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
6268
6269 /* Remember X window and widget in the scroll bar vector. */
6270 SET_SCROLL_BAR_X_WIDGET (bar, widget);
6271 xwindow = XtWindow (widget);
6272 bar->x_window = xwindow;
6273 bar->whole = 1;
6274 bar->horizontal = false;
6275
6276 unblock_input ();
6277 }
6278
6279 static void
x_create_horizontal_toolkit_scroll_bar(struct frame * f,struct scroll_bar * bar)6280 x_create_horizontal_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
6281 {
6282 Window xwindow;
6283 Widget widget;
6284 Arg av[20];
6285 int ac = 0;
6286 const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME;
6287 unsigned long pixel;
6288
6289 block_input ();
6290
6291 #ifdef USE_MOTIF
6292 /* Set resources. Create the widget. */
6293 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
6294 XtSetArg (av[ac], XmNminimum, 0); ++ac;
6295 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
6296 XtSetArg (av[ac], XmNorientation, XmHORIZONTAL); ++ac;
6297 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_RIGHT), ++ac;
6298 XtSetArg (av[ac], XmNincrement, 1); ++ac;
6299 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
6300
6301 /* Note: "background" is the thumb color, and "trough" is the color behind
6302 everything. */
6303 pixel = f->output_data.x->scroll_bar_foreground_pixel;
6304 if (pixel != -1)
6305 {
6306 XtSetArg (av[ac], XmNbackground, pixel);
6307 ++ac;
6308 }
6309
6310 pixel = f->output_data.x->scroll_bar_background_pixel;
6311 if (pixel != -1)
6312 {
6313 XtSetArg (av[ac], XmNtroughColor, pixel);
6314 ++ac;
6315 }
6316
6317 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
6318 (char *) scroll_bar_name, av, ac);
6319
6320 /* Add one callback for everything that can happen. */
6321 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
6322 (XtPointer) bar);
6323 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
6324 (XtPointer) bar);
6325 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
6326 (XtPointer) bar);
6327 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
6328 (XtPointer) bar);
6329 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
6330 (XtPointer) bar);
6331 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
6332 (XtPointer) bar);
6333 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
6334 (XtPointer) bar);
6335
6336 /* Realize the widget. Only after that is the X window created. */
6337 XtRealizeWidget (widget);
6338
6339 /* Set the cursor to an arrow. I didn't find a resource to do that.
6340 And I'm wondering why it hasn't an arrow cursor by default. */
6341 XDefineCursor (XtDisplay (widget), XtWindow (widget),
6342 f->output_data.x->nontext_cursor);
6343
6344 #else /* !USE_MOTIF i.e. use Xaw */
6345
6346 /* Set resources. Create the widget. The background of the
6347 Xaw3d scroll bar widget is a little bit light for my taste.
6348 We don't alter it here to let users change it according
6349 to their taste with `emacs*verticalScrollBar.background: xxx'. */
6350 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
6351 XtSetArg (av[ac], XtNorientation, XtorientHorizontal); ++ac;
6352 /* For smoother scrolling with Xaw3d -sm */
6353 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
6354
6355 pixel = f->output_data.x->scroll_bar_foreground_pixel;
6356 if (pixel != -1)
6357 {
6358 XtSetArg (av[ac], XtNforeground, pixel);
6359 ++ac;
6360 }
6361
6362 pixel = f->output_data.x->scroll_bar_background_pixel;
6363 if (pixel != -1)
6364 {
6365 XtSetArg (av[ac], XtNbackground, pixel);
6366 ++ac;
6367 }
6368
6369 /* Top/bottom shadow colors. */
6370
6371 /* Allocate them, if necessary. */
6372 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
6373 {
6374 pixel = f->output_data.x->scroll_bar_background_pixel;
6375 if (pixel != -1)
6376 {
6377 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
6378 FRAME_X_COLORMAP (f),
6379 &pixel, 1.2, 0x8000))
6380 pixel = -1;
6381 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
6382 }
6383 }
6384 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
6385 {
6386 pixel = f->output_data.x->scroll_bar_background_pixel;
6387 if (pixel != -1)
6388 {
6389 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
6390 FRAME_X_COLORMAP (f),
6391 &pixel, 0.6, 0x4000))
6392 pixel = -1;
6393 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
6394 }
6395 }
6396
6397 #ifdef XtNbeNiceToColormap
6398 /* Tell the toolkit about them. */
6399 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
6400 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
6401 /* We tried to allocate a color for the top/bottom shadow, and
6402 failed, so tell Xaw3d to use dithering instead. */
6403 /* But only if we have a small colormap. Xaw3d can allocate nice
6404 colors itself. */
6405 {
6406 XtSetArg (av[ac], XtNbeNiceToColormap,
6407 DefaultDepthOfScreen (FRAME_X_SCREEN (f)) < 16);
6408 ++ac;
6409 }
6410 else
6411 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
6412 be more consistent with other emacs 3d colors, and since Xaw3d is
6413 not good at dealing with allocation failure. */
6414 {
6415 /* This tells Xaw3d to use real colors instead of dithering for
6416 the shadows. */
6417 XtSetArg (av[ac], XtNbeNiceToColormap, False);
6418 ++ac;
6419
6420 /* Specify the colors. */
6421 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
6422 if (pixel != -1)
6423 {
6424 XtSetArg (av[ac], XtNtopShadowPixel, pixel);
6425 ++ac;
6426 }
6427 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
6428 if (pixel != -1)
6429 {
6430 XtSetArg (av[ac], XtNbottomShadowPixel, pixel);
6431 ++ac;
6432 }
6433 }
6434 #endif
6435
6436 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
6437 f->output_data.x->edit_widget, av, ac);
6438
6439 {
6440 char const *initial = "";
6441 char const *val = initial;
6442 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
6443 #ifdef XtNarrowScrollbars
6444 XtNarrowScrollbars, (XtPointer) &xaw3d_arrow_scroll,
6445 #endif
6446 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
6447 if (xaw3d_arrow_scroll || val == initial)
6448 { /* ARROW_SCROLL */
6449 xaw3d_arrow_scroll = True;
6450 /* Isn't that just a personal preference ? --Stef */
6451 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
6452 }
6453 }
6454
6455 /* Define callbacks. */
6456 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
6457 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
6458 (XtPointer) bar);
6459
6460 /* Realize the widget. Only after that is the X window created. */
6461 XtRealizeWidget (widget);
6462
6463 #endif /* !USE_MOTIF */
6464
6465 /* Install an action hook that lets us detect when the user
6466 finishes interacting with a scroll bar. */
6467 if (horizontal_action_hook_id == 0)
6468 horizontal_action_hook_id
6469 = XtAppAddActionHook (Xt_app_con, xt_horizontal_action_hook, 0);
6470
6471 /* Remember X window and widget in the scroll bar vector. */
6472 SET_SCROLL_BAR_X_WIDGET (bar, widget);
6473 xwindow = XtWindow (widget);
6474 bar->x_window = xwindow;
6475 bar->whole = 1;
6476 bar->horizontal = true;
6477
6478 unblock_input ();
6479 }
6480 #endif /* not USE_GTK */
6481
6482
6483 /* Set the thumb size and position of scroll bar BAR. We are currently
6484 displaying PORTION out of a whole WHOLE, and our position POSITION. */
6485
6486 #ifdef USE_GTK
6487 static void
x_set_toolkit_scroll_bar_thumb(struct scroll_bar * bar,int portion,int position,int whole)6488 x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, int whole)
6489 {
6490 xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
6491 }
6492
6493 static void
x_set_toolkit_horizontal_scroll_bar_thumb(struct scroll_bar * bar,int portion,int position,int whole)6494 x_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, int whole)
6495 {
6496 xg_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
6497 }
6498
6499 #else /* not USE_GTK */
6500 static void
x_set_toolkit_scroll_bar_thumb(struct scroll_bar * bar,int portion,int position,int whole)6501 x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position,
6502 int whole)
6503 {
6504 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6505 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
6506 float top, shown;
6507
6508 block_input ();
6509
6510 #ifdef USE_MOTIF
6511
6512 if (scroll_bar_adjust_thumb_portion_p)
6513 {
6514 /* We use an estimate of 30 chars per line rather than the real
6515 `portion' value. This has the disadvantage that the thumb size
6516 is not very representative, but it makes our life a lot easier.
6517 Otherwise, we have to constantly adjust the thumb size, which
6518 we can't always do quickly enough: while dragging, the size of
6519 the thumb might prevent the user from dragging the thumb all the
6520 way to the end. but Motif and some versions of Xaw3d don't allow
6521 updating the thumb size while dragging. Also, even if we can update
6522 its size, the update will often happen too late.
6523 If you don't believe it, check out revision 1.650 of xterm.c to see
6524 what hoops we were going through and the still poor behavior we got. */
6525 portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
6526 /* When the thumb is at the bottom, position == whole.
6527 So we need to increase `whole' to make space for the thumb. */
6528 whole += portion;
6529 }
6530
6531 if (whole <= 0)
6532 top = 0, shown = 1;
6533 else
6534 {
6535 top = (float) position / whole;
6536 shown = (float) portion / whole;
6537 }
6538
6539 if (bar->dragging == -1)
6540 {
6541 int size, value;
6542
6543 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
6544 is the scroll bar's maximum and MIN is the scroll bar's minimum
6545 value. */
6546 size = clip_to_bounds (1, shown * XM_SB_MAX, XM_SB_MAX);
6547
6548 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
6549 value = top * XM_SB_MAX;
6550 value = min (value, XM_SB_MAX - size);
6551
6552 XmScrollBarSetValues (widget, value, size, 0, 0, False);
6553 }
6554 #else /* !USE_MOTIF i.e. use Xaw */
6555
6556 if (whole == 0)
6557 top = 0, shown = 1;
6558 else
6559 {
6560 top = (float) position / whole;
6561 shown = (float) portion / whole;
6562 }
6563
6564 {
6565 float old_top, old_shown;
6566 Dimension height;
6567 XtVaGetValues (widget,
6568 XtNtopOfThumb, &old_top,
6569 XtNshown, &old_shown,
6570 XtNheight, &height,
6571 NULL);
6572
6573 /* Massage the top+shown values. */
6574 if (bar->dragging == -1 || bar->last_seen_part == scroll_bar_down_arrow)
6575 top = max (0, min (1, top));
6576 else
6577 top = old_top;
6578 #if ! defined (HAVE_XAW3D)
6579 /* With Xaw, 'top' values too closer to 1.0 may
6580 cause the thumb to disappear. Fix that. */
6581 top = min (top, 0.99f);
6582 #endif
6583 /* Keep two pixels available for moving the thumb down. */
6584 shown = max (0, min (1 - top - (2.0f / height), shown));
6585 #if ! defined (HAVE_XAW3D)
6586 /* Likewise with too small 'shown'. */
6587 shown = max (shown, 0.01f);
6588 #endif
6589
6590 /* If the call to XawScrollbarSetThumb below doesn't seem to
6591 work, check that 'NARROWPROTO' is defined in src/config.h.
6592 If this is not so, most likely you need to fix configure. */
6593 if (top != old_top || shown != old_shown)
6594 {
6595 if (bar->dragging == -1)
6596 XawScrollbarSetThumb (widget, top, shown);
6597 else
6598 {
6599 /* Try to make the scrolling a tad smoother. */
6600 if (!xaw3d_pick_top)
6601 shown = min (shown, old_shown);
6602
6603 XawScrollbarSetThumb (widget, top, shown);
6604 }
6605 }
6606 }
6607 #endif /* !USE_MOTIF */
6608
6609 unblock_input ();
6610 }
6611
6612 static void
x_set_toolkit_horizontal_scroll_bar_thumb(struct scroll_bar * bar,int portion,int position,int whole)6613 x_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position,
6614 int whole)
6615 {
6616 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6617 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
6618 float top, shown;
6619
6620 block_input ();
6621
6622 #ifdef USE_MOTIF
6623 bar->whole = whole;
6624 shown = (float) portion / whole;
6625 top = (float) position / (whole - portion);
6626 {
6627 int size = clip_to_bounds (1, shown * XM_SB_MAX, XM_SB_MAX);
6628 int value = clip_to_bounds (0, top * (XM_SB_MAX - size), XM_SB_MAX - size);
6629
6630 XmScrollBarSetValues (widget, value, size, 0, 0, False);
6631 }
6632 #else /* !USE_MOTIF i.e. use Xaw */
6633 bar->whole = whole;
6634 if (whole == 0)
6635 top = 0, shown = 1;
6636 else
6637 {
6638 top = (float) position / whole;
6639 shown = (float) portion / whole;
6640 }
6641
6642 {
6643 float old_top, old_shown;
6644 Dimension height;
6645 XtVaGetValues (widget,
6646 XtNtopOfThumb, &old_top,
6647 XtNshown, &old_shown,
6648 XtNheight, &height,
6649 NULL);
6650
6651 #if false
6652 /* Massage the top+shown values. */
6653 if (bar->dragging == -1 || bar->last_seen_part == scroll_bar_down_arrow)
6654 top = max (0, min (1, top));
6655 else
6656 top = old_top;
6657 #if ! defined (HAVE_XAW3D)
6658 /* With Xaw, 'top' values too closer to 1.0 may
6659 cause the thumb to disappear. Fix that. */
6660 top = min (top, 0.99f);
6661 #endif
6662 /* Keep two pixels available for moving the thumb down. */
6663 shown = max (0, min (1 - top - (2.0f / height), shown));
6664 #if ! defined (HAVE_XAW3D)
6665 /* Likewise with too small 'shown'. */
6666 shown = max (shown, 0.01f);
6667 #endif
6668 #endif
6669
6670 /* If the call to XawScrollbarSetThumb below doesn't seem to
6671 work, check that 'NARROWPROTO' is defined in src/config.h.
6672 If this is not so, most likely you need to fix configure. */
6673 XawScrollbarSetThumb (widget, top, shown);
6674 #if false
6675 if (top != old_top || shown != old_shown)
6676 {
6677 if (bar->dragging == -1)
6678 XawScrollbarSetThumb (widget, top, shown);
6679 else
6680 {
6681 /* Try to make the scrolling a tad smoother. */
6682 if (!xaw3d_pick_top)
6683 shown = min (shown, old_shown);
6684
6685 XawScrollbarSetThumb (widget, top, shown);
6686 }
6687 }
6688 #endif
6689 }
6690 #endif /* !USE_MOTIF */
6691
6692 unblock_input ();
6693 }
6694 #endif /* not USE_GTK */
6695
6696 #endif /* USE_TOOLKIT_SCROLL_BARS */
6697
6698
6699
6700 /************************************************************************
6701 Scroll bars, general
6702 ************************************************************************/
6703
6704 /* Create a scroll bar and return the scroll bar vector for it. W is
6705 the Emacs window on which to create the scroll bar. TOP, LEFT,
6706 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
6707 scroll bar. */
6708
6709 static struct scroll_bar *
x_scroll_bar_create(struct window * w,int top,int left,int width,int height,bool horizontal)6710 x_scroll_bar_create (struct window *w, int top, int left,
6711 int width, int height, bool horizontal)
6712 {
6713 struct frame *f = XFRAME (w->frame);
6714 struct scroll_bar *bar = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev,
6715 PVEC_OTHER);
6716 Lisp_Object barobj;
6717
6718 block_input ();
6719
6720 #ifdef USE_TOOLKIT_SCROLL_BARS
6721 if (horizontal)
6722 x_create_horizontal_toolkit_scroll_bar (f, bar);
6723 else
6724 x_create_toolkit_scroll_bar (f, bar);
6725 #else /* not USE_TOOLKIT_SCROLL_BARS */
6726 {
6727 XSetWindowAttributes a;
6728 unsigned long mask;
6729 Window window;
6730
6731 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
6732 if (a.background_pixel == -1)
6733 a.background_pixel = FRAME_BACKGROUND_PIXEL (f);
6734
6735 a.event_mask = (ButtonPressMask | ButtonReleaseMask
6736 | ButtonMotionMask | PointerMotionHintMask
6737 | ExposureMask);
6738 a.cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
6739
6740 mask = (CWBackPixel | CWEventMask | CWCursor);
6741
6742 /* Clear the area of W that will serve as a scroll bar. This is
6743 for the case that a window has been split horizontally. In
6744 this case, no clear_frame is generated to reduce flickering. */
6745 if (width > 0 && window_box_height (w) > 0)
6746 x_clear_area (f, left, top, width, window_box_height (w));
6747
6748 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6749 /* Position and size of scroll bar. */
6750 left, top, width, height,
6751 /* Border width, depth, class, and visual. */
6752 0,
6753 CopyFromParent,
6754 CopyFromParent,
6755 CopyFromParent,
6756 /* Attributes. */
6757 mask, &a);
6758 bar->x_window = window;
6759 }
6760 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6761
6762 XSETWINDOW (bar->window, w);
6763 bar->top = top;
6764 bar->left = left;
6765 bar->width = width;
6766 bar->height = height;
6767 bar->start = 0;
6768 bar->end = 0;
6769 bar->dragging = -1;
6770 bar->horizontal = horizontal;
6771 #if defined (USE_TOOLKIT_SCROLL_BARS) && defined (USE_LUCID)
6772 bar->last_seen_part = scroll_bar_nowhere;
6773 #endif
6774
6775 /* Add bar to its frame's list of scroll bars. */
6776 bar->next = FRAME_SCROLL_BARS (f);
6777 bar->prev = Qnil;
6778 XSETVECTOR (barobj, bar);
6779 fset_scroll_bars (f, barobj);
6780 if (!NILP (bar->next))
6781 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
6782
6783 /* Map the window/widget. */
6784 #ifdef USE_TOOLKIT_SCROLL_BARS
6785 {
6786 #ifdef USE_GTK
6787 if (horizontal)
6788 xg_update_horizontal_scrollbar_pos (f, bar->x_window, top,
6789 left, width, max (height, 1));
6790 else
6791 xg_update_scrollbar_pos (f, bar->x_window, top,
6792 left, width, max (height, 1));
6793 #else /* not USE_GTK */
6794 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
6795 XtConfigureWidget (scroll_bar, left, top, width, max (height, 1), 0);
6796 XtMapWidget (scroll_bar);
6797 /* Don't obscure any child frames. */
6798 XLowerWindow (FRAME_X_DISPLAY (f), bar->x_window);
6799 #endif /* not USE_GTK */
6800 }
6801 #else /* not USE_TOOLKIT_SCROLL_BARS */
6802 XMapWindow (FRAME_X_DISPLAY (f), bar->x_window);
6803 /* Don't obscure any child frames. */
6804 XLowerWindow (FRAME_X_DISPLAY (f), bar->x_window);
6805 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6806
6807 unblock_input ();
6808 return bar;
6809 }
6810
6811
6812 #ifndef USE_TOOLKIT_SCROLL_BARS
6813
6814 /* Draw BAR's handle in the proper position.
6815
6816 If the handle is already drawn from START to END, don't bother
6817 redrawing it, unless REBUILD; in that case, always
6818 redraw it. (REBUILD is handy for drawing the handle after expose
6819 events.)
6820
6821 Normally, we want to constrain the start and end of the handle to
6822 fit inside its rectangle, but if the user is dragging the scroll
6823 bar handle, we want to let them drag it down all the way, so that
6824 the bar's top is as far down as it goes; otherwise, there's no way
6825 to move to the very end of the buffer. */
6826
6827 static void
x_scroll_bar_set_handle(struct scroll_bar * bar,int start,int end,bool rebuild)6828 x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
6829 bool rebuild)
6830 {
6831 bool dragging = bar->dragging != -1;
6832 Window w = bar->x_window;
6833 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6834 GC gc = f->output_data.x->normal_gc;
6835
6836 /* If the display is already accurate, do nothing. */
6837 if (! rebuild
6838 && start == bar->start
6839 && end == bar->end)
6840 return;
6841
6842 block_input ();
6843
6844 {
6845 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, bar->width);
6846 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, bar->height);
6847 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
6848
6849 /* Make sure the values are reasonable, and try to preserve
6850 the distance between start and end. */
6851 {
6852 int length = end - start;
6853
6854 if (start < 0)
6855 start = 0;
6856 else if (start > top_range)
6857 start = top_range;
6858 end = start + length;
6859
6860 if (end < start)
6861 end = start;
6862 else if (end > top_range && ! dragging)
6863 end = top_range;
6864 }
6865
6866 /* Store the adjusted setting in the scroll bar. */
6867 bar->start = start;
6868 bar->end = end;
6869
6870 /* Clip the end position, just for display. */
6871 if (end > top_range)
6872 end = top_range;
6873
6874 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
6875 below top positions, to make sure the handle is always at least
6876 that many pixels tall. */
6877 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
6878
6879 /* Draw the empty space above the handle. Note that we can't clear
6880 zero-height areas; that means "clear to end of window." */
6881 if ((inside_width > 0) && (start > 0))
6882 x_clear_area1 (FRAME_X_DISPLAY (f), w,
6883 VERTICAL_SCROLL_BAR_LEFT_BORDER,
6884 VERTICAL_SCROLL_BAR_TOP_BORDER,
6885 inside_width, start, False);
6886
6887 /* Change to proper foreground color if one is specified. */
6888 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
6889 XSetForeground (FRAME_X_DISPLAY (f), gc,
6890 f->output_data.x->scroll_bar_foreground_pixel);
6891
6892 /* Draw the handle itself. */
6893 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
6894 /* x, y, width, height */
6895 VERTICAL_SCROLL_BAR_LEFT_BORDER,
6896 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
6897 inside_width, end - start);
6898
6899 /* Restore the foreground color of the GC if we changed it above. */
6900 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
6901 XSetForeground (FRAME_X_DISPLAY (f), gc,
6902 FRAME_FOREGROUND_PIXEL (f));
6903
6904 /* Draw the empty space below the handle. Note that we can't
6905 clear zero-height areas; that means "clear to end of window." */
6906 if ((inside_width > 0) && (end < inside_height))
6907 x_clear_area1 (FRAME_X_DISPLAY (f), w,
6908 VERTICAL_SCROLL_BAR_LEFT_BORDER,
6909 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
6910 inside_width, inside_height - end, False);
6911 }
6912
6913 unblock_input ();
6914 }
6915
6916 #endif /* !USE_TOOLKIT_SCROLL_BARS */
6917
6918 /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
6919 nil. */
6920
6921 static void
x_scroll_bar_remove(struct scroll_bar * bar)6922 x_scroll_bar_remove (struct scroll_bar *bar)
6923 {
6924 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6925 block_input ();
6926
6927 #ifdef USE_TOOLKIT_SCROLL_BARS
6928 #ifdef USE_GTK
6929 xg_remove_scroll_bar (f, bar->x_window);
6930 #else /* not USE_GTK */
6931 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
6932 #endif /* not USE_GTK */
6933 #else
6934 XDestroyWindow (FRAME_X_DISPLAY (f), bar->x_window);
6935 #endif
6936
6937 /* Dissociate this scroll bar from its window. */
6938 if (bar->horizontal)
6939 wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
6940 else
6941 wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
6942
6943 unblock_input ();
6944 }
6945
6946
6947 /* Set the handle of the vertical scroll bar for WINDOW to indicate
6948 that we are displaying PORTION characters out of a total of WHOLE
6949 characters, starting at POSITION. If WINDOW has no scroll bar,
6950 create one. */
6951
6952 static void
XTset_vertical_scroll_bar(struct window * w,int portion,int whole,int position)6953 XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int position)
6954 {
6955 struct frame *f = XFRAME (w->frame);
6956 Lisp_Object barobj;
6957 struct scroll_bar *bar;
6958 int top, height, left, width;
6959 int window_y, window_height;
6960
6961 /* Get window dimensions. */
6962 window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
6963 top = window_y;
6964 height = window_height;
6965 left = WINDOW_SCROLL_BAR_AREA_X (w);
6966 width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
6967
6968 /* Does the scroll bar exist yet? */
6969 if (NILP (w->vertical_scroll_bar))
6970 {
6971 if (width > 0 && height > 0)
6972 {
6973 block_input ();
6974 x_clear_area (f, left, top, width, height);
6975 unblock_input ();
6976 }
6977
6978 bar = x_scroll_bar_create (w, top, left, width, max (height, 1), false);
6979 }
6980 else
6981 {
6982 /* It may just need to be moved and resized. */
6983 unsigned int mask = 0;
6984
6985 bar = XSCROLL_BAR (w->vertical_scroll_bar);
6986
6987 block_input ();
6988
6989 if (left != bar->left)
6990 mask |= CWX;
6991 if (top != bar->top)
6992 mask |= CWY;
6993 if (width != bar->width)
6994 mask |= CWWidth;
6995 if (height != bar->height)
6996 mask |= CWHeight;
6997
6998 #ifdef USE_TOOLKIT_SCROLL_BARS
6999
7000 /* Move/size the scroll bar widget. */
7001 if (mask)
7002 {
7003 /* Since toolkit scroll bars are smaller than the space reserved
7004 for them on the frame, we have to clear "under" them. */
7005 if (width > 0 && height > 0)
7006 x_clear_area (f, left, top, width, height);
7007 #ifdef USE_GTK
7008 xg_update_scrollbar_pos (f, bar->x_window, top,
7009 left, width, max (height, 1));
7010 #else /* not USE_GTK */
7011 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
7012 left, top, width, max (height, 1), 0);
7013 #endif /* not USE_GTK */
7014 }
7015 #else /* not USE_TOOLKIT_SCROLL_BARS */
7016
7017 /* Move/size the scroll bar window. */
7018 if (mask)
7019 {
7020 XWindowChanges wc;
7021
7022 wc.x = left;
7023 wc.y = top;
7024 wc.width = width;
7025 wc.height = height;
7026 XConfigureWindow (FRAME_X_DISPLAY (f), bar->x_window,
7027 mask, &wc);
7028 }
7029
7030 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7031
7032 /* Remember new settings. */
7033 bar->left = left;
7034 bar->top = top;
7035 bar->width = width;
7036 bar->height = height;
7037
7038 unblock_input ();
7039 }
7040
7041 #ifdef USE_TOOLKIT_SCROLL_BARS
7042 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
7043 #else /* not USE_TOOLKIT_SCROLL_BARS */
7044 /* Set the scroll bar's current state, unless we're currently being
7045 dragged. */
7046 if (bar->dragging == -1)
7047 {
7048 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
7049
7050 if (whole == 0)
7051 x_scroll_bar_set_handle (bar, 0, top_range, false);
7052 else
7053 {
7054 int start = ((double) position * top_range) / whole;
7055 int end = ((double) (position + portion) * top_range) / whole;
7056 x_scroll_bar_set_handle (bar, start, end, false);
7057 }
7058 }
7059 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7060
7061 XSETVECTOR (barobj, bar);
7062 wset_vertical_scroll_bar (w, barobj);
7063 }
7064
7065
7066 static void
XTset_horizontal_scroll_bar(struct window * w,int portion,int whole,int position)7067 XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int position)
7068 {
7069 struct frame *f = XFRAME (w->frame);
7070 Lisp_Object barobj;
7071 struct scroll_bar *bar;
7072 int top, height, left, width;
7073 int window_x, window_width;
7074 int pixel_width = WINDOW_PIXEL_WIDTH (w);
7075
7076 /* Get window dimensions. */
7077 window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
7078 left = window_x;
7079 width = window_width;
7080 top = WINDOW_SCROLL_BAR_AREA_Y (w);
7081 height = WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
7082
7083 /* Does the scroll bar exist yet? */
7084 if (NILP (w->horizontal_scroll_bar))
7085 {
7086 if (width > 0 && height > 0)
7087 {
7088 block_input ();
7089
7090 /* Clear also part between window_width and
7091 WINDOW_PIXEL_WIDTH. */
7092 x_clear_area (f, left, top, pixel_width, height);
7093 unblock_input ();
7094 }
7095
7096 bar = x_scroll_bar_create (w, top, left, width, height, true);
7097 }
7098 else
7099 {
7100 /* It may just need to be moved and resized. */
7101 unsigned int mask = 0;
7102
7103 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
7104
7105 block_input ();
7106
7107 if (left != bar->left)
7108 mask |= CWX;
7109 if (top != bar->top)
7110 mask |= CWY;
7111 if (width != bar->width)
7112 mask |= CWWidth;
7113 if (height != bar->height)
7114 mask |= CWHeight;
7115
7116 #ifdef USE_TOOLKIT_SCROLL_BARS
7117 /* Move/size the scroll bar widget. */
7118 if (mask)
7119 {
7120 /* Since toolkit scroll bars are smaller than the space reserved
7121 for them on the frame, we have to clear "under" them. */
7122 if (width > 0 && height > 0)
7123 x_clear_area (f,
7124 WINDOW_LEFT_EDGE_X (w), top,
7125 pixel_width - WINDOW_RIGHT_DIVIDER_WIDTH (w), height);
7126 #ifdef USE_GTK
7127 xg_update_horizontal_scrollbar_pos (f, bar->x_window, top, left,
7128 width, height);
7129 #else /* not USE_GTK */
7130 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
7131 left, top, width, height, 0);
7132 #endif /* not USE_GTK */
7133 }
7134 #else /* not USE_TOOLKIT_SCROLL_BARS */
7135
7136 /* Clear areas not covered by the scroll bar because it's not as
7137 wide as the area reserved for it. This makes sure a
7138 previous mode line display is cleared after C-x 2 C-x 1, for
7139 example. */
7140 {
7141 int area_height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
7142 int rest = area_height - height;
7143 if (rest > 0 && width > 0)
7144 x_clear_area (f, left, top, width, rest);
7145 }
7146
7147 /* Move/size the scroll bar window. */
7148 if (mask)
7149 {
7150 XWindowChanges wc;
7151
7152 wc.x = left;
7153 wc.y = top;
7154 wc.width = width;
7155 wc.height = height;
7156 XConfigureWindow (FRAME_X_DISPLAY (f), bar->x_window,
7157 mask, &wc);
7158 }
7159
7160 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7161
7162 /* Remember new settings. */
7163 bar->left = left;
7164 bar->top = top;
7165 bar->width = width;
7166 bar->height = height;
7167
7168 unblock_input ();
7169 }
7170
7171 #ifdef USE_TOOLKIT_SCROLL_BARS
7172 x_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
7173 #else /* not USE_TOOLKIT_SCROLL_BARS */
7174 /* Set the scroll bar's current state, unless we're currently being
7175 dragged. */
7176 if (bar->dragging == -1)
7177 {
7178 int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, width);
7179
7180 if (whole == 0)
7181 x_scroll_bar_set_handle (bar, 0, left_range, false);
7182 else
7183 {
7184 int start = ((double) position * left_range) / whole;
7185 int end = ((double) (position + portion) * left_range) / whole;
7186 x_scroll_bar_set_handle (bar, start, end, false);
7187 }
7188 }
7189 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7190
7191 XSETVECTOR (barobj, bar);
7192 wset_horizontal_scroll_bar (w, barobj);
7193 }
7194
7195
7196 /* The following three hooks are used when we're doing a thorough
7197 redisplay of the frame. We don't explicitly know which scroll bars
7198 are going to be deleted, because keeping track of when windows go
7199 away is a real pain - "Can you say set-window-configuration, boys
7200 and girls?" Instead, we just assert at the beginning of redisplay
7201 that *all* scroll bars are to be removed, and then save a scroll bar
7202 from the fiery pit when we actually redisplay its window. */
7203
7204 /* Arrange for all scroll bars on FRAME to be removed at the next call
7205 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
7206 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
7207
7208 static void
XTcondemn_scroll_bars(struct frame * frame)7209 XTcondemn_scroll_bars (struct frame *frame)
7210 {
7211 if (!NILP (FRAME_SCROLL_BARS (frame)))
7212 {
7213 if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
7214 {
7215 /* Prepend scrollbars to already condemned ones. */
7216 Lisp_Object last = FRAME_SCROLL_BARS (frame);
7217
7218 while (!NILP (XSCROLL_BAR (last)->next))
7219 last = XSCROLL_BAR (last)->next;
7220
7221 XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
7222 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last;
7223 }
7224
7225 fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame));
7226 fset_scroll_bars (frame, Qnil);
7227 }
7228 }
7229
7230
7231 /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
7232 Note that WINDOW isn't necessarily condemned at all. */
7233
7234 static void
XTredeem_scroll_bar(struct window * w)7235 XTredeem_scroll_bar (struct window *w)
7236 {
7237 struct scroll_bar *bar;
7238 Lisp_Object barobj;
7239 struct frame *f;
7240
7241 /* We can't redeem this window's scroll bar if it doesn't have one. */
7242 if (NILP (w->vertical_scroll_bar) && NILP (w->horizontal_scroll_bar))
7243 emacs_abort ();
7244
7245 if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
7246 {
7247 bar = XSCROLL_BAR (w->vertical_scroll_bar);
7248 /* Unlink it from the condemned list. */
7249 f = XFRAME (WINDOW_FRAME (w));
7250 if (NILP (bar->prev))
7251 {
7252 /* If the prev pointer is nil, it must be the first in one of
7253 the lists. */
7254 if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar))
7255 /* It's not condemned. Everything's fine. */
7256 goto horizontal;
7257 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
7258 w->vertical_scroll_bar))
7259 fset_condemned_scroll_bars (f, bar->next);
7260 else
7261 /* If its prev pointer is nil, it must be at the front of
7262 one or the other! */
7263 emacs_abort ();
7264 }
7265 else
7266 XSCROLL_BAR (bar->prev)->next = bar->next;
7267
7268 if (! NILP (bar->next))
7269 XSCROLL_BAR (bar->next)->prev = bar->prev;
7270
7271 bar->next = FRAME_SCROLL_BARS (f);
7272 bar->prev = Qnil;
7273 XSETVECTOR (barobj, bar);
7274 fset_scroll_bars (f, barobj);
7275 if (! NILP (bar->next))
7276 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
7277 }
7278
7279 horizontal:
7280 if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w))
7281 {
7282 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
7283 /* Unlink it from the condemned list. */
7284 f = XFRAME (WINDOW_FRAME (w));
7285 if (NILP (bar->prev))
7286 {
7287 /* If the prev pointer is nil, it must be the first in one of
7288 the lists. */
7289 if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar))
7290 /* It's not condemned. Everything's fine. */
7291 return;
7292 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
7293 w->horizontal_scroll_bar))
7294 fset_condemned_scroll_bars (f, bar->next);
7295 else
7296 /* If its prev pointer is nil, it must be at the front of
7297 one or the other! */
7298 emacs_abort ();
7299 }
7300 else
7301 XSCROLL_BAR (bar->prev)->next = bar->next;
7302
7303 if (! NILP (bar->next))
7304 XSCROLL_BAR (bar->next)->prev = bar->prev;
7305
7306 bar->next = FRAME_SCROLL_BARS (f);
7307 bar->prev = Qnil;
7308 XSETVECTOR (barobj, bar);
7309 fset_scroll_bars (f, barobj);
7310 if (! NILP (bar->next))
7311 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
7312 }
7313 }
7314
7315 /* Remove all scroll bars on FRAME that haven't been saved since the
7316 last call to `*condemn_scroll_bars_hook'. */
7317
7318 static void
XTjudge_scroll_bars(struct frame * f)7319 XTjudge_scroll_bars (struct frame *f)
7320 {
7321 Lisp_Object bar, next;
7322
7323 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
7324
7325 /* Clear out the condemned list now so we won't try to process any
7326 more events on the hapless scroll bars. */
7327 fset_condemned_scroll_bars (f, Qnil);
7328
7329 for (; ! NILP (bar); bar = next)
7330 {
7331 struct scroll_bar *b = XSCROLL_BAR (bar);
7332
7333 x_scroll_bar_remove (b);
7334
7335 next = b->next;
7336 b->next = b->prev = Qnil;
7337 }
7338
7339 /* Now there should be no references to the condemned scroll bars,
7340 and they should get garbage-collected. */
7341 }
7342
7343
7344 #ifndef USE_TOOLKIT_SCROLL_BARS
7345 /* Handle an Expose or GraphicsExpose event on a scroll bar. This
7346 is a no-op when using toolkit scroll bars.
7347
7348 This may be called from a signal handler, so we have to ignore GC
7349 mark bits. */
7350
7351 static void
x_scroll_bar_expose(struct scroll_bar * bar,const XEvent * event)7352 x_scroll_bar_expose (struct scroll_bar *bar, const XEvent *event)
7353 {
7354 Window w = bar->x_window;
7355 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7356 GC gc = f->output_data.x->normal_gc;
7357
7358 block_input ();
7359
7360 x_scroll_bar_set_handle (bar, bar->start, bar->end, true);
7361
7362 /* Switch to scroll bar foreground color. */
7363 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
7364 XSetForeground (FRAME_X_DISPLAY (f), gc,
7365 f->output_data.x->scroll_bar_foreground_pixel);
7366
7367 /* Draw a one-pixel border just inside the edges of the scroll bar. */
7368 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
7369 /* x, y, width, height */
7370 0, 0, bar->width - 1, bar->height - 1);
7371
7372 /* Restore the foreground color of the GC if we changed it above. */
7373 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
7374 XSetForeground (FRAME_X_DISPLAY (f), gc,
7375 FRAME_FOREGROUND_PIXEL (f));
7376
7377 unblock_input ();
7378
7379 }
7380 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7381
7382 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
7383 is set to something other than NO_EVENT, it is enqueued.
7384
7385 This may be called from a signal handler, so we have to ignore GC
7386 mark bits. */
7387
7388
7389 static void
x_scroll_bar_handle_click(struct scroll_bar * bar,const XEvent * event,struct input_event * emacs_event)7390 x_scroll_bar_handle_click (struct scroll_bar *bar,
7391 const XEvent *event,
7392 struct input_event *emacs_event)
7393 {
7394 if (! WINDOWP (bar->window))
7395 emacs_abort ();
7396
7397 emacs_event->kind = (bar->horizontal
7398 ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT
7399 : SCROLL_BAR_CLICK_EVENT);
7400 emacs_event->code = event->xbutton.button - Button1;
7401 emacs_event->modifiers
7402 = (x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO
7403 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
7404 event->xbutton.state)
7405 | (event->type == ButtonRelease
7406 ? up_modifier
7407 : down_modifier));
7408 emacs_event->frame_or_window = bar->window;
7409 emacs_event->arg = Qnil;
7410 emacs_event->timestamp = event->xbutton.time;
7411 if (bar->horizontal)
7412 {
7413 int left_range
7414 = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
7415 int x = event->xbutton.x - HORIZONTAL_SCROLL_BAR_LEFT_BORDER;
7416
7417 if (x < 0) x = 0;
7418 if (x > left_range) x = left_range;
7419
7420 if (x < bar->start)
7421 emacs_event->part = scroll_bar_before_handle;
7422 else if (x < bar->end + HORIZONTAL_SCROLL_BAR_MIN_HANDLE)
7423 emacs_event->part = scroll_bar_horizontal_handle;
7424 else
7425 emacs_event->part = scroll_bar_after_handle;
7426
7427 #ifndef USE_TOOLKIT_SCROLL_BARS
7428 /* If the user has released the handle, set it to its final position. */
7429 if (event->type == ButtonRelease && bar->dragging != -1)
7430 {
7431 int new_start = - bar->dragging;
7432 int new_end = new_start + bar->end - bar->start;
7433
7434 x_scroll_bar_set_handle (bar, new_start, new_end, false);
7435 bar->dragging = -1;
7436 }
7437 #endif
7438
7439 XSETINT (emacs_event->x, left_range);
7440 XSETINT (emacs_event->y, x);
7441 }
7442 else
7443 {
7444 int top_range
7445 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
7446 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
7447
7448 if (y < 0) y = 0;
7449 if (y > top_range) y = top_range;
7450
7451 if (y < bar->start)
7452 emacs_event->part = scroll_bar_above_handle;
7453 else if (y < bar->end + VERTICAL_SCROLL_BAR_MIN_HANDLE)
7454 emacs_event->part = scroll_bar_handle;
7455 else
7456 emacs_event->part = scroll_bar_below_handle;
7457
7458 #ifndef USE_TOOLKIT_SCROLL_BARS
7459 /* If the user has released the handle, set it to its final position. */
7460 if (event->type == ButtonRelease && bar->dragging != -1)
7461 {
7462 int new_start = y - bar->dragging;
7463 int new_end = new_start + bar->end - bar->start;
7464
7465 x_scroll_bar_set_handle (bar, new_start, new_end, false);
7466 bar->dragging = -1;
7467 }
7468 #endif
7469
7470 XSETINT (emacs_event->x, y);
7471 XSETINT (emacs_event->y, top_range);
7472 }
7473 }
7474
7475 #ifndef USE_TOOLKIT_SCROLL_BARS
7476
7477 /* Handle some mouse motion while someone is dragging the scroll bar.
7478
7479 This may be called from a signal handler, so we have to ignore GC
7480 mark bits. */
7481
7482 static void
x_scroll_bar_note_movement(struct scroll_bar * bar,const XMotionEvent * event)7483 x_scroll_bar_note_movement (struct scroll_bar *bar,
7484 const XMotionEvent *event)
7485 {
7486 struct frame *f = XFRAME (XWINDOW (bar->window)->frame);
7487 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
7488
7489 dpyinfo->last_mouse_movement_time = event->time;
7490 dpyinfo->last_mouse_scroll_bar = bar;
7491 f->mouse_moved = true;
7492
7493 /* If we're dragging the bar, display it. */
7494 if (bar->dragging != -1)
7495 {
7496 /* Where should the handle be now? */
7497 int new_start = event->y - bar->dragging;
7498
7499 if (new_start != bar->start)
7500 {
7501 int new_end = new_start + bar->end - bar->start;
7502
7503 x_scroll_bar_set_handle (bar, new_start, new_end, false);
7504 }
7505 }
7506 }
7507
7508 #endif /* !USE_TOOLKIT_SCROLL_BARS */
7509
7510 /* Return information to the user about the current position of the mouse
7511 on the scroll bar. */
7512
7513 static void
x_scroll_bar_report_motion(struct frame ** fp,Lisp_Object * bar_window,enum scroll_bar_part * part,Lisp_Object * x,Lisp_Object * y,Time * timestamp)7514 x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
7515 enum scroll_bar_part *part, Lisp_Object *x,
7516 Lisp_Object *y, Time *timestamp)
7517 {
7518 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
7519 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
7520 Window w = bar->x_window;
7521 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7522 int win_x, win_y;
7523 Window dummy_window;
7524 int dummy_coord;
7525 unsigned int dummy_mask;
7526
7527 block_input ();
7528
7529 /* Get the mouse's position relative to the scroll bar window, and
7530 report that. */
7531 if (XQueryPointer (FRAME_X_DISPLAY (f), w,
7532
7533 /* Root, child, root x and root y. */
7534 &dummy_window, &dummy_window,
7535 &dummy_coord, &dummy_coord,
7536
7537 /* Position relative to scroll bar. */
7538 &win_x, &win_y,
7539
7540 /* Mouse buttons and modifier keys. */
7541 &dummy_mask))
7542 {
7543 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
7544
7545 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
7546
7547 if (bar->dragging != -1)
7548 win_y -= bar->dragging;
7549
7550 if (win_y < 0)
7551 win_y = 0;
7552 if (win_y > top_range)
7553 win_y = top_range;
7554
7555 *fp = f;
7556 *bar_window = bar->window;
7557
7558 if (bar->dragging != -1)
7559 *part = scroll_bar_handle;
7560 else if (win_y < bar->start)
7561 *part = scroll_bar_above_handle;
7562 else if (win_y < bar->end + VERTICAL_SCROLL_BAR_MIN_HANDLE)
7563 *part = scroll_bar_handle;
7564 else
7565 *part = scroll_bar_below_handle;
7566
7567 XSETINT (*x, win_y);
7568 XSETINT (*y, top_range);
7569
7570 f->mouse_moved = false;
7571 dpyinfo->last_mouse_scroll_bar = NULL;
7572 *timestamp = dpyinfo->last_mouse_movement_time;
7573 }
7574
7575 unblock_input ();
7576 }
7577
7578
7579 /* Return information to the user about the current position of the mouse
7580 on the scroll bar. */
7581
7582 static void
x_horizontal_scroll_bar_report_motion(struct frame ** fp,Lisp_Object * bar_window,enum scroll_bar_part * part,Lisp_Object * x,Lisp_Object * y,Time * timestamp)7583 x_horizontal_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
7584 enum scroll_bar_part *part, Lisp_Object *x,
7585 Lisp_Object *y, Time *timestamp)
7586 {
7587 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
7588 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
7589 Window w = bar->x_window;
7590 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7591 int win_x, win_y;
7592 Window dummy_window;
7593 int dummy_coord;
7594 unsigned int dummy_mask;
7595
7596 block_input ();
7597
7598 /* Get the mouse's position relative to the scroll bar window, and
7599 report that. */
7600 if (XQueryPointer (FRAME_X_DISPLAY (f), w,
7601
7602 /* Root, child, root x and root y. */
7603 &dummy_window, &dummy_window,
7604 &dummy_coord, &dummy_coord,
7605
7606 /* Position relative to scroll bar. */
7607 &win_x, &win_y,
7608
7609 /* Mouse buttons and modifier keys. */
7610 &dummy_mask))
7611 {
7612 int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
7613
7614 win_x -= HORIZONTAL_SCROLL_BAR_LEFT_BORDER;
7615
7616 if (bar->dragging != -1)
7617 win_x -= bar->dragging;
7618
7619 if (win_x < 0)
7620 win_x = 0;
7621 if (win_x > left_range)
7622 win_x = left_range;
7623
7624 *fp = f;
7625 *bar_window = bar->window;
7626
7627 if (bar->dragging != -1)
7628 *part = scroll_bar_horizontal_handle;
7629 else if (win_x < bar->start)
7630 *part = scroll_bar_before_handle;
7631 else if (win_x < bar->end + HORIZONTAL_SCROLL_BAR_MIN_HANDLE)
7632 *part = scroll_bar_handle;
7633 else
7634 *part = scroll_bar_after_handle;
7635
7636 XSETINT (*y, win_x);
7637 XSETINT (*x, left_range);
7638
7639 f->mouse_moved = false;
7640 dpyinfo->last_mouse_scroll_bar = NULL;
7641 *timestamp = dpyinfo->last_mouse_movement_time;
7642 }
7643
7644 unblock_input ();
7645 }
7646
7647
7648 /* The screen has been cleared so we may have changed foreground or
7649 background colors, and the scroll bars may need to be redrawn.
7650 Clear out the scroll bars, and ask for expose events, so we can
7651 redraw them. */
7652
7653 static void
x_scroll_bar_clear(struct frame * f)7654 x_scroll_bar_clear (struct frame *f)
7655 {
7656 #ifndef USE_TOOLKIT_SCROLL_BARS
7657 Lisp_Object bar;
7658
7659 /* We can have scroll bars even if this is 0,
7660 if we just turned off scroll bar mode.
7661 But in that case we should not clear them. */
7662 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
7663 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
7664 bar = XSCROLL_BAR (bar)->next)
7665 XClearArea (FRAME_X_DISPLAY (f),
7666 XSCROLL_BAR (bar)->x_window,
7667 0, 0, 0, 0, True);
7668 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7669 }
7670
7671 #ifdef ENABLE_CHECKING
7672
7673 /* Record the last 100 characters stored
7674 to help debug the loss-of-chars-during-GC problem. */
7675
7676 static int temp_index;
7677 static short temp_buffer[100];
7678
7679 #define STORE_KEYSYM_FOR_DEBUG(keysym) \
7680 if (temp_index == ARRAYELTS (temp_buffer)) \
7681 temp_index = 0; \
7682 temp_buffer[temp_index++] = (keysym)
7683
7684 #else /* not ENABLE_CHECKING */
7685
7686 #define STORE_KEYSYM_FOR_DEBUG(keysym) ((void)0)
7687
7688 #endif /* ENABLE_CHECKING */
7689
7690 /* Set this to nonzero to fake an "X I/O error"
7691 on a particular display. */
7692
7693 static struct x_display_info *XTread_socket_fake_io_error;
7694
7695 /* When we find no input here, we occasionally do a no-op command
7696 to verify that the X server is still running and we can still talk with it.
7697 We try all the open displays, one by one.
7698 This variable is used for cycling thru the displays. */
7699
7700 static struct x_display_info *next_noop_dpyinfo;
7701
7702 enum
7703 {
7704 X_EVENT_NORMAL,
7705 X_EVENT_GOTO_OUT,
7706 X_EVENT_DROP
7707 };
7708
7709 /* Filter events for the current X input method.
7710 DPYINFO is the display this event is for.
7711 EVENT is the X event to filter.
7712
7713 Returns non-zero if the event was filtered, caller shall not process
7714 this event further.
7715 Returns zero if event is wasn't filtered. */
7716
7717 #ifdef HAVE_X_I18N
7718 static int
x_filter_event(struct x_display_info * dpyinfo,XEvent * event)7719 x_filter_event (struct x_display_info *dpyinfo, XEvent *event)
7720 {
7721 /* XFilterEvent returns non-zero if the input method has
7722 consumed the event. We pass the frame's X window to
7723 XFilterEvent because that's the one for which the IC
7724 was created. */
7725
7726 struct frame *f1 = x_any_window_to_frame (dpyinfo,
7727 event->xclient.window);
7728
7729 return XFilterEvent (event, f1 ? FRAME_X_WINDOW (f1) : None);
7730 }
7731 #endif
7732
7733 #ifdef USE_GTK
7734 static int current_count;
7735 static int current_finish;
7736 static struct input_event *current_hold_quit;
7737
7738 /* This is the filter function invoked by the GTK event loop.
7739 It is invoked before the XEvent is translated to a GdkEvent,
7740 so we have a chance to act on the event before GTK. */
7741 static GdkFilterReturn
event_handler_gdk(GdkXEvent * gxev,GdkEvent * ev,gpointer data)7742 event_handler_gdk (GdkXEvent *gxev, GdkEvent *ev, gpointer data)
7743 {
7744 XEvent *xev = (XEvent *) gxev;
7745
7746 block_input ();
7747 if (current_count >= 0)
7748 {
7749 struct x_display_info *dpyinfo;
7750
7751 dpyinfo = x_display_info_for_display (xev->xany.display);
7752
7753 #ifdef HAVE_X_I18N
7754 /* Filter events for the current X input method.
7755 GTK calls XFilterEvent but not for key press and release,
7756 so we do it here. */
7757 if ((xev->type == KeyPress || xev->type == KeyRelease)
7758 && dpyinfo
7759 && x_filter_event (dpyinfo, xev))
7760 {
7761 unblock_input ();
7762 return GDK_FILTER_REMOVE;
7763 }
7764 #endif
7765
7766 if (! dpyinfo)
7767 current_finish = X_EVENT_NORMAL;
7768 else
7769 current_count
7770 += handle_one_xevent (dpyinfo, xev, ¤t_finish,
7771 current_hold_quit);
7772 }
7773 else
7774 current_finish = x_dispatch_event (xev, xev->xany.display);
7775
7776 unblock_input ();
7777
7778 if (current_finish == X_EVENT_GOTO_OUT || current_finish == X_EVENT_DROP)
7779 return GDK_FILTER_REMOVE;
7780
7781 return GDK_FILTER_CONTINUE;
7782 }
7783 #endif /* USE_GTK */
7784
7785
7786 static void xembed_send_message (struct frame *f, Time,
7787 enum xembed_message,
7788 long detail, long data1, long data2);
7789
7790 static void
x_net_wm_state(struct frame * f,Window window)7791 x_net_wm_state (struct frame *f, Window window)
7792 {
7793 int value = FULLSCREEN_NONE;
7794 Lisp_Object lval = Qnil;
7795 bool sticky = false;
7796
7797 x_get_current_wm_state (f, window, &value, &sticky);
7798
7799 switch (value)
7800 {
7801 case FULLSCREEN_WIDTH:
7802 lval = Qfullwidth;
7803 break;
7804 case FULLSCREEN_HEIGHT:
7805 lval = Qfullheight;
7806 break;
7807 case FULLSCREEN_BOTH:
7808 lval = Qfullboth;
7809 break;
7810 case FULLSCREEN_MAXIMIZED:
7811 lval = Qmaximized;
7812 break;
7813 }
7814
7815 frame_size_history_add
7816 (f, Qx_net_wm_state, 0, 0,
7817 list2 (get_frame_param (f, Qfullscreen), lval));
7818
7819 store_frame_param (f, Qfullscreen, lval);
7820 /** store_frame_param (f, Qsticky, sticky ? Qt : Qnil); **/
7821 }
7822
7823 /* Flip back buffers on any frames with undrawn content. */
7824 static void
flush_dirty_back_buffers(void)7825 flush_dirty_back_buffers (void)
7826 {
7827 block_input ();
7828 Lisp_Object tail, frame;
7829 FOR_EACH_FRAME (tail, frame)
7830 {
7831 struct frame *f = XFRAME (frame);
7832 if (FRAME_LIVE_P (f) &&
7833 FRAME_X_P (f) &&
7834 FRAME_X_WINDOW (f) &&
7835 !FRAME_GARBAGED_P (f) &&
7836 !buffer_flipping_blocked_p () &&
7837 FRAME_X_NEED_BUFFER_FLIP (f))
7838 show_back_buffer (f);
7839 }
7840 unblock_input ();
7841 }
7842
7843 /**
7844 mouse_or_wdesc_frame: When not dropping and the mouse was grabbed
7845 for DPYINFO, return the frame where the mouse was seen last. If
7846 there's no such frame, return the frame according to WDESC. When
7847 dropping, return the frame according to WDESC. If there's no such
7848 frame and the mouse was grabbed for DPYINFO, return the frame where
7849 the mouse was seen last. In either case, never return a tooltip
7850 frame. */
7851 static struct frame *
mouse_or_wdesc_frame(struct x_display_info * dpyinfo,int wdesc)7852 mouse_or_wdesc_frame (struct x_display_info *dpyinfo, int wdesc)
7853 {
7854 struct frame *lm_f = (gui_mouse_grabbed (dpyinfo)
7855 ? dpyinfo->last_mouse_frame
7856 : NULL);
7857
7858 if (lm_f && !EQ (track_mouse, Qdropping))
7859 return lm_f;
7860 else
7861 {
7862 struct frame *w_f = x_window_to_frame (dpyinfo, wdesc);
7863
7864 /* Do not return a tooltip frame. */
7865 if (!w_f || FRAME_TOOLTIP_P (w_f))
7866 return EQ (track_mouse, Qdropping) ? lm_f : NULL;
7867 else
7868 /* When dropping it would be probably nice to raise w_f
7869 here. */
7870 return w_f;
7871 }
7872 }
7873
7874 /* Handles the XEvent EVENT on display DPYINFO.
7875
7876 *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
7877 *FINISH is zero if caller should continue reading events.
7878 *FINISH is X_EVENT_DROP if event should not be passed to the toolkit.
7879 *EVENT is unchanged unless we're processing KeyPress event.
7880
7881 We return the number of characters stored into the buffer. */
7882
7883 static int
handle_one_xevent(struct x_display_info * dpyinfo,const XEvent * event,int * finish,struct input_event * hold_quit)7884 handle_one_xevent (struct x_display_info *dpyinfo,
7885 const XEvent *event,
7886 int *finish, struct input_event *hold_quit)
7887 {
7888 union buffered_input_event inev;
7889 int count = 0;
7890 int do_help = 0;
7891 ptrdiff_t nbytes = 0;
7892 struct frame *any, *f = NULL;
7893 struct coding_system coding;
7894 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
7895 /* This holds the state XLookupString needs to implement dead keys
7896 and other tricks known as "compose processing". _X Window System_
7897 says that a portable program can't use this, but Stephen Gildea assures
7898 me that letting the compiler initialize it to zeros will work okay. */
7899 static XComposeStatus compose_status;
7900 XEvent configureEvent;
7901 XEvent next_event;
7902
7903 USE_SAFE_ALLOCA;
7904
7905 *finish = X_EVENT_NORMAL;
7906
7907 EVENT_INIT (inev.ie);
7908 inev.ie.kind = NO_EVENT;
7909 inev.ie.arg = Qnil;
7910
7911 any = x_any_window_to_frame (dpyinfo, event->xany.window);
7912
7913 if (any && any->wait_event_type == event->type)
7914 any->wait_event_type = 0; /* Indicates we got it. */
7915
7916 switch (event->type)
7917 {
7918 case ClientMessage:
7919 {
7920 if (event->xclient.message_type == dpyinfo->Xatom_wm_protocols
7921 && event->xclient.format == 32)
7922 {
7923 if (event->xclient.data.l[0] == dpyinfo->Xatom_wm_take_focus)
7924 {
7925 /* Use the value returned by x_any_window_to_frame
7926 because this could be the shell widget window
7927 if the frame has no title bar. */
7928 f = any;
7929 #ifdef HAVE_X_I18N
7930 /* Not quite sure this is needed -pd */
7931 if (f && FRAME_XIC (f))
7932 XSetICFocus (FRAME_XIC (f));
7933 #endif
7934 #if false
7935 /* Emacs sets WM hints whose `input' field is `true'. This
7936 instructs the WM to set the input focus automatically for
7937 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
7938 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
7939 it has set the focus. So, XSetInputFocus below is not
7940 needed.
7941
7942 The call to XSetInputFocus below has also caused trouble. In
7943 cases where the XSetInputFocus done by the WM and the one
7944 below are temporally close (on a fast machine), the call
7945 below can generate additional FocusIn events which confuse
7946 Emacs. */
7947
7948 /* Since we set WM_TAKE_FOCUS, we must call
7949 XSetInputFocus explicitly. But not if f is null,
7950 since that might be an event for a deleted frame. */
7951 if (f)
7952 {
7953 Display *d = event->xclient.display;
7954 /* Catch and ignore errors, in case window has been
7955 iconified by a window manager such as GWM. */
7956 x_catch_errors (d);
7957 XSetInputFocus (d, event->xclient.window,
7958 /* The ICCCM says this is
7959 the only valid choice. */
7960 RevertToParent,
7961 event->xclient.data.l[1]);
7962 x_uncatch_errors ();
7963 }
7964 /* Not certain about handling scroll bars here */
7965 #endif
7966 goto done;
7967 }
7968
7969 if (event->xclient.data.l[0] == dpyinfo->Xatom_wm_save_yourself)
7970 {
7971 /* Save state modify the WM_COMMAND property to
7972 something which can reinstate us. This notifies
7973 the session manager, who's looking for such a
7974 PropertyNotify. Can restart processing when
7975 a keyboard or mouse event arrives. */
7976 /* If we have a session manager, don't set this.
7977 KDE will then start two Emacsen, one for the
7978 session manager and one for this. */
7979 #ifdef HAVE_X_SM
7980 if (! x_session_have_connection ())
7981 #endif
7982 {
7983 f = x_top_window_to_frame (dpyinfo,
7984 event->xclient.window);
7985 /* This is just so we only give real data once
7986 for a single Emacs process. */
7987 if (f == SELECTED_FRAME ())
7988 XSetCommand (FRAME_X_DISPLAY (f),
7989 event->xclient.window,
7990 initial_argv, initial_argc);
7991 else if (f)
7992 XSetCommand (FRAME_X_DISPLAY (f),
7993 event->xclient.window,
7994 0, 0);
7995 }
7996 goto done;
7997 }
7998
7999 if (event->xclient.data.l[0] == dpyinfo->Xatom_wm_delete_window)
8000 {
8001 f = any;
8002 if (!f)
8003 goto OTHER; /* May be a dialog that is to be removed */
8004
8005 inev.ie.kind = DELETE_WINDOW_EVENT;
8006 XSETFRAME (inev.ie.frame_or_window, f);
8007 goto done;
8008 }
8009
8010 goto done;
8011 }
8012
8013 if (event->xclient.message_type == dpyinfo->Xatom_wm_configure_denied)
8014 goto done;
8015
8016 if (event->xclient.message_type == dpyinfo->Xatom_wm_window_moved)
8017 {
8018 int new_x, new_y;
8019 f = x_window_to_frame (dpyinfo, event->xclient.window);
8020
8021 new_x = event->xclient.data.s[0];
8022 new_y = event->xclient.data.s[1];
8023
8024 if (f)
8025 {
8026 f->left_pos = new_x;
8027 f->top_pos = new_y;
8028 }
8029 goto done;
8030 }
8031
8032 #ifdef X_TOOLKIT_EDITRES
8033 if (event->xclient.message_type == dpyinfo->Xatom_editres)
8034 {
8035 f = any;
8036 if (f)
8037 _XEditResCheckMessages (f->output_data.x->widget,
8038 NULL, (XEvent *) event, NULL);
8039 goto done;
8040 }
8041 #endif /* X_TOOLKIT_EDITRES */
8042
8043 if (event->xclient.message_type == dpyinfo->Xatom_DONE
8044 || event->xclient.message_type == dpyinfo->Xatom_PAGE)
8045 {
8046 /* Ghostview job completed. Kill it. We could
8047 reply with "Next" if we received "Page", but we
8048 currently never do because we are interested in
8049 images, only, which should have 1 page. */
8050 f = x_window_to_frame (dpyinfo, event->xclient.window);
8051 if (!f)
8052 goto OTHER;
8053 #ifndef USE_CAIRO
8054 Pixmap pixmap = (Pixmap) event->xclient.data.l[1];
8055 x_kill_gs_process (pixmap, f);
8056 expose_frame (f, 0, 0, 0, 0);
8057 #endif /* !USE_CAIRO */
8058 goto done;
8059 }
8060
8061 #ifdef USE_TOOLKIT_SCROLL_BARS
8062 /* Scroll bar callbacks send a ClientMessage from which
8063 we construct an input_event. */
8064 if (event->xclient.message_type == dpyinfo->Xatom_Scrollbar)
8065 {
8066 x_scroll_bar_to_input_event (event, &inev.ie);
8067 *finish = X_EVENT_GOTO_OUT;
8068 goto done;
8069 }
8070 else if (event->xclient.message_type == dpyinfo->Xatom_Horizontal_Scrollbar)
8071 {
8072 x_horizontal_scroll_bar_to_input_event (event, &inev.ie);
8073 *finish = X_EVENT_GOTO_OUT;
8074 goto done;
8075 }
8076 #endif /* USE_TOOLKIT_SCROLL_BARS */
8077
8078 /* XEmbed messages from the embedder (if any). */
8079 if (event->xclient.message_type == dpyinfo->Xatom_XEMBED)
8080 {
8081 enum xembed_message msg = event->xclient.data.l[1];
8082 if (msg == XEMBED_FOCUS_IN || msg == XEMBED_FOCUS_OUT)
8083 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8084
8085 *finish = X_EVENT_GOTO_OUT;
8086 goto done;
8087 }
8088
8089 xft_settings_event (dpyinfo, event);
8090
8091 f = any;
8092 if (!f)
8093 goto OTHER;
8094 if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie))
8095 *finish = X_EVENT_DROP;
8096 }
8097 break;
8098
8099 case SelectionNotify:
8100 x_display_set_last_user_time (dpyinfo, event->xselection.time);
8101 #ifdef USE_X_TOOLKIT
8102 if (! x_window_to_frame (dpyinfo, event->xselection.requestor))
8103 goto OTHER;
8104 #endif /* not USE_X_TOOLKIT */
8105 x_handle_selection_notify (&event->xselection);
8106 break;
8107
8108 case SelectionClear: /* Someone has grabbed ownership. */
8109 x_display_set_last_user_time (dpyinfo, event->xselectionclear.time);
8110 #ifdef USE_X_TOOLKIT
8111 if (! x_window_to_frame (dpyinfo, event->xselectionclear.window))
8112 goto OTHER;
8113 #endif /* USE_X_TOOLKIT */
8114 {
8115 const XSelectionClearEvent *eventp = &event->xselectionclear;
8116
8117 inev.sie.kind = SELECTION_CLEAR_EVENT;
8118 SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
8119 SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
8120 SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
8121 }
8122 break;
8123
8124 case SelectionRequest: /* Someone wants our selection. */
8125 x_display_set_last_user_time (dpyinfo, event->xselectionrequest.time);
8126 #ifdef USE_X_TOOLKIT
8127 if (!x_window_to_frame (dpyinfo, event->xselectionrequest.owner))
8128 goto OTHER;
8129 #endif /* USE_X_TOOLKIT */
8130 {
8131 const XSelectionRequestEvent *eventp = &event->xselectionrequest;
8132
8133 inev.sie.kind = SELECTION_REQUEST_EVENT;
8134 SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
8135 SELECTION_EVENT_REQUESTOR (&inev.sie) = eventp->requestor;
8136 SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
8137 SELECTION_EVENT_TARGET (&inev.sie) = eventp->target;
8138 SELECTION_EVENT_PROPERTY (&inev.sie) = eventp->property;
8139 SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
8140 }
8141 break;
8142
8143 case PropertyNotify:
8144 x_display_set_last_user_time (dpyinfo, event->xproperty.time);
8145 f = x_top_window_to_frame (dpyinfo, event->xproperty.window);
8146 if (f && event->xproperty.atom == dpyinfo->Xatom_net_wm_state)
8147 {
8148 bool not_hidden = x_handle_net_wm_state (f, &event->xproperty);
8149 if (not_hidden && FRAME_ICONIFIED_P (f))
8150 {
8151 /* Gnome shell does not iconify us when C-z is pressed.
8152 It hides the frame. So if our state says we aren't
8153 hidden anymore, treat it as deiconified. */
8154 SET_FRAME_VISIBLE (f, 1);
8155 SET_FRAME_ICONIFIED (f, false);
8156 f->output_data.x->has_been_visible = true;
8157 inev.ie.kind = DEICONIFY_EVENT;
8158 XSETFRAME (inev.ie.frame_or_window, f);
8159 }
8160 else if (! not_hidden && ! FRAME_ICONIFIED_P (f))
8161 {
8162 SET_FRAME_VISIBLE (f, 0);
8163 SET_FRAME_ICONIFIED (f, true);
8164 inev.ie.kind = ICONIFY_EVENT;
8165 XSETFRAME (inev.ie.frame_or_window, f);
8166 }
8167 }
8168
8169 x_handle_property_notify (&event->xproperty);
8170 xft_settings_event (dpyinfo, event);
8171 goto OTHER;
8172
8173 case ReparentNotify:
8174 f = x_top_window_to_frame (dpyinfo, event->xreparent.window);
8175 if (f)
8176 {
8177 /* Maybe we shouldn't set this for child frames ?? */
8178 f->output_data.x->parent_desc = event->xreparent.parent;
8179 if (!FRAME_PARENT_FRAME (f))
8180 x_real_positions (f, &f->left_pos, &f->top_pos);
8181 else
8182 {
8183 Window root;
8184 unsigned int dummy_uint;
8185
8186 block_input ();
8187 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
8188 &root, &f->left_pos, &f->top_pos,
8189 &dummy_uint, &dummy_uint, &dummy_uint, &dummy_uint);
8190 unblock_input ();
8191 }
8192
8193 /* Perhaps reparented due to a WM restart. Reset this. */
8194 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
8195 FRAME_DISPLAY_INFO (f)->net_supported_window = 0;
8196
8197 x_set_frame_alpha (f);
8198 }
8199 goto OTHER;
8200
8201 case Expose:
8202 f = x_window_to_frame (dpyinfo, event->xexpose.window);
8203 if (f)
8204 {
8205 if (!FRAME_VISIBLE_P (f))
8206 {
8207 block_input ();
8208 SET_FRAME_VISIBLE (f, 1);
8209 SET_FRAME_ICONIFIED (f, false);
8210 if (FRAME_X_DOUBLE_BUFFERED_P (f))
8211 font_drop_xrender_surfaces (f);
8212 f->output_data.x->has_been_visible = true;
8213 SET_FRAME_GARBAGED (f);
8214 unblock_input ();
8215 }
8216 else if (FRAME_GARBAGED_P (f))
8217 {
8218 #ifdef USE_GTK
8219 /* Go around the back buffer and manually clear the
8220 window the first time we show it. This way, we avoid
8221 showing users the sanity-defying horror of whatever
8222 GtkWindow is rendering beneath us. We've garbaged
8223 the frame, so we'll redraw the whole thing on next
8224 redisplay anyway. Yuck. */
8225 x_clear_area1 (
8226 FRAME_X_DISPLAY (f),
8227 FRAME_X_WINDOW (f),
8228 event->xexpose.x, event->xexpose.y,
8229 event->xexpose.width, event->xexpose.height,
8230 0);
8231 x_clear_under_internal_border (f);
8232 #endif
8233 }
8234
8235
8236 if (!FRAME_GARBAGED_P (f))
8237 {
8238 #ifdef USE_GTK
8239 /* This seems to be needed for GTK 2.6 and later, see
8240 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398. */
8241 x_clear_area (f,
8242 event->xexpose.x, event->xexpose.y,
8243 event->xexpose.width, event->xexpose.height);
8244 #endif
8245 expose_frame (f, event->xexpose.x, event->xexpose.y,
8246 event->xexpose.width, event->xexpose.height);
8247 #ifdef USE_GTK
8248 x_clear_under_internal_border (f);
8249 #endif
8250 }
8251
8252 if (!FRAME_GARBAGED_P (f))
8253 show_back_buffer (f);
8254 }
8255 else
8256 {
8257 #ifndef USE_TOOLKIT_SCROLL_BARS
8258 struct scroll_bar *bar;
8259 #endif
8260 #if defined USE_LUCID
8261 /* Submenus of the Lucid menu bar aren't widgets
8262 themselves, so there's no way to dispatch events
8263 to them. Recognize this case separately. */
8264 {
8265 Widget widget = x_window_to_menu_bar (event->xexpose.window);
8266 if (widget)
8267 xlwmenu_redisplay (widget);
8268 }
8269 #endif /* USE_LUCID */
8270
8271 #ifdef USE_TOOLKIT_SCROLL_BARS
8272 /* Dispatch event to the widget. */
8273 goto OTHER;
8274 #else /* not USE_TOOLKIT_SCROLL_BARS */
8275 bar = x_window_to_scroll_bar (event->xexpose.display,
8276 event->xexpose.window, 2);
8277
8278 if (bar)
8279 x_scroll_bar_expose (bar, event);
8280 #ifdef USE_X_TOOLKIT
8281 else
8282 goto OTHER;
8283 #endif /* USE_X_TOOLKIT */
8284 #endif /* not USE_TOOLKIT_SCROLL_BARS */
8285 }
8286 break;
8287
8288 case GraphicsExpose: /* This occurs when an XCopyArea's
8289 source area was obscured or not
8290 available. */
8291 f = x_window_to_frame (dpyinfo, event->xgraphicsexpose.drawable);
8292 if (f)
8293 {
8294 expose_frame (f, event->xgraphicsexpose.x,
8295 event->xgraphicsexpose.y,
8296 event->xgraphicsexpose.width,
8297 event->xgraphicsexpose.height);
8298 #ifdef USE_GTK
8299 x_clear_under_internal_border (f);
8300 #endif
8301 show_back_buffer (f);
8302 }
8303 #ifdef USE_X_TOOLKIT
8304 else
8305 goto OTHER;
8306 #endif /* USE_X_TOOLKIT */
8307 break;
8308
8309 case NoExpose: /* This occurs when an XCopyArea's
8310 source area was completely
8311 available. */
8312 break;
8313
8314 case UnmapNotify:
8315 /* Redo the mouse-highlight after the tooltip has gone. */
8316 if (event->xunmap.window == tip_window)
8317 {
8318 tip_window = None;
8319 gui_redo_mouse_highlight (dpyinfo);
8320 }
8321
8322 f = x_top_window_to_frame (dpyinfo, event->xunmap.window);
8323 if (f) /* F may no longer exist if
8324 the frame was deleted. */
8325 {
8326 bool visible = FRAME_VISIBLE_P (f);
8327 /* While a frame is unmapped, display generation is
8328 disabled; you don't want to spend time updating a
8329 display that won't ever be seen. */
8330 SET_FRAME_VISIBLE (f, 0);
8331 /* We can't distinguish, from the event, whether the window
8332 has become iconified or invisible. So assume, if it
8333 was previously visible, than now it is iconified.
8334 But x_make_frame_invisible clears both
8335 the visible flag and the iconified flag;
8336 and that way, we know the window is not iconified now. */
8337 if (visible || FRAME_ICONIFIED_P (f))
8338 {
8339 SET_FRAME_ICONIFIED (f, true);
8340 inev.ie.kind = ICONIFY_EVENT;
8341 XSETFRAME (inev.ie.frame_or_window, f);
8342 }
8343 }
8344 goto OTHER;
8345
8346 case MapNotify:
8347 /* We use x_top_window_to_frame because map events can
8348 come for sub-windows and they don't mean that the
8349 frame is visible. */
8350 f = x_top_window_to_frame (dpyinfo, event->xmap.window);
8351 if (f)
8352 {
8353 bool iconified = FRAME_ICONIFIED_P (f);
8354
8355 /* Check if fullscreen was specified before we where mapped the
8356 first time, i.e. from the command line. */
8357 if (!f->output_data.x->has_been_visible)
8358 {
8359
8360 x_check_fullscreen (f);
8361 #ifndef USE_GTK
8362 /* For systems that cannot synthesize `skip_taskbar' for
8363 unmapped windows do the following. */
8364 if (FRAME_SKIP_TASKBAR (f))
8365 x_set_skip_taskbar (f, Qt, Qnil);
8366 #endif /* Not USE_GTK */
8367 }
8368
8369 if (!iconified)
8370 {
8371 /* The `z-group' is reset every time a frame becomes
8372 invisible. Handle this here. */
8373 if (FRAME_Z_GROUP (f) == z_group_above)
8374 x_set_z_group (f, Qabove, Qnil);
8375 else if (FRAME_Z_GROUP (f) == z_group_below)
8376 x_set_z_group (f, Qbelow, Qnil);
8377 }
8378
8379 SET_FRAME_VISIBLE (f, 1);
8380 SET_FRAME_ICONIFIED (f, false);
8381 f->output_data.x->has_been_visible = true;
8382
8383 if (iconified)
8384 {
8385 inev.ie.kind = DEICONIFY_EVENT;
8386 XSETFRAME (inev.ie.frame_or_window, f);
8387 }
8388 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
8389 /* Force a redisplay sooner or later to update the
8390 frame titles in case this is the second frame. */
8391 record_asynch_buffer_change ();
8392 }
8393 goto OTHER;
8394
8395 case KeyPress:
8396
8397 x_display_set_last_user_time (dpyinfo, event->xkey.time);
8398 ignore_next_mouse_click_timeout = 0;
8399
8400 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
8401 /* Dispatch KeyPress events when in menu. */
8402 if (popup_activated ())
8403 goto OTHER;
8404 #endif
8405
8406 f = any;
8407
8408 /* If mouse-highlight is an integer, input clears out
8409 mouse highlighting. */
8410 if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight)
8411 && (f == 0
8412 #if ! defined (USE_GTK)
8413 || !EQ (f->tool_bar_window, hlinfo->mouse_face_window)
8414 #endif
8415 || !EQ (f->tab_bar_window, hlinfo->mouse_face_window))
8416 )
8417 {
8418 clear_mouse_face (hlinfo);
8419 hlinfo->mouse_face_hidden = true;
8420 }
8421
8422 #if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
8423 if (f == 0)
8424 {
8425 /* Scroll bars consume key events, but we want
8426 the keys to go to the scroll bar's frame. */
8427 Widget widget = XtWindowToWidget (dpyinfo->display,
8428 event->xkey.window);
8429 if (widget && XmIsScrollBar (widget))
8430 {
8431 widget = XtParent (widget);
8432 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
8433 }
8434 }
8435 #endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
8436
8437 if (f != 0)
8438 {
8439 KeySym keysym, orig_keysym;
8440 /* al%imercury@uunet.uu.net says that making this 81
8441 instead of 80 fixed a bug whereby meta chars made
8442 his Emacs hang.
8443
8444 It seems that some version of XmbLookupString has
8445 a bug of not returning XBufferOverflow in
8446 status_return even if the input is too long to
8447 fit in 81 bytes. So, we must prepare sufficient
8448 bytes for copy_buffer. 513 bytes (256 chars for
8449 two-byte character set) seems to be a fairly good
8450 approximation. -- 2000.8.10 handa@gnu.org */
8451 unsigned char copy_buffer[513];
8452 unsigned char *copy_bufptr = copy_buffer;
8453 int copy_bufsiz = sizeof (copy_buffer);
8454 int modifiers;
8455 Lisp_Object coding_system = Qlatin_1;
8456 Lisp_Object c;
8457 /* Event will be modified. */
8458 XKeyEvent xkey = event->xkey;
8459
8460 #ifdef USE_GTK
8461 /* Don't pass keys to GTK. A Tab will shift focus to the
8462 tool bar in GTK 2.4. Keys will still go to menus and
8463 dialogs because in that case popup_activated is nonzero
8464 (see above). */
8465 *finish = X_EVENT_DROP;
8466 #endif
8467
8468 xkey.state |= x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f),
8469 extra_keyboard_modifiers);
8470 modifiers = xkey.state;
8471
8472 /* This will have to go some day... */
8473
8474 /* make_lispy_event turns chars into control chars.
8475 Don't do it here because XLookupString is too eager. */
8476 xkey.state &= ~ControlMask;
8477 xkey.state &= ~(dpyinfo->meta_mod_mask
8478 | dpyinfo->super_mod_mask
8479 | dpyinfo->hyper_mod_mask
8480 | dpyinfo->alt_mod_mask);
8481
8482 /* In case Meta is ComposeCharacter,
8483 clear its status. According to Markus Ehrnsperger
8484 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
8485 this enables ComposeCharacter to work whether or
8486 not it is combined with Meta. */
8487 if (modifiers & dpyinfo->meta_mod_mask)
8488 memset (&compose_status, 0, sizeof (compose_status));
8489
8490 #ifdef HAVE_X_I18N
8491 if (FRAME_XIC (f))
8492 {
8493 Status status_return;
8494
8495 coding_system = Vlocale_coding_system;
8496 nbytes = XmbLookupString (FRAME_XIC (f),
8497 &xkey, (char *) copy_bufptr,
8498 copy_bufsiz, &keysym,
8499 &status_return);
8500 if (status_return == XBufferOverflow)
8501 {
8502 copy_bufsiz = nbytes + 1;
8503 copy_bufptr = alloca (copy_bufsiz);
8504 nbytes = XmbLookupString (FRAME_XIC (f),
8505 &xkey, (char *) copy_bufptr,
8506 copy_bufsiz, &keysym,
8507 &status_return);
8508 }
8509 /* Xutf8LookupString is a new but already deprecated interface. -stef */
8510 if (status_return == XLookupNone)
8511 break;
8512 else if (status_return == XLookupChars)
8513 {
8514 keysym = NoSymbol;
8515 modifiers = 0;
8516 }
8517 else if (status_return != XLookupKeySym
8518 && status_return != XLookupBoth)
8519 emacs_abort ();
8520 }
8521 else
8522 nbytes = XLookupString (&xkey, (char *) copy_bufptr,
8523 copy_bufsiz, &keysym,
8524 &compose_status);
8525 #else
8526 nbytes = XLookupString (&xkey, (char *) copy_bufptr,
8527 copy_bufsiz, &keysym,
8528 &compose_status);
8529 #endif
8530
8531 /* If not using XIM/XIC, and a compose sequence is in progress,
8532 we break here. Otherwise, chars_matched is always 0. */
8533 if (compose_status.chars_matched > 0 && nbytes == 0)
8534 break;
8535
8536 memset (&compose_status, 0, sizeof (compose_status));
8537 orig_keysym = keysym;
8538
8539 /* Common for all keysym input events. */
8540 XSETFRAME (inev.ie.frame_or_window, f);
8541 inev.ie.modifiers
8542 = x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), modifiers);
8543 inev.ie.timestamp = xkey.time;
8544
8545 /* First deal with keysyms which have defined
8546 translations to characters. */
8547 if (keysym >= 32 && keysym < 128)
8548 /* Avoid explicitly decoding each ASCII character. */
8549 {
8550 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
8551 inev.ie.code = keysym;
8552 goto done_keysym;
8553 }
8554
8555 /* Keysyms directly mapped to Unicode characters. */
8556 if (keysym >= 0x01000000 && keysym <= 0x0110FFFF)
8557 {
8558 if (keysym < 0x01000080)
8559 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
8560 else
8561 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
8562 inev.ie.code = keysym & 0xFFFFFF;
8563 goto done_keysym;
8564 }
8565
8566 /* Now non-ASCII. */
8567 if (HASH_TABLE_P (Vx_keysym_table)
8568 && (c = Fgethash (make_fixnum (keysym),
8569 Vx_keysym_table,
8570 Qnil),
8571 FIXNATP (c)))
8572 {
8573 inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c))
8574 ? ASCII_KEYSTROKE_EVENT
8575 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
8576 inev.ie.code = XFIXNAT (c);
8577 goto done_keysym;
8578 }
8579
8580 /* Random non-modifier sorts of keysyms. */
8581 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
8582 || keysym == XK_Delete
8583 #ifdef XK_ISO_Left_Tab
8584 || (keysym >= XK_ISO_Left_Tab
8585 && keysym <= XK_ISO_Enter)
8586 #endif
8587 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
8588 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
8589 #ifdef HPUX
8590 /* This recognizes the "extended function
8591 keys". It seems there's no cleaner way.
8592 Test IsModifierKey to avoid handling
8593 mode_switch incorrectly. */
8594 || (XK_Select <= keysym && keysym < XK_KP_Space)
8595 #endif
8596 #ifdef XK_dead_circumflex
8597 || orig_keysym == XK_dead_circumflex
8598 #endif
8599 #ifdef XK_dead_grave
8600 || orig_keysym == XK_dead_grave
8601 #endif
8602 #ifdef XK_dead_tilde
8603 || orig_keysym == XK_dead_tilde
8604 #endif
8605 #ifdef XK_dead_diaeresis
8606 || orig_keysym == XK_dead_diaeresis
8607 #endif
8608 #ifdef XK_dead_macron
8609 || orig_keysym == XK_dead_macron
8610 #endif
8611 #ifdef XK_dead_degree
8612 || orig_keysym == XK_dead_degree
8613 #endif
8614 #ifdef XK_dead_acute
8615 || orig_keysym == XK_dead_acute
8616 #endif
8617 #ifdef XK_dead_cedilla
8618 || orig_keysym == XK_dead_cedilla
8619 #endif
8620 #ifdef XK_dead_breve
8621 || orig_keysym == XK_dead_breve
8622 #endif
8623 #ifdef XK_dead_ogonek
8624 || orig_keysym == XK_dead_ogonek
8625 #endif
8626 #ifdef XK_dead_caron
8627 || orig_keysym == XK_dead_caron
8628 #endif
8629 #ifdef XK_dead_doubleacute
8630 || orig_keysym == XK_dead_doubleacute
8631 #endif
8632 #ifdef XK_dead_abovedot
8633 || orig_keysym == XK_dead_abovedot
8634 #endif
8635 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
8636 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
8637 /* Any "vendor-specific" key is ok. */
8638 || (orig_keysym & (1 << 28))
8639 || (keysym != NoSymbol && nbytes == 0))
8640 && ! (IsModifierKey (orig_keysym)
8641 /* The symbols from XK_ISO_Lock
8642 to XK_ISO_Last_Group_Lock
8643 don't have real modifiers but
8644 should be treated similarly to
8645 Mode_switch by Emacs. */
8646 #if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock
8647 || (XK_ISO_Lock <= orig_keysym
8648 && orig_keysym <= XK_ISO_Last_Group_Lock)
8649 #endif
8650 ))
8651 {
8652 STORE_KEYSYM_FOR_DEBUG (keysym);
8653 /* make_lispy_event will convert this to a symbolic
8654 key. */
8655 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
8656 inev.ie.code = keysym;
8657 goto done_keysym;
8658 }
8659
8660 { /* Raw bytes, not keysym. */
8661 ptrdiff_t i;
8662 int nchars, len;
8663
8664 for (i = 0, nchars = 0; i < nbytes; i++)
8665 {
8666 if (ASCII_CHAR_P (copy_bufptr[i]))
8667 nchars++;
8668 STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
8669 }
8670
8671 if (nchars < nbytes)
8672 {
8673 /* Decode the input data. */
8674
8675 /* The input should be decoded with `coding_system'
8676 which depends on which X*LookupString function
8677 we used just above and the locale. */
8678 setup_coding_system (coding_system, &coding);
8679 coding.src_multibyte = false;
8680 coding.dst_multibyte = true;
8681 /* The input is converted to events, thus we can't
8682 handle composition. Anyway, there's no XIM that
8683 gives us composition information. */
8684 coding.common_flags &= ~CODING_ANNOTATION_MASK;
8685
8686 SAFE_NALLOCA (coding.destination, MAX_MULTIBYTE_LENGTH,
8687 nbytes);
8688 coding.dst_bytes = MAX_MULTIBYTE_LENGTH * nbytes;
8689 coding.mode |= CODING_MODE_LAST_BLOCK;
8690 decode_coding_c_string (&coding, copy_bufptr, nbytes, Qnil);
8691 nbytes = coding.produced;
8692 nchars = coding.produced_char;
8693 copy_bufptr = coding.destination;
8694 }
8695
8696 /* Convert the input data to a sequence of
8697 character events. */
8698 for (i = 0; i < nbytes; i += len)
8699 {
8700 int ch;
8701 if (nchars == nbytes)
8702 ch = copy_bufptr[i], len = 1;
8703 else
8704 ch = STRING_CHAR_AND_LENGTH (copy_bufptr + i, len);
8705 inev.ie.kind = (SINGLE_BYTE_CHAR_P (ch)
8706 ? ASCII_KEYSTROKE_EVENT
8707 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
8708 inev.ie.code = ch;
8709 kbd_buffer_store_buffered_event (&inev, hold_quit);
8710 }
8711
8712 count += nchars;
8713
8714 inev.ie.kind = NO_EVENT; /* Already stored above. */
8715
8716 if (keysym == NoSymbol)
8717 break;
8718 }
8719 /* FIXME: check side effects and remove this. */
8720 ((XEvent *) event)->xkey = xkey;
8721 }
8722 done_keysym:
8723 #ifdef HAVE_X_I18N
8724 /* Don't dispatch this event since XtDispatchEvent calls
8725 XFilterEvent, and two calls in a row may freeze the
8726 client. */
8727 break;
8728 #else
8729 goto OTHER;
8730 #endif
8731
8732 case KeyRelease:
8733 x_display_set_last_user_time (dpyinfo, event->xkey.time);
8734 #ifdef HAVE_X_I18N
8735 /* Don't dispatch this event since XtDispatchEvent calls
8736 XFilterEvent, and two calls in a row may freeze the
8737 client. */
8738 break;
8739 #else
8740 goto OTHER;
8741 #endif
8742
8743 case EnterNotify:
8744 x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
8745 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8746
8747 f = any;
8748
8749 if (f && x_mouse_click_focus_ignore_position)
8750 ignore_next_mouse_click_timeout = event->xmotion.time + 200;
8751
8752 /* EnterNotify counts as mouse movement,
8753 so update things that depend on mouse position. */
8754 if (f && !f->output_data.x->hourglass_p)
8755 x_note_mouse_movement (f, &event->xmotion);
8756 #ifdef USE_GTK
8757 /* We may get an EnterNotify on the buttons in the toolbar. In that
8758 case we moved out of any highlighted area and need to note this. */
8759 if (!f && dpyinfo->last_mouse_glyph_frame)
8760 x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &event->xmotion);
8761 #endif
8762 goto OTHER;
8763
8764 case FocusIn:
8765 /* Some WMs (e.g. Mutter in Gnome Shell), don't unmap
8766 minimized/iconified windows; thus, for those WMs we won't get
8767 a MapNotify when unminimizing/deconifying. Check here if we
8768 are deconizing a window (Bug42655). */
8769 f = any;
8770 if (f && FRAME_ICONIFIED_P (f))
8771 {
8772 SET_FRAME_VISIBLE (f, 1);
8773 SET_FRAME_ICONIFIED (f, false);
8774 f->output_data.x->has_been_visible = true;
8775 inev.ie.kind = DEICONIFY_EVENT;
8776 XSETFRAME (inev.ie.frame_or_window, f);
8777 }
8778
8779 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8780 goto OTHER;
8781
8782 case LeaveNotify:
8783 x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
8784 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8785
8786 f = x_top_window_to_frame (dpyinfo, event->xcrossing.window);
8787 if (f)
8788 {
8789 if (f == hlinfo->mouse_face_mouse_frame)
8790 {
8791 /* If we move outside the frame, then we're
8792 certainly no longer on any text in the frame. */
8793 clear_mouse_face (hlinfo);
8794 hlinfo->mouse_face_mouse_frame = 0;
8795 }
8796
8797 /* Generate a nil HELP_EVENT to cancel a help-echo.
8798 Do it only if there's something to cancel.
8799 Otherwise, the startup message is cleared when
8800 the mouse leaves the frame. */
8801 if (any_help_event_p)
8802 do_help = -1;
8803 }
8804 #ifdef USE_GTK
8805 /* See comment in EnterNotify above */
8806 else if (dpyinfo->last_mouse_glyph_frame)
8807 x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &event->xmotion);
8808 #endif
8809 goto OTHER;
8810
8811 case FocusOut:
8812 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8813 goto OTHER;
8814
8815 case MotionNotify:
8816 {
8817 x_display_set_last_user_time (dpyinfo, event->xmotion.time);
8818 previous_help_echo_string = help_echo_string;
8819 help_echo_string = Qnil;
8820
8821 if (hlinfo->mouse_face_hidden)
8822 {
8823 hlinfo->mouse_face_hidden = false;
8824 clear_mouse_face (hlinfo);
8825 }
8826
8827 f = mouse_or_wdesc_frame (dpyinfo, event->xmotion.window);
8828
8829 #ifdef USE_GTK
8830 if (f && xg_event_is_for_scrollbar (f, event))
8831 f = 0;
8832 #endif
8833 if (f)
8834 {
8835 /* Maybe generate a SELECT_WINDOW_EVENT for
8836 `mouse-autoselect-window' but don't let popup menus
8837 interfere with this (Bug#1261). */
8838 if (!NILP (Vmouse_autoselect_window)
8839 && !popup_activated ()
8840 /* Don't switch if we're currently in the minibuffer.
8841 This tries to work around problems where the
8842 minibuffer gets unselected unexpectedly, and where
8843 you then have to move your mouse all the way down to
8844 the minibuffer to select it. */
8845 && !MINI_WINDOW_P (XWINDOW (selected_window))
8846 /* With `focus-follows-mouse' non-nil create an event
8847 also when the target window is on another frame. */
8848 && (f == XFRAME (selected_frame)
8849 || !NILP (focus_follows_mouse)))
8850 {
8851 static Lisp_Object last_mouse_window;
8852 Lisp_Object window = window_from_coordinates
8853 (f, event->xmotion.x, event->xmotion.y, 0, false, false);
8854
8855 /* A window will be autoselected only when it is not
8856 selected now and the last mouse movement event was
8857 not in it. The remainder of the code is a bit vague
8858 wrt what a "window" is. For immediate autoselection,
8859 the window is usually the entire window but for GTK
8860 where the scroll bars don't count. For delayed
8861 autoselection the window is usually the window's text
8862 area including the margins. */
8863 if (WINDOWP (window)
8864 && !EQ (window, last_mouse_window)
8865 && !EQ (window, selected_window))
8866 {
8867 inev.ie.kind = SELECT_WINDOW_EVENT;
8868 inev.ie.frame_or_window = window;
8869 }
8870
8871 /* Remember the last window where we saw the mouse. */
8872 last_mouse_window = window;
8873 }
8874
8875 if (!x_note_mouse_movement (f, &event->xmotion))
8876 help_echo_string = previous_help_echo_string;
8877 }
8878 else
8879 {
8880 #ifndef USE_TOOLKIT_SCROLL_BARS
8881 struct scroll_bar *bar
8882 = x_window_to_scroll_bar (event->xmotion.display,
8883 event->xmotion.window, 2);
8884
8885 if (bar)
8886 x_scroll_bar_note_movement (bar, &event->xmotion);
8887 #endif /* USE_TOOLKIT_SCROLL_BARS */
8888
8889 /* If we move outside the frame, then we're
8890 certainly no longer on any text in the frame. */
8891 clear_mouse_face (hlinfo);
8892 }
8893
8894 /* If the contents of the global variable help_echo_string
8895 has changed, generate a HELP_EVENT. */
8896 if (!NILP (help_echo_string)
8897 || !NILP (previous_help_echo_string))
8898 do_help = 1;
8899 goto OTHER;
8900 }
8901
8902 case ConfigureNotify:
8903 /* An opaque move can generate a stream of events as the window
8904 is dragged around. If the connection round trip time isn't
8905 really short, they may come faster than we can respond to
8906 them, given the multiple queries we can do to check window
8907 manager state, translate coordinates, etc.
8908
8909 So if this ConfigureNotify is immediately followed by another
8910 for the same window, use the info from the latest update, and
8911 consider the events all handled. */
8912 /* Opaque resize may be trickier; ConfigureNotify events are
8913 mixed with Expose events for multiple windows. */
8914 configureEvent = *event;
8915 while (XPending (dpyinfo->display))
8916 {
8917 XNextEvent (dpyinfo->display, &next_event);
8918 if (next_event.type != ConfigureNotify
8919 || next_event.xconfigure.window != event->xconfigure.window
8920 /* Skipping events with different sizes can lead to a
8921 mispositioned mode line at initial window creation.
8922 Only drop window motion events for now. */
8923 || next_event.xconfigure.width != event->xconfigure.width
8924 || next_event.xconfigure.height != event->xconfigure.height)
8925 {
8926 XPutBackEvent (dpyinfo->display, &next_event);
8927 break;
8928 }
8929 else
8930 configureEvent = next_event;
8931 }
8932
8933 f = x_top_window_to_frame (dpyinfo, configureEvent.xconfigure.window);
8934 /* Unfortunately, we need to call font_drop_xrender_surfaces for
8935 _all_ ConfigureNotify events, otherwise we miss some and
8936 flicker. Don't try to optimize these calls by looking only
8937 for size changes: that's not sufficient. We miss some
8938 surface invalidations and flicker. */
8939 block_input ();
8940 if (f && FRAME_X_DOUBLE_BUFFERED_P (f))
8941 font_drop_xrender_surfaces (f);
8942 unblock_input ();
8943 #if defined USE_CAIRO && !defined USE_GTK
8944 if (f)
8945 x_cr_update_surface_desired_size (f, configureEvent.xconfigure.width,
8946 configureEvent.xconfigure.height);
8947 else if (any && configureEvent.xconfigure.window == FRAME_X_WINDOW (any))
8948 x_cr_update_surface_desired_size (any,
8949 configureEvent.xconfigure.width,
8950 configureEvent.xconfigure.height);
8951 #endif
8952 #ifdef USE_GTK
8953 if (!f
8954 && (f = any)
8955 && configureEvent.xconfigure.window == FRAME_X_WINDOW (f))
8956 {
8957 block_input ();
8958 if (FRAME_X_DOUBLE_BUFFERED_P (f))
8959 font_drop_xrender_surfaces (f);
8960 unblock_input ();
8961 xg_frame_resized (f, configureEvent.xconfigure.width,
8962 configureEvent.xconfigure.height);
8963 #ifdef USE_CAIRO
8964 x_cr_update_surface_desired_size (f, configureEvent.xconfigure.width,
8965 configureEvent.xconfigure.height);
8966 #endif
8967 f = 0;
8968 }
8969 #endif
8970 if (f)
8971 {
8972 #ifdef USE_GTK
8973 /* For GTK+ don't call x_net_wm_state for the scroll bar
8974 window. (Bug#24963, Bug#25887) */
8975 if (configureEvent.xconfigure.window == FRAME_X_WINDOW (f))
8976 #endif
8977 x_net_wm_state (f, configureEvent.xconfigure.window);
8978
8979 #ifdef USE_X_TOOLKIT
8980 /* Tip frames are pure X window, set size for them. */
8981 if (FRAME_TOOLTIP_P (f))
8982 {
8983 if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height
8984 || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width)
8985 {
8986 SET_FRAME_GARBAGED (f);
8987 }
8988 FRAME_PIXEL_HEIGHT (f) = configureEvent.xconfigure.height;
8989 FRAME_PIXEL_WIDTH (f) = configureEvent.xconfigure.width;
8990 }
8991 #endif
8992
8993 #ifndef USE_X_TOOLKIT
8994 #ifndef USE_GTK
8995 int width =
8996 FRAME_PIXEL_TO_TEXT_WIDTH (f, configureEvent.xconfigure.width);
8997 int height =
8998 FRAME_PIXEL_TO_TEXT_HEIGHT (f, configureEvent.xconfigure.height);
8999
9000 /* In the toolkit version, change_frame_size
9001 is called by the code that handles resizing
9002 of the EmacsFrame widget. */
9003
9004 /* Even if the number of character rows and columns has
9005 not changed, the font size may have changed, so we need
9006 to check the pixel dimensions as well. */
9007 if (width != FRAME_TEXT_WIDTH (f)
9008 || height != FRAME_TEXT_HEIGHT (f)
9009 || configureEvent.xconfigure.width != FRAME_PIXEL_WIDTH (f)
9010 || configureEvent.xconfigure.height != FRAME_PIXEL_HEIGHT (f))
9011 {
9012 change_frame_size (f, width, height, false, true, false, true);
9013 x_clear_under_internal_border (f);
9014 SET_FRAME_GARBAGED (f);
9015 cancel_mouse_face (f);
9016 }
9017 #endif /* not USE_GTK */
9018 #endif
9019
9020 #ifdef USE_GTK
9021 /* GTK creates windows but doesn't map them.
9022 Only get real positions when mapped. */
9023 if (FRAME_GTK_OUTER_WIDGET (f)
9024 && gtk_widget_get_mapped (FRAME_GTK_OUTER_WIDGET (f)))
9025 #endif
9026 {
9027 int old_left = f->left_pos;
9028 int old_top = f->top_pos;
9029 Lisp_Object frame = Qnil;
9030
9031 XSETFRAME (frame, f);
9032
9033 if (!FRAME_PARENT_FRAME (f))
9034 x_real_positions (f, &f->left_pos, &f->top_pos);
9035 else
9036 {
9037 Window root;
9038 unsigned int dummy_uint;
9039
9040 block_input ();
9041 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
9042 &root, &f->left_pos, &f->top_pos,
9043 &dummy_uint, &dummy_uint, &dummy_uint, &dummy_uint);
9044 unblock_input ();
9045 }
9046
9047 if (!FRAME_TOOLTIP_P (f)
9048 && (old_left != f->left_pos || old_top != f->top_pos))
9049 {
9050 inev.ie.kind = MOVE_FRAME_EVENT;
9051 XSETFRAME (inev.ie.frame_or_window, f);
9052 }
9053 }
9054
9055
9056 #ifdef HAVE_X_I18N
9057 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
9058 xic_set_statusarea (f);
9059 #endif
9060
9061 }
9062 goto OTHER;
9063
9064 case ButtonRelease:
9065 case ButtonPress:
9066 {
9067 /* If we decide we want to generate an event to be seen
9068 by the rest of Emacs, we put it here. */
9069 bool tab_bar_p = false;
9070 bool tool_bar_p = false;
9071
9072 memset (&compose_status, 0, sizeof (compose_status));
9073 dpyinfo->last_mouse_glyph_frame = NULL;
9074 x_display_set_last_user_time (dpyinfo, event->xbutton.time);
9075
9076 f = mouse_or_wdesc_frame (dpyinfo, event->xmotion.window);
9077 if (f && event->xbutton.type == ButtonPress
9078 && !popup_activated ()
9079 && !x_window_to_scroll_bar (event->xbutton.display,
9080 event->xbutton.window, 2)
9081 && !FRAME_NO_ACCEPT_FOCUS (f))
9082 {
9083 /* When clicking into a child frame or when clicking
9084 into a parent frame with the child frame selected and
9085 `no-accept-focus' is not set, select the clicked
9086 frame. */
9087 struct frame *hf = dpyinfo->highlight_frame;
9088
9089 if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
9090 {
9091 block_input ();
9092 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
9093 RevertToParent, CurrentTime);
9094 if (FRAME_PARENT_FRAME (f))
9095 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
9096 unblock_input ();
9097 }
9098 }
9099
9100 #ifdef USE_GTK
9101 if (f && xg_event_is_for_scrollbar (f, event))
9102 f = 0;
9103 #endif
9104 if (f)
9105 {
9106 /* Is this in the tab-bar? */
9107 if (WINDOWP (f->tab_bar_window)
9108 && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
9109 {
9110 Lisp_Object window;
9111 int x = event->xbutton.x;
9112 int y = event->xbutton.y;
9113
9114 window = window_from_coordinates (f, x, y, 0, true, true);
9115 tab_bar_p = EQ (window, f->tab_bar_window);
9116
9117 if (tab_bar_p && event->xbutton.button < 4)
9118 handle_tab_bar_click
9119 (f, x, y, event->xbutton.type == ButtonPress,
9120 x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state));
9121 }
9122
9123 #if ! defined (USE_GTK)
9124 /* Is this in the tool-bar? */
9125 if (WINDOWP (f->tool_bar_window)
9126 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
9127 {
9128 Lisp_Object window;
9129 int x = event->xbutton.x;
9130 int y = event->xbutton.y;
9131
9132 window = window_from_coordinates (f, x, y, 0, true, true);
9133 tool_bar_p = EQ (window, f->tool_bar_window);
9134
9135 if (tool_bar_p && event->xbutton.button < 4)
9136 handle_tool_bar_click
9137 (f, x, y, event->xbutton.type == ButtonPress,
9138 x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state));
9139 }
9140 #endif /* !USE_GTK */
9141
9142 if (!tab_bar_p && !tool_bar_p)
9143 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
9144 if (! popup_activated ())
9145 #endif
9146 {
9147 if (ignore_next_mouse_click_timeout)
9148 {
9149 if (event->type == ButtonPress
9150 && event->xbutton.time > ignore_next_mouse_click_timeout)
9151 {
9152 ignore_next_mouse_click_timeout = 0;
9153 x_construct_mouse_click (&inev.ie, &event->xbutton, f);
9154 }
9155 if (event->type == ButtonRelease)
9156 ignore_next_mouse_click_timeout = 0;
9157 }
9158 else
9159 x_construct_mouse_click (&inev.ie, &event->xbutton, f);
9160 }
9161 if (FRAME_X_EMBEDDED_P (f))
9162 xembed_send_message (f, event->xbutton.time,
9163 XEMBED_REQUEST_FOCUS, 0, 0, 0);
9164 }
9165 else
9166 {
9167 struct scroll_bar *bar
9168 = x_window_to_scroll_bar (event->xbutton.display,
9169 event->xbutton.window, 2);
9170
9171 #ifdef USE_TOOLKIT_SCROLL_BARS
9172 /* Make the "Ctrl-Mouse-2 splits window" work for toolkit
9173 scroll bars. */
9174 if (bar && event->xbutton.state & ControlMask)
9175 {
9176 x_scroll_bar_handle_click (bar, event, &inev.ie);
9177 *finish = X_EVENT_DROP;
9178 }
9179 #else /* not USE_TOOLKIT_SCROLL_BARS */
9180 if (bar)
9181 x_scroll_bar_handle_click (bar, event, &inev.ie);
9182 #endif /* not USE_TOOLKIT_SCROLL_BARS */
9183 }
9184
9185 if (event->type == ButtonPress)
9186 {
9187 dpyinfo->grabbed |= (1 << event->xbutton.button);
9188 dpyinfo->last_mouse_frame = f;
9189 if (f && !tab_bar_p)
9190 f->last_tab_bar_item = -1;
9191 #if ! defined (USE_GTK)
9192 if (f && !tool_bar_p)
9193 f->last_tool_bar_item = -1;
9194 #endif /* not USE_GTK */
9195 }
9196 else
9197 dpyinfo->grabbed &= ~(1 << event->xbutton.button);
9198
9199 /* Ignore any mouse motion that happened before this event;
9200 any subsequent mouse-movement Emacs events should reflect
9201 only motion after the ButtonPress/Release. */
9202 if (f != 0)
9203 f->mouse_moved = false;
9204
9205 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
9206 f = x_menubar_window_to_frame (dpyinfo, event);
9207 /* For a down-event in the menu bar,
9208 don't pass it to Xt right now.
9209 Instead, save it away
9210 and we will pass it to Xt from kbd_buffer_get_event.
9211 That way, we can run some Lisp code first. */
9212 if (! popup_activated ()
9213 #ifdef USE_GTK
9214 /* Gtk+ menus only react to the first three buttons. */
9215 && event->xbutton.button < 3
9216 #endif
9217 && f && event->type == ButtonPress
9218 /* Verify the event is really within the menu bar
9219 and not just sent to it due to grabbing. */
9220 && event->xbutton.x >= 0
9221 && event->xbutton.x < FRAME_PIXEL_WIDTH (f)
9222 && event->xbutton.y >= 0
9223 && event->xbutton.y < FRAME_MENUBAR_HEIGHT (f)
9224 && event->xbutton.same_screen)
9225 {
9226 if (!f->output_data.x->saved_menu_event)
9227 f->output_data.x->saved_menu_event = xmalloc (sizeof *event);
9228 *f->output_data.x->saved_menu_event = *event;
9229 inev.ie.kind = MENU_BAR_ACTIVATE_EVENT;
9230 XSETFRAME (inev.ie.frame_or_window, f);
9231 *finish = X_EVENT_DROP;
9232 }
9233 else
9234 goto OTHER;
9235 #endif /* USE_X_TOOLKIT || USE_GTK */
9236 }
9237 break;
9238
9239 case CirculateNotify:
9240 goto OTHER;
9241
9242 case CirculateRequest:
9243 goto OTHER;
9244
9245 case VisibilityNotify:
9246 goto OTHER;
9247
9248 case MappingNotify:
9249 /* Someone has changed the keyboard mapping - update the
9250 local cache. */
9251 switch (event->xmapping.request)
9252 {
9253 case MappingModifier:
9254 x_find_modifier_meanings (dpyinfo);
9255 FALLTHROUGH;
9256 case MappingKeyboard:
9257 XRefreshKeyboardMapping ((XMappingEvent *) &event->xmapping);
9258 }
9259 goto OTHER;
9260
9261 case DestroyNotify:
9262 xft_settings_event (dpyinfo, event);
9263 break;
9264
9265 default:
9266 OTHER:
9267 #ifdef USE_X_TOOLKIT
9268 block_input ();
9269 if (*finish != X_EVENT_DROP)
9270 XtDispatchEvent ((XEvent *) event);
9271 unblock_input ();
9272 #endif /* USE_X_TOOLKIT */
9273 break;
9274 }
9275
9276 done:
9277 if (inev.ie.kind != NO_EVENT)
9278 {
9279 kbd_buffer_store_buffered_event (&inev, hold_quit);
9280 count++;
9281 }
9282
9283 if (do_help
9284 && !(hold_quit && hold_quit->kind != NO_EVENT))
9285 {
9286 Lisp_Object frame;
9287
9288 if (f)
9289 XSETFRAME (frame, f);
9290 else
9291 frame = Qnil;
9292
9293 if (do_help > 0)
9294 {
9295 any_help_event_p = true;
9296 gen_help_event (help_echo_string, frame, help_echo_window,
9297 help_echo_object, help_echo_pos);
9298 }
9299 else
9300 {
9301 help_echo_string = Qnil;
9302 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
9303 }
9304 count++;
9305 }
9306
9307 /* Sometimes event processing draws to the frame outside redisplay.
9308 To ensure that these changes become visible, draw them here. */
9309 flush_dirty_back_buffers ();
9310 SAFE_FREE ();
9311 return count;
9312 }
9313
9314 #if defined USE_X_TOOLKIT || defined USE_MOTIF || defined USE_GTK
9315
9316 /* Handles the XEvent EVENT on display DISPLAY.
9317 This is used for event loops outside the normal event handling,
9318 i.e. looping while a popup menu or a dialog is posted.
9319
9320 Returns the value handle_one_xevent sets in the finish argument. */
9321 int
x_dispatch_event(XEvent * event,Display * display)9322 x_dispatch_event (XEvent *event, Display *display)
9323 {
9324 struct x_display_info *dpyinfo;
9325 int finish = X_EVENT_NORMAL;
9326
9327 dpyinfo = x_display_info_for_display (display);
9328
9329 if (dpyinfo)
9330 handle_one_xevent (dpyinfo, event, &finish, 0);
9331
9332 return finish;
9333 }
9334 #endif
9335
9336 /* Read events coming from the X server.
9337 Return as soon as there are no more events to be read.
9338
9339 Return the number of characters stored into the buffer,
9340 thus pretending to be `read' (except the characters we store
9341 in the keyboard buffer can be multibyte, so are not necessarily
9342 C chars). */
9343
9344 static int
XTread_socket(struct terminal * terminal,struct input_event * hold_quit)9345 XTread_socket (struct terminal *terminal, struct input_event *hold_quit)
9346 {
9347 int count = 0;
9348 bool event_found = false;
9349 struct x_display_info *dpyinfo = terminal->display_info.x;
9350
9351 block_input ();
9352
9353 /* For debugging, this gives a way to fake an I/O error. */
9354 if (dpyinfo == XTread_socket_fake_io_error)
9355 {
9356 XTread_socket_fake_io_error = 0;
9357 x_io_error_quitter (dpyinfo->display);
9358 }
9359
9360 #ifndef USE_GTK
9361 while (XPending (dpyinfo->display))
9362 {
9363 int finish;
9364 XEvent event;
9365
9366 XNextEvent (dpyinfo->display, &event);
9367
9368 #ifdef HAVE_X_I18N
9369 /* Filter events for the current X input method. */
9370 if (x_filter_event (dpyinfo, &event))
9371 continue;
9372 #endif
9373 event_found = true;
9374
9375 count += handle_one_xevent (dpyinfo, &event, &finish, hold_quit);
9376
9377 if (finish == X_EVENT_GOTO_OUT)
9378 break;
9379 }
9380
9381 #else /* USE_GTK */
9382
9383 /* For GTK we must use the GTK event loop. But XEvents gets passed
9384 to our filter function above, and then to the big event switch.
9385 We use a bunch of globals to communicate with our filter function,
9386 that is kind of ugly, but it works.
9387
9388 There is no way to do one display at the time, GTK just does events
9389 from all displays. */
9390
9391 while (gtk_events_pending ())
9392 {
9393 current_count = count;
9394 current_hold_quit = hold_quit;
9395
9396 gtk_main_iteration ();
9397
9398 count = current_count;
9399 current_count = -1;
9400 current_hold_quit = 0;
9401
9402 if (current_finish == X_EVENT_GOTO_OUT)
9403 break;
9404 }
9405 #endif /* USE_GTK */
9406
9407 /* On some systems, an X bug causes Emacs to get no more events
9408 when the window is destroyed. Detect that. (1994.) */
9409 if (! event_found)
9410 {
9411 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
9412 One XNOOP in 100 loops will make Emacs terminate.
9413 B. Bretthauer, 1994 */
9414 x_noop_count++;
9415 if (x_noop_count >= 100)
9416 {
9417 x_noop_count=0;
9418
9419 if (next_noop_dpyinfo == 0)
9420 next_noop_dpyinfo = x_display_list;
9421
9422 XNoOp (next_noop_dpyinfo->display);
9423
9424 /* Each time we get here, cycle through the displays now open. */
9425 next_noop_dpyinfo = next_noop_dpyinfo->next;
9426 }
9427 }
9428
9429 /* If the focus was just given to an auto-raising frame,
9430 raise it now. FIXME: handle more than one such frame. */
9431 if (dpyinfo->x_pending_autoraise_frame)
9432 {
9433 x_raise_frame (dpyinfo->x_pending_autoraise_frame);
9434 dpyinfo->x_pending_autoraise_frame = NULL;
9435 }
9436
9437 unblock_input ();
9438
9439 return count;
9440 }
9441
9442
9443
9444
9445 /***********************************************************************
9446 Text Cursor
9447 ***********************************************************************/
9448
9449 /* Set clipping for output in glyph row ROW. W is the window in which
9450 we operate. GC is the graphics context to set clipping in.
9451
9452 ROW may be a text row or, e.g., a mode line. Text rows must be
9453 clipped to the interior of the window dedicated to text display,
9454 mode lines must be clipped to the whole window. */
9455
9456 static void
x_clip_to_row(struct window * w,struct glyph_row * row,enum glyph_row_area area,GC gc)9457 x_clip_to_row (struct window *w, struct glyph_row *row,
9458 enum glyph_row_area area, GC gc)
9459 {
9460 struct frame *f = XFRAME (WINDOW_FRAME (w));
9461 XRectangle clip_rect;
9462 int window_x, window_y, window_width;
9463
9464 window_box (w, area, &window_x, &window_y, &window_width, 0);
9465
9466 clip_rect.x = window_x;
9467 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
9468 clip_rect.y = max (clip_rect.y, window_y);
9469 clip_rect.width = window_width;
9470 clip_rect.height = row->visible_height;
9471
9472 x_set_clip_rectangles (f, gc, &clip_rect, 1);
9473 }
9474
9475
9476 /* Draw a hollow box cursor on window W in glyph row ROW. */
9477
9478 static void
x_draw_hollow_cursor(struct window * w,struct glyph_row * row)9479 x_draw_hollow_cursor (struct window *w, struct glyph_row *row)
9480 {
9481 struct frame *f = XFRAME (WINDOW_FRAME (w));
9482 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
9483 Display *dpy = FRAME_X_DISPLAY (f);
9484 int x, y, wd, h;
9485 XGCValues xgcv;
9486 struct glyph *cursor_glyph;
9487 GC gc;
9488
9489 /* Get the glyph the cursor is on. If we can't tell because
9490 the current matrix is invalid or such, give up. */
9491 cursor_glyph = get_phys_cursor_glyph (w);
9492 if (cursor_glyph == NULL)
9493 return;
9494
9495 /* Compute frame-relative coordinates for phys cursor. */
9496 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
9497 wd = w->phys_cursor_width - 1;
9498
9499 /* The foreground of cursor_gc is typically the same as the normal
9500 background color, which can cause the cursor box to be invisible. */
9501 xgcv.foreground = f->output_data.x->cursor_pixel;
9502 if (dpyinfo->scratch_cursor_gc)
9503 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
9504 else
9505 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_DRAWABLE (f),
9506 GCForeground, &xgcv);
9507 gc = dpyinfo->scratch_cursor_gc;
9508
9509 /* When on R2L character, show cursor at the right edge of the
9510 glyph, unless the cursor box is as wide as the glyph or wider
9511 (the latter happens when x-stretch-cursor is non-nil). */
9512 if ((cursor_glyph->resolved_level & 1) != 0
9513 && cursor_glyph->pixel_width > wd)
9514 {
9515 x += cursor_glyph->pixel_width - wd;
9516 if (wd > 0)
9517 wd -= 1;
9518 }
9519 /* Set clipping, draw the rectangle, and reset clipping again. */
9520 x_clip_to_row (w, row, TEXT_AREA, gc);
9521 x_draw_rectangle (f, gc, x, y, wd, h - 1);
9522 x_reset_clip_rectangles (f, gc);
9523 }
9524
9525
9526 /* Draw a bar cursor on window W in glyph row ROW.
9527
9528 Implementation note: One would like to draw a bar cursor with an
9529 angle equal to the one given by the font property XA_ITALIC_ANGLE.
9530 Unfortunately, I didn't find a font yet that has this property set.
9531 --gerd. */
9532
9533 static void
x_draw_bar_cursor(struct window * w,struct glyph_row * row,int width,enum text_cursor_kinds kind)9534 x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text_cursor_kinds kind)
9535 {
9536 struct frame *f = XFRAME (w->frame);
9537 struct glyph *cursor_glyph;
9538
9539 /* If cursor is out of bounds, don't draw garbage. This can happen
9540 in mini-buffer windows when switching between echo area glyphs
9541 and mini-buffer. */
9542 cursor_glyph = get_phys_cursor_glyph (w);
9543 if (cursor_glyph == NULL)
9544 return;
9545
9546 /* Experimental avoidance of cursor on xwidget. */
9547 if (cursor_glyph->type == XWIDGET_GLYPH)
9548 return;
9549
9550 /* If on an image, draw like a normal cursor. That's usually better
9551 visible than drawing a bar, esp. if the image is large so that
9552 the bar might not be in the window. */
9553 if (cursor_glyph->type == IMAGE_GLYPH)
9554 {
9555 struct glyph_row *r;
9556 r = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
9557 draw_phys_cursor_glyph (w, r, DRAW_CURSOR);
9558 }
9559 else
9560 {
9561 Display *dpy = FRAME_X_DISPLAY (f);
9562 Drawable drawable = FRAME_X_DRAWABLE (f);
9563 GC gc = FRAME_DISPLAY_INFO (f)->scratch_cursor_gc;
9564 unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures;
9565 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
9566 XGCValues xgcv;
9567
9568 /* If the glyph's background equals the color we normally draw
9569 the bars cursor in, the bar cursor in its normal color is
9570 invisible. Use the glyph's foreground color instead in this
9571 case, on the assumption that the glyph's colors are chosen so
9572 that the glyph is legible. */
9573 if (face->background == f->output_data.x->cursor_pixel)
9574 xgcv.background = xgcv.foreground = face->foreground;
9575 else
9576 xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel;
9577 xgcv.graphics_exposures = False;
9578
9579 if (gc)
9580 XChangeGC (dpy, gc, mask, &xgcv);
9581 else
9582 {
9583 gc = XCreateGC (dpy, drawable, mask, &xgcv);
9584 FRAME_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
9585 }
9586
9587 x_clip_to_row (w, row, TEXT_AREA, gc);
9588
9589 if (kind == BAR_CURSOR)
9590 {
9591 int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
9592
9593 if (width < 0)
9594 width = FRAME_CURSOR_WIDTH (f);
9595 width = min (cursor_glyph->pixel_width, width);
9596
9597 w->phys_cursor_width = width;
9598
9599 /* If the character under cursor is R2L, draw the bar cursor
9600 on the right of its glyph, rather than on the left. */
9601 if ((cursor_glyph->resolved_level & 1) != 0)
9602 x += cursor_glyph->pixel_width - width;
9603
9604 x_fill_rectangle (f, gc, x,
9605 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
9606 width, row->height);
9607 }
9608 else /* HBAR_CURSOR */
9609 {
9610 int dummy_x, dummy_y, dummy_h;
9611 int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
9612
9613 if (width < 0)
9614 width = row->height;
9615
9616 width = min (row->height, width);
9617
9618 get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x,
9619 &dummy_y, &dummy_h);
9620
9621 if ((cursor_glyph->resolved_level & 1) != 0
9622 && cursor_glyph->pixel_width > w->phys_cursor_width - 1)
9623 x += cursor_glyph->pixel_width - w->phys_cursor_width + 1;
9624 x_fill_rectangle (f, gc, x,
9625 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
9626 row->height - width),
9627 w->phys_cursor_width - 1, width);
9628 }
9629
9630 x_reset_clip_rectangles (f, gc);
9631 }
9632 }
9633
9634
9635 /* RIF: Define cursor CURSOR on frame F. */
9636
9637 static void
x_define_frame_cursor(struct frame * f,Emacs_Cursor cursor)9638 x_define_frame_cursor (struct frame *f, Emacs_Cursor cursor)
9639 {
9640 if (!f->pointer_invisible
9641 && f->output_data.x->current_cursor != cursor)
9642 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
9643 f->output_data.x->current_cursor = cursor;
9644 }
9645
9646
9647 /* RIF: Clear area on frame F. */
9648
9649 static void
x_clear_frame_area(struct frame * f,int x,int y,int width,int height)9650 x_clear_frame_area (struct frame *f, int x, int y, int width, int height)
9651 {
9652 x_clear_area (f, x, y, width, height);
9653 }
9654
9655
9656 /* RIF: Draw cursor on window W. */
9657
9658 static void
x_draw_window_cursor(struct window * w,struct glyph_row * glyph_row,int x,int y,enum text_cursor_kinds cursor_type,int cursor_width,bool on_p,bool active_p)9659 x_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, int x,
9660 int y, enum text_cursor_kinds cursor_type,
9661 int cursor_width, bool on_p, bool active_p)
9662 {
9663 struct frame *f = XFRAME (WINDOW_FRAME (w));
9664
9665 if (on_p)
9666 {
9667 w->phys_cursor_type = cursor_type;
9668 w->phys_cursor_on_p = true;
9669
9670 if (glyph_row->exact_window_width_line_p
9671 && (glyph_row->reversed_p
9672 ? (w->phys_cursor.hpos < 0)
9673 : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])))
9674 {
9675 glyph_row->cursor_in_fringe_p = true;
9676 draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p);
9677 }
9678 else
9679 {
9680 switch (cursor_type)
9681 {
9682 case HOLLOW_BOX_CURSOR:
9683 x_draw_hollow_cursor (w, glyph_row);
9684 break;
9685
9686 case FILLED_BOX_CURSOR:
9687 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
9688 break;
9689
9690 case BAR_CURSOR:
9691 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
9692 break;
9693
9694 case HBAR_CURSOR:
9695 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
9696 break;
9697
9698 case NO_CURSOR:
9699 w->phys_cursor_width = 0;
9700 break;
9701
9702 default:
9703 emacs_abort ();
9704 }
9705 }
9706
9707 #ifdef HAVE_X_I18N
9708 if (w == XWINDOW (f->selected_window))
9709 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
9710 xic_set_preeditarea (w, x, y);
9711 #endif
9712 }
9713
9714 XFlush (FRAME_X_DISPLAY (f));
9715 }
9716
9717
9718 /* Icons. */
9719
9720 /* Make the x-window of frame F use the gnu icon bitmap. */
9721
9722 static bool
x_bitmap_icon(struct frame * f,Lisp_Object file)9723 x_bitmap_icon (struct frame *f, Lisp_Object file)
9724 {
9725 ptrdiff_t bitmap_id;
9726
9727 if (FRAME_X_WINDOW (f) == 0)
9728 return true;
9729
9730 /* Free up our existing icon bitmap and mask if any. */
9731 if (f->output_data.x->icon_bitmap > 0)
9732 image_destroy_bitmap (f, f->output_data.x->icon_bitmap);
9733 f->output_data.x->icon_bitmap = 0;
9734
9735 if (STRINGP (file))
9736 {
9737 #ifdef USE_GTK
9738 /* Use gtk_window_set_icon_from_file () if available,
9739 It's not restricted to bitmaps */
9740 if (xg_set_icon (f, file))
9741 return false;
9742 #endif /* USE_GTK */
9743 bitmap_id = image_create_bitmap_from_file (f, file);
9744 x_create_bitmap_mask (f, bitmap_id);
9745 }
9746 else
9747 {
9748 /* Create the GNU bitmap and mask if necessary. */
9749 if (FRAME_DISPLAY_INFO (f)->icon_bitmap_id < 0)
9750 {
9751 ptrdiff_t rc = -1;
9752
9753 #ifdef USE_GTK
9754
9755 if (xg_set_icon (f, xg_default_icon_file)
9756 || xg_set_icon_from_xpm_data (f, gnu_xpm_bits))
9757 {
9758 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = -2;
9759 return false;
9760 }
9761
9762 #elif defined (HAVE_XPM) && defined (HAVE_X_WINDOWS)
9763
9764 rc = x_create_bitmap_from_xpm_data (f, gnu_xpm_bits);
9765 if (rc != -1)
9766 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = rc;
9767
9768 #endif
9769
9770 /* If all else fails, use the (black and white) xbm image. */
9771 if (rc == -1)
9772 {
9773 rc = image_create_bitmap_from_data (f,
9774 (char *) gnu_xbm_bits,
9775 gnu_xbm_width,
9776 gnu_xbm_height);
9777 if (rc == -1)
9778 return true;
9779
9780 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = rc;
9781 x_create_bitmap_mask (f, FRAME_DISPLAY_INFO (f)->icon_bitmap_id);
9782 }
9783 }
9784
9785 /* The first time we create the GNU bitmap and mask,
9786 this increments the ref-count one extra time.
9787 As a result, the GNU bitmap and mask are never freed.
9788 That way, we don't have to worry about allocating it again. */
9789 image_reference_bitmap (f, FRAME_DISPLAY_INFO (f)->icon_bitmap_id);
9790
9791 bitmap_id = FRAME_DISPLAY_INFO (f)->icon_bitmap_id;
9792 }
9793
9794 x_wm_set_icon_pixmap (f, bitmap_id);
9795 f->output_data.x->icon_bitmap = bitmap_id;
9796
9797 return false;
9798 }
9799
9800
9801 /* Make the x-window of frame F use a rectangle with text.
9802 Use ICON_NAME as the text. */
9803
9804 bool
x_text_icon(struct frame * f,const char * icon_name)9805 x_text_icon (struct frame *f, const char *icon_name)
9806 {
9807 if (FRAME_X_WINDOW (f) == 0)
9808 return true;
9809
9810 {
9811 XTextProperty text;
9812 text.value = (unsigned char *) icon_name;
9813 text.encoding = XA_STRING;
9814 text.format = 8;
9815 text.nitems = strlen (icon_name);
9816 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), &text);
9817 }
9818
9819 if (f->output_data.x->icon_bitmap > 0)
9820 image_destroy_bitmap (f, f->output_data.x->icon_bitmap);
9821 f->output_data.x->icon_bitmap = 0;
9822 x_wm_set_icon_pixmap (f, 0);
9823
9824 return false;
9825 }
9826
9827 #define X_ERROR_MESSAGE_SIZE 200
9828
9829 /* If non-nil, this should be a string.
9830 It means catch X errors and store the error message in this string.
9831
9832 The reason we use a stack is that x_catch_error/x_uncatch_error can
9833 be called from a signal handler.
9834 */
9835
9836 struct x_error_message_stack {
9837 char string[X_ERROR_MESSAGE_SIZE];
9838 Display *dpy;
9839 x_special_error_handler handler;
9840 void *handler_data;
9841 struct x_error_message_stack *prev;
9842 };
9843 static struct x_error_message_stack *x_error_message;
9844
9845 /* An X error handler which stores the error message in
9846 *x_error_message. This is called from x_error_handler if
9847 x_catch_errors is in effect. */
9848
9849 static void
x_error_catcher(Display * display,XErrorEvent * event)9850 x_error_catcher (Display *display, XErrorEvent *event)
9851 {
9852 XGetErrorText (display, event->error_code,
9853 x_error_message->string,
9854 X_ERROR_MESSAGE_SIZE);
9855 if (x_error_message->handler)
9856 x_error_message->handler (display, event, x_error_message->string,
9857 x_error_message->handler_data);
9858 }
9859
9860 /* Begin trapping X errors for display DPY. Actually we trap X errors
9861 for all displays, but DPY should be the display you are actually
9862 operating on.
9863
9864 After calling this function, X protocol errors no longer cause
9865 Emacs to exit; instead, they are recorded in the string
9866 stored in *x_error_message.
9867
9868 Calling x_check_errors signals an Emacs error if an X error has
9869 occurred since the last call to x_catch_errors or x_check_errors.
9870
9871 Calling x_uncatch_errors resumes the normal error handling.
9872 Calling x_uncatch_errors_after_check is similar, but skips an XSync
9873 to the server, and should be used only immediately after
9874 x_had_errors_p or x_check_errors. */
9875
9876 void
x_catch_errors_with_handler(Display * dpy,x_special_error_handler handler,void * handler_data)9877 x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler,
9878 void *handler_data)
9879 {
9880 struct x_error_message_stack *data = xmalloc (sizeof *data);
9881
9882 /* Make sure any errors from previous requests have been dealt with. */
9883 XSync (dpy, False);
9884
9885 data->dpy = dpy;
9886 data->string[0] = 0;
9887 data->handler = handler;
9888 data->handler_data = handler_data;
9889 data->prev = x_error_message;
9890 x_error_message = data;
9891 }
9892
9893 void
x_catch_errors(Display * dpy)9894 x_catch_errors (Display *dpy)
9895 {
9896 x_catch_errors_with_handler (dpy, NULL, NULL);
9897 }
9898
9899 /* Undo the last x_catch_errors call.
9900 DPY should be the display that was passed to x_catch_errors.
9901
9902 This version should be used only if the immediately preceding
9903 X-protocol-related thing was x_check_errors or x_had_error_p, both
9904 of which issue XSync calls, so we don't need to re-sync here. */
9905
9906 void
x_uncatch_errors_after_check(void)9907 x_uncatch_errors_after_check (void)
9908 {
9909 struct x_error_message_stack *tmp;
9910
9911 block_input ();
9912 tmp = x_error_message;
9913 x_error_message = x_error_message->prev;
9914 xfree (tmp);
9915 unblock_input ();
9916 }
9917
9918 /* Undo the last x_catch_errors call.
9919 DPY should be the display that was passed to x_catch_errors. */
9920
9921 void
x_uncatch_errors(void)9922 x_uncatch_errors (void)
9923 {
9924 struct x_error_message_stack *tmp;
9925
9926 block_input ();
9927
9928 /* The display may have been closed before this function is called.
9929 Check if it is still open before calling XSync. */
9930 if (x_display_info_for_display (x_error_message->dpy) != 0)
9931 XSync (x_error_message->dpy, False);
9932
9933 tmp = x_error_message;
9934 x_error_message = x_error_message->prev;
9935 xfree (tmp);
9936 unblock_input ();
9937 }
9938
9939 /* If any X protocol errors have arrived since the last call to
9940 x_catch_errors or x_check_errors, signal an Emacs error using
9941 sprintf (a buffer, FORMAT, the x error message text) as the text. */
9942
9943 void
x_check_errors(Display * dpy,const char * format)9944 x_check_errors (Display *dpy, const char *format)
9945 {
9946 /* Make sure to catch any errors incurred so far. */
9947 XSync (dpy, False);
9948
9949 if (x_error_message->string[0])
9950 {
9951 char string[X_ERROR_MESSAGE_SIZE];
9952 memcpy (string, x_error_message->string, X_ERROR_MESSAGE_SIZE);
9953 x_uncatch_errors ();
9954 error (format, string);
9955 }
9956 }
9957
9958 /* Nonzero if we had any X protocol errors
9959 since we did x_catch_errors on DPY. */
9960
9961 bool
x_had_errors_p(Display * dpy)9962 x_had_errors_p (Display *dpy)
9963 {
9964 /* Make sure to catch any errors incurred so far. */
9965 XSync (dpy, False);
9966
9967 return x_error_message->string[0] != 0;
9968 }
9969
9970 /* Forget about any errors we have had, since we did x_catch_errors on DPY. */
9971
9972 void
x_clear_errors(Display * dpy)9973 x_clear_errors (Display *dpy)
9974 {
9975 x_error_message->string[0] = 0;
9976 }
9977
9978 #if false
9979 /* See comment in unwind_to_catch why calling this is a bad
9980 * idea. --lorentey */
9981 /* Close off all unclosed x_catch_errors calls. */
9982
9983 void
x_fully_uncatch_errors(void)9984 x_fully_uncatch_errors (void)
9985 {
9986 while (x_error_message)
9987 x_uncatch_errors ();
9988 }
9989 #endif
9990
9991 #if false
9992 static unsigned int x_wire_count;
x_trace_wire(void)9993 x_trace_wire (void)
9994 {
9995 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
9996 }
9997 #endif
9998
9999
10000 /************************************************************************
10001 Handling X errors
10002 ************************************************************************/
10003
10004 /* Error message passed to x_connection_closed. */
10005
10006 static char *error_msg;
10007
10008 /* Handle the loss of connection to display DPY. ERROR_MESSAGE is
10009 the text of an error message that lead to the connection loss. */
10010
10011 static AVOID
x_connection_closed(Display * dpy,const char * error_message,bool ioerror)10012 x_connection_closed (Display *dpy, const char *error_message, bool ioerror)
10013 {
10014 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
10015 Lisp_Object frame, tail;
10016 ptrdiff_t idx = SPECPDL_INDEX ();
10017
10018 error_msg = alloca (strlen (error_message) + 1);
10019 strcpy (error_msg, error_message);
10020
10021 /* Inhibit redisplay while frames are being deleted. */
10022 specbind (Qinhibit_redisplay, Qt);
10023
10024 if (dpyinfo)
10025 {
10026 /* Protect display from being closed when we delete the last
10027 frame on it. */
10028 dpyinfo->reference_count++;
10029 dpyinfo->terminal->reference_count++;
10030 }
10031 if (ioerror) dpyinfo->display = 0;
10032
10033 /* First delete frames whose mini-buffers are on frames
10034 that are on the dead display. */
10035 FOR_EACH_FRAME (tail, frame)
10036 {
10037 Lisp_Object minibuf_frame;
10038 minibuf_frame
10039 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
10040 if (FRAME_X_P (XFRAME (frame))
10041 && FRAME_X_P (XFRAME (minibuf_frame))
10042 && ! EQ (frame, minibuf_frame)
10043 && FRAME_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
10044 delete_frame (frame, Qnoelisp);
10045 }
10046
10047 /* Now delete all remaining frames on the dead display.
10048 We are now sure none of these is used as the mini-buffer
10049 for another frame that we need to delete. */
10050 FOR_EACH_FRAME (tail, frame)
10051 if (FRAME_X_P (XFRAME (frame))
10052 && FRAME_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
10053 {
10054 /* Set this to t so that delete_frame won't get confused
10055 trying to find a replacement. */
10056 kset_default_minibuffer_frame (FRAME_KBOARD (XFRAME (frame)), Qt);
10057 delete_frame (frame, Qnoelisp);
10058 }
10059
10060 /* If DPYINFO is null, this means we didn't open the display in the
10061 first place, so don't try to close it. */
10062 if (dpyinfo)
10063 {
10064 /* We can not call XtCloseDisplay here because it calls XSync.
10065 XSync inside the error handler apparently hangs Emacs. On
10066 current Xt versions, this isn't needed either. */
10067 #ifdef USE_GTK
10068 /* A long-standing GTK bug prevents proper disconnect handling
10069 <https://gitlab.gnome.org/GNOME/gtk/issues/221>. Once,
10070 the resulting Glib error message loop filled a user's disk.
10071 To avoid this, kill Emacs unconditionally on disconnect. */
10072 shut_down_emacs (0, Qnil);
10073 fprintf (stderr, "%s\n\
10074 When compiled with GTK, Emacs cannot recover from X disconnects.\n\
10075 This is a GTK bug: https://gitlab.gnome.org/GNOME/gtk/issues/221\n\
10076 For details, see etc/PROBLEMS.\n",
10077 error_msg);
10078 emacs_abort ();
10079 #endif /* USE_GTK */
10080
10081 /* Indicate that this display is dead. */
10082 dpyinfo->display = 0;
10083
10084 dpyinfo->reference_count--;
10085 dpyinfo->terminal->reference_count--;
10086 if (dpyinfo->reference_count != 0)
10087 /* We have just closed all frames on this display. */
10088 emacs_abort ();
10089
10090 {
10091 Lisp_Object tmp;
10092 XSETTERMINAL (tmp, dpyinfo->terminal);
10093 Fdelete_terminal (tmp, Qnoelisp);
10094 }
10095 }
10096
10097 if (terminal_list == 0)
10098 {
10099 fprintf (stderr, "%s\n", error_msg);
10100 Fkill_emacs (make_fixnum (70));
10101 }
10102
10103 totally_unblock_input ();
10104
10105 unbind_to (idx, Qnil);
10106 clear_waiting_for_input ();
10107
10108 /* Here, we absolutely have to use a non-local exit (e.g. signal, throw,
10109 longjmp), because returning from this function would get us back into
10110 Xlib's code which will directly call `exit'. */
10111 error ("%s", error_msg);
10112 }
10113
10114 static void x_error_quitter (Display *, XErrorEvent *);
10115
10116 /* This is the first-level handler for X protocol errors.
10117 It calls x_error_quitter or x_error_catcher. */
10118
10119 static int
x_error_handler(Display * display,XErrorEvent * event)10120 x_error_handler (Display *display, XErrorEvent *event)
10121 {
10122 #if defined USE_GTK && defined HAVE_GTK3
10123 if ((event->error_code == BadMatch || event->error_code == BadWindow)
10124 && event->request_code == X_SetInputFocus)
10125 {
10126 return 0;
10127 }
10128 #endif
10129
10130 if (x_error_message)
10131 x_error_catcher (display, event);
10132 else
10133 x_error_quitter (display, event);
10134 return 0;
10135 }
10136
10137 /* This is the usual handler for X protocol errors.
10138 It kills all frames on the display that we got the error for.
10139 If that was the only one, it prints an error message and kills Emacs. */
10140
10141 /* .gdbinit puts a breakpoint here, so make sure it is not inlined. */
10142
10143 static void NO_INLINE
x_error_quitter(Display * display,XErrorEvent * event)10144 x_error_quitter (Display *display, XErrorEvent *event)
10145 {
10146 char buf[256], buf1[356];
10147
10148 /* Ignore BadName errors. They can happen because of fonts
10149 or colors that are not defined. */
10150
10151 if (event->error_code == BadName)
10152 return;
10153
10154 /* Note that there is no real way portable across R3/R4 to get the
10155 original error handler. */
10156
10157 XGetErrorText (display, event->error_code, buf, sizeof (buf));
10158 sprintf (buf1, "X protocol error: %s on protocol request %d",
10159 buf, event->request_code);
10160 x_connection_closed (display, buf1, false);
10161 }
10162
10163
10164 /* This is the handler for X IO errors, always.
10165 It kills all frames on the display that we lost touch with.
10166 If that was the only one, it prints an error message and kills Emacs. */
10167
10168 static _Noreturn ATTRIBUTE_COLD int
x_io_error_quitter(Display * display)10169 x_io_error_quitter (Display *display)
10170 {
10171 char buf[256];
10172
10173 snprintf (buf, sizeof buf, "Connection lost to X server '%s'",
10174 DisplayString (display));
10175 x_connection_closed (display, buf, true);
10176 }
10177
10178 /* Changing the font of the frame. */
10179
10180 /* Give frame F the font FONT-OBJECT as its default font. The return
10181 value is FONT-OBJECT. FONTSET is an ID of the fontset for the
10182 frame. If it is negative, generate a new fontset from
10183 FONT-OBJECT. */
10184
10185 static Lisp_Object
x_new_font(struct frame * f,Lisp_Object font_object,int fontset)10186 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
10187 {
10188 struct font *font = XFONT_OBJECT (font_object);
10189 int unit, font_ascent, font_descent;
10190 #ifndef USE_X_TOOLKIT
10191 int old_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f);
10192 int old_tab_bar_height = FRAME_TAB_BAR_HEIGHT (f);
10193 Lisp_Object fullscreen;
10194 #endif
10195
10196 if (fontset < 0)
10197 fontset = fontset_from_font (font_object);
10198 FRAME_FONTSET (f) = fontset;
10199 if (FRAME_FONT (f) == font)
10200 /* This font is already set in frame F. There's nothing more to
10201 do. */
10202 return font_object;
10203
10204 FRAME_FONT (f) = font;
10205 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
10206 FRAME_COLUMN_WIDTH (f) = font->average_width;
10207 get_font_ascent_descent (font, &font_ascent, &font_descent);
10208 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
10209
10210 #ifndef USE_X_TOOLKIT
10211 FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
10212 FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
10213 #endif
10214
10215 /* Compute character columns occupied by scrollbar.
10216
10217 Don't do things differently for non-toolkit scrollbars
10218 (Bug#17163). */
10219 unit = FRAME_COLUMN_WIDTH (f);
10220 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
10221 FRAME_CONFIG_SCROLL_BAR_COLS (f)
10222 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
10223 else
10224 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit;
10225
10226 if (FRAME_X_WINDOW (f) != 0)
10227 {
10228 /* Don't change the size of a tip frame; there's no point in
10229 doing it because it's done in Fx_show_tip, and it leads to
10230 problems because the tip frame has no widget. */
10231 if (!FRAME_TOOLTIP_P (f))
10232 {
10233 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
10234 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
10235 false, Qfont);
10236 #ifndef USE_X_TOOLKIT
10237 if ((FRAME_MENU_BAR_HEIGHT (f) != old_menu_bar_height
10238 || FRAME_TAB_BAR_HEIGHT (f) != old_tab_bar_height)
10239 && !f->after_make_frame
10240 && (EQ (frame_inhibit_implied_resize, Qt)
10241 || (CONSP (frame_inhibit_implied_resize)
10242 && NILP (Fmemq (Qfont, frame_inhibit_implied_resize))))
10243 && (NILP (fullscreen = get_frame_param (f, Qfullscreen))
10244 || EQ (fullscreen, Qfullwidth)))
10245 /* If the menu/tab bar height changes, try to keep text height
10246 constant. */
10247 adjust_frame_size
10248 (f, -1, FRAME_TEXT_HEIGHT (f) + FRAME_MENU_BAR_HEIGHT (f)
10249 + FRAME_TAB_BAR_HEIGHT (f)
10250 - old_menu_bar_height - old_tab_bar_height, 1, false, Qfont);
10251 #endif /* USE_X_TOOLKIT */
10252 }
10253 }
10254
10255 #ifdef HAVE_X_I18N
10256 if (FRAME_XIC (f)
10257 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
10258 {
10259 block_input ();
10260 xic_set_xfontset (f, SSDATA (fontset_ascii (fontset)));
10261 unblock_input ();
10262 }
10263 #endif
10264
10265 return font_object;
10266 }
10267
10268
10269 /***********************************************************************
10270 X Input Methods
10271 ***********************************************************************/
10272
10273 #ifdef HAVE_X_I18N
10274
10275 #ifdef HAVE_X11R6
10276
10277 /* XIM destroy callback function, which is called whenever the
10278 connection to input method XIM dies. CLIENT_DATA contains a
10279 pointer to the x_display_info structure corresponding to XIM. */
10280
10281 static void
xim_destroy_callback(XIM xim,XPointer client_data,XPointer call_data)10282 xim_destroy_callback (XIM xim, XPointer client_data, XPointer call_data)
10283 {
10284 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
10285 Lisp_Object frame, tail;
10286
10287 block_input ();
10288
10289 /* No need to call XDestroyIC.. */
10290 FOR_EACH_FRAME (tail, frame)
10291 {
10292 struct frame *f = XFRAME (frame);
10293 if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo)
10294 {
10295 FRAME_XIC (f) = NULL;
10296 xic_free_xfontset (f);
10297 }
10298 }
10299
10300 /* No need to call XCloseIM. */
10301 dpyinfo->xim = NULL;
10302 XFree (dpyinfo->xim_styles);
10303 unblock_input ();
10304 }
10305
10306 #endif /* HAVE_X11R6 */
10307
10308 /* Open the connection to the XIM server on display DPYINFO.
10309 RESOURCE_NAME is the resource name Emacs uses. */
10310
10311 static void
xim_open_dpy(struct x_display_info * dpyinfo,char * resource_name)10312 xim_open_dpy (struct x_display_info *dpyinfo, char *resource_name)
10313 {
10314 XIM xim;
10315
10316 #ifdef HAVE_XIM
10317 if (use_xim)
10318 {
10319 if (dpyinfo->xim)
10320 XCloseIM (dpyinfo->xim);
10321 xim = XOpenIM (dpyinfo->display, dpyinfo->rdb, resource_name,
10322 emacs_class);
10323 dpyinfo->xim = xim;
10324
10325 if (xim)
10326 {
10327 #ifdef HAVE_X11R6
10328 XIMCallback destroy;
10329 #endif
10330
10331 /* Get supported styles and XIM values. */
10332 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
10333
10334 #ifdef HAVE_X11R6
10335 destroy.callback = xim_destroy_callback;
10336 destroy.client_data = (XPointer)dpyinfo;
10337 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
10338 #endif
10339 }
10340 }
10341
10342 else
10343 #endif /* HAVE_XIM */
10344 dpyinfo->xim = NULL;
10345 }
10346
10347
10348 #ifdef HAVE_X11R6_XIM
10349
10350 /* XIM instantiate callback function, which is called whenever an XIM
10351 server is available. DISPLAY is the display of the XIM.
10352 CLIENT_DATA contains a pointer to an xim_inst_t structure created
10353 when the callback was registered. */
10354
10355 static void
xim_instantiate_callback(Display * display,XPointer client_data,XPointer call_data)10356 xim_instantiate_callback (Display *display, XPointer client_data, XPointer call_data)
10357 {
10358 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
10359 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
10360
10361 /* We don't support multiple XIM connections. */
10362 if (dpyinfo->xim)
10363 return;
10364
10365 xim_open_dpy (dpyinfo, xim_inst->resource_name);
10366
10367 /* Create XIC for the existing frames on the same display, as long
10368 as they have no XIC. */
10369 if (dpyinfo->xim && dpyinfo->reference_count > 0)
10370 {
10371 Lisp_Object tail, frame;
10372
10373 block_input ();
10374 FOR_EACH_FRAME (tail, frame)
10375 {
10376 struct frame *f = XFRAME (frame);
10377
10378 if (FRAME_X_P (f)
10379 && FRAME_DISPLAY_INFO (f) == xim_inst->dpyinfo)
10380 if (FRAME_XIC (f) == NULL)
10381 {
10382 create_frame_xic (f);
10383 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
10384 xic_set_statusarea (f);
10385 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
10386 {
10387 struct window *w = XWINDOW (f->selected_window);
10388 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
10389 }
10390 }
10391 }
10392
10393 unblock_input ();
10394 }
10395 }
10396
10397 #endif /* HAVE_X11R6_XIM */
10398
10399
10400 /* Open a connection to the XIM server on display DPYINFO.
10401 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
10402 connection only at the first time. On X11R6, open the connection
10403 in the XIM instantiate callback function. */
10404
10405 static void
xim_initialize(struct x_display_info * dpyinfo,char * resource_name)10406 xim_initialize (struct x_display_info *dpyinfo, char *resource_name)
10407 {
10408 dpyinfo->xim = NULL;
10409 #ifdef HAVE_XIM
10410 if (use_xim)
10411 {
10412 #ifdef HAVE_X11R6_XIM
10413 struct xim_inst_t *xim_inst = xmalloc (sizeof *xim_inst);
10414 Bool ret;
10415
10416 dpyinfo->xim_callback_data = xim_inst;
10417 xim_inst->dpyinfo = dpyinfo;
10418 xim_inst->resource_name = xstrdup (resource_name);
10419 ret = XRegisterIMInstantiateCallback
10420 (dpyinfo->display, dpyinfo->rdb, xim_inst->resource_name,
10421 emacs_class, xim_instantiate_callback,
10422 /* This is XPointer in XFree86 but (XPointer *)
10423 on Tru64, at least, hence the configure test. */
10424 (XRegisterIMInstantiateCallback_arg6) xim_inst);
10425 eassert (ret == True);
10426 #else /* not HAVE_X11R6_XIM */
10427 xim_open_dpy (dpyinfo, resource_name);
10428 #endif /* not HAVE_X11R6_XIM */
10429 }
10430 #endif /* HAVE_XIM */
10431 }
10432
10433
10434 /* Close the connection to the XIM server on display DPYINFO. */
10435
10436 static void
xim_close_dpy(struct x_display_info * dpyinfo)10437 xim_close_dpy (struct x_display_info *dpyinfo)
10438 {
10439 #ifdef HAVE_XIM
10440 if (use_xim)
10441 {
10442 #ifdef HAVE_X11R6_XIM
10443 struct xim_inst_t *xim_inst = dpyinfo->xim_callback_data;
10444
10445 if (dpyinfo->display)
10446 {
10447 Bool ret = XUnregisterIMInstantiateCallback
10448 (dpyinfo->display, dpyinfo->rdb, xim_inst->resource_name,
10449 emacs_class, xim_instantiate_callback,
10450 (XRegisterIMInstantiateCallback_arg6) xim_inst);
10451 eassert (ret == True);
10452 }
10453 xfree (xim_inst->resource_name);
10454 xfree (xim_inst);
10455 #endif /* HAVE_X11R6_XIM */
10456 if (dpyinfo->display)
10457 XCloseIM (dpyinfo->xim);
10458 dpyinfo->xim = NULL;
10459 XFree (dpyinfo->xim_styles);
10460 }
10461 #endif /* HAVE_XIM */
10462 }
10463
10464 #endif /* not HAVE_X11R6_XIM */
10465
10466
10467
10468 /* Calculate the absolute position in frame F
10469 from its current recorded position values and gravity. */
10470
10471 static void
x_calc_absolute_position(struct frame * f)10472 x_calc_absolute_position (struct frame *f)
10473 {
10474 int flags = f->size_hint_flags;
10475 struct frame *p = FRAME_PARENT_FRAME (f);
10476
10477 /* We have nothing to do if the current position
10478 is already for the top-left corner. */
10479 if (! ((flags & XNegative) || (flags & YNegative)))
10480 return;
10481
10482 /* Treat negative positions as relative to the leftmost bottommost
10483 position that fits on the screen. */
10484 if ((flags & XNegative) && (f->left_pos <= 0))
10485 {
10486 int width = FRAME_PIXEL_WIDTH (f);
10487
10488 /* A frame that has been visible at least once should have outer
10489 edges. */
10490 if (f->output_data.x->has_been_visible && !p)
10491 {
10492 Lisp_Object frame;
10493 Lisp_Object edges = Qnil;
10494
10495 XSETFRAME (frame, f);
10496 edges = Fx_frame_edges (frame, Qouter_edges);
10497 if (!NILP (edges))
10498 width = (XFIXNUM (Fnth (make_fixnum (2), edges))
10499 - XFIXNUM (Fnth (make_fixnum (0), edges)));
10500 }
10501
10502 if (p)
10503 f->left_pos = (FRAME_PIXEL_WIDTH (p) - width - 2 * f->border_width
10504 + f->left_pos);
10505 else
10506 f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
10507 - width + f->left_pos);
10508
10509 }
10510
10511 if ((flags & YNegative) && (f->top_pos <= 0))
10512 {
10513 int height = FRAME_PIXEL_HEIGHT (f);
10514
10515 #if defined USE_X_TOOLKIT && defined USE_MOTIF
10516 /* Something is fishy here. When using Motif, starting Emacs with
10517 `-g -0-0', the frame appears too low by a few pixels.
10518
10519 This seems to be so because initially, while Emacs is starting,
10520 the column widget's height and the frame's pixel height are
10521 different. The column widget's height is the right one. In
10522 later invocations, when Emacs is up, the frame's pixel height
10523 is right, though.
10524
10525 It's not obvious where the initial small difference comes from.
10526 2000-12-01, gerd. */
10527
10528 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
10529 #endif
10530
10531 if (f->output_data.x->has_been_visible && !p)
10532 {
10533 Lisp_Object frame;
10534 Lisp_Object edges = Qnil;
10535
10536 XSETFRAME (frame, f);
10537 if (NILP (edges))
10538 edges = Fx_frame_edges (frame, Qouter_edges);
10539 if (!NILP (edges))
10540 height = (XFIXNUM (Fnth (make_fixnum (3), edges))
10541 - XFIXNUM (Fnth (make_fixnum (1), edges)));
10542 }
10543
10544 if (p)
10545 f->top_pos = (FRAME_PIXEL_HEIGHT (p) - height - 2 * f->border_width
10546 + f->top_pos);
10547 else
10548 f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
10549 - height + f->top_pos);
10550 }
10551
10552 /* The left_pos and top_pos
10553 are now relative to the top and left screen edges,
10554 so the flags should correspond. */
10555 f->size_hint_flags &= ~ (XNegative | YNegative);
10556 }
10557
10558 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
10559 to really change the position, and 0 when calling from
10560 x_make_frame_visible (in that case, XOFF and YOFF are the current
10561 position values). It is -1 when calling from gui_set_frame_parameters,
10562 which means, do adjust for borders but don't change the gravity. */
10563
10564 static void
x_set_offset(struct frame * f,register int xoff,register int yoff,int change_gravity)10565 x_set_offset (struct frame *f, register int xoff, register int yoff, int change_gravity)
10566 {
10567 int modified_top, modified_left;
10568 #ifdef USE_GTK
10569 int scale = xg_get_scale (f);
10570 #endif
10571
10572 if (change_gravity > 0)
10573 {
10574 f->top_pos = yoff;
10575 f->left_pos = xoff;
10576 f->size_hint_flags &= ~ (XNegative | YNegative);
10577 if (xoff < 0)
10578 f->size_hint_flags |= XNegative;
10579 if (yoff < 0)
10580 f->size_hint_flags |= YNegative;
10581 f->win_gravity = NorthWestGravity;
10582 }
10583
10584 x_calc_absolute_position (f);
10585
10586 block_input ();
10587 x_wm_set_size_hint (f, 0, false);
10588
10589 #ifdef USE_GTK
10590 if (x_gtk_use_window_move)
10591 {
10592 /* When a position change was requested and the outer GTK widget
10593 has been realized already, leave it to gtk_window_move to
10594 DTRT and return. Used for Bug#25851 and Bug#25943. Convert
10595 from X pixels to GTK scaled pixels. */
10596 if (change_gravity != 0 && FRAME_GTK_OUTER_WIDGET (f))
10597 gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
10598 f->left_pos / scale, f->top_pos / scale);
10599 unblock_input ();
10600 return;
10601 }
10602 #endif /* USE_GTK */
10603
10604 modified_left = f->left_pos;
10605 modified_top = f->top_pos;
10606
10607 if (change_gravity != 0 && FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A)
10608 {
10609 /* Some WMs (twm, wmaker at least) has an offset that is smaller
10610 than the WM decorations. So we use the calculated offset instead
10611 of the WM decoration sizes here (x/y_pixels_outer_diff). */
10612 modified_left += FRAME_X_OUTPUT (f)->move_offset_left;
10613 modified_top += FRAME_X_OUTPUT (f)->move_offset_top;
10614 }
10615
10616 #ifdef USE_GTK
10617 /* Make sure we adjust for possible scaling. */
10618 gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
10619 modified_left / scale, modified_top / scale);
10620 #else
10621 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10622 modified_left, modified_top);
10623 #endif
10624
10625 /* 'x_sync_with_move' is too costly for dragging child frames. */
10626 if (!FRAME_PARENT_FRAME (f))
10627 {
10628 x_sync_with_move (f, f->left_pos, f->top_pos,
10629 FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN);
10630
10631 /* change_gravity is non-zero when this function is called from Lisp to
10632 programmatically move a frame. In that case, we call
10633 x_check_expected_move to discover if we have a "Type A" or "Type B"
10634 window manager, and, for a "Type A" window manager, adjust the position
10635 of the frame.
10636
10637 We call x_check_expected_move if a programmatic move occurred, and
10638 either the window manager type (A/B) is unknown or it is Type A but we
10639 need to compute the top/left offset adjustment for this frame. */
10640
10641 if (change_gravity != 0
10642 && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
10643 || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
10644 && (FRAME_X_OUTPUT (f)->move_offset_left == 0
10645 && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
10646 x_check_expected_move (f, modified_left, modified_top);
10647 }
10648
10649 unblock_input ();
10650 }
10651
10652 /* Return true if _NET_SUPPORTING_WM_CHECK window exists and _NET_SUPPORTED
10653 on the root window for frame F contains ATOMNAME.
10654 This is how a WM check shall be done according to the Window Manager
10655 Specification/Extended Window Manager Hints at
10656 https://freedesktop.org/wiki/Specifications/wm-spec/. */
10657
10658 bool
x_wm_supports(struct frame * f,Atom want_atom)10659 x_wm_supports (struct frame *f, Atom want_atom)
10660 {
10661 Atom actual_type;
10662 unsigned long actual_size, bytes_remaining;
10663 int i, rc, actual_format;
10664 bool ret;
10665 Window wmcheck_window;
10666 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10667 Window target_window = dpyinfo->root_window;
10668 int max_len = 65536;
10669 Display *dpy = FRAME_X_DISPLAY (f);
10670 unsigned char *tmp_data = NULL;
10671 Atom target_type = XA_WINDOW;
10672
10673 block_input ();
10674
10675 x_catch_errors (dpy);
10676 rc = XGetWindowProperty (dpy, target_window,
10677 dpyinfo->Xatom_net_supporting_wm_check,
10678 0, max_len, False, target_type,
10679 &actual_type, &actual_format, &actual_size,
10680 &bytes_remaining, &tmp_data);
10681
10682 if (rc != Success || actual_type != XA_WINDOW || x_had_errors_p (dpy))
10683 {
10684 if (tmp_data) XFree (tmp_data);
10685 x_uncatch_errors ();
10686 unblock_input ();
10687 return false;
10688 }
10689
10690 wmcheck_window = *(Window *) tmp_data;
10691 XFree (tmp_data);
10692
10693 /* Check if window exists. */
10694 XSelectInput (dpy, wmcheck_window, StructureNotifyMask);
10695 if (x_had_errors_p (dpy))
10696 {
10697 x_uncatch_errors_after_check ();
10698 unblock_input ();
10699 return false;
10700 }
10701
10702 if (dpyinfo->net_supported_window != wmcheck_window)
10703 {
10704 /* Window changed, reload atoms */
10705 if (dpyinfo->net_supported_atoms != NULL)
10706 XFree (dpyinfo->net_supported_atoms);
10707 dpyinfo->net_supported_atoms = NULL;
10708 dpyinfo->nr_net_supported_atoms = 0;
10709 dpyinfo->net_supported_window = 0;
10710
10711 target_type = XA_ATOM;
10712 tmp_data = NULL;
10713 rc = XGetWindowProperty (dpy, target_window,
10714 dpyinfo->Xatom_net_supported,
10715 0, max_len, False, target_type,
10716 &actual_type, &actual_format, &actual_size,
10717 &bytes_remaining, &tmp_data);
10718
10719 if (rc != Success || actual_type != XA_ATOM || x_had_errors_p (dpy))
10720 {
10721 if (tmp_data) XFree (tmp_data);
10722 x_uncatch_errors ();
10723 unblock_input ();
10724 return false;
10725 }
10726
10727 dpyinfo->net_supported_atoms = (Atom *)tmp_data;
10728 dpyinfo->nr_net_supported_atoms = actual_size;
10729 dpyinfo->net_supported_window = wmcheck_window;
10730 }
10731
10732 ret = false;
10733
10734 for (i = 0; !ret && i < dpyinfo->nr_net_supported_atoms; ++i)
10735 ret = dpyinfo->net_supported_atoms[i] == want_atom;
10736
10737 x_uncatch_errors ();
10738 unblock_input ();
10739
10740 return ret;
10741 }
10742
10743 static void
set_wm_state(Lisp_Object frame,bool add,Atom atom,Atom value)10744 set_wm_state (Lisp_Object frame, bool add, Atom atom, Atom value)
10745 {
10746 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (XFRAME (frame));
10747
10748 x_send_client_event (frame, make_fixnum (0), frame,
10749 dpyinfo->Xatom_net_wm_state,
10750 make_fixnum (32),
10751 /* 1 = add, 0 = remove */
10752 Fcons
10753 (make_fixnum (add),
10754 Fcons
10755 (INT_TO_INTEGER (atom),
10756 (value != 0
10757 ? list1 (INT_TO_INTEGER (value))
10758 : Qnil))));
10759 }
10760
10761 void
x_set_sticky(struct frame * f,Lisp_Object new_value,Lisp_Object old_value)10762 x_set_sticky (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
10763 {
10764 Lisp_Object frame;
10765 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10766
10767 XSETFRAME (frame, f);
10768
10769 set_wm_state (frame, !NILP (new_value),
10770 dpyinfo->Xatom_net_wm_state_sticky, None);
10771 }
10772
10773 /**
10774 * x_set_skip_taskbar:
10775 *
10776 * Set frame F's `skip-taskbar' parameter. If non-nil, this should
10777 * remove F's icon from the taskbar associated with the display of F's
10778 * window-system window and inhibit switching to F's window via
10779 * <Alt>-<TAB>. If nil, lift these restrictions.
10780 *
10781 * Some window managers may not honor this parameter.
10782 */
10783 void
x_set_skip_taskbar(struct frame * f,Lisp_Object new_value,Lisp_Object old_value)10784 x_set_skip_taskbar (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
10785 {
10786 if (!EQ (new_value, old_value))
10787 {
10788 #ifdef USE_GTK
10789 xg_set_skip_taskbar (f, new_value);
10790 #else
10791 Lisp_Object frame;
10792 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10793
10794 XSETFRAME (frame, f);
10795 set_wm_state (frame, !NILP (new_value),
10796 dpyinfo->Xatom_net_wm_state_skip_taskbar, None);
10797 #endif /* USE_GTK */
10798 FRAME_SKIP_TASKBAR (f) = !NILP (new_value);
10799 }
10800 }
10801
10802 /**
10803 * x_set_z_group:
10804 *
10805 * Set frame F's `z-group' parameter. If `above', F's window-system
10806 * window is displayed above all windows that do not have the `above'
10807 * property set. If nil, F's window is shown below all windows that
10808 * have the `above' property set and above all windows that have the
10809 * `below' property set. If `below', F's window is displayed below all
10810 * windows that do not have the `below' property set.
10811 *
10812 * Some window managers may not honor this parameter.
10813 *
10814 * Internally, this function also handles a value 'above-suspended'.
10815 * That value is used to temporarily remove F from the 'above' group
10816 * to make sure that it does not obscure a menu currently popped up.
10817 */
10818 void
x_set_z_group(struct frame * f,Lisp_Object new_value,Lisp_Object old_value)10819 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
10820 {
10821 /* We don't care about old_value. The window manager might have
10822 reset the value without telling us. */
10823 Lisp_Object frame;
10824 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10825
10826 XSETFRAME (frame, f);
10827
10828 if (NILP (new_value))
10829 {
10830 set_wm_state (frame, false,
10831 dpyinfo->Xatom_net_wm_state_above, None);
10832 set_wm_state (frame, false,
10833 dpyinfo->Xatom_net_wm_state_below, None);
10834 FRAME_Z_GROUP (f) = z_group_none;
10835 }
10836 else if (EQ (new_value, Qabove))
10837 {
10838 set_wm_state (frame, true,
10839 dpyinfo->Xatom_net_wm_state_above, None);
10840 set_wm_state (frame, false,
10841 dpyinfo->Xatom_net_wm_state_below, None);
10842 FRAME_Z_GROUP (f) = z_group_above;
10843 }
10844 else if (EQ (new_value, Qbelow))
10845 {
10846 set_wm_state (frame, false,
10847 dpyinfo->Xatom_net_wm_state_above, None);
10848 set_wm_state (frame, true,
10849 dpyinfo->Xatom_net_wm_state_below, None);
10850 FRAME_Z_GROUP (f) = z_group_below;
10851 }
10852 else if (EQ (new_value, Qabove_suspended))
10853 {
10854 set_wm_state (frame, false,
10855 dpyinfo->Xatom_net_wm_state_above, None);
10856 FRAME_Z_GROUP (f) = z_group_above_suspended;
10857 }
10858 else
10859 error ("Invalid z-group specification");
10860 }
10861
10862
10863 /* Return the current _NET_WM_STATE.
10864 SIZE_STATE is set to one of the FULLSCREEN_* values.
10865 Set *STICKY to the sticky state.
10866
10867 Return true iff we are not hidden. */
10868
10869 static bool
x_get_current_wm_state(struct frame * f,Window window,int * size_state,bool * sticky)10870 x_get_current_wm_state (struct frame *f,
10871 Window window,
10872 int *size_state,
10873 bool *sticky)
10874 {
10875 unsigned long actual_size;
10876 int i;
10877 bool is_hidden = false;
10878 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10879 long max_len = 65536;
10880 Atom target_type = XA_ATOM;
10881 /* If XCB is available, we can avoid three XSync calls. */
10882 #ifdef USE_XCB
10883 xcb_get_property_cookie_t prop_cookie;
10884 xcb_get_property_reply_t *prop;
10885 xcb_atom_t *reply_data UNINIT;
10886 #else
10887 Display *dpy = FRAME_X_DISPLAY (f);
10888 unsigned long bytes_remaining;
10889 int rc, actual_format;
10890 Atom actual_type;
10891 unsigned char *tmp_data = NULL;
10892 Atom *reply_data UNINIT;
10893 #endif
10894
10895 *sticky = false;
10896 *size_state = FULLSCREEN_NONE;
10897
10898 block_input ();
10899
10900 #ifdef USE_XCB
10901 prop_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, window,
10902 dpyinfo->Xatom_net_wm_state,
10903 target_type, 0, max_len);
10904 prop = xcb_get_property_reply (dpyinfo->xcb_connection, prop_cookie, NULL);
10905 if (prop && prop->type == target_type)
10906 {
10907 int actual_bytes = xcb_get_property_value_length (prop);
10908 eassume (0 <= actual_bytes);
10909 actual_size = actual_bytes / sizeof *reply_data;
10910 reply_data = xcb_get_property_value (prop);
10911 }
10912 else
10913 {
10914 actual_size = 0;
10915 is_hidden = FRAME_ICONIFIED_P (f);
10916 }
10917 #else
10918 x_catch_errors (dpy);
10919 rc = XGetWindowProperty (dpy, window, dpyinfo->Xatom_net_wm_state,
10920 0, max_len, False, target_type,
10921 &actual_type, &actual_format, &actual_size,
10922 &bytes_remaining, &tmp_data);
10923
10924 if (rc == Success && actual_type == target_type && ! x_had_errors_p (dpy))
10925 reply_data = (Atom *) tmp_data;
10926 else
10927 {
10928 actual_size = 0;
10929 is_hidden = FRAME_ICONIFIED_P (f);
10930 }
10931
10932 x_uncatch_errors ();
10933 #endif
10934
10935 for (i = 0; i < actual_size; ++i)
10936 {
10937 Atom a = reply_data[i];
10938 if (a == dpyinfo->Xatom_net_wm_state_hidden)
10939 is_hidden = true;
10940 else if (a == dpyinfo->Xatom_net_wm_state_maximized_horz)
10941 {
10942 if (*size_state == FULLSCREEN_HEIGHT)
10943 *size_state = FULLSCREEN_MAXIMIZED;
10944 else
10945 *size_state = FULLSCREEN_WIDTH;
10946 }
10947 else if (a == dpyinfo->Xatom_net_wm_state_maximized_vert)
10948 {
10949 if (*size_state == FULLSCREEN_WIDTH)
10950 *size_state = FULLSCREEN_MAXIMIZED;
10951 else
10952 *size_state = FULLSCREEN_HEIGHT;
10953 }
10954 else if (a == dpyinfo->Xatom_net_wm_state_fullscreen)
10955 *size_state = FULLSCREEN_BOTH;
10956 else if (a == dpyinfo->Xatom_net_wm_state_sticky)
10957 *sticky = true;
10958 }
10959
10960 #ifdef USE_XCB
10961 free (prop);
10962 #else
10963 if (tmp_data) XFree (tmp_data);
10964 #endif
10965
10966 unblock_input ();
10967 return ! is_hidden;
10968 }
10969
10970 /* Do fullscreen as specified in extended window manager hints */
10971
10972 static bool
do_ewmh_fullscreen(struct frame * f)10973 do_ewmh_fullscreen (struct frame *f)
10974 {
10975 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10976 bool have_net_atom = x_wm_supports (f, dpyinfo->Xatom_net_wm_state);
10977 int cur;
10978 bool dummy;
10979
10980 x_get_current_wm_state (f, FRAME_OUTER_WINDOW (f), &cur, &dummy);
10981
10982 /* Some window managers don't say they support _NET_WM_STATE, but they do say
10983 they support _NET_WM_STATE_FULLSCREEN. Try that also. */
10984 if (!have_net_atom)
10985 have_net_atom = x_wm_supports (f, dpyinfo->Xatom_net_wm_state_fullscreen);
10986
10987 if (have_net_atom && cur != f->want_fullscreen)
10988 {
10989 Lisp_Object frame;
10990
10991 XSETFRAME (frame, f);
10992
10993 /* Keep number of calls to set_wm_state as low as possible.
10994 Some window managers, or possible Gtk+, hangs when too many
10995 are sent at once. */
10996 switch (f->want_fullscreen)
10997 {
10998 case FULLSCREEN_BOTH:
10999 if (cur != FULLSCREEN_BOTH)
11000 set_wm_state (frame, true, dpyinfo->Xatom_net_wm_state_fullscreen,
11001 None);
11002 break;
11003 case FULLSCREEN_WIDTH:
11004 if (x_frame_normalize_before_maximize && cur == FULLSCREEN_MAXIMIZED)
11005 {
11006 set_wm_state (frame, false,
11007 dpyinfo->Xatom_net_wm_state_maximized_horz,
11008 dpyinfo->Xatom_net_wm_state_maximized_vert);
11009 set_wm_state (frame, true,
11010 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
11011 }
11012 else
11013 {
11014 if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_HEIGHT
11015 || cur == FULLSCREEN_MAXIMIZED)
11016 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
11017 dpyinfo->Xatom_net_wm_state_maximized_vert);
11018 if (cur != FULLSCREEN_MAXIMIZED || x_frame_normalize_before_maximize)
11019 set_wm_state (frame, true,
11020 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
11021 }
11022 break;
11023 case FULLSCREEN_HEIGHT:
11024 if (x_frame_normalize_before_maximize && cur == FULLSCREEN_MAXIMIZED)
11025 {
11026 set_wm_state (frame, false,
11027 dpyinfo->Xatom_net_wm_state_maximized_horz,
11028 dpyinfo->Xatom_net_wm_state_maximized_vert);
11029 set_wm_state (frame, true,
11030 dpyinfo->Xatom_net_wm_state_maximized_vert, None);
11031 }
11032 else
11033 {
11034 if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_WIDTH
11035 || cur == FULLSCREEN_MAXIMIZED)
11036 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
11037 dpyinfo->Xatom_net_wm_state_maximized_horz);
11038 if (cur != FULLSCREEN_MAXIMIZED || x_frame_normalize_before_maximize)
11039 set_wm_state (frame, true,
11040 dpyinfo->Xatom_net_wm_state_maximized_vert, None);
11041 }
11042 break;
11043 case FULLSCREEN_MAXIMIZED:
11044 if (x_frame_normalize_before_maximize && cur == FULLSCREEN_BOTH)
11045 {
11046 set_wm_state (frame, false,
11047 dpyinfo->Xatom_net_wm_state_fullscreen, None);
11048 set_wm_state (frame, true,
11049 dpyinfo->Xatom_net_wm_state_maximized_horz,
11050 dpyinfo->Xatom_net_wm_state_maximized_vert);
11051 }
11052 else if (x_frame_normalize_before_maximize && cur == FULLSCREEN_WIDTH)
11053 {
11054 set_wm_state (frame, false,
11055 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
11056 set_wm_state (frame, true,
11057 dpyinfo->Xatom_net_wm_state_maximized_horz,
11058 dpyinfo->Xatom_net_wm_state_maximized_vert);
11059 }
11060 else if (x_frame_normalize_before_maximize && cur == FULLSCREEN_HEIGHT)
11061 {
11062 set_wm_state (frame, false,
11063 dpyinfo->Xatom_net_wm_state_maximized_vert, None);
11064 set_wm_state (frame, true,
11065 dpyinfo->Xatom_net_wm_state_maximized_horz,
11066 dpyinfo->Xatom_net_wm_state_maximized_vert);
11067 }
11068 else
11069 {
11070 if (cur == FULLSCREEN_BOTH)
11071 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
11072 None);
11073 else if (cur == FULLSCREEN_HEIGHT)
11074 set_wm_state (frame, true,
11075 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
11076 else if (cur == FULLSCREEN_WIDTH)
11077 set_wm_state (frame, true, None,
11078 dpyinfo->Xatom_net_wm_state_maximized_vert);
11079 else
11080 set_wm_state (frame, true,
11081 dpyinfo->Xatom_net_wm_state_maximized_horz,
11082 dpyinfo->Xatom_net_wm_state_maximized_vert);
11083 }
11084 break;
11085 case FULLSCREEN_NONE:
11086 if (cur == FULLSCREEN_BOTH)
11087 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
11088 None);
11089 else
11090 set_wm_state (frame, false,
11091 dpyinfo->Xatom_net_wm_state_maximized_horz,
11092 dpyinfo->Xatom_net_wm_state_maximized_vert);
11093 }
11094
11095 f->want_fullscreen = FULLSCREEN_NONE;
11096
11097 }
11098
11099 return have_net_atom;
11100 }
11101
11102 static void
XTfullscreen_hook(struct frame * f)11103 XTfullscreen_hook (struct frame *f)
11104 {
11105 if (FRAME_VISIBLE_P (f))
11106 {
11107 block_input ();
11108 x_check_fullscreen (f);
11109 x_sync (f);
11110 unblock_input ();
11111 }
11112 }
11113
11114
11115 static bool
x_handle_net_wm_state(struct frame * f,const XPropertyEvent * event)11116 x_handle_net_wm_state (struct frame *f, const XPropertyEvent *event)
11117 {
11118 int value = FULLSCREEN_NONE;
11119 Lisp_Object lval;
11120 bool sticky = false;
11121 bool not_hidden = x_get_current_wm_state (f, event->window, &value, &sticky);
11122
11123 lval = Qnil;
11124 switch (value)
11125 {
11126 case FULLSCREEN_WIDTH:
11127 lval = Qfullwidth;
11128 break;
11129 case FULLSCREEN_HEIGHT:
11130 lval = Qfullheight;
11131 break;
11132 case FULLSCREEN_BOTH:
11133 lval = Qfullboth;
11134 break;
11135 case FULLSCREEN_MAXIMIZED:
11136 lval = Qmaximized;
11137 break;
11138 }
11139
11140 frame_size_history_add
11141 (f, Qx_handle_net_wm_state, 0, 0,
11142 list2 (get_frame_param (f, Qfullscreen), lval));
11143
11144 store_frame_param (f, Qfullscreen, lval);
11145 store_frame_param (f, Qsticky, sticky ? Qt : Qnil);
11146
11147 return not_hidden;
11148 }
11149
11150 /* Check if we need to resize the frame due to a fullscreen request.
11151 If so needed, resize the frame. */
11152 static void
x_check_fullscreen(struct frame * f)11153 x_check_fullscreen (struct frame *f)
11154 {
11155 Lisp_Object lval = Qnil;
11156
11157 if (do_ewmh_fullscreen (f))
11158 return;
11159
11160 if (f->output_data.x->parent_desc != FRAME_DISPLAY_INFO (f)->root_window)
11161 return; /* Only fullscreen without WM or with EWM hints (above). */
11162
11163 /* Setting fullscreen to nil doesn't do anything. We could save the
11164 last non-fullscreen size and restore it, but it seems like a
11165 lot of work for this unusual case (no window manager running). */
11166
11167 if (f->want_fullscreen != FULLSCREEN_NONE)
11168 {
11169 int width = FRAME_PIXEL_WIDTH (f), height = FRAME_PIXEL_HEIGHT (f);
11170 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
11171
11172 switch (f->want_fullscreen)
11173 {
11174 /* No difference between these two when there is no WM */
11175 case FULLSCREEN_MAXIMIZED:
11176 lval = Qmaximized;
11177 width = x_display_pixel_width (dpyinfo);
11178 height = x_display_pixel_height (dpyinfo);
11179 break;
11180 case FULLSCREEN_BOTH:
11181 lval = Qfullboth;
11182 width = x_display_pixel_width (dpyinfo);
11183 height = x_display_pixel_height (dpyinfo);
11184 break;
11185 case FULLSCREEN_WIDTH:
11186 lval = Qfullwidth;
11187 width = x_display_pixel_width (dpyinfo);
11188 height = height + FRAME_MENUBAR_HEIGHT (f);
11189 break;
11190 case FULLSCREEN_HEIGHT:
11191 lval = Qfullheight;
11192 height = x_display_pixel_height (dpyinfo);
11193 break;
11194 default:
11195 emacs_abort ();
11196 }
11197
11198 frame_size_history_add
11199 (f, Qx_check_fullscreen, width, height, Qnil);
11200
11201 x_wm_set_size_hint (f, 0, false);
11202
11203 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11204 width, height);
11205
11206 if (FRAME_VISIBLE_P (f))
11207 x_wait_for_event (f, ConfigureNotify);
11208 else
11209 {
11210 change_frame_size (f, width, height - FRAME_MENUBAR_HEIGHT (f),
11211 false, true, false, true);
11212 x_sync (f);
11213 }
11214 }
11215
11216 /* `x_net_wm_state' might have reset the fullscreen frame parameter,
11217 restore it. */
11218 store_frame_param (f, Qfullscreen, lval);
11219 }
11220
11221 /* This function is called by x_set_offset to determine whether the window
11222 manager interfered with the positioning of the frame. Type A window
11223 managers position the surrounding window manager decorations a small
11224 amount above and left of the user-supplied position. Type B window
11225 managers position the surrounding window manager decorations at the
11226 user-specified position. If we detect a Type A window manager, we
11227 compensate by moving the window right and down by the proper amount. */
11228
11229 static void
x_check_expected_move(struct frame * f,int expected_left,int expected_top)11230 x_check_expected_move (struct frame *f, int expected_left, int expected_top)
11231 {
11232 int current_left = 0, current_top = 0;
11233
11234 /* x_real_positions returns the left and top offsets of the outermost
11235 window manager window around the frame. */
11236
11237 x_real_positions (f, ¤t_left, ¤t_top);
11238
11239 if (current_left != expected_left || current_top != expected_top)
11240 {
11241 /* It's a "Type A" window manager. */
11242
11243 int adjusted_left;
11244 int adjusted_top;
11245
11246 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_A;
11247 FRAME_X_OUTPUT (f)->move_offset_left = expected_left - current_left;
11248 FRAME_X_OUTPUT (f)->move_offset_top = expected_top - current_top;
11249
11250 /* Now fix the mispositioned frame's location. */
11251
11252 adjusted_left = expected_left + FRAME_X_OUTPUT (f)->move_offset_left;
11253 adjusted_top = expected_top + FRAME_X_OUTPUT (f)->move_offset_top;
11254
11255 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11256 adjusted_left, adjusted_top);
11257
11258 x_sync_with_move (f, expected_left, expected_top, false);
11259 }
11260 else
11261 /* It's a "Type B" window manager. We don't have to adjust the
11262 frame's position. */
11263
11264 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_B;
11265 }
11266
11267
11268 /* Wait for XGetGeometry to return up-to-date position information for a
11269 recently-moved frame. Call this immediately after calling XMoveWindow.
11270 If FUZZY is non-zero, then LEFT and TOP are just estimates of where the
11271 frame has been moved to, so we use a fuzzy position comparison instead
11272 of an exact comparison. */
11273
11274 static void
x_sync_with_move(struct frame * f,int left,int top,bool fuzzy)11275 x_sync_with_move (struct frame *f, int left, int top, bool fuzzy)
11276 {
11277 int count = 0;
11278
11279 while (count++ < 50)
11280 {
11281 int current_left = 0, current_top = 0;
11282
11283 /* In theory, this call to XSync only needs to happen once, but in
11284 practice, it doesn't seem to work, hence the need for the surrounding
11285 loop. */
11286
11287 XSync (FRAME_X_DISPLAY (f), False);
11288 x_real_positions (f, ¤t_left, ¤t_top);
11289
11290 if (fuzzy)
11291 {
11292 /* The left fuzz-factor is 10 pixels. The top fuzz-factor is 40
11293 pixels. */
11294
11295 if (eabs (current_left - left) <= 10
11296 && eabs (current_top - top) <= 40)
11297 return;
11298 }
11299 else if (current_left == left && current_top == top)
11300 return;
11301 }
11302
11303 /* As a last resort, just wait 0.5 seconds and hope that XGetGeometry
11304 will then return up-to-date position info. */
11305
11306 wait_reading_process_output (0, 500000000, 0, false, Qnil, NULL, 0);
11307 }
11308
11309
11310 /* Wait for an event on frame F matching EVENTTYPE. */
11311 void
x_wait_for_event(struct frame * f,int eventtype)11312 x_wait_for_event (struct frame *f, int eventtype)
11313 {
11314 if (!FLOATP (Vx_wait_for_event_timeout))
11315 return;
11316
11317 int level = interrupt_input_blocked;
11318 fd_set fds;
11319 struct timespec tmo, tmo_at, time_now;
11320 int fd = ConnectionNumber (FRAME_X_DISPLAY (f));
11321
11322 f->wait_event_type = eventtype;
11323
11324 /* Default timeout is 0.1 second. Hopefully not noticeable. */
11325 double timeout = XFLOAT_DATA (Vx_wait_for_event_timeout);
11326 time_t timeout_seconds = (time_t) timeout;
11327 tmo = make_timespec
11328 (timeout_seconds, (long int) ((timeout - timeout_seconds)
11329 * 1000 * 1000 * 1000));
11330 tmo_at = timespec_add (current_timespec (), tmo);
11331
11332 while (f->wait_event_type)
11333 {
11334 pending_signals = true;
11335 totally_unblock_input ();
11336 /* XTread_socket is called after unblock. */
11337 block_input ();
11338 interrupt_input_blocked = level;
11339
11340 FD_ZERO (&fds);
11341 FD_SET (fd, &fds);
11342
11343 time_now = current_timespec ();
11344 if (timespec_cmp (tmo_at, time_now) < 0)
11345 break;
11346
11347 tmo = timespec_sub (tmo_at, time_now);
11348 if (pselect (fd + 1, &fds, NULL, NULL, &tmo, NULL) == 0)
11349 break; /* Timeout */
11350 }
11351
11352 f->wait_event_type = 0;
11353 }
11354
11355
11356 /* Change the size of frame F's X window to WIDTH/HEIGHT in the case F
11357 doesn't have a widget. If CHANGE_GRAVITY, change to
11358 top-left-corner window gravity for this size change and subsequent
11359 size changes. Otherwise leave the window gravity unchanged. */
11360
11361 static void
x_set_window_size_1(struct frame * f,bool change_gravity,int width,int height)11362 x_set_window_size_1 (struct frame *f, bool change_gravity,
11363 int width, int height)
11364 {
11365 int pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
11366 int pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
11367 int old_width = FRAME_PIXEL_WIDTH (f);
11368 int old_height = FRAME_PIXEL_HEIGHT (f);
11369 Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
11370
11371 if (change_gravity)
11372 f->win_gravity = NorthWestGravity;
11373 x_wm_set_size_hint (f, 0, false);
11374
11375 /* When the frame is fullheight and we only want to change the width
11376 or it is fullwidth and we only want to change the height we should
11377 be able to preserve the fullscreen property. However, due to the
11378 fact that we have to send a resize request anyway, the window
11379 manager will abolish it. At least the respective size should
11380 remain unchanged but giving the frame back its normal size will
11381 be broken ... */
11382 if (EQ (fullscreen, Qfullwidth) && width == FRAME_TEXT_WIDTH (f))
11383 {
11384 frame_size_history_add
11385 (f, Qx_set_window_size_1, width, height,
11386 list2i (old_height, pixelheight + FRAME_MENUBAR_HEIGHT (f)));
11387
11388 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11389 old_width, pixelheight + FRAME_MENUBAR_HEIGHT (f));
11390 }
11391 else if (EQ (fullscreen, Qfullheight) && height == FRAME_TEXT_HEIGHT (f))
11392 {
11393 frame_size_history_add
11394 (f, Qx_set_window_size_2, width, height,
11395 list2i (old_width, pixelwidth));
11396
11397 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11398 pixelwidth, old_height);
11399 }
11400
11401 else
11402 {
11403 frame_size_history_add
11404 (f, Qx_set_window_size_3, width, height,
11405 list3i (pixelwidth + FRAME_TOOLBAR_WIDTH (f),
11406 (pixelheight + FRAME_TOOLBAR_HEIGHT (f)
11407 + FRAME_MENUBAR_HEIGHT (f)),
11408 FRAME_MENUBAR_HEIGHT (f)));
11409
11410 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11411 pixelwidth, pixelheight + FRAME_MENUBAR_HEIGHT (f));
11412 fullscreen = Qnil;
11413 }
11414
11415
11416
11417 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
11418 receive in the ConfigureNotify event; if we get what we asked
11419 for, then the event won't cause the screen to become garbaged, so
11420 we have to make sure to do it here. */
11421 SET_FRAME_GARBAGED (f);
11422
11423 /* Now, strictly speaking, we can't be sure that this is accurate,
11424 but the window manager will get around to dealing with the size
11425 change request eventually, and we'll hear how it went when the
11426 ConfigureNotify event gets here.
11427
11428 We could just not bother storing any of this information here,
11429 and let the ConfigureNotify event set everything up, but that
11430 might be kind of confusing to the Lisp code, since size changes
11431 wouldn't be reported in the frame parameters until some random
11432 point in the future when the ConfigureNotify event arrives.
11433
11434 Pass true for DELAY since we can't run Lisp code inside of
11435 a BLOCK_INPUT. */
11436
11437 /* But the ConfigureNotify may in fact never arrive, and then this is
11438 not right if the frame is visible. Instead wait (with timeout)
11439 for the ConfigureNotify. */
11440 if (FRAME_VISIBLE_P (f))
11441 {
11442 x_wait_for_event (f, ConfigureNotify);
11443
11444 if (!NILP (fullscreen))
11445 /* Try to restore fullscreen state. */
11446 {
11447 store_frame_param (f, Qfullscreen, fullscreen);
11448 gui_set_fullscreen (f, fullscreen, fullscreen);
11449 }
11450 }
11451 else
11452 {
11453 change_frame_size (f, width, height, false, true, false, true);
11454 x_sync (f);
11455 }
11456 }
11457
11458
11459 /* Call this to change the size of frame F's x-window.
11460 If CHANGE_GRAVITY, change to top-left-corner window gravity
11461 for this size change and subsequent size changes.
11462 Otherwise we leave the window gravity unchanged. */
11463
11464 void
x_set_window_size(struct frame * f,bool change_gravity,int width,int height,bool pixelwise)11465 x_set_window_size (struct frame *f, bool change_gravity,
11466 int width, int height, bool pixelwise)
11467 {
11468 block_input ();
11469
11470 /* The following breaks our calculations. If it's really needed,
11471 think of something else. */
11472 #if false
11473 if (!FRAME_TOOLTIP_P (f))
11474 {
11475 int text_width, text_height;
11476
11477 /* When the frame is maximized/fullscreen or running under for
11478 example Xmonad, x_set_window_size_1 will be a no-op.
11479 In that case, the right thing to do is extend rows/width to
11480 the current frame size. We do that first if x_set_window_size_1
11481 turns out to not be a no-op (there is no way to know).
11482 The size will be adjusted again if the frame gets a
11483 ConfigureNotify event as a result of x_set_window_size. */
11484 int pixelh = FRAME_PIXEL_HEIGHT (f);
11485 #ifdef USE_X_TOOLKIT
11486 /* The menu bar is not part of text lines. The tool bar
11487 is however. */
11488 pixelh -= FRAME_MENUBAR_HEIGHT (f);
11489 #endif
11490 text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, FRAME_PIXEL_WIDTH (f));
11491 text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelh);
11492
11493 change_frame_size (f, text_width, text_height, false, true, false, true);
11494 }
11495 #endif
11496
11497 /* Pixelize width and height, if necessary. */
11498 if (! pixelwise)
11499 {
11500 width = width * FRAME_COLUMN_WIDTH (f);
11501 height = height * FRAME_LINE_HEIGHT (f);
11502 }
11503
11504 #ifdef USE_GTK
11505 if (FRAME_GTK_WIDGET (f))
11506 xg_frame_set_char_size (f, width, height);
11507 else
11508 x_set_window_size_1 (f, change_gravity, width, height);
11509 #else /* not USE_GTK */
11510 x_set_window_size_1 (f, change_gravity, width, height);
11511 x_clear_under_internal_border (f);
11512 #endif /* not USE_GTK */
11513
11514 /* If cursor was outside the new size, mark it as off. */
11515 mark_window_cursors_off (XWINDOW (f->root_window));
11516
11517 /* Clear out any recollection of where the mouse highlighting was,
11518 since it might be in a place that's outside the new frame size.
11519 Actually checking whether it is outside is a pain in the neck,
11520 so don't try--just let the highlighting be done afresh with new size. */
11521 cancel_mouse_face (f);
11522
11523 unblock_input ();
11524
11525 do_pending_window_change (false);
11526 }
11527
11528 /* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
11529
11530 void
frame_set_mouse_pixel_position(struct frame * f,int pix_x,int pix_y)11531 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
11532 {
11533 block_input ();
11534
11535 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
11536 0, 0, 0, 0, pix_x, pix_y);
11537 unblock_input ();
11538 }
11539
11540 /* Raise frame F. */
11541
11542 static void
x_raise_frame(struct frame * f)11543 x_raise_frame (struct frame *f)
11544 {
11545 block_input ();
11546 if (FRAME_VISIBLE_P (f))
11547 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
11548 XFlush (FRAME_X_DISPLAY (f));
11549 unblock_input ();
11550 }
11551
11552 /* Lower frame F. */
11553
11554 static void
x_lower_frame(struct frame * f)11555 x_lower_frame (struct frame *f)
11556 {
11557 if (FRAME_VISIBLE_P (f))
11558 {
11559 block_input ();
11560 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
11561 XFlush (FRAME_X_DISPLAY (f));
11562 unblock_input ();
11563 }
11564 }
11565
11566 static void
XTframe_raise_lower(struct frame * f,bool raise_flag)11567 XTframe_raise_lower (struct frame *f, bool raise_flag)
11568 {
11569 if (raise_flag)
11570 x_raise_frame (f);
11571 else
11572 x_lower_frame (f);
11573 }
11574
11575 /* Request focus with XEmbed */
11576
11577 static void
xembed_request_focus(struct frame * f)11578 xembed_request_focus (struct frame *f)
11579 {
11580 /* See XEmbed Protocol Specification at
11581 https://freedesktop.org/wiki/Specifications/xembed-spec/ */
11582 if (FRAME_VISIBLE_P (f))
11583 xembed_send_message (f, CurrentTime,
11584 XEMBED_REQUEST_FOCUS, 0, 0, 0);
11585 }
11586
11587 /* Activate frame with Extended Window Manager Hints */
11588
11589 static void
x_ewmh_activate_frame(struct frame * f)11590 x_ewmh_activate_frame (struct frame *f)
11591 {
11592 /* See Window Manager Specification/Extended Window Manager Hints at
11593 https://freedesktop.org/wiki/Specifications/wm-spec/ */
11594
11595 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
11596
11597 if (FRAME_VISIBLE_P (f) && x_wm_supports (f, dpyinfo->Xatom_net_active_window))
11598 {
11599 Lisp_Object frame;
11600 XSETFRAME (frame, f);
11601 x_send_client_event (frame, make_fixnum (0), frame,
11602 dpyinfo->Xatom_net_active_window,
11603 make_fixnum (32),
11604 list2 (make_fixnum (1),
11605 INT_TO_INTEGER (dpyinfo->last_user_time)));
11606 }
11607 }
11608
11609 static Lisp_Object
x_get_focus_frame(struct frame * f)11610 x_get_focus_frame (struct frame *f)
11611 {
11612 Lisp_Object lisp_focus;
11613
11614 struct frame *focus = FRAME_DISPLAY_INFO (f)->x_focus_frame;
11615
11616 if (!focus)
11617 return Qnil;
11618
11619 XSETFRAME (lisp_focus, focus);
11620 return lisp_focus;
11621 }
11622
11623 /* In certain situations, when the window manager follows a
11624 click-to-focus policy, there seems to be no way around calling
11625 XSetInputFocus to give another frame the input focus .
11626
11627 In an ideal world, XSetInputFocus should generally be avoided so
11628 that applications don't interfere with the window manager's focus
11629 policy. But I think it's okay to use when it's clearly done
11630 following a user-command. */
11631
11632 static void
x_focus_frame(struct frame * f,bool noactivate)11633 x_focus_frame (struct frame *f, bool noactivate)
11634 {
11635 Display *dpy = FRAME_X_DISPLAY (f);
11636
11637 block_input ();
11638 x_catch_errors (dpy);
11639
11640 if (FRAME_X_EMBEDDED_P (f))
11641 {
11642 /* For Xembedded frames, normally the embedder forwards key
11643 events. See XEmbed Protocol Specification at
11644 https://freedesktop.org/wiki/Specifications/xembed-spec/ */
11645 xembed_request_focus (f);
11646 }
11647 else
11648 {
11649 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11650 RevertToParent, CurrentTime);
11651 if (!noactivate)
11652 x_ewmh_activate_frame (f);
11653 }
11654
11655 x_uncatch_errors ();
11656 unblock_input ();
11657 }
11658
11659
11660 /* XEmbed implementation. */
11661
11662 #if defined USE_X_TOOLKIT || ! defined USE_GTK
11663
11664 /* XEmbed implementation. */
11665
11666 #define XEMBED_VERSION 0
11667
11668 static void
xembed_set_info(struct frame * f,enum xembed_info flags)11669 xembed_set_info (struct frame *f, enum xembed_info flags)
11670 {
11671 unsigned long data[2];
11672 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
11673
11674 data[0] = XEMBED_VERSION;
11675 data[1] = flags;
11676
11677 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11678 dpyinfo->Xatom_XEMBED_INFO, dpyinfo->Xatom_XEMBED_INFO,
11679 32, PropModeReplace, (unsigned char *) data, 2);
11680 }
11681 #endif /* defined USE_X_TOOLKIT || ! defined USE_GTK */
11682
11683 static void
xembed_send_message(struct frame * f,Time t,enum xembed_message msg,long int detail,long int data1,long int data2)11684 xembed_send_message (struct frame *f, Time t, enum xembed_message msg,
11685 long int detail, long int data1, long int data2)
11686 {
11687 XEvent event;
11688
11689 event.xclient.type = ClientMessage;
11690 event.xclient.window = FRAME_X_OUTPUT (f)->parent_desc;
11691 event.xclient.message_type = FRAME_DISPLAY_INFO (f)->Xatom_XEMBED;
11692 event.xclient.format = 32;
11693 event.xclient.data.l[0] = t;
11694 event.xclient.data.l[1] = msg;
11695 event.xclient.data.l[2] = detail;
11696 event.xclient.data.l[3] = data1;
11697 event.xclient.data.l[4] = data2;
11698
11699 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_OUTPUT (f)->parent_desc,
11700 False, NoEventMask, &event);
11701 XSync (FRAME_X_DISPLAY (f), False);
11702 }
11703
11704 /* Change of visibility. */
11705
11706 /* This tries to wait until the frame is really visible, depending on
11707 the value of Vx_wait_for_event_timeout.
11708 However, if the window manager asks the user where to position
11709 the frame, this will return before the user finishes doing that.
11710 The frame will not actually be visible at that time,
11711 but it will become visible later when the window manager
11712 finishes with it. */
11713
11714 void
x_make_frame_visible(struct frame * f)11715 x_make_frame_visible (struct frame *f)
11716 {
11717 if (FRAME_PARENT_FRAME (f))
11718 {
11719 if (!FRAME_VISIBLE_P (f))
11720 {
11721 block_input ();
11722 #ifdef USE_GTK
11723 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
11724 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11725 f->left_pos, f->top_pos);
11726 #else
11727 XMapRaised (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
11728 #endif
11729 unblock_input ();
11730
11731 SET_FRAME_VISIBLE (f, true);
11732 SET_FRAME_ICONIFIED (f, false);
11733 }
11734 return;
11735 }
11736
11737 block_input ();
11738
11739 gui_set_bitmap_icon (f);
11740
11741 if (! FRAME_VISIBLE_P (f))
11742 {
11743 /* We test asked_for_visible here to make sure we don't
11744 call x_set_offset a second time
11745 if we get to x_make_frame_visible a second time
11746 before the window gets really visible. */
11747 if (! FRAME_ICONIFIED_P (f)
11748 && ! FRAME_X_EMBEDDED_P (f)
11749 && ! f->output_data.x->asked_for_visible)
11750 x_set_offset (f, f->left_pos, f->top_pos, 0);
11751
11752 f->output_data.x->asked_for_visible = true;
11753
11754 if (! EQ (Vx_no_window_manager, Qt))
11755 x_wm_set_window_state (f, NormalState);
11756 #ifdef USE_X_TOOLKIT
11757 if (FRAME_X_EMBEDDED_P (f))
11758 xembed_set_info (f, XEMBED_MAPPED);
11759 else
11760 {
11761 /* This was XtPopup, but that did nothing for an iconified frame. */
11762 XtMapWidget (f->output_data.x->widget);
11763 }
11764 #else /* not USE_X_TOOLKIT */
11765 #ifdef USE_GTK
11766 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
11767 gtk_window_deiconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
11768 #else
11769 if (FRAME_X_EMBEDDED_P (f))
11770 xembed_set_info (f, XEMBED_MAPPED);
11771 else
11772 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11773 #endif /* not USE_GTK */
11774 #endif /* not USE_X_TOOLKIT */
11775 }
11776
11777 XFlush (FRAME_X_DISPLAY (f));
11778
11779 /* Synchronize to ensure Emacs knows the frame is visible
11780 before we do anything else. We do this loop with input not blocked
11781 so that incoming events are handled. */
11782 {
11783 Lisp_Object frame;
11784 /* This must be before UNBLOCK_INPUT
11785 since events that arrive in response to the actions above
11786 will set it when they are handled. */
11787 bool previously_visible = f->output_data.x->has_been_visible;
11788
11789 XSETFRAME (frame, f);
11790
11791 int original_left = f->left_pos;
11792 int original_top = f->top_pos;
11793
11794 /* This must come after we set COUNT. */
11795 unblock_input ();
11796
11797 /* We unblock here so that arriving X events are processed. */
11798
11799 /* Now move the window back to where it was "supposed to be".
11800 But don't do it if the gravity is negative.
11801 When the gravity is negative, this uses a position
11802 that is 3 pixels too low. Perhaps that's really the border width.
11803
11804 Don't do this if the window has never been visible before,
11805 because the window manager may choose the position
11806 and we don't want to override it. */
11807
11808 if (!FRAME_VISIBLE_P (f)
11809 && !FRAME_ICONIFIED_P (f)
11810 && !FRAME_X_EMBEDDED_P (f)
11811 && !FRAME_PARENT_FRAME (f)
11812 && f->win_gravity == NorthWestGravity
11813 && previously_visible)
11814 {
11815 Drawable rootw;
11816 int x, y;
11817 unsigned int width, height, border, depth;
11818
11819 block_input ();
11820
11821 /* On some window managers (such as FVWM) moving an existing
11822 window, even to the same place, causes the window manager
11823 to introduce an offset. This can cause the window to move
11824 to an unexpected location. Check the geometry (a little
11825 slow here) and then verify that the window is in the right
11826 place. If the window is not in the right place, move it
11827 there, and take the potential window manager hit. */
11828 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11829 &rootw, &x, &y, &width, &height, &border, &depth);
11830
11831 if (original_left != x || original_top != y)
11832 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
11833 original_left, original_top);
11834
11835 unblock_input ();
11836 }
11837
11838 /* Try to wait for a MapNotify event (that is what tells us when a
11839 frame becomes visible). */
11840
11841 #ifdef CYGWIN
11842 /* On Cygwin, which uses input polling, we need to force input to
11843 be read. See
11844 https://lists.gnu.org/r/emacs-devel/2013-12/msg00351.html
11845 and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=24091#131.
11846 Fake an alarm signal to let the handler know that there's
11847 something to be read.
11848
11849 It could be confusing if a real alarm arrives while processing
11850 the fake one. Turn it off and let the handler reset it. */
11851 int old_poll_suppress_count = poll_suppress_count;
11852 poll_suppress_count = 1;
11853 poll_for_input_1 ();
11854 poll_suppress_count = old_poll_suppress_count;
11855 #endif
11856 if (! FRAME_VISIBLE_P (f))
11857 x_wait_for_event (f, MapNotify);
11858 }
11859 }
11860
11861 /* Change from mapped state to withdrawn state. */
11862
11863 /* Make the frame visible (mapped and not iconified). */
11864
11865 void
x_make_frame_invisible(struct frame * f)11866 x_make_frame_invisible (struct frame *f)
11867 {
11868 Window window;
11869
11870 /* Use the frame's outermost window, not the one we normally draw on. */
11871 window = FRAME_OUTER_WINDOW (f);
11872
11873 /* Don't keep the highlight on an invisible frame. */
11874 if (FRAME_DISPLAY_INFO (f)->highlight_frame == f)
11875 FRAME_DISPLAY_INFO (f)->highlight_frame = 0;
11876
11877 block_input ();
11878
11879 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
11880 that the current position of the window is user-specified, rather than
11881 program-specified, so that when the window is mapped again, it will be
11882 placed at the same location, without forcing the user to position it
11883 by hand again (they have already done that once for this window.) */
11884 x_wm_set_size_hint (f, 0, true);
11885
11886 #ifdef USE_GTK
11887 if (FRAME_GTK_OUTER_WIDGET (f))
11888 gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f));
11889 else
11890 #else
11891 if (FRAME_X_EMBEDDED_P (f))
11892 xembed_set_info (f, 0);
11893 else
11894 #endif
11895
11896 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
11897 DefaultScreen (FRAME_X_DISPLAY (f))))
11898 {
11899 unblock_input ();
11900 error ("Can't notify window manager of window withdrawal");
11901 }
11902
11903 x_sync (f);
11904
11905 /* We can't distinguish this from iconification
11906 just by the event that we get from the server.
11907 So we can't win using the usual strategy of letting
11908 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
11909 and synchronize with the server to make sure we agree. */
11910 SET_FRAME_VISIBLE (f, 0);
11911 SET_FRAME_ICONIFIED (f, false);
11912
11913 unblock_input ();
11914 }
11915
11916 static void
x_make_frame_visible_invisible(struct frame * f,bool visible)11917 x_make_frame_visible_invisible (struct frame *f, bool visible)
11918 {
11919 if (visible)
11920 x_make_frame_visible (f);
11921 else
11922 x_make_frame_invisible (f);
11923 }
11924
11925 /* Change window state from mapped to iconified. */
11926
11927 void
x_iconify_frame(struct frame * f)11928 x_iconify_frame (struct frame *f)
11929 {
11930 #ifdef USE_X_TOOLKIT
11931 int result;
11932 #endif
11933
11934 /* Don't keep the highlight on an invisible frame. */
11935 if (FRAME_DISPLAY_INFO (f)->highlight_frame == f)
11936 FRAME_DISPLAY_INFO (f)->highlight_frame = 0;
11937
11938 if (FRAME_ICONIFIED_P (f))
11939 return;
11940
11941 block_input ();
11942
11943 gui_set_bitmap_icon (f);
11944
11945 #if defined (USE_GTK)
11946 if (FRAME_GTK_OUTER_WIDGET (f))
11947 {
11948 if (! FRAME_VISIBLE_P (f))
11949 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
11950
11951 gtk_window_iconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
11952 SET_FRAME_VISIBLE (f, 0);
11953 SET_FRAME_ICONIFIED (f, true);
11954 unblock_input ();
11955 return;
11956 }
11957 #endif
11958
11959 #ifdef USE_X_TOOLKIT
11960
11961 if (! FRAME_VISIBLE_P (f))
11962 {
11963 if (! EQ (Vx_no_window_manager, Qt))
11964 x_wm_set_window_state (f, IconicState);
11965 /* This was XtPopup, but that did nothing for an iconified frame. */
11966 XtMapWidget (f->output_data.x->widget);
11967 /* The server won't give us any event to indicate
11968 that an invisible frame was changed to an icon,
11969 so we have to record it here. */
11970 SET_FRAME_VISIBLE (f, 0);
11971 SET_FRAME_ICONIFIED (f, true);
11972 unblock_input ();
11973 return;
11974 }
11975
11976 result = XIconifyWindow (FRAME_X_DISPLAY (f),
11977 XtWindow (f->output_data.x->widget),
11978 DefaultScreen (FRAME_X_DISPLAY (f)));
11979 unblock_input ();
11980
11981 if (!result)
11982 error ("Can't notify window manager of iconification");
11983
11984 SET_FRAME_ICONIFIED (f, true);
11985 SET_FRAME_VISIBLE (f, 0);
11986
11987 block_input ();
11988 XFlush (FRAME_X_DISPLAY (f));
11989 unblock_input ();
11990 #else /* not USE_X_TOOLKIT */
11991
11992 /* Make sure the X server knows where the window should be positioned,
11993 in case the user deiconifies with the window manager. */
11994 if (! FRAME_VISIBLE_P (f)
11995 && ! FRAME_ICONIFIED_P (f)
11996 && ! FRAME_X_EMBEDDED_P (f))
11997 x_set_offset (f, f->left_pos, f->top_pos, 0);
11998
11999 /* Since we don't know which revision of X we're running, we'll use both
12000 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
12001
12002 /* X11R4: send a ClientMessage to the window manager using the
12003 WM_CHANGE_STATE type. */
12004 {
12005 XEvent msg;
12006
12007 msg.xclient.window = FRAME_X_WINDOW (f);
12008 msg.xclient.type = ClientMessage;
12009 msg.xclient.message_type = FRAME_DISPLAY_INFO (f)->Xatom_wm_change_state;
12010 msg.xclient.format = 32;
12011 msg.xclient.data.l[0] = IconicState;
12012
12013 if (! XSendEvent (FRAME_X_DISPLAY (f),
12014 DefaultRootWindow (FRAME_X_DISPLAY (f)),
12015 False,
12016 SubstructureRedirectMask | SubstructureNotifyMask,
12017 &msg))
12018 {
12019 unblock_input ();
12020 error ("Can't notify window manager of iconification");
12021 }
12022 }
12023
12024 /* X11R3: set the initial_state field of the window manager hints to
12025 IconicState. */
12026 x_wm_set_window_state (f, IconicState);
12027
12028 if (!FRAME_VISIBLE_P (f))
12029 {
12030 /* If the frame was withdrawn, before, we must map it. */
12031 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
12032 }
12033
12034 SET_FRAME_ICONIFIED (f, true);
12035 SET_FRAME_VISIBLE (f, 0);
12036
12037 XFlush (FRAME_X_DISPLAY (f));
12038 unblock_input ();
12039 #endif /* not USE_X_TOOLKIT */
12040 }
12041
12042
12043 /* Free X resources of frame F. */
12044
12045 void
x_free_frame_resources(struct frame * f)12046 x_free_frame_resources (struct frame *f)
12047 {
12048 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
12049 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
12050 #ifdef USE_X_TOOLKIT
12051 Lisp_Object bar;
12052 struct scroll_bar *b;
12053 #endif
12054
12055 block_input ();
12056
12057 /* If a display connection is dead, don't try sending more
12058 commands to the X server. */
12059 if (dpyinfo->display)
12060 {
12061 /* Always exit with visible pointer to avoid weird issue
12062 with Xfixes (Bug#17609). */
12063 if (f->pointer_invisible)
12064 FRAME_DISPLAY_INFO (f)->toggle_visible_pointer (f, 0);
12065
12066 /* We must free faces before destroying windows because some
12067 font-driver (e.g. xft) access a window while finishing a
12068 face. */
12069 free_frame_faces (f);
12070 tear_down_x_back_buffer (f);
12071
12072 if (f->output_data.x->icon_desc)
12073 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
12074
12075 #ifdef USE_X_TOOLKIT
12076 /* Explicitly destroy the scroll bars of the frame. Without
12077 this, we get "BadDrawable" errors from the toolkit later on,
12078 presumably from expose events generated for the disappearing
12079 toolkit scroll bars. */
12080 for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
12081 {
12082 b = XSCROLL_BAR (bar);
12083 x_scroll_bar_remove (b);
12084 }
12085 #endif
12086
12087 #ifdef HAVE_X_I18N
12088 if (FRAME_XIC (f))
12089 free_frame_xic (f);
12090 #endif
12091
12092 #ifdef USE_CAIRO
12093 x_cr_destroy_frame_context (f);
12094 #endif
12095 #ifdef USE_X_TOOLKIT
12096 if (f->output_data.x->widget)
12097 {
12098 XtDestroyWidget (f->output_data.x->widget);
12099 f->output_data.x->widget = NULL;
12100 }
12101 /* Tooltips don't have widgets, only a simple X window, even if
12102 we are using a toolkit. */
12103 else if (FRAME_X_WINDOW (f))
12104 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
12105
12106 free_frame_menubar (f);
12107
12108 if (f->shell_position)
12109 xfree (f->shell_position);
12110 #else /* !USE_X_TOOLKIT */
12111
12112 #ifdef USE_GTK
12113 xg_free_frame_widgets (f);
12114 #endif /* USE_GTK */
12115
12116 tear_down_x_back_buffer (f);
12117 if (FRAME_X_WINDOW (f))
12118 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
12119 #endif /* !USE_X_TOOLKIT */
12120
12121 unload_color (f, FRAME_FOREGROUND_PIXEL (f));
12122 unload_color (f, FRAME_BACKGROUND_PIXEL (f));
12123 unload_color (f, f->output_data.x->cursor_pixel);
12124 unload_color (f, f->output_data.x->cursor_foreground_pixel);
12125 unload_color (f, f->output_data.x->border_pixel);
12126 unload_color (f, f->output_data.x->mouse_pixel);
12127
12128 if (f->output_data.x->scroll_bar_background_pixel != -1)
12129 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
12130 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
12131 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
12132 #if defined (USE_LUCID) && defined (USE_TOOLKIT_SCROLL_BARS)
12133 /* Scrollbar shadow colors. */
12134 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
12135 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
12136 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
12137 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
12138 #endif /* USE_LUCID && USE_TOOLKIT_SCROLL_BARS */
12139 if (f->output_data.x->white_relief.pixel != -1)
12140 unload_color (f, f->output_data.x->white_relief.pixel);
12141 if (f->output_data.x->black_relief.pixel != -1)
12142 unload_color (f, f->output_data.x->black_relief.pixel);
12143
12144 x_free_gcs (f);
12145
12146 /* Free extra GCs allocated by x_setup_relief_colors. */
12147 if (f->output_data.x->white_relief.gc)
12148 {
12149 XFreeGC (dpyinfo->display, f->output_data.x->white_relief.gc);
12150 f->output_data.x->white_relief.gc = 0;
12151 }
12152 if (f->output_data.x->black_relief.gc)
12153 {
12154 XFreeGC (dpyinfo->display, f->output_data.x->black_relief.gc);
12155 f->output_data.x->black_relief.gc = 0;
12156 }
12157
12158 /* Free cursors. */
12159 if (f->output_data.x->text_cursor != 0)
12160 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->text_cursor);
12161 if (f->output_data.x->nontext_cursor != 0)
12162 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->nontext_cursor);
12163 if (f->output_data.x->modeline_cursor != 0)
12164 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->modeline_cursor);
12165 if (f->output_data.x->hand_cursor != 0)
12166 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->hand_cursor);
12167 if (f->output_data.x->hourglass_cursor != 0)
12168 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->hourglass_cursor);
12169 if (f->output_data.x->horizontal_drag_cursor != 0)
12170 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->horizontal_drag_cursor);
12171 if (f->output_data.x->vertical_drag_cursor != 0)
12172 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->vertical_drag_cursor);
12173 if (f->output_data.x->left_edge_cursor != 0)
12174 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->left_edge_cursor);
12175 if (f->output_data.x->top_left_corner_cursor != 0)
12176 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_left_corner_cursor);
12177 if (f->output_data.x->top_edge_cursor != 0)
12178 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_edge_cursor);
12179 if (f->output_data.x->top_right_corner_cursor != 0)
12180 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_right_corner_cursor);
12181 if (f->output_data.x->right_edge_cursor != 0)
12182 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->right_edge_cursor);
12183 if (f->output_data.x->bottom_right_corner_cursor != 0)
12184 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_right_corner_cursor);
12185 if (f->output_data.x->bottom_edge_cursor != 0)
12186 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_edge_cursor);
12187 if (f->output_data.x->bottom_left_corner_cursor != 0)
12188 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_left_corner_cursor);
12189
12190 XFlush (FRAME_X_DISPLAY (f));
12191 }
12192
12193 xfree (f->output_data.x->saved_menu_event);
12194 xfree (f->output_data.x);
12195 f->output_data.x = NULL;
12196
12197 if (f == dpyinfo->x_focus_frame)
12198 dpyinfo->x_focus_frame = 0;
12199 if (f == dpyinfo->x_focus_event_frame)
12200 dpyinfo->x_focus_event_frame = 0;
12201 if (f == dpyinfo->highlight_frame)
12202 dpyinfo->highlight_frame = 0;
12203 if (f == hlinfo->mouse_face_mouse_frame)
12204 reset_mouse_highlight (hlinfo);
12205
12206 unblock_input ();
12207 }
12208
12209
12210 /* Destroy the X window of frame F. */
12211
12212 static void
x_destroy_window(struct frame * f)12213 x_destroy_window (struct frame *f)
12214 {
12215 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
12216
12217 /* If a display connection is dead, don't try sending more
12218 commands to the X server. */
12219 if (dpyinfo->display != 0)
12220 x_free_frame_resources (f);
12221
12222 dpyinfo->reference_count--;
12223 }
12224
12225
12226 /* Setting window manager hints. */
12227
12228 /* Set the normal size hints for the window manager, for frame F.
12229 FLAGS is the flags word to use--or 0 meaning preserve the flags
12230 that the window now has.
12231 If USER_POSITION, set the USPosition
12232 flag (this is useful when FLAGS is 0).
12233 The GTK version is in gtkutils.c. */
12234
12235 #ifndef USE_GTK
12236 void
x_wm_set_size_hint(struct frame * f,long flags,bool user_position)12237 x_wm_set_size_hint (struct frame *f, long flags, bool user_position)
12238 {
12239 XSizeHints size_hints;
12240 Window window = FRAME_OUTER_WINDOW (f);
12241
12242 if (!window)
12243 return;
12244
12245 #ifdef USE_X_TOOLKIT
12246 if (f->output_data.x->widget)
12247 {
12248 widget_update_wm_size_hints (f->output_data.x->widget);
12249 return;
12250 }
12251 #endif
12252
12253 /* Setting PMaxSize caused various problems. */
12254 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
12255
12256 size_hints.x = f->left_pos;
12257 size_hints.y = f->top_pos;
12258
12259 size_hints.width = FRAME_PIXEL_WIDTH (f);
12260 size_hints.height = FRAME_PIXEL_HEIGHT (f);
12261
12262 size_hints.width_inc = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
12263 size_hints.height_inc = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
12264
12265 size_hints.max_width = x_display_pixel_width (FRAME_DISPLAY_INFO (f))
12266 - FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
12267 size_hints.max_height = x_display_pixel_height (FRAME_DISPLAY_INFO (f))
12268 - FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
12269
12270 /* Calculate the base and minimum sizes. */
12271 {
12272 int base_width, base_height;
12273
12274 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
12275 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
12276
12277 /* The window manager uses the base width hints to calculate the
12278 current number of rows and columns in the frame while
12279 resizing; min_width and min_height aren't useful for this
12280 purpose, since they might not give the dimensions for a
12281 zero-row, zero-column frame. */
12282
12283 size_hints.flags |= PBaseSize;
12284 size_hints.base_width = base_width;
12285 size_hints.base_height = base_height + FRAME_MENUBAR_HEIGHT (f);
12286 size_hints.min_width = base_width;
12287 size_hints.min_height = base_height;
12288 }
12289
12290 /* If we don't need the old flags, we don't need the old hint at all. */
12291 if (flags)
12292 {
12293 size_hints.flags |= flags;
12294 goto no_read;
12295 }
12296
12297 {
12298 XSizeHints hints; /* Sometimes I hate X Windows... */
12299 long supplied_return;
12300 int value;
12301
12302 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
12303 &supplied_return);
12304
12305 if (flags)
12306 size_hints.flags |= flags;
12307 else
12308 {
12309 if (value == 0)
12310 hints.flags = 0;
12311 if (hints.flags & PSize)
12312 size_hints.flags |= PSize;
12313 if (hints.flags & PPosition)
12314 size_hints.flags |= PPosition;
12315 if (hints.flags & USPosition)
12316 size_hints.flags |= USPosition;
12317 if (hints.flags & USSize)
12318 size_hints.flags |= USSize;
12319 }
12320 }
12321
12322 no_read:
12323
12324 #ifdef PWinGravity
12325 size_hints.win_gravity = f->win_gravity;
12326 size_hints.flags |= PWinGravity;
12327
12328 if (user_position)
12329 {
12330 size_hints.flags &= ~ PPosition;
12331 size_hints.flags |= USPosition;
12332 }
12333 #endif /* PWinGravity */
12334
12335 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
12336 }
12337 #endif /* not USE_GTK */
12338
12339 /* Used for IconicState or NormalState */
12340
12341 static void
x_wm_set_window_state(struct frame * f,int state)12342 x_wm_set_window_state (struct frame *f, int state)
12343 {
12344 #ifdef USE_X_TOOLKIT
12345 Arg al[1];
12346
12347 XtSetArg (al[0], XtNinitialState, state);
12348 XtSetValues (f->output_data.x->widget, al, 1);
12349 #else /* not USE_X_TOOLKIT */
12350 Window window = FRAME_X_WINDOW (f);
12351
12352 f->output_data.x->wm_hints.flags |= StateHint;
12353 f->output_data.x->wm_hints.initial_state = state;
12354
12355 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
12356 #endif /* not USE_X_TOOLKIT */
12357 }
12358
12359 static void
x_wm_set_icon_pixmap(struct frame * f,ptrdiff_t pixmap_id)12360 x_wm_set_icon_pixmap (struct frame *f, ptrdiff_t pixmap_id)
12361 {
12362 Pixmap icon_pixmap, icon_mask;
12363
12364 #if !defined USE_X_TOOLKIT && !defined USE_GTK
12365 Window window = FRAME_OUTER_WINDOW (f);
12366 #endif
12367
12368 if (pixmap_id > 0)
12369 {
12370 icon_pixmap = image_bitmap_pixmap (f, pixmap_id);
12371 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
12372 icon_mask = x_bitmap_mask (f, pixmap_id);
12373 f->output_data.x->wm_hints.icon_mask = icon_mask;
12374 }
12375 else
12376 {
12377 /* It seems there is no way to turn off use of an icon
12378 pixmap. */
12379 return;
12380 }
12381
12382
12383 #ifdef USE_GTK
12384 {
12385 xg_set_frame_icon (f, icon_pixmap, icon_mask);
12386 return;
12387 }
12388
12389 #elif defined (USE_X_TOOLKIT) /* same as in x_wm_set_window_state. */
12390
12391 {
12392 Arg al[1];
12393 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
12394 XtSetValues (f->output_data.x->widget, al, 1);
12395 XtSetArg (al[0], XtNiconMask, icon_mask);
12396 XtSetValues (f->output_data.x->widget, al, 1);
12397 }
12398
12399 #else /* not USE_X_TOOLKIT && not USE_GTK */
12400
12401 f->output_data.x->wm_hints.flags |= (IconPixmapHint | IconMaskHint);
12402 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
12403
12404 #endif /* not USE_X_TOOLKIT && not USE_GTK */
12405 }
12406
12407 void
x_wm_set_icon_position(struct frame * f,int icon_x,int icon_y)12408 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
12409 {
12410 Window window = FRAME_OUTER_WINDOW (f);
12411
12412 f->output_data.x->wm_hints.flags |= IconPositionHint;
12413 f->output_data.x->wm_hints.icon_x = icon_x;
12414 f->output_data.x->wm_hints.icon_y = icon_y;
12415
12416 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
12417 }
12418
12419
12420 /***********************************************************************
12421 Fonts
12422 ***********************************************************************/
12423
12424 #ifdef GLYPH_DEBUG
12425
12426 /* Check that FONT is valid on frame F. It is if it can be found in F's
12427 font table. */
12428
12429 static void
x_check_font(struct frame * f,struct font * font)12430 x_check_font (struct frame *f, struct font *font)
12431 {
12432 eassert (font != NULL && ! NILP (font->props[FONT_TYPE_INDEX]));
12433 if (font->driver->check)
12434 eassert (font->driver->check (f, font) == 0);
12435 }
12436
12437 #endif /* GLYPH_DEBUG */
12438
12439
12440 /***********************************************************************
12441 Image Hooks
12442 ***********************************************************************/
12443
12444 static void
x_free_pixmap(struct frame * f,Emacs_Pixmap pixmap)12445 x_free_pixmap (struct frame *f, Emacs_Pixmap pixmap)
12446 {
12447 #ifdef USE_CAIRO
12448 if (pixmap)
12449 {
12450 xfree (pixmap->data);
12451 xfree (pixmap);
12452 }
12453 #else
12454 XFreePixmap (FRAME_X_DISPLAY (f), pixmap);
12455 #endif
12456 }
12457
12458
12459 /***********************************************************************
12460 Initialization
12461 ***********************************************************************/
12462
12463 #ifdef USE_X_TOOLKIT
12464 static XrmOptionDescRec emacs_options[] = {
12465 {(char *) "-geometry", (char *) ".geometry", XrmoptionSepArg, NULL},
12466 {(char *) "-iconic", (char *) ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
12467
12468 {(char *) "-internal-border-width",
12469 (char *) "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
12470 {(char *) "-ib", (char *) "*EmacsScreen.internalBorderWidth",
12471 XrmoptionSepArg, NULL},
12472 {(char *) "-T", (char *) "*EmacsShell.title", XrmoptionSepArg, NULL},
12473 {(char *) "-wn", (char *) "*EmacsShell.title", XrmoptionSepArg, NULL},
12474 {(char *) "-title", (char *) "*EmacsShell.title", XrmoptionSepArg, NULL},
12475 {(char *) "-iconname", (char *) "*EmacsShell.iconName",
12476 XrmoptionSepArg, NULL},
12477 {(char *) "-in", (char *) "*EmacsShell.iconName", XrmoptionSepArg, NULL},
12478 {(char *) "-mc", (char *) "*pointerColor", XrmoptionSepArg, NULL},
12479 {(char *) "-cr", (char *) "*cursorColor", XrmoptionSepArg, NULL}
12480 };
12481
12482 /* Whether atimer for Xt timeouts is activated or not. */
12483
12484 static bool x_timeout_atimer_activated_flag;
12485
12486 #endif /* USE_X_TOOLKIT */
12487
12488 static int x_initialized;
12489
12490 /* Test whether two display-name strings agree up to the dot that separates
12491 the screen number from the server number. */
12492 static bool
same_x_server(const char * name1,const char * name2)12493 same_x_server (const char *name1, const char *name2)
12494 {
12495 bool seen_colon = false;
12496 Lisp_Object sysname = Fsystem_name ();
12497 if (! STRINGP (sysname))
12498 sysname = empty_unibyte_string;
12499 const char *system_name = SSDATA (sysname);
12500 ptrdiff_t system_name_length = SBYTES (sysname);
12501 ptrdiff_t length_until_period = 0;
12502
12503 while (system_name[length_until_period] != 0
12504 && system_name[length_until_period] != '.')
12505 length_until_period++;
12506
12507 /* Treat `unix' like an empty host name. */
12508 if (! strncmp (name1, "unix:", 5))
12509 name1 += 4;
12510 if (! strncmp (name2, "unix:", 5))
12511 name2 += 4;
12512 /* Treat this host's name like an empty host name. */
12513 if (! strncmp (name1, system_name, system_name_length)
12514 && name1[system_name_length] == ':')
12515 name1 += system_name_length;
12516 if (! strncmp (name2, system_name, system_name_length)
12517 && name2[system_name_length] == ':')
12518 name2 += system_name_length;
12519 /* Treat this host's domainless name like an empty host name. */
12520 if (! strncmp (name1, system_name, length_until_period)
12521 && name1[length_until_period] == ':')
12522 name1 += length_until_period;
12523 if (! strncmp (name2, system_name, length_until_period)
12524 && name2[length_until_period] == ':')
12525 name2 += length_until_period;
12526
12527 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
12528 {
12529 if (*name1 == ':')
12530 seen_colon = true;
12531 if (seen_colon && *name1 == '.')
12532 return true;
12533 }
12534 return (seen_colon
12535 && (*name1 == '.' || *name1 == '\0')
12536 && (*name2 == '.' || *name2 == '\0'));
12537 }
12538
12539 /* Count number of set bits in mask and number of bits to shift to
12540 get to the first bit. With MASK 0x7e0, *BITS is set to 6, and *OFFSET
12541 to 5. */
12542 static void
get_bits_and_offset(unsigned long mask,int * bits,int * offset)12543 get_bits_and_offset (unsigned long mask, int *bits, int *offset)
12544 {
12545 int nr = 0;
12546 int off = 0;
12547
12548 while (!(mask & 1))
12549 {
12550 off++;
12551 mask >>= 1;
12552 }
12553
12554 while (mask & 1)
12555 {
12556 nr++;
12557 mask >>= 1;
12558 }
12559
12560 *offset = off;
12561 *bits = nr;
12562 }
12563
12564 /* Return true iff display DISPLAY is available for use.
12565 But don't permanently open it, just test its availability. */
12566
12567 bool
x_display_ok(const char * display)12568 x_display_ok (const char *display)
12569 {
12570 /* XOpenDisplay fails if it gets a signal. Block SIGIO which may arrive. */
12571 unrequest_sigio ();
12572 Display *dpy = XOpenDisplay (display);
12573 request_sigio ();
12574 if (!dpy)
12575 return false;
12576 XCloseDisplay (dpy);
12577 return true;
12578 }
12579
12580 #ifdef USE_GTK
12581 static void
my_log_handler(const gchar * log_domain,GLogLevelFlags log_level,const gchar * msg,gpointer user_data)12582 my_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
12583 const gchar *msg, gpointer user_data)
12584 {
12585 if (!strstr (msg, "g_set_prgname"))
12586 fprintf (stderr, "%s-WARNING **: %s\n", log_domain, msg);
12587 }
12588 #endif
12589
12590 /* Create invisible cursor on X display referred by DPYINFO. */
12591
12592 static Cursor
make_invisible_cursor(struct x_display_info * dpyinfo)12593 make_invisible_cursor (struct x_display_info *dpyinfo)
12594 {
12595 Display *dpy = dpyinfo->display;
12596 static char const no_data[] = { 0 };
12597 Pixmap pix;
12598 XColor col;
12599 Cursor c = 0;
12600
12601 x_catch_errors (dpy);
12602 pix = XCreateBitmapFromData (dpy, dpyinfo->root_window, no_data, 1, 1);
12603 if (! x_had_errors_p (dpy) && pix != None)
12604 {
12605 Cursor pixc;
12606 col.pixel = 0;
12607 col.red = col.green = col.blue = 0;
12608 col.flags = DoRed | DoGreen | DoBlue;
12609 pixc = XCreatePixmapCursor (dpy, pix, pix, &col, &col, 0, 0);
12610 if (! x_had_errors_p (dpy) && pixc != None)
12611 c = pixc;
12612 XFreePixmap (dpy, pix);
12613 }
12614
12615 x_uncatch_errors ();
12616
12617 return c;
12618 }
12619
12620 /* True if DPY supports Xfixes extension >= 4. */
12621
12622 static bool
x_probe_xfixes_extension(Display * dpy)12623 x_probe_xfixes_extension (Display *dpy)
12624 {
12625 #ifdef HAVE_XFIXES
12626 int major, minor;
12627 return XFixesQueryVersion (dpy, &major, &minor) && major >= 4;
12628 #else
12629 return false;
12630 #endif /* HAVE_XFIXES */
12631 }
12632
12633 /* Toggle mouse pointer visibility on frame F by using Xfixes functions. */
12634
12635 static void
xfixes_toggle_visible_pointer(struct frame * f,bool invisible)12636 xfixes_toggle_visible_pointer (struct frame *f, bool invisible)
12637 {
12638 #ifdef HAVE_XFIXES
12639 if (invisible)
12640 XFixesHideCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
12641 else
12642 XFixesShowCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
12643 f->pointer_invisible = invisible;
12644 #else
12645 emacs_abort ();
12646 #endif /* HAVE_XFIXES */
12647 }
12648
12649 /* Toggle mouse pointer visibility on frame F by using invisible cursor. */
12650
12651 static void
x_toggle_visible_pointer(struct frame * f,bool invisible)12652 x_toggle_visible_pointer (struct frame *f, bool invisible)
12653 {
12654 eassert (FRAME_DISPLAY_INFO (f)->invisible_cursor != 0);
12655 if (invisible)
12656 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12657 FRAME_DISPLAY_INFO (f)->invisible_cursor);
12658 else
12659 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12660 f->output_data.x->current_cursor);
12661 f->pointer_invisible = invisible;
12662 }
12663
12664 /* Setup pointer blanking, prefer Xfixes if available. */
12665
12666 static void
x_setup_pointer_blanking(struct x_display_info * dpyinfo)12667 x_setup_pointer_blanking (struct x_display_info *dpyinfo)
12668 {
12669 /* FIXME: the brave tester should set EMACS_XFIXES because we're suspecting
12670 X server bug, see https://debbugs.gnu.org/cgi/bugreport.cgi?bug=17609. */
12671 if (egetenv ("EMACS_XFIXES") && x_probe_xfixes_extension (dpyinfo->display))
12672 dpyinfo->toggle_visible_pointer = xfixes_toggle_visible_pointer;
12673 else
12674 {
12675 dpyinfo->toggle_visible_pointer = x_toggle_visible_pointer;
12676 dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo);
12677 }
12678 }
12679
12680 /* Current X display connection identifier. Incremented for each next
12681 connection established. */
12682 static unsigned x_display_id;
12683
12684 /* Open a connection to X display DISPLAY_NAME, and return
12685 the structure that describes the open display.
12686 If we cannot contact the display, return null. */
12687
12688 struct x_display_info *
x_term_init(Lisp_Object display_name,char * xrm_option,char * resource_name)12689 x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
12690 {
12691 Display *dpy;
12692 struct terminal *terminal;
12693 struct x_display_info *dpyinfo;
12694 XrmDatabase xrdb;
12695 #ifdef USE_XCB
12696 xcb_connection_t *xcb_conn;
12697 #endif
12698
12699 block_input ();
12700
12701 if (!x_initialized)
12702 {
12703 x_initialize ();
12704 ++x_initialized;
12705 }
12706
12707 if (! x_display_ok (SSDATA (display_name)))
12708 error ("Display %s can't be opened", SSDATA (display_name));
12709
12710 #ifdef USE_GTK
12711 {
12712 #define NUM_ARGV 10
12713 int argc;
12714 char *argv[NUM_ARGV];
12715 char **argv2 = argv;
12716 guint id;
12717
12718 if (x_initialized++ > 1)
12719 {
12720 xg_display_open (SSDATA (display_name), &dpy);
12721 }
12722 else
12723 {
12724 static char display_opt[] = "--display";
12725 static char name_opt[] = "--name";
12726
12727 for (argc = 0; argc < NUM_ARGV; ++argc)
12728 argv[argc] = 0;
12729
12730 argc = 0;
12731 argv[argc++] = initial_argv[0];
12732
12733 if (! NILP (display_name))
12734 {
12735 argv[argc++] = display_opt;
12736 argv[argc++] = SSDATA (display_name);
12737 }
12738
12739 argv[argc++] = name_opt;
12740 argv[argc++] = resource_name;
12741
12742 XSetLocaleModifiers ("");
12743
12744 /* Work around GLib bug that outputs a faulty warning. See
12745 https://bugzilla.gnome.org/show_bug.cgi?id=563627. */
12746 id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
12747 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
12748
12749 /* NULL window -> events for all windows go to our function.
12750 Call before gtk_init so Gtk+ event filters comes after our. */
12751 gdk_window_add_filter (NULL, event_handler_gdk, NULL);
12752
12753 /* gtk_init does set_locale. Fix locale before and after. */
12754 fixup_locale ();
12755 unrequest_sigio (); /* See comment in x_display_ok. */
12756 gtk_init (&argc, &argv2);
12757 request_sigio ();
12758
12759 g_log_remove_handler ("GLib", id);
12760
12761 xg_initialize ();
12762
12763 /* Do this after the call to xg_initialize, because when
12764 Fontconfig is used, xg_initialize calls its initialization
12765 function which in some versions of Fontconfig calls setlocale. */
12766 fixup_locale ();
12767
12768 dpy = DEFAULT_GDK_DISPLAY ();
12769
12770 #ifndef HAVE_GTK3
12771 /* Load our own gtkrc if it exists. */
12772 {
12773 const char *file = "~/.emacs.d/gtkrc";
12774 Lisp_Object s, abs_file;
12775
12776 s = build_string (file);
12777 abs_file = Fexpand_file_name (s, Qnil);
12778
12779 if (! NILP (abs_file) && !NILP (Ffile_readable_p (abs_file)))
12780 gtk_rc_parse (SSDATA (abs_file));
12781 }
12782 #endif
12783
12784 XSetErrorHandler (x_error_handler);
12785 XSetIOErrorHandler (x_io_error_quitter);
12786 }
12787 }
12788 #else /* not USE_GTK */
12789 #ifdef USE_X_TOOLKIT
12790 /* weiner@footloose.sps.mot.com reports that this causes
12791 errors with X11R5:
12792 X protocol error: BadAtom (invalid Atom parameter)
12793 on protocol request 18skiloaf.
12794 So let's not use it until R6. */
12795 #ifdef HAVE_X11XTR6
12796 XtSetLanguageProc (NULL, NULL, NULL);
12797 #endif
12798
12799 {
12800 int argc = 0;
12801 char *argv[3];
12802
12803 argv[0] = (char *) "";
12804 argc = 1;
12805 if (xrm_option)
12806 {
12807 argv[argc++] = (char *) "-xrm";
12808 argv[argc++] = xrm_option;
12809 }
12810 turn_on_atimers (false);
12811 unrequest_sigio (); /* See comment in x_display_ok. */
12812 dpy = XtOpenDisplay (Xt_app_con, SSDATA (display_name),
12813 resource_name, EMACS_CLASS,
12814 emacs_options, XtNumber (emacs_options),
12815 &argc, argv);
12816 request_sigio ();
12817 turn_on_atimers (true);
12818
12819 #ifdef HAVE_X11XTR6
12820 /* I think this is to compensate for XtSetLanguageProc. */
12821 fixup_locale ();
12822 #endif
12823 }
12824
12825 #else /* not USE_X_TOOLKIT */
12826 XSetLocaleModifiers ("");
12827 unrequest_sigio (); /* See comment in x_display_ok. */
12828 dpy = XOpenDisplay (SSDATA (display_name));
12829 request_sigio ();
12830 #endif /* not USE_X_TOOLKIT */
12831 #endif /* not USE_GTK*/
12832
12833 /* Detect failure. */
12834 if (dpy == 0)
12835 {
12836 unblock_input ();
12837 return 0;
12838 }
12839
12840 #ifdef USE_XCB
12841 xcb_conn = XGetXCBConnection (dpy);
12842 if (xcb_conn == 0)
12843 {
12844 #ifdef USE_GTK
12845 xg_display_close (dpy);
12846 #else
12847 #ifdef USE_X_TOOLKIT
12848 XtCloseDisplay (dpy);
12849 #else
12850 XCloseDisplay (dpy);
12851 #endif
12852 #endif /* ! USE_GTK */
12853
12854 unblock_input ();
12855 return 0;
12856 }
12857 #endif
12858
12859 /* We have definitely succeeded. Record the new connection. */
12860
12861 dpyinfo = xzalloc (sizeof *dpyinfo);
12862 terminal = x_create_terminal (dpyinfo);
12863
12864 {
12865 struct x_display_info *share;
12866
12867 for (share = x_display_list; share; share = share->next)
12868 if (same_x_server (SSDATA (XCAR (share->name_list_element)),
12869 SSDATA (display_name)))
12870 break;
12871 if (share)
12872 terminal->kboard = share->terminal->kboard;
12873 else
12874 {
12875 terminal->kboard = allocate_kboard (Qx);
12876
12877 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->u.s.function, Qunbound))
12878 {
12879 char *vendor = ServerVendor (dpy);
12880
12881 /* Temporarily hide the partially initialized terminal. */
12882 terminal_list = terminal->next_terminal;
12883 unblock_input ();
12884 kset_system_key_alist
12885 (terminal->kboard,
12886 call1 (Qvendor_specific_keysyms,
12887 vendor ? build_string (vendor) : empty_unibyte_string));
12888 block_input ();
12889 terminal->next_terminal = terminal_list;
12890 terminal_list = terminal;
12891 }
12892
12893 /* Don't let the initial kboard remain current longer than necessary.
12894 That would cause problems if a file loaded on startup tries to
12895 prompt in the mini-buffer. */
12896 if (current_kboard == initial_kboard)
12897 current_kboard = terminal->kboard;
12898 }
12899 terminal->kboard->reference_count++;
12900 }
12901
12902 /* Put this display on the chain. */
12903 dpyinfo->next = x_display_list;
12904 x_display_list = dpyinfo;
12905
12906 dpyinfo->name_list_element = Fcons (display_name, Qnil);
12907 dpyinfo->display = dpy;
12908 dpyinfo->connection = ConnectionNumber (dpyinfo->display);
12909 #ifdef USE_XCB
12910 dpyinfo->xcb_connection = xcb_conn;
12911 #endif
12912
12913 /* https://lists.gnu.org/r/emacs-devel/2015-11/msg00194.html */
12914 dpyinfo->smallest_font_height = 1;
12915 dpyinfo->smallest_char_width = 1;
12916
12917 /* Set the name of the terminal. */
12918 terminal->name = xlispstrdup (display_name);
12919
12920 #if false
12921 XSetAfterFunction (x_current_display, x_trace_wire);
12922 #endif
12923
12924 Lisp_Object system_name = Fsystem_name ();
12925
12926 ptrdiff_t nbytes = SBYTES (Vinvocation_name) + 1;
12927 if (STRINGP (system_name)
12928 && INT_ADD_WRAPV (nbytes, SBYTES (system_name) + 1, &nbytes))
12929 memory_full (SIZE_MAX);
12930 dpyinfo->x_id = ++x_display_id;
12931 dpyinfo->x_id_name = xmalloc (nbytes);
12932 char *nametail = lispstpcpy (dpyinfo->x_id_name, Vinvocation_name);
12933 if (STRINGP (system_name))
12934 {
12935 *nametail++ = '@';
12936 lispstpcpy (nametail, system_name);
12937 }
12938
12939 /* Figure out which modifier bits mean what. */
12940 x_find_modifier_meanings (dpyinfo);
12941
12942 /* Get the scroll bar cursor. */
12943 #ifdef USE_GTK
12944 /* We must create a GTK cursor, it is required for GTK widgets. */
12945 dpyinfo->xg_cursor = xg_create_default_cursor (dpyinfo->display);
12946 #endif /* USE_GTK */
12947
12948 dpyinfo->vertical_scroll_bar_cursor
12949 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
12950
12951 dpyinfo->horizontal_scroll_bar_cursor
12952 = XCreateFontCursor (dpyinfo->display, XC_sb_h_double_arrow);
12953
12954 xrdb = x_load_resources (dpyinfo->display, xrm_option,
12955 resource_name, EMACS_CLASS);
12956 #ifdef HAVE_XRMSETDATABASE
12957 XrmSetDatabase (dpyinfo->display, xrdb);
12958 #else
12959 dpyinfo->display->db = xrdb;
12960 #endif
12961 /* Put the rdb where we can find it in a way that works on
12962 all versions. */
12963 dpyinfo->rdb = xrdb;
12964
12965 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
12966 DefaultScreen (dpyinfo->display));
12967 select_visual (dpyinfo);
12968 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
12969 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
12970 dpyinfo->icon_bitmap_id = -1;
12971 dpyinfo->wm_type = X_WMTYPE_UNKNOWN;
12972
12973 reset_mouse_highlight (&dpyinfo->mouse_highlight);
12974
12975 /* See if we can construct pixel values from RGB values. */
12976 if (dpyinfo->visual->class == TrueColor)
12977 {
12978 get_bits_and_offset (dpyinfo->visual->red_mask,
12979 &dpyinfo->red_bits, &dpyinfo->red_offset);
12980 get_bits_and_offset (dpyinfo->visual->blue_mask,
12981 &dpyinfo->blue_bits, &dpyinfo->blue_offset);
12982 get_bits_and_offset (dpyinfo->visual->green_mask,
12983 &dpyinfo->green_bits, &dpyinfo->green_offset);
12984 }
12985
12986 /* See if a private colormap is requested. */
12987 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
12988 {
12989 if (dpyinfo->visual->class == PseudoColor)
12990 {
12991 AUTO_STRING (privateColormap, "privateColormap");
12992 AUTO_STRING (PrivateColormap, "PrivateColormap");
12993 Lisp_Object value
12994 = gui_display_get_resource (dpyinfo, privateColormap,
12995 PrivateColormap, Qnil, Qnil);
12996 if (STRINGP (value)
12997 && (!strcmp (SSDATA (value), "true")
12998 || !strcmp (SSDATA (value), "on")))
12999 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
13000 }
13001 }
13002 else
13003 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
13004 dpyinfo->visual, AllocNone);
13005
13006 #ifdef HAVE_XDBE
13007 dpyinfo->supports_xdbe = false;
13008 int xdbe_major;
13009 int xdbe_minor;
13010 if (XdbeQueryExtension (dpyinfo->display, &xdbe_major, &xdbe_minor))
13011 dpyinfo->supports_xdbe = true;
13012 #endif
13013
13014 #if defined USE_CAIRO || defined HAVE_XFT
13015 {
13016 /* If we are using Xft, the following precautions should be made:
13017
13018 1. Make sure that the Xrender extension is added before the Xft one.
13019 Otherwise, the close-display hook set by Xft is called after the one
13020 for Xrender, and the former tries to re-add the latter. This results
13021 in inconsistency of internal states and leads to X protocol error when
13022 one reconnects to the same X server (Bug#1696).
13023
13024 2. Check dpi value in X resources. It is better we use it as well,
13025 since Xft will use it, as will all Gnome applications. If our real DPI
13026 is smaller or larger than the one Xft uses, our font will look smaller
13027 or larger than other for other applications, even if it is the same
13028 font name (monospace-10 for example). */
13029
13030 int event_base, error_base;
13031 char *v;
13032 double d;
13033
13034 XRenderQueryExtension (dpyinfo->display, &event_base, &error_base);
13035
13036 v = XGetDefault (dpyinfo->display, "Xft", "dpi");
13037 if (v != NULL && sscanf (v, "%lf", &d) == 1)
13038 dpyinfo->resy = dpyinfo->resx = d;
13039 }
13040 #endif
13041
13042 if (dpyinfo->resy < 1)
13043 {
13044 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
13045 double pixels = DisplayHeight (dpyinfo->display, screen_number);
13046 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
13047 /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
13048 dpyinfo->resy = (mm < 1) ? 100 : pixels * 25.4 / mm;
13049 pixels = DisplayWidth (dpyinfo->display, screen_number);
13050 mm = DisplayWidthMM (dpyinfo->display, screen_number);
13051 /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
13052 dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm;
13053 }
13054
13055 {
13056 static const struct
13057 {
13058 const char *name;
13059 int offset;
13060 } atom_refs[] = {
13061 #define ATOM_REFS_INIT(string, member) \
13062 { string, offsetof (struct x_display_info, member) },
13063 ATOM_REFS_INIT ("WM_PROTOCOLS", Xatom_wm_protocols)
13064 ATOM_REFS_INIT ("WM_TAKE_FOCUS", Xatom_wm_take_focus)
13065 ATOM_REFS_INIT ("WM_SAVE_YOURSELF", Xatom_wm_save_yourself)
13066 ATOM_REFS_INIT ("WM_DELETE_WINDOW", Xatom_wm_delete_window)
13067 ATOM_REFS_INIT ("WM_CHANGE_STATE", Xatom_wm_change_state)
13068 ATOM_REFS_INIT ("WM_CONFIGURE_DENIED", Xatom_wm_configure_denied)
13069 ATOM_REFS_INIT ("WM_MOVED", Xatom_wm_window_moved)
13070 ATOM_REFS_INIT ("WM_CLIENT_LEADER", Xatom_wm_client_leader)
13071 ATOM_REFS_INIT ("Editres", Xatom_editres)
13072 ATOM_REFS_INIT ("CLIPBOARD", Xatom_CLIPBOARD)
13073 ATOM_REFS_INIT ("TIMESTAMP", Xatom_TIMESTAMP)
13074 ATOM_REFS_INIT ("TEXT", Xatom_TEXT)
13075 ATOM_REFS_INIT ("COMPOUND_TEXT", Xatom_COMPOUND_TEXT)
13076 ATOM_REFS_INIT ("UTF8_STRING", Xatom_UTF8_STRING)
13077 ATOM_REFS_INIT ("DELETE", Xatom_DELETE)
13078 ATOM_REFS_INIT ("MULTIPLE", Xatom_MULTIPLE)
13079 ATOM_REFS_INIT ("INCR", Xatom_INCR)
13080 ATOM_REFS_INIT ("_EMACS_TMP_", Xatom_EMACS_TMP)
13081 ATOM_REFS_INIT ("TARGETS", Xatom_TARGETS)
13082 ATOM_REFS_INIT ("NULL", Xatom_NULL)
13083 ATOM_REFS_INIT ("ATOM", Xatom_ATOM)
13084 ATOM_REFS_INIT ("ATOM_PAIR", Xatom_ATOM_PAIR)
13085 ATOM_REFS_INIT ("CLIPBOARD_MANAGER", Xatom_CLIPBOARD_MANAGER)
13086 ATOM_REFS_INIT ("_XEMBED_INFO", Xatom_XEMBED_INFO)
13087 /* For properties of font. */
13088 ATOM_REFS_INIT ("PIXEL_SIZE", Xatom_PIXEL_SIZE)
13089 ATOM_REFS_INIT ("AVERAGE_WIDTH", Xatom_AVERAGE_WIDTH)
13090 ATOM_REFS_INIT ("_MULE_BASELINE_OFFSET", Xatom_MULE_BASELINE_OFFSET)
13091 ATOM_REFS_INIT ("_MULE_RELATIVE_COMPOSE", Xatom_MULE_RELATIVE_COMPOSE)
13092 ATOM_REFS_INIT ("_MULE_DEFAULT_ASCENT", Xatom_MULE_DEFAULT_ASCENT)
13093 /* Ghostscript support. */
13094 ATOM_REFS_INIT ("DONE", Xatom_DONE)
13095 ATOM_REFS_INIT ("PAGE", Xatom_PAGE)
13096 ATOM_REFS_INIT ("SCROLLBAR", Xatom_Scrollbar)
13097 ATOM_REFS_INIT ("HORIZONTAL_SCROLLBAR", Xatom_Horizontal_Scrollbar)
13098 ATOM_REFS_INIT ("_XEMBED", Xatom_XEMBED)
13099 /* EWMH */
13100 ATOM_REFS_INIT ("_NET_WM_STATE", Xatom_net_wm_state)
13101 ATOM_REFS_INIT ("_NET_WM_STATE_FULLSCREEN", Xatom_net_wm_state_fullscreen)
13102 ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_HORZ",
13103 Xatom_net_wm_state_maximized_horz)
13104 ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_VERT",
13105 Xatom_net_wm_state_maximized_vert)
13106 ATOM_REFS_INIT ("_NET_WM_STATE_STICKY", Xatom_net_wm_state_sticky)
13107 ATOM_REFS_INIT ("_NET_WM_STATE_HIDDEN", Xatom_net_wm_state_hidden)
13108 ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE", Xatom_net_window_type)
13109 ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE_TOOLTIP",
13110 Xatom_net_window_type_tooltip)
13111 ATOM_REFS_INIT ("_NET_WM_ICON_NAME", Xatom_net_wm_icon_name)
13112 ATOM_REFS_INIT ("_NET_WM_NAME", Xatom_net_wm_name)
13113 ATOM_REFS_INIT ("_NET_SUPPORTED", Xatom_net_supported)
13114 ATOM_REFS_INIT ("_NET_SUPPORTING_WM_CHECK", Xatom_net_supporting_wm_check)
13115 ATOM_REFS_INIT ("_NET_WM_WINDOW_OPACITY", Xatom_net_wm_window_opacity)
13116 ATOM_REFS_INIT ("_NET_ACTIVE_WINDOW", Xatom_net_active_window)
13117 ATOM_REFS_INIT ("_NET_FRAME_EXTENTS", Xatom_net_frame_extents)
13118 ATOM_REFS_INIT ("_NET_CURRENT_DESKTOP", Xatom_net_current_desktop)
13119 ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea)
13120 /* Session management */
13121 ATOM_REFS_INIT ("SM_CLIENT_ID", Xatom_SM_CLIENT_ID)
13122 ATOM_REFS_INIT ("_XSETTINGS_SETTINGS", Xatom_xsettings_prop)
13123 ATOM_REFS_INIT ("MANAGER", Xatom_xsettings_mgr)
13124 ATOM_REFS_INIT ("_NET_WM_STATE_SKIP_TASKBAR", Xatom_net_wm_state_skip_taskbar)
13125 ATOM_REFS_INIT ("_NET_WM_STATE_ABOVE", Xatom_net_wm_state_above)
13126 ATOM_REFS_INIT ("_NET_WM_STATE_BELOW", Xatom_net_wm_state_below)
13127 };
13128
13129 int i;
13130 enum { atom_count = ARRAYELTS (atom_refs) };
13131 /* 1 for _XSETTINGS_SN. */
13132 enum { total_atom_count = 1 + atom_count };
13133 Atom atoms_return[total_atom_count];
13134 char *atom_names[total_atom_count];
13135 static char const xsettings_fmt[] = "_XSETTINGS_S%d";
13136 char xsettings_atom_name[sizeof xsettings_fmt - 2
13137 + INT_STRLEN_BOUND (int)];
13138
13139 for (i = 0; i < atom_count; i++)
13140 atom_names[i] = (char *) atom_refs[i].name;
13141
13142 /* Build _XSETTINGS_SN atom name. */
13143 sprintf (xsettings_atom_name, xsettings_fmt,
13144 XScreenNumberOfScreen (dpyinfo->screen));
13145 atom_names[i] = xsettings_atom_name;
13146
13147 XInternAtoms (dpyinfo->display, atom_names, total_atom_count,
13148 False, atoms_return);
13149
13150 for (i = 0; i < atom_count; i++)
13151 *(Atom *) ((char *) dpyinfo + atom_refs[i].offset) = atoms_return[i];
13152
13153 /* Manually copy last atom. */
13154 dpyinfo->Xatom_xsettings_sel = atoms_return[i];
13155 }
13156
13157 dpyinfo->x_dnd_atoms_size = 8;
13158 dpyinfo->x_dnd_atoms = xmalloc (sizeof *dpyinfo->x_dnd_atoms
13159 * dpyinfo->x_dnd_atoms_size);
13160 dpyinfo->gray
13161 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13162 gray_bits, gray_width, gray_height,
13163 1, 0, 1);
13164
13165 x_setup_pointer_blanking (dpyinfo);
13166
13167 #ifdef HAVE_X_I18N
13168 xim_initialize (dpyinfo, resource_name);
13169 #endif
13170
13171 xsettings_initialize (dpyinfo);
13172
13173 /* This is only needed for distinguishing keyboard and process input. */
13174 if (dpyinfo->connection != 0)
13175 add_keyboard_wait_descriptor (dpyinfo->connection);
13176
13177 #ifdef F_SETOWN
13178 fcntl (dpyinfo->connection, F_SETOWN, getpid ());
13179 #endif /* ! defined (F_SETOWN) */
13180
13181 if (interrupt_input)
13182 init_sigio (dpyinfo->connection);
13183
13184 #ifdef USE_LUCID
13185 {
13186 XrmValue d, fr, to;
13187 Font font;
13188
13189 dpy = dpyinfo->display;
13190 d.addr = (XPointer)&dpy;
13191 d.size = sizeof (Display *);
13192 fr.addr = (char *) XtDefaultFont;
13193 fr.size = sizeof (XtDefaultFont);
13194 to.size = sizeof (Font *);
13195 to.addr = (XPointer)&font;
13196 x_catch_errors (dpy);
13197 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
13198 emacs_abort ();
13199 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
13200 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
13201 /* Do not free XFontStruct returned by the above call to XQueryFont.
13202 This leads to X protocol errors at XtCloseDisplay (Bug#18403). */
13203 x_uncatch_errors ();
13204 }
13205 #endif
13206
13207 /* See if we should run in synchronous mode. This is useful
13208 for debugging X code. */
13209 {
13210 AUTO_STRING (synchronous, "synchronous");
13211 AUTO_STRING (Synchronous, "Synchronous");
13212 Lisp_Object value = gui_display_get_resource (dpyinfo, synchronous,
13213 Synchronous, Qnil, Qnil);
13214 if (STRINGP (value)
13215 && (!strcmp (SSDATA (value), "true")
13216 || !strcmp (SSDATA (value), "on")))
13217 XSynchronize (dpyinfo->display, True);
13218 }
13219
13220 {
13221 AUTO_STRING (useXIM, "useXIM");
13222 AUTO_STRING (UseXIM, "UseXIM");
13223 Lisp_Object value = gui_display_get_resource (dpyinfo, useXIM, UseXIM,
13224 Qnil, Qnil);
13225 #ifdef USE_XIM
13226 if (STRINGP (value)
13227 && (!strcmp (SSDATA (value), "false")
13228 || !strcmp (SSDATA (value), "off")))
13229 use_xim = false;
13230 #else
13231 if (STRINGP (value)
13232 && (!strcmp (SSDATA (value), "true")
13233 || !strcmp (SSDATA (value), "on")))
13234 use_xim = true;
13235 #endif
13236 }
13237
13238 #ifdef HAVE_X_SM
13239 /* Only do this for the very first display in the Emacs session.
13240 Ignore X session management when Emacs was first started on a
13241 tty or started as a daemon. */
13242 if (terminal->id == 1 && ! IS_DAEMON)
13243 x_session_initialize (dpyinfo);
13244 #endif
13245
13246 #ifdef USE_CAIRO
13247 x_extension_initialize (dpyinfo);
13248 #endif
13249
13250 unblock_input ();
13251
13252 return dpyinfo;
13253 }
13254
13255 /* Get rid of display DPYINFO, deleting all frames on it,
13256 and without sending any more commands to the X server. */
13257
13258 static void
x_delete_display(struct x_display_info * dpyinfo)13259 x_delete_display (struct x_display_info *dpyinfo)
13260 {
13261 struct terminal *t;
13262 struct color_name_cache_entry *color_entry, *next_color_entry;
13263
13264 /* Close all frames and delete the generic struct terminal for this
13265 X display. */
13266 for (t = terminal_list; t; t = t->next_terminal)
13267 if (t->type == output_x_window && t->display_info.x == dpyinfo)
13268 {
13269 #ifdef HAVE_X_SM
13270 /* Close X session management when we close its display. */
13271 if (t->id == 1 && x_session_have_connection ())
13272 x_session_close ();
13273 #endif
13274 delete_terminal (t);
13275 break;
13276 }
13277
13278 if (next_noop_dpyinfo == dpyinfo)
13279 next_noop_dpyinfo = dpyinfo->next;
13280
13281 if (x_display_list == dpyinfo)
13282 x_display_list = dpyinfo->next;
13283 else
13284 {
13285 struct x_display_info *tail;
13286
13287 for (tail = x_display_list; tail; tail = tail->next)
13288 if (tail->next == dpyinfo)
13289 tail->next = tail->next->next;
13290 }
13291
13292 for (color_entry = dpyinfo->color_names;
13293 color_entry;
13294 color_entry = next_color_entry)
13295 {
13296 next_color_entry = color_entry->next;
13297 xfree (color_entry->name);
13298 xfree (color_entry);
13299 }
13300
13301 xfree (dpyinfo->x_id_name);
13302 xfree (dpyinfo->x_dnd_atoms);
13303 xfree (dpyinfo->color_cells);
13304 xfree (dpyinfo);
13305 }
13306
13307 #ifdef USE_X_TOOLKIT
13308
13309 /* Atimer callback function for TIMER. Called every 0.1s to process
13310 Xt timeouts, if needed. We must avoid calling XtAppPending as
13311 much as possible because that function does an implicit XFlush
13312 that slows us down. */
13313
13314 static void
x_process_timeouts(struct atimer * timer)13315 x_process_timeouts (struct atimer *timer)
13316 {
13317 block_input ();
13318 x_timeout_atimer_activated_flag = false;
13319 if (toolkit_scroll_bar_interaction || popup_activated ())
13320 {
13321 while (XtAppPending (Xt_app_con) & XtIMTimer)
13322 XtAppProcessEvent (Xt_app_con, XtIMTimer);
13323 /* Reactivate the atimer for next time. */
13324 x_activate_timeout_atimer ();
13325 }
13326 unblock_input ();
13327 }
13328
13329 /* Install an asynchronous timer that processes Xt timeout events
13330 every 0.1s as long as either `toolkit_scroll_bar_interaction' or
13331 `popup_activated_flag' (in xmenu.c) is set. Make sure to call this
13332 function whenever these variables are set. This is necessary
13333 because some widget sets use timeouts internally, for example the
13334 LessTif menu bar, or the Xaw3d scroll bar. When Xt timeouts aren't
13335 processed, these widgets don't behave normally. */
13336
13337 void
x_activate_timeout_atimer(void)13338 x_activate_timeout_atimer (void)
13339 {
13340 block_input ();
13341 if (!x_timeout_atimer_activated_flag)
13342 {
13343 struct timespec interval = make_timespec (0, 100 * 1000 * 1000);
13344 start_atimer (ATIMER_RELATIVE, interval, x_process_timeouts, 0);
13345 x_timeout_atimer_activated_flag = true;
13346 }
13347 unblock_input ();
13348 }
13349
13350 #endif /* USE_X_TOOLKIT */
13351
13352
13353 /* Set up use of X before we make the first connection. */
13354
13355 extern frame_parm_handler x_frame_parm_handlers[];
13356
13357 static struct redisplay_interface x_redisplay_interface =
13358 {
13359 x_frame_parm_handlers,
13360 gui_produce_glyphs,
13361 gui_write_glyphs,
13362 gui_insert_glyphs,
13363 gui_clear_end_of_line,
13364 x_scroll_run,
13365 x_after_update_window_line,
13366 NULL, /* update_window_begin */
13367 NULL, /* update_window_end */
13368 x_flip_and_flush,
13369 gui_clear_window_mouse_face,
13370 gui_get_glyph_overhangs,
13371 gui_fix_overlapping_area,
13372 x_draw_fringe_bitmap,
13373 #ifdef USE_CAIRO
13374 x_cr_define_fringe_bitmap,
13375 x_cr_destroy_fringe_bitmap,
13376 #else
13377 0, /* define_fringe_bitmap */
13378 0, /* destroy_fringe_bitmap */
13379 #endif
13380 x_compute_glyph_string_overhangs,
13381 x_draw_glyph_string,
13382 x_define_frame_cursor,
13383 x_clear_frame_area,
13384 x_clear_under_internal_border,
13385 x_draw_window_cursor,
13386 x_draw_vertical_window_border,
13387 x_draw_window_divider,
13388 x_shift_glyphs_for_insert, /* Never called; see comment in function. */
13389 x_show_hourglass,
13390 x_hide_hourglass,
13391 x_default_font_parameter
13392 };
13393
13394
13395 /* This function is called when the last frame on a display is deleted. */
13396 void
x_delete_terminal(struct terminal * terminal)13397 x_delete_terminal (struct terminal *terminal)
13398 {
13399 struct x_display_info *dpyinfo = terminal->display_info.x;
13400
13401 /* Protect against recursive calls. delete_frame in
13402 delete_terminal calls us back when it deletes our last frame. */
13403 if (!terminal->name)
13404 return;
13405
13406 block_input ();
13407 #ifdef HAVE_X_I18N
13408 /* We must close our connection to the XIM server before closing the
13409 X display. */
13410 if (dpyinfo->xim)
13411 xim_close_dpy (dpyinfo);
13412 #endif
13413
13414 /* Normally, the display is available... */
13415 if (dpyinfo->display)
13416 {
13417 image_destroy_all_bitmaps (dpyinfo);
13418 XSetCloseDownMode (dpyinfo->display, DestroyAll);
13419
13420 /* Whether or not XCloseDisplay destroys the associated resource
13421 database depends on the version of libX11. To avoid both
13422 crash and memory leak, we dissociate the database from the
13423 display and then destroy dpyinfo->rdb ourselves.
13424
13425 Unfortunately, the above strategy does not work in some
13426 situations due to a bug in newer versions of libX11: because
13427 XrmSetDatabase doesn't clear the flag XlibDisplayDfltRMDB if
13428 dpy->db is NULL, XCloseDisplay destroys the associated
13429 database whereas it has not been created by XGetDefault
13430 (Bug#21974 in freedesktop.org Bugzilla). As a workaround, we
13431 don't destroy the database here in order to avoid the crash
13432 in the above situations for now, though that may cause memory
13433 leaks in other situations. */
13434 #if false
13435 #ifdef HAVE_XRMSETDATABASE
13436 XrmSetDatabase (dpyinfo->display, NULL);
13437 #else
13438 dpyinfo->display->db = NULL;
13439 #endif
13440 /* We used to call XrmDestroyDatabase from x_delete_display, but
13441 some older versions of libX11 crash if we call it after
13442 closing all the displays. */
13443 XrmDestroyDatabase (dpyinfo->rdb);
13444 #endif
13445
13446 #ifdef USE_GTK
13447 xg_display_close (dpyinfo->display);
13448 #else
13449 #ifdef USE_X_TOOLKIT
13450 XtCloseDisplay (dpyinfo->display);
13451 #else
13452 XCloseDisplay (dpyinfo->display);
13453 #endif
13454 #endif /* ! USE_GTK */
13455 /* Do not close the connection here because it's already closed
13456 by X(t)CloseDisplay (Bug#18403). */
13457 dpyinfo->display = NULL;
13458 }
13459
13460 /* ...but if called from x_connection_closed, the display may already
13461 be closed and dpyinfo->display was set to 0 to indicate that. Since
13462 X server is most likely gone, explicit close is the only reliable
13463 way to continue and avoid Bug#19147. */
13464 else if (dpyinfo->connection >= 0)
13465 emacs_close (dpyinfo->connection);
13466
13467 /* No more input on this descriptor. */
13468 delete_keyboard_wait_descriptor (dpyinfo->connection);
13469 /* Mark as dead. */
13470 dpyinfo->connection = -1;
13471
13472 x_delete_display (dpyinfo);
13473 unblock_input ();
13474 }
13475
13476 /* Create a struct terminal, initialize it with the X11 specific
13477 functions and make DISPLAY->TERMINAL point to it. */
13478
13479 static struct terminal *
x_create_terminal(struct x_display_info * dpyinfo)13480 x_create_terminal (struct x_display_info *dpyinfo)
13481 {
13482 struct terminal *terminal;
13483
13484 terminal = create_terminal (output_x_window, &x_redisplay_interface);
13485
13486 terminal->display_info.x = dpyinfo;
13487 dpyinfo->terminal = terminal;
13488
13489 /* kboard is initialized in x_term_init. */
13490
13491 terminal->clear_frame_hook = x_clear_frame;
13492 terminal->ins_del_lines_hook = x_ins_del_lines;
13493 terminal->delete_glyphs_hook = x_delete_glyphs;
13494 terminal->ring_bell_hook = XTring_bell;
13495 terminal->toggle_invisible_pointer_hook = XTtoggle_invisible_pointer;
13496 terminal->update_begin_hook = x_update_begin;
13497 terminal->update_end_hook = x_update_end;
13498 terminal->read_socket_hook = XTread_socket;
13499 terminal->frame_up_to_date_hook = XTframe_up_to_date;
13500 terminal->buffer_flipping_unblocked_hook = XTbuffer_flipping_unblocked_hook;
13501 terminal->defined_color_hook = x_defined_color;
13502 terminal->query_frame_background_color = x_query_frame_background_color;
13503 terminal->query_colors = x_query_colors;
13504 terminal->mouse_position_hook = XTmouse_position;
13505 terminal->get_focus_frame = x_get_focus_frame;
13506 terminal->focus_frame_hook = x_focus_frame;
13507 terminal->frame_rehighlight_hook = XTframe_rehighlight;
13508 terminal->frame_raise_lower_hook = XTframe_raise_lower;
13509 terminal->frame_visible_invisible_hook = x_make_frame_visible_invisible;
13510 terminal->fullscreen_hook = XTfullscreen_hook;
13511 terminal->iconify_frame_hook = x_iconify_frame;
13512 terminal->set_window_size_hook = x_set_window_size;
13513 terminal->set_frame_offset_hook = x_set_offset;
13514 terminal->set_frame_alpha_hook = x_set_frame_alpha;
13515 terminal->set_new_font_hook = x_new_font;
13516 terminal->set_bitmap_icon_hook = x_bitmap_icon;
13517 terminal->implicit_set_name_hook = x_implicitly_set_name;
13518 terminal->menu_show_hook = x_menu_show;
13519 #ifdef HAVE_EXT_MENU_BAR
13520 terminal->activate_menubar_hook = x_activate_menubar;
13521 #endif
13522 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
13523 terminal->popup_dialog_hook = xw_popup_dialog;
13524 #endif
13525 terminal->change_tab_bar_height_hook = x_change_tab_bar_height;
13526 #ifndef HAVE_EXT_TOOL_BAR
13527 terminal->change_tool_bar_height_hook = x_change_tool_bar_height;
13528 #endif
13529 terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
13530 terminal->set_horizontal_scroll_bar_hook = XTset_horizontal_scroll_bar;
13531 terminal->set_scroll_bar_default_width_hook = x_set_scroll_bar_default_width;
13532 terminal->set_scroll_bar_default_height_hook = x_set_scroll_bar_default_height;
13533 terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
13534 terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
13535 terminal->judge_scroll_bars_hook = XTjudge_scroll_bars;
13536 terminal->get_string_resource_hook = x_get_string_resource;
13537 terminal->free_pixmap = x_free_pixmap;
13538 terminal->delete_frame_hook = x_destroy_window;
13539 terminal->delete_terminal_hook = x_delete_terminal;
13540 /* Other hooks are NULL by default. */
13541
13542 return terminal;
13543 }
13544
13545 static void
x_initialize(void)13546 x_initialize (void)
13547 {
13548 baud_rate = 19200;
13549
13550 x_noop_count = 0;
13551 any_help_event_p = false;
13552 ignore_next_mouse_click_timeout = 0;
13553
13554 #ifdef USE_GTK
13555 current_count = -1;
13556 #endif
13557
13558 /* Try to use interrupt input; if we can't, then start polling. */
13559 Fset_input_interrupt_mode (Qt);
13560
13561 #if THREADS_ENABLED
13562 /* This must be called before any other Xlib routines. */
13563 if (XInitThreads () == 0)
13564 fputs ("Warning: An error occurred initializing X11 thread support!\n",
13565 stderr);
13566 #endif
13567
13568 #ifdef USE_X_TOOLKIT
13569 XtToolkitInitialize ();
13570
13571 Xt_app_con = XtCreateApplicationContext ();
13572
13573 /* Register a converter from strings to pixels, which uses
13574 Emacs' color allocation infrastructure. */
13575 XtAppSetTypeConverter (Xt_app_con,
13576 XtRString, XtRPixel, cvt_string_to_pixel,
13577 cvt_string_to_pixel_args,
13578 XtNumber (cvt_string_to_pixel_args),
13579 XtCacheByDisplay, cvt_pixel_dtor);
13580
13581 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
13582 #endif
13583
13584 #ifdef USE_TOOLKIT_SCROLL_BARS
13585 #ifndef USE_GTK
13586 xaw3d_arrow_scroll = False;
13587 xaw3d_pick_top = True;
13588 #endif
13589 #endif
13590
13591 #ifdef USE_CAIRO
13592 gui_init_fringe (&x_redisplay_interface);
13593 #endif
13594
13595 /* Note that there is no real way portable across R3/R4 to get the
13596 original error handler. */
13597 XSetErrorHandler (x_error_handler);
13598 XSetIOErrorHandler (x_io_error_quitter);
13599 }
13600
13601 #ifdef USE_GTK
13602 void
init_xterm(void)13603 init_xterm (void)
13604 {
13605 /* Emacs can handle only core input events, so make sure
13606 Gtk doesn't use Xinput or Xinput2 extensions. */
13607 xputenv ("GDK_CORE_DEVICE_EVENTS=1");
13608 }
13609 #endif
13610
13611 void
syms_of_xterm(void)13612 syms_of_xterm (void)
13613 {
13614 x_error_message = NULL;
13615 PDUMPER_IGNORE (x_error_message);
13616
13617 DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
13618 DEFSYM (Qlatin_1, "latin-1");
13619
13620 #ifdef USE_GTK
13621 xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
13622 staticpro (&xg_default_icon_file);
13623
13624 DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock");
13625 #endif
13626
13627 DEFVAR_BOOL ("x-use-underline-position-properties",
13628 x_use_underline_position_properties,
13629 doc: /* Non-nil means make use of UNDERLINE_POSITION font properties.
13630 A value of nil means ignore them. If you encounter fonts with bogus
13631 UNDERLINE_POSITION font properties, set this to nil. You can also use
13632 `underline-minimum-offset' to override the font's UNDERLINE_POSITION for
13633 small font display sizes. */);
13634 x_use_underline_position_properties = true;
13635 DEFSYM (Qx_use_underline_position_properties,
13636 "x-use-underline-position-properties");
13637
13638 DEFVAR_BOOL ("x-underline-at-descent-line",
13639 x_underline_at_descent_line,
13640 doc: /* Non-nil means to draw the underline at the same place as the descent line.
13641 (If `line-spacing' is in effect, that moves the underline lower by
13642 that many pixels.)
13643 A value of nil means to draw the underline according to the value of the
13644 variable `x-use-underline-position-properties', which is usually at the
13645 baseline level. The default value is nil. */);
13646 x_underline_at_descent_line = false;
13647 DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line");
13648
13649 DEFVAR_BOOL ("x-mouse-click-focus-ignore-position",
13650 x_mouse_click_focus_ignore_position,
13651 doc: /* Non-nil means that a mouse click to focus a frame does not move point.
13652 This variable is used only when the window manager requires that you
13653 click on a frame to select it (give it focus). In that case, a value
13654 of nil, means that the selected window and cursor position changes to
13655 reflect the mouse click position, while a non-nil value means that the
13656 selected window or cursor position is preserved. */);
13657 x_mouse_click_focus_ignore_position = false;
13658
13659 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
13660 doc: /* Which toolkit scroll bars Emacs uses, if any.
13661 A value of nil means Emacs doesn't use toolkit scroll bars.
13662 With the X Window system, the value is a symbol describing the
13663 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
13664 With MS Windows or Nextstep, the value is t. */);
13665 #ifdef USE_TOOLKIT_SCROLL_BARS
13666 #ifdef USE_MOTIF
13667 Vx_toolkit_scroll_bars = intern_c_string ("motif");
13668 #elif defined HAVE_XAW3D
13669 Vx_toolkit_scroll_bars = intern_c_string ("xaw3d");
13670 #elif USE_GTK
13671 Vx_toolkit_scroll_bars = intern_c_string ("gtk");
13672 #else
13673 Vx_toolkit_scroll_bars = intern_c_string ("xaw");
13674 #endif
13675 #else
13676 Vx_toolkit_scroll_bars = Qnil;
13677 #endif
13678
13679 DEFSYM (Qmodifier_value, "modifier-value");
13680 DEFSYM (Qctrl, "ctrl");
13681 Fput (Qctrl, Qmodifier_value, make_fixnum (ctrl_modifier));
13682 DEFSYM (Qalt, "alt");
13683 Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier));
13684 DEFSYM (Qhyper, "hyper");
13685 Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier));
13686 DEFSYM (Qmeta, "meta");
13687 Fput (Qmeta, Qmodifier_value, make_fixnum (meta_modifier));
13688 DEFSYM (Qsuper, "super");
13689 Fput (Qsuper, Qmodifier_value, make_fixnum (super_modifier));
13690
13691 DEFVAR_LISP ("x-ctrl-keysym", Vx_ctrl_keysym,
13692 doc: /* Which keys Emacs uses for the ctrl modifier.
13693 This should be one of the symbols `ctrl', `alt', `hyper', `meta',
13694 `super'. For example, `ctrl' means use the Ctrl_L and Ctrl_R keysyms.
13695 The default is nil, which is the same as `ctrl'. */);
13696 Vx_ctrl_keysym = Qnil;
13697
13698 DEFVAR_LISP ("x-alt-keysym", Vx_alt_keysym,
13699 doc: /* Which keys Emacs uses for the alt modifier.
13700 This should be one of the symbols `ctrl', `alt', `hyper', `meta',
13701 `super'. For example, `alt' means use the Alt_L and Alt_R keysyms.
13702 The default is nil, which is the same as `alt'. */);
13703 Vx_alt_keysym = Qnil;
13704
13705 DEFVAR_LISP ("x-hyper-keysym", Vx_hyper_keysym,
13706 doc: /* Which keys Emacs uses for the hyper modifier.
13707 This should be one of the symbols `ctrl', `alt', `hyper', `meta',
13708 `super'. For example, `hyper' means use the Hyper_L and Hyper_R
13709 keysyms. The default is nil, which is the same as `hyper'. */);
13710 Vx_hyper_keysym = Qnil;
13711
13712 DEFVAR_LISP ("x-meta-keysym", Vx_meta_keysym,
13713 doc: /* Which keys Emacs uses for the meta modifier.
13714 This should be one of the symbols `ctrl', `alt', `hyper', `meta',
13715 `super'. For example, `meta' means use the Meta_L and Meta_R keysyms.
13716 The default is nil, which is the same as `meta'. */);
13717 Vx_meta_keysym = Qnil;
13718
13719 DEFVAR_LISP ("x-super-keysym", Vx_super_keysym,
13720 doc: /* Which keys Emacs uses for the super modifier.
13721 This should be one of the symbols `ctrl', `alt', `hyper', `meta',
13722 `super'. For example, `super' means use the Super_L and Super_R
13723 keysyms. The default is nil, which is the same as `super'. */);
13724 Vx_super_keysym = Qnil;
13725
13726 DEFVAR_LISP ("x-wait-for-event-timeout", Vx_wait_for_event_timeout,
13727 doc: /* How long to wait for X events.
13728
13729 Emacs will wait up to this many seconds to receive X events after
13730 making changes which affect the state of the graphical interface.
13731 Under some window managers this can take an indefinite amount of time,
13732 so it is important to limit the wait.
13733
13734 If set to a non-float value, there will be no wait at all. */);
13735 Vx_wait_for_event_timeout = make_float (0.1);
13736
13737 DEFVAR_LISP ("x-keysym-table", Vx_keysym_table,
13738 doc: /* Hash table of character codes indexed by X keysym codes. */);
13739 Vx_keysym_table = make_hash_table (hashtest_eql, 900,
13740 DEFAULT_REHASH_SIZE,
13741 DEFAULT_REHASH_THRESHOLD,
13742 Qnil, false);
13743
13744 DEFVAR_BOOL ("x-frame-normalize-before-maximize",
13745 x_frame_normalize_before_maximize,
13746 doc: /* Non-nil means normalize frame before maximizing.
13747 If this variable is t, Emacs first asks the window manager to give the
13748 frame its normal size, and only then the final state, whenever changing
13749 from a full-height, full-width or full-both state to the maximized one
13750 or when changing from the maximized to the full-height or full-width
13751 state.
13752
13753 Set this variable only if your window manager cannot handle the
13754 transition between the various maximization states. */);
13755 x_frame_normalize_before_maximize = false;
13756
13757 DEFVAR_BOOL ("x-gtk-use-window-move", x_gtk_use_window_move,
13758 doc: /* Non-nil means rely on gtk_window_move to set frame positions.
13759 If this variable is t (the default), the GTK build uses the function
13760 gtk_window_move to set or store frame positions and disables some time
13761 consuming frame position adjustments. In newer versions of GTK, Emacs
13762 always uses gtk_window_move and ignores the value of this variable. */);
13763 x_gtk_use_window_move = true;
13764 }
13765