]> code.delx.au - gnu-emacs/blob - src/xterm.c
* test/lisp/help-fns-tests.el: Add several tests for 'describe-function'.
[gnu-emacs] / src / xterm.c
1 /* X Communication module for terminals which understand the X protocol.
2
3 Copyright (C) 1989, 1993-2016 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 <http://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 <stdio.h>
25 #ifdef USE_CAIRO
26 #include <math.h>
27 #endif
28
29 #include "lisp.h"
30 #include "blockinput.h"
31
32 /* This may include sys/types.h, and that somehow loses
33 if this is not done before the other system files. */
34 #include "xterm.h"
35 #include <X11/cursorfont.h>
36
37 /* If we have Xfixes extension, use it for pointer blanking. */
38 #ifdef HAVE_XFIXES
39 #include <X11/extensions/Xfixes.h>
40 #endif
41
42 /* Using Xft implies that XRender is available. */
43 #ifdef HAVE_XFT
44 #include <X11/extensions/Xrender.h>
45 #endif
46
47 /* Load sys/types.h if not already loaded.
48 In some systems loading it twice is suicidal. */
49 #ifndef makedev
50 #include <sys/types.h>
51 #endif /* makedev */
52
53 #include <sys/ioctl.h>
54
55 #include "systime.h"
56
57 #include <fcntl.h>
58 #include <errno.h>
59 #include <sys/stat.h>
60 #include "character.h"
61 #include "coding.h"
62 #include "composite.h"
63 #include "frame.h"
64 #include "dispextern.h"
65 #include "xwidget.h"
66 #include "fontset.h"
67 #include "termhooks.h"
68 #include "termopts.h"
69 #include "termchar.h"
70 #include "emacs-icon.h"
71 #include "buffer.h"
72 #include "window.h"
73 #include "keyboard.h"
74 #include "atimer.h"
75 #include "font.h"
76 #include "xsettings.h"
77 #include "sysselect.h"
78 #include "menu.h"
79
80 #ifdef USE_X_TOOLKIT
81 #include <X11/Shell.h>
82 #endif
83
84 #include <unistd.h>
85
86 #ifdef USE_GTK
87 #include "gtkutil.h"
88 #ifdef HAVE_GTK3
89 #include <X11/Xproto.h>
90 #endif
91 #endif
92
93 #if defined (USE_LUCID) || defined (USE_MOTIF)
94 #include "../lwlib/xlwmenu.h"
95 #endif
96
97 #ifdef USE_X_TOOLKIT
98
99 /* Include toolkit specific headers for the scroll bar widget. */
100
101 #ifdef USE_TOOLKIT_SCROLL_BARS
102 #if defined USE_MOTIF
103 #include <Xm/Xm.h> /* For LESSTIF_VERSION */
104 #include <Xm/ScrollBar.h>
105 #else /* !USE_MOTIF i.e. use Xaw */
106
107 #ifdef HAVE_XAW3D
108 #include <X11/Xaw3d/Simple.h>
109 #include <X11/Xaw3d/Scrollbar.h>
110 #include <X11/Xaw3d/ThreeD.h>
111 #else /* !HAVE_XAW3D */
112 #include <X11/Xaw/Simple.h>
113 #include <X11/Xaw/Scrollbar.h>
114 #endif /* !HAVE_XAW3D */
115 #ifndef XtNpickTop
116 #define XtNpickTop "pickTop"
117 #endif /* !XtNpickTop */
118 #endif /* !USE_MOTIF */
119 #endif /* USE_TOOLKIT_SCROLL_BARS */
120
121 #endif /* USE_X_TOOLKIT */
122
123 #ifdef USE_X_TOOLKIT
124 #include "widget.h"
125 #ifndef XtNinitialState
126 #define XtNinitialState "initialState"
127 #endif
128 #endif
129
130 #include "bitmaps/gray.xbm"
131
132 #ifdef HAVE_XKB
133 #include <X11/XKBlib.h>
134 #endif
135
136 /* Default to using XIM if available. */
137 #ifdef USE_XIM
138 bool use_xim = true;
139 #else
140 bool use_xim = false; /* configure --without-xim */
141 #endif
142
143 /* Non-zero means that a HELP_EVENT has been generated since Emacs
144 start. */
145
146 static bool any_help_event_p;
147
148 /* This is a chain of structures for all the X displays currently in
149 use. */
150
151 struct x_display_info *x_display_list;
152
153 #ifdef USE_X_TOOLKIT
154
155 /* The application context for Xt use. */
156 XtAppContext Xt_app_con;
157 static String Xt_default_resources[] = {0};
158
159 /* Non-zero means user is interacting with a toolkit scroll bar. */
160 static bool toolkit_scroll_bar_interaction;
161
162 #endif /* USE_X_TOOLKIT */
163
164 /* Non-zero timeout value means ignore next mouse click if it arrives
165 before that timeout elapses (i.e. as part of the same sequence of
166 events resulting from clicking on a frame to select it). */
167
168 static Time ignore_next_mouse_click_timeout;
169
170 /* Used locally within XTread_socket. */
171
172 static int x_noop_count;
173
174 #ifdef USE_GTK
175 /* The name of the Emacs icon file. */
176 static Lisp_Object xg_default_icon_file;
177 #endif
178
179 /* Some functions take this as char *, not const char *. */
180 static char emacs_class[] = EMACS_CLASS;
181
182 enum xembed_info
183 {
184 XEMBED_MAPPED = 1 << 0
185 };
186
187 enum xembed_message
188 {
189 XEMBED_EMBEDDED_NOTIFY = 0,
190 XEMBED_WINDOW_ACTIVATE = 1,
191 XEMBED_WINDOW_DEACTIVATE = 2,
192 XEMBED_REQUEST_FOCUS = 3,
193 XEMBED_FOCUS_IN = 4,
194 XEMBED_FOCUS_OUT = 5,
195 XEMBED_FOCUS_NEXT = 6,
196 XEMBED_FOCUS_PREV = 7,
197
198 XEMBED_MODALITY_ON = 10,
199 XEMBED_MODALITY_OFF = 11,
200 XEMBED_REGISTER_ACCELERATOR = 12,
201 XEMBED_UNREGISTER_ACCELERATOR = 13,
202 XEMBED_ACTIVATE_ACCELERATOR = 14
203 };
204
205 static void x_free_cr_resources (struct frame *);
206 static bool x_alloc_nearest_color_1 (Display *, Colormap, XColor *);
207 static void x_raise_frame (struct frame *);
208 static void x_lower_frame (struct frame *);
209 static int x_io_error_quitter (Display *);
210 static struct terminal *x_create_terminal (struct x_display_info *);
211 static void x_frame_rehighlight (struct x_display_info *);
212
213 static void x_clip_to_row (struct window *, struct glyph_row *,
214 enum glyph_row_area, GC);
215 static struct scroll_bar *x_window_to_scroll_bar (Display *, Window, int);
216 static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *,
217 enum scroll_bar_part *,
218 Lisp_Object *, Lisp_Object *,
219 Time *);
220 static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object *,
221 enum scroll_bar_part *,
222 Lisp_Object *, Lisp_Object *,
223 Time *);
224 static bool x_handle_net_wm_state (struct frame *, const XPropertyEvent *);
225 static void x_check_fullscreen (struct frame *);
226 static void x_check_expected_move (struct frame *, int, int);
227 static void x_sync_with_move (struct frame *, int, int, bool);
228 static int handle_one_xevent (struct x_display_info *,
229 const XEvent *, int *,
230 struct input_event *);
231 #if ! (defined USE_X_TOOLKIT || defined USE_MOTIF)
232 static int x_dispatch_event (XEvent *, Display *);
233 #endif
234 static void x_wm_set_window_state (struct frame *, int);
235 static void x_wm_set_icon_pixmap (struct frame *, ptrdiff_t);
236 static void x_initialize (void);
237
238 static bool get_current_wm_state (struct frame *, Window, int *, bool *);
239
240 /* Flush display of frame F. */
241
242 static void
243 x_flush (struct frame *f)
244 {
245 eassert (f && FRAME_X_P (f));
246 /* Don't call XFlush when it is not safe to redisplay; the X
247 connection may be broken. */
248 if (!NILP (Vinhibit_redisplay))
249 return;
250
251 block_input ();
252 XFlush (FRAME_X_DISPLAY (f));
253 unblock_input ();
254 }
255
256
257 /* Remove calls to XFlush by defining XFlush to an empty replacement.
258 Calls to XFlush should be unnecessary because the X output buffer
259 is flushed automatically as needed by calls to XPending,
260 XNextEvent, or XWindowEvent according to the XFlush man page.
261 XTread_socket calls XPending. Removing XFlush improves
262 performance. */
263
264 #define XFlush(DISPLAY) (void) 0
265
266 \f
267 /***********************************************************************
268 Debugging
269 ***********************************************************************/
270
271 #if false
272
273 /* This is a function useful for recording debugging information about
274 the sequence of occurrences in this file. */
275
276 struct record
277 {
278 char *locus;
279 int type;
280 };
281
282 struct record event_record[100];
283
284 int event_record_index;
285
286 void
287 record_event (char *locus, int type)
288 {
289 if (event_record_index == ARRAYELTS (event_record))
290 event_record_index = 0;
291
292 event_record[event_record_index].locus = locus;
293 event_record[event_record_index].type = type;
294 event_record_index++;
295 }
296
297 #endif
298
299 #ifdef USE_CAIRO
300
301 #define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context)
302 #define FRAME_CR_SURFACE(f) ((f)->output_data.x->cr_surface)
303
304 static struct x_gc_ext_data *
305 x_gc_get_ext_data (struct frame *f, GC gc, int create_if_not_found_p)
306 {
307 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
308 XEDataObject object;
309 XExtData **head, *ext_data;
310
311 object.gc = gc;
312 head = XEHeadOfExtensionList (object);
313 ext_data = XFindOnExtensionList (head, dpyinfo->ext_codes->extension);
314 if (ext_data == NULL)
315 {
316 if (!create_if_not_found_p)
317 return NULL;
318 else
319 {
320 ext_data = xzalloc (sizeof (*ext_data));
321 ext_data->number = dpyinfo->ext_codes->extension;
322 ext_data->private_data = xzalloc (sizeof (struct x_gc_ext_data));
323 XAddToExtensionList (head, ext_data);
324 }
325 }
326 return (struct x_gc_ext_data *) ext_data->private_data;
327 }
328
329 static void
330 x_extension_initialize (struct x_display_info *dpyinfo)
331 {
332 XExtCodes *ext_codes = XAddExtension (dpyinfo->display);
333
334 dpyinfo->ext_codes = ext_codes;
335 }
336
337 static void
338 x_cr_destroy_surface (struct frame *f)
339 {
340 if (FRAME_CR_SURFACE (f))
341 {
342 cairo_t *cr = FRAME_CR_CONTEXT (f);
343 cairo_surface_destroy (FRAME_CR_SURFACE (f));
344 FRAME_CR_SURFACE (f) = 0;
345 if (cr) cairo_destroy (cr);
346 FRAME_CR_CONTEXT (f) = NULL;
347 }
348 }
349
350 cairo_t *
351 x_begin_cr_clip (struct frame *f, GC gc)
352 {
353 cairo_t *cr = FRAME_CR_CONTEXT (f);
354
355 if (!cr)
356 {
357
358 if (! FRAME_CR_SURFACE (f))
359 {
360 cairo_surface_t *surface;
361 surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
362 FRAME_X_WINDOW (f),
363 FRAME_DISPLAY_INFO (f)->visual,
364 FRAME_PIXEL_WIDTH (f),
365 FRAME_PIXEL_HEIGHT (f));
366 cr = cairo_create (surface);
367 cairo_surface_destroy (surface);
368 }
369 else
370 cr = cairo_create (FRAME_CR_SURFACE (f));
371 FRAME_CR_CONTEXT (f) = cr;
372 }
373 cairo_save (cr);
374
375 if (gc)
376 {
377 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
378
379 if (gc_ext && gc_ext->n_clip_rects)
380 {
381 int i;
382
383 for (i = 0; i < gc_ext->n_clip_rects; i++)
384 cairo_rectangle (cr, gc_ext->clip_rects[i].x,
385 gc_ext->clip_rects[i].y,
386 gc_ext->clip_rects[i].width,
387 gc_ext->clip_rects[i].height);
388 cairo_clip (cr);
389 }
390 }
391
392 return cr;
393 }
394
395 void
396 x_end_cr_clip (struct frame *f)
397 {
398 cairo_restore (FRAME_CR_CONTEXT (f));
399 }
400
401 void
402 x_set_cr_source_with_gc_foreground (struct frame *f, GC gc)
403 {
404 XGCValues xgcv;
405 XColor color;
406
407 XGetGCValues (FRAME_X_DISPLAY (f), gc, GCForeground, &xgcv);
408 color.pixel = xgcv.foreground;
409 x_query_color (f, &color);
410 cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
411 color.green / 65535.0, color.blue / 65535.0);
412 }
413
414 void
415 x_set_cr_source_with_gc_background (struct frame *f, GC gc)
416 {
417 XGCValues xgcv;
418 XColor color;
419
420 XGetGCValues (FRAME_X_DISPLAY (f), gc, GCBackground, &xgcv);
421 color.pixel = xgcv.background;
422 x_query_color (f, &color);
423 cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
424 color.green / 65535.0, color.blue / 65535.0);
425 }
426
427 /* Fringe bitmaps. */
428
429 static int max_fringe_bmp = 0;
430 static cairo_pattern_t **fringe_bmp = 0;
431
432 static void
433 x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
434 {
435 int i, stride;
436 cairo_surface_t *surface;
437 unsigned char *data;
438 cairo_pattern_t *pattern;
439
440 if (which >= max_fringe_bmp)
441 {
442 i = max_fringe_bmp;
443 max_fringe_bmp = which + 20;
444 fringe_bmp = (cairo_pattern_t **) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (cairo_pattern_t *));
445 while (i < max_fringe_bmp)
446 fringe_bmp[i++] = 0;
447 }
448
449 block_input ();
450
451 surface = cairo_image_surface_create (CAIRO_FORMAT_A1, wd, h);
452 stride = cairo_image_surface_get_stride (surface);
453 data = cairo_image_surface_get_data (surface);
454
455 for (i = 0; i < h; i++)
456 {
457 *((unsigned short *) data) = bits[i];
458 data += stride;
459 }
460
461 cairo_surface_mark_dirty (surface);
462 pattern = cairo_pattern_create_for_surface (surface);
463 cairo_surface_destroy (surface);
464
465 unblock_input ();
466
467 fringe_bmp[which] = pattern;
468 }
469
470 static void
471 x_cr_destroy_fringe_bitmap (int which)
472 {
473 if (which >= max_fringe_bmp)
474 return;
475
476 if (fringe_bmp[which])
477 {
478 block_input ();
479 cairo_pattern_destroy (fringe_bmp[which]);
480 unblock_input ();
481 }
482 fringe_bmp[which] = 0;
483 }
484
485 static void
486 x_cr_draw_image (struct frame *f, GC gc, cairo_pattern_t *image,
487 int src_x, int src_y, int width, int height,
488 int dest_x, int dest_y, bool overlay_p)
489 {
490 cairo_t *cr;
491 cairo_matrix_t matrix;
492 cairo_surface_t *surface;
493 cairo_format_t format;
494
495 cr = x_begin_cr_clip (f, gc);
496 if (overlay_p)
497 cairo_rectangle (cr, dest_x, dest_y, width, height);
498 else
499 {
500 x_set_cr_source_with_gc_background (f, gc);
501 cairo_rectangle (cr, dest_x, dest_y, width, height);
502 cairo_fill_preserve (cr);
503 }
504 cairo_clip (cr);
505 cairo_matrix_init_translate (&matrix, src_x - dest_x, src_y - dest_y);
506 cairo_pattern_set_matrix (image, &matrix);
507 cairo_pattern_get_surface (image, &surface);
508 format = cairo_image_surface_get_format (surface);
509 if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1)
510 {
511 cairo_set_source (cr, image);
512 cairo_fill (cr);
513 }
514 else
515 {
516 x_set_cr_source_with_gc_foreground (f, gc);
517 cairo_mask (cr, image);
518 }
519 x_end_cr_clip (f);
520 }
521
522 void
523 x_cr_draw_frame (cairo_t *cr, struct frame *f)
524 {
525 int width, height;
526
527 width = FRAME_PIXEL_WIDTH (f);
528 height = FRAME_PIXEL_HEIGHT (f);
529
530 x_free_cr_resources (f);
531 FRAME_CR_CONTEXT (f) = cr;
532 x_clear_area (f, 0, 0, width, height);
533 expose_frame (f, 0, 0, width, height);
534 FRAME_CR_CONTEXT (f) = NULL;
535 }
536
537 static cairo_status_t
538 x_cr_accumulate_data (void *closure, const unsigned char *data,
539 unsigned int length)
540 {
541 Lisp_Object *acc = (Lisp_Object *) closure;
542
543 *acc = Fcons (make_unibyte_string ((char const *) data, length), *acc);
544
545 return CAIRO_STATUS_SUCCESS;
546 }
547
548 static void
549 x_cr_destroy (Lisp_Object arg)
550 {
551 cairo_t *cr = (cairo_t *) XSAVE_POINTER (arg, 0);
552
553 block_input ();
554 cairo_destroy (cr);
555 unblock_input ();
556 }
557
558 Lisp_Object
559 x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
560 {
561 struct frame *f;
562 cairo_surface_t *surface;
563 cairo_t *cr;
564 int width, height;
565 void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL;
566 Lisp_Object acc = Qnil;
567 int count = SPECPDL_INDEX ();
568
569 specbind (Qredisplay_dont_pause, Qt);
570 redisplay_preserve_echo_area (31);
571
572 f = XFRAME (XCAR (frames));
573 frames = XCDR (frames);
574 width = FRAME_PIXEL_WIDTH (f);
575 height = FRAME_PIXEL_HEIGHT (f);
576
577 block_input ();
578 #ifdef CAIRO_HAS_PDF_SURFACE
579 if (surface_type == CAIRO_SURFACE_TYPE_PDF)
580 {
581 surface = cairo_pdf_surface_create_for_stream (x_cr_accumulate_data, &acc,
582 width, height);
583 surface_set_size_func = cairo_pdf_surface_set_size;
584 }
585 else
586 #endif
587 #ifdef CAIRO_HAS_PNG_FUNCTIONS
588 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
589 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
590 else
591 #endif
592 #ifdef CAIRO_HAS_PS_SURFACE
593 if (surface_type == CAIRO_SURFACE_TYPE_PS)
594 {
595 surface = cairo_ps_surface_create_for_stream (x_cr_accumulate_data, &acc,
596 width, height);
597 surface_set_size_func = cairo_ps_surface_set_size;
598 }
599 else
600 #endif
601 #ifdef CAIRO_HAS_SVG_SURFACE
602 if (surface_type == CAIRO_SURFACE_TYPE_SVG)
603 surface = cairo_svg_surface_create_for_stream (x_cr_accumulate_data, &acc,
604 width, height);
605 else
606 #endif
607 abort ();
608
609 cr = cairo_create (surface);
610 cairo_surface_destroy (surface);
611 record_unwind_protect (x_cr_destroy, make_save_ptr (cr));
612
613 while (1)
614 {
615 x_free_cr_resources (f);
616 FRAME_CR_CONTEXT (f) = cr;
617 x_clear_area (f, 0, 0, width, height);
618 expose_frame (f, 0, 0, width, height);
619 FRAME_CR_CONTEXT (f) = NULL;
620
621 if (NILP (frames))
622 break;
623
624 cairo_surface_show_page (surface);
625 f = XFRAME (XCAR (frames));
626 frames = XCDR (frames);
627 width = FRAME_PIXEL_WIDTH (f);
628 height = FRAME_PIXEL_HEIGHT (f);
629 if (surface_set_size_func)
630 (*surface_set_size_func) (surface, width, height);
631
632 unblock_input ();
633 QUIT;
634 block_input ();
635 }
636
637 #ifdef CAIRO_HAS_PNG_FUNCTIONS
638 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
639 {
640 cairo_surface_flush (surface);
641 cairo_surface_write_to_png_stream (surface, x_cr_accumulate_data, &acc);
642 }
643 #endif
644 unblock_input ();
645
646 unbind_to (count, Qnil);
647
648 return CALLN (Fapply, intern ("concat"), Fnreverse (acc));
649 }
650
651 #endif /* USE_CAIRO */
652
653 static void
654 x_free_cr_resources (struct frame *f)
655 {
656 #ifdef USE_CAIRO
657 if (f == NULL)
658 {
659 Lisp_Object rest, frame;
660 FOR_EACH_FRAME (rest, frame)
661 if (FRAME_X_P (XFRAME (frame)))
662 x_free_cr_resources (XFRAME (frame));
663 }
664 else
665 {
666 cairo_t *cr = FRAME_CR_CONTEXT (f);
667
668 if (cr)
669 {
670 cairo_surface_t *surface = cairo_get_target (cr);
671
672 if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
673 {
674 cairo_destroy (cr);
675 FRAME_CR_CONTEXT (f) = NULL;
676 }
677 }
678 }
679 #endif
680 }
681
682 static void
683 x_set_clip_rectangles (struct frame *f, GC gc, XRectangle *rectangles, int n)
684 {
685 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, rectangles, n, Unsorted);
686 #ifdef USE_CAIRO
687 eassert (n >= 0 && n <= MAX_CLIP_RECTS);
688
689 {
690 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 1);
691
692 gc_ext->n_clip_rects = n;
693 memcpy (gc_ext->clip_rects, rectangles, sizeof (XRectangle) * n);
694 }
695 #endif
696 }
697
698 static void
699 x_reset_clip_rectangles (struct frame *f, GC gc)
700 {
701 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
702 #ifdef USE_CAIRO
703 {
704 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
705
706 if (gc_ext)
707 gc_ext->n_clip_rects = 0;
708 }
709 #endif
710 }
711
712 static void
713 x_fill_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
714 {
715 #ifdef USE_CAIRO
716 cairo_t *cr;
717
718 cr = x_begin_cr_clip (f, gc);
719 x_set_cr_source_with_gc_foreground (f, gc);
720 cairo_rectangle (cr, x, y, width, height);
721 cairo_fill (cr);
722 x_end_cr_clip (f);
723 #else
724 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
725 gc, x, y, width, height);
726 #endif
727 }
728
729 static void
730 x_draw_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
731 {
732 #ifdef USE_CAIRO
733 cairo_t *cr;
734
735 cr = x_begin_cr_clip (f, gc);
736 x_set_cr_source_with_gc_foreground (f, gc);
737 cairo_rectangle (cr, x + 0.5, y + 0.5, width, height);
738 cairo_set_line_width (cr, 1);
739 cairo_stroke (cr);
740 x_end_cr_clip (f);
741 #else
742 XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
743 gc, x, y, width, height);
744 #endif
745 }
746
747 static void
748 x_clear_window (struct frame *f)
749 {
750 #ifdef USE_CAIRO
751 cairo_t *cr;
752
753 cr = x_begin_cr_clip (f, NULL);
754 x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
755 cairo_paint (cr);
756 x_end_cr_clip (f);
757 #else
758 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
759 #endif
760 }
761
762 #ifdef USE_CAIRO
763 static void
764 x_fill_trapezoid_for_relief (struct frame *f, GC gc, int x, int y,
765 int width, int height, int top_p)
766 {
767 cairo_t *cr;
768
769 cr = x_begin_cr_clip (f, gc);
770 x_set_cr_source_with_gc_foreground (f, gc);
771 cairo_move_to (cr, top_p ? x : x + height, y);
772 cairo_line_to (cr, x, y + height);
773 cairo_line_to (cr, top_p ? x + width - height : x + width, y + height);
774 cairo_line_to (cr, x + width, y);
775 cairo_fill (cr);
776 x_end_cr_clip (f);
777 }
778
779 enum corners
780 {
781 CORNER_BOTTOM_RIGHT, /* 0 -> pi/2 */
782 CORNER_BOTTOM_LEFT, /* pi/2 -> pi */
783 CORNER_TOP_LEFT, /* pi -> 3pi/2 */
784 CORNER_TOP_RIGHT, /* 3pi/2 -> 2pi */
785 CORNER_LAST
786 };
787
788 static void
789 x_erase_corners_for_relief (struct frame *f, GC gc, int x, int y,
790 int width, int height,
791 double radius, double margin, int corners)
792 {
793 cairo_t *cr;
794 int i;
795
796 cr = x_begin_cr_clip (f, gc);
797 x_set_cr_source_with_gc_background (f, gc);
798 for (i = 0; i < CORNER_LAST; i++)
799 if (corners & (1 << i))
800 {
801 double xm, ym, xc, yc;
802
803 if (i == CORNER_TOP_LEFT || i == CORNER_BOTTOM_LEFT)
804 xm = x - margin, xc = xm + radius;
805 else
806 xm = x + width + margin, xc = xm - radius;
807 if (i == CORNER_TOP_LEFT || i == CORNER_TOP_RIGHT)
808 ym = y - margin, yc = ym + radius;
809 else
810 ym = y + height + margin, yc = ym - radius;
811
812 cairo_move_to (cr, xm, ym);
813 cairo_arc (cr, xc, yc, radius, i * M_PI_2, (i + 1) * M_PI_2);
814 }
815 cairo_clip (cr);
816 cairo_rectangle (cr, x, y, width, height);
817 cairo_fill (cr);
818 x_end_cr_clip (f);
819 }
820
821 static void
822 x_draw_horizontal_wave (struct frame *f, GC gc, int x, int y,
823 int width, int height, int wave_length)
824 {
825 cairo_t *cr;
826 double dx = wave_length, dy = height - 1;
827 int xoffset, n;
828
829 cr = x_begin_cr_clip (f, gc);
830 x_set_cr_source_with_gc_foreground (f, gc);
831 cairo_rectangle (cr, x, y, width, height);
832 cairo_clip (cr);
833
834 if (x >= 0)
835 {
836 xoffset = x % (wave_length * 2);
837 if (xoffset == 0)
838 xoffset = wave_length * 2;
839 }
840 else
841 xoffset = x % (wave_length * 2) + wave_length * 2;
842 n = (width + xoffset) / wave_length + 1;
843 if (xoffset > wave_length)
844 {
845 xoffset -= wave_length;
846 --n;
847 y += height - 1;
848 dy = -dy;
849 }
850
851 cairo_move_to (cr, x - xoffset + 0.5, y + 0.5);
852 while (--n >= 0)
853 {
854 cairo_rel_line_to (cr, dx, dy);
855 dy = -dy;
856 }
857 cairo_set_line_width (cr, 1);
858 cairo_stroke (cr);
859 x_end_cr_clip (f);
860 }
861 #endif
862
863 \f
864 /* Return the struct x_display_info corresponding to DPY. */
865
866 struct x_display_info *
867 x_display_info_for_display (Display *dpy)
868 {
869 struct x_display_info *dpyinfo;
870
871 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
872 if (dpyinfo->display == dpy)
873 return dpyinfo;
874
875 return 0;
876 }
877
878 static Window
879 x_find_topmost_parent (struct frame *f)
880 {
881 struct x_output *x = f->output_data.x;
882 Window win = None, wi = x->parent_desc;
883 Display *dpy = FRAME_X_DISPLAY (f);
884
885 while (wi != FRAME_DISPLAY_INFO (f)->root_window)
886 {
887 Window root;
888 Window *children;
889 unsigned int nchildren;
890
891 win = wi;
892 if (XQueryTree (dpy, win, &root, &wi, &children, &nchildren))
893 XFree (children);
894 else
895 break;
896 }
897
898 return win;
899 }
900
901 #define OPAQUE 0xffffffff
902
903 void
904 x_set_frame_alpha (struct frame *f)
905 {
906 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
907 Display *dpy = FRAME_X_DISPLAY (f);
908 Window win = FRAME_OUTER_WINDOW (f);
909 double alpha = 1.0;
910 double alpha_min = 1.0;
911 unsigned long opac;
912 Window parent;
913
914 if (dpyinfo->x_highlight_frame == f)
915 alpha = f->alpha[0];
916 else
917 alpha = f->alpha[1];
918
919 if (FLOATP (Vframe_alpha_lower_limit))
920 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
921 else if (INTEGERP (Vframe_alpha_lower_limit))
922 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
923
924 if (alpha < 0.0)
925 return;
926 else if (alpha > 1.0)
927 alpha = 1.0;
928 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
929 alpha = alpha_min;
930
931 opac = alpha * OPAQUE;
932
933 x_catch_errors (dpy);
934
935 /* If there is a parent from the window manager, put the property there
936 also, to work around broken window managers that fail to do that.
937 Do this unconditionally as this function is called on reparent when
938 alpha has not changed on the frame. */
939
940 parent = x_find_topmost_parent (f);
941 if (parent != None)
942 XChangeProperty (dpy, parent, dpyinfo->Xatom_net_wm_window_opacity,
943 XA_CARDINAL, 32, PropModeReplace,
944 (unsigned char *) &opac, 1);
945
946 /* return unless necessary */
947 {
948 unsigned char *data;
949 Atom actual;
950 int rc, format;
951 unsigned long n, left;
952
953 rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
954 0, 1, False, XA_CARDINAL,
955 &actual, &format, &n, &left,
956 &data);
957
958 if (rc == Success && actual != None)
959 {
960 unsigned long value = *(unsigned long *)data;
961 XFree (data);
962 if (value == opac)
963 {
964 x_uncatch_errors ();
965 return;
966 }
967 }
968 }
969
970 XChangeProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
971 XA_CARDINAL, 32, PropModeReplace,
972 (unsigned char *) &opac, 1);
973 x_uncatch_errors ();
974 }
975
976 /***********************************************************************
977 Starting and ending an update
978 ***********************************************************************/
979
980 /* Start an update of frame F. This function is installed as a hook
981 for update_begin, i.e. it is called when update_begin is called.
982 This function is called prior to calls to x_update_window_begin for
983 each window being updated. Currently, there is nothing to do here
984 because all interesting stuff is done on a window basis. */
985
986 static void
987 x_update_begin (struct frame *f)
988 {
989 #ifdef USE_CAIRO
990 if (! NILP (tip_frame) && XFRAME (tip_frame) == f
991 && ! FRAME_VISIBLE_P (f))
992 return;
993
994 if (! FRAME_CR_SURFACE (f))
995 {
996 int width, height;
997 #ifdef USE_GTK
998 if (FRAME_GTK_WIDGET (f))
999 {
1000 GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
1001 width = gdk_window_get_width (w);
1002 height = gdk_window_get_height (w);
1003 }
1004 else
1005 #endif
1006 {
1007 width = FRAME_PIXEL_WIDTH (f);
1008 height = FRAME_PIXEL_HEIGHT (f);
1009 if (! FRAME_EXTERNAL_TOOL_BAR (f))
1010 height += FRAME_TOOL_BAR_HEIGHT (f);
1011 if (! FRAME_EXTERNAL_MENU_BAR (f))
1012 height += FRAME_MENU_BAR_HEIGHT (f);
1013 }
1014
1015 if (width > 0 && height > 0)
1016 {
1017 block_input();
1018 FRAME_CR_SURFACE (f) = cairo_image_surface_create
1019 (CAIRO_FORMAT_ARGB32, width, height);
1020 unblock_input();
1021 }
1022 }
1023 #endif /* USE_CAIRO */
1024 }
1025
1026 /* Start update of window W. */
1027
1028 static void
1029 x_update_window_begin (struct window *w)
1030 {
1031 struct frame *f = XFRAME (WINDOW_FRAME (w));
1032 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1033
1034 w->output_cursor = w->cursor;
1035
1036 block_input ();
1037
1038 if (f == hlinfo->mouse_face_mouse_frame)
1039 {
1040 /* Don't do highlighting for mouse motion during the update. */
1041 hlinfo->mouse_face_defer = true;
1042
1043 /* If F needs to be redrawn, simply forget about any prior mouse
1044 highlighting. */
1045 if (FRAME_GARBAGED_P (f))
1046 hlinfo->mouse_face_window = Qnil;
1047 }
1048
1049 unblock_input ();
1050 }
1051
1052
1053 /* Draw a vertical window border from (x,y0) to (x,y1) */
1054
1055 static void
1056 x_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
1057 {
1058 struct frame *f = XFRAME (WINDOW_FRAME (w));
1059 struct face *face;
1060
1061 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
1062 if (face)
1063 XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
1064 face->foreground);
1065
1066 #ifdef USE_CAIRO
1067 x_fill_rectangle (f, f->output_data.x->normal_gc, x, y0, 1, y1 - y0);
1068 #else
1069 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1070 f->output_data.x->normal_gc, x, y0, x, y1);
1071 #endif
1072 }
1073
1074 /* Draw a window divider from (x0,y0) to (x1,y1) */
1075
1076 static void
1077 x_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
1078 {
1079 struct frame *f = XFRAME (WINDOW_FRAME (w));
1080 struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
1081 struct face *face_first
1082 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
1083 struct face *face_last
1084 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
1085 unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
1086 unsigned long color_first = (face_first
1087 ? face_first->foreground
1088 : FRAME_FOREGROUND_PIXEL (f));
1089 unsigned long color_last = (face_last
1090 ? face_last->foreground
1091 : FRAME_FOREGROUND_PIXEL (f));
1092 Display *display = FRAME_X_DISPLAY (f);
1093
1094 if (y1 - y0 > x1 - x0 && x1 - x0 > 2)
1095 /* Vertical. */
1096 {
1097 XSetForeground (display, f->output_data.x->normal_gc, color_first);
1098 x_fill_rectangle (f, f->output_data.x->normal_gc,
1099 x0, y0, 1, y1 - y0);
1100 XSetForeground (display, f->output_data.x->normal_gc, color);
1101 x_fill_rectangle (f, f->output_data.x->normal_gc,
1102 x0 + 1, y0, x1 - x0 - 2, y1 - y0);
1103 XSetForeground (display, f->output_data.x->normal_gc, color_last);
1104 x_fill_rectangle (f, f->output_data.x->normal_gc,
1105 x1 - 1, y0, 1, y1 - y0);
1106 }
1107 else if (x1 - x0 > y1 - y0 && y1 - y0 > 3)
1108 /* Horizontal. */
1109 {
1110 XSetForeground (display, f->output_data.x->normal_gc, color_first);
1111 x_fill_rectangle (f, f->output_data.x->normal_gc,
1112 x0, y0, x1 - x0, 1);
1113 XSetForeground (display, f->output_data.x->normal_gc, color);
1114 x_fill_rectangle (f, f->output_data.x->normal_gc,
1115 x0, y0 + 1, x1 - x0, y1 - y0 - 2);
1116 XSetForeground (display, f->output_data.x->normal_gc, color_last);
1117 x_fill_rectangle (f, f->output_data.x->normal_gc,
1118 x0, y1 - 1, x1 - x0, 1);
1119 }
1120 else
1121 {
1122 XSetForeground (display, f->output_data.x->normal_gc, color);
1123 x_fill_rectangle (f, f->output_data.x->normal_gc,
1124 x0, y0, x1 - x0, y1 - y0);
1125 }
1126 }
1127
1128 /* End update of window W.
1129
1130 Draw vertical borders between horizontally adjacent windows, and
1131 display W's cursor if CURSOR_ON_P is non-zero.
1132
1133 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
1134 glyphs in mouse-face were overwritten. In that case we have to
1135 make sure that the mouse-highlight is properly redrawn.
1136
1137 W may be a menu bar pseudo-window in case we don't have X toolkit
1138 support. Such windows don't have a cursor, so don't display it
1139 here. */
1140
1141 static void
1142 x_update_window_end (struct window *w, bool cursor_on_p,
1143 bool mouse_face_overwritten_p)
1144 {
1145 if (!w->pseudo_window_p)
1146 {
1147 block_input ();
1148
1149 if (cursor_on_p)
1150 display_and_set_cursor (w, true,
1151 w->output_cursor.hpos, w->output_cursor.vpos,
1152 w->output_cursor.x, w->output_cursor.y);
1153
1154 if (draw_window_fringes (w, true))
1155 {
1156 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1157 x_draw_right_divider (w);
1158 else
1159 x_draw_vertical_border (w);
1160 }
1161
1162 unblock_input ();
1163 }
1164
1165 /* If a row with mouse-face was overwritten, arrange for
1166 XTframe_up_to_date to redisplay the mouse highlight. */
1167 if (mouse_face_overwritten_p)
1168 {
1169 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
1170
1171 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1172 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1173 hlinfo->mouse_face_window = Qnil;
1174 }
1175 }
1176
1177
1178 /* End update of frame F. This function is installed as a hook in
1179 update_end. */
1180
1181 static void
1182 x_update_end (struct frame *f)
1183 {
1184 /* Mouse highlight may be displayed again. */
1185 MOUSE_HL_INFO (f)->mouse_face_defer = false;
1186
1187 #ifdef USE_CAIRO
1188 if (FRAME_CR_SURFACE (f))
1189 {
1190 cairo_t *cr = 0;
1191 block_input();
1192 #if defined (USE_GTK) && defined (HAVE_GTK3)
1193 if (FRAME_GTK_WIDGET (f))
1194 {
1195 GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
1196 cr = gdk_cairo_create (w);
1197 }
1198 else
1199 #endif
1200 {
1201 cairo_surface_t *surface;
1202 int width = FRAME_PIXEL_WIDTH (f);
1203 int height = FRAME_PIXEL_HEIGHT (f);
1204 if (! FRAME_EXTERNAL_TOOL_BAR (f))
1205 height += FRAME_TOOL_BAR_HEIGHT (f);
1206 if (! FRAME_EXTERNAL_MENU_BAR (f))
1207 height += FRAME_MENU_BAR_HEIGHT (f);
1208 surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
1209 FRAME_X_WINDOW (f),
1210 FRAME_DISPLAY_INFO (f)->visual,
1211 width,
1212 height);
1213 cr = cairo_create (surface);
1214 cairo_surface_destroy (surface);
1215 }
1216
1217 cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), 0, 0);
1218 cairo_paint (cr);
1219 cairo_destroy (cr);
1220 unblock_input ();
1221 }
1222 #endif /* USE_CAIRO */
1223
1224 #ifndef XFlush
1225 block_input ();
1226 XFlush (FRAME_X_DISPLAY (f));
1227 unblock_input ();
1228 #endif
1229 }
1230
1231
1232 /* This function is called from various places in xdisp.c
1233 whenever a complete update has been performed. */
1234
1235 static void
1236 XTframe_up_to_date (struct frame *f)
1237 {
1238 if (FRAME_X_P (f))
1239 FRAME_MOUSE_UPDATE (f);
1240 }
1241
1242
1243 /* Clear under internal border if any (GTK has its own version). */
1244 #ifndef USE_GTK
1245 void
1246 x_clear_under_internal_border (struct frame *f)
1247 {
1248 if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
1249 {
1250 int border = FRAME_INTERNAL_BORDER_WIDTH (f);
1251 int width = FRAME_PIXEL_WIDTH (f);
1252 int height = FRAME_PIXEL_HEIGHT (f);
1253 int margin = FRAME_TOP_MARGIN_HEIGHT (f);
1254
1255 block_input ();
1256 x_clear_area (f, 0, 0, border, height);
1257 x_clear_area (f, 0, margin, width, border);
1258 x_clear_area (f, width - border, 0, border, height);
1259 x_clear_area (f, 0, height - border, width, border);
1260 unblock_input ();
1261 }
1262 }
1263 #endif
1264
1265 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
1266 arrow bitmaps, or clear the fringes if no bitmaps are required
1267 before DESIRED_ROW is made current. This function is called from
1268 update_window_line only if it is known that there are differences
1269 between bitmaps to be drawn between current row and DESIRED_ROW. */
1270
1271 static void
1272 x_after_update_window_line (struct window *w, struct glyph_row *desired_row)
1273 {
1274 eassert (w);
1275
1276 if (!desired_row->mode_line_p && !w->pseudo_window_p)
1277 desired_row->redraw_fringe_bitmaps_p = true;
1278
1279 #ifdef USE_X_TOOLKIT
1280 /* When a window has disappeared, make sure that no rest of
1281 full-width rows stays visible in the internal border. Could
1282 check here if updated window is the leftmost/rightmost window,
1283 but I guess it's not worth doing since vertically split windows
1284 are almost never used, internal border is rarely set, and the
1285 overhead is very small. */
1286 {
1287 struct frame *f;
1288 int width, height;
1289
1290 if (windows_or_buffers_changed
1291 && desired_row->full_width_p
1292 && (f = XFRAME (w->frame),
1293 width = FRAME_INTERNAL_BORDER_WIDTH (f),
1294 width != 0)
1295 && (height = desired_row->visible_height,
1296 height > 0))
1297 {
1298 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
1299
1300 block_input ();
1301 x_clear_area (f, 0, y, width, height);
1302 x_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
1303 unblock_input ();
1304 }
1305 }
1306 #endif
1307 }
1308
1309 static void
1310 x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fringe_bitmap_params *p)
1311 {
1312 struct frame *f = XFRAME (WINDOW_FRAME (w));
1313 Display *display = FRAME_X_DISPLAY (f);
1314 GC gc = f->output_data.x->normal_gc;
1315 struct face *face = p->face;
1316
1317 /* Must clip because of partially visible lines. */
1318 x_clip_to_row (w, row, ANY_AREA, gc);
1319
1320 if (p->bx >= 0 && !p->overlay_p)
1321 {
1322 /* In case the same realized face is used for fringes and
1323 for something displayed in the text (e.g. face `region' on
1324 mono-displays, the fill style may have been changed to
1325 FillSolid in x_draw_glyph_string_background. */
1326 if (face->stipple)
1327 XSetFillStyle (display, face->gc, FillOpaqueStippled);
1328 else
1329 XSetForeground (display, face->gc, face->background);
1330
1331 x_fill_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
1332
1333 if (!face->stipple)
1334 XSetForeground (display, face->gc, face->foreground);
1335 }
1336
1337 #ifdef USE_CAIRO
1338 if (p->which && p->which < max_fringe_bmp)
1339 {
1340 XGCValues gcv;
1341
1342 XGetGCValues (display, gc, GCForeground | GCBackground, &gcv);
1343 XSetForeground (display, gc, (p->cursor_p
1344 ? (p->overlay_p ? face->background
1345 : f->output_data.x->cursor_pixel)
1346 : face->foreground));
1347 XSetBackground (display, gc, face->background);
1348 x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, p->dh,
1349 p->wd, p->h, p->x, p->y, p->overlay_p);
1350 XSetForeground (display, gc, gcv.foreground);
1351 XSetBackground (display, gc, gcv.background);
1352 }
1353 #else /* not USE_CAIRO */
1354 if (p->which)
1355 {
1356 Window window = FRAME_X_WINDOW (f);
1357 char *bits;
1358 Pixmap pixmap, clipmask = (Pixmap) 0;
1359 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
1360 XGCValues gcv;
1361
1362 if (p->wd > 8)
1363 bits = (char *) (p->bits + p->dh);
1364 else
1365 bits = (char *) p->bits + p->dh;
1366
1367 /* Draw the bitmap. I believe these small pixmaps can be cached
1368 by the server. */
1369 pixmap = XCreatePixmapFromBitmapData (display, window, bits, p->wd, p->h,
1370 (p->cursor_p
1371 ? (p->overlay_p ? face->background
1372 : f->output_data.x->cursor_pixel)
1373 : face->foreground),
1374 face->background, depth);
1375
1376 if (p->overlay_p)
1377 {
1378 clipmask = XCreatePixmapFromBitmapData (display,
1379 FRAME_DISPLAY_INFO (f)->root_window,
1380 bits, p->wd, p->h,
1381 1, 0, 1);
1382 gcv.clip_mask = clipmask;
1383 gcv.clip_x_origin = p->x;
1384 gcv.clip_y_origin = p->y;
1385 XChangeGC (display, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
1386 }
1387
1388 XCopyArea (display, pixmap, window, gc, 0, 0,
1389 p->wd, p->h, p->x, p->y);
1390 XFreePixmap (display, pixmap);
1391
1392 if (p->overlay_p)
1393 {
1394 gcv.clip_mask = (Pixmap) 0;
1395 XChangeGC (display, gc, GCClipMask, &gcv);
1396 XFreePixmap (display, clipmask);
1397 }
1398 }
1399 #endif /* not USE_CAIRO */
1400
1401 x_reset_clip_rectangles (f, gc);
1402 }
1403
1404 /***********************************************************************
1405 Glyph display
1406 ***********************************************************************/
1407
1408
1409
1410 static void x_set_glyph_string_clipping (struct glyph_string *);
1411 static void x_set_glyph_string_gc (struct glyph_string *);
1412 static void x_draw_glyph_string_foreground (struct glyph_string *);
1413 static void x_draw_composite_glyph_string_foreground (struct glyph_string *);
1414 static void x_draw_glyph_string_box (struct glyph_string *);
1415 static void x_draw_glyph_string (struct glyph_string *);
1416 static _Noreturn void x_delete_glyphs (struct frame *, int);
1417 static void x_compute_glyph_string_overhangs (struct glyph_string *);
1418 static void x_set_cursor_gc (struct glyph_string *);
1419 static void x_set_mode_line_face_gc (struct glyph_string *);
1420 static void x_set_mouse_face_gc (struct glyph_string *);
1421 static bool x_alloc_lighter_color (struct frame *, Display *, Colormap,
1422 unsigned long *, double, int);
1423 static void x_setup_relief_color (struct frame *, struct relief *,
1424 double, int, unsigned long);
1425 static void x_setup_relief_colors (struct glyph_string *);
1426 static void x_draw_image_glyph_string (struct glyph_string *);
1427 static void x_draw_image_relief (struct glyph_string *);
1428 static void x_draw_image_foreground (struct glyph_string *);
1429 static void x_draw_image_foreground_1 (struct glyph_string *, Pixmap);
1430 static void x_clear_glyph_string_rect (struct glyph_string *, int,
1431 int, int, int);
1432 static void x_draw_relief_rect (struct frame *, int, int, int, int,
1433 int, bool, bool, bool, bool, bool,
1434 XRectangle *);
1435 static void x_draw_box_rect (struct glyph_string *, int, int, int, int,
1436 int, bool, bool, XRectangle *);
1437 static void x_scroll_bar_clear (struct frame *);
1438
1439 #ifdef GLYPH_DEBUG
1440 static void x_check_font (struct frame *, struct font *);
1441 #endif
1442
1443
1444 /* Set S->gc to a suitable GC for drawing glyph string S in cursor
1445 face. */
1446
1447 static void
1448 x_set_cursor_gc (struct glyph_string *s)
1449 {
1450 if (s->font == FRAME_FONT (s->f)
1451 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
1452 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
1453 && !s->cmp)
1454 s->gc = s->f->output_data.x->cursor_gc;
1455 else
1456 {
1457 /* Cursor on non-default face: must merge. */
1458 XGCValues xgcv;
1459 unsigned long mask;
1460
1461 xgcv.background = s->f->output_data.x->cursor_pixel;
1462 xgcv.foreground = s->face->background;
1463
1464 /* If the glyph would be invisible, try a different foreground. */
1465 if (xgcv.foreground == xgcv.background)
1466 xgcv.foreground = s->face->foreground;
1467 if (xgcv.foreground == xgcv.background)
1468 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
1469 if (xgcv.foreground == xgcv.background)
1470 xgcv.foreground = s->face->foreground;
1471
1472 /* Make sure the cursor is distinct from text in this face. */
1473 if (xgcv.background == s->face->background
1474 && xgcv.foreground == s->face->foreground)
1475 {
1476 xgcv.background = s->face->foreground;
1477 xgcv.foreground = s->face->background;
1478 }
1479
1480 IF_DEBUG (x_check_font (s->f, s->font));
1481 xgcv.graphics_exposures = False;
1482 mask = GCForeground | GCBackground | GCGraphicsExposures;
1483
1484 if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1485 XChangeGC (s->display, FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1486 mask, &xgcv);
1487 else
1488 FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
1489 = XCreateGC (s->display, s->window, mask, &xgcv);
1490
1491 s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1492 }
1493 }
1494
1495
1496 /* Set up S->gc of glyph string S for drawing text in mouse face. */
1497
1498 static void
1499 x_set_mouse_face_gc (struct glyph_string *s)
1500 {
1501 int face_id;
1502 struct face *face;
1503
1504 /* What face has to be used last for the mouse face? */
1505 face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
1506 face = FACE_FROM_ID_OR_NULL (s->f, face_id);
1507 if (face == NULL)
1508 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1509
1510 if (s->first_glyph->type == CHAR_GLYPH)
1511 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
1512 else
1513 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
1514 s->face = FACE_FROM_ID (s->f, face_id);
1515 prepare_face_for_display (s->f, s->face);
1516
1517 if (s->font == s->face->font)
1518 s->gc = s->face->gc;
1519 else
1520 {
1521 /* Otherwise construct scratch_cursor_gc with values from FACE
1522 except for FONT. */
1523 XGCValues xgcv;
1524 unsigned long mask;
1525
1526 xgcv.background = s->face->background;
1527 xgcv.foreground = s->face->foreground;
1528 xgcv.graphics_exposures = False;
1529 mask = GCForeground | GCBackground | GCGraphicsExposures;
1530
1531 if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1532 XChangeGC (s->display, FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1533 mask, &xgcv);
1534 else
1535 FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
1536 = XCreateGC (s->display, s->window, mask, &xgcv);
1537
1538 s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1539
1540 }
1541 eassert (s->gc != 0);
1542 }
1543
1544
1545 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
1546 Faces to use in the mode line have already been computed when the
1547 matrix was built, so there isn't much to do, here. */
1548
1549 static void
1550 x_set_mode_line_face_gc (struct glyph_string *s)
1551 {
1552 s->gc = s->face->gc;
1553 }
1554
1555
1556 /* Set S->gc of glyph string S for drawing that glyph string. Set
1557 S->stippled_p to a non-zero value if the face of S has a stipple
1558 pattern. */
1559
1560 static void
1561 x_set_glyph_string_gc (struct glyph_string *s)
1562 {
1563 prepare_face_for_display (s->f, s->face);
1564
1565 if (s->hl == DRAW_NORMAL_TEXT)
1566 {
1567 s->gc = s->face->gc;
1568 s->stippled_p = s->face->stipple != 0;
1569 }
1570 else if (s->hl == DRAW_INVERSE_VIDEO)
1571 {
1572 x_set_mode_line_face_gc (s);
1573 s->stippled_p = s->face->stipple != 0;
1574 }
1575 else if (s->hl == DRAW_CURSOR)
1576 {
1577 x_set_cursor_gc (s);
1578 s->stippled_p = false;
1579 }
1580 else if (s->hl == DRAW_MOUSE_FACE)
1581 {
1582 x_set_mouse_face_gc (s);
1583 s->stippled_p = s->face->stipple != 0;
1584 }
1585 else if (s->hl == DRAW_IMAGE_RAISED
1586 || s->hl == DRAW_IMAGE_SUNKEN)
1587 {
1588 s->gc = s->face->gc;
1589 s->stippled_p = s->face->stipple != 0;
1590 }
1591 else
1592 emacs_abort ();
1593
1594 /* GC must have been set. */
1595 eassert (s->gc != 0);
1596 }
1597
1598
1599 /* Set clipping for output of glyph string S. S may be part of a mode
1600 line or menu if we don't have X toolkit support. */
1601
1602 static void
1603 x_set_glyph_string_clipping (struct glyph_string *s)
1604 {
1605 XRectangle *r = s->clip;
1606 int n = get_glyph_string_clip_rects (s, r, 2);
1607
1608 if (n > 0)
1609 x_set_clip_rectangles (s->f, s->gc, r, n);
1610 s->num_clips = n;
1611 }
1612
1613
1614 /* Set SRC's clipping for output of glyph string DST. This is called
1615 when we are drawing DST's left_overhang or right_overhang only in
1616 the area of SRC. */
1617
1618 static void
1619 x_set_glyph_string_clipping_exactly (struct glyph_string *src, struct glyph_string *dst)
1620 {
1621 XRectangle r;
1622
1623 r.x = src->x;
1624 r.width = src->width;
1625 r.y = src->y;
1626 r.height = src->height;
1627 dst->clip[0] = r;
1628 dst->num_clips = 1;
1629 x_set_clip_rectangles (dst->f, dst->gc, &r, 1);
1630 }
1631
1632
1633 /* RIF:
1634 Compute left and right overhang of glyph string S. */
1635
1636 static void
1637 x_compute_glyph_string_overhangs (struct glyph_string *s)
1638 {
1639 if (s->cmp == NULL
1640 && (s->first_glyph->type == CHAR_GLYPH
1641 || s->first_glyph->type == COMPOSITE_GLYPH))
1642 {
1643 struct font_metrics metrics;
1644
1645 if (s->first_glyph->type == CHAR_GLYPH)
1646 {
1647 unsigned *code = alloca (sizeof (unsigned) * s->nchars);
1648 struct font *font = s->font;
1649 int i;
1650
1651 for (i = 0; i < s->nchars; i++)
1652 code[i] = (s->char2b[i].byte1 << 8) | s->char2b[i].byte2;
1653 font->driver->text_extents (font, code, s->nchars, &metrics);
1654 }
1655 else
1656 {
1657 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1658
1659 composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics);
1660 }
1661 s->right_overhang = (metrics.rbearing > metrics.width
1662 ? metrics.rbearing - metrics.width : 0);
1663 s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0;
1664 }
1665 else if (s->cmp)
1666 {
1667 s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
1668 s->left_overhang = - s->cmp->lbearing;
1669 }
1670 }
1671
1672
1673 /* Fill rectangle X, Y, W, H with background color of glyph string S. */
1674
1675 static void
1676 x_clear_glyph_string_rect (struct glyph_string *s, int x, int y, int w, int h)
1677 {
1678 XGCValues xgcv;
1679 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
1680 XSetForeground (s->display, s->gc, xgcv.background);
1681 x_fill_rectangle (s->f, s->gc, x, y, w, h);
1682 XSetForeground (s->display, s->gc, xgcv.foreground);
1683 }
1684
1685
1686 /* Draw the background of glyph_string S. If S->background_filled_p
1687 is non-zero don't draw it. FORCE_P non-zero means draw the
1688 background even if it wouldn't be drawn normally. This is used
1689 when a string preceding S draws into the background of S, or S
1690 contains the first component of a composition. */
1691
1692 static void
1693 x_draw_glyph_string_background (struct glyph_string *s, bool force_p)
1694 {
1695 /* Nothing to do if background has already been drawn or if it
1696 shouldn't be drawn in the first place. */
1697 if (!s->background_filled_p)
1698 {
1699 int box_line_width = max (s->face->box_line_width, 0);
1700
1701 if (s->stippled_p)
1702 {
1703 /* Fill background with a stipple pattern. */
1704 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
1705 x_fill_rectangle (s->f, s->gc, s->x,
1706 s->y + box_line_width,
1707 s->background_width,
1708 s->height - 2 * box_line_width);
1709 XSetFillStyle (s->display, s->gc, FillSolid);
1710 s->background_filled_p = true;
1711 }
1712 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
1713 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust
1714 font dimensions, since the actual glyphs might be
1715 much smaller. So in that case we always clear the
1716 rectangle with background color. */
1717 || FONT_TOO_HIGH (s->font)
1718 || s->font_not_found_p
1719 || s->extends_to_end_of_line_p
1720 || force_p)
1721 {
1722 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
1723 s->background_width,
1724 s->height - 2 * box_line_width);
1725 s->background_filled_p = true;
1726 }
1727 }
1728 }
1729
1730
1731 /* Draw the foreground of glyph string S. */
1732
1733 static void
1734 x_draw_glyph_string_foreground (struct glyph_string *s)
1735 {
1736 int i, x;
1737
1738 /* If first glyph of S has a left box line, start drawing the text
1739 of S to the right of that box line. */
1740 if (s->face->box != FACE_NO_BOX
1741 && s->first_glyph->left_box_line_p)
1742 x = s->x + eabs (s->face->box_line_width);
1743 else
1744 x = s->x;
1745
1746 /* Draw characters of S as rectangles if S's font could not be
1747 loaded. */
1748 if (s->font_not_found_p)
1749 {
1750 for (i = 0; i < s->nchars; ++i)
1751 {
1752 struct glyph *g = s->first_glyph + i;
1753 x_draw_rectangle (s->f,
1754 s->gc, x, s->y, g->pixel_width - 1,
1755 s->height - 1);
1756 x += g->pixel_width;
1757 }
1758 }
1759 else
1760 {
1761 struct font *font = s->font;
1762 int boff = font->baseline_offset;
1763 int y;
1764
1765 if (font->vertical_centering)
1766 boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff;
1767
1768 y = s->ybase - boff;
1769 if (s->for_overlaps
1770 || (s->background_filled_p && s->hl != DRAW_CURSOR))
1771 font->driver->draw (s, 0, s->nchars, x, y, false);
1772 else
1773 font->driver->draw (s, 0, s->nchars, x, y, true);
1774 if (s->face->overstrike)
1775 font->driver->draw (s, 0, s->nchars, x + 1, y, false);
1776 }
1777 }
1778
1779 /* Draw the foreground of composite glyph string S. */
1780
1781 static void
1782 x_draw_composite_glyph_string_foreground (struct glyph_string *s)
1783 {
1784 int i, j, x;
1785 struct font *font = s->font;
1786
1787 /* If first glyph of S has a left box line, start drawing the text
1788 of S to the right of that box line. */
1789 if (s->face && s->face->box != FACE_NO_BOX
1790 && s->first_glyph->left_box_line_p)
1791 x = s->x + eabs (s->face->box_line_width);
1792 else
1793 x = s->x;
1794
1795 /* S is a glyph string for a composition. S->cmp_from is the index
1796 of the first character drawn for glyphs of this composition.
1797 S->cmp_from == 0 means we are drawing the very first character of
1798 this composition. */
1799
1800 /* Draw a rectangle for the composition if the font for the very
1801 first character of the composition could not be loaded. */
1802 if (s->font_not_found_p)
1803 {
1804 if (s->cmp_from == 0)
1805 x_draw_rectangle (s->f, s->gc, x, s->y,
1806 s->width - 1, s->height - 1);
1807 }
1808 else if (! s->first_glyph->u.cmp.automatic)
1809 {
1810 int y = s->ybase;
1811
1812 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
1813 /* TAB in a composition means display glyphs with padding
1814 space on the left or right. */
1815 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
1816 {
1817 int xx = x + s->cmp->offsets[j * 2];
1818 int yy = y - s->cmp->offsets[j * 2 + 1];
1819
1820 font->driver->draw (s, j, j + 1, xx, yy, false);
1821 if (s->face->overstrike)
1822 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
1823 }
1824 }
1825 else
1826 {
1827 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1828 Lisp_Object glyph;
1829 int y = s->ybase;
1830 int width = 0;
1831
1832 for (i = j = s->cmp_from; i < s->cmp_to; i++)
1833 {
1834 glyph = LGSTRING_GLYPH (gstring, i);
1835 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1836 width += LGLYPH_WIDTH (glyph);
1837 else
1838 {
1839 int xoff, yoff, wadjust;
1840
1841 if (j < i)
1842 {
1843 font->driver->draw (s, j, i, x, y, false);
1844 if (s->face->overstrike)
1845 font->driver->draw (s, j, i, x + 1, y, false);
1846 x += width;
1847 }
1848 xoff = LGLYPH_XOFF (glyph);
1849 yoff = LGLYPH_YOFF (glyph);
1850 wadjust = LGLYPH_WADJUST (glyph);
1851 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
1852 if (s->face->overstrike)
1853 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
1854 false);
1855 x += wadjust;
1856 j = i + 1;
1857 width = 0;
1858 }
1859 }
1860 if (j < i)
1861 {
1862 font->driver->draw (s, j, i, x, y, false);
1863 if (s->face->overstrike)
1864 font->driver->draw (s, j, i, x + 1, y, false);
1865 }
1866 }
1867 }
1868
1869
1870 /* Draw the foreground of glyph string S for glyphless characters. */
1871
1872 static void
1873 x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
1874 {
1875 struct glyph *glyph = s->first_glyph;
1876 XChar2b char2b[8];
1877 int x, i, j;
1878
1879 /* If first glyph of S has a left box line, start drawing the text
1880 of S to the right of that box line. */
1881 if (s->face && s->face->box != FACE_NO_BOX
1882 && s->first_glyph->left_box_line_p)
1883 x = s->x + eabs (s->face->box_line_width);
1884 else
1885 x = s->x;
1886
1887 s->char2b = char2b;
1888
1889 for (i = 0; i < s->nchars; i++, glyph++)
1890 {
1891 char buf[7], *str = NULL;
1892 int len = glyph->u.glyphless.len;
1893
1894 if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
1895 {
1896 if (len > 0
1897 && CHAR_TABLE_P (Vglyphless_char_display)
1898 && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
1899 >= 1))
1900 {
1901 Lisp_Object acronym
1902 = (! glyph->u.glyphless.for_no_font
1903 ? CHAR_TABLE_REF (Vglyphless_char_display,
1904 glyph->u.glyphless.ch)
1905 : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
1906 if (STRINGP (acronym))
1907 str = SSDATA (acronym);
1908 }
1909 }
1910 else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE)
1911 {
1912 sprintf (buf, "%0*X",
1913 glyph->u.glyphless.ch < 0x10000 ? 4 : 6,
1914 glyph->u.glyphless.ch + 0u);
1915 str = buf;
1916 }
1917
1918 if (str)
1919 {
1920 int upper_len = (len + 1) / 2;
1921 unsigned code;
1922
1923 /* It is assured that all LEN characters in STR is ASCII. */
1924 for (j = 0; j < len; j++)
1925 {
1926 code = s->font->driver->encode_char (s->font, str[j]);
1927 STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF);
1928 }
1929 s->font->driver->draw (s, 0, upper_len,
1930 x + glyph->slice.glyphless.upper_xoff,
1931 s->ybase + glyph->slice.glyphless.upper_yoff,
1932 false);
1933 s->font->driver->draw (s, upper_len, len,
1934 x + glyph->slice.glyphless.lower_xoff,
1935 s->ybase + glyph->slice.glyphless.lower_yoff,
1936 false);
1937 }
1938 if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
1939 x_draw_rectangle (s->f, s->gc,
1940 x, s->ybase - glyph->ascent,
1941 glyph->pixel_width - 1,
1942 glyph->ascent + glyph->descent - 1);
1943 x += glyph->pixel_width;
1944 }
1945 }
1946
1947 #ifdef USE_X_TOOLKIT
1948
1949 #ifdef USE_LUCID
1950
1951 /* Return the frame on which widget WIDGET is used.. Abort if frame
1952 cannot be determined. */
1953
1954 static struct frame *
1955 x_frame_of_widget (Widget widget)
1956 {
1957 struct x_display_info *dpyinfo;
1958 Lisp_Object tail, frame;
1959 struct frame *f;
1960
1961 dpyinfo = x_display_info_for_display (XtDisplay (widget));
1962
1963 /* Find the top-level shell of the widget. Note that this function
1964 can be called when the widget is not yet realized, so XtWindow
1965 (widget) == 0. That's the reason we can't simply use
1966 x_any_window_to_frame. */
1967 while (!XtIsTopLevelShell (widget))
1968 widget = XtParent (widget);
1969
1970 /* Look for a frame with that top-level widget. Allocate the color
1971 on that frame to get the right gamma correction value. */
1972 FOR_EACH_FRAME (tail, frame)
1973 {
1974 f = XFRAME (frame);
1975 if (FRAME_X_P (f)
1976 && f->output_data.nothing != 1
1977 && FRAME_DISPLAY_INFO (f) == dpyinfo
1978 && f->output_data.x->widget == widget)
1979 return f;
1980 }
1981 emacs_abort ();
1982 }
1983
1984 /* Allocate a color which is lighter or darker than *PIXEL by FACTOR
1985 or DELTA. Try a color with RGB values multiplied by FACTOR first.
1986 If this produces the same color as PIXEL, try a color where all RGB
1987 values have DELTA added. Return the allocated color in *PIXEL.
1988 DISPLAY is the X display, CMAP is the colormap to operate on.
1989 Value is true if successful. */
1990
1991 bool
1992 x_alloc_lighter_color_for_widget (Widget widget, Display *display, Colormap cmap,
1993 unsigned long *pixel, double factor, int delta)
1994 {
1995 struct frame *f = x_frame_of_widget (widget);
1996 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
1997 }
1998
1999 #endif /* USE_LUCID */
2000
2001
2002 /* Structure specifying which arguments should be passed by Xt to
2003 cvt_string_to_pixel. We want the widget's screen and colormap. */
2004
2005 static XtConvertArgRec cvt_string_to_pixel_args[] =
2006 {
2007 {XtWidgetBaseOffset, (XtPointer) offsetof (WidgetRec, core.screen),
2008 sizeof (Screen *)},
2009 {XtWidgetBaseOffset, (XtPointer) offsetof (WidgetRec, core.colormap),
2010 sizeof (Colormap)}
2011 };
2012
2013
2014 /* The address of this variable is returned by
2015 cvt_string_to_pixel. */
2016
2017 static Pixel cvt_string_to_pixel_value;
2018
2019
2020 /* Convert a color name to a pixel color.
2021
2022 DPY is the display we are working on.
2023
2024 ARGS is an array of *NARGS XrmValue structures holding additional
2025 information about the widget for which the conversion takes place.
2026 The contents of this array are determined by the specification
2027 in cvt_string_to_pixel_args.
2028
2029 FROM is a pointer to an XrmValue which points to the color name to
2030 convert. TO is an XrmValue in which to return the pixel color.
2031
2032 CLOSURE_RET is a pointer to user-data, in which we record if
2033 we allocated the color or not.
2034
2035 Value is True if successful, False otherwise. */
2036
2037 static Boolean
2038 cvt_string_to_pixel (Display *dpy, XrmValue *args, Cardinal *nargs,
2039 XrmValue *from, XrmValue *to,
2040 XtPointer *closure_ret)
2041 {
2042 Screen *screen;
2043 Colormap cmap;
2044 Pixel pixel;
2045 String color_name;
2046 XColor color;
2047
2048 if (*nargs != 2)
2049 {
2050 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
2051 "wrongParameters", "cvt_string_to_pixel",
2052 "XtToolkitError",
2053 "Screen and colormap args required", NULL, NULL);
2054 return False;
2055 }
2056
2057 screen = *(Screen **) args[0].addr;
2058 cmap = *(Colormap *) args[1].addr;
2059 color_name = (String) from->addr;
2060
2061 if (strcmp (color_name, XtDefaultBackground) == 0)
2062 {
2063 *closure_ret = (XtPointer) False;
2064 pixel = WhitePixelOfScreen (screen);
2065 }
2066 else if (strcmp (color_name, XtDefaultForeground) == 0)
2067 {
2068 *closure_ret = (XtPointer) False;
2069 pixel = BlackPixelOfScreen (screen);
2070 }
2071 else if (XParseColor (dpy, cmap, color_name, &color)
2072 && x_alloc_nearest_color_1 (dpy, cmap, &color))
2073 {
2074 pixel = color.pixel;
2075 *closure_ret = (XtPointer) True;
2076 }
2077 else
2078 {
2079 String params[1];
2080 Cardinal nparams = 1;
2081
2082 params[0] = color_name;
2083 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
2084 "badValue", "cvt_string_to_pixel",
2085 "XtToolkitError", "Invalid color '%s'",
2086 params, &nparams);
2087 return False;
2088 }
2089
2090 if (to->addr != NULL)
2091 {
2092 if (to->size < sizeof (Pixel))
2093 {
2094 to->size = sizeof (Pixel);
2095 return False;
2096 }
2097
2098 *(Pixel *) to->addr = pixel;
2099 }
2100 else
2101 {
2102 cvt_string_to_pixel_value = pixel;
2103 to->addr = (XtPointer) &cvt_string_to_pixel_value;
2104 }
2105
2106 to->size = sizeof (Pixel);
2107 return True;
2108 }
2109
2110
2111 /* Free a pixel color which was previously allocated via
2112 cvt_string_to_pixel. This is registered as the destructor
2113 for this type of resource via XtSetTypeConverter.
2114
2115 APP is the application context in which we work.
2116
2117 TO is a pointer to an XrmValue holding the color to free.
2118 CLOSURE is the value we stored in CLOSURE_RET for this color
2119 in cvt_string_to_pixel.
2120
2121 ARGS and NARGS are like for cvt_string_to_pixel. */
2122
2123 static void
2124 cvt_pixel_dtor (XtAppContext app, XrmValuePtr to, XtPointer closure, XrmValuePtr args,
2125 Cardinal *nargs)
2126 {
2127 if (*nargs != 2)
2128 {
2129 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
2130 "XtToolkitError",
2131 "Screen and colormap arguments required",
2132 NULL, NULL);
2133 }
2134 else if (closure != NULL)
2135 {
2136 /* We did allocate the pixel, so free it. */
2137 Screen *screen = *(Screen **) args[0].addr;
2138 Colormap cmap = *(Colormap *) args[1].addr;
2139 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
2140 (Pixel *) to->addr, 1);
2141 }
2142 }
2143
2144
2145 #endif /* USE_X_TOOLKIT */
2146
2147
2148 /* Value is an array of XColor structures for the contents of the
2149 color map of display DPY. Set *NCELLS to the size of the array.
2150 Note that this probably shouldn't be called for large color maps,
2151 say a 24-bit TrueColor map. */
2152
2153 static const XColor *
2154 x_color_cells (Display *dpy, int *ncells)
2155 {
2156 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
2157 eassume (dpyinfo);
2158
2159 if (dpyinfo->color_cells == NULL)
2160 {
2161 Screen *screen = dpyinfo->screen;
2162 int ncolor_cells = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
2163 int i;
2164
2165 dpyinfo->color_cells = xnmalloc (ncolor_cells,
2166 sizeof *dpyinfo->color_cells);
2167 dpyinfo->ncolor_cells = ncolor_cells;
2168
2169 for (i = 0; i < ncolor_cells; ++i)
2170 dpyinfo->color_cells[i].pixel = i;
2171
2172 XQueryColors (dpy, dpyinfo->cmap,
2173 dpyinfo->color_cells, ncolor_cells);
2174 }
2175
2176 *ncells = dpyinfo->ncolor_cells;
2177 return dpyinfo->color_cells;
2178 }
2179
2180
2181 /* On frame F, translate pixel colors to RGB values for the NCOLORS
2182 colors in COLORS. Use cached information, if available. */
2183
2184 void
2185 x_query_colors (struct frame *f, XColor *colors, int ncolors)
2186 {
2187 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2188
2189 if (dpyinfo->red_bits > 0)
2190 {
2191 /* For TrueColor displays, we can decompose the RGB value
2192 directly. */
2193 int i;
2194 unsigned int rmult, gmult, bmult;
2195 unsigned int rmask, gmask, bmask;
2196
2197 rmask = (1 << dpyinfo->red_bits) - 1;
2198 gmask = (1 << dpyinfo->green_bits) - 1;
2199 bmask = (1 << dpyinfo->blue_bits) - 1;
2200 /* If we're widening, for example, 8 bits in the pixel value to
2201 16 bits for the separate-color representation, we want to
2202 extrapolate the lower bits based on those bits available --
2203 in other words, we'd like 0xff to become 0xffff instead of
2204 the 0xff00 we'd get by just zero-filling the lower bits.
2205
2206 We generate a 32-bit scaled-up value and shift it, in case
2207 the bit count doesn't divide 16 evenly (e.g., when dealing
2208 with a 3-3-2 bit RGB display), to get more of the lower bits
2209 correct.
2210
2211 Should we cache the multipliers in dpyinfo? Maybe
2212 special-case the 8-8-8 common case? */
2213 rmult = 0xffffffff / rmask;
2214 gmult = 0xffffffff / gmask;
2215 bmult = 0xffffffff / bmask;
2216
2217 for (i = 0; i < ncolors; ++i)
2218 {
2219 unsigned int r, g, b;
2220 unsigned long pixel = colors[i].pixel;
2221
2222 r = (pixel >> dpyinfo->red_offset) & rmask;
2223 g = (pixel >> dpyinfo->green_offset) & gmask;
2224 b = (pixel >> dpyinfo->blue_offset) & bmask;
2225
2226 colors[i].red = (r * rmult) >> 16;
2227 colors[i].green = (g * gmult) >> 16;
2228 colors[i].blue = (b * bmult) >> 16;
2229 }
2230 return;
2231 }
2232
2233 if (dpyinfo->color_cells)
2234 {
2235 int i;
2236 for (i = 0; i < ncolors; ++i)
2237 {
2238 unsigned long pixel = colors[i].pixel;
2239 eassert (pixel < dpyinfo->ncolor_cells);
2240 eassert (dpyinfo->color_cells[pixel].pixel == pixel);
2241 colors[i] = dpyinfo->color_cells[pixel];
2242 }
2243 return;
2244 }
2245
2246 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
2247 }
2248
2249
2250 /* On frame F, translate pixel color to RGB values for the color in
2251 COLOR. Use cached information, if available. */
2252
2253 void
2254 x_query_color (struct frame *f, XColor *color)
2255 {
2256 x_query_colors (f, color, 1);
2257 }
2258
2259
2260 /* On frame F, translate the color name to RGB values. Use cached
2261 information, if possible.
2262
2263 Note that there is currently no way to clean old entries out of the
2264 cache. However, it is limited to names in the server's database,
2265 and names we've actually looked up; list-colors-display is probably
2266 the most color-intensive case we're likely to hit. */
2267
2268 Status x_parse_color (struct frame *f, const char *color_name,
2269 XColor *color)
2270 {
2271 Display *dpy = FRAME_X_DISPLAY (f);
2272 Colormap cmap = FRAME_X_COLORMAP (f);
2273 struct color_name_cache_entry *cache_entry;
2274
2275 if (color_name[0] == '#')
2276 {
2277 /* The hex form is parsed directly by XParseColor without
2278 talking to the X server. No need for caching. */
2279 return XParseColor (dpy, cmap, color_name, color);
2280 }
2281
2282 for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names; cache_entry;
2283 cache_entry = cache_entry->next)
2284 {
2285 if (!xstrcasecmp(cache_entry->name, color_name))
2286 {
2287 *color = cache_entry->rgb;
2288 return 1;
2289 }
2290 }
2291
2292 if (XParseColor (dpy, cmap, color_name, color) == 0)
2293 /* No caching of negative results, currently. */
2294 return 0;
2295
2296 cache_entry = xzalloc (sizeof *cache_entry);
2297 cache_entry->rgb = *color;
2298 cache_entry->name = xstrdup (color_name);
2299 cache_entry->next = FRAME_DISPLAY_INFO (f)->color_names;
2300 FRAME_DISPLAY_INFO (f)->color_names = cache_entry;
2301 return 1;
2302 }
2303
2304
2305 /* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
2306 exact match can't be allocated, try the nearest color available.
2307 Value is true if successful. Set *COLOR to the color
2308 allocated. */
2309
2310 static bool
2311 x_alloc_nearest_color_1 (Display *dpy, Colormap cmap, XColor *color)
2312 {
2313 bool rc;
2314
2315 rc = XAllocColor (dpy, cmap, color) != 0;
2316 if (rc == 0)
2317 {
2318 /* If we got to this point, the colormap is full, so we're going
2319 to try to get the next closest color. The algorithm used is
2320 a least-squares matching, which is what X uses for closest
2321 color matching with StaticColor visuals. */
2322 int nearest, i;
2323 int max_color_delta = 255;
2324 int max_delta = 3 * max_color_delta;
2325 int nearest_delta = max_delta + 1;
2326 int ncells;
2327 const XColor *cells = x_color_cells (dpy, &ncells);
2328
2329 for (nearest = i = 0; i < ncells; ++i)
2330 {
2331 int dred = (color->red >> 8) - (cells[i].red >> 8);
2332 int dgreen = (color->green >> 8) - (cells[i].green >> 8);
2333 int dblue = (color->blue >> 8) - (cells[i].blue >> 8);
2334 int delta = dred * dred + dgreen * dgreen + dblue * dblue;
2335
2336 if (delta < nearest_delta)
2337 {
2338 nearest = i;
2339 nearest_delta = delta;
2340 }
2341 }
2342
2343 color->red = cells[nearest].red;
2344 color->green = cells[nearest].green;
2345 color->blue = cells[nearest].blue;
2346 rc = XAllocColor (dpy, cmap, color) != 0;
2347 }
2348 else
2349 {
2350 /* If allocation succeeded, and the allocated pixel color is not
2351 equal to a cached pixel color recorded earlier, there was a
2352 change in the colormap, so clear the color cache. */
2353 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
2354 eassume (dpyinfo);
2355
2356 if (dpyinfo->color_cells)
2357 {
2358 XColor *cached_color = &dpyinfo->color_cells[color->pixel];
2359 if (cached_color->red != color->red
2360 || cached_color->blue != color->blue
2361 || cached_color->green != color->green)
2362 {
2363 xfree (dpyinfo->color_cells);
2364 dpyinfo->color_cells = NULL;
2365 dpyinfo->ncolor_cells = 0;
2366 }
2367 }
2368 }
2369
2370 #ifdef DEBUG_X_COLORS
2371 if (rc)
2372 register_color (color->pixel);
2373 #endif /* DEBUG_X_COLORS */
2374
2375 return rc;
2376 }
2377
2378
2379 /* Allocate the color COLOR->pixel on frame F, colormap CMAP, after
2380 gamma correction. If an exact match can't be allocated, try the
2381 nearest color available. Value is true if successful. Set *COLOR
2382 to the color allocated. */
2383
2384 bool
2385 x_alloc_nearest_color (struct frame *f, Colormap cmap, XColor *color)
2386 {
2387 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2388
2389 gamma_correct (f, color);
2390
2391 if (dpyinfo->red_bits > 0)
2392 {
2393 color->pixel = x_make_truecolor_pixel (dpyinfo,
2394 color->red,
2395 color->green,
2396 color->blue);
2397 return true;
2398 }
2399
2400 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
2401 }
2402
2403
2404 /* Allocate color PIXEL on frame F. PIXEL must already be allocated.
2405 It's necessary to do this instead of just using PIXEL directly to
2406 get color reference counts right. */
2407
2408 unsigned long
2409 x_copy_color (struct frame *f, unsigned long pixel)
2410 {
2411 XColor color;
2412
2413 /* If display has an immutable color map, freeing colors is not
2414 necessary and some servers don't allow it. Since we won't free a
2415 color once we've allocated it, we don't need to re-allocate it to
2416 maintain the server's reference count. */
2417 if (!x_mutable_colormap (FRAME_X_VISUAL (f)))
2418 return pixel;
2419
2420 color.pixel = pixel;
2421 block_input ();
2422 /* The color could still be found in the color_cells array. */
2423 x_query_color (f, &color);
2424 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
2425 unblock_input ();
2426 #ifdef DEBUG_X_COLORS
2427 register_color (pixel);
2428 #endif
2429 return color.pixel;
2430 }
2431
2432
2433 /* Brightness beyond which a color won't have its highlight brightness
2434 boosted.
2435
2436 Nominally, highlight colors for `3d' faces are calculated by
2437 brightening an object's color by a constant scale factor, but this
2438 doesn't yield good results for dark colors, so for colors who's
2439 brightness is less than this value (on a scale of 0-65535) have an
2440 use an additional additive factor.
2441
2442 The value here is set so that the default menu-bar/mode-line color
2443 (grey75) will not have its highlights changed at all. */
2444 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
2445
2446
2447 /* Allocate a color which is lighter or darker than *PIXEL by FACTOR
2448 or DELTA. Try a color with RGB values multiplied by FACTOR first.
2449 If this produces the same color as PIXEL, try a color where all RGB
2450 values have DELTA added. Return the allocated color in *PIXEL.
2451 DISPLAY is the X display, CMAP is the colormap to operate on.
2452 Value is non-zero if successful. */
2453
2454 static bool
2455 x_alloc_lighter_color (struct frame *f, Display *display, Colormap cmap,
2456 unsigned long *pixel, double factor, int delta)
2457 {
2458 XColor color, new;
2459 long bright;
2460 bool success_p;
2461
2462 /* Get RGB color values. */
2463 color.pixel = *pixel;
2464 x_query_color (f, &color);
2465
2466 /* Change RGB values by specified FACTOR. Avoid overflow! */
2467 eassert (factor >= 0);
2468 new.red = min (0xffff, factor * color.red);
2469 new.green = min (0xffff, factor * color.green);
2470 new.blue = min (0xffff, factor * color.blue);
2471
2472 /* Calculate brightness of COLOR. */
2473 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
2474
2475 /* We only boost colors that are darker than
2476 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
2477 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
2478 /* Make an additive adjustment to NEW, because it's dark enough so
2479 that scaling by FACTOR alone isn't enough. */
2480 {
2481 /* How far below the limit this color is (0 - 1, 1 being darker). */
2482 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
2483 /* The additive adjustment. */
2484 int min_delta = delta * dimness * factor / 2;
2485
2486 if (factor < 1)
2487 {
2488 new.red = max (0, new.red - min_delta);
2489 new.green = max (0, new.green - min_delta);
2490 new.blue = max (0, new.blue - min_delta);
2491 }
2492 else
2493 {
2494 new.red = min (0xffff, min_delta + new.red);
2495 new.green = min (0xffff, min_delta + new.green);
2496 new.blue = min (0xffff, min_delta + new.blue);
2497 }
2498 }
2499
2500 /* Try to allocate the color. */
2501 success_p = x_alloc_nearest_color (f, cmap, &new);
2502 if (success_p)
2503 {
2504 if (new.pixel == *pixel)
2505 {
2506 /* If we end up with the same color as before, try adding
2507 delta to the RGB values. */
2508 x_free_colors (f, &new.pixel, 1);
2509
2510 new.red = min (0xffff, delta + color.red);
2511 new.green = min (0xffff, delta + color.green);
2512 new.blue = min (0xffff, delta + color.blue);
2513 success_p = x_alloc_nearest_color (f, cmap, &new);
2514 }
2515 else
2516 success_p = true;
2517 *pixel = new.pixel;
2518 }
2519
2520 return success_p;
2521 }
2522
2523
2524 /* Set up the foreground color for drawing relief lines of glyph
2525 string S. RELIEF is a pointer to a struct relief containing the GC
2526 with which lines will be drawn. Use a color that is FACTOR or
2527 DELTA lighter or darker than the relief's background which is found
2528 in S->f->output_data.x->relief_background. If such a color cannot
2529 be allocated, use DEFAULT_PIXEL, instead. */
2530
2531 static void
2532 x_setup_relief_color (struct frame *f, struct relief *relief, double factor,
2533 int delta, unsigned long default_pixel)
2534 {
2535 XGCValues xgcv;
2536 struct x_output *di = f->output_data.x;
2537 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
2538 unsigned long pixel;
2539 unsigned long background = di->relief_background;
2540 Colormap cmap = FRAME_X_COLORMAP (f);
2541 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2542 Display *dpy = FRAME_X_DISPLAY (f);
2543
2544 xgcv.graphics_exposures = False;
2545 xgcv.line_width = 1;
2546
2547 /* Free previously allocated color. The color cell will be reused
2548 when it has been freed as many times as it was allocated, so this
2549 doesn't affect faces using the same colors. */
2550 if (relief->gc && relief->pixel != -1)
2551 {
2552 x_free_colors (f, &relief->pixel, 1);
2553 relief->pixel = -1;
2554 }
2555
2556 /* Allocate new color. */
2557 xgcv.foreground = default_pixel;
2558 pixel = background;
2559 if (dpyinfo->n_planes != 1
2560 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
2561 xgcv.foreground = relief->pixel = pixel;
2562
2563 if (relief->gc == 0)
2564 {
2565 xgcv.stipple = dpyinfo->gray;
2566 mask |= GCStipple;
2567 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
2568 }
2569 else
2570 XChangeGC (dpy, relief->gc, mask, &xgcv);
2571 }
2572
2573
2574 /* Set up colors for the relief lines around glyph string S. */
2575
2576 static void
2577 x_setup_relief_colors (struct glyph_string *s)
2578 {
2579 struct x_output *di = s->f->output_data.x;
2580 unsigned long color;
2581
2582 if (s->face->use_box_color_for_shadows_p)
2583 color = s->face->box_color;
2584 else if (s->first_glyph->type == IMAGE_GLYPH
2585 && s->img->pixmap
2586 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2587 color = IMAGE_BACKGROUND (s->img, s->f, 0);
2588 else
2589 {
2590 XGCValues xgcv;
2591
2592 /* Get the background color of the face. */
2593 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
2594 color = xgcv.background;
2595 }
2596
2597 if (di->white_relief.gc == 0
2598 || color != di->relief_background)
2599 {
2600 di->relief_background = color;
2601 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
2602 WHITE_PIX_DEFAULT (s->f));
2603 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
2604 BLACK_PIX_DEFAULT (s->f));
2605 }
2606 }
2607
2608
2609 /* Draw a relief on frame F inside the rectangle given by LEFT_X,
2610 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
2611 to draw, it must be >= 0. RAISED_P means draw a raised
2612 relief. LEFT_P means draw a relief on the left side of
2613 the rectangle. RIGHT_P means draw a relief on the right
2614 side of the rectangle. CLIP_RECT is the clipping rectangle to use
2615 when drawing. */
2616
2617 static void
2618 x_draw_relief_rect (struct frame *f,
2619 int left_x, int top_y, int right_x, int bottom_y,
2620 int width, bool raised_p, bool top_p, bool bot_p,
2621 bool left_p, bool right_p,
2622 XRectangle *clip_rect)
2623 {
2624 #ifdef USE_CAIRO
2625 GC top_left_gc, bottom_right_gc;
2626 int corners = 0;
2627
2628 if (raised_p)
2629 {
2630 top_left_gc = f->output_data.x->white_relief.gc;
2631 bottom_right_gc = f->output_data.x->black_relief.gc;
2632 }
2633 else
2634 {
2635 top_left_gc = f->output_data.x->black_relief.gc;
2636 bottom_right_gc = f->output_data.x->white_relief.gc;
2637 }
2638
2639 x_set_clip_rectangles (f, top_left_gc, clip_rect, 1);
2640 x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1);
2641
2642 if (left_p)
2643 {
2644 x_fill_rectangle (f, top_left_gc, left_x, top_y,
2645 width, bottom_y + 1 - top_y);
2646 if (top_p)
2647 corners |= 1 << CORNER_TOP_LEFT;
2648 if (bot_p)
2649 corners |= 1 << CORNER_BOTTOM_LEFT;
2650 }
2651 if (right_p)
2652 {
2653 x_fill_rectangle (f, bottom_right_gc, right_x + 1 - width, top_y,
2654 width, bottom_y + 1 - top_y);
2655 if (top_p)
2656 corners |= 1 << CORNER_TOP_RIGHT;
2657 if (bot_p)
2658 corners |= 1 << CORNER_BOTTOM_RIGHT;
2659 }
2660 if (top_p)
2661 {
2662 if (!right_p)
2663 x_fill_rectangle (f, top_left_gc, left_x, top_y,
2664 right_x + 1 - left_x, width);
2665 else
2666 x_fill_trapezoid_for_relief (f, top_left_gc, left_x, top_y,
2667 right_x + 1 - left_x, width, 1);
2668 }
2669 if (bot_p)
2670 {
2671 if (!left_p)
2672 x_fill_rectangle (f, bottom_right_gc, left_x, bottom_y + 1 - width,
2673 right_x + 1 - left_x, width);
2674 else
2675 x_fill_trapezoid_for_relief (f, bottom_right_gc,
2676 left_x, bottom_y + 1 - width,
2677 right_x + 1 - left_x, width, 0);
2678 }
2679 if (left_p && width != 1)
2680 x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
2681 1, bottom_y + 1 - top_y);
2682 if (top_p && width != 1)
2683 x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
2684 right_x + 1 - left_x, 1);
2685 if (corners)
2686 {
2687 XSetBackground (FRAME_X_DISPLAY (f), top_left_gc,
2688 FRAME_BACKGROUND_PIXEL (f));
2689 x_erase_corners_for_relief (f, top_left_gc, left_x, top_y,
2690 right_x - left_x + 1, bottom_y - top_y + 1,
2691 6, 1, corners);
2692 }
2693
2694 x_reset_clip_rectangles (f, top_left_gc);
2695 x_reset_clip_rectangles (f, bottom_right_gc);
2696 #else
2697 Display *dpy = FRAME_X_DISPLAY (f);
2698 Window window = FRAME_X_WINDOW (f);
2699 int i;
2700 GC gc;
2701
2702 if (raised_p)
2703 gc = f->output_data.x->white_relief.gc;
2704 else
2705 gc = f->output_data.x->black_relief.gc;
2706 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
2707
2708 /* This code is more complicated than it has to be, because of two
2709 minor hacks to make the boxes look nicer: (i) if width > 1, draw
2710 the outermost line using the black relief. (ii) Omit the four
2711 corner pixels. */
2712
2713 /* Top. */
2714 if (top_p)
2715 {
2716 if (width == 1)
2717 XDrawLine (dpy, window, gc,
2718 left_x + left_p, top_y,
2719 right_x + !right_p, top_y);
2720
2721 for (i = 1; i < width; ++i)
2722 XDrawLine (dpy, window, gc,
2723 left_x + i * left_p, top_y + i,
2724 right_x + 1 - i * right_p, top_y + i);
2725 }
2726
2727 /* Left. */
2728 if (left_p)
2729 {
2730 if (width == 1)
2731 XDrawLine (dpy, window, gc, left_x, top_y + 1, left_x, bottom_y);
2732
2733 XClearArea (dpy, window, left_x, top_y, 1, 1, False);
2734 XClearArea (dpy, window, left_x, bottom_y, 1, 1, False);
2735
2736 for (i = (width > 1 ? 1 : 0); i < width; ++i)
2737 XDrawLine (dpy, window, gc,
2738 left_x + i, top_y + (i + 1) * top_p,
2739 left_x + i, bottom_y + 1 - (i + 1) * bot_p);
2740 }
2741
2742 XSetClipMask (dpy, gc, None);
2743 if (raised_p)
2744 gc = f->output_data.x->black_relief.gc;
2745 else
2746 gc = f->output_data.x->white_relief.gc;
2747 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
2748
2749 if (width > 1)
2750 {
2751 /* Outermost top line. */
2752 if (top_p)
2753 XDrawLine (dpy, window, gc,
2754 left_x + left_p, top_y,
2755 right_x + !right_p, top_y);
2756
2757 /* Outermost left line. */
2758 if (left_p)
2759 XDrawLine (dpy, window, gc, left_x, top_y + 1, left_x, bottom_y);
2760 }
2761
2762 /* Bottom. */
2763 if (bot_p)
2764 {
2765 XDrawLine (dpy, window, gc,
2766 left_x + left_p, bottom_y,
2767 right_x + !right_p, bottom_y);
2768 for (i = 1; i < width; ++i)
2769 XDrawLine (dpy, window, gc,
2770 left_x + i * left_p, bottom_y - i,
2771 right_x + 1 - i * right_p, bottom_y - i);
2772 }
2773
2774 /* Right. */
2775 if (right_p)
2776 {
2777 XClearArea (dpy, window, right_x, top_y, 1, 1, False);
2778 XClearArea (dpy, window, right_x, bottom_y, 1, 1, False);
2779 for (i = 0; i < width; ++i)
2780 XDrawLine (dpy, window, gc,
2781 right_x - i, top_y + (i + 1) * top_p,
2782 right_x - i, bottom_y + 1 - (i + 1) * bot_p);
2783 }
2784
2785 x_reset_clip_rectangles (f, gc);
2786
2787 #endif
2788 }
2789
2790
2791 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
2792 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
2793 draw, it must be >= 0. LEFT_P means draw a line on the
2794 left side of the rectangle. RIGHT_P means draw a line
2795 on the right side of the rectangle. CLIP_RECT is the clipping
2796 rectangle to use when drawing. */
2797
2798 static void
2799 x_draw_box_rect (struct glyph_string *s,
2800 int left_x, int top_y, int right_x, int bottom_y, int width,
2801 bool left_p, bool right_p, XRectangle *clip_rect)
2802 {
2803 XGCValues xgcv;
2804
2805 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
2806 XSetForeground (s->display, s->gc, s->face->box_color);
2807 x_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
2808
2809 /* Top. */
2810 x_fill_rectangle (s->f, s->gc,
2811 left_x, top_y, right_x - left_x + 1, width);
2812
2813 /* Left. */
2814 if (left_p)
2815 x_fill_rectangle (s->f, s->gc,
2816 left_x, top_y, width, bottom_y - top_y + 1);
2817
2818 /* Bottom. */
2819 x_fill_rectangle (s->f, s->gc,
2820 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
2821
2822 /* Right. */
2823 if (right_p)
2824 x_fill_rectangle (s->f, s->gc,
2825 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
2826
2827 XSetForeground (s->display, s->gc, xgcv.foreground);
2828 x_reset_clip_rectangles (s->f, s->gc);
2829 }
2830
2831
2832 /* Draw a box around glyph string S. */
2833
2834 static void
2835 x_draw_glyph_string_box (struct glyph_string *s)
2836 {
2837 int width, left_x, right_x, top_y, bottom_y, last_x;
2838 bool raised_p, left_p, right_p;
2839 struct glyph *last_glyph;
2840 XRectangle clip_rect;
2841
2842 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2843 ? WINDOW_RIGHT_EDGE_X (s->w)
2844 : window_box_right (s->w, s->area));
2845
2846 /* The glyph that may have a right box line. */
2847 last_glyph = (s->cmp || s->img
2848 ? s->first_glyph
2849 : s->first_glyph + s->nchars - 1);
2850
2851 width = eabs (s->face->box_line_width);
2852 raised_p = s->face->box == FACE_RAISED_BOX;
2853 left_x = s->x;
2854 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
2855 ? last_x - 1
2856 : min (last_x, s->x + s->background_width) - 1);
2857 top_y = s->y;
2858 bottom_y = top_y + s->height - 1;
2859
2860 left_p = (s->first_glyph->left_box_line_p
2861 || (s->hl == DRAW_MOUSE_FACE
2862 && (s->prev == NULL
2863 || s->prev->hl != s->hl)));
2864 right_p = (last_glyph->right_box_line_p
2865 || (s->hl == DRAW_MOUSE_FACE
2866 && (s->next == NULL
2867 || s->next->hl != s->hl)));
2868
2869 get_glyph_string_clip_rect (s, &clip_rect);
2870
2871 if (s->face->box == FACE_SIMPLE_BOX)
2872 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
2873 left_p, right_p, &clip_rect);
2874 else
2875 {
2876 x_setup_relief_colors (s);
2877 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
2878 width, raised_p, true, true, left_p, right_p,
2879 &clip_rect);
2880 }
2881 }
2882
2883
2884 /* Draw foreground of image glyph string S. */
2885
2886 static void
2887 x_draw_image_foreground (struct glyph_string *s)
2888 {
2889 int x = s->x;
2890 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2891
2892 /* If first glyph of S has a left box line, start drawing it to the
2893 right of that line. */
2894 if (s->face->box != FACE_NO_BOX
2895 && s->first_glyph->left_box_line_p
2896 && s->slice.x == 0)
2897 x += eabs (s->face->box_line_width);
2898
2899 /* If there is a margin around the image, adjust x- and y-position
2900 by that margin. */
2901 if (s->slice.x == 0)
2902 x += s->img->hmargin;
2903 if (s->slice.y == 0)
2904 y += s->img->vmargin;
2905
2906 if (s->img->pixmap)
2907 {
2908 if (s->img->mask)
2909 {
2910 /* We can't set both a clip mask and use XSetClipRectangles
2911 because the latter also sets a clip mask. We also can't
2912 trust on the shape extension to be available
2913 (XShapeCombineRegion). So, compute the rectangle to draw
2914 manually. */
2915 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
2916 | GCFunction);
2917 XGCValues xgcv;
2918 XRectangle clip_rect, image_rect, r;
2919
2920 xgcv.clip_mask = s->img->mask;
2921 xgcv.clip_x_origin = x;
2922 xgcv.clip_y_origin = y;
2923 xgcv.function = GXcopy;
2924 XChangeGC (s->display, s->gc, mask, &xgcv);
2925
2926 get_glyph_string_clip_rect (s, &clip_rect);
2927 image_rect.x = x;
2928 image_rect.y = y;
2929 image_rect.width = s->slice.width;
2930 image_rect.height = s->slice.height;
2931 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
2932 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
2933 s->slice.x + r.x - x, s->slice.y + r.y - y,
2934 r.width, r.height, r.x, r.y);
2935 }
2936 else
2937 {
2938 XRectangle clip_rect, image_rect, r;
2939
2940 get_glyph_string_clip_rect (s, &clip_rect);
2941 image_rect.x = x;
2942 image_rect.y = y;
2943 image_rect.width = s->slice.width;
2944 image_rect.height = s->slice.height;
2945 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
2946 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
2947 s->slice.x + r.x - x, s->slice.y + r.y - y,
2948 r.width, r.height, r.x, r.y);
2949
2950 /* When the image has a mask, we can expect that at
2951 least part of a mouse highlight or a block cursor will
2952 be visible. If the image doesn't have a mask, make
2953 a block cursor visible by drawing a rectangle around
2954 the image. I believe it's looking better if we do
2955 nothing here for mouse-face. */
2956 if (s->hl == DRAW_CURSOR)
2957 {
2958 int relief = eabs (s->img->relief);
2959 x_draw_rectangle (s->f, s->gc,
2960 x - relief, y - relief,
2961 s->slice.width + relief*2 - 1,
2962 s->slice.height + relief*2 - 1);
2963 }
2964 }
2965 }
2966 else
2967 /* Draw a rectangle if image could not be loaded. */
2968 x_draw_rectangle (s->f, s->gc, x, y,
2969 s->slice.width - 1, s->slice.height - 1);
2970 }
2971
2972
2973 /* Draw a relief around the image glyph string S. */
2974
2975 static void
2976 x_draw_image_relief (struct glyph_string *s)
2977 {
2978 int x1, y1, thick;
2979 bool raised_p, top_p, bot_p, left_p, right_p;
2980 int extra_x, extra_y;
2981 XRectangle r;
2982 int x = s->x;
2983 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2984
2985 /* If first glyph of S has a left box line, start drawing it to the
2986 right of that line. */
2987 if (s->face->box != FACE_NO_BOX
2988 && s->first_glyph->left_box_line_p
2989 && s->slice.x == 0)
2990 x += eabs (s->face->box_line_width);
2991
2992 /* If there is a margin around the image, adjust x- and y-position
2993 by that margin. */
2994 if (s->slice.x == 0)
2995 x += s->img->hmargin;
2996 if (s->slice.y == 0)
2997 y += s->img->vmargin;
2998
2999 if (s->hl == DRAW_IMAGE_SUNKEN
3000 || s->hl == DRAW_IMAGE_RAISED)
3001 {
3002 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3003 raised_p = s->hl == DRAW_IMAGE_RAISED;
3004 }
3005 else
3006 {
3007 thick = eabs (s->img->relief);
3008 raised_p = s->img->relief > 0;
3009 }
3010
3011 x1 = x + s->slice.width - 1;
3012 y1 = y + s->slice.height - 1;
3013
3014 extra_x = extra_y = 0;
3015 if (s->face->id == TOOL_BAR_FACE_ID)
3016 {
3017 if (CONSP (Vtool_bar_button_margin)
3018 && INTEGERP (XCAR (Vtool_bar_button_margin))
3019 && INTEGERP (XCDR (Vtool_bar_button_margin)))
3020 {
3021 extra_x = XINT (XCAR (Vtool_bar_button_margin));
3022 extra_y = XINT (XCDR (Vtool_bar_button_margin));
3023 }
3024 else if (INTEGERP (Vtool_bar_button_margin))
3025 extra_x = extra_y = XINT (Vtool_bar_button_margin);
3026 }
3027
3028 top_p = bot_p = left_p = right_p = false;
3029
3030 if (s->slice.x == 0)
3031 x -= thick + extra_x, left_p = true;
3032 if (s->slice.y == 0)
3033 y -= thick + extra_y, top_p = true;
3034 if (s->slice.x + s->slice.width == s->img->width)
3035 x1 += thick + extra_x, right_p = true;
3036 if (s->slice.y + s->slice.height == s->img->height)
3037 y1 += thick + extra_y, bot_p = true;
3038
3039 x_setup_relief_colors (s);
3040 get_glyph_string_clip_rect (s, &r);
3041 x_draw_relief_rect (s->f, x, y, x1, y1, thick, raised_p,
3042 top_p, bot_p, left_p, right_p, &r);
3043 }
3044
3045
3046 /* Draw the foreground of image glyph string S to PIXMAP. */
3047
3048 static void
3049 x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap)
3050 {
3051 int x = 0;
3052 int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice);
3053
3054 /* If first glyph of S has a left box line, start drawing it to the
3055 right of that line. */
3056 if (s->face->box != FACE_NO_BOX
3057 && s->first_glyph->left_box_line_p
3058 && s->slice.x == 0)
3059 x += eabs (s->face->box_line_width);
3060
3061 /* If there is a margin around the image, adjust x- and y-position
3062 by that margin. */
3063 if (s->slice.x == 0)
3064 x += s->img->hmargin;
3065 if (s->slice.y == 0)
3066 y += s->img->vmargin;
3067
3068 if (s->img->pixmap)
3069 {
3070 if (s->img->mask)
3071 {
3072 /* We can't set both a clip mask and use XSetClipRectangles
3073 because the latter also sets a clip mask. We also can't
3074 trust on the shape extension to be available
3075 (XShapeCombineRegion). So, compute the rectangle to draw
3076 manually. */
3077 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3078 | GCFunction);
3079 XGCValues xgcv;
3080
3081 xgcv.clip_mask = s->img->mask;
3082 xgcv.clip_x_origin = x - s->slice.x;
3083 xgcv.clip_y_origin = y - s->slice.y;
3084 xgcv.function = GXcopy;
3085 XChangeGC (s->display, s->gc, mask, &xgcv);
3086
3087 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3088 s->slice.x, s->slice.y,
3089 s->slice.width, s->slice.height, x, y);
3090 XSetClipMask (s->display, s->gc, None);
3091 }
3092 else
3093 {
3094 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3095 s->slice.x, s->slice.y,
3096 s->slice.width, s->slice.height, x, y);
3097
3098 /* When the image has a mask, we can expect that at
3099 least part of a mouse highlight or a block cursor will
3100 be visible. If the image doesn't have a mask, make
3101 a block cursor visible by drawing a rectangle around
3102 the image. I believe it's looking better if we do
3103 nothing here for mouse-face. */
3104 if (s->hl == DRAW_CURSOR)
3105 {
3106 int r = eabs (s->img->relief);
3107 x_draw_rectangle (s->f, s->gc, x - r, y - r,
3108 s->slice.width + r*2 - 1,
3109 s->slice.height + r*2 - 1);
3110 }
3111 }
3112 }
3113 else
3114 /* Draw a rectangle if image could not be loaded. */
3115 x_draw_rectangle (s->f, s->gc, x, y,
3116 s->slice.width - 1, s->slice.height - 1);
3117 }
3118
3119
3120 /* Draw part of the background of glyph string S. X, Y, W, and H
3121 give the rectangle to draw. */
3122
3123 static void
3124 x_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, int w, int h)
3125 {
3126 if (s->stippled_p)
3127 {
3128 /* Fill background with a stipple pattern. */
3129 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3130 x_fill_rectangle (s->f, s->gc, x, y, w, h);
3131 XSetFillStyle (s->display, s->gc, FillSolid);
3132 }
3133 else
3134 x_clear_glyph_string_rect (s, x, y, w, h);
3135 }
3136
3137
3138 /* Draw image glyph string S.
3139
3140 s->y
3141 s->x +-------------------------
3142 | s->face->box
3143 |
3144 | +-------------------------
3145 | | s->img->margin
3146 | |
3147 | | +-------------------
3148 | | | the image
3149
3150 */
3151
3152 static void
3153 x_draw_image_glyph_string (struct glyph_string *s)
3154 {
3155 int box_line_hwidth = eabs (s->face->box_line_width);
3156 int box_line_vwidth = max (s->face->box_line_width, 0);
3157 int height;
3158 Pixmap pixmap = None;
3159
3160 height = s->height;
3161 if (s->slice.y == 0)
3162 height -= box_line_vwidth;
3163 if (s->slice.y + s->slice.height >= s->img->height)
3164 height -= box_line_vwidth;
3165
3166 /* Fill background with face under the image. Do it only if row is
3167 taller than image or if image has a clip mask to reduce
3168 flickering. */
3169 s->stippled_p = s->face->stipple != 0;
3170 if (height > s->slice.height
3171 || s->img->hmargin
3172 || s->img->vmargin
3173 || s->img->mask
3174 || s->img->pixmap == 0
3175 || s->width != s->background_width)
3176 {
3177 if (s->img->mask)
3178 {
3179 /* Create a pixmap as large as the glyph string. Fill it
3180 with the background color. Copy the image to it, using
3181 its mask. Copy the temporary pixmap to the display. */
3182 Screen *screen = FRAME_X_SCREEN (s->f);
3183 int depth = DefaultDepthOfScreen (screen);
3184
3185 /* Create a pixmap as large as the glyph string. */
3186 pixmap = XCreatePixmap (s->display, s->window,
3187 s->background_width,
3188 s->height, depth);
3189
3190 /* Don't clip in the following because we're working on the
3191 pixmap. */
3192 XSetClipMask (s->display, s->gc, None);
3193
3194 /* Fill the pixmap with the background color/stipple. */
3195 if (s->stippled_p)
3196 {
3197 /* Fill background with a stipple pattern. */
3198 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3199 XSetTSOrigin (s->display, s->gc, - s->x, - s->y);
3200 XFillRectangle (s->display, pixmap, s->gc,
3201 0, 0, s->background_width, s->height);
3202 XSetFillStyle (s->display, s->gc, FillSolid);
3203 XSetTSOrigin (s->display, s->gc, 0, 0);
3204 }
3205 else
3206 {
3207 XGCValues xgcv;
3208 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
3209 &xgcv);
3210 XSetForeground (s->display, s->gc, xgcv.background);
3211 XFillRectangle (s->display, pixmap, s->gc,
3212 0, 0, s->background_width, s->height);
3213 XSetForeground (s->display, s->gc, xgcv.foreground);
3214 }
3215 }
3216 else
3217 {
3218 int x = s->x;
3219 int y = s->y;
3220 int width = s->background_width;
3221
3222 if (s->first_glyph->left_box_line_p
3223 && s->slice.x == 0)
3224 {
3225 x += box_line_hwidth;
3226 width -= box_line_hwidth;
3227 }
3228
3229 if (s->slice.y == 0)
3230 y += box_line_vwidth;
3231
3232 x_draw_glyph_string_bg_rect (s, x, y, width, height);
3233 }
3234
3235 s->background_filled_p = true;
3236 }
3237
3238 /* Draw the foreground. */
3239 #ifdef USE_CAIRO
3240 if (s->img->cr_data)
3241 {
3242 cairo_t *cr = x_begin_cr_clip (s->f, s->gc);
3243
3244 int x = s->x + s->img->hmargin;
3245 int y = s->y + s->img->vmargin;
3246 int width = s->background_width;
3247
3248 cairo_set_source_surface (cr, s->img->cr_data,
3249 x - s->slice.x,
3250 y - s->slice.y);
3251 cairo_rectangle (cr, x, y, width, height);
3252 cairo_fill (cr);
3253 x_end_cr_clip (s->f);
3254 }
3255 else
3256 #endif
3257 if (pixmap != None)
3258 {
3259 x_draw_image_foreground_1 (s, pixmap);
3260 x_set_glyph_string_clipping (s);
3261 XCopyArea (s->display, pixmap, s->window, s->gc,
3262 0, 0, s->background_width, s->height, s->x, s->y);
3263 XFreePixmap (s->display, pixmap);
3264 }
3265 else
3266 x_draw_image_foreground (s);
3267
3268 /* If we must draw a relief around the image, do it. */
3269 if (s->img->relief
3270 || s->hl == DRAW_IMAGE_RAISED
3271 || s->hl == DRAW_IMAGE_SUNKEN)
3272 x_draw_image_relief (s);
3273 }
3274
3275
3276 /* Draw stretch glyph string S. */
3277
3278 static void
3279 x_draw_stretch_glyph_string (struct glyph_string *s)
3280 {
3281 eassert (s->first_glyph->type == STRETCH_GLYPH);
3282
3283 if (s->hl == DRAW_CURSOR
3284 && !x_stretch_cursor_p)
3285 {
3286 /* If `x-stretch-cursor' is nil, don't draw a block cursor as
3287 wide as the stretch glyph. */
3288 int width, background_width = s->background_width;
3289 int x = s->x;
3290
3291 if (!s->row->reversed_p)
3292 {
3293 int left_x = window_box_left_offset (s->w, TEXT_AREA);
3294
3295 if (x < left_x)
3296 {
3297 background_width -= left_x - x;
3298 x = left_x;
3299 }
3300 }
3301 else
3302 {
3303 /* In R2L rows, draw the cursor on the right edge of the
3304 stretch glyph. */
3305 int right_x = window_box_right (s->w, TEXT_AREA);
3306
3307 if (x + background_width > right_x)
3308 background_width -= x - right_x;
3309 x += background_width;
3310 }
3311 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
3312 if (s->row->reversed_p)
3313 x -= width;
3314
3315 /* Draw cursor. */
3316 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
3317
3318 /* Clear rest using the GC of the original non-cursor face. */
3319 if (width < background_width)
3320 {
3321 int y = s->y;
3322 int w = background_width - width, h = s->height;
3323 XRectangle r;
3324 GC gc;
3325
3326 if (!s->row->reversed_p)
3327 x += width;
3328 else
3329 x = s->x;
3330 if (s->row->mouse_face_p
3331 && cursor_in_mouse_face_p (s->w))
3332 {
3333 x_set_mouse_face_gc (s);
3334 gc = s->gc;
3335 }
3336 else
3337 gc = s->face->gc;
3338
3339 get_glyph_string_clip_rect (s, &r);
3340 x_set_clip_rectangles (s->f, gc, &r, 1);
3341
3342 if (s->face->stipple)
3343 {
3344 /* Fill background with a stipple pattern. */
3345 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3346 x_fill_rectangle (s->f, gc, x, y, w, h);
3347 XSetFillStyle (s->display, gc, FillSolid);
3348 }
3349 else
3350 {
3351 XGCValues xgcv;
3352 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
3353 XSetForeground (s->display, gc, xgcv.background);
3354 x_fill_rectangle (s->f, gc, x, y, w, h);
3355 XSetForeground (s->display, gc, xgcv.foreground);
3356 }
3357
3358 x_reset_clip_rectangles (s->f, gc);
3359 }
3360 }
3361 else if (!s->background_filled_p)
3362 {
3363 int background_width = s->background_width;
3364 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3365
3366 /* Don't draw into left margin, fringe or scrollbar area
3367 except for header line and mode line. */
3368 if (x < left_x && !s->row->mode_line_p)
3369 {
3370 background_width -= left_x - x;
3371 x = left_x;
3372 }
3373 if (background_width > 0)
3374 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
3375 }
3376
3377 s->background_filled_p = true;
3378 }
3379
3380 /*
3381 Draw a wavy line under S. The wave fills wave_height pixels from y0.
3382
3383 x0 wave_length = 2
3384 --
3385 y0 * * * * *
3386 |* * * * * * * * *
3387 wave_height = 3 | * * * *
3388
3389 */
3390
3391 static void
3392 x_draw_underwave (struct glyph_string *s)
3393 {
3394 int wave_height = 3, wave_length = 2;
3395 #ifdef USE_CAIRO
3396 x_draw_horizontal_wave (s->f, s->gc, s->x, s->ybase - wave_height + 3,
3397 s->width, wave_height, wave_length);
3398 #else /* not USE_CAIRO */
3399 int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax;
3400 bool odd;
3401 XRectangle wave_clip, string_clip, final_clip;
3402
3403 dx = wave_length;
3404 dy = wave_height - 1;
3405 x0 = s->x;
3406 y0 = s->ybase - wave_height + 3;
3407 width = s->width;
3408 xmax = x0 + width;
3409
3410 /* Find and set clipping rectangle */
3411
3412 wave_clip.x = x0;
3413 wave_clip.y = y0;
3414 wave_clip.width = width;
3415 wave_clip.height = wave_height;
3416 get_glyph_string_clip_rect (s, &string_clip);
3417
3418 if (!x_intersect_rectangles (&wave_clip, &string_clip, &final_clip))
3419 return;
3420
3421 XSetClipRectangles (s->display, s->gc, 0, 0, &final_clip, 1, Unsorted);
3422
3423 /* Draw the waves */
3424
3425 x1 = x0 - (x0 % dx);
3426 x2 = x1 + dx;
3427 odd = (x1 / dx) & 1;
3428 y1 = y2 = y0;
3429
3430 if (odd)
3431 y1 += dy;
3432 else
3433 y2 += dy;
3434
3435 if (INT_MAX - dx < xmax)
3436 emacs_abort ();
3437
3438 while (x1 <= xmax)
3439 {
3440 XDrawLine (s->display, s->window, s->gc, x1, y1, x2, y2);
3441 x1 = x2, y1 = y2;
3442 x2 += dx, y2 = y0 + odd*dy;
3443 odd = !odd;
3444 }
3445
3446 /* Restore previous clipping rectangle(s) */
3447 XSetClipRectangles (s->display, s->gc, 0, 0, s->clip, s->num_clips, Unsorted);
3448 #endif /* not USE_CAIRO */
3449 }
3450
3451
3452 /* Draw glyph string S. */
3453
3454 static void
3455 x_draw_glyph_string (struct glyph_string *s)
3456 {
3457 bool relief_drawn_p = false;
3458
3459 /* If S draws into the background of its successors, draw the
3460 background of the successors first so that S can draw into it.
3461 This makes S->next use XDrawString instead of XDrawImageString. */
3462 if (s->next && s->right_overhang && !s->for_overlaps)
3463 {
3464 int width;
3465 struct glyph_string *next;
3466
3467 for (width = 0, next = s->next;
3468 next && width < s->right_overhang;
3469 width += next->width, next = next->next)
3470 if (next->first_glyph->type != IMAGE_GLYPH)
3471 {
3472 x_set_glyph_string_gc (next);
3473 x_set_glyph_string_clipping (next);
3474 if (next->first_glyph->type == STRETCH_GLYPH)
3475 x_draw_stretch_glyph_string (next);
3476 else
3477 x_draw_glyph_string_background (next, true);
3478 next->num_clips = 0;
3479 }
3480 }
3481
3482 /* Set up S->gc, set clipping and draw S. */
3483 x_set_glyph_string_gc (s);
3484
3485 /* Draw relief (if any) in advance for char/composition so that the
3486 glyph string can be drawn over it. */
3487 if (!s->for_overlaps
3488 && s->face->box != FACE_NO_BOX
3489 && (s->first_glyph->type == CHAR_GLYPH
3490 || s->first_glyph->type == COMPOSITE_GLYPH))
3491
3492 {
3493 x_set_glyph_string_clipping (s);
3494 x_draw_glyph_string_background (s, true);
3495 x_draw_glyph_string_box (s);
3496 x_set_glyph_string_clipping (s);
3497 relief_drawn_p = true;
3498 }
3499 else if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */
3500 && !s->clip_tail
3501 && ((s->prev && s->prev->hl != s->hl && s->left_overhang)
3502 || (s->next && s->next->hl != s->hl && s->right_overhang)))
3503 /* We must clip just this glyph. left_overhang part has already
3504 drawn when s->prev was drawn, and right_overhang part will be
3505 drawn later when s->next is drawn. */
3506 x_set_glyph_string_clipping_exactly (s, s);
3507 else
3508 x_set_glyph_string_clipping (s);
3509
3510 switch (s->first_glyph->type)
3511 {
3512 case IMAGE_GLYPH:
3513 x_draw_image_glyph_string (s);
3514 break;
3515
3516 case XWIDGET_GLYPH:
3517 x_draw_xwidget_glyph_string (s);
3518 break;
3519
3520 case STRETCH_GLYPH:
3521 x_draw_stretch_glyph_string (s);
3522 break;
3523
3524 case CHAR_GLYPH:
3525 if (s->for_overlaps)
3526 s->background_filled_p = true;
3527 else
3528 x_draw_glyph_string_background (s, false);
3529 x_draw_glyph_string_foreground (s);
3530 break;
3531
3532 case COMPOSITE_GLYPH:
3533 if (s->for_overlaps || (s->cmp_from > 0
3534 && ! s->first_glyph->u.cmp.automatic))
3535 s->background_filled_p = true;
3536 else
3537 x_draw_glyph_string_background (s, true);
3538 x_draw_composite_glyph_string_foreground (s);
3539 break;
3540
3541 case GLYPHLESS_GLYPH:
3542 if (s->for_overlaps)
3543 s->background_filled_p = true;
3544 else
3545 x_draw_glyph_string_background (s, true);
3546 x_draw_glyphless_glyph_string_foreground (s);
3547 break;
3548
3549 default:
3550 emacs_abort ();
3551 }
3552
3553 if (!s->for_overlaps)
3554 {
3555 /* Draw underline. */
3556 if (s->face->underline_p)
3557 {
3558 if (s->face->underline_type == FACE_UNDER_WAVE)
3559 {
3560 if (s->face->underline_defaulted_p)
3561 x_draw_underwave (s);
3562 else
3563 {
3564 XGCValues xgcv;
3565 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3566 XSetForeground (s->display, s->gc, s->face->underline_color);
3567 x_draw_underwave (s);
3568 XSetForeground (s->display, s->gc, xgcv.foreground);
3569 }
3570 }
3571 else if (s->face->underline_type == FACE_UNDER_LINE)
3572 {
3573 unsigned long thickness, position;
3574 int y;
3575
3576 if (s->prev && s->prev->face->underline_p
3577 && s->prev->face->underline_type == FACE_UNDER_LINE)
3578 {
3579 /* We use the same underline style as the previous one. */
3580 thickness = s->prev->underline_thickness;
3581 position = s->prev->underline_position;
3582 }
3583 else
3584 {
3585 /* Get the underline thickness. Default is 1 pixel. */
3586 if (s->font && s->font->underline_thickness > 0)
3587 thickness = s->font->underline_thickness;
3588 else
3589 thickness = 1;
3590 if (x_underline_at_descent_line)
3591 position = (s->height - thickness) - (s->ybase - s->y);
3592 else
3593 {
3594 /* Get the underline position. This is the recommended
3595 vertical offset in pixels from the baseline to the top of
3596 the underline. This is a signed value according to the
3597 specs, and its default is
3598
3599 ROUND ((maximum descent) / 2), with
3600 ROUND(x) = floor (x + 0.5) */
3601
3602 if (x_use_underline_position_properties
3603 && s->font && s->font->underline_position >= 0)
3604 position = s->font->underline_position;
3605 else if (s->font)
3606 position = (s->font->descent + 1) / 2;
3607 else
3608 position = underline_minimum_offset;
3609 }
3610 position = max (position, underline_minimum_offset);
3611 }
3612 /* Check the sanity of thickness and position. We should
3613 avoid drawing underline out of the current line area. */
3614 if (s->y + s->height <= s->ybase + position)
3615 position = (s->height - 1) - (s->ybase - s->y);
3616 if (s->y + s->height < s->ybase + position + thickness)
3617 thickness = (s->y + s->height) - (s->ybase + position);
3618 s->underline_thickness = thickness;
3619 s->underline_position = position;
3620 y = s->ybase + position;
3621 if (s->face->underline_defaulted_p)
3622 x_fill_rectangle (s->f, s->gc,
3623 s->x, y, s->width, thickness);
3624 else
3625 {
3626 XGCValues xgcv;
3627 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3628 XSetForeground (s->display, s->gc, s->face->underline_color);
3629 x_fill_rectangle (s->f, s->gc,
3630 s->x, y, s->width, thickness);
3631 XSetForeground (s->display, s->gc, xgcv.foreground);
3632 }
3633 }
3634 }
3635 /* Draw overline. */
3636 if (s->face->overline_p)
3637 {
3638 unsigned long dy = 0, h = 1;
3639
3640 if (s->face->overline_color_defaulted_p)
3641 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3642 s->width, h);
3643 else
3644 {
3645 XGCValues xgcv;
3646 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3647 XSetForeground (s->display, s->gc, s->face->overline_color);
3648 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3649 s->width, h);
3650 XSetForeground (s->display, s->gc, xgcv.foreground);
3651 }
3652 }
3653
3654 /* Draw strike-through. */
3655 if (s->face->strike_through_p)
3656 {
3657 unsigned long h = 1;
3658 unsigned long dy = (s->height - h) / 2;
3659
3660 if (s->face->strike_through_color_defaulted_p)
3661 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3662 s->width, h);
3663 else
3664 {
3665 XGCValues xgcv;
3666 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3667 XSetForeground (s->display, s->gc, s->face->strike_through_color);
3668 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3669 s->width, h);
3670 XSetForeground (s->display, s->gc, xgcv.foreground);
3671 }
3672 }
3673
3674 /* Draw relief if not yet drawn. */
3675 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
3676 x_draw_glyph_string_box (s);
3677
3678 if (s->prev)
3679 {
3680 struct glyph_string *prev;
3681
3682 for (prev = s->prev; prev; prev = prev->prev)
3683 if (prev->hl != s->hl
3684 && prev->x + prev->width + prev->right_overhang > s->x)
3685 {
3686 /* As prev was drawn while clipped to its own area, we
3687 must draw the right_overhang part using s->hl now. */
3688 enum draw_glyphs_face save = prev->hl;
3689
3690 prev->hl = s->hl;
3691 x_set_glyph_string_gc (prev);
3692 x_set_glyph_string_clipping_exactly (s, prev);
3693 if (prev->first_glyph->type == CHAR_GLYPH)
3694 x_draw_glyph_string_foreground (prev);
3695 else
3696 x_draw_composite_glyph_string_foreground (prev);
3697 x_reset_clip_rectangles (prev->f, prev->gc);
3698 prev->hl = save;
3699 prev->num_clips = 0;
3700 }
3701 }
3702
3703 if (s->next)
3704 {
3705 struct glyph_string *next;
3706
3707 for (next = s->next; next; next = next->next)
3708 if (next->hl != s->hl
3709 && next->x - next->left_overhang < s->x + s->width)
3710 {
3711 /* As next will be drawn while clipped to its own area,
3712 we must draw the left_overhang part using s->hl now. */
3713 enum draw_glyphs_face save = next->hl;
3714
3715 next->hl = s->hl;
3716 x_set_glyph_string_gc (next);
3717 x_set_glyph_string_clipping_exactly (s, next);
3718 if (next->first_glyph->type == CHAR_GLYPH)
3719 x_draw_glyph_string_foreground (next);
3720 else
3721 x_draw_composite_glyph_string_foreground (next);
3722 x_reset_clip_rectangles (next->f, next->gc);
3723 next->hl = save;
3724 next->num_clips = 0;
3725 next->clip_head = s->next;
3726 }
3727 }
3728 }
3729
3730 /* Reset clipping. */
3731 x_reset_clip_rectangles (s->f, s->gc);
3732 s->num_clips = 0;
3733 }
3734
3735 /* Shift display to make room for inserted glyphs. */
3736
3737 static void
3738 x_shift_glyphs_for_insert (struct frame *f, int x, int y, int width, int height, int shift_by)
3739 {
3740 /* Never called on a GUI frame, see
3741 http://lists.gnu.org/archive/html/emacs-devel/2015-05/msg00456.html
3742 */
3743 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
3744 f->output_data.x->normal_gc,
3745 x, y, width, height,
3746 x + shift_by, y);
3747 }
3748
3749 /* Delete N glyphs at the nominal cursor position. Not implemented
3750 for X frames. */
3751
3752 static void
3753 x_delete_glyphs (struct frame *f, register int n)
3754 {
3755 emacs_abort ();
3756 }
3757
3758
3759 /* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
3760 If they are <= 0, this is probably an error. */
3761
3762 static ATTRIBUTE_UNUSED void
3763 x_clear_area1 (Display *dpy, Window window,
3764 int x, int y, int width, int height, int exposures)
3765 {
3766 eassert (width > 0 && height > 0);
3767 XClearArea (dpy, window, x, y, width, height, exposures);
3768 }
3769
3770 void
3771 x_clear_area (struct frame *f, int x, int y, int width, int height)
3772 {
3773 #ifdef USE_CAIRO
3774 cairo_t *cr;
3775
3776 eassert (width > 0 && height > 0);
3777
3778 cr = x_begin_cr_clip (f, NULL);
3779 x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
3780 cairo_rectangle (cr, x, y, width, height);
3781 cairo_fill (cr);
3782 x_end_cr_clip (f);
3783 #else
3784 x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3785 x, y, width, height, False);
3786 #endif
3787 }
3788
3789
3790 /* Clear an entire frame. */
3791
3792 static void
3793 x_clear_frame (struct frame *f)
3794 {
3795 /* Clearing the frame will erase any cursor, so mark them all as no
3796 longer visible. */
3797 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
3798
3799 block_input ();
3800
3801 x_clear_window (f);
3802
3803 /* We have to clear the scroll bars. If we have changed colors or
3804 something like that, then they should be notified. */
3805 x_scroll_bar_clear (f);
3806
3807 #if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
3808 /* Make sure scroll bars are redrawn. As they aren't redrawn by
3809 redisplay, do it here. */
3810 if (FRAME_GTK_WIDGET (f))
3811 gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
3812 #endif
3813
3814 XFlush (FRAME_X_DISPLAY (f));
3815
3816 unblock_input ();
3817 }
3818
3819 /* RIF: Show hourglass cursor on frame F. */
3820
3821 static void
3822 x_show_hourglass (struct frame *f)
3823 {
3824 Display *dpy = FRAME_X_DISPLAY (f);
3825
3826 if (dpy)
3827 {
3828 struct x_output *x = FRAME_X_OUTPUT (f);
3829 #ifdef USE_X_TOOLKIT
3830 if (x->widget)
3831 #else
3832 if (FRAME_OUTER_WINDOW (f))
3833 #endif
3834 {
3835 x->hourglass_p = true;
3836
3837 if (!x->hourglass_window)
3838 {
3839 unsigned long mask = CWCursor;
3840 XSetWindowAttributes attrs;
3841 #ifdef USE_GTK
3842 Window parent = FRAME_X_WINDOW (f);
3843 #else
3844 Window parent = FRAME_OUTER_WINDOW (f);
3845 #endif
3846 attrs.cursor = x->hourglass_cursor;
3847
3848 x->hourglass_window = XCreateWindow
3849 (dpy, parent, 0, 0, 32000, 32000, 0, 0,
3850 InputOnly, CopyFromParent, mask, &attrs);
3851 }
3852
3853 XMapRaised (dpy, x->hourglass_window);
3854 XFlush (dpy);
3855 }
3856 }
3857 }
3858
3859 /* RIF: Cancel hourglass cursor on frame F. */
3860
3861 static void
3862 x_hide_hourglass (struct frame *f)
3863 {
3864 struct x_output *x = FRAME_X_OUTPUT (f);
3865
3866 /* Watch out for newly created frames. */
3867 if (x->hourglass_window)
3868 {
3869 XUnmapWindow (FRAME_X_DISPLAY (f), x->hourglass_window);
3870 /* Sync here because XTread_socket looks at the
3871 hourglass_p flag that is reset to zero below. */
3872 XSync (FRAME_X_DISPLAY (f), False);
3873 x->hourglass_p = false;
3874 }
3875 }
3876
3877 /* Invert the middle quarter of the frame for .15 sec. */
3878
3879 static void
3880 XTflash (struct frame *f)
3881 {
3882 block_input ();
3883
3884 {
3885 #ifdef USE_GTK
3886 /* Use Gdk routines to draw. This way, we won't draw over scroll bars
3887 when the scroll bars and the edit widget share the same X window. */
3888 GdkWindow *window = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
3889 #ifdef HAVE_GTK3
3890 cairo_t *cr = gdk_cairo_create (window);
3891 cairo_set_source_rgb (cr, 1, 1, 1);
3892 cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
3893 #define XFillRectangle(d, win, gc, x, y, w, h) \
3894 do { \
3895 cairo_rectangle (cr, x, y, w, h); \
3896 cairo_fill (cr); \
3897 } \
3898 while (false)
3899 #else /* ! HAVE_GTK3 */
3900 GdkGCValues vals;
3901 GdkGC *gc;
3902 vals.foreground.pixel = (FRAME_FOREGROUND_PIXEL (f)
3903 ^ FRAME_BACKGROUND_PIXEL (f));
3904 vals.function = GDK_XOR;
3905 gc = gdk_gc_new_with_values (window,
3906 &vals, GDK_GC_FUNCTION | GDK_GC_FOREGROUND);
3907 #define XFillRectangle(d, win, gc, x, y, w, h) \
3908 gdk_draw_rectangle (window, gc, true, x, y, w, h)
3909 #endif /* ! HAVE_GTK3 */
3910 #else /* ! USE_GTK */
3911 GC gc;
3912
3913 /* Create a GC that will use the GXxor function to flip foreground
3914 pixels into background pixels. */
3915 {
3916 XGCValues values;
3917
3918 values.function = GXxor;
3919 values.foreground = (FRAME_FOREGROUND_PIXEL (f)
3920 ^ FRAME_BACKGROUND_PIXEL (f));
3921
3922 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3923 GCFunction | GCForeground, &values);
3924 }
3925 #endif
3926 {
3927 /* Get the height not including a menu bar widget. */
3928 int height = FRAME_PIXEL_HEIGHT (f);
3929 /* Height of each line to flash. */
3930 int flash_height = FRAME_LINE_HEIGHT (f);
3931 /* These will be the left and right margins of the rectangles. */
3932 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
3933 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
3934 int width = flash_right - flash_left;
3935
3936 /* If window is tall, flash top and bottom line. */
3937 if (height > 3 * FRAME_LINE_HEIGHT (f))
3938 {
3939 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3940 flash_left,
3941 (FRAME_INTERNAL_BORDER_WIDTH (f)
3942 + FRAME_TOP_MARGIN_HEIGHT (f)),
3943 width, flash_height);
3944 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3945 flash_left,
3946 (height - flash_height
3947 - FRAME_INTERNAL_BORDER_WIDTH (f)),
3948 width, flash_height);
3949
3950 }
3951 else
3952 /* If it is short, flash it all. */
3953 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3954 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
3955 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
3956
3957 x_flush (f);
3958
3959 {
3960 struct timespec delay = make_timespec (0, 150 * 1000 * 1000);
3961 struct timespec wakeup = timespec_add (current_timespec (), delay);
3962
3963 /* Keep waiting until past the time wakeup or any input gets
3964 available. */
3965 while (! detect_input_pending ())
3966 {
3967 struct timespec current = current_timespec ();
3968 struct timespec timeout;
3969
3970 /* Break if result would not be positive. */
3971 if (timespec_cmp (wakeup, current) <= 0)
3972 break;
3973
3974 /* How long `select' should wait. */
3975 timeout = make_timespec (0, 10 * 1000 * 1000);
3976
3977 /* Try to wait that long--but we might wake up sooner. */
3978 pselect (0, NULL, NULL, NULL, &timeout, NULL);
3979 }
3980 }
3981
3982 /* If window is tall, flash top and bottom line. */
3983 if (height > 3 * FRAME_LINE_HEIGHT (f))
3984 {
3985 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3986 flash_left,
3987 (FRAME_INTERNAL_BORDER_WIDTH (f)
3988 + FRAME_TOP_MARGIN_HEIGHT (f)),
3989 width, flash_height);
3990 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3991 flash_left,
3992 (height - flash_height
3993 - FRAME_INTERNAL_BORDER_WIDTH (f)),
3994 width, flash_height);
3995 }
3996 else
3997 /* If it is short, flash it all. */
3998 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3999 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4000 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4001
4002 #ifdef USE_GTK
4003 #ifdef HAVE_GTK3
4004 cairo_destroy (cr);
4005 #else
4006 g_object_unref (G_OBJECT (gc));
4007 #endif
4008 #undef XFillRectangle
4009 #else
4010 XFreeGC (FRAME_X_DISPLAY (f), gc);
4011 #endif
4012 x_flush (f);
4013 }
4014 }
4015
4016 unblock_input ();
4017 }
4018
4019
4020 static void
4021 XTtoggle_invisible_pointer (struct frame *f, bool invisible)
4022 {
4023 block_input ();
4024 FRAME_DISPLAY_INFO (f)->toggle_visible_pointer (f, invisible);
4025 unblock_input ();
4026 }
4027
4028
4029 /* Make audible bell. */
4030
4031 static void
4032 XTring_bell (struct frame *f)
4033 {
4034 if (FRAME_X_DISPLAY (f))
4035 {
4036 if (visible_bell)
4037 XTflash (f);
4038 else
4039 {
4040 block_input ();
4041 #ifdef HAVE_XKB
4042 XkbBell (FRAME_X_DISPLAY (f), None, 0, None);
4043 #else
4044 XBell (FRAME_X_DISPLAY (f), 0);
4045 #endif
4046 XFlush (FRAME_X_DISPLAY (f));
4047 unblock_input ();
4048 }
4049 }
4050 }
4051
4052 /***********************************************************************
4053 Line Dance
4054 ***********************************************************************/
4055
4056 /* Perform an insert-lines or delete-lines operation, inserting N
4057 lines or deleting -N lines at vertical position VPOS. */
4058
4059 static void
4060 x_ins_del_lines (struct frame *f, int vpos, int n)
4061 {
4062 emacs_abort ();
4063 }
4064
4065
4066 /* Scroll part of the display as described by RUN. */
4067
4068 static void
4069 x_scroll_run (struct window *w, struct run *run)
4070 {
4071 struct frame *f = XFRAME (w->frame);
4072 int x, y, width, height, from_y, to_y, bottom_y;
4073
4074 /* Get frame-relative bounding box of the text display area of W,
4075 without mode lines. Include in this box the left and right
4076 fringe of W. */
4077 window_box (w, ANY_AREA, &x, &y, &width, &height);
4078
4079 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4080 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4081 bottom_y = y + height;
4082
4083 if (to_y < from_y)
4084 {
4085 /* Scrolling up. Make sure we don't copy part of the mode
4086 line at the bottom. */
4087 if (from_y + run->height > bottom_y)
4088 height = bottom_y - from_y;
4089 else
4090 height = run->height;
4091 }
4092 else
4093 {
4094 /* Scrolling down. Make sure we don't copy over the mode line.
4095 at the bottom. */
4096 if (to_y + run->height > bottom_y)
4097 height = bottom_y - to_y;
4098 else
4099 height = run->height;
4100 }
4101
4102 block_input ();
4103
4104 /* Cursor off. Will be switched on again in x_update_window_end. */
4105 x_clear_cursor (w);
4106
4107 #ifdef USE_CAIRO
4108 SET_FRAME_GARBAGED (f);
4109 #else
4110 XCopyArea (FRAME_X_DISPLAY (f),
4111 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
4112 f->output_data.x->normal_gc,
4113 x, from_y,
4114 width, height,
4115 x, to_y);
4116 #endif
4117
4118 unblock_input ();
4119 }
4120
4121
4122 \f
4123 /***********************************************************************
4124 Exposure Events
4125 ***********************************************************************/
4126
4127 \f
4128 static void
4129 frame_highlight (struct frame *f)
4130 {
4131 /* We used to only do this if Vx_no_window_manager was non-nil, but
4132 the ICCCM (section 4.1.6) says that the window's border pixmap
4133 and border pixel are window attributes which are "private to the
4134 client", so we can always change it to whatever we want. */
4135 block_input ();
4136 /* I recently started to get errors in this XSetWindowBorder, depending on
4137 the window-manager in use, tho something more is at play since I've been
4138 using that same window-manager binary for ever. Let's not crash just
4139 because of this (bug#9310). */
4140 x_catch_errors (FRAME_X_DISPLAY (f));
4141 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4142 f->output_data.x->border_pixel);
4143 x_uncatch_errors ();
4144 unblock_input ();
4145 x_update_cursor (f, true);
4146 x_set_frame_alpha (f);
4147 }
4148
4149 static void
4150 frame_unhighlight (struct frame *f)
4151 {
4152 /* We used to only do this if Vx_no_window_manager was non-nil, but
4153 the ICCCM (section 4.1.6) says that the window's border pixmap
4154 and border pixel are window attributes which are "private to the
4155 client", so we can always change it to whatever we want. */
4156 block_input ();
4157 /* Same as above for XSetWindowBorder (bug#9310). */
4158 x_catch_errors (FRAME_X_DISPLAY (f));
4159 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4160 f->output_data.x->border_tile);
4161 x_uncatch_errors ();
4162 unblock_input ();
4163 x_update_cursor (f, true);
4164 x_set_frame_alpha (f);
4165 }
4166
4167 /* The focus has changed. Update the frames as necessary to reflect
4168 the new situation. Note that we can't change the selected frame
4169 here, because the Lisp code we are interrupting might become confused.
4170 Each event gets marked with the frame in which it occurred, so the
4171 Lisp code can tell when the switch took place by examining the events. */
4172
4173 static void
4174 x_new_focus_frame (struct x_display_info *dpyinfo, struct frame *frame)
4175 {
4176 struct frame *old_focus = dpyinfo->x_focus_frame;
4177
4178 if (frame != dpyinfo->x_focus_frame)
4179 {
4180 /* Set this before calling other routines, so that they see
4181 the correct value of x_focus_frame. */
4182 dpyinfo->x_focus_frame = frame;
4183
4184 if (old_focus && old_focus->auto_lower)
4185 x_lower_frame (old_focus);
4186
4187 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4188 dpyinfo->x_pending_autoraise_frame = dpyinfo->x_focus_frame;
4189 else
4190 dpyinfo->x_pending_autoraise_frame = NULL;
4191 }
4192
4193 x_frame_rehighlight (dpyinfo);
4194 }
4195
4196 /* Handle FocusIn and FocusOut state changes for FRAME.
4197 If FRAME has focus and there exists more than one frame, puts
4198 a FOCUS_IN_EVENT into *BUFP. */
4199
4200 static void
4201 x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct frame *frame, struct input_event *bufp)
4202 {
4203 if (type == FocusIn)
4204 {
4205 if (dpyinfo->x_focus_event_frame != frame)
4206 {
4207 x_new_focus_frame (dpyinfo, frame);
4208 dpyinfo->x_focus_event_frame = frame;
4209
4210 /* Don't stop displaying the initial startup message
4211 for a switch-frame event we don't need. */
4212 /* When run as a daemon, Vterminal_frame is always NIL. */
4213 bufp->arg = (((NILP (Vterminal_frame)
4214 || ! FRAME_X_P (XFRAME (Vterminal_frame))
4215 || EQ (Fdaemonp (), Qt))
4216 && CONSP (Vframe_list)
4217 && !NILP (XCDR (Vframe_list)))
4218 ? Qt : Qnil);
4219 bufp->kind = FOCUS_IN_EVENT;
4220 XSETFRAME (bufp->frame_or_window, frame);
4221 }
4222
4223 frame->output_data.x->focus_state |= state;
4224
4225 #ifdef HAVE_X_I18N
4226 if (FRAME_XIC (frame))
4227 XSetICFocus (FRAME_XIC (frame));
4228 #endif
4229 }
4230 else if (type == FocusOut)
4231 {
4232 frame->output_data.x->focus_state &= ~state;
4233
4234 if (dpyinfo->x_focus_event_frame == frame)
4235 {
4236 dpyinfo->x_focus_event_frame = 0;
4237 x_new_focus_frame (dpyinfo, 0);
4238
4239 bufp->kind = FOCUS_OUT_EVENT;
4240 XSETFRAME (bufp->frame_or_window, frame);
4241 }
4242
4243 #ifdef HAVE_X_I18N
4244 if (FRAME_XIC (frame))
4245 XUnsetICFocus (FRAME_XIC (frame));
4246 #endif
4247 if (frame->pointer_invisible)
4248 XTtoggle_invisible_pointer (frame, false);
4249 }
4250 }
4251
4252 /* Return the Emacs frame-object corresponding to an X window.
4253 It could be the frame's main window or an icon window. */
4254
4255 static struct frame *
4256 x_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4257 {
4258 Lisp_Object tail, frame;
4259 struct frame *f;
4260
4261 if (wdesc == None)
4262 return NULL;
4263
4264 FOR_EACH_FRAME (tail, frame)
4265 {
4266 f = XFRAME (frame);
4267 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4268 continue;
4269 if (f->output_data.x->hourglass_window == wdesc)
4270 return f;
4271 #ifdef USE_X_TOOLKIT
4272 if ((f->output_data.x->edit_widget
4273 && XtWindow (f->output_data.x->edit_widget) == wdesc)
4274 /* A tooltip frame? */
4275 || (!f->output_data.x->edit_widget
4276 && FRAME_X_WINDOW (f) == wdesc)
4277 || f->output_data.x->icon_desc == wdesc)
4278 return f;
4279 #else /* not USE_X_TOOLKIT */
4280 #ifdef USE_GTK
4281 if (f->output_data.x->edit_widget)
4282 {
4283 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4284 struct x_output *x = f->output_data.x;
4285 if (gwdesc != 0 && gwdesc == x->edit_widget)
4286 return f;
4287 }
4288 #endif /* USE_GTK */
4289 if (FRAME_X_WINDOW (f) == wdesc
4290 || f->output_data.x->icon_desc == wdesc)
4291 return f;
4292 #endif /* not USE_X_TOOLKIT */
4293 }
4294 return 0;
4295 }
4296
4297 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
4298
4299 /* Like x_window_to_frame but also compares the window with the widget's
4300 windows. */
4301
4302 static struct frame *
4303 x_any_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4304 {
4305 Lisp_Object tail, frame;
4306 struct frame *f, *found = NULL;
4307 struct x_output *x;
4308
4309 if (wdesc == None)
4310 return NULL;
4311
4312 FOR_EACH_FRAME (tail, frame)
4313 {
4314 if (found)
4315 break;
4316 f = XFRAME (frame);
4317 if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo)
4318 {
4319 /* This frame matches if the window is any of its widgets. */
4320 x = f->output_data.x;
4321 if (x->hourglass_window == wdesc)
4322 found = f;
4323 else if (x->widget)
4324 {
4325 #ifdef USE_GTK
4326 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4327 if (gwdesc != 0
4328 && gtk_widget_get_toplevel (gwdesc) == x->widget)
4329 found = f;
4330 #else
4331 if (wdesc == XtWindow (x->widget)
4332 || wdesc == XtWindow (x->column_widget)
4333 || wdesc == XtWindow (x->edit_widget))
4334 found = f;
4335 /* Match if the window is this frame's menubar. */
4336 else if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
4337 found = f;
4338 #endif
4339 }
4340 else if (FRAME_X_WINDOW (f) == wdesc)
4341 /* A tooltip frame. */
4342 found = f;
4343 }
4344 }
4345
4346 return found;
4347 }
4348
4349 /* Likewise, but consider only the menu bar widget. */
4350
4351 static struct frame *
4352 x_menubar_window_to_frame (struct x_display_info *dpyinfo,
4353 const XEvent *event)
4354 {
4355 Window wdesc = event->xany.window;
4356 Lisp_Object tail, frame;
4357 struct frame *f;
4358 struct x_output *x;
4359
4360 if (wdesc == None)
4361 return NULL;
4362
4363 FOR_EACH_FRAME (tail, frame)
4364 {
4365 f = XFRAME (frame);
4366 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4367 continue;
4368 x = f->output_data.x;
4369 #ifdef USE_GTK
4370 if (x->menubar_widget && xg_event_is_for_menubar (f, event))
4371 return f;
4372 #else
4373 /* Match if the window is this frame's menubar. */
4374 if (x->menubar_widget
4375 && lw_window_is_in_menubar (wdesc, x->menubar_widget))
4376 return f;
4377 #endif
4378 }
4379 return 0;
4380 }
4381
4382 /* Return the frame whose principal (outermost) window is WDESC.
4383 If WDESC is some other (smaller) window, we return 0. */
4384
4385 struct frame *
4386 x_top_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4387 {
4388 Lisp_Object tail, frame;
4389 struct frame *f;
4390 struct x_output *x;
4391
4392 if (wdesc == None)
4393 return NULL;
4394
4395 FOR_EACH_FRAME (tail, frame)
4396 {
4397 f = XFRAME (frame);
4398 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4399 continue;
4400 x = f->output_data.x;
4401
4402 if (x->widget)
4403 {
4404 /* This frame matches if the window is its topmost widget. */
4405 #ifdef USE_GTK
4406 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4407 if (gwdesc == x->widget)
4408 return f;
4409 #else
4410 if (wdesc == XtWindow (x->widget))
4411 return f;
4412 #endif
4413 }
4414 else if (FRAME_X_WINDOW (f) == wdesc)
4415 /* Tooltip frame. */
4416 return f;
4417 }
4418 return 0;
4419 }
4420
4421 #else /* !USE_X_TOOLKIT && !USE_GTK */
4422
4423 #define x_any_window_to_frame(d, i) x_window_to_frame (d, i)
4424 #define x_top_window_to_frame(d, i) x_window_to_frame (d, i)
4425
4426 #endif /* USE_X_TOOLKIT || USE_GTK */
4427
4428 /* The focus may have changed. Figure out if it is a real focus change,
4429 by checking both FocusIn/Out and Enter/LeaveNotify events.
4430
4431 Returns FOCUS_IN_EVENT event in *BUFP. */
4432
4433 static void
4434 x_detect_focus_change (struct x_display_info *dpyinfo, struct frame *frame,
4435 const XEvent *event, struct input_event *bufp)
4436 {
4437 if (!frame)
4438 return;
4439
4440 switch (event->type)
4441 {
4442 case EnterNotify:
4443 case LeaveNotify:
4444 {
4445 struct frame *focus_frame = dpyinfo->x_focus_event_frame;
4446 int focus_state
4447 = focus_frame ? focus_frame->output_data.x->focus_state : 0;
4448
4449 if (event->xcrossing.detail != NotifyInferior
4450 && event->xcrossing.focus
4451 && ! (focus_state & FOCUS_EXPLICIT))
4452 x_focus_changed ((event->type == EnterNotify ? FocusIn : FocusOut),
4453 FOCUS_IMPLICIT,
4454 dpyinfo, frame, bufp);
4455 }
4456 break;
4457
4458 case FocusIn:
4459 case FocusOut:
4460 x_focus_changed (event->type,
4461 (event->xfocus.detail == NotifyPointer ?
4462 FOCUS_IMPLICIT : FOCUS_EXPLICIT),
4463 dpyinfo, frame, bufp);
4464 break;
4465
4466 case ClientMessage:
4467 if (event->xclient.message_type == dpyinfo->Xatom_XEMBED)
4468 {
4469 enum xembed_message msg = event->xclient.data.l[1];
4470 x_focus_changed ((msg == XEMBED_FOCUS_IN ? FocusIn : FocusOut),
4471 FOCUS_EXPLICIT, dpyinfo, frame, bufp);
4472 }
4473 break;
4474 }
4475 }
4476
4477
4478 #if !defined USE_X_TOOLKIT && !defined USE_GTK
4479 /* Handle an event saying the mouse has moved out of an Emacs frame. */
4480
4481 void
4482 x_mouse_leave (struct x_display_info *dpyinfo)
4483 {
4484 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
4485 }
4486 #endif
4487
4488 /* The focus has changed, or we have redirected a frame's focus to
4489 another frame (this happens when a frame uses a surrogate
4490 mini-buffer frame). Shift the highlight as appropriate.
4491
4492 The FRAME argument doesn't necessarily have anything to do with which
4493 frame is being highlighted or un-highlighted; we only use it to find
4494 the appropriate X display info. */
4495
4496 static void
4497 XTframe_rehighlight (struct frame *frame)
4498 {
4499 x_frame_rehighlight (FRAME_DISPLAY_INFO (frame));
4500 }
4501
4502 static void
4503 x_frame_rehighlight (struct x_display_info *dpyinfo)
4504 {
4505 struct frame *old_highlight = dpyinfo->x_highlight_frame;
4506
4507 if (dpyinfo->x_focus_frame)
4508 {
4509 dpyinfo->x_highlight_frame
4510 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4511 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4512 : dpyinfo->x_focus_frame);
4513 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
4514 {
4515 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
4516 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
4517 }
4518 }
4519 else
4520 dpyinfo->x_highlight_frame = 0;
4521
4522 if (dpyinfo->x_highlight_frame != old_highlight)
4523 {
4524 if (old_highlight)
4525 frame_unhighlight (old_highlight);
4526 if (dpyinfo->x_highlight_frame)
4527 frame_highlight (dpyinfo->x_highlight_frame);
4528 }
4529 }
4530
4531
4532 \f
4533 /* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
4534
4535 /* Initialize mode_switch_bit and modifier_meaning. */
4536 static void
4537 x_find_modifier_meanings (struct x_display_info *dpyinfo)
4538 {
4539 int min_code, max_code;
4540 KeySym *syms;
4541 int syms_per_code;
4542 XModifierKeymap *mods;
4543
4544 dpyinfo->meta_mod_mask = 0;
4545 dpyinfo->shift_lock_mask = 0;
4546 dpyinfo->alt_mod_mask = 0;
4547 dpyinfo->super_mod_mask = 0;
4548 dpyinfo->hyper_mod_mask = 0;
4549
4550 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
4551
4552 syms = XGetKeyboardMapping (dpyinfo->display,
4553 min_code, max_code - min_code + 1,
4554 &syms_per_code);
4555 mods = XGetModifierMapping (dpyinfo->display);
4556
4557 /* Scan the modifier table to see which modifier bits the Meta and
4558 Alt keysyms are on. */
4559 {
4560 int row, col; /* The row and column in the modifier table. */
4561 bool found_alt_or_meta;
4562
4563 for (row = 3; row < 8; row++)
4564 {
4565 found_alt_or_meta = false;
4566 for (col = 0; col < mods->max_keypermod; col++)
4567 {
4568 KeyCode code = mods->modifiermap[(row * mods->max_keypermod) + col];
4569
4570 /* Zeroes are used for filler. Skip them. */
4571 if (code == 0)
4572 continue;
4573
4574 /* Are any of this keycode's keysyms a meta key? */
4575 {
4576 int code_col;
4577
4578 for (code_col = 0; code_col < syms_per_code; code_col++)
4579 {
4580 int sym = syms[((code - min_code) * syms_per_code) + code_col];
4581
4582 switch (sym)
4583 {
4584 case XK_Meta_L:
4585 case XK_Meta_R:
4586 found_alt_or_meta = true;
4587 dpyinfo->meta_mod_mask |= (1 << row);
4588 break;
4589
4590 case XK_Alt_L:
4591 case XK_Alt_R:
4592 found_alt_or_meta = true;
4593 dpyinfo->alt_mod_mask |= (1 << row);
4594 break;
4595
4596 case XK_Hyper_L:
4597 case XK_Hyper_R:
4598 if (!found_alt_or_meta)
4599 dpyinfo->hyper_mod_mask |= (1 << row);
4600 code_col = syms_per_code;
4601 col = mods->max_keypermod;
4602 break;
4603
4604 case XK_Super_L:
4605 case XK_Super_R:
4606 if (!found_alt_or_meta)
4607 dpyinfo->super_mod_mask |= (1 << row);
4608 code_col = syms_per_code;
4609 col = mods->max_keypermod;
4610 break;
4611
4612 case XK_Shift_Lock:
4613 /* Ignore this if it's not on the lock modifier. */
4614 if (!found_alt_or_meta && ((1 << row) == LockMask))
4615 dpyinfo->shift_lock_mask = LockMask;
4616 code_col = syms_per_code;
4617 col = mods->max_keypermod;
4618 break;
4619 }
4620 }
4621 }
4622 }
4623 }
4624 }
4625
4626 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
4627 if (! dpyinfo->meta_mod_mask)
4628 {
4629 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
4630 dpyinfo->alt_mod_mask = 0;
4631 }
4632
4633 /* If some keys are both alt and meta,
4634 make them just meta, not alt. */
4635 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
4636 {
4637 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
4638 }
4639
4640 XFree (syms);
4641 XFreeModifiermap (mods);
4642 }
4643
4644 /* Convert between the modifier bits X uses and the modifier bits
4645 Emacs uses. */
4646
4647 int
4648 x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state)
4649 {
4650 int mod_meta = meta_modifier;
4651 int mod_alt = alt_modifier;
4652 int mod_hyper = hyper_modifier;
4653 int mod_super = super_modifier;
4654 Lisp_Object tem;
4655
4656 tem = Fget (Vx_alt_keysym, Qmodifier_value);
4657 if (INTEGERP (tem)) mod_alt = XINT (tem) & INT_MAX;
4658 tem = Fget (Vx_meta_keysym, Qmodifier_value);
4659 if (INTEGERP (tem)) mod_meta = XINT (tem) & INT_MAX;
4660 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
4661 if (INTEGERP (tem)) mod_hyper = XINT (tem) & INT_MAX;
4662 tem = Fget (Vx_super_keysym, Qmodifier_value);
4663 if (INTEGERP (tem)) mod_super = XINT (tem) & INT_MAX;
4664
4665 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
4666 | ((state & ControlMask) ? ctrl_modifier : 0)
4667 | ((state & dpyinfo->meta_mod_mask) ? mod_meta : 0)
4668 | ((state & dpyinfo->alt_mod_mask) ? mod_alt : 0)
4669 | ((state & dpyinfo->super_mod_mask) ? mod_super : 0)
4670 | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0));
4671 }
4672
4673 static int
4674 x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, EMACS_INT state)
4675 {
4676 EMACS_INT mod_meta = meta_modifier;
4677 EMACS_INT mod_alt = alt_modifier;
4678 EMACS_INT mod_hyper = hyper_modifier;
4679 EMACS_INT mod_super = super_modifier;
4680
4681 Lisp_Object tem;
4682
4683 tem = Fget (Vx_alt_keysym, Qmodifier_value);
4684 if (INTEGERP (tem)) mod_alt = XINT (tem);
4685 tem = Fget (Vx_meta_keysym, Qmodifier_value);
4686 if (INTEGERP (tem)) mod_meta = XINT (tem);
4687 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
4688 if (INTEGERP (tem)) mod_hyper = XINT (tem);
4689 tem = Fget (Vx_super_keysym, Qmodifier_value);
4690 if (INTEGERP (tem)) mod_super = XINT (tem);
4691
4692
4693 return ( ((state & mod_alt) ? dpyinfo->alt_mod_mask : 0)
4694 | ((state & mod_super) ? dpyinfo->super_mod_mask : 0)
4695 | ((state & mod_hyper) ? dpyinfo->hyper_mod_mask : 0)
4696 | ((state & shift_modifier) ? ShiftMask : 0)
4697 | ((state & ctrl_modifier) ? ControlMask : 0)
4698 | ((state & mod_meta) ? dpyinfo->meta_mod_mask : 0));
4699 }
4700
4701 /* Convert a keysym to its name. */
4702
4703 char *
4704 x_get_keysym_name (int keysym)
4705 {
4706 char *value;
4707
4708 block_input ();
4709 value = XKeysymToString (keysym);
4710 unblock_input ();
4711
4712 return value;
4713 }
4714
4715 /* Mouse clicks and mouse movement. Rah.
4716
4717 Formerly, we used PointerMotionHintMask (in standard_event_mask)
4718 so that we would have to call XQueryPointer after each MotionNotify
4719 event to ask for another such event. However, this made mouse tracking
4720 slow, and there was a bug that made it eventually stop.
4721
4722 Simply asking for MotionNotify all the time seems to work better.
4723
4724 In order to avoid asking for motion events and then throwing most
4725 of them away or busy-polling the server for mouse positions, we ask
4726 the server for pointer motion hints. This means that we get only
4727 one event per group of mouse movements. "Groups" are delimited by
4728 other kinds of events (focus changes and button clicks, for
4729 example), or by XQueryPointer calls; when one of these happens, we
4730 get another MotionNotify event the next time the mouse moves. This
4731 is at least as efficient as getting motion events when mouse
4732 tracking is on, and I suspect only negligibly worse when tracking
4733 is off. */
4734
4735 /* Prepare a mouse-event in *RESULT for placement in the input queue.
4736
4737 If the event is a button press, then note that we have grabbed
4738 the mouse. */
4739
4740 static Lisp_Object
4741 construct_mouse_click (struct input_event *result,
4742 const XButtonEvent *event,
4743 struct frame *f)
4744 {
4745 /* Make the event type NO_EVENT; we'll change that when we decide
4746 otherwise. */
4747 result->kind = MOUSE_CLICK_EVENT;
4748 result->code = event->button - Button1;
4749 result->timestamp = event->time;
4750 result->modifiers = (x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f),
4751 event->state)
4752 | (event->type == ButtonRelease
4753 ? up_modifier
4754 : down_modifier));
4755
4756 XSETINT (result->x, event->x);
4757 XSETINT (result->y, event->y);
4758 XSETFRAME (result->frame_or_window, f);
4759 result->arg = Qnil;
4760 return Qnil;
4761 }
4762
4763 /* Function to report a mouse movement to the mainstream Emacs code.
4764 The input handler calls this.
4765
4766 We have received a mouse movement event, which is given in *event.
4767 If the mouse is over a different glyph than it was last time, tell
4768 the mainstream emacs code by setting mouse_moved. If not, ask for
4769 another motion event, so we can check again the next time it moves. */
4770
4771 static bool
4772 note_mouse_movement (struct frame *frame, const XMotionEvent *event)
4773 {
4774 XRectangle *r;
4775 struct x_display_info *dpyinfo;
4776
4777 if (!FRAME_X_OUTPUT (frame))
4778 return false;
4779
4780 dpyinfo = FRAME_DISPLAY_INFO (frame);
4781 dpyinfo->last_mouse_movement_time = event->time;
4782 dpyinfo->last_mouse_motion_frame = frame;
4783 dpyinfo->last_mouse_motion_x = event->x;
4784 dpyinfo->last_mouse_motion_y = event->y;
4785
4786 if (event->window != FRAME_X_WINDOW (frame))
4787 {
4788 frame->mouse_moved = true;
4789 dpyinfo->last_mouse_scroll_bar = NULL;
4790 note_mouse_highlight (frame, -1, -1);
4791 dpyinfo->last_mouse_glyph_frame = NULL;
4792 return true;
4793 }
4794
4795
4796 /* Has the mouse moved off the glyph it was on at the last sighting? */
4797 r = &dpyinfo->last_mouse_glyph;
4798 if (frame != dpyinfo->last_mouse_glyph_frame
4799 || event->x < r->x || event->x >= r->x + r->width
4800 || event->y < r->y || event->y >= r->y + r->height)
4801 {
4802 frame->mouse_moved = true;
4803 dpyinfo->last_mouse_scroll_bar = NULL;
4804 note_mouse_highlight (frame, event->x, event->y);
4805 /* Remember which glyph we're now on. */
4806 remember_mouse_glyph (frame, event->x, event->y, r);
4807 dpyinfo->last_mouse_glyph_frame = frame;
4808 return true;
4809 }
4810
4811 return false;
4812 }
4813
4814 /* Return the current position of the mouse.
4815 *FP should be a frame which indicates which display to ask about.
4816
4817 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
4818 and *PART to the frame, window, and scroll bar part that the mouse
4819 is over. Set *X and *Y to the portion and whole of the mouse's
4820 position on the scroll bar.
4821
4822 If the mouse movement started elsewhere, set *FP to the frame the
4823 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
4824 the mouse is over.
4825
4826 Set *TIMESTAMP to the server time-stamp for the time at which the mouse
4827 was at this position.
4828
4829 Don't store anything if we don't have a valid set of values to report.
4830
4831 This clears the mouse_moved flag, so we can wait for the next mouse
4832 movement. */
4833
4834 static void
4835 XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
4836 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
4837 Time *timestamp)
4838 {
4839 struct frame *f1;
4840 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
4841
4842 block_input ();
4843
4844 if (dpyinfo->last_mouse_scroll_bar && insist == 0)
4845 {
4846 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
4847
4848 if (bar->horizontal)
4849 x_horizontal_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp);
4850 else
4851 x_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp);
4852 }
4853 else
4854 {
4855 Window root;
4856 int root_x, root_y;
4857
4858 Window dummy_window;
4859 int dummy;
4860
4861 Lisp_Object frame, tail;
4862
4863 /* Clear the mouse-moved flag for every frame on this display. */
4864 FOR_EACH_FRAME (tail, frame)
4865 if (FRAME_X_P (XFRAME (frame))
4866 && FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
4867 XFRAME (frame)->mouse_moved = false;
4868
4869 dpyinfo->last_mouse_scroll_bar = NULL;
4870
4871 /* Figure out which root window we're on. */
4872 XQueryPointer (FRAME_X_DISPLAY (*fp),
4873 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
4874
4875 /* The root window which contains the pointer. */
4876 &root,
4877
4878 /* Trash which we can't trust if the pointer is on
4879 a different screen. */
4880 &dummy_window,
4881
4882 /* The position on that root window. */
4883 &root_x, &root_y,
4884
4885 /* More trash we can't trust. */
4886 &dummy, &dummy,
4887
4888 /* Modifier keys and pointer buttons, about which
4889 we don't care. */
4890 (unsigned int *) &dummy);
4891
4892 /* Now we have a position on the root; find the innermost window
4893 containing the pointer. */
4894 {
4895 Window win, child;
4896 int win_x, win_y;
4897 int parent_x = 0, parent_y = 0;
4898
4899 win = root;
4900
4901 /* XTranslateCoordinates can get errors if the window
4902 structure is changing at the same time this function
4903 is running. So at least we must not crash from them. */
4904
4905 x_catch_errors (FRAME_X_DISPLAY (*fp));
4906
4907 if (x_mouse_grabbed (dpyinfo))
4908 {
4909 /* If mouse was grabbed on a frame, give coords for that frame
4910 even if the mouse is now outside it. */
4911 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
4912
4913 /* From-window. */
4914 root,
4915
4916 /* To-window. */
4917 FRAME_X_WINDOW (dpyinfo->last_mouse_frame),
4918
4919 /* From-position, to-position. */
4920 root_x, root_y, &win_x, &win_y,
4921
4922 /* Child of win. */
4923 &child);
4924 f1 = dpyinfo->last_mouse_frame;
4925 }
4926 else
4927 {
4928 while (true)
4929 {
4930 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
4931
4932 /* From-window, to-window. */
4933 root, win,
4934
4935 /* From-position, to-position. */
4936 root_x, root_y, &win_x, &win_y,
4937
4938 /* Child of win. */
4939 &child);
4940
4941 if (child == None || child == win)
4942 break;
4943 #ifdef USE_GTK
4944 /* We don't wan't to know the innermost window. We
4945 want the edit window. For non-Gtk+ the innermost
4946 window is the edit window. For Gtk+ it might not
4947 be. It might be the tool bar for example. */
4948 if (x_window_to_frame (dpyinfo, win))
4949 break;
4950 #endif
4951 win = child;
4952 parent_x = win_x;
4953 parent_y = win_y;
4954 }
4955
4956 /* Now we know that:
4957 win is the innermost window containing the pointer
4958 (XTC says it has no child containing the pointer),
4959 win_x and win_y are the pointer's position in it
4960 (XTC did this the last time through), and
4961 parent_x and parent_y are the pointer's position in win's parent.
4962 (They are what win_x and win_y were when win was child.
4963 If win is the root window, it has no parent, and
4964 parent_{x,y} are invalid, but that's okay, because we'll
4965 never use them in that case.) */
4966
4967 #ifdef USE_GTK
4968 /* We don't wan't to know the innermost window. We
4969 want the edit window. */
4970 f1 = x_window_to_frame (dpyinfo, win);
4971 #else
4972 /* Is win one of our frames? */
4973 f1 = x_any_window_to_frame (dpyinfo, win);
4974 #endif
4975
4976 #ifdef USE_X_TOOLKIT
4977 /* If we end up with the menu bar window, say it's not
4978 on the frame. */
4979 if (f1 != NULL
4980 && f1->output_data.x->menubar_widget
4981 && win == XtWindow (f1->output_data.x->menubar_widget))
4982 f1 = NULL;
4983 #endif /* USE_X_TOOLKIT */
4984 }
4985
4986 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
4987 f1 = 0;
4988
4989 x_uncatch_errors_after_check ();
4990
4991 /* If not, is it one of our scroll bars? */
4992 if (! f1)
4993 {
4994 struct scroll_bar *bar;
4995
4996 bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win, 2);
4997
4998 if (bar)
4999 {
5000 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5001 win_x = parent_x;
5002 win_y = parent_y;
5003 }
5004 }
5005
5006 if (f1 == 0 && insist > 0)
5007 f1 = SELECTED_FRAME ();
5008
5009 if (f1)
5010 {
5011 /* Ok, we found a frame. Store all the values.
5012 last_mouse_glyph is a rectangle used to reduce the
5013 generation of mouse events. To not miss any motion
5014 events, we must divide the frame into rectangles of the
5015 size of the smallest character that could be displayed
5016 on it, i.e. into the same rectangles that matrices on
5017 the frame are divided into. */
5018
5019 /* FIXME: what if F1 is not an X frame? */
5020 dpyinfo = FRAME_DISPLAY_INFO (f1);
5021 remember_mouse_glyph (f1, win_x, win_y, &dpyinfo->last_mouse_glyph);
5022 dpyinfo->last_mouse_glyph_frame = f1;
5023
5024 *bar_window = Qnil;
5025 *part = 0;
5026 *fp = f1;
5027 XSETINT (*x, win_x);
5028 XSETINT (*y, win_y);
5029 *timestamp = dpyinfo->last_mouse_movement_time;
5030 }
5031 }
5032 }
5033
5034 unblock_input ();
5035 }
5036
5037
5038 \f
5039 /***********************************************************************
5040 Scroll bars
5041 ***********************************************************************/
5042
5043 /* Scroll bar support. */
5044
5045 /* Given an X window ID and a DISPLAY, find the struct scroll_bar which
5046 manages it.
5047 This can be called in GC, so we have to make sure to strip off mark
5048 bits. */
5049
5050 static struct scroll_bar *
5051 x_window_to_scroll_bar (Display *display, Window window_id, int type)
5052 {
5053 Lisp_Object tail, frame;
5054
5055 #if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
5056 window_id = (Window) xg_get_scroll_id_for_window (display, window_id);
5057 #endif /* USE_GTK && USE_TOOLKIT_SCROLL_BARS */
5058
5059 FOR_EACH_FRAME (tail, frame)
5060 {
5061 Lisp_Object bar, condemned;
5062
5063 if (! FRAME_X_P (XFRAME (frame)))
5064 continue;
5065
5066 /* Scan this frame's scroll bar list for a scroll bar with the
5067 right window ID. */
5068 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
5069 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
5070 /* This trick allows us to search both the ordinary and
5071 condemned scroll bar lists with one loop. */
5072 ! NILP (bar) || (bar = condemned,
5073 condemned = Qnil,
5074 ! NILP (bar));
5075 bar = XSCROLL_BAR (bar)->next)
5076 if (XSCROLL_BAR (bar)->x_window == window_id
5077 && FRAME_X_DISPLAY (XFRAME (frame)) == display
5078 && (type = 2
5079 || (type == 1 && XSCROLL_BAR (bar)->horizontal)
5080 || (type == 0 && !XSCROLL_BAR (bar)->horizontal)))
5081 return XSCROLL_BAR (bar);
5082 }
5083
5084 return NULL;
5085 }
5086
5087
5088 #if defined USE_LUCID
5089
5090 /* Return the Lucid menu bar WINDOW is part of. Return null
5091 if WINDOW is not part of a menu bar. */
5092
5093 static Widget
5094 x_window_to_menu_bar (Window window)
5095 {
5096 Lisp_Object tail, frame;
5097
5098 FOR_EACH_FRAME (tail, frame)
5099 if (FRAME_X_P (XFRAME (frame)))
5100 {
5101 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
5102
5103 if (menu_bar && xlwmenu_window_p (menu_bar, window))
5104 return menu_bar;
5105 }
5106 return NULL;
5107 }
5108
5109 #endif /* USE_LUCID */
5110
5111 \f
5112 /************************************************************************
5113 Toolkit scroll bars
5114 ************************************************************************/
5115
5116 #ifdef USE_TOOLKIT_SCROLL_BARS
5117
5118 static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part,
5119 int, int, bool);
5120
5121 /* Lisp window being scrolled. Set when starting to interact with
5122 a toolkit scroll bar, reset to nil when ending the interaction. */
5123
5124 static Lisp_Object window_being_scrolled;
5125
5126 /* Whether this is an Xaw with arrow-scrollbars. This should imply
5127 that movements of 1/20 of the screen size are mapped to up/down. */
5128
5129 #ifndef USE_GTK
5130 /* Id of action hook installed for scroll bars. */
5131
5132 static XtActionHookId action_hook_id;
5133 static XtActionHookId horizontal_action_hook_id;
5134
5135 static Boolean xaw3d_arrow_scroll;
5136
5137 /* Whether the drag scrolling maintains the mouse at the top of the
5138 thumb. If not, resizing the thumb needs to be done more carefully
5139 to avoid jerkiness. */
5140
5141 static Boolean xaw3d_pick_top;
5142
5143 /* Action hook installed via XtAppAddActionHook when toolkit scroll
5144 bars are used.. The hook is responsible for detecting when
5145 the user ends an interaction with the scroll bar, and generates
5146 a `end-scroll' SCROLL_BAR_CLICK_EVENT' event if so. */
5147
5148 static void
5149 xt_action_hook (Widget widget, XtPointer client_data, String action_name,
5150 XEvent *event, String *params, Cardinal *num_params)
5151 {
5152 bool scroll_bar_p;
5153 const char *end_action;
5154
5155 #ifdef USE_MOTIF
5156 scroll_bar_p = XmIsScrollBar (widget);
5157 end_action = "Release";
5158 #else /* !USE_MOTIF i.e. use Xaw */
5159 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
5160 end_action = "EndScroll";
5161 #endif /* USE_MOTIF */
5162
5163 if (scroll_bar_p
5164 && strcmp (action_name, end_action) == 0
5165 && WINDOWP (window_being_scrolled))
5166 {
5167 struct window *w;
5168 struct scroll_bar *bar;
5169
5170 x_send_scroll_bar_event (window_being_scrolled,
5171 scroll_bar_end_scroll, 0, 0, false);
5172 w = XWINDOW (window_being_scrolled);
5173 bar = XSCROLL_BAR (w->vertical_scroll_bar);
5174
5175 if (bar->dragging != -1)
5176 {
5177 bar->dragging = -1;
5178 /* The thumb size is incorrect while dragging: fix it. */
5179 set_vertical_scroll_bar (w);
5180 }
5181 window_being_scrolled = Qnil;
5182 #if defined (USE_LUCID)
5183 bar->last_seen_part = scroll_bar_nowhere;
5184 #endif
5185 /* Xt timeouts no longer needed. */
5186 toolkit_scroll_bar_interaction = false;
5187 }
5188 }
5189
5190
5191 static void
5192 xt_horizontal_action_hook (Widget widget, XtPointer client_data, String action_name,
5193 XEvent *event, String *params, Cardinal *num_params)
5194 {
5195 bool scroll_bar_p;
5196 const char *end_action;
5197
5198 #ifdef USE_MOTIF
5199 scroll_bar_p = XmIsScrollBar (widget);
5200 end_action = "Release";
5201 #else /* !USE_MOTIF i.e. use Xaw */
5202 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
5203 end_action = "EndScroll";
5204 #endif /* USE_MOTIF */
5205
5206 if (scroll_bar_p
5207 && strcmp (action_name, end_action) == 0
5208 && WINDOWP (window_being_scrolled))
5209 {
5210 struct window *w;
5211 struct scroll_bar *bar;
5212
5213 x_send_scroll_bar_event (window_being_scrolled,
5214 scroll_bar_end_scroll, 0, 0, true);
5215 w = XWINDOW (window_being_scrolled);
5216 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
5217
5218 if (bar->dragging != -1)
5219 {
5220 bar->dragging = -1;
5221 /* The thumb size is incorrect while dragging: fix it. */
5222 set_horizontal_scroll_bar (w);
5223 }
5224 window_being_scrolled = Qnil;
5225 #if defined (USE_LUCID)
5226 bar->last_seen_part = scroll_bar_nowhere;
5227 #endif
5228 /* Xt timeouts no longer needed. */
5229 toolkit_scroll_bar_interaction = false;
5230 }
5231 }
5232 #endif /* not USE_GTK */
5233
5234 /* Send a client message with message type Xatom_Scrollbar for a
5235 scroll action to the frame of WINDOW. PART is a value identifying
5236 the part of the scroll bar that was clicked on. PORTION is the
5237 amount to scroll of a whole of WHOLE. */
5238
5239 static void
5240 x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part,
5241 int portion, int whole, bool horizontal)
5242 {
5243 XEvent event;
5244 XClientMessageEvent *ev = &event.xclient;
5245 struct window *w = XWINDOW (window);
5246 struct frame *f = XFRAME (w->frame);
5247 intptr_t iw = (intptr_t) w;
5248 enum { BITS_PER_INTPTR = CHAR_BIT * sizeof iw };
5249 verify (BITS_PER_INTPTR <= 64);
5250 int sign_shift = BITS_PER_INTPTR - 32;
5251
5252 block_input ();
5253
5254 /* Construct a ClientMessage event to send to the frame. */
5255 ev->type = ClientMessage;
5256 ev->message_type = (horizontal
5257 ? FRAME_DISPLAY_INFO (f)->Xatom_Horizontal_Scrollbar
5258 : FRAME_DISPLAY_INFO (f)->Xatom_Scrollbar);
5259 ev->display = FRAME_X_DISPLAY (f);
5260 ev->window = FRAME_X_WINDOW (f);
5261 ev->format = 32;
5262
5263 /* A 32-bit X client on a 64-bit X server can pass a window pointer
5264 as-is. A 64-bit client on a 32-bit X server is in trouble
5265 because a pointer does not fit and would be truncated while
5266 passing through the server. So use two slots and hope that X12
5267 will resolve such issues someday. */
5268 ev->data.l[0] = iw >> 31 >> 1;
5269 ev->data.l[1] = sign_shift <= 0 ? iw : iw << sign_shift >> sign_shift;
5270 ev->data.l[2] = part;
5271 ev->data.l[3] = portion;
5272 ev->data.l[4] = whole;
5273
5274 /* Make Xt timeouts work while the scroll bar is active. */
5275 #ifdef USE_X_TOOLKIT
5276 toolkit_scroll_bar_interaction = true;
5277 x_activate_timeout_atimer ();
5278 #endif
5279
5280 /* Setting the event mask to zero means that the message will
5281 be sent to the client that created the window, and if that
5282 window no longer exists, no event will be sent. */
5283 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
5284 unblock_input ();
5285 }
5286
5287
5288 /* Transform a scroll bar ClientMessage EVENT to an Emacs input event
5289 in *IEVENT. */
5290
5291 static void
5292 x_scroll_bar_to_input_event (const XEvent *event,
5293 struct input_event *ievent)
5294 {
5295 const XClientMessageEvent *ev = &event->xclient;
5296 Lisp_Object window;
5297 struct window *w;
5298
5299 /* See the comment in the function above. */
5300 intptr_t iw0 = ev->data.l[0];
5301 intptr_t iw1 = ev->data.l[1];
5302 intptr_t iw = (iw0 << 31 << 1) + (iw1 & 0xffffffffu);
5303 w = (struct window *) iw;
5304
5305 XSETWINDOW (window, w);
5306
5307 ievent->kind = SCROLL_BAR_CLICK_EVENT;
5308 ievent->frame_or_window = window;
5309 ievent->arg = Qnil;
5310 #ifdef USE_GTK
5311 ievent->timestamp = CurrentTime;
5312 #else
5313 ievent->timestamp =
5314 XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame)));
5315 #endif
5316 ievent->code = 0;
5317 ievent->part = ev->data.l[2];
5318 ievent->x = make_number (ev->data.l[3]);
5319 ievent->y = make_number (ev->data.l[4]);
5320 ievent->modifiers = 0;
5321 }
5322
5323 /* Transform a horizontal scroll bar ClientMessage EVENT to an Emacs
5324 input event in *IEVENT. */
5325
5326 static void
5327 x_horizontal_scroll_bar_to_input_event (const XEvent *event,
5328 struct input_event *ievent)
5329 {
5330 const XClientMessageEvent *ev = &event->xclient;
5331 Lisp_Object window;
5332 struct window *w;
5333
5334 /* See the comment in the function above. */
5335 intptr_t iw0 = ev->data.l[0];
5336 intptr_t iw1 = ev->data.l[1];
5337 intptr_t iw = (iw0 << 31 << 1) + (iw1 & 0xffffffffu);
5338 w = (struct window *) iw;
5339
5340 XSETWINDOW (window, w);
5341
5342 ievent->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
5343 ievent->frame_or_window = window;
5344 ievent->arg = Qnil;
5345 #ifdef USE_GTK
5346 ievent->timestamp = CurrentTime;
5347 #else
5348 ievent->timestamp =
5349 XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame)));
5350 #endif
5351 ievent->code = 0;
5352 ievent->part = ev->data.l[2];
5353 ievent->x = make_number (ev->data.l[3]);
5354 ievent->y = make_number (ev->data.l[4]);
5355 ievent->modifiers = 0;
5356 }
5357
5358
5359 #ifdef USE_MOTIF
5360
5361 /* Minimum and maximum values used for Motif scroll bars. */
5362
5363 #define XM_SB_MAX 10000000
5364
5365 /* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
5366 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
5367 CALL_DATA is a pointer to a XmScrollBarCallbackStruct. */
5368
5369 static void
5370 xm_scroll_callback (Widget widget, XtPointer client_data, XtPointer call_data)
5371 {
5372 struct scroll_bar *bar = client_data;
5373 XmScrollBarCallbackStruct *cs = call_data;
5374 enum scroll_bar_part part = scroll_bar_nowhere;
5375 bool horizontal = bar->horizontal;
5376 int whole = 0, portion = 0;
5377
5378 switch (cs->reason)
5379 {
5380 case XmCR_DECREMENT:
5381 bar->dragging = -1;
5382 part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow;
5383 break;
5384
5385 case XmCR_INCREMENT:
5386 bar->dragging = -1;
5387 part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow;
5388 break;
5389
5390 case XmCR_PAGE_DECREMENT:
5391 bar->dragging = -1;
5392 part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle;
5393 break;
5394
5395 case XmCR_PAGE_INCREMENT:
5396 bar->dragging = -1;
5397 part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle;
5398 break;
5399
5400 case XmCR_TO_TOP:
5401 bar->dragging = -1;
5402 part = horizontal ? scroll_bar_to_leftmost : scroll_bar_to_top;
5403 break;
5404
5405 case XmCR_TO_BOTTOM:
5406 bar->dragging = -1;
5407 part = horizontal ? scroll_bar_to_rightmost : scroll_bar_to_bottom;
5408 break;
5409
5410 case XmCR_DRAG:
5411 {
5412 int slider_size;
5413
5414 block_input ();
5415 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
5416 unblock_input ();
5417
5418 if (horizontal)
5419 {
5420 portion = bar->whole * ((float)cs->value / XM_SB_MAX);
5421 whole = bar->whole * ((float)(XM_SB_MAX - slider_size) / XM_SB_MAX);
5422 portion = min (portion, whole);
5423 part = scroll_bar_horizontal_handle;
5424 }
5425 else
5426 {
5427 whole = XM_SB_MAX - slider_size;
5428 portion = min (cs->value, whole);
5429 part = scroll_bar_handle;
5430 }
5431
5432 bar->dragging = cs->value;
5433 }
5434 break;
5435
5436 case XmCR_VALUE_CHANGED:
5437 break;
5438 };
5439
5440 if (part != scroll_bar_nowhere)
5441 {
5442 window_being_scrolled = bar->window;
5443 x_send_scroll_bar_event (bar->window, part, portion, whole,
5444 bar->horizontal);
5445 }
5446 }
5447
5448 #elif defined USE_GTK
5449
5450 /* Scroll bar callback for GTK scroll bars. WIDGET is the scroll
5451 bar widget. DATA is a pointer to the scroll_bar structure. */
5452
5453 static gboolean
5454 xg_scroll_callback (GtkRange *range,
5455 GtkScrollType scroll,
5456 gdouble value,
5457 gpointer user_data)
5458 {
5459 int whole = 0, portion = 0;
5460 struct scroll_bar *bar = user_data;
5461 enum scroll_bar_part part = scroll_bar_nowhere;
5462 GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
5463 struct frame *f = g_object_get_data (G_OBJECT (range), XG_FRAME_DATA);
5464
5465 if (xg_ignore_gtk_scrollbar) return false;
5466
5467 switch (scroll)
5468 {
5469 case GTK_SCROLL_JUMP:
5470 /* Buttons 1 2 or 3 must be grabbed. */
5471 if (FRAME_DISPLAY_INFO (f)->grabbed != 0
5472 && FRAME_DISPLAY_INFO (f)->grabbed < (1 << 4))
5473 {
5474 if (bar->horizontal)
5475 {
5476 part = scroll_bar_horizontal_handle;
5477 whole = (int)(gtk_adjustment_get_upper (adj) -
5478 gtk_adjustment_get_page_size (adj));
5479 portion = min ((int)value, whole);
5480 bar->dragging = portion;
5481 }
5482 else
5483 {
5484 part = scroll_bar_handle;
5485 whole = gtk_adjustment_get_upper (adj) -
5486 gtk_adjustment_get_page_size (adj);
5487 portion = min ((int)value, whole);
5488 bar->dragging = portion;
5489 }
5490 }
5491 break;
5492 case GTK_SCROLL_STEP_BACKWARD:
5493 part = (bar->horizontal
5494 ? scroll_bar_left_arrow : scroll_bar_up_arrow);
5495 bar->dragging = -1;
5496 break;
5497 case GTK_SCROLL_STEP_FORWARD:
5498 part = (bar->horizontal
5499 ? scroll_bar_right_arrow : scroll_bar_down_arrow);
5500 bar->dragging = -1;
5501 break;
5502 case GTK_SCROLL_PAGE_BACKWARD:
5503 part = (bar->horizontal
5504 ? scroll_bar_before_handle : scroll_bar_above_handle);
5505 bar->dragging = -1;
5506 break;
5507 case GTK_SCROLL_PAGE_FORWARD:
5508 part = (bar->horizontal
5509 ? scroll_bar_after_handle : scroll_bar_below_handle);
5510 bar->dragging = -1;
5511 break;
5512 default:
5513 break;
5514 }
5515
5516 if (part != scroll_bar_nowhere)
5517 {
5518 window_being_scrolled = bar->window;
5519 x_send_scroll_bar_event (bar->window, part, portion, whole,
5520 bar->horizontal);
5521 }
5522
5523 return false;
5524 }
5525
5526 /* Callback for button release. Sets dragging to -1 when dragging is done. */
5527
5528 static gboolean
5529 xg_end_scroll_callback (GtkWidget *widget,
5530 GdkEventButton *event,
5531 gpointer user_data)
5532 {
5533 struct scroll_bar *bar = user_data;
5534 bar->dragging = -1;
5535 if (WINDOWP (window_being_scrolled))
5536 {
5537 x_send_scroll_bar_event (window_being_scrolled,
5538 scroll_bar_end_scroll, 0, 0, bar->horizontal);
5539 window_being_scrolled = Qnil;
5540 }
5541
5542 return false;
5543 }
5544
5545
5546 #else /* not USE_GTK and not USE_MOTIF */
5547
5548 /* Xaw scroll bar callback. Invoked when the thumb is dragged.
5549 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
5550 scroll bar struct. CALL_DATA is a pointer to a float saying where
5551 the thumb is. */
5552
5553 static void
5554 xaw_jump_callback (Widget widget, XtPointer client_data, XtPointer call_data)
5555 {
5556 struct scroll_bar *bar = client_data;
5557 float *top_addr = call_data;
5558 float top = *top_addr;
5559 float shown;
5560 int whole, portion, height, width;
5561 enum scroll_bar_part part;
5562 bool horizontal = bar->horizontal;
5563
5564
5565 if (horizontal)
5566 {
5567 /* Get the size of the thumb, a value between 0 and 1. */
5568 block_input ();
5569 XtVaGetValues (widget, XtNshown, &shown, XtNwidth, &width, NULL);
5570 unblock_input ();
5571
5572 if (shown < 1)
5573 {
5574 whole = bar->whole - (shown * bar->whole);
5575 portion = min (top * bar->whole, whole);
5576 }
5577 else
5578 {
5579 whole = bar->whole;
5580 portion = 0;
5581 }
5582
5583 part = scroll_bar_horizontal_handle;
5584 }
5585 else
5586 {
5587 /* Get the size of the thumb, a value between 0 and 1. */
5588 block_input ();
5589 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
5590 unblock_input ();
5591
5592 whole = 10000000;
5593 portion = shown < 1 ? top * whole : 0;
5594
5595 if (shown < 1 && (eabs (top + shown - 1) < 1.0f / height))
5596 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
5597 the bottom, so we force the scrolling whenever we see that we're
5598 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
5599 we try to ensure that we always stay two pixels away from the
5600 bottom). */
5601 part = scroll_bar_down_arrow;
5602 else
5603 part = scroll_bar_handle;
5604 }
5605
5606 window_being_scrolled = bar->window;
5607 bar->dragging = portion;
5608 bar->last_seen_part = part;
5609 x_send_scroll_bar_event (bar->window, part, portion, whole, bar->horizontal);
5610 }
5611
5612
5613 /* Xaw scroll bar callback. Invoked for incremental scrolling.,
5614 i.e. line or page up or down. WIDGET is the Xaw scroll bar
5615 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
5616 the scroll bar. CALL_DATA is an integer specifying the action that
5617 has taken place. Its magnitude is in the range 0..height of the
5618 scroll bar. Negative values mean scroll towards buffer start.
5619 Values < height of scroll bar mean line-wise movement. */
5620
5621 static void
5622 xaw_scroll_callback (Widget widget, XtPointer client_data, XtPointer call_data)
5623 {
5624 struct scroll_bar *bar = client_data;
5625 /* The position really is stored cast to a pointer. */
5626 int position = (intptr_t) call_data;
5627 Dimension height, width;
5628 enum scroll_bar_part part;
5629
5630 if (bar->horizontal)
5631 {
5632 /* Get the width of the scroll bar. */
5633 block_input ();
5634 XtVaGetValues (widget, XtNwidth, &width, NULL);
5635 unblock_input ();
5636
5637 if (eabs (position) >= width)
5638 part = (position < 0) ? scroll_bar_before_handle : scroll_bar_after_handle;
5639
5640 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
5641 it maps line-movement to call_data = max(5, height/20). */
5642 else if (xaw3d_arrow_scroll && eabs (position) <= max (5, width / 20))
5643 part = (position < 0) ? scroll_bar_left_arrow : scroll_bar_right_arrow;
5644 else
5645 part = scroll_bar_move_ratio;
5646
5647 window_being_scrolled = bar->window;
5648 bar->dragging = -1;
5649 bar->last_seen_part = part;
5650 x_send_scroll_bar_event (bar->window, part, position, width,
5651 bar->horizontal);
5652 }
5653 else
5654 {
5655
5656 /* Get the height of the scroll bar. */
5657 block_input ();
5658 XtVaGetValues (widget, XtNheight, &height, NULL);
5659 unblock_input ();
5660
5661 if (eabs (position) >= height)
5662 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
5663
5664 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
5665 it maps line-movement to call_data = max(5, height/20). */
5666 else if (xaw3d_arrow_scroll && eabs (position) <= max (5, height / 20))
5667 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
5668 else
5669 part = scroll_bar_move_ratio;
5670
5671 window_being_scrolled = bar->window;
5672 bar->dragging = -1;
5673 bar->last_seen_part = part;
5674 x_send_scroll_bar_event (bar->window, part, position, height,
5675 bar->horizontal);
5676 }
5677 }
5678
5679 #endif /* not USE_GTK and not USE_MOTIF */
5680
5681 #define SCROLL_BAR_NAME "verticalScrollBar"
5682 #define SCROLL_BAR_HORIZONTAL_NAME "horizontalScrollBar"
5683
5684 /* Create the widget for scroll bar BAR on frame F. Record the widget
5685 and X window of the scroll bar in BAR. */
5686
5687 #ifdef USE_GTK
5688 static void
5689 x_create_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
5690 {
5691 const char *scroll_bar_name = SCROLL_BAR_NAME;
5692
5693 block_input ();
5694 xg_create_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
5695 G_CALLBACK (xg_end_scroll_callback),
5696 scroll_bar_name);
5697 unblock_input ();
5698 }
5699
5700 static void
5701 x_create_horizontal_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
5702 {
5703 const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME;
5704
5705 block_input ();
5706 xg_create_horizontal_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
5707 G_CALLBACK (xg_end_scroll_callback),
5708 scroll_bar_name);
5709 unblock_input ();
5710 }
5711
5712 #else /* not USE_GTK */
5713
5714 static void
5715 x_create_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
5716 {
5717 Window xwindow;
5718 Widget widget;
5719 Arg av[20];
5720 int ac = 0;
5721 const char *scroll_bar_name = SCROLL_BAR_NAME;
5722 unsigned long pixel;
5723
5724 block_input ();
5725
5726 #ifdef USE_MOTIF
5727 /* Set resources. Create the widget. */
5728 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
5729 XtSetArg (av[ac], XmNminimum, 0); ++ac;
5730 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
5731 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
5732 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
5733 XtSetArg (av[ac], XmNincrement, 1); ++ac;
5734 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
5735
5736 pixel = f->output_data.x->scroll_bar_foreground_pixel;
5737 if (pixel != -1)
5738 {
5739 XtSetArg (av[ac], XmNforeground, pixel);
5740 ++ac;
5741 }
5742
5743 pixel = f->output_data.x->scroll_bar_background_pixel;
5744 if (pixel != -1)
5745 {
5746 XtSetArg (av[ac], XmNbackground, pixel);
5747 ++ac;
5748 }
5749
5750 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
5751 (char *) scroll_bar_name, av, ac);
5752
5753 /* Add one callback for everything that can happen. */
5754 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
5755 (XtPointer) bar);
5756 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
5757 (XtPointer) bar);
5758 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
5759 (XtPointer) bar);
5760 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
5761 (XtPointer) bar);
5762 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
5763 (XtPointer) bar);
5764 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
5765 (XtPointer) bar);
5766 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
5767 (XtPointer) bar);
5768
5769 /* Realize the widget. Only after that is the X window created. */
5770 XtRealizeWidget (widget);
5771
5772 /* Set the cursor to an arrow. I didn't find a resource to do that.
5773 And I'm wondering why it hasn't an arrow cursor by default. */
5774 XDefineCursor (XtDisplay (widget), XtWindow (widget),
5775 f->output_data.x->nontext_cursor);
5776
5777 #else /* !USE_MOTIF i.e. use Xaw */
5778
5779 /* Set resources. Create the widget. The background of the
5780 Xaw3d scroll bar widget is a little bit light for my taste.
5781 We don't alter it here to let users change it according
5782 to their taste with `emacs*verticalScrollBar.background: xxx'. */
5783 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
5784 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
5785 /* For smoother scrolling with Xaw3d -sm */
5786 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
5787
5788 pixel = f->output_data.x->scroll_bar_foreground_pixel;
5789 if (pixel != -1)
5790 {
5791 XtSetArg (av[ac], XtNforeground, pixel);
5792 ++ac;
5793 }
5794
5795 pixel = f->output_data.x->scroll_bar_background_pixel;
5796 if (pixel != -1)
5797 {
5798 XtSetArg (av[ac], XtNbackground, pixel);
5799 ++ac;
5800 }
5801
5802 /* Top/bottom shadow colors. */
5803
5804 /* Allocate them, if necessary. */
5805 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
5806 {
5807 pixel = f->output_data.x->scroll_bar_background_pixel;
5808 if (pixel != -1)
5809 {
5810 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
5811 FRAME_X_COLORMAP (f),
5812 &pixel, 1.2, 0x8000))
5813 pixel = -1;
5814 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
5815 }
5816 }
5817 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
5818 {
5819 pixel = f->output_data.x->scroll_bar_background_pixel;
5820 if (pixel != -1)
5821 {
5822 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
5823 FRAME_X_COLORMAP (f),
5824 &pixel, 0.6, 0x4000))
5825 pixel = -1;
5826 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
5827 }
5828 }
5829
5830 #ifdef XtNbeNiceToColormap
5831 /* Tell the toolkit about them. */
5832 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
5833 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
5834 /* We tried to allocate a color for the top/bottom shadow, and
5835 failed, so tell Xaw3d to use dithering instead. */
5836 /* But only if we have a small colormap. Xaw3d can allocate nice
5837 colors itself. */
5838 {
5839 XtSetArg (av[ac], XtNbeNiceToColormap,
5840 DefaultDepthOfScreen (FRAME_X_SCREEN (f)) < 16);
5841 ++ac;
5842 }
5843 else
5844 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
5845 be more consistent with other emacs 3d colors, and since Xaw3d is
5846 not good at dealing with allocation failure. */
5847 {
5848 /* This tells Xaw3d to use real colors instead of dithering for
5849 the shadows. */
5850 XtSetArg (av[ac], XtNbeNiceToColormap, False);
5851 ++ac;
5852
5853 /* Specify the colors. */
5854 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
5855 if (pixel != -1)
5856 {
5857 XtSetArg (av[ac], XtNtopShadowPixel, pixel);
5858 ++ac;
5859 }
5860 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
5861 if (pixel != -1)
5862 {
5863 XtSetArg (av[ac], XtNbottomShadowPixel, pixel);
5864 ++ac;
5865 }
5866 }
5867 #endif
5868
5869 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
5870 f->output_data.x->edit_widget, av, ac);
5871
5872 {
5873 char const *initial = "";
5874 char const *val = initial;
5875 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
5876 #ifdef XtNarrowScrollbars
5877 XtNarrowScrollbars, (XtPointer) &xaw3d_arrow_scroll,
5878 #endif
5879 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
5880 if (xaw3d_arrow_scroll || val == initial)
5881 { /* ARROW_SCROLL */
5882 xaw3d_arrow_scroll = True;
5883 /* Isn't that just a personal preference ? --Stef */
5884 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
5885 }
5886 }
5887
5888 /* Define callbacks. */
5889 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
5890 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
5891 (XtPointer) bar);
5892
5893 /* Realize the widget. Only after that is the X window created. */
5894 XtRealizeWidget (widget);
5895
5896 #endif /* !USE_MOTIF */
5897
5898 /* Install an action hook that lets us detect when the user
5899 finishes interacting with a scroll bar. */
5900 if (action_hook_id == 0)
5901 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
5902
5903 /* Remember X window and widget in the scroll bar vector. */
5904 SET_SCROLL_BAR_X_WIDGET (bar, widget);
5905 xwindow = XtWindow (widget);
5906 bar->x_window = xwindow;
5907 bar->whole = 1;
5908 bar->horizontal = false;
5909
5910 unblock_input ();
5911 }
5912
5913 static void
5914 x_create_horizontal_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
5915 {
5916 Window xwindow;
5917 Widget widget;
5918 Arg av[20];
5919 int ac = 0;
5920 const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME;
5921 unsigned long pixel;
5922
5923 block_input ();
5924
5925 #ifdef USE_MOTIF
5926 /* Set resources. Create the widget. */
5927 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
5928 XtSetArg (av[ac], XmNminimum, 0); ++ac;
5929 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
5930 XtSetArg (av[ac], XmNorientation, XmHORIZONTAL); ++ac;
5931 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_RIGHT), ++ac;
5932 XtSetArg (av[ac], XmNincrement, 1); ++ac;
5933 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
5934
5935 pixel = f->output_data.x->scroll_bar_foreground_pixel;
5936 if (pixel != -1)
5937 {
5938 XtSetArg (av[ac], XmNforeground, pixel);
5939 ++ac;
5940 }
5941
5942 pixel = f->output_data.x->scroll_bar_background_pixel;
5943 if (pixel != -1)
5944 {
5945 XtSetArg (av[ac], XmNbackground, pixel);
5946 ++ac;
5947 }
5948
5949 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
5950 (char *) scroll_bar_name, av, ac);
5951
5952 /* Add one callback for everything that can happen. */
5953 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
5954 (XtPointer) bar);
5955 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
5956 (XtPointer) bar);
5957 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
5958 (XtPointer) bar);
5959 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
5960 (XtPointer) bar);
5961 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
5962 (XtPointer) bar);
5963 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
5964 (XtPointer) bar);
5965 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
5966 (XtPointer) bar);
5967
5968 /* Realize the widget. Only after that is the X window created. */
5969 XtRealizeWidget (widget);
5970
5971 /* Set the cursor to an arrow. I didn't find a resource to do that.
5972 And I'm wondering why it hasn't an arrow cursor by default. */
5973 XDefineCursor (XtDisplay (widget), XtWindow (widget),
5974 f->output_data.x->nontext_cursor);
5975
5976 #else /* !USE_MOTIF i.e. use Xaw */
5977
5978 /* Set resources. Create the widget. The background of the
5979 Xaw3d scroll bar widget is a little bit light for my taste.
5980 We don't alter it here to let users change it according
5981 to their taste with `emacs*verticalScrollBar.background: xxx'. */
5982 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
5983 XtSetArg (av[ac], XtNorientation, XtorientHorizontal); ++ac;
5984 /* For smoother scrolling with Xaw3d -sm */
5985 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
5986
5987 pixel = f->output_data.x->scroll_bar_foreground_pixel;
5988 if (pixel != -1)
5989 {
5990 XtSetArg (av[ac], XtNforeground, pixel);
5991 ++ac;
5992 }
5993
5994 pixel = f->output_data.x->scroll_bar_background_pixel;
5995 if (pixel != -1)
5996 {
5997 XtSetArg (av[ac], XtNbackground, pixel);
5998 ++ac;
5999 }
6000
6001 /* Top/bottom shadow colors. */
6002
6003 /* Allocate them, if necessary. */
6004 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
6005 {
6006 pixel = f->output_data.x->scroll_bar_background_pixel;
6007 if (pixel != -1)
6008 {
6009 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
6010 FRAME_X_COLORMAP (f),
6011 &pixel, 1.2, 0x8000))
6012 pixel = -1;
6013 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
6014 }
6015 }
6016 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
6017 {
6018 pixel = f->output_data.x->scroll_bar_background_pixel;
6019 if (pixel != -1)
6020 {
6021 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
6022 FRAME_X_COLORMAP (f),
6023 &pixel, 0.6, 0x4000))
6024 pixel = -1;
6025 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
6026 }
6027 }
6028
6029 #ifdef XtNbeNiceToColormap
6030 /* Tell the toolkit about them. */
6031 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
6032 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
6033 /* We tried to allocate a color for the top/bottom shadow, and
6034 failed, so tell Xaw3d to use dithering instead. */
6035 /* But only if we have a small colormap. Xaw3d can allocate nice
6036 colors itself. */
6037 {
6038 XtSetArg (av[ac], XtNbeNiceToColormap,
6039 DefaultDepthOfScreen (FRAME_X_SCREEN (f)) < 16);
6040 ++ac;
6041 }
6042 else
6043 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
6044 be more consistent with other emacs 3d colors, and since Xaw3d is
6045 not good at dealing with allocation failure. */
6046 {
6047 /* This tells Xaw3d to use real colors instead of dithering for
6048 the shadows. */
6049 XtSetArg (av[ac], XtNbeNiceToColormap, False);
6050 ++ac;
6051
6052 /* Specify the colors. */
6053 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
6054 if (pixel != -1)
6055 {
6056 XtSetArg (av[ac], XtNtopShadowPixel, pixel);
6057 ++ac;
6058 }
6059 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
6060 if (pixel != -1)
6061 {
6062 XtSetArg (av[ac], XtNbottomShadowPixel, pixel);
6063 ++ac;
6064 }
6065 }
6066 #endif
6067
6068 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
6069 f->output_data.x->edit_widget, av, ac);
6070
6071 {
6072 char const *initial = "";
6073 char const *val = initial;
6074 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
6075 #ifdef XtNarrowScrollbars
6076 XtNarrowScrollbars, (XtPointer) &xaw3d_arrow_scroll,
6077 #endif
6078 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
6079 if (xaw3d_arrow_scroll || val == initial)
6080 { /* ARROW_SCROLL */
6081 xaw3d_arrow_scroll = True;
6082 /* Isn't that just a personal preference ? --Stef */
6083 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
6084 }
6085 }
6086
6087 /* Define callbacks. */
6088 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
6089 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
6090 (XtPointer) bar);
6091
6092 /* Realize the widget. Only after that is the X window created. */
6093 XtRealizeWidget (widget);
6094
6095 #endif /* !USE_MOTIF */
6096
6097 /* Install an action hook that lets us detect when the user
6098 finishes interacting with a scroll bar. */
6099 if (horizontal_action_hook_id == 0)
6100 horizontal_action_hook_id
6101 = XtAppAddActionHook (Xt_app_con, xt_horizontal_action_hook, 0);
6102
6103 /* Remember X window and widget in the scroll bar vector. */
6104 SET_SCROLL_BAR_X_WIDGET (bar, widget);
6105 xwindow = XtWindow (widget);
6106 bar->x_window = xwindow;
6107 bar->whole = 1;
6108 bar->horizontal = true;
6109
6110 unblock_input ();
6111 }
6112 #endif /* not USE_GTK */
6113
6114
6115 /* Set the thumb size and position of scroll bar BAR. We are currently
6116 displaying PORTION out of a whole WHOLE, and our position POSITION. */
6117
6118 #ifdef USE_GTK
6119 static void
6120 x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, int whole)
6121 {
6122 xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
6123 }
6124
6125 static void
6126 x_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, int whole)
6127 {
6128 xg_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
6129 }
6130
6131 #else /* not USE_GTK */
6132 static void
6133 x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position,
6134 int whole)
6135 {
6136 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6137 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
6138 float top, shown;
6139
6140 block_input ();
6141
6142 #ifdef USE_MOTIF
6143
6144 if (scroll_bar_adjust_thumb_portion_p)
6145 {
6146 /* We use an estimate of 30 chars per line rather than the real
6147 `portion' value. This has the disadvantage that the thumb size
6148 is not very representative, but it makes our life a lot easier.
6149 Otherwise, we have to constantly adjust the thumb size, which
6150 we can't always do quickly enough: while dragging, the size of
6151 the thumb might prevent the user from dragging the thumb all the
6152 way to the end. but Motif and some versions of Xaw3d don't allow
6153 updating the thumb size while dragging. Also, even if we can update
6154 its size, the update will often happen too late.
6155 If you don't believe it, check out revision 1.650 of xterm.c to see
6156 what hoops we were going through and the still poor behavior we got. */
6157 portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
6158 /* When the thumb is at the bottom, position == whole.
6159 So we need to increase `whole' to make space for the thumb. */
6160 whole += portion;
6161 }
6162
6163 if (whole <= 0)
6164 top = 0, shown = 1;
6165 else
6166 {
6167 top = (float) position / whole;
6168 shown = (float) portion / whole;
6169 }
6170
6171 if (bar->dragging == -1)
6172 {
6173 int size, value;
6174
6175 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
6176 is the scroll bar's maximum and MIN is the scroll bar's minimum
6177 value. */
6178 size = clip_to_bounds (1, shown * XM_SB_MAX, XM_SB_MAX);
6179
6180 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
6181 value = top * XM_SB_MAX;
6182 value = min (value, XM_SB_MAX - size);
6183
6184 XmScrollBarSetValues (widget, value, size, 0, 0, False);
6185 }
6186 #else /* !USE_MOTIF i.e. use Xaw */
6187
6188 if (whole == 0)
6189 top = 0, shown = 1;
6190 else
6191 {
6192 top = (float) position / whole;
6193 shown = (float) portion / whole;
6194 }
6195
6196 {
6197 float old_top, old_shown;
6198 Dimension height;
6199 XtVaGetValues (widget,
6200 XtNtopOfThumb, &old_top,
6201 XtNshown, &old_shown,
6202 XtNheight, &height,
6203 NULL);
6204
6205 /* Massage the top+shown values. */
6206 if (bar->dragging == -1 || bar->last_seen_part == scroll_bar_down_arrow)
6207 top = max (0, min (1, top));
6208 else
6209 top = old_top;
6210 #if ! defined (HAVE_XAW3D)
6211 /* With Xaw, 'top' values too closer to 1.0 may
6212 cause the thumb to disappear. Fix that. */
6213 top = min (top, 0.99f);
6214 #endif
6215 /* Keep two pixels available for moving the thumb down. */
6216 shown = max (0, min (1 - top - (2.0f / height), shown));
6217 #if ! defined (HAVE_XAW3D)
6218 /* Likewise with too small 'shown'. */
6219 shown = max (shown, 0.01f);
6220 #endif
6221
6222 /* If the call to XawScrollbarSetThumb below doesn't seem to
6223 work, check that 'NARROWPROTO' is defined in src/config.h.
6224 If this is not so, most likely you need to fix configure. */
6225 if (top != old_top || shown != old_shown)
6226 {
6227 if (bar->dragging == -1)
6228 XawScrollbarSetThumb (widget, top, shown);
6229 else
6230 {
6231 /* Try to make the scrolling a tad smoother. */
6232 if (!xaw3d_pick_top)
6233 shown = min (shown, old_shown);
6234
6235 XawScrollbarSetThumb (widget, top, shown);
6236 }
6237 }
6238 }
6239 #endif /* !USE_MOTIF */
6240
6241 unblock_input ();
6242 }
6243
6244 static void
6245 x_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position,
6246 int whole)
6247 {
6248 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6249 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
6250 float top, shown;
6251
6252 block_input ();
6253
6254 #ifdef USE_MOTIF
6255 bar->whole = whole;
6256 shown = (float) portion / whole;
6257 top = (float) position / (whole - portion);
6258 {
6259 int size = clip_to_bounds (1, shown * XM_SB_MAX, XM_SB_MAX);
6260 int value = clip_to_bounds (0, top * (XM_SB_MAX - size), XM_SB_MAX - size);
6261
6262 XmScrollBarSetValues (widget, value, size, 0, 0, False);
6263 }
6264 #else /* !USE_MOTIF i.e. use Xaw */
6265 bar->whole = whole;
6266 if (whole == 0)
6267 top = 0, shown = 1;
6268 else
6269 {
6270 top = (float) position / whole;
6271 shown = (float) portion / whole;
6272 }
6273
6274 {
6275 float old_top, old_shown;
6276 Dimension height;
6277 XtVaGetValues (widget,
6278 XtNtopOfThumb, &old_top,
6279 XtNshown, &old_shown,
6280 XtNheight, &height,
6281 NULL);
6282
6283 #if false
6284 /* Massage the top+shown values. */
6285 if (bar->dragging == -1 || bar->last_seen_part == scroll_bar_down_arrow)
6286 top = max (0, min (1, top));
6287 else
6288 top = old_top;
6289 #if ! defined (HAVE_XAW3D)
6290 /* With Xaw, 'top' values too closer to 1.0 may
6291 cause the thumb to disappear. Fix that. */
6292 top = min (top, 0.99f);
6293 #endif
6294 /* Keep two pixels available for moving the thumb down. */
6295 shown = max (0, min (1 - top - (2.0f / height), shown));
6296 #if ! defined (HAVE_XAW3D)
6297 /* Likewise with too small 'shown'. */
6298 shown = max (shown, 0.01f);
6299 #endif
6300 #endif
6301
6302 /* If the call to XawScrollbarSetThumb below doesn't seem to
6303 work, check that 'NARROWPROTO' is defined in src/config.h.
6304 If this is not so, most likely you need to fix configure. */
6305 XawScrollbarSetThumb (widget, top, shown);
6306 #if false
6307 if (top != old_top || shown != old_shown)
6308 {
6309 if (bar->dragging == -1)
6310 XawScrollbarSetThumb (widget, top, shown);
6311 else
6312 {
6313 /* Try to make the scrolling a tad smoother. */
6314 if (!xaw3d_pick_top)
6315 shown = min (shown, old_shown);
6316
6317 XawScrollbarSetThumb (widget, top, shown);
6318 }
6319 }
6320 #endif
6321 }
6322 #endif /* !USE_MOTIF */
6323
6324 unblock_input ();
6325 }
6326 #endif /* not USE_GTK */
6327
6328 #endif /* USE_TOOLKIT_SCROLL_BARS */
6329
6330
6331 \f
6332 /************************************************************************
6333 Scroll bars, general
6334 ************************************************************************/
6335
6336 /* Create a scroll bar and return the scroll bar vector for it. W is
6337 the Emacs window on which to create the scroll bar. TOP, LEFT,
6338 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
6339 scroll bar. */
6340
6341 static struct scroll_bar *
6342 x_scroll_bar_create (struct window *w, int top, int left,
6343 int width, int height, bool horizontal)
6344 {
6345 struct frame *f = XFRAME (w->frame);
6346 struct scroll_bar *bar
6347 = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, x_window, PVEC_OTHER);
6348 Lisp_Object barobj;
6349
6350 block_input ();
6351
6352 #ifdef USE_TOOLKIT_SCROLL_BARS
6353 if (horizontal)
6354 x_create_horizontal_toolkit_scroll_bar (f, bar);
6355 else
6356 x_create_toolkit_scroll_bar (f, bar);
6357 #else /* not USE_TOOLKIT_SCROLL_BARS */
6358 {
6359 XSetWindowAttributes a;
6360 unsigned long mask;
6361 Window window;
6362
6363 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
6364 if (a.background_pixel == -1)
6365 a.background_pixel = FRAME_BACKGROUND_PIXEL (f);
6366
6367 a.event_mask = (ButtonPressMask | ButtonReleaseMask
6368 | ButtonMotionMask | PointerMotionHintMask
6369 | ExposureMask);
6370 a.cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
6371
6372 mask = (CWBackPixel | CWEventMask | CWCursor);
6373
6374 /* Clear the area of W that will serve as a scroll bar. This is
6375 for the case that a window has been split horizontally. In
6376 this case, no clear_frame is generated to reduce flickering. */
6377 if (width > 0 && window_box_height (w) > 0)
6378 x_clear_area (f, left, top, width, window_box_height (w));
6379
6380 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6381 /* Position and size of scroll bar. */
6382 left, top, width, height,
6383 /* Border width, depth, class, and visual. */
6384 0,
6385 CopyFromParent,
6386 CopyFromParent,
6387 CopyFromParent,
6388 /* Attributes. */
6389 mask, &a);
6390 bar->x_window = window;
6391 }
6392 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6393
6394 XSETWINDOW (bar->window, w);
6395 bar->top = top;
6396 bar->left = left;
6397 bar->width = width;
6398 bar->height = height;
6399 bar->start = 0;
6400 bar->end = 0;
6401 bar->dragging = -1;
6402 bar->horizontal = horizontal;
6403 #if defined (USE_TOOLKIT_SCROLL_BARS) && defined (USE_LUCID)
6404 bar->last_seen_part = scroll_bar_nowhere;
6405 #endif
6406
6407 /* Add bar to its frame's list of scroll bars. */
6408 bar->next = FRAME_SCROLL_BARS (f);
6409 bar->prev = Qnil;
6410 XSETVECTOR (barobj, bar);
6411 fset_scroll_bars (f, barobj);
6412 if (!NILP (bar->next))
6413 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
6414
6415 /* Map the window/widget. */
6416 #ifdef USE_TOOLKIT_SCROLL_BARS
6417 {
6418 #ifdef USE_GTK
6419 if (horizontal)
6420 xg_update_horizontal_scrollbar_pos (f, bar->x_window, top,
6421 left, width, max (height, 1));
6422 else
6423 xg_update_scrollbar_pos (f, bar->x_window, top,
6424 left, width, max (height, 1));
6425 #else /* not USE_GTK */
6426 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
6427 XtConfigureWidget (scroll_bar, left, top, width, max (height, 1), 0);
6428 XtMapWidget (scroll_bar);
6429 #endif /* not USE_GTK */
6430 }
6431 #else /* not USE_TOOLKIT_SCROLL_BARS */
6432 XMapRaised (FRAME_X_DISPLAY (f), bar->x_window);
6433 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6434
6435 unblock_input ();
6436 return bar;
6437 }
6438
6439
6440 #ifndef USE_TOOLKIT_SCROLL_BARS
6441
6442 /* Draw BAR's handle in the proper position.
6443
6444 If the handle is already drawn from START to END, don't bother
6445 redrawing it, unless REBUILD; in that case, always
6446 redraw it. (REBUILD is handy for drawing the handle after expose
6447 events.)
6448
6449 Normally, we want to constrain the start and end of the handle to
6450 fit inside its rectangle, but if the user is dragging the scroll
6451 bar handle, we want to let them drag it down all the way, so that
6452 the bar's top is as far down as it goes; otherwise, there's no way
6453 to move to the very end of the buffer. */
6454
6455 static void
6456 x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
6457 bool rebuild)
6458 {
6459 bool dragging = bar->dragging != -1;
6460 Window w = bar->x_window;
6461 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6462 GC gc = f->output_data.x->normal_gc;
6463
6464 /* If the display is already accurate, do nothing. */
6465 if (! rebuild
6466 && start == bar->start
6467 && end == bar->end)
6468 return;
6469
6470 block_input ();
6471
6472 {
6473 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, bar->width);
6474 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, bar->height);
6475 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
6476
6477 /* Make sure the values are reasonable, and try to preserve
6478 the distance between start and end. */
6479 {
6480 int length = end - start;
6481
6482 if (start < 0)
6483 start = 0;
6484 else if (start > top_range)
6485 start = top_range;
6486 end = start + length;
6487
6488 if (end < start)
6489 end = start;
6490 else if (end > top_range && ! dragging)
6491 end = top_range;
6492 }
6493
6494 /* Store the adjusted setting in the scroll bar. */
6495 bar->start = start;
6496 bar->end = end;
6497
6498 /* Clip the end position, just for display. */
6499 if (end > top_range)
6500 end = top_range;
6501
6502 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
6503 below top positions, to make sure the handle is always at least
6504 that many pixels tall. */
6505 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
6506
6507 /* Draw the empty space above the handle. Note that we can't clear
6508 zero-height areas; that means "clear to end of window." */
6509 if ((inside_width > 0) && (start > 0))
6510 x_clear_area1 (FRAME_X_DISPLAY (f), w,
6511 VERTICAL_SCROLL_BAR_LEFT_BORDER,
6512 VERTICAL_SCROLL_BAR_TOP_BORDER,
6513 inside_width, start, False);
6514
6515 /* Change to proper foreground color if one is specified. */
6516 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
6517 XSetForeground (FRAME_X_DISPLAY (f), gc,
6518 f->output_data.x->scroll_bar_foreground_pixel);
6519
6520 /* Draw the handle itself. */
6521 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
6522 /* x, y, width, height */
6523 VERTICAL_SCROLL_BAR_LEFT_BORDER,
6524 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
6525 inside_width, end - start);
6526
6527 /* Restore the foreground color of the GC if we changed it above. */
6528 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
6529 XSetForeground (FRAME_X_DISPLAY (f), gc,
6530 FRAME_FOREGROUND_PIXEL (f));
6531
6532 /* Draw the empty space below the handle. Note that we can't
6533 clear zero-height areas; that means "clear to end of window." */
6534 if ((inside_width > 0) && (end < inside_height))
6535 x_clear_area1 (FRAME_X_DISPLAY (f), w,
6536 VERTICAL_SCROLL_BAR_LEFT_BORDER,
6537 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
6538 inside_width, inside_height - end, False);
6539 }
6540
6541 unblock_input ();
6542 }
6543
6544 #endif /* !USE_TOOLKIT_SCROLL_BARS */
6545
6546 /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
6547 nil. */
6548
6549 static void
6550 x_scroll_bar_remove (struct scroll_bar *bar)
6551 {
6552 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6553 block_input ();
6554
6555 #ifdef USE_TOOLKIT_SCROLL_BARS
6556 #ifdef USE_GTK
6557 xg_remove_scroll_bar (f, bar->x_window);
6558 #else /* not USE_GTK */
6559 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
6560 #endif /* not USE_GTK */
6561 #else
6562 XDestroyWindow (FRAME_X_DISPLAY (f), bar->x_window);
6563 #endif
6564
6565 /* Dissociate this scroll bar from its window. */
6566 if (bar->horizontal)
6567 wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
6568 else
6569 wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
6570
6571 unblock_input ();
6572 }
6573
6574
6575 /* Set the handle of the vertical scroll bar for WINDOW to indicate
6576 that we are displaying PORTION characters out of a total of WHOLE
6577 characters, starting at POSITION. If WINDOW has no scroll bar,
6578 create one. */
6579
6580 static void
6581 XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int position)
6582 {
6583 struct frame *f = XFRAME (w->frame);
6584 Lisp_Object barobj;
6585 struct scroll_bar *bar;
6586 int top, height, left, width;
6587 int window_y, window_height;
6588
6589 /* Get window dimensions. */
6590 window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
6591 top = window_y;
6592 height = window_height;
6593 left = WINDOW_SCROLL_BAR_AREA_X (w);
6594 width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
6595
6596 /* Does the scroll bar exist yet? */
6597 if (NILP (w->vertical_scroll_bar))
6598 {
6599 if (width > 0 && height > 0)
6600 {
6601 block_input ();
6602 x_clear_area (f, left, top, width, height);
6603 unblock_input ();
6604 }
6605
6606 bar = x_scroll_bar_create (w, top, left, width, max (height, 1), false);
6607 }
6608 else
6609 {
6610 /* It may just need to be moved and resized. */
6611 unsigned int mask = 0;
6612
6613 bar = XSCROLL_BAR (w->vertical_scroll_bar);
6614
6615 block_input ();
6616
6617 if (left != bar->left)
6618 mask |= CWX;
6619 if (top != bar->top)
6620 mask |= CWY;
6621 if (width != bar->width)
6622 mask |= CWWidth;
6623 if (height != bar->height)
6624 mask |= CWHeight;
6625
6626 #ifdef USE_TOOLKIT_SCROLL_BARS
6627
6628 /* Move/size the scroll bar widget. */
6629 if (mask)
6630 {
6631 /* Since toolkit scroll bars are smaller than the space reserved
6632 for them on the frame, we have to clear "under" them. */
6633 if (width > 0 && height > 0)
6634 x_clear_area (f, left, top, width, height);
6635 #ifdef USE_GTK
6636 xg_update_scrollbar_pos (f, bar->x_window, top,
6637 left, width, max (height, 1));
6638 #else /* not USE_GTK */
6639 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
6640 left, top, width, max (height, 1), 0);
6641 #endif /* not USE_GTK */
6642 }
6643 #else /* not USE_TOOLKIT_SCROLL_BARS */
6644
6645 /* Move/size the scroll bar window. */
6646 if (mask)
6647 {
6648 XWindowChanges wc;
6649
6650 wc.x = left;
6651 wc.y = top;
6652 wc.width = width;
6653 wc.height = height;
6654 XConfigureWindow (FRAME_X_DISPLAY (f), bar->x_window,
6655 mask, &wc);
6656 }
6657
6658 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6659
6660 /* Remember new settings. */
6661 bar->left = left;
6662 bar->top = top;
6663 bar->width = width;
6664 bar->height = height;
6665
6666 unblock_input ();
6667 }
6668
6669 #ifdef USE_TOOLKIT_SCROLL_BARS
6670 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
6671 #else /* not USE_TOOLKIT_SCROLL_BARS */
6672 /* Set the scroll bar's current state, unless we're currently being
6673 dragged. */
6674 if (bar->dragging == -1)
6675 {
6676 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
6677
6678 if (whole == 0)
6679 x_scroll_bar_set_handle (bar, 0, top_range, false);
6680 else
6681 {
6682 int start = ((double) position * top_range) / whole;
6683 int end = ((double) (position + portion) * top_range) / whole;
6684 x_scroll_bar_set_handle (bar, start, end, false);
6685 }
6686 }
6687 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6688
6689 XSETVECTOR (barobj, bar);
6690 wset_vertical_scroll_bar (w, barobj);
6691 }
6692
6693
6694 static void
6695 XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int position)
6696 {
6697 struct frame *f = XFRAME (w->frame);
6698 Lisp_Object barobj;
6699 struct scroll_bar *bar;
6700 int top, height, left, width;
6701 int window_x, window_width;
6702 int pixel_width = WINDOW_PIXEL_WIDTH (w);
6703
6704 /* Get window dimensions. */
6705 window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
6706 left = window_x;
6707 width = window_width;
6708 top = WINDOW_SCROLL_BAR_AREA_Y (w);
6709 height = WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
6710
6711 /* Does the scroll bar exist yet? */
6712 if (NILP (w->horizontal_scroll_bar))
6713 {
6714 if (width > 0 && height > 0)
6715 {
6716 block_input ();
6717
6718 /* Clear also part between window_width and
6719 WINDOW_PIXEL_WIDTH. */
6720 x_clear_area (f, left, top, pixel_width, height);
6721 unblock_input ();
6722 }
6723
6724 bar = x_scroll_bar_create (w, top, left, width, height, true);
6725 }
6726 else
6727 {
6728 /* It may just need to be moved and resized. */
6729 unsigned int mask = 0;
6730
6731 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
6732
6733 block_input ();
6734
6735 if (left != bar->left)
6736 mask |= CWX;
6737 if (top != bar->top)
6738 mask |= CWY;
6739 if (width != bar->width)
6740 mask |= CWWidth;
6741 if (height != bar->height)
6742 mask |= CWHeight;
6743
6744 #ifdef USE_TOOLKIT_SCROLL_BARS
6745 /* Move/size the scroll bar widget. */
6746 if (mask)
6747 {
6748 /* Since toolkit scroll bars are smaller than the space reserved
6749 for them on the frame, we have to clear "under" them. */
6750 if (width > 0 && height > 0)
6751 x_clear_area (f,
6752 WINDOW_LEFT_EDGE_X (w), top,
6753 pixel_width - WINDOW_RIGHT_DIVIDER_WIDTH (w), height);
6754 #ifdef USE_GTK
6755 xg_update_horizontal_scrollbar_pos (f, bar->x_window, top, left,
6756 width, height);
6757 #else /* not USE_GTK */
6758 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
6759 left, top, width, height, 0);
6760 #endif /* not USE_GTK */
6761 }
6762 #else /* not USE_TOOLKIT_SCROLL_BARS */
6763
6764 /* Clear areas not covered by the scroll bar because it's not as
6765 wide as the area reserved for it. This makes sure a
6766 previous mode line display is cleared after C-x 2 C-x 1, for
6767 example. */
6768 {
6769 int area_height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
6770 int rest = area_height - height;
6771 if (rest > 0 && width > 0)
6772 x_clear_area (f, left, top, width, rest);
6773 }
6774
6775 /* Move/size the scroll bar window. */
6776 if (mask)
6777 {
6778 XWindowChanges wc;
6779
6780 wc.x = left;
6781 wc.y = top;
6782 wc.width = width;
6783 wc.height = height;
6784 XConfigureWindow (FRAME_X_DISPLAY (f), bar->x_window,
6785 mask, &wc);
6786 }
6787
6788 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6789
6790 /* Remember new settings. */
6791 bar->left = left;
6792 bar->top = top;
6793 bar->width = width;
6794 bar->height = height;
6795
6796 unblock_input ();
6797 }
6798
6799 #ifdef USE_TOOLKIT_SCROLL_BARS
6800 x_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
6801 #else /* not USE_TOOLKIT_SCROLL_BARS */
6802 /* Set the scroll bar's current state, unless we're currently being
6803 dragged. */
6804 if (bar->dragging == -1)
6805 {
6806 int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, width);
6807
6808 if (whole == 0)
6809 x_scroll_bar_set_handle (bar, 0, left_range, false);
6810 else
6811 {
6812 int start = ((double) position * left_range) / whole;
6813 int end = ((double) (position + portion) * left_range) / whole;
6814 x_scroll_bar_set_handle (bar, start, end, false);
6815 }
6816 }
6817 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6818
6819 XSETVECTOR (barobj, bar);
6820 wset_horizontal_scroll_bar (w, barobj);
6821 }
6822
6823
6824 /* The following three hooks are used when we're doing a thorough
6825 redisplay of the frame. We don't explicitly know which scroll bars
6826 are going to be deleted, because keeping track of when windows go
6827 away is a real pain - "Can you say set-window-configuration, boys
6828 and girls?" Instead, we just assert at the beginning of redisplay
6829 that *all* scroll bars are to be removed, and then save a scroll bar
6830 from the fiery pit when we actually redisplay its window. */
6831
6832 /* Arrange for all scroll bars on FRAME to be removed at the next call
6833 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
6834 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
6835
6836 static void
6837 XTcondemn_scroll_bars (struct frame *frame)
6838 {
6839 if (!NILP (FRAME_SCROLL_BARS (frame)))
6840 {
6841 if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
6842 {
6843 /* Prepend scrollbars to already condemned ones. */
6844 Lisp_Object last = FRAME_SCROLL_BARS (frame);
6845
6846 while (!NILP (XSCROLL_BAR (last)->next))
6847 last = XSCROLL_BAR (last)->next;
6848
6849 XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
6850 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last;
6851 }
6852
6853 fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame));
6854 fset_scroll_bars (frame, Qnil);
6855 }
6856 }
6857
6858
6859 /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
6860 Note that WINDOW isn't necessarily condemned at all. */
6861
6862 static void
6863 XTredeem_scroll_bar (struct window *w)
6864 {
6865 struct scroll_bar *bar;
6866 Lisp_Object barobj;
6867 struct frame *f;
6868
6869 /* We can't redeem this window's scroll bar if it doesn't have one. */
6870 if (NILP (w->vertical_scroll_bar) && NILP (w->horizontal_scroll_bar))
6871 emacs_abort ();
6872
6873 if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
6874 {
6875 bar = XSCROLL_BAR (w->vertical_scroll_bar);
6876 /* Unlink it from the condemned list. */
6877 f = XFRAME (WINDOW_FRAME (w));
6878 if (NILP (bar->prev))
6879 {
6880 /* If the prev pointer is nil, it must be the first in one of
6881 the lists. */
6882 if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar))
6883 /* It's not condemned. Everything's fine. */
6884 goto horizontal;
6885 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
6886 w->vertical_scroll_bar))
6887 fset_condemned_scroll_bars (f, bar->next);
6888 else
6889 /* If its prev pointer is nil, it must be at the front of
6890 one or the other! */
6891 emacs_abort ();
6892 }
6893 else
6894 XSCROLL_BAR (bar->prev)->next = bar->next;
6895
6896 if (! NILP (bar->next))
6897 XSCROLL_BAR (bar->next)->prev = bar->prev;
6898
6899 bar->next = FRAME_SCROLL_BARS (f);
6900 bar->prev = Qnil;
6901 XSETVECTOR (barobj, bar);
6902 fset_scroll_bars (f, barobj);
6903 if (! NILP (bar->next))
6904 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
6905 }
6906
6907 horizontal:
6908 if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w))
6909 {
6910 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
6911 /* Unlink it from the condemned list. */
6912 f = XFRAME (WINDOW_FRAME (w));
6913 if (NILP (bar->prev))
6914 {
6915 /* If the prev pointer is nil, it must be the first in one of
6916 the lists. */
6917 if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar))
6918 /* It's not condemned. Everything's fine. */
6919 return;
6920 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
6921 w->horizontal_scroll_bar))
6922 fset_condemned_scroll_bars (f, bar->next);
6923 else
6924 /* If its prev pointer is nil, it must be at the front of
6925 one or the other! */
6926 emacs_abort ();
6927 }
6928 else
6929 XSCROLL_BAR (bar->prev)->next = bar->next;
6930
6931 if (! NILP (bar->next))
6932 XSCROLL_BAR (bar->next)->prev = bar->prev;
6933
6934 bar->next = FRAME_SCROLL_BARS (f);
6935 bar->prev = Qnil;
6936 XSETVECTOR (barobj, bar);
6937 fset_scroll_bars (f, barobj);
6938 if (! NILP (bar->next))
6939 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
6940 }
6941 }
6942
6943 /* Remove all scroll bars on FRAME that haven't been saved since the
6944 last call to `*condemn_scroll_bars_hook'. */
6945
6946 static void
6947 XTjudge_scroll_bars (struct frame *f)
6948 {
6949 Lisp_Object bar, next;
6950
6951 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
6952
6953 /* Clear out the condemned list now so we won't try to process any
6954 more events on the hapless scroll bars. */
6955 fset_condemned_scroll_bars (f, Qnil);
6956
6957 for (; ! NILP (bar); bar = next)
6958 {
6959 struct scroll_bar *b = XSCROLL_BAR (bar);
6960
6961 x_scroll_bar_remove (b);
6962
6963 next = b->next;
6964 b->next = b->prev = Qnil;
6965 }
6966
6967 /* Now there should be no references to the condemned scroll bars,
6968 and they should get garbage-collected. */
6969 }
6970
6971
6972 #ifndef USE_TOOLKIT_SCROLL_BARS
6973 /* Handle an Expose or GraphicsExpose event on a scroll bar. This
6974 is a no-op when using toolkit scroll bars.
6975
6976 This may be called from a signal handler, so we have to ignore GC
6977 mark bits. */
6978
6979 static void
6980 x_scroll_bar_expose (struct scroll_bar *bar, const XEvent *event)
6981 {
6982 Window w = bar->x_window;
6983 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6984 GC gc = f->output_data.x->normal_gc;
6985
6986 block_input ();
6987
6988 x_scroll_bar_set_handle (bar, bar->start, bar->end, true);
6989
6990 /* Switch to scroll bar foreground color. */
6991 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
6992 XSetForeground (FRAME_X_DISPLAY (f), gc,
6993 f->output_data.x->scroll_bar_foreground_pixel);
6994
6995 /* Draw a one-pixel border just inside the edges of the scroll bar. */
6996 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
6997 /* x, y, width, height */
6998 0, 0, bar->width - 1, bar->height - 1);
6999
7000 /* Restore the foreground color of the GC if we changed it above. */
7001 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
7002 XSetForeground (FRAME_X_DISPLAY (f), gc,
7003 FRAME_FOREGROUND_PIXEL (f));
7004
7005 unblock_input ();
7006
7007 }
7008 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7009
7010 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
7011 is set to something other than NO_EVENT, it is enqueued.
7012
7013 This may be called from a signal handler, so we have to ignore GC
7014 mark bits. */
7015
7016
7017 static void
7018 x_scroll_bar_handle_click (struct scroll_bar *bar,
7019 const XEvent *event,
7020 struct input_event *emacs_event)
7021 {
7022 if (! WINDOWP (bar->window))
7023 emacs_abort ();
7024
7025 emacs_event->kind = (bar->horizontal
7026 ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT
7027 : SCROLL_BAR_CLICK_EVENT);
7028 emacs_event->code = event->xbutton.button - Button1;
7029 emacs_event->modifiers
7030 = (x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO
7031 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
7032 event->xbutton.state)
7033 | (event->type == ButtonRelease
7034 ? up_modifier
7035 : down_modifier));
7036 emacs_event->frame_or_window = bar->window;
7037 emacs_event->arg = Qnil;
7038 emacs_event->timestamp = event->xbutton.time;
7039 if (bar->horizontal)
7040 {
7041 int left_range
7042 = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
7043 int x = event->xbutton.x - HORIZONTAL_SCROLL_BAR_LEFT_BORDER;
7044
7045 if (x < 0) x = 0;
7046 if (x > left_range) x = left_range;
7047
7048 if (x < bar->start)
7049 emacs_event->part = scroll_bar_before_handle;
7050 else if (x < bar->end + HORIZONTAL_SCROLL_BAR_MIN_HANDLE)
7051 emacs_event->part = scroll_bar_horizontal_handle;
7052 else
7053 emacs_event->part = scroll_bar_after_handle;
7054
7055 #ifndef USE_TOOLKIT_SCROLL_BARS
7056 /* If the user has released the handle, set it to its final position. */
7057 if (event->type == ButtonRelease && bar->dragging != -1)
7058 {
7059 int new_start = - bar->dragging;
7060 int new_end = new_start + bar->end - bar->start;
7061
7062 x_scroll_bar_set_handle (bar, new_start, new_end, false);
7063 bar->dragging = -1;
7064 }
7065 #endif
7066
7067 XSETINT (emacs_event->x, left_range);
7068 XSETINT (emacs_event->y, x);
7069 }
7070 else
7071 {
7072 int top_range
7073 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
7074 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
7075
7076 if (y < 0) y = 0;
7077 if (y > top_range) y = top_range;
7078
7079 if (y < bar->start)
7080 emacs_event->part = scroll_bar_above_handle;
7081 else if (y < bar->end + VERTICAL_SCROLL_BAR_MIN_HANDLE)
7082 emacs_event->part = scroll_bar_handle;
7083 else
7084 emacs_event->part = scroll_bar_below_handle;
7085
7086 #ifndef USE_TOOLKIT_SCROLL_BARS
7087 /* If the user has released the handle, set it to its final position. */
7088 if (event->type == ButtonRelease && bar->dragging != -1)
7089 {
7090 int new_start = y - bar->dragging;
7091 int new_end = new_start + bar->end - bar->start;
7092
7093 x_scroll_bar_set_handle (bar, new_start, new_end, false);
7094 bar->dragging = -1;
7095 }
7096 #endif
7097
7098 XSETINT (emacs_event->x, y);
7099 XSETINT (emacs_event->y, top_range);
7100 }
7101 }
7102
7103 #ifndef USE_TOOLKIT_SCROLL_BARS
7104
7105 /* Handle some mouse motion while someone is dragging the scroll bar.
7106
7107 This may be called from a signal handler, so we have to ignore GC
7108 mark bits. */
7109
7110 static void
7111 x_scroll_bar_note_movement (struct scroll_bar *bar,
7112 const XMotionEvent *event)
7113 {
7114 struct frame *f = XFRAME (XWINDOW (bar->window)->frame);
7115 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
7116
7117 dpyinfo->last_mouse_movement_time = event->time;
7118 dpyinfo->last_mouse_scroll_bar = bar;
7119 f->mouse_moved = true;
7120
7121 /* If we're dragging the bar, display it. */
7122 if (bar->dragging != -1)
7123 {
7124 /* Where should the handle be now? */
7125 int new_start = event->y - bar->dragging;
7126
7127 if (new_start != bar->start)
7128 {
7129 int new_end = new_start + bar->end - bar->start;
7130
7131 x_scroll_bar_set_handle (bar, new_start, new_end, false);
7132 }
7133 }
7134 }
7135
7136 #endif /* !USE_TOOLKIT_SCROLL_BARS */
7137
7138 /* Return information to the user about the current position of the mouse
7139 on the scroll bar. */
7140
7141 static void
7142 x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
7143 enum scroll_bar_part *part, Lisp_Object *x,
7144 Lisp_Object *y, Time *timestamp)
7145 {
7146 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
7147 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
7148 Window w = bar->x_window;
7149 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7150 int win_x, win_y;
7151 Window dummy_window;
7152 int dummy_coord;
7153 unsigned int dummy_mask;
7154
7155 block_input ();
7156
7157 /* Get the mouse's position relative to the scroll bar window, and
7158 report that. */
7159 if (XQueryPointer (FRAME_X_DISPLAY (f), w,
7160
7161 /* Root, child, root x and root y. */
7162 &dummy_window, &dummy_window,
7163 &dummy_coord, &dummy_coord,
7164
7165 /* Position relative to scroll bar. */
7166 &win_x, &win_y,
7167
7168 /* Mouse buttons and modifier keys. */
7169 &dummy_mask))
7170 {
7171 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
7172
7173 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
7174
7175 if (bar->dragging != -1)
7176 win_y -= bar->dragging;
7177
7178 if (win_y < 0)
7179 win_y = 0;
7180 if (win_y > top_range)
7181 win_y = top_range;
7182
7183 *fp = f;
7184 *bar_window = bar->window;
7185
7186 if (bar->dragging != -1)
7187 *part = scroll_bar_handle;
7188 else if (win_y < bar->start)
7189 *part = scroll_bar_above_handle;
7190 else if (win_y < bar->end + VERTICAL_SCROLL_BAR_MIN_HANDLE)
7191 *part = scroll_bar_handle;
7192 else
7193 *part = scroll_bar_below_handle;
7194
7195 XSETINT (*x, win_y);
7196 XSETINT (*y, top_range);
7197
7198 f->mouse_moved = false;
7199 dpyinfo->last_mouse_scroll_bar = NULL;
7200 *timestamp = dpyinfo->last_mouse_movement_time;
7201 }
7202
7203 unblock_input ();
7204 }
7205
7206
7207 /* Return information to the user about the current position of the mouse
7208 on the scroll bar. */
7209
7210 static void
7211 x_horizontal_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
7212 enum scroll_bar_part *part, Lisp_Object *x,
7213 Lisp_Object *y, Time *timestamp)
7214 {
7215 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
7216 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
7217 Window w = bar->x_window;
7218 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7219 int win_x, win_y;
7220 Window dummy_window;
7221 int dummy_coord;
7222 unsigned int dummy_mask;
7223
7224 block_input ();
7225
7226 /* Get the mouse's position relative to the scroll bar window, and
7227 report that. */
7228 if (XQueryPointer (FRAME_X_DISPLAY (f), w,
7229
7230 /* Root, child, root x and root y. */
7231 &dummy_window, &dummy_window,
7232 &dummy_coord, &dummy_coord,
7233
7234 /* Position relative to scroll bar. */
7235 &win_x, &win_y,
7236
7237 /* Mouse buttons and modifier keys. */
7238 &dummy_mask))
7239 {
7240 int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
7241
7242 win_x -= HORIZONTAL_SCROLL_BAR_LEFT_BORDER;
7243
7244 if (bar->dragging != -1)
7245 win_x -= bar->dragging;
7246
7247 if (win_x < 0)
7248 win_x = 0;
7249 if (win_x > left_range)
7250 win_x = left_range;
7251
7252 *fp = f;
7253 *bar_window = bar->window;
7254
7255 if (bar->dragging != -1)
7256 *part = scroll_bar_horizontal_handle;
7257 else if (win_x < bar->start)
7258 *part = scroll_bar_before_handle;
7259 else if (win_x < bar->end + HORIZONTAL_SCROLL_BAR_MIN_HANDLE)
7260 *part = scroll_bar_handle;
7261 else
7262 *part = scroll_bar_after_handle;
7263
7264 XSETINT (*y, win_x);
7265 XSETINT (*x, left_range);
7266
7267 f->mouse_moved = false;
7268 dpyinfo->last_mouse_scroll_bar = NULL;
7269 *timestamp = dpyinfo->last_mouse_movement_time;
7270 }
7271
7272 unblock_input ();
7273 }
7274
7275
7276 /* The screen has been cleared so we may have changed foreground or
7277 background colors, and the scroll bars may need to be redrawn.
7278 Clear out the scroll bars, and ask for expose events, so we can
7279 redraw them. */
7280
7281 static void
7282 x_scroll_bar_clear (struct frame *f)
7283 {
7284 #ifndef USE_TOOLKIT_SCROLL_BARS
7285 Lisp_Object bar;
7286
7287 /* We can have scroll bars even if this is 0,
7288 if we just turned off scroll bar mode.
7289 But in that case we should not clear them. */
7290 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
7291 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
7292 bar = XSCROLL_BAR (bar)->next)
7293 XClearArea (FRAME_X_DISPLAY (f),
7294 XSCROLL_BAR (bar)->x_window,
7295 0, 0, 0, 0, True);
7296 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7297 }
7298
7299 #ifdef ENABLE_CHECKING
7300
7301 /* Record the last 100 characters stored
7302 to help debug the loss-of-chars-during-GC problem. */
7303
7304 static int temp_index;
7305 static short temp_buffer[100];
7306
7307 #define STORE_KEYSYM_FOR_DEBUG(keysym) \
7308 if (temp_index == ARRAYELTS (temp_buffer)) \
7309 temp_index = 0; \
7310 temp_buffer[temp_index++] = (keysym)
7311
7312 #else /* not ENABLE_CHECKING */
7313
7314 #define STORE_KEYSYM_FOR_DEBUG(keysym) ((void)0)
7315
7316 #endif /* ENABLE_CHECKING */
7317
7318 /* Set this to nonzero to fake an "X I/O error"
7319 on a particular display. */
7320
7321 static struct x_display_info *XTread_socket_fake_io_error;
7322
7323 /* When we find no input here, we occasionally do a no-op command
7324 to verify that the X server is still running and we can still talk with it.
7325 We try all the open displays, one by one.
7326 This variable is used for cycling thru the displays. */
7327
7328 static struct x_display_info *next_noop_dpyinfo;
7329
7330 enum
7331 {
7332 X_EVENT_NORMAL,
7333 X_EVENT_GOTO_OUT,
7334 X_EVENT_DROP
7335 };
7336
7337 /* Filter events for the current X input method.
7338 DPYINFO is the display this event is for.
7339 EVENT is the X event to filter.
7340
7341 Returns non-zero if the event was filtered, caller shall not process
7342 this event further.
7343 Returns zero if event is wasn't filtered. */
7344
7345 #ifdef HAVE_X_I18N
7346 static int
7347 x_filter_event (struct x_display_info *dpyinfo, XEvent *event)
7348 {
7349 /* XFilterEvent returns non-zero if the input method has
7350 consumed the event. We pass the frame's X window to
7351 XFilterEvent because that's the one for which the IC
7352 was created. */
7353
7354 struct frame *f1 = x_any_window_to_frame (dpyinfo,
7355 event->xclient.window);
7356
7357 return XFilterEvent (event, f1 ? FRAME_X_WINDOW (f1) : None);
7358 }
7359 #endif
7360
7361 #ifdef USE_GTK
7362 static int current_count;
7363 static int current_finish;
7364 static struct input_event *current_hold_quit;
7365
7366 /* This is the filter function invoked by the GTK event loop.
7367 It is invoked before the XEvent is translated to a GdkEvent,
7368 so we have a chance to act on the event before GTK. */
7369 static GdkFilterReturn
7370 event_handler_gdk (GdkXEvent *gxev, GdkEvent *ev, gpointer data)
7371 {
7372 XEvent *xev = (XEvent *) gxev;
7373
7374 block_input ();
7375 if (current_count >= 0)
7376 {
7377 struct x_display_info *dpyinfo;
7378
7379 dpyinfo = x_display_info_for_display (xev->xany.display);
7380
7381 #ifdef HAVE_X_I18N
7382 /* Filter events for the current X input method.
7383 GTK calls XFilterEvent but not for key press and release,
7384 so we do it here. */
7385 if ((xev->type == KeyPress || xev->type == KeyRelease)
7386 && dpyinfo
7387 && x_filter_event (dpyinfo, xev))
7388 {
7389 unblock_input ();
7390 return GDK_FILTER_REMOVE;
7391 }
7392 #endif
7393
7394 if (! dpyinfo)
7395 current_finish = X_EVENT_NORMAL;
7396 else
7397 current_count
7398 += handle_one_xevent (dpyinfo, xev, &current_finish,
7399 current_hold_quit);
7400 }
7401 else
7402 current_finish = x_dispatch_event (xev, xev->xany.display);
7403
7404 unblock_input ();
7405
7406 if (current_finish == X_EVENT_GOTO_OUT || current_finish == X_EVENT_DROP)
7407 return GDK_FILTER_REMOVE;
7408
7409 return GDK_FILTER_CONTINUE;
7410 }
7411 #endif /* USE_GTK */
7412
7413
7414 static void xembed_send_message (struct frame *f, Time,
7415 enum xembed_message,
7416 long detail, long data1, long data2);
7417
7418 static void
7419 x_net_wm_state (struct frame *f, Window window)
7420 {
7421 int value = FULLSCREEN_NONE;
7422 Lisp_Object lval = Qnil;
7423 bool sticky = false;
7424
7425 get_current_wm_state (f, window, &value, &sticky);
7426
7427 switch (value)
7428 {
7429 case FULLSCREEN_WIDTH:
7430 lval = Qfullwidth;
7431 break;
7432 case FULLSCREEN_HEIGHT:
7433 lval = Qfullheight;
7434 break;
7435 case FULLSCREEN_BOTH:
7436 lval = Qfullboth;
7437 break;
7438 case FULLSCREEN_MAXIMIZED:
7439 lval = Qmaximized;
7440 break;
7441 }
7442
7443 frame_size_history_add
7444 (f, Qx_net_wm_state, 0, 0,
7445 list2 (get_frame_param (f, Qfullscreen), lval));
7446
7447 store_frame_param (f, Qfullscreen, lval);
7448 /** store_frame_param (f, Qsticky, sticky ? Qt : Qnil); **/
7449 }
7450
7451 /* Handles the XEvent EVENT on display DPYINFO.
7452
7453 *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
7454 *FINISH is zero if caller should continue reading events.
7455 *FINISH is X_EVENT_DROP if event should not be passed to the toolkit.
7456 *EVENT is unchanged unless we're processing KeyPress event.
7457
7458 We return the number of characters stored into the buffer. */
7459
7460 static int
7461 handle_one_xevent (struct x_display_info *dpyinfo,
7462 const XEvent *event,
7463 int *finish, struct input_event *hold_quit)
7464 {
7465 union buffered_input_event inev;
7466 int count = 0;
7467 int do_help = 0;
7468 ptrdiff_t nbytes = 0;
7469 struct frame *any, *f = NULL;
7470 struct coding_system coding;
7471 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
7472 /* This holds the state XLookupString needs to implement dead keys
7473 and other tricks known as "compose processing". _X Window System_
7474 says that a portable program can't use this, but Stephen Gildea assures
7475 me that letting the compiler initialize it to zeros will work okay. */
7476 static XComposeStatus compose_status;
7477 XEvent configureEvent;
7478 XEvent next_event;
7479
7480 USE_SAFE_ALLOCA;
7481
7482 *finish = X_EVENT_NORMAL;
7483
7484 EVENT_INIT (inev.ie);
7485 inev.ie.kind = NO_EVENT;
7486 inev.ie.arg = Qnil;
7487
7488 any = x_any_window_to_frame (dpyinfo, event->xany.window);
7489
7490 if (any && any->wait_event_type == event->type)
7491 any->wait_event_type = 0; /* Indicates we got it. */
7492
7493 switch (event->type)
7494 {
7495 case ClientMessage:
7496 {
7497 if (event->xclient.message_type == dpyinfo->Xatom_wm_protocols
7498 && event->xclient.format == 32)
7499 {
7500 if (event->xclient.data.l[0] == dpyinfo->Xatom_wm_take_focus)
7501 {
7502 /* Use the value returned by x_any_window_to_frame
7503 because this could be the shell widget window
7504 if the frame has no title bar. */
7505 f = any;
7506 #ifdef HAVE_X_I18N
7507 /* Not quite sure this is needed -pd */
7508 if (f && FRAME_XIC (f))
7509 XSetICFocus (FRAME_XIC (f));
7510 #endif
7511 #if false
7512 /* Emacs sets WM hints whose `input' field is `true'. This
7513 instructs the WM to set the input focus automatically for
7514 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
7515 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
7516 it has set the focus. So, XSetInputFocus below is not
7517 needed.
7518
7519 The call to XSetInputFocus below has also caused trouble. In
7520 cases where the XSetInputFocus done by the WM and the one
7521 below are temporally close (on a fast machine), the call
7522 below can generate additional FocusIn events which confuse
7523 Emacs. */
7524
7525 /* Since we set WM_TAKE_FOCUS, we must call
7526 XSetInputFocus explicitly. But not if f is null,
7527 since that might be an event for a deleted frame. */
7528 if (f)
7529 {
7530 Display *d = event->xclient.display;
7531 /* Catch and ignore errors, in case window has been
7532 iconified by a window manager such as GWM. */
7533 x_catch_errors (d);
7534 XSetInputFocus (d, event->xclient.window,
7535 /* The ICCCM says this is
7536 the only valid choice. */
7537 RevertToParent,
7538 event->xclient.data.l[1]);
7539 x_uncatch_errors ();
7540 }
7541 /* Not certain about handling scroll bars here */
7542 #endif
7543 goto done;
7544 }
7545
7546 if (event->xclient.data.l[0] == dpyinfo->Xatom_wm_save_yourself)
7547 {
7548 /* Save state modify the WM_COMMAND property to
7549 something which can reinstate us. This notifies
7550 the session manager, who's looking for such a
7551 PropertyNotify. Can restart processing when
7552 a keyboard or mouse event arrives. */
7553 /* If we have a session manager, don't set this.
7554 KDE will then start two Emacsen, one for the
7555 session manager and one for this. */
7556 #ifdef HAVE_X_SM
7557 if (! x_session_have_connection ())
7558 #endif
7559 {
7560 f = x_top_window_to_frame (dpyinfo,
7561 event->xclient.window);
7562 /* This is just so we only give real data once
7563 for a single Emacs process. */
7564 if (f == SELECTED_FRAME ())
7565 XSetCommand (FRAME_X_DISPLAY (f),
7566 event->xclient.window,
7567 initial_argv, initial_argc);
7568 else if (f)
7569 XSetCommand (FRAME_X_DISPLAY (f),
7570 event->xclient.window,
7571 0, 0);
7572 }
7573 goto done;
7574 }
7575
7576 if (event->xclient.data.l[0] == dpyinfo->Xatom_wm_delete_window)
7577 {
7578 f = any;
7579 if (!f)
7580 goto OTHER; /* May be a dialog that is to be removed */
7581
7582 inev.ie.kind = DELETE_WINDOW_EVENT;
7583 XSETFRAME (inev.ie.frame_or_window, f);
7584 goto done;
7585 }
7586
7587 goto done;
7588 }
7589
7590 if (event->xclient.message_type == dpyinfo->Xatom_wm_configure_denied)
7591 goto done;
7592
7593 if (event->xclient.message_type == dpyinfo->Xatom_wm_window_moved)
7594 {
7595 int new_x, new_y;
7596 f = x_window_to_frame (dpyinfo, event->xclient.window);
7597
7598 new_x = event->xclient.data.s[0];
7599 new_y = event->xclient.data.s[1];
7600
7601 if (f)
7602 {
7603 f->left_pos = new_x;
7604 f->top_pos = new_y;
7605 }
7606 goto done;
7607 }
7608
7609 #ifdef X_TOOLKIT_EDITRES
7610 if (event->xclient.message_type == dpyinfo->Xatom_editres)
7611 {
7612 f = any;
7613 if (f)
7614 _XEditResCheckMessages (f->output_data.x->widget,
7615 NULL, (XEvent *) event, NULL);
7616 goto done;
7617 }
7618 #endif /* X_TOOLKIT_EDITRES */
7619
7620 if (event->xclient.message_type == dpyinfo->Xatom_DONE
7621 || event->xclient.message_type == dpyinfo->Xatom_PAGE)
7622 {
7623 /* Ghostview job completed. Kill it. We could
7624 reply with "Next" if we received "Page", but we
7625 currently never do because we are interested in
7626 images, only, which should have 1 page. */
7627 Pixmap pixmap = (Pixmap) event->xclient.data.l[1];
7628 f = x_window_to_frame (dpyinfo, event->xclient.window);
7629 if (!f)
7630 goto OTHER;
7631 x_kill_gs_process (pixmap, f);
7632 expose_frame (f, 0, 0, 0, 0);
7633 goto done;
7634 }
7635
7636 #ifdef USE_TOOLKIT_SCROLL_BARS
7637 /* Scroll bar callbacks send a ClientMessage from which
7638 we construct an input_event. */
7639 if (event->xclient.message_type == dpyinfo->Xatom_Scrollbar)
7640 {
7641 x_scroll_bar_to_input_event (event, &inev.ie);
7642 *finish = X_EVENT_GOTO_OUT;
7643 goto done;
7644 }
7645 else if (event->xclient.message_type == dpyinfo->Xatom_Horizontal_Scrollbar)
7646 {
7647 x_horizontal_scroll_bar_to_input_event (event, &inev.ie);
7648 *finish = X_EVENT_GOTO_OUT;
7649 goto done;
7650 }
7651 #endif /* USE_TOOLKIT_SCROLL_BARS */
7652
7653 /* XEmbed messages from the embedder (if any). */
7654 if (event->xclient.message_type == dpyinfo->Xatom_XEMBED)
7655 {
7656 enum xembed_message msg = event->xclient.data.l[1];
7657 if (msg == XEMBED_FOCUS_IN || msg == XEMBED_FOCUS_OUT)
7658 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
7659
7660 *finish = X_EVENT_GOTO_OUT;
7661 goto done;
7662 }
7663
7664 xft_settings_event (dpyinfo, event);
7665
7666 f = any;
7667 if (!f)
7668 goto OTHER;
7669 if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie))
7670 *finish = X_EVENT_DROP;
7671 }
7672 break;
7673
7674 case SelectionNotify:
7675 x_display_set_last_user_time (dpyinfo, event->xselection.time);
7676 #ifdef USE_X_TOOLKIT
7677 if (! x_window_to_frame (dpyinfo, event->xselection.requestor))
7678 goto OTHER;
7679 #endif /* not USE_X_TOOLKIT */
7680 x_handle_selection_notify (&event->xselection);
7681 break;
7682
7683 case SelectionClear: /* Someone has grabbed ownership. */
7684 x_display_set_last_user_time (dpyinfo, event->xselectionclear.time);
7685 #ifdef USE_X_TOOLKIT
7686 if (! x_window_to_frame (dpyinfo, event->xselectionclear.window))
7687 goto OTHER;
7688 #endif /* USE_X_TOOLKIT */
7689 {
7690 const XSelectionClearEvent *eventp = &event->xselectionclear;
7691
7692 inev.sie.kind = SELECTION_CLEAR_EVENT;
7693 SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
7694 SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
7695 SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
7696 }
7697 break;
7698
7699 case SelectionRequest: /* Someone wants our selection. */
7700 x_display_set_last_user_time (dpyinfo, event->xselectionrequest.time);
7701 #ifdef USE_X_TOOLKIT
7702 if (!x_window_to_frame (dpyinfo, event->xselectionrequest.owner))
7703 goto OTHER;
7704 #endif /* USE_X_TOOLKIT */
7705 {
7706 const XSelectionRequestEvent *eventp = &event->xselectionrequest;
7707
7708 inev.sie.kind = SELECTION_REQUEST_EVENT;
7709 SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
7710 SELECTION_EVENT_REQUESTOR (&inev.sie) = eventp->requestor;
7711 SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
7712 SELECTION_EVENT_TARGET (&inev.sie) = eventp->target;
7713 SELECTION_EVENT_PROPERTY (&inev.sie) = eventp->property;
7714 SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
7715 }
7716 break;
7717
7718 case PropertyNotify:
7719 x_display_set_last_user_time (dpyinfo, event->xproperty.time);
7720 f = x_top_window_to_frame (dpyinfo, event->xproperty.window);
7721 if (f && event->xproperty.atom == dpyinfo->Xatom_net_wm_state)
7722 {
7723 bool not_hidden = x_handle_net_wm_state (f, &event->xproperty);
7724 if (not_hidden && FRAME_ICONIFIED_P (f))
7725 {
7726 /* Gnome shell does not iconify us when C-z is pressed.
7727 It hides the frame. So if our state says we aren't
7728 hidden anymore, treat it as deiconified. */
7729 SET_FRAME_VISIBLE (f, 1);
7730 SET_FRAME_ICONIFIED (f, false);
7731 f->output_data.x->has_been_visible = true;
7732 inev.ie.kind = DEICONIFY_EVENT;
7733 XSETFRAME (inev.ie.frame_or_window, f);
7734 }
7735 else if (! not_hidden && ! FRAME_ICONIFIED_P (f))
7736 {
7737 SET_FRAME_VISIBLE (f, 0);
7738 SET_FRAME_ICONIFIED (f, true);
7739 inev.ie.kind = ICONIFY_EVENT;
7740 XSETFRAME (inev.ie.frame_or_window, f);
7741 }
7742 }
7743
7744 x_handle_property_notify (&event->xproperty);
7745 xft_settings_event (dpyinfo, event);
7746 goto OTHER;
7747
7748 case ReparentNotify:
7749 f = x_top_window_to_frame (dpyinfo, event->xreparent.window);
7750 if (f)
7751 {
7752 f->output_data.x->parent_desc = event->xreparent.parent;
7753 x_real_positions (f, &f->left_pos, &f->top_pos);
7754
7755 /* Perhaps reparented due to a WM restart. Reset this. */
7756 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
7757 FRAME_DISPLAY_INFO (f)->net_supported_window = 0;
7758
7759 x_set_frame_alpha (f);
7760 }
7761 goto OTHER;
7762
7763 case Expose:
7764 f = x_window_to_frame (dpyinfo, event->xexpose.window);
7765 if (f)
7766 {
7767 if (!FRAME_VISIBLE_P (f))
7768 {
7769 SET_FRAME_VISIBLE (f, 1);
7770 SET_FRAME_ICONIFIED (f, false);
7771 f->output_data.x->has_been_visible = true;
7772 SET_FRAME_GARBAGED (f);
7773 }
7774 else
7775 {
7776 #ifdef USE_GTK
7777 /* This seems to be needed for GTK 2.6 and later, see
7778 http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398. */
7779 x_clear_area (f,
7780 event->xexpose.x, event->xexpose.y,
7781 event->xexpose.width, event->xexpose.height);
7782 #endif
7783 expose_frame (f, event->xexpose.x, event->xexpose.y,
7784 event->xexpose.width, event->xexpose.height);
7785 }
7786 }
7787 else
7788 {
7789 #ifndef USE_TOOLKIT_SCROLL_BARS
7790 struct scroll_bar *bar;
7791 #endif
7792 #if defined USE_LUCID
7793 /* Submenus of the Lucid menu bar aren't widgets
7794 themselves, so there's no way to dispatch events
7795 to them. Recognize this case separately. */
7796 {
7797 Widget widget = x_window_to_menu_bar (event->xexpose.window);
7798 if (widget)
7799 xlwmenu_redisplay (widget);
7800 }
7801 #endif /* USE_LUCID */
7802
7803 #ifdef USE_TOOLKIT_SCROLL_BARS
7804 /* Dispatch event to the widget. */
7805 goto OTHER;
7806 #else /* not USE_TOOLKIT_SCROLL_BARS */
7807 bar = x_window_to_scroll_bar (event->xexpose.display,
7808 event->xexpose.window, 2);
7809
7810 if (bar)
7811 x_scroll_bar_expose (bar, event);
7812 #ifdef USE_X_TOOLKIT
7813 else
7814 goto OTHER;
7815 #endif /* USE_X_TOOLKIT */
7816 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7817 }
7818 break;
7819
7820 case GraphicsExpose: /* This occurs when an XCopyArea's
7821 source area was obscured or not
7822 available. */
7823 f = x_window_to_frame (dpyinfo, event->xgraphicsexpose.drawable);
7824 if (f)
7825 expose_frame (f, event->xgraphicsexpose.x,
7826 event->xgraphicsexpose.y,
7827 event->xgraphicsexpose.width,
7828 event->xgraphicsexpose.height);
7829 #ifdef USE_X_TOOLKIT
7830 else
7831 goto OTHER;
7832 #endif /* USE_X_TOOLKIT */
7833 break;
7834
7835 case NoExpose: /* This occurs when an XCopyArea's
7836 source area was completely
7837 available. */
7838 break;
7839
7840 case UnmapNotify:
7841 /* Redo the mouse-highlight after the tooltip has gone. */
7842 if (event->xunmap.window == tip_window)
7843 {
7844 tip_window = 0;
7845 x_redo_mouse_highlight (dpyinfo);
7846 }
7847
7848 f = x_top_window_to_frame (dpyinfo, event->xunmap.window);
7849 if (f) /* F may no longer exist if
7850 the frame was deleted. */
7851 {
7852 bool visible = FRAME_VISIBLE_P (f);
7853 /* While a frame is unmapped, display generation is
7854 disabled; you don't want to spend time updating a
7855 display that won't ever be seen. */
7856 SET_FRAME_VISIBLE (f, 0);
7857 /* We can't distinguish, from the event, whether the window
7858 has become iconified or invisible. So assume, if it
7859 was previously visible, than now it is iconified.
7860 But x_make_frame_invisible clears both
7861 the visible flag and the iconified flag;
7862 and that way, we know the window is not iconified now. */
7863 if (visible || FRAME_ICONIFIED_P (f))
7864 {
7865 SET_FRAME_ICONIFIED (f, true);
7866 inev.ie.kind = ICONIFY_EVENT;
7867 XSETFRAME (inev.ie.frame_or_window, f);
7868 }
7869 }
7870 goto OTHER;
7871
7872 case MapNotify:
7873 /* We use x_top_window_to_frame because map events can
7874 come for sub-windows and they don't mean that the
7875 frame is visible. */
7876 f = x_top_window_to_frame (dpyinfo, event->xmap.window);
7877 if (f)
7878 {
7879 bool iconified = FRAME_ICONIFIED_P (f);
7880
7881 /* Check if fullscreen was specified before we where mapped the
7882 first time, i.e. from the command line. */
7883 if (!f->output_data.x->has_been_visible)
7884 x_check_fullscreen (f);
7885
7886 SET_FRAME_VISIBLE (f, 1);
7887 SET_FRAME_ICONIFIED (f, false);
7888 f->output_data.x->has_been_visible = true;
7889
7890 if (iconified)
7891 {
7892 inev.ie.kind = DEICONIFY_EVENT;
7893 XSETFRAME (inev.ie.frame_or_window, f);
7894 }
7895 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
7896 /* Force a redisplay sooner or later to update the
7897 frame titles in case this is the second frame. */
7898 record_asynch_buffer_change ();
7899 }
7900 goto OTHER;
7901
7902 case KeyPress:
7903
7904 x_display_set_last_user_time (dpyinfo, event->xkey.time);
7905 ignore_next_mouse_click_timeout = 0;
7906
7907 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
7908 /* Dispatch KeyPress events when in menu. */
7909 if (popup_activated ())
7910 goto OTHER;
7911 #endif
7912
7913 f = any;
7914
7915 /* If mouse-highlight is an integer, input clears out
7916 mouse highlighting. */
7917 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
7918 #if ! defined (USE_GTK)
7919 && (f == 0
7920 || !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
7921 #endif
7922 )
7923 {
7924 clear_mouse_face (hlinfo);
7925 hlinfo->mouse_face_hidden = true;
7926 }
7927
7928 #if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
7929 if (f == 0)
7930 {
7931 /* Scroll bars consume key events, but we want
7932 the keys to go to the scroll bar's frame. */
7933 Widget widget = XtWindowToWidget (dpyinfo->display,
7934 event->xkey.window);
7935 if (widget && XmIsScrollBar (widget))
7936 {
7937 widget = XtParent (widget);
7938 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
7939 }
7940 }
7941 #endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
7942
7943 if (f != 0)
7944 {
7945 KeySym keysym, orig_keysym;
7946 /* al%imercury@uunet.uu.net says that making this 81
7947 instead of 80 fixed a bug whereby meta chars made
7948 his Emacs hang.
7949
7950 It seems that some version of XmbLookupString has
7951 a bug of not returning XBufferOverflow in
7952 status_return even if the input is too long to
7953 fit in 81 bytes. So, we must prepare sufficient
7954 bytes for copy_buffer. 513 bytes (256 chars for
7955 two-byte character set) seems to be a fairly good
7956 approximation. -- 2000.8.10 handa@etl.go.jp */
7957 unsigned char copy_buffer[513];
7958 unsigned char *copy_bufptr = copy_buffer;
7959 int copy_bufsiz = sizeof (copy_buffer);
7960 int modifiers;
7961 Lisp_Object coding_system = Qlatin_1;
7962 Lisp_Object c;
7963 /* Event will be modified. */
7964 XKeyEvent xkey = event->xkey;
7965
7966 #ifdef USE_GTK
7967 /* Don't pass keys to GTK. A Tab will shift focus to the
7968 tool bar in GTK 2.4. Keys will still go to menus and
7969 dialogs because in that case popup_activated is nonzero
7970 (see above). */
7971 *finish = X_EVENT_DROP;
7972 #endif
7973
7974 xkey.state |= x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f),
7975 extra_keyboard_modifiers);
7976 modifiers = xkey.state;
7977
7978 /* This will have to go some day... */
7979
7980 /* make_lispy_event turns chars into control chars.
7981 Don't do it here because XLookupString is too eager. */
7982 xkey.state &= ~ControlMask;
7983 xkey.state &= ~(dpyinfo->meta_mod_mask
7984 | dpyinfo->super_mod_mask
7985 | dpyinfo->hyper_mod_mask
7986 | dpyinfo->alt_mod_mask);
7987
7988 /* In case Meta is ComposeCharacter,
7989 clear its status. According to Markus Ehrnsperger
7990 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
7991 this enables ComposeCharacter to work whether or
7992 not it is combined with Meta. */
7993 if (modifiers & dpyinfo->meta_mod_mask)
7994 memset (&compose_status, 0, sizeof (compose_status));
7995
7996 #ifdef HAVE_X_I18N
7997 if (FRAME_XIC (f))
7998 {
7999 Status status_return;
8000
8001 coding_system = Vlocale_coding_system;
8002 nbytes = XmbLookupString (FRAME_XIC (f),
8003 &xkey, (char *) copy_bufptr,
8004 copy_bufsiz, &keysym,
8005 &status_return);
8006 if (status_return == XBufferOverflow)
8007 {
8008 copy_bufsiz = nbytes + 1;
8009 copy_bufptr = alloca (copy_bufsiz);
8010 nbytes = XmbLookupString (FRAME_XIC (f),
8011 &xkey, (char *) copy_bufptr,
8012 copy_bufsiz, &keysym,
8013 &status_return);
8014 }
8015 /* Xutf8LookupString is a new but already deprecated interface. -stef */
8016 if (status_return == XLookupNone)
8017 break;
8018 else if (status_return == XLookupChars)
8019 {
8020 keysym = NoSymbol;
8021 modifiers = 0;
8022 }
8023 else if (status_return != XLookupKeySym
8024 && status_return != XLookupBoth)
8025 emacs_abort ();
8026 }
8027 else
8028 nbytes = XLookupString (&xkey, (char *) copy_bufptr,
8029 copy_bufsiz, &keysym,
8030 &compose_status);
8031 #else
8032 nbytes = XLookupString (&xkey, (char *) copy_bufptr,
8033 copy_bufsiz, &keysym,
8034 &compose_status);
8035 #endif
8036
8037 /* If not using XIM/XIC, and a compose sequence is in progress,
8038 we break here. Otherwise, chars_matched is always 0. */
8039 if (compose_status.chars_matched > 0 && nbytes == 0)
8040 break;
8041
8042 memset (&compose_status, 0, sizeof (compose_status));
8043 orig_keysym = keysym;
8044
8045 /* Common for all keysym input events. */
8046 XSETFRAME (inev.ie.frame_or_window, f);
8047 inev.ie.modifiers
8048 = x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), modifiers);
8049 inev.ie.timestamp = xkey.time;
8050
8051 /* First deal with keysyms which have defined
8052 translations to characters. */
8053 if (keysym >= 32 && keysym < 128)
8054 /* Avoid explicitly decoding each ASCII character. */
8055 {
8056 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
8057 inev.ie.code = keysym;
8058 goto done_keysym;
8059 }
8060
8061 /* Keysyms directly mapped to Unicode characters. */
8062 if (keysym >= 0x01000000 && keysym <= 0x0110FFFF)
8063 {
8064 if (keysym < 0x01000080)
8065 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
8066 else
8067 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
8068 inev.ie.code = keysym & 0xFFFFFF;
8069 goto done_keysym;
8070 }
8071
8072 /* Now non-ASCII. */
8073 if (HASH_TABLE_P (Vx_keysym_table)
8074 && (c = Fgethash (make_number (keysym),
8075 Vx_keysym_table,
8076 Qnil),
8077 NATNUMP (c)))
8078 {
8079 inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c))
8080 ? ASCII_KEYSTROKE_EVENT
8081 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
8082 inev.ie.code = XFASTINT (c);
8083 goto done_keysym;
8084 }
8085
8086 /* Random non-modifier sorts of keysyms. */
8087 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
8088 || keysym == XK_Delete
8089 #ifdef XK_ISO_Left_Tab
8090 || (keysym >= XK_ISO_Left_Tab
8091 && keysym <= XK_ISO_Enter)
8092 #endif
8093 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
8094 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
8095 #ifdef HPUX
8096 /* This recognizes the "extended function
8097 keys". It seems there's no cleaner way.
8098 Test IsModifierKey to avoid handling
8099 mode_switch incorrectly. */
8100 || (XK_Select <= keysym && keysym < XK_KP_Space)
8101 #endif
8102 #ifdef XK_dead_circumflex
8103 || orig_keysym == XK_dead_circumflex
8104 #endif
8105 #ifdef XK_dead_grave
8106 || orig_keysym == XK_dead_grave
8107 #endif
8108 #ifdef XK_dead_tilde
8109 || orig_keysym == XK_dead_tilde
8110 #endif
8111 #ifdef XK_dead_diaeresis
8112 || orig_keysym == XK_dead_diaeresis
8113 #endif
8114 #ifdef XK_dead_macron
8115 || orig_keysym == XK_dead_macron
8116 #endif
8117 #ifdef XK_dead_degree
8118 || orig_keysym == XK_dead_degree
8119 #endif
8120 #ifdef XK_dead_acute
8121 || orig_keysym == XK_dead_acute
8122 #endif
8123 #ifdef XK_dead_cedilla
8124 || orig_keysym == XK_dead_cedilla
8125 #endif
8126 #ifdef XK_dead_breve
8127 || orig_keysym == XK_dead_breve
8128 #endif
8129 #ifdef XK_dead_ogonek
8130 || orig_keysym == XK_dead_ogonek
8131 #endif
8132 #ifdef XK_dead_caron
8133 || orig_keysym == XK_dead_caron
8134 #endif
8135 #ifdef XK_dead_doubleacute
8136 || orig_keysym == XK_dead_doubleacute
8137 #endif
8138 #ifdef XK_dead_abovedot
8139 || orig_keysym == XK_dead_abovedot
8140 #endif
8141 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
8142 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
8143 /* Any "vendor-specific" key is ok. */
8144 || (orig_keysym & (1 << 28))
8145 || (keysym != NoSymbol && nbytes == 0))
8146 && ! (IsModifierKey (orig_keysym)
8147 /* The symbols from XK_ISO_Lock
8148 to XK_ISO_Last_Group_Lock
8149 don't have real modifiers but
8150 should be treated similarly to
8151 Mode_switch by Emacs. */
8152 #if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock
8153 || (XK_ISO_Lock <= orig_keysym
8154 && orig_keysym <= XK_ISO_Last_Group_Lock)
8155 #endif
8156 ))
8157 {
8158 STORE_KEYSYM_FOR_DEBUG (keysym);
8159 /* make_lispy_event will convert this to a symbolic
8160 key. */
8161 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
8162 inev.ie.code = keysym;
8163 goto done_keysym;
8164 }
8165
8166 { /* Raw bytes, not keysym. */
8167 ptrdiff_t i;
8168 int nchars, len;
8169
8170 for (i = 0, nchars = 0; i < nbytes; i++)
8171 {
8172 if (ASCII_CHAR_P (copy_bufptr[i]))
8173 nchars++;
8174 STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
8175 }
8176
8177 if (nchars < nbytes)
8178 {
8179 /* Decode the input data. */
8180
8181 /* The input should be decoded with `coding_system'
8182 which depends on which X*LookupString function
8183 we used just above and the locale. */
8184 setup_coding_system (coding_system, &coding);
8185 coding.src_multibyte = false;
8186 coding.dst_multibyte = true;
8187 /* The input is converted to events, thus we can't
8188 handle composition. Anyway, there's no XIM that
8189 gives us composition information. */
8190 coding.common_flags &= ~CODING_ANNOTATION_MASK;
8191
8192 SAFE_NALLOCA (coding.destination, MAX_MULTIBYTE_LENGTH,
8193 nbytes);
8194 coding.dst_bytes = MAX_MULTIBYTE_LENGTH * nbytes;
8195 coding.mode |= CODING_MODE_LAST_BLOCK;
8196 decode_coding_c_string (&coding, copy_bufptr, nbytes, Qnil);
8197 nbytes = coding.produced;
8198 nchars = coding.produced_char;
8199 copy_bufptr = coding.destination;
8200 }
8201
8202 /* Convert the input data to a sequence of
8203 character events. */
8204 for (i = 0; i < nbytes; i += len)
8205 {
8206 int ch;
8207 if (nchars == nbytes)
8208 ch = copy_bufptr[i], len = 1;
8209 else
8210 ch = STRING_CHAR_AND_LENGTH (copy_bufptr + i, len);
8211 inev.ie.kind = (SINGLE_BYTE_CHAR_P (ch)
8212 ? ASCII_KEYSTROKE_EVENT
8213 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
8214 inev.ie.code = ch;
8215 kbd_buffer_store_buffered_event (&inev, hold_quit);
8216 }
8217
8218 count += nchars;
8219
8220 inev.ie.kind = NO_EVENT; /* Already stored above. */
8221
8222 if (keysym == NoSymbol)
8223 break;
8224 }
8225 /* FIXME: check side effects and remove this. */
8226 ((XEvent *) event)->xkey = xkey;
8227 }
8228 done_keysym:
8229 #ifdef HAVE_X_I18N
8230 /* Don't dispatch this event since XtDispatchEvent calls
8231 XFilterEvent, and two calls in a row may freeze the
8232 client. */
8233 break;
8234 #else
8235 goto OTHER;
8236 #endif
8237
8238 case KeyRelease:
8239 x_display_set_last_user_time (dpyinfo, event->xkey.time);
8240 #ifdef HAVE_X_I18N
8241 /* Don't dispatch this event since XtDispatchEvent calls
8242 XFilterEvent, and two calls in a row may freeze the
8243 client. */
8244 break;
8245 #else
8246 goto OTHER;
8247 #endif
8248
8249 case EnterNotify:
8250 x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
8251 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8252
8253 f = any;
8254
8255 if (f && x_mouse_click_focus_ignore_position)
8256 ignore_next_mouse_click_timeout = event->xmotion.time + 200;
8257
8258 /* EnterNotify counts as mouse movement,
8259 so update things that depend on mouse position. */
8260 if (f && !f->output_data.x->hourglass_p)
8261 note_mouse_movement (f, &event->xmotion);
8262 #ifdef USE_GTK
8263 /* We may get an EnterNotify on the buttons in the toolbar. In that
8264 case we moved out of any highlighted area and need to note this. */
8265 if (!f && dpyinfo->last_mouse_glyph_frame)
8266 note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &event->xmotion);
8267 #endif
8268 goto OTHER;
8269
8270 case FocusIn:
8271 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8272 goto OTHER;
8273
8274 case LeaveNotify:
8275 x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
8276 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8277
8278 f = x_top_window_to_frame (dpyinfo, event->xcrossing.window);
8279 if (f)
8280 {
8281 if (f == hlinfo->mouse_face_mouse_frame)
8282 {
8283 /* If we move outside the frame, then we're
8284 certainly no longer on any text in the frame. */
8285 clear_mouse_face (hlinfo);
8286 hlinfo->mouse_face_mouse_frame = 0;
8287 }
8288
8289 /* Generate a nil HELP_EVENT to cancel a help-echo.
8290 Do it only if there's something to cancel.
8291 Otherwise, the startup message is cleared when
8292 the mouse leaves the frame. */
8293 if (any_help_event_p)
8294 do_help = -1;
8295 }
8296 #ifdef USE_GTK
8297 /* See comment in EnterNotify above */
8298 else if (dpyinfo->last_mouse_glyph_frame)
8299 note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &event->xmotion);
8300 #endif
8301 goto OTHER;
8302
8303 case FocusOut:
8304 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8305 goto OTHER;
8306
8307 case MotionNotify:
8308 {
8309 x_display_set_last_user_time (dpyinfo, event->xmotion.time);
8310 previous_help_echo_string = help_echo_string;
8311 help_echo_string = Qnil;
8312
8313 f = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
8314 : x_window_to_frame (dpyinfo, event->xmotion.window));
8315
8316 if (hlinfo->mouse_face_hidden)
8317 {
8318 hlinfo->mouse_face_hidden = false;
8319 clear_mouse_face (hlinfo);
8320 }
8321
8322 #ifdef USE_GTK
8323 if (f && xg_event_is_for_scrollbar (f, event))
8324 f = 0;
8325 #endif
8326 if (f)
8327 {
8328
8329 /* Generate SELECT_WINDOW_EVENTs when needed.
8330 Don't let popup menus influence things (bug#1261). */
8331 if (!NILP (Vmouse_autoselect_window) && !popup_activated ())
8332 {
8333 static Lisp_Object last_mouse_window;
8334 Lisp_Object window = window_from_coordinates
8335 (f, event->xmotion.x, event->xmotion.y, 0, false);
8336
8337 /* Window will be selected only when it is not selected now and
8338 last mouse movement event was not in it. Minibuffer window
8339 will be selected only when it is active. */
8340 if (WINDOWP (window)
8341 && !EQ (window, last_mouse_window)
8342 && !EQ (window, selected_window)
8343 /* For click-to-focus window managers
8344 create event iff we don't leave the
8345 selected frame. */
8346 && (focus_follows_mouse
8347 || (EQ (XWINDOW (window)->frame,
8348 XWINDOW (selected_window)->frame))))
8349 {
8350 inev.ie.kind = SELECT_WINDOW_EVENT;
8351 inev.ie.frame_or_window = window;
8352 }
8353 /* Remember the last window where we saw the mouse. */
8354 last_mouse_window = window;
8355 }
8356 if (!note_mouse_movement (f, &event->xmotion))
8357 help_echo_string = previous_help_echo_string;
8358 }
8359 else
8360 {
8361 #ifndef USE_TOOLKIT_SCROLL_BARS
8362 struct scroll_bar *bar
8363 = x_window_to_scroll_bar (event->xmotion.display,
8364 event->xmotion.window, 2);
8365
8366 if (bar)
8367 x_scroll_bar_note_movement (bar, &event->xmotion);
8368 #endif /* USE_TOOLKIT_SCROLL_BARS */
8369
8370 /* If we move outside the frame, then we're
8371 certainly no longer on any text in the frame. */
8372 clear_mouse_face (hlinfo);
8373 }
8374
8375 /* If the contents of the global variable help_echo_string
8376 has changed, generate a HELP_EVENT. */
8377 if (!NILP (help_echo_string)
8378 || !NILP (previous_help_echo_string))
8379 do_help = 1;
8380 goto OTHER;
8381 }
8382
8383 case ConfigureNotify:
8384 /* An opaque move can generate a stream of events as the window
8385 is dragged around. If the connection round trip time isn't
8386 really short, they may come faster than we can respond to
8387 them, given the multiple queries we can do to check window
8388 manager state, translate coordinates, etc.
8389
8390 So if this ConfigureNotify is immediately followed by another
8391 for the same window, use the info from the latest update, and
8392 consider the events all handled. */
8393 /* Opaque resize may be trickier; ConfigureNotify events are
8394 mixed with Expose events for multiple windows. */
8395 configureEvent = *event;
8396 while (XPending (dpyinfo->display))
8397 {
8398 XNextEvent (dpyinfo->display, &next_event);
8399 if (next_event.type != ConfigureNotify
8400 || next_event.xconfigure.window != event->xconfigure.window
8401 /* Skipping events with different sizes can lead to a
8402 mispositioned mode line at initial window creation.
8403 Only drop window motion events for now. */
8404 || next_event.xconfigure.width != event->xconfigure.width
8405 || next_event.xconfigure.height != event->xconfigure.height)
8406 {
8407 XPutBackEvent (dpyinfo->display, &next_event);
8408 break;
8409 }
8410 else
8411 configureEvent = next_event;
8412 }
8413 f = x_top_window_to_frame (dpyinfo, configureEvent.xconfigure.window);
8414 #ifdef USE_CAIRO
8415 if (f) x_cr_destroy_surface (f);
8416 #endif
8417 #ifdef USE_GTK
8418 if (!f
8419 && (f = any)
8420 && configureEvent.xconfigure.window == FRAME_X_WINDOW (f))
8421 {
8422 xg_frame_resized (f, configureEvent.xconfigure.width,
8423 configureEvent.xconfigure.height);
8424 #ifdef USE_CAIRO
8425 x_cr_destroy_surface (f);
8426 #endif
8427 f = 0;
8428 }
8429 #endif
8430 if (f)
8431 {
8432 x_net_wm_state (f, configureEvent.xconfigure.window);
8433
8434 #ifdef USE_X_TOOLKIT
8435 /* Tip frames are pure X window, set size for them. */
8436 if (! NILP (tip_frame) && XFRAME (tip_frame) == f)
8437 {
8438 if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height
8439 || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width)
8440 SET_FRAME_GARBAGED (f);
8441 FRAME_PIXEL_HEIGHT (f) = configureEvent.xconfigure.height;
8442 FRAME_PIXEL_WIDTH (f) = configureEvent.xconfigure.width;
8443 }
8444 #endif
8445
8446 #ifndef USE_X_TOOLKIT
8447 #ifndef USE_GTK
8448 int width =
8449 FRAME_PIXEL_TO_TEXT_WIDTH (f, configureEvent.xconfigure.width);
8450 int height =
8451 FRAME_PIXEL_TO_TEXT_HEIGHT (f, configureEvent.xconfigure.height);
8452
8453 /* In the toolkit version, change_frame_size
8454 is called by the code that handles resizing
8455 of the EmacsFrame widget. */
8456
8457 /* Even if the number of character rows and columns has
8458 not changed, the font size may have changed, so we need
8459 to check the pixel dimensions as well. */
8460 if (width != FRAME_TEXT_WIDTH (f)
8461 || height != FRAME_TEXT_HEIGHT (f)
8462 || configureEvent.xconfigure.width != FRAME_PIXEL_WIDTH (f)
8463 || configureEvent.xconfigure.height != FRAME_PIXEL_HEIGHT (f))
8464 {
8465 change_frame_size (f, width, height, false, true, false, true);
8466 x_clear_under_internal_border (f);
8467 SET_FRAME_GARBAGED (f);
8468 cancel_mouse_face (f);
8469 }
8470 #endif /* not USE_GTK */
8471 #endif
8472
8473 #ifdef USE_GTK
8474 /* GTK creates windows but doesn't map them.
8475 Only get real positions when mapped. */
8476 if (FRAME_GTK_OUTER_WIDGET (f)
8477 && gtk_widget_get_mapped (FRAME_GTK_OUTER_WIDGET (f)))
8478 #endif
8479 x_real_positions (f, &f->left_pos, &f->top_pos);
8480
8481 #ifdef HAVE_X_I18N
8482 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
8483 xic_set_statusarea (f);
8484 #endif
8485
8486 }
8487 goto OTHER;
8488
8489 case ButtonRelease:
8490 case ButtonPress:
8491 {
8492 /* If we decide we want to generate an event to be seen
8493 by the rest of Emacs, we put it here. */
8494 bool tool_bar_p = false;
8495
8496 memset (&compose_status, 0, sizeof (compose_status));
8497 dpyinfo->last_mouse_glyph_frame = NULL;
8498 x_display_set_last_user_time (dpyinfo, event->xbutton.time);
8499
8500 f = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
8501 : x_window_to_frame (dpyinfo, event->xbutton.window));
8502
8503 #ifdef USE_GTK
8504 if (f && xg_event_is_for_scrollbar (f, event))
8505 f = 0;
8506 #endif
8507 if (f)
8508 {
8509 #if ! defined (USE_GTK)
8510 /* Is this in the tool-bar? */
8511 if (WINDOWP (f->tool_bar_window)
8512 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
8513 {
8514 Lisp_Object window;
8515 int x = event->xbutton.x;
8516 int y = event->xbutton.y;
8517
8518 window = window_from_coordinates (f, x, y, 0, true);
8519 tool_bar_p = EQ (window, f->tool_bar_window);
8520
8521 if (tool_bar_p && event->xbutton.button < 4)
8522 handle_tool_bar_click
8523 (f, x, y, event->xbutton.type == ButtonPress,
8524 x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state));
8525 }
8526 #endif /* !USE_GTK */
8527
8528 if (!tool_bar_p)
8529 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
8530 if (! popup_activated ())
8531 #endif
8532 {
8533 if (ignore_next_mouse_click_timeout)
8534 {
8535 if (event->type == ButtonPress
8536 && event->xbutton.time > ignore_next_mouse_click_timeout)
8537 {
8538 ignore_next_mouse_click_timeout = 0;
8539 construct_mouse_click (&inev.ie, &event->xbutton, f);
8540 }
8541 if (event->type == ButtonRelease)
8542 ignore_next_mouse_click_timeout = 0;
8543 }
8544 else
8545 construct_mouse_click (&inev.ie, &event->xbutton, f);
8546 }
8547 if (FRAME_X_EMBEDDED_P (f))
8548 xembed_send_message (f, event->xbutton.time,
8549 XEMBED_REQUEST_FOCUS, 0, 0, 0);
8550 }
8551 else
8552 {
8553 struct scroll_bar *bar
8554 = x_window_to_scroll_bar (event->xbutton.display,
8555 event->xbutton.window, 2);
8556
8557 #ifdef USE_TOOLKIT_SCROLL_BARS
8558 /* Make the "Ctrl-Mouse-2 splits window" work for toolkit
8559 scroll bars. */
8560 if (bar && event->xbutton.state & ControlMask)
8561 {
8562 x_scroll_bar_handle_click (bar, event, &inev.ie);
8563 *finish = X_EVENT_DROP;
8564 }
8565 #else /* not USE_TOOLKIT_SCROLL_BARS */
8566 if (bar)
8567 x_scroll_bar_handle_click (bar, event, &inev.ie);
8568 #endif /* not USE_TOOLKIT_SCROLL_BARS */
8569 }
8570
8571 if (event->type == ButtonPress)
8572 {
8573 dpyinfo->grabbed |= (1 << event->xbutton.button);
8574 dpyinfo->last_mouse_frame = f;
8575 #if ! defined (USE_GTK)
8576 if (f && !tool_bar_p)
8577 f->last_tool_bar_item = -1;
8578 #endif /* not USE_GTK */
8579 }
8580 else
8581 dpyinfo->grabbed &= ~(1 << event->xbutton.button);
8582
8583 /* Ignore any mouse motion that happened before this event;
8584 any subsequent mouse-movement Emacs events should reflect
8585 only motion after the ButtonPress/Release. */
8586 if (f != 0)
8587 f->mouse_moved = false;
8588
8589 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
8590 f = x_menubar_window_to_frame (dpyinfo, event);
8591 /* For a down-event in the menu bar,
8592 don't pass it to Xt right now.
8593 Instead, save it away
8594 and we will pass it to Xt from kbd_buffer_get_event.
8595 That way, we can run some Lisp code first. */
8596 if (! popup_activated ()
8597 #ifdef USE_GTK
8598 /* Gtk+ menus only react to the first three buttons. */
8599 && event->xbutton.button < 3
8600 #endif
8601 && f && event->type == ButtonPress
8602 /* Verify the event is really within the menu bar
8603 and not just sent to it due to grabbing. */
8604 && event->xbutton.x >= 0
8605 && event->xbutton.x < FRAME_PIXEL_WIDTH (f)
8606 && event->xbutton.y >= 0
8607 && event->xbutton.y < FRAME_MENUBAR_HEIGHT (f)
8608 && event->xbutton.same_screen)
8609 {
8610 if (!f->output_data.x->saved_menu_event)
8611 f->output_data.x->saved_menu_event = xmalloc (sizeof *event);
8612 *f->output_data.x->saved_menu_event = *event;
8613 inev.ie.kind = MENU_BAR_ACTIVATE_EVENT;
8614 XSETFRAME (inev.ie.frame_or_window, f);
8615 *finish = X_EVENT_DROP;
8616 }
8617 else
8618 goto OTHER;
8619 #endif /* USE_X_TOOLKIT || USE_GTK */
8620 }
8621 break;
8622
8623 case CirculateNotify:
8624 goto OTHER;
8625
8626 case CirculateRequest:
8627 goto OTHER;
8628
8629 case VisibilityNotify:
8630 goto OTHER;
8631
8632 case MappingNotify:
8633 /* Someone has changed the keyboard mapping - update the
8634 local cache. */
8635 switch (event->xmapping.request)
8636 {
8637 case MappingModifier:
8638 x_find_modifier_meanings (dpyinfo);
8639 /* This is meant to fall through. */
8640 case MappingKeyboard:
8641 XRefreshKeyboardMapping ((XMappingEvent *) &event->xmapping);
8642 }
8643 goto OTHER;
8644
8645 case DestroyNotify:
8646 xft_settings_event (dpyinfo, event);
8647 break;
8648
8649 default:
8650 OTHER:
8651 #ifdef USE_X_TOOLKIT
8652 block_input ();
8653 if (*finish != X_EVENT_DROP)
8654 XtDispatchEvent ((XEvent *) event);
8655 unblock_input ();
8656 #endif /* USE_X_TOOLKIT */
8657 break;
8658 }
8659
8660 done:
8661 if (inev.ie.kind != NO_EVENT)
8662 {
8663 kbd_buffer_store_buffered_event (&inev, hold_quit);
8664 count++;
8665 }
8666
8667 if (do_help
8668 && !(hold_quit && hold_quit->kind != NO_EVENT))
8669 {
8670 Lisp_Object frame;
8671
8672 if (f)
8673 XSETFRAME (frame, f);
8674 else
8675 frame = Qnil;
8676
8677 if (do_help > 0)
8678 {
8679 any_help_event_p = true;
8680 gen_help_event (help_echo_string, frame, help_echo_window,
8681 help_echo_object, help_echo_pos);
8682 }
8683 else
8684 {
8685 help_echo_string = Qnil;
8686 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
8687 }
8688 count++;
8689 }
8690
8691 SAFE_FREE ();
8692 return count;
8693 }
8694
8695 /* Handles the XEvent EVENT on display DISPLAY.
8696 This is used for event loops outside the normal event handling,
8697 i.e. looping while a popup menu or a dialog is posted.
8698
8699 Returns the value handle_one_xevent sets in the finish argument. */
8700 int
8701 x_dispatch_event (XEvent *event, Display *display)
8702 {
8703 struct x_display_info *dpyinfo;
8704 int finish = X_EVENT_NORMAL;
8705
8706 dpyinfo = x_display_info_for_display (display);
8707
8708 if (dpyinfo)
8709 handle_one_xevent (dpyinfo, event, &finish, 0);
8710
8711 return finish;
8712 }
8713
8714 /* Read events coming from the X server.
8715 Return as soon as there are no more events to be read.
8716
8717 Return the number of characters stored into the buffer,
8718 thus pretending to be `read' (except the characters we store
8719 in the keyboard buffer can be multibyte, so are not necessarily
8720 C chars). */
8721
8722 static int
8723 XTread_socket (struct terminal *terminal, struct input_event *hold_quit)
8724 {
8725 int count = 0;
8726 bool event_found = false;
8727 struct x_display_info *dpyinfo = terminal->display_info.x;
8728
8729 block_input ();
8730
8731 /* For debugging, this gives a way to fake an I/O error. */
8732 if (dpyinfo == XTread_socket_fake_io_error)
8733 {
8734 XTread_socket_fake_io_error = 0;
8735 x_io_error_quitter (dpyinfo->display);
8736 }
8737
8738 #ifndef USE_GTK
8739 while (XPending (dpyinfo->display))
8740 {
8741 int finish;
8742 XEvent event;
8743
8744 XNextEvent (dpyinfo->display, &event);
8745
8746 #ifdef HAVE_X_I18N
8747 /* Filter events for the current X input method. */
8748 if (x_filter_event (dpyinfo, &event))
8749 continue;
8750 #endif
8751 event_found = true;
8752
8753 count += handle_one_xevent (dpyinfo, &event, &finish, hold_quit);
8754
8755 if (finish == X_EVENT_GOTO_OUT)
8756 break;
8757 }
8758
8759 #else /* USE_GTK */
8760
8761 /* For GTK we must use the GTK event loop. But XEvents gets passed
8762 to our filter function above, and then to the big event switch.
8763 We use a bunch of globals to communicate with our filter function,
8764 that is kind of ugly, but it works.
8765
8766 There is no way to do one display at the time, GTK just does events
8767 from all displays. */
8768
8769 while (gtk_events_pending ())
8770 {
8771 current_count = count;
8772 current_hold_quit = hold_quit;
8773
8774 gtk_main_iteration ();
8775
8776 count = current_count;
8777 current_count = -1;
8778 current_hold_quit = 0;
8779
8780 if (current_finish == X_EVENT_GOTO_OUT)
8781 break;
8782 }
8783 #endif /* USE_GTK */
8784
8785 /* On some systems, an X bug causes Emacs to get no more events
8786 when the window is destroyed. Detect that. (1994.) */
8787 if (! event_found)
8788 {
8789 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
8790 One XNOOP in 100 loops will make Emacs terminate.
8791 B. Bretthauer, 1994 */
8792 x_noop_count++;
8793 if (x_noop_count >= 100)
8794 {
8795 x_noop_count=0;
8796
8797 if (next_noop_dpyinfo == 0)
8798 next_noop_dpyinfo = x_display_list;
8799
8800 XNoOp (next_noop_dpyinfo->display);
8801
8802 /* Each time we get here, cycle through the displays now open. */
8803 next_noop_dpyinfo = next_noop_dpyinfo->next;
8804 }
8805 }
8806
8807 /* If the focus was just given to an auto-raising frame,
8808 raise it now. FIXME: handle more than one such frame. */
8809 if (dpyinfo->x_pending_autoraise_frame)
8810 {
8811 x_raise_frame (dpyinfo->x_pending_autoraise_frame);
8812 dpyinfo->x_pending_autoraise_frame = NULL;
8813 }
8814
8815 unblock_input ();
8816
8817 return count;
8818 }
8819
8820
8821
8822 \f
8823 /***********************************************************************
8824 Text Cursor
8825 ***********************************************************************/
8826
8827 /* Set clipping for output in glyph row ROW. W is the window in which
8828 we operate. GC is the graphics context to set clipping in.
8829
8830 ROW may be a text row or, e.g., a mode line. Text rows must be
8831 clipped to the interior of the window dedicated to text display,
8832 mode lines must be clipped to the whole window. */
8833
8834 static void
8835 x_clip_to_row (struct window *w, struct glyph_row *row,
8836 enum glyph_row_area area, GC gc)
8837 {
8838 struct frame *f = XFRAME (WINDOW_FRAME (w));
8839 XRectangle clip_rect;
8840 int window_x, window_y, window_width;
8841
8842 window_box (w, area, &window_x, &window_y, &window_width, 0);
8843
8844 clip_rect.x = window_x;
8845 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
8846 clip_rect.y = max (clip_rect.y, window_y);
8847 clip_rect.width = window_width;
8848 clip_rect.height = row->visible_height;
8849
8850 x_set_clip_rectangles (f, gc, &clip_rect, 1);
8851 }
8852
8853
8854 /* Draw a hollow box cursor on window W in glyph row ROW. */
8855
8856 static void
8857 x_draw_hollow_cursor (struct window *w, struct glyph_row *row)
8858 {
8859 struct frame *f = XFRAME (WINDOW_FRAME (w));
8860 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
8861 Display *dpy = FRAME_X_DISPLAY (f);
8862 int x, y, wd, h;
8863 XGCValues xgcv;
8864 struct glyph *cursor_glyph;
8865 GC gc;
8866
8867 /* Get the glyph the cursor is on. If we can't tell because
8868 the current matrix is invalid or such, give up. */
8869 cursor_glyph = get_phys_cursor_glyph (w);
8870 if (cursor_glyph == NULL)
8871 return;
8872
8873 /* Compute frame-relative coordinates for phys cursor. */
8874 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
8875 wd = w->phys_cursor_width - 1;
8876
8877 /* The foreground of cursor_gc is typically the same as the normal
8878 background color, which can cause the cursor box to be invisible. */
8879 xgcv.foreground = f->output_data.x->cursor_pixel;
8880 if (dpyinfo->scratch_cursor_gc)
8881 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
8882 else
8883 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
8884 GCForeground, &xgcv);
8885 gc = dpyinfo->scratch_cursor_gc;
8886
8887 /* When on R2L character, show cursor at the right edge of the
8888 glyph, unless the cursor box is as wide as the glyph or wider
8889 (the latter happens when x-stretch-cursor is non-nil). */
8890 if ((cursor_glyph->resolved_level & 1) != 0
8891 && cursor_glyph->pixel_width > wd)
8892 {
8893 x += cursor_glyph->pixel_width - wd;
8894 if (wd > 0)
8895 wd -= 1;
8896 }
8897 /* Set clipping, draw the rectangle, and reset clipping again. */
8898 x_clip_to_row (w, row, TEXT_AREA, gc);
8899 x_draw_rectangle (f, gc, x, y, wd, h - 1);
8900 x_reset_clip_rectangles (f, gc);
8901 }
8902
8903
8904 /* Draw a bar cursor on window W in glyph row ROW.
8905
8906 Implementation note: One would like to draw a bar cursor with an
8907 angle equal to the one given by the font property XA_ITALIC_ANGLE.
8908 Unfortunately, I didn't find a font yet that has this property set.
8909 --gerd. */
8910
8911 static void
8912 x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text_cursor_kinds kind)
8913 {
8914 struct frame *f = XFRAME (w->frame);
8915 struct glyph *cursor_glyph;
8916
8917 /* If cursor is out of bounds, don't draw garbage. This can happen
8918 in mini-buffer windows when switching between echo area glyphs
8919 and mini-buffer. */
8920 cursor_glyph = get_phys_cursor_glyph (w);
8921 if (cursor_glyph == NULL)
8922 return;
8923
8924 /* Experimental avoidance of cursor on xwidget. */
8925 if (cursor_glyph->type == XWIDGET_GLYPH)
8926 return;
8927
8928 /* If on an image, draw like a normal cursor. That's usually better
8929 visible than drawing a bar, esp. if the image is large so that
8930 the bar might not be in the window. */
8931 if (cursor_glyph->type == IMAGE_GLYPH)
8932 {
8933 struct glyph_row *r;
8934 r = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
8935 draw_phys_cursor_glyph (w, r, DRAW_CURSOR);
8936 }
8937 else
8938 {
8939 Display *dpy = FRAME_X_DISPLAY (f);
8940 Window window = FRAME_X_WINDOW (f);
8941 GC gc = FRAME_DISPLAY_INFO (f)->scratch_cursor_gc;
8942 unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures;
8943 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
8944 XGCValues xgcv;
8945
8946 /* If the glyph's background equals the color we normally draw
8947 the bars cursor in, the bar cursor in its normal color is
8948 invisible. Use the glyph's foreground color instead in this
8949 case, on the assumption that the glyph's colors are chosen so
8950 that the glyph is legible. */
8951 if (face->background == f->output_data.x->cursor_pixel)
8952 xgcv.background = xgcv.foreground = face->foreground;
8953 else
8954 xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel;
8955 xgcv.graphics_exposures = False;
8956
8957 if (gc)
8958 XChangeGC (dpy, gc, mask, &xgcv);
8959 else
8960 {
8961 gc = XCreateGC (dpy, window, mask, &xgcv);
8962 FRAME_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
8963 }
8964
8965 x_clip_to_row (w, row, TEXT_AREA, gc);
8966
8967 if (kind == BAR_CURSOR)
8968 {
8969 int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
8970
8971 if (width < 0)
8972 width = FRAME_CURSOR_WIDTH (f);
8973 width = min (cursor_glyph->pixel_width, width);
8974
8975 w->phys_cursor_width = width;
8976
8977 /* If the character under cursor is R2L, draw the bar cursor
8978 on the right of its glyph, rather than on the left. */
8979 if ((cursor_glyph->resolved_level & 1) != 0)
8980 x += cursor_glyph->pixel_width - width;
8981
8982 x_fill_rectangle (f, gc, x,
8983 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
8984 width, row->height);
8985 }
8986 else /* HBAR_CURSOR */
8987 {
8988 int dummy_x, dummy_y, dummy_h;
8989 int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
8990
8991 if (width < 0)
8992 width = row->height;
8993
8994 width = min (row->height, width);
8995
8996 get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x,
8997 &dummy_y, &dummy_h);
8998
8999 if ((cursor_glyph->resolved_level & 1) != 0
9000 && cursor_glyph->pixel_width > w->phys_cursor_width - 1)
9001 x += cursor_glyph->pixel_width - w->phys_cursor_width + 1;
9002 x_fill_rectangle (f, gc, x,
9003 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
9004 row->height - width),
9005 w->phys_cursor_width - 1, width);
9006 }
9007
9008 x_reset_clip_rectangles (f, gc);
9009 }
9010 }
9011
9012
9013 /* RIF: Define cursor CURSOR on frame F. */
9014
9015 static void
9016 x_define_frame_cursor (struct frame *f, Cursor cursor)
9017 {
9018 if (!f->pointer_invisible
9019 && f->output_data.x->current_cursor != cursor)
9020 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
9021 f->output_data.x->current_cursor = cursor;
9022 }
9023
9024
9025 /* RIF: Clear area on frame F. */
9026
9027 static void
9028 x_clear_frame_area (struct frame *f, int x, int y, int width, int height)
9029 {
9030 x_clear_area (f, x, y, width, height);
9031 #ifdef USE_GTK
9032 /* Must queue a redraw, because scroll bars might have been cleared. */
9033 if (FRAME_GTK_WIDGET (f))
9034 gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
9035 #endif
9036 }
9037
9038
9039 /* RIF: Draw cursor on window W. */
9040
9041 static void
9042 x_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, int x,
9043 int y, enum text_cursor_kinds cursor_type,
9044 int cursor_width, bool on_p, bool active_p)
9045 {
9046 struct frame *f = XFRAME (WINDOW_FRAME (w));
9047
9048 if (on_p)
9049 {
9050 w->phys_cursor_type = cursor_type;
9051 w->phys_cursor_on_p = true;
9052
9053 if (glyph_row->exact_window_width_line_p
9054 && (glyph_row->reversed_p
9055 ? (w->phys_cursor.hpos < 0)
9056 : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])))
9057 {
9058 glyph_row->cursor_in_fringe_p = true;
9059 draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p);
9060 }
9061 else
9062 {
9063 switch (cursor_type)
9064 {
9065 case HOLLOW_BOX_CURSOR:
9066 x_draw_hollow_cursor (w, glyph_row);
9067 break;
9068
9069 case FILLED_BOX_CURSOR:
9070 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
9071 break;
9072
9073 case BAR_CURSOR:
9074 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
9075 break;
9076
9077 case HBAR_CURSOR:
9078 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
9079 break;
9080
9081 case NO_CURSOR:
9082 w->phys_cursor_width = 0;
9083 break;
9084
9085 default:
9086 emacs_abort ();
9087 }
9088 }
9089
9090 #ifdef HAVE_X_I18N
9091 if (w == XWINDOW (f->selected_window))
9092 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
9093 xic_set_preeditarea (w, x, y);
9094 #endif
9095 }
9096
9097 XFlush (FRAME_X_DISPLAY (f));
9098 }
9099
9100 \f
9101 /* Icons. */
9102
9103 /* Make the x-window of frame F use the gnu icon bitmap. */
9104
9105 bool
9106 x_bitmap_icon (struct frame *f, Lisp_Object file)
9107 {
9108 ptrdiff_t bitmap_id;
9109
9110 if (FRAME_X_WINDOW (f) == 0)
9111 return true;
9112
9113 /* Free up our existing icon bitmap and mask if any. */
9114 if (f->output_data.x->icon_bitmap > 0)
9115 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
9116 f->output_data.x->icon_bitmap = 0;
9117
9118 if (STRINGP (file))
9119 {
9120 #ifdef USE_GTK
9121 /* Use gtk_window_set_icon_from_file () if available,
9122 It's not restricted to bitmaps */
9123 if (xg_set_icon (f, file))
9124 return false;
9125 #endif /* USE_GTK */
9126 bitmap_id = x_create_bitmap_from_file (f, file);
9127 x_create_bitmap_mask (f, bitmap_id);
9128 }
9129 else
9130 {
9131 /* Create the GNU bitmap and mask if necessary. */
9132 if (FRAME_DISPLAY_INFO (f)->icon_bitmap_id < 0)
9133 {
9134 ptrdiff_t rc = -1;
9135
9136 #ifdef USE_GTK
9137
9138 if (xg_set_icon (f, xg_default_icon_file)
9139 || xg_set_icon_from_xpm_data (f, gnu_xpm_bits))
9140 {
9141 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = -2;
9142 return false;
9143 }
9144
9145 #elif defined (HAVE_XPM) && defined (HAVE_X_WINDOWS)
9146
9147 rc = x_create_bitmap_from_xpm_data (f, gnu_xpm_bits);
9148 if (rc != -1)
9149 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = rc;
9150
9151 #endif
9152
9153 /* If all else fails, use the (black and white) xbm image. */
9154 if (rc == -1)
9155 {
9156 rc = x_create_bitmap_from_data (f, (char *) gnu_xbm_bits,
9157 gnu_xbm_width, gnu_xbm_height);
9158 if (rc == -1)
9159 return true;
9160
9161 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = rc;
9162 x_create_bitmap_mask (f, FRAME_DISPLAY_INFO (f)->icon_bitmap_id);
9163 }
9164 }
9165
9166 /* The first time we create the GNU bitmap and mask,
9167 this increments the ref-count one extra time.
9168 As a result, the GNU bitmap and mask are never freed.
9169 That way, we don't have to worry about allocating it again. */
9170 x_reference_bitmap (f, FRAME_DISPLAY_INFO (f)->icon_bitmap_id);
9171
9172 bitmap_id = FRAME_DISPLAY_INFO (f)->icon_bitmap_id;
9173 }
9174
9175 x_wm_set_icon_pixmap (f, bitmap_id);
9176 f->output_data.x->icon_bitmap = bitmap_id;
9177
9178 return false;
9179 }
9180
9181
9182 /* Make the x-window of frame F use a rectangle with text.
9183 Use ICON_NAME as the text. */
9184
9185 bool
9186 x_text_icon (struct frame *f, const char *icon_name)
9187 {
9188 if (FRAME_X_WINDOW (f) == 0)
9189 return true;
9190
9191 {
9192 XTextProperty text;
9193 text.value = (unsigned char *) icon_name;
9194 text.encoding = XA_STRING;
9195 text.format = 8;
9196 text.nitems = strlen (icon_name);
9197 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), &text);
9198 }
9199
9200 if (f->output_data.x->icon_bitmap > 0)
9201 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
9202 f->output_data.x->icon_bitmap = 0;
9203 x_wm_set_icon_pixmap (f, 0);
9204
9205 return false;
9206 }
9207 \f
9208 #define X_ERROR_MESSAGE_SIZE 200
9209
9210 /* If non-nil, this should be a string.
9211 It means catch X errors and store the error message in this string.
9212
9213 The reason we use a stack is that x_catch_error/x_uncatch_error can
9214 be called from a signal handler.
9215 */
9216
9217 struct x_error_message_stack {
9218 char string[X_ERROR_MESSAGE_SIZE];
9219 Display *dpy;
9220 x_special_error_handler handler;
9221 void *handler_data;
9222 struct x_error_message_stack *prev;
9223 };
9224 static struct x_error_message_stack *x_error_message;
9225
9226 /* An X error handler which stores the error message in
9227 *x_error_message. This is called from x_error_handler if
9228 x_catch_errors is in effect. */
9229
9230 static void
9231 x_error_catcher (Display *display, XErrorEvent *event)
9232 {
9233 XGetErrorText (display, event->error_code,
9234 x_error_message->string,
9235 X_ERROR_MESSAGE_SIZE);
9236 if (x_error_message->handler)
9237 x_error_message->handler (display, event, x_error_message->string,
9238 x_error_message->handler_data);
9239 }
9240
9241 /* Begin trapping X errors for display DPY. Actually we trap X errors
9242 for all displays, but DPY should be the display you are actually
9243 operating on.
9244
9245 After calling this function, X protocol errors no longer cause
9246 Emacs to exit; instead, they are recorded in the string
9247 stored in *x_error_message.
9248
9249 Calling x_check_errors signals an Emacs error if an X error has
9250 occurred since the last call to x_catch_errors or x_check_errors.
9251
9252 Calling x_uncatch_errors resumes the normal error handling.
9253 Calling x_uncatch_errors_after_check is similar, but skips an XSync
9254 to the server, and should be used only immediately after
9255 x_had_errors_p or x_check_errors. */
9256
9257 void
9258 x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler,
9259 void *handler_data)
9260 {
9261 struct x_error_message_stack *data = xmalloc (sizeof *data);
9262
9263 /* Make sure any errors from previous requests have been dealt with. */
9264 XSync (dpy, False);
9265
9266 data->dpy = dpy;
9267 data->string[0] = 0;
9268 data->handler = handler;
9269 data->handler_data = handler_data;
9270 data->prev = x_error_message;
9271 x_error_message = data;
9272 }
9273
9274 void
9275 x_catch_errors (Display *dpy)
9276 {
9277 x_catch_errors_with_handler (dpy, NULL, NULL);
9278 }
9279
9280 /* Undo the last x_catch_errors call.
9281 DPY should be the display that was passed to x_catch_errors.
9282
9283 This version should be used only if the immediately preceding
9284 X-protocol-related thing was x_check_errors or x_had_error_p, both
9285 of which issue XSync calls, so we don't need to re-sync here. */
9286
9287 void
9288 x_uncatch_errors_after_check (void)
9289 {
9290 struct x_error_message_stack *tmp;
9291
9292 block_input ();
9293 tmp = x_error_message;
9294 x_error_message = x_error_message->prev;
9295 xfree (tmp);
9296 unblock_input ();
9297 }
9298
9299 /* Undo the last x_catch_errors call.
9300 DPY should be the display that was passed to x_catch_errors. */
9301
9302 void
9303 x_uncatch_errors (void)
9304 {
9305 struct x_error_message_stack *tmp;
9306
9307 block_input ();
9308
9309 /* The display may have been closed before this function is called.
9310 Check if it is still open before calling XSync. */
9311 if (x_display_info_for_display (x_error_message->dpy) != 0)
9312 XSync (x_error_message->dpy, False);
9313
9314 tmp = x_error_message;
9315 x_error_message = x_error_message->prev;
9316 xfree (tmp);
9317 unblock_input ();
9318 }
9319
9320 /* If any X protocol errors have arrived since the last call to
9321 x_catch_errors or x_check_errors, signal an Emacs error using
9322 sprintf (a buffer, FORMAT, the x error message text) as the text. */
9323
9324 void
9325 x_check_errors (Display *dpy, const char *format)
9326 {
9327 /* Make sure to catch any errors incurred so far. */
9328 XSync (dpy, False);
9329
9330 if (x_error_message->string[0])
9331 {
9332 char string[X_ERROR_MESSAGE_SIZE];
9333 memcpy (string, x_error_message->string, X_ERROR_MESSAGE_SIZE);
9334 x_uncatch_errors ();
9335 error (format, string);
9336 }
9337 }
9338
9339 /* Nonzero if we had any X protocol errors
9340 since we did x_catch_errors on DPY. */
9341
9342 bool
9343 x_had_errors_p (Display *dpy)
9344 {
9345 /* Make sure to catch any errors incurred so far. */
9346 XSync (dpy, False);
9347
9348 return x_error_message->string[0] != 0;
9349 }
9350
9351 /* Forget about any errors we have had, since we did x_catch_errors on DPY. */
9352
9353 void
9354 x_clear_errors (Display *dpy)
9355 {
9356 x_error_message->string[0] = 0;
9357 }
9358
9359 #if false
9360 /* See comment in unwind_to_catch why calling this is a bad
9361 * idea. --lorentey */
9362 /* Close off all unclosed x_catch_errors calls. */
9363
9364 void
9365 x_fully_uncatch_errors (void)
9366 {
9367 while (x_error_message)
9368 x_uncatch_errors ();
9369 }
9370 #endif
9371
9372 #if false
9373 static unsigned int x_wire_count;
9374 x_trace_wire (void)
9375 {
9376 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
9377 }
9378 #endif
9379
9380 \f
9381 /************************************************************************
9382 Handling X errors
9383 ************************************************************************/
9384
9385 /* Error message passed to x_connection_closed. */
9386
9387 static char *error_msg;
9388
9389 /* Handle the loss of connection to display DPY. ERROR_MESSAGE is
9390 the text of an error message that lead to the connection loss. */
9391
9392 static _Noreturn void
9393 x_connection_closed (Display *dpy, const char *error_message, bool ioerror)
9394 {
9395 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
9396 Lisp_Object frame, tail;
9397 ptrdiff_t idx = SPECPDL_INDEX ();
9398
9399 error_msg = alloca (strlen (error_message) + 1);
9400 strcpy (error_msg, error_message);
9401
9402 /* Inhibit redisplay while frames are being deleted. */
9403 specbind (Qinhibit_redisplay, Qt);
9404
9405 if (dpyinfo)
9406 {
9407 /* Protect display from being closed when we delete the last
9408 frame on it. */
9409 dpyinfo->reference_count++;
9410 dpyinfo->terminal->reference_count++;
9411 }
9412 if (ioerror) dpyinfo->display = 0;
9413
9414 /* First delete frames whose mini-buffers are on frames
9415 that are on the dead display. */
9416 FOR_EACH_FRAME (tail, frame)
9417 {
9418 Lisp_Object minibuf_frame;
9419 minibuf_frame
9420 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
9421 if (FRAME_X_P (XFRAME (frame))
9422 && FRAME_X_P (XFRAME (minibuf_frame))
9423 && ! EQ (frame, minibuf_frame)
9424 && FRAME_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
9425 delete_frame (frame, Qnoelisp);
9426 }
9427
9428 /* Now delete all remaining frames on the dead display.
9429 We are now sure none of these is used as the mini-buffer
9430 for another frame that we need to delete. */
9431 FOR_EACH_FRAME (tail, frame)
9432 if (FRAME_X_P (XFRAME (frame))
9433 && FRAME_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
9434 {
9435 /* Set this to t so that delete_frame won't get confused
9436 trying to find a replacement. */
9437 kset_default_minibuffer_frame (FRAME_KBOARD (XFRAME (frame)), Qt);
9438 delete_frame (frame, Qnoelisp);
9439 }
9440
9441 /* If DPYINFO is null, this means we didn't open the display in the
9442 first place, so don't try to close it. */
9443 if (dpyinfo)
9444 {
9445 /* We can not call XtCloseDisplay here because it calls XSync.
9446 XSync inside the error handler apparently hangs Emacs. On
9447 current Xt versions, this isn't needed either. */
9448 #ifdef USE_GTK
9449 /* A long-standing GTK bug prevents proper disconnect handling
9450 (https://bugzilla.gnome.org/show_bug.cgi?id=85715). Once,
9451 the resulting Glib error message loop filled a user's disk.
9452 To avoid this, kill Emacs unconditionally on disconnect. */
9453 shut_down_emacs (0, Qnil);
9454 fprintf (stderr, "%s\n\
9455 When compiled with GTK, Emacs cannot recover from X disconnects.\n\
9456 This is a GTK bug: https://bugzilla.gnome.org/show_bug.cgi?id=85715\n\
9457 For details, see etc/PROBLEMS.\n",
9458 error_msg);
9459 emacs_abort ();
9460 #endif /* USE_GTK */
9461
9462 /* Indicate that this display is dead. */
9463 dpyinfo->display = 0;
9464
9465 dpyinfo->reference_count--;
9466 dpyinfo->terminal->reference_count--;
9467 if (dpyinfo->reference_count != 0)
9468 /* We have just closed all frames on this display. */
9469 emacs_abort ();
9470
9471 {
9472 Lisp_Object tmp;
9473 XSETTERMINAL (tmp, dpyinfo->terminal);
9474 Fdelete_terminal (tmp, Qnoelisp);
9475 }
9476 }
9477
9478 if (terminal_list == 0)
9479 {
9480 fprintf (stderr, "%s\n", error_msg);
9481 Fkill_emacs (make_number (70));
9482 /* NOTREACHED */
9483 }
9484
9485 totally_unblock_input ();
9486
9487 unbind_to (idx, Qnil);
9488 clear_waiting_for_input ();
9489
9490 /* Here, we absolutely have to use a non-local exit (e.g. signal, throw,
9491 longjmp), because returning from this function would get us back into
9492 Xlib's code which will directly call `exit'. */
9493 error ("%s", error_msg);
9494 }
9495
9496 /* We specifically use it before defining it, so that gcc doesn't inline it,
9497 otherwise gdb doesn't know how to properly put a breakpoint on it. */
9498 static void x_error_quitter (Display *, XErrorEvent *);
9499
9500 /* This is the first-level handler for X protocol errors.
9501 It calls x_error_quitter or x_error_catcher. */
9502
9503 static int
9504 x_error_handler (Display *display, XErrorEvent *event)
9505 {
9506 #if defined USE_GTK && defined HAVE_GTK3
9507 if ((event->error_code == BadMatch || event->error_code == BadWindow)
9508 && event->request_code == X_SetInputFocus)
9509 {
9510 return 0;
9511 }
9512 #endif
9513
9514 if (x_error_message)
9515 x_error_catcher (display, event);
9516 else
9517 x_error_quitter (display, event);
9518 return 0;
9519 }
9520
9521 /* This is the usual handler for X protocol errors.
9522 It kills all frames on the display that we got the error for.
9523 If that was the only one, it prints an error message and kills Emacs. */
9524
9525 /* .gdbinit puts a breakpoint here, so make sure it is not inlined. */
9526
9527 /* On older GCC versions, just putting x_error_quitter
9528 after x_error_handler prevents inlining into the former. */
9529
9530 static void NO_INLINE
9531 x_error_quitter (Display *display, XErrorEvent *event)
9532 {
9533 char buf[256], buf1[356];
9534
9535 /* Ignore BadName errors. They can happen because of fonts
9536 or colors that are not defined. */
9537
9538 if (event->error_code == BadName)
9539 return;
9540
9541 /* Note that there is no real way portable across R3/R4 to get the
9542 original error handler. */
9543
9544 XGetErrorText (display, event->error_code, buf, sizeof (buf));
9545 sprintf (buf1, "X protocol error: %s on protocol request %d",
9546 buf, event->request_code);
9547 x_connection_closed (display, buf1, false);
9548 }
9549
9550
9551 /* This is the handler for X IO errors, always.
9552 It kills all frames on the display that we lost touch with.
9553 If that was the only one, it prints an error message and kills Emacs. */
9554
9555 static _Noreturn int
9556 x_io_error_quitter (Display *display)
9557 {
9558 char buf[256];
9559
9560 snprintf (buf, sizeof buf, "Connection lost to X server '%s'",
9561 DisplayString (display));
9562 x_connection_closed (display, buf, true);
9563 assume (false);
9564 }
9565 \f
9566 /* Changing the font of the frame. */
9567
9568 /* Give frame F the font FONT-OBJECT as its default font. The return
9569 value is FONT-OBJECT. FONTSET is an ID of the fontset for the
9570 frame. If it is negative, generate a new fontset from
9571 FONT-OBJECT. */
9572
9573 Lisp_Object
9574 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
9575 {
9576 struct font *font = XFONT_OBJECT (font_object);
9577 int unit, font_ascent, font_descent;
9578 #ifndef USE_X_TOOLKIT
9579 int old_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f);
9580 Lisp_Object fullscreen;
9581 #endif
9582
9583 if (fontset < 0)
9584 fontset = fontset_from_font (font_object);
9585 FRAME_FONTSET (f) = fontset;
9586 if (FRAME_FONT (f) == font)
9587 /* This font is already set in frame F. There's nothing more to
9588 do. */
9589 return font_object;
9590
9591 FRAME_FONT (f) = font;
9592 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
9593 FRAME_COLUMN_WIDTH (f) = font->average_width;
9594 get_font_ascent_descent (font, &font_ascent, &font_descent);
9595 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
9596
9597 #ifndef USE_X_TOOLKIT
9598 FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
9599 #endif
9600
9601 /* Compute character columns occupied by scrollbar.
9602
9603 Don't do things differently for non-toolkit scrollbars
9604 (Bug#17163). */
9605 unit = FRAME_COLUMN_WIDTH (f);
9606 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
9607 FRAME_CONFIG_SCROLL_BAR_COLS (f)
9608 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
9609 else
9610 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit;
9611
9612 if (FRAME_X_WINDOW (f) != 0)
9613 {
9614 /* Don't change the size of a tip frame; there's no point in
9615 doing it because it's done in Fx_show_tip, and it leads to
9616 problems because the tip frame has no widget. */
9617 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
9618 {
9619 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
9620 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
9621 false, Qfont);
9622 #ifndef USE_X_TOOLKIT
9623 if (FRAME_MENU_BAR_HEIGHT (f) != old_menu_bar_height
9624 && !f->after_make_frame
9625 && (EQ (frame_inhibit_implied_resize, Qt)
9626 || (CONSP (frame_inhibit_implied_resize)
9627 && NILP (Fmemq (Qfont, frame_inhibit_implied_resize))))
9628 && (NILP (fullscreen = get_frame_param (f, Qfullscreen))
9629 || EQ (fullscreen, Qfullwidth)))
9630 /* If the menu bar height changes, try to keep text height
9631 constant. */
9632 adjust_frame_size
9633 (f, -1, FRAME_TEXT_HEIGHT (f) + FRAME_MENU_BAR_HEIGHT (f)
9634 - old_menu_bar_height, 1, false, Qfont);
9635 #endif /* USE_X_TOOLKIT */
9636 }
9637 }
9638
9639 #ifdef HAVE_X_I18N
9640 if (FRAME_XIC (f)
9641 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
9642 {
9643 block_input ();
9644 xic_set_xfontset (f, SSDATA (fontset_ascii (fontset)));
9645 unblock_input ();
9646 }
9647 #endif
9648
9649 return font_object;
9650 }
9651
9652 \f
9653 /***********************************************************************
9654 X Input Methods
9655 ***********************************************************************/
9656
9657 #ifdef HAVE_X_I18N
9658
9659 #ifdef HAVE_X11R6
9660
9661 /* XIM destroy callback function, which is called whenever the
9662 connection to input method XIM dies. CLIENT_DATA contains a
9663 pointer to the x_display_info structure corresponding to XIM. */
9664
9665 static void
9666 xim_destroy_callback (XIM xim, XPointer client_data, XPointer call_data)
9667 {
9668 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
9669 Lisp_Object frame, tail;
9670
9671 block_input ();
9672
9673 /* No need to call XDestroyIC.. */
9674 FOR_EACH_FRAME (tail, frame)
9675 {
9676 struct frame *f = XFRAME (frame);
9677 if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo)
9678 {
9679 FRAME_XIC (f) = NULL;
9680 xic_free_xfontset (f);
9681 }
9682 }
9683
9684 /* No need to call XCloseIM. */
9685 dpyinfo->xim = NULL;
9686 XFree (dpyinfo->xim_styles);
9687 unblock_input ();
9688 }
9689
9690 #endif /* HAVE_X11R6 */
9691
9692 /* Open the connection to the XIM server on display DPYINFO.
9693 RESOURCE_NAME is the resource name Emacs uses. */
9694
9695 static void
9696 xim_open_dpy (struct x_display_info *dpyinfo, char *resource_name)
9697 {
9698 XIM xim;
9699
9700 #ifdef HAVE_XIM
9701 if (use_xim)
9702 {
9703 if (dpyinfo->xim)
9704 XCloseIM (dpyinfo->xim);
9705 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name,
9706 emacs_class);
9707 dpyinfo->xim = xim;
9708
9709 if (xim)
9710 {
9711 #ifdef HAVE_X11R6
9712 XIMCallback destroy;
9713 #endif
9714
9715 /* Get supported styles and XIM values. */
9716 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
9717
9718 #ifdef HAVE_X11R6
9719 destroy.callback = xim_destroy_callback;
9720 destroy.client_data = (XPointer)dpyinfo;
9721 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
9722 #endif
9723 }
9724 }
9725
9726 else
9727 #endif /* HAVE_XIM */
9728 dpyinfo->xim = NULL;
9729 }
9730
9731
9732 #ifdef HAVE_X11R6_XIM
9733
9734 /* XIM instantiate callback function, which is called whenever an XIM
9735 server is available. DISPLAY is the display of the XIM.
9736 CLIENT_DATA contains a pointer to an xim_inst_t structure created
9737 when the callback was registered. */
9738
9739 static void
9740 xim_instantiate_callback (Display *display, XPointer client_data, XPointer call_data)
9741 {
9742 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
9743 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
9744
9745 /* We don't support multiple XIM connections. */
9746 if (dpyinfo->xim)
9747 return;
9748
9749 xim_open_dpy (dpyinfo, xim_inst->resource_name);
9750
9751 /* Create XIC for the existing frames on the same display, as long
9752 as they have no XIC. */
9753 if (dpyinfo->xim && dpyinfo->reference_count > 0)
9754 {
9755 Lisp_Object tail, frame;
9756
9757 block_input ();
9758 FOR_EACH_FRAME (tail, frame)
9759 {
9760 struct frame *f = XFRAME (frame);
9761
9762 if (FRAME_X_P (f)
9763 && FRAME_DISPLAY_INFO (f) == xim_inst->dpyinfo)
9764 if (FRAME_XIC (f) == NULL)
9765 {
9766 create_frame_xic (f);
9767 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
9768 xic_set_statusarea (f);
9769 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
9770 {
9771 struct window *w = XWINDOW (f->selected_window);
9772 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
9773 }
9774 }
9775 }
9776
9777 unblock_input ();
9778 }
9779 }
9780
9781 #endif /* HAVE_X11R6_XIM */
9782
9783
9784 /* Open a connection to the XIM server on display DPYINFO.
9785 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
9786 connection only at the first time. On X11R6, open the connection
9787 in the XIM instantiate callback function. */
9788
9789 static void
9790 xim_initialize (struct x_display_info *dpyinfo, char *resource_name)
9791 {
9792 dpyinfo->xim = NULL;
9793 #ifdef HAVE_XIM
9794 if (use_xim)
9795 {
9796 #ifdef HAVE_X11R6_XIM
9797 struct xim_inst_t *xim_inst = xmalloc (sizeof *xim_inst);
9798 Bool ret;
9799
9800 dpyinfo->xim_callback_data = xim_inst;
9801 xim_inst->dpyinfo = dpyinfo;
9802 xim_inst->resource_name = xstrdup (resource_name);
9803 ret = XRegisterIMInstantiateCallback
9804 (dpyinfo->display, dpyinfo->xrdb, xim_inst->resource_name,
9805 emacs_class, xim_instantiate_callback,
9806 /* This is XPointer in XFree86 but (XPointer *)
9807 on Tru64, at least, hence the configure test. */
9808 (XRegisterIMInstantiateCallback_arg6) xim_inst);
9809 eassert (ret == True);
9810 #else /* not HAVE_X11R6_XIM */
9811 xim_open_dpy (dpyinfo, resource_name);
9812 #endif /* not HAVE_X11R6_XIM */
9813 }
9814 #endif /* HAVE_XIM */
9815 }
9816
9817
9818 /* Close the connection to the XIM server on display DPYINFO. */
9819
9820 static void
9821 xim_close_dpy (struct x_display_info *dpyinfo)
9822 {
9823 #ifdef HAVE_XIM
9824 if (use_xim)
9825 {
9826 #ifdef HAVE_X11R6_XIM
9827 struct xim_inst_t *xim_inst = dpyinfo->xim_callback_data;
9828
9829 if (dpyinfo->display)
9830 {
9831 Bool ret = XUnregisterIMInstantiateCallback
9832 (dpyinfo->display, dpyinfo->xrdb, xim_inst->resource_name,
9833 emacs_class, xim_instantiate_callback,
9834 (XRegisterIMInstantiateCallback_arg6) xim_inst);
9835 eassert (ret == True);
9836 }
9837 xfree (xim_inst->resource_name);
9838 xfree (xim_inst);
9839 #endif /* HAVE_X11R6_XIM */
9840 if (dpyinfo->display)
9841 XCloseIM (dpyinfo->xim);
9842 dpyinfo->xim = NULL;
9843 XFree (dpyinfo->xim_styles);
9844 }
9845 #endif /* HAVE_XIM */
9846 }
9847
9848 #endif /* not HAVE_X11R6_XIM */
9849
9850
9851 \f
9852 /* Calculate the absolute position in frame F
9853 from its current recorded position values and gravity. */
9854
9855 static void
9856 x_calc_absolute_position (struct frame *f)
9857 {
9858 int flags = f->size_hint_flags;
9859
9860 /* We have nothing to do if the current position
9861 is already for the top-left corner. */
9862 if (! ((flags & XNegative) || (flags & YNegative)))
9863 return;
9864
9865 /* Treat negative positions as relative to the leftmost bottommost
9866 position that fits on the screen. */
9867 if (flags & XNegative)
9868 f->left_pos = x_display_pixel_width (FRAME_DISPLAY_INFO (f))
9869 - FRAME_PIXEL_WIDTH (f) + f->left_pos;
9870
9871 {
9872 int height = FRAME_PIXEL_HEIGHT (f);
9873
9874 #if defined USE_X_TOOLKIT && defined USE_MOTIF
9875 /* Something is fishy here. When using Motif, starting Emacs with
9876 `-g -0-0', the frame appears too low by a few pixels.
9877
9878 This seems to be so because initially, while Emacs is starting,
9879 the column widget's height and the frame's pixel height are
9880 different. The column widget's height is the right one. In
9881 later invocations, when Emacs is up, the frame's pixel height
9882 is right, though.
9883
9884 It's not obvious where the initial small difference comes from.
9885 2000-12-01, gerd. */
9886
9887 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
9888 #endif
9889
9890 if (flags & YNegative)
9891 f->top_pos = x_display_pixel_height (FRAME_DISPLAY_INFO (f))
9892 - height + f->top_pos;
9893 }
9894
9895 /* The left_pos and top_pos
9896 are now relative to the top and left screen edges,
9897 so the flags should correspond. */
9898 f->size_hint_flags &= ~ (XNegative | YNegative);
9899 }
9900
9901 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
9902 to really change the position, and 0 when calling from
9903 x_make_frame_visible (in that case, XOFF and YOFF are the current
9904 position values). It is -1 when calling from x_set_frame_parameters,
9905 which means, do adjust for borders but don't change the gravity. */
9906
9907 void
9908 x_set_offset (struct frame *f, register int xoff, register int yoff, int change_gravity)
9909 {
9910 int modified_top, modified_left;
9911
9912 if (change_gravity > 0)
9913 {
9914 f->top_pos = yoff;
9915 f->left_pos = xoff;
9916 f->size_hint_flags &= ~ (XNegative | YNegative);
9917 if (xoff < 0)
9918 f->size_hint_flags |= XNegative;
9919 if (yoff < 0)
9920 f->size_hint_flags |= YNegative;
9921 f->win_gravity = NorthWestGravity;
9922 }
9923 x_calc_absolute_position (f);
9924
9925 block_input ();
9926 x_wm_set_size_hint (f, 0, false);
9927
9928 modified_left = f->left_pos;
9929 modified_top = f->top_pos;
9930
9931 if (change_gravity != 0 && FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A)
9932 {
9933 /* Some WMs (twm, wmaker at least) has an offset that is smaller
9934 than the WM decorations. So we use the calculated offset instead
9935 of the WM decoration sizes here (x/y_pixels_outer_diff). */
9936 modified_left += FRAME_X_OUTPUT (f)->move_offset_left;
9937 modified_top += FRAME_X_OUTPUT (f)->move_offset_top;
9938 }
9939
9940 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
9941 modified_left, modified_top);
9942
9943 x_sync_with_move (f, f->left_pos, f->top_pos,
9944 FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN);
9945
9946 /* change_gravity is non-zero when this function is called from Lisp to
9947 programmatically move a frame. In that case, we call
9948 x_check_expected_move to discover if we have a "Type A" or "Type B"
9949 window manager, and, for a "Type A" window manager, adjust the position
9950 of the frame.
9951
9952 We call x_check_expected_move if a programmatic move occurred, and
9953 either the window manager type (A/B) is unknown or it is Type A but we
9954 need to compute the top/left offset adjustment for this frame. */
9955
9956 if (change_gravity != 0
9957 && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
9958 || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
9959 && (FRAME_X_OUTPUT (f)->move_offset_left == 0
9960 && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
9961 x_check_expected_move (f, modified_left, modified_top);
9962
9963 unblock_input ();
9964 }
9965
9966 /* Return true if _NET_SUPPORTING_WM_CHECK window exists and _NET_SUPPORTED
9967 on the root window for frame F contains ATOMNAME.
9968 This is how a WM check shall be done according to the Window Manager
9969 Specification/Extended Window Manager Hints at
9970 http://freedesktop.org/wiki/Specifications/wm-spec. */
9971
9972 bool
9973 x_wm_supports (struct frame *f, Atom want_atom)
9974 {
9975 Atom actual_type;
9976 unsigned long actual_size, bytes_remaining;
9977 int i, rc, actual_format;
9978 bool ret;
9979 Window wmcheck_window;
9980 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
9981 Window target_window = dpyinfo->root_window;
9982 int max_len = 65536;
9983 Display *dpy = FRAME_X_DISPLAY (f);
9984 unsigned char *tmp_data = NULL;
9985 Atom target_type = XA_WINDOW;
9986
9987 block_input ();
9988
9989 x_catch_errors (dpy);
9990 rc = XGetWindowProperty (dpy, target_window,
9991 dpyinfo->Xatom_net_supporting_wm_check,
9992 0, max_len, False, target_type,
9993 &actual_type, &actual_format, &actual_size,
9994 &bytes_remaining, &tmp_data);
9995
9996 if (rc != Success || actual_type != XA_WINDOW || x_had_errors_p (dpy))
9997 {
9998 if (tmp_data) XFree (tmp_data);
9999 x_uncatch_errors ();
10000 unblock_input ();
10001 return false;
10002 }
10003
10004 wmcheck_window = *(Window *) tmp_data;
10005 XFree (tmp_data);
10006
10007 /* Check if window exists. */
10008 XSelectInput (dpy, wmcheck_window, StructureNotifyMask);
10009 if (x_had_errors_p (dpy))
10010 {
10011 x_uncatch_errors_after_check ();
10012 unblock_input ();
10013 return false;
10014 }
10015
10016 if (dpyinfo->net_supported_window != wmcheck_window)
10017 {
10018 /* Window changed, reload atoms */
10019 if (dpyinfo->net_supported_atoms != NULL)
10020 XFree (dpyinfo->net_supported_atoms);
10021 dpyinfo->net_supported_atoms = NULL;
10022 dpyinfo->nr_net_supported_atoms = 0;
10023 dpyinfo->net_supported_window = 0;
10024
10025 target_type = XA_ATOM;
10026 tmp_data = NULL;
10027 rc = XGetWindowProperty (dpy, target_window,
10028 dpyinfo->Xatom_net_supported,
10029 0, max_len, False, target_type,
10030 &actual_type, &actual_format, &actual_size,
10031 &bytes_remaining, &tmp_data);
10032
10033 if (rc != Success || actual_type != XA_ATOM || x_had_errors_p (dpy))
10034 {
10035 if (tmp_data) XFree (tmp_data);
10036 x_uncatch_errors ();
10037 unblock_input ();
10038 return false;
10039 }
10040
10041 dpyinfo->net_supported_atoms = (Atom *)tmp_data;
10042 dpyinfo->nr_net_supported_atoms = actual_size;
10043 dpyinfo->net_supported_window = wmcheck_window;
10044 }
10045
10046 ret = false;
10047
10048 for (i = 0; !ret && i < dpyinfo->nr_net_supported_atoms; ++i)
10049 ret = dpyinfo->net_supported_atoms[i] == want_atom;
10050
10051 x_uncatch_errors ();
10052 unblock_input ();
10053
10054 return ret;
10055 }
10056
10057 static void
10058 set_wm_state (Lisp_Object frame, bool add, Atom atom, Atom value)
10059 {
10060 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (XFRAME (frame));
10061
10062 x_send_client_event (frame, make_number (0), frame,
10063 dpyinfo->Xatom_net_wm_state,
10064 make_number (32),
10065 /* 1 = add, 0 = remove */
10066 Fcons
10067 (make_number (add),
10068 Fcons
10069 (make_fixnum_or_float (atom),
10070 (value != 0
10071 ? list1 (make_fixnum_or_float (value))
10072 : Qnil))));
10073 }
10074
10075 void
10076 x_set_sticky (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
10077 {
10078 Lisp_Object frame;
10079 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10080
10081 XSETFRAME (frame, f);
10082
10083 set_wm_state (frame, !NILP (new_value),
10084 dpyinfo->Xatom_net_wm_state_sticky, None);
10085 }
10086
10087 /* Return the current _NET_WM_STATE.
10088 SIZE_STATE is set to one of the FULLSCREEN_* values.
10089 Set *STICKY to the sticky state.
10090
10091 Return true iff we are not hidden. */
10092
10093 static bool
10094 get_current_wm_state (struct frame *f,
10095 Window window,
10096 int *size_state,
10097 bool *sticky)
10098 {
10099 unsigned long actual_size;
10100 int i;
10101 bool is_hidden = false;
10102 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10103 long max_len = 65536;
10104 Atom target_type = XA_ATOM;
10105 /* If XCB is available, we can avoid three XSync calls. */
10106 #ifdef USE_XCB
10107 xcb_get_property_cookie_t prop_cookie;
10108 xcb_get_property_reply_t *prop;
10109 xcb_atom_t *reply_data;
10110 #else
10111 Display *dpy = FRAME_X_DISPLAY (f);
10112 unsigned long bytes_remaining;
10113 int rc, actual_format;
10114 Atom actual_type;
10115 unsigned char *tmp_data = NULL;
10116 Atom *reply_data;
10117 #endif
10118
10119 *sticky = false;
10120 *size_state = FULLSCREEN_NONE;
10121
10122 block_input ();
10123
10124 #ifdef USE_XCB
10125 prop_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, window,
10126 dpyinfo->Xatom_net_wm_state,
10127 target_type, 0, max_len);
10128 prop = xcb_get_property_reply (dpyinfo->xcb_connection, prop_cookie, NULL);
10129 if (prop && prop->type == target_type)
10130 {
10131 int actual_bytes = xcb_get_property_value_length (prop);
10132 eassume (0 <= actual_bytes);
10133 actual_size = actual_bytes / sizeof *reply_data;
10134 reply_data = xcb_get_property_value (prop);
10135 }
10136 else
10137 {
10138 actual_size = 0;
10139 is_hidden = FRAME_ICONIFIED_P (f);
10140 }
10141 #else
10142 x_catch_errors (dpy);
10143 rc = XGetWindowProperty (dpy, window, dpyinfo->Xatom_net_wm_state,
10144 0, max_len, False, target_type,
10145 &actual_type, &actual_format, &actual_size,
10146 &bytes_remaining, &tmp_data);
10147
10148 if (rc == Success && actual_type == target_type && ! x_had_errors_p (dpy))
10149 reply_data = (Atom *) tmp_data;
10150 else
10151 {
10152 actual_size = 0;
10153 is_hidden = FRAME_ICONIFIED_P (f);
10154 }
10155
10156 x_uncatch_errors ();
10157 #endif
10158
10159 for (i = 0; i < actual_size; ++i)
10160 {
10161 Atom a = reply_data[i];
10162 if (a == dpyinfo->Xatom_net_wm_state_hidden)
10163 is_hidden = true;
10164 else if (a == dpyinfo->Xatom_net_wm_state_maximized_horz)
10165 {
10166 if (*size_state == FULLSCREEN_HEIGHT)
10167 *size_state = FULLSCREEN_MAXIMIZED;
10168 else
10169 *size_state = FULLSCREEN_WIDTH;
10170 }
10171 else if (a == dpyinfo->Xatom_net_wm_state_maximized_vert)
10172 {
10173 if (*size_state == FULLSCREEN_WIDTH)
10174 *size_state = FULLSCREEN_MAXIMIZED;
10175 else
10176 *size_state = FULLSCREEN_HEIGHT;
10177 }
10178 else if (a == dpyinfo->Xatom_net_wm_state_fullscreen)
10179 *size_state = FULLSCREEN_BOTH;
10180 else if (a == dpyinfo->Xatom_net_wm_state_sticky)
10181 *sticky = true;
10182 }
10183
10184 #ifdef USE_XCB
10185 free (prop);
10186 #else
10187 if (tmp_data) XFree (tmp_data);
10188 #endif
10189
10190 unblock_input ();
10191 return ! is_hidden;
10192 }
10193
10194 /* Do fullscreen as specified in extended window manager hints */
10195
10196 static bool
10197 do_ewmh_fullscreen (struct frame *f)
10198 {
10199 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10200 bool have_net_atom = x_wm_supports (f, dpyinfo->Xatom_net_wm_state);
10201 int cur;
10202 bool dummy;
10203
10204 get_current_wm_state (f, FRAME_OUTER_WINDOW (f), &cur, &dummy);
10205
10206 /* Some window managers don't say they support _NET_WM_STATE, but they do say
10207 they support _NET_WM_STATE_FULLSCREEN. Try that also. */
10208 if (!have_net_atom)
10209 have_net_atom = x_wm_supports (f, dpyinfo->Xatom_net_wm_state_fullscreen);
10210
10211 if (have_net_atom && cur != f->want_fullscreen)
10212 {
10213 Lisp_Object frame;
10214
10215 XSETFRAME (frame, f);
10216
10217 /* Keep number of calls to set_wm_state as low as possible.
10218 Some window managers, or possible Gtk+, hangs when too many
10219 are sent at once. */
10220 switch (f->want_fullscreen)
10221 {
10222 case FULLSCREEN_BOTH:
10223 if (cur != FULLSCREEN_BOTH)
10224 set_wm_state (frame, true, dpyinfo->Xatom_net_wm_state_fullscreen,
10225 None);
10226 break;
10227 case FULLSCREEN_WIDTH:
10228 if (x_frame_normalize_before_maximize && cur == FULLSCREEN_MAXIMIZED)
10229 {
10230 set_wm_state (frame, false,
10231 dpyinfo->Xatom_net_wm_state_maximized_horz,
10232 dpyinfo->Xatom_net_wm_state_maximized_vert);
10233 set_wm_state (frame, true,
10234 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
10235 }
10236 else
10237 {
10238 if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_HEIGHT
10239 || cur == FULLSCREEN_MAXIMIZED)
10240 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
10241 dpyinfo->Xatom_net_wm_state_maximized_vert);
10242 if (cur != FULLSCREEN_MAXIMIZED || x_frame_normalize_before_maximize)
10243 set_wm_state (frame, true,
10244 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
10245 }
10246 break;
10247 case FULLSCREEN_HEIGHT:
10248 if (x_frame_normalize_before_maximize && cur == FULLSCREEN_MAXIMIZED)
10249 {
10250 set_wm_state (frame, false,
10251 dpyinfo->Xatom_net_wm_state_maximized_horz,
10252 dpyinfo->Xatom_net_wm_state_maximized_vert);
10253 set_wm_state (frame, true,
10254 dpyinfo->Xatom_net_wm_state_maximized_vert, None);
10255 }
10256 else
10257 {
10258 if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_WIDTH
10259 || cur == FULLSCREEN_MAXIMIZED)
10260 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
10261 dpyinfo->Xatom_net_wm_state_maximized_horz);
10262 if (cur != FULLSCREEN_MAXIMIZED || x_frame_normalize_before_maximize)
10263 set_wm_state (frame, true,
10264 dpyinfo->Xatom_net_wm_state_maximized_vert, None);
10265 }
10266 break;
10267 case FULLSCREEN_MAXIMIZED:
10268 if (x_frame_normalize_before_maximize && cur == FULLSCREEN_BOTH)
10269 {
10270 set_wm_state (frame, false,
10271 dpyinfo->Xatom_net_wm_state_fullscreen, None);
10272 set_wm_state (frame, true,
10273 dpyinfo->Xatom_net_wm_state_maximized_horz,
10274 dpyinfo->Xatom_net_wm_state_maximized_vert);
10275 }
10276 else if (x_frame_normalize_before_maximize && cur == FULLSCREEN_WIDTH)
10277 {
10278 set_wm_state (frame, false,
10279 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
10280 set_wm_state (frame, true,
10281 dpyinfo->Xatom_net_wm_state_maximized_horz,
10282 dpyinfo->Xatom_net_wm_state_maximized_vert);
10283 }
10284 else if (x_frame_normalize_before_maximize && cur == FULLSCREEN_HEIGHT)
10285 {
10286 set_wm_state (frame, false,
10287 dpyinfo->Xatom_net_wm_state_maximized_vert, None);
10288 set_wm_state (frame, true,
10289 dpyinfo->Xatom_net_wm_state_maximized_horz,
10290 dpyinfo->Xatom_net_wm_state_maximized_vert);
10291 }
10292 else
10293 {
10294 if (cur == FULLSCREEN_BOTH)
10295 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
10296 None);
10297 else if (cur == FULLSCREEN_HEIGHT)
10298 set_wm_state (frame, true,
10299 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
10300 else if (cur == FULLSCREEN_WIDTH)
10301 set_wm_state (frame, true, None,
10302 dpyinfo->Xatom_net_wm_state_maximized_vert);
10303 else
10304 set_wm_state (frame, true,
10305 dpyinfo->Xatom_net_wm_state_maximized_horz,
10306 dpyinfo->Xatom_net_wm_state_maximized_vert);
10307 }
10308 break;
10309 case FULLSCREEN_NONE:
10310 if (cur == FULLSCREEN_BOTH)
10311 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
10312 None);
10313 else
10314 set_wm_state (frame, false,
10315 dpyinfo->Xatom_net_wm_state_maximized_horz,
10316 dpyinfo->Xatom_net_wm_state_maximized_vert);
10317 }
10318
10319 f->want_fullscreen = FULLSCREEN_NONE;
10320
10321 }
10322
10323 return have_net_atom;
10324 }
10325
10326 static void
10327 XTfullscreen_hook (struct frame *f)
10328 {
10329 if (FRAME_VISIBLE_P (f))
10330 {
10331 block_input ();
10332 x_check_fullscreen (f);
10333 x_sync (f);
10334 unblock_input ();
10335 }
10336 }
10337
10338
10339 static bool
10340 x_handle_net_wm_state (struct frame *f, const XPropertyEvent *event)
10341 {
10342 int value = FULLSCREEN_NONE;
10343 Lisp_Object lval;
10344 bool sticky = false;
10345 bool not_hidden = get_current_wm_state (f, event->window, &value, &sticky);
10346
10347 lval = Qnil;
10348 switch (value)
10349 {
10350 case FULLSCREEN_WIDTH:
10351 lval = Qfullwidth;
10352 break;
10353 case FULLSCREEN_HEIGHT:
10354 lval = Qfullheight;
10355 break;
10356 case FULLSCREEN_BOTH:
10357 lval = Qfullboth;
10358 break;
10359 case FULLSCREEN_MAXIMIZED:
10360 lval = Qmaximized;
10361 break;
10362 }
10363
10364 frame_size_history_add
10365 (f, Qx_handle_net_wm_state, 0, 0,
10366 list2 (get_frame_param (f, Qfullscreen), lval));
10367
10368 store_frame_param (f, Qfullscreen, lval);
10369 store_frame_param (f, Qsticky, sticky ? Qt : Qnil);
10370
10371 return not_hidden;
10372 }
10373
10374 /* Check if we need to resize the frame due to a fullscreen request.
10375 If so needed, resize the frame. */
10376 static void
10377 x_check_fullscreen (struct frame *f)
10378 {
10379 Lisp_Object lval = Qnil;
10380
10381 if (do_ewmh_fullscreen (f))
10382 return;
10383
10384 if (f->output_data.x->parent_desc != FRAME_DISPLAY_INFO (f)->root_window)
10385 return; /* Only fullscreen without WM or with EWM hints (above). */
10386
10387 /* Setting fullscreen to nil doesn't do anything. We could save the
10388 last non-fullscreen size and restore it, but it seems like a
10389 lot of work for this unusual case (no window manager running). */
10390
10391 if (f->want_fullscreen != FULLSCREEN_NONE)
10392 {
10393 int width = FRAME_PIXEL_WIDTH (f), height = FRAME_PIXEL_HEIGHT (f);
10394 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10395
10396 switch (f->want_fullscreen)
10397 {
10398 /* No difference between these two when there is no WM */
10399 case FULLSCREEN_MAXIMIZED:
10400 lval = Qmaximized;
10401 width = x_display_pixel_width (dpyinfo);
10402 height = x_display_pixel_height (dpyinfo);
10403 break;
10404 case FULLSCREEN_BOTH:
10405 lval = Qfullboth;
10406 width = x_display_pixel_width (dpyinfo);
10407 height = x_display_pixel_height (dpyinfo);
10408 break;
10409 case FULLSCREEN_WIDTH:
10410 lval = Qfullwidth;
10411 width = x_display_pixel_width (dpyinfo);
10412 height = height + FRAME_MENUBAR_HEIGHT (f);
10413 break;
10414 case FULLSCREEN_HEIGHT:
10415 lval = Qfullheight;
10416 height = x_display_pixel_height (dpyinfo);
10417 break;
10418 default:
10419 emacs_abort ();
10420 }
10421
10422 frame_size_history_add
10423 (f, Qx_check_fullscreen, width, height, Qnil);
10424
10425 x_wm_set_size_hint (f, 0, false);
10426
10427 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10428 width, height);
10429
10430 if (FRAME_VISIBLE_P (f))
10431 x_wait_for_event (f, ConfigureNotify);
10432 else
10433 {
10434 change_frame_size (f, width, height - FRAME_MENUBAR_HEIGHT (f),
10435 false, true, false, true);
10436 x_sync (f);
10437 }
10438 }
10439
10440 /* `x_net_wm_state' might have reset the fullscreen frame parameter,
10441 restore it. */
10442 store_frame_param (f, Qfullscreen, lval);
10443 }
10444
10445 /* This function is called by x_set_offset to determine whether the window
10446 manager interfered with the positioning of the frame. Type A window
10447 managers position the surrounding window manager decorations a small
10448 amount above and left of the user-supplied position. Type B window
10449 managers position the surrounding window manager decorations at the
10450 user-specified position. If we detect a Type A window manager, we
10451 compensate by moving the window right and down by the proper amount. */
10452
10453 static void
10454 x_check_expected_move (struct frame *f, int expected_left, int expected_top)
10455 {
10456 int current_left = 0, current_top = 0;
10457
10458 /* x_real_positions returns the left and top offsets of the outermost
10459 window manager window around the frame. */
10460
10461 x_real_positions (f, &current_left, &current_top);
10462
10463 if (current_left != expected_left || current_top != expected_top)
10464 {
10465 /* It's a "Type A" window manager. */
10466
10467 int adjusted_left;
10468 int adjusted_top;
10469
10470 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_A;
10471 FRAME_X_OUTPUT (f)->move_offset_left = expected_left - current_left;
10472 FRAME_X_OUTPUT (f)->move_offset_top = expected_top - current_top;
10473
10474 /* Now fix the mispositioned frame's location. */
10475
10476 adjusted_left = expected_left + FRAME_X_OUTPUT (f)->move_offset_left;
10477 adjusted_top = expected_top + FRAME_X_OUTPUT (f)->move_offset_top;
10478
10479 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10480 adjusted_left, adjusted_top);
10481
10482 x_sync_with_move (f, expected_left, expected_top, false);
10483 }
10484 else
10485 /* It's a "Type B" window manager. We don't have to adjust the
10486 frame's position. */
10487
10488 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_B;
10489 }
10490
10491
10492 /* Wait for XGetGeometry to return up-to-date position information for a
10493 recently-moved frame. Call this immediately after calling XMoveWindow.
10494 If FUZZY is non-zero, then LEFT and TOP are just estimates of where the
10495 frame has been moved to, so we use a fuzzy position comparison instead
10496 of an exact comparison. */
10497
10498 static void
10499 x_sync_with_move (struct frame *f, int left, int top, bool fuzzy)
10500 {
10501 int count = 0;
10502
10503 while (count++ < 50)
10504 {
10505 int current_left = 0, current_top = 0;
10506
10507 /* In theory, this call to XSync only needs to happen once, but in
10508 practice, it doesn't seem to work, hence the need for the surrounding
10509 loop. */
10510
10511 XSync (FRAME_X_DISPLAY (f), False);
10512 x_real_positions (f, &current_left, &current_top);
10513
10514 if (fuzzy)
10515 {
10516 /* The left fuzz-factor is 10 pixels. The top fuzz-factor is 40
10517 pixels. */
10518
10519 if (eabs (current_left - left) <= 10
10520 && eabs (current_top - top) <= 40)
10521 return;
10522 }
10523 else if (current_left == left && current_top == top)
10524 return;
10525 }
10526
10527 /* As a last resort, just wait 0.5 seconds and hope that XGetGeometry
10528 will then return up-to-date position info. */
10529
10530 wait_reading_process_output (0, 500000000, 0, false, Qnil, NULL, 0);
10531 }
10532
10533
10534 /* Wait for an event on frame F matching EVENTTYPE. */
10535 void
10536 x_wait_for_event (struct frame *f, int eventtype)
10537 {
10538 int level = interrupt_input_blocked;
10539
10540 fd_set fds;
10541 struct timespec tmo, tmo_at, time_now;
10542 int fd = ConnectionNumber (FRAME_X_DISPLAY (f));
10543
10544 f->wait_event_type = eventtype;
10545
10546 /* Set timeout to 0.1 second. Hopefully not noticeable.
10547 Maybe it should be configurable. */
10548 tmo = make_timespec (0, 100 * 1000 * 1000);
10549 tmo_at = timespec_add (current_timespec (), tmo);
10550
10551 while (f->wait_event_type)
10552 {
10553 pending_signals = true;
10554 totally_unblock_input ();
10555 /* XTread_socket is called after unblock. */
10556 block_input ();
10557 interrupt_input_blocked = level;
10558
10559 FD_ZERO (&fds);
10560 FD_SET (fd, &fds);
10561
10562 time_now = current_timespec ();
10563 if (timespec_cmp (tmo_at, time_now) < 0)
10564 break;
10565
10566 tmo = timespec_sub (tmo_at, time_now);
10567 if (pselect (fd + 1, &fds, NULL, NULL, &tmo, NULL) == 0)
10568 break; /* Timeout */
10569 }
10570
10571 f->wait_event_type = 0;
10572 }
10573
10574
10575 /* Change the size of frame F's X window to WIDTH/HEIGHT in the case F
10576 doesn't have a widget. If CHANGE_GRAVITY, change to
10577 top-left-corner window gravity for this size change and subsequent
10578 size changes. Otherwise leave the window gravity unchanged. */
10579
10580 static void
10581 x_set_window_size_1 (struct frame *f, bool change_gravity,
10582 int width, int height)
10583 {
10584 int pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
10585 int pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
10586 int old_width = FRAME_PIXEL_WIDTH (f);
10587 int old_height = FRAME_PIXEL_HEIGHT (f);
10588 Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
10589
10590 if (change_gravity) f->win_gravity = NorthWestGravity;
10591 x_wm_set_size_hint (f, 0, false);
10592
10593 /* When the frame is fullheight and we only want to change the width
10594 or it is fullwidth and we only want to change the height we should
10595 be able to preserve the fullscreen property. However, due to the
10596 fact that we have to send a resize request anyway, the window
10597 manager will abolish it. At least the respective size should
10598 remain unchanged but giving the frame back its normal size will
10599 be broken ... */
10600 if (EQ (fullscreen, Qfullwidth) && width == FRAME_TEXT_WIDTH (f))
10601 {
10602 frame_size_history_add
10603 (f, Qx_set_window_size_1, width, height,
10604 list2 (make_number (old_height),
10605 make_number (pixelheight + FRAME_MENUBAR_HEIGHT (f))));
10606
10607 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10608 old_width, pixelheight + FRAME_MENUBAR_HEIGHT (f));
10609 }
10610 else if (EQ (fullscreen, Qfullheight) && height == FRAME_TEXT_HEIGHT (f))
10611 {
10612 frame_size_history_add
10613 (f, Qx_set_window_size_2, width, height,
10614 list2 (make_number (old_width), make_number (pixelwidth)));
10615
10616 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10617 pixelwidth, old_height);
10618 }
10619
10620 else
10621 {
10622 frame_size_history_add
10623 (f, Qx_set_window_size_3, width, height,
10624 list3 (make_number (pixelwidth + FRAME_TOOLBAR_WIDTH (f)),
10625 make_number (pixelheight + FRAME_TOOLBAR_HEIGHT (f)
10626 + FRAME_MENUBAR_HEIGHT (f)),
10627 make_number (FRAME_MENUBAR_HEIGHT (f))));
10628
10629 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10630 pixelwidth, pixelheight + FRAME_MENUBAR_HEIGHT (f));
10631 fullscreen = Qnil;
10632 }
10633
10634
10635
10636 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
10637 receive in the ConfigureNotify event; if we get what we asked
10638 for, then the event won't cause the screen to become garbaged, so
10639 we have to make sure to do it here. */
10640 SET_FRAME_GARBAGED (f);
10641
10642 /* Now, strictly speaking, we can't be sure that this is accurate,
10643 but the window manager will get around to dealing with the size
10644 change request eventually, and we'll hear how it went when the
10645 ConfigureNotify event gets here.
10646
10647 We could just not bother storing any of this information here,
10648 and let the ConfigureNotify event set everything up, but that
10649 might be kind of confusing to the Lisp code, since size changes
10650 wouldn't be reported in the frame parameters until some random
10651 point in the future when the ConfigureNotify event arrives.
10652
10653 Pass true for DELAY since we can't run Lisp code inside of
10654 a BLOCK_INPUT. */
10655
10656 /* But the ConfigureNotify may in fact never arrive, and then this is
10657 not right if the frame is visible. Instead wait (with timeout)
10658 for the ConfigureNotify. */
10659 if (FRAME_VISIBLE_P (f))
10660 {
10661 x_wait_for_event (f, ConfigureNotify);
10662
10663 if (!NILP (fullscreen))
10664 /* Try to restore fullscreen state. */
10665 {
10666 store_frame_param (f, Qfullscreen, fullscreen);
10667 x_set_fullscreen (f, fullscreen, fullscreen);
10668 }
10669 }
10670 else
10671 {
10672 change_frame_size (f, width, height, false, true, false, true);
10673 x_sync (f);
10674 }
10675 }
10676
10677
10678 /* Call this to change the size of frame F's x-window.
10679 If CHANGE_GRAVITY, change to top-left-corner window gravity
10680 for this size change and subsequent size changes.
10681 Otherwise we leave the window gravity unchanged. */
10682
10683 void
10684 x_set_window_size (struct frame *f, bool change_gravity,
10685 int width, int height, bool pixelwise)
10686 {
10687 block_input ();
10688
10689 /* The following breaks our calculations. If it's really needed,
10690 think of something else. */
10691 #if false
10692 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
10693 {
10694 int text_width, text_height;
10695
10696 /* When the frame is maximized/fullscreen or running under for
10697 example Xmonad, x_set_window_size_1 will be a no-op.
10698 In that case, the right thing to do is extend rows/width to
10699 the current frame size. We do that first if x_set_window_size_1
10700 turns out to not be a no-op (there is no way to know).
10701 The size will be adjusted again if the frame gets a
10702 ConfigureNotify event as a result of x_set_window_size. */
10703 int pixelh = FRAME_PIXEL_HEIGHT (f);
10704 #ifdef USE_X_TOOLKIT
10705 /* The menu bar is not part of text lines. The tool bar
10706 is however. */
10707 pixelh -= FRAME_MENUBAR_HEIGHT (f);
10708 #endif
10709 text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, FRAME_PIXEL_WIDTH (f));
10710 text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelh);
10711
10712 change_frame_size (f, text_width, text_height, false, true, false, true);
10713 }
10714 #endif
10715
10716 /* Pixelize width and height, if necessary. */
10717 if (! pixelwise)
10718 {
10719 width = width * FRAME_COLUMN_WIDTH (f);
10720 height = height * FRAME_LINE_HEIGHT (f);
10721 }
10722
10723 #ifdef USE_GTK
10724 if (FRAME_GTK_WIDGET (f))
10725 xg_frame_set_char_size (f, width, height);
10726 else
10727 x_set_window_size_1 (f, change_gravity, width, height);
10728 #else /* not USE_GTK */
10729 x_set_window_size_1 (f, change_gravity, width, height);
10730 x_clear_under_internal_border (f);
10731 #endif /* not USE_GTK */
10732
10733 /* If cursor was outside the new size, mark it as off. */
10734 mark_window_cursors_off (XWINDOW (f->root_window));
10735
10736 /* Clear out any recollection of where the mouse highlighting was,
10737 since it might be in a place that's outside the new frame size.
10738 Actually checking whether it is outside is a pain in the neck,
10739 so don't try--just let the highlighting be done afresh with new size. */
10740 cancel_mouse_face (f);
10741
10742 unblock_input ();
10743
10744 do_pending_window_change (false);
10745 }
10746
10747 /* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
10748
10749 void
10750 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
10751 {
10752 block_input ();
10753
10754 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
10755 0, 0, 0, 0, pix_x, pix_y);
10756 unblock_input ();
10757 }
10758 \f
10759 /* Raise frame F. */
10760
10761 void
10762 x_raise_frame (struct frame *f)
10763 {
10764 block_input ();
10765 if (FRAME_VISIBLE_P (f))
10766 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
10767 XFlush (FRAME_X_DISPLAY (f));
10768 unblock_input ();
10769 }
10770
10771 /* Lower frame F. */
10772
10773 static void
10774 x_lower_frame (struct frame *f)
10775 {
10776 if (FRAME_VISIBLE_P (f))
10777 {
10778 block_input ();
10779 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
10780 XFlush (FRAME_X_DISPLAY (f));
10781 unblock_input ();
10782 }
10783 }
10784
10785 /* Request focus with XEmbed */
10786
10787 void
10788 xembed_request_focus (struct frame *f)
10789 {
10790 /* See XEmbed Protocol Specification at
10791 http://freedesktop.org/wiki/Specifications/xembed-spec */
10792 if (FRAME_VISIBLE_P (f))
10793 xembed_send_message (f, CurrentTime,
10794 XEMBED_REQUEST_FOCUS, 0, 0, 0);
10795 }
10796
10797 /* Activate frame with Extended Window Manager Hints */
10798
10799 void
10800 x_ewmh_activate_frame (struct frame *f)
10801 {
10802 /* See Window Manager Specification/Extended Window Manager Hints at
10803 http://freedesktop.org/wiki/Specifications/wm-spec */
10804
10805 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10806
10807 if (FRAME_VISIBLE_P (f) && x_wm_supports (f, dpyinfo->Xatom_net_active_window))
10808 {
10809 Lisp_Object frame;
10810 XSETFRAME (frame, f);
10811 x_send_client_event (frame, make_number (0), frame,
10812 dpyinfo->Xatom_net_active_window,
10813 make_number (32),
10814 list2i (1, dpyinfo->last_user_time));
10815 }
10816 }
10817
10818 static void
10819 XTframe_raise_lower (struct frame *f, bool raise_flag)
10820 {
10821 if (raise_flag)
10822 x_raise_frame (f);
10823 else
10824 x_lower_frame (f);
10825 }
10826 \f
10827 /* XEmbed implementation. */
10828
10829 #if defined USE_X_TOOLKIT || ! defined USE_GTK
10830
10831 /* XEmbed implementation. */
10832
10833 #define XEMBED_VERSION 0
10834
10835 static void
10836 xembed_set_info (struct frame *f, enum xembed_info flags)
10837 {
10838 unsigned long data[2];
10839 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10840
10841 data[0] = XEMBED_VERSION;
10842 data[1] = flags;
10843
10844 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10845 dpyinfo->Xatom_XEMBED_INFO, dpyinfo->Xatom_XEMBED_INFO,
10846 32, PropModeReplace, (unsigned char *) data, 2);
10847 }
10848 #endif /* defined USE_X_TOOLKIT || ! defined USE_GTK */
10849
10850 static void
10851 xembed_send_message (struct frame *f, Time t, enum xembed_message msg,
10852 long int detail, long int data1, long int data2)
10853 {
10854 XEvent event;
10855
10856 event.xclient.type = ClientMessage;
10857 event.xclient.window = FRAME_X_OUTPUT (f)->parent_desc;
10858 event.xclient.message_type = FRAME_DISPLAY_INFO (f)->Xatom_XEMBED;
10859 event.xclient.format = 32;
10860 event.xclient.data.l[0] = t;
10861 event.xclient.data.l[1] = msg;
10862 event.xclient.data.l[2] = detail;
10863 event.xclient.data.l[3] = data1;
10864 event.xclient.data.l[4] = data2;
10865
10866 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_OUTPUT (f)->parent_desc,
10867 False, NoEventMask, &event);
10868 XSync (FRAME_X_DISPLAY (f), False);
10869 }
10870 \f
10871 /* Change of visibility. */
10872
10873 /* This tries to wait until the frame is really visible.
10874 However, if the window manager asks the user where to position
10875 the frame, this will return before the user finishes doing that.
10876 The frame will not actually be visible at that time,
10877 but it will become visible later when the window manager
10878 finishes with it. */
10879
10880 void
10881 x_make_frame_visible (struct frame *f)
10882 {
10883 int original_top, original_left;
10884 int tries = 0;
10885
10886 block_input ();
10887
10888 x_set_bitmap_icon (f);
10889
10890 if (! FRAME_VISIBLE_P (f))
10891 {
10892 /* We test FRAME_GARBAGED_P here to make sure we don't
10893 call x_set_offset a second time
10894 if we get to x_make_frame_visible a second time
10895 before the window gets really visible. */
10896 if (! FRAME_ICONIFIED_P (f)
10897 && ! FRAME_X_EMBEDDED_P (f)
10898 && ! f->output_data.x->asked_for_visible)
10899 x_set_offset (f, f->left_pos, f->top_pos, 0);
10900
10901 f->output_data.x->asked_for_visible = true;
10902
10903 if (! EQ (Vx_no_window_manager, Qt))
10904 x_wm_set_window_state (f, NormalState);
10905 #ifdef USE_X_TOOLKIT
10906 if (FRAME_X_EMBEDDED_P (f))
10907 xembed_set_info (f, XEMBED_MAPPED);
10908 else
10909 {
10910 /* This was XtPopup, but that did nothing for an iconified frame. */
10911 XtMapWidget (f->output_data.x->widget);
10912 }
10913 #else /* not USE_X_TOOLKIT */
10914 #ifdef USE_GTK
10915 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
10916 gtk_window_deiconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
10917 #else
10918 if (FRAME_X_EMBEDDED_P (f))
10919 xembed_set_info (f, XEMBED_MAPPED);
10920 else
10921 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
10922 #endif /* not USE_GTK */
10923 #endif /* not USE_X_TOOLKIT */
10924 }
10925
10926 XFlush (FRAME_X_DISPLAY (f));
10927
10928 /* Synchronize to ensure Emacs knows the frame is visible
10929 before we do anything else. We do this loop with input not blocked
10930 so that incoming events are handled. */
10931 {
10932 Lisp_Object frame;
10933 /* This must be before UNBLOCK_INPUT
10934 since events that arrive in response to the actions above
10935 will set it when they are handled. */
10936 bool previously_visible = f->output_data.x->has_been_visible;
10937
10938 original_left = f->left_pos;
10939 original_top = f->top_pos;
10940
10941 /* This must come after we set COUNT. */
10942 unblock_input ();
10943
10944 /* We unblock here so that arriving X events are processed. */
10945
10946 /* Now move the window back to where it was "supposed to be".
10947 But don't do it if the gravity is negative.
10948 When the gravity is negative, this uses a position
10949 that is 3 pixels too low. Perhaps that's really the border width.
10950
10951 Don't do this if the window has never been visible before,
10952 because the window manager may choose the position
10953 and we don't want to override it. */
10954
10955 if (! FRAME_VISIBLE_P (f)
10956 && ! FRAME_ICONIFIED_P (f)
10957 && ! FRAME_X_EMBEDDED_P (f)
10958 && f->win_gravity == NorthWestGravity
10959 && previously_visible)
10960 {
10961 Drawable rootw;
10962 int x, y;
10963 unsigned int width, height, border, depth;
10964
10965 block_input ();
10966
10967 /* On some window managers (such as FVWM) moving an existing
10968 window, even to the same place, causes the window manager
10969 to introduce an offset. This can cause the window to move
10970 to an unexpected location. Check the geometry (a little
10971 slow here) and then verify that the window is in the right
10972 place. If the window is not in the right place, move it
10973 there, and take the potential window manager hit. */
10974 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10975 &rootw, &x, &y, &width, &height, &border, &depth);
10976
10977 if (original_left != x || original_top != y)
10978 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10979 original_left, original_top);
10980
10981 unblock_input ();
10982 }
10983
10984 XSETFRAME (frame, f);
10985
10986 /* Process X events until a MapNotify event has been seen. */
10987 while (!FRAME_VISIBLE_P (f))
10988 {
10989 /* Force processing of queued events. */
10990 x_sync (f);
10991
10992 /* If on another desktop, the deiconify/map may be ignored and the
10993 frame never becomes visible. XMonad does this.
10994 Prevent an endless loop. */
10995 if (FRAME_ICONIFIED_P (f) && ++tries > 100)
10996 break;
10997
10998 /* This hack is still in use at least for Cygwin. See
10999 http://lists.gnu.org/archive/html/emacs-devel/2013-12/msg00351.html.
11000
11001 Machines that do polling rather than SIGIO have been
11002 observed to go into a busy-wait here. So we'll fake an
11003 alarm signal to let the handler know that there's something
11004 to be read. We used to raise a real alarm, but it seems
11005 that the handler isn't always enabled here. This is
11006 probably a bug. */
11007 if (input_polling_used ())
11008 {
11009 /* It could be confusing if a real alarm arrives while
11010 processing the fake one. Turn it off and let the
11011 handler reset it. */
11012 int old_poll_suppress_count = poll_suppress_count;
11013 poll_suppress_count = 1;
11014 poll_for_input_1 ();
11015 poll_suppress_count = old_poll_suppress_count;
11016 }
11017
11018 if (XPending (FRAME_X_DISPLAY (f)))
11019 {
11020 XEvent xev;
11021 XNextEvent (FRAME_X_DISPLAY (f), &xev);
11022 x_dispatch_event (&xev, FRAME_X_DISPLAY (f));
11023 }
11024 }
11025 }
11026 }
11027
11028 /* Change from mapped state to withdrawn state. */
11029
11030 /* Make the frame visible (mapped and not iconified). */
11031
11032 void
11033 x_make_frame_invisible (struct frame *f)
11034 {
11035 Window window;
11036
11037 /* Use the frame's outermost window, not the one we normally draw on. */
11038 window = FRAME_OUTER_WINDOW (f);
11039
11040 /* Don't keep the highlight on an invisible frame. */
11041 if (FRAME_DISPLAY_INFO (f)->x_highlight_frame == f)
11042 FRAME_DISPLAY_INFO (f)->x_highlight_frame = 0;
11043
11044 block_input ();
11045
11046 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
11047 that the current position of the window is user-specified, rather than
11048 program-specified, so that when the window is mapped again, it will be
11049 placed at the same location, without forcing the user to position it
11050 by hand again (they have already done that once for this window.) */
11051 x_wm_set_size_hint (f, 0, true);
11052
11053 #ifdef USE_GTK
11054 if (FRAME_GTK_OUTER_WIDGET (f))
11055 gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f));
11056 else
11057 #else
11058 if (FRAME_X_EMBEDDED_P (f))
11059 xembed_set_info (f, 0);
11060 else
11061 #endif
11062 {
11063
11064 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
11065 DefaultScreen (FRAME_X_DISPLAY (f))))
11066 {
11067 unblock_input ();
11068 error ("Can't notify window manager of window withdrawal");
11069 }
11070 }
11071
11072 /* We can't distinguish this from iconification
11073 just by the event that we get from the server.
11074 So we can't win using the usual strategy of letting
11075 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
11076 and synchronize with the server to make sure we agree. */
11077 SET_FRAME_VISIBLE (f, 0);
11078 SET_FRAME_ICONIFIED (f, false);
11079
11080 x_sync (f);
11081
11082 unblock_input ();
11083 }
11084
11085 /* Change window state from mapped to iconified. */
11086
11087 void
11088 x_iconify_frame (struct frame *f)
11089 {
11090 #ifdef USE_X_TOOLKIT
11091 int result;
11092 #endif
11093
11094 /* Don't keep the highlight on an invisible frame. */
11095 if (FRAME_DISPLAY_INFO (f)->x_highlight_frame == f)
11096 FRAME_DISPLAY_INFO (f)->x_highlight_frame = 0;
11097
11098 if (FRAME_ICONIFIED_P (f))
11099 return;
11100
11101 block_input ();
11102
11103 x_set_bitmap_icon (f);
11104
11105 #if defined (USE_GTK)
11106 if (FRAME_GTK_OUTER_WIDGET (f))
11107 {
11108 if (! FRAME_VISIBLE_P (f))
11109 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
11110
11111 gtk_window_iconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
11112 SET_FRAME_VISIBLE (f, 0);
11113 SET_FRAME_ICONIFIED (f, true);
11114 unblock_input ();
11115 return;
11116 }
11117 #endif
11118
11119 #ifdef USE_X_TOOLKIT
11120
11121 if (! FRAME_VISIBLE_P (f))
11122 {
11123 if (! EQ (Vx_no_window_manager, Qt))
11124 x_wm_set_window_state (f, IconicState);
11125 /* This was XtPopup, but that did nothing for an iconified frame. */
11126 XtMapWidget (f->output_data.x->widget);
11127 /* The server won't give us any event to indicate
11128 that an invisible frame was changed to an icon,
11129 so we have to record it here. */
11130 SET_FRAME_VISIBLE (f, 0);
11131 SET_FRAME_ICONIFIED (f, true);
11132 unblock_input ();
11133 return;
11134 }
11135
11136 result = XIconifyWindow (FRAME_X_DISPLAY (f),
11137 XtWindow (f->output_data.x->widget),
11138 DefaultScreen (FRAME_X_DISPLAY (f)));
11139 unblock_input ();
11140
11141 if (!result)
11142 error ("Can't notify window manager of iconification");
11143
11144 SET_FRAME_ICONIFIED (f, true);
11145 SET_FRAME_VISIBLE (f, 0);
11146
11147 block_input ();
11148 XFlush (FRAME_X_DISPLAY (f));
11149 unblock_input ();
11150 #else /* not USE_X_TOOLKIT */
11151
11152 /* Make sure the X server knows where the window should be positioned,
11153 in case the user deiconifies with the window manager. */
11154 if (! FRAME_VISIBLE_P (f)
11155 && ! FRAME_ICONIFIED_P (f)
11156 && ! FRAME_X_EMBEDDED_P (f))
11157 x_set_offset (f, f->left_pos, f->top_pos, 0);
11158
11159 /* Since we don't know which revision of X we're running, we'll use both
11160 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
11161
11162 /* X11R4: send a ClientMessage to the window manager using the
11163 WM_CHANGE_STATE type. */
11164 {
11165 XEvent msg;
11166
11167 msg.xclient.window = FRAME_X_WINDOW (f);
11168 msg.xclient.type = ClientMessage;
11169 msg.xclient.message_type = FRAME_DISPLAY_INFO (f)->Xatom_wm_change_state;
11170 msg.xclient.format = 32;
11171 msg.xclient.data.l[0] = IconicState;
11172
11173 if (! XSendEvent (FRAME_X_DISPLAY (f),
11174 DefaultRootWindow (FRAME_X_DISPLAY (f)),
11175 False,
11176 SubstructureRedirectMask | SubstructureNotifyMask,
11177 &msg))
11178 {
11179 unblock_input ();
11180 error ("Can't notify window manager of iconification");
11181 }
11182 }
11183
11184 /* X11R3: set the initial_state field of the window manager hints to
11185 IconicState. */
11186 x_wm_set_window_state (f, IconicState);
11187
11188 if (!FRAME_VISIBLE_P (f))
11189 {
11190 /* If the frame was withdrawn, before, we must map it. */
11191 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11192 }
11193
11194 SET_FRAME_ICONIFIED (f, true);
11195 SET_FRAME_VISIBLE (f, 0);
11196
11197 XFlush (FRAME_X_DISPLAY (f));
11198 unblock_input ();
11199 #endif /* not USE_X_TOOLKIT */
11200 }
11201
11202 \f
11203 /* Free X resources of frame F. */
11204
11205 void
11206 x_free_frame_resources (struct frame *f)
11207 {
11208 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
11209 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
11210 #ifdef USE_X_TOOLKIT
11211 Lisp_Object bar;
11212 struct scroll_bar *b;
11213 #endif
11214
11215 block_input ();
11216
11217 /* If a display connection is dead, don't try sending more
11218 commands to the X server. */
11219 if (dpyinfo->display)
11220 {
11221 /* Always exit with visible pointer to avoid weird issue
11222 with Xfixes (Bug#17609). */
11223 if (f->pointer_invisible)
11224 FRAME_DISPLAY_INFO (f)->toggle_visible_pointer (f, 0);
11225
11226 /* We must free faces before destroying windows because some
11227 font-driver (e.g. xft) access a window while finishing a
11228 face. */
11229 free_frame_faces (f);
11230
11231 if (f->output_data.x->icon_desc)
11232 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
11233
11234 #ifdef USE_X_TOOLKIT
11235 /* Explicitly destroy the scroll bars of the frame. Without
11236 this, we get "BadDrawable" errors from the toolkit later on,
11237 presumably from expose events generated for the disappearing
11238 toolkit scroll bars. */
11239 for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
11240 {
11241 b = XSCROLL_BAR (bar);
11242 x_scroll_bar_remove (b);
11243 }
11244 #endif
11245
11246 #ifdef HAVE_X_I18N
11247 if (FRAME_XIC (f))
11248 free_frame_xic (f);
11249 #endif
11250
11251 x_free_cr_resources (f);
11252 #ifdef USE_X_TOOLKIT
11253 if (f->output_data.x->widget)
11254 {
11255 XtDestroyWidget (f->output_data.x->widget);
11256 f->output_data.x->widget = NULL;
11257 }
11258 /* Tooltips don't have widgets, only a simple X window, even if
11259 we are using a toolkit. */
11260 else if (FRAME_X_WINDOW (f))
11261 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11262
11263 free_frame_menubar (f);
11264
11265 if (f->shell_position)
11266 xfree (f->shell_position);
11267 #else /* !USE_X_TOOLKIT */
11268
11269 #ifdef USE_GTK
11270 xg_free_frame_widgets (f);
11271 #endif /* USE_GTK */
11272
11273 if (FRAME_X_WINDOW (f))
11274 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11275 #endif /* !USE_X_TOOLKIT */
11276
11277 unload_color (f, FRAME_FOREGROUND_PIXEL (f));
11278 unload_color (f, FRAME_BACKGROUND_PIXEL (f));
11279 unload_color (f, f->output_data.x->cursor_pixel);
11280 unload_color (f, f->output_data.x->cursor_foreground_pixel);
11281 unload_color (f, f->output_data.x->border_pixel);
11282 unload_color (f, f->output_data.x->mouse_pixel);
11283
11284 if (f->output_data.x->scroll_bar_background_pixel != -1)
11285 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
11286 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
11287 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
11288 #if defined (USE_LUCID) && defined (USE_TOOLKIT_SCROLL_BARS)
11289 /* Scrollbar shadow colors. */
11290 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
11291 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
11292 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
11293 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
11294 #endif /* USE_LUCID && USE_TOOLKIT_SCROLL_BARS */
11295 if (f->output_data.x->white_relief.pixel != -1)
11296 unload_color (f, f->output_data.x->white_relief.pixel);
11297 if (f->output_data.x->black_relief.pixel != -1)
11298 unload_color (f, f->output_data.x->black_relief.pixel);
11299
11300 x_free_gcs (f);
11301
11302 /* Free extra GCs allocated by x_setup_relief_colors. */
11303 if (f->output_data.x->white_relief.gc)
11304 {
11305 XFreeGC (dpyinfo->display, f->output_data.x->white_relief.gc);
11306 f->output_data.x->white_relief.gc = 0;
11307 }
11308 if (f->output_data.x->black_relief.gc)
11309 {
11310 XFreeGC (dpyinfo->display, f->output_data.x->black_relief.gc);
11311 f->output_data.x->black_relief.gc = 0;
11312 }
11313
11314 /* Free cursors. */
11315 if (f->output_data.x->text_cursor != 0)
11316 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->text_cursor);
11317 if (f->output_data.x->nontext_cursor != 0)
11318 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->nontext_cursor);
11319 if (f->output_data.x->modeline_cursor != 0)
11320 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->modeline_cursor);
11321 if (f->output_data.x->hand_cursor != 0)
11322 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->hand_cursor);
11323 if (f->output_data.x->hourglass_cursor != 0)
11324 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->hourglass_cursor);
11325 if (f->output_data.x->horizontal_drag_cursor != 0)
11326 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->horizontal_drag_cursor);
11327 if (f->output_data.x->vertical_drag_cursor != 0)
11328 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->vertical_drag_cursor);
11329
11330 XFlush (FRAME_X_DISPLAY (f));
11331 }
11332
11333 xfree (f->output_data.x->saved_menu_event);
11334 xfree (f->output_data.x);
11335 f->output_data.x = NULL;
11336
11337 if (f == dpyinfo->x_focus_frame)
11338 dpyinfo->x_focus_frame = 0;
11339 if (f == dpyinfo->x_focus_event_frame)
11340 dpyinfo->x_focus_event_frame = 0;
11341 if (f == dpyinfo->x_highlight_frame)
11342 dpyinfo->x_highlight_frame = 0;
11343 if (f == hlinfo->mouse_face_mouse_frame)
11344 reset_mouse_highlight (hlinfo);
11345
11346 unblock_input ();
11347 }
11348
11349
11350 /* Destroy the X window of frame F. */
11351
11352 static void
11353 x_destroy_window (struct frame *f)
11354 {
11355 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
11356
11357 /* If a display connection is dead, don't try sending more
11358 commands to the X server. */
11359 if (dpyinfo->display != 0)
11360 x_free_frame_resources (f);
11361
11362 dpyinfo->reference_count--;
11363 }
11364
11365 \f
11366 /* Setting window manager hints. */
11367
11368 /* Set the normal size hints for the window manager, for frame F.
11369 FLAGS is the flags word to use--or 0 meaning preserve the flags
11370 that the window now has.
11371 If USER_POSITION, set the USPosition
11372 flag (this is useful when FLAGS is 0).
11373 The GTK version is in gtkutils.c. */
11374
11375 #ifndef USE_GTK
11376 void
11377 x_wm_set_size_hint (struct frame *f, long flags, bool user_position)
11378 {
11379 XSizeHints size_hints;
11380 Window window = FRAME_OUTER_WINDOW (f);
11381
11382 if (!window)
11383 return;
11384
11385 #ifdef USE_X_TOOLKIT
11386 if (f->output_data.x->widget)
11387 {
11388 widget_update_wm_size_hints (f->output_data.x->widget);
11389 return;
11390 }
11391 #endif
11392
11393 /* Setting PMaxSize caused various problems. */
11394 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
11395
11396 size_hints.x = f->left_pos;
11397 size_hints.y = f->top_pos;
11398
11399 size_hints.width = FRAME_PIXEL_WIDTH (f);
11400 size_hints.height = FRAME_PIXEL_HEIGHT (f);
11401
11402 size_hints.width_inc = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
11403 size_hints.height_inc = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
11404
11405 size_hints.max_width = x_display_pixel_width (FRAME_DISPLAY_INFO (f))
11406 - FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
11407 size_hints.max_height = x_display_pixel_height (FRAME_DISPLAY_INFO (f))
11408 - FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
11409
11410 /* Calculate the base and minimum sizes. */
11411 {
11412 int base_width, base_height;
11413
11414 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
11415 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
11416
11417 /* The window manager uses the base width hints to calculate the
11418 current number of rows and columns in the frame while
11419 resizing; min_width and min_height aren't useful for this
11420 purpose, since they might not give the dimensions for a
11421 zero-row, zero-column frame. */
11422
11423 size_hints.flags |= PBaseSize;
11424 size_hints.base_width = base_width;
11425 size_hints.base_height = base_height + FRAME_MENUBAR_HEIGHT (f);
11426 size_hints.min_width = base_width;
11427 size_hints.min_height = base_height;
11428 }
11429
11430 /* If we don't need the old flags, we don't need the old hint at all. */
11431 if (flags)
11432 {
11433 size_hints.flags |= flags;
11434 goto no_read;
11435 }
11436
11437 {
11438 XSizeHints hints; /* Sometimes I hate X Windows... */
11439 long supplied_return;
11440 int value;
11441
11442 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
11443 &supplied_return);
11444
11445 if (flags)
11446 size_hints.flags |= flags;
11447 else
11448 {
11449 if (value == 0)
11450 hints.flags = 0;
11451 if (hints.flags & PSize)
11452 size_hints.flags |= PSize;
11453 if (hints.flags & PPosition)
11454 size_hints.flags |= PPosition;
11455 if (hints.flags & USPosition)
11456 size_hints.flags |= USPosition;
11457 if (hints.flags & USSize)
11458 size_hints.flags |= USSize;
11459 }
11460 }
11461
11462 no_read:
11463
11464 #ifdef PWinGravity
11465 size_hints.win_gravity = f->win_gravity;
11466 size_hints.flags |= PWinGravity;
11467
11468 if (user_position)
11469 {
11470 size_hints.flags &= ~ PPosition;
11471 size_hints.flags |= USPosition;
11472 }
11473 #endif /* PWinGravity */
11474
11475 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
11476 }
11477 #endif /* not USE_GTK */
11478
11479 /* Used for IconicState or NormalState */
11480
11481 static void
11482 x_wm_set_window_state (struct frame *f, int state)
11483 {
11484 #ifdef USE_X_TOOLKIT
11485 Arg al[1];
11486
11487 XtSetArg (al[0], XtNinitialState, state);
11488 XtSetValues (f->output_data.x->widget, al, 1);
11489 #else /* not USE_X_TOOLKIT */
11490 Window window = FRAME_X_WINDOW (f);
11491
11492 f->output_data.x->wm_hints.flags |= StateHint;
11493 f->output_data.x->wm_hints.initial_state = state;
11494
11495 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
11496 #endif /* not USE_X_TOOLKIT */
11497 }
11498
11499 static void
11500 x_wm_set_icon_pixmap (struct frame *f, ptrdiff_t pixmap_id)
11501 {
11502 Pixmap icon_pixmap, icon_mask;
11503
11504 #if !defined USE_X_TOOLKIT && !defined USE_GTK
11505 Window window = FRAME_OUTER_WINDOW (f);
11506 #endif
11507
11508 if (pixmap_id > 0)
11509 {
11510 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
11511 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
11512 icon_mask = x_bitmap_mask (f, pixmap_id);
11513 f->output_data.x->wm_hints.icon_mask = icon_mask;
11514 }
11515 else
11516 {
11517 /* It seems there is no way to turn off use of an icon
11518 pixmap. */
11519 return;
11520 }
11521
11522
11523 #ifdef USE_GTK
11524 {
11525 xg_set_frame_icon (f, icon_pixmap, icon_mask);
11526 return;
11527 }
11528
11529 #elif defined (USE_X_TOOLKIT) /* same as in x_wm_set_window_state. */
11530
11531 {
11532 Arg al[1];
11533 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
11534 XtSetValues (f->output_data.x->widget, al, 1);
11535 XtSetArg (al[0], XtNiconMask, icon_mask);
11536 XtSetValues (f->output_data.x->widget, al, 1);
11537 }
11538
11539 #else /* not USE_X_TOOLKIT && not USE_GTK */
11540
11541 f->output_data.x->wm_hints.flags |= (IconPixmapHint | IconMaskHint);
11542 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
11543
11544 #endif /* not USE_X_TOOLKIT && not USE_GTK */
11545 }
11546
11547 void
11548 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
11549 {
11550 Window window = FRAME_OUTER_WINDOW (f);
11551
11552 f->output_data.x->wm_hints.flags |= IconPositionHint;
11553 f->output_data.x->wm_hints.icon_x = icon_x;
11554 f->output_data.x->wm_hints.icon_y = icon_y;
11555
11556 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
11557 }
11558
11559 \f
11560 /***********************************************************************
11561 Fonts
11562 ***********************************************************************/
11563
11564 #ifdef GLYPH_DEBUG
11565
11566 /* Check that FONT is valid on frame F. It is if it can be found in F's
11567 font table. */
11568
11569 static void
11570 x_check_font (struct frame *f, struct font *font)
11571 {
11572 eassert (font != NULL && ! NILP (font->props[FONT_TYPE_INDEX]));
11573 if (font->driver->check)
11574 eassert (font->driver->check (f, font) == 0);
11575 }
11576
11577 #endif /* GLYPH_DEBUG */
11578
11579 \f
11580 /***********************************************************************
11581 Initialization
11582 ***********************************************************************/
11583
11584 #ifdef USE_X_TOOLKIT
11585 static XrmOptionDescRec emacs_options[] = {
11586 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
11587 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
11588
11589 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
11590 XrmoptionSepArg, NULL},
11591 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
11592
11593 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
11594 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
11595 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
11596 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
11597 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
11598 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
11599 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
11600 };
11601
11602 /* Whether atimer for Xt timeouts is activated or not. */
11603
11604 static bool x_timeout_atimer_activated_flag;
11605
11606 #endif /* USE_X_TOOLKIT */
11607
11608 static int x_initialized;
11609
11610 /* Test whether two display-name strings agree up to the dot that separates
11611 the screen number from the server number. */
11612 static bool
11613 same_x_server (const char *name1, const char *name2)
11614 {
11615 bool seen_colon = false;
11616 Lisp_Object sysname = Fsystem_name ();
11617 const char *system_name = SSDATA (sysname);
11618 ptrdiff_t system_name_length = SBYTES (sysname);
11619 ptrdiff_t length_until_period = 0;
11620
11621 while (system_name[length_until_period] != 0
11622 && system_name[length_until_period] != '.')
11623 length_until_period++;
11624
11625 /* Treat `unix' like an empty host name. */
11626 if (! strncmp (name1, "unix:", 5))
11627 name1 += 4;
11628 if (! strncmp (name2, "unix:", 5))
11629 name2 += 4;
11630 /* Treat this host's name like an empty host name. */
11631 if (! strncmp (name1, system_name, system_name_length)
11632 && name1[system_name_length] == ':')
11633 name1 += system_name_length;
11634 if (! strncmp (name2, system_name, system_name_length)
11635 && name2[system_name_length] == ':')
11636 name2 += system_name_length;
11637 /* Treat this host's domainless name like an empty host name. */
11638 if (! strncmp (name1, system_name, length_until_period)
11639 && name1[length_until_period] == ':')
11640 name1 += length_until_period;
11641 if (! strncmp (name2, system_name, length_until_period)
11642 && name2[length_until_period] == ':')
11643 name2 += length_until_period;
11644
11645 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
11646 {
11647 if (*name1 == ':')
11648 seen_colon = true;
11649 if (seen_colon && *name1 == '.')
11650 return true;
11651 }
11652 return (seen_colon
11653 && (*name1 == '.' || *name1 == '\0')
11654 && (*name2 == '.' || *name2 == '\0'));
11655 }
11656
11657 /* Count number of set bits in mask and number of bits to shift to
11658 get to the first bit. With MASK 0x7e0, *BITS is set to 6, and *OFFSET
11659 to 5. */
11660 static void
11661 get_bits_and_offset (unsigned long mask, int *bits, int *offset)
11662 {
11663 int nr = 0;
11664 int off = 0;
11665
11666 while (!(mask & 1))
11667 {
11668 off++;
11669 mask >>= 1;
11670 }
11671
11672 while (mask & 1)
11673 {
11674 nr++;
11675 mask >>= 1;
11676 }
11677
11678 *offset = off;
11679 *bits = nr;
11680 }
11681
11682 /* Return true iff display DISPLAY is available for use.
11683 But don't permanently open it, just test its availability. */
11684
11685 bool
11686 x_display_ok (const char *display)
11687 {
11688 /* XOpenDisplay fails if it gets a signal. Block SIGIO which may arrive. */
11689 unrequest_sigio ();
11690 Display *dpy = XOpenDisplay (display);
11691 request_sigio ();
11692 if (!dpy)
11693 return false;
11694 XCloseDisplay (dpy);
11695 return true;
11696 }
11697
11698 #ifdef USE_GTK
11699 static void
11700 my_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
11701 const gchar *msg, gpointer user_data)
11702 {
11703 if (!strstr (msg, "g_set_prgname"))
11704 fprintf (stderr, "%s-WARNING **: %s\n", log_domain, msg);
11705 }
11706 #endif
11707
11708 /* Create invisible cursor on X display referred by DPYINFO. */
11709
11710 static Cursor
11711 make_invisible_cursor (struct x_display_info *dpyinfo)
11712 {
11713 Display *dpy = dpyinfo->display;
11714 static char const no_data[] = { 0 };
11715 Pixmap pix;
11716 XColor col;
11717 Cursor c = 0;
11718
11719 x_catch_errors (dpy);
11720 pix = XCreateBitmapFromData (dpy, dpyinfo->root_window, no_data, 1, 1);
11721 if (! x_had_errors_p (dpy) && pix != None)
11722 {
11723 Cursor pixc;
11724 col.pixel = 0;
11725 col.red = col.green = col.blue = 0;
11726 col.flags = DoRed | DoGreen | DoBlue;
11727 pixc = XCreatePixmapCursor (dpy, pix, pix, &col, &col, 0, 0);
11728 if (! x_had_errors_p (dpy) && pixc != None)
11729 c = pixc;
11730 XFreePixmap (dpy, pix);
11731 }
11732
11733 x_uncatch_errors ();
11734
11735 return c;
11736 }
11737
11738 /* True if DPY supports Xfixes extension >= 4. */
11739
11740 static bool
11741 x_probe_xfixes_extension (Display *dpy)
11742 {
11743 #ifdef HAVE_XFIXES
11744 int major, minor;
11745 return XFixesQueryVersion (dpy, &major, &minor) && major >= 4;
11746 #else
11747 return false;
11748 #endif /* HAVE_XFIXES */
11749 }
11750
11751 /* Toggle mouse pointer visibility on frame F by using Xfixes functions. */
11752
11753 static void
11754 xfixes_toggle_visible_pointer (struct frame *f, bool invisible)
11755 {
11756 #ifdef HAVE_XFIXES
11757 if (invisible)
11758 XFixesHideCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11759 else
11760 XFixesShowCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11761 f->pointer_invisible = invisible;
11762 #else
11763 emacs_abort ();
11764 #endif /* HAVE_XFIXES */
11765 }
11766
11767 /* Toggle mouse pointer visibility on frame F by using invisible cursor. */
11768
11769 static void
11770 x_toggle_visible_pointer (struct frame *f, bool invisible)
11771 {
11772 eassert (FRAME_DISPLAY_INFO (f)->invisible_cursor != 0);
11773 if (invisible)
11774 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11775 FRAME_DISPLAY_INFO (f)->invisible_cursor);
11776 else
11777 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11778 f->output_data.x->current_cursor);
11779 f->pointer_invisible = invisible;
11780 }
11781
11782 /* Setup pointer blanking, prefer Xfixes if available. */
11783
11784 static void
11785 x_setup_pointer_blanking (struct x_display_info *dpyinfo)
11786 {
11787 /* FIXME: the brave tester should set EMACS_XFIXES because we're suspecting
11788 X server bug, see http://debbugs.gnu.org/cgi/bugreport.cgi?bug=17609. */
11789 if (egetenv ("EMACS_XFIXES") && x_probe_xfixes_extension (dpyinfo->display))
11790 dpyinfo->toggle_visible_pointer = xfixes_toggle_visible_pointer;
11791 else
11792 {
11793 dpyinfo->toggle_visible_pointer = x_toggle_visible_pointer;
11794 dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo);
11795 }
11796 }
11797
11798 /* Current X display connection identifier. Incremented for each next
11799 connection established. */
11800 static unsigned x_display_id;
11801
11802 /* Open a connection to X display DISPLAY_NAME, and return
11803 the structure that describes the open display.
11804 If we cannot contact the display, return null. */
11805
11806 struct x_display_info *
11807 x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
11808 {
11809 Display *dpy;
11810 struct terminal *terminal;
11811 struct x_display_info *dpyinfo;
11812 XrmDatabase xrdb;
11813 #ifdef USE_XCB
11814 xcb_connection_t *xcb_conn;
11815 #endif
11816
11817 block_input ();
11818
11819 if (!x_initialized)
11820 {
11821 x_initialize ();
11822 ++x_initialized;
11823 }
11824
11825 if (! x_display_ok (SSDATA (display_name)))
11826 error ("Display %s can't be opened", SSDATA (display_name));
11827
11828 #ifdef USE_GTK
11829 {
11830 #define NUM_ARGV 10
11831 int argc;
11832 char *argv[NUM_ARGV];
11833 char **argv2 = argv;
11834 guint id;
11835
11836 if (x_initialized++ > 1)
11837 {
11838 xg_display_open (SSDATA (display_name), &dpy);
11839 }
11840 else
11841 {
11842 static char display_opt[] = "--display";
11843 static char name_opt[] = "--name";
11844
11845 for (argc = 0; argc < NUM_ARGV; ++argc)
11846 argv[argc] = 0;
11847
11848 argc = 0;
11849 argv[argc++] = initial_argv[0];
11850
11851 if (! NILP (display_name))
11852 {
11853 argv[argc++] = display_opt;
11854 argv[argc++] = SSDATA (display_name);
11855 }
11856
11857 argv[argc++] = name_opt;
11858 argv[argc++] = resource_name;
11859
11860 XSetLocaleModifiers ("");
11861
11862 /* Work around GLib bug that outputs a faulty warning. See
11863 https://bugzilla.gnome.org/show_bug.cgi?id=563627. */
11864 id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
11865 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
11866
11867 /* NULL window -> events for all windows go to our function.
11868 Call before gtk_init so Gtk+ event filters comes after our. */
11869 gdk_window_add_filter (NULL, event_handler_gdk, NULL);
11870
11871 /* gtk_init does set_locale. Fix locale before and after. */
11872 fixup_locale ();
11873 unrequest_sigio (); /* See comment in x_display_ok. */
11874 gtk_init (&argc, &argv2);
11875 request_sigio ();
11876 fixup_locale ();
11877
11878 g_log_remove_handler ("GLib", id);
11879
11880 xg_initialize ();
11881
11882 dpy = DEFAULT_GDK_DISPLAY ();
11883
11884 #if ! GTK_CHECK_VERSION (2, 90, 0)
11885 /* Load our own gtkrc if it exists. */
11886 {
11887 const char *file = "~/.emacs.d/gtkrc";
11888 Lisp_Object s, abs_file;
11889
11890 s = build_string (file);
11891 abs_file = Fexpand_file_name (s, Qnil);
11892
11893 if (! NILP (abs_file) && !NILP (Ffile_readable_p (abs_file)))
11894 gtk_rc_parse (SSDATA (abs_file));
11895 }
11896 #endif
11897
11898 XSetErrorHandler (x_error_handler);
11899 XSetIOErrorHandler (x_io_error_quitter);
11900 }
11901 }
11902 #else /* not USE_GTK */
11903 #ifdef USE_X_TOOLKIT
11904 /* weiner@footloose.sps.mot.com reports that this causes
11905 errors with X11R5:
11906 X protocol error: BadAtom (invalid Atom parameter)
11907 on protocol request 18skiloaf.
11908 So let's not use it until R6. */
11909 #ifdef HAVE_X11XTR6
11910 XtSetLanguageProc (NULL, NULL, NULL);
11911 #endif
11912
11913 {
11914 int argc = 0;
11915 char *argv[3];
11916
11917 argv[0] = "";
11918 argc = 1;
11919 if (xrm_option)
11920 {
11921 argv[argc++] = "-xrm";
11922 argv[argc++] = xrm_option;
11923 }
11924 turn_on_atimers (false);
11925 unrequest_sigio (); /* See comment in x_display_ok. */
11926 dpy = XtOpenDisplay (Xt_app_con, SSDATA (display_name),
11927 resource_name, EMACS_CLASS,
11928 emacs_options, XtNumber (emacs_options),
11929 &argc, argv);
11930 request_sigio ();
11931 turn_on_atimers (true);
11932
11933 #ifdef HAVE_X11XTR6
11934 /* I think this is to compensate for XtSetLanguageProc. */
11935 fixup_locale ();
11936 #endif
11937 }
11938
11939 #else /* not USE_X_TOOLKIT */
11940 XSetLocaleModifiers ("");
11941 unrequest_sigio (); // See comment in x_display_ok.
11942 dpy = XOpenDisplay (SSDATA (display_name));
11943 request_sigio ();
11944 #endif /* not USE_X_TOOLKIT */
11945 #endif /* not USE_GTK*/
11946
11947 /* Detect failure. */
11948 if (dpy == 0)
11949 {
11950 unblock_input ();
11951 return 0;
11952 }
11953
11954 #ifdef USE_XCB
11955 xcb_conn = XGetXCBConnection (dpy);
11956 if (xcb_conn == 0)
11957 {
11958 #ifdef USE_GTK
11959 xg_display_close (dpy);
11960 #else
11961 #ifdef USE_X_TOOLKIT
11962 XtCloseDisplay (dpy);
11963 #else
11964 XCloseDisplay (dpy);
11965 #endif
11966 #endif /* ! USE_GTK */
11967
11968 unblock_input ();
11969 return 0;
11970 }
11971 #endif
11972
11973 /* We have definitely succeeded. Record the new connection. */
11974
11975 dpyinfo = xzalloc (sizeof *dpyinfo);
11976 terminal = x_create_terminal (dpyinfo);
11977
11978 {
11979 struct x_display_info *share;
11980
11981 for (share = x_display_list; share; share = share->next)
11982 if (same_x_server (SSDATA (XCAR (share->name_list_element)),
11983 SSDATA (display_name)))
11984 break;
11985 if (share)
11986 terminal->kboard = share->terminal->kboard;
11987 else
11988 {
11989 terminal->kboard = allocate_kboard (Qx);
11990
11991 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
11992 {
11993 char *vendor = ServerVendor (dpy);
11994
11995 /* Temporarily hide the partially initialized terminal. */
11996 terminal_list = terminal->next_terminal;
11997 unblock_input ();
11998 kset_system_key_alist
11999 (terminal->kboard,
12000 call1 (Qvendor_specific_keysyms,
12001 vendor ? build_string (vendor) : empty_unibyte_string));
12002 block_input ();
12003 terminal->next_terminal = terminal_list;
12004 terminal_list = terminal;
12005 }
12006
12007 /* Don't let the initial kboard remain current longer than necessary.
12008 That would cause problems if a file loaded on startup tries to
12009 prompt in the mini-buffer. */
12010 if (current_kboard == initial_kboard)
12011 current_kboard = terminal->kboard;
12012 }
12013 terminal->kboard->reference_count++;
12014 }
12015
12016 /* Put this display on the chain. */
12017 dpyinfo->next = x_display_list;
12018 x_display_list = dpyinfo;
12019
12020 dpyinfo->name_list_element = Fcons (display_name, Qnil);
12021 dpyinfo->display = dpy;
12022 dpyinfo->connection = ConnectionNumber (dpyinfo->display);
12023 #ifdef USE_XCB
12024 dpyinfo->xcb_connection = xcb_conn;
12025 #endif
12026
12027 /* http://lists.gnu.org/archive/html/emacs-devel/2015-11/msg00194.html */
12028 dpyinfo->smallest_font_height = 1;
12029 dpyinfo->smallest_char_width = 1;
12030
12031 /* Set the name of the terminal. */
12032 terminal->name = xlispstrdup (display_name);
12033
12034 #if false
12035 XSetAfterFunction (x_current_display, x_trace_wire);
12036 #endif
12037
12038 Lisp_Object system_name = Fsystem_name ();
12039 ptrdiff_t nbytes;
12040 if (INT_ADD_WRAPV (SBYTES (Vinvocation_name), SBYTES (system_name) + 2,
12041 &nbytes))
12042 memory_full (SIZE_MAX);
12043 dpyinfo->x_id = ++x_display_id;
12044 dpyinfo->x_id_name = xmalloc (nbytes);
12045 char *nametail = lispstpcpy (dpyinfo->x_id_name, Vinvocation_name);
12046 *nametail++ = '@';
12047 lispstpcpy (nametail, system_name);
12048
12049 /* Figure out which modifier bits mean what. */
12050 x_find_modifier_meanings (dpyinfo);
12051
12052 /* Get the scroll bar cursor. */
12053 #ifdef USE_GTK
12054 /* We must create a GTK cursor, it is required for GTK widgets. */
12055 dpyinfo->xg_cursor = xg_create_default_cursor (dpyinfo->display);
12056 #endif /* USE_GTK */
12057
12058 dpyinfo->vertical_scroll_bar_cursor
12059 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
12060
12061 dpyinfo->horizontal_scroll_bar_cursor
12062 = XCreateFontCursor (dpyinfo->display, XC_sb_h_double_arrow);
12063
12064 xrdb = x_load_resources (dpyinfo->display, xrm_option,
12065 resource_name, EMACS_CLASS);
12066 #ifdef HAVE_XRMSETDATABASE
12067 XrmSetDatabase (dpyinfo->display, xrdb);
12068 #else
12069 dpyinfo->display->db = xrdb;
12070 #endif
12071 /* Put the rdb where we can find it in a way that works on
12072 all versions. */
12073 dpyinfo->xrdb = xrdb;
12074
12075 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
12076 DefaultScreen (dpyinfo->display));
12077 select_visual (dpyinfo);
12078 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
12079 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
12080 dpyinfo->icon_bitmap_id = -1;
12081 dpyinfo->wm_type = X_WMTYPE_UNKNOWN;
12082
12083 reset_mouse_highlight (&dpyinfo->mouse_highlight);
12084
12085 /* See if we can construct pixel values from RGB values. */
12086 if (dpyinfo->visual->class == TrueColor)
12087 {
12088 get_bits_and_offset (dpyinfo->visual->red_mask,
12089 &dpyinfo->red_bits, &dpyinfo->red_offset);
12090 get_bits_and_offset (dpyinfo->visual->blue_mask,
12091 &dpyinfo->blue_bits, &dpyinfo->blue_offset);
12092 get_bits_and_offset (dpyinfo->visual->green_mask,
12093 &dpyinfo->green_bits, &dpyinfo->green_offset);
12094 }
12095
12096 /* See if a private colormap is requested. */
12097 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
12098 {
12099 if (dpyinfo->visual->class == PseudoColor)
12100 {
12101 AUTO_STRING (privateColormap, "privateColormap");
12102 AUTO_STRING (PrivateColormap, "PrivateColormap");
12103 Lisp_Object value
12104 = display_x_get_resource (dpyinfo, privateColormap,
12105 PrivateColormap, Qnil, Qnil);
12106 if (STRINGP (value)
12107 && (!strcmp (SSDATA (value), "true")
12108 || !strcmp (SSDATA (value), "on")))
12109 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
12110 }
12111 }
12112 else
12113 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
12114 dpyinfo->visual, AllocNone);
12115
12116 #ifdef HAVE_XFT
12117 {
12118 /* If we are using Xft, the following precautions should be made:
12119
12120 1. Make sure that the Xrender extension is added before the Xft one.
12121 Otherwise, the close-display hook set by Xft is called after the one
12122 for Xrender, and the former tries to re-add the latter. This results
12123 in inconsistency of internal states and leads to X protocol error when
12124 one reconnects to the same X server (Bug#1696).
12125
12126 2. Check dpi value in X resources. It is better we use it as well,
12127 since Xft will use it, as will all Gnome applications. If our real DPI
12128 is smaller or larger than the one Xft uses, our font will look smaller
12129 or larger than other for other applications, even if it is the same
12130 font name (monospace-10 for example). */
12131
12132 int event_base, error_base;
12133 char *v;
12134 double d;
12135
12136 XRenderQueryExtension (dpyinfo->display, &event_base, &error_base);
12137
12138 v = XGetDefault (dpyinfo->display, "Xft", "dpi");
12139 if (v != NULL && sscanf (v, "%lf", &d) == 1)
12140 dpyinfo->resy = dpyinfo->resx = d;
12141 }
12142 #endif
12143
12144 if (dpyinfo->resy < 1)
12145 {
12146 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
12147 double pixels = DisplayHeight (dpyinfo->display, screen_number);
12148 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
12149 /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
12150 dpyinfo->resy = (mm < 1) ? 100 : pixels * 25.4 / mm;
12151 pixels = DisplayWidth (dpyinfo->display, screen_number);
12152 mm = DisplayWidthMM (dpyinfo->display, screen_number);
12153 /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
12154 dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm;
12155 }
12156
12157 {
12158 static const struct
12159 {
12160 const char *name;
12161 int offset;
12162 } atom_refs[] = {
12163 #define ATOM_REFS_INIT(string, member) \
12164 { string, offsetof (struct x_display_info, member) },
12165 ATOM_REFS_INIT ("WM_PROTOCOLS", Xatom_wm_protocols)
12166 ATOM_REFS_INIT ("WM_TAKE_FOCUS", Xatom_wm_take_focus)
12167 ATOM_REFS_INIT ("WM_SAVE_YOURSELF", Xatom_wm_save_yourself)
12168 ATOM_REFS_INIT ("WM_DELETE_WINDOW", Xatom_wm_delete_window)
12169 ATOM_REFS_INIT ("WM_CHANGE_STATE", Xatom_wm_change_state)
12170 ATOM_REFS_INIT ("WM_CONFIGURE_DENIED", Xatom_wm_configure_denied)
12171 ATOM_REFS_INIT ("WM_MOVED", Xatom_wm_window_moved)
12172 ATOM_REFS_INIT ("WM_CLIENT_LEADER", Xatom_wm_client_leader)
12173 ATOM_REFS_INIT ("Editres", Xatom_editres)
12174 ATOM_REFS_INIT ("CLIPBOARD", Xatom_CLIPBOARD)
12175 ATOM_REFS_INIT ("TIMESTAMP", Xatom_TIMESTAMP)
12176 ATOM_REFS_INIT ("TEXT", Xatom_TEXT)
12177 ATOM_REFS_INIT ("COMPOUND_TEXT", Xatom_COMPOUND_TEXT)
12178 ATOM_REFS_INIT ("UTF8_STRING", Xatom_UTF8_STRING)
12179 ATOM_REFS_INIT ("DELETE", Xatom_DELETE)
12180 ATOM_REFS_INIT ("MULTIPLE", Xatom_MULTIPLE)
12181 ATOM_REFS_INIT ("INCR", Xatom_INCR)
12182 ATOM_REFS_INIT ("_EMACS_TMP_", Xatom_EMACS_TMP)
12183 ATOM_REFS_INIT ("TARGETS", Xatom_TARGETS)
12184 ATOM_REFS_INIT ("NULL", Xatom_NULL)
12185 ATOM_REFS_INIT ("ATOM", Xatom_ATOM)
12186 ATOM_REFS_INIT ("ATOM_PAIR", Xatom_ATOM_PAIR)
12187 ATOM_REFS_INIT ("CLIPBOARD_MANAGER", Xatom_CLIPBOARD_MANAGER)
12188 ATOM_REFS_INIT ("_XEMBED_INFO", Xatom_XEMBED_INFO)
12189 /* For properties of font. */
12190 ATOM_REFS_INIT ("PIXEL_SIZE", Xatom_PIXEL_SIZE)
12191 ATOM_REFS_INIT ("AVERAGE_WIDTH", Xatom_AVERAGE_WIDTH)
12192 ATOM_REFS_INIT ("_MULE_BASELINE_OFFSET", Xatom_MULE_BASELINE_OFFSET)
12193 ATOM_REFS_INIT ("_MULE_RELATIVE_COMPOSE", Xatom_MULE_RELATIVE_COMPOSE)
12194 ATOM_REFS_INIT ("_MULE_DEFAULT_ASCENT", Xatom_MULE_DEFAULT_ASCENT)
12195 /* Ghostscript support. */
12196 ATOM_REFS_INIT ("DONE", Xatom_DONE)
12197 ATOM_REFS_INIT ("PAGE", Xatom_PAGE)
12198 ATOM_REFS_INIT ("SCROLLBAR", Xatom_Scrollbar)
12199 ATOM_REFS_INIT ("HORIZONTAL_SCROLLBAR", Xatom_Horizontal_Scrollbar)
12200 ATOM_REFS_INIT ("_XEMBED", Xatom_XEMBED)
12201 /* EWMH */
12202 ATOM_REFS_INIT ("_NET_WM_STATE", Xatom_net_wm_state)
12203 ATOM_REFS_INIT ("_NET_WM_STATE_FULLSCREEN", Xatom_net_wm_state_fullscreen)
12204 ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_HORZ",
12205 Xatom_net_wm_state_maximized_horz)
12206 ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_VERT",
12207 Xatom_net_wm_state_maximized_vert)
12208 ATOM_REFS_INIT ("_NET_WM_STATE_STICKY", Xatom_net_wm_state_sticky)
12209 ATOM_REFS_INIT ("_NET_WM_STATE_HIDDEN", Xatom_net_wm_state_hidden)
12210 ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE", Xatom_net_window_type)
12211 ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE_TOOLTIP",
12212 Xatom_net_window_type_tooltip)
12213 ATOM_REFS_INIT ("_NET_WM_ICON_NAME", Xatom_net_wm_icon_name)
12214 ATOM_REFS_INIT ("_NET_WM_NAME", Xatom_net_wm_name)
12215 ATOM_REFS_INIT ("_NET_SUPPORTED", Xatom_net_supported)
12216 ATOM_REFS_INIT ("_NET_SUPPORTING_WM_CHECK", Xatom_net_supporting_wm_check)
12217 ATOM_REFS_INIT ("_NET_WM_WINDOW_OPACITY", Xatom_net_wm_window_opacity)
12218 ATOM_REFS_INIT ("_NET_ACTIVE_WINDOW", Xatom_net_active_window)
12219 ATOM_REFS_INIT ("_NET_FRAME_EXTENTS", Xatom_net_frame_extents)
12220 ATOM_REFS_INIT ("_NET_CURRENT_DESKTOP", Xatom_net_current_desktop)
12221 ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea)
12222 /* Session management */
12223 ATOM_REFS_INIT ("SM_CLIENT_ID", Xatom_SM_CLIENT_ID)
12224 ATOM_REFS_INIT ("_XSETTINGS_SETTINGS", Xatom_xsettings_prop)
12225 ATOM_REFS_INIT ("MANAGER", Xatom_xsettings_mgr)
12226 };
12227
12228 int i;
12229 enum { atom_count = ARRAYELTS (atom_refs) };
12230 /* 1 for _XSETTINGS_SN. */
12231 enum { total_atom_count = 1 + atom_count };
12232 Atom atoms_return[total_atom_count];
12233 char *atom_names[total_atom_count];
12234 static char const xsettings_fmt[] = "_XSETTINGS_S%d";
12235 char xsettings_atom_name[sizeof xsettings_fmt - 2
12236 + INT_STRLEN_BOUND (int)];
12237
12238 for (i = 0; i < atom_count; i++)
12239 atom_names[i] = (char *) atom_refs[i].name;
12240
12241 /* Build _XSETTINGS_SN atom name. */
12242 sprintf (xsettings_atom_name, xsettings_fmt,
12243 XScreenNumberOfScreen (dpyinfo->screen));
12244 atom_names[i] = xsettings_atom_name;
12245
12246 XInternAtoms (dpyinfo->display, atom_names, total_atom_count,
12247 False, atoms_return);
12248
12249 for (i = 0; i < atom_count; i++)
12250 *(Atom *) ((char *) dpyinfo + atom_refs[i].offset) = atoms_return[i];
12251
12252 /* Manually copy last atom. */
12253 dpyinfo->Xatom_xsettings_sel = atoms_return[i];
12254 }
12255
12256 dpyinfo->x_dnd_atoms_size = 8;
12257 dpyinfo->x_dnd_atoms = xmalloc (sizeof *dpyinfo->x_dnd_atoms
12258 * dpyinfo->x_dnd_atoms_size);
12259 dpyinfo->gray
12260 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
12261 gray_bits, gray_width, gray_height,
12262 1, 0, 1);
12263
12264 x_setup_pointer_blanking (dpyinfo);
12265
12266 #ifdef HAVE_X_I18N
12267 xim_initialize (dpyinfo, resource_name);
12268 #endif
12269
12270 xsettings_initialize (dpyinfo);
12271
12272 /* This is only needed for distinguishing keyboard and process input. */
12273 if (dpyinfo->connection != 0)
12274 add_keyboard_wait_descriptor (dpyinfo->connection);
12275
12276 #ifdef F_SETOWN
12277 fcntl (dpyinfo->connection, F_SETOWN, getpid ());
12278 #endif /* ! defined (F_SETOWN) */
12279
12280 if (interrupt_input)
12281 init_sigio (dpyinfo->connection);
12282
12283 #ifdef USE_LUCID
12284 {
12285 XrmValue d, fr, to;
12286 Font font;
12287
12288 dpy = dpyinfo->display;
12289 d.addr = (XPointer)&dpy;
12290 d.size = sizeof (Display *);
12291 fr.addr = XtDefaultFont;
12292 fr.size = sizeof (XtDefaultFont);
12293 to.size = sizeof (Font *);
12294 to.addr = (XPointer)&font;
12295 x_catch_errors (dpy);
12296 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
12297 emacs_abort ();
12298 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
12299 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
12300 /* Do not free XFontStruct returned by the above call to XQueryFont.
12301 This leads to X protocol errors at XtCloseDisplay (Bug#18403). */
12302 x_uncatch_errors ();
12303 }
12304 #endif
12305
12306 /* See if we should run in synchronous mode. This is useful
12307 for debugging X code. */
12308 {
12309 AUTO_STRING (synchronous, "synchronous");
12310 AUTO_STRING (Synchronous, "Synchronous");
12311 Lisp_Object value = display_x_get_resource (dpyinfo, synchronous,
12312 Synchronous, Qnil, Qnil);
12313 if (STRINGP (value)
12314 && (!strcmp (SSDATA (value), "true")
12315 || !strcmp (SSDATA (value), "on")))
12316 XSynchronize (dpyinfo->display, True);
12317 }
12318
12319 {
12320 AUTO_STRING (useXIM, "useXIM");
12321 AUTO_STRING (UseXIM, "UseXIM");
12322 Lisp_Object value = display_x_get_resource (dpyinfo, useXIM, UseXIM,
12323 Qnil, Qnil);
12324 #ifdef USE_XIM
12325 if (STRINGP (value)
12326 && (!strcmp (SSDATA (value), "false")
12327 || !strcmp (SSDATA (value), "off")))
12328 use_xim = false;
12329 #else
12330 if (STRINGP (value)
12331 && (!strcmp (SSDATA (value), "true")
12332 || !strcmp (SSDATA (value), "on")))
12333 use_xim = true;
12334 #endif
12335 }
12336
12337 #ifdef HAVE_X_SM
12338 /* Only do this for the very first display in the Emacs session.
12339 Ignore X session management when Emacs was first started on a
12340 tty or started as a daemon. */
12341 if (terminal->id == 1 && ! IS_DAEMON)
12342 x_session_initialize (dpyinfo);
12343 #endif
12344
12345 #ifdef USE_CAIRO
12346 x_extension_initialize (dpyinfo);
12347 #endif
12348
12349 unblock_input ();
12350
12351 return dpyinfo;
12352 }
12353 \f
12354 /* Get rid of display DPYINFO, deleting all frames on it,
12355 and without sending any more commands to the X server. */
12356
12357 static void
12358 x_delete_display (struct x_display_info *dpyinfo)
12359 {
12360 struct terminal *t;
12361 struct color_name_cache_entry *color_entry, *next_color_entry;
12362
12363 /* Close all frames and delete the generic struct terminal for this
12364 X display. */
12365 for (t = terminal_list; t; t = t->next_terminal)
12366 if (t->type == output_x_window && t->display_info.x == dpyinfo)
12367 {
12368 #ifdef HAVE_X_SM
12369 /* Close X session management when we close its display. */
12370 if (t->id == 1 && x_session_have_connection ())
12371 x_session_close ();
12372 #endif
12373 delete_terminal (t);
12374 break;
12375 }
12376
12377 if (next_noop_dpyinfo == dpyinfo)
12378 next_noop_dpyinfo = dpyinfo->next;
12379
12380 if (x_display_list == dpyinfo)
12381 x_display_list = dpyinfo->next;
12382 else
12383 {
12384 struct x_display_info *tail;
12385
12386 for (tail = x_display_list; tail; tail = tail->next)
12387 if (tail->next == dpyinfo)
12388 tail->next = tail->next->next;
12389 }
12390
12391 for (color_entry = dpyinfo->color_names;
12392 color_entry;
12393 color_entry = next_color_entry)
12394 {
12395 next_color_entry = color_entry->next;
12396 xfree (color_entry->name);
12397 xfree (color_entry);
12398 }
12399
12400 xfree (dpyinfo->x_id_name);
12401 xfree (dpyinfo->x_dnd_atoms);
12402 xfree (dpyinfo->color_cells);
12403 xfree (dpyinfo);
12404 }
12405
12406 #ifdef USE_X_TOOLKIT
12407
12408 /* Atimer callback function for TIMER. Called every 0.1s to process
12409 Xt timeouts, if needed. We must avoid calling XtAppPending as
12410 much as possible because that function does an implicit XFlush
12411 that slows us down. */
12412
12413 static void
12414 x_process_timeouts (struct atimer *timer)
12415 {
12416 block_input ();
12417 x_timeout_atimer_activated_flag = false;
12418 if (toolkit_scroll_bar_interaction || popup_activated ())
12419 {
12420 while (XtAppPending (Xt_app_con) & XtIMTimer)
12421 XtAppProcessEvent (Xt_app_con, XtIMTimer);
12422 /* Reactivate the atimer for next time. */
12423 x_activate_timeout_atimer ();
12424 }
12425 unblock_input ();
12426 }
12427
12428 /* Install an asynchronous timer that processes Xt timeout events
12429 every 0.1s as long as either `toolkit_scroll_bar_interaction' or
12430 `popup_activated_flag' (in xmenu.c) is set. Make sure to call this
12431 function whenever these variables are set. This is necessary
12432 because some widget sets use timeouts internally, for example the
12433 LessTif menu bar, or the Xaw3d scroll bar. When Xt timeouts aren't
12434 processed, these widgets don't behave normally. */
12435
12436 void
12437 x_activate_timeout_atimer (void)
12438 {
12439 block_input ();
12440 if (!x_timeout_atimer_activated_flag)
12441 {
12442 struct timespec interval = make_timespec (0, 100 * 1000 * 1000);
12443 start_atimer (ATIMER_RELATIVE, interval, x_process_timeouts, 0);
12444 x_timeout_atimer_activated_flag = true;
12445 }
12446 unblock_input ();
12447 }
12448
12449 #endif /* USE_X_TOOLKIT */
12450
12451 \f
12452 /* Set up use of X before we make the first connection. */
12453
12454 static struct redisplay_interface x_redisplay_interface =
12455 {
12456 x_frame_parm_handlers,
12457 x_produce_glyphs,
12458 x_write_glyphs,
12459 x_insert_glyphs,
12460 x_clear_end_of_line,
12461 x_scroll_run,
12462 x_after_update_window_line,
12463 x_update_window_begin,
12464 x_update_window_end,
12465 x_flush,
12466 x_clear_window_mouse_face,
12467 x_get_glyph_overhangs,
12468 x_fix_overlapping_area,
12469 x_draw_fringe_bitmap,
12470 #ifdef USE_CAIRO
12471 x_cr_define_fringe_bitmap,
12472 x_cr_destroy_fringe_bitmap,
12473 #else
12474 0, /* define_fringe_bitmap */
12475 0, /* destroy_fringe_bitmap */
12476 #endif
12477 x_compute_glyph_string_overhangs,
12478 x_draw_glyph_string,
12479 x_define_frame_cursor,
12480 x_clear_frame_area,
12481 x_draw_window_cursor,
12482 x_draw_vertical_window_border,
12483 x_draw_window_divider,
12484 x_shift_glyphs_for_insert, /* Never called; see comment in function. */
12485 x_show_hourglass,
12486 x_hide_hourglass
12487 };
12488
12489
12490 /* This function is called when the last frame on a display is deleted. */
12491 void
12492 x_delete_terminal (struct terminal *terminal)
12493 {
12494 struct x_display_info *dpyinfo = terminal->display_info.x;
12495
12496 /* Protect against recursive calls. delete_frame in
12497 delete_terminal calls us back when it deletes our last frame. */
12498 if (!terminal->name)
12499 return;
12500
12501 block_input ();
12502 #ifdef HAVE_X_I18N
12503 /* We must close our connection to the XIM server before closing the
12504 X display. */
12505 if (dpyinfo->xim)
12506 xim_close_dpy (dpyinfo);
12507 #endif
12508
12509 /* Normally, the display is available... */
12510 if (dpyinfo->display)
12511 {
12512 x_destroy_all_bitmaps (dpyinfo);
12513 XSetCloseDownMode (dpyinfo->display, DestroyAll);
12514
12515 /* Whether or not XCloseDisplay destroys the associated resource
12516 database depends on the version of libX11. To avoid both
12517 crash and memory leak, we dissociate the database from the
12518 display and then destroy dpyinfo->xrdb ourselves.
12519
12520 Unfortunately, the above strategy does not work in some
12521 situations due to a bug in newer versions of libX11: because
12522 XrmSetDatabase doesn't clear the flag XlibDisplayDfltRMDB if
12523 dpy->db is NULL, XCloseDisplay destroys the associated
12524 database whereas it has not been created by XGetDefault
12525 (Bug#21974 in freedesktop.org Bugzilla). As a workaround, we
12526 don't destroy the database here in order to avoid the crash
12527 in the above situations for now, though that may cause memory
12528 leaks in other situations. */
12529 #if false
12530 #ifdef HAVE_XRMSETDATABASE
12531 XrmSetDatabase (dpyinfo->display, NULL);
12532 #else
12533 dpyinfo->display->db = NULL;
12534 #endif
12535 /* We used to call XrmDestroyDatabase from x_delete_display, but
12536 some older versions of libX11 crash if we call it after
12537 closing all the displays. */
12538 XrmDestroyDatabase (dpyinfo->xrdb);
12539 #endif
12540
12541 #ifdef USE_GTK
12542 xg_display_close (dpyinfo->display);
12543 #else
12544 #ifdef USE_X_TOOLKIT
12545 XtCloseDisplay (dpyinfo->display);
12546 #else
12547 XCloseDisplay (dpyinfo->display);
12548 #endif
12549 #endif /* ! USE_GTK */
12550 /* Do not close the connection here because it's already closed
12551 by X(t)CloseDisplay (Bug#18403). */
12552 dpyinfo->display = NULL;
12553 }
12554
12555 /* ...but if called from x_connection_closed, the display may already
12556 be closed and dpyinfo->display was set to 0 to indicate that. Since
12557 X server is most likely gone, explicit close is the only reliable
12558 way to continue and avoid Bug#19147. */
12559 else if (dpyinfo->connection >= 0)
12560 emacs_close (dpyinfo->connection);
12561
12562 /* No more input on this descriptor. */
12563 delete_keyboard_wait_descriptor (dpyinfo->connection);
12564 /* Mark as dead. */
12565 dpyinfo->connection = -1;
12566
12567 x_delete_display (dpyinfo);
12568 unblock_input ();
12569 }
12570
12571 /* Create a struct terminal, initialize it with the X11 specific
12572 functions and make DISPLAY->TERMINAL point to it. */
12573
12574 static struct terminal *
12575 x_create_terminal (struct x_display_info *dpyinfo)
12576 {
12577 struct terminal *terminal;
12578
12579 terminal = create_terminal (output_x_window, &x_redisplay_interface);
12580
12581 terminal->display_info.x = dpyinfo;
12582 dpyinfo->terminal = terminal;
12583
12584 /* kboard is initialized in x_term_init. */
12585
12586 terminal->clear_frame_hook = x_clear_frame;
12587 terminal->ins_del_lines_hook = x_ins_del_lines;
12588 terminal->delete_glyphs_hook = x_delete_glyphs;
12589 terminal->ring_bell_hook = XTring_bell;
12590 terminal->toggle_invisible_pointer_hook = XTtoggle_invisible_pointer;
12591 terminal->update_begin_hook = x_update_begin;
12592 terminal->update_end_hook = x_update_end;
12593 terminal->read_socket_hook = XTread_socket;
12594 terminal->frame_up_to_date_hook = XTframe_up_to_date;
12595 terminal->mouse_position_hook = XTmouse_position;
12596 terminal->frame_rehighlight_hook = XTframe_rehighlight;
12597 terminal->frame_raise_lower_hook = XTframe_raise_lower;
12598 terminal->fullscreen_hook = XTfullscreen_hook;
12599 terminal->menu_show_hook = x_menu_show;
12600 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
12601 terminal->popup_dialog_hook = xw_popup_dialog;
12602 #endif
12603 terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
12604 terminal->set_horizontal_scroll_bar_hook = XTset_horizontal_scroll_bar;
12605 terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
12606 terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
12607 terminal->judge_scroll_bars_hook = XTjudge_scroll_bars;
12608 terminal->delete_frame_hook = x_destroy_window;
12609 terminal->delete_terminal_hook = x_delete_terminal;
12610 /* Other hooks are NULL by default. */
12611
12612 return terminal;
12613 }
12614
12615 static void
12616 x_initialize (void)
12617 {
12618 baud_rate = 19200;
12619
12620 x_noop_count = 0;
12621 any_help_event_p = false;
12622 ignore_next_mouse_click_timeout = 0;
12623
12624 #ifdef USE_GTK
12625 current_count = -1;
12626 #endif
12627
12628 /* Try to use interrupt input; if we can't, then start polling. */
12629 Fset_input_interrupt_mode (Qt);
12630
12631 #ifdef USE_X_TOOLKIT
12632 XtToolkitInitialize ();
12633
12634 Xt_app_con = XtCreateApplicationContext ();
12635
12636 /* Register a converter from strings to pixels, which uses
12637 Emacs' color allocation infrastructure. */
12638 XtAppSetTypeConverter (Xt_app_con,
12639 XtRString, XtRPixel, cvt_string_to_pixel,
12640 cvt_string_to_pixel_args,
12641 XtNumber (cvt_string_to_pixel_args),
12642 XtCacheByDisplay, cvt_pixel_dtor);
12643
12644 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
12645 #endif
12646
12647 #ifdef USE_TOOLKIT_SCROLL_BARS
12648 #ifndef USE_GTK
12649 xaw3d_arrow_scroll = False;
12650 xaw3d_pick_top = True;
12651 #endif
12652 #endif
12653
12654 #ifdef USE_CAIRO
12655 x_cr_init_fringe (&x_redisplay_interface);
12656 #endif
12657
12658 /* Note that there is no real way portable across R3/R4 to get the
12659 original error handler. */
12660 XSetErrorHandler (x_error_handler);
12661 XSetIOErrorHandler (x_io_error_quitter);
12662 }
12663
12664 #ifdef USE_GTK
12665 void
12666 init_xterm (void)
12667 {
12668 /* Emacs can handle only core input events, so make sure
12669 Gtk doesn't use Xinput or Xinput2 extensions. */
12670 xputenv ("GDK_CORE_DEVICE_EVENTS=1");
12671 }
12672 #endif
12673
12674 void
12675 syms_of_xterm (void)
12676 {
12677 x_error_message = NULL;
12678
12679 DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
12680 DEFSYM (Qlatin_1, "latin-1");
12681
12682 #ifdef USE_GTK
12683 xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
12684 staticpro (&xg_default_icon_file);
12685
12686 DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock");
12687 #endif
12688
12689 DEFVAR_BOOL ("x-use-underline-position-properties",
12690 x_use_underline_position_properties,
12691 doc: /* Non-nil means make use of UNDERLINE_POSITION font properties.
12692 A value of nil means ignore them. If you encounter fonts with bogus
12693 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
12694 to 4.1, set this to nil. You can also use `underline-minimum-offset'
12695 to override the font's UNDERLINE_POSITION for small font display
12696 sizes. */);
12697 x_use_underline_position_properties = true;
12698
12699 DEFVAR_BOOL ("x-underline-at-descent-line",
12700 x_underline_at_descent_line,
12701 doc: /* Non-nil means to draw the underline at the same place as the descent line.
12702 A value of nil means to draw the underline according to the value of the
12703 variable `x-use-underline-position-properties', which is usually at the
12704 baseline level. The default value is nil. */);
12705 x_underline_at_descent_line = false;
12706
12707 DEFVAR_BOOL ("x-mouse-click-focus-ignore-position",
12708 x_mouse_click_focus_ignore_position,
12709 doc: /* Non-nil means that a mouse click to focus a frame does not move point.
12710 This variable is only used when the window manager requires that you
12711 click on a frame to select it (give it focus). In that case, a value
12712 of nil, means that the selected window and cursor position changes to
12713 reflect the mouse click position, while a non-nil value means that the
12714 selected window or cursor position is preserved. */);
12715 x_mouse_click_focus_ignore_position = false;
12716
12717 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
12718 doc: /* Which toolkit scroll bars Emacs uses, if any.
12719 A value of nil means Emacs doesn't use toolkit scroll bars.
12720 With the X Window system, the value is a symbol describing the
12721 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
12722 With MS Windows or Nextstep, the value is t. */);
12723 #ifdef USE_TOOLKIT_SCROLL_BARS
12724 #ifdef USE_MOTIF
12725 Vx_toolkit_scroll_bars = intern_c_string ("motif");
12726 #elif defined HAVE_XAW3D
12727 Vx_toolkit_scroll_bars = intern_c_string ("xaw3d");
12728 #elif USE_GTK
12729 Vx_toolkit_scroll_bars = intern_c_string ("gtk");
12730 #else
12731 Vx_toolkit_scroll_bars = intern_c_string ("xaw");
12732 #endif
12733 #else
12734 Vx_toolkit_scroll_bars = Qnil;
12735 #endif
12736
12737 DEFSYM (Qmodifier_value, "modifier-value");
12738 DEFSYM (Qalt, "alt");
12739 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
12740 DEFSYM (Qhyper, "hyper");
12741 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
12742 DEFSYM (Qmeta, "meta");
12743 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
12744 DEFSYM (Qsuper, "super");
12745 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
12746
12747 DEFVAR_LISP ("x-alt-keysym", Vx_alt_keysym,
12748 doc: /* Which keys Emacs uses for the alt modifier.
12749 This should be one of the symbols `alt', `hyper', `meta', `super'.
12750 For example, `alt' means use the Alt_L and Alt_R keysyms. The default
12751 is nil, which is the same as `alt'. */);
12752 Vx_alt_keysym = Qnil;
12753
12754 DEFVAR_LISP ("x-hyper-keysym", Vx_hyper_keysym,
12755 doc: /* Which keys Emacs uses for the hyper modifier.
12756 This should be one of the symbols `alt', `hyper', `meta', `super'.
12757 For example, `hyper' means use the Hyper_L and Hyper_R keysyms. The
12758 default is nil, which is the same as `hyper'. */);
12759 Vx_hyper_keysym = Qnil;
12760
12761 DEFVAR_LISP ("x-meta-keysym", Vx_meta_keysym,
12762 doc: /* Which keys Emacs uses for the meta modifier.
12763 This should be one of the symbols `alt', `hyper', `meta', `super'.
12764 For example, `meta' means use the Meta_L and Meta_R keysyms. The
12765 default is nil, which is the same as `meta'. */);
12766 Vx_meta_keysym = Qnil;
12767
12768 DEFVAR_LISP ("x-super-keysym", Vx_super_keysym,
12769 doc: /* Which keys Emacs uses for the super modifier.
12770 This should be one of the symbols `alt', `hyper', `meta', `super'.
12771 For example, `super' means use the Super_L and Super_R keysyms. The
12772 default is nil, which is the same as `super'. */);
12773 Vx_super_keysym = Qnil;
12774
12775 DEFVAR_LISP ("x-keysym-table", Vx_keysym_table,
12776 doc: /* Hash table of character codes indexed by X keysym codes. */);
12777 Vx_keysym_table = make_hash_table (hashtest_eql, make_number (900),
12778 make_float (DEFAULT_REHASH_SIZE),
12779 make_float (DEFAULT_REHASH_THRESHOLD),
12780 Qnil);
12781
12782 DEFVAR_BOOL ("x-frame-normalize-before-maximize",
12783 x_frame_normalize_before_maximize,
12784 doc: /* Non-nil means normalize frame before maximizing.
12785 If this variable is t, Emacs first asks the window manager to give the
12786 frame its normal size, and only then the final state, whenever changing
12787 from a full-height, full-width or full-both state to the maximized one
12788 or when changing from the maximized to the full-height or full-width
12789 state.
12790
12791 Set this variable only if your window manager cannot handle the
12792 transition between the various maximization states. */);
12793 x_frame_normalize_before_maximize = false;
12794 }