Merge from origin/emacs-25
[emacs.git] / src / xterm.c
blob747669446f57bb51dcd1642f94106cee33a6b0bc
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 #include <stdlib.h>
26 #ifdef USE_CAIRO
27 #include <math.h>
28 #endif
30 #include "lisp.h"
31 #include "blockinput.h"
33 /* This may include sys/types.h, and that somehow loses
34 if this is not done before the other system files. */
35 #include "xterm.h"
36 #include <X11/cursorfont.h>
38 /* If we have Xfixes extension, use it for pointer blanking. */
39 #ifdef HAVE_XFIXES
40 #include <X11/extensions/Xfixes.h>
41 #endif
43 /* Using Xft implies that XRender is available. */
44 #ifdef HAVE_XFT
45 #include <X11/extensions/Xrender.h>
46 #endif
48 /* Load sys/types.h if not already loaded.
49 In some systems loading it twice is suicidal. */
50 #ifndef makedev
51 #include <sys/types.h>
52 #endif /* makedev */
54 #include <sys/ioctl.h>
56 #include "systime.h"
58 #include <fcntl.h>
59 #include <errno.h>
60 #include <sys/stat.h>
61 #include "character.h"
62 #include "coding.h"
63 #include "composite.h"
64 #include "frame.h"
65 #include "dispextern.h"
66 #include "xwidget.h"
67 #include "fontset.h"
68 #include "termhooks.h"
69 #include "termopts.h"
70 #include "termchar.h"
71 #include "emacs-icon.h"
72 #include "buffer.h"
73 #include "window.h"
74 #include "keyboard.h"
75 #include "atimer.h"
76 #include "font.h"
77 #include "xsettings.h"
78 #include "sysselect.h"
79 #include "menu.h"
81 #ifdef USE_X_TOOLKIT
82 #include <X11/Shell.h>
83 #endif
85 #include <unistd.h>
87 #ifdef USE_GTK
88 #include "gtkutil.h"
89 #ifdef HAVE_GTK3
90 #include <X11/Xproto.h>
91 #endif
92 #endif
94 #if defined (USE_LUCID) || defined (USE_MOTIF)
95 #include "../lwlib/xlwmenu.h"
96 #endif
98 #ifdef USE_X_TOOLKIT
100 /* Include toolkit specific headers for the scroll bar widget. */
102 #ifdef USE_TOOLKIT_SCROLL_BARS
103 #if defined USE_MOTIF
104 #include <Xm/Xm.h> /* For LESSTIF_VERSION */
105 #include <Xm/ScrollBar.h>
106 #else /* !USE_MOTIF i.e. use Xaw */
108 #ifdef HAVE_XAW3D
109 #include <X11/Xaw3d/Simple.h>
110 #include <X11/Xaw3d/Scrollbar.h>
111 #include <X11/Xaw3d/ThreeD.h>
112 #else /* !HAVE_XAW3D */
113 #include <X11/Xaw/Simple.h>
114 #include <X11/Xaw/Scrollbar.h>
115 #endif /* !HAVE_XAW3D */
116 #ifndef XtNpickTop
117 #define XtNpickTop "pickTop"
118 #endif /* !XtNpickTop */
119 #endif /* !USE_MOTIF */
120 #endif /* USE_TOOLKIT_SCROLL_BARS */
122 #endif /* USE_X_TOOLKIT */
124 #ifdef USE_X_TOOLKIT
125 #include "widget.h"
126 #ifndef XtNinitialState
127 #define XtNinitialState "initialState"
128 #endif
129 #endif
131 #include "bitmaps/gray.xbm"
133 #ifdef HAVE_XKB
134 #include <X11/XKBlib.h>
135 #endif
137 /* Default to using XIM if available. */
138 #ifdef USE_XIM
139 bool use_xim = true;
140 #else
141 bool use_xim = false; /* configure --without-xim */
142 #endif
144 /* Non-zero means that a HELP_EVENT has been generated since Emacs
145 start. */
147 static bool any_help_event_p;
149 /* This is a chain of structures for all the X displays currently in
150 use. */
152 struct x_display_info *x_display_list;
154 #ifdef USE_X_TOOLKIT
156 /* The application context for Xt use. */
157 XtAppContext Xt_app_con;
158 static String Xt_default_resources[] = {0};
160 /* Non-zero means user is interacting with a toolkit scroll bar. */
161 static bool toolkit_scroll_bar_interaction;
163 #endif /* USE_X_TOOLKIT */
165 /* Non-zero timeout value means ignore next mouse click if it arrives
166 before that timeout elapses (i.e. as part of the same sequence of
167 events resulting from clicking on a frame to select it). */
169 static Time ignore_next_mouse_click_timeout;
171 /* Used locally within XTread_socket. */
173 static int x_noop_count;
175 #ifdef USE_GTK
176 /* The name of the Emacs icon file. */
177 static Lisp_Object xg_default_icon_file;
178 #endif
180 /* Some functions take this as char *, not const char *. */
181 static char emacs_class[] = EMACS_CLASS;
183 enum xembed_info
185 XEMBED_MAPPED = 1 << 0
188 enum xembed_message
190 XEMBED_EMBEDDED_NOTIFY = 0,
191 XEMBED_WINDOW_ACTIVATE = 1,
192 XEMBED_WINDOW_DEACTIVATE = 2,
193 XEMBED_REQUEST_FOCUS = 3,
194 XEMBED_FOCUS_IN = 4,
195 XEMBED_FOCUS_OUT = 5,
196 XEMBED_FOCUS_NEXT = 6,
197 XEMBED_FOCUS_PREV = 7,
199 XEMBED_MODALITY_ON = 10,
200 XEMBED_MODALITY_OFF = 11,
201 XEMBED_REGISTER_ACCELERATOR = 12,
202 XEMBED_UNREGISTER_ACCELERATOR = 13,
203 XEMBED_ACTIVATE_ACCELERATOR = 14
206 static void x_free_cr_resources (struct frame *);
207 static bool x_alloc_nearest_color_1 (Display *, Colormap, XColor *);
208 static void x_raise_frame (struct frame *);
209 static void x_lower_frame (struct frame *);
210 static int x_io_error_quitter (Display *);
211 static struct terminal *x_create_terminal (struct x_display_info *);
212 static void x_frame_rehighlight (struct x_display_info *);
214 static void x_clip_to_row (struct window *, struct glyph_row *,
215 enum glyph_row_area, GC);
216 static struct scroll_bar *x_window_to_scroll_bar (Display *, Window, int);
217 static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *,
218 enum scroll_bar_part *,
219 Lisp_Object *, Lisp_Object *,
220 Time *);
221 static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object *,
222 enum scroll_bar_part *,
223 Lisp_Object *, Lisp_Object *,
224 Time *);
225 static bool x_handle_net_wm_state (struct frame *, const XPropertyEvent *);
226 static void x_check_fullscreen (struct frame *);
227 static void x_check_expected_move (struct frame *, int, int);
228 static void x_sync_with_move (struct frame *, int, int, bool);
229 static int handle_one_xevent (struct x_display_info *,
230 const XEvent *, int *,
231 struct input_event *);
232 #if ! (defined USE_X_TOOLKIT || defined USE_MOTIF)
233 static int x_dispatch_event (XEvent *, Display *);
234 #endif
235 static void x_wm_set_window_state (struct frame *, int);
236 static void x_wm_set_icon_pixmap (struct frame *, ptrdiff_t);
237 static void x_initialize (void);
239 static bool get_current_wm_state (struct frame *, Window, int *, bool *);
241 /* Flush display of frame F. */
243 static void
244 x_flush (struct frame *f)
246 eassert (f && FRAME_X_P (f));
247 /* Don't call XFlush when it is not safe to redisplay; the X
248 connection may be broken. */
249 if (!NILP (Vinhibit_redisplay))
250 return;
252 block_input ();
253 XFlush (FRAME_X_DISPLAY (f));
254 unblock_input ();
258 /* Remove calls to XFlush by defining XFlush to an empty replacement.
259 Calls to XFlush should be unnecessary because the X output buffer
260 is flushed automatically as needed by calls to XPending,
261 XNextEvent, or XWindowEvent according to the XFlush man page.
262 XTread_socket calls XPending. Removing XFlush improves
263 performance. */
265 #define XFlush(DISPLAY) (void) 0
268 /***********************************************************************
269 Debugging
270 ***********************************************************************/
272 #if false
274 /* This is a function useful for recording debugging information about
275 the sequence of occurrences in this file. */
277 struct record
279 char *locus;
280 int type;
283 struct record event_record[100];
285 int event_record_index;
287 void
288 record_event (char *locus, int type)
290 if (event_record_index == ARRAYELTS (event_record))
291 event_record_index = 0;
293 event_record[event_record_index].locus = locus;
294 event_record[event_record_index].type = type;
295 event_record_index++;
298 #endif
300 #ifdef USE_CAIRO
302 #define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context)
303 #define FRAME_CR_SURFACE(f) ((f)->output_data.x->cr_surface)
305 static struct x_gc_ext_data *
306 x_gc_get_ext_data (struct frame *f, GC gc, int create_if_not_found_p)
308 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
309 XEDataObject object;
310 XExtData **head, *ext_data;
312 object.gc = gc;
313 head = XEHeadOfExtensionList (object);
314 ext_data = XFindOnExtensionList (head, dpyinfo->ext_codes->extension);
315 if (ext_data == NULL)
317 if (!create_if_not_found_p)
318 return NULL;
319 else
321 ext_data = xzalloc (sizeof (*ext_data));
322 ext_data->number = dpyinfo->ext_codes->extension;
323 ext_data->private_data = xzalloc (sizeof (struct x_gc_ext_data));
324 XAddToExtensionList (head, ext_data);
327 return (struct x_gc_ext_data *) ext_data->private_data;
330 static void
331 x_extension_initialize (struct x_display_info *dpyinfo)
333 XExtCodes *ext_codes = XAddExtension (dpyinfo->display);
335 dpyinfo->ext_codes = ext_codes;
338 static void
339 x_cr_destroy_surface (struct frame *f)
341 if (FRAME_CR_SURFACE (f))
343 cairo_t *cr = FRAME_CR_CONTEXT (f);
344 cairo_surface_destroy (FRAME_CR_SURFACE (f));
345 FRAME_CR_SURFACE (f) = 0;
346 if (cr) cairo_destroy (cr);
347 FRAME_CR_CONTEXT (f) = NULL;
351 cairo_t *
352 x_begin_cr_clip (struct frame *f, GC gc)
354 cairo_t *cr = FRAME_CR_CONTEXT (f);
356 if (!cr)
359 if (! FRAME_CR_SURFACE (f))
361 cairo_surface_t *surface;
362 surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
363 FRAME_X_WINDOW (f),
364 FRAME_DISPLAY_INFO (f)->visual,
365 FRAME_PIXEL_WIDTH (f),
366 FRAME_PIXEL_HEIGHT (f));
367 cr = cairo_create (surface);
368 cairo_surface_destroy (surface);
370 else
371 cr = cairo_create (FRAME_CR_SURFACE (f));
372 FRAME_CR_CONTEXT (f) = cr;
374 cairo_save (cr);
376 if (gc)
378 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
380 if (gc_ext && gc_ext->n_clip_rects)
382 int i;
384 for (i = 0; i < gc_ext->n_clip_rects; i++)
385 cairo_rectangle (cr, gc_ext->clip_rects[i].x,
386 gc_ext->clip_rects[i].y,
387 gc_ext->clip_rects[i].width,
388 gc_ext->clip_rects[i].height);
389 cairo_clip (cr);
393 return cr;
396 void
397 x_end_cr_clip (struct frame *f)
399 cairo_restore (FRAME_CR_CONTEXT (f));
402 void
403 x_set_cr_source_with_gc_foreground (struct frame *f, GC gc)
405 XGCValues xgcv;
406 XColor color;
408 XGetGCValues (FRAME_X_DISPLAY (f), gc, GCForeground, &xgcv);
409 color.pixel = xgcv.foreground;
410 x_query_color (f, &color);
411 cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
412 color.green / 65535.0, color.blue / 65535.0);
415 void
416 x_set_cr_source_with_gc_background (struct frame *f, GC gc)
418 XGCValues xgcv;
419 XColor color;
421 XGetGCValues (FRAME_X_DISPLAY (f), gc, GCBackground, &xgcv);
422 color.pixel = xgcv.background;
423 x_query_color (f, &color);
424 cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
425 color.green / 65535.0, color.blue / 65535.0);
428 /* Fringe bitmaps. */
430 static int max_fringe_bmp = 0;
431 static cairo_pattern_t **fringe_bmp = 0;
433 static void
434 x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
436 int i, stride;
437 cairo_surface_t *surface;
438 unsigned char *data;
439 cairo_pattern_t *pattern;
441 if (which >= max_fringe_bmp)
443 i = max_fringe_bmp;
444 max_fringe_bmp = which + 20;
445 fringe_bmp = (cairo_pattern_t **) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (cairo_pattern_t *));
446 while (i < max_fringe_bmp)
447 fringe_bmp[i++] = 0;
450 block_input ();
452 surface = cairo_image_surface_create (CAIRO_FORMAT_A1, wd, h);
453 stride = cairo_image_surface_get_stride (surface);
454 data = cairo_image_surface_get_data (surface);
456 for (i = 0; i < h; i++)
458 *((unsigned short *) data) = bits[i];
459 data += stride;
462 cairo_surface_mark_dirty (surface);
463 pattern = cairo_pattern_create_for_surface (surface);
464 cairo_surface_destroy (surface);
466 unblock_input ();
468 fringe_bmp[which] = pattern;
471 static void
472 x_cr_destroy_fringe_bitmap (int which)
474 if (which >= max_fringe_bmp)
475 return;
477 if (fringe_bmp[which])
479 block_input ();
480 cairo_pattern_destroy (fringe_bmp[which]);
481 unblock_input ();
483 fringe_bmp[which] = 0;
486 static void
487 x_cr_draw_image (struct frame *f, GC gc, cairo_pattern_t *image,
488 int src_x, int src_y, int width, int height,
489 int dest_x, int dest_y, bool overlay_p)
491 cairo_t *cr;
492 cairo_matrix_t matrix;
493 cairo_surface_t *surface;
494 cairo_format_t format;
496 cr = x_begin_cr_clip (f, gc);
497 if (overlay_p)
498 cairo_rectangle (cr, dest_x, dest_y, width, height);
499 else
501 x_set_cr_source_with_gc_background (f, gc);
502 cairo_rectangle (cr, dest_x, dest_y, width, height);
503 cairo_fill_preserve (cr);
505 cairo_clip (cr);
506 cairo_matrix_init_translate (&matrix, src_x - dest_x, src_y - dest_y);
507 cairo_pattern_set_matrix (image, &matrix);
508 cairo_pattern_get_surface (image, &surface);
509 format = cairo_image_surface_get_format (surface);
510 if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1)
512 cairo_set_source (cr, image);
513 cairo_fill (cr);
515 else
517 x_set_cr_source_with_gc_foreground (f, gc);
518 cairo_mask (cr, image);
520 x_end_cr_clip (f);
523 void
524 x_cr_draw_frame (cairo_t *cr, struct frame *f)
526 int width, height;
528 width = FRAME_PIXEL_WIDTH (f);
529 height = FRAME_PIXEL_HEIGHT (f);
531 x_free_cr_resources (f);
532 FRAME_CR_CONTEXT (f) = cr;
533 x_clear_area (f, 0, 0, width, height);
534 expose_frame (f, 0, 0, width, height);
535 FRAME_CR_CONTEXT (f) = NULL;
538 static cairo_status_t
539 x_cr_accumulate_data (void *closure, const unsigned char *data,
540 unsigned int length)
542 Lisp_Object *acc = (Lisp_Object *) closure;
544 *acc = Fcons (make_unibyte_string ((char const *) data, length), *acc);
546 return CAIRO_STATUS_SUCCESS;
549 static void
550 x_cr_destroy (Lisp_Object arg)
552 cairo_t *cr = (cairo_t *) XSAVE_POINTER (arg, 0);
554 block_input ();
555 cairo_destroy (cr);
556 unblock_input ();
559 Lisp_Object
560 x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
562 struct frame *f;
563 cairo_surface_t *surface;
564 cairo_t *cr;
565 int width, height;
566 void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL;
567 Lisp_Object acc = Qnil;
568 int count = SPECPDL_INDEX ();
570 specbind (Qredisplay_dont_pause, Qt);
571 redisplay_preserve_echo_area (31);
573 f = XFRAME (XCAR (frames));
574 frames = XCDR (frames);
575 width = FRAME_PIXEL_WIDTH (f);
576 height = FRAME_PIXEL_HEIGHT (f);
578 block_input ();
579 #ifdef CAIRO_HAS_PDF_SURFACE
580 if (surface_type == CAIRO_SURFACE_TYPE_PDF)
582 surface = cairo_pdf_surface_create_for_stream (x_cr_accumulate_data, &acc,
583 width, height);
584 surface_set_size_func = cairo_pdf_surface_set_size;
586 else
587 #endif
588 #ifdef CAIRO_HAS_PNG_FUNCTIONS
589 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
590 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
591 else
592 #endif
593 #ifdef CAIRO_HAS_PS_SURFACE
594 if (surface_type == CAIRO_SURFACE_TYPE_PS)
596 surface = cairo_ps_surface_create_for_stream (x_cr_accumulate_data, &acc,
597 width, height);
598 surface_set_size_func = cairo_ps_surface_set_size;
600 else
601 #endif
602 #ifdef CAIRO_HAS_SVG_SURFACE
603 if (surface_type == CAIRO_SURFACE_TYPE_SVG)
604 surface = cairo_svg_surface_create_for_stream (x_cr_accumulate_data, &acc,
605 width, height);
606 else
607 #endif
608 abort ();
610 cr = cairo_create (surface);
611 cairo_surface_destroy (surface);
612 record_unwind_protect (x_cr_destroy, make_save_ptr (cr));
614 while (1)
616 x_free_cr_resources (f);
617 FRAME_CR_CONTEXT (f) = cr;
618 x_clear_area (f, 0, 0, width, height);
619 expose_frame (f, 0, 0, width, height);
620 FRAME_CR_CONTEXT (f) = NULL;
622 if (NILP (frames))
623 break;
625 cairo_surface_show_page (surface);
626 f = XFRAME (XCAR (frames));
627 frames = XCDR (frames);
628 width = FRAME_PIXEL_WIDTH (f);
629 height = FRAME_PIXEL_HEIGHT (f);
630 if (surface_set_size_func)
631 (*surface_set_size_func) (surface, width, height);
633 unblock_input ();
634 QUIT;
635 block_input ();
638 #ifdef CAIRO_HAS_PNG_FUNCTIONS
639 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
641 cairo_surface_flush (surface);
642 cairo_surface_write_to_png_stream (surface, x_cr_accumulate_data, &acc);
644 #endif
645 unblock_input ();
647 unbind_to (count, Qnil);
649 return CALLN (Fapply, intern ("concat"), Fnreverse (acc));
652 #endif /* USE_CAIRO */
654 static void
655 x_free_cr_resources (struct frame *f)
657 #ifdef USE_CAIRO
658 if (f == NULL)
660 Lisp_Object rest, frame;
661 FOR_EACH_FRAME (rest, frame)
662 if (FRAME_X_P (XFRAME (frame)))
663 x_free_cr_resources (XFRAME (frame));
665 else
667 cairo_t *cr = FRAME_CR_CONTEXT (f);
669 if (cr)
671 cairo_surface_t *surface = cairo_get_target (cr);
673 if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
675 cairo_destroy (cr);
676 FRAME_CR_CONTEXT (f) = NULL;
680 #endif
683 static void
684 x_set_clip_rectangles (struct frame *f, GC gc, XRectangle *rectangles, int n)
686 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, rectangles, n, Unsorted);
687 #ifdef USE_CAIRO
688 eassert (n >= 0 && n <= MAX_CLIP_RECTS);
691 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 1);
693 gc_ext->n_clip_rects = n;
694 memcpy (gc_ext->clip_rects, rectangles, sizeof (XRectangle) * n);
696 #endif
699 static void
700 x_reset_clip_rectangles (struct frame *f, GC gc)
702 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
703 #ifdef USE_CAIRO
705 struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
707 if (gc_ext)
708 gc_ext->n_clip_rects = 0;
710 #endif
713 static void
714 x_fill_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
716 #ifdef USE_CAIRO
717 cairo_t *cr;
719 cr = x_begin_cr_clip (f, gc);
720 x_set_cr_source_with_gc_foreground (f, gc);
721 cairo_rectangle (cr, x, y, width, height);
722 cairo_fill (cr);
723 x_end_cr_clip (f);
724 #else
725 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
726 gc, x, y, width, height);
727 #endif
730 static void
731 x_draw_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
733 #ifdef USE_CAIRO
734 cairo_t *cr;
736 cr = x_begin_cr_clip (f, gc);
737 x_set_cr_source_with_gc_foreground (f, gc);
738 cairo_rectangle (cr, x + 0.5, y + 0.5, width, height);
739 cairo_set_line_width (cr, 1);
740 cairo_stroke (cr);
741 x_end_cr_clip (f);
742 #else
743 XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
744 gc, x, y, width, height);
745 #endif
748 static void
749 x_clear_window (struct frame *f)
751 #ifdef USE_CAIRO
752 cairo_t *cr;
754 cr = x_begin_cr_clip (f, NULL);
755 x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
756 cairo_paint (cr);
757 x_end_cr_clip (f);
758 #else
759 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
760 #endif
763 #ifdef USE_CAIRO
764 static void
765 x_fill_trapezoid_for_relief (struct frame *f, GC gc, int x, int y,
766 int width, int height, int top_p)
768 cairo_t *cr;
770 cr = x_begin_cr_clip (f, gc);
771 x_set_cr_source_with_gc_foreground (f, gc);
772 cairo_move_to (cr, top_p ? x : x + height, y);
773 cairo_line_to (cr, x, y + height);
774 cairo_line_to (cr, top_p ? x + width - height : x + width, y + height);
775 cairo_line_to (cr, x + width, y);
776 cairo_fill (cr);
777 x_end_cr_clip (f);
780 enum corners
782 CORNER_BOTTOM_RIGHT, /* 0 -> pi/2 */
783 CORNER_BOTTOM_LEFT, /* pi/2 -> pi */
784 CORNER_TOP_LEFT, /* pi -> 3pi/2 */
785 CORNER_TOP_RIGHT, /* 3pi/2 -> 2pi */
786 CORNER_LAST
789 static void
790 x_erase_corners_for_relief (struct frame *f, GC gc, int x, int y,
791 int width, int height,
792 double radius, double margin, int corners)
794 cairo_t *cr;
795 int i;
797 cr = x_begin_cr_clip (f, gc);
798 x_set_cr_source_with_gc_background (f, gc);
799 for (i = 0; i < CORNER_LAST; i++)
800 if (corners & (1 << i))
802 double xm, ym, xc, yc;
804 if (i == CORNER_TOP_LEFT || i == CORNER_BOTTOM_LEFT)
805 xm = x - margin, xc = xm + radius;
806 else
807 xm = x + width + margin, xc = xm - radius;
808 if (i == CORNER_TOP_LEFT || i == CORNER_TOP_RIGHT)
809 ym = y - margin, yc = ym + radius;
810 else
811 ym = y + height + margin, yc = ym - radius;
813 cairo_move_to (cr, xm, ym);
814 cairo_arc (cr, xc, yc, radius, i * M_PI_2, (i + 1) * M_PI_2);
816 cairo_clip (cr);
817 cairo_rectangle (cr, x, y, width, height);
818 cairo_fill (cr);
819 x_end_cr_clip (f);
822 static void
823 x_draw_horizontal_wave (struct frame *f, GC gc, int x, int y,
824 int width, int height, int wave_length)
826 cairo_t *cr;
827 double dx = wave_length, dy = height - 1;
828 int xoffset, n;
830 cr = x_begin_cr_clip (f, gc);
831 x_set_cr_source_with_gc_foreground (f, gc);
832 cairo_rectangle (cr, x, y, width, height);
833 cairo_clip (cr);
835 if (x >= 0)
837 xoffset = x % (wave_length * 2);
838 if (xoffset == 0)
839 xoffset = wave_length * 2;
841 else
842 xoffset = x % (wave_length * 2) + wave_length * 2;
843 n = (width + xoffset) / wave_length + 1;
844 if (xoffset > wave_length)
846 xoffset -= wave_length;
847 --n;
848 y += height - 1;
849 dy = -dy;
852 cairo_move_to (cr, x - xoffset + 0.5, y + 0.5);
853 while (--n >= 0)
855 cairo_rel_line_to (cr, dx, dy);
856 dy = -dy;
858 cairo_set_line_width (cr, 1);
859 cairo_stroke (cr);
860 x_end_cr_clip (f);
862 #endif
865 /* Return the struct x_display_info corresponding to DPY. */
867 struct x_display_info *
868 x_display_info_for_display (Display *dpy)
870 struct x_display_info *dpyinfo;
872 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
873 if (dpyinfo->display == dpy)
874 return dpyinfo;
876 return 0;
879 static Window
880 x_find_topmost_parent (struct frame *f)
882 struct x_output *x = f->output_data.x;
883 Window win = None, wi = x->parent_desc;
884 Display *dpy = FRAME_X_DISPLAY (f);
886 while (wi != FRAME_DISPLAY_INFO (f)->root_window)
888 Window root;
889 Window *children;
890 unsigned int nchildren;
892 win = wi;
893 if (XQueryTree (dpy, win, &root, &wi, &children, &nchildren))
894 XFree (children);
895 else
896 break;
899 return win;
902 #define OPAQUE 0xffffffff
904 void
905 x_set_frame_alpha (struct frame *f)
907 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
908 Display *dpy = FRAME_X_DISPLAY (f);
909 Window win = FRAME_OUTER_WINDOW (f);
910 double alpha = 1.0;
911 double alpha_min = 1.0;
912 unsigned long opac;
913 Window parent;
915 if (dpyinfo->x_highlight_frame == f)
916 alpha = f->alpha[0];
917 else
918 alpha = f->alpha[1];
920 if (FLOATP (Vframe_alpha_lower_limit))
921 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
922 else if (INTEGERP (Vframe_alpha_lower_limit))
923 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
925 if (alpha < 0.0)
926 return;
927 else if (alpha > 1.0)
928 alpha = 1.0;
929 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
930 alpha = alpha_min;
932 opac = alpha * OPAQUE;
934 x_catch_errors (dpy);
936 /* If there is a parent from the window manager, put the property there
937 also, to work around broken window managers that fail to do that.
938 Do this unconditionally as this function is called on reparent when
939 alpha has not changed on the frame. */
941 parent = x_find_topmost_parent (f);
942 if (parent != None)
943 XChangeProperty (dpy, parent, dpyinfo->Xatom_net_wm_window_opacity,
944 XA_CARDINAL, 32, PropModeReplace,
945 (unsigned char *) &opac, 1);
947 /* return unless necessary */
949 unsigned char *data;
950 Atom actual;
951 int rc, format;
952 unsigned long n, left;
954 rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
955 0, 1, False, XA_CARDINAL,
956 &actual, &format, &n, &left,
957 &data);
959 if (rc == Success && actual != None)
961 unsigned long value = *(unsigned long *)data;
962 XFree (data);
963 if (value == opac)
965 x_uncatch_errors ();
966 return;
971 XChangeProperty (dpy, win, dpyinfo->Xatom_net_wm_window_opacity,
972 XA_CARDINAL, 32, PropModeReplace,
973 (unsigned char *) &opac, 1);
974 x_uncatch_errors ();
977 /***********************************************************************
978 Starting and ending an update
979 ***********************************************************************/
981 /* Start an update of frame F. This function is installed as a hook
982 for update_begin, i.e. it is called when update_begin is called.
983 This function is called prior to calls to x_update_window_begin for
984 each window being updated. Currently, there is nothing to do here
985 because all interesting stuff is done on a window basis. */
987 static void
988 x_update_begin (struct frame *f)
990 #ifdef USE_CAIRO
991 if (! NILP (tip_frame) && XFRAME (tip_frame) == f
992 && ! FRAME_VISIBLE_P (f))
993 return;
995 if (! FRAME_CR_SURFACE (f))
997 int width, height;
998 #ifdef USE_GTK
999 if (FRAME_GTK_WIDGET (f))
1001 GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
1002 width = gdk_window_get_width (w);
1003 height = gdk_window_get_height (w);
1005 else
1006 #endif
1008 width = FRAME_PIXEL_WIDTH (f);
1009 height = FRAME_PIXEL_HEIGHT (f);
1010 if (! FRAME_EXTERNAL_TOOL_BAR (f))
1011 height += FRAME_TOOL_BAR_HEIGHT (f);
1012 if (! FRAME_EXTERNAL_MENU_BAR (f))
1013 height += FRAME_MENU_BAR_HEIGHT (f);
1016 if (width > 0 && height > 0)
1018 block_input();
1019 FRAME_CR_SURFACE (f) = cairo_image_surface_create
1020 (CAIRO_FORMAT_ARGB32, width, height);
1021 unblock_input();
1024 #endif /* USE_CAIRO */
1027 /* Start update of window W. */
1029 static void
1030 x_update_window_begin (struct window *w)
1032 struct frame *f = XFRAME (WINDOW_FRAME (w));
1033 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1035 w->output_cursor = w->cursor;
1037 block_input ();
1039 if (f == hlinfo->mouse_face_mouse_frame)
1041 /* Don't do highlighting for mouse motion during the update. */
1042 hlinfo->mouse_face_defer = true;
1044 /* If F needs to be redrawn, simply forget about any prior mouse
1045 highlighting. */
1046 if (FRAME_GARBAGED_P (f))
1047 hlinfo->mouse_face_window = Qnil;
1050 unblock_input ();
1054 /* Draw a vertical window border from (x,y0) to (x,y1) */
1056 static void
1057 x_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
1059 struct frame *f = XFRAME (WINDOW_FRAME (w));
1060 struct face *face;
1062 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
1063 if (face)
1064 XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
1065 face->foreground);
1067 #ifdef USE_CAIRO
1068 x_fill_rectangle (f, f->output_data.x->normal_gc, x, y0, 1, y1 - y0);
1069 #else
1070 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1071 f->output_data.x->normal_gc, x, y0, x, y1);
1072 #endif
1075 /* Draw a window divider from (x0,y0) to (x1,y1) */
1077 static void
1078 x_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
1080 struct frame *f = XFRAME (WINDOW_FRAME (w));
1081 struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
1082 struct face *face_first
1083 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
1084 struct face *face_last
1085 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
1086 unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
1087 unsigned long color_first = (face_first
1088 ? face_first->foreground
1089 : FRAME_FOREGROUND_PIXEL (f));
1090 unsigned long color_last = (face_last
1091 ? face_last->foreground
1092 : FRAME_FOREGROUND_PIXEL (f));
1093 Display *display = FRAME_X_DISPLAY (f);
1095 if (y1 - y0 > x1 - x0 && x1 - x0 > 2)
1096 /* Vertical. */
1098 XSetForeground (display, f->output_data.x->normal_gc, color_first);
1099 x_fill_rectangle (f, f->output_data.x->normal_gc,
1100 x0, y0, 1, y1 - y0);
1101 XSetForeground (display, f->output_data.x->normal_gc, color);
1102 x_fill_rectangle (f, f->output_data.x->normal_gc,
1103 x0 + 1, y0, x1 - x0 - 2, y1 - y0);
1104 XSetForeground (display, f->output_data.x->normal_gc, color_last);
1105 x_fill_rectangle (f, f->output_data.x->normal_gc,
1106 x1 - 1, y0, 1, y1 - y0);
1108 else if (x1 - x0 > y1 - y0 && y1 - y0 > 3)
1109 /* Horizontal. */
1111 XSetForeground (display, f->output_data.x->normal_gc, color_first);
1112 x_fill_rectangle (f, f->output_data.x->normal_gc,
1113 x0, y0, x1 - x0, 1);
1114 XSetForeground (display, f->output_data.x->normal_gc, color);
1115 x_fill_rectangle (f, f->output_data.x->normal_gc,
1116 x0, y0 + 1, x1 - x0, y1 - y0 - 2);
1117 XSetForeground (display, f->output_data.x->normal_gc, color_last);
1118 x_fill_rectangle (f, f->output_data.x->normal_gc,
1119 x0, y1 - 1, x1 - x0, 1);
1121 else
1123 XSetForeground (display, f->output_data.x->normal_gc, color);
1124 x_fill_rectangle (f, f->output_data.x->normal_gc,
1125 x0, y0, x1 - x0, y1 - y0);
1129 /* End update of window W.
1131 Draw vertical borders between horizontally adjacent windows, and
1132 display W's cursor if CURSOR_ON_P is non-zero.
1134 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
1135 glyphs in mouse-face were overwritten. In that case we have to
1136 make sure that the mouse-highlight is properly redrawn.
1138 W may be a menu bar pseudo-window in case we don't have X toolkit
1139 support. Such windows don't have a cursor, so don't display it
1140 here. */
1142 static void
1143 x_update_window_end (struct window *w, bool cursor_on_p,
1144 bool mouse_face_overwritten_p)
1146 if (!w->pseudo_window_p)
1148 block_input ();
1150 if (cursor_on_p)
1151 display_and_set_cursor (w, true,
1152 w->output_cursor.hpos, w->output_cursor.vpos,
1153 w->output_cursor.x, w->output_cursor.y);
1155 if (draw_window_fringes (w, true))
1157 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1158 x_draw_right_divider (w);
1159 else
1160 x_draw_vertical_border (w);
1163 unblock_input ();
1166 /* If a row with mouse-face was overwritten, arrange for
1167 XTframe_up_to_date to redisplay the mouse highlight. */
1168 if (mouse_face_overwritten_p)
1170 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
1172 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1173 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1174 hlinfo->mouse_face_window = Qnil;
1179 /* End update of frame F. This function is installed as a hook in
1180 update_end. */
1182 static void
1183 x_update_end (struct frame *f)
1185 /* Mouse highlight may be displayed again. */
1186 MOUSE_HL_INFO (f)->mouse_face_defer = false;
1188 #ifdef USE_CAIRO
1189 if (FRAME_CR_SURFACE (f))
1191 cairo_t *cr = 0;
1192 block_input();
1193 #if defined (USE_GTK) && defined (HAVE_GTK3)
1194 if (FRAME_GTK_WIDGET (f))
1196 GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
1197 cr = gdk_cairo_create (w);
1199 else
1200 #endif
1202 cairo_surface_t *surface;
1203 int width = FRAME_PIXEL_WIDTH (f);
1204 int height = FRAME_PIXEL_HEIGHT (f);
1205 if (! FRAME_EXTERNAL_TOOL_BAR (f))
1206 height += FRAME_TOOL_BAR_HEIGHT (f);
1207 if (! FRAME_EXTERNAL_MENU_BAR (f))
1208 height += FRAME_MENU_BAR_HEIGHT (f);
1209 surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
1210 FRAME_X_WINDOW (f),
1211 FRAME_DISPLAY_INFO (f)->visual,
1212 width,
1213 height);
1214 cr = cairo_create (surface);
1215 cairo_surface_destroy (surface);
1218 cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), 0, 0);
1219 cairo_paint (cr);
1220 cairo_destroy (cr);
1221 unblock_input ();
1223 #endif /* USE_CAIRO */
1225 #ifndef XFlush
1226 block_input ();
1227 XFlush (FRAME_X_DISPLAY (f));
1228 unblock_input ();
1229 #endif
1233 /* This function is called from various places in xdisp.c
1234 whenever a complete update has been performed. */
1236 static void
1237 XTframe_up_to_date (struct frame *f)
1239 if (FRAME_X_P (f))
1240 FRAME_MOUSE_UPDATE (f);
1244 /* Clear under internal border if any (GTK has its own version). */
1245 #ifndef USE_GTK
1246 void
1247 x_clear_under_internal_border (struct frame *f)
1249 if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
1251 int border = FRAME_INTERNAL_BORDER_WIDTH (f);
1252 int width = FRAME_PIXEL_WIDTH (f);
1253 int height = FRAME_PIXEL_HEIGHT (f);
1254 int margin = FRAME_TOP_MARGIN_HEIGHT (f);
1256 block_input ();
1257 x_clear_area (f, 0, 0, border, height);
1258 x_clear_area (f, 0, margin, width, border);
1259 x_clear_area (f, width - border, 0, border, height);
1260 x_clear_area (f, 0, height - border, width, border);
1261 unblock_input ();
1264 #endif
1266 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
1267 arrow bitmaps, or clear the fringes if no bitmaps are required
1268 before DESIRED_ROW is made current. This function is called from
1269 update_window_line only if it is known that there are differences
1270 between bitmaps to be drawn between current row and DESIRED_ROW. */
1272 static void
1273 x_after_update_window_line (struct window *w, struct glyph_row *desired_row)
1275 eassert (w);
1277 if (!desired_row->mode_line_p && !w->pseudo_window_p)
1278 desired_row->redraw_fringe_bitmaps_p = true;
1280 #ifdef USE_X_TOOLKIT
1281 /* When a window has disappeared, make sure that no rest of
1282 full-width rows stays visible in the internal border. Could
1283 check here if updated window is the leftmost/rightmost window,
1284 but I guess it's not worth doing since vertically split windows
1285 are almost never used, internal border is rarely set, and the
1286 overhead is very small. */
1288 struct frame *f;
1289 int width, height;
1291 if (windows_or_buffers_changed
1292 && desired_row->full_width_p
1293 && (f = XFRAME (w->frame),
1294 width = FRAME_INTERNAL_BORDER_WIDTH (f),
1295 width != 0)
1296 && (height = desired_row->visible_height,
1297 height > 0))
1299 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
1301 block_input ();
1302 x_clear_area (f, 0, y, width, height);
1303 x_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
1304 unblock_input ();
1307 #endif
1310 static void
1311 x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fringe_bitmap_params *p)
1313 struct frame *f = XFRAME (WINDOW_FRAME (w));
1314 Display *display = FRAME_X_DISPLAY (f);
1315 GC gc = f->output_data.x->normal_gc;
1316 struct face *face = p->face;
1318 /* Must clip because of partially visible lines. */
1319 x_clip_to_row (w, row, ANY_AREA, gc);
1321 if (p->bx >= 0 && !p->overlay_p)
1323 /* In case the same realized face is used for fringes and
1324 for something displayed in the text (e.g. face `region' on
1325 mono-displays, the fill style may have been changed to
1326 FillSolid in x_draw_glyph_string_background. */
1327 if (face->stipple)
1328 XSetFillStyle (display, face->gc, FillOpaqueStippled);
1329 else
1330 XSetForeground (display, face->gc, face->background);
1332 x_fill_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
1334 if (!face->stipple)
1335 XSetForeground (display, face->gc, face->foreground);
1338 #ifdef USE_CAIRO
1339 if (p->which && p->which < max_fringe_bmp)
1341 XGCValues gcv;
1343 XGetGCValues (display, gc, GCForeground | GCBackground, &gcv);
1344 XSetForeground (display, gc, (p->cursor_p
1345 ? (p->overlay_p ? face->background
1346 : f->output_data.x->cursor_pixel)
1347 : face->foreground));
1348 XSetBackground (display, gc, face->background);
1349 x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, p->dh,
1350 p->wd, p->h, p->x, p->y, p->overlay_p);
1351 XSetForeground (display, gc, gcv.foreground);
1352 XSetBackground (display, gc, gcv.background);
1354 #else /* not USE_CAIRO */
1355 if (p->which)
1357 Window window = FRAME_X_WINDOW (f);
1358 char *bits;
1359 Pixmap pixmap, clipmask = (Pixmap) 0;
1360 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
1361 XGCValues gcv;
1363 if (p->wd > 8)
1364 bits = (char *) (p->bits + p->dh);
1365 else
1366 bits = (char *) p->bits + p->dh;
1368 /* Draw the bitmap. I believe these small pixmaps can be cached
1369 by the server. */
1370 pixmap = XCreatePixmapFromBitmapData (display, window, bits, p->wd, p->h,
1371 (p->cursor_p
1372 ? (p->overlay_p ? face->background
1373 : f->output_data.x->cursor_pixel)
1374 : face->foreground),
1375 face->background, depth);
1377 if (p->overlay_p)
1379 clipmask = XCreatePixmapFromBitmapData (display,
1380 FRAME_DISPLAY_INFO (f)->root_window,
1381 bits, p->wd, p->h,
1382 1, 0, 1);
1383 gcv.clip_mask = clipmask;
1384 gcv.clip_x_origin = p->x;
1385 gcv.clip_y_origin = p->y;
1386 XChangeGC (display, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
1389 XCopyArea (display, pixmap, window, gc, 0, 0,
1390 p->wd, p->h, p->x, p->y);
1391 XFreePixmap (display, pixmap);
1393 if (p->overlay_p)
1395 gcv.clip_mask = (Pixmap) 0;
1396 XChangeGC (display, gc, GCClipMask, &gcv);
1397 XFreePixmap (display, clipmask);
1400 #endif /* not USE_CAIRO */
1402 x_reset_clip_rectangles (f, gc);
1405 /***********************************************************************
1406 Glyph display
1407 ***********************************************************************/
1411 static void x_set_glyph_string_clipping (struct glyph_string *);
1412 static void x_set_glyph_string_gc (struct glyph_string *);
1413 static void x_draw_glyph_string_foreground (struct glyph_string *);
1414 static void x_draw_composite_glyph_string_foreground (struct glyph_string *);
1415 static void x_draw_glyph_string_box (struct glyph_string *);
1416 static void x_draw_glyph_string (struct glyph_string *);
1417 static _Noreturn void x_delete_glyphs (struct frame *, int);
1418 static void x_compute_glyph_string_overhangs (struct glyph_string *);
1419 static void x_set_cursor_gc (struct glyph_string *);
1420 static void x_set_mode_line_face_gc (struct glyph_string *);
1421 static void x_set_mouse_face_gc (struct glyph_string *);
1422 static bool x_alloc_lighter_color (struct frame *, Display *, Colormap,
1423 unsigned long *, double, int);
1424 static void x_setup_relief_color (struct frame *, struct relief *,
1425 double, int, unsigned long);
1426 static void x_setup_relief_colors (struct glyph_string *);
1427 static void x_draw_image_glyph_string (struct glyph_string *);
1428 static void x_draw_image_relief (struct glyph_string *);
1429 static void x_draw_image_foreground (struct glyph_string *);
1430 static void x_draw_image_foreground_1 (struct glyph_string *, Pixmap);
1431 static void x_clear_glyph_string_rect (struct glyph_string *, int,
1432 int, int, int);
1433 static void x_draw_relief_rect (struct frame *, int, int, int, int,
1434 int, bool, bool, bool, bool, bool,
1435 XRectangle *);
1436 static void x_draw_box_rect (struct glyph_string *, int, int, int, int,
1437 int, bool, bool, XRectangle *);
1438 static void x_scroll_bar_clear (struct frame *);
1440 #ifdef GLYPH_DEBUG
1441 static void x_check_font (struct frame *, struct font *);
1442 #endif
1445 /* Set S->gc to a suitable GC for drawing glyph string S in cursor
1446 face. */
1448 static void
1449 x_set_cursor_gc (struct glyph_string *s)
1451 if (s->font == FRAME_FONT (s->f)
1452 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
1453 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
1454 && !s->cmp)
1455 s->gc = s->f->output_data.x->cursor_gc;
1456 else
1458 /* Cursor on non-default face: must merge. */
1459 XGCValues xgcv;
1460 unsigned long mask;
1462 xgcv.background = s->f->output_data.x->cursor_pixel;
1463 xgcv.foreground = s->face->background;
1465 /* If the glyph would be invisible, try a different foreground. */
1466 if (xgcv.foreground == xgcv.background)
1467 xgcv.foreground = s->face->foreground;
1468 if (xgcv.foreground == xgcv.background)
1469 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
1470 if (xgcv.foreground == xgcv.background)
1471 xgcv.foreground = s->face->foreground;
1473 /* Make sure the cursor is distinct from text in this face. */
1474 if (xgcv.background == s->face->background
1475 && xgcv.foreground == s->face->foreground)
1477 xgcv.background = s->face->foreground;
1478 xgcv.foreground = s->face->background;
1481 IF_DEBUG (x_check_font (s->f, s->font));
1482 xgcv.graphics_exposures = False;
1483 mask = GCForeground | GCBackground | GCGraphicsExposures;
1485 if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1486 XChangeGC (s->display, FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1487 mask, &xgcv);
1488 else
1489 FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
1490 = XCreateGC (s->display, s->window, mask, &xgcv);
1492 s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1497 /* Set up S->gc of glyph string S for drawing text in mouse face. */
1499 static void
1500 x_set_mouse_face_gc (struct glyph_string *s)
1502 int face_id;
1503 struct face *face;
1505 /* What face has to be used last for the mouse face? */
1506 face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
1507 face = FACE_FROM_ID_OR_NULL (s->f, face_id);
1508 if (face == NULL)
1509 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1511 if (s->first_glyph->type == CHAR_GLYPH)
1512 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
1513 else
1514 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
1515 s->face = FACE_FROM_ID (s->f, face_id);
1516 prepare_face_for_display (s->f, s->face);
1518 if (s->font == s->face->font)
1519 s->gc = s->face->gc;
1520 else
1522 /* Otherwise construct scratch_cursor_gc with values from FACE
1523 except for FONT. */
1524 XGCValues xgcv;
1525 unsigned long mask;
1527 xgcv.background = s->face->background;
1528 xgcv.foreground = s->face->foreground;
1529 xgcv.graphics_exposures = False;
1530 mask = GCForeground | GCBackground | GCGraphicsExposures;
1532 if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1533 XChangeGC (s->display, FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1534 mask, &xgcv);
1535 else
1536 FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
1537 = XCreateGC (s->display, s->window, mask, &xgcv);
1539 s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1542 eassert (s->gc != 0);
1546 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
1547 Faces to use in the mode line have already been computed when the
1548 matrix was built, so there isn't much to do, here. */
1550 static void
1551 x_set_mode_line_face_gc (struct glyph_string *s)
1553 s->gc = s->face->gc;
1557 /* Set S->gc of glyph string S for drawing that glyph string. Set
1558 S->stippled_p to a non-zero value if the face of S has a stipple
1559 pattern. */
1561 static void
1562 x_set_glyph_string_gc (struct glyph_string *s)
1564 prepare_face_for_display (s->f, s->face);
1566 if (s->hl == DRAW_NORMAL_TEXT)
1568 s->gc = s->face->gc;
1569 s->stippled_p = s->face->stipple != 0;
1571 else if (s->hl == DRAW_INVERSE_VIDEO)
1573 x_set_mode_line_face_gc (s);
1574 s->stippled_p = s->face->stipple != 0;
1576 else if (s->hl == DRAW_CURSOR)
1578 x_set_cursor_gc (s);
1579 s->stippled_p = false;
1581 else if (s->hl == DRAW_MOUSE_FACE)
1583 x_set_mouse_face_gc (s);
1584 s->stippled_p = s->face->stipple != 0;
1586 else if (s->hl == DRAW_IMAGE_RAISED
1587 || s->hl == DRAW_IMAGE_SUNKEN)
1589 s->gc = s->face->gc;
1590 s->stippled_p = s->face->stipple != 0;
1592 else
1593 emacs_abort ();
1595 /* GC must have been set. */
1596 eassert (s->gc != 0);
1600 /* Set clipping for output of glyph string S. S may be part of a mode
1601 line or menu if we don't have X toolkit support. */
1603 static void
1604 x_set_glyph_string_clipping (struct glyph_string *s)
1606 XRectangle *r = s->clip;
1607 int n = get_glyph_string_clip_rects (s, r, 2);
1609 if (n > 0)
1610 x_set_clip_rectangles (s->f, s->gc, r, n);
1611 s->num_clips = n;
1615 /* Set SRC's clipping for output of glyph string DST. This is called
1616 when we are drawing DST's left_overhang or right_overhang only in
1617 the area of SRC. */
1619 static void
1620 x_set_glyph_string_clipping_exactly (struct glyph_string *src, struct glyph_string *dst)
1622 XRectangle r;
1624 r.x = src->x;
1625 r.width = src->width;
1626 r.y = src->y;
1627 r.height = src->height;
1628 dst->clip[0] = r;
1629 dst->num_clips = 1;
1630 x_set_clip_rectangles (dst->f, dst->gc, &r, 1);
1634 /* RIF:
1635 Compute left and right overhang of glyph string S. */
1637 static void
1638 x_compute_glyph_string_overhangs (struct glyph_string *s)
1640 if (s->cmp == NULL
1641 && (s->first_glyph->type == CHAR_GLYPH
1642 || s->first_glyph->type == COMPOSITE_GLYPH))
1644 struct font_metrics metrics;
1646 if (s->first_glyph->type == CHAR_GLYPH)
1648 unsigned *code = alloca (sizeof (unsigned) * s->nchars);
1649 struct font *font = s->font;
1650 int i;
1652 for (i = 0; i < s->nchars; i++)
1653 code[i] = (s->char2b[i].byte1 << 8) | s->char2b[i].byte2;
1654 font->driver->text_extents (font, code, s->nchars, &metrics);
1656 else
1658 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1660 composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics);
1662 s->right_overhang = (metrics.rbearing > metrics.width
1663 ? metrics.rbearing - metrics.width : 0);
1664 s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0;
1666 else if (s->cmp)
1668 s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
1669 s->left_overhang = - s->cmp->lbearing;
1674 /* Fill rectangle X, Y, W, H with background color of glyph string S. */
1676 static void
1677 x_clear_glyph_string_rect (struct glyph_string *s, int x, int y, int w, int h)
1679 XGCValues xgcv;
1680 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
1681 XSetForeground (s->display, s->gc, xgcv.background);
1682 x_fill_rectangle (s->f, s->gc, x, y, w, h);
1683 XSetForeground (s->display, s->gc, xgcv.foreground);
1687 /* Draw the background of glyph_string S. If S->background_filled_p
1688 is non-zero don't draw it. FORCE_P non-zero means draw the
1689 background even if it wouldn't be drawn normally. This is used
1690 when a string preceding S draws into the background of S, or S
1691 contains the first component of a composition. */
1693 static void
1694 x_draw_glyph_string_background (struct glyph_string *s, bool force_p)
1696 /* Nothing to do if background has already been drawn or if it
1697 shouldn't be drawn in the first place. */
1698 if (!s->background_filled_p)
1700 int box_line_width = max (s->face->box_line_width, 0);
1702 if (s->stippled_p)
1704 /* Fill background with a stipple pattern. */
1705 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
1706 x_fill_rectangle (s->f, s->gc, s->x,
1707 s->y + box_line_width,
1708 s->background_width,
1709 s->height - 2 * box_line_width);
1710 XSetFillStyle (s->display, s->gc, FillSolid);
1711 s->background_filled_p = true;
1713 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
1714 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust
1715 font dimensions, since the actual glyphs might be
1716 much smaller. So in that case we always clear the
1717 rectangle with background color. */
1718 || FONT_TOO_HIGH (s->font)
1719 || s->font_not_found_p
1720 || s->extends_to_end_of_line_p
1721 || force_p)
1723 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
1724 s->background_width,
1725 s->height - 2 * box_line_width);
1726 s->background_filled_p = true;
1732 /* Draw the foreground of glyph string S. */
1734 static void
1735 x_draw_glyph_string_foreground (struct glyph_string *s)
1737 int i, x;
1739 /* If first glyph of S has a left box line, start drawing the text
1740 of S to the right of that box line. */
1741 if (s->face->box != FACE_NO_BOX
1742 && s->first_glyph->left_box_line_p)
1743 x = s->x + eabs (s->face->box_line_width);
1744 else
1745 x = s->x;
1747 /* Draw characters of S as rectangles if S's font could not be
1748 loaded. */
1749 if (s->font_not_found_p)
1751 for (i = 0; i < s->nchars; ++i)
1753 struct glyph *g = s->first_glyph + i;
1754 x_draw_rectangle (s->f,
1755 s->gc, x, s->y, g->pixel_width - 1,
1756 s->height - 1);
1757 x += g->pixel_width;
1760 else
1762 struct font *font = s->font;
1763 int boff = font->baseline_offset;
1764 int y;
1766 if (font->vertical_centering)
1767 boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff;
1769 y = s->ybase - boff;
1770 if (s->for_overlaps
1771 || (s->background_filled_p && s->hl != DRAW_CURSOR))
1772 font->driver->draw (s, 0, s->nchars, x, y, false);
1773 else
1774 font->driver->draw (s, 0, s->nchars, x, y, true);
1775 if (s->face->overstrike)
1776 font->driver->draw (s, 0, s->nchars, x + 1, y, false);
1780 /* Draw the foreground of composite glyph string S. */
1782 static void
1783 x_draw_composite_glyph_string_foreground (struct glyph_string *s)
1785 int i, j, x;
1786 struct font *font = s->font;
1788 /* If first glyph of S has a left box line, start drawing the text
1789 of S to the right of that box line. */
1790 if (s->face && s->face->box != FACE_NO_BOX
1791 && s->first_glyph->left_box_line_p)
1792 x = s->x + eabs (s->face->box_line_width);
1793 else
1794 x = s->x;
1796 /* S is a glyph string for a composition. S->cmp_from is the index
1797 of the first character drawn for glyphs of this composition.
1798 S->cmp_from == 0 means we are drawing the very first character of
1799 this composition. */
1801 /* Draw a rectangle for the composition if the font for the very
1802 first character of the composition could not be loaded. */
1803 if (s->font_not_found_p)
1805 if (s->cmp_from == 0)
1806 x_draw_rectangle (s->f, s->gc, x, s->y,
1807 s->width - 1, s->height - 1);
1809 else if (! s->first_glyph->u.cmp.automatic)
1811 int y = s->ybase;
1813 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
1814 /* TAB in a composition means display glyphs with padding
1815 space on the left or right. */
1816 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
1818 int xx = x + s->cmp->offsets[j * 2];
1819 int yy = y - s->cmp->offsets[j * 2 + 1];
1821 font->driver->draw (s, j, j + 1, xx, yy, false);
1822 if (s->face->overstrike)
1823 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
1826 else
1828 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1829 Lisp_Object glyph;
1830 int y = s->ybase;
1831 int width = 0;
1833 for (i = j = s->cmp_from; i < s->cmp_to; i++)
1835 glyph = LGSTRING_GLYPH (gstring, i);
1836 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1837 width += LGLYPH_WIDTH (glyph);
1838 else
1840 int xoff, yoff, wadjust;
1842 if (j < i)
1844 font->driver->draw (s, j, i, x, y, false);
1845 if (s->face->overstrike)
1846 font->driver->draw (s, j, i, x + 1, y, false);
1847 x += width;
1849 xoff = LGLYPH_XOFF (glyph);
1850 yoff = LGLYPH_YOFF (glyph);
1851 wadjust = LGLYPH_WADJUST (glyph);
1852 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
1853 if (s->face->overstrike)
1854 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
1855 false);
1856 x += wadjust;
1857 j = i + 1;
1858 width = 0;
1861 if (j < i)
1863 font->driver->draw (s, j, i, x, y, false);
1864 if (s->face->overstrike)
1865 font->driver->draw (s, j, i, x + 1, y, false);
1871 /* Draw the foreground of glyph string S for glyphless characters. */
1873 static void
1874 x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
1876 struct glyph *glyph = s->first_glyph;
1877 XChar2b char2b[8];
1878 int x, i, j;
1880 /* If first glyph of S has a left box line, start drawing the text
1881 of S to the right of that box line. */
1882 if (s->face && s->face->box != FACE_NO_BOX
1883 && s->first_glyph->left_box_line_p)
1884 x = s->x + eabs (s->face->box_line_width);
1885 else
1886 x = s->x;
1888 s->char2b = char2b;
1890 for (i = 0; i < s->nchars; i++, glyph++)
1892 char buf[7], *str = NULL;
1893 int len = glyph->u.glyphless.len;
1895 if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
1897 if (len > 0
1898 && CHAR_TABLE_P (Vglyphless_char_display)
1899 && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
1900 >= 1))
1902 Lisp_Object acronym
1903 = (! glyph->u.glyphless.for_no_font
1904 ? CHAR_TABLE_REF (Vglyphless_char_display,
1905 glyph->u.glyphless.ch)
1906 : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
1907 if (STRINGP (acronym))
1908 str = SSDATA (acronym);
1911 else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE)
1913 sprintf (buf, "%0*X",
1914 glyph->u.glyphless.ch < 0x10000 ? 4 : 6,
1915 glyph->u.glyphless.ch + 0u);
1916 str = buf;
1919 if (str)
1921 int upper_len = (len + 1) / 2;
1922 unsigned code;
1924 /* It is assured that all LEN characters in STR is ASCII. */
1925 for (j = 0; j < len; j++)
1927 code = s->font->driver->encode_char (s->font, str[j]);
1928 STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF);
1930 s->font->driver->draw (s, 0, upper_len,
1931 x + glyph->slice.glyphless.upper_xoff,
1932 s->ybase + glyph->slice.glyphless.upper_yoff,
1933 false);
1934 s->font->driver->draw (s, upper_len, len,
1935 x + glyph->slice.glyphless.lower_xoff,
1936 s->ybase + glyph->slice.glyphless.lower_yoff,
1937 false);
1939 if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
1940 x_draw_rectangle (s->f, s->gc,
1941 x, s->ybase - glyph->ascent,
1942 glyph->pixel_width - 1,
1943 glyph->ascent + glyph->descent - 1);
1944 x += glyph->pixel_width;
1948 #ifdef USE_X_TOOLKIT
1950 #ifdef USE_LUCID
1952 /* Return the frame on which widget WIDGET is used.. Abort if frame
1953 cannot be determined. */
1955 static struct frame *
1956 x_frame_of_widget (Widget widget)
1958 struct x_display_info *dpyinfo;
1959 Lisp_Object tail, frame;
1960 struct frame *f;
1962 dpyinfo = x_display_info_for_display (XtDisplay (widget));
1964 /* Find the top-level shell of the widget. Note that this function
1965 can be called when the widget is not yet realized, so XtWindow
1966 (widget) == 0. That's the reason we can't simply use
1967 x_any_window_to_frame. */
1968 while (!XtIsTopLevelShell (widget))
1969 widget = XtParent (widget);
1971 /* Look for a frame with that top-level widget. Allocate the color
1972 on that frame to get the right gamma correction value. */
1973 FOR_EACH_FRAME (tail, frame)
1975 f = XFRAME (frame);
1976 if (FRAME_X_P (f)
1977 && f->output_data.nothing != 1
1978 && FRAME_DISPLAY_INFO (f) == dpyinfo
1979 && f->output_data.x->widget == widget)
1980 return f;
1982 emacs_abort ();
1985 /* Allocate a color which is lighter or darker than *PIXEL by FACTOR
1986 or DELTA. Try a color with RGB values multiplied by FACTOR first.
1987 If this produces the same color as PIXEL, try a color where all RGB
1988 values have DELTA added. Return the allocated color in *PIXEL.
1989 DISPLAY is the X display, CMAP is the colormap to operate on.
1990 Value is true if successful. */
1992 bool
1993 x_alloc_lighter_color_for_widget (Widget widget, Display *display, Colormap cmap,
1994 unsigned long *pixel, double factor, int delta)
1996 struct frame *f = x_frame_of_widget (widget);
1997 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
2000 #endif /* USE_LUCID */
2003 /* Structure specifying which arguments should be passed by Xt to
2004 cvt_string_to_pixel. We want the widget's screen and colormap. */
2006 static XtConvertArgRec cvt_string_to_pixel_args[] =
2008 {XtWidgetBaseOffset, (XtPointer) offsetof (WidgetRec, core.screen),
2009 sizeof (Screen *)},
2010 {XtWidgetBaseOffset, (XtPointer) offsetof (WidgetRec, core.colormap),
2011 sizeof (Colormap)}
2015 /* The address of this variable is returned by
2016 cvt_string_to_pixel. */
2018 static Pixel cvt_string_to_pixel_value;
2021 /* Convert a color name to a pixel color.
2023 DPY is the display we are working on.
2025 ARGS is an array of *NARGS XrmValue structures holding additional
2026 information about the widget for which the conversion takes place.
2027 The contents of this array are determined by the specification
2028 in cvt_string_to_pixel_args.
2030 FROM is a pointer to an XrmValue which points to the color name to
2031 convert. TO is an XrmValue in which to return the pixel color.
2033 CLOSURE_RET is a pointer to user-data, in which we record if
2034 we allocated the color or not.
2036 Value is True if successful, False otherwise. */
2038 static Boolean
2039 cvt_string_to_pixel (Display *dpy, XrmValue *args, Cardinal *nargs,
2040 XrmValue *from, XrmValue *to,
2041 XtPointer *closure_ret)
2043 Screen *screen;
2044 Colormap cmap;
2045 Pixel pixel;
2046 String color_name;
2047 XColor color;
2049 if (*nargs != 2)
2051 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
2052 "wrongParameters", "cvt_string_to_pixel",
2053 "XtToolkitError",
2054 "Screen and colormap args required", NULL, NULL);
2055 return False;
2058 screen = *(Screen **) args[0].addr;
2059 cmap = *(Colormap *) args[1].addr;
2060 color_name = (String) from->addr;
2062 if (strcmp (color_name, XtDefaultBackground) == 0)
2064 *closure_ret = (XtPointer) False;
2065 pixel = WhitePixelOfScreen (screen);
2067 else if (strcmp (color_name, XtDefaultForeground) == 0)
2069 *closure_ret = (XtPointer) False;
2070 pixel = BlackPixelOfScreen (screen);
2072 else if (XParseColor (dpy, cmap, color_name, &color)
2073 && x_alloc_nearest_color_1 (dpy, cmap, &color))
2075 pixel = color.pixel;
2076 *closure_ret = (XtPointer) True;
2078 else
2080 String params[1];
2081 Cardinal nparams = 1;
2083 params[0] = color_name;
2084 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
2085 "badValue", "cvt_string_to_pixel",
2086 "XtToolkitError", "Invalid color '%s'",
2087 params, &nparams);
2088 return False;
2091 if (to->addr != NULL)
2093 if (to->size < sizeof (Pixel))
2095 to->size = sizeof (Pixel);
2096 return False;
2099 *(Pixel *) to->addr = pixel;
2101 else
2103 cvt_string_to_pixel_value = pixel;
2104 to->addr = (XtPointer) &cvt_string_to_pixel_value;
2107 to->size = sizeof (Pixel);
2108 return True;
2112 /* Free a pixel color which was previously allocated via
2113 cvt_string_to_pixel. This is registered as the destructor
2114 for this type of resource via XtSetTypeConverter.
2116 APP is the application context in which we work.
2118 TO is a pointer to an XrmValue holding the color to free.
2119 CLOSURE is the value we stored in CLOSURE_RET for this color
2120 in cvt_string_to_pixel.
2122 ARGS and NARGS are like for cvt_string_to_pixel. */
2124 static void
2125 cvt_pixel_dtor (XtAppContext app, XrmValuePtr to, XtPointer closure, XrmValuePtr args,
2126 Cardinal *nargs)
2128 if (*nargs != 2)
2130 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
2131 "XtToolkitError",
2132 "Screen and colormap arguments required",
2133 NULL, NULL);
2135 else if (closure != NULL)
2137 /* We did allocate the pixel, so free it. */
2138 Screen *screen = *(Screen **) args[0].addr;
2139 Colormap cmap = *(Colormap *) args[1].addr;
2140 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
2141 (Pixel *) to->addr, 1);
2146 #endif /* USE_X_TOOLKIT */
2149 /* Value is an array of XColor structures for the contents of the
2150 color map of display DPY. Set *NCELLS to the size of the array.
2151 Note that this probably shouldn't be called for large color maps,
2152 say a 24-bit TrueColor map. */
2154 static const XColor *
2155 x_color_cells (Display *dpy, int *ncells)
2157 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
2158 eassume (dpyinfo);
2160 if (dpyinfo->color_cells == NULL)
2162 Screen *screen = dpyinfo->screen;
2163 int ncolor_cells = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
2164 int i;
2166 dpyinfo->color_cells = xnmalloc (ncolor_cells,
2167 sizeof *dpyinfo->color_cells);
2168 dpyinfo->ncolor_cells = ncolor_cells;
2170 for (i = 0; i < ncolor_cells; ++i)
2171 dpyinfo->color_cells[i].pixel = i;
2173 XQueryColors (dpy, dpyinfo->cmap,
2174 dpyinfo->color_cells, ncolor_cells);
2177 *ncells = dpyinfo->ncolor_cells;
2178 return dpyinfo->color_cells;
2182 /* On frame F, translate pixel colors to RGB values for the NCOLORS
2183 colors in COLORS. Use cached information, if available. */
2185 void
2186 x_query_colors (struct frame *f, XColor *colors, int ncolors)
2188 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2190 if (dpyinfo->red_bits > 0)
2192 /* For TrueColor displays, we can decompose the RGB value
2193 directly. */
2194 int i;
2195 unsigned int rmult, gmult, bmult;
2196 unsigned int rmask, gmask, bmask;
2198 rmask = (1 << dpyinfo->red_bits) - 1;
2199 gmask = (1 << dpyinfo->green_bits) - 1;
2200 bmask = (1 << dpyinfo->blue_bits) - 1;
2201 /* If we're widening, for example, 8 bits in the pixel value to
2202 16 bits for the separate-color representation, we want to
2203 extrapolate the lower bits based on those bits available --
2204 in other words, we'd like 0xff to become 0xffff instead of
2205 the 0xff00 we'd get by just zero-filling the lower bits.
2207 We generate a 32-bit scaled-up value and shift it, in case
2208 the bit count doesn't divide 16 evenly (e.g., when dealing
2209 with a 3-3-2 bit RGB display), to get more of the lower bits
2210 correct.
2212 Should we cache the multipliers in dpyinfo? Maybe
2213 special-case the 8-8-8 common case? */
2214 rmult = 0xffffffff / rmask;
2215 gmult = 0xffffffff / gmask;
2216 bmult = 0xffffffff / bmask;
2218 for (i = 0; i < ncolors; ++i)
2220 unsigned int r, g, b;
2221 unsigned long pixel = colors[i].pixel;
2223 r = (pixel >> dpyinfo->red_offset) & rmask;
2224 g = (pixel >> dpyinfo->green_offset) & gmask;
2225 b = (pixel >> dpyinfo->blue_offset) & bmask;
2227 colors[i].red = (r * rmult) >> 16;
2228 colors[i].green = (g * gmult) >> 16;
2229 colors[i].blue = (b * bmult) >> 16;
2231 return;
2234 if (dpyinfo->color_cells)
2236 int i;
2237 for (i = 0; i < ncolors; ++i)
2239 unsigned long pixel = colors[i].pixel;
2240 eassert (pixel < dpyinfo->ncolor_cells);
2241 eassert (dpyinfo->color_cells[pixel].pixel == pixel);
2242 colors[i] = dpyinfo->color_cells[pixel];
2244 return;
2247 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
2251 /* On frame F, translate pixel color to RGB values for the color in
2252 COLOR. Use cached information, if available. */
2254 void
2255 x_query_color (struct frame *f, XColor *color)
2257 x_query_colors (f, color, 1);
2261 /* On frame F, translate the color name to RGB values. Use cached
2262 information, if possible.
2264 Note that there is currently no way to clean old entries out of the
2265 cache. However, it is limited to names in the server's database,
2266 and names we've actually looked up; list-colors-display is probably
2267 the most color-intensive case we're likely to hit. */
2269 Status x_parse_color (struct frame *f, const char *color_name,
2270 XColor *color)
2272 Display *dpy = FRAME_X_DISPLAY (f);
2273 Colormap cmap = FRAME_X_COLORMAP (f);
2274 struct color_name_cache_entry *cache_entry;
2276 if (color_name[0] == '#')
2278 /* The hex form is parsed directly by XParseColor without
2279 talking to the X server. No need for caching. */
2280 return XParseColor (dpy, cmap, color_name, color);
2283 for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names; cache_entry;
2284 cache_entry = cache_entry->next)
2286 if (!xstrcasecmp(cache_entry->name, color_name))
2288 *color = cache_entry->rgb;
2289 return 1;
2293 if (XParseColor (dpy, cmap, color_name, color) == 0)
2294 /* No caching of negative results, currently. */
2295 return 0;
2297 cache_entry = xzalloc (sizeof *cache_entry);
2298 cache_entry->rgb = *color;
2299 cache_entry->name = xstrdup (color_name);
2300 cache_entry->next = FRAME_DISPLAY_INFO (f)->color_names;
2301 FRAME_DISPLAY_INFO (f)->color_names = cache_entry;
2302 return 1;
2306 /* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
2307 exact match can't be allocated, try the nearest color available.
2308 Value is true if successful. Set *COLOR to the color
2309 allocated. */
2311 static bool
2312 x_alloc_nearest_color_1 (Display *dpy, Colormap cmap, XColor *color)
2314 bool rc;
2316 rc = XAllocColor (dpy, cmap, color) != 0;
2317 if (rc == 0)
2319 /* If we got to this point, the colormap is full, so we're going
2320 to try to get the next closest color. The algorithm used is
2321 a least-squares matching, which is what X uses for closest
2322 color matching with StaticColor visuals. */
2323 int nearest, i;
2324 int max_color_delta = 255;
2325 int max_delta = 3 * max_color_delta;
2326 int nearest_delta = max_delta + 1;
2327 int ncells;
2328 const XColor *cells = x_color_cells (dpy, &ncells);
2330 for (nearest = i = 0; i < ncells; ++i)
2332 int dred = (color->red >> 8) - (cells[i].red >> 8);
2333 int dgreen = (color->green >> 8) - (cells[i].green >> 8);
2334 int dblue = (color->blue >> 8) - (cells[i].blue >> 8);
2335 int delta = dred * dred + dgreen * dgreen + dblue * dblue;
2337 if (delta < nearest_delta)
2339 nearest = i;
2340 nearest_delta = delta;
2344 color->red = cells[nearest].red;
2345 color->green = cells[nearest].green;
2346 color->blue = cells[nearest].blue;
2347 rc = XAllocColor (dpy, cmap, color) != 0;
2349 else
2351 /* If allocation succeeded, and the allocated pixel color is not
2352 equal to a cached pixel color recorded earlier, there was a
2353 change in the colormap, so clear the color cache. */
2354 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
2355 eassume (dpyinfo);
2357 if (dpyinfo->color_cells)
2359 XColor *cached_color = &dpyinfo->color_cells[color->pixel];
2360 if (cached_color->red != color->red
2361 || cached_color->blue != color->blue
2362 || cached_color->green != color->green)
2364 xfree (dpyinfo->color_cells);
2365 dpyinfo->color_cells = NULL;
2366 dpyinfo->ncolor_cells = 0;
2371 #ifdef DEBUG_X_COLORS
2372 if (rc)
2373 register_color (color->pixel);
2374 #endif /* DEBUG_X_COLORS */
2376 return rc;
2380 /* Allocate the color COLOR->pixel on frame F, colormap CMAP, after
2381 gamma correction. If an exact match can't be allocated, try the
2382 nearest color available. Value is true if successful. Set *COLOR
2383 to the color allocated. */
2385 bool
2386 x_alloc_nearest_color (struct frame *f, Colormap cmap, XColor *color)
2388 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2390 gamma_correct (f, color);
2392 if (dpyinfo->red_bits > 0)
2394 color->pixel = x_make_truecolor_pixel (dpyinfo,
2395 color->red,
2396 color->green,
2397 color->blue);
2398 return true;
2401 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
2405 /* Allocate color PIXEL on frame F. PIXEL must already be allocated.
2406 It's necessary to do this instead of just using PIXEL directly to
2407 get color reference counts right. */
2409 unsigned long
2410 x_copy_color (struct frame *f, unsigned long pixel)
2412 XColor color;
2414 /* If display has an immutable color map, freeing colors is not
2415 necessary and some servers don't allow it. Since we won't free a
2416 color once we've allocated it, we don't need to re-allocate it to
2417 maintain the server's reference count. */
2418 if (!x_mutable_colormap (FRAME_X_VISUAL (f)))
2419 return pixel;
2421 color.pixel = pixel;
2422 block_input ();
2423 /* The color could still be found in the color_cells array. */
2424 x_query_color (f, &color);
2425 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
2426 unblock_input ();
2427 #ifdef DEBUG_X_COLORS
2428 register_color (pixel);
2429 #endif
2430 return color.pixel;
2434 /* Brightness beyond which a color won't have its highlight brightness
2435 boosted.
2437 Nominally, highlight colors for `3d' faces are calculated by
2438 brightening an object's color by a constant scale factor, but this
2439 doesn't yield good results for dark colors, so for colors who's
2440 brightness is less than this value (on a scale of 0-65535) have an
2441 use an additional additive factor.
2443 The value here is set so that the default menu-bar/mode-line color
2444 (grey75) will not have its highlights changed at all. */
2445 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
2448 /* Allocate a color which is lighter or darker than *PIXEL by FACTOR
2449 or DELTA. Try a color with RGB values multiplied by FACTOR first.
2450 If this produces the same color as PIXEL, try a color where all RGB
2451 values have DELTA added. Return the allocated color in *PIXEL.
2452 DISPLAY is the X display, CMAP is the colormap to operate on.
2453 Value is non-zero if successful. */
2455 static bool
2456 x_alloc_lighter_color (struct frame *f, Display *display, Colormap cmap,
2457 unsigned long *pixel, double factor, int delta)
2459 XColor color, new;
2460 long bright;
2461 bool success_p;
2463 /* Get RGB color values. */
2464 color.pixel = *pixel;
2465 x_query_color (f, &color);
2467 /* Change RGB values by specified FACTOR. Avoid overflow! */
2468 eassert (factor >= 0);
2469 new.red = min (0xffff, factor * color.red);
2470 new.green = min (0xffff, factor * color.green);
2471 new.blue = min (0xffff, factor * color.blue);
2473 /* Calculate brightness of COLOR. */
2474 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
2476 /* We only boost colors that are darker than
2477 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
2478 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
2479 /* Make an additive adjustment to NEW, because it's dark enough so
2480 that scaling by FACTOR alone isn't enough. */
2482 /* How far below the limit this color is (0 - 1, 1 being darker). */
2483 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
2484 /* The additive adjustment. */
2485 int min_delta = delta * dimness * factor / 2;
2487 if (factor < 1)
2489 new.red = max (0, new.red - min_delta);
2490 new.green = max (0, new.green - min_delta);
2491 new.blue = max (0, new.blue - min_delta);
2493 else
2495 new.red = min (0xffff, min_delta + new.red);
2496 new.green = min (0xffff, min_delta + new.green);
2497 new.blue = min (0xffff, min_delta + new.blue);
2501 /* Try to allocate the color. */
2502 success_p = x_alloc_nearest_color (f, cmap, &new);
2503 if (success_p)
2505 if (new.pixel == *pixel)
2507 /* If we end up with the same color as before, try adding
2508 delta to the RGB values. */
2509 x_free_colors (f, &new.pixel, 1);
2511 new.red = min (0xffff, delta + color.red);
2512 new.green = min (0xffff, delta + color.green);
2513 new.blue = min (0xffff, delta + color.blue);
2514 success_p = x_alloc_nearest_color (f, cmap, &new);
2516 else
2517 success_p = true;
2518 *pixel = new.pixel;
2521 return success_p;
2525 /* Set up the foreground color for drawing relief lines of glyph
2526 string S. RELIEF is a pointer to a struct relief containing the GC
2527 with which lines will be drawn. Use a color that is FACTOR or
2528 DELTA lighter or darker than the relief's background which is found
2529 in S->f->output_data.x->relief_background. If such a color cannot
2530 be allocated, use DEFAULT_PIXEL, instead. */
2532 static void
2533 x_setup_relief_color (struct frame *f, struct relief *relief, double factor,
2534 int delta, unsigned long default_pixel)
2536 XGCValues xgcv;
2537 struct x_output *di = f->output_data.x;
2538 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
2539 unsigned long pixel;
2540 unsigned long background = di->relief_background;
2541 Colormap cmap = FRAME_X_COLORMAP (f);
2542 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2543 Display *dpy = FRAME_X_DISPLAY (f);
2545 xgcv.graphics_exposures = False;
2546 xgcv.line_width = 1;
2548 /* Free previously allocated color. The color cell will be reused
2549 when it has been freed as many times as it was allocated, so this
2550 doesn't affect faces using the same colors. */
2551 if (relief->gc && relief->pixel != -1)
2553 x_free_colors (f, &relief->pixel, 1);
2554 relief->pixel = -1;
2557 /* Allocate new color. */
2558 xgcv.foreground = default_pixel;
2559 pixel = background;
2560 if (dpyinfo->n_planes != 1
2561 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
2562 xgcv.foreground = relief->pixel = pixel;
2564 if (relief->gc == 0)
2566 xgcv.stipple = dpyinfo->gray;
2567 mask |= GCStipple;
2568 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
2570 else
2571 XChangeGC (dpy, relief->gc, mask, &xgcv);
2575 /* Set up colors for the relief lines around glyph string S. */
2577 static void
2578 x_setup_relief_colors (struct glyph_string *s)
2580 struct x_output *di = s->f->output_data.x;
2581 unsigned long color;
2583 if (s->face->use_box_color_for_shadows_p)
2584 color = s->face->box_color;
2585 else if (s->first_glyph->type == IMAGE_GLYPH
2586 && s->img->pixmap
2587 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2588 color = IMAGE_BACKGROUND (s->img, s->f, 0);
2589 else
2591 XGCValues xgcv;
2593 /* Get the background color of the face. */
2594 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
2595 color = xgcv.background;
2598 if (di->white_relief.gc == 0
2599 || color != di->relief_background)
2601 di->relief_background = color;
2602 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
2603 WHITE_PIX_DEFAULT (s->f));
2604 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
2605 BLACK_PIX_DEFAULT (s->f));
2610 /* Draw a relief on frame F inside the rectangle given by LEFT_X,
2611 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
2612 to draw, it must be >= 0. RAISED_P means draw a raised
2613 relief. LEFT_P means draw a relief on the left side of
2614 the rectangle. RIGHT_P means draw a relief on the right
2615 side of the rectangle. CLIP_RECT is the clipping rectangle to use
2616 when drawing. */
2618 static void
2619 x_draw_relief_rect (struct frame *f,
2620 int left_x, int top_y, int right_x, int bottom_y,
2621 int width, bool raised_p, bool top_p, bool bot_p,
2622 bool left_p, bool right_p,
2623 XRectangle *clip_rect)
2625 #ifdef USE_CAIRO
2626 GC top_left_gc, bottom_right_gc;
2627 int corners = 0;
2629 if (raised_p)
2631 top_left_gc = f->output_data.x->white_relief.gc;
2632 bottom_right_gc = f->output_data.x->black_relief.gc;
2634 else
2636 top_left_gc = f->output_data.x->black_relief.gc;
2637 bottom_right_gc = f->output_data.x->white_relief.gc;
2640 x_set_clip_rectangles (f, top_left_gc, clip_rect, 1);
2641 x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1);
2643 if (left_p)
2645 x_fill_rectangle (f, top_left_gc, left_x, top_y,
2646 width, bottom_y + 1 - top_y);
2647 if (top_p)
2648 corners |= 1 << CORNER_TOP_LEFT;
2649 if (bot_p)
2650 corners |= 1 << CORNER_BOTTOM_LEFT;
2652 if (right_p)
2654 x_fill_rectangle (f, bottom_right_gc, right_x + 1 - width, top_y,
2655 width, bottom_y + 1 - top_y);
2656 if (top_p)
2657 corners |= 1 << CORNER_TOP_RIGHT;
2658 if (bot_p)
2659 corners |= 1 << CORNER_BOTTOM_RIGHT;
2661 if (top_p)
2663 if (!right_p)
2664 x_fill_rectangle (f, top_left_gc, left_x, top_y,
2665 right_x + 1 - left_x, width);
2666 else
2667 x_fill_trapezoid_for_relief (f, top_left_gc, left_x, top_y,
2668 right_x + 1 - left_x, width, 1);
2670 if (bot_p)
2672 if (!left_p)
2673 x_fill_rectangle (f, bottom_right_gc, left_x, bottom_y + 1 - width,
2674 right_x + 1 - left_x, width);
2675 else
2676 x_fill_trapezoid_for_relief (f, bottom_right_gc,
2677 left_x, bottom_y + 1 - width,
2678 right_x + 1 - left_x, width, 0);
2680 if (left_p && width != 1)
2681 x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
2682 1, bottom_y + 1 - top_y);
2683 if (top_p && width != 1)
2684 x_fill_rectangle (f, bottom_right_gc, left_x, top_y,
2685 right_x + 1 - left_x, 1);
2686 if (corners)
2688 XSetBackground (FRAME_X_DISPLAY (f), top_left_gc,
2689 FRAME_BACKGROUND_PIXEL (f));
2690 x_erase_corners_for_relief (f, top_left_gc, left_x, top_y,
2691 right_x - left_x + 1, bottom_y - top_y + 1,
2692 6, 1, corners);
2695 x_reset_clip_rectangles (f, top_left_gc);
2696 x_reset_clip_rectangles (f, bottom_right_gc);
2697 #else
2698 Display *dpy = FRAME_X_DISPLAY (f);
2699 Window window = FRAME_X_WINDOW (f);
2700 int i;
2701 GC gc;
2703 if (raised_p)
2704 gc = f->output_data.x->white_relief.gc;
2705 else
2706 gc = f->output_data.x->black_relief.gc;
2707 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
2709 /* This code is more complicated than it has to be, because of two
2710 minor hacks to make the boxes look nicer: (i) if width > 1, draw
2711 the outermost line using the black relief. (ii) Omit the four
2712 corner pixels. */
2714 /* Top. */
2715 if (top_p)
2717 if (width == 1)
2718 XDrawLine (dpy, window, gc,
2719 left_x + left_p, top_y,
2720 right_x + !right_p, top_y);
2722 for (i = 1; i < width; ++i)
2723 XDrawLine (dpy, window, gc,
2724 left_x + i * left_p, top_y + i,
2725 right_x + 1 - i * right_p, top_y + i);
2728 /* Left. */
2729 if (left_p)
2731 if (width == 1)
2732 XDrawLine (dpy, window, gc, left_x, top_y + 1, left_x, bottom_y);
2734 XClearArea (dpy, window, left_x, top_y, 1, 1, False);
2735 XClearArea (dpy, window, left_x, bottom_y, 1, 1, False);
2737 for (i = (width > 1 ? 1 : 0); i < width; ++i)
2738 XDrawLine (dpy, window, gc,
2739 left_x + i, top_y + (i + 1) * top_p,
2740 left_x + i, bottom_y + 1 - (i + 1) * bot_p);
2743 XSetClipMask (dpy, gc, None);
2744 if (raised_p)
2745 gc = f->output_data.x->black_relief.gc;
2746 else
2747 gc = f->output_data.x->white_relief.gc;
2748 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
2750 if (width > 1)
2752 /* Outermost top line. */
2753 if (top_p)
2754 XDrawLine (dpy, window, gc,
2755 left_x + left_p, top_y,
2756 right_x + !right_p, top_y);
2758 /* Outermost left line. */
2759 if (left_p)
2760 XDrawLine (dpy, window, gc, left_x, top_y + 1, left_x, bottom_y);
2763 /* Bottom. */
2764 if (bot_p)
2766 XDrawLine (dpy, window, gc,
2767 left_x + left_p, bottom_y,
2768 right_x + !right_p, bottom_y);
2769 for (i = 1; i < width; ++i)
2770 XDrawLine (dpy, window, gc,
2771 left_x + i * left_p, bottom_y - i,
2772 right_x + 1 - i * right_p, bottom_y - i);
2775 /* Right. */
2776 if (right_p)
2778 XClearArea (dpy, window, right_x, top_y, 1, 1, False);
2779 XClearArea (dpy, window, right_x, bottom_y, 1, 1, False);
2780 for (i = 0; i < width; ++i)
2781 XDrawLine (dpy, window, gc,
2782 right_x - i, top_y + (i + 1) * top_p,
2783 right_x - i, bottom_y + 1 - (i + 1) * bot_p);
2786 x_reset_clip_rectangles (f, gc);
2788 #endif
2792 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
2793 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
2794 draw, it must be >= 0. LEFT_P means draw a line on the
2795 left side of the rectangle. RIGHT_P means draw a line
2796 on the right side of the rectangle. CLIP_RECT is the clipping
2797 rectangle to use when drawing. */
2799 static void
2800 x_draw_box_rect (struct glyph_string *s,
2801 int left_x, int top_y, int right_x, int bottom_y, int width,
2802 bool left_p, bool right_p, XRectangle *clip_rect)
2804 XGCValues xgcv;
2806 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
2807 XSetForeground (s->display, s->gc, s->face->box_color);
2808 x_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
2810 /* Top. */
2811 x_fill_rectangle (s->f, s->gc,
2812 left_x, top_y, right_x - left_x + 1, width);
2814 /* Left. */
2815 if (left_p)
2816 x_fill_rectangle (s->f, s->gc,
2817 left_x, top_y, width, bottom_y - top_y + 1);
2819 /* Bottom. */
2820 x_fill_rectangle (s->f, s->gc,
2821 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
2823 /* Right. */
2824 if (right_p)
2825 x_fill_rectangle (s->f, s->gc,
2826 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
2828 XSetForeground (s->display, s->gc, xgcv.foreground);
2829 x_reset_clip_rectangles (s->f, s->gc);
2833 /* Draw a box around glyph string S. */
2835 static void
2836 x_draw_glyph_string_box (struct glyph_string *s)
2838 int width, left_x, right_x, top_y, bottom_y, last_x;
2839 bool raised_p, left_p, right_p;
2840 struct glyph *last_glyph;
2841 XRectangle clip_rect;
2843 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2844 ? WINDOW_RIGHT_EDGE_X (s->w)
2845 : window_box_right (s->w, s->area));
2847 /* The glyph that may have a right box line. */
2848 last_glyph = (s->cmp || s->img
2849 ? s->first_glyph
2850 : s->first_glyph + s->nchars - 1);
2852 width = eabs (s->face->box_line_width);
2853 raised_p = s->face->box == FACE_RAISED_BOX;
2854 left_x = s->x;
2855 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
2856 ? last_x - 1
2857 : min (last_x, s->x + s->background_width) - 1);
2858 top_y = s->y;
2859 bottom_y = top_y + s->height - 1;
2861 left_p = (s->first_glyph->left_box_line_p
2862 || (s->hl == DRAW_MOUSE_FACE
2863 && (s->prev == NULL
2864 || s->prev->hl != s->hl)));
2865 right_p = (last_glyph->right_box_line_p
2866 || (s->hl == DRAW_MOUSE_FACE
2867 && (s->next == NULL
2868 || s->next->hl != s->hl)));
2870 get_glyph_string_clip_rect (s, &clip_rect);
2872 if (s->face->box == FACE_SIMPLE_BOX)
2873 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
2874 left_p, right_p, &clip_rect);
2875 else
2877 x_setup_relief_colors (s);
2878 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
2879 width, raised_p, true, true, left_p, right_p,
2880 &clip_rect);
2885 /* Draw foreground of image glyph string S. */
2887 static void
2888 x_draw_image_foreground (struct glyph_string *s)
2890 int x = s->x;
2891 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2893 /* If first glyph of S has a left box line, start drawing it to the
2894 right of that line. */
2895 if (s->face->box != FACE_NO_BOX
2896 && s->first_glyph->left_box_line_p
2897 && s->slice.x == 0)
2898 x += eabs (s->face->box_line_width);
2900 /* If there is a margin around the image, adjust x- and y-position
2901 by that margin. */
2902 if (s->slice.x == 0)
2903 x += s->img->hmargin;
2904 if (s->slice.y == 0)
2905 y += s->img->vmargin;
2907 if (s->img->pixmap)
2909 if (s->img->mask)
2911 /* We can't set both a clip mask and use XSetClipRectangles
2912 because the latter also sets a clip mask. We also can't
2913 trust on the shape extension to be available
2914 (XShapeCombineRegion). So, compute the rectangle to draw
2915 manually. */
2916 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
2917 | GCFunction);
2918 XGCValues xgcv;
2919 XRectangle clip_rect, image_rect, r;
2921 xgcv.clip_mask = s->img->mask;
2922 xgcv.clip_x_origin = x;
2923 xgcv.clip_y_origin = y;
2924 xgcv.function = GXcopy;
2925 XChangeGC (s->display, s->gc, mask, &xgcv);
2927 get_glyph_string_clip_rect (s, &clip_rect);
2928 image_rect.x = x;
2929 image_rect.y = y;
2930 image_rect.width = s->slice.width;
2931 image_rect.height = s->slice.height;
2932 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
2933 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
2934 s->slice.x + r.x - x, s->slice.y + r.y - y,
2935 r.width, r.height, r.x, r.y);
2937 else
2939 XRectangle clip_rect, image_rect, r;
2941 get_glyph_string_clip_rect (s, &clip_rect);
2942 image_rect.x = x;
2943 image_rect.y = y;
2944 image_rect.width = s->slice.width;
2945 image_rect.height = s->slice.height;
2946 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
2947 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
2948 s->slice.x + r.x - x, s->slice.y + r.y - y,
2949 r.width, r.height, r.x, r.y);
2951 /* When the image has a mask, we can expect that at
2952 least part of a mouse highlight or a block cursor will
2953 be visible. If the image doesn't have a mask, make
2954 a block cursor visible by drawing a rectangle around
2955 the image. I believe it's looking better if we do
2956 nothing here for mouse-face. */
2957 if (s->hl == DRAW_CURSOR)
2959 int relief = eabs (s->img->relief);
2960 x_draw_rectangle (s->f, s->gc,
2961 x - relief, y - relief,
2962 s->slice.width + relief*2 - 1,
2963 s->slice.height + relief*2 - 1);
2967 else
2968 /* Draw a rectangle if image could not be loaded. */
2969 x_draw_rectangle (s->f, s->gc, x, y,
2970 s->slice.width - 1, s->slice.height - 1);
2974 /* Draw a relief around the image glyph string S. */
2976 static void
2977 x_draw_image_relief (struct glyph_string *s)
2979 int x1, y1, thick;
2980 bool raised_p, top_p, bot_p, left_p, right_p;
2981 int extra_x, extra_y;
2982 XRectangle r;
2983 int x = s->x;
2984 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2986 /* If first glyph of S has a left box line, start drawing it to the
2987 right of that line. */
2988 if (s->face->box != FACE_NO_BOX
2989 && s->first_glyph->left_box_line_p
2990 && s->slice.x == 0)
2991 x += eabs (s->face->box_line_width);
2993 /* If there is a margin around the image, adjust x- and y-position
2994 by that margin. */
2995 if (s->slice.x == 0)
2996 x += s->img->hmargin;
2997 if (s->slice.y == 0)
2998 y += s->img->vmargin;
3000 if (s->hl == DRAW_IMAGE_SUNKEN
3001 || s->hl == DRAW_IMAGE_RAISED)
3003 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3004 raised_p = s->hl == DRAW_IMAGE_RAISED;
3006 else
3008 thick = eabs (s->img->relief);
3009 raised_p = s->img->relief > 0;
3012 x1 = x + s->slice.width - 1;
3013 y1 = y + s->slice.height - 1;
3015 extra_x = extra_y = 0;
3016 if (s->face->id == TOOL_BAR_FACE_ID)
3018 if (CONSP (Vtool_bar_button_margin)
3019 && INTEGERP (XCAR (Vtool_bar_button_margin))
3020 && INTEGERP (XCDR (Vtool_bar_button_margin)))
3022 extra_x = XINT (XCAR (Vtool_bar_button_margin));
3023 extra_y = XINT (XCDR (Vtool_bar_button_margin));
3025 else if (INTEGERP (Vtool_bar_button_margin))
3026 extra_x = extra_y = XINT (Vtool_bar_button_margin);
3029 top_p = bot_p = left_p = right_p = false;
3031 if (s->slice.x == 0)
3032 x -= thick + extra_x, left_p = true;
3033 if (s->slice.y == 0)
3034 y -= thick + extra_y, top_p = true;
3035 if (s->slice.x + s->slice.width == s->img->width)
3036 x1 += thick + extra_x, right_p = true;
3037 if (s->slice.y + s->slice.height == s->img->height)
3038 y1 += thick + extra_y, bot_p = true;
3040 x_setup_relief_colors (s);
3041 get_glyph_string_clip_rect (s, &r);
3042 x_draw_relief_rect (s->f, x, y, x1, y1, thick, raised_p,
3043 top_p, bot_p, left_p, right_p, &r);
3047 /* Draw the foreground of image glyph string S to PIXMAP. */
3049 static void
3050 x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap)
3052 int x = 0;
3053 int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice);
3055 /* If first glyph of S has a left box line, start drawing it to the
3056 right of that line. */
3057 if (s->face->box != FACE_NO_BOX
3058 && s->first_glyph->left_box_line_p
3059 && s->slice.x == 0)
3060 x += eabs (s->face->box_line_width);
3062 /* If there is a margin around the image, adjust x- and y-position
3063 by that margin. */
3064 if (s->slice.x == 0)
3065 x += s->img->hmargin;
3066 if (s->slice.y == 0)
3067 y += s->img->vmargin;
3069 if (s->img->pixmap)
3071 if (s->img->mask)
3073 /* We can't set both a clip mask and use XSetClipRectangles
3074 because the latter also sets a clip mask. We also can't
3075 trust on the shape extension to be available
3076 (XShapeCombineRegion). So, compute the rectangle to draw
3077 manually. */
3078 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3079 | GCFunction);
3080 XGCValues xgcv;
3082 xgcv.clip_mask = s->img->mask;
3083 xgcv.clip_x_origin = x - s->slice.x;
3084 xgcv.clip_y_origin = y - s->slice.y;
3085 xgcv.function = GXcopy;
3086 XChangeGC (s->display, s->gc, mask, &xgcv);
3088 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3089 s->slice.x, s->slice.y,
3090 s->slice.width, s->slice.height, x, y);
3091 XSetClipMask (s->display, s->gc, None);
3093 else
3095 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
3096 s->slice.x, s->slice.y,
3097 s->slice.width, s->slice.height, x, y);
3099 /* When the image has a mask, we can expect that at
3100 least part of a mouse highlight or a block cursor will
3101 be visible. If the image doesn't have a mask, make
3102 a block cursor visible by drawing a rectangle around
3103 the image. I believe it's looking better if we do
3104 nothing here for mouse-face. */
3105 if (s->hl == DRAW_CURSOR)
3107 int r = eabs (s->img->relief);
3108 x_draw_rectangle (s->f, s->gc, x - r, y - r,
3109 s->slice.width + r*2 - 1,
3110 s->slice.height + r*2 - 1);
3114 else
3115 /* Draw a rectangle if image could not be loaded. */
3116 x_draw_rectangle (s->f, s->gc, x, y,
3117 s->slice.width - 1, s->slice.height - 1);
3121 /* Draw part of the background of glyph string S. X, Y, W, and H
3122 give the rectangle to draw. */
3124 static void
3125 x_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, int w, int h)
3127 if (s->stippled_p)
3129 /* Fill background with a stipple pattern. */
3130 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3131 x_fill_rectangle (s->f, s->gc, x, y, w, h);
3132 XSetFillStyle (s->display, s->gc, FillSolid);
3134 else
3135 x_clear_glyph_string_rect (s, x, y, w, h);
3139 /* Draw image glyph string S.
3141 s->y
3142 s->x +-------------------------
3143 | s->face->box
3145 | +-------------------------
3146 | | s->img->margin
3148 | | +-------------------
3149 | | | the image
3153 static void
3154 x_draw_image_glyph_string (struct glyph_string *s)
3156 int box_line_hwidth = eabs (s->face->box_line_width);
3157 int box_line_vwidth = max (s->face->box_line_width, 0);
3158 int height;
3159 Pixmap pixmap = None;
3161 height = s->height;
3162 if (s->slice.y == 0)
3163 height -= box_line_vwidth;
3164 if (s->slice.y + s->slice.height >= s->img->height)
3165 height -= box_line_vwidth;
3167 /* Fill background with face under the image. Do it only if row is
3168 taller than image or if image has a clip mask to reduce
3169 flickering. */
3170 s->stippled_p = s->face->stipple != 0;
3171 if (height > s->slice.height
3172 || s->img->hmargin
3173 || s->img->vmargin
3174 || s->img->mask
3175 || s->img->pixmap == 0
3176 || s->width != s->background_width)
3178 if (s->img->mask)
3180 /* Create a pixmap as large as the glyph string. Fill it
3181 with the background color. Copy the image to it, using
3182 its mask. Copy the temporary pixmap to the display. */
3183 Screen *screen = FRAME_X_SCREEN (s->f);
3184 int depth = DefaultDepthOfScreen (screen);
3186 /* Create a pixmap as large as the glyph string. */
3187 pixmap = XCreatePixmap (s->display, s->window,
3188 s->background_width,
3189 s->height, depth);
3191 /* Don't clip in the following because we're working on the
3192 pixmap. */
3193 XSetClipMask (s->display, s->gc, None);
3195 /* Fill the pixmap with the background color/stipple. */
3196 if (s->stippled_p)
3198 /* Fill background with a stipple pattern. */
3199 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3200 XSetTSOrigin (s->display, s->gc, - s->x, - s->y);
3201 XFillRectangle (s->display, pixmap, s->gc,
3202 0, 0, s->background_width, s->height);
3203 XSetFillStyle (s->display, s->gc, FillSolid);
3204 XSetTSOrigin (s->display, s->gc, 0, 0);
3206 else
3208 XGCValues xgcv;
3209 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
3210 &xgcv);
3211 XSetForeground (s->display, s->gc, xgcv.background);
3212 XFillRectangle (s->display, pixmap, s->gc,
3213 0, 0, s->background_width, s->height);
3214 XSetForeground (s->display, s->gc, xgcv.foreground);
3217 else
3219 int x = s->x;
3220 int y = s->y;
3221 int width = s->background_width;
3223 if (s->first_glyph->left_box_line_p
3224 && s->slice.x == 0)
3226 x += box_line_hwidth;
3227 width -= box_line_hwidth;
3230 if (s->slice.y == 0)
3231 y += box_line_vwidth;
3233 x_draw_glyph_string_bg_rect (s, x, y, width, height);
3236 s->background_filled_p = true;
3239 /* Draw the foreground. */
3240 #ifdef USE_CAIRO
3241 if (s->img->cr_data)
3243 cairo_t *cr = x_begin_cr_clip (s->f, s->gc);
3245 int x = s->x + s->img->hmargin;
3246 int y = s->y + s->img->vmargin;
3247 int width = s->background_width;
3249 cairo_set_source_surface (cr, s->img->cr_data,
3250 x - s->slice.x,
3251 y - s->slice.y);
3252 cairo_rectangle (cr, x, y, width, height);
3253 cairo_fill (cr);
3254 x_end_cr_clip (s->f);
3256 else
3257 #endif
3258 if (pixmap != None)
3260 x_draw_image_foreground_1 (s, pixmap);
3261 x_set_glyph_string_clipping (s);
3262 XCopyArea (s->display, pixmap, s->window, s->gc,
3263 0, 0, s->background_width, s->height, s->x, s->y);
3264 XFreePixmap (s->display, pixmap);
3266 else
3267 x_draw_image_foreground (s);
3269 /* If we must draw a relief around the image, do it. */
3270 if (s->img->relief
3271 || s->hl == DRAW_IMAGE_RAISED
3272 || s->hl == DRAW_IMAGE_SUNKEN)
3273 x_draw_image_relief (s);
3277 /* Draw stretch glyph string S. */
3279 static void
3280 x_draw_stretch_glyph_string (struct glyph_string *s)
3282 eassert (s->first_glyph->type == STRETCH_GLYPH);
3284 if (s->hl == DRAW_CURSOR
3285 && !x_stretch_cursor_p)
3287 /* If `x-stretch-cursor' is nil, don't draw a block cursor as
3288 wide as the stretch glyph. */
3289 int width, background_width = s->background_width;
3290 int x = s->x;
3292 if (!s->row->reversed_p)
3294 int left_x = window_box_left_offset (s->w, TEXT_AREA);
3296 if (x < left_x)
3298 background_width -= left_x - x;
3299 x = left_x;
3302 else
3304 /* In R2L rows, draw the cursor on the right edge of the
3305 stretch glyph. */
3306 int right_x = window_box_right (s->w, TEXT_AREA);
3308 if (x + background_width > right_x)
3309 background_width -= x - right_x;
3310 x += background_width;
3312 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
3313 if (s->row->reversed_p)
3314 x -= width;
3316 /* Draw cursor. */
3317 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
3319 /* Clear rest using the GC of the original non-cursor face. */
3320 if (width < background_width)
3322 int y = s->y;
3323 int w = background_width - width, h = s->height;
3324 XRectangle r;
3325 GC gc;
3327 if (!s->row->reversed_p)
3328 x += width;
3329 else
3330 x = s->x;
3331 if (s->row->mouse_face_p
3332 && cursor_in_mouse_face_p (s->w))
3334 x_set_mouse_face_gc (s);
3335 gc = s->gc;
3337 else
3338 gc = s->face->gc;
3340 get_glyph_string_clip_rect (s, &r);
3341 x_set_clip_rectangles (s->f, gc, &r, 1);
3343 if (s->face->stipple)
3345 /* Fill background with a stipple pattern. */
3346 XSetFillStyle (s->display, gc, FillOpaqueStippled);
3347 x_fill_rectangle (s->f, gc, x, y, w, h);
3348 XSetFillStyle (s->display, gc, FillSolid);
3350 else
3352 XGCValues xgcv;
3353 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
3354 XSetForeground (s->display, gc, xgcv.background);
3355 x_fill_rectangle (s->f, gc, x, y, w, h);
3356 XSetForeground (s->display, gc, xgcv.foreground);
3359 x_reset_clip_rectangles (s->f, gc);
3362 else if (!s->background_filled_p)
3364 int background_width = s->background_width;
3365 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
3367 /* Don't draw into left margin, fringe or scrollbar area
3368 except for header line and mode line. */
3369 if (x < left_x && !s->row->mode_line_p)
3371 background_width -= left_x - x;
3372 x = left_x;
3374 if (background_width > 0)
3375 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
3378 s->background_filled_p = true;
3382 Draw a wavy line under S. The wave fills wave_height pixels from y0.
3384 x0 wave_length = 2
3386 y0 * * * * *
3387 |* * * * * * * * *
3388 wave_height = 3 | * * * *
3392 static void
3393 x_draw_underwave (struct glyph_string *s)
3395 int wave_height = 3, wave_length = 2;
3396 #ifdef USE_CAIRO
3397 x_draw_horizontal_wave (s->f, s->gc, s->x, s->ybase - wave_height + 3,
3398 s->width, wave_height, wave_length);
3399 #else /* not USE_CAIRO */
3400 int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax;
3401 bool odd;
3402 XRectangle wave_clip, string_clip, final_clip;
3404 dx = wave_length;
3405 dy = wave_height - 1;
3406 x0 = s->x;
3407 y0 = s->ybase - wave_height + 3;
3408 width = s->width;
3409 xmax = x0 + width;
3411 /* Find and set clipping rectangle */
3413 wave_clip.x = x0;
3414 wave_clip.y = y0;
3415 wave_clip.width = width;
3416 wave_clip.height = wave_height;
3417 get_glyph_string_clip_rect (s, &string_clip);
3419 if (!x_intersect_rectangles (&wave_clip, &string_clip, &final_clip))
3420 return;
3422 XSetClipRectangles (s->display, s->gc, 0, 0, &final_clip, 1, Unsorted);
3424 /* Draw the waves */
3426 x1 = x0 - (x0 % dx);
3427 x2 = x1 + dx;
3428 odd = (x1 / dx) & 1;
3429 y1 = y2 = y0;
3431 if (odd)
3432 y1 += dy;
3433 else
3434 y2 += dy;
3436 if (INT_MAX - dx < xmax)
3437 emacs_abort ();
3439 while (x1 <= xmax)
3441 XDrawLine (s->display, s->window, s->gc, x1, y1, x2, y2);
3442 x1 = x2, y1 = y2;
3443 x2 += dx, y2 = y0 + odd*dy;
3444 odd = !odd;
3447 /* Restore previous clipping rectangle(s) */
3448 XSetClipRectangles (s->display, s->gc, 0, 0, s->clip, s->num_clips, Unsorted);
3449 #endif /* not USE_CAIRO */
3453 /* Draw glyph string S. */
3455 static void
3456 x_draw_glyph_string (struct glyph_string *s)
3458 bool relief_drawn_p = false;
3460 /* If S draws into the background of its successors, draw the
3461 background of the successors first so that S can draw into it.
3462 This makes S->next use XDrawString instead of XDrawImageString. */
3463 if (s->next && s->right_overhang && !s->for_overlaps)
3465 int width;
3466 struct glyph_string *next;
3468 for (width = 0, next = s->next;
3469 next && width < s->right_overhang;
3470 width += next->width, next = next->next)
3471 if (next->first_glyph->type != IMAGE_GLYPH)
3473 x_set_glyph_string_gc (next);
3474 x_set_glyph_string_clipping (next);
3475 if (next->first_glyph->type == STRETCH_GLYPH)
3476 x_draw_stretch_glyph_string (next);
3477 else
3478 x_draw_glyph_string_background (next, true);
3479 next->num_clips = 0;
3483 /* Set up S->gc, set clipping and draw S. */
3484 x_set_glyph_string_gc (s);
3486 /* Draw relief (if any) in advance for char/composition so that the
3487 glyph string can be drawn over it. */
3488 if (!s->for_overlaps
3489 && s->face->box != FACE_NO_BOX
3490 && (s->first_glyph->type == CHAR_GLYPH
3491 || s->first_glyph->type == COMPOSITE_GLYPH))
3494 x_set_glyph_string_clipping (s);
3495 x_draw_glyph_string_background (s, true);
3496 x_draw_glyph_string_box (s);
3497 x_set_glyph_string_clipping (s);
3498 relief_drawn_p = true;
3500 else if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */
3501 && !s->clip_tail
3502 && ((s->prev && s->prev->hl != s->hl && s->left_overhang)
3503 || (s->next && s->next->hl != s->hl && s->right_overhang)))
3504 /* We must clip just this glyph. left_overhang part has already
3505 drawn when s->prev was drawn, and right_overhang part will be
3506 drawn later when s->next is drawn. */
3507 x_set_glyph_string_clipping_exactly (s, s);
3508 else
3509 x_set_glyph_string_clipping (s);
3511 switch (s->first_glyph->type)
3513 case IMAGE_GLYPH:
3514 x_draw_image_glyph_string (s);
3515 break;
3517 case XWIDGET_GLYPH:
3518 x_draw_xwidget_glyph_string (s);
3519 break;
3521 case STRETCH_GLYPH:
3522 x_draw_stretch_glyph_string (s);
3523 break;
3525 case CHAR_GLYPH:
3526 if (s->for_overlaps)
3527 s->background_filled_p = true;
3528 else
3529 x_draw_glyph_string_background (s, false);
3530 x_draw_glyph_string_foreground (s);
3531 break;
3533 case COMPOSITE_GLYPH:
3534 if (s->for_overlaps || (s->cmp_from > 0
3535 && ! s->first_glyph->u.cmp.automatic))
3536 s->background_filled_p = true;
3537 else
3538 x_draw_glyph_string_background (s, true);
3539 x_draw_composite_glyph_string_foreground (s);
3540 break;
3542 case GLYPHLESS_GLYPH:
3543 if (s->for_overlaps)
3544 s->background_filled_p = true;
3545 else
3546 x_draw_glyph_string_background (s, true);
3547 x_draw_glyphless_glyph_string_foreground (s);
3548 break;
3550 default:
3551 emacs_abort ();
3554 if (!s->for_overlaps)
3556 /* Draw underline. */
3557 if (s->face->underline_p)
3559 if (s->face->underline_type == FACE_UNDER_WAVE)
3561 if (s->face->underline_defaulted_p)
3562 x_draw_underwave (s);
3563 else
3565 XGCValues xgcv;
3566 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3567 XSetForeground (s->display, s->gc, s->face->underline_color);
3568 x_draw_underwave (s);
3569 XSetForeground (s->display, s->gc, xgcv.foreground);
3572 else if (s->face->underline_type == FACE_UNDER_LINE)
3574 unsigned long thickness, position;
3575 int y;
3577 if (s->prev && s->prev->face->underline_p
3578 && s->prev->face->underline_type == FACE_UNDER_LINE)
3580 /* We use the same underline style as the previous one. */
3581 thickness = s->prev->underline_thickness;
3582 position = s->prev->underline_position;
3584 else
3586 /* Get the underline thickness. Default is 1 pixel. */
3587 if (s->font && s->font->underline_thickness > 0)
3588 thickness = s->font->underline_thickness;
3589 else
3590 thickness = 1;
3591 if (x_underline_at_descent_line)
3592 position = (s->height - thickness) - (s->ybase - s->y);
3593 else
3595 /* Get the underline position. This is the recommended
3596 vertical offset in pixels from the baseline to the top of
3597 the underline. This is a signed value according to the
3598 specs, and its default is
3600 ROUND ((maximum descent) / 2), with
3601 ROUND(x) = floor (x + 0.5) */
3603 if (x_use_underline_position_properties
3604 && s->font && s->font->underline_position >= 0)
3605 position = s->font->underline_position;
3606 else if (s->font)
3607 position = (s->font->descent + 1) / 2;
3608 else
3609 position = underline_minimum_offset;
3611 position = max (position, underline_minimum_offset);
3613 /* Check the sanity of thickness and position. We should
3614 avoid drawing underline out of the current line area. */
3615 if (s->y + s->height <= s->ybase + position)
3616 position = (s->height - 1) - (s->ybase - s->y);
3617 if (s->y + s->height < s->ybase + position + thickness)
3618 thickness = (s->y + s->height) - (s->ybase + position);
3619 s->underline_thickness = thickness;
3620 s->underline_position = position;
3621 y = s->ybase + position;
3622 if (s->face->underline_defaulted_p)
3623 x_fill_rectangle (s->f, s->gc,
3624 s->x, y, s->width, thickness);
3625 else
3627 XGCValues xgcv;
3628 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3629 XSetForeground (s->display, s->gc, s->face->underline_color);
3630 x_fill_rectangle (s->f, s->gc,
3631 s->x, y, s->width, thickness);
3632 XSetForeground (s->display, s->gc, xgcv.foreground);
3636 /* Draw overline. */
3637 if (s->face->overline_p)
3639 unsigned long dy = 0, h = 1;
3641 if (s->face->overline_color_defaulted_p)
3642 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3643 s->width, h);
3644 else
3646 XGCValues xgcv;
3647 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3648 XSetForeground (s->display, s->gc, s->face->overline_color);
3649 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3650 s->width, h);
3651 XSetForeground (s->display, s->gc, xgcv.foreground);
3655 /* Draw strike-through. */
3656 if (s->face->strike_through_p)
3658 unsigned long h = 1;
3659 unsigned long dy = (s->height - h) / 2;
3661 if (s->face->strike_through_color_defaulted_p)
3662 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3663 s->width, h);
3664 else
3666 XGCValues xgcv;
3667 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3668 XSetForeground (s->display, s->gc, s->face->strike_through_color);
3669 x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
3670 s->width, h);
3671 XSetForeground (s->display, s->gc, xgcv.foreground);
3675 /* Draw relief if not yet drawn. */
3676 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
3677 x_draw_glyph_string_box (s);
3679 if (s->prev)
3681 struct glyph_string *prev;
3683 for (prev = s->prev; prev; prev = prev->prev)
3684 if (prev->hl != s->hl
3685 && prev->x + prev->width + prev->right_overhang > s->x)
3687 /* As prev was drawn while clipped to its own area, we
3688 must draw the right_overhang part using s->hl now. */
3689 enum draw_glyphs_face save = prev->hl;
3691 prev->hl = s->hl;
3692 x_set_glyph_string_gc (prev);
3693 x_set_glyph_string_clipping_exactly (s, prev);
3694 if (prev->first_glyph->type == CHAR_GLYPH)
3695 x_draw_glyph_string_foreground (prev);
3696 else
3697 x_draw_composite_glyph_string_foreground (prev);
3698 x_reset_clip_rectangles (prev->f, prev->gc);
3699 prev->hl = save;
3700 prev->num_clips = 0;
3704 if (s->next)
3706 struct glyph_string *next;
3708 for (next = s->next; next; next = next->next)
3709 if (next->hl != s->hl
3710 && next->x - next->left_overhang < s->x + s->width)
3712 /* As next will be drawn while clipped to its own area,
3713 we must draw the left_overhang part using s->hl now. */
3714 enum draw_glyphs_face save = next->hl;
3716 next->hl = s->hl;
3717 x_set_glyph_string_gc (next);
3718 x_set_glyph_string_clipping_exactly (s, next);
3719 if (next->first_glyph->type == CHAR_GLYPH)
3720 x_draw_glyph_string_foreground (next);
3721 else
3722 x_draw_composite_glyph_string_foreground (next);
3723 x_reset_clip_rectangles (next->f, next->gc);
3724 next->hl = save;
3725 next->num_clips = 0;
3726 next->clip_head = s->next;
3731 /* Reset clipping. */
3732 x_reset_clip_rectangles (s->f, s->gc);
3733 s->num_clips = 0;
3736 /* Shift display to make room for inserted glyphs. */
3738 static void
3739 x_shift_glyphs_for_insert (struct frame *f, int x, int y, int width, int height, int shift_by)
3741 /* Never called on a GUI frame, see
3742 http://lists.gnu.org/archive/html/emacs-devel/2015-05/msg00456.html
3744 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
3745 f->output_data.x->normal_gc,
3746 x, y, width, height,
3747 x + shift_by, y);
3750 /* Delete N glyphs at the nominal cursor position. Not implemented
3751 for X frames. */
3753 static void
3754 x_delete_glyphs (struct frame *f, register int n)
3756 emacs_abort ();
3760 /* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
3761 If they are <= 0, this is probably an error. */
3763 static ATTRIBUTE_UNUSED void
3764 x_clear_area1 (Display *dpy, Window window,
3765 int x, int y, int width, int height, int exposures)
3767 eassert (width > 0 && height > 0);
3768 XClearArea (dpy, window, x, y, width, height, exposures);
3771 void
3772 x_clear_area (struct frame *f, int x, int y, int width, int height)
3774 #ifdef USE_CAIRO
3775 cairo_t *cr;
3777 eassert (width > 0 && height > 0);
3779 cr = x_begin_cr_clip (f, NULL);
3780 x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
3781 cairo_rectangle (cr, x, y, width, height);
3782 cairo_fill (cr);
3783 x_end_cr_clip (f);
3784 #else
3785 x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3786 x, y, width, height, False);
3787 #endif
3791 /* Clear an entire frame. */
3793 static void
3794 x_clear_frame (struct frame *f)
3796 /* Clearing the frame will erase any cursor, so mark them all as no
3797 longer visible. */
3798 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
3800 block_input ();
3802 x_clear_window (f);
3804 /* We have to clear the scroll bars. If we have changed colors or
3805 something like that, then they should be notified. */
3806 x_scroll_bar_clear (f);
3808 #if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
3809 /* Make sure scroll bars are redrawn. As they aren't redrawn by
3810 redisplay, do it here. */
3811 if (FRAME_GTK_WIDGET (f))
3812 gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
3813 #endif
3815 XFlush (FRAME_X_DISPLAY (f));
3817 unblock_input ();
3820 /* RIF: Show hourglass cursor on frame F. */
3822 static void
3823 x_show_hourglass (struct frame *f)
3825 Display *dpy = FRAME_X_DISPLAY (f);
3827 if (dpy)
3829 struct x_output *x = FRAME_X_OUTPUT (f);
3830 #ifdef USE_X_TOOLKIT
3831 if (x->widget)
3832 #else
3833 if (FRAME_OUTER_WINDOW (f))
3834 #endif
3836 x->hourglass_p = true;
3838 if (!x->hourglass_window)
3840 unsigned long mask = CWCursor;
3841 XSetWindowAttributes attrs;
3842 #ifdef USE_GTK
3843 Window parent = FRAME_X_WINDOW (f);
3844 #else
3845 Window parent = FRAME_OUTER_WINDOW (f);
3846 #endif
3847 attrs.cursor = x->hourglass_cursor;
3849 x->hourglass_window = XCreateWindow
3850 (dpy, parent, 0, 0, 32000, 32000, 0, 0,
3851 InputOnly, CopyFromParent, mask, &attrs);
3854 XMapRaised (dpy, x->hourglass_window);
3855 XFlush (dpy);
3860 /* RIF: Cancel hourglass cursor on frame F. */
3862 static void
3863 x_hide_hourglass (struct frame *f)
3865 struct x_output *x = FRAME_X_OUTPUT (f);
3867 /* Watch out for newly created frames. */
3868 if (x->hourglass_window)
3870 XUnmapWindow (FRAME_X_DISPLAY (f), x->hourglass_window);
3871 /* Sync here because XTread_socket looks at the
3872 hourglass_p flag that is reset to zero below. */
3873 XSync (FRAME_X_DISPLAY (f), False);
3874 x->hourglass_p = false;
3878 /* Invert the middle quarter of the frame for .15 sec. */
3880 static void
3881 XTflash (struct frame *f)
3883 block_input ();
3886 #ifdef USE_GTK
3887 /* Use Gdk routines to draw. This way, we won't draw over scroll bars
3888 when the scroll bars and the edit widget share the same X window. */
3889 GdkWindow *window = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
3890 #ifdef HAVE_GTK3
3891 cairo_t *cr = gdk_cairo_create (window);
3892 cairo_set_source_rgb (cr, 1, 1, 1);
3893 cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
3894 #define XFillRectangle(d, win, gc, x, y, w, h) \
3895 do { \
3896 cairo_rectangle (cr, x, y, w, h); \
3897 cairo_fill (cr); \
3899 while (false)
3900 #else /* ! HAVE_GTK3 */
3901 GdkGCValues vals;
3902 GdkGC *gc;
3903 vals.foreground.pixel = (FRAME_FOREGROUND_PIXEL (f)
3904 ^ FRAME_BACKGROUND_PIXEL (f));
3905 vals.function = GDK_XOR;
3906 gc = gdk_gc_new_with_values (window,
3907 &vals, GDK_GC_FUNCTION | GDK_GC_FOREGROUND);
3908 #define XFillRectangle(d, win, gc, x, y, w, h) \
3909 gdk_draw_rectangle (window, gc, true, x, y, w, h)
3910 #endif /* ! HAVE_GTK3 */
3911 #else /* ! USE_GTK */
3912 GC gc;
3914 /* Create a GC that will use the GXxor function to flip foreground
3915 pixels into background pixels. */
3917 XGCValues values;
3919 values.function = GXxor;
3920 values.foreground = (FRAME_FOREGROUND_PIXEL (f)
3921 ^ FRAME_BACKGROUND_PIXEL (f));
3923 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3924 GCFunction | GCForeground, &values);
3926 #endif
3928 /* Get the height not including a menu bar widget. */
3929 int height = FRAME_PIXEL_HEIGHT (f);
3930 /* Height of each line to flash. */
3931 int flash_height = FRAME_LINE_HEIGHT (f);
3932 /* These will be the left and right margins of the rectangles. */
3933 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
3934 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
3935 int width = flash_right - flash_left;
3937 /* If window is tall, flash top and bottom line. */
3938 if (height > 3 * FRAME_LINE_HEIGHT (f))
3940 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3941 flash_left,
3942 (FRAME_INTERNAL_BORDER_WIDTH (f)
3943 + FRAME_TOP_MARGIN_HEIGHT (f)),
3944 width, flash_height);
3945 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3946 flash_left,
3947 (height - flash_height
3948 - FRAME_INTERNAL_BORDER_WIDTH (f)),
3949 width, flash_height);
3952 else
3953 /* If it is short, flash it all. */
3954 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3955 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
3956 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
3958 x_flush (f);
3961 struct timespec delay = make_timespec (0, 150 * 1000 * 1000);
3962 struct timespec wakeup = timespec_add (current_timespec (), delay);
3964 /* Keep waiting until past the time wakeup or any input gets
3965 available. */
3966 while (! detect_input_pending ())
3968 struct timespec current = current_timespec ();
3969 struct timespec timeout;
3971 /* Break if result would not be positive. */
3972 if (timespec_cmp (wakeup, current) <= 0)
3973 break;
3975 /* How long `select' should wait. */
3976 timeout = make_timespec (0, 10 * 1000 * 1000);
3978 /* Try to wait that long--but we might wake up sooner. */
3979 pselect (0, NULL, NULL, NULL, &timeout, NULL);
3983 /* If window is tall, flash top and bottom line. */
3984 if (height > 3 * FRAME_LINE_HEIGHT (f))
3986 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3987 flash_left,
3988 (FRAME_INTERNAL_BORDER_WIDTH (f)
3989 + FRAME_TOP_MARGIN_HEIGHT (f)),
3990 width, flash_height);
3991 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3992 flash_left,
3993 (height - flash_height
3994 - FRAME_INTERNAL_BORDER_WIDTH (f)),
3995 width, flash_height);
3997 else
3998 /* If it is short, flash it all. */
3999 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
4000 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
4001 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
4003 #ifdef USE_GTK
4004 #ifdef HAVE_GTK3
4005 cairo_destroy (cr);
4006 #else
4007 g_object_unref (G_OBJECT (gc));
4008 #endif
4009 #undef XFillRectangle
4010 #else
4011 XFreeGC (FRAME_X_DISPLAY (f), gc);
4012 #endif
4013 x_flush (f);
4017 unblock_input ();
4021 static void
4022 XTtoggle_invisible_pointer (struct frame *f, bool invisible)
4024 block_input ();
4025 FRAME_DISPLAY_INFO (f)->toggle_visible_pointer (f, invisible);
4026 unblock_input ();
4030 /* Make audible bell. */
4032 static void
4033 XTring_bell (struct frame *f)
4035 if (FRAME_X_DISPLAY (f))
4037 if (visible_bell)
4038 XTflash (f);
4039 else
4041 block_input ();
4042 #ifdef HAVE_XKB
4043 XkbBell (FRAME_X_DISPLAY (f), None, 0, None);
4044 #else
4045 XBell (FRAME_X_DISPLAY (f), 0);
4046 #endif
4047 XFlush (FRAME_X_DISPLAY (f));
4048 unblock_input ();
4053 /***********************************************************************
4054 Line Dance
4055 ***********************************************************************/
4057 /* Perform an insert-lines or delete-lines operation, inserting N
4058 lines or deleting -N lines at vertical position VPOS. */
4060 static void
4061 x_ins_del_lines (struct frame *f, int vpos, int n)
4063 emacs_abort ();
4067 /* Scroll part of the display as described by RUN. */
4069 static void
4070 x_scroll_run (struct window *w, struct run *run)
4072 struct frame *f = XFRAME (w->frame);
4073 int x, y, width, height, from_y, to_y, bottom_y;
4075 /* Get frame-relative bounding box of the text display area of W,
4076 without mode lines. Include in this box the left and right
4077 fringe of W. */
4078 window_box (w, ANY_AREA, &x, &y, &width, &height);
4080 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
4081 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
4082 bottom_y = y + height;
4084 if (to_y < from_y)
4086 /* Scrolling up. Make sure we don't copy part of the mode
4087 line at the bottom. */
4088 if (from_y + run->height > bottom_y)
4089 height = bottom_y - from_y;
4090 else
4091 height = run->height;
4093 else
4095 /* Scrolling down. Make sure we don't copy over the mode line.
4096 at the bottom. */
4097 if (to_y + run->height > bottom_y)
4098 height = bottom_y - to_y;
4099 else
4100 height = run->height;
4103 block_input ();
4105 /* Cursor off. Will be switched on again in x_update_window_end. */
4106 x_clear_cursor (w);
4108 #ifdef USE_CAIRO
4109 SET_FRAME_GARBAGED (f);
4110 #else
4111 XCopyArea (FRAME_X_DISPLAY (f),
4112 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
4113 f->output_data.x->normal_gc,
4114 x, from_y,
4115 width, height,
4116 x, to_y);
4117 #endif
4119 unblock_input ();
4124 /***********************************************************************
4125 Exposure Events
4126 ***********************************************************************/
4129 static void
4130 frame_highlight (struct frame *f)
4132 /* We used to only do this if Vx_no_window_manager was non-nil, but
4133 the ICCCM (section 4.1.6) says that the window's border pixmap
4134 and border pixel are window attributes which are "private to the
4135 client", so we can always change it to whatever we want. */
4136 block_input ();
4137 /* I recently started to get errors in this XSetWindowBorder, depending on
4138 the window-manager in use, tho something more is at play since I've been
4139 using that same window-manager binary for ever. Let's not crash just
4140 because of this (bug#9310). */
4141 x_catch_errors (FRAME_X_DISPLAY (f));
4142 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4143 f->output_data.x->border_pixel);
4144 x_uncatch_errors ();
4145 unblock_input ();
4146 x_update_cursor (f, true);
4147 x_set_frame_alpha (f);
4150 static void
4151 frame_unhighlight (struct frame *f)
4153 /* We used to only do this if Vx_no_window_manager was non-nil, but
4154 the ICCCM (section 4.1.6) says that the window's border pixmap
4155 and border pixel are window attributes which are "private to the
4156 client", so we can always change it to whatever we want. */
4157 block_input ();
4158 /* Same as above for XSetWindowBorder (bug#9310). */
4159 x_catch_errors (FRAME_X_DISPLAY (f));
4160 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4161 f->output_data.x->border_tile);
4162 x_uncatch_errors ();
4163 unblock_input ();
4164 x_update_cursor (f, true);
4165 x_set_frame_alpha (f);
4168 /* The focus has changed. Update the frames as necessary to reflect
4169 the new situation. Note that we can't change the selected frame
4170 here, because the Lisp code we are interrupting might become confused.
4171 Each event gets marked with the frame in which it occurred, so the
4172 Lisp code can tell when the switch took place by examining the events. */
4174 static void
4175 x_new_focus_frame (struct x_display_info *dpyinfo, struct frame *frame)
4177 struct frame *old_focus = dpyinfo->x_focus_frame;
4179 if (frame != dpyinfo->x_focus_frame)
4181 /* Set this before calling other routines, so that they see
4182 the correct value of x_focus_frame. */
4183 dpyinfo->x_focus_frame = frame;
4185 if (old_focus && old_focus->auto_lower)
4186 x_lower_frame (old_focus);
4188 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4189 dpyinfo->x_pending_autoraise_frame = dpyinfo->x_focus_frame;
4190 else
4191 dpyinfo->x_pending_autoraise_frame = NULL;
4194 x_frame_rehighlight (dpyinfo);
4197 /* Handle FocusIn and FocusOut state changes for FRAME.
4198 If FRAME has focus and there exists more than one frame, puts
4199 a FOCUS_IN_EVENT into *BUFP. */
4201 static void
4202 x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct frame *frame, struct input_event *bufp)
4204 if (type == FocusIn)
4206 if (dpyinfo->x_focus_event_frame != frame)
4208 x_new_focus_frame (dpyinfo, frame);
4209 dpyinfo->x_focus_event_frame = frame;
4211 /* Don't stop displaying the initial startup message
4212 for a switch-frame event we don't need. */
4213 /* When run as a daemon, Vterminal_frame is always NIL. */
4214 bufp->arg = (((NILP (Vterminal_frame)
4215 || ! FRAME_X_P (XFRAME (Vterminal_frame))
4216 || EQ (Fdaemonp (), Qt))
4217 && CONSP (Vframe_list)
4218 && !NILP (XCDR (Vframe_list)))
4219 ? Qt : Qnil);
4220 bufp->kind = FOCUS_IN_EVENT;
4221 XSETFRAME (bufp->frame_or_window, frame);
4224 frame->output_data.x->focus_state |= state;
4226 #ifdef HAVE_X_I18N
4227 if (FRAME_XIC (frame))
4228 XSetICFocus (FRAME_XIC (frame));
4229 #endif
4231 else if (type == FocusOut)
4233 frame->output_data.x->focus_state &= ~state;
4235 if (dpyinfo->x_focus_event_frame == frame)
4237 dpyinfo->x_focus_event_frame = 0;
4238 x_new_focus_frame (dpyinfo, 0);
4240 bufp->kind = FOCUS_OUT_EVENT;
4241 XSETFRAME (bufp->frame_or_window, frame);
4244 #ifdef HAVE_X_I18N
4245 if (FRAME_XIC (frame))
4246 XUnsetICFocus (FRAME_XIC (frame));
4247 #endif
4248 if (frame->pointer_invisible)
4249 XTtoggle_invisible_pointer (frame, false);
4253 /* Return the Emacs frame-object corresponding to an X window.
4254 It could be the frame's main window or an icon window. */
4256 static struct frame *
4257 x_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4259 Lisp_Object tail, frame;
4260 struct frame *f;
4262 if (wdesc == None)
4263 return NULL;
4265 FOR_EACH_FRAME (tail, frame)
4267 f = XFRAME (frame);
4268 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4269 continue;
4270 if (f->output_data.x->hourglass_window == wdesc)
4271 return f;
4272 #ifdef USE_X_TOOLKIT
4273 if ((f->output_data.x->edit_widget
4274 && XtWindow (f->output_data.x->edit_widget) == wdesc)
4275 /* A tooltip frame? */
4276 || (!f->output_data.x->edit_widget
4277 && FRAME_X_WINDOW (f) == wdesc)
4278 || f->output_data.x->icon_desc == wdesc)
4279 return f;
4280 #else /* not USE_X_TOOLKIT */
4281 #ifdef USE_GTK
4282 if (f->output_data.x->edit_widget)
4284 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4285 struct x_output *x = f->output_data.x;
4286 if (gwdesc != 0 && gwdesc == x->edit_widget)
4287 return f;
4289 #endif /* USE_GTK */
4290 if (FRAME_X_WINDOW (f) == wdesc
4291 || f->output_data.x->icon_desc == wdesc)
4292 return f;
4293 #endif /* not USE_X_TOOLKIT */
4295 return 0;
4298 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
4300 /* Like x_window_to_frame but also compares the window with the widget's
4301 windows. */
4303 static struct frame *
4304 x_any_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4306 Lisp_Object tail, frame;
4307 struct frame *f, *found = NULL;
4308 struct x_output *x;
4310 if (wdesc == None)
4311 return NULL;
4313 FOR_EACH_FRAME (tail, frame)
4315 if (found)
4316 break;
4317 f = XFRAME (frame);
4318 if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo)
4320 /* This frame matches if the window is any of its widgets. */
4321 x = f->output_data.x;
4322 if (x->hourglass_window == wdesc)
4323 found = f;
4324 else if (x->widget)
4326 #ifdef USE_GTK
4327 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4328 if (gwdesc != 0
4329 && gtk_widget_get_toplevel (gwdesc) == x->widget)
4330 found = f;
4331 #else
4332 if (wdesc == XtWindow (x->widget)
4333 || wdesc == XtWindow (x->column_widget)
4334 || wdesc == XtWindow (x->edit_widget))
4335 found = f;
4336 /* Match if the window is this frame's menubar. */
4337 else if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
4338 found = f;
4339 #endif
4341 else if (FRAME_X_WINDOW (f) == wdesc)
4342 /* A tooltip frame. */
4343 found = f;
4347 return found;
4350 /* Likewise, but consider only the menu bar widget. */
4352 static struct frame *
4353 x_menubar_window_to_frame (struct x_display_info *dpyinfo,
4354 const XEvent *event)
4356 Window wdesc = event->xany.window;
4357 Lisp_Object tail, frame;
4358 struct frame *f;
4359 struct x_output *x;
4361 if (wdesc == None)
4362 return NULL;
4364 FOR_EACH_FRAME (tail, frame)
4366 f = XFRAME (frame);
4367 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4368 continue;
4369 x = f->output_data.x;
4370 #ifdef USE_GTK
4371 if (x->menubar_widget && xg_event_is_for_menubar (f, event))
4372 return f;
4373 #else
4374 /* Match if the window is this frame's menubar. */
4375 if (x->menubar_widget
4376 && lw_window_is_in_menubar (wdesc, x->menubar_widget))
4377 return f;
4378 #endif
4380 return 0;
4383 /* Return the frame whose principal (outermost) window is WDESC.
4384 If WDESC is some other (smaller) window, we return 0. */
4386 struct frame *
4387 x_top_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
4389 Lisp_Object tail, frame;
4390 struct frame *f;
4391 struct x_output *x;
4393 if (wdesc == None)
4394 return NULL;
4396 FOR_EACH_FRAME (tail, frame)
4398 f = XFRAME (frame);
4399 if (!FRAME_X_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo)
4400 continue;
4401 x = f->output_data.x;
4403 if (x->widget)
4405 /* This frame matches if the window is its topmost widget. */
4406 #ifdef USE_GTK
4407 GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
4408 if (gwdesc == x->widget)
4409 return f;
4410 #else
4411 if (wdesc == XtWindow (x->widget))
4412 return f;
4413 #endif
4415 else if (FRAME_X_WINDOW (f) == wdesc)
4416 /* Tooltip frame. */
4417 return f;
4419 return 0;
4422 #else /* !USE_X_TOOLKIT && !USE_GTK */
4424 #define x_any_window_to_frame(d, i) x_window_to_frame (d, i)
4425 #define x_top_window_to_frame(d, i) x_window_to_frame (d, i)
4427 #endif /* USE_X_TOOLKIT || USE_GTK */
4429 /* The focus may have changed. Figure out if it is a real focus change,
4430 by checking both FocusIn/Out and Enter/LeaveNotify events.
4432 Returns FOCUS_IN_EVENT event in *BUFP. */
4434 static void
4435 x_detect_focus_change (struct x_display_info *dpyinfo, struct frame *frame,
4436 const XEvent *event, struct input_event *bufp)
4438 if (!frame)
4439 return;
4441 switch (event->type)
4443 case EnterNotify:
4444 case LeaveNotify:
4446 struct frame *focus_frame = dpyinfo->x_focus_event_frame;
4447 int focus_state
4448 = focus_frame ? focus_frame->output_data.x->focus_state : 0;
4450 if (event->xcrossing.detail != NotifyInferior
4451 && event->xcrossing.focus
4452 && ! (focus_state & FOCUS_EXPLICIT))
4453 x_focus_changed ((event->type == EnterNotify ? FocusIn : FocusOut),
4454 FOCUS_IMPLICIT,
4455 dpyinfo, frame, bufp);
4457 break;
4459 case FocusIn:
4460 case FocusOut:
4461 x_focus_changed (event->type,
4462 (event->xfocus.detail == NotifyPointer ?
4463 FOCUS_IMPLICIT : FOCUS_EXPLICIT),
4464 dpyinfo, frame, bufp);
4465 break;
4467 case ClientMessage:
4468 if (event->xclient.message_type == dpyinfo->Xatom_XEMBED)
4470 enum xembed_message msg = event->xclient.data.l[1];
4471 x_focus_changed ((msg == XEMBED_FOCUS_IN ? FocusIn : FocusOut),
4472 FOCUS_EXPLICIT, dpyinfo, frame, bufp);
4474 break;
4479 #if !defined USE_X_TOOLKIT && !defined USE_GTK
4480 /* Handle an event saying the mouse has moved out of an Emacs frame. */
4482 void
4483 x_mouse_leave (struct x_display_info *dpyinfo)
4485 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
4487 #endif
4489 /* The focus has changed, or we have redirected a frame's focus to
4490 another frame (this happens when a frame uses a surrogate
4491 mini-buffer frame). Shift the highlight as appropriate.
4493 The FRAME argument doesn't necessarily have anything to do with which
4494 frame is being highlighted or un-highlighted; we only use it to find
4495 the appropriate X display info. */
4497 static void
4498 XTframe_rehighlight (struct frame *frame)
4500 x_frame_rehighlight (FRAME_DISPLAY_INFO (frame));
4503 static void
4504 x_frame_rehighlight (struct x_display_info *dpyinfo)
4506 struct frame *old_highlight = dpyinfo->x_highlight_frame;
4508 if (dpyinfo->x_focus_frame)
4510 dpyinfo->x_highlight_frame
4511 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4512 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4513 : dpyinfo->x_focus_frame);
4514 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
4516 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
4517 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
4520 else
4521 dpyinfo->x_highlight_frame = 0;
4523 if (dpyinfo->x_highlight_frame != old_highlight)
4525 if (old_highlight)
4526 frame_unhighlight (old_highlight);
4527 if (dpyinfo->x_highlight_frame)
4528 frame_highlight (dpyinfo->x_highlight_frame);
4534 /* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
4536 /* Initialize mode_switch_bit and modifier_meaning. */
4537 static void
4538 x_find_modifier_meanings (struct x_display_info *dpyinfo)
4540 int min_code, max_code;
4541 KeySym *syms;
4542 int syms_per_code;
4543 XModifierKeymap *mods;
4545 dpyinfo->meta_mod_mask = 0;
4546 dpyinfo->shift_lock_mask = 0;
4547 dpyinfo->alt_mod_mask = 0;
4548 dpyinfo->super_mod_mask = 0;
4549 dpyinfo->hyper_mod_mask = 0;
4551 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
4553 syms = XGetKeyboardMapping (dpyinfo->display,
4554 min_code, max_code - min_code + 1,
4555 &syms_per_code);
4556 mods = XGetModifierMapping (dpyinfo->display);
4558 /* Scan the modifier table to see which modifier bits the Meta and
4559 Alt keysyms are on. */
4561 int row, col; /* The row and column in the modifier table. */
4562 bool found_alt_or_meta;
4564 for (row = 3; row < 8; row++)
4566 found_alt_or_meta = false;
4567 for (col = 0; col < mods->max_keypermod; col++)
4569 KeyCode code = mods->modifiermap[(row * mods->max_keypermod) + col];
4571 /* Zeroes are used for filler. Skip them. */
4572 if (code == 0)
4573 continue;
4575 /* Are any of this keycode's keysyms a meta key? */
4577 int code_col;
4579 for (code_col = 0; code_col < syms_per_code; code_col++)
4581 int sym = syms[((code - min_code) * syms_per_code) + code_col];
4583 switch (sym)
4585 case XK_Meta_L:
4586 case XK_Meta_R:
4587 found_alt_or_meta = true;
4588 dpyinfo->meta_mod_mask |= (1 << row);
4589 break;
4591 case XK_Alt_L:
4592 case XK_Alt_R:
4593 found_alt_or_meta = true;
4594 dpyinfo->alt_mod_mask |= (1 << row);
4595 break;
4597 case XK_Hyper_L:
4598 case XK_Hyper_R:
4599 if (!found_alt_or_meta)
4600 dpyinfo->hyper_mod_mask |= (1 << row);
4601 code_col = syms_per_code;
4602 col = mods->max_keypermod;
4603 break;
4605 case XK_Super_L:
4606 case XK_Super_R:
4607 if (!found_alt_or_meta)
4608 dpyinfo->super_mod_mask |= (1 << row);
4609 code_col = syms_per_code;
4610 col = mods->max_keypermod;
4611 break;
4613 case XK_Shift_Lock:
4614 /* Ignore this if it's not on the lock modifier. */
4615 if (!found_alt_or_meta && ((1 << row) == LockMask))
4616 dpyinfo->shift_lock_mask = LockMask;
4617 code_col = syms_per_code;
4618 col = mods->max_keypermod;
4619 break;
4627 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
4628 if (! dpyinfo->meta_mod_mask)
4630 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
4631 dpyinfo->alt_mod_mask = 0;
4634 /* If some keys are both alt and meta,
4635 make them just meta, not alt. */
4636 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
4638 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
4641 XFree (syms);
4642 XFreeModifiermap (mods);
4645 /* Convert between the modifier bits X uses and the modifier bits
4646 Emacs uses. */
4649 x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state)
4651 int mod_meta = meta_modifier;
4652 int mod_alt = alt_modifier;
4653 int mod_hyper = hyper_modifier;
4654 int mod_super = super_modifier;
4655 Lisp_Object tem;
4657 tem = Fget (Vx_alt_keysym, Qmodifier_value);
4658 if (INTEGERP (tem)) mod_alt = XINT (tem) & INT_MAX;
4659 tem = Fget (Vx_meta_keysym, Qmodifier_value);
4660 if (INTEGERP (tem)) mod_meta = XINT (tem) & INT_MAX;
4661 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
4662 if (INTEGERP (tem)) mod_hyper = XINT (tem) & INT_MAX;
4663 tem = Fget (Vx_super_keysym, Qmodifier_value);
4664 if (INTEGERP (tem)) mod_super = XINT (tem) & INT_MAX;
4666 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
4667 | ((state & ControlMask) ? ctrl_modifier : 0)
4668 | ((state & dpyinfo->meta_mod_mask) ? mod_meta : 0)
4669 | ((state & dpyinfo->alt_mod_mask) ? mod_alt : 0)
4670 | ((state & dpyinfo->super_mod_mask) ? mod_super : 0)
4671 | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0));
4674 static int
4675 x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, EMACS_INT state)
4677 EMACS_INT mod_meta = meta_modifier;
4678 EMACS_INT mod_alt = alt_modifier;
4679 EMACS_INT mod_hyper = hyper_modifier;
4680 EMACS_INT mod_super = super_modifier;
4682 Lisp_Object tem;
4684 tem = Fget (Vx_alt_keysym, Qmodifier_value);
4685 if (INTEGERP (tem)) mod_alt = XINT (tem);
4686 tem = Fget (Vx_meta_keysym, Qmodifier_value);
4687 if (INTEGERP (tem)) mod_meta = XINT (tem);
4688 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
4689 if (INTEGERP (tem)) mod_hyper = XINT (tem);
4690 tem = Fget (Vx_super_keysym, Qmodifier_value);
4691 if (INTEGERP (tem)) mod_super = XINT (tem);
4694 return ( ((state & mod_alt) ? dpyinfo->alt_mod_mask : 0)
4695 | ((state & mod_super) ? dpyinfo->super_mod_mask : 0)
4696 | ((state & mod_hyper) ? dpyinfo->hyper_mod_mask : 0)
4697 | ((state & shift_modifier) ? ShiftMask : 0)
4698 | ((state & ctrl_modifier) ? ControlMask : 0)
4699 | ((state & mod_meta) ? dpyinfo->meta_mod_mask : 0));
4702 /* Convert a keysym to its name. */
4704 char *
4705 x_get_keysym_name (int keysym)
4707 char *value;
4709 block_input ();
4710 value = XKeysymToString (keysym);
4711 unblock_input ();
4713 return value;
4716 /* Mouse clicks and mouse movement. Rah.
4718 Formerly, we used PointerMotionHintMask (in standard_event_mask)
4719 so that we would have to call XQueryPointer after each MotionNotify
4720 event to ask for another such event. However, this made mouse tracking
4721 slow, and there was a bug that made it eventually stop.
4723 Simply asking for MotionNotify all the time seems to work better.
4725 In order to avoid asking for motion events and then throwing most
4726 of them away or busy-polling the server for mouse positions, we ask
4727 the server for pointer motion hints. This means that we get only
4728 one event per group of mouse movements. "Groups" are delimited by
4729 other kinds of events (focus changes and button clicks, for
4730 example), or by XQueryPointer calls; when one of these happens, we
4731 get another MotionNotify event the next time the mouse moves. This
4732 is at least as efficient as getting motion events when mouse
4733 tracking is on, and I suspect only negligibly worse when tracking
4734 is off. */
4736 /* Prepare a mouse-event in *RESULT for placement in the input queue.
4738 If the event is a button press, then note that we have grabbed
4739 the mouse. */
4741 static Lisp_Object
4742 construct_mouse_click (struct input_event *result,
4743 const XButtonEvent *event,
4744 struct frame *f)
4746 /* Make the event type NO_EVENT; we'll change that when we decide
4747 otherwise. */
4748 result->kind = MOUSE_CLICK_EVENT;
4749 result->code = event->button - Button1;
4750 result->timestamp = event->time;
4751 result->modifiers = (x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f),
4752 event->state)
4753 | (event->type == ButtonRelease
4754 ? up_modifier
4755 : down_modifier));
4757 XSETINT (result->x, event->x);
4758 XSETINT (result->y, event->y);
4759 XSETFRAME (result->frame_or_window, f);
4760 result->arg = Qnil;
4761 return Qnil;
4764 /* Function to report a mouse movement to the mainstream Emacs code.
4765 The input handler calls this.
4767 We have received a mouse movement event, which is given in *event.
4768 If the mouse is over a different glyph than it was last time, tell
4769 the mainstream emacs code by setting mouse_moved. If not, ask for
4770 another motion event, so we can check again the next time it moves. */
4772 static bool
4773 note_mouse_movement (struct frame *frame, const XMotionEvent *event)
4775 XRectangle *r;
4776 struct x_display_info *dpyinfo;
4778 if (!FRAME_X_OUTPUT (frame))
4779 return false;
4781 dpyinfo = FRAME_DISPLAY_INFO (frame);
4782 dpyinfo->last_mouse_movement_time = event->time;
4783 dpyinfo->last_mouse_motion_frame = frame;
4784 dpyinfo->last_mouse_motion_x = event->x;
4785 dpyinfo->last_mouse_motion_y = event->y;
4787 if (event->window != FRAME_X_WINDOW (frame))
4789 frame->mouse_moved = true;
4790 dpyinfo->last_mouse_scroll_bar = NULL;
4791 note_mouse_highlight (frame, -1, -1);
4792 dpyinfo->last_mouse_glyph_frame = NULL;
4793 return true;
4797 /* Has the mouse moved off the glyph it was on at the last sighting? */
4798 r = &dpyinfo->last_mouse_glyph;
4799 if (frame != dpyinfo->last_mouse_glyph_frame
4800 || event->x < r->x || event->x >= r->x + r->width
4801 || event->y < r->y || event->y >= r->y + r->height)
4803 frame->mouse_moved = true;
4804 dpyinfo->last_mouse_scroll_bar = NULL;
4805 note_mouse_highlight (frame, event->x, event->y);
4806 /* Remember which glyph we're now on. */
4807 remember_mouse_glyph (frame, event->x, event->y, r);
4808 dpyinfo->last_mouse_glyph_frame = frame;
4809 return true;
4812 return false;
4815 /* Return the current position of the mouse.
4816 *FP should be a frame which indicates which display to ask about.
4818 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
4819 and *PART to the frame, window, and scroll bar part that the mouse
4820 is over. Set *X and *Y to the portion and whole of the mouse's
4821 position on the scroll bar.
4823 If the mouse movement started elsewhere, set *FP to the frame the
4824 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
4825 the mouse is over.
4827 Set *TIMESTAMP to the server time-stamp for the time at which the mouse
4828 was at this position.
4830 Don't store anything if we don't have a valid set of values to report.
4832 This clears the mouse_moved flag, so we can wait for the next mouse
4833 movement. */
4835 static void
4836 XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
4837 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
4838 Time *timestamp)
4840 struct frame *f1;
4841 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
4843 block_input ();
4845 if (dpyinfo->last_mouse_scroll_bar && insist == 0)
4847 struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
4849 if (bar->horizontal)
4850 x_horizontal_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp);
4851 else
4852 x_scroll_bar_report_motion (fp, bar_window, part, x, y, timestamp);
4854 else
4856 Window root;
4857 int root_x, root_y;
4859 Window dummy_window;
4860 int dummy;
4862 Lisp_Object frame, tail;
4864 /* Clear the mouse-moved flag for every frame on this display. */
4865 FOR_EACH_FRAME (tail, frame)
4866 if (FRAME_X_P (XFRAME (frame))
4867 && FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
4868 XFRAME (frame)->mouse_moved = false;
4870 dpyinfo->last_mouse_scroll_bar = NULL;
4872 /* Figure out which root window we're on. */
4873 XQueryPointer (FRAME_X_DISPLAY (*fp),
4874 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
4876 /* The root window which contains the pointer. */
4877 &root,
4879 /* Trash which we can't trust if the pointer is on
4880 a different screen. */
4881 &dummy_window,
4883 /* The position on that root window. */
4884 &root_x, &root_y,
4886 /* More trash we can't trust. */
4887 &dummy, &dummy,
4889 /* Modifier keys and pointer buttons, about which
4890 we don't care. */
4891 (unsigned int *) &dummy);
4893 /* Now we have a position on the root; find the innermost window
4894 containing the pointer. */
4896 Window win, child;
4897 int win_x, win_y;
4898 int parent_x = 0, parent_y = 0;
4900 win = root;
4902 /* XTranslateCoordinates can get errors if the window
4903 structure is changing at the same time this function
4904 is running. So at least we must not crash from them. */
4906 x_catch_errors (FRAME_X_DISPLAY (*fp));
4908 if (x_mouse_grabbed (dpyinfo))
4910 /* If mouse was grabbed on a frame, give coords for that frame
4911 even if the mouse is now outside it. */
4912 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
4914 /* From-window. */
4915 root,
4917 /* To-window. */
4918 FRAME_X_WINDOW (dpyinfo->last_mouse_frame),
4920 /* From-position, to-position. */
4921 root_x, root_y, &win_x, &win_y,
4923 /* Child of win. */
4924 &child);
4925 f1 = dpyinfo->last_mouse_frame;
4927 else
4929 while (true)
4931 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
4933 /* From-window, to-window. */
4934 root, win,
4936 /* From-position, to-position. */
4937 root_x, root_y, &win_x, &win_y,
4939 /* Child of win. */
4940 &child);
4942 if (child == None || child == win)
4943 break;
4944 #ifdef USE_GTK
4945 /* We don't wan't to know the innermost window. We
4946 want the edit window. For non-Gtk+ the innermost
4947 window is the edit window. For Gtk+ it might not
4948 be. It might be the tool bar for example. */
4949 if (x_window_to_frame (dpyinfo, win))
4950 break;
4951 #endif
4952 win = child;
4953 parent_x = win_x;
4954 parent_y = win_y;
4957 /* Now we know that:
4958 win is the innermost window containing the pointer
4959 (XTC says it has no child containing the pointer),
4960 win_x and win_y are the pointer's position in it
4961 (XTC did this the last time through), and
4962 parent_x and parent_y are the pointer's position in win's parent.
4963 (They are what win_x and win_y were when win was child.
4964 If win is the root window, it has no parent, and
4965 parent_{x,y} are invalid, but that's okay, because we'll
4966 never use them in that case.) */
4968 #ifdef USE_GTK
4969 /* We don't wan't to know the innermost window. We
4970 want the edit window. */
4971 f1 = x_window_to_frame (dpyinfo, win);
4972 #else
4973 /* Is win one of our frames? */
4974 f1 = x_any_window_to_frame (dpyinfo, win);
4975 #endif
4977 #ifdef USE_X_TOOLKIT
4978 /* If we end up with the menu bar window, say it's not
4979 on the frame. */
4980 if (f1 != NULL
4981 && f1->output_data.x->menubar_widget
4982 && win == XtWindow (f1->output_data.x->menubar_widget))
4983 f1 = NULL;
4984 #endif /* USE_X_TOOLKIT */
4987 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
4988 f1 = 0;
4990 x_uncatch_errors_after_check ();
4992 /* If not, is it one of our scroll bars? */
4993 if (! f1)
4995 struct scroll_bar *bar;
4997 bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win, 2);
4999 if (bar)
5001 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5002 win_x = parent_x;
5003 win_y = parent_y;
5007 if (f1 == 0 && insist > 0)
5008 f1 = SELECTED_FRAME ();
5010 if (f1)
5012 /* Ok, we found a frame. Store all the values.
5013 last_mouse_glyph is a rectangle used to reduce the
5014 generation of mouse events. To not miss any motion
5015 events, we must divide the frame into rectangles of the
5016 size of the smallest character that could be displayed
5017 on it, i.e. into the same rectangles that matrices on
5018 the frame are divided into. */
5020 /* FIXME: what if F1 is not an X frame? */
5021 dpyinfo = FRAME_DISPLAY_INFO (f1);
5022 remember_mouse_glyph (f1, win_x, win_y, &dpyinfo->last_mouse_glyph);
5023 dpyinfo->last_mouse_glyph_frame = f1;
5025 *bar_window = Qnil;
5026 *part = 0;
5027 *fp = f1;
5028 XSETINT (*x, win_x);
5029 XSETINT (*y, win_y);
5030 *timestamp = dpyinfo->last_mouse_movement_time;
5035 unblock_input ();
5040 /***********************************************************************
5041 Scroll bars
5042 ***********************************************************************/
5044 /* Scroll bar support. */
5046 /* Given an X window ID and a DISPLAY, find the struct scroll_bar which
5047 manages it.
5048 This can be called in GC, so we have to make sure to strip off mark
5049 bits. */
5051 static struct scroll_bar *
5052 x_window_to_scroll_bar (Display *display, Window window_id, int type)
5054 Lisp_Object tail, frame;
5056 #if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
5057 window_id = (Window) xg_get_scroll_id_for_window (display, window_id);
5058 #endif /* USE_GTK && USE_TOOLKIT_SCROLL_BARS */
5060 FOR_EACH_FRAME (tail, frame)
5062 Lisp_Object bar, condemned;
5064 if (! FRAME_X_P (XFRAME (frame)))
5065 continue;
5067 /* Scan this frame's scroll bar list for a scroll bar with the
5068 right window ID. */
5069 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
5070 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
5071 /* This trick allows us to search both the ordinary and
5072 condemned scroll bar lists with one loop. */
5073 ! NILP (bar) || (bar = condemned,
5074 condemned = Qnil,
5075 ! NILP (bar));
5076 bar = XSCROLL_BAR (bar)->next)
5077 if (XSCROLL_BAR (bar)->x_window == window_id
5078 && FRAME_X_DISPLAY (XFRAME (frame)) == display
5079 && (type = 2
5080 || (type == 1 && XSCROLL_BAR (bar)->horizontal)
5081 || (type == 0 && !XSCROLL_BAR (bar)->horizontal)))
5082 return XSCROLL_BAR (bar);
5085 return NULL;
5089 #if defined USE_LUCID
5091 /* Return the Lucid menu bar WINDOW is part of. Return null
5092 if WINDOW is not part of a menu bar. */
5094 static Widget
5095 x_window_to_menu_bar (Window window)
5097 Lisp_Object tail, frame;
5099 FOR_EACH_FRAME (tail, frame)
5100 if (FRAME_X_P (XFRAME (frame)))
5102 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
5104 if (menu_bar && xlwmenu_window_p (menu_bar, window))
5105 return menu_bar;
5107 return NULL;
5110 #endif /* USE_LUCID */
5113 /************************************************************************
5114 Toolkit scroll bars
5115 ************************************************************************/
5117 #ifdef USE_TOOLKIT_SCROLL_BARS
5119 static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part,
5120 int, int, bool);
5122 /* Lisp window being scrolled. Set when starting to interact with
5123 a toolkit scroll bar, reset to nil when ending the interaction. */
5125 static Lisp_Object window_being_scrolled;
5127 /* Whether this is an Xaw with arrow-scrollbars. This should imply
5128 that movements of 1/20 of the screen size are mapped to up/down. */
5130 #ifndef USE_GTK
5131 /* Id of action hook installed for scroll bars. */
5133 static XtActionHookId action_hook_id;
5134 static XtActionHookId horizontal_action_hook_id;
5136 static Boolean xaw3d_arrow_scroll;
5138 /* Whether the drag scrolling maintains the mouse at the top of the
5139 thumb. If not, resizing the thumb needs to be done more carefully
5140 to avoid jerkiness. */
5142 static Boolean xaw3d_pick_top;
5144 /* Action hook installed via XtAppAddActionHook when toolkit scroll
5145 bars are used.. The hook is responsible for detecting when
5146 the user ends an interaction with the scroll bar, and generates
5147 a `end-scroll' SCROLL_BAR_CLICK_EVENT' event if so. */
5149 static void
5150 xt_action_hook (Widget widget, XtPointer client_data, String action_name,
5151 XEvent *event, String *params, Cardinal *num_params)
5153 bool scroll_bar_p;
5154 const char *end_action;
5156 #ifdef USE_MOTIF
5157 scroll_bar_p = XmIsScrollBar (widget);
5158 end_action = "Release";
5159 #else /* !USE_MOTIF i.e. use Xaw */
5160 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
5161 end_action = "EndScroll";
5162 #endif /* USE_MOTIF */
5164 if (scroll_bar_p
5165 && strcmp (action_name, end_action) == 0
5166 && WINDOWP (window_being_scrolled))
5168 struct window *w;
5169 struct scroll_bar *bar;
5171 x_send_scroll_bar_event (window_being_scrolled,
5172 scroll_bar_end_scroll, 0, 0, false);
5173 w = XWINDOW (window_being_scrolled);
5174 bar = XSCROLL_BAR (w->vertical_scroll_bar);
5176 if (bar->dragging != -1)
5178 bar->dragging = -1;
5179 /* The thumb size is incorrect while dragging: fix it. */
5180 set_vertical_scroll_bar (w);
5182 window_being_scrolled = Qnil;
5183 #if defined (USE_LUCID)
5184 bar->last_seen_part = scroll_bar_nowhere;
5185 #endif
5186 /* Xt timeouts no longer needed. */
5187 toolkit_scroll_bar_interaction = false;
5192 static void
5193 xt_horizontal_action_hook (Widget widget, XtPointer client_data, String action_name,
5194 XEvent *event, String *params, Cardinal *num_params)
5196 bool scroll_bar_p;
5197 const char *end_action;
5199 #ifdef USE_MOTIF
5200 scroll_bar_p = XmIsScrollBar (widget);
5201 end_action = "Release";
5202 #else /* !USE_MOTIF i.e. use Xaw */
5203 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
5204 end_action = "EndScroll";
5205 #endif /* USE_MOTIF */
5207 if (scroll_bar_p
5208 && strcmp (action_name, end_action) == 0
5209 && WINDOWP (window_being_scrolled))
5211 struct window *w;
5212 struct scroll_bar *bar;
5214 x_send_scroll_bar_event (window_being_scrolled,
5215 scroll_bar_end_scroll, 0, 0, true);
5216 w = XWINDOW (window_being_scrolled);
5217 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
5219 if (bar->dragging != -1)
5221 bar->dragging = -1;
5222 /* The thumb size is incorrect while dragging: fix it. */
5223 set_horizontal_scroll_bar (w);
5225 window_being_scrolled = Qnil;
5226 #if defined (USE_LUCID)
5227 bar->last_seen_part = scroll_bar_nowhere;
5228 #endif
5229 /* Xt timeouts no longer needed. */
5230 toolkit_scroll_bar_interaction = false;
5233 #endif /* not USE_GTK */
5235 /* Send a client message with message type Xatom_Scrollbar for a
5236 scroll action to the frame of WINDOW. PART is a value identifying
5237 the part of the scroll bar that was clicked on. PORTION is the
5238 amount to scroll of a whole of WHOLE. */
5240 static void
5241 x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part,
5242 int portion, int whole, bool horizontal)
5244 XEvent event;
5245 XClientMessageEvent *ev = &event.xclient;
5246 struct window *w = XWINDOW (window);
5247 struct frame *f = XFRAME (w->frame);
5248 intptr_t iw = (intptr_t) w;
5249 verify (INTPTR_WIDTH <= 64);
5250 int sign_shift = INTPTR_WIDTH - 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;