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