Update define-ibuffer-op doc string
[emacs.git] / src / xterm.c
blobcd1d712f39ad28cd07bc1caa9871d2d10d63df9c
1 /* X Communication module for terminals which understand the X protocol.
3 Copyright (C) 1989, 1993-2016 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
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.
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/>. */
20 /* New display code by Gerd Moellmann <gerd@gnu.org>. */
21 /* Xt features made by Fred Pierresteguy. */
23 #include <config.h>
24 #include <stdio.h>
25 #ifdef USE_CAIRO
26 #include <math.h>
27 #endif
29 #include "lisp.h"
30 #include "blockinput.h"
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>
37 /* If we have Xfixes extension, use it for pointer blanking. */
38 #ifdef HAVE_XFIXES
39 #include <X11/extensions/Xfixes.h>
40 #endif
42 /* Using Xft implies that XRender is available. */
43 #ifdef HAVE_XFT
44 #include <X11/extensions/Xrender.h>
45 #endif
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 */
53 #include <sys/ioctl.h>
55 #include "systime.h"
57 #include <fcntl.h>
58 #include <errno.h>
59 #include <sys/stat.h>
60 #include "character.h"
61 #include "coding.h"
62 #include "composite.h"
63 #include "frame.h"
64 #include "dispextern.h"
65 #include "xwidget.h"
66 #include "fontset.h"
67 #include "termhooks.h"
68 #include "termopts.h"
69 #include "termchar.h"
70 #include "emacs-icon.h"
71 #include "buffer.h"
72 #include "window.h"
73 #include "keyboard.h"
74 #include "atimer.h"
75 #include "font.h"
76 #include "xsettings.h"
77 #include "sysselect.h"
78 #include "menu.h"
80 #ifdef USE_X_TOOLKIT
81 #include <X11/Shell.h>
82 #endif
84 #include <unistd.h>
86 #ifdef USE_GTK
87 #include "gtkutil.h"
88 #ifdef HAVE_GTK3
89 #include <X11/Xproto.h>
90 #endif
91 #endif
93 #if defined (USE_LUCID) || defined (USE_MOTIF)
94 #include "../lwlib/xlwmenu.h"
95 #endif
97 #ifdef USE_X_TOOLKIT
99 /* Include toolkit specific headers for the scroll bar widget. */
101 #ifdef USE_TOOLKIT_SCROLL_BARS
102 #if defined USE_MOTIF
103 #include <Xm/Xm.h> /* For LESSTIF_VERSION */
104 #include <Xm/ScrollBar.h>
105 #else /* !USE_MOTIF i.e. use Xaw */
107 #ifdef HAVE_XAW3D
108 #include <X11/Xaw3d/Simple.h>
109 #include <X11/Xaw3d/Scrollbar.h>
110 #include <X11/Xaw3d/ThreeD.h>
111 #else /* !HAVE_XAW3D */
112 #include <X11/Xaw/Simple.h>
113 #include <X11/Xaw/Scrollbar.h>
114 #endif /* !HAVE_XAW3D */
115 #ifndef XtNpickTop
116 #define XtNpickTop "pickTop"
117 #endif /* !XtNpickTop */
118 #endif /* !USE_MOTIF */
119 #endif /* USE_TOOLKIT_SCROLL_BARS */
121 #endif /* USE_X_TOOLKIT */
123 #ifdef USE_X_TOOLKIT
124 #include "widget.h"
125 #ifndef XtNinitialState
126 #define XtNinitialState "initialState"
127 #endif
128 #endif
130 #include "bitmaps/gray.xbm"
132 #ifdef HAVE_XKB
133 #include <X11/XKBlib.h>
134 #endif
136 /* Default to using XIM if available. */
137 #ifdef USE_XIM
138 bool use_xim = true;
139 #else
140 bool use_xim = false; /* configure --without-xim */
141 #endif
143 /* Non-zero means that a HELP_EVENT has been generated since Emacs
144 start. */
146 static bool any_help_event_p;
148 /* This is a chain of structures for all the X displays currently in
149 use. */
151 struct x_display_info *x_display_list;
153 #ifdef USE_X_TOOLKIT
155 /* The application context for Xt use. */
156 XtAppContext Xt_app_con;
157 static String Xt_default_resources[] = {0};
159 /* Non-zero means user is interacting with a toolkit scroll bar. */
160 static bool toolkit_scroll_bar_interaction;
162 #endif /* USE_X_TOOLKIT */
164 /* Non-zero timeout value means ignore next mouse click if it arrives
165 before that timeout elapses (i.e. as part of the same sequence of
166 events resulting from clicking on a frame to select it). */
168 static Time ignore_next_mouse_click_timeout;
170 /* Used locally within XTread_socket. */
172 static int x_noop_count;
174 #ifdef USE_GTK
175 /* The name of the Emacs icon file. */
176 static Lisp_Object xg_default_icon_file;
177 #endif
179 /* Some functions take this as char *, not const char *. */
180 static char emacs_class[] = EMACS_CLASS;
182 enum xembed_info
184 XEMBED_MAPPED = 1 << 0
187 enum xembed_message
189 XEMBED_EMBEDDED_NOTIFY = 0,
190 XEMBED_WINDOW_ACTIVATE = 1,
191 XEMBED_WINDOW_DEACTIVATE = 2,
192 XEMBED_REQUEST_FOCUS = 3,
193 XEMBED_FOCUS_IN = 4,
194 XEMBED_FOCUS_OUT = 5,
195 XEMBED_FOCUS_NEXT = 6,
196 XEMBED_FOCUS_PREV = 7,
198 XEMBED_MODALITY_ON = 10,
199 XEMBED_MODALITY_OFF = 11,
200 XEMBED_REGISTER_ACCELERATOR = 12,
201 XEMBED_UNREGISTER_ACCELERATOR = 13,
202 XEMBED_ACTIVATE_ACCELERATOR = 14
205 static void x_free_cr_resources (struct frame *);
206 static bool x_alloc_nearest_color_1 (Display *, Colormap, XColor *);
207 static void x_raise_frame (struct frame *);
208 static void x_lower_frame (struct frame *);
209 static int x_io_error_quitter (Display *);
210 static struct terminal *x_create_terminal (struct x_display_info *);
211 static void x_frame_rehighlight (struct x_display_info *);
213 static void x_clip_to_row (struct window *, struct glyph_row *,
214 enum glyph_row_area, GC);
215 static struct scroll_bar *x_window_to_scroll_bar (Display *, Window, int);
216 static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *,
217 enum scroll_bar_part *,
218 Lisp_Object *, Lisp_Object *,
219 Time *);
220 static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object *,
221 enum scroll_bar_part *,
222 Lisp_Object *, Lisp_Object *,
223 Time *);
224 static bool x_handle_net_wm_state (struct frame *, const XPropertyEvent *);
225 static void x_check_fullscreen (struct frame *);
226 static void x_check_expected_move (struct frame *, int, int);
227 static void x_sync_with_move (struct frame *, int, int, bool);
228 static int handle_one_xevent (struct x_display_info *,
229 const XEvent *, int *,
230 struct input_event *);
231 #if ! (defined USE_X_TOOLKIT || defined USE_MOTIF)
232 static int x_dispatch_event (XEvent *, Display *);
233 #endif
234 static void x_wm_set_window_state (struct frame *, int);
235 static void x_wm_set_icon_pixmap (struct frame *, ptrdiff_t);
236 static void x_initialize (void);
238 static bool get_current_wm_state (struct frame *, Window, int *, bool *);
240 /* Flush display of frame F. */
242 static void
243 x_flush (struct frame *f)
245 eassert (f && FRAME_X_P (f));
246 /* Don't call XFlush when it is not safe to redisplay; the X
247 connection may be broken. */
248 if (!NILP (Vinhibit_redisplay))
249 return;
251 block_input ();
252 XFlush (FRAME_X_DISPLAY (f));
253 unblock_input ();
257 /* Remove calls to XFlush by defining XFlush to an empty replacement.
258 Calls to XFlush should be unnecessary because the X output buffer
259 is flushed automatically as needed by calls to XPending,
260 XNextEvent, or XWindowEvent according to the XFlush man page.
261 XTread_socket calls XPending. Removing XFlush improves
262 performance. */
264 #define XFlush(DISPLAY) (void) 0
267 /***********************************************************************
268 Debugging
269 ***********************************************************************/
271 #if false
273 /* This is a function useful for recording debugging information about
274 the sequence of occurrences in this file. */
276 struct record
278 char *locus;
279 int type;
282 struct record event_record[100];
284 int event_record_index;
286 void
287 record_event (char *locus, int type)
289 if (event_record_index == ARRAYELTS (event_record))
290 event_record_index = 0;
292 event_record[event_record_index].locus = locus;
293 event_record[event_record_index].type = type;
294 event_record_index++;
297 #endif
299 #ifdef USE_CAIRO
301 #define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context)
302 #define FRAME_CR_SURFACE(f) ((f)->output_data.x->cr_surface)
304 static struct x_gc_ext_data *
305 x_gc_get_ext_data (struct frame *f, GC gc, int create_if_not_found_p)
307 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
308 XEDataObject object;
309 XExtData **head, *ext_data;
311 object.gc = gc;
312 head = XEHeadOfExtensionList (object);
313 ext_data = XFindOnExtensionList (head, dpyinfo->ext_codes->extension);
314 if (ext_data == NULL)
316 if (!create_if_not_found_p)
317 return NULL;
318 else
320 ext_data = xzalloc (sizeof (*ext_data));
321 ext_data->number = dpyinfo->ext_codes->extension;
322 ext_data->private_data = xzalloc (sizeof (struct x_gc_ext_data));
323 XAddToExtensionList (head, ext_data);
326 return (struct x_gc_ext_data *) ext_data->private_data;
329 static void
330 x_extension_initialize (struct x_display_info *dpyinfo)
332 XExtCodes *ext_codes = XAddExtension (dpyinfo->display);
334 dpyinfo->ext_codes = ext_codes;
337 static void
338 x_cr_destroy_surface (struct frame *f)
340 if (FRAME_CR_SURFACE (f))
342 cairo_t *cr = FRAME_CR_CONTEXT (f);
343 cairo_surface_destroy (FRAME_CR_SURFACE (f));
344 FRAME_CR_SURFACE (f) = 0;
345 if (cr) cairo_destroy (cr);
346 FRAME_CR_CONTEXT (f) = NULL;
350 cairo_t *
351 x_begin_cr_clip (struct frame *f, GC gc)
353 cairo_t *cr = FRAME_CR_CONTEXT (f);
355 if (!cr)
358 if (! FRAME_CR_SURFACE (f))
360 cairo_surface_t *surface;
361 surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
362 FRAME_X_WINDOW (f),
363 FRAME_DISPLAY_INFO (f)->visual,
364 FRAME_PIXEL_WIDTH (f),
365 FRAME_PIXEL_HEIGHT (f));
366 cr = cairo_create (surface);
367 cairo_surface_destroy (surface);
369 else
370 cr = cairo_create (FRAME_CR_SURFACE (f));
371 FRAME_CR_CONTEXT (f) = cr;
373 cairo_save (cr);
375 if (gc)
377 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
379 if (gc_ext && gc_ext->n_clip_rects)
381 int i;
383 for (i = 0; i < gc_ext->n_clip_rects; i++)
384 cairo_rectangle (cr, gc_ext->clip_rects[i].x,
385 gc_ext->clip_rects[i].y,
386 gc_ext->clip_rects[i].width,
387 gc_ext->clip_rects[i].height);
388 cairo_clip (cr);
392 return cr;
395 void
396 x_end_cr_clip (struct frame *f)
398 cairo_restore (FRAME_CR_CONTEXT (f));
401 void
402 x_set_cr_source_with_gc_foreground (struct frame *f, GC gc)
404 XGCValues xgcv;
405 XColor color;
407 XGetGCValues (FRAME_X_DISPLAY (f), gc, GCForeground, &xgcv);
408 color.pixel = xgcv.foreground;
409 x_query_color (f, &color);
410 cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
411 color.green / 65535.0, color.blue / 65535.0);
414 void
415 x_set_cr_source_with_gc_background (struct frame *f, GC gc)
417 XGCValues xgcv;
418 XColor color;
420 XGetGCValues (FRAME_X_DISPLAY (f), gc, GCBackground, &xgcv);
421 color.pixel = xgcv.background;
422 x_query_color (f, &color);
423 cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
424 color.green / 65535.0, color.blue / 65535.0);
427 /* Fringe bitmaps. */
429 static int max_fringe_bmp = 0;
430 static cairo_pattern_t **fringe_bmp = 0;
432 static void
433 x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
435 int i, stride;
436 cairo_surface_t *surface;
437 unsigned char *data;
438 cairo_pattern_t *pattern;
440 if (which >= max_fringe_bmp)
442 i = max_fringe_bmp;
443 max_fringe_bmp = which + 20;
444 fringe_bmp = (cairo_pattern_t **) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (cairo_pattern_t *));
445 while (i < max_fringe_bmp)
446 fringe_bmp[i++] = 0;
449 block_input ();
451 surface = cairo_image_surface_create (CAIRO_FORMAT_A1, wd, h);
452 stride = cairo_image_surface_get_stride (surface);
453 data = cairo_image_surface_get_data (surface);
455 for (i = 0; i < h; i++)
457 *((unsigned short *) data) = bits[i];
458 data += stride;
461 cairo_surface_mark_dirty (surface);
462 pattern = cairo_pattern_create_for_surface (surface);
463 cairo_surface_destroy (surface);
465 unblock_input ();
467 fringe_bmp[which] = pattern;
470 static void
471 x_cr_destroy_fringe_bitmap (int which)
473 if (which >= max_fringe_bmp)
474 return;
476 if (fringe_bmp[which])
478 block_input ();
479 cairo_pattern_destroy (fringe_bmp[which]);
480 unblock_input ();
482 fringe_bmp[which] = 0;
485 static void
486 x_cr_draw_image (struct frame *f, GC gc, cairo_pattern_t *image,
487 int src_x, int src_y, int width, int height,
488 int dest_x, int dest_y, bool overlay_p)
490 cairo_t *cr;
491 cairo_matrix_t matrix;
492 cairo_surface_t *surface;
493 cairo_format_t format;
495 cr = x_begin_cr_clip (f, gc);
496 if (overlay_p)
497 cairo_rectangle (cr, dest_x, dest_y, width, height);
498 else
500 x_set_cr_source_with_gc_background (f, gc);
501 cairo_rectangle (cr, dest_x, dest_y, width, height);
502 cairo_fill_preserve (cr);
504 cairo_clip (cr);
505 cairo_matrix_init_translate (&matrix, src_x - dest_x, src_y - dest_y);
506 cairo_pattern_set_matrix (image, &matrix);
507 cairo_pattern_get_surface (image, &surface);
508 format = cairo_image_surface_get_format (surface);
509 if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1)
511 cairo_set_source (cr, image);
512 cairo_fill (cr);
514 else
516 x_set_cr_source_with_gc_foreground (f, gc);
517 cairo_mask (cr, image);
519 x_end_cr_clip (f);
522 void
523 x_cr_draw_frame (cairo_t *cr, struct frame *f)
525 int width, height;
527 width = FRAME_PIXEL_WIDTH (f);
528 height = FRAME_PIXEL_HEIGHT (f);
530 x_free_cr_resources (f);
531 FRAME_CR_CONTEXT (f) = cr;
532 x_clear_area (f, 0, 0, width, height);
533 expose_frame (f, 0, 0, width, height);
534 FRAME_CR_CONTEXT (f) = NULL;
537 static cairo_status_t
538 x_cr_accumulate_data (void *closure, const unsigned char *data,
539 unsigned int length)
541 Lisp_Object *acc = (Lisp_Object *) closure;
543 *acc = Fcons (make_unibyte_string ((char const *) data, length), *acc);
545 return CAIRO_STATUS_SUCCESS;
548 static void
549 x_cr_destroy (Lisp_Object arg)
551 cairo_t *cr = (cairo_t *) XSAVE_POINTER (arg, 0);
553 block_input ();
554 cairo_destroy (cr);
555 unblock_input ();
558 Lisp_Object
559 x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
561 struct frame *f;
562 cairo_surface_t *surface;
563 cairo_t *cr;
564 int width, height;
565 void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL;
566 Lisp_Object acc = Qnil;
567 int count = SPECPDL_INDEX ();
569 specbind (Qredisplay_dont_pause, Qt);
570 redisplay_preserve_echo_area (31);
572 f = XFRAME (XCAR (frames));
573 frames = XCDR (frames);
574 width = FRAME_PIXEL_WIDTH (f);
575 height = FRAME_PIXEL_HEIGHT (f);
577 block_input ();
578 #ifdef CAIRO_HAS_PDF_SURFACE
579 if (surface_type == CAIRO_SURFACE_TYPE_PDF)
581 surface = cairo_pdf_surface_create_for_stream (x_cr_accumulate_data, &acc,
582 width, height);
583 surface_set_size_func = cairo_pdf_surface_set_size;
585 else
586 #endif
587 #ifdef CAIRO_HAS_PNG_FUNCTIONS
588 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
589 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
590 else
591 #endif
592 #ifdef CAIRO_HAS_PS_SURFACE
593 if (surface_type == CAIRO_SURFACE_TYPE_PS)
595 surface = cairo_ps_surface_create_for_stream (x_cr_accumulate_data, &acc,
596 width, height);
597 surface_set_size_func = cairo_ps_surface_set_size;
599 else
600 #endif
601 #ifdef CAIRO_HAS_SVG_SURFACE
602 if (surface_type == CAIRO_SURFACE_TYPE_SVG)
603 surface = cairo_svg_surface_create_for_stream (x_cr_accumulate_data, &acc,
604 width, height);
605 else
606 #endif
607 abort ();
609 cr = cairo_create (surface);
610 cairo_surface_destroy (surface);
611 record_unwind_protect (x_cr_destroy, make_save_ptr (cr));
613 while (1)
615 x_free_cr_resources (f);
616 FRAME_CR_CONTEXT (f) = cr;
617 x_clear_area (f, 0, 0, width, height);
618 expose_frame (f, 0, 0, width, height);
619 FRAME_CR_CONTEXT (f) = NULL;
621 if (NILP (frames))
622 break;
624 cairo_surface_show_page (surface);
625 f = XFRAME (XCAR (frames));
626 frames = XCDR (frames);
627 width = FRAME_PIXEL_WIDTH (f);
628 height = FRAME_PIXEL_HEIGHT (f);
629 if (surface_set_size_func)
630 (*surface_set_size_func) (surface, width, height);
632 unblock_input ();
633 QUIT;
634 block_input ();
637 #ifdef CAIRO_HAS_PNG_FUNCTIONS
638 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
640 cairo_surface_flush (surface);
641 cairo_surface_write_to_png_stream (surface, x_cr_accumulate_data, &acc);
643 #endif
644 unblock_input ();
646 unbind_to (count, Qnil);
648 return CALLN (Fapply, intern ("concat"), Fnreverse (acc));
651 #endif /* USE_CAIRO */
653 static void
654 x_free_cr_resources (struct frame *f)
656 #ifdef USE_CAIRO
657 if (f == NULL)
659 Lisp_Object rest, frame;
660 FOR_EACH_FRAME (rest, frame)
661 if (FRAME_X_P (XFRAME (frame)))
662 x_free_cr_resources (XFRAME (frame));
664 else
666 cairo_t *cr = FRAME_CR_CONTEXT (f);
668 if (cr)
670 cairo_surface_t *surface = cairo_get_target (cr);
672 if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
674 cairo_destroy (cr);
675 FRAME_CR_CONTEXT (f) = NULL;
679 #endif
682 static void
683 x_set_clip_rectangles (struct frame *f, GC gc, XRectangle *rectangles, int n)
685 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, rectangles, n, Unsorted);
686 #ifdef USE_CAIRO
687 eassert (n >= 0 && n <= MAX_CLIP_RECTS);
690 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 1);
692 gc_ext->n_clip_rects = n;
693 memcpy (gc_ext->clip_rects, rectangles, sizeof (XRectangle) * n);
695 #endif
698 static void
699 x_reset_clip_rectangles (struct frame *f, GC gc)
701 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
702 #ifdef USE_CAIRO
704 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
706 if (gc_ext)
707 gc_ext->n_clip_rects = 0;
709 #endif
712 static void
713 x_fill_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
715 #ifdef USE_CAIRO
716 cairo_t *cr;
718 cr = x_begin_cr_clip (f, gc);
719 x_set_cr_source_with_gc_foreground (f, gc);
720 cairo_rectangle (cr, x, y, width, height);
721 cairo_fill (cr);
722 x_end_cr_clip (f);
723 #else
724 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
725 gc, x, y, width, height);
726 #endif
729 static void
730 x_draw_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
732 #ifdef USE_CAIRO
733 cairo_t *cr;
735 cr = x_begin_cr_clip (f, gc);
736 x_set_cr_source_with_gc_foreground (f, gc);
737 cairo_rectangle (cr, x + 0.5, y + 0.5, width, height);
738 cairo_set_line_width (cr, 1);
739 cairo_stroke (cr);
740 x_end_cr_clip (f);
741 #else
742 XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
743 gc, x, y, width, height);
744 #endif
747 static void
748 x_clear_window (struct frame *f)
750 #ifdef USE_CAIRO
751 cairo_t *cr;
753 cr = x_begin_cr_clip (f, NULL);
754 x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
755 cairo_paint (cr);
756 x_end_cr_clip (f);
757 #else
758 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
759 #endif
762 #ifdef USE_CAIRO
763 static void
764 x_fill_trapezoid_for_relief (struct frame *f, GC gc, int x, int y,
765 int width, int height, int top_p)
767 cairo_t *cr;
769 cr = x_begin_cr_clip (f, gc);
770 x_set_cr_source_with_gc_foreground (f, gc);
771 cairo_move_to (cr, top_p ? x : x + height, y);
772 cairo_line_to (cr, x, y + height);
773 cairo_line_to (cr, top_p ? x + width - height : x + width, y + height);
774 cairo_line_to (cr, x + width, y);
775 cairo_fill (cr);
776 x_end_cr_clip (f);
779 enum corners
781 CORNER_BOTTOM_RIGHT, /* 0 -> pi/2 */
782 CORNER_BOTTOM_LEFT, /* pi/2 -> pi */
783 CORNER_TOP_LEFT, /* pi -> 3pi/2 */
784 CORNER_TOP_RIGHT, /* 3pi/2 -> 2pi */
785 CORNER_LAST
788 static void
789 x_erase_corners_for_relief (struct frame *f, GC gc, int x, int y,
790 int width, int height,
791 double radius, double margin, int corners)
793 cairo_t *cr;
794 int i;
796 cr = x_begin_cr_clip (f, gc);
797 x_set_cr_source_with_gc_background (f, gc);
798 for (i = 0; i < CORNER_LAST; i++)
799 if (corners & (1 << i))
801 double xm, ym, xc, yc;
803 if (i == CORNER_TOP_LEFT || i == CORNER_BOTTOM_LEFT)
804 xm = x - margin, xc = xm + radius;
805 else
806 xm = x + width + margin, xc = xm - radius;
807 if (i == CORNER_TOP_LEFT || i == CORNER_TOP_RIGHT)
808 ym = y - margin, yc = ym + radius;
809 else
810 ym = y + height + margin, yc = ym - radius;
812 cairo_move_to (cr, xm, ym);
813 cairo_arc (cr, xc, yc, radius, i * M_PI_2, (i + 1) * M_PI_2);
815 cairo_clip (cr);
816 cairo_rectangle (cr, x, y, width, height);
817 cairo_fill (cr);
818 x_end_cr_clip (f);
821 static void
822 x_draw_horizontal_wave (struct frame *f, GC gc, int x, int y,
823 int width, int height, int wave_length)
825 cairo_t *cr;
826 double dx = wave_length, dy = height - 1;
827 int xoffset, n;
829 cr = x_begin_cr_clip (f, gc);
830 x_set_cr_source_with_gc_foreground (f, gc);
831 cairo_rectangle (cr, x, y, width, height);
832 cairo_clip (cr);
834 if (x >= 0)
836 xoffset = x % (wave_length * 2);
837 if (xoffset == 0)
838 xoffset = wave_length * 2;
840 else
841 xoffset = x % (wave_length * 2) + wave_length * 2;
842 n = (width + xoffset) / wave_length + 1;
843 if (xoffset > wave_length)
845 xoffset -= wave_length;
846 --n;
847 y += height - 1;
848 dy = -dy;
851 cairo_move_to (cr, x - xoffset + 0.5, y + 0.5);
852 while (--n >= 0)
854 cairo_rel_line_to (cr, dx, dy);
855 dy = -dy;
857 cairo_set_line_width (cr, 1);
858 cairo_stroke (cr);
859 x_end_cr_clip (f);
861 #endif
864 /* Return the struct x_display_info corresponding to DPY. */
866 struct x_display_info *
867 x_display_info_for_display (Display *dpy)
869 struct x_display_info *dpyinfo;
871 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
872 if (dpyinfo->display == dpy)
873 return dpyinfo;
875 return 0;
878 static Window
879 x_find_topmost_parent (struct frame *f)
881 struct x_output *x = f->output_data.x;
882 Window win = None, wi = x->parent_desc;
883 Display *dpy = FRAME_X_DISPLAY (f);
885 while (wi != FRAME_DISPLAY_INFO (f)->root_window)
887 Window root;
888 Window *children;
889 unsigned int nchildren;
891 win = wi;
892 if (XQueryTree (dpy, win, &root, &wi, &children, &nchildren))
893 XFree (children);
894 else
895 break;
898 return win;
901 #define OPAQUE 0xffffffff
903 void
904 x_set_frame_alpha (struct frame *f)
906 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
907 Display *dpy = FRAME_X_DISPLAY (f);
908 Window win = FRAME_OUTER_WINDOW (f);
909 double alpha = 1.0;
910 double alpha_min = 1.0;
911 unsigned long opac;
912 Window parent;
914 if (dpyinfo->x_highlight_frame == f)
915 alpha = f->alpha[0];
916 else
917 alpha = f->alpha[1];
919 if (FLOATP (Vframe_alpha_lower_limit))
920 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
921 else if (INTEGERP (Vframe_alpha_lower_limit))
922 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
924 if (alpha < 0.0)
925 return;
926 else if (alpha > 1.0)
927 alpha = 1.0;
928 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
929 alpha = alpha_min;
931 opac = alpha * OPAQUE;
933 x_catch_errors (dpy);
935 /* If there is a parent from the window manager, put the property there
936 also, to work around broken window managers that fail to do that.
937 Do this unconditionally as this function is called on reparent when
938 alpha has not changed on the frame. */
940 parent = x_find_topmost_parent (f);
941 if (parent != None)
942 XChangeProperty (dpy, parent, dpyinfo->Xatom_net_wm_window_opacity,
943 XA_CARDINAL, 32, PropModeReplace,
944 (unsigned char *) &opac, 1);
946 /* return unless necessary */
948 unsigned char *data;
949 Atom actual;
950 int rc, format;
951 unsigned long n, left;
953 rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
954 0, 1, False, XA_CARDINAL,
955 &actual, &format, &n, &left,
956 &data);
958 if (rc == Success && actual != None)
960 unsigned long value = *(unsigned long *)data;
961 XFree (data);
962 if (value == opac)
964 x_uncatch_errors ();
965 return;
970 XChangeProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
971 XA_CARDINAL, 32, PropModeReplace,
972 (unsigned char *) &opac, 1);
973 x_uncatch_errors ();
976 /***********************************************************************
977 Starting and ending an update
978 ***********************************************************************/
980 /* Start an update of frame F. This function is installed as a hook
981 for update_begin, i.e. it is called when update_begin is called.
982 This function is called prior to calls to x_update_window_begin for
983 each window being updated. Currently, there is nothing to do here
984 because all interesting stuff is done on a window basis. */
986 static void
987 x_update_begin (struct frame *f)
989 #ifdef USE_CAIRO
990 if (! NILP (tip_frame) && XFRAME (tip_frame) == f
991 && ! FRAME_VISIBLE_P (f))
992 return;
994 if (! FRAME_CR_SURFACE (f))
996 int width, height;
997 #ifdef USE_GTK
998 if (FRAME_GTK_WIDGET (f))
1000 GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
1001 width = gdk_window_get_width (w);
1002 height = gdk_window_get_height (w);
1004 else
1005 #endif
1007 width = FRAME_PIXEL_WIDTH (f);
1008 height = FRAME_PIXEL_HEIGHT (f);
1009 if (! FRAME_EXTERNAL_TOOL_BAR (f))
1010 height += FRAME_TOOL_BAR_HEIGHT (f);
1011 if (! FRAME_EXTERNAL_MENU_BAR (f))
1012 height += FRAME_MENU_BAR_HEIGHT (f);
1015 if (width > 0 && height > 0)
1017 block_input();
1018 FRAME_CR_SURFACE (f) = cairo_image_surface_create
1019 (CAIRO_FORMAT_ARGB32, width, height);
1020 unblock_input();
1023 #endif /* USE_CAIRO */
1026 /* Start update of window W. */
1028 static void
1029 x_update_window_begin (struct window *w)
1031 struct frame *f = XFRAME (WINDOW_FRAME (w));
1032 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1034 w->output_cursor = w->cursor;
1036 block_input ();
1038 if (f == hlinfo->mouse_face_mouse_frame)
1040 /* Don't do highlighting for mouse motion during the update. */
1041 hlinfo->mouse_face_defer = true;
1043 /* If F needs to be redrawn, simply forget about any prior mouse
1044 highlighting. */
1045 if (FRAME_GARBAGED_P (f))
1046 hlinfo->mouse_face_window = Qnil;
1049 unblock_input ();
1053 /* Draw a vertical window border from (x,y0) to (x,y1) */
1055 static void
1056 x_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
1058 struct frame *f = XFRAME (WINDOW_FRAME (w));
1059 struct face *face;
1061 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
1062 if (face)
1063 XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
1064 face->foreground);
1066 #ifdef USE_CAIRO
1067 x_fill_rectangle (f, f->output_data.x->normal_gc, x, y0, 1, y1 - y0);
1068 #else
1069 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1070 f->output_data.x->normal_gc, x, y0, x, y1);
1071 #endif
1074 /* Draw a window divider from (x0,y0) to (x1,y1) */
1076 static void
1077 x_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
1079 struct frame *f = XFRAME (WINDOW_FRAME (w));
1080 struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
1081 struct face *face_first
1082 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
1083 struct face *face_last
1084 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
1085 unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
1086 unsigned long color_first = (face_first
1087 ? face_first->foreground
1088 : FRAME_FOREGROUND_PIXEL (f));
1089 unsigned long color_last = (face_last
1090 ? face_last->foreground
1091 : FRAME_FOREGROUND_PIXEL (f));
1092 Display *display = FRAME_X_DISPLAY (f);
1094 if (y1 - y0 > x1 - x0 && x1 - x0 > 2)
1095 /* Vertical. */
1097 XSetForeground (display, f->output_data.x->normal_gc, color_first);
1098 x_fill_rectangle (f, f->output_data.x->normal_gc,
1099 x0, y0, 1, y1 - y0);
1100 XSetForeground (display, f->output_data.x->normal_gc, color);
1101 x_fill_rectangle (f, f->output_data.x->normal_gc,
1102 x0 + 1, y0, x1 - x0 - 2, y1 - y0);
1103 XSetForeground (display, f->output_data.x->normal_gc, color_last);
1104 x_fill_rectangle (f, f->output_data.x->normal_gc,
1105 x1 - 1, y0, 1, y1 - y0);
1107 else if (x1 - x0 > y1 - y0 && y1 - y0 > 3)
1108 /* Horizontal. */
1110 XSetForeground (display, f->output_data.x->normal_gc, color_first);
1111 x_fill_rectangle (f, f->output_data.x->normal_gc,
1112 x0, y0, x1 - x0, 1);
1113 XSetForeground (display, f->output_data.x->normal_gc, color);
1114 x_fill_rectangle (f, f->output_data.x->normal_gc,
1115 x0, y0 + 1, x1 - x0, y1 - y0 - 2);
1116 XSetForeground (display, f->output_data.x->normal_gc, color_last);
1117 x_fill_rectangle (f, f->output_data.x->normal_gc,
1118 x0, y1 - 1, x1 - x0, 1);
1120 else
1122 XSetForeground (display, f->output_data.x->normal_gc, color);
1123 x_fill_rectangle (f, f->output_data.x->normal_gc,
1124 x0, y0, x1 - x0, y1 - y0);
1128 /* End update of window W.
1130 Draw vertical borders between horizontally adjacent windows, and
1131 display W's cursor if CURSOR_ON_P is non-zero.
1133 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
1134 glyphs in mouse-face were overwritten. In that case we have to
1135 make sure that the mouse-highlight is properly redrawn.
1137 W may be a menu bar pseudo-window in case we don't have X toolkit
1138 support. Such windows don't have a cursor, so don't display it
1139 here. */
1141 static void
1142 x_update_window_end (struct window *w, bool cursor_on_p,
1143 bool mouse_face_overwritten_p)
1145 if (!w->pseudo_window_p)
1147 block_input ();
1149 if (cursor_on_p)
1150 display_and_set_cursor (w, true,
1151 w->output_cursor.hpos, w->output_cursor.vpos,
1152 w->output_cursor.x, w->output_cursor.y);
1154 if (draw_window_fringes (w, true))
1156 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1157 x_draw_right_divider (w);
1158 else
1159 x_draw_vertical_border (w);
1162 unblock_input ();
1165 /* If a row with mouse-face was overwritten, arrange for
1166 XTframe_up_to_date to redisplay the mouse highlight. */
1167 if (mouse_face_overwritten_p)
1169 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
1171 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1172 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1173 hlinfo->mouse_face_window = Qnil;
1178 /* End update of frame F. This function is installed as a hook in
1179 update_end. */
1181 static void
1182 x_update_end (struct frame *f)
1184 /* Mouse highlight may be displayed again. */
1185 MOUSE_HL_INFO (f)->mouse_face_defer = false;
1187 #ifdef USE_CAIRO
1188 if (FRAME_CR_SURFACE (f))
1190 cairo_t *cr = 0;
1191 block_input();
1192 #if defined (USE_GTK) && defined (HAVE_GTK3)
1193 if (FRAME_GTK_WIDGET (f))
1195 GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
1196 cr = gdk_cairo_create (w);
1198 else
1199 #endif
1201 cairo_surface_t *surface;
1202 int width = FRAME_PIXEL_WIDTH (f);
1203 int height = FRAME_PIXEL_HEIGHT (f);
1204 if (! FRAME_EXTERNAL_TOOL_BAR (f))
1205 height += FRAME_TOOL_BAR_HEIGHT (f);
1206 if (! FRAME_EXTERNAL_MENU_BAR (f))
1207 height += FRAME_MENU_BAR_HEIGHT (f);
1208 surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
1209 FRAME_X_WINDOW (f),
1210 FRAME_DISPLAY_INFO (f)->visual,
1211 width,
1212 height);
1213 cr = cairo_create (surface);
1214 cairo_surface_destroy (surface);
1217 cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), 0, 0);
1218 cairo_paint (cr);
1219 cairo_destroy (cr);
1220 unblock_input ();
1222 #endif /* USE_CAIRO */
1224 #ifndef XFlush
1225 block_input ();
1226 XFlush (FRAME_X_DISPLAY (f));
1227 unblock_input ();
1228 #endif
1232 /* This function is called from various places in xdisp.c
1233 whenever a complete update has been performed. */
1235 static void
1236 XTframe_up_to_date (struct frame *f)
1238 if (FRAME_X_P (f))
1239 FRAME_MOUSE_UPDATE (f);
1243 /* Clear under internal border if any (GTK has its own version). */
1244 #ifndef USE_GTK
1245 void
1246 x_clear_under_internal_border (struct frame *f)
1248 if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
1250 int border = FRAME_INTERNAL_BORDER_WIDTH (f);
1251 int width = FRAME_PIXEL_WIDTH (f);
1252 int height = FRAME_PIXEL_HEIGHT (f);
1253 int margin = FRAME_TOP_MARGIN_HEIGHT (f);
1255 block_input ();
1256 x_clear_area (f, 0, 0, border, height);
1257 x_clear_area (f, 0, margin, width, border);
1258 x_clear_area (f, width - border, 0, border, height);
1259 x_clear_area (f, 0, height - border, width, border);
1260 unblock_input ();
1263 #endif
1265 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
1266 arrow bitmaps, or clear the fringes if no bitmaps are required
1267 before DESIRED_ROW is made current. This function is called from
1268 update_window_line only if it is known that there are differences
1269 between bitmaps to be drawn between current row and DESIRED_ROW. */
1271 static void
1272 x_after_update_window_line (struct window *w, struct glyph_row *desired_row)
1274 eassert (w);
1276 if (!desired_row->mode_line_p && !w->pseudo_window_p)
1277 desired_row->redraw_fringe_bitmaps_p = true;
1279 #ifdef USE_X_TOOLKIT
1280 /* When a window has disappeared, make sure that no rest of
1281 full-width rows stays visible in the internal border. Could
1282 check here if updated window is the leftmost/rightmost window,
1283 but I guess it's not worth doing since vertically split windows
1284 are almost never used, internal border is rarely set, and the
1285 overhead is very small. */
1287 struct frame *f;
1288 int width, height;
1290 if (windows_or_buffers_changed
1291 && desired_row->full_width_p
1292 && (f = XFRAME (w->frame),
1293 width = FRAME_INTERNAL_BORDER_WIDTH (f),
1294 width != 0)
1295 && (height = desired_row->visible_height,
1296 height > 0))
1298 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
1300 block_input ();
1301 x_clear_area (f, 0, y, width, height);
1302 x_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
1303 unblock_input ();
1306 #endif
1309 static void
1310 x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fringe_bitmap_params *p)
1312 struct frame *f = XFRAME (WINDOW_FRAME (w));
1313 Display *display = FRAME_X_DISPLAY (f);
1314 GC gc = f->output_data.x->normal_gc;
1315 struct face *face = p->face;
1317 /* Must clip because of partially visible lines. */
1318 x_clip_to_row (w, row, ANY_AREA, gc);
1320 if (p->bx >= 0 && !p->overlay_p)
1322 /* In case the same realized face is used for fringes and
1323 for something displayed in the text (e.g. face `region' on
1324 mono-displays, the fill style may have been changed to
1325 FillSolid in x_draw_glyph_string_background. */
1326 if (face->stipple)
1327 XSetFillStyle (display, face->gc, FillOpaqueStippled);
1328 else
1329 XSetForeground (display, face->gc, face->background);
1331 x_fill_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
1333 if (!face->stipple)
1334 XSetForeground (display, face->gc, face->foreground);
1337 #ifdef USE_CAIRO
1338 if (p->which && p->which < max_fringe_bmp)
1340 XGCValues gcv;
1342 XGetGCValues (display, gc, GCForeground | GCBackground, &gcv);
1343 XSetForeground (display, gc, (p->cursor_p
1344 ? (p->overlay_p ? face->background
1345 : f->output_data.x->cursor_pixel)
1346 : face->foreground));
1347 XSetBackground (display, gc, face->background);
1348 x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, p->dh,
1349 p->wd, p->h, p->x, p->y, p->overlay_p);
1350 XSetForeground (display, gc, gcv.foreground);
1351 XSetBackground (display, gc, gcv.background);
1353 #else /* not USE_CAIRO */
1354 if (p->which)
1356 Window window = FRAME_X_WINDOW (f);
1357 char *bits;
1358 Pixmap pixmap, clipmask = (Pixmap) 0;
1359 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
1360 XGCValues gcv;
1362 if (p->wd > 8)
1363 bits = (char *) (p->bits + p->dh);
1364 else
1365 bits = (char *) p->bits + p->dh;
1367 /* Draw the bitmap. I believe these small pixmaps can be cached
1368 by the server. */
1369 pixmap = XCreatePixmapFromBitmapData (display, window, bits, p->wd, p->h,
1370 (p->cursor_p
1371 ? (p->overlay_p ? face->background
1372 : f->output_data.x->cursor_pixel)
1373 : face->foreground),
1374 face->background, depth);
1376 if (p->overlay_p)
1378 clipmask = XCreatePixmapFromBitmapData (display,
1379 FRAME_DISPLAY_INFO (f)->root_window,
1380 bits, p->wd, p->h,
1381 1, 0, 1);
1382 gcv.clip_mask = clipmask;
1383 gcv.clip_x_origin = p->x;
1384 gcv.clip_y_origin = p->y;
1385 XChangeGC (display, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
1388 XCopyArea (display, pixmap, window, gc, 0, 0,
1389 p->wd, p->h, p->x, p->y);
1390 XFreePixmap (display, pixmap);
1392 if (p->overlay_p)
1394 gcv.clip_mask = (Pixmap) 0;
1395 XChangeGC (display, gc, GCClipMask, &gcv);
1396 XFreePixmap (display, clipmask);
1399 #endif /* not USE_CAIRO */
1401 x_reset_clip_rectangles (f, gc);
1404 /***********************************************************************
1405 Glyph display
1406 ***********************************************************************/
1410 static void x_set_glyph_string_clipping (struct glyph_string *);
1411 static void x_set_glyph_string_gc (struct glyph_string *);
1412 static void x_draw_glyph_string_foreground (struct glyph_string *);
1413 static void x_draw_composite_glyph_string_foreground (struct glyph_string *);
1414 static void x_draw_glyph_string_box (struct glyph_string *);
1415 static void x_draw_glyph_string (struct glyph_string *);
1416 static _Noreturn void x_delete_glyphs (struct frame *, int);
1417 static void x_compute_glyph_string_overhangs (struct glyph_string *);
1418 static void x_set_cursor_gc (struct glyph_string *);
1419 static void x_set_mode_line_face_gc (struct glyph_string *);
1420 static void x_set_mouse_face_gc (struct glyph_string *);
1421 static bool x_alloc_lighter_color (struct frame *, Display *, Colormap,
1422 unsigned long *, double, int);
1423 static void x_setup_relief_color (struct frame *, struct relief *,
1424 double, int, unsigned long);
1425 static void x_setup_relief_colors (struct glyph_string *);
1426 static void x_draw_image_glyph_string (struct glyph_string *);
1427 static void x_draw_image_relief (struct glyph_string *);
1428 static void x_draw_image_foreground (struct glyph_string *);
1429 static void x_draw_image_foreground_1 (struct glyph_string *, Pixmap);
1430 static void x_clear_glyph_string_rect (struct glyph_string *, int,
1431 int, int, int);
1432 static void x_draw_relief_rect (struct frame *, int, int, int, int,
1433 int, bool, bool, bool, bool, bool,
1434 XRectangle *);
1435 static void x_draw_box_rect (struct glyph_string *, int, int, int, int,
1436 int, bool, bool, XRectangle *);
1437 static void x_scroll_bar_clear (struct frame *);
1439 #ifdef GLYPH_DEBUG
1440 static void x_check_font (struct frame *, struct font *);
1441 #endif
1444 /* Set S->gc to a suitable GC for drawing glyph string S in cursor
1445 face. */
1447 static void
1448 x_set_cursor_gc (struct glyph_string *s)
1450 if (s->font == FRAME_FONT (s->f)
1451 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
1452 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
1453 && !s->cmp)
1454 s->gc = s->f->output_data.x->cursor_gc;
1455 else
1457 /* Cursor on non-default face: must merge. */
1458 XGCValues xgcv;
1459 unsigned long mask;
1461 xgcv.background = s->f->output_data.x->cursor_pixel;
1462 xgcv.foreground = s->face->background;
1464 /* If the glyph would be invisible, try a different foreground. */
1465 if (xgcv.foreground == xgcv.background)
1466 xgcv.foreground = s->face->foreground;
1467 if (xgcv.foreground == xgcv.background)
1468 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
1469 if (xgcv.foreground == xgcv.background)
1470 xgcv.foreground = s->face->foreground;
1472 /* Make sure the cursor is distinct from text in this face. */
1473 if (xgcv.background == s->face->background
1474 && xgcv.foreground == s->face->foreground)
1476 xgcv.background = s->face->foreground;
1477 xgcv.foreground = s->face->background;
1480 IF_DEBUG (x_check_font (s->f, s->font));
1481 xgcv.graphics_exposures = False;
1482 mask = GCForeground | GCBackground | GCGraphicsExposures;
1484 if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1485 XChangeGC (s->display, FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1486 mask, &xgcv);
1487 else
1488 FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
1489 = XCreateGC (s->display, s->window, mask, &xgcv);
1491 s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1496 /* Set up S->gc of glyph string S for drawing text in mouse face. */
1498 static void
1499 x_set_mouse_face_gc (struct glyph_string *s)
1501 int face_id;
1502 struct face *face;
1504 /* What face has to be used last for the mouse face? */
1505 face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
1506 face = FACE_FROM_ID_OR_NULL (s->f, face_id);
1507 if (face == NULL)
1508 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1510 if (s->first_glyph->type == CHAR_GLYPH)
1511 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
1512 else
1513 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
1514 s->face = FACE_FROM_ID (s->f, face_id);
1515 prepare_face_for_display (s->f, s->face);
1517 if (s->font == s->face->font)
1518 s->gc = s->face->gc;
1519 else
1521 /* Otherwise construct scratch_cursor_gc with values from FACE
1522 except for FONT. */
1523 XGCValues xgcv;
1524 unsigned long mask;
1526 xgcv.background = s->face->background;
1527 xgcv.foreground = s->face->foreground;
1528 xgcv.graphics_exposures = False;
1529 mask = GCForeground | GCBackground | GCGraphicsExposures;
1531 if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1532 XChangeGC (s->display, FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1533 mask, &xgcv);
1534 else
1535 FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
1536 = XCreateGC (s->display, s->window, mask, &xgcv);
1538 s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1541 eassert (s->gc != 0);
1545 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
1546 Faces to use in the mode line have already been computed when the
1547 matrix was built, so there isn't much to do, here. */
1549 static void
1550 x_set_mode_line_face_gc (struct glyph_string *s)
1552 s->gc = s->face->gc;
1556 /* Set S->gc of glyph string S for drawing that glyph string. Set
1557 S->stippled_p to a non-zero value if the face of S has a stipple
1558 pattern. */
1560 static void
1561 x_set_glyph_string_gc (struct glyph_string *s)
1563 prepare_face_for_display (s->f, s->face);
1565 if (s->hl == DRAW_NORMAL_TEXT)
1567 s->gc = s->face->gc;
1568 s->stippled_p = s->face->stipple != 0;
1570 else if (s->hl == DRAW_INVERSE_VIDEO)
1572 x_set_mode_line_face_gc (s);
1573 s->stippled_p = s->face->stipple != 0;
1575 else if (s->hl == DRAW_CURSOR)
1577 x_set_cursor_gc (s);
1578 s->stippled_p = false;
1580 else if (s->hl == DRAW_MOUSE_FACE)
1582 x_set_mouse_face_gc (s);
1583 s->stippled_p = s->face->stipple != 0;
1585 else if (s->hl == DRAW_IMAGE_RAISED
1586 || s->hl == DRAW_IMAGE_SUNKEN)
1588 s->gc = s->face->gc;
1589 s->stippled_p = s->face->stipple != 0;
1591 else
1592 emacs_abort ();
1594 /* GC must have been set. */
1595 eassert (s->gc != 0);
1599 /* Set clipping for output of glyph string S. S may be part of a mode
1600 line or menu if we don't have X toolkit support. */
1602 static void
1603 x_set_glyph_string_clipping (struct glyph_string *s)
1605 XRectangle *r = s->clip;
1606 int n = get_glyph_string_clip_rects (s, r, 2);
1608 if (n > 0)
1609 x_set_clip_rectangles (s->f, s->gc, r, n);
1610 s->num_clips = n;
1614 /* Set SRC's clipping for output of glyph string DST. This is called
1615 when we are drawing DST's left_overhang or right_overhang only in
1616 the area of SRC. */
1618 static void
1619 x_set_glyph_string_clipping_exactly (struct glyph_string *src, struct glyph_string *dst)
1621 XRectangle r;
1623 r.x = src->x;
1624 r.width = src->width;
1625 r.y = src->y;
1626 r.height = src->height;
1627 dst->clip[0] = r;
1628 dst->num_clips = 1;
1629 x_set_clip_rectangles (dst->f, dst->gc, &r, 1);
1633 /* RIF:
1634 Compute left and right overhang of glyph string S. */
1636 static void
1637 x_compute_glyph_string_overhangs (struct glyph_string *s)
1639 if (s->cmp == NULL
1640 && (s->first_glyph->type == CHAR_GLYPH
1641 || s->first_glyph->type == COMPOSITE_GLYPH))
1643 struct font_metrics metrics;
1645 if (s->first_glyph->type == CHAR_GLYPH)
1647 unsigned *code = alloca (sizeof (unsigned) * s->nchars);
1648 struct font *font = s->font;
1649 int i;
1651 for (i = 0; i < s->nchars; i++)
1652 code[i] = (s->char2b[i].byte1 << 8) | s->char2b[i].byte2;
1653 font->driver->text_extents (font, code, s->nchars, &metrics);
1655 else
1657 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1659 composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics);
1661 s->right_overhang = (metrics.rbearing > metrics.width
1662 ? metrics.rbearing - metrics.width : 0);
1663 s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0;
1665 else if (s->cmp)
1667 s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
1668 s->left_overhang = - s->cmp->lbearing;
1673 /* Fill rectangle X, Y, W, H with background color of glyph string S. */
1675 static void
1676 x_clear_glyph_string_rect (struct glyph_string *s, int x, int y, int w, int h)
1678 XGCValues xgcv;
1679 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
1680 XSetForeground (s->display, s->gc, xgcv.background);
1681 x_fill_rectangle (s->f, s->gc, x, y, w, h);
1682 XSetForeground (s->display, s->gc, xgcv.foreground);
1686 /* Draw the background of glyph_string S. If S->background_filled_p
1687 is non-zero don't draw it. FORCE_P non-zero means draw the
1688 background even if it wouldn't be drawn normally. This is used
1689 when a string preceding S draws into the background of S, or S
1690 contains the first component of a composition. */
1692 static void
1693 x_draw_glyph_string_background (struct glyph_string *s, bool force_p)
1695 /* Nothing to do if background has already been drawn or if it
1696 shouldn't be drawn in the first place. */
1697 if (!s->background_filled_p)
1699 int box_line_width = max (s->face->box_line_width, 0);
1701 if (s->stippled_p)
1703 /* Fill background with a stipple pattern. */
1704 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
1705 x_fill_rectangle (s->f, s->gc, s->x,
1706 s->y + box_line_width,
1707 s->background_width,
1708 s->height - 2 * box_line_width);
1709 XSetFillStyle (s->display, s->gc, FillSolid);
1710 s->background_filled_p = true;
1712 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
1713 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust
1714 font dimensions, since the actual glyphs might be
1715 much smaller. So in that case we always clear the
1716 rectangle with background color. */
1717 || FONT_TOO_HIGH (s->font)
1718 || s->font_not_found_p
1719 || s->extends_to_end_of_line_p
1720 || force_p)
1722 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
1723 s->background_width,
1724 s->height - 2 * box_line_width);
1725 s->background_filled_p = true;
1731 /* Draw the foreground of glyph string S. */
1733 static void
1734 x_draw_glyph_string_foreground (struct glyph_string *s)
1736 int i, x;
1738 /* If first glyph of S has a left box line, start drawing the text
1739 of S to the right of that box line. */
1740 if (s->face->box != FACE_NO_BOX
1741 && s->first_glyph->left_box_line_p)
1742 x = s->x + eabs (s->face->box_line_width);
1743 else
1744 x = s->x;
1746 /* Draw characters of S as rectangles if S's font could not be
1747 loaded. */
1748 if (s->font_not_found_p)
1750 for (i = 0; i < s->nchars; ++i)
1752 struct glyph *g = s->first_glyph + i;
1753 x_draw_rectangle (s->f,
1754 s->gc, x, s->y, g->pixel_width - 1,
1755 s->height - 1);
1756 x += g->pixel_width;
1759 else
1761 struct font *font = s->font;
1762 int boff = font->baseline_offset;
1763 int y;
1765 if (font->vertical_centering)
1766 boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff;
1768 y = s->ybase - boff;
1769 if (s->for_overlaps
1770 || (s->background_filled_p && s->hl != DRAW_CURSOR))
1771 font->driver->draw (s, 0, s->nchars, x, y, false);
1772 else
1773 font->driver->draw (s, 0, s->nchars, x, y, true);
1774 if (s->face->overstrike)
1775 font->driver->draw (s, 0, s->nchars, x + 1, y, false);
1779 /* Draw the foreground of composite glyph string S. */
1781 static void
1782 x_draw_composite_glyph_string_foreground (struct glyph_string *s)
1784 int i, j, x;
1785 struct font *font = s->font;
1787 /* If first glyph of S has a left box line, start drawing the text
1788 of S to the right of that box line. */
1789 if (s->face && s->face->box != FACE_NO_BOX
1790 && s->first_glyph->left_box_line_p)
1791 x = s->x + eabs (s->face->box_line_width);
1792 else
1793 x = s->x;
1795 /* S is a glyph string for a composition. S->cmp_from is the index
1796 of the first character drawn for glyphs of this composition.
1797 S->cmp_from == 0 means we are drawing the very first character of
1798 this composition. */
1800 /* Draw a rectangle for the composition if the font for the very
1801 first character of the composition could not be loaded. */
1802 if (s->font_not_found_p)
1804 if (s->cmp_from == 0)
1805 x_draw_rectangle (s->f, s->gc, x, s->y,
1806 s->width - 1, s->height - 1);
1808 else if (! s->first_glyph->u.cmp.automatic)
1810 int y = s->ybase;
1812 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
1813 /* TAB in a composition means display glyphs with padding
1814 space on the left or right. */
1815 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
1817 int xx = x + s->cmp->offsets[j * 2];
1818 int yy = y - s->cmp->offsets[j * 2 + 1];
1820 font->driver->draw (s, j, j + 1, xx, yy, false);
1821 if (s->face->overstrike)
1822 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
1825 else
1827 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1828 Lisp_Object glyph;
1829 int y = s->ybase;
1830 int width = 0;
1832 for (i = j = s->cmp_from; i < s->cmp_to; i++)
1834 glyph = LGSTRING_GLYPH (gstring, i);
1835 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1836 width += LGLYPH_WIDTH (glyph);
1837 else
1839 int xoff, yoff, wadjust;
1841 if (j < i)
1843 font->driver->draw (s, j, i, x, y, false);
1844 if (s->face->overstrike)
1845 font->driver->draw (s, j, i, x + 1, y, false);
1846 x += width;
1848 xoff = LGLYPH_XOFF (glyph);
1849 yoff = LGLYPH_YOFF (glyph);
1850 wadjust = LGLYPH_WADJUST (glyph);
1851 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
1852 if (s->face->overstrike)
1853 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
1854 false);
1855 x += wadjust;
1856 j = i + 1;
1857 width = 0;
1860 if (j < i)
1862 font->driver->draw (s, j, i, x, y, false);
1863 if (s->face->overstrike)
1864 font->driver->draw (s, j, i, x + 1, y, false);
1870 /* Draw the foreground of glyph string S for glyphless characters. */
1872 static void
1873 x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
1875 struct glyph *glyph = s->first_glyph;
1876 XChar2b char2b[8];
1877 int x, i, j;
1879 /* If first glyph of S has a left box line, start drawing the text
1880 of S to the right of that box line. */
1881 if (s->face && s->face->box != FACE_NO_BOX
1882 && s->first_glyph->left_box_line_p)
1883 x = s->x + eabs (s->face->box_line_width);
1884 else
1885 x = s->x;
1887 s->char2b = char2b;
1889 for (i = 0; i < s->nchars; i++, glyph++)
1891 char buf[7], *str = NULL;
1892 int len = glyph->u.glyphless.len;
1894 if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
1896 if (len > 0
1897 && CHAR_TABLE_P (Vglyphless_char_display)
1898 && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
1899 >= 1))
1901 Lisp_Object acronym
1902 = (! glyph->u.glyphless.for_no_font
1903 ? CHAR_TABLE_REF (Vglyphless_char_display,
1904 glyph->u.glyphless.ch)
1905 : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
1906 if (STRINGP (acronym))
1907 str = SSDATA (acronym);
1910 else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE)
1912 sprintf (buf, "%0*X",
1913 glyph->u.glyphless.ch < 0x10000 ? 4 : 6,
1914 glyph->u.glyphless.ch + 0u);
1915 str = buf;
1918 if (str)
1920 int upper_len = (len + 1) / 2;
1921 unsigned code;
1923 /* It is assured that all LEN characters in STR is ASCII. */
1924 for (j = 0; j < len; j++)
1926 code = s->font->driver->encode_char (s->font, str[j]);
1927 STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF);
1929 s->font->driver->draw (s, 0, upper_len,
1930 x + glyph->slice.glyphless.upper_xoff,
1931 s->ybase + glyph->slice.glyphless.upper_yoff,
1932 false);
1933 s->font->driver->draw (s, upper_len, len,
1934 x + glyph->slice.glyphless.lower_xoff,
1935 s->ybase + glyph->slice.glyphless.lower_yoff,
1936 false);
1938 if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
1939 x_draw_rectangle (s->f, s->gc,
1940 x, s->ybase - glyph->ascent,
1941 glyph->pixel_width - 1,
1942 glyph->ascent + glyph->descent - 1);
1943 x += glyph->pixel_width;
1947 #ifdef USE_X_TOOLKIT
1949 #ifdef USE_LUCID
1951 /* Return the frame on which widget WIDGET is used.. Abort if frame
1952 cannot be determined. */
1954 static struct frame *
1955 x_frame_of_widget (Widget widget)
1957 struct x_display_info *dpyinfo;
1958 Lisp_Object tail, frame;
1959 struct frame *f;
1961 dpyinfo = x_display_info_for_display (XtDisplay (widget));
1963 /* Find the top-level shell of the widget. Note that this function
1964 can be called when the widget is not yet realized, so XtWindow
1965 (widget) == 0. That's the reason we can't simply use
1966 x_any_window_to_frame. */
1967 while (!XtIsTopLevelShell (widget))
1968 widget = XtParent (widget);
1970 /* Look for a frame with that top-level widget. Allocate the color
1971 on that frame to get the right gamma correction value. */
1972 FOR_EACH_FRAME (tail, frame)
1974 f = XFRAME (frame);
1975 if (FRAME_X_P (f)
1976 && f->output_data.nothing != 1
1977 && FRAME_DISPLAY_INFO (f) == dpyinfo
1978 && f->output_data.x->widget == widget)
1979 return f;
1981 emacs_abort ();
1984 /* Allocate a color which is lighter or darker than *PIXEL by FACTOR
1985 or DELTA. Try a color with RGB values multiplied by FACTOR first.
1986 If this produces the same color as PIXEL, try a color where all RGB
1987 values have DELTA added. Return the allocated color in *PIXEL.
1988 DISPLAY is the X display, CMAP is the colormap to operate on.
1989 Value is true if successful. */
1991 bool
1992 x_alloc_lighter_color_for_widget (Widget widget, Display *display, Colormap cmap,
1993 unsigned long *pixel, double factor, int delta)
1995 struct frame *f = x_frame_of_widget (widget);
1996 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
1999 #endif /* USE_LUCID */
2002 /* Structure specifying which arguments should be passed by Xt to
2003 cvt_string_to_pixel. We want the widget's screen and colormap. */
2005 static XtConvertArgRec cvt_string_to_pixel_args[] =
2007 {XtWidgetBaseOffset, (XtPointer) offsetof (WidgetRec, core.screen),
2008 sizeof (Screen *)},
2009 {XtWidgetBaseOffset, (XtPointer) offsetof (WidgetRec, core.colormap),
2010 sizeof (Colormap)}
2014 /* The address of this variable is returned by
2015 cvt_string_to_pixel. */
2017 static Pixel cvt_string_to_pixel_value;
2020 /* Convert a color name to a pixel color.
2022 DPY is the display we are working on.
2024 ARGS is an array of *NARGS XrmValue structures holding additional
2025 information about the widget for which the conversion takes place.
2026 The contents of this array are determined by the specification
2027 in cvt_string_to_pixel_args.
2029 FROM is a pointer to an XrmValue which points to the color name to
2030 convert. TO is an XrmValue in which to return the pixel color.
2032 CLOSURE_RET is a pointer to user-data, in which we record if
2033 we allocated the color or not.
2035 Value is True if successful, False otherwise. */
2037 static Boolean
2038 cvt_string_to_pixel (Display *dpy, XrmValue *args, Cardinal *nargs,
2039 XrmValue *from, XrmValue *to,
2040 XtPointer *closure_ret)
2042 Screen *screen;
2043 Colormap cmap;
2044 Pixel pixel;
2045 String color_name;
2046 XColor color;
2048 if (*nargs != 2)
2050 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
2051 "wrongParameters", "cvt_string_to_pixel",
2052 "XtToolkitError",
2053 "Screen and colormap args required", NULL, NULL);
2054 return False;
2057 screen = *(Screen **) args[0].addr;
2058 cmap = *(Colormap *) args[1].addr;
2059 color_name = (String) from->addr;
2061 if (strcmp (color_name, XtDefaultBackground) == 0)
2063 *closure_ret = (XtPointer) False;
2064 pixel = WhitePixelOfScreen (screen);
2066 else if (strcmp (color_name, XtDefaultForeground) == 0)
2068 *closure_ret = (XtPointer) False;
2069 pixel = BlackPixelOfScreen (screen);
2071 else if (XParseColor (dpy, cmap, color_name, &color)
2072 && x_alloc_nearest_color_1 (dpy, cmap, &color))
2074 pixel = color.pixel;
2075 *closure_ret = (XtPointer) True;
2077 else
2079 String params[1];
2080 Cardinal nparams = 1;
2082 params[0] = color_name;
2083 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
2084 "badValue", "cvt_string_to_pixel",
2085 "XtToolkitError", "Invalid color '%s'",
2086 params, &nparams);
2087 return False;
2090 if (to->addr != NULL)
2092 if (to->size < sizeof (Pixel))
2094 to->size = sizeof (Pixel);
2095 return False;
2098 *(Pixel *) to->addr = pixel;
2100 else
2102 cvt_string_to_pixel_value = pixel;
2103 to->addr = (XtPointer) &cvt_string_to_pixel_value;
2106 to->size = sizeof (Pixel);
2107 return True;
2111 /* Free a pixel color which was previously allocated via
2112 cvt_string_to_pixel. This is registered as the destructor
2113 for this type of resource via XtSetTypeConverter.
2115 APP is the application context in which we work.
2117 TO is a pointer to an XrmValue holding the color to free.
2118 CLOSURE is the value we stored in CLOSURE_RET for this color
2119 in cvt_string_to_pixel.
2121 ARGS and NARGS are like for cvt_string_to_pixel. */
2123 static void
2124 cvt_pixel_dtor (XtAppContext app, XrmValuePtr to, XtPointer closure, XrmValuePtr args,
2125 Cardinal *nargs)
2127 if (*nargs != 2)
2129 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
2130 "XtToolkitError",
2131 "Screen and colormap arguments required",
2132 NULL, NULL);
2134 else if (closure != NULL)
2136 /* We did allocate the pixel, so free it. */
2137 Screen *screen = *(Screen **) args[0].addr;
2138 Colormap cmap = *(Colormap *) args[1].addr;
2139 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
2140 (Pixel *) to->addr, 1);
2145 #endif /* USE_X_TOOLKIT */
2148 /* Value is an array of XColor structures for the contents of the
2149 color map of display DPY. Set *NCELLS to the size of the array.
2150 Note that this probably shouldn't be called for large color maps,
2151 say a 24-bit TrueColor map. */
2153 static const XColor *
2154 x_color_cells (Display *dpy, int *ncells)
2156 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
2157 eassume (dpyinfo);
2159 if (dpyinfo->color_cells == NULL)
2161 Screen *screen = dpyinfo->screen;
2162 int ncolor_cells = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
2163 int i;
2165 dpyinfo->color_cells = xnmalloc (ncolor_cells,
2166 sizeof *dpyinfo->color_cells);
2167 dpyinfo->ncolor_cells = ncolor_cells;
2169 for (i = 0; i < ncolor_cells; ++i)
2170 dpyinfo->color_cells[i].pixel = i;
2172 XQueryColors (dpy, dpyinfo->cmap,
2173 dpyinfo->color_cells, ncolor_cells);
2176 *ncells = dpyinfo->ncolor_cells;
2177 return dpyinfo->color_cells;
2181 /* On frame F, translate pixel colors to RGB values for the NCOLORS
2182 colors in COLORS. Use cached information, if available. */
2184 void
2185 x_query_colors (struct frame *f, XColor *colors, int ncolors)
2187 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2189 if (dpyinfo->red_bits > 0)
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;
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.
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.
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;
2217 for (i = 0; i < ncolors; ++i)
2219 unsigned int r, g, b;
2220 unsigned long pixel = colors[i].pixel;
2222 r = (pixel >> dpyinfo->red_offset) & rmask;
2223 g = (pixel >> dpyinfo->green_offset) & gmask;
2224 b = (pixel >> dpyinfo->blue_offset) & bmask;
2226 colors[i].red = (r * rmult) >> 16;
2227 colors[i].green = (g * gmult) >> 16;
2228 colors[i].blue = (b * bmult) >> 16;
2230 return;
2233 if (dpyinfo->color_cells)
2235 int i;
2236 for (i = 0; i < ncolors; ++i)
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];
2243 return;
2246 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
2250 /* On frame F, translate pixel color to RGB values for the color in
2251 COLOR. Use cached information, if available. */
2253 void
2254 x_query_color (struct frame *f, XColor *color)
2256 x_query_colors (f, color, 1);
2260 /* On frame F, translate the color name to RGB values. Use cached
2261 information, if possible.
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. */
2268 Status x_parse_color (struct frame *f, const char *color_name,
2269 XColor *color)
2271 Display *dpy = FRAME_X_DISPLAY (f);
2272 Colormap cmap = FRAME_X_COLORMAP (f);
2273 struct color_name_cache_entry *cache_entry;
2275 if (color_name[0] == '#')
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);
2282 for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names; cache_entry;
2283 cache_entry = cache_entry->next)
2285 if (!xstrcasecmp(cache_entry->name, color_name))
2287 *color = cache_entry->rgb;
2288 return 1;
2292 if (XParseColor (dpy, cmap, color_name, color) == 0)
2293 /* No caching of negative results, currently. */
2294 return 0;
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;
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. */
2310 static bool
2311 x_alloc_nearest_color_1 (Display *dpy, Colormap cmap, XColor *color)
2313 bool rc;
2315 rc = XAllocColor (dpy, cmap, color) != 0;
2316 if (rc == 0)
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);
2329 for (nearest = i = 0; i < ncells; ++i)
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;
2336 if (delta < nearest_delta)
2338 nearest = i;
2339 nearest_delta = delta;
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;
2348 else
2350 /* If allocation succeeded, and the allocated pixel color is not
2351 equal to a cached pixel color recorded earlier, there was a
2352 change in the colormap, so clear the color cache. */
2353 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
2354 eassume (dpyinfo);
2356 if (dpyinfo->color_cells)
2358 XColor *cached_color = &dpyinfo->color_cells[color->pixel];
2359 if (cached_color->red != color->red
2360 || cached_color->blue != color->blue
2361 || cached_color->green != color->green)
2363 xfree (dpyinfo->color_cells);
2364 dpyinfo->color_cells = NULL;
2365 dpyinfo->ncolor_cells = 0;
2370 #ifdef DEBUG_X_COLORS
2371 if (rc)
2372 register_color (color->pixel);
2373 #endif /* DEBUG_X_COLORS */
2375 return rc;
2379 /* Allocate the color COLOR->pixel on frame F, colormap CMAP, after
2380 gamma correction. If an exact match can't be allocated, try the
2381 nearest color available. Value is true if successful. Set *COLOR
2382 to the color allocated. */
2384 bool
2385 x_alloc_nearest_color (struct frame *f, Colormap cmap, XColor *color)
2387 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2389 gamma_correct (f, color);
2391 if (dpyinfo->red_bits > 0)
2393 color->pixel = x_make_truecolor_pixel (dpyinfo,
2394 color->red,
2395 color->green,
2396 color->blue);
2397 return true;
2400 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
2404 /* Allocate color PIXEL on frame F. PIXEL must already be allocated.
2405 It's necessary to do this instead of just using PIXEL directly to
2406 get color reference counts right. */
2408 unsigned long
2409 x_copy_color (struct frame *f, unsigned long pixel)
2411 XColor color;
2413 /* If display has an immutable color map, freeing colors is not
2414 necessary and some servers don't allow it. Since we won't free a
2415 color once we've allocated it, we don't need to re-allocate it to
2416 maintain the server's reference count. */
2417 if (!x_mutable_colormap (FRAME_X_VISUAL (f)))
2418 return pixel;
2420 color.pixel = pixel;
2421 block_input ();
2422 /* The color could still be found in the color_cells array. */
2423 x_query_color (f, &color);
2424 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
2425 unblock_input ();
2426 #ifdef DEBUG_X_COLORS
2427 register_color (pixel);
2428 #endif
2429 return color.pixel;
2433 /* Brightness beyond which a color won't have its highlight brightness
2434 boosted.
2436 Nominally, highlight colors for `3d' faces are calculated by
2437 brightening an object's color by a constant scale factor, but this
2438 doesn't yield good results for dark colors, so for colors who's
2439 brightness is less than this value (on a scale of 0-65535) have an
2440 use an additional additive factor.
2442 The value here is set so that the default menu-bar/mode-line color
2443 (grey75) will not have its highlights changed at all. */
2444 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
2447 /* Allocate a color which is lighter or darker than *PIXEL by FACTOR
2448 or DELTA. Try a color with RGB values multiplied by FACTOR first.
2449 If this produces the same color as PIXEL, try a color where all RGB
2450 values have DELTA added. Return the allocated color in *PIXEL.
2451 DISPLAY is the X display, CMAP is the colormap to operate on.
2452 Value is non-zero if successful. */
2454 static bool
2455 x_alloc_lighter_color (struct frame *f, Display *display, Colormap cmap,
2456 unsigned long *pixel, double factor, int delta)
2458 XColor color, new;
2459 long bright;
2460 bool success_p;
2462 /* Get RGB color values. */
2463 color.pixel = *pixel;
2464 x_query_color (f, &color);
2466 /* Change RGB values by specified FACTOR. Avoid overflow! */
2467 eassert (factor >= 0);
2468 new.red = min (0xffff, factor * color.red);
2469 new.green = min (0xffff, factor * color.green);
2470 new.blue = min (0xffff, factor * color.blue);
2472 /* Calculate brightness of COLOR. */
2473 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
2475 /* We only boost colors that are darker than
2476 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
2477 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
2478 /* Make an additive adjustment to NEW, because it's dark enough so
2479 that scaling by FACTOR alone isn't enough. */
2481 /* How far below the limit this color is (0 - 1, 1 being darker). */
2482 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
2483 /* The additive adjustment. */
2484 int min_delta = delta * dimness * factor / 2;
2486 if (factor < 1)
2488 new.red = max (0, new.red - min_delta);
2489 new.green = max (0, new.green - min_delta);
2490 new.blue = max (0, new.blue - min_delta);
2492 else
2494 new.red = min (0xffff, min_delta + new.red);
2495 new.green = min (0xffff, min_delta + new.green);
2496 new.blue = min (0xffff, min_delta + new.blue);
2500 /* Try to allocate the color. */
2501 success_p = x_alloc_nearest_color (f, cmap, &new);
2502 if (success_p)
2504 if (new.pixel == *pixel)
2506 /* If we end up with the same color as before, try adding
2507 delta to the RGB values. */
2508 x_free_colors (f, &new.pixel, 1);
2510 new.red = min (0xffff, delta + color.red);
2511 new.green = min (0xffff, delta + color.green);
2512 new.blue = min (0xffff, delta + color.blue);
2513 success_p = x_alloc_nearest_color (f, cmap, &new);
2515 else
2516 success_p = true;
2517 *pixel = new.pixel;
2520 return success_p;
2524 /* Set up the foreground color for drawing relief lines of glyph
2525 string S. RELIEF is a pointer to a struct relief containing the GC
2526 with which lines will be drawn. Use a color that is FACTOR or
2527 DELTA lighter or darker than the relief's background which is found
2528 in S->f->output_data.x->relief_background. If such a color cannot
2529 be allocated, use DEFAULT_PIXEL, instead. */
2531 static void
2532 x_setup_relief_color (struct frame *f, struct relief *relief, double factor,
2533 int delta, unsigned long default_pixel)
2535 XGCValues xgcv;
2536 struct x_output *di = f->output_data.x;
2537 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
2538 unsigned long pixel;
2539 unsigned long background = di->relief_background;
2540 Colormap cmap = FRAME_X_COLORMAP (f);
2541 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2542 Display *dpy = FRAME_X_DISPLAY (f);
2544 xgcv.graphics_exposures = False;
2545 xgcv.line_width = 1;
2547 /* Free previously allocated color. The color cell will be reused
2548 when it has been freed as many times as it was allocated, so this
2549 doesn't affect faces using the same colors. */
2550 if (relief->gc && relief->pixel != -1)
2552 x_free_colors (f, &relief->pixel, 1);
2553 relief->pixel = -1;
2556 /* Allocate new color. */
2557 xgcv.foreground = default_pixel;
2558 pixel = background;
2559 if (dpyinfo->n_planes != 1
2560 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
2561 xgcv.foreground = relief->pixel = pixel;
2563 if (relief->gc == 0)
2565 xgcv.stipple = dpyinfo->gray;
2566 mask |= GCStipple;
2567 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
2569 else
2570 XChangeGC (dpy, relief->gc, mask, &xgcv);
2574 /* Set up colors for the relief lines around glyph string S. */
2576 static void
2577 x_setup_relief_colors (struct glyph_string *s)
2579 struct x_output *di = s->f->output_data.x;
2580 unsigned long color;
2582 if (s->face->use_box_color_for_shadows_p)
2583 color = s->face->box_color;
2584 else if (s->first_glyph->type == IMAGE_GLYPH
2585 && s->img->pixmap
2586 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2587 color = IMAGE_BACKGROUND (s->img, s->f, 0);
2588 else
2590 XGCValues xgcv;
2592 /* Get the background color of the face. */
2593 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
2594 color = xgcv.background;
2597 if (di->white_relief.gc == 0
2598 || color != di->relief_background)
2600 di->relief_background = color;
2601 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
2602 WHITE_PIX_DEFAULT (s->f));
2603 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
2604 BLACK_PIX_DEFAULT (s->f));
2609 /* Draw a relief on frame F inside the rectangle given by LEFT_X,
2610 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
2611 to draw, it must be >= 0. RAISED_P means draw a raised
2612 relief. LEFT_P means draw a relief on the left side of
2613 the rectangle. RIGHT_P means draw a relief on the right
2614 side of the rectangle. CLIP_RECT is the clipping rectangle to use
2615 when drawing. */
2617 static void
2618 x_draw_relief_rect (struct frame *f,
2619 int left_x, int top_y, int right_x, int bottom_y,
2620 int width, bool raised_p, bool top_p, bool bot_p,
2621 bool left_p, bool right_p,
2622 XRectangle *clip_rect)
2624 #ifdef USE_CAIRO
2625 GC top_left_gc, bottom_right_gc;
2626 int corners = 0;
2628 if (raised_p)
2630 top_left_gc = f->output_data.x->white_relief.gc;
2631 bottom_right_gc = f->output_data.x->black_relief.gc;
2633 else
2635 top_left_gc = f->output_data.x->black_relief.gc;
2636 bottom_right_gc = f->output_data.x->white_relief.gc;
2639 x_set_clip_rectangles (f, top_left_gc, clip_rect, 1);
2640 x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1);
2642 if (left_p)
2644 x_fill_rectangle (f, top_left_gc, left_x, top_y,
2645 width, bottom_y + 1 - top_y);
2646 if (top_p)
2647 corners |= 1 << CORNER_TOP_LEFT;
2648 if (bot_p)
2649 corners |= 1 << CORNER_BOTTOM_LEFT;
2651 if (right_p)
2653 x_fill_rectangle (f, bottom_right_gc, right_x + 1 - width, top_y,
2654 width, bottom_y + 1 - top_y);
2655 if (top_p)
2656 corners |= 1 << CORNER_TOP_RIGHT;
2657 if (bot_p)
2658 corners |= 1 << CORNER_BOTTOM_RIGHT;
2660 if (top_p)
2662 if (!right_p)
2663 x_fill_rectangle (f, top_left_gc, left_x, top_y,
2664 right_x + 1 - left_x, width);
2665 else
2666 x_fill_trapezoid_for_relief (f, top_left_gc, left_x, top_y,
2667 right_x + 1 - left_x, width, 1);
2669 if (bot_p)
2671 if (!left_p)
2672 x_fill_rectangle (f, bottom_right_gc, left_x, bottom_y + 1 - width,
2673 right_x + 1 - left_x, width);
2674 else
2675 x_fill_trapezoid_for_relief (f, bottom_right_gc,
2676 left_x, bottom_y + 1 - width,
2677 right_x + 1 - left_x, width, 0);
2679 if (left_p && width != 1)
2680 x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
2681 1, bottom_y + 1 - top_y);
2682 if (top_p && width != 1)
2683 x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
2684 right_x + 1 - left_x, 1);
2685 if (corners)
2687 XSetBackground (FRAME_X_DISPLAY (f), top_left_gc,
2688 FRAME_BACKGROUND_PIXEL (f));
2689 x_erase_corners_for_relief (f, top_left_gc, left_x, top_y,
2690 right_x - left_x + 1, bottom_y - top_y + 1,
2691 6, 1, corners);
2694 x_reset_clip_rectangles (f, top_left_gc);
2695 x_reset_clip_rectangles (f, bottom_right_gc);
2696 #else
2697 Display *dpy = FRAME_X_DISPLAY (f);
2698 Window window = FRAME_X_WINDOW (f);
2699 int i;
2700 GC gc;
2702 if (raised_p)
2703 gc = f->output_data.x->white_relief.gc;
2704 else
2705 gc = f->output_data.x->black_relief.gc;
2706 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
2708 /* This code is more complicated than it has to be, because of two
2709 minor hacks to make the boxes look nicer: (i) if width > 1, draw
2710 the outermost line using the black relief. (ii) Omit the four
2711 corner pixels. */
2713 /* Top. */
2714 if (top_p)
2716 if (width == 1)
2717 XDrawLine (dpy, window, gc,
2718 left_x + left_p, top_y,
2719 right_x + !right_p, top_y);
2721 for (i = 1; i < width; ++i)
2722 XDrawLine (dpy, window, gc,
2723 left_x + i * left_p, top_y + i,
2724 right_x + 1 - i * right_p, top_y + i);
2727 /* Left. */
2728 if (left_p)
2730 if (width == 1)
2731 XDrawLine (dpy, window, gc, left_x, top_y + 1, left_x, bottom_y);
2733 XClearArea (dpy, window, left_x, top_y, 1, 1, False);
2734 XClearArea (dpy, window, left_x, bottom_y, 1, 1, False);
2736 for (i = (width > 1 ? 1 : 0); i < width; ++i)
2737 XDrawLine (dpy, window, gc,
2738 left_x + i, top_y + (i + 1) * top_p,
2739 left_x + i, bottom_y + 1 - (i + 1) * bot_p);
2742 XSetClipMask (dpy, gc, None);
2743 if (raised_p)
2744 gc = f->output_data.x->black_relief.gc;
2745 else
2746 gc = f->output_data.x->white_relief.gc;
2747 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
2749 if (width > 1)
2751 /* Outermost top line. */
2752 if (top_p)
2753 XDrawLine (dpy, window, gc,
2754 left_x + left_p, top_y,
2755 right_x + !right_p, top_y);
2757 /* Outermost left line. */
2758 if (left_p)
2759 XDrawLine (dpy, window, gc, left_x, top_y + 1, left_x, bottom_y);
2762 /* Bottom. */
2763 if (bot_p)
2765 XDrawLine (dpy, window, gc,
2766 left_x + left_p, bottom_y,
2767 right_x + !right_p, bottom_y);
2768 for (i = 1; i < width; ++i)
2769 XDrawLine (dpy, window, gc,
2770 left_x + i * left_p, bottom_y - i,
2771 right_x + 1 - i * right_p, bottom_y - i);
2774 /* Right. */
2775 if (right_p)
2777 XClearArea (dpy, window, right_x, top_y, 1, 1, False);
2778 XClearArea (dpy, window, right_x, bottom_y, 1, 1, False);
2779 for (i = 0; i < width; ++i)
2780 XDrawLine (dpy, window, gc,
2781 right_x - i, top_y + (i + 1) * top_p,
2782 right_x - i, bottom_y + 1 - (i + 1) * bot_p);
2785 x_reset_clip_rectangles (f, gc);
2787 #endif
2791 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
2792 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
2793 draw, it must be >= 0. LEFT_P means draw a line on the
2794 left side of the rectangle. RIGHT_P means draw a line
2795 on the right side of the rectangle. CLIP_RECT is the clipping
2796 rectangle to use when drawing. */
2798 static void
2799 x_draw_box_rect (struct glyph_string *s,
2800 int left_x, int top_y, int right_x, int bottom_y, int width,
2801 bool left_p, bool right_p, XRectangle *clip_rect)
2803 XGCValues xgcv;
2805 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
2806 XSetForeground (s->display, s->gc, s->face->box_color);
2807 x_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
2809 /* Top. */
2810 x_fill_rectangle (s->f, s->gc,
2811 left_x, top_y, right_x - left_x + 1, width);
2813 /* Left. */
2814 if (left_p)
2815 x_fill_rectangle (s->f, s->gc,
2816 left_x, top_y, width, bottom_y - top_y + 1);
2818 /* Bottom. */
2819 x_fill_rectangle (s->f, s->gc,
2820 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
2822 /* Right. */
2823 if (right_p)
2824 x_fill_rectangle (s->f, s->gc,
2825 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
2827 XSetForeground (s->display, s->gc, xgcv.foreground);
2828 x_reset_clip_rectangles (s->f, s->gc);
2832 /* Draw a box around glyph string S. */
2834 static void
2835 x_draw_glyph_string_box (struct glyph_string *s)
2837 int width, left_x, right_x, top_y, bottom_y, last_x;
2838 bool raised_p, left_p, right_p;
2839 struct glyph *last_glyph;
2840 XRectangle clip_rect;
2842 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2843 ? WINDOW_RIGHT_EDGE_X (s->w)
2844 : window_box_right (s->w, s->area));
2846 /* The glyph that may have a right box line. */
2847 last_glyph = (s->cmp || s->img
2848 ? s->first_glyph
2849 : s->first_glyph + s->nchars - 1);
2851 width = eabs (s->face->box_line_width);
2852 raised_p = s->face->box == FACE_RAISED_BOX;
2853 left_x = s->x;
2854 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
2855 ? last_x - 1
2856 : min (last_x, s->x + s->background_width) - 1);
2857 top_y = s->y;
2858 bottom_y = top_y + s->height - 1;
2860 left_p = (s->first_glyph->left_box_line_p
2861 || (s->hl == DRAW_MOUSE_FACE
2862 && (s->prev == NULL
2863 || s->prev->hl != s->hl)));
2864 right_p = (last_glyph->right_box_line_p
2865 || (s->hl == DRAW_MOUSE_FACE
2866 && (s->next == NULL
2867 || s->next->hl != s->hl)));
2869 get_glyph_string_clip_rect (s, &clip_rect);
2871 if (s->face->box == FACE_SIMPLE_BOX)
2872 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
2873 left_p, right_p, &clip_rect);
2874 else
2876 x_setup_relief_colors (s);
2877 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
2878 width, raised_p, true, true, left_p, right_p,
2879 &clip_rect);
2884 /* Draw foreground of image glyph string S. */
2886 static void
2887 x_draw_image_foreground (struct glyph_string *s)
2889 int x = s->x;
2890 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2892 /* If first glyph of S has a left box line, start drawing it to the
2893 right of that line. */
2894 if (s->face->box != FACE_NO_BOX
2895 && s->first_glyph->left_box_line_p
2896 && s->slice.x == 0)
2897 x += eabs (s->face->box_line_width);
2899 /* If there is a margin around the image, adjust x- and y-position
2900 by that margin. */
2901 if (s->slice.x == 0)
2902 x += s->img->hmargin;
2903 if (s->slice.y == 0)
2904 y += s->img->vmargin;
2906 if (s->img->pixmap)
2908 if (s->img->mask)
2910 /* We can't set both a clip mask and use XSetClipRectangles
2911 because the latter also sets a clip mask. We also can't
2912 trust on the shape extension to be available
2913 (XShapeCombineRegion). So, compute the rectangle to draw
2914 manually. */
2915 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
2916 | GCFunction);
2917 XGCValues xgcv;
2918 XRectangle clip_rect, image_rect, r;
2920 xgcv.clip_mask = s->img->mask;
2921 xgcv.clip_x_origin = x;
2922 xgcv.clip_y_origin = y;
2923 xgcv.function = GXcopy;
2924 XChangeGC (s->display, s->gc, mask, &xgcv);
2926 get_glyph_string_clip_rect (s, &clip_rect);
2927 image_rect.x = x;
2928 image_rect.y = y;
2929 image_rect.width = s->slice.width;
2930 image_rect.height = s->slice.height;
2931 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
2932 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
2933 s->slice.x + r.x - x, s->slice.y + r.y - y,
2934 r.width, r.height, r.x, r.y);
2936 else
2938 XRectangle clip_rect, image_rect, r;
2940 get_glyph_string_clip_rect (s, &clip_rect);
2941 image_rect.x = x;
2942 image_rect.y = y;
2943 image_rect.width = s->slice.width;
2944 image_rect.height = s->slice.height;
2945 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
2946 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
2947 s->slice.x + r.x - x, s->slice.y + r.y - y,
2948 r.width, r.height, r.x, r.y);
2950 /* When the image has a mask, we can expect that at
2951 least part of a mouse highlight or a block cursor will
2952 be visible. If the image doesn't have a mask, make
2953 a block cursor visible by drawing a rectangle around
2954 the image. I believe it's looking better if we do
2955 nothing here for mouse-face. */
2956 if (s->hl == DRAW_CURSOR)
2958 int relief = eabs (s->img->relief);
2959 x_draw_rectangle (s->f, s->gc,
2960 x - relief, y - relief,
2961 s->slice.width + relief*2 - 1,
2962 s->slice.height + relief*2 - 1);
2966 else
2967 /* Draw a rectangle if image could not be loaded. */
2968 x_draw_rectangle (s->f, s->gc, x, y,
2969 s->slice.width - 1, s->slice.height - 1);
2973 /* Draw a relief around the image glyph string S. */
2975 static void
2976 x_draw_image_relief (struct glyph_string *s)
2978 int x1, y1, thick;
2979 bool raised_p, top_p, bot_p, left_p, right_p;
2980 int extra_x, extra_y;
2981 XRectangle r;
2982 int x = s->x;
2983 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2985 /* If first glyph of S has a left box line, start drawing it to the
2986 right of that line. */
2987 if (s->face->box != FACE_NO_BOX
2988 && s->first_glyph->left_box_line_p
2989 && s->slice.x == 0)
2990 x += eabs (s->face->box_line_width);
2992 /* If there is a margin around the image, adjust x- and y-position
2993 by that margin. */
2994 if (s->slice.x == 0)
2995 x += s->img->hmargin;
2996 if (s->slice.y == 0)
2997 y += s->img->vmargin;
2999 if (s->hl == DRAW_IMAGE_SUNKEN
3000 || s->hl == DRAW_IMAGE_RAISED)
3002 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3003 raised_p = s->hl == DRAW_IMAGE_RAISED;
3005 else
3007 thick = eabs (s->img->relief);
3008 raised_p = s->img->relief > 0;
3011 x1 = x + s->slice.width - 1;
3012 y1 = y + s->slice.height - 1;
3014 extra_x = extra_y = 0;
3015 if (s->face->id == TOOL_BAR_FACE_ID)
3017 if (CONSP (Vtool_bar_button_margin)
3018 && INTEGERP (XCAR (Vtool_bar_button_margin))
3019 && INTEGERP (XCDR (Vtool_bar_button_margin)))
3021 extra_x = XINT (XCAR (Vtool_bar_button_margin));
3022 extra_y = XINT (XCDR (Vtool_bar_button_margin));
3024 else if (INTEGERP (Vtool_bar_button_margin))
3025 extra_x = extra_y = XINT (Vtool_bar_button_margin);
3028 top_p = bot_p = left_p = right_p = false;
3030 if (s->slice.x == 0)
3031 x -= thick + extra_x, left_p = true;
3032 if (s->slice.y == 0)
3033 y -= thick + extra_y, top_p = true;
3034 if (s->slice.x + s->slice.width == s->img->width)
3035 x1 += thick + extra_x, right_p = true;
3036 if (s->slice.y + s->slice.height == s->img->height)
3037 y1 += thick + extra_y, bot_p = true;
3039 x_setup_relief_colors (s);
3040 get_glyph_string_clip_rect (s, &r);
3041 x_draw_relief_rect (s->f, x, y, x1, y1, thick, raised_p,
3042 top_p, bot_p, left_p, right_p, &r);
3046 /* Draw the foreground of image glyph string S to PIXMAP. */
3048 static void
3049 x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap)
3051 int x = 0;
3052 int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice);
3054 /* If first glyph of S has a left box line, start drawing it to the
3055 right of that line. */
3056 if (s->face->box != FACE_NO_BOX
3057 && s->first_glyph->left_box_line_p
3058 && s->slice.x == 0)
3059 x += eabs (s->face->box_line_width);
3061 /* If there is a margin around the image, adjust x- and y-position
3062 by that margin. */
3063 if (s->slice.x == 0)
3064 x += s->img->hmargin;
3065 if (s->slice.y == 0)
3066 y += s->img->vmargin;
3068 if (s->img->pixmap)
3070 if (s->img->mask)
3072 /* We can't set both a clip mask and use XSetClipRectangles
3073 because the latter also sets a clip mask. We also can't
3074 trust on the shape extension to be available
3075 (XShapeCombineRegion). So, compute the rectangle to draw
3076 manually. */
3077 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3078 | GCFunction);
3079 XGCValues xgcv;
3081 xgcv.clip_mask = s->img->mask;
3082 xgcv.clip_x_origin = x - s->slice.x;
3083 xgcv.clip_y_origin = y - s->slice.y;
3084 xgcv.function = GXcopy;
3085 XChangeGC (s->display, s->gc, mask, &xgcv);
3087 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3088 s->slice.x, s->slice.y,
3089 s->slice.width, s->slice.height, x, y);
3090 XSetClipMask (s->display, s->gc, None);
3092 else
3094 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3095 s->slice.x, s->slice.y,
3096 s->slice.width, s->slice.height, x, y);
3098 /* When the image has a mask, we can expect that at
3099 least part of a mouse highlight or a block cursor will
3100 be visible. If the image doesn't have a mask, make
3101 a block cursor visible by drawing a rectangle around
3102 the image. I believe it's looking better if we do
3103 nothing here for mouse-face. */
3104 if (s->hl == DRAW_CURSOR)
3106 int r = eabs (s->img->relief);
3107 x_draw_rectangle (s->f, s->gc, x - r, y - r,
3108 s->slice.width + r*2 - 1,
3109 s->slice.height + r*2 - 1);
3113 else
3114 /* Draw a rectangle if image could not be loaded. */
3115 x_draw_rectangle (s->f, s->gc, x, y,
3116 s->slice.width - 1, s->slice.height - 1);
3120 /* Draw part of the background of glyph string S. X, Y, W, and H
3121 give the rectangle to draw. */
3123 static void
3124 x_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, int w, int h)
3126 if (s->stippled_p)
3128 /* Fill background with a stipple pattern. */
3129 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3130 x_fill_rectangle (s->f, s->gc, x, y, w, h);
3131 XSetFillStyle (s->display, s->gc, FillSolid);
3133 else
3134 x_clear_glyph_string_rect (s, x, y, w, h);
3138 /* Draw image glyph string S.
3140 s->y
3141 s->x +-------------------------
3142 | s->face->box
3144 | +-------------------------
3145 | | s->img->margin
3147 | | +-------------------
3148 | | | the image
3152 static void
3153 x_draw_image_glyph_string (struct glyph_string *s)
3155 int box_line_hwidth = eabs (s->face->box_line_width);
3156 int box_line_vwidth = max (s->face->box_line_width, 0);
3157 int height;
3158 Pixmap pixmap = None;
3160 height = s->height;
3161 if (s->slice.y == 0)
3162 height -= box_line_vwidth;
3163 if (s->slice.y + s->slice.height >= s->img->height)
3164 height -= box_line_vwidth;
3166 /* Fill background with face under the image. Do it only if row is
3167 taller than image or if image has a clip mask to reduce
3168 flickering. */
3169 s->stippled_p = s->face->stipple != 0;
3170 if (height > s->slice.height
3171 || s->img->hmargin
3172 || s->img->vmargin
3173 || s->img->mask
3174 || s->img->pixmap == 0
3175 || s->width != s->background_width)
3177 if (s->img->mask)
3179 /* Create a pixmap as large as the glyph string. Fill it
3180 with the background color. Copy the image to it, using
3181 its mask. Copy the temporary pixmap to the display. */
3182 Screen *screen = FRAME_X_SCREEN (s->f);
3183 int depth = DefaultDepthOfScreen (screen);
3185 /* Create a pixmap as large as the glyph string. */
3186 pixmap = XCreatePixmap (s->display, s->window,
3187 s->background_width,
3188 s->height, depth);
3190 /* Don't clip in the following because we're working on the
3191 pixmap. */
3192 XSetClipMask (s->display, s->gc, None);
3194 /* Fill the pixmap with the background color/stipple. */
3195 if (s->stippled_p)
3197 /* Fill background with a stipple pattern. */
3198 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3199 XSetTSOrigin (s->display, s->gc, - s->x, - s->y);
3200 XFillRectangle (s->display, pixmap, s->gc,
3201 0, 0, s->background_width, s->height);
3202 XSetFillStyle (s->display, s->gc, FillSolid);
3203 XSetTSOrigin (s->display, s->gc, 0, 0);
3205 else
3207 XGCValues xgcv;
3208 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
3209 &xgcv);
3210 XSetForeground (s->display, s->gc, xgcv.background);
3211 XFillRectangle (s->display, pixmap, s->gc,
3212 0, 0, s->background_width, s->height);
3213 XSetForeground (s->display, s->gc, xgcv.foreground);
3216 else
3218 int x = s->x;
3219 int y = s->y;
3220 int width = s->background_width;
3222 if (s->first_glyph->left_box_line_p
3223 && s->slice.x == 0)
3225 x += box_line_hwidth;
3226 width -= box_line_hwidth;
3229 if (s->slice.y == 0)
3230 y += box_line_vwidth;
3232 x_draw_glyph_string_bg_rect (s, x, y, width, height);
3235 s->background_filled_p = true;
3238 /* Draw the foreground. */
3239 #ifdef USE_CAIRO
3240 if (s->img->cr_data)
3242 cairo_t *cr = x_begin_cr_clip (s->f, s->gc);
3244 int x = s->x + s->img->hmargin;
3245 int y = s->y + s->img->vmargin;
3246 int width = s->background_width;
3248 cairo_set_source_surface (cr, s->img->cr_data,
3249 x - s->slice.x,
3250 y - s->slice.y);
3251 cairo_rectangle (cr, x, y, width, height);
3252 cairo_fill (cr);
3253 x_end_cr_clip (s->f);
3255 else
3256 #endif
3257 if (pixmap != None)
3259 x_draw_image_foreground_1 (s, pixmap);
3260 x_set_glyph_string_clipping (s);
3261 XCopyArea (s->display, pixmap, s->window, s->gc,
3262 0, 0, s->background_width, s->height, s->x, s->y);
3263 XFreePixmap (s->display, pixmap);
3265 else
3266 x_draw_image_foreground (s);
3268 /* If we must draw a relief around the image, do it. */
3269 if (s->img->relief
3270 || s->hl == DRAW_IMAGE_RAISED
3271 || s->hl == DRAW_IMAGE_SUNKEN)
3272 x_draw_image_relief (s);
3276 /* Draw stretch glyph string S. */
3278 static void
3279 x_draw_stretch_glyph_string (struct glyph_string *s)
3281 eassert (s->first_glyph->type == STRETCH_GLYPH);
3283 if (s->hl == DRAW_CURSOR
3284 && !x_stretch_cursor_p)
3286 /* If `x-stretch-cursor' is nil, don't draw a block cursor as
3287 wide as the stretch glyph. */
3288 int width, background_width = s->background_width;
3289 int x = s->x;
3291 if (!s->row->reversed_p)
3293 int left_x = window_box_left_offset (s->w, TEXT_AREA);
3295 if (x < left_x)
3297 background_width -= left_x - x;
3298 x = left_x;
3301 else
3303 /* In R2L rows, draw the cursor on the right edge of the
3304 stretch glyph. */
3305 int right_x = window_box_right (s->w, TEXT_AREA);
3307 if (x + background_width > right_x)
3308 background_width -= x - right_x;
3309 x += background_width;
3311 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
3312 if (s->row->reversed_p)
3313 x -= width;
3315 /* Draw cursor. */
3316 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
3318 /* Clear rest using the GC of the original non-cursor face. */
3319 if (width < background_width)
3321 int y = s->y;
3322 int w = background_width - width, h = s->height;
3323 XRectangle r;
3324 GC gc;
3326 if (!s->row->reversed_p)
3327 x += width;
3328 else
3329 x = s->x;
3330 if (s->row->mouse_face_p
3331 && cursor_in_mouse_face_p (s->w))
3333 x_set_mouse_face_gc (s);
3334 gc = s->gc;
3336 else
3337 gc = s->face->gc;
3339 get_glyph_string_clip_rect (s, &r);
3340 x_set_clip_rectangles (s->f, gc, &r, 1);
3342 if (s->face->stipple)
3344 /* Fill background with a stipple pattern. */
3345 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3346 x_fill_rectangle (s->f, gc, x, y, w, h);
3347 XSetFillStyle (s->display, gc, FillSolid);
3349 else
3351 XGCValues xgcv;
3352 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
3353 XSetForeground (s->display, gc, xgcv.background);
3354 x_fill_rectangle (s->f, gc, x, y, w, h);
3355 XSetForeground (s->display, gc, xgcv.foreground);
3358 x_reset_clip_rectangles (s->f, gc);
3361 else if (!s->background_filled_p)
3363 int background_width = s->background_width;
3364 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3366 /* Don't draw into left margin, fringe or scrollbar area
3367 except for header line and mode line. */
3368 if (x < left_x && !s->row->mode_line_p)
3370 background_width -= left_x - x;
3371 x = left_x;
3373 if (background_width > 0)
3374 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
3377 s->background_filled_p = true;
3381 Draw a wavy line under S. The wave fills wave_height pixels from y0.
3383 x0 wave_length = 2
3385 y0 * * * * *
3386 |* * * * * * * * *
3387 wave_height = 3 | * * * *
3391 static void
3392 x_draw_underwave (struct glyph_string *s)
3394 int wave_height = 3, wave_length = 2;
3395 #ifdef USE_CAIRO
3396 x_draw_horizontal_wave (s->f, s->gc, s->x, s->ybase - wave_height + 3,
3397 s->width, wave_height, wave_length);
3398 #else /* not USE_CAIRO */
3399 int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax;
3400 bool odd;
3401 XRectangle wave_clip, string_clip, final_clip;
3403 dx = wave_length;
3404 dy = wave_height - 1;
3405 x0 = s->x;
3406 y0 = s->ybase - wave_height + 3;
3407 width = s->width;
3408 xmax = x0 + width;
3410 /* Find and set clipping rectangle */
3412 wave_clip.x = x0;
3413 wave_clip.y = y0;
3414 wave_clip.width = width;
3415 wave_clip.height = wave_height;
3416 get_glyph_string_clip_rect (s, &string_clip);
3418 if (!x_intersect_rectangles (&wave_clip, &string_clip, &final_clip))
3419 return;
3421 XSetClipRectangles (s->display, s->gc, 0, 0, &final_clip, 1, Unsorted);
3423 /* Draw the waves */
3425 x1 = x0 - (x0 % dx);
3426 x2 = x1 + dx;
3427 odd = (x1 / dx) & 1;
3428 y1 = y2 = y0;
3430 if (odd)
3431 y1 += dy;
3432 else
3433 y2 += dy;
3435 if (INT_MAX - dx < xmax)
3436 emacs_abort ();
3438 while (x1 <= xmax)
3440 XDrawLine (s->display, s->window, s->gc, x1, y1, x2, y2);
3441 x1 = x2, y1 = y2;
3442 x2 += dx, y2 = y0 + odd*dy;
3443 odd = !odd;
3446 /* Restore previous clipping rectangle(s) */
3447 XSetClipRectangles (s->display, s->gc, 0, 0, s->clip, s->num_clips, Unsorted);
3448 #endif /* not USE_CAIRO */
3452 /* Draw glyph string S. */
3454 static void
3455 x_draw_glyph_string (struct glyph_string *s)
3457 bool relief_drawn_p = false;
3459 /* If S draws into the background of its successors, draw the
3460 background of the successors first so that S can draw into it.
3461 This makes S->next use XDrawString instead of XDrawImageString. */
3462 if (s->next && s->right_overhang && !s->for_overlaps)
3464 int width;
3465 struct glyph_string *next;
3467 for (width = 0, next = s->next;
3468 next && width < s->right_overhang;
3469 width += next->width, next = next->next)
3470 if (next->first_glyph->type != IMAGE_GLYPH)
3472 x_set_glyph_string_gc (next);
3473 x_set_glyph_string_clipping (next);
3474 if (next->first_glyph->type == STRETCH_GLYPH)
3475 x_draw_stretch_glyph_string (next);
3476 else
3477 x_draw_glyph_string_background (next, true);
3478 next->num_clips = 0;
3482 /* Set up S->gc, set clipping and draw S. */
3483 x_set_glyph_string_gc (s);
3485 /* Draw relief (if any) in advance for char/composition so that the
3486 glyph string can be drawn over it. */
3487 if (!s->for_overlaps
3488 && s->face->box != FACE_NO_BOX
3489 && (s->first_glyph->type == CHAR_GLYPH
3490 || s->first_glyph->type == COMPOSITE_GLYPH))
3493 x_set_glyph_string_clipping (s);
3494 x_draw_glyph_string_background (s, true);
3495 x_draw_glyph_string_box (s);
3496 x_set_glyph_string_clipping (s);
3497 relief_drawn_p = true;
3499 else if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */
3500 && !s->clip_tail
3501 && ((s->prev && s->prev->hl != s->hl && s->left_overhang)
3502 || (s->next && s->next->hl != s->hl && s->right_overhang)))
3503 /* We must clip just this glyph. left_overhang part has already
3504 drawn when s->prev was drawn, and right_overhang part will be
3505 drawn later when s->next is drawn. */
3506 x_set_glyph_string_clipping_exactly (s, s);
3507 else
3508 x_set_glyph_string_clipping (s);
3510 switch (s->first_glyph->type)
3512 case IMAGE_GLYPH:
3513 x_draw_image_glyph_string (s);
3514 break;
3516 case XWIDGET_GLYPH:
3517 x_draw_xwidget_glyph_string (s);
3518 break;
3520 case STRETCH_GLYPH:
3521 x_draw_stretch_glyph_string (s);
3522 break;
3524 case CHAR_GLYPH:
3525 if (s->for_overlaps)
3526 s->background_filled_p = true;
3527 else
3528 x_draw_glyph_string_background (s, false);
3529 x_draw_glyph_string_foreground (s);
3530 break;
3532 case COMPOSITE_GLYPH:
3533 if (s->for_overlaps || (s->cmp_from > 0
3534 && ! s->first_glyph->u.cmp.automatic))
3535 s->background_filled_p = true;
3536 else
3537 x_draw_glyph_string_background (s, true);
3538 x_draw_composite_glyph_string_foreground (s);
3539 break;
3541 case GLYPHLESS_GLYPH:
3542 if (s->for_overlaps)
3543 s->background_filled_p = true;
3544 else
3545 x_draw_glyph_string_background (s, true);
3546 x_draw_glyphless_glyph_string_foreground (s);
3547 break;
3549 default:
3550 emacs_abort ();
3553 if (!s->for_overlaps)
3555 /* Draw underline. */
3556 if (s->face->underline_p)
3558 if (s->face->underline_type == FACE_UNDER_WAVE)
3560 if (s->face->underline_defaulted_p)
3561 x_draw_underwave (s);
3562 else
3564 XGCValues xgcv;
3565 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3566 XSetForeground (s->display, s->gc, s->face->underline_color);
3567 x_draw_underwave (s);
3568 XSetForeground (s->display, s->gc, xgcv.foreground);
3571 else if (s->face->underline_type == FACE_UNDER_LINE)
3573 unsigned long thickness, position;
3574 int y;
3576 if (s->prev && s->prev->face->underline_p
3577 && s->prev->face->underline_type == FACE_UNDER_LINE)
3579 /* We use the same underline style as the previous one. */
3580 thickness = s->prev->underline_thickness;
3581 position = s->prev->underline_position;
3583 else
3585 /* Get the underline thickness. Default is 1 pixel. */
3586 if (s->font && s->font->underline_thickness > 0)
3587 thickness = s->font->underline_thickness;
3588 else
3589 thickness = 1;
3590 if (x_underline_at_descent_line)
3591 position = (s->height - thickness) - (s->ybase - s->y);
3592 else
3594 /* Get the underline position. This is the recommended
3595 vertical offset in pixels from the baseline to the top of
3596 the underline. This is a signed value according to the
3597 specs, and its default is
3599 ROUND ((maximum descent) / 2), with
3600 ROUND(x) = floor (x + 0.5) */
3602 if (x_use_underline_position_properties
3603 && s->font && s->font->underline_position >= 0)
3604 position = s->font->underline_position;
3605 else if (s->font)
3606 position = (s->font->descent + 1) / 2;
3607 else
3608 position = underline_minimum_offset;
3610 position = max (position, underline_minimum_offset);
3612 /* Check the sanity of thickness and position. We should
3613 avoid drawing underline out of the current line area. */
3614 if (s->y + s->height <= s->ybase + position)
3615 position = (s->height - 1) - (s->ybase - s->y);
3616 if (s->y + s->height < s->ybase + position + thickness)
3617 thickness = (s->y + s->height) - (s->ybase + position);
3618 s->underline_thickness = thickness;
3619 s->underline_position = position;
3620 y = s->ybase + position;
3621 if (s->face->underline_defaulted_p)
3622 x_fill_rectangle (s->f, s->gc,
3623 s->x, y, s->width, thickness);
3624 else
3626 XGCValues xgcv;
3627 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3628 XSetForeground (s->display, s->gc, s->face->underline_color);
3629 x_fill_rectangle (s->f, s->gc,
3630 s->x, y, s->width, thickness);
3631 XSetForeground (s->display, s->gc, xgcv.foreground);
3635 /* Draw overline. */
3636 if (s->face->overline_p)
3638 unsigned long dy = 0, h = 1;
3640 if (s->face->overline_color_defaulted_p)
3641 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3642 s->width, h);
3643 else
3645 XGCValues xgcv;
3646 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3647 XSetForeground (s->display, s->gc, s->face->overline_color);
3648 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3649 s->width, h);
3650 XSetForeground (s->display, s->gc, xgcv.foreground);
3654 /* Draw strike-through. */
3655 if (s->face->strike_through_p)
3657 unsigned long h = 1;
3658 unsigned long dy = (s->height - h) / 2;
3660 if (s->face->strike_through_color_defaulted_p)
3661 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3662 s->width, h);
3663 else
3665 XGCValues xgcv;
3666 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3667 XSetForeground (s->display, s->gc, s->face->strike_through_color);
3668 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3669 s->width, h);
3670 XSetForeground (s->display, s->gc, xgcv.foreground);
3674 /* Draw relief if not yet drawn. */
3675 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
3676 x_draw_glyph_string_box (s);
3678 if (s->prev)
3680 struct glyph_string *prev;
3682 for (prev = s->prev; prev; prev = prev->prev)
3683 if (prev->hl != s->hl
3684 && prev->x + prev->width + prev->right_overhang > s->x)
3686 /* As prev was drawn while clipped to its own area, we
3687 must draw the right_overhang part using s->hl now. */
3688 enum draw_glyphs_face save = prev->hl;
3690 prev->hl = s->hl;
3691 x_set_glyph_string_gc (prev);
3692 x_set_glyph_string_clipping_exactly (s, prev);
3693 if (prev->first_glyph->type == CHAR_GLYPH)
3694 x_draw_glyph_string_foreground (prev);
3695 else
3696 x_draw_composite_glyph_string_foreground (prev);
3697 x_reset_clip_rectangles (prev->f, prev->gc);
3698 prev->hl = save;
3699 prev->num_clips = 0;
3703 if (s->next)
3705 struct glyph_string *next;
3707 for (next = s->next; next; next = next->next)
3708 if (next->hl != s->hl
3709 && next->x - next->left_overhang < s->x + s->width)
3711 /* As next will be drawn while clipped to its own area,
3712 we must draw the left_overhang part using s->hl now. */
3713 enum draw_glyphs_face save = next->hl;
3715 next->hl = s->hl;
3716 x_set_glyph_string_gc (next);
3717 x_set_glyph_string_clipping_exactly (s, next);
3718 if (next->first_glyph->type == CHAR_GLYPH)
3719 x_draw_glyph_string_foreground (next);
3720 else
3721 x_draw_composite_glyph_string_foreground (next);
3722 x_reset_clip_rectangles (next->f, next->gc);
3723 next->hl = save;
3724 next->num_clips = 0;
3725 next->clip_head = s->next;
3730 /* Reset clipping. */
3731 x_reset_clip_rectangles (s->f, s->gc);
3732 s->num_clips = 0;
3735 /* Shift display to make room for inserted glyphs. */
3737 static void
3738 x_shift_glyphs_for_insert (struct frame *f, int x, int y, int width, int height, int shift_by)
3740 /* Never called on a GUI frame, see
3741 http://lists.gnu.org/archive/html/emacs-devel/2015-05/msg00456.html
3743 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
3744 f->output_data.x->normal_gc,
3745 x, y, width, height,
3746 x + shift_by, y);
3749 /* Delete N glyphs at the nominal cursor position. Not implemented
3750 for X frames. */
3752 static void
3753 x_delete_glyphs (struct frame *f, register int n)
3755 emacs_abort ();
3759 /* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
3760 If they are <= 0, this is probably an error. */
3762 static ATTRIBUTE_UNUSED void
3763 x_clear_area1 (Display *dpy, Window window,
3764 int x, int y, int width, int height, int exposures)
3766 eassert (width > 0 && height > 0);
3767 XClearArea (dpy, window, x, y, width, height, exposures);
3770 void
3771 x_clear_area (struct frame *f, int x, int y, int width, int height)
3773 #ifdef USE_CAIRO
3774 cairo_t *cr;
3776 eassert (width > 0 && height > 0);
3778 cr = x_begin_cr_clip (f, NULL);
3779 x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
3780 cairo_rectangle (cr, x, y, width, height);
3781 cairo_fill (cr);
3782 x_end_cr_clip (f);
3783 #else
3784 x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3785 x, y, width, height, False);
3786 #endif
3790 /* Clear an entire frame. */
3792 static void
3793 x_clear_frame (struct frame *f)
3795 /* Clearing the frame will erase any cursor, so mark them all as no
3796 longer visible. */
3797 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
3799 block_input ();
3801 x_clear_window (f);
3803 /* We have to clear the scroll bars. If we have changed colors or
3804 something like that, then they should be notified. */
3805 x_scroll_bar_clear (f);
3807 #if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
3808 /* Make sure scroll bars are redrawn. As they aren't redrawn by
3809 redisplay, do it here. */
3810 if (FRAME_GTK_WIDGET (f))
3811 gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
3812 #endif
3814 XFlush (FRAME_X_DISPLAY (f));
3816 unblock_input ();
3819 /* RIF: Show hourglass cursor on frame F. */
3821 static void
3822 x_show_hourglass (struct frame *f)
3824 Display *dpy = FRAME_X_DISPLAY (f);
3826 if (dpy)
3828 struct x_output *x = FRAME_X_OUTPUT (f);
3829 #ifdef USE_X_TOOLKIT
3830 if (x->widget)
3831 #else
3832 if (FRAME_OUTER_WINDOW (f))
3833 #endif
3835 x->hourglass_p = true;
3837 if (!x->hourglass_window)
3839 unsigned long mask = CWCursor;
3840 XSetWindowAttributes attrs;
3841 #ifdef USE_GTK
3842 Window parent = FRAME_X_WINDOW (f);
3843 #else
3844 Window parent = FRAME_OUTER_WINDOW (f);
3845 #endif
3846 attrs.cursor = x->hourglass_cursor;
3848 x->hourglass_window = XCreateWindow
3849 (dpy, parent, 0, 0, 32000, 32000, 0, 0,
3850 InputOnly, CopyFromParent, mask, &attrs);
3853 XMapRaised (dpy, x->hourglass_window);
3854 XFlush (dpy);
3859 /* RIF: Cancel hourglass cursor on frame F. */
3861 static void
3862 x_hide_hourglass (struct frame *f)
3864 struct x_output *x = FRAME_X_OUTPUT (f);
3866 /* Watch out for newly created frames. */
3867 if (x->hourglass_window)
3869 XUnmapWindow (FRAME_X_DISPLAY (f), x->hourglass_window);
3870 /* Sync here because XTread_socket looks at the
3871 hourglass_p flag that is reset to zero below. */
3872 XSync (FRAME_X_DISPLAY (f), False);
3873 x->hourglass_p = false;
3877 /* Invert the middle quarter of the frame for .15 sec. */
3879 static void
3880 XTflash (struct frame *f)
3882 block_input ();
3885 #ifdef USE_GTK
3886 /* Use Gdk routines to draw. This way, we won't draw over scroll bars
3887 when the scroll bars and the edit widget share the same X window. */
3888 GdkWindow *window = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
3889 #ifdef HAVE_GTK3
3890 cairo_t *cr = gdk_cairo_create (window);
3891 cairo_set_source_rgb (cr, 1, 1, 1);
3892 cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
3893 #define XFillRectangle(d, win, gc, x, y, w, h) \
3894 do { \
3895 cairo_rectangle (cr, x, y, w, h); \
3896 cairo_fill (cr); \
3898 while (false)
3899 #else /* ! HAVE_GTK3 */
3900 GdkGCValues vals;
3901 GdkGC *gc;
3902 vals.foreground.pixel = (FRAME_FOREGROUND_PIXEL (f)
3903 ^ FRAME_BACKGROUND_PIXEL (f));
3904 vals.function = GDK_XOR;
3905 gc = gdk_gc_new_with_values (window,
3906 &vals, GDK_GC_FUNCTION | GDK_GC_FOREGROUND);
3907 #define XFillRectangle(d, win, gc, x, y, w, h) \
3908 gdk_draw_rectangle (window, gc, true, x, y, w, h)
3909 #endif /* ! HAVE_GTK3 */
3910 #else /* ! USE_GTK */
3911 GC gc;
3913 /* Create a GC that will use the GXxor function to flip foreground
3914 pixels into background pixels. */
3916 XGCValues values;
3918 values.function = GXxor;
3919 values.foreground = (FRAME_FOREGROUND_PIXEL (f)
3920 ^ FRAME_BACKGROUND_PIXEL (f));
3922 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3923 GCFunction | GCForeground, &values);
3925 #endif
3927 /* Get the height not including a menu bar widget. */
3928 int height = FRAME_PIXEL_HEIGHT (f);
3929 /* Height of each line to flash. */
3930 int flash_height = FRAME_LINE_HEIGHT (f);
3931 /* These will be the left and right margins of the rectangles. */
3932 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
3933 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
3934 int width = flash_right - flash_left;
3936 /* If window is tall, flash top and bottom line. */
3937 if (height > 3 * FRAME_LINE_HEIGHT (f))
3939 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3940 flash_left,
3941 (FRAME_INTERNAL_BORDER_WIDTH (f)
3942 + FRAME_TOP_MARGIN_HEIGHT (f)),
3943 width, flash_height);
3944 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3945 flash_left,
3946 (height - flash_height
3947 - FRAME_INTERNAL_BORDER_WIDTH (f)),
3948 width, flash_height);
3951 else
3952 /* If it is short, flash it all. */
3953 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3954 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
3955 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
3957 x_flush (f);
3960 struct timespec delay = make_timespec (0, 150 * 1000 * 1000);
3961 struct timespec wakeup = timespec_add (current_timespec (), delay);
3963 /* Keep waiting until past the time wakeup or any input gets
3964 available. */
3965 while (! detect_input_pending ())
3967 struct timespec current = current_timespec ();
3968 struct timespec timeout;
3970 /* Break if result would not be positive. */
3971 if (timespec_cmp (wakeup, current) <= 0)
3972 break;
3974 /* How long `select' should wait. */
3975 timeout = make_timespec (0, 10 * 1000 * 1000);
3977 /* Try to wait that long--but we might wake up sooner. */
3978 pselect (0, NULL, NULL, NULL, &timeout, NULL);
3982 /* If window is tall, flash top and bottom line. */
3983 if (height > 3 * FRAME_LINE_HEIGHT (f))
3985 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3986 flash_left,
3987 (FRAME_INTERNAL_BORDER_WIDTH (f)
3988 + FRAME_TOP_MARGIN_HEIGHT (f)),
3989 width, flash_height);
3990 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3991 flash_left,
3992 (height - flash_height
3993 - FRAME_INTERNAL_BORDER_WIDTH (f)),
3994 width, flash_height);
3996 else
3997 /* If it is short, flash it all. */
3998 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3999 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4000 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4002 #ifdef USE_GTK
4003 #ifdef HAVE_GTK3
4004 cairo_destroy (cr);
4005 #else
4006 g_object_unref (G_OBJECT (gc));
4007 #endif
4008 #undef XFillRectangle
4009 #else
4010 XFreeGC (FRAME_X_DISPLAY (f), gc);
4011 #endif
4012 x_flush (f);
4016 unblock_input ();
4020 static void
4021 XTtoggle_invisible_pointer (struct frame *f, bool invisible)
4023 block_input ();
4024 FRAME_DISPLAY_INFO (f)->toggle_visible_pointer (f, invisible);
4025 unblock_input ();
4029 /* Make audible bell. */
4031 static void
4032 XTring_bell (struct frame *f)
4034 if (FRAME_X_DISPLAY (f))
4036 if (visible_bell)
4037 XTflash (f);
4038 else
4040 block_input ();
4041 #ifdef HAVE_XKB
4042 XkbBell (FRAME_X_DISPLAY (f), None, 0, None);
4043 #else
4044 XBell (FRAME_X_DISPLAY (f), 0);
4045 #endif
4046 XFlush (FRAME_X_DISPLAY (f));
4047 unblock_input ();
4052 /***********************************************************************
4053 Line Dance
4054 ***********************************************************************/
4056 /* Perform an insert-lines or delete-lines operation, inserting N
4057 lines or deleting -N lines at vertical position VPOS. */
4059 static void
4060 x_ins_del_lines (struct frame *f, int vpos, int n)
4062 emacs_abort ();
4066 /* Scroll part of the display as described by RUN. */
4068 static void
4069 x_scroll_run (struct window *w, struct run *run)
4071 struct frame *f = XFRAME (w->frame);
4072 int x, y, width, height, from_y, to_y, bottom_y;
4074 /* Get frame-relative bounding box of the text display area of W,
4075 without mode lines. Include in this box the left and right
4076 fringe of W. */
4077 window_box (w, ANY_AREA, &x, &y, &width, &height);
4079 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4080 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4081 bottom_y = y + height;
4083 if (to_y < from_y)
4085 /* Scrolling up. Make sure we don't copy part of the mode
4086 line at the bottom. */
4087 if (from_y + run->height > bottom_y)
4088 height = bottom_y - from_y;
4089 else
4090 height = run->height;
4092 else
4094 /* Scrolling down. Make sure we don't copy over the mode line.
4095 at the bottom. */
4096 if (to_y + run->height > bottom_y)
4097 height = bottom_y - to_y;
4098 else
4099 height = run->height;
4102 block_input ();
4104 /* Cursor off. Will be switched on again in x_update_window_end. */
4105 x_clear_cursor (w);
4107 #ifdef USE_CAIRO
4108 SET_FRAME_GARBAGED (f);
4109 #else
4110 XCopyArea (FRAME_X_DISPLAY (f),
4111 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
4112 f->output_data.x->normal_gc,
4113 x, from_y,
4114 width, height,
4115 x, to_y);
4116 #endif
4118 unblock_input ();
4123 /***********************************************************************
4124 Exposure Events
4125 ***********************************************************************/
4128 static void
4129 frame_highlight (struct frame *f)
4131 /* We used to only do this if Vx_no_window_manager was non-nil, but
4132 the ICCCM (section 4.1.6) says that the window's border pixmap
4133 and border pixel are window attributes which are "private to the
4134 client", so we can always change it to whatever we want. */
4135 block_input ();
4136 /* I recently started to get errors in this XSetWindowBorder, depending on
4137 the window-manager in use, tho something more is at play since I've been
4138 using that same window-manager binary for ever. Let's not crash just
4139 because of this (bug#9310). */
4140 x_catch_errors (FRAME_X_DISPLAY (f));
4141 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4142 f->output_data.x->border_pixel);
4143 x_uncatch_errors ();
4144 unblock_input ();
4145 x_update_cursor (f, true);
4146 x_set_frame_alpha (f);
4149 static void
4150 frame_unhighlight (struct frame *f)
4152 /* We used to only do this if Vx_no_window_manager was non-nil, but
4153 the ICCCM (section 4.1.6) says that the window's border pixmap
4154 and border pixel are window attributes which are "private to the
4155 client", so we can always change it to whatever we want. */
4156 block_input ();
4157 /* Same as above for XSetWindowBorder (bug#9310). */
4158 x_catch_errors (FRAME_X_DISPLAY (f));
4159 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4160 f->output_data.x->border_tile);
4161 x_uncatch_errors ();
4162 unblock_input ();
4163 x_update_cursor (f, true);
4164 x_set_frame_alpha (f);
4167 /* The focus has changed. Update the frames as necessary to reflect
4168 the new situation. Note that we can't change the selected frame
4169 here, because the Lisp code we are interrupting might become confused.
4170 Each event gets marked with the frame in which it occurred, so the
4171 Lisp code can tell when the switch took place by examining the events. */
4173 static void
4174 x_new_focus_frame (struct x_display_info *dpyinfo, struct frame *frame)
4176 struct frame *old_focus = dpyinfo->x_focus_frame;
4178 if (frame != dpyinfo->x_focus_frame)
4180 /* Set this before calling other routines, so that they see
4181 the correct value of x_focus_frame. */
4182 dpyinfo->x_focus_frame = frame;
4184 if (old_focus && old_focus->auto_lower)
4185 x_lower_frame (old_focus);
4187 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4188 dpyinfo->x_pending_autoraise_frame = dpyinfo->x_focus_frame;
4189 else
4190 dpyinfo->x_pending_autoraise_frame = NULL;
4193 x_frame_rehighlight (dpyinfo);
4196 /* Handle FocusIn and FocusOut state changes for FRAME.
4197 If FRAME has focus and there exists more than one frame, puts
4198 a FOCUS_IN_EVENT into *BUFP. */
4200 static void
4201 x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct frame *frame, struct input_event *bufp)
4203 if (type == FocusIn)
4205 if (dpyinfo->x_focus_event_frame != frame)
4207 x_new_focus_frame (dpyinfo, frame);
4208 dpyinfo->x_focus_event_frame = frame;
4210 /* Don't stop displaying the initial startup message
4211 for a switch-frame event we don't need. */
4212 /* When run as a daemon, Vterminal_frame is always NIL. */
4213 bufp->arg = (((NILP (Vterminal_frame)
4214 || ! FRAME_X_P (XFRAME (Vterminal_frame))
4215 || EQ (Fdaemonp (), Qt))
4216 && CONSP (Vframe_list)
4217 && !NILP (XCDR (Vframe_list)))
4218 ? Qt : Qnil);
4219 bufp->kind = FOCUS_IN_EVENT;
4220 XSETFRAME (bufp->frame_or_window, frame);
4223 frame->output_data.x->focus_state |= state;
4225 #ifdef HAVE_X_I18N
4226 if (FRAME_XIC (frame))
4227 XSetICFocus (FRAME_XIC (frame));
4228 #endif
4230 else if (type == FocusOut)
4232 frame->output_data.x->focus_state &= ~state;
4234 if (dpyinfo->x_focus_event_frame == frame)
4236 dpyinfo->x_focus_event_frame = 0;
4237 x_new_focus_frame (dpyinfo, 0);
4239 bufp->kind = FOCUS_OUT_EVENT;
4240 XSETFRAME (bufp->frame_or_window, frame);
4243 #ifdef HAVE_X_I18N
4244 if (FRAME_XIC (frame))
4245 XUnsetICFocus (FRAME_XIC (frame));
4246 #endif
4247 if (frame->pointer_invisible)
4248 XTtoggle_invisible_pointer (frame, false);
4252 /* Return the Emacs frame-object corresponding to an X window.
4253 It could be the frame's main window or an icon window. */
4255 static struct frame *
4256 x_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4258 Lisp_Object tail, frame;
4259 struct frame *f;
4261 if (wdesc == None)
4262 return NULL;
4264 FOR_EACH_FRAME (tail, frame)
4266 f = XFRAME (frame);
4267 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4268 continue;
4269 if (f->output_data.x->hourglass_window == wdesc)
4270 return f;
4271 #ifdef USE_X_TOOLKIT
4272 if ((f->output_data.x->edit_widget
4273 && XtWindow (f->output_data.x->edit_widget) == wdesc)
4274 /* A tooltip frame? */
4275 || (!f->output_data.x->edit_widget
4276 && FRAME_X_WINDOW (f) == wdesc)
4277 || f->output_data.x->icon_desc == wdesc)
4278 return f;
4279 #else /* not USE_X_TOOLKIT */
4280 #ifdef USE_GTK
4281 if (f->output_data.x->edit_widget)
4283 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4284 struct x_output *x = f->output_data.x;
4285 if (gwdesc != 0 && gwdesc == x->edit_widget)
4286 return f;
4288 #endif /* USE_GTK */
4289 if (FRAME_X_WINDOW (f) == wdesc
4290 || f->output_data.x->icon_desc == wdesc)
4291 return f;
4292 #endif /* not USE_X_TOOLKIT */
4294 return 0;
4297 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
4299 /* Like x_window_to_frame but also compares the window with the widget's
4300 windows. */
4302 static struct frame *
4303 x_any_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4305 Lisp_Object tail, frame;
4306 struct frame *f, *found = NULL;
4307 struct x_output *x;
4309 if (wdesc == None)
4310 return NULL;
4312 FOR_EACH_FRAME (tail, frame)
4314 if (found)
4315 break;
4316 f = XFRAME (frame);
4317 if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo)
4319 /* This frame matches if the window is any of its widgets. */
4320 x = f->output_data.x;
4321 if (x->hourglass_window == wdesc)
4322 found = f;
4323 else if (x->widget)
4325 #ifdef USE_GTK
4326 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4327 if (gwdesc != 0
4328 && gtk_widget_get_toplevel (gwdesc) == x->widget)
4329 found = f;
4330 #else
4331 if (wdesc == XtWindow (x->widget)
4332 || wdesc == XtWindow (x->column_widget)
4333 || wdesc == XtWindow (x->edit_widget))
4334 found = f;
4335 /* Match if the window is this frame's menubar. */
4336 else if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
4337 found = f;
4338 #endif
4340 else if (FRAME_X_WINDOW (f) == wdesc)
4341 /* A tooltip frame. */
4342 found = f;
4346 return found;
4349 /* Likewise, but consider only the menu bar widget. */
4351 static struct frame *
4352 x_menubar_window_to_frame (struct x_display_info *dpyinfo,
4353 const XEvent *event)
4355 Window wdesc = event->xany.window;
4356 Lisp_Object tail, frame;
4357 struct frame *f;
4358 struct x_output *x;
4360 if (wdesc == None)
4361 return NULL;
4363 FOR_EACH_FRAME (tail, frame)
4365 f = XFRAME (frame);
4366 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4367 continue;
4368 x = f->output_data.x;
4369 #ifdef USE_GTK
4370 if (x->menubar_widget && xg_event_is_for_menubar (f, event))
4371 return f;
4372 #else
4373 /* Match if the window is this frame's menubar. */
4374 if (x->menubar_widget
4375 && lw_window_is_in_menubar (wdesc, x->menubar_widget))
4376 return f;
4377 #endif
4379 return 0;
4382 /* Return the frame whose principal (outermost) window is WDESC.
4383 If WDESC is some other (smaller) window, we return 0. */
4385 struct frame *
4386 x_top_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4388 Lisp_Object tail, frame;
4389 struct frame *f;
4390 struct x_output *x;
4392 if (wdesc == None)
4393 return NULL;
4395 FOR_EACH_FRAME (tail, frame)
4397 f = XFRAME (frame);
4398 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4399 continue;
4400 x = f->output_data.x;
4402 if (x->widget)
4404 /* This frame matches if the window is its topmost widget. */
4405 #ifdef USE_GTK
4406 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4407 if (gwdesc == x->widget)
4408 return f;
4409 #else
4410 if (wdesc == XtWindow (x->widget))
4411 return f;
4412 #endif
4414 else if (FRAME_X_WINDOW (f) == wdesc)
4415 /* Tooltip frame. */
4416 return f;
4418 return 0;
4421 #else /* !USE_X_TOOLKIT && !USE_GTK */
4423 #define x_any_window_to_frame(d, i) x_window_to_frame (d, i)
4424 #define x_top_window_to_frame(d, i) x_window_to_frame (d, i)
4426 #endif /* USE_X_TOOLKIT || USE_GTK */
4428 /* The focus may have changed. Figure out if it is a real focus change,
4429 by checking both FocusIn/Out and Enter/LeaveNotify events.
4431 Returns FOCUS_IN_EVENT event in *BUFP. */
4433 static void
4434 x_detect_focus_change (struct x_display_info *dpyinfo, struct frame *frame,
4435 const XEvent *event, struct input_event *bufp)
4437 if (!frame)
4438 return;
4440 switch (event->type)
4442 case EnterNotify:
4443 case LeaveNotify:
4445 struct frame *focus_frame = dpyinfo->x_focus_event_frame;
4446 int focus_state
4447 = focus_frame ? focus_frame->output_data.x->focus_state : 0;
4449 if (event->xcrossing.detail != NotifyInferior
4450 && event->xcrossing.focus
4451 && ! (focus_state & FOCUS_EXPLICIT))
4452 x_focus_changed ((event->type == EnterNotify ? FocusIn : FocusOut),
4453 FOCUS_IMPLICIT,
4454 dpyinfo, frame, bufp);
4456 break;
4458 case FocusIn:
4459 case FocusOut:
4460 x_focus_changed (event->type,
4461 (event->xfocus.detail == NotifyPointer ?
4462 FOCUS_IMPLICIT : FOCUS_EXPLICIT),
4463 dpyinfo, frame, bufp);
4464 break;
4466 case ClientMessage:
4467 if (event->xclient.message_type == dpyinfo->Xatom_XEMBED)
4469 enum xembed_message msg = event->xclient.data.l[1];
4470 x_focus_changed ((msg == XEMBED_FOCUS_IN ? FocusIn : FocusOut),
4471 FOCUS_EXPLICIT, dpyinfo, frame, bufp);
4473 break;
4478 #if !defined USE_X_TOOLKIT && !defined USE_GTK
4479 /* Handle an event saying the mouse has moved out of an Emacs frame. */
4481 void
4482 x_mouse_leave (struct x_display_info *dpyinfo)
4484 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
4486 #endif
4488 /* The focus has changed, or we have redirected a frame's focus to
4489 another frame (this happens when a frame uses a surrogate
4490 mini-buffer frame). Shift the highlight as appropriate.
4492 The FRAME argument doesn't necessarily have anything to do with which
4493 frame is being highlighted or un-highlighted; we only use it to find
4494 the appropriate X display info. */
4496 static void
4497 XTframe_rehighlight (struct frame *frame)
4499 x_frame_rehighlight (FRAME_DISPLAY_INFO (frame));
4502 static void
4503 x_frame_rehighlight (struct x_display_info *dpyinfo)
4505 struct frame *old_highlight = dpyinfo->x_highlight_frame;
4507 if (dpyinfo->x_focus_frame)
4509 dpyinfo->x_highlight_frame
4510 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4511 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4512 : dpyinfo->x_focus_frame);
4513 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
4515 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
4516 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
4519 else
4520 dpyinfo->x_highlight_frame = 0;
4522 if (dpyinfo->x_highlight_frame != old_highlight)
4524 if (old_highlight)
4525 frame_unhighlight (old_highlight);
4526 if (dpyinfo->x_highlight_frame)
4527 frame_highlight (dpyinfo->x_highlight_frame);
4533 /* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
4535 /* Initialize mode_switch_bit and modifier_meaning. */
4536 static void
4537 x_find_modifier_meanings (struct x_display_info *dpyinfo)
4539 int min_code, max_code;
4540 KeySym *syms;
4541 int syms_per_code;
4542 XModifierKeymap *mods;
4544 dpyinfo->meta_mod_mask = 0;
4545 dpyinfo->shift_lock_mask = 0;
4546 dpyinfo->alt_mod_mask = 0;
4547 dpyinfo->super_mod_mask = 0;
4548 dpyinfo->hyper_mod_mask = 0;
4550 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
4552 syms = XGetKeyboardMapping (dpyinfo->display,
4553 min_code, max_code - min_code + 1,
4554 &syms_per_code);
4555 mods = XGetModifierMapping (dpyinfo->display);
4557 /* Scan the modifier table to see which modifier bits the Meta and
4558 Alt keysyms are on. */
4560 int row, col; /* The row and column in the modifier table. */
4561 bool found_alt_or_meta;
4563 for (row = 3; row < 8; row++)
4565 found_alt_or_meta = false;
4566 for (col = 0; col < mods->max_keypermod; col++)
4568 KeyCode code = mods->modifiermap[(row * mods->max_keypermod) + col];
4570 /* Zeroes are used for filler. Skip them. */
4571 if (code == 0)
4572 continue;
4574 /* Are any of this keycode's keysyms a meta key? */
4576 int code_col;
4578 for (code_col = 0; code_col < syms_per_code; code_col++)
4580 int sym = syms[((code - min_code) * syms_per_code) + code_col];
4582 switch (sym)
4584 case XK_Meta_L:
4585 case XK_Meta_R:
4586 found_alt_or_meta = true;
4587 dpyinfo->meta_mod_mask |= (1 << row);
4588 break;
4590 case XK_Alt_L:
4591 case XK_Alt_R:
4592 found_alt_or_meta = true;
4593 dpyinfo->alt_mod_mask |= (1 << row);
4594 break;
4596 case XK_Hyper_L:
4597 case XK_Hyper_R:
4598 if (!found_alt_or_meta)
4599 dpyinfo->hyper_mod_mask |= (1 << row);
4600 code_col = syms_per_code;
4601 col = mods->max_keypermod;
4602 break;
4604 case XK_Super_L:
4605 case XK_Super_R:
4606 if (!found_alt_or_meta)
4607 dpyinfo->super_mod_mask |= (1 << row);
4608 code_col = syms_per_code;
4609 col = mods->max_keypermod;
4610 break;
4612 case XK_Shift_Lock:
4613 /* Ignore this if it's not on the lock modifier. */
4614 if (!found_alt_or_meta && ((1 << row) == LockMask))
4615 dpyinfo->shift_lock_mask = LockMask;
4616 code_col = syms_per_code;
4617 col = mods->max_keypermod;
4618 break;
4626 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
4627 if (! dpyinfo->meta_mod_mask)
4629 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
4630 dpyinfo->alt_mod_mask = 0;
4633 /* If some keys are both alt and meta,
4634 make them just meta, not alt. */
4635 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
4637 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
4640 XFree (syms);
4641 XFreeModifiermap (mods);
4644 /* Convert between the modifier bits X uses and the modifier bits
4645 Emacs uses. */
4648 x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state)
4650 int mod_meta = meta_modifier;
4651 int mod_alt = alt_modifier;
4652 int mod_hyper = hyper_modifier;
4653 int mod_super = super_modifier;
4654 Lisp_Object tem;
4656 tem = Fget (Vx_alt_keysym, Qmodifier_value);
4657 if (INTEGERP (tem)) mod_alt = XINT (tem) & INT_MAX;
4658 tem = Fget (Vx_meta_keysym, Qmodifier_value);
4659 if (INTEGERP (tem)) mod_meta = XINT (tem) & INT_MAX;
4660 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
4661 if (INTEGERP (tem)) mod_hyper = XINT (tem) & INT_MAX;
4662 tem = Fget (Vx_super_keysym, Qmodifier_value);
4663 if (INTEGERP (tem)) mod_super = XINT (tem) & INT_MAX;
4665 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
4666 | ((state & ControlMask) ? ctrl_modifier : 0)
4667 | ((state & dpyinfo->meta_mod_mask) ? mod_meta : 0)
4668 | ((state & dpyinfo->alt_mod_mask) ? mod_alt : 0)
4669 | ((state & dpyinfo->super_mod_mask) ? mod_super : 0)
4670 | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0));
4673 static int
4674 x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, EMACS_INT state)
4676 EMACS_INT mod_meta = meta_modifier;
4677 EMACS_INT mod_alt = alt_modifier;
4678 EMACS_INT mod_hyper = hyper_modifier;
4679 EMACS_INT mod_super = super_modifier;
4681 Lisp_Object tem;
4683 tem = Fget (Vx_alt_keysym, Qmodifier_value);
4684 if (INTEGERP (tem)) mod_alt = XINT (tem);
4685 tem = Fget (Vx_meta_keysym, Qmodifier_value);
4686 if (INTEGERP (tem)) mod_meta = XINT (tem);
4687 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
4688 if (INTEGERP (tem)) mod_hyper = XINT (tem);
4689 tem = Fget (Vx_super_keysym, Qmodifier_value);
4690 if (INTEGERP (tem)) mod_super = XINT (tem);
4693 return ( ((state & mod_alt) ? dpyinfo->alt_mod_mask : 0)
4694 | ((state & mod_super) ? dpyinfo->super_mod_mask : 0)
4695 | ((state & mod_hyper) ? dpyinfo->hyper_mod_mask : 0)
4696 | ((state & shift_modifier) ? ShiftMask : 0)
4697 | ((state & ctrl_modifier) ? ControlMask : 0)
4698 | ((state & mod_meta) ? dpyinfo->meta_mod_mask : 0));
4701 /* Convert a keysym to its name. */
4703 char *
4704 x_get_keysym_name (int keysym)
4706 char *value;
4708 block_input ();
4709 value = XKeysymToString (keysym);
4710 unblock_input ();
4712 return value;
4715 /* Mouse clicks and mouse movement. Rah.
4717 Formerly, we used PointerMotionHintMask (in standard_event_mask)
4718 so that we would have to call XQueryPointer after each MotionNotify
4719 event to ask for another such event. However, this made mouse tracking
4720 slow, and there was a bug that made it eventually stop.
4722 Simply asking for MotionNotify all the time seems to work better.
4724 In order to avoid asking for motion events and then throwing most
4725 of them away or busy-polling the server for mouse positions, we ask
4726 the server for pointer motion hints. This means that we get only
4727 one event per group of mouse movements. "Groups" are delimited by
4728 other kinds of events (focus changes and button clicks, for
4729 example), or by XQueryPointer calls; when one of these happens, we
4730 get another MotionNotify event the next time the mouse moves. This
4731 is at least as efficient as getting motion events when mouse
4732 tracking is on, and I suspect only negligibly worse when tracking
4733 is off. */
4735 /* Prepare a mouse-event in *RESULT for placement in the input queue.
4737 If the event is a button press, then note that we have grabbed
4738 the mouse. */
4740 static Lisp_Object
4741 construct_mouse_click (struct input_event *result,
4742 const XButtonEvent *event,
4743 struct frame *f)
4745 /* Make the event type NO_EVENT; we'll change that when we decide
4746 otherwise. */
4747 result->kind = MOUSE_CLICK_EVENT;
4748 result->code = event->button - Button1;
4749 result->timestamp = event->time;
4750 result->modifiers = (x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f),
4751 event->state)
4752 | (event->type == ButtonRelease
4753 ? up_modifier
4754 : down_modifier));
4756 XSETINT (result->x, event->x);
4757 XSETINT (result->y, event->y);
4758 XSETFRAME (result->frame_or_window, f);
4759 result->arg = Qnil;
4760 return Qnil;
4763 /* Function to report a mouse movement to the mainstream Emacs code.
4764 The input handler calls this.
4766 We have received a mouse movement event, which is given in *event.
4767 If the mouse is over a different glyph than it was last time, tell
4768 the mainstream emacs code by setting mouse_moved. If not, ask for
4769 another motion event, so we can check again the next time it moves. */
4771 static bool
4772 note_mouse_movement (struct frame *frame, const XMotionEvent *event)
4774 XRectangle *r;
4775 struct x_display_info *dpyinfo;
4777 if (!FRAME_X_OUTPUT (frame))
4778 return false;
4780 dpyinfo = FRAME_DISPLAY_INFO (frame);
4781 dpyinfo->last_mouse_movement_time = event->time;
4782 dpyinfo->last_mouse_motion_frame = frame;
4783 dpyinfo->last_mouse_motion_x = event->x;
4784 dpyinfo->last_mouse_motion_y = event->y;
4786 if (event->window != FRAME_X_WINDOW (frame))
4788 frame->mouse_moved = true;
4789 dpyinfo->last_mouse_scroll_bar = NULL;
4790 note_mouse_highlight (frame, -1, -1);
4791 dpyinfo->last_mouse_glyph_frame = NULL;
4792 return true;
4796 /* Has the mouse moved off the glyph it was on at the last sighting? */
4797 r = &dpyinfo->last_mouse_glyph;
4798 if (frame != dpyinfo->last_mouse_glyph_frame
4799 || event->x < r->x || event->x >= r->x + r->width
4800 || event->y < r->y || event->y >= r->y + r->height)
4802 frame->mouse_moved = true;
4803 dpyinfo->last_mouse_scroll_bar = NULL;
4804 note_mouse_highlight (frame, event->x, event->y);
4805 /* Remember which glyph we're now on. */
4806 remember_mouse_glyph (frame, event->x, event->y, r);
4807 dpyinfo->last_mouse_glyph_frame = frame;
4808 return true;
4811 return false;
4814 /* Return the current position of the mouse.
4815 *FP should be a frame which indicates which display to ask about.
4817 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
4818 and *PART to the frame, window, and scroll bar part that the mouse
4819 is over. Set *X and *Y to the portion and whole of the mouse's
4820 position on the scroll bar.
4822 If the mouse movement started elsewhere, set *FP to the frame the
4823 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
4824 the mouse is over.
4826 Set *TIMESTAMP to the server time-stamp for the time at which the mouse
4827 was at this position.
4829 Don't store anything if we don't have a valid set of values to report.
4831 This clears the mouse_moved flag, so we can wait for the next mouse
4832 movement. */
4834 static void
4835 XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
4836 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
4837 Time *timestamp)
4839 struct frame *f1;
4840 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
4842 block_input ();
4844 if (dpyinfo->last_mouse_scroll_bar && insist == 0)
4846 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
4848 if (bar->horizontal)
4849 x_horizontal_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp);
4850 else
4851 x_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp);
4853 else
4855 Window root;
4856 int root_x, root_y;
4858 Window dummy_window;
4859 int dummy;
4861 Lisp_Object frame, tail;
4863 /* Clear the mouse-moved flag for every frame on this display. */
4864 FOR_EACH_FRAME (tail, frame)
4865 if (FRAME_X_P (XFRAME (frame))
4866 && FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
4867 XFRAME (frame)->mouse_moved = false;
4869 dpyinfo->last_mouse_scroll_bar = NULL;
4871 /* Figure out which root window we're on. */
4872 XQueryPointer (FRAME_X_DISPLAY (*fp),
4873 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
4875 /* The root window which contains the pointer. */
4876 &root,
4878 /* Trash which we can't trust if the pointer is on
4879 a different screen. */
4880 &dummy_window,
4882 /* The position on that root window. */
4883 &root_x, &root_y,
4885 /* More trash we can't trust. */
4886 &dummy, &dummy,
4888 /* Modifier keys and pointer buttons, about which
4889 we don't care. */
4890 (unsigned int *) &dummy);
4892 /* Now we have a position on the root; find the innermost window
4893 containing the pointer. */
4895 Window win, child;
4896 int win_x, win_y;
4897 int parent_x = 0, parent_y = 0;
4899 win = root;
4901 /* XTranslateCoordinates can get errors if the window
4902 structure is changing at the same time this function
4903 is running. So at least we must not crash from them. */
4905 x_catch_errors (FRAME_X_DISPLAY (*fp));
4907 if (x_mouse_grabbed (dpyinfo))
4909 /* If mouse was grabbed on a frame, give coords for that frame
4910 even if the mouse is now outside it. */
4911 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
4913 /* From-window. */
4914 root,
4916 /* To-window. */
4917 FRAME_X_WINDOW (dpyinfo->last_mouse_frame),
4919 /* From-position, to-position. */
4920 root_x, root_y, &win_x, &win_y,
4922 /* Child of win. */
4923 &child);
4924 f1 = dpyinfo->last_mouse_frame;
4926 else
4928 while (true)
4930 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
4932 /* From-window, to-window. */
4933 root, win,
4935 /* From-position, to-position. */
4936 root_x, root_y, &win_x, &win_y,
4938 /* Child of win. */
4939 &child);
4941 if (child == None || child == win)
4942 break;
4943 #ifdef USE_GTK
4944 /* We don't wan't to know the innermost window. We
4945 want the edit window. For non-Gtk+ the innermost
4946 window is the edit window. For Gtk+ it might not
4947 be. It might be the tool bar for example. */
4948 if (x_window_to_frame (dpyinfo, win))
4949 break;
4950 #endif
4951 win = child;
4952 parent_x = win_x;
4953 parent_y = win_y;
4956 /* Now we know that:
4957 win is the innermost window containing the pointer
4958 (XTC says it has no child containing the pointer),
4959 win_x and win_y are the pointer's position in it
4960 (XTC did this the last time through), and
4961 parent_x and parent_y are the pointer's position in win's parent.
4962 (They are what win_x and win_y were when win was child.
4963 If win is the root window, it has no parent, and
4964 parent_{x,y} are invalid, but that's okay, because we'll
4965 never use them in that case.) */
4967 #ifdef USE_GTK
4968 /* We don't wan't to know the innermost window. We
4969 want the edit window. */
4970 f1 = x_window_to_frame (dpyinfo, win);
4971 #else
4972 /* Is win one of our frames? */
4973 f1 = x_any_window_to_frame (dpyinfo, win);
4974 #endif
4976 #ifdef USE_X_TOOLKIT
4977 /* If we end up with the menu bar window, say it's not
4978 on the frame. */
4979 if (f1 != NULL
4980 && f1->output_data.x->menubar_widget
4981 && win == XtWindow (f1->output_data.x->menubar_widget))
4982 f1 = NULL;
4983 #endif /* USE_X_TOOLKIT */
4986 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
4987 f1 = 0;
4989 x_uncatch_errors_after_check ();
4991 /* If not, is it one of our scroll bars? */
4992 if (! f1)
4994 struct scroll_bar *bar;
4996 bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win, 2);
4998 if (bar)
5000 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5001 win_x = parent_x;
5002 win_y = parent_y;
5006 if (f1 == 0 && insist > 0)
5007 f1 = SELECTED_FRAME ();
5009 if (f1)
5011 /* Ok, we found a frame. Store all the values.
5012 last_mouse_glyph is a rectangle used to reduce the
5013 generation of mouse events. To not miss any motion
5014 events, we must divide the frame into rectangles of the
5015 size of the smallest character that could be displayed
5016 on it, i.e. into the same rectangles that matrices on
5017 the frame are divided into. */
5019 /* FIXME: what if F1 is not an X frame? */
5020 dpyinfo = FRAME_DISPLAY_INFO (f1);
5021 remember_mouse_glyph (f1, win_x, win_y, &dpyinfo->last_mouse_glyph);
5022 dpyinfo->last_mouse_glyph_frame = f1;
5024 *bar_window = Qnil;
5025 *part = 0;
5026 *fp = f1;
5027 XSETINT (*x, win_x);
5028 XSETINT (*y, win_y);
5029 *timestamp = dpyinfo->last_mouse_movement_time;
5034 unblock_input ();
5039 /***********************************************************************
5040 Scroll bars
5041 ***********************************************************************/
5043 /* Scroll bar support. */
5045 /* Given an X window ID and a DISPLAY, find the struct scroll_bar which
5046 manages it.
5047 This can be called in GC, so we have to make sure to strip off mark
5048 bits. */
5050 static struct scroll_bar *
5051 x_window_to_scroll_bar (Display *display, Window window_id, int type)
5053 Lisp_Object tail, frame;
5055 #if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
5056 window_id = (Window) xg_get_scroll_id_for_window (display, window_id);
5057 #endif /* USE_GTK && USE_TOOLKIT_SCROLL_BARS */
5059 FOR_EACH_FRAME (tail, frame)
5061 Lisp_Object bar, condemned;
5063 if (! FRAME_X_P (XFRAME (frame)))
5064 continue;
5066 /* Scan this frame's scroll bar list for a scroll bar with the
5067 right window ID. */
5068 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
5069 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
5070 /* This trick allows us to search both the ordinary and
5071 condemned scroll bar lists with one loop. */
5072 ! NILP (bar) || (bar = condemned,
5073 condemned = Qnil,
5074 ! NILP (bar));
5075 bar = XSCROLL_BAR (bar)->next)
5076 if (XSCROLL_BAR (bar)->x_window == window_id
5077 && FRAME_X_DISPLAY (XFRAME (frame)) == display
5078 && (type = 2
5079 || (type == 1 && XSCROLL_BAR (bar)->horizontal)
5080 || (type == 0 && !XSCROLL_BAR (bar)->horizontal)))
5081 return XSCROLL_BAR (bar);
5084 return NULL;
5088 #if defined USE_LUCID
5090 /* Return the Lucid menu bar WINDOW is part of. Return null
5091 if WINDOW is not part of a menu bar. */
5093 static Widget
5094 x_window_to_menu_bar (Window window)
5096 Lisp_Object tail, frame;
5098 FOR_EACH_FRAME (tail, frame)
5099 if (FRAME_X_P (XFRAME (frame)))
5101 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
5103 if (menu_bar && xlwmenu_window_p (menu_bar, window))
5104 return menu_bar;
5106 return NULL;
5109 #endif /* USE_LUCID */
5112 /************************************************************************
5113 Toolkit scroll bars
5114 ************************************************************************/
5116 #ifdef USE_TOOLKIT_SCROLL_BARS
5118 static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part,
5119 int, int, bool);
5121 /* Lisp window being scrolled. Set when starting to interact with
5122 a toolkit scroll bar, reset to nil when ending the interaction. */
5124 static Lisp_Object window_being_scrolled;
5126 /* Whether this is an Xaw with arrow-scrollbars. This should imply
5127 that movements of 1/20 of the screen size are mapped to up/down. */
5129 #ifndef USE_GTK
5130 /* Id of action hook installed for scroll bars. */
5132 static XtActionHookId action_hook_id;
5133 static XtActionHookId horizontal_action_hook_id;
5135 static Boolean xaw3d_arrow_scroll;
5137 /* Whether the drag scrolling maintains the mouse at the top of the
5138 thumb. If not, resizing the thumb needs to be done more carefully
5139 to avoid jerkiness. */
5141 static Boolean xaw3d_pick_top;
5143 /* Action hook installed via XtAppAddActionHook when toolkit scroll
5144 bars are used.. The hook is responsible for detecting when
5145 the user ends an interaction with the scroll bar, and generates
5146 a `end-scroll' SCROLL_BAR_CLICK_EVENT' event if so. */
5148 static void
5149 xt_action_hook (Widget widget, XtPointer client_data, String action_name,
5150 XEvent *event, String *params, Cardinal *num_params)
5152 bool scroll_bar_p;
5153 const char *end_action;
5155 #ifdef USE_MOTIF
5156 scroll_bar_p = XmIsScrollBar (widget);
5157 end_action = "Release";
5158 #else /* !USE_MOTIF i.e. use Xaw */
5159 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
5160 end_action = "EndScroll";
5161 #endif /* USE_MOTIF */
5163 if (scroll_bar_p
5164 && strcmp (action_name, end_action) == 0
5165 && WINDOWP (window_being_scrolled))
5167 struct window *w;
5168 struct scroll_bar *bar;
5170 x_send_scroll_bar_event (window_being_scrolled,
5171 scroll_bar_end_scroll, 0, 0, false);
5172 w = XWINDOW (window_being_scrolled);
5173 bar = XSCROLL_BAR (w->vertical_scroll_bar);
5175 if (bar->dragging != -1)
5177 bar->dragging = -1;
5178 /* The thumb size is incorrect while dragging: fix it. */
5179 set_vertical_scroll_bar (w);
5181 window_being_scrolled = Qnil;
5182 #if defined (USE_LUCID)
5183 bar->last_seen_part = scroll_bar_nowhere;
5184 #endif
5185 /* Xt timeouts no longer needed. */
5186 toolkit_scroll_bar_interaction = false;
5191 static void
5192 xt_horizontal_action_hook (Widget widget, XtPointer client_data, String action_name,
5193 XEvent *event, String *params, Cardinal *num_params)
5195 bool scroll_bar_p;
5196 const char *end_action;
5198 #ifdef USE_MOTIF
5199 scroll_bar_p = XmIsScrollBar (widget);
5200 end_action = "Release";
5201 #else /* !USE_MOTIF i.e. use Xaw */
5202 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
5203 end_action = "EndScroll";
5204 #endif /* USE_MOTIF */
5206 if (scroll_bar_p
5207 && strcmp (action_name, end_action) == 0
5208 && WINDOWP (window_being_scrolled))
5210 struct window *w;
5211 struct scroll_bar *bar;
5213 x_send_scroll_bar_event (window_being_scrolled,
5214 scroll_bar_end_scroll, 0, 0, true);
5215 w = XWINDOW (window_being_scrolled);
5216 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
5218 if (bar->dragging != -1)
5220 bar->dragging = -1;
5221 /* The thumb size is incorrect while dragging: fix it. */
5222 set_horizontal_scroll_bar (w);
5224 window_being_scrolled = Qnil;
5225 #if defined (USE_LUCID)
5226 bar->last_seen_part = scroll_bar_nowhere;
5227 #endif
5228 /* Xt timeouts no longer needed. */
5229 toolkit_scroll_bar_interaction = false;
5232 #endif /* not USE_GTK */
5234 /* Send a client message with message type Xatom_Scrollbar for a
5235 scroll action to the frame of WINDOW. PART is a value identifying
5236 the part of the scroll bar that was clicked on. PORTION is the
5237 amount to scroll of a whole of WHOLE. */
5239 static void
5240 x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part,
5241 int portion, int whole, bool horizontal)
5243 XEvent event;
5244 XClientMessageEvent *ev = &event.xclient;
5245 struct window *w = XWINDOW (window);
5246 struct frame *f = XFRAME (w->frame);
5247 intptr_t iw = (intptr_t) w;
5248 enum { BITS_PER_INTPTR = CHAR_BIT * sizeof iw };
5249 verify (BITS_PER_INTPTR <= 64);
5250 int sign_shift = BITS_PER_INTPTR - 32;
5252 block_input ();
5254 /* Construct a ClientMessage event to send to the frame. */
5255 ev->type = ClientMessage;
5256 ev->message_type = (horizontal
5257 ? FRAME_DISPLAY_INFO (f)->Xatom_Horizontal_Scrollbar
5258 : FRAME_DISPLAY_INFO (f)->Xatom_Scrollbar);
5259 ev->display = FRAME_X_DISPLAY (f);
5260 ev->window = FRAME_X_WINDOW (f);
5261 ev->format = 32;
5263 /* A 32-bit X client on a 64-bit X server can pass a window pointer
5264 as-is. A 64-bit client on a 32-bit X server is in trouble
5265 because a pointer does not fit and would be truncated while
5266 passing through the server. So use two slots and hope that X12
5267 will resolve such issues someday. */
5268 ev->data.l[0] = iw >> 31 >> 1;
5269 ev->data.l[1] = sign_shift <= 0 ? iw : iw << sign_shift >> sign_shift;
5270 ev->data.l[2] = part;
5271 ev->data.l[3] = portion;
5272 ev->data.l[4] = whole;
5274 /* Make Xt timeouts work while the scroll bar is active. */
5275 #ifdef USE_X_TOOLKIT
5276 toolkit_scroll_bar_interaction = true;
5277 x_activate_timeout_atimer ();
5278 #endif
5280 /* Setting the event mask to zero means that the message will
5281 be sent to the client that created the window, and if that
5282 window no longer exists, no event will be sent. */
5283 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
5284 unblock_input ();
5288 /* Transform a scroll bar ClientMessage EVENT to an Emacs input event
5289 in *IEVENT. */
5291 static void
5292 x_scroll_bar_to_input_event (const XEvent *event,
5293 struct input_event *ievent)
5295 const XClientMessageEvent *ev = &event->xclient;
5296 Lisp_Object window;
5297 struct window *w;
5299 /* See the comment in the function above. */
5300 intptr_t iw0 = ev->data.l[0];
5301 intptr_t iw1 = ev->data.l[1];
5302 intptr_t iw = (iw0 << 31 << 1) + (iw1 & 0xffffffffu);
5303 w = (struct window *) iw;
5305 XSETWINDOW (window, w);
5307 ievent->kind = SCROLL_BAR_CLICK_EVENT;
5308 ievent->frame_or_window = window;
5309 ievent->arg = Qnil;
5310 #ifdef USE_GTK
5311 ievent->timestamp = CurrentTime;
5312 #else
5313 ievent->timestamp =
5314 XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame)));
5315 #endif
5316 ievent->code = 0;
5317 ievent->part = ev->data.l[2];
5318 ievent->x = make_number (ev->data.l[3]);
5319 ievent->y = make_number (ev->data.l[4]);
5320 ievent->modifiers = 0;
5323 /* Transform a horizontal scroll bar ClientMessage EVENT to an Emacs
5324 input event in *IEVENT. */
5326 static void
5327 x_horizontal_scroll_bar_to_input_event (const XEvent *event,
5328 struct input_event *ievent)
5330 const XClientMessageEvent *ev = &event->xclient;
5331 Lisp_Object window;
5332 struct window *w;
5334 /* See the comment in the function above. */
5335 intptr_t iw0 = ev->data.l[0];
5336 intptr_t iw1 = ev->data.l[1];
5337 intptr_t iw = (iw0 << 31 << 1) + (iw1 & 0xffffffffu);
5338 w = (struct window *) iw;
5340 XSETWINDOW (window, w);
5342 ievent->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
5343 ievent->frame_or_window = window;
5344 ievent->arg = Qnil;
5345 #ifdef USE_GTK
5346 ievent->timestamp = CurrentTime;
5347 #else
5348 ievent->timestamp =
5349 XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame)));
5350 #endif
5351 ievent->code = 0;
5352 ievent->part = ev->data.l[2];
5353 ievent->x = make_number (ev->data.l[3]);
5354 ievent->y = make_number (ev->data.l[4]);
5355 ievent->modifiers = 0;
5359 #ifdef USE_MOTIF
5361 /* Minimum and maximum values used for Motif scroll bars. */
5363 #define XM_SB_MAX 10000000
5365 /* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
5366 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
5367 CALL_DATA is a pointer to a XmScrollBarCallbackStruct. */
5369 static void
5370 xm_scroll_callback (Widget widget, XtPointer client_data, XtPointer call_data)
5372 struct scroll_bar *bar = client_data;
5373 XmScrollBarCallbackStruct *cs = call_data;
5374 enum scroll_bar_part part = scroll_bar_nowhere;
5375 bool horizontal = bar->horizontal;
5376 int whole = 0, portion = 0;
5378 switch (cs->reason)
5380 case XmCR_DECREMENT:
5381 bar->dragging = -1;
5382 part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow;
5383 break;
5385 case XmCR_INCREMENT:
5386 bar->dragging = -1;
5387 part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow;
5388 break;
5390 case XmCR_PAGE_DECREMENT:
5391 bar->dragging = -1;
5392 part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle;
5393 break;
5395 case XmCR_PAGE_INCREMENT:
5396 bar->dragging = -1;
5397 part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle;
5398 break;
5400 case XmCR_TO_TOP:
5401 bar->dragging = -1;
5402 part = horizontal ? scroll_bar_to_leftmost : scroll_bar_to_top;
5403 break;
5405 case XmCR_TO_BOTTOM:
5406 bar->dragging = -1;
5407 part = horizontal ? scroll_bar_to_rightmost : scroll_bar_to_bottom;
5408 break;
5410 case XmCR_DRAG:
5412 int slider_size;
5414 block_input ();
5415 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
5416 unblock_input ();
5418 if (horizontal)
5420 portion = bar->whole * ((float)cs->value / XM_SB_MAX);
5421 whole = bar->whole * ((float)(XM_SB_MAX - slider_size) / XM_SB_MAX);
5422 portion = min (portion, whole);
5423 part = scroll_bar_horizontal_handle;
5425 else
5427 whole = XM_SB_MAX - slider_size;
5428 portion = min (cs->value, whole);
5429 part = scroll_bar_handle;
5432 bar->dragging = cs->value;
5434 break;
5436 case XmCR_VALUE_CHANGED:
5437 break;
5440 if (part != scroll_bar_nowhere)
5442 window_being_scrolled = bar->window;
5443 x_send_scroll_bar_event (bar->window, part, portion, whole,
5444 bar->horizontal);
5448 #elif defined USE_GTK
5450 /* Scroll bar callback for GTK scroll bars. WIDGET is the scroll
5451 bar widget. DATA is a pointer to the scroll_bar structure. */
5453 static gboolean
5454 xg_scroll_callback (GtkRange *range,
5455 GtkScrollType scroll,
5456 gdouble value,
5457 gpointer user_data)
5459 int whole = 0, portion = 0;
5460 struct scroll_bar *bar = user_data;
5461 enum scroll_bar_part part = scroll_bar_nowhere;
5462 GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
5463 struct frame *f = g_object_get_data (G_OBJECT (range), XG_FRAME_DATA);
5465 if (xg_ignore_gtk_scrollbar) return false;
5467 switch (scroll)
5469 case GTK_SCROLL_JUMP:
5470 /* Buttons 1 2 or 3 must be grabbed. */
5471 if (FRAME_DISPLAY_INFO (f)->grabbed != 0
5472 && FRAME_DISPLAY_INFO (f)->grabbed < (1 << 4))
5474 if (bar->horizontal)
5476 part = scroll_bar_horizontal_handle;
5477 whole = (int)(gtk_adjustment_get_upper (adj) -
5478 gtk_adjustment_get_page_size (adj));
5479 portion = min ((int)value, whole);
5480 bar->dragging = portion;
5482 else
5484 part = scroll_bar_handle;
5485 whole = gtk_adjustment_get_upper (adj) -
5486 gtk_adjustment_get_page_size (adj);
5487 portion = min ((int)value, whole);
5488 bar->dragging = portion;
5491 break;
5492 case GTK_SCROLL_STEP_BACKWARD:
5493 part = (bar->horizontal
5494 ? scroll_bar_left_arrow : scroll_bar_up_arrow);
5495 bar->dragging = -1;
5496 break;
5497 case GTK_SCROLL_STEP_FORWARD:
5498 part = (bar->horizontal
5499 ? scroll_bar_right_arrow : scroll_bar_down_arrow);
5500 bar->dragging = -1;
5501 break;
5502 case GTK_SCROLL_PAGE_BACKWARD:
5503 part = (bar->horizontal
5504 ? scroll_bar_before_handle : scroll_bar_above_handle);
5505 bar->dragging = -1;
5506 break;
5507 case GTK_SCROLL_PAGE_FORWARD:
5508 part = (bar->horizontal
5509 ? scroll_bar_after_handle : scroll_bar_below_handle);
5510 bar->dragging = -1;
5511 break;
5512 default:
5513 break;
5516 if (part != scroll_bar_nowhere)
5518 window_being_scrolled = bar->window;
5519 x_send_scroll_bar_event (bar->window, part, portion, whole,
5520 bar->horizontal);
5523 return false;
5526 /* Callback for button release. Sets dragging to -1 when dragging is done. */
5528 static gboolean
5529 xg_end_scroll_callback (GtkWidget *widget,
5530 GdkEventButton *event,
5531 gpointer user_data)
5533 struct scroll_bar *bar = user_data;
5534 bar->dragging = -1;
5535 if (WINDOWP (window_being_scrolled))
5537 x_send_scroll_bar_event (window_being_scrolled,
5538 scroll_bar_end_scroll, 0, 0, bar->horizontal);
5539 window_being_scrolled = Qnil;
5542 return false;
5546 #else /* not USE_GTK and not USE_MOTIF */
5548 /* Xaw scroll bar callback. Invoked when the thumb is dragged.
5549 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
5550 scroll bar struct. CALL_DATA is a pointer to a float saying where
5551 the thumb is. */
5553 static void
5554 xaw_jump_callback (Widget widget, XtPointer client_data, XtPointer call_data)
5556 struct scroll_bar *bar = client_data;
5557 float *top_addr = call_data;
5558 float top = *top_addr;
5559 float shown;
5560 int whole, portion, height, width;
5561 enum scroll_bar_part part;
5562 bool horizontal = bar->horizontal;
5565 if (horizontal)
5567 /* Get the size of the thumb, a value between 0 and 1. */
5568 block_input ();
5569 XtVaGetValues (widget, XtNshown, &shown, XtNwidth, &width, NULL);
5570 unblock_input ();
5572 if (shown < 1)
5574 whole = bar->whole - (shown * bar->whole);
5575 portion = min (top * bar->whole, whole);
5577 else
5579 whole = bar->whole;
5580 portion = 0;
5583 part = scroll_bar_horizontal_handle;
5585 else
5587 /* Get the size of the thumb, a value between 0 and 1. */
5588 block_input ();
5589 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
5590 unblock_input ();
5592 whole = 10000000;
5593 portion = shown < 1 ? top * whole : 0;
5595 if (shown < 1 && (eabs (top + shown - 1) < 1.0f / height))
5596 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
5597 the bottom, so we force the scrolling whenever we see that we're
5598 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
5599 we try to ensure that we always stay two pixels away from the
5600 bottom). */
5601 part = scroll_bar_down_arrow;
5602 else
5603 part = scroll_bar_handle;
5606 window_being_scrolled = bar->window;
5607 bar->dragging = portion;
5608 bar->last_seen_part = part;
5609 x_send_scroll_bar_event (bar->window, part, portion, whole, bar->horizontal);
5613 /* Xaw scroll bar callback. Invoked for incremental scrolling.,
5614 i.e. line or page up or down. WIDGET is the Xaw scroll bar
5615 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
5616 the scroll bar. CALL_DATA is an integer specifying the action that
5617 has taken place. Its magnitude is in the range 0..height of the
5618 scroll bar. Negative values mean scroll towards buffer start.
5619 Values < height of scroll bar mean line-wise movement. */
5621 static void
5622 xaw_scroll_callback (Widget widget, XtPointer client_data, XtPointer call_data)
5624 struct scroll_bar *bar = client_data;
5625 /* The position really is stored cast to a pointer. */
5626 int position = (intptr_t) call_data;
5627 Dimension height, width;
5628 enum scroll_bar_part part;
5630 if (bar->horizontal)
5632 /* Get the width of the scroll bar. */
5633 block_input ();
5634 XtVaGetValues (widget, XtNwidth, &width, NULL);
5635 unblock_input ();
5637 if (eabs (position) >= width)
5638 part = (position < 0) ? scroll_bar_before_handle : scroll_bar_after_handle;
5640 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
5641 it maps line-movement to call_data = max(5, height/20). */
5642 else if (xaw3d_arrow_scroll && eabs (position) <= max (5, width / 20))
5643 part = (position < 0) ? scroll_bar_left_arrow : scroll_bar_right_arrow;
5644 else
5645 part = scroll_bar_move_ratio;
5647 window_being_scrolled = bar->window;
5648 bar->dragging = -1;
5649 bar->last_seen_part = part;
5650 x_send_scroll_bar_event (bar->window, part, position, width,
5651 bar->horizontal);
5653 else
5656 /* Get the height of the scroll bar. */
5657 block_input ();
5658 XtVaGetValues (widget, XtNheight, &height, NULL);
5659 unblock_input ();
5661 if (eabs (position) >= height)
5662 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
5664 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
5665 it maps line-movement to call_data = max(5, height/20). */
5666 else if (xaw3d_arrow_scroll && eabs (position) <= max (5, height / 20))
5667 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
5668 else
5669 part = scroll_bar_move_ratio;
5671 window_being_scrolled = bar->window;
5672 bar->dragging = -1;
5673 bar->last_seen_part = part;
5674 x_send_scroll_bar_event (bar->window, part, position, height,
5675 bar->horizontal);
5679 #endif /* not USE_GTK and not USE_MOTIF */
5681 #define SCROLL_BAR_NAME "verticalScrollBar"
5682 #define SCROLL_BAR_HORIZONTAL_NAME "horizontalScrollBar"
5684 /* Create the widget for scroll bar BAR on frame F. Record the widget
5685 and X window of the scroll bar in BAR. */
5687 #ifdef USE_GTK
5688 static void
5689 x_create_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
5691 const char *scroll_bar_name = SCROLL_BAR_NAME;
5693 block_input ();
5694 xg_create_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
5695 G_CALLBACK (xg_end_scroll_callback),
5696 scroll_bar_name);
5697 unblock_input ();
5700 static void
5701 x_create_horizontal_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
5703 const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME;
5705 block_input ();
5706 xg_create_horizontal_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
5707 G_CALLBACK (xg_end_scroll_callback),
5708 scroll_bar_name);
5709 unblock_input ();
5712 #else /* not USE_GTK */
5714 static void
5715 x_create_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
5717 Window xwindow;
5718 Widget widget;
5719 Arg av[20];
5720 int ac = 0;
5721 const char *scroll_bar_name = SCROLL_BAR_NAME;
5722 unsigned long pixel;
5724 block_input ();
5726 #ifdef USE_MOTIF
5727 /* Set resources. Create the widget. */
5728 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
5729 XtSetArg (av[ac], XmNminimum, 0); ++ac;
5730 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
5731 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
5732 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
5733 XtSetArg (av[ac], XmNincrement, 1); ++ac;
5734 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
5736 pixel = f->output_data.x->scroll_bar_foreground_pixel;
5737 if (pixel != -1)
5739 XtSetArg (av[ac], XmNforeground, pixel);
5740 ++ac;
5743 pixel = f->output_data.x->scroll_bar_background_pixel;
5744 if (pixel != -1)
5746 XtSetArg (av[ac], XmNbackground, pixel);
5747 ++ac;
5750 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
5751 (char *) scroll_bar_name, av, ac);
5753 /* Add one callback for everything that can happen. */
5754 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
5755 (XtPointer) bar);
5756 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
5757 (XtPointer) bar);
5758 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
5759 (XtPointer) bar);
5760 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
5761 (XtPointer) bar);
5762 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
5763 (XtPointer) bar);
5764 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
5765 (XtPointer) bar);
5766 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
5767 (XtPointer) bar);
5769 /* Realize the widget. Only after that is the X window created. */
5770 XtRealizeWidget (widget);
5772 /* Set the cursor to an arrow. I didn't find a resource to do that.
5773 And I'm wondering why it hasn't an arrow cursor by default. */
5774 XDefineCursor (XtDisplay (widget), XtWindow (widget),
5775 f->output_data.x->nontext_cursor);
5777 #else /* !USE_MOTIF i.e. use Xaw */
5779 /* Set resources. Create the widget. The background of the
5780 Xaw3d scroll bar widget is a little bit light for my taste.
5781 We don't alter it here to let users change it according
5782 to their taste with `emacs*verticalScrollBar.background: xxx'. */
5783 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
5784 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
5785 /* For smoother scrolling with Xaw3d -sm */
5786 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
5788 pixel = f->output_data.x->scroll_bar_foreground_pixel;
5789 if (pixel != -1)
5791 XtSetArg (av[ac], XtNforeground, pixel);
5792 ++ac;
5795 pixel = f->output_data.x->scroll_bar_background_pixel;
5796 if (pixel != -1)
5798 XtSetArg (av[ac], XtNbackground, pixel);
5799 ++ac;
5802 /* Top/bottom shadow colors. */
5804 /* Allocate them, if necessary. */
5805 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
5807 pixel = f->output_data.x->scroll_bar_background_pixel;
5808 if (pixel != -1)
5810 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
5811 FRAME_X_COLORMAP (f),
5812 &pixel, 1.2, 0x8000))
5813 pixel = -1;
5814 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
5817 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
5819 pixel = f->output_data.x->scroll_bar_background_pixel;
5820 if (pixel != -1)
5822 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
5823 FRAME_X_COLORMAP (f),
5824 &pixel, 0.6, 0x4000))
5825 pixel = -1;
5826 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
5830 #ifdef XtNbeNiceToColormap
5831 /* Tell the toolkit about them. */
5832 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
5833 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
5834 /* We tried to allocate a color for the top/bottom shadow, and
5835 failed, so tell Xaw3d to use dithering instead. */
5836 /* But only if we have a small colormap. Xaw3d can allocate nice
5837 colors itself. */
5839 XtSetArg (av[ac], XtNbeNiceToColormap,
5840 DefaultDepthOfScreen (FRAME_X_SCREEN (f)) < 16);
5841 ++ac;
5843 else
5844 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
5845 be more consistent with other emacs 3d colors, and since Xaw3d is
5846 not good at dealing with allocation failure. */
5848 /* This tells Xaw3d to use real colors instead of dithering for
5849 the shadows. */
5850 XtSetArg (av[ac], XtNbeNiceToColormap, False);
5851 ++ac;
5853 /* Specify the colors. */
5854 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
5855 if (pixel != -1)
5857 XtSetArg (av[ac], XtNtopShadowPixel, pixel);
5858 ++ac;
5860 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
5861 if (pixel != -1)
5863 XtSetArg (av[ac], XtNbottomShadowPixel, pixel);
5864 ++ac;
5867 #endif
5869 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
5870 f->output_data.x->edit_widget, av, ac);
5873 char const *initial = "";
5874 char const *val = initial;
5875 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
5876 #ifdef XtNarrowScrollbars
5877 XtNarrowScrollbars, (XtPointer) &xaw3d_arrow_scroll,
5878 #endif
5879 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
5880 if (xaw3d_arrow_scroll || val == initial)
5881 { /* ARROW_SCROLL */
5882 xaw3d_arrow_scroll = True;
5883 /* Isn't that just a personal preference ? --Stef */
5884 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
5888 /* Define callbacks. */
5889 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
5890 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
5891 (XtPointer) bar);
5893 /* Realize the widget. Only after that is the X window created. */
5894 XtRealizeWidget (widget);
5896 #endif /* !USE_MOTIF */
5898 /* Install an action hook that lets us detect when the user
5899 finishes interacting with a scroll bar. */
5900 if (action_hook_id == 0)
5901 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
5903 /* Remember X window and widget in the scroll bar vector. */
5904 SET_SCROLL_BAR_X_WIDGET (bar, widget);
5905 xwindow = XtWindow (widget);
5906 bar->x_window = xwindow;
5907 bar->whole = 1;
5908 bar->horizontal = false;
5910 unblock_input ();
5913 static void
5914 x_create_horizontal_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
5916 Window xwindow;
5917 Widget widget;
5918 Arg av[20];
5919 int ac = 0;
5920 const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME;
5921 unsigned long pixel;
5923 block_input ();
5925 #ifdef USE_MOTIF
5926 /* Set resources. Create the widget. */
5927 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
5928 XtSetArg (av[ac], XmNminimum, 0); ++ac;
5929 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
5930 XtSetArg (av[ac], XmNorientation, XmHORIZONTAL); ++ac;
5931 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_RIGHT), ++ac;
5932 XtSetArg (av[ac], XmNincrement, 1); ++ac;
5933 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
5935 pixel = f->output_data.x->scroll_bar_foreground_pixel;
5936 if (pixel != -1)
5938 XtSetArg (av[ac], XmNforeground, pixel);
5939 ++ac;
5942 pixel = f->output_data.x->scroll_bar_background_pixel;
5943 if (pixel != -1)
5945 XtSetArg (av[ac], XmNbackground, pixel);
5946 ++ac;
5949 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
5950 (char *) scroll_bar_name, av, ac);
5952 /* Add one callback for everything that can happen. */
5953 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
5954 (XtPointer) bar);
5955 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
5956 (XtPointer) bar);
5957 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
5958 (XtPointer) bar);
5959 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
5960 (XtPointer) bar);
5961 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
5962 (XtPointer) bar);
5963 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
5964 (XtPointer) bar);
5965 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
5966 (XtPointer) bar);
5968 /* Realize the widget. Only after that is the X window created. */
5969 XtRealizeWidget (widget);
5971 /* Set the cursor to an arrow. I didn't find a resource to do that.
5972 And I'm wondering why it hasn't an arrow cursor by default. */
5973 XDefineCursor (XtDisplay (widget), XtWindow (widget),
5974 f->output_data.x->nontext_cursor);
5976 #else /* !USE_MOTIF i.e. use Xaw */
5978 /* Set resources. Create the widget. The background of the
5979 Xaw3d scroll bar widget is a little bit light for my taste.
5980 We don't alter it here to let users change it according
5981 to their taste with `emacs*verticalScrollBar.background: xxx'. */
5982 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
5983 XtSetArg (av[ac], XtNorientation, XtorientHorizontal); ++ac;
5984 /* For smoother scrolling with Xaw3d -sm */
5985 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
5987 pixel = f->output_data.x->scroll_bar_foreground_pixel;
5988 if (pixel != -1)
5990 XtSetArg (av[ac], XtNforeground, pixel);
5991 ++ac;
5994 pixel = f->output_data.x->scroll_bar_background_pixel;
5995 if (pixel != -1)
5997 XtSetArg (av[ac], XtNbackground, pixel);
5998 ++ac;
6001 /* Top/bottom shadow colors. */
6003 /* Allocate them, if necessary. */
6004 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
6006 pixel = f->output_data.x->scroll_bar_background_pixel;
6007 if (pixel != -1)
6009 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
6010 FRAME_X_COLORMAP (f),
6011 &pixel, 1.2, 0x8000))
6012 pixel = -1;
6013 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
6016 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
6018 pixel = f->output_data.x->scroll_bar_background_pixel;
6019 if (pixel != -1)
6021 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f),
6022 FRAME_X_COLORMAP (f),
6023 &pixel, 0.6, 0x4000))
6024 pixel = -1;
6025 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
6029 #ifdef XtNbeNiceToColormap
6030 /* Tell the toolkit about them. */
6031 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
6032 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
6033 /* We tried to allocate a color for the top/bottom shadow, and
6034 failed, so tell Xaw3d to use dithering instead. */
6035 /* But only if we have a small colormap. Xaw3d can allocate nice
6036 colors itself. */
6038 XtSetArg (av[ac], XtNbeNiceToColormap,
6039 DefaultDepthOfScreen (FRAME_X_SCREEN (f)) < 16);
6040 ++ac;
6042 else
6043 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
6044 be more consistent with other emacs 3d colors, and since Xaw3d is
6045 not good at dealing with allocation failure. */
6047 /* This tells Xaw3d to use real colors instead of dithering for
6048 the shadows. */
6049 XtSetArg (av[ac], XtNbeNiceToColormap, False);
6050 ++ac;
6052 /* Specify the colors. */
6053 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
6054 if (pixel != -1)
6056 XtSetArg (av[ac], XtNtopShadowPixel, pixel);
6057 ++ac;
6059 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
6060 if (pixel != -1)
6062 XtSetArg (av[ac], XtNbottomShadowPixel, pixel);
6063 ++ac;
6066 #endif
6068 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
6069 f->output_data.x->edit_widget, av, ac);
6072 char const *initial = "";
6073 char const *val = initial;
6074 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
6075 #ifdef XtNarrowScrollbars
6076 XtNarrowScrollbars, (XtPointer) &xaw3d_arrow_scroll,
6077 #endif
6078 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
6079 if (xaw3d_arrow_scroll || val == initial)
6080 { /* ARROW_SCROLL */
6081 xaw3d_arrow_scroll = True;
6082 /* Isn't that just a personal preference ? --Stef */
6083 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
6087 /* Define callbacks. */
6088 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
6089 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
6090 (XtPointer) bar);
6092 /* Realize the widget. Only after that is the X window created. */
6093 XtRealizeWidget (widget);
6095 #endif /* !USE_MOTIF */
6097 /* Install an action hook that lets us detect when the user
6098 finishes interacting with a scroll bar. */
6099 if (horizontal_action_hook_id == 0)
6100 horizontal_action_hook_id
6101 = XtAppAddActionHook (Xt_app_con, xt_horizontal_action_hook, 0);
6103 /* Remember X window and widget in the scroll bar vector. */
6104 SET_SCROLL_BAR_X_WIDGET (bar, widget);
6105 xwindow = XtWindow (widget);
6106 bar->x_window = xwindow;
6107 bar->whole = 1;
6108 bar->horizontal = true;
6110 unblock_input ();
6112 #endif /* not USE_GTK */
6115 /* Set the thumb size and position of scroll bar BAR. We are currently
6116 displaying PORTION out of a whole WHOLE, and our position POSITION. */
6118 #ifdef USE_GTK
6119 static void
6120 x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, int whole)
6122 xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
6125 static void
6126 x_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position, int whole)
6128 xg_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
6131 #else /* not USE_GTK */
6132 static void
6133 x_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position,
6134 int whole)
6136 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6137 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
6138 float top, shown;
6140 block_input ();
6142 #ifdef USE_MOTIF
6144 if (scroll_bar_adjust_thumb_portion_p)
6146 /* We use an estimate of 30 chars per line rather than the real
6147 `portion' value. This has the disadvantage that the thumb size
6148 is not very representative, but it makes our life a lot easier.
6149 Otherwise, we have to constantly adjust the thumb size, which
6150 we can't always do quickly enough: while dragging, the size of
6151 the thumb might prevent the user from dragging the thumb all the
6152 way to the end. but Motif and some versions of Xaw3d don't allow
6153 updating the thumb size while dragging. Also, even if we can update
6154 its size, the update will often happen too late.
6155 If you don't believe it, check out revision 1.650 of xterm.c to see
6156 what hoops we were going through and the still poor behavior we got. */
6157 portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
6158 /* When the thumb is at the bottom, position == whole.
6159 So we need to increase `whole' to make space for the thumb. */
6160 whole += portion;
6163 if (whole <= 0)
6164 top = 0, shown = 1;
6165 else
6167 top = (float) position / whole;
6168 shown = (float) portion / whole;
6171 if (bar->dragging == -1)
6173 int size, value;
6175 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
6176 is the scroll bar's maximum and MIN is the scroll bar's minimum
6177 value. */
6178 size = clip_to_bounds (1, shown * XM_SB_MAX, XM_SB_MAX);
6180 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
6181 value = top * XM_SB_MAX;
6182 value = min (value, XM_SB_MAX - size);
6184 XmScrollBarSetValues (widget, value, size, 0, 0, False);
6186 #else /* !USE_MOTIF i.e. use Xaw */
6188 if (whole == 0)
6189 top = 0, shown = 1;
6190 else
6192 top = (float) position / whole;
6193 shown = (float) portion / whole;
6197 float old_top, old_shown;
6198 Dimension height;
6199 XtVaGetValues (widget,
6200 XtNtopOfThumb, &old_top,
6201 XtNshown, &old_shown,
6202 XtNheight, &height,
6203 NULL);
6205 /* Massage the top+shown values. */
6206 if (bar->dragging == -1 || bar->last_seen_part == scroll_bar_down_arrow)
6207 top = max (0, min (1, top));
6208 else
6209 top = old_top;
6210 #if ! defined (HAVE_XAW3D)
6211 /* With Xaw, 'top' values too closer to 1.0 may
6212 cause the thumb to disappear. Fix that. */
6213 top = min (top, 0.99f);
6214 #endif
6215 /* Keep two pixels available for moving the thumb down. */
6216 shown = max (0, min (1 - top - (2.0f / height), shown));
6217 #if ! defined (HAVE_XAW3D)
6218 /* Likewise with too small 'shown'. */
6219 shown = max (shown, 0.01f);
6220 #endif
6222 /* If the call to XawScrollbarSetThumb below doesn't seem to
6223 work, check that 'NARROWPROTO' is defined in src/config.h.
6224 If this is not so, most likely you need to fix configure. */
6225 if (top != old_top || shown != old_shown)
6227 if (bar->dragging == -1)
6228 XawScrollbarSetThumb (widget, top, shown);
6229 else
6231 /* Try to make the scrolling a tad smoother. */
6232 if (!xaw3d_pick_top)
6233 shown = min (shown, old_shown);
6235 XawScrollbarSetThumb (widget, top, shown);
6239 #endif /* !USE_MOTIF */
6241 unblock_input ();
6244 static void
6245 x_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, int portion, int position,
6246 int whole)
6248 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6249 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
6250 float top, shown;
6252 block_input ();
6254 #ifdef USE_MOTIF
6255 bar->whole = whole;
6256 shown = (float) portion / whole;
6257 top = (float) position / (whole - portion);
6259 int size = clip_to_bounds (1, shown * XM_SB_MAX, XM_SB_MAX);
6260 int value = clip_to_bounds (0, top * (XM_SB_MAX - size), XM_SB_MAX - size);
6262 XmScrollBarSetValues (widget, value, size, 0, 0, False);
6264 #else /* !USE_MOTIF i.e. use Xaw */
6265 bar->whole = whole;
6266 if (whole == 0)
6267 top = 0, shown = 1;
6268 else
6270 top = (float) position / whole;
6271 shown = (float) portion / whole;
6275 float old_top, old_shown;
6276 Dimension height;
6277 XtVaGetValues (widget,
6278 XtNtopOfThumb, &old_top,
6279 XtNshown, &old_shown,
6280 XtNheight, &height,
6281 NULL);
6283 #if false
6284 /* Massage the top+shown values. */
6285 if (bar->dragging == -1 || bar->last_seen_part == scroll_bar_down_arrow)
6286 top = max (0, min (1, top));
6287 else
6288 top = old_top;
6289 #if ! defined (HAVE_XAW3D)
6290 /* With Xaw, 'top' values too closer to 1.0 may
6291 cause the thumb to disappear. Fix that. */
6292 top = min (top, 0.99f);
6293 #endif
6294 /* Keep two pixels available for moving the thumb down. */
6295 shown = max (0, min (1 - top - (2.0f / height), shown));
6296 #if ! defined (HAVE_XAW3D)
6297 /* Likewise with too small 'shown'. */
6298 shown = max (shown, 0.01f);
6299 #endif
6300 #endif
6302 /* If the call to XawScrollbarSetThumb below doesn't seem to
6303 work, check that 'NARROWPROTO' is defined in src/config.h.
6304 If this is not so, most likely you need to fix configure. */
6305 XawScrollbarSetThumb (widget, top, shown);
6306 #if false
6307 if (top != old_top || shown != old_shown)
6309 if (bar->dragging == -1)
6310 XawScrollbarSetThumb (widget, top, shown);
6311 else
6313 /* Try to make the scrolling a tad smoother. */
6314 if (!xaw3d_pick_top)
6315 shown = min (shown, old_shown);
6317 XawScrollbarSetThumb (widget, top, shown);
6320 #endif
6322 #endif /* !USE_MOTIF */
6324 unblock_input ();
6326 #endif /* not USE_GTK */
6328 #endif /* USE_TOOLKIT_SCROLL_BARS */
6332 /************************************************************************
6333 Scroll bars, general
6334 ************************************************************************/
6336 /* Create a scroll bar and return the scroll bar vector for it. W is
6337 the Emacs window on which to create the scroll bar. TOP, LEFT,
6338 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
6339 scroll bar. */
6341 static struct scroll_bar *
6342 x_scroll_bar_create (struct window *w, int top, int left,
6343 int width, int height, bool horizontal)
6345 struct frame *f = XFRAME (w->frame);
6346 struct scroll_bar *bar
6347 = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, x_window, PVEC_OTHER);
6348 Lisp_Object barobj;
6350 block_input ();
6352 #ifdef USE_TOOLKIT_SCROLL_BARS
6353 if (horizontal)
6354 x_create_horizontal_toolkit_scroll_bar (f, bar);
6355 else
6356 x_create_toolkit_scroll_bar (f, bar);
6357 #else /* not USE_TOOLKIT_SCROLL_BARS */
6359 XSetWindowAttributes a;
6360 unsigned long mask;
6361 Window window;
6363 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
6364 if (a.background_pixel == -1)
6365 a.background_pixel = FRAME_BACKGROUND_PIXEL (f);
6367 a.event_mask = (ButtonPressMask | ButtonReleaseMask
6368 | ButtonMotionMask | PointerMotionHintMask
6369 | ExposureMask);
6370 a.cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
6372 mask = (CWBackPixel | CWEventMask | CWCursor);
6374 /* Clear the area of W that will serve as a scroll bar. This is
6375 for the case that a window has been split horizontally. In
6376 this case, no clear_frame is generated to reduce flickering. */
6377 if (width > 0 && window_box_height (w) > 0)
6378 x_clear_area (f, left, top, width, window_box_height (w));
6380 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6381 /* Position and size of scroll bar. */
6382 left, top, width, height,
6383 /* Border width, depth, class, and visual. */
6385 CopyFromParent,
6386 CopyFromParent,
6387 CopyFromParent,
6388 /* Attributes. */
6389 mask, &a);
6390 bar->x_window = window;
6392 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6394 XSETWINDOW (bar->window, w);
6395 bar->top = top;
6396 bar->left = left;
6397 bar->width = width;
6398 bar->height = height;
6399 bar->start = 0;
6400 bar->end = 0;
6401 bar->dragging = -1;
6402 bar->horizontal = horizontal;
6403 #if defined (USE_TOOLKIT_SCROLL_BARS) && defined (USE_LUCID)
6404 bar->last_seen_part = scroll_bar_nowhere;
6405 #endif
6407 /* Add bar to its frame's list of scroll bars. */
6408 bar->next = FRAME_SCROLL_BARS (f);
6409 bar->prev = Qnil;
6410 XSETVECTOR (barobj, bar);
6411 fset_scroll_bars (f, barobj);
6412 if (!NILP (bar->next))
6413 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
6415 /* Map the window/widget. */
6416 #ifdef USE_TOOLKIT_SCROLL_BARS
6418 #ifdef USE_GTK
6419 if (horizontal)
6420 xg_update_horizontal_scrollbar_pos (f, bar->x_window, top,
6421 left, width, max (height, 1));
6422 else
6423 xg_update_scrollbar_pos (f, bar->x_window, top,
6424 left, width, max (height, 1));
6425 #else /* not USE_GTK */
6426 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
6427 XtConfigureWidget (scroll_bar, left, top, width, max (height, 1), 0);
6428 XtMapWidget (scroll_bar);
6429 #endif /* not USE_GTK */
6431 #else /* not USE_TOOLKIT_SCROLL_BARS */
6432 XMapRaised (FRAME_X_DISPLAY (f), bar->x_window);
6433 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6435 unblock_input ();
6436 return bar;
6440 #ifndef USE_TOOLKIT_SCROLL_BARS
6442 /* Draw BAR's handle in the proper position.
6444 If the handle is already drawn from START to END, don't bother
6445 redrawing it, unless REBUILD; in that case, always
6446 redraw it. (REBUILD is handy for drawing the handle after expose
6447 events.)
6449 Normally, we want to constrain the start and end of the handle to
6450 fit inside its rectangle, but if the user is dragging the scroll
6451 bar handle, we want to let them drag it down all the way, so that
6452 the bar's top is as far down as it goes; otherwise, there's no way
6453 to move to the very end of the buffer. */
6455 static void
6456 x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
6457 bool rebuild)
6459 bool dragging = bar->dragging != -1;
6460 Window w = bar->x_window;
6461 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6462 GC gc = f->output_data.x->normal_gc;
6464 /* If the display is already accurate, do nothing. */
6465 if (! rebuild
6466 && start == bar->start
6467 && end == bar->end)
6468 return;
6470 block_input ();
6473 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, bar->width);
6474 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, bar->height);
6475 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
6477 /* Make sure the values are reasonable, and try to preserve
6478 the distance between start and end. */
6480 int length = end - start;
6482 if (start < 0)
6483 start = 0;
6484 else if (start > top_range)
6485 start = top_range;
6486 end = start + length;
6488 if (end < start)
6489 end = start;
6490 else if (end > top_range && ! dragging)
6491 end = top_range;
6494 /* Store the adjusted setting in the scroll bar. */
6495 bar->start = start;
6496 bar->end = end;
6498 /* Clip the end position, just for display. */
6499 if (end > top_range)
6500 end = top_range;
6502 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
6503 below top positions, to make sure the handle is always at least
6504 that many pixels tall. */
6505 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
6507 /* Draw the empty space above the handle. Note that we can't clear
6508 zero-height areas; that means "clear to end of window." */
6509 if ((inside_width > 0) && (start > 0))
6510 x_clear_area1 (FRAME_X_DISPLAY (f), w,
6511 VERTICAL_SCROLL_BAR_LEFT_BORDER,
6512 VERTICAL_SCROLL_BAR_TOP_BORDER,
6513 inside_width, start, False);
6515 /* Change to proper foreground color if one is specified. */
6516 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
6517 XSetForeground (FRAME_X_DISPLAY (f), gc,
6518 f->output_data.x->scroll_bar_foreground_pixel);
6520 /* Draw the handle itself. */
6521 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
6522 /* x, y, width, height */
6523 VERTICAL_SCROLL_BAR_LEFT_BORDER,
6524 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
6525 inside_width, end - start);
6527 /* Restore the foreground color of the GC if we changed it above. */
6528 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
6529 XSetForeground (FRAME_X_DISPLAY (f), gc,
6530 FRAME_FOREGROUND_PIXEL (f));
6532 /* Draw the empty space below the handle. Note that we can't
6533 clear zero-height areas; that means "clear to end of window." */
6534 if ((inside_width > 0) && (end < inside_height))
6535 x_clear_area1 (FRAME_X_DISPLAY (f), w,
6536 VERTICAL_SCROLL_BAR_LEFT_BORDER,
6537 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
6538 inside_width, inside_height - end, False);
6541 unblock_input ();
6544 #endif /* !USE_TOOLKIT_SCROLL_BARS */
6546 /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
6547 nil. */
6549 static void
6550 x_scroll_bar_remove (struct scroll_bar *bar)
6552 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6553 block_input ();
6555 #ifdef USE_TOOLKIT_SCROLL_BARS
6556 #ifdef USE_GTK
6557 xg_remove_scroll_bar (f, bar->x_window);
6558 #else /* not USE_GTK */
6559 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
6560 #endif /* not USE_GTK */
6561 #else
6562 XDestroyWindow (FRAME_X_DISPLAY (f), bar->x_window);
6563 #endif
6565 /* Dissociate this scroll bar from its window. */
6566 if (bar->horizontal)
6567 wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
6568 else
6569 wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
6571 unblock_input ();
6575 /* Set the handle of the vertical scroll bar for WINDOW to indicate
6576 that we are displaying PORTION characters out of a total of WHOLE
6577 characters, starting at POSITION. If WINDOW has no scroll bar,
6578 create one. */
6580 static void
6581 XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int position)
6583 struct frame *f = XFRAME (w->frame);
6584 Lisp_Object barobj;
6585 struct scroll_bar *bar;
6586 int top, height, left, width;
6587 int window_y, window_height;
6589 /* Get window dimensions. */
6590 window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
6591 top = window_y;
6592 height = window_height;
6593 left = WINDOW_SCROLL_BAR_AREA_X (w);
6594 width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
6596 /* Does the scroll bar exist yet? */
6597 if (NILP (w->vertical_scroll_bar))
6599 if (width > 0 && height > 0)
6601 block_input ();
6602 x_clear_area (f, left, top, width, height);
6603 unblock_input ();
6606 bar = x_scroll_bar_create (w, top, left, width, max (height, 1), false);
6608 else
6610 /* It may just need to be moved and resized. */
6611 unsigned int mask = 0;
6613 bar = XSCROLL_BAR (w->vertical_scroll_bar);
6615 block_input ();
6617 if (left != bar->left)
6618 mask |= CWX;
6619 if (top != bar->top)
6620 mask |= CWY;
6621 if (width != bar->width)
6622 mask |= CWWidth;
6623 if (height != bar->height)
6624 mask |= CWHeight;
6626 #ifdef USE_TOOLKIT_SCROLL_BARS
6628 /* Move/size the scroll bar widget. */
6629 if (mask)
6631 /* Since toolkit scroll bars are smaller than the space reserved
6632 for them on the frame, we have to clear "under" them. */
6633 if (width > 0 && height > 0)
6634 x_clear_area (f, left, top, width, height);
6635 #ifdef USE_GTK
6636 xg_update_scrollbar_pos (f, bar->x_window, top,
6637 left, width, max (height, 1));
6638 #else /* not USE_GTK */
6639 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
6640 left, top, width, max (height, 1), 0);
6641 #endif /* not USE_GTK */
6643 #else /* not USE_TOOLKIT_SCROLL_BARS */
6645 /* Move/size the scroll bar window. */
6646 if (mask)
6648 XWindowChanges wc;
6650 wc.x = left;
6651 wc.y = top;
6652 wc.width = width;
6653 wc.height = height;
6654 XConfigureWindow (FRAME_X_DISPLAY (f), bar->x_window,
6655 mask, &wc);
6658 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6660 /* Remember new settings. */
6661 bar->left = left;
6662 bar->top = top;
6663 bar->width = width;
6664 bar->height = height;
6666 unblock_input ();
6669 #ifdef USE_TOOLKIT_SCROLL_BARS
6670 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
6671 #else /* not USE_TOOLKIT_SCROLL_BARS */
6672 /* Set the scroll bar's current state, unless we're currently being
6673 dragged. */
6674 if (bar->dragging == -1)
6676 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
6678 if (whole == 0)
6679 x_scroll_bar_set_handle (bar, 0, top_range, false);
6680 else
6682 int start = ((double) position * top_range) / whole;
6683 int end = ((double) (position + portion) * top_range) / whole;
6684 x_scroll_bar_set_handle (bar, start, end, false);
6687 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6689 XSETVECTOR (barobj, bar);
6690 wset_vertical_scroll_bar (w, barobj);
6694 static void
6695 XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int position)
6697 struct frame *f = XFRAME (w->frame);
6698 Lisp_Object barobj;
6699 struct scroll_bar *bar;
6700 int top, height, left, width;
6701 int window_x, window_width;
6702 int pixel_width = WINDOW_PIXEL_WIDTH (w);
6704 /* Get window dimensions. */
6705 window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
6706 left = window_x;
6707 width = window_width;
6708 top = WINDOW_SCROLL_BAR_AREA_Y (w);
6709 height = WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
6711 /* Does the scroll bar exist yet? */
6712 if (NILP (w->horizontal_scroll_bar))
6714 if (width > 0 && height > 0)
6716 block_input ();
6718 /* Clear also part between window_width and
6719 WINDOW_PIXEL_WIDTH. */
6720 x_clear_area (f, left, top, pixel_width, height);
6721 unblock_input ();
6724 bar = x_scroll_bar_create (w, top, left, width, height, true);
6726 else
6728 /* It may just need to be moved and resized. */
6729 unsigned int mask = 0;
6731 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
6733 block_input ();
6735 if (left != bar->left)
6736 mask |= CWX;
6737 if (top != bar->top)
6738 mask |= CWY;
6739 if (width != bar->width)
6740 mask |= CWWidth;
6741 if (height != bar->height)
6742 mask |= CWHeight;
6744 #ifdef USE_TOOLKIT_SCROLL_BARS
6745 /* Move/size the scroll bar widget. */
6746 if (mask)
6748 /* Since toolkit scroll bars are smaller than the space reserved
6749 for them on the frame, we have to clear "under" them. */
6750 if (width > 0 && height > 0)
6751 x_clear_area (f,
6752 WINDOW_LEFT_EDGE_X (w), top,
6753 pixel_width - WINDOW_RIGHT_DIVIDER_WIDTH (w), height);
6754 #ifdef USE_GTK
6755 xg_update_horizontal_scrollbar_pos (f, bar->x_window, top, left,
6756 width, height);
6757 #else /* not USE_GTK */
6758 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
6759 left, top, width, height, 0);
6760 #endif /* not USE_GTK */
6762 #else /* not USE_TOOLKIT_SCROLL_BARS */
6764 /* Clear areas not covered by the scroll bar because it's not as
6765 wide as the area reserved for it. This makes sure a
6766 previous mode line display is cleared after C-x 2 C-x 1, for
6767 example. */
6769 int area_height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
6770 int rest = area_height - height;
6771 if (rest > 0 && width > 0)
6772 x_clear_area (f, left, top, width, rest);
6775 /* Move/size the scroll bar window. */
6776 if (mask)
6778 XWindowChanges wc;
6780 wc.x = left;
6781 wc.y = top;
6782 wc.width = width;
6783 wc.height = height;
6784 XConfigureWindow (FRAME_X_DISPLAY (f), bar->x_window,
6785 mask, &wc);
6788 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6790 /* Remember new settings. */
6791 bar->left = left;
6792 bar->top = top;
6793 bar->width = width;
6794 bar->height = height;
6796 unblock_input ();
6799 #ifdef USE_TOOLKIT_SCROLL_BARS
6800 x_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
6801 #else /* not USE_TOOLKIT_SCROLL_BARS */
6802 /* Set the scroll bar's current state, unless we're currently being
6803 dragged. */
6804 if (bar->dragging == -1)
6806 int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, width);
6808 if (whole == 0)
6809 x_scroll_bar_set_handle (bar, 0, left_range, false);
6810 else
6812 int start = ((double) position * left_range) / whole;
6813 int end = ((double) (position + portion) * left_range) / whole;
6814 x_scroll_bar_set_handle (bar, start, end, false);
6817 #endif /* not USE_TOOLKIT_SCROLL_BARS */
6819 XSETVECTOR (barobj, bar);
6820 wset_horizontal_scroll_bar (w, barobj);
6824 /* The following three hooks are used when we're doing a thorough
6825 redisplay of the frame. We don't explicitly know which scroll bars
6826 are going to be deleted, because keeping track of when windows go
6827 away is a real pain - "Can you say set-window-configuration, boys
6828 and girls?" Instead, we just assert at the beginning of redisplay
6829 that *all* scroll bars are to be removed, and then save a scroll bar
6830 from the fiery pit when we actually redisplay its window. */
6832 /* Arrange for all scroll bars on FRAME to be removed at the next call
6833 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
6834 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
6836 static void
6837 XTcondemn_scroll_bars (struct frame *frame)
6839 if (!NILP (FRAME_SCROLL_BARS (frame)))
6841 if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
6843 /* Prepend scrollbars to already condemned ones. */
6844 Lisp_Object last = FRAME_SCROLL_BARS (frame);
6846 while (!NILP (XSCROLL_BAR (last)->next))
6847 last = XSCROLL_BAR (last)->next;
6849 XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
6850 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last;
6853 fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame));
6854 fset_scroll_bars (frame, Qnil);
6859 /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
6860 Note that WINDOW isn't necessarily condemned at all. */
6862 static void
6863 XTredeem_scroll_bar (struct window *w)
6865 struct scroll_bar *bar;
6866 Lisp_Object barobj;
6867 struct frame *f;
6869 /* We can't redeem this window's scroll bar if it doesn't have one. */
6870 if (NILP (w->vertical_scroll_bar) && NILP (w->horizontal_scroll_bar))
6871 emacs_abort ();
6873 if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
6875 bar = XSCROLL_BAR (w->vertical_scroll_bar);
6876 /* Unlink it from the condemned list. */
6877 f = XFRAME (WINDOW_FRAME (w));
6878 if (NILP (bar->prev))
6880 /* If the prev pointer is nil, it must be the first in one of
6881 the lists. */
6882 if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar))
6883 /* It's not condemned. Everything's fine. */
6884 goto horizontal;
6885 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
6886 w->vertical_scroll_bar))
6887 fset_condemned_scroll_bars (f, bar->next);
6888 else
6889 /* If its prev pointer is nil, it must be at the front of
6890 one or the other! */
6891 emacs_abort ();
6893 else
6894 XSCROLL_BAR (bar->prev)->next = bar->next;
6896 if (! NILP (bar->next))
6897 XSCROLL_BAR (bar->next)->prev = bar->prev;
6899 bar->next = FRAME_SCROLL_BARS (f);
6900 bar->prev = Qnil;
6901 XSETVECTOR (barobj, bar);
6902 fset_scroll_bars (f, barobj);
6903 if (! NILP (bar->next))
6904 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
6907 horizontal:
6908 if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w))
6910 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
6911 /* Unlink it from the condemned list. */
6912 f = XFRAME (WINDOW_FRAME (w));
6913 if (NILP (bar->prev))
6915 /* If the prev pointer is nil, it must be the first in one of
6916 the lists. */
6917 if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar))
6918 /* It's not condemned. Everything's fine. */
6919 return;
6920 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
6921 w->horizontal_scroll_bar))
6922 fset_condemned_scroll_bars (f, bar->next);
6923 else
6924 /* If its prev pointer is nil, it must be at the front of
6925 one or the other! */
6926 emacs_abort ();
6928 else
6929 XSCROLL_BAR (bar->prev)->next = bar->next;
6931 if (! NILP (bar->next))
6932 XSCROLL_BAR (bar->next)->prev = bar->prev;
6934 bar->next = FRAME_SCROLL_BARS (f);
6935 bar->prev = Qnil;
6936 XSETVECTOR (barobj, bar);
6937 fset_scroll_bars (f, barobj);
6938 if (! NILP (bar->next))
6939 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
6943 /* Remove all scroll bars on FRAME that haven't been saved since the
6944 last call to `*condemn_scroll_bars_hook'. */
6946 static void
6947 XTjudge_scroll_bars (struct frame *f)
6949 Lisp_Object bar, next;
6951 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
6953 /* Clear out the condemned list now so we won't try to process any
6954 more events on the hapless scroll bars. */
6955 fset_condemned_scroll_bars (f, Qnil);
6957 for (; ! NILP (bar); bar = next)
6959 struct scroll_bar *b = XSCROLL_BAR (bar);
6961 x_scroll_bar_remove (b);
6963 next = b->next;
6964 b->next = b->prev = Qnil;
6967 /* Now there should be no references to the condemned scroll bars,
6968 and they should get garbage-collected. */
6972 #ifndef USE_TOOLKIT_SCROLL_BARS
6973 /* Handle an Expose or GraphicsExpose event on a scroll bar. This
6974 is a no-op when using toolkit scroll bars.
6976 This may be called from a signal handler, so we have to ignore GC
6977 mark bits. */
6979 static void
6980 x_scroll_bar_expose (struct scroll_bar *bar, const XEvent *event)
6982 Window w = bar->x_window;
6983 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
6984 GC gc = f->output_data.x->normal_gc;
6986 block_input ();
6988 x_scroll_bar_set_handle (bar, bar->start, bar->end, true);
6990 /* Switch to scroll bar foreground color. */
6991 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
6992 XSetForeground (FRAME_X_DISPLAY (f), gc,
6993 f->output_data.x->scroll_bar_foreground_pixel);
6995 /* Draw a one-pixel border just inside the edges of the scroll bar. */
6996 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
6997 /* x, y, width, height */
6998 0, 0, bar->width - 1, bar->height - 1);
7000 /* Restore the foreground color of the GC if we changed it above. */
7001 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
7002 XSetForeground (FRAME_X_DISPLAY (f), gc,
7003 FRAME_FOREGROUND_PIXEL (f));
7005 unblock_input ();
7008 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7010 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
7011 is set to something other than NO_EVENT, it is enqueued.
7013 This may be called from a signal handler, so we have to ignore GC
7014 mark bits. */
7017 static void
7018 x_scroll_bar_handle_click (struct scroll_bar *bar,
7019 const XEvent *event,
7020 struct input_event *emacs_event)
7022 if (! WINDOWP (bar->window))
7023 emacs_abort ();
7025 emacs_event->kind = (bar->horizontal
7026 ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT
7027 : SCROLL_BAR_CLICK_EVENT);
7028 emacs_event->code = event->xbutton.button - Button1;
7029 emacs_event->modifiers
7030 = (x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO
7031 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
7032 event->xbutton.state)
7033 | (event->type == ButtonRelease
7034 ? up_modifier
7035 : down_modifier));
7036 emacs_event->frame_or_window = bar->window;
7037 emacs_event->arg = Qnil;
7038 emacs_event->timestamp = event->xbutton.time;
7039 if (bar->horizontal)
7041 int left_range
7042 = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
7043 int x = event->xbutton.x - HORIZONTAL_SCROLL_BAR_LEFT_BORDER;
7045 if (x < 0) x = 0;
7046 if (x > left_range) x = left_range;
7048 if (x < bar->start)
7049 emacs_event->part = scroll_bar_before_handle;
7050 else if (x < bar->end + HORIZONTAL_SCROLL_BAR_MIN_HANDLE)
7051 emacs_event->part = scroll_bar_horizontal_handle;
7052 else
7053 emacs_event->part = scroll_bar_after_handle;
7055 #ifndef USE_TOOLKIT_SCROLL_BARS
7056 /* If the user has released the handle, set it to its final position. */
7057 if (event->type == ButtonRelease && bar->dragging != -1)
7059 int new_start = - bar->dragging;
7060 int new_end = new_start + bar->end - bar->start;
7062 x_scroll_bar_set_handle (bar, new_start, new_end, false);
7063 bar->dragging = -1;
7065 #endif
7067 XSETINT (emacs_event->x, left_range);
7068 XSETINT (emacs_event->y, x);
7070 else
7072 int top_range
7073 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
7074 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
7076 if (y < 0) y = 0;
7077 if (y > top_range) y = top_range;
7079 if (y < bar->start)
7080 emacs_event->part = scroll_bar_above_handle;
7081 else if (y < bar->end + VERTICAL_SCROLL_BAR_MIN_HANDLE)
7082 emacs_event->part = scroll_bar_handle;
7083 else
7084 emacs_event->part = scroll_bar_below_handle;
7086 #ifndef USE_TOOLKIT_SCROLL_BARS
7087 /* If the user has released the handle, set it to its final position. */
7088 if (event->type == ButtonRelease && bar->dragging != -1)
7090 int new_start = y - bar->dragging;
7091 int new_end = new_start + bar->end - bar->start;
7093 x_scroll_bar_set_handle (bar, new_start, new_end, false);
7094 bar->dragging = -1;
7096 #endif
7098 XSETINT (emacs_event->x, y);
7099 XSETINT (emacs_event->y, top_range);
7103 #ifndef USE_TOOLKIT_SCROLL_BARS
7105 /* Handle some mouse motion while someone is dragging the scroll bar.
7107 This may be called from a signal handler, so we have to ignore GC
7108 mark bits. */
7110 static void
7111 x_scroll_bar_note_movement (struct scroll_bar *bar,
7112 const XMotionEvent *event)
7114 struct frame *f = XFRAME (XWINDOW (bar->window)->frame);
7115 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
7117 dpyinfo->last_mouse_movement_time = event->time;
7118 dpyinfo->last_mouse_scroll_bar = bar;
7119 f->mouse_moved = true;
7121 /* If we're dragging the bar, display it. */
7122 if (bar->dragging != -1)
7124 /* Where should the handle be now? */
7125 int new_start = event->y - bar->dragging;
7127 if (new_start != bar->start)
7129 int new_end = new_start + bar->end - bar->start;
7131 x_scroll_bar_set_handle (bar, new_start, new_end, false);
7136 #endif /* !USE_TOOLKIT_SCROLL_BARS */
7138 /* Return information to the user about the current position of the mouse
7139 on the scroll bar. */
7141 static void
7142 x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
7143 enum scroll_bar_part *part, Lisp_Object *x,
7144 Lisp_Object *y, Time *timestamp)
7146 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
7147 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
7148 Window w = bar->x_window;
7149 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7150 int win_x, win_y;
7151 Window dummy_window;
7152 int dummy_coord;
7153 unsigned int dummy_mask;
7155 block_input ();
7157 /* Get the mouse's position relative to the scroll bar window, and
7158 report that. */
7159 if (XQueryPointer (FRAME_X_DISPLAY (f), w,
7161 /* Root, child, root x and root y. */
7162 &dummy_window, &dummy_window,
7163 &dummy_coord, &dummy_coord,
7165 /* Position relative to scroll bar. */
7166 &win_x, &win_y,
7168 /* Mouse buttons and modifier keys. */
7169 &dummy_mask))
7171 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
7173 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
7175 if (bar->dragging != -1)
7176 win_y -= bar->dragging;
7178 if (win_y < 0)
7179 win_y = 0;
7180 if (win_y > top_range)
7181 win_y = top_range;
7183 *fp = f;
7184 *bar_window = bar->window;
7186 if (bar->dragging != -1)
7187 *part = scroll_bar_handle;
7188 else if (win_y < bar->start)
7189 *part = scroll_bar_above_handle;
7190 else if (win_y < bar->end + VERTICAL_SCROLL_BAR_MIN_HANDLE)
7191 *part = scroll_bar_handle;
7192 else
7193 *part = scroll_bar_below_handle;
7195 XSETINT (*x, win_y);
7196 XSETINT (*y, top_range);
7198 f->mouse_moved = false;
7199 dpyinfo->last_mouse_scroll_bar = NULL;
7200 *timestamp = dpyinfo->last_mouse_movement_time;
7203 unblock_input ();
7207 /* Return information to the user about the current position of the mouse
7208 on the scroll bar. */
7210 static void
7211 x_horizontal_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
7212 enum scroll_bar_part *part, Lisp_Object *x,
7213 Lisp_Object *y, Time *timestamp)
7215 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
7216 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
7217 Window w = bar->x_window;
7218 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7219 int win_x, win_y;
7220 Window dummy_window;
7221 int dummy_coord;
7222 unsigned int dummy_mask;
7224 block_input ();
7226 /* Get the mouse's position relative to the scroll bar window, and
7227 report that. */
7228 if (XQueryPointer (FRAME_X_DISPLAY (f), w,
7230 /* Root, child, root x and root y. */
7231 &dummy_window, &dummy_window,
7232 &dummy_coord, &dummy_coord,
7234 /* Position relative to scroll bar. */
7235 &win_x, &win_y,
7237 /* Mouse buttons and modifier keys. */
7238 &dummy_mask))
7240 int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
7242 win_x -= HORIZONTAL_SCROLL_BAR_LEFT_BORDER;
7244 if (bar->dragging != -1)
7245 win_x -= bar->dragging;
7247 if (win_x < 0)
7248 win_x = 0;
7249 if (win_x > left_range)
7250 win_x = left_range;
7252 *fp = f;
7253 *bar_window = bar->window;
7255 if (bar->dragging != -1)
7256 *part = scroll_bar_horizontal_handle;
7257 else if (win_x < bar->start)
7258 *part = scroll_bar_before_handle;
7259 else if (win_x < bar->end + HORIZONTAL_SCROLL_BAR_MIN_HANDLE)
7260 *part = scroll_bar_handle;
7261 else
7262 *part = scroll_bar_after_handle;
7264 XSETINT (*y, win_x);
7265 XSETINT (*x, left_range);
7267 f->mouse_moved = false;
7268 dpyinfo->last_mouse_scroll_bar = NULL;
7269 *timestamp = dpyinfo->last_mouse_movement_time;
7272 unblock_input ();
7276 /* The screen has been cleared so we may have changed foreground or
7277 background colors, and the scroll bars may need to be redrawn.
7278 Clear out the scroll bars, and ask for expose events, so we can
7279 redraw them. */
7281 static void
7282 x_scroll_bar_clear (struct frame *f)
7284 #ifndef USE_TOOLKIT_SCROLL_BARS
7285 Lisp_Object bar;
7287 /* We can have scroll bars even if this is 0,
7288 if we just turned off scroll bar mode.
7289 But in that case we should not clear them. */
7290 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
7291 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
7292 bar = XSCROLL_BAR (bar)->next)
7293 XClearArea (FRAME_X_DISPLAY (f),
7294 XSCROLL_BAR (bar)->x_window,
7295 0, 0, 0, 0, True);
7296 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7299 #ifdef ENABLE_CHECKING
7301 /* Record the last 100 characters stored
7302 to help debug the loss-of-chars-during-GC problem. */
7304 static int temp_index;
7305 static short temp_buffer[100];
7307 #define STORE_KEYSYM_FOR_DEBUG(keysym) \
7308 if (temp_index == ARRAYELTS (temp_buffer)) \
7309 temp_index = 0; \
7310 temp_buffer[temp_index++] = (keysym)
7312 #else /* not ENABLE_CHECKING */
7314 #define STORE_KEYSYM_FOR_DEBUG(keysym) ((void)0)
7316 #endif /* ENABLE_CHECKING */
7318 /* Set this to nonzero to fake an "X I/O error"
7319 on a particular display. */
7321 static struct x_display_info *XTread_socket_fake_io_error;
7323 /* When we find no input here, we occasionally do a no-op command
7324 to verify that the X server is still running and we can still talk with it.
7325 We try all the open displays, one by one.
7326 This variable is used for cycling thru the displays. */
7328 static struct x_display_info *next_noop_dpyinfo;
7330 enum
7332 X_EVENT_NORMAL,
7333 X_EVENT_GOTO_OUT,
7334 X_EVENT_DROP
7337 /* Filter events for the current X input method.
7338 DPYINFO is the display this event is for.
7339 EVENT is the X event to filter.
7341 Returns non-zero if the event was filtered, caller shall not process
7342 this event further.
7343 Returns zero if event is wasn't filtered. */
7345 #ifdef HAVE_X_I18N
7346 static int
7347 x_filter_event (struct x_display_info *dpyinfo, XEvent *event)
7349 /* XFilterEvent returns non-zero if the input method has
7350 consumed the event. We pass the frame's X window to
7351 XFilterEvent because that's the one for which the IC
7352 was created. */
7354 struct frame *f1 = x_any_window_to_frame (dpyinfo,
7355 event->xclient.window);
7357 return XFilterEvent (event, f1 ? FRAME_X_WINDOW (f1) : None);
7359 #endif
7361 #ifdef USE_GTK
7362 static int current_count;
7363 static int current_finish;
7364 static struct input_event *current_hold_quit;
7366 /* This is the filter function invoked by the GTK event loop.
7367 It is invoked before the XEvent is translated to a GdkEvent,
7368 so we have a chance to act on the event before GTK. */
7369 static GdkFilterReturn
7370 event_handler_gdk (GdkXEvent *gxev, GdkEvent *ev, gpointer data)
7372 XEvent *xev = (XEvent *) gxev;
7374 block_input ();
7375 if (current_count >= 0)
7377 struct x_display_info *dpyinfo;
7379 dpyinfo = x_display_info_for_display (xev->xany.display);
7381 #ifdef HAVE_X_I18N
7382 /* Filter events for the current X input method.
7383 GTK calls XFilterEvent but not for key press and release,
7384 so we do it here. */
7385 if ((xev->type == KeyPress || xev->type == KeyRelease)
7386 && dpyinfo
7387 && x_filter_event (dpyinfo, xev))
7389 unblock_input ();
7390 return GDK_FILTER_REMOVE;
7392 #endif
7394 if (! dpyinfo)
7395 current_finish = X_EVENT_NORMAL;
7396 else
7397 current_count
7398 += handle_one_xevent (dpyinfo, xev, &current_finish,
7399 current_hold_quit);
7401 else
7402 current_finish = x_dispatch_event (xev, xev->xany.display);
7404 unblock_input ();
7406 if (current_finish == X_EVENT_GOTO_OUT || current_finish == X_EVENT_DROP)
7407 return GDK_FILTER_REMOVE;
7409 return GDK_FILTER_CONTINUE;
7411 #endif /* USE_GTK */
7414 static void xembed_send_message (struct frame *f, Time,
7415 enum xembed_message,
7416 long detail, long data1, long data2);
7418 static void
7419 x_net_wm_state (struct frame *f, Window window)
7421 int value = FULLSCREEN_NONE;
7422 Lisp_Object lval = Qnil;
7423 bool sticky = false;
7425 get_current_wm_state (f, window, &value, &sticky);
7427 switch (value)
7429 case FULLSCREEN_WIDTH:
7430 lval = Qfullwidth;
7431 break;
7432 case FULLSCREEN_HEIGHT:
7433 lval = Qfullheight;
7434 break;
7435 case FULLSCREEN_BOTH:
7436 lval = Qfullboth;
7437 break;
7438 case FULLSCREEN_MAXIMIZED:
7439 lval = Qmaximized;
7440 break;
7443 frame_size_history_add
7444 (f, Qx_net_wm_state, 0, 0,
7445 list2 (get_frame_param (f, Qfullscreen), lval));
7447 store_frame_param (f, Qfullscreen, lval);
7448 /** store_frame_param (f, Qsticky, sticky ? Qt : Qnil); **/
7451 /* Handles the XEvent EVENT on display DPYINFO.
7453 *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
7454 *FINISH is zero if caller should continue reading events.
7455 *FINISH is X_EVENT_DROP if event should not be passed to the toolkit.
7456 *EVENT is unchanged unless we're processing KeyPress event.
7458 We return the number of characters stored into the buffer. */
7460 static int
7461 handle_one_xevent (struct x_display_info *dpyinfo,
7462 const XEvent *event,
7463 int *finish, struct input_event *hold_quit)
7465 union buffered_input_event inev;
7466 int count = 0;
7467 int do_help = 0;
7468 ptrdiff_t nbytes = 0;
7469 struct frame *any, *f = NULL;
7470 struct coding_system coding;
7471 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
7472 /* This holds the state XLookupString needs to implement dead keys
7473 and other tricks known as "compose processing". _X Window System_
7474 says that a portable program can't use this, but Stephen Gildea assures
7475 me that letting the compiler initialize it to zeros will work okay. */
7476 static XComposeStatus compose_status;
7477 XEvent configureEvent;
7478 XEvent next_event;
7480 USE_SAFE_ALLOCA;
7482 *finish = X_EVENT_NORMAL;
7484 EVENT_INIT (inev.ie);
7485 inev.ie.kind = NO_EVENT;
7486 inev.ie.arg = Qnil;
7488 any = x_any_window_to_frame (dpyinfo, event->xany.window);
7490 if (any && any->wait_event_type == event->type)
7491 any->wait_event_type = 0; /* Indicates we got it. */
7493 switch (event->type)
7495 case ClientMessage:
7497 if (event->xclient.message_type == dpyinfo->Xatom_wm_protocols
7498 && event->xclient.format == 32)
7500 if (event->xclient.data.l[0] == dpyinfo->Xatom_wm_take_focus)
7502 /* Use the value returned by x_any_window_to_frame
7503 because this could be the shell widget window
7504 if the frame has no title bar. */
7505 f = any;
7506 #ifdef HAVE_X_I18N
7507 /* Not quite sure this is needed -pd */
7508 if (f && FRAME_XIC (f))
7509 XSetICFocus (FRAME_XIC (f));
7510 #endif
7511 #if false
7512 /* Emacs sets WM hints whose `input' field is `true'. This
7513 instructs the WM to set the input focus automatically for
7514 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
7515 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
7516 it has set the focus. So, XSetInputFocus below is not
7517 needed.
7519 The call to XSetInputFocus below has also caused trouble. In
7520 cases where the XSetInputFocus done by the WM and the one
7521 below are temporally close (on a fast machine), the call
7522 below can generate additional FocusIn events which confuse
7523 Emacs. */
7525 /* Since we set WM_TAKE_FOCUS, we must call
7526 XSetInputFocus explicitly. But not if f is null,
7527 since that might be an event for a deleted frame. */
7528 if (f)
7530 Display *d = event->xclient.display;
7531 /* Catch and ignore errors, in case window has been
7532 iconified by a window manager such as GWM. */
7533 x_catch_errors (d);
7534 XSetInputFocus (d, event->xclient.window,
7535 /* The ICCCM says this is
7536 the only valid choice. */
7537 RevertToParent,
7538 event->xclient.data.l[1]);
7539 x_uncatch_errors ();
7541 /* Not certain about handling scroll bars here */
7542 #endif
7543 goto done;
7546 if (event->xclient.data.l[0] == dpyinfo->Xatom_wm_save_yourself)
7548 /* Save state modify the WM_COMMAND property to
7549 something which can reinstate us. This notifies
7550 the session manager, who's looking for such a
7551 PropertyNotify. Can restart processing when
7552 a keyboard or mouse event arrives. */
7553 /* If we have a session manager, don't set this.
7554 KDE will then start two Emacsen, one for the
7555 session manager and one for this. */
7556 #ifdef HAVE_X_SM
7557 if (! x_session_have_connection ())
7558 #endif
7560 f = x_top_window_to_frame (dpyinfo,
7561 event->xclient.window);
7562 /* This is just so we only give real data once
7563 for a single Emacs process. */
7564 if (f == SELECTED_FRAME ())
7565 XSetCommand (FRAME_X_DISPLAY (f),
7566 event->xclient.window,
7567 initial_argv, initial_argc);
7568 else if (f)
7569 XSetCommand (FRAME_X_DISPLAY (f),
7570 event->xclient.window,
7571 0, 0);
7573 goto done;
7576 if (event->xclient.data.l[0] == dpyinfo->Xatom_wm_delete_window)
7578 f = any;
7579 if (!f)
7580 goto OTHER; /* May be a dialog that is to be removed */
7582 inev.ie.kind = DELETE_WINDOW_EVENT;
7583 XSETFRAME (inev.ie.frame_or_window, f);
7584 goto done;
7587 goto done;
7590 if (event->xclient.message_type == dpyinfo->Xatom_wm_configure_denied)
7591 goto done;
7593 if (event->xclient.message_type == dpyinfo->Xatom_wm_window_moved)
7595 int new_x, new_y;
7596 f = x_window_to_frame (dpyinfo, event->xclient.window);
7598 new_x = event->xclient.data.s[0];
7599 new_y = event->xclient.data.s[1];
7601 if (f)
7603 f->left_pos = new_x;
7604 f->top_pos = new_y;
7606 goto done;
7609 #ifdef X_TOOLKIT_EDITRES
7610 if (event->xclient.message_type == dpyinfo->Xatom_editres)
7612 f = any;
7613 if (f)
7614 _XEditResCheckMessages (f->output_data.x->widget,
7615 NULL, (XEvent *) event, NULL);
7616 goto done;
7618 #endif /* X_TOOLKIT_EDITRES */
7620 if (event->xclient.message_type == dpyinfo->Xatom_DONE
7621 || event->xclient.message_type == dpyinfo->Xatom_PAGE)
7623 /* Ghostview job completed. Kill it. We could
7624 reply with "Next" if we received "Page", but we
7625 currently never do because we are interested in
7626 images, only, which should have 1 page. */
7627 Pixmap pixmap = (Pixmap) event->xclient.data.l[1];
7628 f = x_window_to_frame (dpyinfo, event->xclient.window);
7629 if (!f)
7630 goto OTHER;
7631 x_kill_gs_process (pixmap, f);
7632 expose_frame (f, 0, 0, 0, 0);
7633 goto done;
7636 #ifdef USE_TOOLKIT_SCROLL_BARS
7637 /* Scroll bar callbacks send a ClientMessage from which
7638 we construct an input_event. */
7639 if (event->xclient.message_type == dpyinfo->Xatom_Scrollbar)
7641 x_scroll_bar_to_input_event (event, &inev.ie);
7642 *finish = X_EVENT_GOTO_OUT;
7643 goto done;
7645 else if (event->xclient.message_type == dpyinfo->Xatom_Horizontal_Scrollbar)
7647 x_horizontal_scroll_bar_to_input_event (event, &inev.ie);
7648 *finish = X_EVENT_GOTO_OUT;
7649 goto done;
7651 #endif /* USE_TOOLKIT_SCROLL_BARS */
7653 /* XEmbed messages from the embedder (if any). */
7654 if (event->xclient.message_type == dpyinfo->Xatom_XEMBED)
7656 enum xembed_message msg = event->xclient.data.l[1];
7657 if (msg == XEMBED_FOCUS_IN || msg == XEMBED_FOCUS_OUT)
7658 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
7660 *finish = X_EVENT_GOTO_OUT;
7661 goto done;
7664 xft_settings_event (dpyinfo, event);
7666 f = any;
7667 if (!f)
7668 goto OTHER;
7669 if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie))
7670 *finish = X_EVENT_DROP;
7672 break;
7674 case SelectionNotify:
7675 x_display_set_last_user_time (dpyinfo, event->xselection.time);
7676 #ifdef USE_X_TOOLKIT
7677 if (! x_window_to_frame (dpyinfo, event->xselection.requestor))
7678 goto OTHER;
7679 #endif /* not USE_X_TOOLKIT */
7680 x_handle_selection_notify (&event->xselection);
7681 break;
7683 case SelectionClear: /* Someone has grabbed ownership. */
7684 x_display_set_last_user_time (dpyinfo, event->xselectionclear.time);
7685 #ifdef USE_X_TOOLKIT
7686 if (! x_window_to_frame (dpyinfo, event->xselectionclear.window))
7687 goto OTHER;
7688 #endif /* USE_X_TOOLKIT */
7690 const XSelectionClearEvent *eventp = &event->xselectionclear;
7692 inev.sie.kind = SELECTION_CLEAR_EVENT;
7693 SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
7694 SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
7695 SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
7697 break;
7699 case SelectionRequest: /* Someone wants our selection. */
7700 x_display_set_last_user_time (dpyinfo, event->xselectionrequest.time);
7701 #ifdef USE_X_TOOLKIT
7702 if (!x_window_to_frame (dpyinfo, event->xselectionrequest.owner))
7703 goto OTHER;
7704 #endif /* USE_X_TOOLKIT */
7706 const XSelectionRequestEvent *eventp = &event->xselectionrequest;
7708 inev.sie.kind = SELECTION_REQUEST_EVENT;
7709 SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
7710 SELECTION_EVENT_REQUESTOR (&inev.sie) = eventp->requestor;
7711 SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
7712 SELECTION_EVENT_TARGET (&inev.sie) = eventp->target;
7713 SELECTION_EVENT_PROPERTY (&inev.sie) = eventp->property;
7714 SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
7716 break;
7718 case PropertyNotify:
7719 x_display_set_last_user_time (dpyinfo, event->xproperty.time);
7720 f = x_top_window_to_frame (dpyinfo, event->xproperty.window);
7721 if (f && event->xproperty.atom == dpyinfo->Xatom_net_wm_state)
7723 bool not_hidden = x_handle_net_wm_state (f, &event->xproperty);
7724 if (not_hidden && FRAME_ICONIFIED_P (f))
7726 /* Gnome shell does not iconify us when C-z is pressed.
7727 It hides the frame. So if our state says we aren't
7728 hidden anymore, treat it as deiconified. */
7729 SET_FRAME_VISIBLE (f, 1);
7730 SET_FRAME_ICONIFIED (f, false);
7731 f->output_data.x->has_been_visible = true;
7732 inev.ie.kind = DEICONIFY_EVENT;
7733 XSETFRAME (inev.ie.frame_or_window, f);
7735 else if (! not_hidden && ! FRAME_ICONIFIED_P (f))
7737 SET_FRAME_VISIBLE (f, 0);
7738 SET_FRAME_ICONIFIED (f, true);
7739 inev.ie.kind = ICONIFY_EVENT;
7740 XSETFRAME (inev.ie.frame_or_window, f);
7744 x_handle_property_notify (&event->xproperty);
7745 xft_settings_event (dpyinfo, event);
7746 goto OTHER;
7748 case ReparentNotify:
7749 f = x_top_window_to_frame (dpyinfo, event->xreparent.window);
7750 if (f)
7752 f->output_data.x->parent_desc = event->xreparent.parent;
7753 x_real_positions (f, &f->left_pos, &f->top_pos);
7755 /* Perhaps reparented due to a WM restart. Reset this. */
7756 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
7757 FRAME_DISPLAY_INFO (f)->net_supported_window = 0;
7759 x_set_frame_alpha (f);
7761 goto OTHER;
7763 case Expose:
7764 f = x_window_to_frame (dpyinfo, event->xexpose.window);
7765 if (f)
7767 if (!FRAME_VISIBLE_P (f))
7769 SET_FRAME_VISIBLE (f, 1);
7770 SET_FRAME_ICONIFIED (f, false);
7771 f->output_data.x->has_been_visible = true;
7772 SET_FRAME_GARBAGED (f);
7774 else
7776 #ifdef USE_GTK
7777 /* This seems to be needed for GTK 2.6 and later, see
7778 http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398. */
7779 x_clear_area (f,
7780 event->xexpose.x, event->xexpose.y,
7781 event->xexpose.width, event->xexpose.height);
7782 #endif
7783 expose_frame (f, event->xexpose.x, event->xexpose.y,
7784 event->xexpose.width, event->xexpose.height);
7787 else
7789 #ifndef USE_TOOLKIT_SCROLL_BARS
7790 struct scroll_bar *bar;
7791 #endif
7792 #if defined USE_LUCID
7793 /* Submenus of the Lucid menu bar aren't widgets
7794 themselves, so there's no way to dispatch events
7795 to them. Recognize this case separately. */
7797 Widget widget = x_window_to_menu_bar (event->xexpose.window);
7798 if (widget)
7799 xlwmenu_redisplay (widget);
7801 #endif /* USE_LUCID */
7803 #ifdef USE_TOOLKIT_SCROLL_BARS
7804 /* Dispatch event to the widget. */
7805 goto OTHER;
7806 #else /* not USE_TOOLKIT_SCROLL_BARS */
7807 bar = x_window_to_scroll_bar (event->xexpose.display,
7808 event->xexpose.window, 2);
7810 if (bar)
7811 x_scroll_bar_expose (bar, event);
7812 #ifdef USE_X_TOOLKIT
7813 else
7814 goto OTHER;
7815 #endif /* USE_X_TOOLKIT */
7816 #endif /* not USE_TOOLKIT_SCROLL_BARS */
7818 break;
7820 case GraphicsExpose: /* This occurs when an XCopyArea's
7821 source area was obscured or not
7822 available. */
7823 f = x_window_to_frame (dpyinfo, event->xgraphicsexpose.drawable);
7824 if (f)
7825 expose_frame (f, event->xgraphicsexpose.x,
7826 event->xgraphicsexpose.y,
7827 event->xgraphicsexpose.width,
7828 event->xgraphicsexpose.height);
7829 #ifdef USE_X_TOOLKIT
7830 else
7831 goto OTHER;
7832 #endif /* USE_X_TOOLKIT */
7833 break;
7835 case NoExpose: /* This occurs when an XCopyArea's
7836 source area was completely
7837 available. */
7838 break;
7840 case UnmapNotify:
7841 /* Redo the mouse-highlight after the tooltip has gone. */
7842 if (event->xunmap.window == tip_window)
7844 tip_window = 0;
7845 x_redo_mouse_highlight (dpyinfo);
7848 f = x_top_window_to_frame (dpyinfo, event->xunmap.window);
7849 if (f) /* F may no longer exist if
7850 the frame was deleted. */
7852 bool visible = FRAME_VISIBLE_P (f);
7853 /* While a frame is unmapped, display generation is
7854 disabled; you don't want to spend time updating a
7855 display that won't ever be seen. */
7856 SET_FRAME_VISIBLE (f, 0);
7857 /* We can't distinguish, from the event, whether the window
7858 has become iconified or invisible. So assume, if it
7859 was previously visible, than now it is iconified.
7860 But x_make_frame_invisible clears both
7861 the visible flag and the iconified flag;
7862 and that way, we know the window is not iconified now. */
7863 if (visible || FRAME_ICONIFIED_P (f))
7865 SET_FRAME_ICONIFIED (f, true);
7866 inev.ie.kind = ICONIFY_EVENT;
7867 XSETFRAME (inev.ie.frame_or_window, f);
7870 goto OTHER;
7872 case MapNotify:
7873 /* We use x_top_window_to_frame because map events can
7874 come for sub-windows and they don't mean that the
7875 frame is visible. */
7876 f = x_top_window_to_frame (dpyinfo, event->xmap.window);
7877 if (f)
7879 bool iconified = FRAME_ICONIFIED_P (f);
7881 /* Check if fullscreen was specified before we where mapped the
7882 first time, i.e. from the command line. */
7883 if (!f->output_data.x->has_been_visible)
7884 x_check_fullscreen (f);
7886 SET_FRAME_VISIBLE (f, 1);
7887 SET_FRAME_ICONIFIED (f, false);
7888 f->output_data.x->has_been_visible = true;
7890 if (iconified)
7892 inev.ie.kind = DEICONIFY_EVENT;
7893 XSETFRAME (inev.ie.frame_or_window, f);
7895 else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list)))
7896 /* Force a redisplay sooner or later to update the
7897 frame titles in case this is the second frame. */
7898 record_asynch_buffer_change ();
7900 goto OTHER;
7902 case KeyPress:
7904 x_display_set_last_user_time (dpyinfo, event->xkey.time);
7905 ignore_next_mouse_click_timeout = 0;
7907 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
7908 /* Dispatch KeyPress events when in menu. */
7909 if (popup_activated ())
7910 goto OTHER;
7911 #endif
7913 f = any;
7915 /* If mouse-highlight is an integer, input clears out
7916 mouse highlighting. */
7917 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
7918 #if ! defined (USE_GTK)
7919 && (f == 0
7920 || !EQ (f->tool_bar_window, hlinfo->mouse_face_window))
7921 #endif
7924 clear_mouse_face (hlinfo);
7925 hlinfo->mouse_face_hidden = true;
7928 #if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
7929 if (f == 0)
7931 /* Scroll bars consume key events, but we want
7932 the keys to go to the scroll bar's frame. */
7933 Widget widget = XtWindowToWidget (dpyinfo->display,
7934 event->xkey.window);
7935 if (widget && XmIsScrollBar (widget))
7937 widget = XtParent (widget);
7938 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
7941 #endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
7943 if (f != 0)
7945 KeySym keysym, orig_keysym;
7946 /* al%imercury@uunet.uu.net says that making this 81
7947 instead of 80 fixed a bug whereby meta chars made
7948 his Emacs hang.
7950 It seems that some version of XmbLookupString has
7951 a bug of not returning XBufferOverflow in
7952 status_return even if the input is too long to
7953 fit in 81 bytes. So, we must prepare sufficient
7954 bytes for copy_buffer. 513 bytes (256 chars for
7955 two-byte character set) seems to be a fairly good
7956 approximation. -- 2000.8.10 handa@etl.go.jp */
7957 unsigned char copy_buffer[513];
7958 unsigned char *copy_bufptr = copy_buffer;
7959 int copy_bufsiz = sizeof (copy_buffer);
7960 int modifiers;
7961 Lisp_Object coding_system = Qlatin_1;
7962 Lisp_Object c;
7963 /* Event will be modified. */
7964 XKeyEvent xkey = event->xkey;
7966 #ifdef USE_GTK
7967 /* Don't pass keys to GTK. A Tab will shift focus to the
7968 tool bar in GTK 2.4. Keys will still go to menus and
7969 dialogs because in that case popup_activated is nonzero
7970 (see above). */
7971 *finish = X_EVENT_DROP;
7972 #endif
7974 xkey.state |= x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f),
7975 extra_keyboard_modifiers);
7976 modifiers = xkey.state;
7978 /* This will have to go some day... */
7980 /* make_lispy_event turns chars into control chars.
7981 Don't do it here because XLookupString is too eager. */
7982 xkey.state &= ~ControlMask;
7983 xkey.state &= ~(dpyinfo->meta_mod_mask
7984 | dpyinfo->super_mod_mask
7985 | dpyinfo->hyper_mod_mask
7986 | dpyinfo->alt_mod_mask);
7988 /* In case Meta is ComposeCharacter,
7989 clear its status. According to Markus Ehrnsperger
7990 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
7991 this enables ComposeCharacter to work whether or
7992 not it is combined with Meta. */
7993 if (modifiers & dpyinfo->meta_mod_mask)
7994 memset (&compose_status, 0, sizeof (compose_status));
7996 #ifdef HAVE_X_I18N
7997 if (FRAME_XIC (f))
7999 Status status_return;
8001 coding_system = Vlocale_coding_system;
8002 nbytes = XmbLookupString (FRAME_XIC (f),
8003 &xkey, (char *) copy_bufptr,
8004 copy_bufsiz, &keysym,
8005 &status_return);
8006 if (status_return == XBufferOverflow)
8008 copy_bufsiz = nbytes + 1;
8009 copy_bufptr = alloca (copy_bufsiz);
8010 nbytes = XmbLookupString (FRAME_XIC (f),
8011 &xkey, (char *) copy_bufptr,
8012 copy_bufsiz, &keysym,
8013 &status_return);
8015 /* Xutf8LookupString is a new but already deprecated interface. -stef */
8016 if (status_return == XLookupNone)
8017 break;
8018 else if (status_return == XLookupChars)
8020 keysym = NoSymbol;
8021 modifiers = 0;
8023 else if (status_return != XLookupKeySym
8024 && status_return != XLookupBoth)
8025 emacs_abort ();
8027 else
8028 nbytes = XLookupString (&xkey, (char *) copy_bufptr,
8029 copy_bufsiz, &keysym,
8030 &compose_status);
8031 #else
8032 nbytes = XLookupString (&xkey, (char *) copy_bufptr,
8033 copy_bufsiz, &keysym,
8034 &compose_status);
8035 #endif
8037 /* If not using XIM/XIC, and a compose sequence is in progress,
8038 we break here. Otherwise, chars_matched is always 0. */
8039 if (compose_status.chars_matched > 0 && nbytes == 0)
8040 break;
8042 memset (&compose_status, 0, sizeof (compose_status));
8043 orig_keysym = keysym;
8045 /* Common for all keysym input events. */
8046 XSETFRAME (inev.ie.frame_or_window, f);
8047 inev.ie.modifiers
8048 = x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), modifiers);
8049 inev.ie.timestamp = xkey.time;
8051 /* First deal with keysyms which have defined
8052 translations to characters. */
8053 if (keysym >= 32 && keysym < 128)
8054 /* Avoid explicitly decoding each ASCII character. */
8056 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
8057 inev.ie.code = keysym;
8058 goto done_keysym;
8061 /* Keysyms directly mapped to Unicode characters. */
8062 if (keysym >= 0x01000000 && keysym <= 0x0110FFFF)
8064 if (keysym < 0x01000080)
8065 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
8066 else
8067 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
8068 inev.ie.code = keysym & 0xFFFFFF;
8069 goto done_keysym;
8072 /* Now non-ASCII. */
8073 if (HASH_TABLE_P (Vx_keysym_table)
8074 && (c = Fgethash (make_number (keysym),
8075 Vx_keysym_table,
8076 Qnil),
8077 NATNUMP (c)))
8079 inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c))
8080 ? ASCII_KEYSTROKE_EVENT
8081 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
8082 inev.ie.code = XFASTINT (c);
8083 goto done_keysym;
8086 /* Random non-modifier sorts of keysyms. */
8087 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
8088 || keysym == XK_Delete
8089 #ifdef XK_ISO_Left_Tab
8090 || (keysym >= XK_ISO_Left_Tab
8091 && keysym <= XK_ISO_Enter)
8092 #endif
8093 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
8094 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
8095 #ifdef HPUX
8096 /* This recognizes the "extended function
8097 keys". It seems there's no cleaner way.
8098 Test IsModifierKey to avoid handling
8099 mode_switch incorrectly. */
8100 || (XK_Select <= keysym && keysym < XK_KP_Space)
8101 #endif
8102 #ifdef XK_dead_circumflex
8103 || orig_keysym == XK_dead_circumflex
8104 #endif
8105 #ifdef XK_dead_grave
8106 || orig_keysym == XK_dead_grave
8107 #endif
8108 #ifdef XK_dead_tilde
8109 || orig_keysym == XK_dead_tilde
8110 #endif
8111 #ifdef XK_dead_diaeresis
8112 || orig_keysym == XK_dead_diaeresis
8113 #endif
8114 #ifdef XK_dead_macron
8115 || orig_keysym == XK_dead_macron
8116 #endif
8117 #ifdef XK_dead_degree
8118 || orig_keysym == XK_dead_degree
8119 #endif
8120 #ifdef XK_dead_acute
8121 || orig_keysym == XK_dead_acute
8122 #endif
8123 #ifdef XK_dead_cedilla
8124 || orig_keysym == XK_dead_cedilla
8125 #endif
8126 #ifdef XK_dead_breve
8127 || orig_keysym == XK_dead_breve
8128 #endif
8129 #ifdef XK_dead_ogonek
8130 || orig_keysym == XK_dead_ogonek
8131 #endif
8132 #ifdef XK_dead_caron
8133 || orig_keysym == XK_dead_caron
8134 #endif
8135 #ifdef XK_dead_doubleacute
8136 || orig_keysym == XK_dead_doubleacute
8137 #endif
8138 #ifdef XK_dead_abovedot
8139 || orig_keysym == XK_dead_abovedot
8140 #endif
8141 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
8142 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
8143 /* Any "vendor-specific" key is ok. */
8144 || (orig_keysym & (1 << 28))
8145 || (keysym != NoSymbol && nbytes == 0))
8146 && ! (IsModifierKey (orig_keysym)
8147 /* The symbols from XK_ISO_Lock
8148 to XK_ISO_Last_Group_Lock
8149 don't have real modifiers but
8150 should be treated similarly to
8151 Mode_switch by Emacs. */
8152 #if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock
8153 || (XK_ISO_Lock <= orig_keysym
8154 && orig_keysym <= XK_ISO_Last_Group_Lock)
8155 #endif
8158 STORE_KEYSYM_FOR_DEBUG (keysym);
8159 /* make_lispy_event will convert this to a symbolic
8160 key. */
8161 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
8162 inev.ie.code = keysym;
8163 goto done_keysym;
8166 { /* Raw bytes, not keysym. */
8167 ptrdiff_t i;
8168 int nchars, len;
8170 for (i = 0, nchars = 0; i < nbytes; i++)
8172 if (ASCII_CHAR_P (copy_bufptr[i]))
8173 nchars++;
8174 STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
8177 if (nchars < nbytes)
8179 /* Decode the input data. */
8181 /* The input should be decoded with `coding_system'
8182 which depends on which X*LookupString function
8183 we used just above and the locale. */
8184 setup_coding_system (coding_system, &coding);
8185 coding.src_multibyte = false;
8186 coding.dst_multibyte = true;
8187 /* The input is converted to events, thus we can't
8188 handle composition. Anyway, there's no XIM that
8189 gives us composition information. */
8190 coding.common_flags &= ~CODING_ANNOTATION_MASK;
8192 SAFE_NALLOCA (coding.destination, MAX_MULTIBYTE_LENGTH,
8193 nbytes);
8194 coding.dst_bytes = MAX_MULTIBYTE_LENGTH * nbytes;
8195 coding.mode |= CODING_MODE_LAST_BLOCK;
8196 decode_coding_c_string (&coding, copy_bufptr, nbytes, Qnil);
8197 nbytes = coding.produced;
8198 nchars = coding.produced_char;
8199 copy_bufptr = coding.destination;
8202 /* Convert the input data to a sequence of
8203 character events. */
8204 for (i = 0; i < nbytes; i += len)
8206 int ch;
8207 if (nchars == nbytes)
8208 ch = copy_bufptr[i], len = 1;
8209 else
8210 ch = STRING_CHAR_AND_LENGTH (copy_bufptr + i, len);
8211 inev.ie.kind = (SINGLE_BYTE_CHAR_P (ch)
8212 ? ASCII_KEYSTROKE_EVENT
8213 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
8214 inev.ie.code = ch;
8215 kbd_buffer_store_buffered_event (&inev, hold_quit);
8218 count += nchars;
8220 inev.ie.kind = NO_EVENT; /* Already stored above. */
8222 if (keysym == NoSymbol)
8223 break;
8225 /* FIXME: check side effects and remove this. */
8226 ((XEvent *) event)->xkey = xkey;
8228 done_keysym:
8229 #ifdef HAVE_X_I18N
8230 /* Don't dispatch this event since XtDispatchEvent calls
8231 XFilterEvent, and two calls in a row may freeze the
8232 client. */
8233 break;
8234 #else
8235 goto OTHER;
8236 #endif
8238 case KeyRelease:
8239 x_display_set_last_user_time (dpyinfo, event->xkey.time);
8240 #ifdef HAVE_X_I18N
8241 /* Don't dispatch this event since XtDispatchEvent calls
8242 XFilterEvent, and two calls in a row may freeze the
8243 client. */
8244 break;
8245 #else
8246 goto OTHER;
8247 #endif
8249 case EnterNotify:
8250 x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
8251 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8253 f = any;
8255 if (f && x_mouse_click_focus_ignore_position)
8256 ignore_next_mouse_click_timeout = event->xmotion.time + 200;
8258 /* EnterNotify counts as mouse movement,
8259 so update things that depend on mouse position. */
8260 if (f && !f->output_data.x->hourglass_p)
8261 note_mouse_movement (f, &event->xmotion);
8262 #ifdef USE_GTK
8263 /* We may get an EnterNotify on the buttons in the toolbar. In that
8264 case we moved out of any highlighted area and need to note this. */
8265 if (!f && dpyinfo->last_mouse_glyph_frame)
8266 note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &event->xmotion);
8267 #endif
8268 goto OTHER;
8270 case FocusIn:
8271 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8272 goto OTHER;
8274 case LeaveNotify:
8275 x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
8276 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8278 f = x_top_window_to_frame (dpyinfo, event->xcrossing.window);
8279 if (f)
8281 if (f == hlinfo->mouse_face_mouse_frame)
8283 /* If we move outside the frame, then we're
8284 certainly no longer on any text in the frame. */
8285 clear_mouse_face (hlinfo);
8286 hlinfo->mouse_face_mouse_frame = 0;
8289 /* Generate a nil HELP_EVENT to cancel a help-echo.
8290 Do it only if there's something to cancel.
8291 Otherwise, the startup message is cleared when
8292 the mouse leaves the frame. */
8293 if (any_help_event_p)
8294 do_help = -1;
8296 #ifdef USE_GTK
8297 /* See comment in EnterNotify above */
8298 else if (dpyinfo->last_mouse_glyph_frame)
8299 note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &event->xmotion);
8300 #endif
8301 goto OTHER;
8303 case FocusOut:
8304 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
8305 goto OTHER;
8307 case MotionNotify:
8309 x_display_set_last_user_time (dpyinfo, event->xmotion.time);
8310 previous_help_echo_string = help_echo_string;
8311 help_echo_string = Qnil;
8313 f = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
8314 : x_window_to_frame (dpyinfo, event->xmotion.window));
8316 if (hlinfo->mouse_face_hidden)
8318 hlinfo->mouse_face_hidden = false;
8319 clear_mouse_face (hlinfo);
8322 #ifdef USE_GTK
8323 if (f && xg_event_is_for_scrollbar (f, event))
8324 f = 0;
8325 #endif
8326 if (f)
8329 /* Generate SELECT_WINDOW_EVENTs when needed.
8330 Don't let popup menus influence things (bug#1261). */
8331 if (!NILP (Vmouse_autoselect_window) && !popup_activated ())
8333 static Lisp_Object last_mouse_window;
8334 Lisp_Object window = window_from_coordinates
8335 (f, event->xmotion.x, event->xmotion.y, 0, false);
8337 /* Window will be selected only when it is not selected now and
8338 last mouse movement event was not in it. Minibuffer window
8339 will be selected only when it is active. */
8340 if (WINDOWP (window)
8341 && !EQ (window, last_mouse_window)
8342 && !EQ (window, selected_window)
8343 /* For click-to-focus window managers
8344 create event iff we don't leave the
8345 selected frame. */
8346 && (focus_follows_mouse
8347 || (EQ (XWINDOW (window)->frame,
8348 XWINDOW (selected_window)->frame))))
8350 inev.ie.kind = SELECT_WINDOW_EVENT;
8351 inev.ie.frame_or_window = window;
8353 /* Remember the last window where we saw the mouse. */
8354 last_mouse_window = window;
8356 if (!note_mouse_movement (f, &event->xmotion))
8357 help_echo_string = previous_help_echo_string;
8359 else
8361 #ifndef USE_TOOLKIT_SCROLL_BARS
8362 struct scroll_bar *bar
8363 = x_window_to_scroll_bar (event->xmotion.display,
8364 event->xmotion.window, 2);
8366 if (bar)
8367 x_scroll_bar_note_movement (bar, &event->xmotion);
8368 #endif /* USE_TOOLKIT_SCROLL_BARS */
8370 /* If we move outside the frame, then we're
8371 certainly no longer on any text in the frame. */
8372 clear_mouse_face (hlinfo);
8375 /* If the contents of the global variable help_echo_string
8376 has changed, generate a HELP_EVENT. */
8377 if (!NILP (help_echo_string)
8378 || !NILP (previous_help_echo_string))
8379 do_help = 1;
8380 goto OTHER;
8383 case ConfigureNotify:
8384 /* An opaque move can generate a stream of events as the window
8385 is dragged around. If the connection round trip time isn't
8386 really short, they may come faster than we can respond to
8387 them, given the multiple queries we can do to check window
8388 manager state, translate coordinates, etc.
8390 So if this ConfigureNotify is immediately followed by another
8391 for the same window, use the info from the latest update, and
8392 consider the events all handled. */
8393 /* Opaque resize may be trickier; ConfigureNotify events are
8394 mixed with Expose events for multiple windows. */
8395 configureEvent = *event;
8396 while (XPending (dpyinfo->display))
8398 XNextEvent (dpyinfo->display, &next_event);
8399 if (next_event.type != ConfigureNotify
8400 || next_event.xconfigure.window != event->xconfigure.window
8401 /* Skipping events with different sizes can lead to a
8402 mispositioned mode line at initial window creation.
8403 Only drop window motion events for now. */
8404 || next_event.xconfigure.width != event->xconfigure.width
8405 || next_event.xconfigure.height != event->xconfigure.height)
8407 XPutBackEvent (dpyinfo->display, &next_event);
8408 break;
8410 else
8411 configureEvent = next_event;
8413 f = x_top_window_to_frame (dpyinfo, configureEvent.xconfigure.window);
8414 #ifdef USE_CAIRO
8415 if (f) x_cr_destroy_surface (f);
8416 #endif
8417 #ifdef USE_GTK
8418 if (!f
8419 && (f = any)
8420 && configureEvent.xconfigure.window == FRAME_X_WINDOW (f))
8422 xg_frame_resized (f, configureEvent.xconfigure.width,
8423 configureEvent.xconfigure.height);
8424 #ifdef USE_CAIRO
8425 x_cr_destroy_surface (f);
8426 #endif
8427 f = 0;
8429 #endif
8430 if (f)
8432 x_net_wm_state (f, configureEvent.xconfigure.window);
8434 #ifdef USE_X_TOOLKIT
8435 /* Tip frames are pure X window, set size for them. */
8436 if (! NILP (tip_frame) && XFRAME (tip_frame) == f)
8438 if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height
8439 || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width)
8440 SET_FRAME_GARBAGED (f);
8441 FRAME_PIXEL_HEIGHT (f) = configureEvent.xconfigure.height;
8442 FRAME_PIXEL_WIDTH (f) = configureEvent.xconfigure.width;
8444 #endif
8446 #ifndef USE_X_TOOLKIT
8447 #ifndef USE_GTK
8448 int width =
8449 FRAME_PIXEL_TO_TEXT_WIDTH (f, configureEvent.xconfigure.width);
8450 int height =
8451 FRAME_PIXEL_TO_TEXT_HEIGHT (f, configureEvent.xconfigure.height);
8453 /* In the toolkit version, change_frame_size
8454 is called by the code that handles resizing
8455 of the EmacsFrame widget. */
8457 /* Even if the number of character rows and columns has
8458 not changed, the font size may have changed, so we need
8459 to check the pixel dimensions as well. */
8460 if (width != FRAME_TEXT_WIDTH (f)
8461 || height != FRAME_TEXT_HEIGHT (f)
8462 || configureEvent.xconfigure.width != FRAME_PIXEL_WIDTH (f)
8463 || configureEvent.xconfigure.height != FRAME_PIXEL_HEIGHT (f))
8465 change_frame_size (f, width, height, false, true, false, true);
8466 x_clear_under_internal_border (f);
8467 SET_FRAME_GARBAGED (f);
8468 cancel_mouse_face (f);
8470 #endif /* not USE_GTK */
8471 #endif
8473 #ifdef USE_GTK
8474 /* GTK creates windows but doesn't map them.
8475 Only get real positions when mapped. */
8476 if (FRAME_GTK_OUTER_WIDGET (f)
8477 && gtk_widget_get_mapped (FRAME_GTK_OUTER_WIDGET (f)))
8478 #endif
8479 x_real_positions (f, &f->left_pos, &f->top_pos);
8481 #ifdef HAVE_X_I18N
8482 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
8483 xic_set_statusarea (f);
8484 #endif
8487 goto OTHER;
8489 case ButtonRelease:
8490 case ButtonPress:
8492 /* If we decide we want to generate an event to be seen
8493 by the rest of Emacs, we put it here. */
8494 bool tool_bar_p = false;
8496 memset (&compose_status, 0, sizeof (compose_status));
8497 dpyinfo->last_mouse_glyph_frame = NULL;
8498 x_display_set_last_user_time (dpyinfo, event->xbutton.time);
8500 f = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
8501 : x_window_to_frame (dpyinfo, event->xbutton.window));
8503 #ifdef USE_GTK
8504 if (f && xg_event_is_for_scrollbar (f, event))
8505 f = 0;
8506 #endif
8507 if (f)
8509 #if ! defined (USE_GTK)
8510 /* Is this in the tool-bar? */
8511 if (WINDOWP (f->tool_bar_window)
8512 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
8514 Lisp_Object window;
8515 int x = event->xbutton.x;
8516 int y = event->xbutton.y;
8518 window = window_from_coordinates (f, x, y, 0, true);
8519 tool_bar_p = EQ (window, f->tool_bar_window);
8521 if (tool_bar_p && event->xbutton.button < 4)
8522 handle_tool_bar_click
8523 (f, x, y, event->xbutton.type == ButtonPress,
8524 x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state));
8526 #endif /* !USE_GTK */
8528 if (!tool_bar_p)
8529 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
8530 if (! popup_activated ())
8531 #endif
8533 if (ignore_next_mouse_click_timeout)
8535 if (event->type == ButtonPress
8536 && event->xbutton.time > ignore_next_mouse_click_timeout)
8538 ignore_next_mouse_click_timeout = 0;
8539 construct_mouse_click (&inev.ie, &event->xbutton, f);
8541 if (event->type == ButtonRelease)
8542 ignore_next_mouse_click_timeout = 0;
8544 else
8545 construct_mouse_click (&inev.ie, &event->xbutton, f);
8547 if (FRAME_X_EMBEDDED_P (f))
8548 xembed_send_message (f, event->xbutton.time,
8549 XEMBED_REQUEST_FOCUS, 0, 0, 0);
8551 else
8553 struct scroll_bar *bar
8554 = x_window_to_scroll_bar (event->xbutton.display,
8555 event->xbutton.window, 2);
8557 #ifdef USE_TOOLKIT_SCROLL_BARS
8558 /* Make the "Ctrl-Mouse-2 splits window" work for toolkit
8559 scroll bars. */
8560 if (bar && event->xbutton.state & ControlMask)
8562 x_scroll_bar_handle_click (bar, event, &inev.ie);
8563 *finish = X_EVENT_DROP;
8565 #else /* not USE_TOOLKIT_SCROLL_BARS */
8566 if (bar)
8567 x_scroll_bar_handle_click (bar, event, &inev.ie);
8568 #endif /* not USE_TOOLKIT_SCROLL_BARS */
8571 if (event->type == ButtonPress)
8573 dpyinfo->grabbed |= (1 << event->xbutton.button);
8574 dpyinfo->last_mouse_frame = f;
8575 #if ! defined (USE_GTK)
8576 if (f && !tool_bar_p)
8577 f->last_tool_bar_item = -1;
8578 #endif /* not USE_GTK */
8580 else
8581 dpyinfo->grabbed &= ~(1 << event->xbutton.button);
8583 /* Ignore any mouse motion that happened before this event;
8584 any subsequent mouse-movement Emacs events should reflect
8585 only motion after the ButtonPress/Release. */
8586 if (f != 0)
8587 f->mouse_moved = false;
8589 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
8590 f = x_menubar_window_to_frame (dpyinfo, event);
8591 /* For a down-event in the menu bar,
8592 don't pass it to Xt right now.
8593 Instead, save it away
8594 and we will pass it to Xt from kbd_buffer_get_event.
8595 That way, we can run some Lisp code first. */
8596 if (! popup_activated ()
8597 #ifdef USE_GTK
8598 /* Gtk+ menus only react to the first three buttons. */
8599 && event->xbutton.button < 3
8600 #endif
8601 && f && event->type == ButtonPress
8602 /* Verify the event is really within the menu bar
8603 and not just sent to it due to grabbing. */
8604 && event->xbutton.x >= 0
8605 && event->xbutton.x < FRAME_PIXEL_WIDTH (f)
8606 && event->xbutton.y >= 0
8607 && event->xbutton.y < FRAME_MENUBAR_HEIGHT (f)
8608 && event->xbutton.same_screen)
8610 if (!f->output_data.x->saved_menu_event)
8611 f->output_data.x->saved_menu_event = xmalloc (sizeof *event);
8612 *f->output_data.x->saved_menu_event = *event;
8613 inev.ie.kind = MENU_BAR_ACTIVATE_EVENT;
8614 XSETFRAME (inev.ie.frame_or_window, f);
8615 *finish = X_EVENT_DROP;
8617 else
8618 goto OTHER;
8619 #endif /* USE_X_TOOLKIT || USE_GTK */
8621 break;
8623 case CirculateNotify:
8624 goto OTHER;
8626 case CirculateRequest:
8627 goto OTHER;
8629 case VisibilityNotify:
8630 goto OTHER;
8632 case MappingNotify:
8633 /* Someone has changed the keyboard mapping - update the
8634 local cache. */
8635 switch (event->xmapping.request)
8637 case MappingModifier:
8638 x_find_modifier_meanings (dpyinfo);
8639 /* This is meant to fall through. */
8640 case MappingKeyboard:
8641 XRefreshKeyboardMapping ((XMappingEvent *) &event->xmapping);
8643 goto OTHER;
8645 case DestroyNotify:
8646 xft_settings_event (dpyinfo, event);
8647 break;
8649 default:
8650 OTHER:
8651 #ifdef USE_X_TOOLKIT
8652 block_input ();
8653 if (*finish != X_EVENT_DROP)
8654 XtDispatchEvent ((XEvent *) event);
8655 unblock_input ();
8656 #endif /* USE_X_TOOLKIT */
8657 break;
8660 done:
8661 if (inev.ie.kind != NO_EVENT)
8663 kbd_buffer_store_buffered_event (&inev, hold_quit);
8664 count++;
8667 if (do_help
8668 && !(hold_quit && hold_quit->kind != NO_EVENT))
8670 Lisp_Object frame;
8672 if (f)
8673 XSETFRAME (frame, f);
8674 else
8675 frame = Qnil;
8677 if (do_help > 0)
8679 any_help_event_p = true;
8680 gen_help_event (help_echo_string, frame, help_echo_window,
8681 help_echo_object, help_echo_pos);
8683 else
8685 help_echo_string = Qnil;
8686 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
8688 count++;
8691 SAFE_FREE ();
8692 return count;
8695 /* Handles the XEvent EVENT on display DISPLAY.
8696 This is used for event loops outside the normal event handling,
8697 i.e. looping while a popup menu or a dialog is posted.
8699 Returns the value handle_one_xevent sets in the finish argument. */
8701 x_dispatch_event (XEvent *event, Display *display)
8703 struct x_display_info *dpyinfo;
8704 int finish = X_EVENT_NORMAL;
8706 dpyinfo = x_display_info_for_display (display);
8708 if (dpyinfo)
8709 handle_one_xevent (dpyinfo, event, &finish, 0);
8711 return finish;
8714 /* Read events coming from the X server.
8715 Return as soon as there are no more events to be read.
8717 Return the number of characters stored into the buffer,
8718 thus pretending to be `read' (except the characters we store
8719 in the keyboard buffer can be multibyte, so are not necessarily
8720 C chars). */
8722 static int
8723 XTread_socket (struct terminal *terminal, struct input_event *hold_quit)
8725 int count = 0;
8726 bool event_found = false;
8727 struct x_display_info *dpyinfo = terminal->display_info.x;
8729 block_input ();
8731 /* For debugging, this gives a way to fake an I/O error. */
8732 if (dpyinfo == XTread_socket_fake_io_error)
8734 XTread_socket_fake_io_error = 0;
8735 x_io_error_quitter (dpyinfo->display);
8738 #ifndef USE_GTK
8739 while (XPending (dpyinfo->display))
8741 int finish;
8742 XEvent event;
8744 XNextEvent (dpyinfo->display, &event);
8746 #ifdef HAVE_X_I18N
8747 /* Filter events for the current X input method. */
8748 if (x_filter_event (dpyinfo, &event))
8749 continue;
8750 #endif
8751 event_found = true;
8753 count += handle_one_xevent (dpyinfo, &event, &finish, hold_quit);
8755 if (finish == X_EVENT_GOTO_OUT)
8756 break;
8759 #else /* USE_GTK */
8761 /* For GTK we must use the GTK event loop. But XEvents gets passed
8762 to our filter function above, and then to the big event switch.
8763 We use a bunch of globals to communicate with our filter function,
8764 that is kind of ugly, but it works.
8766 There is no way to do one display at the time, GTK just does events
8767 from all displays. */
8769 while (gtk_events_pending ())
8771 current_count = count;
8772 current_hold_quit = hold_quit;
8774 gtk_main_iteration ();
8776 count = current_count;
8777 current_count = -1;
8778 current_hold_quit = 0;
8780 if (current_finish == X_EVENT_GOTO_OUT)
8781 break;
8783 #endif /* USE_GTK */
8785 /* On some systems, an X bug causes Emacs to get no more events
8786 when the window is destroyed. Detect that. (1994.) */
8787 if (! event_found)
8789 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
8790 One XNOOP in 100 loops will make Emacs terminate.
8791 B. Bretthauer, 1994 */
8792 x_noop_count++;
8793 if (x_noop_count >= 100)
8795 x_noop_count=0;
8797 if (next_noop_dpyinfo == 0)
8798 next_noop_dpyinfo = x_display_list;
8800 XNoOp (next_noop_dpyinfo->display);
8802 /* Each time we get here, cycle through the displays now open. */
8803 next_noop_dpyinfo = next_noop_dpyinfo->next;
8807 /* If the focus was just given to an auto-raising frame,
8808 raise it now. FIXME: handle more than one such frame. */
8809 if (dpyinfo->x_pending_autoraise_frame)
8811 x_raise_frame (dpyinfo->x_pending_autoraise_frame);
8812 dpyinfo->x_pending_autoraise_frame = NULL;
8815 unblock_input ();
8817 return count;
8823 /***********************************************************************
8824 Text Cursor
8825 ***********************************************************************/
8827 /* Set clipping for output in glyph row ROW. W is the window in which
8828 we operate. GC is the graphics context to set clipping in.
8830 ROW may be a text row or, e.g., a mode line. Text rows must be
8831 clipped to the interior of the window dedicated to text display,
8832 mode lines must be clipped to the whole window. */
8834 static void
8835 x_clip_to_row (struct window *w, struct glyph_row *row,
8836 enum glyph_row_area area, GC gc)
8838 struct frame *f = XFRAME (WINDOW_FRAME (w));
8839 XRectangle clip_rect;
8840 int window_x, window_y, window_width;
8842 window_box (w, area, &window_x, &window_y, &window_width, 0);
8844 clip_rect.x = window_x;
8845 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
8846 clip_rect.y = max (clip_rect.y, window_y);
8847 clip_rect.width = window_width;
8848 clip_rect.height = row->visible_height;
8850 x_set_clip_rectangles (f, gc, &clip_rect, 1);
8854 /* Draw a hollow box cursor on window W in glyph row ROW. */
8856 static void
8857 x_draw_hollow_cursor (struct window *w, struct glyph_row *row)
8859 struct frame *f = XFRAME (WINDOW_FRAME (w));
8860 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
8861 Display *dpy = FRAME_X_DISPLAY (f);
8862 int x, y, wd, h;
8863 XGCValues xgcv;
8864 struct glyph *cursor_glyph;
8865 GC gc;
8867 /* Get the glyph the cursor is on. If we can't tell because
8868 the current matrix is invalid or such, give up. */
8869 cursor_glyph = get_phys_cursor_glyph (w);
8870 if (cursor_glyph == NULL)
8871 return;
8873 /* Compute frame-relative coordinates for phys cursor. */
8874 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
8875 wd = w->phys_cursor_width - 1;
8877 /* The foreground of cursor_gc is typically the same as the normal
8878 background color, which can cause the cursor box to be invisible. */
8879 xgcv.foreground = f->output_data.x->cursor_pixel;
8880 if (dpyinfo->scratch_cursor_gc)
8881 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
8882 else
8883 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
8884 GCForeground, &xgcv);
8885 gc = dpyinfo->scratch_cursor_gc;
8887 /* When on R2L character, show cursor at the right edge of the
8888 glyph, unless the cursor box is as wide as the glyph or wider
8889 (the latter happens when x-stretch-cursor is non-nil). */
8890 if ((cursor_glyph->resolved_level & 1) != 0
8891 && cursor_glyph->pixel_width > wd)
8893 x += cursor_glyph->pixel_width - wd;
8894 if (wd > 0)
8895 wd -= 1;
8897 /* Set clipping, draw the rectangle, and reset clipping again. */
8898 x_clip_to_row (w, row, TEXT_AREA, gc);
8899 x_draw_rectangle (f, gc, x, y, wd, h - 1);
8900 x_reset_clip_rectangles (f, gc);
8904 /* Draw a bar cursor on window W in glyph row ROW.
8906 Implementation note: One would like to draw a bar cursor with an
8907 angle equal to the one given by the font property XA_ITALIC_ANGLE.
8908 Unfortunately, I didn't find a font yet that has this property set.
8909 --gerd. */
8911 static void
8912 x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text_cursor_kinds kind)
8914 struct frame *f = XFRAME (w->frame);
8915 struct glyph *cursor_glyph;
8917 /* If cursor is out of bounds, don't draw garbage. This can happen
8918 in mini-buffer windows when switching between echo area glyphs
8919 and mini-buffer. */
8920 cursor_glyph = get_phys_cursor_glyph (w);
8921 if (cursor_glyph == NULL)
8922 return;
8924 /* Experimental avoidance of cursor on xwidget. */
8925 if (cursor_glyph->type == XWIDGET_GLYPH)
8926 return;
8928 /* If on an image, draw like a normal cursor. That's usually better
8929 visible than drawing a bar, esp. if the image is large so that
8930 the bar might not be in the window. */
8931 if (cursor_glyph->type == IMAGE_GLYPH)
8933 struct glyph_row *r;
8934 r = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
8935 draw_phys_cursor_glyph (w, r, DRAW_CURSOR);
8937 else
8939 Display *dpy = FRAME_X_DISPLAY (f);
8940 Window window = FRAME_X_WINDOW (f);
8941 GC gc = FRAME_DISPLAY_INFO (f)->scratch_cursor_gc;
8942 unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures;
8943 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
8944 XGCValues xgcv;
8946 /* If the glyph's background equals the color we normally draw
8947 the bars cursor in, the bar cursor in its normal color is
8948 invisible. Use the glyph's foreground color instead in this
8949 case, on the assumption that the glyph's colors are chosen so
8950 that the glyph is legible. */
8951 if (face->background == f->output_data.x->cursor_pixel)
8952 xgcv.background = xgcv.foreground = face->foreground;
8953 else
8954 xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel;
8955 xgcv.graphics_exposures = False;
8957 if (gc)
8958 XChangeGC (dpy, gc, mask, &xgcv);
8959 else
8961 gc = XCreateGC (dpy, window, mask, &xgcv);
8962 FRAME_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
8965 x_clip_to_row (w, row, TEXT_AREA, gc);
8967 if (kind == BAR_CURSOR)
8969 int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
8971 if (width < 0)
8972 width = FRAME_CURSOR_WIDTH (f);
8973 width = min (cursor_glyph->pixel_width, width);
8975 w->phys_cursor_width = width;
8977 /* If the character under cursor is R2L, draw the bar cursor
8978 on the right of its glyph, rather than on the left. */
8979 if ((cursor_glyph->resolved_level & 1) != 0)
8980 x += cursor_glyph->pixel_width - width;
8982 x_fill_rectangle (f, gc, x,
8983 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
8984 width, row->height);
8986 else /* HBAR_CURSOR */
8988 int dummy_x, dummy_y, dummy_h;
8989 int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
8991 if (width < 0)
8992 width = row->height;
8994 width = min (row->height, width);
8996 get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x,
8997 &dummy_y, &dummy_h);
8999 if ((cursor_glyph->resolved_level & 1) != 0
9000 && cursor_glyph->pixel_width > w->phys_cursor_width - 1)
9001 x += cursor_glyph->pixel_width - w->phys_cursor_width + 1;
9002 x_fill_rectangle (f, gc, x,
9003 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
9004 row->height - width),
9005 w->phys_cursor_width - 1, width);
9008 x_reset_clip_rectangles (f, gc);
9013 /* RIF: Define cursor CURSOR on frame F. */
9015 static void
9016 x_define_frame_cursor (struct frame *f, Cursor cursor)
9018 if (!f->pointer_invisible
9019 && f->output_data.x->current_cursor != cursor)
9020 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
9021 f->output_data.x->current_cursor = cursor;
9025 /* RIF: Clear area on frame F. */
9027 static void
9028 x_clear_frame_area (struct frame *f, int x, int y, int width, int height)
9030 x_clear_area (f, x, y, width, height);
9031 #ifdef USE_GTK
9032 /* Must queue a redraw, because scroll bars might have been cleared. */
9033 if (FRAME_GTK_WIDGET (f))
9034 gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
9035 #endif
9039 /* RIF: Draw cursor on window W. */
9041 static void
9042 x_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, int x,
9043 int y, enum text_cursor_kinds cursor_type,
9044 int cursor_width, bool on_p, bool active_p)
9046 struct frame *f = XFRAME (WINDOW_FRAME (w));
9048 if (on_p)
9050 w->phys_cursor_type = cursor_type;
9051 w->phys_cursor_on_p = true;
9053 if (glyph_row->exact_window_width_line_p
9054 && (glyph_row->reversed_p
9055 ? (w->phys_cursor.hpos < 0)
9056 : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])))
9058 glyph_row->cursor_in_fringe_p = true;
9059 draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p);
9061 else
9063 switch (cursor_type)
9065 case HOLLOW_BOX_CURSOR:
9066 x_draw_hollow_cursor (w, glyph_row);
9067 break;
9069 case FILLED_BOX_CURSOR:
9070 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
9071 break;
9073 case BAR_CURSOR:
9074 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
9075 break;
9077 case HBAR_CURSOR:
9078 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
9079 break;
9081 case NO_CURSOR:
9082 w->phys_cursor_width = 0;
9083 break;
9085 default:
9086 emacs_abort ();
9090 #ifdef HAVE_X_I18N
9091 if (w == XWINDOW (f->selected_window))
9092 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
9093 xic_set_preeditarea (w, x, y);
9094 #endif
9097 XFlush (FRAME_X_DISPLAY (f));
9101 /* Icons. */
9103 /* Make the x-window of frame F use the gnu icon bitmap. */
9105 bool
9106 x_bitmap_icon (struct frame *f, Lisp_Object file)
9108 ptrdiff_t bitmap_id;
9110 if (FRAME_X_WINDOW (f) == 0)
9111 return true;
9113 /* Free up our existing icon bitmap and mask if any. */
9114 if (f->output_data.x->icon_bitmap > 0)
9115 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
9116 f->output_data.x->icon_bitmap = 0;
9118 if (STRINGP (file))
9120 #ifdef USE_GTK
9121 /* Use gtk_window_set_icon_from_file () if available,
9122 It's not restricted to bitmaps */
9123 if (xg_set_icon (f, file))
9124 return false;
9125 #endif /* USE_GTK */
9126 bitmap_id = x_create_bitmap_from_file (f, file);
9127 x_create_bitmap_mask (f, bitmap_id);
9129 else
9131 /* Create the GNU bitmap and mask if necessary. */
9132 if (FRAME_DISPLAY_INFO (f)->icon_bitmap_id < 0)
9134 ptrdiff_t rc = -1;
9136 #ifdef USE_GTK
9138 if (xg_set_icon (f, xg_default_icon_file)
9139 || xg_set_icon_from_xpm_data (f, gnu_xpm_bits))
9141 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = -2;
9142 return false;
9145 #elif defined (HAVE_XPM) && defined (HAVE_X_WINDOWS)
9147 rc = x_create_bitmap_from_xpm_data (f, gnu_xpm_bits);
9148 if (rc != -1)
9149 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = rc;
9151 #endif
9153 /* If all else fails, use the (black and white) xbm image. */
9154 if (rc == -1)
9156 rc = x_create_bitmap_from_data (f, (char *) gnu_xbm_bits,
9157 gnu_xbm_width, gnu_xbm_height);
9158 if (rc == -1)
9159 return true;
9161 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = rc;
9162 x_create_bitmap_mask (f, FRAME_DISPLAY_INFO (f)->icon_bitmap_id);
9166 /* The first time we create the GNU bitmap and mask,
9167 this increments the ref-count one extra time.
9168 As a result, the GNU bitmap and mask are never freed.
9169 That way, we don't have to worry about allocating it again. */
9170 x_reference_bitmap (f, FRAME_DISPLAY_INFO (f)->icon_bitmap_id);
9172 bitmap_id = FRAME_DISPLAY_INFO (f)->icon_bitmap_id;
9175 x_wm_set_icon_pixmap (f, bitmap_id);
9176 f->output_data.x->icon_bitmap = bitmap_id;
9178 return false;
9182 /* Make the x-window of frame F use a rectangle with text.
9183 Use ICON_NAME as the text. */
9185 bool
9186 x_text_icon (struct frame *f, const char *icon_name)
9188 if (FRAME_X_WINDOW (f) == 0)
9189 return true;
9192 XTextProperty text;
9193 text.value = (unsigned char *) icon_name;
9194 text.encoding = XA_STRING;
9195 text.format = 8;
9196 text.nitems = strlen (icon_name);
9197 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), &text);
9200 if (f->output_data.x->icon_bitmap > 0)
9201 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
9202 f->output_data.x->icon_bitmap = 0;
9203 x_wm_set_icon_pixmap (f, 0);
9205 return false;
9208 #define X_ERROR_MESSAGE_SIZE 200
9210 /* If non-nil, this should be a string.
9211 It means catch X errors and store the error message in this string.
9213 The reason we use a stack is that x_catch_error/x_uncatch_error can
9214 be called from a signal handler.
9217 struct x_error_message_stack {
9218 char string[X_ERROR_MESSAGE_SIZE];
9219 Display *dpy;
9220 x_special_error_handler handler;
9221 void *handler_data;
9222 struct x_error_message_stack *prev;
9224 static struct x_error_message_stack *x_error_message;
9226 /* An X error handler which stores the error message in
9227 *x_error_message. This is called from x_error_handler if
9228 x_catch_errors is in effect. */
9230 static void
9231 x_error_catcher (Display *display, XErrorEvent *event)
9233 XGetErrorText (display, event->error_code,
9234 x_error_message->string,
9235 X_ERROR_MESSAGE_SIZE);
9236 if (x_error_message->handler)
9237 x_error_message->handler (display, event, x_error_message->string,
9238 x_error_message->handler_data);
9241 /* Begin trapping X errors for display DPY. Actually we trap X errors
9242 for all displays, but DPY should be the display you are actually
9243 operating on.
9245 After calling this function, X protocol errors no longer cause
9246 Emacs to exit; instead, they are recorded in the string
9247 stored in *x_error_message.
9249 Calling x_check_errors signals an Emacs error if an X error has
9250 occurred since the last call to x_catch_errors or x_check_errors.
9252 Calling x_uncatch_errors resumes the normal error handling.
9253 Calling x_uncatch_errors_after_check is similar, but skips an XSync
9254 to the server, and should be used only immediately after
9255 x_had_errors_p or x_check_errors. */
9257 void
9258 x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler,
9259 void *handler_data)
9261 struct x_error_message_stack *data = xmalloc (sizeof *data);
9263 /* Make sure any errors from previous requests have been dealt with. */
9264 XSync (dpy, False);
9266 data->dpy = dpy;
9267 data->string[0] = 0;
9268 data->handler = handler;
9269 data->handler_data = handler_data;
9270 data->prev = x_error_message;
9271 x_error_message = data;
9274 void
9275 x_catch_errors (Display *dpy)
9277 x_catch_errors_with_handler (dpy, NULL, NULL);
9280 /* Undo the last x_catch_errors call.
9281 DPY should be the display that was passed to x_catch_errors.
9283 This version should be used only if the immediately preceding
9284 X-protocol-related thing was x_check_errors or x_had_error_p, both
9285 of which issue XSync calls, so we don't need to re-sync here. */
9287 void
9288 x_uncatch_errors_after_check (void)
9290 struct x_error_message_stack *tmp;
9292 block_input ();
9293 tmp = x_error_message;
9294 x_error_message = x_error_message->prev;
9295 xfree (tmp);
9296 unblock_input ();
9299 /* Undo the last x_catch_errors call.
9300 DPY should be the display that was passed to x_catch_errors. */
9302 void
9303 x_uncatch_errors (void)
9305 struct x_error_message_stack *tmp;
9307 block_input ();
9309 /* The display may have been closed before this function is called.
9310 Check if it is still open before calling XSync. */
9311 if (x_display_info_for_display (x_error_message->dpy) != 0)
9312 XSync (x_error_message->dpy, False);
9314 tmp = x_error_message;
9315 x_error_message = x_error_message->prev;
9316 xfree (tmp);
9317 unblock_input ();
9320 /* If any X protocol errors have arrived since the last call to
9321 x_catch_errors or x_check_errors, signal an Emacs error using
9322 sprintf (a buffer, FORMAT, the x error message text) as the text. */
9324 void
9325 x_check_errors (Display *dpy, const char *format)
9327 /* Make sure to catch any errors incurred so far. */
9328 XSync (dpy, False);
9330 if (x_error_message->string[0])
9332 char string[X_ERROR_MESSAGE_SIZE];
9333 memcpy (string, x_error_message->string, X_ERROR_MESSAGE_SIZE);
9334 x_uncatch_errors ();
9335 error (format, string);
9339 /* Nonzero if we had any X protocol errors
9340 since we did x_catch_errors on DPY. */
9342 bool
9343 x_had_errors_p (Display *dpy)
9345 /* Make sure to catch any errors incurred so far. */
9346 XSync (dpy, False);
9348 return x_error_message->string[0] != 0;
9351 /* Forget about any errors we have had, since we did x_catch_errors on DPY. */
9353 void
9354 x_clear_errors (Display *dpy)
9356 x_error_message->string[0] = 0;
9359 #if false
9360 /* See comment in unwind_to_catch why calling this is a bad
9361 * idea. --lorentey */
9362 /* Close off all unclosed x_catch_errors calls. */
9364 void
9365 x_fully_uncatch_errors (void)
9367 while (x_error_message)
9368 x_uncatch_errors ();
9370 #endif
9372 #if false
9373 static unsigned int x_wire_count;
9374 x_trace_wire (void)
9376 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
9378 #endif
9381 /************************************************************************
9382 Handling X errors
9383 ************************************************************************/
9385 /* Error message passed to x_connection_closed. */
9387 static char *error_msg;
9389 /* Handle the loss of connection to display DPY. ERROR_MESSAGE is
9390 the text of an error message that lead to the connection loss. */
9392 static _Noreturn void
9393 x_connection_closed (Display *dpy, const char *error_message, bool ioerror)
9395 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
9396 Lisp_Object frame, tail;
9397 ptrdiff_t idx = SPECPDL_INDEX ();
9399 error_msg = alloca (strlen (error_message) + 1);
9400 strcpy (error_msg, error_message);
9402 /* Inhibit redisplay while frames are being deleted. */
9403 specbind (Qinhibit_redisplay, Qt);
9405 if (dpyinfo)
9407 /* Protect display from being closed when we delete the last
9408 frame on it. */
9409 dpyinfo->reference_count++;
9410 dpyinfo->terminal->reference_count++;
9412 if (ioerror) dpyinfo->display = 0;
9414 /* First delete frames whose mini-buffers are on frames
9415 that are on the dead display. */
9416 FOR_EACH_FRAME (tail, frame)
9418 Lisp_Object minibuf_frame;
9419 minibuf_frame
9420 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
9421 if (FRAME_X_P (XFRAME (frame))
9422 && FRAME_X_P (XFRAME (minibuf_frame))
9423 && ! EQ (frame, minibuf_frame)
9424 && FRAME_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
9425 delete_frame (frame, Qnoelisp);
9428 /* Now delete all remaining frames on the dead display.
9429 We are now sure none of these is used as the mini-buffer
9430 for another frame that we need to delete. */
9431 FOR_EACH_FRAME (tail, frame)
9432 if (FRAME_X_P (XFRAME (frame))
9433 && FRAME_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
9435 /* Set this to t so that delete_frame won't get confused
9436 trying to find a replacement. */
9437 kset_default_minibuffer_frame (FRAME_KBOARD (XFRAME (frame)), Qt);
9438 delete_frame (frame, Qnoelisp);
9441 /* If DPYINFO is null, this means we didn't open the display in the
9442 first place, so don't try to close it. */
9443 if (dpyinfo)
9445 /* We can not call XtCloseDisplay here because it calls XSync.
9446 XSync inside the error handler apparently hangs Emacs. On
9447 current Xt versions, this isn't needed either. */
9448 #ifdef USE_GTK
9449 /* A long-standing GTK bug prevents proper disconnect handling
9450 (https://bugzilla.gnome.org/show_bug.cgi?id=85715). Once,
9451 the resulting Glib error message loop filled a user's disk.
9452 To avoid this, kill Emacs unconditionally on disconnect. */
9453 shut_down_emacs (0, Qnil);
9454 fprintf (stderr, "%s\n\
9455 When compiled with GTK, Emacs cannot recover from X disconnects.\n\
9456 This is a GTK bug: https://bugzilla.gnome.org/show_bug.cgi?id=85715\n\
9457 For details, see etc/PROBLEMS.\n",
9458 error_msg);
9459 emacs_abort ();
9460 #endif /* USE_GTK */
9462 /* Indicate that this display is dead. */
9463 dpyinfo->display = 0;
9465 dpyinfo->reference_count--;
9466 dpyinfo->terminal->reference_count--;
9467 if (dpyinfo->reference_count != 0)
9468 /* We have just closed all frames on this display. */
9469 emacs_abort ();
9472 Lisp_Object tmp;
9473 XSETTERMINAL (tmp, dpyinfo->terminal);
9474 Fdelete_terminal (tmp, Qnoelisp);
9478 if (terminal_list == 0)
9480 fprintf (stderr, "%s\n", error_msg);
9481 Fkill_emacs (make_number (70));
9482 /* NOTREACHED */
9485 totally_unblock_input ();
9487 unbind_to (idx, Qnil);
9488 clear_waiting_for_input ();
9490 /* Here, we absolutely have to use a non-local exit (e.g. signal, throw,
9491 longjmp), because returning from this function would get us back into
9492 Xlib's code which will directly call `exit'. */
9493 error ("%s", error_msg);
9496 /* We specifically use it before defining it, so that gcc doesn't inline it,
9497 otherwise gdb doesn't know how to properly put a breakpoint on it. */
9498 static void x_error_quitter (Display *, XErrorEvent *);
9500 /* This is the first-level handler for X protocol errors.
9501 It calls x_error_quitter or x_error_catcher. */
9503 static int
9504 x_error_handler (Display *display, XErrorEvent *event)
9506 #if defined USE_GTK && defined HAVE_GTK3
9507 if ((event->error_code == BadMatch || event->error_code == BadWindow)
9508 && event->request_code == X_SetInputFocus)
9510 return 0;
9512 #endif
9514 if (x_error_message)
9515 x_error_catcher (display, event);
9516 else
9517 x_error_quitter (display, event);
9518 return 0;
9521 /* This is the usual handler for X protocol errors.
9522 It kills all frames on the display that we got the error for.
9523 If that was the only one, it prints an error message and kills Emacs. */
9525 /* .gdbinit puts a breakpoint here, so make sure it is not inlined. */
9527 /* On older GCC versions, just putting x_error_quitter
9528 after x_error_handler prevents inlining into the former. */
9530 static void NO_INLINE
9531 x_error_quitter (Display *display, XErrorEvent *event)
9533 char buf[256], buf1[356];
9535 /* Ignore BadName errors. They can happen because of fonts
9536 or colors that are not defined. */
9538 if (event->error_code == BadName)
9539 return;
9541 /* Note that there is no real way portable across R3/R4 to get the
9542 original error handler. */
9544 XGetErrorText (display, event->error_code, buf, sizeof (buf));
9545 sprintf (buf1, "X protocol error: %s on protocol request %d",
9546 buf, event->request_code);
9547 x_connection_closed (display, buf1, false);
9551 /* This is the handler for X IO errors, always.
9552 It kills all frames on the display that we lost touch with.
9553 If that was the only one, it prints an error message and kills Emacs. */
9555 static _Noreturn int
9556 x_io_error_quitter (Display *display)
9558 char buf[256];
9560 snprintf (buf, sizeof buf, "Connection lost to X server '%s'",
9561 DisplayString (display));
9562 x_connection_closed (display, buf, true);
9563 assume (false);
9566 /* Changing the font of the frame. */
9568 /* Give frame F the font FONT-OBJECT as its default font. The return
9569 value is FONT-OBJECT. FONTSET is an ID of the fontset for the
9570 frame. If it is negative, generate a new fontset from
9571 FONT-OBJECT. */
9573 Lisp_Object
9574 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
9576 struct font *font = XFONT_OBJECT (font_object);
9577 int unit, font_ascent, font_descent;
9578 #ifndef USE_X_TOOLKIT
9579 int old_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f);
9580 Lisp_Object fullscreen;
9581 #endif
9583 if (fontset < 0)
9584 fontset = fontset_from_font (font_object);
9585 FRAME_FONTSET (f) = fontset;
9586 if (FRAME_FONT (f) == font)
9587 /* This font is already set in frame F. There's nothing more to
9588 do. */
9589 return font_object;
9591 FRAME_FONT (f) = font;
9592 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
9593 FRAME_COLUMN_WIDTH (f) = font->average_width;
9594 get_font_ascent_descent (font, &font_ascent, &font_descent);
9595 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
9597 #ifndef USE_X_TOOLKIT
9598 FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
9599 #endif
9601 /* Compute character columns occupied by scrollbar.
9603 Don't do things differently for non-toolkit scrollbars
9604 (Bug#17163). */
9605 unit = FRAME_COLUMN_WIDTH (f);
9606 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
9607 FRAME_CONFIG_SCROLL_BAR_COLS (f)
9608 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
9609 else
9610 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit;
9612 if (FRAME_X_WINDOW (f) != 0)
9614 /* Don't change the size of a tip frame; there's no point in
9615 doing it because it's done in Fx_show_tip, and it leads to
9616 problems because the tip frame has no widget. */
9617 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
9619 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
9620 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
9621 false, Qfont);
9622 #ifndef USE_X_TOOLKIT
9623 if (FRAME_MENU_BAR_HEIGHT (f) != old_menu_bar_height
9624 && !f->after_make_frame
9625 && (EQ (frame_inhibit_implied_resize, Qt)
9626 || (CONSP (frame_inhibit_implied_resize)
9627 && NILP (Fmemq (Qfont, frame_inhibit_implied_resize))))
9628 && (NILP (fullscreen = get_frame_param (f, Qfullscreen))
9629 || EQ (fullscreen, Qfullwidth)))
9630 /* If the menu bar height changes, try to keep text height
9631 constant. */
9632 adjust_frame_size
9633 (f, -1, FRAME_TEXT_HEIGHT (f) + FRAME_MENU_BAR_HEIGHT (f)
9634 - old_menu_bar_height, 1, false, Qfont);
9635 #endif /* USE_X_TOOLKIT */
9639 #ifdef HAVE_X_I18N
9640 if (FRAME_XIC (f)
9641 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
9643 block_input ();
9644 xic_set_xfontset (f, SSDATA (fontset_ascii (fontset)));
9645 unblock_input ();
9647 #endif
9649 return font_object;
9653 /***********************************************************************
9654 X Input Methods
9655 ***********************************************************************/
9657 #ifdef HAVE_X_I18N
9659 #ifdef HAVE_X11R6
9661 /* XIM destroy callback function, which is called whenever the
9662 connection to input method XIM dies. CLIENT_DATA contains a
9663 pointer to the x_display_info structure corresponding to XIM. */
9665 static void
9666 xim_destroy_callback (XIM xim, XPointer client_data, XPointer call_data)
9668 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
9669 Lisp_Object frame, tail;
9671 block_input ();
9673 /* No need to call XDestroyIC.. */
9674 FOR_EACH_FRAME (tail, frame)
9676 struct frame *f = XFRAME (frame);
9677 if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo)
9679 FRAME_XIC (f) = NULL;
9680 xic_free_xfontset (f);
9684 /* No need to call XCloseIM. */
9685 dpyinfo->xim = NULL;
9686 XFree (dpyinfo->xim_styles);
9687 unblock_input ();
9690 #endif /* HAVE_X11R6 */
9692 /* Open the connection to the XIM server on display DPYINFO.
9693 RESOURCE_NAME is the resource name Emacs uses. */
9695 static void
9696 xim_open_dpy (struct x_display_info *dpyinfo, char *resource_name)
9698 XIM xim;
9700 #ifdef HAVE_XIM
9701 if (use_xim)
9703 if (dpyinfo->xim)
9704 XCloseIM (dpyinfo->xim);
9705 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name,
9706 emacs_class);
9707 dpyinfo->xim = xim;
9709 if (xim)
9711 #ifdef HAVE_X11R6
9712 XIMCallback destroy;
9713 #endif
9715 /* Get supported styles and XIM values. */
9716 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
9718 #ifdef HAVE_X11R6
9719 destroy.callback = xim_destroy_callback;
9720 destroy.client_data = (XPointer)dpyinfo;
9721 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
9722 #endif
9726 else
9727 #endif /* HAVE_XIM */
9728 dpyinfo->xim = NULL;
9732 #ifdef HAVE_X11R6_XIM
9734 /* XIM instantiate callback function, which is called whenever an XIM
9735 server is available. DISPLAY is the display of the XIM.
9736 CLIENT_DATA contains a pointer to an xim_inst_t structure created
9737 when the callback was registered. */
9739 static void
9740 xim_instantiate_callback (Display *display, XPointer client_data, XPointer call_data)
9742 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
9743 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
9745 /* We don't support multiple XIM connections. */
9746 if (dpyinfo->xim)
9747 return;
9749 xim_open_dpy (dpyinfo, xim_inst->resource_name);
9751 /* Create XIC for the existing frames on the same display, as long
9752 as they have no XIC. */
9753 if (dpyinfo->xim && dpyinfo->reference_count > 0)
9755 Lisp_Object tail, frame;
9757 block_input ();
9758 FOR_EACH_FRAME (tail, frame)
9760 struct frame *f = XFRAME (frame);
9762 if (FRAME_X_P (f)
9763 && FRAME_DISPLAY_INFO (f) == xim_inst->dpyinfo)
9764 if (FRAME_XIC (f) == NULL)
9766 create_frame_xic (f);
9767 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
9768 xic_set_statusarea (f);
9769 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
9771 struct window *w = XWINDOW (f->selected_window);
9772 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
9777 unblock_input ();
9781 #endif /* HAVE_X11R6_XIM */
9784 /* Open a connection to the XIM server on display DPYINFO.
9785 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
9786 connection only at the first time. On X11R6, open the connection
9787 in the XIM instantiate callback function. */
9789 static void
9790 xim_initialize (struct x_display_info *dpyinfo, char *resource_name)
9792 dpyinfo->xim = NULL;
9793 #ifdef HAVE_XIM
9794 if (use_xim)
9796 #ifdef HAVE_X11R6_XIM
9797 struct xim_inst_t *xim_inst = xmalloc (sizeof *xim_inst);
9798 Bool ret;
9800 dpyinfo->xim_callback_data = xim_inst;
9801 xim_inst->dpyinfo = dpyinfo;
9802 xim_inst->resource_name = xstrdup (resource_name);
9803 ret = XRegisterIMInstantiateCallback
9804 (dpyinfo->display, dpyinfo->xrdb, xim_inst->resource_name,
9805 emacs_class, xim_instantiate_callback,
9806 /* This is XPointer in XFree86 but (XPointer *)
9807 on Tru64, at least, hence the configure test. */
9808 (XRegisterIMInstantiateCallback_arg6) xim_inst);
9809 eassert (ret == True);
9810 #else /* not HAVE_X11R6_XIM */
9811 xim_open_dpy (dpyinfo, resource_name);
9812 #endif /* not HAVE_X11R6_XIM */
9814 #endif /* HAVE_XIM */
9818 /* Close the connection to the XIM server on display DPYINFO. */
9820 static void
9821 xim_close_dpy (struct x_display_info *dpyinfo)
9823 #ifdef HAVE_XIM
9824 if (use_xim)
9826 #ifdef HAVE_X11R6_XIM
9827 struct xim_inst_t *xim_inst = dpyinfo->xim_callback_data;
9829 if (dpyinfo->display)
9831 Bool ret = XUnregisterIMInstantiateCallback
9832 (dpyinfo->display, dpyinfo->xrdb, xim_inst->resource_name,
9833 emacs_class, xim_instantiate_callback,
9834 (XRegisterIMInstantiateCallback_arg6) xim_inst);
9835 eassert (ret == True);
9837 xfree (xim_inst->resource_name);
9838 xfree (xim_inst);
9839 #endif /* HAVE_X11R6_XIM */
9840 if (dpyinfo->display)
9841 XCloseIM (dpyinfo->xim);
9842 dpyinfo->xim = NULL;
9843 XFree (dpyinfo->xim_styles);
9845 #endif /* HAVE_XIM */
9848 #endif /* not HAVE_X11R6_XIM */
9852 /* Calculate the absolute position in frame F
9853 from its current recorded position values and gravity. */
9855 static void
9856 x_calc_absolute_position (struct frame *f)
9858 int flags = f->size_hint_flags;
9860 /* We have nothing to do if the current position
9861 is already for the top-left corner. */
9862 if (! ((flags & XNegative) || (flags & YNegative)))
9863 return;
9865 /* Treat negative positions as relative to the leftmost bottommost
9866 position that fits on the screen. */
9867 if (flags & XNegative)
9868 f->left_pos = x_display_pixel_width (FRAME_DISPLAY_INFO (f))
9869 - FRAME_PIXEL_WIDTH (f) + f->left_pos;
9872 int height = FRAME_PIXEL_HEIGHT (f);
9874 #if defined USE_X_TOOLKIT && defined USE_MOTIF
9875 /* Something is fishy here. When using Motif, starting Emacs with
9876 `-g -0-0', the frame appears too low by a few pixels.
9878 This seems to be so because initially, while Emacs is starting,
9879 the column widget's height and the frame's pixel height are
9880 different. The column widget's height is the right one. In
9881 later invocations, when Emacs is up, the frame's pixel height
9882 is right, though.
9884 It's not obvious where the initial small difference comes from.
9885 2000-12-01, gerd. */
9887 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
9888 #endif
9890 if (flags & YNegative)
9891 f->top_pos = x_display_pixel_height (FRAME_DISPLAY_INFO (f))
9892 - height + f->top_pos;
9895 /* The left_pos and top_pos
9896 are now relative to the top and left screen edges,
9897 so the flags should correspond. */
9898 f->size_hint_flags &= ~ (XNegative | YNegative);
9901 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
9902 to really change the position, and 0 when calling from
9903 x_make_frame_visible (in that case, XOFF and YOFF are the current
9904 position values). It is -1 when calling from x_set_frame_parameters,
9905 which means, do adjust for borders but don't change the gravity. */
9907 void
9908 x_set_offset (struct frame *f, register int xoff, register int yoff, int change_gravity)
9910 int modified_top, modified_left;
9912 if (change_gravity > 0)
9914 f->top_pos = yoff;
9915 f->left_pos = xoff;
9916 f->size_hint_flags &= ~ (XNegative | YNegative);
9917 if (xoff < 0)
9918 f->size_hint_flags |= XNegative;
9919 if (yoff < 0)
9920 f->size_hint_flags |= YNegative;
9921 f->win_gravity = NorthWestGravity;
9923 x_calc_absolute_position (f);
9925 block_input ();
9926 x_wm_set_size_hint (f, 0, false);
9928 modified_left = f->left_pos;
9929 modified_top = f->top_pos;
9931 if (change_gravity != 0 && FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A)
9933 /* Some WMs (twm, wmaker at least) has an offset that is smaller
9934 than the WM decorations. So we use the calculated offset instead
9935 of the WM decoration sizes here (x/y_pixels_outer_diff). */
9936 modified_left += FRAME_X_OUTPUT (f)->move_offset_left;
9937 modified_top += FRAME_X_OUTPUT (f)->move_offset_top;
9940 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
9941 modified_left, modified_top);
9943 x_sync_with_move (f, f->left_pos, f->top_pos,
9944 FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN);
9946 /* change_gravity is non-zero when this function is called from Lisp to
9947 programmatically move a frame. In that case, we call
9948 x_check_expected_move to discover if we have a "Type A" or "Type B"
9949 window manager, and, for a "Type A" window manager, adjust the position
9950 of the frame.
9952 We call x_check_expected_move if a programmatic move occurred, and
9953 either the window manager type (A/B) is unknown or it is Type A but we
9954 need to compute the top/left offset adjustment for this frame. */
9956 if (change_gravity != 0
9957 && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
9958 || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
9959 && (FRAME_X_OUTPUT (f)->move_offset_left == 0
9960 && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
9961 x_check_expected_move (f, modified_left, modified_top);
9963 unblock_input ();
9966 /* Return true if _NET_SUPPORTING_WM_CHECK window exists and _NET_SUPPORTED
9967 on the root window for frame F contains ATOMNAME.
9968 This is how a WM check shall be done according to the Window Manager
9969 Specification/Extended Window Manager Hints at
9970 http://freedesktop.org/wiki/Specifications/wm-spec. */
9972 bool
9973 x_wm_supports (struct frame *f, Atom want_atom)
9975 Atom actual_type;
9976 unsigned long actual_size, bytes_remaining;
9977 int i, rc, actual_format;
9978 bool ret;
9979 Window wmcheck_window;
9980 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
9981 Window target_window = dpyinfo->root_window;
9982 int max_len = 65536;
9983 Display *dpy = FRAME_X_DISPLAY (f);
9984 unsigned char *tmp_data = NULL;
9985 Atom target_type = XA_WINDOW;
9987 block_input ();
9989 x_catch_errors (dpy);
9990 rc = XGetWindowProperty (dpy, target_window,
9991 dpyinfo->Xatom_net_supporting_wm_check,
9992 0, max_len, False, target_type,
9993 &actual_type, &actual_format, &actual_size,
9994 &bytes_remaining, &tmp_data);
9996 if (rc != Success || actual_type != XA_WINDOW || x_had_errors_p (dpy))
9998 if (tmp_data) XFree (tmp_data);
9999 x_uncatch_errors ();
10000 unblock_input ();
10001 return false;
10004 wmcheck_window = *(Window *) tmp_data;
10005 XFree (tmp_data);
10007 /* Check if window exists. */
10008 XSelectInput (dpy, wmcheck_window, StructureNotifyMask);
10009 if (x_had_errors_p (dpy))
10011 x_uncatch_errors_after_check ();
10012 unblock_input ();
10013 return false;
10016 if (dpyinfo->net_supported_window != wmcheck_window)
10018 /* Window changed, reload atoms */
10019 if (dpyinfo->net_supported_atoms != NULL)
10020 XFree (dpyinfo->net_supported_atoms);
10021 dpyinfo->net_supported_atoms = NULL;
10022 dpyinfo->nr_net_supported_atoms = 0;
10023 dpyinfo->net_supported_window = 0;
10025 target_type = XA_ATOM;
10026 tmp_data = NULL;
10027 rc = XGetWindowProperty (dpy, target_window,
10028 dpyinfo->Xatom_net_supported,
10029 0, max_len, False, target_type,
10030 &actual_type, &actual_format, &actual_size,
10031 &bytes_remaining, &tmp_data);
10033 if (rc != Success || actual_type != XA_ATOM || x_had_errors_p (dpy))
10035 if (tmp_data) XFree (tmp_data);
10036 x_uncatch_errors ();
10037 unblock_input ();
10038 return false;
10041 dpyinfo->net_supported_atoms = (Atom *)tmp_data;
10042 dpyinfo->nr_net_supported_atoms = actual_size;
10043 dpyinfo->net_supported_window = wmcheck_window;
10046 ret = false;
10048 for (i = 0; !ret && i < dpyinfo->nr_net_supported_atoms; ++i)
10049 ret = dpyinfo->net_supported_atoms[i] == want_atom;
10051 x_uncatch_errors ();
10052 unblock_input ();
10054 return ret;
10057 static void
10058 set_wm_state (Lisp_Object frame, bool add, Atom atom, Atom value)
10060 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (XFRAME (frame));
10062 x_send_client_event (frame, make_number (0), frame,
10063 dpyinfo->Xatom_net_wm_state,
10064 make_number (32),
10065 /* 1 = add, 0 = remove */
10066 Fcons
10067 (make_number (add),
10068 Fcons
10069 (make_fixnum_or_float (atom),
10070 (value != 0
10071 ? list1 (make_fixnum_or_float (value))
10072 : Qnil))));
10075 void
10076 x_set_sticky (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
10078 Lisp_Object frame;
10079 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10081 XSETFRAME (frame, f);
10083 set_wm_state (frame, !NILP (new_value),
10084 dpyinfo->Xatom_net_wm_state_sticky, None);
10087 /* Return the current _NET_WM_STATE.
10088 SIZE_STATE is set to one of the FULLSCREEN_* values.
10089 Set *STICKY to the sticky state.
10091 Return true iff we are not hidden. */
10093 static bool
10094 get_current_wm_state (struct frame *f,
10095 Window window,
10096 int *size_state,
10097 bool *sticky)
10099 unsigned long actual_size;
10100 int i;
10101 bool is_hidden = false;
10102 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10103 long max_len = 65536;
10104 Atom target_type = XA_ATOM;
10105 /* If XCB is available, we can avoid three XSync calls. */
10106 #ifdef USE_XCB
10107 xcb_get_property_cookie_t prop_cookie;
10108 xcb_get_property_reply_t *prop;
10109 xcb_atom_t *reply_data;
10110 #else
10111 Display *dpy = FRAME_X_DISPLAY (f);
10112 unsigned long bytes_remaining;
10113 int rc, actual_format;
10114 Atom actual_type;
10115 unsigned char *tmp_data = NULL;
10116 Atom *reply_data;
10117 #endif
10119 *sticky = false;
10120 *size_state = FULLSCREEN_NONE;
10122 block_input ();
10124 #ifdef USE_XCB
10125 prop_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, window,
10126 dpyinfo->Xatom_net_wm_state,
10127 target_type, 0, max_len);
10128 prop = xcb_get_property_reply (dpyinfo->xcb_connection, prop_cookie, NULL);
10129 if (prop && prop->type == target_type)
10131 int actual_bytes = xcb_get_property_value_length (prop);
10132 eassume (0 <= actual_bytes);
10133 actual_size = actual_bytes / sizeof *reply_data;
10134 reply_data = xcb_get_property_value (prop);
10136 else
10138 actual_size = 0;
10139 is_hidden = FRAME_ICONIFIED_P (f);
10141 #else
10142 x_catch_errors (dpy);
10143 rc = XGetWindowProperty (dpy, window, dpyinfo->Xatom_net_wm_state,
10144 0, max_len, False, target_type,
10145 &actual_type, &actual_format, &actual_size,
10146 &bytes_remaining, &tmp_data);
10148 if (rc == Success && actual_type == target_type && ! x_had_errors_p (dpy))
10149 reply_data = (Atom *) tmp_data;
10150 else
10152 actual_size = 0;
10153 is_hidden = FRAME_ICONIFIED_P (f);
10156 x_uncatch_errors ();
10157 #endif
10159 for (i = 0; i < actual_size; ++i)
10161 Atom a = reply_data[i];
10162 if (a == dpyinfo->Xatom_net_wm_state_hidden)
10163 is_hidden = true;
10164 else if (a == dpyinfo->Xatom_net_wm_state_maximized_horz)
10166 if (*size_state == FULLSCREEN_HEIGHT)
10167 *size_state = FULLSCREEN_MAXIMIZED;
10168 else
10169 *size_state = FULLSCREEN_WIDTH;
10171 else if (a == dpyinfo->Xatom_net_wm_state_maximized_vert)
10173 if (*size_state == FULLSCREEN_WIDTH)
10174 *size_state = FULLSCREEN_MAXIMIZED;
10175 else
10176 *size_state = FULLSCREEN_HEIGHT;
10178 else if (a == dpyinfo->Xatom_net_wm_state_fullscreen)
10179 *size_state = FULLSCREEN_BOTH;
10180 else if (a == dpyinfo->Xatom_net_wm_state_sticky)
10181 *sticky = true;
10184 #ifdef USE_XCB
10185 free (prop);
10186 #else
10187 if (tmp_data) XFree (tmp_data);
10188 #endif
10190 unblock_input ();
10191 return ! is_hidden;
10194 /* Do fullscreen as specified in extended window manager hints */
10196 static bool
10197 do_ewmh_fullscreen (struct frame *f)
10199 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10200 bool have_net_atom = x_wm_supports (f, dpyinfo->Xatom_net_wm_state);
10201 int cur;
10202 bool dummy;
10204 get_current_wm_state (f, FRAME_OUTER_WINDOW (f), &cur, &dummy);
10206 /* Some window managers don't say they support _NET_WM_STATE, but they do say
10207 they support _NET_WM_STATE_FULLSCREEN. Try that also. */
10208 if (!have_net_atom)
10209 have_net_atom = x_wm_supports (f, dpyinfo->Xatom_net_wm_state_fullscreen);
10211 if (have_net_atom && cur != f->want_fullscreen)
10213 Lisp_Object frame;
10215 XSETFRAME (frame, f);
10217 /* Keep number of calls to set_wm_state as low as possible.
10218 Some window managers, or possible Gtk+, hangs when too many
10219 are sent at once. */
10220 switch (f->want_fullscreen)
10222 case FULLSCREEN_BOTH:
10223 if (cur != FULLSCREEN_BOTH)
10224 set_wm_state (frame, true, dpyinfo->Xatom_net_wm_state_fullscreen,
10225 None);
10226 break;
10227 case FULLSCREEN_WIDTH:
10228 if (x_frame_normalize_before_maximize && cur == FULLSCREEN_MAXIMIZED)
10230 set_wm_state (frame, false,
10231 dpyinfo->Xatom_net_wm_state_maximized_horz,
10232 dpyinfo->Xatom_net_wm_state_maximized_vert);
10233 set_wm_state (frame, true,
10234 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
10236 else
10238 if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_HEIGHT
10239 || cur == FULLSCREEN_MAXIMIZED)
10240 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
10241 dpyinfo->Xatom_net_wm_state_maximized_vert);
10242 if (cur != FULLSCREEN_MAXIMIZED || x_frame_normalize_before_maximize)
10243 set_wm_state (frame, true,
10244 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
10246 break;
10247 case FULLSCREEN_HEIGHT:
10248 if (x_frame_normalize_before_maximize && cur == FULLSCREEN_MAXIMIZED)
10250 set_wm_state (frame, false,
10251 dpyinfo->Xatom_net_wm_state_maximized_horz,
10252 dpyinfo->Xatom_net_wm_state_maximized_vert);
10253 set_wm_state (frame, true,
10254 dpyinfo->Xatom_net_wm_state_maximized_vert, None);
10256 else
10258 if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_WIDTH
10259 || cur == FULLSCREEN_MAXIMIZED)
10260 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
10261 dpyinfo->Xatom_net_wm_state_maximized_horz);
10262 if (cur != FULLSCREEN_MAXIMIZED || x_frame_normalize_before_maximize)
10263 set_wm_state (frame, true,
10264 dpyinfo->Xatom_net_wm_state_maximized_vert, None);
10266 break;
10267 case FULLSCREEN_MAXIMIZED:
10268 if (x_frame_normalize_before_maximize && cur == FULLSCREEN_BOTH)
10270 set_wm_state (frame, false,
10271 dpyinfo->Xatom_net_wm_state_fullscreen, None);
10272 set_wm_state (frame, true,
10273 dpyinfo->Xatom_net_wm_state_maximized_horz,
10274 dpyinfo->Xatom_net_wm_state_maximized_vert);
10276 else if (x_frame_normalize_before_maximize && cur == FULLSCREEN_WIDTH)
10278 set_wm_state (frame, false,
10279 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
10280 set_wm_state (frame, true,
10281 dpyinfo->Xatom_net_wm_state_maximized_horz,
10282 dpyinfo->Xatom_net_wm_state_maximized_vert);
10284 else if (x_frame_normalize_before_maximize && cur == FULLSCREEN_HEIGHT)
10286 set_wm_state (frame, false,
10287 dpyinfo->Xatom_net_wm_state_maximized_vert, None);
10288 set_wm_state (frame, true,
10289 dpyinfo->Xatom_net_wm_state_maximized_horz,
10290 dpyinfo->Xatom_net_wm_state_maximized_vert);
10292 else
10294 if (cur == FULLSCREEN_BOTH)
10295 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
10296 None);
10297 else if (cur == FULLSCREEN_HEIGHT)
10298 set_wm_state (frame, true,
10299 dpyinfo->Xatom_net_wm_state_maximized_horz, None);
10300 else if (cur == FULLSCREEN_WIDTH)
10301 set_wm_state (frame, true, None,
10302 dpyinfo->Xatom_net_wm_state_maximized_vert);
10303 else
10304 set_wm_state (frame, true,
10305 dpyinfo->Xatom_net_wm_state_maximized_horz,
10306 dpyinfo->Xatom_net_wm_state_maximized_vert);
10308 break;
10309 case FULLSCREEN_NONE:
10310 if (cur == FULLSCREEN_BOTH)
10311 set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen,
10312 None);
10313 else
10314 set_wm_state (frame, false,
10315 dpyinfo->Xatom_net_wm_state_maximized_horz,
10316 dpyinfo->Xatom_net_wm_state_maximized_vert);
10319 f->want_fullscreen = FULLSCREEN_NONE;
10323 return have_net_atom;
10326 static void
10327 XTfullscreen_hook (struct frame *f)
10329 if (FRAME_VISIBLE_P (f))
10331 block_input ();
10332 x_check_fullscreen (f);
10333 x_sync (f);
10334 unblock_input ();
10339 static bool
10340 x_handle_net_wm_state (struct frame *f, const XPropertyEvent *event)
10342 int value = FULLSCREEN_NONE;
10343 Lisp_Object lval;
10344 bool sticky = false;
10345 bool not_hidden = get_current_wm_state (f, event->window, &value, &sticky);
10347 lval = Qnil;
10348 switch (value)
10350 case FULLSCREEN_WIDTH:
10351 lval = Qfullwidth;
10352 break;
10353 case FULLSCREEN_HEIGHT:
10354 lval = Qfullheight;
10355 break;
10356 case FULLSCREEN_BOTH:
10357 lval = Qfullboth;
10358 break;
10359 case FULLSCREEN_MAXIMIZED:
10360 lval = Qmaximized;
10361 break;
10364 frame_size_history_add
10365 (f, Qx_handle_net_wm_state, 0, 0,
10366 list2 (get_frame_param (f, Qfullscreen), lval));
10368 store_frame_param (f, Qfullscreen, lval);
10369 store_frame_param (f, Qsticky, sticky ? Qt : Qnil);
10371 return not_hidden;
10374 /* Check if we need to resize the frame due to a fullscreen request.
10375 If so needed, resize the frame. */
10376 static void
10377 x_check_fullscreen (struct frame *f)
10379 Lisp_Object lval = Qnil;
10381 if (do_ewmh_fullscreen (f))
10382 return;
10384 if (f->output_data.x->parent_desc != FRAME_DISPLAY_INFO (f)->root_window)
10385 return; /* Only fullscreen without WM or with EWM hints (above). */
10387 /* Setting fullscreen to nil doesn't do anything. We could save the
10388 last non-fullscreen size and restore it, but it seems like a
10389 lot of work for this unusual case (no window manager running). */
10391 if (f->want_fullscreen != FULLSCREEN_NONE)
10393 int width = FRAME_PIXEL_WIDTH (f), height = FRAME_PIXEL_HEIGHT (f);
10394 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10396 switch (f->want_fullscreen)
10398 /* No difference between these two when there is no WM */
10399 case FULLSCREEN_MAXIMIZED:
10400 lval = Qmaximized;
10401 width = x_display_pixel_width (dpyinfo);
10402 height = x_display_pixel_height (dpyinfo);
10403 break;
10404 case FULLSCREEN_BOTH:
10405 lval = Qfullboth;
10406 width = x_display_pixel_width (dpyinfo);
10407 height = x_display_pixel_height (dpyinfo);
10408 break;
10409 case FULLSCREEN_WIDTH:
10410 lval = Qfullwidth;
10411 width = x_display_pixel_width (dpyinfo);
10412 height = height + FRAME_MENUBAR_HEIGHT (f);
10413 break;
10414 case FULLSCREEN_HEIGHT:
10415 lval = Qfullheight;
10416 height = x_display_pixel_height (dpyinfo);
10417 break;
10418 default:
10419 emacs_abort ();
10422 frame_size_history_add
10423 (f, Qx_check_fullscreen, width, height, Qnil);
10425 x_wm_set_size_hint (f, 0, false);
10427 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10428 width, height);
10430 if (FRAME_VISIBLE_P (f))
10431 x_wait_for_event (f, ConfigureNotify);
10432 else
10434 change_frame_size (f, width, height - FRAME_MENUBAR_HEIGHT (f),
10435 false, true, false, true);
10436 x_sync (f);
10440 /* `x_net_wm_state' might have reset the fullscreen frame parameter,
10441 restore it. */
10442 store_frame_param (f, Qfullscreen, lval);
10445 /* This function is called by x_set_offset to determine whether the window
10446 manager interfered with the positioning of the frame. Type A window
10447 managers position the surrounding window manager decorations a small
10448 amount above and left of the user-supplied position. Type B window
10449 managers position the surrounding window manager decorations at the
10450 user-specified position. If we detect a Type A window manager, we
10451 compensate by moving the window right and down by the proper amount. */
10453 static void
10454 x_check_expected_move (struct frame *f, int expected_left, int expected_top)
10456 int current_left = 0, current_top = 0;
10458 /* x_real_positions returns the left and top offsets of the outermost
10459 window manager window around the frame. */
10461 x_real_positions (f, &current_left, &current_top);
10463 if (current_left != expected_left || current_top != expected_top)
10465 /* It's a "Type A" window manager. */
10467 int adjusted_left;
10468 int adjusted_top;
10470 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_A;
10471 FRAME_X_OUTPUT (f)->move_offset_left = expected_left - current_left;
10472 FRAME_X_OUTPUT (f)->move_offset_top = expected_top - current_top;
10474 /* Now fix the mispositioned frame's location. */
10476 adjusted_left = expected_left + FRAME_X_OUTPUT (f)->move_offset_left;
10477 adjusted_top = expected_top + FRAME_X_OUTPUT (f)->move_offset_top;
10479 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10480 adjusted_left, adjusted_top);
10482 x_sync_with_move (f, expected_left, expected_top, false);
10484 else
10485 /* It's a "Type B" window manager. We don't have to adjust the
10486 frame's position. */
10488 FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_B;
10492 /* Wait for XGetGeometry to return up-to-date position information for a
10493 recently-moved frame. Call this immediately after calling XMoveWindow.
10494 If FUZZY is non-zero, then LEFT and TOP are just estimates of where the
10495 frame has been moved to, so we use a fuzzy position comparison instead
10496 of an exact comparison. */
10498 static void
10499 x_sync_with_move (struct frame *f, int left, int top, bool fuzzy)
10501 int count = 0;
10503 while (count++ < 50)
10505 int current_left = 0, current_top = 0;
10507 /* In theory, this call to XSync only needs to happen once, but in
10508 practice, it doesn't seem to work, hence the need for the surrounding
10509 loop. */
10511 XSync (FRAME_X_DISPLAY (f), False);
10512 x_real_positions (f, &current_left, &current_top);
10514 if (fuzzy)
10516 /* The left fuzz-factor is 10 pixels. The top fuzz-factor is 40
10517 pixels. */
10519 if (eabs (current_left - left) <= 10
10520 && eabs (current_top - top) <= 40)
10521 return;
10523 else if (current_left == left && current_top == top)
10524 return;
10527 /* As a last resort, just wait 0.5 seconds and hope that XGetGeometry
10528 will then return up-to-date position info. */
10530 wait_reading_process_output (0, 500000000, 0, false, Qnil, NULL, 0);
10534 /* Wait for an event on frame F matching EVENTTYPE. */
10535 void
10536 x_wait_for_event (struct frame *f, int eventtype)
10538 int level = interrupt_input_blocked;
10540 fd_set fds;
10541 struct timespec tmo, tmo_at, time_now;
10542 int fd = ConnectionNumber (FRAME_X_DISPLAY (f));
10544 f->wait_event_type = eventtype;
10546 /* Set timeout to 0.1 second. Hopefully not noticeable.
10547 Maybe it should be configurable. */
10548 tmo = make_timespec (0, 100 * 1000 * 1000);
10549 tmo_at = timespec_add (current_timespec (), tmo);
10551 while (f->wait_event_type)
10553 pending_signals = true;
10554 totally_unblock_input ();
10555 /* XTread_socket is called after unblock. */
10556 block_input ();
10557 interrupt_input_blocked = level;
10559 FD_ZERO (&fds);
10560 FD_SET (fd, &fds);
10562 time_now = current_timespec ();
10563 if (timespec_cmp (tmo_at, time_now) < 0)
10564 break;
10566 tmo = timespec_sub (tmo_at, time_now);
10567 if (pselect (fd + 1, &fds, NULL, NULL, &tmo, NULL) == 0)
10568 break; /* Timeout */
10571 f->wait_event_type = 0;
10575 /* Change the size of frame F's X window to WIDTH/HEIGHT in the case F
10576 doesn't have a widget. If CHANGE_GRAVITY, change to
10577 top-left-corner window gravity for this size change and subsequent
10578 size changes. Otherwise leave the window gravity unchanged. */
10580 static void
10581 x_set_window_size_1 (struct frame *f, bool change_gravity,
10582 int width, int height)
10584 int pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
10585 int pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
10586 int old_width = FRAME_PIXEL_WIDTH (f);
10587 int old_height = FRAME_PIXEL_HEIGHT (f);
10588 Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
10590 if (change_gravity) f->win_gravity = NorthWestGravity;
10591 x_wm_set_size_hint (f, 0, false);
10593 /* When the frame is fullheight and we only want to change the width
10594 or it is fullwidth and we only want to change the height we should
10595 be able to preserve the fullscreen property. However, due to the
10596 fact that we have to send a resize request anyway, the window
10597 manager will abolish it. At least the respective size should
10598 remain unchanged but giving the frame back its normal size will
10599 be broken ... */
10600 if (EQ (fullscreen, Qfullwidth) && width == FRAME_TEXT_WIDTH (f))
10602 frame_size_history_add
10603 (f, Qx_set_window_size_1, width, height,
10604 list2 (make_number (old_height),
10605 make_number (pixelheight + FRAME_MENUBAR_HEIGHT (f))));
10607 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10608 old_width, pixelheight + FRAME_MENUBAR_HEIGHT (f));
10610 else if (EQ (fullscreen, Qfullheight) && height == FRAME_TEXT_HEIGHT (f))
10612 frame_size_history_add
10613 (f, Qx_set_window_size_2, width, height,
10614 list2 (make_number (old_width), make_number (pixelwidth)));
10616 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10617 pixelwidth, old_height);
10620 else
10622 frame_size_history_add
10623 (f, Qx_set_window_size_3, width, height,
10624 list3 (make_number (pixelwidth + FRAME_TOOLBAR_WIDTH (f)),
10625 make_number (pixelheight + FRAME_TOOLBAR_HEIGHT (f)
10626 + FRAME_MENUBAR_HEIGHT (f)),
10627 make_number (FRAME_MENUBAR_HEIGHT (f))));
10629 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10630 pixelwidth, pixelheight + FRAME_MENUBAR_HEIGHT (f));
10631 fullscreen = Qnil;
10636 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
10637 receive in the ConfigureNotify event; if we get what we asked
10638 for, then the event won't cause the screen to become garbaged, so
10639 we have to make sure to do it here. */
10640 SET_FRAME_GARBAGED (f);
10642 /* Now, strictly speaking, we can't be sure that this is accurate,
10643 but the window manager will get around to dealing with the size
10644 change request eventually, and we'll hear how it went when the
10645 ConfigureNotify event gets here.
10647 We could just not bother storing any of this information here,
10648 and let the ConfigureNotify event set everything up, but that
10649 might be kind of confusing to the Lisp code, since size changes
10650 wouldn't be reported in the frame parameters until some random
10651 point in the future when the ConfigureNotify event arrives.
10653 Pass true for DELAY since we can't run Lisp code inside of
10654 a BLOCK_INPUT. */
10656 /* But the ConfigureNotify may in fact never arrive, and then this is
10657 not right if the frame is visible. Instead wait (with timeout)
10658 for the ConfigureNotify. */
10659 if (FRAME_VISIBLE_P (f))
10661 x_wait_for_event (f, ConfigureNotify);
10663 if (!NILP (fullscreen))
10664 /* Try to restore fullscreen state. */
10666 store_frame_param (f, Qfullscreen, fullscreen);
10667 x_set_fullscreen (f, fullscreen, fullscreen);
10670 else
10672 change_frame_size (f, width, height, false, true, false, true);
10673 x_sync (f);
10678 /* Call this to change the size of frame F's x-window.
10679 If CHANGE_GRAVITY, change to top-left-corner window gravity
10680 for this size change and subsequent size changes.
10681 Otherwise we leave the window gravity unchanged. */
10683 void
10684 x_set_window_size (struct frame *f, bool change_gravity,
10685 int width, int height, bool pixelwise)
10687 block_input ();
10689 /* The following breaks our calculations. If it's really needed,
10690 think of something else. */
10691 #if false
10692 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
10694 int text_width, text_height;
10696 /* When the frame is maximized/fullscreen or running under for
10697 example Xmonad, x_set_window_size_1 will be a no-op.
10698 In that case, the right thing to do is extend rows/width to
10699 the current frame size. We do that first if x_set_window_size_1
10700 turns out to not be a no-op (there is no way to know).
10701 The size will be adjusted again if the frame gets a
10702 ConfigureNotify event as a result of x_set_window_size. */
10703 int pixelh = FRAME_PIXEL_HEIGHT (f);
10704 #ifdef USE_X_TOOLKIT
10705 /* The menu bar is not part of text lines. The tool bar
10706 is however. */
10707 pixelh -= FRAME_MENUBAR_HEIGHT (f);
10708 #endif
10709 text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, FRAME_PIXEL_WIDTH (f));
10710 text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelh);
10712 change_frame_size (f, text_width, text_height, false, true, false, true);
10714 #endif
10716 /* Pixelize width and height, if necessary. */
10717 if (! pixelwise)
10719 width = width * FRAME_COLUMN_WIDTH (f);
10720 height = height * FRAME_LINE_HEIGHT (f);
10723 #ifdef USE_GTK
10724 if (FRAME_GTK_WIDGET (f))
10725 xg_frame_set_char_size (f, width, height);
10726 else
10727 x_set_window_size_1 (f, change_gravity, width, height);
10728 #else /* not USE_GTK */
10729 x_set_window_size_1 (f, change_gravity, width, height);
10730 x_clear_under_internal_border (f);
10731 #endif /* not USE_GTK */
10733 /* If cursor was outside the new size, mark it as off. */
10734 mark_window_cursors_off (XWINDOW (f->root_window));
10736 /* Clear out any recollection of where the mouse highlighting was,
10737 since it might be in a place that's outside the new frame size.
10738 Actually checking whether it is outside is a pain in the neck,
10739 so don't try--just let the highlighting be done afresh with new size. */
10740 cancel_mouse_face (f);
10742 unblock_input ();
10744 do_pending_window_change (false);
10747 /* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
10749 void
10750 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
10752 block_input ();
10754 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
10755 0, 0, 0, 0, pix_x, pix_y);
10756 unblock_input ();
10759 /* Raise frame F. */
10761 void
10762 x_raise_frame (struct frame *f)
10764 block_input ();
10765 if (FRAME_VISIBLE_P (f))
10766 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
10767 XFlush (FRAME_X_DISPLAY (f));
10768 unblock_input ();
10771 /* Lower frame F. */
10773 static void
10774 x_lower_frame (struct frame *f)
10776 if (FRAME_VISIBLE_P (f))
10778 block_input ();
10779 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
10780 XFlush (FRAME_X_DISPLAY (f));
10781 unblock_input ();
10785 /* Request focus with XEmbed */
10787 void
10788 xembed_request_focus (struct frame *f)
10790 /* See XEmbed Protocol Specification at
10791 http://freedesktop.org/wiki/Specifications/xembed-spec */
10792 if (FRAME_VISIBLE_P (f))
10793 xembed_send_message (f, CurrentTime,
10794 XEMBED_REQUEST_FOCUS, 0, 0, 0);
10797 /* Activate frame with Extended Window Manager Hints */
10799 void
10800 x_ewmh_activate_frame (struct frame *f)
10802 /* See Window Manager Specification/Extended Window Manager Hints at
10803 http://freedesktop.org/wiki/Specifications/wm-spec */
10805 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10807 if (FRAME_VISIBLE_P (f) && x_wm_supports (f, dpyinfo->Xatom_net_active_window))
10809 Lisp_Object frame;
10810 XSETFRAME (frame, f);
10811 x_send_client_event (frame, make_number (0), frame,
10812 dpyinfo->Xatom_net_active_window,
10813 make_number (32),
10814 list2i (1, dpyinfo->last_user_time));
10818 static void
10819 XTframe_raise_lower (struct frame *f, bool raise_flag)
10821 if (raise_flag)
10822 x_raise_frame (f);
10823 else
10824 x_lower_frame (f);
10827 /* XEmbed implementation. */
10829 #if defined USE_X_TOOLKIT || ! defined USE_GTK
10831 /* XEmbed implementation. */
10833 #define XEMBED_VERSION 0
10835 static void
10836 xembed_set_info (struct frame *f, enum xembed_info flags)
10838 unsigned long data[2];
10839 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
10841 data[0] = XEMBED_VERSION;
10842 data[1] = flags;
10844 XChangeProperty (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10845 dpyinfo->Xatom_XEMBED_INFO, dpyinfo->Xatom_XEMBED_INFO,
10846 32, PropModeReplace, (unsigned char *) data, 2);
10848 #endif /* defined USE_X_TOOLKIT || ! defined USE_GTK */
10850 static void
10851 xembed_send_message (struct frame *f, Time t, enum xembed_message msg,
10852 long int detail, long int data1, long int data2)
10854 XEvent event;
10856 event.xclient.type = ClientMessage;
10857 event.xclient.window = FRAME_X_OUTPUT (f)->parent_desc;
10858 event.xclient.message_type = FRAME_DISPLAY_INFO (f)->Xatom_XEMBED;
10859 event.xclient.format = 32;
10860 event.xclient.data.l[0] = t;
10861 event.xclient.data.l[1] = msg;
10862 event.xclient.data.l[2] = detail;
10863 event.xclient.data.l[3] = data1;
10864 event.xclient.data.l[4] = data2;
10866 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_OUTPUT (f)->parent_desc,
10867 False, NoEventMask, &event);
10868 XSync (FRAME_X_DISPLAY (f), False);
10871 /* Change of visibility. */
10873 /* This tries to wait until the frame is really visible.
10874 However, if the window manager asks the user where to position
10875 the frame, this will return before the user finishes doing that.
10876 The frame will not actually be visible at that time,
10877 but it will become visible later when the window manager
10878 finishes with it. */
10880 void
10881 x_make_frame_visible (struct frame *f)
10883 int original_top, original_left;
10884 int tries = 0;
10886 block_input ();
10888 x_set_bitmap_icon (f);
10890 if (! FRAME_VISIBLE_P (f))
10892 /* We test FRAME_GARBAGED_P here to make sure we don't
10893 call x_set_offset a second time
10894 if we get to x_make_frame_visible a second time
10895 before the window gets really visible. */
10896 if (! FRAME_ICONIFIED_P (f)
10897 && ! FRAME_X_EMBEDDED_P (f)
10898 && ! f->output_data.x->asked_for_visible)
10899 x_set_offset (f, f->left_pos, f->top_pos, 0);
10901 f->output_data.x->asked_for_visible = true;
10903 if (! EQ (Vx_no_window_manager, Qt))
10904 x_wm_set_window_state (f, NormalState);
10905 #ifdef USE_X_TOOLKIT
10906 if (FRAME_X_EMBEDDED_P (f))
10907 xembed_set_info (f, XEMBED_MAPPED);
10908 else
10910 /* This was XtPopup, but that did nothing for an iconified frame. */
10911 XtMapWidget (f->output_data.x->widget);
10913 #else /* not USE_X_TOOLKIT */
10914 #ifdef USE_GTK
10915 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
10916 gtk_window_deiconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
10917 #else
10918 if (FRAME_X_EMBEDDED_P (f))
10919 xembed_set_info (f, XEMBED_MAPPED);
10920 else
10921 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
10922 #endif /* not USE_GTK */
10923 #endif /* not USE_X_TOOLKIT */
10926 XFlush (FRAME_X_DISPLAY (f));
10928 /* Synchronize to ensure Emacs knows the frame is visible
10929 before we do anything else. We do this loop with input not blocked
10930 so that incoming events are handled. */
10932 Lisp_Object frame;
10933 /* This must be before UNBLOCK_INPUT
10934 since events that arrive in response to the actions above
10935 will set it when they are handled. */
10936 bool previously_visible = f->output_data.x->has_been_visible;
10938 original_left = f->left_pos;
10939 original_top = f->top_pos;
10941 /* This must come after we set COUNT. */
10942 unblock_input ();
10944 /* We unblock here so that arriving X events are processed. */
10946 /* Now move the window back to where it was "supposed to be".
10947 But don't do it if the gravity is negative.
10948 When the gravity is negative, this uses a position
10949 that is 3 pixels too low. Perhaps that's really the border width.
10951 Don't do this if the window has never been visible before,
10952 because the window manager may choose the position
10953 and we don't want to override it. */
10955 if (! FRAME_VISIBLE_P (f)
10956 && ! FRAME_ICONIFIED_P (f)
10957 && ! FRAME_X_EMBEDDED_P (f)
10958 && f->win_gravity == NorthWestGravity
10959 && previously_visible)
10961 Drawable rootw;
10962 int x, y;
10963 unsigned int width, height, border, depth;
10965 block_input ();
10967 /* On some window managers (such as FVWM) moving an existing
10968 window, even to the same place, causes the window manager
10969 to introduce an offset. This can cause the window to move
10970 to an unexpected location. Check the geometry (a little
10971 slow here) and then verify that the window is in the right
10972 place. If the window is not in the right place, move it
10973 there, and take the potential window manager hit. */
10974 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10975 &rootw, &x, &y, &width, &height, &border, &depth);
10977 if (original_left != x || original_top != y)
10978 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10979 original_left, original_top);
10981 unblock_input ();
10984 XSETFRAME (frame, f);
10986 /* Process X events until a MapNotify event has been seen. */
10987 while (!FRAME_VISIBLE_P (f))
10989 /* Force processing of queued events. */
10990 x_sync (f);
10992 /* If on another desktop, the deiconify/map may be ignored and the
10993 frame never becomes visible. XMonad does this.
10994 Prevent an endless loop. */
10995 if (FRAME_ICONIFIED_P (f) && ++tries > 100)
10996 break;
10998 /* This hack is still in use at least for Cygwin. See
10999 http://lists.gnu.org/archive/html/emacs-devel/2013-12/msg00351.html.
11001 Machines that do polling rather than SIGIO have been
11002 observed to go into a busy-wait here. So we'll fake an
11003 alarm signal to let the handler know that there's something
11004 to be read. We used to raise a real alarm, but it seems
11005 that the handler isn't always enabled here. This is
11006 probably a bug. */
11007 if (input_polling_used ())
11009 /* It could be confusing if a real alarm arrives while
11010 processing the fake one. Turn it off and let the
11011 handler reset it. */
11012 int old_poll_suppress_count = poll_suppress_count;
11013 poll_suppress_count = 1;
11014 poll_for_input_1 ();
11015 poll_suppress_count = old_poll_suppress_count;
11018 if (XPending (FRAME_X_DISPLAY (f)))
11020 XEvent xev;
11021 XNextEvent (FRAME_X_DISPLAY (f), &xev);
11022 x_dispatch_event (&xev, FRAME_X_DISPLAY (f));
11028 /* Change from mapped state to withdrawn state. */
11030 /* Make the frame visible (mapped and not iconified). */
11032 void
11033 x_make_frame_invisible (struct frame *f)
11035 Window window;
11037 /* Use the frame's outermost window, not the one we normally draw on. */
11038 window = FRAME_OUTER_WINDOW (f);
11040 /* Don't keep the highlight on an invisible frame. */
11041 if (FRAME_DISPLAY_INFO (f)->x_highlight_frame == f)
11042 FRAME_DISPLAY_INFO (f)->x_highlight_frame = 0;
11044 block_input ();
11046 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
11047 that the current position of the window is user-specified, rather than
11048 program-specified, so that when the window is mapped again, it will be
11049 placed at the same location, without forcing the user to position it
11050 by hand again (they have already done that once for this window.) */
11051 x_wm_set_size_hint (f, 0, true);
11053 #ifdef USE_GTK
11054 if (FRAME_GTK_OUTER_WIDGET (f))
11055 gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f));
11056 else
11057 #else
11058 if (FRAME_X_EMBEDDED_P (f))
11059 xembed_set_info (f, 0);
11060 else
11061 #endif
11064 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
11065 DefaultScreen (FRAME_X_DISPLAY (f))))
11067 unblock_input ();
11068 error ("Can't notify window manager of window withdrawal");
11072 /* We can't distinguish this from iconification
11073 just by the event that we get from the server.
11074 So we can't win using the usual strategy of letting
11075 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
11076 and synchronize with the server to make sure we agree. */
11077 SET_FRAME_VISIBLE (f, 0);
11078 SET_FRAME_ICONIFIED (f, false);
11080 x_sync (f);
11082 unblock_input ();
11085 /* Change window state from mapped to iconified. */
11087 void
11088 x_iconify_frame (struct frame *f)
11090 #ifdef USE_X_TOOLKIT
11091 int result;
11092 #endif
11094 /* Don't keep the highlight on an invisible frame. */
11095 if (FRAME_DISPLAY_INFO (f)->x_highlight_frame == f)
11096 FRAME_DISPLAY_INFO (f)->x_highlight_frame = 0;
11098 if (FRAME_ICONIFIED_P (f))
11099 return;
11101 block_input ();
11103 x_set_bitmap_icon (f);
11105 #if defined (USE_GTK)
11106 if (FRAME_GTK_OUTER_WIDGET (f))
11108 if (! FRAME_VISIBLE_P (f))
11109 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
11111 gtk_window_iconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
11112 SET_FRAME_VISIBLE (f, 0);
11113 SET_FRAME_ICONIFIED (f, true);
11114 unblock_input ();
11115 return;
11117 #endif
11119 #ifdef USE_X_TOOLKIT
11121 if (! FRAME_VISIBLE_P (f))
11123 if (! EQ (Vx_no_window_manager, Qt))
11124 x_wm_set_window_state (f, IconicState);
11125 /* This was XtPopup, but that did nothing for an iconified frame. */
11126 XtMapWidget (f->output_data.x->widget);
11127 /* The server won't give us any event to indicate
11128 that an invisible frame was changed to an icon,
11129 so we have to record it here. */
11130 SET_FRAME_VISIBLE (f, 0);
11131 SET_FRAME_ICONIFIED (f, true);
11132 unblock_input ();
11133 return;
11136 result = XIconifyWindow (FRAME_X_DISPLAY (f),
11137 XtWindow (f->output_data.x->widget),
11138 DefaultScreen (FRAME_X_DISPLAY (f)));
11139 unblock_input ();
11141 if (!result)
11142 error ("Can't notify window manager of iconification");
11144 SET_FRAME_ICONIFIED (f, true);
11145 SET_FRAME_VISIBLE (f, 0);
11147 block_input ();
11148 XFlush (FRAME_X_DISPLAY (f));
11149 unblock_input ();
11150 #else /* not USE_X_TOOLKIT */
11152 /* Make sure the X server knows where the window should be positioned,
11153 in case the user deiconifies with the window manager. */
11154 if (! FRAME_VISIBLE_P (f)
11155 && ! FRAME_ICONIFIED_P (f)
11156 && ! FRAME_X_EMBEDDED_P (f))
11157 x_set_offset (f, f->left_pos, f->top_pos, 0);
11159 /* Since we don't know which revision of X we're running, we'll use both
11160 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
11162 /* X11R4: send a ClientMessage to the window manager using the
11163 WM_CHANGE_STATE type. */
11165 XEvent msg;
11167 msg.xclient.window = FRAME_X_WINDOW (f);
11168 msg.xclient.type = ClientMessage;
11169 msg.xclient.message_type = FRAME_DISPLAY_INFO (f)->Xatom_wm_change_state;
11170 msg.xclient.format = 32;
11171 msg.xclient.data.l[0] = IconicState;
11173 if (! XSendEvent (FRAME_X_DISPLAY (f),
11174 DefaultRootWindow (FRAME_X_DISPLAY (f)),
11175 False,
11176 SubstructureRedirectMask | SubstructureNotifyMask,
11177 &msg))
11179 unblock_input ();
11180 error ("Can't notify window manager of iconification");
11184 /* X11R3: set the initial_state field of the window manager hints to
11185 IconicState. */
11186 x_wm_set_window_state (f, IconicState);
11188 if (!FRAME_VISIBLE_P (f))
11190 /* If the frame was withdrawn, before, we must map it. */
11191 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11194 SET_FRAME_ICONIFIED (f, true);
11195 SET_FRAME_VISIBLE (f, 0);
11197 XFlush (FRAME_X_DISPLAY (f));
11198 unblock_input ();
11199 #endif /* not USE_X_TOOLKIT */
11203 /* Free X resources of frame F. */
11205 void
11206 x_free_frame_resources (struct frame *f)
11208 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
11209 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
11210 #ifdef USE_X_TOOLKIT
11211 Lisp_Object bar;
11212 struct scroll_bar *b;
11213 #endif
11215 block_input ();
11217 /* If a display connection is dead, don't try sending more
11218 commands to the X server. */
11219 if (dpyinfo->display)
11221 /* Always exit with visible pointer to avoid weird issue
11222 with Xfixes (Bug#17609). */
11223 if (f->pointer_invisible)
11224 FRAME_DISPLAY_INFO (f)->toggle_visible_pointer (f, 0);
11226 /* We must free faces before destroying windows because some
11227 font-driver (e.g. xft) access a window while finishing a
11228 face. */
11229 free_frame_faces (f);
11231 if (f->output_data.x->icon_desc)
11232 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
11234 #ifdef USE_X_TOOLKIT
11235 /* Explicitly destroy the scroll bars of the frame. Without
11236 this, we get "BadDrawable" errors from the toolkit later on,
11237 presumably from expose events generated for the disappearing
11238 toolkit scroll bars. */
11239 for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
11241 b = XSCROLL_BAR (bar);
11242 x_scroll_bar_remove (b);
11244 #endif
11246 #ifdef HAVE_X_I18N
11247 if (FRAME_XIC (f))
11248 free_frame_xic (f);
11249 #endif
11251 x_free_cr_resources (f);
11252 #ifdef USE_X_TOOLKIT
11253 if (f->output_data.x->widget)
11255 XtDestroyWidget (f->output_data.x->widget);
11256 f->output_data.x->widget = NULL;
11258 /* Tooltips don't have widgets, only a simple X window, even if
11259 we are using a toolkit. */
11260 else if (FRAME_X_WINDOW (f))
11261 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11263 free_frame_menubar (f);
11265 if (f->shell_position)
11266 xfree (f->shell_position);
11267 #else /* !USE_X_TOOLKIT */
11269 #ifdef USE_GTK
11270 xg_free_frame_widgets (f);
11271 #endif /* USE_GTK */
11273 if (FRAME_X_WINDOW (f))
11274 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11275 #endif /* !USE_X_TOOLKIT */
11277 unload_color (f, FRAME_FOREGROUND_PIXEL (f));
11278 unload_color (f, FRAME_BACKGROUND_PIXEL (f));
11279 unload_color (f, f->output_data.x->cursor_pixel);
11280 unload_color (f, f->output_data.x->cursor_foreground_pixel);
11281 unload_color (f, f->output_data.x->border_pixel);
11282 unload_color (f, f->output_data.x->mouse_pixel);
11284 if (f->output_data.x->scroll_bar_background_pixel != -1)
11285 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
11286 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
11287 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
11288 #if defined (USE_LUCID) && defined (USE_TOOLKIT_SCROLL_BARS)
11289 /* Scrollbar shadow colors. */
11290 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
11291 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
11292 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
11293 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
11294 #endif /* USE_LUCID && USE_TOOLKIT_SCROLL_BARS */
11295 if (f->output_data.x->white_relief.pixel != -1)
11296 unload_color (f, f->output_data.x->white_relief.pixel);
11297 if (f->output_data.x->black_relief.pixel != -1)
11298 unload_color (f, f->output_data.x->black_relief.pixel);
11300 x_free_gcs (f);
11302 /* Free extra GCs allocated by x_setup_relief_colors. */
11303 if (f->output_data.x->white_relief.gc)
11305 XFreeGC (dpyinfo->display, f->output_data.x->white_relief.gc);
11306 f->output_data.x->white_relief.gc = 0;
11308 if (f->output_data.x->black_relief.gc)
11310 XFreeGC (dpyinfo->display, f->output_data.x->black_relief.gc);
11311 f->output_data.x->black_relief.gc = 0;
11314 /* Free cursors. */
11315 if (f->output_data.x->text_cursor != 0)
11316 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->text_cursor);
11317 if (f->output_data.x->nontext_cursor != 0)
11318 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->nontext_cursor);
11319 if (f->output_data.x->modeline_cursor != 0)
11320 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->modeline_cursor);
11321 if (f->output_data.x->hand_cursor != 0)
11322 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->hand_cursor);
11323 if (f->output_data.x->hourglass_cursor != 0)
11324 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->hourglass_cursor);
11325 if (f->output_data.x->horizontal_drag_cursor != 0)
11326 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->horizontal_drag_cursor);
11327 if (f->output_data.x->vertical_drag_cursor != 0)
11328 XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->vertical_drag_cursor);
11330 XFlush (FRAME_X_DISPLAY (f));
11333 xfree (f->output_data.x->saved_menu_event);
11334 xfree (f->output_data.x);
11335 f->output_data.x = NULL;
11337 if (f == dpyinfo->x_focus_frame)
11338 dpyinfo->x_focus_frame = 0;
11339 if (f == dpyinfo->x_focus_event_frame)
11340 dpyinfo->x_focus_event_frame = 0;
11341 if (f == dpyinfo->x_highlight_frame)
11342 dpyinfo->x_highlight_frame = 0;
11343 if (f == hlinfo->mouse_face_mouse_frame)
11344 reset_mouse_highlight (hlinfo);
11346 unblock_input ();
11350 /* Destroy the X window of frame F. */
11352 static void
11353 x_destroy_window (struct frame *f)
11355 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
11357 /* If a display connection is dead, don't try sending more
11358 commands to the X server. */
11359 if (dpyinfo->display != 0)
11360 x_free_frame_resources (f);
11362 dpyinfo->reference_count--;
11366 /* Setting window manager hints. */
11368 /* Set the normal size hints for the window manager, for frame F.
11369 FLAGS is the flags word to use--or 0 meaning preserve the flags
11370 that the window now has.
11371 If USER_POSITION, set the USPosition
11372 flag (this is useful when FLAGS is 0).
11373 The GTK version is in gtkutils.c. */
11375 #ifndef USE_GTK
11376 void
11377 x_wm_set_size_hint (struct frame *f, long flags, bool user_position)
11379 XSizeHints size_hints;
11380 Window window = FRAME_OUTER_WINDOW (f);
11382 if (!window)
11383 return;
11385 #ifdef USE_X_TOOLKIT
11386 if (f->output_data.x->widget)
11388 widget_update_wm_size_hints (f->output_data.x->widget);
11389 return;
11391 #endif
11393 /* Setting PMaxSize caused various problems. */
11394 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
11396 size_hints.x = f->left_pos;
11397 size_hints.y = f->top_pos;
11399 size_hints.width = FRAME_PIXEL_WIDTH (f);
11400 size_hints.height = FRAME_PIXEL_HEIGHT (f);
11402 size_hints.width_inc = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
11403 size_hints.height_inc = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
11405 size_hints.max_width = x_display_pixel_width (FRAME_DISPLAY_INFO (f))
11406 - FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
11407 size_hints.max_height = x_display_pixel_height (FRAME_DISPLAY_INFO (f))
11408 - FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
11410 /* Calculate the base and minimum sizes. */
11412 int base_width, base_height;
11414 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
11415 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
11417 /* The window manager uses the base width hints to calculate the
11418 current number of rows and columns in the frame while
11419 resizing; min_width and min_height aren't useful for this
11420 purpose, since they might not give the dimensions for a
11421 zero-row, zero-column frame. */
11423 size_hints.flags |= PBaseSize;
11424 size_hints.base_width = base_width;
11425 size_hints.base_height = base_height + FRAME_MENUBAR_HEIGHT (f);
11426 size_hints.min_width = base_width;
11427 size_hints.min_height = base_height;
11430 /* If we don't need the old flags, we don't need the old hint at all. */
11431 if (flags)
11433 size_hints.flags |= flags;
11434 goto no_read;
11438 XSizeHints hints; /* Sometimes I hate X Windows... */
11439 long supplied_return;
11440 int value;
11442 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
11443 &supplied_return);
11445 if (flags)
11446 size_hints.flags |= flags;
11447 else
11449 if (value == 0)
11450 hints.flags = 0;
11451 if (hints.flags & PSize)
11452 size_hints.flags |= PSize;
11453 if (hints.flags & PPosition)
11454 size_hints.flags |= PPosition;
11455 if (hints.flags & USPosition)
11456 size_hints.flags |= USPosition;
11457 if (hints.flags & USSize)
11458 size_hints.flags |= USSize;
11462 no_read:
11464 #ifdef PWinGravity
11465 size_hints.win_gravity = f->win_gravity;
11466 size_hints.flags |= PWinGravity;
11468 if (user_position)
11470 size_hints.flags &= ~ PPosition;
11471 size_hints.flags |= USPosition;
11473 #endif /* PWinGravity */
11475 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
11477 #endif /* not USE_GTK */
11479 /* Used for IconicState or NormalState */
11481 static void
11482 x_wm_set_window_state (struct frame *f, int state)
11484 #ifdef USE_X_TOOLKIT
11485 Arg al[1];
11487 XtSetArg (al[0], XtNinitialState, state);
11488 XtSetValues (f->output_data.x->widget, al, 1);
11489 #else /* not USE_X_TOOLKIT */
11490 Window window = FRAME_X_WINDOW (f);
11492 f->output_data.x->wm_hints.flags |= StateHint;
11493 f->output_data.x->wm_hints.initial_state = state;
11495 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
11496 #endif /* not USE_X_TOOLKIT */
11499 static void
11500 x_wm_set_icon_pixmap (struct frame *f, ptrdiff_t pixmap_id)
11502 Pixmap icon_pixmap, icon_mask;
11504 #if !defined USE_X_TOOLKIT && !defined USE_GTK
11505 Window window = FRAME_OUTER_WINDOW (f);
11506 #endif
11508 if (pixmap_id > 0)
11510 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
11511 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
11512 icon_mask = x_bitmap_mask (f, pixmap_id);
11513 f->output_data.x->wm_hints.icon_mask = icon_mask;
11515 else
11517 /* It seems there is no way to turn off use of an icon
11518 pixmap. */
11519 return;
11523 #ifdef USE_GTK
11525 xg_set_frame_icon (f, icon_pixmap, icon_mask);
11526 return;
11529 #elif defined (USE_X_TOOLKIT) /* same as in x_wm_set_window_state. */
11532 Arg al[1];
11533 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
11534 XtSetValues (f->output_data.x->widget, al, 1);
11535 XtSetArg (al[0], XtNiconMask, icon_mask);
11536 XtSetValues (f->output_data.x->widget, al, 1);
11539 #else /* not USE_X_TOOLKIT && not USE_GTK */
11541 f->output_data.x->wm_hints.flags |= (IconPixmapHint | IconMaskHint);
11542 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
11544 #endif /* not USE_X_TOOLKIT && not USE_GTK */
11547 void
11548 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
11550 Window window = FRAME_OUTER_WINDOW (f);
11552 f->output_data.x->wm_hints.flags |= IconPositionHint;
11553 f->output_data.x->wm_hints.icon_x = icon_x;
11554 f->output_data.x->wm_hints.icon_y = icon_y;
11556 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
11560 /***********************************************************************
11561 Fonts
11562 ***********************************************************************/
11564 #ifdef GLYPH_DEBUG
11566 /* Check that FONT is valid on frame F. It is if it can be found in F's
11567 font table. */
11569 static void
11570 x_check_font (struct frame *f, struct font *font)
11572 eassert (font != NULL && ! NILP (font->props[FONT_TYPE_INDEX]));
11573 if (font->driver->check)
11574 eassert (font->driver->check (f, font) == 0);
11577 #endif /* GLYPH_DEBUG */
11580 /***********************************************************************
11581 Initialization
11582 ***********************************************************************/
11584 #ifdef USE_X_TOOLKIT
11585 static XrmOptionDescRec emacs_options[] = {
11586 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
11587 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
11589 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
11590 XrmoptionSepArg, NULL},
11591 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
11593 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
11594 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
11595 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
11596 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
11597 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
11598 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
11599 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
11602 /* Whether atimer for Xt timeouts is activated or not. */
11604 static bool x_timeout_atimer_activated_flag;
11606 #endif /* USE_X_TOOLKIT */
11608 static int x_initialized;
11610 /* Test whether two display-name strings agree up to the dot that separates
11611 the screen number from the server number. */
11612 static bool
11613 same_x_server (const char *name1, const char *name2)
11615 bool seen_colon = false;
11616 Lisp_Object sysname = Fsystem_name ();
11617 const char *system_name = SSDATA (sysname);
11618 ptrdiff_t system_name_length = SBYTES (sysname);
11619 ptrdiff_t length_until_period = 0;
11621 while (system_name[length_until_period] != 0
11622 && system_name[length_until_period] != '.')
11623 length_until_period++;
11625 /* Treat `unix' like an empty host name. */
11626 if (! strncmp (name1, "unix:", 5))
11627 name1 += 4;
11628 if (! strncmp (name2, "unix:", 5))
11629 name2 += 4;
11630 /* Treat this host's name like an empty host name. */
11631 if (! strncmp (name1, system_name, system_name_length)
11632 && name1[system_name_length] == ':')
11633 name1 += system_name_length;
11634 if (! strncmp (name2, system_name, system_name_length)
11635 && name2[system_name_length] == ':')
11636 name2 += system_name_length;
11637 /* Treat this host's domainless name like an empty host name. */
11638 if (! strncmp (name1, system_name, length_until_period)
11639 && name1[length_until_period] == ':')
11640 name1 += length_until_period;
11641 if (! strncmp (name2, system_name, length_until_period)
11642 && name2[length_until_period] == ':')
11643 name2 += length_until_period;
11645 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
11647 if (*name1 == ':')
11648 seen_colon = true;
11649 if (seen_colon && *name1 == '.')
11650 return true;
11652 return (seen_colon
11653 && (*name1 == '.' || *name1 == '\0')
11654 && (*name2 == '.' || *name2 == '\0'));
11657 /* Count number of set bits in mask and number of bits to shift to
11658 get to the first bit. With MASK 0x7e0, *BITS is set to 6, and *OFFSET
11659 to 5. */
11660 static void
11661 get_bits_and_offset (unsigned long mask, int *bits, int *offset)
11663 int nr = 0;
11664 int off = 0;
11666 while (!(mask & 1))
11668 off++;
11669 mask >>= 1;
11672 while (mask & 1)
11674 nr++;
11675 mask >>= 1;
11678 *offset = off;
11679 *bits = nr;
11682 /* Return true iff display DISPLAY is available for use.
11683 But don't permanently open it, just test its availability. */
11685 bool
11686 x_display_ok (const char *display)
11688 /* XOpenDisplay fails if it gets a signal. Block SIGIO which may arrive. */
11689 unrequest_sigio ();
11690 Display *dpy = XOpenDisplay (display);
11691 request_sigio ();
11692 if (!dpy)
11693 return false;
11694 XCloseDisplay (dpy);
11695 return true;
11698 #ifdef USE_GTK
11699 static void
11700 my_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
11701 const gchar *msg, gpointer user_data)
11703 if (!strstr (msg, "g_set_prgname"))
11704 fprintf (stderr, "%s-WARNING **: %s\n", log_domain, msg);
11706 #endif
11708 /* Create invisible cursor on X display referred by DPYINFO. */
11710 static Cursor
11711 make_invisible_cursor (struct x_display_info *dpyinfo)
11713 Display *dpy = dpyinfo->display;
11714 static char const no_data[] = { 0 };
11715 Pixmap pix;
11716 XColor col;
11717 Cursor c = 0;
11719 x_catch_errors (dpy);
11720 pix = XCreateBitmapFromData (dpy, dpyinfo->root_window, no_data, 1, 1);
11721 if (! x_had_errors_p (dpy) && pix != None)
11723 Cursor pixc;
11724 col.pixel = 0;
11725 col.red = col.green = col.blue = 0;
11726 col.flags = DoRed | DoGreen | DoBlue;
11727 pixc = XCreatePixmapCursor (dpy, pix, pix, &col, &col, 0, 0);
11728 if (! x_had_errors_p (dpy) && pixc != None)
11729 c = pixc;
11730 XFreePixmap (dpy, pix);
11733 x_uncatch_errors ();
11735 return c;
11738 /* True if DPY supports Xfixes extension >= 4. */
11740 static bool
11741 x_probe_xfixes_extension (Display *dpy)
11743 #ifdef HAVE_XFIXES
11744 int major, minor;
11745 return XFixesQueryVersion (dpy, &major, &minor) && major >= 4;
11746 #else
11747 return false;
11748 #endif /* HAVE_XFIXES */
11751 /* Toggle mouse pointer visibility on frame F by using Xfixes functions. */
11753 static void
11754 xfixes_toggle_visible_pointer (struct frame *f, bool invisible)
11756 #ifdef HAVE_XFIXES
11757 if (invisible)
11758 XFixesHideCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11759 else
11760 XFixesShowCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
11761 f->pointer_invisible = invisible;
11762 #else
11763 emacs_abort ();
11764 #endif /* HAVE_XFIXES */
11767 /* Toggle mouse pointer visibility on frame F by using invisible cursor. */
11769 static void
11770 x_toggle_visible_pointer (struct frame *f, bool invisible)
11772 eassert (FRAME_DISPLAY_INFO (f)->invisible_cursor != 0);
11773 if (invisible)
11774 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11775 FRAME_DISPLAY_INFO (f)->invisible_cursor);
11776 else
11777 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11778 f->output_data.x->current_cursor);
11779 f->pointer_invisible = invisible;
11782 /* Setup pointer blanking, prefer Xfixes if available. */
11784 static void
11785 x_setup_pointer_blanking (struct x_display_info *dpyinfo)
11787 /* FIXME: the brave tester should set EMACS_XFIXES because we're suspecting
11788 X server bug, see http://debbugs.gnu.org/cgi/bugreport.cgi?bug=17609. */
11789 if (egetenv ("EMACS_XFIXES") && x_probe_xfixes_extension (dpyinfo->display))
11790 dpyinfo->toggle_visible_pointer = xfixes_toggle_visible_pointer;
11791 else
11793 dpyinfo->toggle_visible_pointer = x_toggle_visible_pointer;
11794 dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo);
11798 /* Current X display connection identifier. Incremented for each next
11799 connection established. */
11800 static unsigned x_display_id;
11802 /* Open a connection to X display DISPLAY_NAME, and return
11803 the structure that describes the open display.
11804 If we cannot contact the display, return null. */
11806 struct x_display_info *
11807 x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
11809 Display *dpy;
11810 struct terminal *terminal;
11811 struct x_display_info *dpyinfo;
11812 XrmDatabase xrdb;
11813 #ifdef USE_XCB
11814 xcb_connection_t *xcb_conn;
11815 #endif
11817 block_input ();
11819 if (!x_initialized)
11821 x_initialize ();
11822 ++x_initialized;
11825 if (! x_display_ok (SSDATA (display_name)))
11826 error ("Display %s can't be opened", SSDATA (display_name));
11828 #ifdef USE_GTK
11830 #define NUM_ARGV 10
11831 int argc;
11832 char *argv[NUM_ARGV];
11833 char **argv2 = argv;
11834 guint id;
11836 if (x_initialized++ > 1)
11838 xg_display_open (SSDATA (display_name), &dpy);
11840 else
11842 static char display_opt[] = "--display";
11843 static char name_opt[] = "--name";
11845 for (argc = 0; argc < NUM_ARGV; ++argc)
11846 argv[argc] = 0;
11848 argc = 0;
11849 argv[argc++] = initial_argv[0];
11851 if (! NILP (display_name))
11853 argv[argc++] = display_opt;
11854 argv[argc++] = SSDATA (display_name);
11857 argv[argc++] = name_opt;
11858 argv[argc++] = resource_name;
11860 XSetLocaleModifiers ("");
11862 /* Work around GLib bug that outputs a faulty warning. See
11863 https://bugzilla.gnome.org/show_bug.cgi?id=563627. */
11864 id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
11865 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
11867 /* NULL window -> events for all windows go to our function.
11868 Call before gtk_init so Gtk+ event filters comes after our. */
11869 gdk_window_add_filter (NULL, event_handler_gdk, NULL);
11871 /* gtk_init does set_locale. Fix locale before and after. */
11872 fixup_locale ();
11873 unrequest_sigio (); /* See comment in x_display_ok. */
11874 gtk_init (&argc, &argv2);
11875 request_sigio ();
11876 fixup_locale ();
11878 g_log_remove_handler ("GLib", id);
11880 xg_initialize ();
11882 dpy = DEFAULT_GDK_DISPLAY ();
11884 #if ! GTK_CHECK_VERSION (2, 90, 0)
11885 /* Load our own gtkrc if it exists. */
11887 const char *file = "~/.emacs.d/gtkrc";
11888 Lisp_Object s, abs_file;
11890 s = build_string (file);
11891 abs_file = Fexpand_file_name (s, Qnil);
11893 if (! NILP (abs_file) && !NILP (Ffile_readable_p (abs_file)))
11894 gtk_rc_parse (SSDATA (abs_file));
11896 #endif
11898 XSetErrorHandler (x_error_handler);
11899 XSetIOErrorHandler (x_io_error_quitter);
11902 #else /* not USE_GTK */
11903 #ifdef USE_X_TOOLKIT
11904 /* weiner@footloose.sps.mot.com reports that this causes
11905 errors with X11R5:
11906 X protocol error: BadAtom (invalid Atom parameter)
11907 on protocol request 18skiloaf.
11908 So let's not use it until R6. */
11909 #ifdef HAVE_X11XTR6
11910 XtSetLanguageProc (NULL, NULL, NULL);
11911 #endif
11914 int argc = 0;
11915 char *argv[3];
11917 argv[0] = "";
11918 argc = 1;
11919 if (xrm_option)
11921 argv[argc++] = "-xrm";
11922 argv[argc++] = xrm_option;
11924 turn_on_atimers (false);
11925 unrequest_sigio (); /* See comment in x_display_ok. */
11926 dpy = XtOpenDisplay (Xt_app_con, SSDATA (display_name),
11927 resource_name, EMACS_CLASS,
11928 emacs_options, XtNumber (emacs_options),
11929 &argc, argv);
11930 request_sigio ();
11931 turn_on_atimers (true);
11933 #ifdef HAVE_X11XTR6
11934 /* I think this is to compensate for XtSetLanguageProc. */
11935 fixup_locale ();
11936 #endif
11939 #else /* not USE_X_TOOLKIT */
11940 XSetLocaleModifiers ("");
11941 unrequest_sigio (); // See comment in x_display_ok.
11942 dpy = XOpenDisplay (SSDATA (display_name));
11943 request_sigio ();
11944 #endif /* not USE_X_TOOLKIT */
11945 #endif /* not USE_GTK*/
11947 /* Detect failure. */
11948 if (dpy == 0)
11950 unblock_input ();
11951 return 0;
11954 #ifdef USE_XCB
11955 xcb_conn = XGetXCBConnection (dpy);
11956 if (xcb_conn == 0)
11958 #ifdef USE_GTK
11959 xg_display_close (dpy);
11960 #else
11961 #ifdef USE_X_TOOLKIT
11962 XtCloseDisplay (dpy);
11963 #else
11964 XCloseDisplay (dpy);
11965 #endif
11966 #endif /* ! USE_GTK */
11968 unblock_input ();
11969 return 0;
11971 #endif
11973 /* We have definitely succeeded. Record the new connection. */
11975 dpyinfo = xzalloc (sizeof *dpyinfo);
11976 terminal = x_create_terminal (dpyinfo);
11979 struct x_display_info *share;
11981 for (share = x_display_list; share; share = share->next)
11982 if (same_x_server (SSDATA (XCAR (share->name_list_element)),
11983 SSDATA (display_name)))
11984 break;
11985 if (share)
11986 terminal->kboard = share->terminal->kboard;
11987 else
11989 terminal->kboard = allocate_kboard (Qx);
11991 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
11993 char *vendor = ServerVendor (dpy);
11995 /* Temporarily hide the partially initialized terminal. */
11996 terminal_list = terminal->next_terminal;
11997 unblock_input ();
11998 kset_system_key_alist
11999 (terminal->kboard,
12000 call1 (Qvendor_specific_keysyms,
12001 vendor ? build_string (vendor) : empty_unibyte_string));
12002 block_input ();
12003 terminal->next_terminal = terminal_list;
12004 terminal_list = terminal;
12007 /* Don't let the initial kboard remain current longer than necessary.
12008 That would cause problems if a file loaded on startup tries to
12009 prompt in the mini-buffer. */
12010 if (current_kboard == initial_kboard)
12011 current_kboard = terminal->kboard;
12013 terminal->kboard->reference_count++;
12016 /* Put this display on the chain. */
12017 dpyinfo->next = x_display_list;
12018 x_display_list = dpyinfo;
12020 dpyinfo->name_list_element = Fcons (display_name, Qnil);
12021 dpyinfo->display = dpy;
12022 dpyinfo->connection = ConnectionNumber (dpyinfo->display);
12023 #ifdef USE_XCB
12024 dpyinfo->xcb_connection = xcb_conn;
12025 #endif
12027 /* http://lists.gnu.org/archive/html/emacs-devel/2015-11/msg00194.html */
12028 dpyinfo->smallest_font_height = 1;
12029 dpyinfo->smallest_char_width = 1;
12031 /* Set the name of the terminal. */
12032 terminal->name = xlispstrdup (display_name);
12034 #if false
12035 XSetAfterFunction (x_current_display, x_trace_wire);
12036 #endif
12038 Lisp_Object system_name = Fsystem_name ();
12039 ptrdiff_t nbytes;
12040 if (INT_ADD_WRAPV (SBYTES (Vinvocation_name), SBYTES (system_name) + 2,
12041 &nbytes))
12042 memory_full (SIZE_MAX);
12043 dpyinfo->x_id = ++x_display_id;
12044 dpyinfo->x_id_name = xmalloc (nbytes);
12045 char *nametail = lispstpcpy (dpyinfo->x_id_name, Vinvocation_name);
12046 *nametail++ = '@';
12047 lispstpcpy (nametail, system_name);
12049 /* Figure out which modifier bits mean what. */
12050 x_find_modifier_meanings (dpyinfo);
12052 /* Get the scroll bar cursor. */
12053 #ifdef USE_GTK
12054 /* We must create a GTK cursor, it is required for GTK widgets. */
12055 dpyinfo->xg_cursor = xg_create_default_cursor (dpyinfo->display);
12056 #endif /* USE_GTK */
12058 dpyinfo->vertical_scroll_bar_cursor
12059 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
12061 dpyinfo->horizontal_scroll_bar_cursor
12062 = XCreateFontCursor (dpyinfo->display, XC_sb_h_double_arrow);
12064 xrdb = x_load_resources (dpyinfo->display, xrm_option,
12065 resource_name, EMACS_CLASS);
12066 #ifdef HAVE_XRMSETDATABASE
12067 XrmSetDatabase (dpyinfo->display, xrdb);
12068 #else
12069 dpyinfo->display->db = xrdb;
12070 #endif
12071 /* Put the rdb where we can find it in a way that works on
12072 all versions. */
12073 dpyinfo->xrdb = xrdb;
12075 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
12076 DefaultScreen (dpyinfo->display));
12077 select_visual (dpyinfo);
12078 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
12079 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
12080 dpyinfo->icon_bitmap_id = -1;
12081 dpyinfo->wm_type = X_WMTYPE_UNKNOWN;
12083 reset_mouse_highlight (&dpyinfo->mouse_highlight);
12085 /* See if we can construct pixel values from RGB values. */
12086 if (dpyinfo->visual->class == TrueColor)
12088 get_bits_and_offset (dpyinfo->visual->red_mask,
12089 &dpyinfo->red_bits, &dpyinfo->red_offset);
12090 get_bits_and_offset (dpyinfo->visual->blue_mask,
12091 &dpyinfo->blue_bits, &dpyinfo->blue_offset);
12092 get_bits_and_offset (dpyinfo->visual->green_mask,
12093 &dpyinfo->green_bits, &dpyinfo->green_offset);
12096 /* See if a private colormap is requested. */
12097 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
12099 if (dpyinfo->visual->class == PseudoColor)
12101 AUTO_STRING (privateColormap, "privateColormap");
12102 AUTO_STRING (PrivateColormap, "PrivateColormap");
12103 Lisp_Object value
12104 = display_x_get_resource (dpyinfo, privateColormap,
12105 PrivateColormap, Qnil, Qnil);
12106 if (STRINGP (value)
12107 && (!strcmp (SSDATA (value), "true")
12108 || !strcmp (SSDATA (value), "on")))
12109 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
12112 else
12113 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
12114 dpyinfo->visual, AllocNone);
12116 #ifdef HAVE_XFT
12118 /* If we are using Xft, the following precautions should be made:
12120 1. Make sure that the Xrender extension is added before the Xft one.
12121 Otherwise, the close-display hook set by Xft is called after the one
12122 for Xrender, and the former tries to re-add the latter. This results
12123 in inconsistency of internal states and leads to X protocol error when
12124 one reconnects to the same X server (Bug#1696).
12126 2. Check dpi value in X resources. It is better we use it as well,
12127 since Xft will use it, as will all Gnome applications. If our real DPI
12128 is smaller or larger than the one Xft uses, our font will look smaller
12129 or larger than other for other applications, even if it is the same
12130 font name (monospace-10 for example). */
12132 int event_base, error_base;
12133 char *v;
12134 double d;
12136 XRenderQueryExtension (dpyinfo->display, &event_base, &error_base);
12138 v = XGetDefault (dpyinfo->display, "Xft", "dpi");
12139 if (v != NULL && sscanf (v, "%lf", &d) == 1)
12140 dpyinfo->resy = dpyinfo->resx = d;
12142 #endif
12144 if (dpyinfo->resy < 1)
12146 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
12147 double pixels = DisplayHeight (dpyinfo->display, screen_number);
12148 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
12149 /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
12150 dpyinfo->resy = (mm < 1) ? 100 : pixels * 25.4 / mm;
12151 pixels = DisplayWidth (dpyinfo->display, screen_number);
12152 mm = DisplayWidthMM (dpyinfo->display, screen_number);
12153 /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
12154 dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm;
12158 static const struct
12160 const char *name;
12161 int offset;
12162 } atom_refs[] = {
12163 #define ATOM_REFS_INIT(string, member) \
12164 { string, offsetof (struct x_display_info, member) },
12165 ATOM_REFS_INIT ("WM_PROTOCOLS", Xatom_wm_protocols)
12166 ATOM_REFS_INIT ("WM_TAKE_FOCUS", Xatom_wm_take_focus)
12167 ATOM_REFS_INIT ("WM_SAVE_YOURSELF", Xatom_wm_save_yourself)
12168 ATOM_REFS_INIT ("WM_DELETE_WINDOW", Xatom_wm_delete_window)
12169 ATOM_REFS_INIT ("WM_CHANGE_STATE", Xatom_wm_change_state)
12170 ATOM_REFS_INIT ("WM_CONFIGURE_DENIED", Xatom_wm_configure_denied)
12171 ATOM_REFS_INIT ("WM_MOVED", Xatom_wm_window_moved)
12172 ATOM_REFS_INIT ("WM_CLIENT_LEADER", Xatom_wm_client_leader)
12173 ATOM_REFS_INIT ("Editres", Xatom_editres)
12174 ATOM_REFS_INIT ("CLIPBOARD", Xatom_CLIPBOARD)
12175 ATOM_REFS_INIT ("TIMESTAMP", Xatom_TIMESTAMP)
12176 ATOM_REFS_INIT ("TEXT", Xatom_TEXT)
12177 ATOM_REFS_INIT ("COMPOUND_TEXT", Xatom_COMPOUND_TEXT)
12178 ATOM_REFS_INIT ("UTF8_STRING", Xatom_UTF8_STRING)
12179 ATOM_REFS_INIT ("DELETE", Xatom_DELETE)
12180 ATOM_REFS_INIT ("MULTIPLE", Xatom_MULTIPLE)
12181 ATOM_REFS_INIT ("INCR", Xatom_INCR)
12182 ATOM_REFS_INIT ("_EMACS_TMP_", Xatom_EMACS_TMP)
12183 ATOM_REFS_INIT ("TARGETS", Xatom_TARGETS)
12184 ATOM_REFS_INIT ("NULL", Xatom_NULL)
12185 ATOM_REFS_INIT ("ATOM", Xatom_ATOM)
12186 ATOM_REFS_INIT ("ATOM_PAIR", Xatom_ATOM_PAIR)
12187 ATOM_REFS_INIT ("CLIPBOARD_MANAGER", Xatom_CLIPBOARD_MANAGER)
12188 ATOM_REFS_INIT ("_XEMBED_INFO", Xatom_XEMBED_INFO)
12189 /* For properties of font. */
12190 ATOM_REFS_INIT ("PIXEL_SIZE", Xatom_PIXEL_SIZE)
12191 ATOM_REFS_INIT ("AVERAGE_WIDTH", Xatom_AVERAGE_WIDTH)
12192 ATOM_REFS_INIT ("_MULE_BASELINE_OFFSET", Xatom_MULE_BASELINE_OFFSET)
12193 ATOM_REFS_INIT ("_MULE_RELATIVE_COMPOSE", Xatom_MULE_RELATIVE_COMPOSE)
12194 ATOM_REFS_INIT ("_MULE_DEFAULT_ASCENT", Xatom_MULE_DEFAULT_ASCENT)
12195 /* Ghostscript support. */
12196 ATOM_REFS_INIT ("DONE", Xatom_DONE)
12197 ATOM_REFS_INIT ("PAGE", Xatom_PAGE)
12198 ATOM_REFS_INIT ("SCROLLBAR", Xatom_Scrollbar)
12199 ATOM_REFS_INIT ("HORIZONTAL_SCROLLBAR", Xatom_Horizontal_Scrollbar)
12200 ATOM_REFS_INIT ("_XEMBED", Xatom_XEMBED)
12201 /* EWMH */
12202 ATOM_REFS_INIT ("_NET_WM_STATE", Xatom_net_wm_state)
12203 ATOM_REFS_INIT ("_NET_WM_STATE_FULLSCREEN", Xatom_net_wm_state_fullscreen)
12204 ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_HORZ",
12205 Xatom_net_wm_state_maximized_horz)
12206 ATOM_REFS_INIT ("_NET_WM_STATE_MAXIMIZED_VERT",
12207 Xatom_net_wm_state_maximized_vert)
12208 ATOM_REFS_INIT ("_NET_WM_STATE_STICKY", Xatom_net_wm_state_sticky)
12209 ATOM_REFS_INIT ("_NET_WM_STATE_HIDDEN", Xatom_net_wm_state_hidden)
12210 ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE", Xatom_net_window_type)
12211 ATOM_REFS_INIT ("_NET_WM_WINDOW_TYPE_TOOLTIP",
12212 Xatom_net_window_type_tooltip)
12213 ATOM_REFS_INIT ("_NET_WM_ICON_NAME", Xatom_net_wm_icon_name)
12214 ATOM_REFS_INIT ("_NET_WM_NAME", Xatom_net_wm_name)
12215 ATOM_REFS_INIT ("_NET_SUPPORTED", Xatom_net_supported)
12216 ATOM_REFS_INIT ("_NET_SUPPORTING_WM_CHECK", Xatom_net_supporting_wm_check)
12217 ATOM_REFS_INIT ("_NET_WM_WINDOW_OPACITY", Xatom_net_wm_window_opacity)
12218 ATOM_REFS_INIT ("_NET_ACTIVE_WINDOW", Xatom_net_active_window)
12219 ATOM_REFS_INIT ("_NET_FRAME_EXTENTS", Xatom_net_frame_extents)
12220 ATOM_REFS_INIT ("_NET_CURRENT_DESKTOP", Xatom_net_current_desktop)
12221 ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea)
12222 /* Session management */
12223 ATOM_REFS_INIT ("SM_CLIENT_ID", Xatom_SM_CLIENT_ID)
12224 ATOM_REFS_INIT ("_XSETTINGS_SETTINGS", Xatom_xsettings_prop)
12225 ATOM_REFS_INIT ("MANAGER", Xatom_xsettings_mgr)
12228 int i;
12229 enum { atom_count = ARRAYELTS (atom_refs) };
12230 /* 1 for _XSETTINGS_SN. */
12231 enum { total_atom_count = 1 + atom_count };
12232 Atom atoms_return[total_atom_count];
12233 char *atom_names[total_atom_count];
12234 static char const xsettings_fmt[] = "_XSETTINGS_S%d";
12235 char xsettings_atom_name[sizeof xsettings_fmt - 2
12236 + INT_STRLEN_BOUND (int)];
12238 for (i = 0; i < atom_count; i++)
12239 atom_names[i] = (char *) atom_refs[i].name;
12241 /* Build _XSETTINGS_SN atom name. */
12242 sprintf (xsettings_atom_name, xsettings_fmt,
12243 XScreenNumberOfScreen (dpyinfo->screen));
12244 atom_names[i] = xsettings_atom_name;
12246 XInternAtoms (dpyinfo->display, atom_names, total_atom_count,
12247 False, atoms_return);
12249 for (i = 0; i < atom_count; i++)
12250 *(Atom *) ((char *) dpyinfo + atom_refs[i].offset) = atoms_return[i];
12252 /* Manually copy last atom. */
12253 dpyinfo->Xatom_xsettings_sel = atoms_return[i];
12256 dpyinfo->x_dnd_atoms_size = 8;
12257 dpyinfo->x_dnd_atoms = xmalloc (sizeof *dpyinfo->x_dnd_atoms
12258 * dpyinfo->x_dnd_atoms_size);
12259 dpyinfo->gray
12260 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
12261 gray_bits, gray_width, gray_height,
12262 1, 0, 1);
12264 x_setup_pointer_blanking (dpyinfo);
12266 #ifdef HAVE_X_I18N
12267 xim_initialize (dpyinfo, resource_name);
12268 #endif
12270 xsettings_initialize (dpyinfo);
12272 /* This is only needed for distinguishing keyboard and process input. */
12273 if (dpyinfo->connection != 0)
12274 add_keyboard_wait_descriptor (dpyinfo->connection);
12276 #ifdef F_SETOWN
12277 fcntl (dpyinfo->connection, F_SETOWN, getpid ());
12278 #endif /* ! defined (F_SETOWN) */
12280 if (interrupt_input)
12281 init_sigio (dpyinfo->connection);
12283 #ifdef USE_LUCID
12285 XrmValue d, fr, to;
12286 Font font;
12288 dpy = dpyinfo->display;
12289 d.addr = (XPointer)&dpy;
12290 d.size = sizeof (Display *);
12291 fr.addr = XtDefaultFont;
12292 fr.size = sizeof (XtDefaultFont);
12293 to.size = sizeof (Font *);
12294 to.addr = (XPointer)&font;
12295 x_catch_errors (dpy);
12296 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
12297 emacs_abort ();
12298 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
12299 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
12300 /* Do not free XFontStruct returned by the above call to XQueryFont.
12301 This leads to X protocol errors at XtCloseDisplay (Bug#18403). */
12302 x_uncatch_errors ();
12304 #endif
12306 /* See if we should run in synchronous mode. This is useful
12307 for debugging X code. */
12309 AUTO_STRING (synchronous, "synchronous");
12310 AUTO_STRING (Synchronous, "Synchronous");
12311 Lisp_Object value = display_x_get_resource (dpyinfo, synchronous,
12312 Synchronous, Qnil, Qnil);
12313 if (STRINGP (value)
12314 && (!strcmp (SSDATA (value), "true")
12315 || !strcmp (SSDATA (value), "on")))
12316 XSynchronize (dpyinfo->display, True);
12320 AUTO_STRING (useXIM, "useXIM");
12321 AUTO_STRING (UseXIM, "UseXIM");
12322 Lisp_Object value = display_x_get_resource (dpyinfo, useXIM, UseXIM,
12323 Qnil, Qnil);
12324 #ifdef USE_XIM
12325 if (STRINGP (value)
12326 && (!strcmp (SSDATA (value), "false")
12327 || !strcmp (SSDATA (value), "off")))
12328 use_xim = false;
12329 #else
12330 if (STRINGP (value)
12331 && (!strcmp (SSDATA (value), "true")
12332 || !strcmp (SSDATA (value), "on")))
12333 use_xim = true;
12334 #endif
12337 #ifdef HAVE_X_SM
12338 /* Only do this for the very first display in the Emacs session.
12339 Ignore X session management when Emacs was first started on a
12340 tty or started as a daemon. */
12341 if (terminal->id == 1 && ! IS_DAEMON)
12342 x_session_initialize (dpyinfo);
12343 #endif
12345 #ifdef USE_CAIRO
12346 x_extension_initialize (dpyinfo);
12347 #endif
12349 unblock_input ();
12351 return dpyinfo;
12354 /* Get rid of display DPYINFO, deleting all frames on it,
12355 and without sending any more commands to the X server. */
12357 static void
12358 x_delete_display (struct x_display_info *dpyinfo)
12360 struct terminal *t;
12361 struct color_name_cache_entry *color_entry, *next_color_entry;
12363 /* Close all frames and delete the generic struct terminal for this
12364 X display. */
12365 for (t = terminal_list; t; t = t->next_terminal)
12366 if (t->type == output_x_window && t->display_info.x == dpyinfo)
12368 #ifdef HAVE_X_SM
12369 /* Close X session management when we close its display. */
12370 if (t->id == 1 && x_session_have_connection ())
12371 x_session_close ();
12372 #endif
12373 delete_terminal (t);
12374 break;
12377 if (next_noop_dpyinfo == dpyinfo)
12378 next_noop_dpyinfo = dpyinfo->next;
12380 if (x_display_list == dpyinfo)
12381 x_display_list = dpyinfo->next;
12382 else
12384 struct x_display_info *tail;
12386 for (tail = x_display_list; tail; tail = tail->next)
12387 if (tail->next == dpyinfo)
12388 tail->next = tail->next->next;
12391 for (color_entry = dpyinfo->color_names;
12392 color_entry;
12393 color_entry = next_color_entry)
12395 next_color_entry = color_entry->next;
12396 xfree (color_entry->name);
12397 xfree (color_entry);
12400 xfree (dpyinfo->x_id_name);
12401 xfree (dpyinfo->x_dnd_atoms);
12402 xfree (dpyinfo->color_cells);
12403 xfree (dpyinfo);
12406 #ifdef USE_X_TOOLKIT
12408 /* Atimer callback function for TIMER. Called every 0.1s to process
12409 Xt timeouts, if needed. We must avoid calling XtAppPending as
12410 much as possible because that function does an implicit XFlush
12411 that slows us down. */
12413 static void
12414 x_process_timeouts (struct atimer *timer)
12416 block_input ();
12417 x_timeout_atimer_activated_flag = false;
12418 if (toolkit_scroll_bar_interaction || popup_activated ())
12420 while (XtAppPending (Xt_app_con) & XtIMTimer)
12421 XtAppProcessEvent (Xt_app_con, XtIMTimer);
12422 /* Reactivate the atimer for next time. */
12423 x_activate_timeout_atimer ();
12425 unblock_input ();
12428 /* Install an asynchronous timer that processes Xt timeout events
12429 every 0.1s as long as either `toolkit_scroll_bar_interaction' or
12430 `popup_activated_flag' (in xmenu.c) is set. Make sure to call this
12431 function whenever these variables are set. This is necessary
12432 because some widget sets use timeouts internally, for example the
12433 LessTif menu bar, or the Xaw3d scroll bar. When Xt timeouts aren't
12434 processed, these widgets don't behave normally. */
12436 void
12437 x_activate_timeout_atimer (void)
12439 block_input ();
12440 if (!x_timeout_atimer_activated_flag)
12442 struct timespec interval = make_timespec (0, 100 * 1000 * 1000);
12443 start_atimer (ATIMER_RELATIVE, interval, x_process_timeouts, 0);
12444 x_timeout_atimer_activated_flag = true;
12446 unblock_input ();
12449 #endif /* USE_X_TOOLKIT */
12452 /* Set up use of X before we make the first connection. */
12454 static struct redisplay_interface x_redisplay_interface =
12456 x_frame_parm_handlers,
12457 x_produce_glyphs,
12458 x_write_glyphs,
12459 x_insert_glyphs,
12460 x_clear_end_of_line,
12461 x_scroll_run,
12462 x_after_update_window_line,
12463 x_update_window_begin,
12464 x_update_window_end,
12465 x_flush,
12466 x_clear_window_mouse_face,
12467 x_get_glyph_overhangs,
12468 x_fix_overlapping_area,
12469 x_draw_fringe_bitmap,
12470 #ifdef USE_CAIRO
12471 x_cr_define_fringe_bitmap,
12472 x_cr_destroy_fringe_bitmap,
12473 #else
12474 0, /* define_fringe_bitmap */
12475 0, /* destroy_fringe_bitmap */
12476 #endif
12477 x_compute_glyph_string_overhangs,
12478 x_draw_glyph_string,
12479 x_define_frame_cursor,
12480 x_clear_frame_area,
12481 x_draw_window_cursor,
12482 x_draw_vertical_window_border,
12483 x_draw_window_divider,
12484 x_shift_glyphs_for_insert, /* Never called; see comment in function. */
12485 x_show_hourglass,
12486 x_hide_hourglass
12490 /* This function is called when the last frame on a display is deleted. */
12491 void
12492 x_delete_terminal (struct terminal *terminal)
12494 struct x_display_info *dpyinfo = terminal->display_info.x;
12496 /* Protect against recursive calls. delete_frame in
12497 delete_terminal calls us back when it deletes our last frame. */
12498 if (!terminal->name)
12499 return;
12501 block_input ();
12502 #ifdef HAVE_X_I18N
12503 /* We must close our connection to the XIM server before closing the
12504 X display. */
12505 if (dpyinfo->xim)
12506 xim_close_dpy (dpyinfo);
12507 #endif
12509 /* Normally, the display is available... */
12510 if (dpyinfo->display)
12512 x_destroy_all_bitmaps (dpyinfo);
12513 XSetCloseDownMode (dpyinfo->display, DestroyAll);
12515 /* Whether or not XCloseDisplay destroys the associated resource
12516 database depends on the version of libX11. To avoid both
12517 crash and memory leak, we dissociate the database from the
12518 display and then destroy dpyinfo->xrdb ourselves.
12520 Unfortunately, the above strategy does not work in some
12521 situations due to a bug in newer versions of libX11: because
12522 XrmSetDatabase doesn't clear the flag XlibDisplayDfltRMDB if
12523 dpy->db is NULL, XCloseDisplay destroys the associated
12524 database whereas it has not been created by XGetDefault
12525 (Bug#21974 in freedesktop.org Bugzilla). As a workaround, we
12526 don't destroy the database here in order to avoid the crash
12527 in the above situations for now, though that may cause memory
12528 leaks in other situations. */
12529 #if false
12530 #ifdef HAVE_XRMSETDATABASE
12531 XrmSetDatabase (dpyinfo->display, NULL);
12532 #else
12533 dpyinfo->display->db = NULL;
12534 #endif
12535 /* We used to call XrmDestroyDatabase from x_delete_display, but
12536 some older versions of libX11 crash if we call it after
12537 closing all the displays. */
12538 XrmDestroyDatabase (dpyinfo->xrdb);
12539 #endif
12541 #ifdef USE_GTK
12542 xg_display_close (dpyinfo->display);
12543 #else
12544 #ifdef USE_X_TOOLKIT
12545 XtCloseDisplay (dpyinfo->display);
12546 #else
12547 XCloseDisplay (dpyinfo->display);
12548 #endif
12549 #endif /* ! USE_GTK */
12550 /* Do not close the connection here because it's already closed
12551 by X(t)CloseDisplay (Bug#18403). */
12552 dpyinfo->display = NULL;
12555 /* ...but if called from x_connection_closed, the display may already
12556 be closed and dpyinfo->display was set to 0 to indicate that. Since
12557 X server is most likely gone, explicit close is the only reliable
12558 way to continue and avoid Bug#19147. */
12559 else if (dpyinfo->connection >= 0)
12560 emacs_close (dpyinfo->connection);
12562 /* No more input on this descriptor. */
12563 delete_keyboard_wait_descriptor (dpyinfo->connection);
12564 /* Mark as dead. */
12565 dpyinfo->connection = -1;
12567 x_delete_display (dpyinfo);
12568 unblock_input ();
12571 /* Create a struct terminal, initialize it with the X11 specific
12572 functions and make DISPLAY->TERMINAL point to it. */
12574 static struct terminal *
12575 x_create_terminal (struct x_display_info *dpyinfo)
12577 struct terminal *terminal;
12579 terminal = create_terminal (output_x_window, &x_redisplay_interface);
12581 terminal->display_info.x = dpyinfo;
12582 dpyinfo->terminal = terminal;
12584 /* kboard is initialized in x_term_init. */
12586 terminal->clear_frame_hook = x_clear_frame;
12587 terminal->ins_del_lines_hook = x_ins_del_lines;
12588 terminal->delete_glyphs_hook = x_delete_glyphs;
12589 terminal->ring_bell_hook = XTring_bell;
12590 terminal->toggle_invisible_pointer_hook = XTtoggle_invisible_pointer;
12591 terminal->update_begin_hook = x_update_begin;
12592 terminal->update_end_hook = x_update_end;
12593 terminal->read_socket_hook = XTread_socket;
12594 terminal->frame_up_to_date_hook = XTframe_up_to_date;
12595 terminal->mouse_position_hook = XTmouse_position;
12596 terminal->frame_rehighlight_hook = XTframe_rehighlight;
12597 terminal->frame_raise_lower_hook = XTframe_raise_lower;
12598 terminal->fullscreen_hook = XTfullscreen_hook;
12599 terminal->menu_show_hook = x_menu_show;
12600 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
12601 terminal->popup_dialog_hook = xw_popup_dialog;
12602 #endif
12603 terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
12604 terminal->set_horizontal_scroll_bar_hook = XTset_horizontal_scroll_bar;
12605 terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
12606 terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
12607 terminal->judge_scroll_bars_hook = XTjudge_scroll_bars;
12608 terminal->delete_frame_hook = x_destroy_window;
12609 terminal->delete_terminal_hook = x_delete_terminal;
12610 /* Other hooks are NULL by default. */
12612 return terminal;
12615 static void
12616 x_initialize (void)
12618 baud_rate = 19200;
12620 x_noop_count = 0;
12621 any_help_event_p = false;
12622 ignore_next_mouse_click_timeout = 0;
12624 #ifdef USE_GTK
12625 current_count = -1;
12626 #endif
12628 /* Try to use interrupt input; if we can't, then start polling. */
12629 Fset_input_interrupt_mode (Qt);
12631 #ifdef USE_X_TOOLKIT
12632 XtToolkitInitialize ();
12634 Xt_app_con = XtCreateApplicationContext ();
12636 /* Register a converter from strings to pixels, which uses
12637 Emacs' color allocation infrastructure. */
12638 XtAppSetTypeConverter (Xt_app_con,
12639 XtRString, XtRPixel, cvt_string_to_pixel,
12640 cvt_string_to_pixel_args,
12641 XtNumber (cvt_string_to_pixel_args),
12642 XtCacheByDisplay, cvt_pixel_dtor);
12644 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
12645 #endif
12647 #ifdef USE_TOOLKIT_SCROLL_BARS
12648 #ifndef USE_GTK
12649 xaw3d_arrow_scroll = False;
12650 xaw3d_pick_top = True;
12651 #endif
12652 #endif
12654 #ifdef USE_CAIRO
12655 x_cr_init_fringe (&x_redisplay_interface);
12656 #endif
12658 /* Note that there is no real way portable across R3/R4 to get the
12659 original error handler. */
12660 XSetErrorHandler (x_error_handler);
12661 XSetIOErrorHandler (x_io_error_quitter);
12664 #ifdef USE_GTK
12665 void
12666 init_xterm (void)
12668 /* Emacs can handle only core input events, so make sure
12669 Gtk doesn't use Xinput or Xinput2 extensions. */
12670 xputenv ("GDK_CORE_DEVICE_EVENTS=1");
12672 #endif
12674 void
12675 syms_of_xterm (void)
12677 x_error_message = NULL;
12679 DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
12680 DEFSYM (Qlatin_1, "latin-1");
12682 #ifdef USE_GTK
12683 xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
12684 staticpro (&xg_default_icon_file);
12686 DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock");
12687 #endif
12689 DEFVAR_BOOL ("x-use-underline-position-properties",
12690 x_use_underline_position_properties,
12691 doc: /* Non-nil means make use of UNDERLINE_POSITION font properties.
12692 A value of nil means ignore them. If you encounter fonts with bogus
12693 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
12694 to 4.1, set this to nil. You can also use `underline-minimum-offset'
12695 to override the font's UNDERLINE_POSITION for small font display
12696 sizes. */);
12697 x_use_underline_position_properties = true;
12699 DEFVAR_BOOL ("x-underline-at-descent-line",
12700 x_underline_at_descent_line,
12701 doc: /* Non-nil means to draw the underline at the same place as the descent line.
12702 A value of nil means to draw the underline according to the value of the
12703 variable `x-use-underline-position-properties', which is usually at the
12704 baseline level. The default value is nil. */);
12705 x_underline_at_descent_line = false;
12707 DEFVAR_BOOL ("x-mouse-click-focus-ignore-position",
12708 x_mouse_click_focus_ignore_position,
12709 doc: /* Non-nil means that a mouse click to focus a frame does not move point.
12710 This variable is only used when the window manager requires that you
12711 click on a frame to select it (give it focus). In that case, a value
12712 of nil, means that the selected window and cursor position changes to
12713 reflect the mouse click position, while a non-nil value means that the
12714 selected window or cursor position is preserved. */);
12715 x_mouse_click_focus_ignore_position = false;
12717 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
12718 doc: /* Which toolkit scroll bars Emacs uses, if any.
12719 A value of nil means Emacs doesn't use toolkit scroll bars.
12720 With the X Window system, the value is a symbol describing the
12721 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
12722 With MS Windows or Nextstep, the value is t. */);
12723 #ifdef USE_TOOLKIT_SCROLL_BARS
12724 #ifdef USE_MOTIF
12725 Vx_toolkit_scroll_bars = intern_c_string ("motif");
12726 #elif defined HAVE_XAW3D
12727 Vx_toolkit_scroll_bars = intern_c_string ("xaw3d");
12728 #elif USE_GTK
12729 Vx_toolkit_scroll_bars = intern_c_string ("gtk");
12730 #else
12731 Vx_toolkit_scroll_bars = intern_c_string ("xaw");
12732 #endif
12733 #else
12734 Vx_toolkit_scroll_bars = Qnil;
12735 #endif
12737 DEFSYM (Qmodifier_value, "modifier-value");
12738 DEFSYM (Qalt, "alt");
12739 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
12740 DEFSYM (Qhyper, "hyper");
12741 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
12742 DEFSYM (Qmeta, "meta");
12743 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
12744 DEFSYM (Qsuper, "super");
12745 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
12747 DEFVAR_LISP ("x-alt-keysym", Vx_alt_keysym,
12748 doc: /* Which keys Emacs uses for the alt modifier.
12749 This should be one of the symbols `alt', `hyper', `meta', `super'.
12750 For example, `alt' means use the Alt_L and Alt_R keysyms. The default
12751 is nil, which is the same as `alt'. */);
12752 Vx_alt_keysym = Qnil;
12754 DEFVAR_LISP ("x-hyper-keysym", Vx_hyper_keysym,
12755 doc: /* Which keys Emacs uses for the hyper modifier.
12756 This should be one of the symbols `alt', `hyper', `meta', `super'.
12757 For example, `hyper' means use the Hyper_L and Hyper_R keysyms. The
12758 default is nil, which is the same as `hyper'. */);
12759 Vx_hyper_keysym = Qnil;
12761 DEFVAR_LISP ("x-meta-keysym", Vx_meta_keysym,
12762 doc: /* Which keys Emacs uses for the meta modifier.
12763 This should be one of the symbols `alt', `hyper', `meta', `super'.
12764 For example, `meta' means use the Meta_L and Meta_R keysyms. The
12765 default is nil, which is the same as `meta'. */);
12766 Vx_meta_keysym = Qnil;
12768 DEFVAR_LISP ("x-super-keysym", Vx_super_keysym,
12769 doc: /* Which keys Emacs uses for the super modifier.
12770 This should be one of the symbols `alt', `hyper', `meta', `super'.
12771 For example, `super' means use the Super_L and Super_R keysyms. The
12772 default is nil, which is the same as `super'. */);
12773 Vx_super_keysym = Qnil;
12775 DEFVAR_LISP ("x-keysym-table", Vx_keysym_table,
12776 doc: /* Hash table of character codes indexed by X keysym codes. */);
12777 Vx_keysym_table = make_hash_table (hashtest_eql, make_number (900),
12778 make_float (DEFAULT_REHASH_SIZE),
12779 make_float (DEFAULT_REHASH_THRESHOLD),
12780 Qnil);
12782 DEFVAR_BOOL ("x-frame-normalize-before-maximize",
12783 x_frame_normalize_before_maximize,
12784 doc: /* Non-nil means normalize frame before maximizing.
12785 If this variable is t, Emacs first asks the window manager to give the
12786 frame its normal size, and only then the final state, whenever changing
12787 from a full-height, full-width or full-both state to the maximized one
12788 or when changing from the maximized to the full-height or full-width
12789 state.
12791 Set this variable only if your window manager cannot handle the
12792 transition between the various maximization states. */);
12793 x_frame_normalize_before_maximize = false;