This source file includes following definitions.
- emacs_menu_bar_init
- emacs_menu_bar_class_init
- emacs_menu_bar_get_preferred_width
- emacs_menu_bar_new
- xg_set_screen
- xg_display_open
- xg_get_gdk_scale
- xg_get_scale
- xg_display_close
- xg_create_default_cursor
- xg_get_pixbuf_from_pix_and_mask
- xg_get_pixbuf_from_surface
- file_for_image
- xg_get_image_for_pixmap
- xg_set_cursor
- xg_list_insert
- xg_list_remove
- get_utf8_string
- xg_check_special_colors
- hierarchy_ch_cb
- qttip_cb
- xg_prepare_tooltip
- xg_show_tooltip
- xg_hide_tooltip
- xg_show_tooltip
- xg_hide_tooltip
- my_log_handler
- xg_is_menu_window
- xg_set_geometry
- xg_frame_resized
- xg_frame_set_char_size
- xg_height_or_width_changed
- xg_win_to_widget
- xg_set_widget_bg
- style_changed_cb
- delete_cb
- xg_create_frame_widgets
- xg_create_frame_outer_widgets
- xg_free_frame_widgets
- xg_wm_set_size_hint
- xg_set_background_color
- xg_set_undecorated
- xg_frame_restack
- xg_set_skip_taskbar
- xg_set_no_focus_on_map
- xg_set_no_accept_focus
- xg_set_override_redirect
- xg_set_frame_icon
- get_dialog_title
- dialog_delete_callback
- create_dialog
- xg_dialog_response_cb
- pop_down_dialog
- xg_maybe_add_timer
- xg_dialog_run
- xg_uses_old_file_dialog
- xg_get_file_name_from_chooser
- xg_toggle_visibility_cb
- xg_toggle_notify_cb
- xg_get_file_with_chooser
- xg_get_file_name_from_selector
- xg_get_file_with_selection
- xg_get_file_name
- xg_weight_to_symbol
- xg_style_to_symbol
- xg_font_filter
- xg_get_font
- make_cl_data
- update_cl_data
- unref_cl_data
- xg_mark_data
- menuitem_destroy_callback
- menuitem_highlight_callback
- menu_destroy_callback
- make_widget_for_menu_item
- make_menu_item
- xg_create_one_menuitem
- menu_bar_button_pressed_cb
- create_menus
- xg_create_widget
- xg_get_menu_item_label
- xg_item_label_same_p
- xg_destroy_widgets
- xg_update_menubar
- xg_update_menu_item
- xg_update_toggle_item
- xg_update_radio_item
- xg_update_submenu
- xg_modify_menubar_widgets
- menubar_map_cb
- xg_update_frame_menubar
- free_frame_menubar
- xg_event_is_for_menubar
- xg_store_widget_in_map
- xg_remove_widget_from_map
- xg_get_widget_from_map
- find_scrollbar_cb
- xg_get_widget_from_map
- update_theme_scrollbar_width
- update_theme_scrollbar_height
- xg_get_default_scrollbar_width
- xg_get_default_scrollbar_height
- xg_get_scroll_id_for_window
- xg_gtk_scroll_destroy
- xg_scroll_bar_size_allocate_cb
- xg_finish_scroll_bar_creation
- xg_create_scroll_bar
- xg_create_horizontal_scroll_bar
- xg_remove_scroll_bar
- xg_update_scrollbar_pos
- xg_update_horizontal_scrollbar_pos
- int_gtk_range_get_value
- xg_set_toolkit_scroll_bar_thumb
- xg_set_toolkit_horizontal_scroll_bar_thumb
- xg_event_is_for_scrollbar
- xg_page_setup_dialog
- xg_get_page_setup
- draw_page
- xg_print_frames_dialog
- xg_tool_bar_button_cb
- xg_tool_bar_callback
- xg_get_tool_bar_widgets
- xg_tool_bar_help_callback
- xg_tool_bar_item_expose_callback
- xg_pack_tool_bar
- tb_size_cb
- xg_create_tool_bar
- find_rtl_image
- xg_make_tool_item
- is_box_type
- xg_tool_item_stale_p
- xg_update_tool_bar_sizes
- find_icon_from_name
- update_frame_tool_bar
- free_frame_tool_bar
- xg_change_toolbar_position
- xg_initialize
- xg_add_virtual_mods
- xg_virtual_mods_to_x
- xg_im_context_commit
- xg_im_context_preedit_changed
- xg_im_context_preedit_end
- xg_widget_key_press_event_cb
- xg_filter_key
- xg_widget_style_updated
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <config.h>
21
22 #ifdef USE_GTK
23 #include <float.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #include <c-ctype.h>
28
29 #include "lisp.h"
30 #include "dispextern.h"
31 #include "frame.h"
32 #include "systime.h"
33 #ifndef HAVE_PGTK
34 #include "xterm.h"
35 #define xp x
36 typedef struct x_output xp_output;
37 #else
38 #define xp pgtk
39 typedef struct pgtk_output xp_output;
40 #endif
41 #include "blockinput.h"
42 #include "window.h"
43 #include "gtkutil.h"
44 #include "termhooks.h"
45 #include "keyboard.h"
46 #include "coding.h"
47
48 #include <gdk/gdkkeysyms.h>
49
50 #ifdef HAVE_XINPUT2
51 #include <X11/extensions/XInput2.h>
52 #endif
53
54 #ifdef HAVE_XFT
55 #include <X11/Xft/Xft.h>
56 #endif
57
58 #ifdef HAVE_GTK3
59 #ifndef HAVE_PGTK
60 #include <gtk/gtkx.h>
61 #endif
62 #include "emacsgtkfixed.h"
63 #endif
64
65 #ifdef HAVE_XDBE
66 #include <X11/extensions/Xdbe.h>
67 #endif
68
69 #ifdef HAVE_GTK3
70 #define XG_TEXT_CANCEL "Cancel"
71 #define XG_TEXT_OK "OK"
72 #define XG_TEXT_OPEN "Open"
73 #else
74 #define XG_TEXT_CANCEL GTK_STOCK_CANCEL
75 #define XG_TEXT_OK GTK_STOCK_OK
76 #define XG_TEXT_OPEN GTK_STOCK_OPEN
77 #endif
78
79 #ifdef HAVE_GTK3
80 static void emacs_menu_bar_get_preferred_width (GtkWidget *, gint *, gint *);
81 static GType emacs_menu_bar_get_type (void);
82
83 typedef struct _EmacsMenuBar
84 {
85 GtkMenuBar parent;
86 } EmacsMenuBar;
87
88 typedef struct _EmacsMenuBarClass
89 {
90 GtkMenuBarClass parent;
91 } EmacsMenuBarClass;
92
93 G_DEFINE_TYPE (EmacsMenuBar, emacs_menu_bar, GTK_TYPE_MENU_BAR)
94 #endif
95
96 #ifndef HAVE_PGTK
97 static void xg_im_context_commit (GtkIMContext *, gchar *, gpointer);
98 static void xg_im_context_preedit_changed (GtkIMContext *, gpointer);
99 static void xg_im_context_preedit_end (GtkIMContext *, gpointer);
100 static bool xg_widget_key_press_event_cb (GtkWidget *, GdkEvent *, gpointer);
101 #endif
102
103 #if GTK_CHECK_VERSION (3, 10, 0)
104 static void xg_widget_style_updated (GtkWidget *, gpointer);
105 #endif
106
107 #ifndef HAVE_GTK3
108
109 #ifdef HAVE_FREETYPE
110 #define gtk_font_chooser_dialog_new(x, y) \
111 gtk_font_selection_dialog_new (x)
112 #undef GTK_FONT_CHOOSER
113 #define GTK_FONT_CHOOSER(x) GTK_FONT_SELECTION_DIALOG (x)
114 #define gtk_font_chooser_set_font(x, y) \
115 gtk_font_selection_dialog_set_font_name (x, y)
116 #endif
117
118 #define gtk_box_new(ori, spacing) \
119 ((ori) == GTK_ORIENTATION_HORIZONTAL \
120 ? gtk_hbox_new (FALSE, (spacing)) : gtk_vbox_new (FALSE, (spacing)))
121 #define gtk_scrollbar_new(ori, spacing) \
122 ((ori) == GTK_ORIENTATION_HORIZONTAL \
123 ? gtk_hscrollbar_new ((spacing)) : gtk_vscrollbar_new ((spacing)))
124 #endif
125
126 #define XG_BIN_CHILD(x) gtk_bin_get_child (GTK_BIN (x))
127
128 static void update_theme_scrollbar_width (void);
129 static void update_theme_scrollbar_height (void);
130
131 #define TB_INFO_KEY "xg_frame_tb_info"
132 struct xg_frame_tb_info
133 {
134 Lisp_Object last_tool_bar;
135 Lisp_Object style;
136 int n_last_items;
137 int hmargin, vmargin;
138 GtkTextDirection dir;
139 };
140
141 #ifdef HAVE_XWIDGETS
142 bool xg_gtk_initialized;
143 #endif
144
145 static GtkWidget *xg_get_widget_from_map (ptrdiff_t idx, Display *dpy);
146
147
148
149 #ifdef HAVE_GTK3
150 static void
151 emacs_menu_bar_init (EmacsMenuBar *menu_bar)
152 {
153 return;
154 }
155
156 static void
157 emacs_menu_bar_class_init (EmacsMenuBarClass *klass)
158 {
159 GtkWidgetClass *widget_class;
160
161 widget_class = GTK_WIDGET_CLASS (klass);
162 widget_class->get_preferred_width = emacs_menu_bar_get_preferred_width;
163 }
164
165 static void
166 emacs_menu_bar_get_preferred_width (GtkWidget *widget,
167 gint *minimum, gint *natural)
168 {
169 GtkWidgetClass *widget_class;
170
171 widget_class = GTK_WIDGET_CLASS (emacs_menu_bar_parent_class);
172 widget_class->get_preferred_width (widget, minimum, natural);
173
174 if (minimum)
175 *minimum = 0;
176 }
177
178 static GtkWidget *
179 emacs_menu_bar_new (void)
180 {
181 return GTK_WIDGET (g_object_new (emacs_menu_bar_get_type (), NULL));
182 }
183
184 #endif
185
186
187
188
189
190
191
192
193
194 static GdkDisplay *gdpy_def;
195
196
197
198
199
200 static void
201 xg_set_screen (GtkWidget *w, struct frame *f)
202 {
203 #ifndef HAVE_PGTK
204 if (FRAME_X_DISPLAY (f) != DEFAULT_GDK_DISPLAY ())
205 {
206 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
207 GdkScreen *gscreen = gdk_display_get_default_screen (gdpy);
208
209 if (GTK_IS_MENU (w))
210 gtk_menu_set_screen (GTK_MENU (w), gscreen);
211 else
212 gtk_window_set_screen (GTK_WINDOW (w), gscreen);
213 }
214 #else
215 if (FRAME_X_DISPLAY (f) != DEFAULT_GDK_DISPLAY ())
216 {
217 GdkScreen *gscreen = gdk_display_get_default_screen (FRAME_X_DISPLAY (f));
218
219 if (GTK_IS_MENU (w))
220 gtk_menu_set_screen (GTK_MENU (w), gscreen);
221 else
222 gtk_window_set_screen (GTK_WINDOW (w), gscreen);
223 }
224 #endif
225 }
226
227
228
229
230
231
232
233
234
235 void
236 #ifndef HAVE_PGTK
237 xg_display_open (char *display_name, Display **dpy)
238 #else
239 xg_display_open (char *display_name, GdkDisplay **dpy)
240 #endif
241 {
242 GdkDisplay *gdpy;
243
244 unrequest_sigio ();
245 #ifndef HAVE_PGTK
246 gdpy = gdk_display_open (display_name);
247 #else
248 gdpy = gdk_display_open (strlen (display_name) == 0 ? NULL : display_name);
249 #endif
250 request_sigio ();
251 if (!gdpy_def && gdpy)
252 {
253 gdpy_def = gdpy;
254 gdk_display_manager_set_default_display (gdk_display_manager_get (),
255 gdpy);
256 }
257
258 #ifndef HAVE_PGTK
259 *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
260 #else
261 *dpy = gdpy;
262 #endif
263 }
264
265
266 static int
267 xg_get_gdk_scale (void)
268 {
269 #ifdef HAVE_GTK3
270 const char *sscale = getenv ("GDK_SCALE");
271
272 if (sscale)
273 {
274 long scale = atol (sscale);
275 if (0 < scale)
276 return min (scale, INT_MAX);
277 }
278 #endif
279
280 return 1;
281 }
282
283 int
284 xg_get_scale (struct frame *f)
285 {
286 #ifdef HAVE_PGTK
287 return 1;
288 #endif
289 #ifdef HAVE_GTK3
290 if (FRAME_GTK_WIDGET (f))
291 return gtk_widget_get_scale_factor (FRAME_GTK_WIDGET (f));
292 #endif
293 return xg_get_gdk_scale ();
294 }
295
296
297
298 void
299 #ifndef HAVE_PGTK
300 xg_display_close (Display *dpy)
301 #else
302 xg_display_close (GdkDisplay *gdpy)
303 #endif
304 {
305 #ifndef HAVE_PGTK
306 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
307
308
309
310
311 if (gdk_display_get_default () == gdpy)
312 {
313 struct x_display_info *dpyinfo;
314 GdkDisplay *gdpy_new = NULL;
315
316
317 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
318 if (dpyinfo->display != dpy)
319 {
320 gdpy_new = gdk_x11_lookup_xdisplay (dpyinfo->display);
321 gdk_display_manager_set_default_display (gdk_display_manager_get (),
322 gdpy_new);
323 break;
324 }
325 gdpy_def = gdpy_new;
326 }
327
328 gdk_display_close (gdpy);
329
330 #else
331
332
333
334
335 if (gdk_display_get_default () == gdpy)
336 {
337 struct pgtk_display_info *dpyinfo;
338 GdkDisplay *gdpy_new = NULL;
339
340
341 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
342 if (dpyinfo->gdpy != gdpy)
343 {
344 gdpy_new = dpyinfo->gdpy;
345 gdk_display_manager_set_default_display (gdk_display_manager_get (),
346 gdpy_new);
347 break;
348 }
349 gdpy_def = gdpy_new;
350 }
351
352 gdk_display_close (gdpy);
353 #endif
354 }
355
356
357
358
359
360
361
362
363
364 GdkCursor *
365 #ifndef HAVE_PGTK
366 xg_create_default_cursor (Display *dpy)
367 #else
368 xg_create_default_cursor (GdkDisplay *gdpy)
369 #endif
370 {
371 #ifndef HAVE_PGTK
372 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
373 #endif
374 return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
375 }
376
377 #ifndef HAVE_PGTK
378
379
380 static GdkPixbuf *
381 xg_get_pixbuf_from_pix_and_mask (struct frame *f,
382 Pixmap pix,
383 Pixmap mask)
384 {
385 GdkPixbuf *icon_buf = 0;
386 int iunused;
387 Window wunused;
388 unsigned int width, height, depth, uunused;
389
390 if (FRAME_DISPLAY_INFO (f)->red_bits != 8)
391 return 0;
392 XGetGeometry (FRAME_X_DISPLAY (f), pix, &wunused, &iunused, &iunused,
393 &width, &height, &uunused, &depth);
394 if (depth != 24)
395 return 0;
396 XImage *xim = XGetImage (FRAME_X_DISPLAY (f), pix, 0, 0, width, height,
397 ~0, XYPixmap);
398 if (xim)
399 {
400 XImage *xmm = (! mask ? 0
401 : XGetImage (FRAME_X_DISPLAY (f), mask, 0, 0,
402 width, height, ~0, XYPixmap));
403 icon_buf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
404 if (icon_buf)
405 {
406 guchar *pixels = gdk_pixbuf_get_pixels (icon_buf);
407 int rowjunkwidth = gdk_pixbuf_get_rowstride (icon_buf) - width * 4;
408 for (int y = 0; y < height; y++, pixels += rowjunkwidth)
409 for (int x = 0; x < width; x++)
410 {
411 unsigned long rgb = XGetPixel (xim, x, y);
412 *pixels++ = (rgb >> 16) & 255;
413 *pixels++ = (rgb >> 8) & 255;
414 *pixels++ = rgb & 255;
415 *pixels++ = xmm && !XGetPixel (xmm, x, y) ? 0 : 255;
416 }
417 }
418
419 if (xmm)
420 XDestroyImage (xmm);
421 XDestroyImage (xim);
422 }
423
424 return icon_buf;
425 }
426
427 #if defined USE_CAIRO && !defined HAVE_GTK3
428 static GdkPixbuf *
429 xg_get_pixbuf_from_surface (cairo_surface_t *surface)
430 {
431 int width = cairo_image_surface_get_width (surface);
432 int height = cairo_image_surface_get_height (surface);
433 GdkPixbuf *icon_buf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
434 width, height);
435 if (icon_buf)
436 {
437 guchar *pixels = gdk_pixbuf_get_pixels (icon_buf);
438 int rowstride = gdk_pixbuf_get_rowstride (icon_buf);
439 cairo_surface_t *icon_surface
440 = cairo_image_surface_create_for_data (pixels, CAIRO_FORMAT_ARGB32,
441 width, height, rowstride);
442 cairo_t *cr = cairo_create (icon_surface);
443 cairo_surface_destroy (icon_surface);
444 cairo_set_source_surface (cr, surface, 0, 0);
445 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
446 cairo_paint (cr);
447 cairo_destroy (cr);
448
449 for (int y = 0; y < height; y++)
450 {
451 for (int x = 0; x < width; x++)
452 {
453 guint32 argb = ((guint32 *) pixels)[x];
454 int alpha = argb >> 24;
455
456 if (alpha == 0)
457 ((guint32 *) pixels)[x] = 0;
458 else
459 {
460 int red = (argb >> 16) & 0xff, green = (argb >> 8) & 0xff;
461 int blue = argb & 0xff;
462
463 pixels[x * 4 ] = red * 0xff / alpha;
464 pixels[x * 4 + 1] = green * 0xff / alpha;
465 pixels[x * 4 + 2] = blue * 0xff / alpha;
466 pixels[x * 4 + 3] = alpha;
467 }
468 }
469 pixels += rowstride;
470 }
471 }
472
473 return icon_buf;
474 }
475 #endif
476
477 #endif
478
479 static Lisp_Object
480 file_for_image (Lisp_Object image)
481 {
482 Lisp_Object specified_file = Qnil;
483 Lisp_Object tail;
484
485 for (tail = XCDR (image);
486 NILP (specified_file) && CONSP (tail) && CONSP (XCDR (tail));
487 tail = XCDR (XCDR (tail)))
488 if (EQ (XCAR (tail), QCfile))
489 specified_file = XCAR (XCDR (tail));
490
491 return specified_file;
492 }
493
494
495
496
497
498
499
500
501
502
503
504
505 static GtkWidget *
506 xg_get_image_for_pixmap (struct frame *f,
507 struct image *img,
508 GtkWidget *widget,
509 GtkImage *old_widget)
510 {
511 #ifdef USE_CAIRO
512 cairo_surface_t *surface;
513 #else
514 GdkPixbuf *icon_buf;
515 #endif
516
517
518
519
520 Lisp_Object specified_file = file_for_image (img->spec);
521 Lisp_Object file;
522
523
524
525
526
527 if (STRINGP (specified_file)
528 && STRINGP (file = image_find_image_file (specified_file)))
529 {
530 char *encoded_file = SSDATA (ENCODE_FILE (file));
531 if (! old_widget)
532 old_widget = GTK_IMAGE (gtk_image_new_from_file (encoded_file));
533 else
534 gtk_image_set_from_file (old_widget, encoded_file);
535
536 return GTK_WIDGET (old_widget);
537 }
538
539
540
541
542
543 #ifdef USE_CAIRO
544 if (cairo_pattern_get_type (img->cr_data) == CAIRO_PATTERN_TYPE_SURFACE)
545 cairo_pattern_get_surface (img->cr_data, &surface);
546 else
547 surface = NULL;
548
549 if (surface)
550 {
551 #ifdef HAVE_GTK3
552 if (! old_widget)
553 old_widget = GTK_IMAGE (gtk_image_new_from_surface (surface));
554 else
555 gtk_image_set_from_surface (old_widget, surface);
556 #else
557 GdkPixbuf *icon_buf = xg_get_pixbuf_from_surface (surface);
558
559 if (icon_buf)
560 {
561 if (! old_widget)
562 old_widget = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_buf));
563 else
564 gtk_image_set_from_pixbuf (old_widget, icon_buf);
565
566 g_object_unref (G_OBJECT (icon_buf));
567 }
568 #endif
569 }
570 #else
571
572
573
574
575
576
577
578
579
580 icon_buf = xg_get_pixbuf_from_pix_and_mask (f, img->pixmap, img->mask);
581
582 if (icon_buf)
583 {
584 if (! old_widget)
585 old_widget = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_buf));
586 else
587 gtk_image_set_from_pixbuf (old_widget, icon_buf);
588
589 g_object_unref (G_OBJECT (icon_buf));
590 }
591 #endif
592
593 return GTK_WIDGET (old_widget);
594 }
595
596
597
598
599
600
601 static void
602 xg_set_cursor (GtkWidget *w, GdkCursor *cursor)
603 {
604 GdkWindow *window = gtk_widget_get_window (w);
605 GList *children = gdk_window_peek_children (window);
606
607 gdk_window_set_cursor (window, cursor);
608
609
610
611
612
613
614 for ( ; children; children = g_list_next (children))
615 gdk_window_set_cursor (GDK_WINDOW (children->data), cursor);
616 }
617
618
619
620 static void
621 xg_list_insert (xg_list_node *list, xg_list_node *node)
622 {
623 xg_list_node *list_start = list->next;
624
625 if (list_start) list_start->prev = node;
626 node->next = list_start;
627 node->prev = 0;
628 list->next = node;
629 }
630
631
632
633 static void
634 xg_list_remove (xg_list_node *list, xg_list_node *node)
635 {
636 xg_list_node *list_start = list->next;
637 if (node == list_start)
638 {
639 list->next = node->next;
640 if (list->next) list->next->prev = 0;
641 }
642 else
643 {
644 node->prev->next = node->next;
645 if (node->next) node->next->prev = node->prev;
646 }
647 }
648
649
650
651
652
653
654 static char *
655 get_utf8_string (const char *str)
656 {
657 char *utf8_str;
658
659 if (!str) return NULL;
660
661
662 if (!g_utf8_validate (str, -1, NULL))
663 utf8_str = g_locale_to_utf8 (str, -1, 0, 0, 0);
664 else
665 return g_strdup (str);
666
667 if (!utf8_str)
668 {
669
670 ptrdiff_t len;
671 ptrdiff_t nr_bad = 0;
672 gsize bytes_read;
673 gsize bytes_written;
674 unsigned char *p = (unsigned char *)str;
675 char *cp, *up;
676 GError *err = NULL;
677
678 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
679 &bytes_written, &err))
680 && err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
681 {
682 ++nr_bad;
683 p += bytes_written+1;
684 g_error_free (err);
685 err = NULL;
686 }
687
688 if (err)
689 {
690 g_error_free (err);
691 err = NULL;
692 }
693 if (cp) g_free (cp);
694
695 len = strlen (str);
696 ptrdiff_t alloc;
697 if (ckd_mul (&alloc, nr_bad, 4)
698 || ckd_add (&alloc, alloc, len + 1)
699 || SIZE_MAX < alloc)
700 memory_full (SIZE_MAX);
701 up = utf8_str = xmalloc (alloc);
702 p = (unsigned char *)str;
703
704 while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
705 &bytes_written, &err))
706 && err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
707 {
708 memcpy (up, p, bytes_written);
709 up += bytes_written;
710 up += sprintf (up, "\\%03o", p[bytes_written]);
711 p += bytes_written + 1;
712 g_error_free (err);
713 err = NULL;
714 }
715
716 if (cp)
717 {
718 strcpy (up, cp);
719 g_free (cp);
720 }
721 if (err)
722 {
723 g_error_free (err);
724 err = NULL;
725 }
726 }
727 return utf8_str;
728 }
729
730
731
732
733
734 bool
735 xg_check_special_colors (struct frame *f,
736 const char *color_name,
737 Emacs_Color *color)
738 {
739 bool success_p;
740 bool get_bg;
741 bool get_fg;
742 #ifdef HAVE_GTK3
743 GtkStyleContext *gsty;
744 GdkRGBA col;
745 char buf[sizeof "rgb://rrrr/gggg/bbbb"];
746 int state;
747 GdkRGBA *c;
748 unsigned short r, g, b;
749 #else
750 GtkStyle *gsty;
751 GdkColor *grgb;
752 #endif
753
754 get_bg = !strcmp ("gtk_selection_bg_color", color_name);
755 get_fg = !get_bg && !strcmp ("gtk_selection_fg_color", color_name);
756 success_p = false;
757
758 #ifdef HAVE_PGTK
759 while (FRAME_PARENT_FRAME (f))
760 f = FRAME_PARENT_FRAME (f);
761 #endif
762
763 if (!FRAME_GTK_WIDGET (f) || !(get_bg || get_fg))
764 return success_p;
765
766 block_input ();
767 #ifdef HAVE_GTK3
768 gsty = gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
769 state = GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED;
770
771 if (get_fg)
772 gtk_style_context_get_color (gsty, state, &col);
773 else
774 {
775
776
777
778
779 gtk_style_context_get (gsty, state,
780 GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &c,
781 NULL);
782 col = *c;
783 gdk_rgba_free (c);
784 }
785
786 r = col.red * 65535;
787 g = col.green * 65535;
788 b = col.blue * 65535;
789 #ifndef HAVE_PGTK
790 sprintf (buf, "rgb:%04x/%04x/%04x", r, g, b);
791 success_p = x_parse_color (f, buf, color) != 0;
792 #else
793 sprintf (buf, "#%04x%04x%04x", r, g, b);
794 success_p = pgtk_parse_color (f, buf, color) != 0;
795 #endif
796 #else
797 gsty = gtk_widget_get_style (FRAME_GTK_WIDGET (f));
798 grgb = (get_bg ? &gsty->bg[GTK_STATE_SELECTED]
799 : &gsty->fg[GTK_STATE_SELECTED]);
800
801 color->red = grgb->red;
802 color->green = grgb->green;
803 color->blue = grgb->blue;
804 color->pixel = grgb->pixel;
805 success_p = 1;
806 #endif
807 unblock_input ();
808 return success_p;
809 }
810
811
812
813
814
815
816
817 #ifndef HAVE_PGTK
818
819
820
821
822
823 static void
824 hierarchy_ch_cb (GtkWidget *widget,
825 GtkWidget *previous_toplevel,
826 gpointer user_data)
827 {
828 struct frame *f = user_data;
829 xp_output *x = f->output_data.xp;
830 GtkWidget *top = gtk_widget_get_toplevel (x->ttip_lbl);
831
832 if (! top || ! GTK_IS_WINDOW (top))
833 gtk_widget_hide (previous_toplevel);
834 }
835
836
837
838
839
840
841
842 static gboolean
843 qttip_cb (GtkWidget *widget,
844 gint xpos,
845 gint ypos,
846 gboolean keyboard_mode,
847 GtkTooltip *tooltip,
848 gpointer user_data)
849 {
850 struct frame *f = user_data;
851 xp_output *x = f->output_data.xp;
852 if (x->ttip_widget == NULL)
853 {
854 GtkWidget *p;
855 GList *list, *iter;
856
857 g_object_set (G_OBJECT (widget), "has-tooltip", FALSE, NULL);
858 x->ttip_widget = tooltip;
859 g_object_ref (G_OBJECT (tooltip));
860 x->ttip_lbl = gtk_label_new ("");
861 g_object_ref (G_OBJECT (x->ttip_lbl));
862 gtk_tooltip_set_custom (tooltip, x->ttip_lbl);
863 x->ttip_window = GTK_WINDOW (gtk_widget_get_toplevel (x->ttip_lbl));
864
865
866 p = gtk_widget_get_parent (x->ttip_lbl);
867 list = gtk_container_get_children (GTK_CONTAINER (p));
868 for (iter = list; iter; iter = g_list_next (iter))
869 {
870 GtkWidget *w = GTK_WIDGET (iter->data);
871 if (GTK_IS_LABEL (w))
872 gtk_label_set_line_wrap (GTK_LABEL (w), FALSE);
873 }
874 g_list_free (list);
875
876
877 gtk_window_set_title (x->ttip_window, "");
878
879 gtk_widget_realize (GTK_WIDGET (x->ttip_window));
880 gtk_widget_realize (x->ttip_lbl);
881
882 g_signal_connect (x->ttip_lbl, "hierarchy-changed",
883 G_CALLBACK (hierarchy_ch_cb), f);
884 }
885
886 return FALSE;
887 }
888
889
890
891
892 bool
893 xg_prepare_tooltip (struct frame *f,
894 Lisp_Object string,
895 int *width,
896 int *height)
897 {
898 xp_output *x = f->output_data.xp;
899 GtkWidget *widget;
900 GdkWindow *gwin;
901 GdkScreen *screen;
902 GtkSettings *settings;
903 gboolean tt_enabled = TRUE;
904 GtkRequisition req;
905 Lisp_Object encoded_string;
906
907 if (!x->ttip_lbl)
908 return FALSE;
909
910 block_input ();
911 encoded_string = ENCODE_UTF_8 (string);
912 widget = GTK_WIDGET (x->ttip_lbl);
913 gwin = gtk_widget_get_window (GTK_WIDGET (x->ttip_window));
914 screen = gdk_window_get_screen (gwin);
915 settings = gtk_settings_get_for_screen (screen);
916 g_object_get (settings, "gtk-enable-tooltips", &tt_enabled, NULL);
917 if (tt_enabled)
918 {
919 g_object_set (settings, "gtk-enable-tooltips", FALSE, NULL);
920
921 g_object_set_data (G_OBJECT (x->ttip_window), "restore-tt",
922 (gpointer)f);
923 }
924
925
926 g_object_set_data (G_OBJECT
927 (gtk_widget_get_display (GTK_WIDGET (x->ttip_window))),
928 "gdk-display-current-tooltip", NULL);
929
930
931
932 gtk_tooltip_set_custom (x->ttip_widget, widget);
933 gtk_tooltip_set_text (x->ttip_widget, SSDATA (encoded_string));
934 gtk_widget_get_preferred_size (GTK_WIDGET (x->ttip_window), NULL, &req);
935 if (width) *width = req.width;
936 if (height) *height = req.height;
937
938 unblock_input ();
939
940 return TRUE;
941 }
942
943
944
945
946 void
947 xg_show_tooltip (struct frame *f, int root_x, int root_y)
948 {
949 xp_output *x = f->output_data.xp;
950 if (x->ttip_window)
951 {
952 block_input ();
953 #ifndef HAVE_PGTK
954 gtk_window_move (x->ttip_window, root_x / xg_get_scale (f),
955 root_y / xg_get_scale (f));
956 gtk_widget_show (GTK_WIDGET (x->ttip_window));
957 #else
958 gtk_widget_show (GTK_WIDGET (x->ttip_window));
959 gtk_window_move (x->ttip_window, root_x / xg_get_scale (f),
960 root_y / xg_get_scale (f));
961 #endif
962 unblock_input ();
963 }
964 }
965
966
967
968
969
970 bool
971 xg_hide_tooltip (struct frame *f)
972 {
973 if (f->output_data.xp->ttip_window)
974 {
975 GtkWindow *win = f->output_data.xp->ttip_window;
976 block_input ();
977 gtk_widget_hide (GTK_WIDGET (win));
978
979 if (g_object_get_data (G_OBJECT (win), "restore-tt"))
980 {
981 GdkWindow *gwin = gtk_widget_get_window (GTK_WIDGET (win));
982 GdkScreen *screen = gdk_window_get_screen (gwin);
983 GtkSettings *settings = gtk_settings_get_for_screen (screen);
984 g_object_set (settings, "gtk-enable-tooltips", TRUE, NULL);
985 }
986 unblock_input ();
987
988 return TRUE;
989 }
990 return FALSE;
991 }
992
993 #else
994
995 void
996 xg_show_tooltip (struct frame *f,
997 Lisp_Object string)
998 {
999 Lisp_Object encoded_string = ENCODE_UTF_8 (string);
1000 gtk_widget_set_tooltip_text (FRAME_GTK_OUTER_WIDGET (f)
1001 ? FRAME_GTK_OUTER_WIDGET (f)
1002 : FRAME_GTK_WIDGET (f),
1003 SSDATA (encoded_string));
1004 }
1005
1006 bool
1007 xg_hide_tooltip (struct frame *f)
1008 {
1009 if (FRAME_GTK_OUTER_WIDGET (f))
1010 gtk_widget_set_tooltip_text (FRAME_GTK_OUTER_WIDGET (f), NULL);
1011 gtk_widget_set_tooltip_text (FRAME_GTK_WIDGET (f), NULL);
1012 return TRUE;
1013 }
1014
1015 #endif
1016
1017
1018
1019
1020
1021
1022 #if ! GTK_CHECK_VERSION (3, 22, 0)
1023 static void
1024 my_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
1025 const gchar *msg, gpointer user_data)
1026 {
1027 if (!strstr (msg, "visible children"))
1028 fprintf (stderr, "XX %s-WARNING **: %s\n", log_domain, msg);
1029 }
1030 #endif
1031
1032 #if defined HAVE_GTK3 && defined HAVE_XINPUT2
1033 bool
1034 xg_is_menu_window (Display *dpy, Window wdesc)
1035 {
1036 GtkWidget *gwdesc = xg_win_to_widget (dpy, wdesc);
1037
1038 if (GTK_IS_WINDOW (gwdesc))
1039 {
1040 GtkWidget *fw = gtk_bin_get_child (GTK_BIN (gwdesc));
1041 if (GTK_IS_MENU (fw))
1042 {
1043 GtkWidget *parent
1044 = gtk_menu_shell_get_parent_shell (GTK_MENU_SHELL (fw));
1045 return GTK_IS_MENU_BAR (parent);
1046 }
1047 }
1048
1049 return false;
1050 }
1051 #endif
1052
1053
1054
1055
1056
1057
1058 static void
1059 xg_set_geometry (struct frame *f)
1060 {
1061 if (f->size_hint_flags & (USPosition | PPosition))
1062 {
1063 int scale = xg_get_scale (f);
1064 #if ! GTK_CHECK_VERSION (3, 22, 0)
1065 if (x_gtk_use_window_move)
1066 {
1067 #endif
1068
1069
1070
1071 #ifndef HAVE_PGTK
1072 if (f->size_hint_flags & XNegative)
1073 f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
1074 - FRAME_PIXEL_WIDTH (f) + f->left_pos);
1075
1076 if (f->size_hint_flags & YNegative)
1077 f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
1078 - FRAME_PIXEL_HEIGHT (f) + f->top_pos);
1079 #else
1080 if (f->size_hint_flags & XNegative)
1081 f->left_pos = (pgtk_display_pixel_width (FRAME_DISPLAY_INFO (f))
1082 - FRAME_PIXEL_WIDTH (f) + f->left_pos);
1083
1084 if (f->size_hint_flags & YNegative)
1085 f->top_pos = (pgtk_display_pixel_height (FRAME_DISPLAY_INFO (f))
1086 - FRAME_PIXEL_HEIGHT (f) + f->top_pos);
1087 #endif
1088
1089
1090 gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1091 f->left_pos / scale, f->top_pos / scale);
1092
1093
1094 f->size_hint_flags &= ~ (XNegative | YNegative);
1095 # if ! GTK_CHECK_VERSION (3, 22, 0)
1096 }
1097 else
1098 {
1099
1100 int left = f->left_pos / scale;
1101 int xneg = f->size_hint_flags & XNegative;
1102 int top = f->top_pos / scale;
1103 int yneg = f->size_hint_flags & YNegative;
1104 char geom_str[sizeof "=x--" + 4 * INT_STRLEN_BOUND (int)];
1105 guint id;
1106
1107 if (xneg)
1108 left = -left;
1109 if (yneg)
1110 top = -top;
1111
1112 sprintf (geom_str, "=%dx%d%c%d%c%d",
1113 FRAME_PIXEL_WIDTH (f),
1114 FRAME_PIXEL_HEIGHT (f),
1115 (xneg ? '-' : '+'), left,
1116 (yneg ? '-' : '+'), top);
1117
1118
1119 id = g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
1120 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
1121
1122 if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1123 geom_str))
1124 fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
1125
1126 g_log_remove_handler ("Gtk", id);
1127 }
1128 #endif
1129 }
1130 }
1131
1132
1133
1134 void
1135 xg_frame_resized (struct frame *f, int width, int height)
1136 {
1137
1138 if (width != FRAME_PIXEL_WIDTH (f)
1139 || height != FRAME_PIXEL_HEIGHT (f)
1140 || (f->new_size_p
1141 && ((f->new_width >= 0 && width != f->new_width)
1142 || (f->new_height >= 0 && height != f->new_height))))
1143 {
1144 if (CONSP (frame_size_history))
1145 frame_size_history_extra
1146 (f, build_string ("xg_frame_resized, changed"),
1147 FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f), width, height,
1148 f->new_size_p ? f->new_width : -1,
1149 f->new_size_p ? f->new_height : -1);
1150
1151 FRAME_RIF (f)->clear_under_internal_border (f);
1152 change_frame_size (f, width, height, false, true, false);
1153 SET_FRAME_GARBAGED (f);
1154 cancel_mouse_face (f);
1155 }
1156 else if (CONSP (frame_size_history))
1157 frame_size_history_extra
1158 (f, build_string ("xg_frame_resized, unchanged"),
1159 FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f), width, height,
1160 f->new_size_p ? f->new_width : -1,
1161 f->new_size_p ? f->new_height : -1);
1162
1163 }
1164
1165
1166
1167 void
1168 xg_frame_set_char_size (struct frame *f, int width, int height)
1169 {
1170 Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
1171 gint gwidth, gheight;
1172 int outer_height
1173 = height + FRAME_TOOLBAR_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
1174 int outer_width = width + FRAME_TOOLBAR_WIDTH (f);
1175 bool was_visible = false;
1176 bool hide_child_frame;
1177
1178 #ifndef HAVE_PGTK
1179 gtk_window_get_size (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1180 &gwidth, &gheight);
1181 #else
1182 if (FRAME_GTK_OUTER_WIDGET (f))
1183 {
1184 gtk_window_get_size (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1185 &gwidth, &gheight);
1186 }
1187 else
1188 {
1189 GtkAllocation alloc;
1190 gtk_widget_get_allocation (FRAME_GTK_WIDGET (f), &alloc);
1191 gwidth = alloc.width;
1192 gheight = alloc.height;
1193 }
1194 #endif
1195
1196
1197 FRAME_RIF (f)->clear_under_internal_border (f);
1198
1199 outer_height /= xg_get_scale (f);
1200 outer_width /= xg_get_scale (f);
1201
1202 xg_wm_set_size_hint (f, 0, 0);
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213 if (EQ (fullscreen, Qfullwidth) && width == FRAME_PIXEL_WIDTH (f))
1214 #ifndef HAVE_PGTK
1215 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1216 gwidth, outer_height);
1217 #else
1218 if (FRAME_GTK_OUTER_WIDGET (f))
1219 {
1220 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1221 gwidth, outer_height);
1222 }
1223 else
1224 {
1225 gtk_widget_set_size_request (FRAME_GTK_WIDGET (f),
1226 gwidth, outer_height);
1227 }
1228 #endif
1229 else if (EQ (fullscreen, Qfullheight) && height == FRAME_PIXEL_HEIGHT (f))
1230 #ifndef HAVE_PGTK
1231 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1232 outer_width, gheight);
1233 #else
1234 if (FRAME_GTK_OUTER_WIDGET (f))
1235 {
1236 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1237 outer_width, gheight);
1238 }
1239 else
1240 {
1241 gtk_widget_set_size_request (FRAME_GTK_WIDGET (f),
1242 outer_width, gheight);
1243 }
1244 #endif
1245 else if (FRAME_PARENT_FRAME (f) && FRAME_VISIBLE_P (f))
1246 {
1247 was_visible = true;
1248 #ifndef HAVE_PGTK
1249 hide_child_frame = EQ (x_gtk_resize_child_frames, Qhide);
1250 #else
1251 hide_child_frame = false;
1252 #endif
1253
1254 if (outer_width != gwidth || outer_height != gheight)
1255 {
1256 if (hide_child_frame)
1257 {
1258 block_input ();
1259 #ifndef HAVE_PGTK
1260 gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f));
1261 #else
1262 gtk_widget_hide (FRAME_WIDGET (f));
1263 #endif
1264 unblock_input ();
1265 }
1266
1267 #ifndef HAVE_PGTK
1268 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1269 outer_width, outer_height);
1270 #else
1271 if (FRAME_GTK_OUTER_WIDGET (f))
1272 {
1273 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1274 outer_width, outer_height);
1275 }
1276 else
1277 {
1278 gtk_widget_set_size_request (FRAME_GTK_WIDGET (f),
1279 outer_width, outer_height);
1280 }
1281 #endif
1282
1283 if (hide_child_frame)
1284 {
1285 block_input ();
1286 #ifndef HAVE_PGTK
1287 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
1288 #else
1289 gtk_widget_show_all (FRAME_WIDGET (f));
1290 #endif
1291 unblock_input ();
1292 }
1293
1294 fullscreen = Qnil;
1295 }
1296 }
1297 else
1298 {
1299 #ifndef HAVE_PGTK
1300 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1301 outer_width, outer_height);
1302 #else
1303 if (FRAME_GTK_OUTER_WIDGET (f))
1304 {
1305 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1306 outer_width, outer_height);
1307 }
1308 else
1309 {
1310 gtk_widget_set_size_request (FRAME_GTK_WIDGET (f),
1311 outer_width, outer_height);
1312 }
1313 #endif
1314 fullscreen = Qnil;
1315 }
1316
1317 SET_FRAME_GARBAGED (f);
1318 cancel_mouse_face (f);
1319
1320
1321
1322
1323
1324
1325
1326
1327 if (FRAME_VISIBLE_P (f) && !was_visible)
1328 {
1329 if (CONSP (frame_size_history))
1330 frame_size_history_extra
1331 (f, build_string ("xg_frame_set_char_size, visible"),
1332 FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f), width, height,
1333 f->new_width, f->new_height);
1334
1335
1336 (void)gtk_events_pending ();
1337 gdk_flush ();
1338 #ifndef HAVE_PGTK
1339 x_wait_for_event (f, ConfigureNotify);
1340 #endif
1341
1342 if (!NILP (fullscreen))
1343
1344 {
1345 store_frame_param (f, Qfullscreen, fullscreen);
1346 gui_set_fullscreen (f, fullscreen, fullscreen);
1347 }
1348 }
1349 else
1350 {
1351 if (CONSP (frame_size_history))
1352 frame_size_history_extra
1353 (f, build_string ("xg_frame_set_char_size, invisible"),
1354 FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f), width, height,
1355 f->new_width, f->new_height);
1356
1357 adjust_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, width),
1358 FRAME_PIXEL_TO_TEXT_HEIGHT (f, height),
1359 5, 0, Qxg_frame_set_char_size);
1360 }
1361 }
1362
1363
1364
1365
1366 #if 0
1367 static void
1368 xg_height_or_width_changed (struct frame *f)
1369 {
1370 gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1371 FRAME_TOTAL_PIXEL_WIDTH (f),
1372 FRAME_TOTAL_PIXEL_HEIGHT (f));
1373 f->output_data.xp->hint_flags = 0;
1374 x_wm_set_size_hint (f, 0, 0);
1375 }
1376 #endif
1377
1378 #ifndef HAVE_PGTK
1379
1380
1381
1382
1383
1384
1385 GtkWidget *
1386 xg_win_to_widget (Display *dpy, Window wdesc)
1387 {
1388 gpointer gdkwin;
1389 GtkWidget *gwdesc = 0;
1390
1391 block_input ();
1392
1393 gdkwin = gdk_x11_window_lookup_for_display (gdk_x11_lookup_xdisplay (dpy),
1394 wdesc);
1395 if (gdkwin)
1396 {
1397 GdkEvent event;
1398 event.any.window = gdkwin;
1399 event.any.type = GDK_NOTHING;
1400 gwdesc = gtk_get_event_widget (&event);
1401 }
1402
1403 unblock_input ();
1404 return gwdesc;
1405 }
1406 #endif
1407
1408
1409
1410 static void
1411 xg_set_widget_bg (struct frame *f, GtkWidget *w, unsigned long pixel)
1412 {
1413 #ifdef HAVE_GTK3
1414 Emacs_Color xbg;
1415 xbg.pixel = pixel;
1416 #ifndef HAVE_PGTK
1417 if (XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &xbg))
1418 #else
1419 xbg.red = (pixel >> 16) & 0xff;
1420 xbg.green = (pixel >> 8) & 0xff;
1421 xbg.blue = (pixel >> 0) & 0xff;
1422 xbg.red |= xbg.red << 8;
1423 xbg.green |= xbg.green << 8;
1424 xbg.blue |= xbg.blue << 8;
1425 #endif
1426 {
1427 const char format[] = "* { background-color: #%02x%02x%02x; }";
1428
1429 char buffer[sizeof format];
1430 int n = snprintf(buffer, sizeof buffer, format,
1431 xbg.red >> 8, xbg.green >> 8, xbg.blue >> 8);
1432 eassert (n > 0);
1433 eassert (n < sizeof buffer);
1434 GtkCssProvider *provider = gtk_css_provider_new ();
1435 gtk_css_provider_load_from_data (provider, buffer, -1, NULL);
1436 gtk_style_context_add_provider (gtk_widget_get_style_context(w),
1437 GTK_STYLE_PROVIDER (provider),
1438 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1439 g_clear_object (&provider);
1440 }
1441 #else
1442 GdkColor bg;
1443 GdkColormap *map = gtk_widget_get_colormap (w);
1444 gdk_colormap_query_color (map, pixel, &bg);
1445 gtk_widget_modify_bg (FRAME_GTK_WIDGET (f), GTK_STATE_NORMAL, &bg);
1446 #endif
1447 }
1448
1449
1450
1451
1452 static void
1453 style_changed_cb (GObject *go,
1454 GParamSpec *spec,
1455 gpointer user_data)
1456 {
1457 struct input_event event;
1458 GdkDisplay *gdpy = user_data;
1459 const char *display_name = gdk_display_get_name (gdpy);
1460 #ifndef HAVE_PGTK
1461 Display *dpy = GDK_DISPLAY_XDISPLAY (gdpy);
1462 #else
1463 GdkDisplay *dpy = gdpy;
1464 #endif
1465
1466 #ifndef HAVE_PGTK
1467 if (display_name == NULL)
1468 display_name = "";
1469 #endif
1470
1471 EVENT_INIT (event);
1472 event.kind = CONFIG_CHANGED_EVENT;
1473 event.frame_or_window = build_string (display_name);
1474
1475 event.arg = intern ("theme-name");
1476 kbd_buffer_store_event (&event);
1477
1478 update_theme_scrollbar_width ();
1479 update_theme_scrollbar_height ();
1480
1481
1482
1483 if (dpy)
1484 {
1485 Lisp_Object rest, frame;
1486 FOR_EACH_FRAME (rest, frame)
1487 {
1488 struct frame *f = XFRAME (frame);
1489 if (FRAME_LIVE_P (f)
1490 #ifndef HAVE_PGTK
1491 && FRAME_X_P (f)
1492 #else
1493 && FRAME_PGTK_P (f)
1494 #endif
1495 && FRAME_X_DISPLAY (f) == dpy)
1496 {
1497 FRAME_TERMINAL (f)->set_scroll_bar_default_width_hook (f);
1498 FRAME_TERMINAL (f)->set_scroll_bar_default_height_hook (f);
1499 xg_frame_set_char_size (f, FRAME_PIXEL_WIDTH (f),
1500 FRAME_PIXEL_HEIGHT (f));
1501 }
1502 }
1503 }
1504 }
1505
1506
1507
1508 #ifndef HAVE_PGTK
1509 static gboolean
1510 delete_cb (GtkWidget *widget,
1511 GdkEvent *event,
1512 gpointer user_data)
1513 {
1514 return TRUE;
1515 }
1516 #endif
1517
1518
1519
1520
1521 bool
1522 xg_create_frame_widgets (struct frame *f)
1523 {
1524 GtkWidget *wtop;
1525 GtkWidget *wvbox, *whbox;
1526 GtkWidget *wfixed;
1527 #ifndef HAVE_GTK3
1528 GtkRcStyle *style;
1529 #endif
1530 #ifndef HAVE_PGTK
1531 GtkIMContext *imc;
1532 #endif
1533 GtkWindowType type = GTK_WINDOW_TOPLEVEL;
1534 char *title = 0;
1535
1536 block_input ();
1537
1538 #ifndef HAVE_PGTK
1539 if (FRAME_X_EMBEDDED_P (f))
1540 {
1541 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
1542 wtop = gtk_plug_new_for_display (gdpy, f->output_data.xp->parent_desc);
1543 }
1544 else
1545 wtop = gtk_window_new (type);
1546 #else
1547 if (f->tooltip)
1548 {
1549 type = GTK_WINDOW_POPUP;
1550 }
1551 wtop = gtk_window_new (type);
1552 gtk_widget_add_events (wtop, GDK_ALL_EVENTS_MASK);
1553 #endif
1554
1555 gtk_widget_set_app_paintable (wtop, f->alpha_background != 1.0);
1556 #if GTK_CHECK_VERSION (3, 10, 0)
1557 g_signal_connect (G_OBJECT (wtop), "style-updated",
1558 G_CALLBACK (xg_widget_style_updated), f);
1559 #endif
1560
1561
1562
1563
1564
1565 #if (! defined HAVE_GTK3 \
1566 && defined HAVE_GTK_WINDOW_SET_HAS_RESIZE_GRIP)
1567 gtk_window_set_has_resize_grip (GTK_WINDOW (wtop), FALSE);
1568 #endif
1569
1570 xg_set_screen (wtop, f);
1571
1572 wvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1573 whbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1574 gtk_box_set_homogeneous (GTK_BOX (wvbox), FALSE);
1575 gtk_box_set_homogeneous (GTK_BOX (whbox), FALSE);
1576
1577 #ifdef HAVE_GTK3
1578 wfixed = emacs_fixed_new (f);
1579 #else
1580 wfixed = gtk_fixed_new ();
1581 #endif
1582
1583 if (! wtop || ! wvbox || ! whbox || ! wfixed)
1584 {
1585 if (wtop) gtk_widget_destroy (wtop);
1586 if (wvbox) gtk_widget_destroy (wvbox);
1587 if (whbox) gtk_widget_destroy (whbox);
1588 if (wfixed) gtk_widget_destroy (wfixed);
1589
1590 unblock_input ();
1591 return 0;
1592 }
1593
1594
1595 gtk_widget_set_name (wtop, EMACS_CLASS);
1596 gtk_widget_set_name (wvbox, "pane");
1597 gtk_widget_set_name (wfixed, SSDATA (Vx_resource_name));
1598
1599
1600 if (! NILP (f->title))
1601 title = SSDATA (ENCODE_UTF_8 (f->title));
1602 else if (! NILP (f->name))
1603 title = SSDATA (ENCODE_UTF_8 (f->name));
1604
1605 if (title)
1606 gtk_window_set_title (GTK_WINDOW (wtop), title);
1607
1608 if (FRAME_UNDECORATED (f))
1609 {
1610 gtk_window_set_decorated (GTK_WINDOW (wtop), FALSE);
1611 store_frame_param (f, Qundecorated, Qt);
1612 }
1613
1614 FRAME_GTK_OUTER_WIDGET (f) = wtop;
1615 FRAME_GTK_WIDGET (f) = wfixed;
1616 f->output_data.xp->vbox_widget = wvbox;
1617 f->output_data.xp->hbox_widget = whbox;
1618
1619 gtk_widget_set_has_window (wfixed, TRUE);
1620
1621 gtk_container_add (GTK_CONTAINER (wtop), wvbox);
1622 gtk_box_pack_start (GTK_BOX (wvbox), whbox, TRUE, TRUE, 0);
1623 gtk_box_pack_start (GTK_BOX (whbox), wfixed, TRUE, TRUE, 0);
1624
1625 if (FRAME_EXTERNAL_TOOL_BAR (f))
1626 update_frame_tool_bar (f);
1627
1628
1629
1630
1631
1632
1633
1634 #ifndef HAVE_PGTK
1635 gtk_widget_set_double_buffered (wfixed, FALSE);
1636 #endif
1637
1638 #if ! GTK_CHECK_VERSION (3, 22, 0)
1639 gtk_window_set_wmclass (GTK_WINDOW (wtop),
1640 SSDATA (Vx_resource_name),
1641 SSDATA (Vx_resource_class));
1642 #endif
1643
1644 #ifndef HAVE_PGTK
1645
1646
1647 g_signal_connect (G_OBJECT (wtop), "delete-event",
1648 G_CALLBACK (delete_cb), f);
1649 #endif
1650
1651
1652
1653
1654 xg_set_geometry (f);
1655 f->win_gravity
1656 = gtk_window_get_gravity (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1657
1658 gtk_widget_add_events (wfixed,
1659 GDK_POINTER_MOTION_MASK
1660 #ifndef HAVE_PGTK
1661 | GDK_EXPOSURE_MASK
1662 #endif
1663 | GDK_BUTTON_PRESS_MASK
1664 | GDK_BUTTON_RELEASE_MASK
1665 | GDK_KEY_PRESS_MASK
1666 | GDK_ENTER_NOTIFY_MASK
1667 | GDK_LEAVE_NOTIFY_MASK
1668 | GDK_FOCUS_CHANGE_MASK
1669 | GDK_STRUCTURE_MASK
1670 #ifdef HAVE_PGTK
1671 | GDK_SCROLL_MASK
1672 | GDK_SMOOTH_SCROLL_MASK
1673 #endif
1674 | GDK_VISIBILITY_NOTIFY_MASK);
1675
1676 GdkScreen *screen = gtk_widget_get_screen (wtop);
1677
1678 #if !defined HAVE_PGTK
1679 GdkVisual *visual = gdk_x11_screen_lookup_visual (screen,
1680 XVisualIDFromVisual (FRAME_X_VISUAL (f)));
1681
1682 if (!visual)
1683 emacs_abort ();
1684 #else
1685 GdkVisual *visual = gdk_screen_get_rgba_visual (screen);
1686 #endif
1687
1688 gtk_widget_set_visual (wtop, visual);
1689 gtk_widget_set_visual (wfixed, visual);
1690
1691 #ifndef HAVE_PGTK
1692
1693
1694 gtk_widget_realize (wfixed);
1695 FRAME_X_WINDOW (f) = GTK_WIDGET_TO_X_WIN (wfixed);
1696 initial_set_up_x_back_buffer (f);
1697 #endif
1698
1699
1700
1701 xg_set_widget_bg (f, wfixed, FRAME_BACKGROUND_PIXEL (f));
1702
1703 #ifndef HAVE_GTK3
1704
1705
1706
1707 style = gtk_widget_get_modifier_style (wfixed);
1708
1709
1710 style->bg_pixmap_name[GTK_STATE_NORMAL] = g_strdup ("<none>");
1711 gtk_widget_modify_style (wfixed, style);
1712 gtk_widget_set_can_focus (wfixed, TRUE);
1713 #else
1714 gtk_widget_set_can_focus (wfixed, TRUE);
1715 #ifdef HAVE_PGTK
1716 gtk_widget_grab_focus (wfixed);
1717 #endif
1718 gtk_window_set_resizable (GTK_WINDOW (wtop), TRUE);
1719 #endif
1720
1721 if (FRAME_OVERRIDE_REDIRECT (f))
1722 {
1723 GdkWindow *gwin = gtk_widget_get_window (wtop);
1724
1725 if (gwin)
1726 gdk_window_set_override_redirect (gwin, TRUE);
1727 }
1728
1729
1730 f->output_data.xp->ttip_widget = 0;
1731 f->output_data.xp->ttip_lbl = 0;
1732 f->output_data.xp->ttip_window = 0;
1733 #ifndef HAVE_PGTK
1734 gtk_widget_set_tooltip_text (wtop, "Dummy text");
1735 g_signal_connect (wtop, "query-tooltip", G_CALLBACK (qttip_cb), f);
1736
1737 imc = gtk_im_multicontext_new ();
1738 g_object_ref (imc);
1739 gtk_im_context_set_use_preedit (imc, TRUE);
1740
1741 g_signal_connect (G_OBJECT (imc), "commit",
1742 G_CALLBACK (xg_im_context_commit), f);
1743 g_signal_connect (G_OBJECT (imc), "preedit-changed",
1744 G_CALLBACK (xg_im_context_preedit_changed), NULL);
1745 g_signal_connect (G_OBJECT (imc), "preedit-end",
1746 G_CALLBACK (xg_im_context_preedit_end), NULL);
1747 FRAME_X_OUTPUT (f)->im_context = imc;
1748
1749 g_signal_connect (G_OBJECT (wfixed), "key-press-event",
1750 G_CALLBACK (xg_widget_key_press_event_cb),
1751 NULL);
1752 #endif
1753
1754 {
1755 GtkSettings *gs = gtk_settings_get_for_screen (screen);
1756
1757 if (! g_signal_handler_find (G_OBJECT (gs),
1758 G_SIGNAL_MATCH_FUNC,
1759 0, 0, 0,
1760 (gpointer) G_CALLBACK (style_changed_cb),
1761 0))
1762 {
1763 g_signal_connect (G_OBJECT (gs), "notify::gtk-theme-name",
1764 G_CALLBACK (style_changed_cb),
1765 gdk_screen_get_display (screen));
1766 }
1767 }
1768
1769 unblock_input ();
1770
1771 return 1;
1772 }
1773
1774 #ifdef HAVE_PGTK
1775 void
1776 xg_create_frame_outer_widgets (struct frame *f)
1777 {
1778 GtkWidget *wtop;
1779 GtkWidget *wvbox, *whbox;
1780 GtkWindowType type = GTK_WINDOW_TOPLEVEL;
1781 char *title = 0;
1782
1783 block_input ();
1784
1785 wtop = gtk_window_new (type);
1786 gtk_widget_add_events (wtop, GDK_ALL_EVENTS_MASK);
1787
1788 xg_set_screen (wtop, f);
1789
1790 wvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1791 whbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1792 gtk_box_set_homogeneous (GTK_BOX (wvbox), FALSE);
1793 gtk_box_set_homogeneous (GTK_BOX (whbox), FALSE);
1794
1795
1796 gtk_widget_set_name (wtop, EMACS_CLASS);
1797 gtk_widget_set_name (wvbox, "pane");
1798
1799
1800 if (! NILP (f->title))
1801 title = SSDATA (ENCODE_UTF_8 (f->title));
1802 else if (! NILP (f->name))
1803 title = SSDATA (ENCODE_UTF_8 (f->name));
1804
1805 if (title)
1806 gtk_window_set_title (GTK_WINDOW (wtop), title);
1807
1808 if (FRAME_UNDECORATED (f))
1809 {
1810 gtk_window_set_decorated (GTK_WINDOW (wtop), FALSE);
1811 store_frame_param (f, Qundecorated, Qt);
1812 }
1813
1814 FRAME_GTK_OUTER_WIDGET (f) = wtop;
1815 f->output_data.xp->vbox_widget = wvbox;
1816 f->output_data.xp->hbox_widget = whbox;
1817
1818 gtk_container_add (GTK_CONTAINER (wtop), wvbox);
1819 gtk_box_pack_start (GTK_BOX (wvbox), whbox, TRUE, TRUE, 0);
1820
1821 if (FRAME_EXTERNAL_TOOL_BAR (f))
1822 update_frame_tool_bar (f);
1823
1824 #if ! GTK_CHECK_VERSION (3, 22, 0)
1825 gtk_window_set_wmclass (GTK_WINDOW (wtop),
1826 SSDATA (Vx_resource_name),
1827 SSDATA (Vx_resource_class));
1828 #endif
1829
1830
1831
1832
1833 xg_set_geometry (f);
1834 f->win_gravity
1835 = gtk_window_get_gravity (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
1836
1837 gtk_window_set_resizable (GTK_WINDOW (wtop), TRUE);
1838
1839 if (FRAME_OVERRIDE_REDIRECT (f))
1840 {
1841 GdkWindow *gwin = gtk_widget_get_window (wtop);
1842
1843 if (gwin)
1844 gdk_window_set_override_redirect (gwin, TRUE);
1845 }
1846
1847
1848 f->output_data.xp->ttip_widget = 0;
1849 f->output_data.xp->ttip_lbl = 0;
1850 f->output_data.xp->ttip_window = 0;
1851 #ifndef HAVE_PGTK
1852 gtk_widget_set_tooltip_text (wtop, "Dummy text");
1853 g_signal_connect (wtop, "query-tooltip", G_CALLBACK (qttip_cb), f);
1854 #endif
1855
1856 {
1857 GdkScreen *screen = gtk_widget_get_screen (wtop);
1858 GtkSettings *gs = gtk_settings_get_for_screen (screen);
1859
1860 if (! g_signal_handler_find (G_OBJECT (gs),
1861 G_SIGNAL_MATCH_FUNC,
1862 0, 0, 0,
1863 (gpointer) G_CALLBACK (style_changed_cb),
1864 0))
1865 {
1866 g_signal_connect (G_OBJECT (gs), "notify::gtk-theme-name",
1867 G_CALLBACK (style_changed_cb),
1868 gdk_screen_get_display (screen));
1869 }
1870 }
1871
1872 unblock_input ();
1873 }
1874 #endif
1875
1876 void
1877 xg_free_frame_widgets (struct frame *f)
1878 {
1879 if (FRAME_GTK_OUTER_WIDGET (f))
1880 {
1881 xp_output *x = f->output_data.xp;
1882 struct xg_frame_tb_info *tbinfo
1883 = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
1884 TB_INFO_KEY);
1885 if (tbinfo)
1886 xfree (tbinfo);
1887
1888
1889 #ifndef HAVE_PGTK
1890 #ifdef HAVE_XDBE
1891 eassert (!FRAME_X_DOUBLE_BUFFERED_P (f));
1892 #endif
1893 g_object_unref (FRAME_X_OUTPUT (f)->im_context);
1894 #endif
1895 gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f));
1896 FRAME_X_WINDOW (f) = 0;
1897 #ifndef HAVE_PGTK
1898 FRAME_X_RAW_DRAWABLE (f) = 0;
1899 #endif
1900 FRAME_GTK_OUTER_WIDGET (f) = 0;
1901 if (x->ttip_widget)
1902 {
1903
1904
1905 gtk_tooltip_set_custom (x->ttip_widget, NULL);
1906 g_object_unref (G_OBJECT (x->ttip_widget));
1907 }
1908 if (x->ttip_lbl)
1909 gtk_widget_destroy (x->ttip_lbl);
1910 }
1911 }
1912
1913
1914
1915
1916
1917
1918
1919 void
1920 xg_wm_set_size_hint (struct frame *f, long int flags, bool user_position)
1921 {
1922
1923
1924 GdkGeometry size_hints;
1925 gint hint_flags = 0;
1926 int base_width, base_height;
1927 int win_gravity = f->win_gravity;
1928 Lisp_Object fs_state, frame;
1929 int scale = xg_get_scale (f);
1930
1931
1932
1933
1934 if (NILP (Vafter_init_time)
1935 || !FRAME_GTK_OUTER_WIDGET (f)
1936 || FRAME_PARENT_FRAME (f))
1937 return;
1938
1939 XSETFRAME (frame, f);
1940 fs_state = Fframe_parameter (frame, Qfullscreen);
1941 if ((EQ (fs_state, Qmaximized) || EQ (fs_state, Qfullboth))
1942 #ifndef HAVE_PGTK
1943 && (x_wm_supports (f, FRAME_DISPLAY_INFO (f)->Xatom_net_wm_state) ||
1944 x_wm_supports (f, FRAME_DISPLAY_INFO (f)->Xatom_net_wm_state_fullscreen))
1945 #endif
1946 )
1947 {
1948
1949
1950
1951 return;
1952 }
1953
1954 if (flags)
1955 {
1956 memset (&size_hints, 0, sizeof (size_hints));
1957 f->output_data.xp->size_hints = size_hints;
1958 f->output_data.xp->hint_flags = hint_flags;
1959 }
1960 else
1961 flags = f->size_hint_flags;
1962
1963 size_hints = f->output_data.xp->size_hints;
1964 hint_flags = f->output_data.xp->hint_flags;
1965
1966 hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
1967 size_hints.width_inc = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
1968 size_hints.height_inc = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
1969
1970 hint_flags |= GDK_HINT_BASE_SIZE;
1971
1972
1973
1974 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 1) + FRAME_TOOLBAR_WIDTH (f);
1975 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 1)
1976 + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
1977
1978 size_hints.base_width = base_width;
1979 size_hints.base_height = base_height;
1980 size_hints.min_width = base_width;
1981 size_hints.min_height = base_height;
1982
1983
1984
1985 hint_flags |= GDK_HINT_WIN_GRAVITY;
1986 size_hints.win_gravity = 0;
1987 if (win_gravity == NorthWestGravity)
1988 size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
1989 else if (win_gravity == NorthGravity)
1990 size_hints.win_gravity = GDK_GRAVITY_NORTH;
1991 else if (win_gravity == NorthEastGravity)
1992 size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
1993 else if (win_gravity == WestGravity)
1994 size_hints.win_gravity = GDK_GRAVITY_WEST;
1995 else if (win_gravity == CenterGravity)
1996 size_hints.win_gravity = GDK_GRAVITY_CENTER;
1997 else if (win_gravity == EastGravity)
1998 size_hints.win_gravity = GDK_GRAVITY_EAST;
1999 else if (win_gravity == SouthWestGravity)
2000 size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
2001 else if (win_gravity == SouthGravity)
2002 size_hints.win_gravity = GDK_GRAVITY_SOUTH;
2003 else if (win_gravity == SouthEastGravity)
2004 size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
2005 else if (win_gravity == StaticGravity)
2006 size_hints.win_gravity = GDK_GRAVITY_STATIC;
2007
2008 if (flags & PPosition)
2009 hint_flags |= GDK_HINT_POS;
2010 if (flags & USPosition)
2011 hint_flags |= GDK_HINT_USER_POS;
2012 if (flags & USSize)
2013 hint_flags |= GDK_HINT_USER_SIZE;
2014
2015 if (user_position)
2016 {
2017 hint_flags &= ~GDK_HINT_POS;
2018 hint_flags |= GDK_HINT_USER_POS;
2019 }
2020
2021 size_hints.base_width /= scale;
2022 size_hints.base_height /= scale;
2023 size_hints.width_inc /= scale;
2024 size_hints.height_inc /= scale;
2025
2026 if (hint_flags != f->output_data.xp->hint_flags
2027 || memcmp (&size_hints,
2028 &f->output_data.xp->size_hints,
2029 sizeof (size_hints)) != 0)
2030 {
2031 block_input ();
2032 gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
2033 NULL, &size_hints, hint_flags);
2034 f->output_data.xp->size_hints = size_hints;
2035 f->output_data.xp->hint_flags = hint_flags;
2036 unblock_input ();
2037 }
2038 }
2039
2040
2041
2042
2043
2044
2045
2046 void
2047 xg_set_background_color (struct frame *f, unsigned long bg)
2048 {
2049 if (FRAME_GTK_WIDGET (f))
2050 {
2051 block_input ();
2052 xg_set_widget_bg (f, FRAME_GTK_WIDGET (f), FRAME_BACKGROUND_PIXEL (f));
2053
2054 #ifdef USE_TOOLKIT_SCROLL_BARS
2055 Lisp_Object bar;
2056 for (bar = FRAME_SCROLL_BARS (f);
2057 !NILP (bar);
2058 bar = XSCROLL_BAR (bar)->next)
2059 {
2060 GtkWidget *scrollbar = xg_get_widget_from_map (XSCROLL_BAR (bar)->x_window,
2061 FRAME_X_DISPLAY (f));
2062 GtkWidget *webox = gtk_widget_get_parent (scrollbar);
2063 xg_set_widget_bg (f, webox, FRAME_BACKGROUND_PIXEL (f));
2064 }
2065 #endif
2066 unblock_input ();
2067 }
2068 }
2069
2070
2071
2072 void
2073 xg_set_undecorated (struct frame *f, Lisp_Object undecorated)
2074 {
2075 #ifdef HAVE_PGTK
2076 if (!FRAME_GTK_OUTER_WIDGET (f))
2077 return;
2078 #endif
2079 if (FRAME_GTK_WIDGET (f))
2080 {
2081 block_input ();
2082 gtk_window_set_decorated (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
2083 NILP (undecorated) ? TRUE : FALSE);
2084 unblock_input ();
2085 }
2086 }
2087
2088
2089
2090
2091 void
2092 xg_frame_restack (struct frame *f1, struct frame *f2, bool above_flag)
2093 {
2094 block_input ();
2095 if (FRAME_GTK_OUTER_WIDGET (f1) && FRAME_GTK_OUTER_WIDGET (f2))
2096 {
2097 GdkWindow *gwin1 = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f1));
2098 GdkWindow *gwin2 = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f2));
2099 Lisp_Object frame1, frame2;
2100
2101 XSETFRAME (frame1, f1);
2102 XSETFRAME (frame2, f2);
2103
2104 gdk_window_restack (gwin1, gwin2, above_flag);
2105 #ifndef HAVE_PGTK
2106 XSync (FRAME_X_DISPLAY (f1), False);
2107 #else
2108 gdk_flush ();
2109 #endif
2110 }
2111 unblock_input ();
2112 }
2113
2114
2115
2116 void
2117 xg_set_skip_taskbar (struct frame *f, Lisp_Object skip_taskbar)
2118 {
2119 block_input ();
2120 #ifndef HAVE_PGTK
2121 if (FRAME_GTK_WIDGET (f))
2122 gdk_window_set_skip_taskbar_hint
2123 (gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f)),
2124 NILP (skip_taskbar) ? FALSE : TRUE);
2125 #else
2126 if (FRAME_GTK_OUTER_WIDGET (f))
2127 gdk_window_set_skip_taskbar_hint
2128 (gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f)),
2129 NILP (skip_taskbar) ? FALSE : TRUE);
2130 #endif
2131 unblock_input ();
2132 }
2133
2134
2135
2136 void
2137 xg_set_no_focus_on_map (struct frame *f, Lisp_Object no_focus_on_map)
2138 {
2139 #ifdef HAVE_PGTK
2140 if (!FRAME_GTK_OUTER_WIDGET (f))
2141 return;
2142 #endif
2143 block_input ();
2144 if (FRAME_GTK_WIDGET (f))
2145 {
2146 GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
2147 gboolean g_no_focus_on_map = NILP (no_focus_on_map) ? TRUE : FALSE;
2148
2149 gtk_window_set_focus_on_map (gwin, g_no_focus_on_map);
2150 }
2151 unblock_input ();
2152 }
2153
2154
2155 void
2156 xg_set_no_accept_focus (struct frame *f, Lisp_Object no_accept_focus)
2157 {
2158 gboolean g_no_accept_focus = NILP (no_accept_focus) ? TRUE : FALSE;
2159 #ifdef HAVE_PGTK
2160 if (!FRAME_GTK_OUTER_WIDGET (f))
2161 {
2162 if (FRAME_WIDGET (f))
2163 gtk_widget_set_can_focus (FRAME_WIDGET (f), g_no_accept_focus);
2164 return;
2165 }
2166 #endif
2167 block_input ();
2168 if (FRAME_GTK_WIDGET (f))
2169 {
2170 GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
2171 gtk_window_set_accept_focus (gwin, g_no_accept_focus);
2172 }
2173 unblock_input ();
2174 }
2175
2176 void
2177 xg_set_override_redirect (struct frame *f, Lisp_Object override_redirect)
2178 {
2179 block_input ();
2180
2181 if (FRAME_GTK_OUTER_WIDGET (f))
2182 {
2183 GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
2184
2185 gdk_window_set_override_redirect (gwin, NILP (override_redirect) ? FALSE : TRUE);
2186 }
2187
2188 unblock_input ();
2189 }
2190
2191 #ifndef HAVE_PGTK
2192
2193
2194
2195 void
2196 xg_set_frame_icon (struct frame *f, Pixmap icon_pixmap, Pixmap icon_mask)
2197 {
2198 #ifdef HAVE_PGTK
2199 if (!FRAME_GTK_OUTER_WIDGET (f))
2200 return;
2201 #endif
2202 GdkPixbuf *gp = xg_get_pixbuf_from_pix_and_mask (f,
2203 icon_pixmap,
2204 icon_mask);
2205 if (gp)
2206 gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), gp);
2207 }
2208 #endif
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218 static const char *
2219 get_dialog_title (char key)
2220 {
2221 const char *title = "";
2222
2223 switch (key) {
2224 case 'E': case 'e':
2225 title = "Error";
2226 break;
2227
2228 case 'I': case 'i':
2229 title = "Information";
2230 break;
2231
2232 case 'L': case 'l':
2233 title = "Prompt";
2234 break;
2235
2236 case 'P': case 'p':
2237 title = "Prompt";
2238 break;
2239
2240 case 'Q': case 'q':
2241 title = "Question";
2242 break;
2243 }
2244
2245 return title;
2246 }
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259 static gboolean
2260 dialog_delete_callback (GtkWidget *w, GdkEvent *event, gpointer user_data)
2261 {
2262 gtk_widget_unmap (w);
2263 return TRUE;
2264 }
2265
2266
2267
2268
2269
2270
2271
2272
2273 static GtkWidget *
2274 create_dialog (widget_value *wv,
2275 GCallback select_cb,
2276 GCallback deactivate_cb)
2277 {
2278 const char *title = get_dialog_title (wv->name[0]);
2279 int total_buttons = wv->name[1] - '0';
2280 int right_buttons = wv->name[4] - '0';
2281 int left_buttons;
2282 int button_nr = 0;
2283 int button_spacing = 10;
2284 GtkWidget *wdialog = gtk_dialog_new ();
2285 GtkDialog *wd = GTK_DIALOG (wdialog);
2286 widget_value *item;
2287 GtkWidget *whbox_down;
2288
2289
2290
2291 bool make_two_rows = total_buttons > 4;
2292
2293 #if GTK_CHECK_VERSION (3, 12, 0)
2294 GtkBuilder *gbld = gtk_builder_new ();
2295 GObject *go = gtk_buildable_get_internal_child (GTK_BUILDABLE (wd),
2296 gbld,
2297 "action_area");
2298 GtkBox *cur_box = GTK_BOX (go);
2299 g_object_unref (G_OBJECT (gbld));
2300 #else
2301 GtkBox *cur_box = GTK_BOX (gtk_dialog_get_action_area (wd));
2302 #endif
2303
2304 if (right_buttons == 0) right_buttons = total_buttons/2;
2305 left_buttons = total_buttons - right_buttons;
2306
2307 gtk_window_set_title (GTK_WINDOW (wdialog), title);
2308 gtk_widget_set_name (wdialog, "emacs-dialog");
2309
2310
2311 if (make_two_rows)
2312 {
2313 GtkWidget *wvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, button_spacing);
2314 GtkWidget *whbox_up = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2315 gtk_box_set_homogeneous (GTK_BOX (wvbox), TRUE);
2316 gtk_box_set_homogeneous (GTK_BOX (whbox_up), FALSE);
2317 whbox_down = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2318 gtk_box_set_homogeneous (GTK_BOX (whbox_down), FALSE);
2319
2320 gtk_box_pack_start (cur_box, wvbox, FALSE, FALSE, 0);
2321 gtk_box_pack_start (GTK_BOX (wvbox), whbox_up, FALSE, FALSE, 0);
2322 gtk_box_pack_start (GTK_BOX (wvbox), whbox_down, FALSE, FALSE, 0);
2323
2324 cur_box = GTK_BOX (whbox_up);
2325 }
2326
2327 g_signal_connect (G_OBJECT (wdialog), "delete-event",
2328 G_CALLBACK (dialog_delete_callback), 0);
2329
2330 if (deactivate_cb)
2331 {
2332 g_signal_connect (G_OBJECT (wdialog), "close", deactivate_cb, 0);
2333 g_signal_connect (G_OBJECT (wdialog), "response", deactivate_cb, 0);
2334 }
2335
2336 for (item = wv->contents; item; item = item->next)
2337 {
2338 char *utf8_label = get_utf8_string (item->value);
2339 GtkWidget *w;
2340 GtkRequisition req;
2341
2342 if (item->name && strcmp (item->name, "message") == 0)
2343 {
2344 GtkBox *wvbox = GTK_BOX (gtk_dialog_get_content_area (wd));
2345
2346 w = gtk_label_new (utf8_label);
2347 gtk_box_pack_start (wvbox, gtk_label_new (""), FALSE, FALSE, 0);
2348 gtk_box_pack_start (wvbox, w, TRUE, TRUE, 0);
2349 #if GTK_CHECK_VERSION (3, 14, 0)
2350 gtk_widget_set_halign (w, GTK_ALIGN_START);
2351 gtk_widget_set_valign (w, GTK_ALIGN_CENTER);
2352 #else
2353 gtk_misc_set_alignment (GTK_MISC (w), 0.1, 0.5);
2354 #endif
2355
2356
2357 gtk_widget_realize (w);
2358 gtk_widget_get_preferred_size (w, NULL, &req);
2359 gtk_box_set_spacing (wvbox, req.height);
2360 if (item->value && strlen (item->value) > 0)
2361 button_spacing = 2*req.width/strlen (item->value);
2362 if (button_spacing < 10) button_spacing = 10;
2363 }
2364 else
2365 {
2366
2367 w = gtk_button_new_with_label (utf8_label);
2368 if (! item->enabled)
2369 gtk_widget_set_sensitive (w, FALSE);
2370 if (select_cb)
2371 g_signal_connect (G_OBJECT (w), "clicked",
2372 select_cb, item->call_data);
2373
2374 gtk_box_pack_start (cur_box, w, TRUE, TRUE, button_spacing);
2375 if (++button_nr == left_buttons)
2376 {
2377 if (make_two_rows)
2378 cur_box = GTK_BOX (whbox_down);
2379 }
2380 }
2381
2382 if (utf8_label)
2383 g_free (utf8_label);
2384 }
2385
2386 return wdialog;
2387 }
2388
2389 struct xg_dialog_data
2390 {
2391 GMainLoop *loop;
2392 int response;
2393 GtkWidget *w;
2394 guint timerid;
2395 };
2396
2397
2398
2399
2400
2401 static void
2402 xg_dialog_response_cb (GtkDialog *w,
2403 gint response,
2404 gpointer user_data)
2405 {
2406 struct xg_dialog_data *dd = user_data;
2407 dd->response = response;
2408 g_main_loop_quit (dd->loop);
2409 }
2410
2411
2412
2413
2414 static void
2415 pop_down_dialog (void *arg)
2416 {
2417 struct xg_dialog_data *dd = arg;
2418
2419 block_input ();
2420 if (dd->w) gtk_widget_destroy (dd->w);
2421 if (dd->timerid != 0) g_source_remove (dd->timerid);
2422
2423 g_main_loop_quit (dd->loop);
2424 g_main_loop_unref (dd->loop);
2425
2426 unblock_input ();
2427 }
2428
2429
2430
2431
2432 static gboolean
2433 xg_maybe_add_timer (gpointer data)
2434 {
2435 struct xg_dialog_data *dd = data;
2436 struct timespec next_time = timer_check ();
2437
2438 dd->timerid = 0;
2439
2440 if (timespec_valid_p (next_time))
2441 {
2442 time_t s = next_time.tv_sec;
2443 int per_ms = TIMESPEC_HZ / 1000;
2444 int ms = (next_time.tv_nsec + per_ms - 1) / per_ms;
2445 if (s <= ((guint) -1 - ms) / 1000)
2446 dd->timerid = g_timeout_add (s * 1000 + ms, xg_maybe_add_timer, dd);
2447 }
2448 return FALSE;
2449 }
2450
2451
2452
2453
2454
2455
2456 static int
2457 xg_dialog_run (struct frame *f, GtkWidget *w)
2458 {
2459 specpdl_ref count = SPECPDL_INDEX ();
2460 struct xg_dialog_data dd;
2461
2462 xg_set_screen (w, f);
2463 gtk_window_set_transient_for (GTK_WINDOW (w),
2464 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
2465 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
2466 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
2467
2468 dd.loop = g_main_loop_new (NULL, FALSE);
2469 dd.response = GTK_RESPONSE_CANCEL;
2470 dd.w = w;
2471 dd.timerid = 0;
2472
2473 g_signal_connect (G_OBJECT (w),
2474 "response",
2475 G_CALLBACK (xg_dialog_response_cb),
2476 &dd);
2477
2478 g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
2479 gtk_widget_show (w);
2480
2481 record_unwind_protect_ptr (pop_down_dialog, &dd);
2482
2483 (void) xg_maybe_add_timer (&dd);
2484 g_main_loop_run (dd.loop);
2485
2486 dd.w = 0;
2487 unbind_to (count, Qnil);
2488
2489 return dd.response;
2490 }
2491
2492
2493
2494
2495
2496
2497
2498 bool
2499 xg_uses_old_file_dialog (void)
2500 {
2501 #ifdef HAVE_GTK_FILE_SELECTION_NEW
2502 return x_gtk_use_old_file_dialog;
2503 #else
2504 return 0;
2505 #endif
2506 }
2507
2508
2509 typedef char * (*xg_get_file_func) (GtkWidget *);
2510
2511
2512
2513
2514 static char *
2515 xg_get_file_name_from_chooser (GtkWidget *w)
2516 {
2517 return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w));
2518 }
2519
2520
2521
2522
2523 static void
2524 xg_toggle_visibility_cb (GtkWidget *widget, gpointer data)
2525 {
2526 GtkFileChooser *dialog = GTK_FILE_CHOOSER (data);
2527 gboolean visible;
2528 g_object_get (G_OBJECT (dialog), "show-hidden", &visible, NULL);
2529 g_object_set (G_OBJECT (dialog), "show-hidden", !visible, NULL);
2530 }
2531
2532
2533
2534
2535
2536
2537
2538
2539 static void
2540 xg_toggle_notify_cb (GObject *gobject, GParamSpec *arg1, gpointer user_data)
2541 {
2542 if (strcmp (arg1->name, "show-hidden") == 0)
2543 {
2544 GtkWidget *wtoggle = GTK_WIDGET (user_data);
2545 gboolean visible, toggle_on;
2546
2547 g_object_get (G_OBJECT (gobject), "show-hidden", &visible, NULL);
2548 toggle_on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wtoggle));
2549
2550 if (!!visible != !!toggle_on)
2551 {
2552 gpointer cb = (gpointer) G_CALLBACK (xg_toggle_visibility_cb);
2553 g_signal_handlers_block_by_func (G_OBJECT (wtoggle), cb, gobject);
2554 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), visible);
2555 g_signal_handlers_unblock_by_func (G_OBJECT (wtoggle), cb, gobject);
2556 }
2557 x_gtk_show_hidden_files = visible;
2558 }
2559 }
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572 static GtkWidget *
2573 xg_get_file_with_chooser (struct frame *f,
2574 char *prompt,
2575 char *default_filename,
2576 bool mustmatch_p, bool only_dir_p,
2577 xg_get_file_func *func)
2578 {
2579 char msgbuf[1024];
2580
2581 GtkWidget *filewin, *wtoggle, *wbox;
2582 GtkWidget *wmessage UNINIT;
2583 GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
2584 GtkFileChooserAction action = (mustmatch_p ?
2585 GTK_FILE_CHOOSER_ACTION_OPEN :
2586 GTK_FILE_CHOOSER_ACTION_SAVE);
2587
2588 if (only_dir_p)
2589 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
2590
2591 filewin = gtk_file_chooser_dialog_new (prompt, gwin, action,
2592 XG_TEXT_CANCEL, GTK_RESPONSE_CANCEL,
2593 (mustmatch_p || only_dir_p ?
2594 XG_TEXT_OPEN : XG_TEXT_OK),
2595 GTK_RESPONSE_OK,
2596 NULL);
2597 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filewin), TRUE);
2598
2599 wbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
2600 gtk_box_set_homogeneous (GTK_BOX (wbox), FALSE);
2601 gtk_widget_show (wbox);
2602 wtoggle = gtk_check_button_new_with_label ("Show hidden files.");
2603
2604 g_object_set (G_OBJECT (filewin), "show-hidden",
2605 x_gtk_show_hidden_files, NULL);
2606 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle),
2607 x_gtk_show_hidden_files);
2608
2609 gtk_widget_show (wtoggle);
2610 g_signal_connect (G_OBJECT (wtoggle), "clicked",
2611 G_CALLBACK (xg_toggle_visibility_cb), filewin);
2612 g_signal_connect (G_OBJECT (filewin), "notify",
2613 G_CALLBACK (xg_toggle_notify_cb), wtoggle);
2614
2615 if (x_gtk_file_dialog_help_text)
2616 {
2617 char *z = msgbuf;
2618
2619
2620 if (gtk_check_version (2, 10, 0) && action != GTK_FILE_CHOOSER_ACTION_SAVE)
2621 z = stpcpy (z, "\nType C-l to display a file name text entry box.\n");
2622 strcpy (z, "\nIf you don't like this file selector, use the "
2623 "corresponding\nkey binding or customize "
2624 "use-file-dialog to turn it off.");
2625
2626 wmessage = gtk_label_new (msgbuf);
2627 gtk_widget_show (wmessage);
2628 }
2629
2630 gtk_box_pack_start (GTK_BOX (wbox), wtoggle, FALSE, FALSE, 0);
2631 if (x_gtk_file_dialog_help_text)
2632 gtk_box_pack_start (GTK_BOX (wbox), wmessage, FALSE, FALSE, 0);
2633 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (filewin), wbox);
2634
2635 if (default_filename)
2636 {
2637 Lisp_Object file;
2638 char *utf8_filename;
2639
2640 file = build_string (default_filename);
2641
2642
2643
2644 if (default_filename[0] != '/')
2645 file = Fexpand_file_name (file, Qnil);
2646
2647 utf8_filename = SSDATA (ENCODE_UTF_8 (file));
2648 if (! NILP (Ffile_directory_p (file)))
2649 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filewin),
2650 utf8_filename);
2651 else
2652 {
2653 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filewin),
2654 utf8_filename);
2655 if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
2656 {
2657 char *cp = strrchr (utf8_filename, '/');
2658 if (cp) ++cp;
2659 else cp = utf8_filename;
2660 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filewin), cp);
2661 }
2662 }
2663 }
2664
2665 *func = xg_get_file_name_from_chooser;
2666 return filewin;
2667 }
2668
2669 #ifdef HAVE_GTK_FILE_SELECTION_NEW
2670
2671
2672
2673
2674 static char *
2675 xg_get_file_name_from_selector (GtkWidget *w)
2676 {
2677 GtkFileSelection *filesel = GTK_FILE_SELECTION (w);
2678 return xstrdup (gtk_file_selection_get_filename (filesel));
2679 }
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691 static GtkWidget *
2692 xg_get_file_with_selection (struct frame *f,
2693 char *prompt,
2694 char *default_filename,
2695 bool mustmatch_p, bool only_dir_p,
2696 xg_get_file_func *func)
2697 {
2698 GtkWidget *filewin;
2699 GtkFileSelection *filesel;
2700
2701 filewin = gtk_file_selection_new (prompt);
2702 filesel = GTK_FILE_SELECTION (filewin);
2703
2704 if (default_filename)
2705 gtk_file_selection_set_filename (filesel, default_filename);
2706
2707 if (mustmatch_p)
2708 {
2709
2710 gtk_widget_set_sensitive (filesel->selection_entry, FALSE);
2711 gtk_file_selection_hide_fileop_buttons (filesel);
2712 }
2713
2714 *func = xg_get_file_name_from_selector;
2715
2716 return filewin;
2717 }
2718 #endif
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733 char *
2734 xg_get_file_name (struct frame *f,
2735 char *prompt,
2736 char *default_filename,
2737 bool mustmatch_p,
2738 bool only_dir_p)
2739 {
2740 GtkWidget *w = 0;
2741 char *fn = 0;
2742 int filesel_done = 0;
2743 xg_get_file_func func;
2744
2745 #ifdef HAVE_PGTK
2746 if (!FRAME_GTK_OUTER_WIDGET (f))
2747 error ("Can't open dialog from child frames");
2748 #endif
2749
2750 #ifdef HAVE_GTK_FILE_SELECTION_NEW
2751
2752 if (xg_uses_old_file_dialog ())
2753 w = xg_get_file_with_selection (f, prompt, default_filename,
2754 mustmatch_p, only_dir_p, &func);
2755 else
2756 w = xg_get_file_with_chooser (f, prompt, default_filename,
2757 mustmatch_p, only_dir_p, &func);
2758
2759 #else
2760 w = xg_get_file_with_chooser (f, prompt, default_filename,
2761 mustmatch_p, only_dir_p, &func);
2762 #endif
2763
2764 gtk_widget_set_name (w, "emacs-filedialog");
2765
2766 filesel_done = xg_dialog_run (f, w);
2767 if (filesel_done == GTK_RESPONSE_OK)
2768 fn = (*func) (w);
2769
2770 gtk_widget_destroy (w);
2771 return fn;
2772 }
2773
2774
2775
2776
2777
2778 #ifdef HAVE_FREETYPE
2779
2780 #ifdef HAVE_GTK3
2781
2782 static
2783 Lisp_Object xg_weight_to_symbol (PangoWeight w)
2784 {
2785 return
2786 (w <= PANGO_WEIGHT_THIN ? Qthin
2787 : w <= PANGO_WEIGHT_ULTRALIGHT ? Qultra_light
2788 : w <= PANGO_WEIGHT_LIGHT ? Qlight
2789 #if PANGO_VERSION_CHECK(1, 36, 7)
2790 : w <= PANGO_WEIGHT_SEMILIGHT ? Qsemi_light
2791 #endif
2792 : w <= PANGO_WEIGHT_BOOK ? Qbook
2793 : w <= PANGO_WEIGHT_NORMAL ? Qnormal
2794 : w <= PANGO_WEIGHT_MEDIUM ? Qmedium
2795 : w <= PANGO_WEIGHT_SEMIBOLD ? Qsemi_bold
2796 : w <= PANGO_WEIGHT_BOLD ? Qbold
2797 : w <= PANGO_WEIGHT_ULTRABOLD ? Qultra_bold
2798 : w <= PANGO_WEIGHT_HEAVY ? Qblack
2799 : Qultra_heavy);
2800 }
2801
2802 static
2803 Lisp_Object xg_style_to_symbol (PangoStyle s)
2804 {
2805 return
2806 (s == PANGO_STYLE_OBLIQUE ? Qoblique
2807 : s == PANGO_STYLE_ITALIC ? Qitalic
2808 : Qnormal);
2809 }
2810
2811 #endif
2812
2813
2814 static char *x_last_font_name;
2815
2816 #ifdef HAVE_GTK3
2817 static gboolean
2818 xg_font_filter (const PangoFontFamily *family,
2819 const PangoFontFace *face,
2820 gpointer data)
2821 {
2822 const char *name = pango_font_family_get_name ((PangoFontFamily *)family);
2823 ptrdiff_t namelen = strlen (name);
2824
2825 if (font_is_ignored (name, namelen))
2826 return FALSE;
2827 return TRUE;
2828 }
2829 #endif
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840 Lisp_Object
2841 xg_get_font (struct frame *f, const char *default_name)
2842 {
2843 GtkWidget *w;
2844 int done = 0;
2845 Lisp_Object font = Qnil;
2846
2847 #ifdef HAVE_PGTK
2848 if (!FRAME_GTK_OUTER_WIDGET (f))
2849 error ("Can't open dialog from child frames");
2850 #endif
2851
2852 w = gtk_font_chooser_dialog_new
2853 ("Pick a font", GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
2854
2855 #ifdef HAVE_GTK3
2856 gtk_font_chooser_set_filter_func (GTK_FONT_CHOOSER (w), xg_font_filter, NULL, NULL);
2857 #endif
2858 if (default_name)
2859 {
2860
2861
2862 char *p = strrchr (default_name, '-');
2863 if (p)
2864 {
2865 char *ep = p+1;
2866 while (c_isdigit (*ep))
2867 ++ep;
2868 if (*ep == '\0') *p = ' ';
2869 }
2870 }
2871 else if (x_last_font_name)
2872 default_name = x_last_font_name;
2873
2874 if (default_name)
2875 {
2876 #ifdef HAVE_GTK3
2877 PangoFontDescription *desc
2878 = pango_font_description_from_string (default_name);
2879 gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (w), desc);
2880 pango_font_description_free (desc);
2881 #else
2882 gtk_font_chooser_set_font (GTK_FONT_CHOOSER (w), default_name);
2883 #endif
2884 }
2885
2886 gtk_widget_set_name (w, "emacs-fontdialog");
2887 done = xg_dialog_run (f, w);
2888 if (done == GTK_RESPONSE_OK)
2889 {
2890 #ifdef HAVE_GTK3
2891
2892 PangoFontDescription *desc
2893 = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (w));
2894
2895 if (desc)
2896 {
2897 const char *family = pango_font_description_get_family (desc);
2898 gint size = pango_font_description_get_size (desc);
2899 PangoWeight weight = pango_font_description_get_weight (desc);
2900 PangoStyle style = pango_font_description_get_style (desc);
2901
2902 font = CALLN (Ffont_spec,
2903 QCfamily, build_string (family),
2904 QCsize, make_float (pango_units_to_double (size)),
2905 QCweight, xg_weight_to_symbol (weight),
2906 QCslant, xg_style_to_symbol (style));
2907
2908 char *font_desc_str = pango_font_description_to_string (desc);
2909 dupstring (&x_last_font_name, font_desc_str);
2910 g_free (font_desc_str);
2911 pango_font_description_free (desc);
2912 }
2913
2914 #else
2915
2916 char *font_name
2917 = gtk_font_selection_dialog_get_font_name (GTK_FONT_CHOOSER (w));
2918
2919 if (font_name)
2920 {
2921 font = build_string (font_name);
2922 g_free (x_last_font_name);
2923 x_last_font_name = font_name;
2924 }
2925 #endif
2926 }
2927
2928 gtk_widget_destroy (w);
2929 return font;
2930 }
2931 #endif
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943 #define MENU_ITEM_NAME "emacs-menuitem"
2944
2945
2946
2947
2948 static xg_list_node xg_menu_cb_list;
2949
2950
2951
2952 static xg_list_node xg_menu_item_cb_list;
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964 static xg_menu_cb_data *
2965 make_cl_data (xg_menu_cb_data *cl_data, struct frame *f, GCallback highlight_cb)
2966 {
2967 if (! cl_data)
2968 {
2969 cl_data = xmalloc (sizeof *cl_data);
2970 cl_data->f = f;
2971 cl_data->menu_bar_vector = f->menu_bar_vector;
2972 cl_data->menu_bar_items_used = f->menu_bar_items_used;
2973 cl_data->highlight_cb = highlight_cb;
2974 cl_data->ref_count = 0;
2975
2976 xg_list_insert (&xg_menu_cb_list, &cl_data->ptrs);
2977 }
2978
2979 cl_data->ref_count++;
2980
2981 return cl_data;
2982 }
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995 static void
2996 update_cl_data (xg_menu_cb_data *cl_data,
2997 struct frame *f,
2998 GCallback highlight_cb)
2999 {
3000 if (cl_data)
3001 {
3002 cl_data->f = f;
3003 cl_data->menu_bar_vector = f->menu_bar_vector;
3004 cl_data->menu_bar_items_used = f->menu_bar_items_used;
3005 cl_data->highlight_cb = highlight_cb;
3006 }
3007 }
3008
3009
3010
3011
3012 static void
3013 unref_cl_data (xg_menu_cb_data *cl_data)
3014 {
3015 if (cl_data && cl_data->ref_count > 0)
3016 {
3017 cl_data->ref_count--;
3018 if (cl_data->ref_count == 0)
3019 {
3020 xg_list_remove (&xg_menu_cb_list, &cl_data->ptrs);
3021 xfree (cl_data);
3022 }
3023 }
3024 }
3025
3026
3027
3028 void
3029 xg_mark_data (void)
3030 {
3031 xg_list_node *iter;
3032 Lisp_Object rest, frame;
3033
3034 for (iter = xg_menu_cb_list.next; iter; iter = iter->next)
3035 mark_object (((xg_menu_cb_data *) iter)->menu_bar_vector);
3036
3037 for (iter = xg_menu_item_cb_list.next; iter; iter = iter->next)
3038 {
3039 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data *) iter;
3040
3041 if (! NILP (cb_data->help))
3042 mark_object (cb_data->help);
3043 }
3044
3045 FOR_EACH_FRAME (rest, frame)
3046 {
3047 struct frame *f = XFRAME (frame);
3048
3049 if ((FRAME_X_P (f) || FRAME_PGTK_P (f)) && FRAME_GTK_OUTER_WIDGET (f))
3050 {
3051 struct xg_frame_tb_info *tbinfo
3052 = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
3053 TB_INFO_KEY);
3054 if (tbinfo)
3055 {
3056 mark_object (tbinfo->last_tool_bar);
3057 mark_object (tbinfo->style);
3058 }
3059 }
3060 }
3061
3062 #ifndef HAVE_PGTK
3063 if (xg_pending_quit_event.kind != NO_EVENT)
3064 {
3065 eassert (xg_pending_quit_event.kind == ASCII_KEYSTROKE_EVENT);
3066
3067 mark_object (xg_pending_quit_event.frame_or_window);
3068 mark_object (xg_pending_quit_event.arg);
3069 }
3070 #endif
3071 }
3072
3073
3074
3075
3076
3077 static void
3078 menuitem_destroy_callback (GtkWidget *w, gpointer client_data)
3079 {
3080 if (client_data)
3081 {
3082 xg_menu_item_cb_data *data = client_data;
3083 xg_list_remove (&xg_menu_item_cb_list, &data->ptrs);
3084 xfree (data);
3085 }
3086 }
3087
3088
3089
3090
3091
3092
3093
3094
3095 static gboolean
3096 menuitem_highlight_callback (GtkWidget *w,
3097 GdkEventCrossing *event,
3098 gpointer client_data)
3099 {
3100 GdkEvent ev;
3101 GtkWidget *subwidget;
3102 xg_menu_item_cb_data *data;
3103
3104 ev.crossing = *event;
3105 subwidget = gtk_get_event_widget (&ev);
3106 data = g_object_get_data (G_OBJECT (subwidget), XG_ITEM_DATA);
3107 if (data)
3108 {
3109 if (! NILP (data->help) && data->cl_data->highlight_cb)
3110 {
3111 gpointer call_data = event->type == GDK_LEAVE_NOTIFY ? 0 : data;
3112 GtkCallback func = (GtkCallback) data->cl_data->highlight_cb;
3113 (*func) (subwidget, call_data);
3114 }
3115 }
3116
3117 return FALSE;
3118 }
3119
3120
3121
3122
3123
3124 static void
3125 menu_destroy_callback (GtkWidget *w, gpointer client_data)
3126 {
3127 unref_cl_data (client_data);
3128 }
3129
3130
3131
3132
3133
3134
3135 static GtkWidget *
3136 make_widget_for_menu_item (const char *utf8_label, const char *utf8_key)
3137 {
3138 GtkWidget *wlbl;
3139 GtkWidget *wkey;
3140 GtkWidget *wbox;
3141
3142 wbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
3143 gtk_box_set_homogeneous (GTK_BOX (wbox), FALSE);
3144 wlbl = gtk_label_new (utf8_label);
3145 wkey = gtk_label_new (utf8_key);
3146
3147 #if GTK_CHECK_VERSION (3, 14, 0)
3148 gtk_widget_set_halign (wlbl, GTK_ALIGN_START);
3149 gtk_widget_set_valign (wlbl, GTK_ALIGN_CENTER);
3150 gtk_widget_set_halign (wkey, GTK_ALIGN_START);
3151 gtk_widget_set_valign (wkey, GTK_ALIGN_CENTER);
3152 #else
3153 gtk_misc_set_alignment (GTK_MISC (wlbl), 0.0, 0.5);
3154 gtk_misc_set_alignment (GTK_MISC (wkey), 0.0, 0.5);
3155 #endif
3156 gtk_box_pack_start (GTK_BOX (wbox), wlbl, TRUE, TRUE, 0);
3157 gtk_box_pack_start (GTK_BOX (wbox), wkey, FALSE, FALSE, 0);
3158
3159 gtk_widget_set_name (wlbl, MENU_ITEM_NAME);
3160 gtk_widget_set_name (wkey, MENU_ITEM_NAME);
3161 gtk_widget_set_name (wbox, MENU_ITEM_NAME);
3162
3163 return wbox;
3164 }
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180 static GtkWidget *
3181 make_menu_item (const char *utf8_label,
3182 const char *utf8_key,
3183 widget_value *item,
3184 GSList **group)
3185 {
3186 GtkWidget *w;
3187 GtkWidget *wtoadd = 0;
3188
3189
3190
3191
3192
3193 if (! utf8_label) utf8_label = " ";
3194
3195 if (utf8_key)
3196 wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
3197
3198 if (item->button_type == BUTTON_TYPE_TOGGLE)
3199 {
3200 *group = NULL;
3201 if (utf8_key) w = gtk_check_menu_item_new ();
3202 else w = gtk_check_menu_item_new_with_label (utf8_label);
3203 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), item->selected);
3204 }
3205 else if (item->button_type == BUTTON_TYPE_RADIO)
3206 {
3207 if (utf8_key) w = gtk_radio_menu_item_new (*group);
3208 else w = gtk_radio_menu_item_new_with_label (*group, utf8_label);
3209 *group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (w));
3210 if (item->selected)
3211 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE);
3212 }
3213 else
3214 {
3215 *group = NULL;
3216 if (utf8_key) w = gtk_menu_item_new ();
3217 else w = gtk_menu_item_new_with_label (utf8_label);
3218 }
3219
3220 if (wtoadd) gtk_container_add (GTK_CONTAINER (w), wtoadd);
3221 if (! item->enabled) gtk_widget_set_sensitive (w, FALSE);
3222
3223 #ifdef HAVE_PGTK
3224 if (!NILP (item->help))
3225 gtk_widget_set_tooltip_text (w, SSDATA (item->help));
3226 #endif
3227
3228 return w;
3229 }
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245 static GtkWidget *
3246 xg_create_one_menuitem (widget_value *item,
3247 struct frame *f,
3248 GCallback select_cb,
3249 GCallback highlight_cb,
3250 xg_menu_cb_data *cl_data,
3251 GSList **group)
3252 {
3253 char *utf8_label;
3254 char *utf8_key;
3255 GtkWidget *w;
3256 xg_menu_item_cb_data *cb_data;
3257
3258 utf8_label = get_utf8_string (item->name);
3259 utf8_key = get_utf8_string (item->key);
3260
3261 w = make_menu_item (utf8_label, utf8_key, item, group);
3262
3263 if (utf8_label) g_free (utf8_label);
3264 if (utf8_key) g_free (utf8_key);
3265
3266 cb_data = xmalloc (sizeof *cb_data);
3267
3268 xg_list_insert (&xg_menu_item_cb_list, &cb_data->ptrs);
3269
3270 cb_data->select_id = 0;
3271 cb_data->help = item->help;
3272 cb_data->cl_data = cl_data;
3273 cb_data->call_data = item->call_data;
3274
3275 g_signal_connect (G_OBJECT (w),
3276 "destroy",
3277 G_CALLBACK (menuitem_destroy_callback),
3278 cb_data);
3279
3280
3281 g_object_set_data (G_OBJECT (w), XG_ITEM_DATA, cb_data);
3282
3283
3284 if (item->call_data && ! item->contents)
3285 {
3286 if (select_cb)
3287 cb_data->select_id
3288 = g_signal_connect (G_OBJECT (w), "activate", select_cb, cb_data);
3289 }
3290
3291 return w;
3292 }
3293
3294 #ifdef HAVE_PGTK
3295 static gboolean
3296 menu_bar_button_pressed_cb (GtkWidget *widget, GdkEvent *event,
3297 gpointer user_data)
3298 {
3299 struct frame *f = user_data;
3300
3301 if (event->button.button < 4
3302 && event->button.window != gtk_widget_get_window (widget)
3303 && !popup_activated ())
3304 {
3305 pgtk_menu_set_in_use (true);
3306 set_frame_menubar (f, true);
3307 }
3308
3309 return false;
3310 }
3311 #endif
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333 static GtkWidget *
3334 create_menus (widget_value *data,
3335 struct frame *f,
3336 GCallback select_cb,
3337 GCallback deactivate_cb,
3338 GCallback highlight_cb,
3339 bool pop_up_p,
3340 bool menu_bar_p,
3341 GtkWidget *topmenu,
3342 xg_menu_cb_data *cl_data,
3343 const char *name)
3344 {
3345 widget_value *item;
3346 GtkWidget *wmenu = topmenu;
3347 GSList *group = NULL;
3348
3349 if (! topmenu)
3350 {
3351 if (! menu_bar_p)
3352 {
3353 wmenu = gtk_menu_new ();
3354 xg_set_screen (wmenu, f);
3355
3356
3357
3358 g_signal_connect (G_OBJECT (wmenu),
3359 "enter-notify-event",
3360 G_CALLBACK (menuitem_highlight_callback),
3361 NULL);
3362 g_signal_connect (G_OBJECT (wmenu),
3363 "leave-notify-event",
3364 G_CALLBACK (menuitem_highlight_callback),
3365 NULL);
3366 }
3367 else
3368 {
3369 #ifndef HAVE_GTK3
3370 wmenu = gtk_menu_bar_new ();
3371 #else
3372 wmenu = emacs_menu_bar_new ();
3373 #endif
3374
3375 #ifdef HAVE_PGTK
3376 g_signal_connect (G_OBJECT (wmenu), "button-press-event",
3377 G_CALLBACK (menu_bar_button_pressed_cb), f);
3378 #endif
3379
3380
3381
3382
3383 gtk_widget_set_size_request (wmenu, 1, -1);
3384 }
3385
3386
3387 cl_data = make_cl_data (cl_data, f, highlight_cb);
3388 g_object_set_data (G_OBJECT (wmenu), XG_FRAME_DATA, (gpointer)cl_data);
3389 g_signal_connect (G_OBJECT (wmenu), "destroy",
3390 G_CALLBACK (menu_destroy_callback), cl_data);
3391
3392 if (name)
3393 gtk_widget_set_name (wmenu, name);
3394
3395 #ifndef HAVE_PGTK
3396 if (deactivate_cb)
3397 g_signal_connect (G_OBJECT (wmenu),
3398 "selection-done", deactivate_cb, 0);
3399 #else
3400 if (deactivate_cb)
3401 g_signal_connect (G_OBJECT (wmenu),
3402 "deactivate", deactivate_cb, 0);
3403 #endif
3404 }
3405
3406 for (item = data; item; item = item->next)
3407 {
3408 GtkWidget *w;
3409
3410 if (pop_up_p && !item->contents && !item->call_data
3411 && !menu_separator_name_p (item->name))
3412 {
3413 char *utf8_label;
3414
3415
3416 group = NULL;
3417 utf8_label = get_utf8_string (item->name);
3418
3419 w = gtk_menu_item_new_with_label (utf8_label);
3420 gtk_widget_set_sensitive (w, FALSE);
3421 if (utf8_label) g_free (utf8_label);
3422 }
3423 else if (menu_separator_name_p (item->name))
3424 {
3425 group = NULL;
3426
3427 w = gtk_separator_menu_item_new ();
3428 }
3429 else
3430 {
3431 w = xg_create_one_menuitem (item,
3432 f,
3433 item->contents ? 0 : select_cb,
3434 highlight_cb,
3435 cl_data,
3436 &group);
3437
3438
3439
3440 if (item->contents || menu_bar_p)
3441 {
3442 GtkWidget *submenu = create_menus (item->contents,
3443 f,
3444 select_cb,
3445 deactivate_cb,
3446 highlight_cb,
3447 0,
3448 0,
3449 0,
3450 cl_data,
3451 0);
3452 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
3453 }
3454 }
3455
3456 gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), w);
3457 gtk_widget_set_name (w, MENU_ITEM_NAME);
3458 }
3459
3460 return wmenu;
3461 }
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478 GtkWidget *
3479 xg_create_widget (const char *type, const char *name, struct frame *f,
3480 widget_value *val, GCallback select_cb,
3481 GCallback deactivate_cb, GCallback highlight_cb)
3482 {
3483 GtkWidget *w = 0;
3484 bool menu_bar_p = strcmp (type, "menubar") == 0;
3485 bool pop_up_p = strcmp (type, "popup") == 0;
3486
3487 if (strcmp (type, "dialog") == 0)
3488 {
3489 w = create_dialog (val, select_cb, deactivate_cb);
3490 xg_set_screen (w, f);
3491 gtk_window_set_transient_for (GTK_WINDOW (w),
3492 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
3493 gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
3494 gtk_widget_set_name (w, "emacs-dialog");
3495 gtk_window_set_modal (GTK_WINDOW (w), TRUE);
3496 }
3497 else if (menu_bar_p || pop_up_p)
3498 {
3499 w = create_menus (val->contents,
3500 f,
3501 select_cb,
3502 deactivate_cb,
3503 highlight_cb,
3504 pop_up_p,
3505 menu_bar_p,
3506 0,
3507 0,
3508 name);
3509
3510
3511
3512 if (pop_up_p)
3513 {
3514
3515 gtk_widget_realize (w);
3516 xg_set_cursor (w, FRAME_DISPLAY_INFO (f)->xg_cursor);
3517 }
3518 }
3519 else
3520 {
3521 fprintf (stderr, "bad type in xg_create_widget: %s, doing nothing\n",
3522 type);
3523 }
3524
3525 return w;
3526 }
3527
3528
3529
3530 static const char *
3531 xg_get_menu_item_label (GtkMenuItem *witem)
3532 {
3533 GtkLabel *wlabel = GTK_LABEL (XG_BIN_CHILD (witem));
3534 return gtk_label_get_label (wlabel);
3535 }
3536
3537
3538
3539 static bool
3540 xg_item_label_same_p (GtkMenuItem *witem, const char *label)
3541 {
3542 char *utf8_label = get_utf8_string (label);
3543 const char *old_label = witem ? xg_get_menu_item_label (witem) : 0;
3544
3545 bool is_same = (old_label
3546 ? utf8_label && strcmp (utf8_label, old_label) == 0
3547 : !utf8_label);
3548
3549 if (utf8_label) g_free (utf8_label);
3550
3551 return is_same;
3552 }
3553
3554
3555
3556 static void
3557 xg_destroy_widgets (GList *list)
3558 {
3559 GList *iter;
3560
3561 for (iter = list; iter; iter = g_list_next (iter))
3562 {
3563 GtkWidget *w = GTK_WIDGET (iter->data);
3564
3565
3566 gtk_widget_destroy (w);
3567 }
3568 }
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582 static void
3583 xg_update_menubar (GtkWidget *menubar,
3584 struct frame *f,
3585 GList **list,
3586 GList *iter,
3587 int pos,
3588 widget_value *val,
3589 GCallback select_cb,
3590 GCallback deactivate_cb,
3591 GCallback highlight_cb,
3592 xg_menu_cb_data *cl_data)
3593 {
3594 if (! iter && ! val)
3595 return;
3596 else if (iter && ! val)
3597 {
3598
3599 xg_destroy_widgets (iter);
3600
3601
3602 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar),
3603 gtk_menu_item_new_with_label (""),
3604 0);
3605
3606 val = 0;
3607 iter = 0;
3608 }
3609 else if (! iter && val)
3610 {
3611
3612 create_menus (val, f, select_cb, deactivate_cb, highlight_cb,
3613 0, 1, menubar, cl_data, 0);
3614
3615
3616 val = 0;
3617 iter = 0;
3618 }
3619
3620 else if (xg_item_label_same_p (GTK_MENU_ITEM (iter->data), val->name))
3621 {
3622
3623 val = val->next;
3624 iter = g_list_next (iter);
3625 ++pos;
3626 }
3627 else
3628 {
3629 GtkMenuItem *witem = GTK_MENU_ITEM (iter->data);
3630 GtkMenuItem *witem2 = 0;
3631 bool val_in_menubar = 0;
3632 bool iter_in_new_menubar = 0;
3633 GList *iter2;
3634 widget_value *cur;
3635
3636
3637 for (iter2 = iter;
3638 iter2 && ! val_in_menubar;
3639 iter2 = g_list_next (iter2))
3640 {
3641 witem2 = GTK_MENU_ITEM (iter2->data);
3642 val_in_menubar = xg_item_label_same_p (witem2, val->name);
3643 }
3644
3645
3646
3647 for (cur = val; cur && ! iter_in_new_menubar; cur = cur->next)
3648 iter_in_new_menubar = xg_item_label_same_p (witem, cur->name);
3649
3650 if (val_in_menubar && ! iter_in_new_menubar)
3651 {
3652 int nr = pos;
3653
3654
3655
3656
3657
3658
3659 g_object_ref (G_OBJECT (witem));
3660 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem));
3661 gtk_widget_destroy (GTK_WIDGET (witem));
3662
3663
3664 g_list_free (*list);
3665 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
3666 while (nr-- > 0) iter = g_list_next (iter);
3667 }
3668 else if (! val_in_menubar && ! iter_in_new_menubar)
3669 {
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684 GtkLabel *wlabel = GTK_LABEL (XG_BIN_CHILD (witem));
3685 char *utf8_label = get_utf8_string (val->name);
3686
3687
3688
3689
3690
3691
3692 gtk_label_set_text (wlabel, utf8_label);
3693 g_object_notify (G_OBJECT (witem), "label");
3694 if (utf8_label) g_free (utf8_label);
3695 iter = g_list_next (iter);
3696 val = val->next;
3697 ++pos;
3698 }
3699 else if (! val_in_menubar && iter_in_new_menubar)
3700 {
3701
3702
3703
3704
3705
3706 int nr = pos;
3707 GSList *group = 0;
3708 GtkWidget *w = xg_create_one_menuitem (val,
3709 f,
3710 select_cb,
3711 highlight_cb,
3712 cl_data,
3713 &group);
3714
3715
3716
3717 GtkWidget *submenu = create_menus (NULL, f,
3718 select_cb, deactivate_cb,
3719 highlight_cb,
3720 0, 0, 0, cl_data, 0);
3721
3722 gtk_widget_set_name (w, MENU_ITEM_NAME);
3723 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), w, pos);
3724 gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
3725
3726 g_list_free (*list);
3727 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
3728 while (nr-- > 0) iter = g_list_next (iter);
3729 iter = g_list_next (iter);
3730 val = val->next;
3731 ++pos;
3732 }
3733 else
3734 {
3735 int nr = pos;
3736
3737
3738
3739
3740
3741 g_object_ref (G_OBJECT (witem2));
3742 gtk_container_remove (GTK_CONTAINER (menubar), GTK_WIDGET (witem2));
3743 gtk_menu_shell_insert (GTK_MENU_SHELL (menubar),
3744 GTK_WIDGET (witem2), pos);
3745 g_object_unref (G_OBJECT (witem2));
3746
3747 g_list_free (*list);
3748 *list = iter = gtk_container_get_children (GTK_CONTAINER (menubar));
3749 while (nr-- > 0) iter = g_list_next (iter);
3750 if (iter) iter = g_list_next (iter);
3751 val = val->next;
3752 ++pos;
3753 }
3754 }
3755
3756
3757 xg_update_menubar (menubar, f, list, iter, pos, val,
3758 select_cb, deactivate_cb, highlight_cb, cl_data);
3759 }
3760
3761
3762
3763
3764
3765
3766 static void
3767 xg_update_menu_item (widget_value *val,
3768 GtkWidget *w,
3769 GCallback select_cb,
3770 GCallback highlight_cb,
3771 xg_menu_cb_data *cl_data)
3772 {
3773 GtkWidget *wchild;
3774 GtkLabel *wlbl = 0;
3775 GtkLabel *wkey = 0;
3776 char *utf8_label;
3777 char *utf8_key;
3778 const char *old_label = 0;
3779 const char *old_key = 0;
3780 xg_menu_item_cb_data *cb_data;
3781 bool label_changed = false;
3782
3783 wchild = XG_BIN_CHILD (w);
3784 utf8_label = get_utf8_string (val->name);
3785 utf8_key = get_utf8_string (val->key);
3786
3787
3788 if (GTK_IS_BOX (wchild))
3789 {
3790 GList *list = gtk_container_get_children (GTK_CONTAINER (wchild));
3791
3792 wlbl = GTK_LABEL (list->data);
3793 wkey = GTK_LABEL (list->next->data);
3794 g_list_free (list);
3795
3796 if (! utf8_key)
3797 {
3798
3799 g_object_ref (G_OBJECT (wlbl));
3800 gtk_container_remove (GTK_CONTAINER (w), wchild);
3801 gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (wlbl));
3802 g_object_unref (G_OBJECT (wlbl));
3803 wkey = 0;
3804 }
3805
3806 }
3807 else
3808 {
3809 wlbl = GTK_LABEL (wchild);
3810
3811
3812 if (utf8_key)
3813 {
3814 GtkWidget *wtoadd = make_widget_for_menu_item (utf8_label, utf8_key);
3815 GList *list = gtk_container_get_children (GTK_CONTAINER (wtoadd));
3816
3817 wlbl = GTK_LABEL (list->data);
3818 wkey = GTK_LABEL (list->next->data);
3819 g_list_free (list);
3820
3821 gtk_container_remove (GTK_CONTAINER (w), wchild);
3822 gtk_container_add (GTK_CONTAINER (w), wtoadd);
3823 }
3824 }
3825
3826 if (wkey) old_key = gtk_label_get_label (wkey);
3827 if (wlbl) old_label = gtk_label_get_label (wlbl);
3828
3829 if (wkey && utf8_key && (! old_key || strcmp (utf8_key, old_key) != 0))
3830 {
3831 label_changed = true;
3832 gtk_label_set_text (wkey, utf8_key);
3833 }
3834
3835 if (utf8_label && (! old_label || strcmp (utf8_label, old_label) != 0))
3836 {
3837 label_changed = true;
3838 gtk_label_set_text (wlbl, utf8_label);
3839 }
3840
3841 if (utf8_key) g_free (utf8_key);
3842 if (utf8_label) g_free (utf8_label);
3843
3844 if (! val->enabled && gtk_widget_get_sensitive (w))
3845 gtk_widget_set_sensitive (w, FALSE);
3846 else if (val->enabled && ! gtk_widget_get_sensitive (w))
3847 gtk_widget_set_sensitive (w, TRUE);
3848
3849 cb_data = g_object_get_data (G_OBJECT (w), XG_ITEM_DATA);
3850 if (cb_data)
3851 {
3852 cb_data->call_data = val->call_data;
3853 cb_data->help = val->help;
3854 cb_data->cl_data = cl_data;
3855
3856
3857 if (val->call_data && ! val->contents)
3858 {
3859
3860 if (! cb_data->select_id)
3861 cb_data->select_id
3862 = g_signal_connect (G_OBJECT (w), "activate",
3863 select_cb, cb_data);
3864 }
3865 else if (cb_data->select_id)
3866 {
3867 g_signal_handler_disconnect (w, cb_data->select_id);
3868 cb_data->select_id = 0;
3869 }
3870 }
3871
3872 if (label_changed)
3873 g_object_notify (G_OBJECT (w), "label");
3874 }
3875
3876
3877
3878 static void
3879 xg_update_toggle_item (widget_value *val, GtkWidget *w)
3880 {
3881 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
3882 }
3883
3884
3885
3886 static void
3887 xg_update_radio_item (widget_value *val, GtkWidget *w)
3888 {
3889 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), val->selected);
3890 }
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904 static GtkWidget *
3905 xg_update_submenu (GtkWidget *submenu,
3906 struct frame *f,
3907 widget_value *val,
3908 GCallback select_cb,
3909 GCallback deactivate_cb,
3910 GCallback highlight_cb,
3911 xg_menu_cb_data *cl_data)
3912 {
3913 GtkWidget *newsub = submenu;
3914 GList *list = 0;
3915 GList *iter;
3916 widget_value *cur;
3917 GList *first_radio = 0;
3918
3919 if (submenu)
3920 list = gtk_container_get_children (GTK_CONTAINER (submenu));
3921
3922 for (cur = val, iter = list;
3923 cur && iter;
3924 iter = g_list_next (iter), cur = cur->next)
3925 {
3926 GtkWidget *w = GTK_WIDGET (iter->data);
3927
3928
3929
3930
3931 if (cur->button_type == BUTTON_TYPE_RADIO && ! first_radio)
3932 first_radio = iter;
3933 else if (cur->button_type != BUTTON_TYPE_RADIO
3934 && ! GTK_IS_RADIO_MENU_ITEM (w))
3935 first_radio = 0;
3936
3937 if (GTK_IS_SEPARATOR_MENU_ITEM (w))
3938 {
3939 if (! menu_separator_name_p (cur->name))
3940 break;
3941 }
3942 else if (GTK_IS_CHECK_MENU_ITEM (w))
3943 {
3944 if (cur->button_type != BUTTON_TYPE_TOGGLE)
3945 break;
3946 xg_update_toggle_item (cur, w);
3947 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
3948 }
3949 else if (GTK_IS_RADIO_MENU_ITEM (w))
3950 {
3951 if (cur->button_type != BUTTON_TYPE_RADIO)
3952 break;
3953 xg_update_radio_item (cur, w);
3954 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
3955 }
3956 else if (GTK_IS_MENU_ITEM (w))
3957 {
3958 GtkMenuItem *witem = GTK_MENU_ITEM (w);
3959 GtkWidget *sub;
3960
3961 if (cur->button_type != BUTTON_TYPE_NONE ||
3962 menu_separator_name_p (cur->name))
3963 break;
3964
3965 xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
3966
3967 sub = gtk_menu_item_get_submenu (witem);
3968 if (sub && ! cur->contents)
3969 {
3970
3971 g_object_ref (G_OBJECT (sub));
3972 gtk_menu_item_set_submenu (witem, NULL);
3973 gtk_widget_destroy (sub);
3974 }
3975 else if (cur->contents)
3976 {
3977 GtkWidget *nsub;
3978
3979 nsub = xg_update_submenu (sub, f, cur->contents,
3980 select_cb, deactivate_cb,
3981 highlight_cb, cl_data);
3982
3983
3984 if (nsub != sub)
3985 gtk_menu_item_set_submenu (witem, nsub);
3986 }
3987 }
3988 else
3989 {
3990
3991
3992 break;
3993 }
3994 }
3995
3996
3997 if (iter)
3998 {
3999
4000
4001 if (cur && first_radio) xg_destroy_widgets (first_radio);
4002 else xg_destroy_widgets (iter);
4003 }
4004
4005 if (cur)
4006 {
4007
4008 newsub = create_menus (cur,
4009 f,
4010 select_cb,
4011 deactivate_cb,
4012 highlight_cb,
4013 0,
4014 0,
4015 submenu,
4016 cl_data,
4017 0);
4018 }
4019
4020 if (list) g_list_free (list);
4021
4022 return newsub;
4023 }
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034 void
4035 xg_modify_menubar_widgets (GtkWidget *menubar, struct frame *f,
4036 widget_value *val, bool deep_p,
4037 GCallback select_cb, GCallback deactivate_cb,
4038 GCallback highlight_cb)
4039 {
4040 xg_menu_cb_data *cl_data;
4041 GList *list = gtk_container_get_children (GTK_CONTAINER (menubar));
4042
4043 if (! list) return;
4044
4045 cl_data = g_object_get_data (G_OBJECT (menubar), XG_FRAME_DATA);
4046
4047 xg_update_menubar (menubar, f, &list, list, 0, val->contents,
4048 select_cb, deactivate_cb, highlight_cb, cl_data);
4049
4050 if (deep_p)
4051 {
4052 widget_value *cur;
4053
4054
4055
4056
4057
4058
4059 update_cl_data (cl_data, f, highlight_cb);
4060
4061 for (cur = val->contents; cur; cur = cur->next)
4062 {
4063 GList *iter;
4064 GtkWidget *sub = 0;
4065 GtkWidget *newsub;
4066 GtkMenuItem *witem = 0;
4067
4068
4069 for (iter = list ; iter; iter = g_list_next (iter))
4070 {
4071 witem = GTK_MENU_ITEM (iter->data);
4072 if (xg_item_label_same_p (witem, cur->name))
4073 {
4074 sub = gtk_menu_item_get_submenu (witem);
4075 break;
4076 }
4077 }
4078
4079 newsub = xg_update_submenu (sub,
4080 f,
4081 cur->contents,
4082 select_cb,
4083 deactivate_cb,
4084 highlight_cb,
4085 cl_data);
4086
4087
4088
4089 if (newsub != sub && witem != 0)
4090 {
4091 xg_set_screen (newsub, f);
4092 gtk_menu_item_set_submenu (witem, newsub);
4093 }
4094 }
4095 }
4096
4097 g_list_free (list);
4098 gtk_widget_show_all (menubar);
4099 }
4100
4101
4102
4103
4104
4105 static void
4106 menubar_map_cb (GtkWidget *w, gpointer user_data)
4107 {
4108 GtkRequisition req;
4109 struct frame *f = user_data;
4110 gtk_widget_get_preferred_size (w, NULL, &req);
4111 req.height *= xg_get_scale (f);
4112 if (FRAME_MENUBAR_HEIGHT (f) != req.height)
4113 {
4114 FRAME_MENUBAR_HEIGHT (f) = req.height;
4115 adjust_frame_size (f, -1, -1, 2, 0, Qmenu_bar_lines);
4116 }
4117 }
4118
4119
4120
4121
4122 void
4123 xg_update_frame_menubar (struct frame *f)
4124 {
4125 xp_output *x = f->output_data.xp;
4126 GtkRequisition req;
4127 int scale = xg_get_scale (f);
4128
4129 if (!x->menubar_widget || gtk_widget_get_mapped (x->menubar_widget))
4130 return;
4131
4132 if (x->menubar_widget && gtk_widget_get_parent (x->menubar_widget))
4133 return;
4134
4135 block_input ();
4136
4137 gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->menubar_widget,
4138 FALSE, FALSE, 0);
4139 gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->menubar_widget, 0);
4140
4141 g_signal_connect (x->menubar_widget, "map", G_CALLBACK (menubar_map_cb), f);
4142 gtk_widget_show_all (x->menubar_widget);
4143 gtk_widget_get_preferred_size (x->menubar_widget, NULL, &req);
4144 req.height *= xg_get_scale (f);
4145
4146 #if !defined HAVE_PGTK && defined HAVE_GTK3
4147 if (FRAME_DISPLAY_INFO (f)->n_planes == 32)
4148 {
4149 GdkScreen *screen = gtk_widget_get_screen (x->menubar_widget);
4150 GdkVisual *visual = gdk_screen_get_system_visual (screen);
4151
4152 gtk_widget_realize (x->menubar_widget);
4153 gtk_widget_set_visual (x->menubar_widget, visual);
4154 }
4155 #endif
4156
4157 if (FRAME_MENUBAR_HEIGHT (f) != (req.height * scale))
4158 {
4159 FRAME_MENUBAR_HEIGHT (f) = req.height * scale;
4160 adjust_frame_size (f, -1, -1, 2, 0, Qmenu_bar_lines);
4161 }
4162 unblock_input ();
4163 }
4164
4165
4166
4167
4168 void
4169 free_frame_menubar (struct frame *f)
4170 {
4171 xp_output *x = f->output_data.xp;
4172
4173 if (x->menubar_widget)
4174 {
4175 block_input ();
4176
4177 gtk_container_remove (GTK_CONTAINER (x->vbox_widget), x->menubar_widget);
4178
4179
4180 x->menubar_widget = 0;
4181 FRAME_MENUBAR_HEIGHT (f) = 0;
4182 adjust_frame_size (f, -1, -1, 2, 0, Qmenu_bar_lines);
4183 unblock_input ();
4184 }
4185 }
4186
4187 #ifndef HAVE_PGTK
4188 bool
4189 xg_event_is_for_menubar (struct frame *f, const XEvent *event)
4190 {
4191 struct x_output *x = f->output_data.x;
4192 GList *iter;
4193 GdkRectangle rec;
4194 GList *list;
4195 GdkDisplay *gdpy;
4196 GdkWindow *gw;
4197 GdkEvent gevent;
4198 GtkWidget *gwdesc;
4199
4200 if (! x->menubar_widget) return 0;
4201
4202 #ifdef HAVE_XINPUT2
4203 XIDeviceEvent *xev = (XIDeviceEvent *) event->xcookie.data;
4204 if (event->type == GenericEvent)
4205 {
4206 if (! (xev->event_x >= 0
4207 && xev->event_x < FRAME_PIXEL_WIDTH (f)
4208 && xev->event_y >= 0
4209 && xev->event_y < FRAME_MENUBAR_HEIGHT (f)))
4210 return 0;
4211 }
4212 else
4213 #endif
4214 if (! (event->xbutton.x >= 0
4215 && event->xbutton.x < FRAME_PIXEL_WIDTH (f)
4216 && event->xbutton.y >= 0
4217 && event->xbutton.y < FRAME_MENUBAR_HEIGHT (f)
4218 && event->xbutton.same_screen))
4219 return 0;
4220
4221 gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
4222 #ifdef HAVE_XINPUT2
4223 if (event->type == GenericEvent)
4224 gw = gdk_x11_window_lookup_for_display (gdpy, xev->event);
4225 else
4226 #endif
4227 gw = gdk_x11_window_lookup_for_display (gdpy, event->xbutton.window);
4228 if (! gw) return 0;
4229 gevent.any.window = gw;
4230 gevent.any.type = GDK_NOTHING;
4231 gwdesc = gtk_get_event_widget (&gevent);
4232 if (! gwdesc) return 0;
4233 if (! GTK_IS_MENU_BAR (gwdesc)
4234 && ! GTK_IS_MENU_ITEM (gwdesc)
4235 && ! gtk_widget_is_ancestor (x->menubar_widget, gwdesc))
4236 return 0;
4237
4238 list = gtk_container_get_children (GTK_CONTAINER (x->menubar_widget));
4239 if (! list) return 0;
4240 int scale = xg_get_scale (f);
4241 #ifdef HAVE_XINPUT2
4242 if (event->type == GenericEvent)
4243 {
4244 rec.x = xev->event_x / scale;
4245 rec.y = xev->event_y / scale;
4246 }
4247 else
4248 {
4249 #endif
4250 rec.x = event->xbutton.x / scale;
4251 rec.y = event->xbutton.y / scale;
4252 #ifdef HAVE_XINPUT2
4253 }
4254 #endif
4255
4256 rec.width = 1;
4257 rec.height = 1;
4258
4259 for (iter = list ; iter; iter = g_list_next (iter))
4260 {
4261 GtkWidget *w = GTK_WIDGET (iter->data);
4262 if (gtk_widget_get_mapped (w) && gtk_widget_intersect (w, &rec, NULL))
4263 break;
4264 }
4265 g_list_free (list);
4266 return iter != 0;
4267 }
4268 #endif
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280 bool xg_ignore_gtk_scrollbar;
4281
4282
4283 static int scroll_bar_width_for_theme;
4284 static int scroll_bar_height_for_theme;
4285
4286 #if defined HAVE_PGTK || !defined HAVE_GTK3
4287
4288
4289
4290
4291
4292 static struct
4293 {
4294 GtkWidget **widgets;
4295 ptrdiff_t max_size;
4296 ptrdiff_t used;
4297 } id_to_widget;
4298
4299
4300
4301 #define ID_TO_WIDGET_INCR 32
4302
4303
4304
4305 static ptrdiff_t
4306 xg_store_widget_in_map (GtkWidget *w)
4307 {
4308 ptrdiff_t i;
4309
4310 if (id_to_widget.max_size == id_to_widget.used)
4311 {
4312 ptrdiff_t new_size;
4313 if (TYPE_MAXIMUM (Window) - ID_TO_WIDGET_INCR < id_to_widget.max_size)
4314 memory_full (SIZE_MAX);
4315
4316 new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR;
4317 id_to_widget.widgets = xnrealloc (id_to_widget.widgets,
4318 new_size, sizeof (GtkWidget *));
4319
4320 for (i = id_to_widget.max_size; i < new_size; ++i)
4321 id_to_widget.widgets[i] = 0;
4322 id_to_widget.max_size = new_size;
4323 }
4324
4325
4326
4327
4328 for (i = 0; i < id_to_widget.max_size; ++i)
4329 {
4330 if (! id_to_widget.widgets[i])
4331 {
4332 id_to_widget.widgets[i] = w;
4333 ++id_to_widget.used;
4334
4335 return i;
4336 }
4337 }
4338
4339
4340 emacs_abort ();
4341 }
4342
4343
4344
4345
4346 static void
4347 xg_remove_widget_from_map (ptrdiff_t idx)
4348 {
4349 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
4350 {
4351 id_to_widget.widgets[idx] = 0;
4352 --id_to_widget.used;
4353 }
4354 }
4355
4356
4357
4358 static GtkWidget *
4359 xg_get_widget_from_map (ptrdiff_t idx, Display *dpy)
4360 {
4361 if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
4362 return id_to_widget.widgets[idx];
4363
4364 return 0;
4365 }
4366
4367 #else
4368 static void
4369 find_scrollbar_cb (GtkWidget *widget, gpointer user_data)
4370 {
4371 GtkWidget **scroll_bar = user_data;
4372
4373 if (GTK_IS_SCROLLBAR (widget))
4374 *scroll_bar = widget;
4375 }
4376
4377 static GtkWidget *
4378 xg_get_widget_from_map (ptrdiff_t window, Display *dpy)
4379 {
4380 GtkWidget *gwdesc, *scroll_bar = NULL;
4381 GdkWindow *gdkwin;
4382
4383 gdkwin = gdk_x11_window_lookup_for_display (gdk_x11_lookup_xdisplay (dpy),
4384 (Window) window);
4385 if (gdkwin)
4386 {
4387 GdkEvent event;
4388 event.any.window = gdkwin;
4389 event.any.type = GDK_NOTHING;
4390 gwdesc = gtk_get_event_widget (&event);
4391
4392 if (gwdesc && GTK_IS_EVENT_BOX (gwdesc))
4393 gtk_container_forall (GTK_CONTAINER (gwdesc),
4394 find_scrollbar_cb, &scroll_bar);
4395 }
4396 else
4397 return NULL;
4398
4399 return scroll_bar;
4400 }
4401 #endif
4402
4403 static void
4404 update_theme_scrollbar_width (void)
4405 {
4406 #ifdef HAVE_GTK3
4407 GtkAdjustment *vadj;
4408 #else
4409 GtkObject *vadj;
4410 #endif
4411 GtkWidget *wscroll;
4412 int w = 0, b = 0;
4413
4414 vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX, 0.1, 0.1, 0.1);
4415 wscroll = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT (vadj));
4416 g_object_ref_sink (G_OBJECT (wscroll));
4417 gtk_widget_style_get (wscroll, "slider-width", &w, "trough-border", &b, NULL);
4418 gtk_widget_destroy (wscroll);
4419 g_object_unref (G_OBJECT (wscroll));
4420 w += 2*b;
4421 #ifndef HAVE_GTK3
4422 if (w < 16) w = 16;
4423 #endif
4424 scroll_bar_width_for_theme = w;
4425 }
4426
4427 static void
4428 update_theme_scrollbar_height (void)
4429 {
4430 #ifdef HAVE_GTK3
4431 GtkAdjustment *hadj;
4432 #else
4433 GtkObject *hadj;
4434 #endif
4435 GtkWidget *wscroll;
4436 int w = 0, b = 0;
4437
4438 hadj = gtk_adjustment_new (YG_SB_MIN, YG_SB_MIN, YG_SB_MAX, 0.1, 0.1, 0.1);
4439 wscroll = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (hadj));
4440 g_object_ref_sink (G_OBJECT (wscroll));
4441 gtk_widget_style_get (wscroll, "slider-width", &w, "trough-border", &b, NULL);
4442 gtk_widget_destroy (wscroll);
4443 g_object_unref (G_OBJECT (wscroll));
4444 w += 2*b;
4445 if (w < 12) w = 12;
4446 scroll_bar_height_for_theme = w;
4447 }
4448
4449 int
4450 xg_get_default_scrollbar_width (struct frame *f)
4451 {
4452 return scroll_bar_width_for_theme * xg_get_scale (f);
4453 }
4454
4455 int
4456 xg_get_default_scrollbar_height (struct frame *f)
4457 {
4458
4459 return scroll_bar_width_for_theme * xg_get_scale (f);
4460 }
4461
4462 #ifndef HAVE_GTK3
4463
4464
4465
4466 ptrdiff_t
4467 xg_get_scroll_id_for_window (Display *dpy, Window wid)
4468 {
4469 ptrdiff_t idx;
4470 GtkWidget *w;
4471
4472 w = xg_win_to_widget (dpy, wid);
4473
4474 if (w)
4475 {
4476 for (idx = 0; idx < id_to_widget.max_size; ++idx)
4477 if (id_to_widget.widgets[idx] == w)
4478 return idx;
4479 }
4480
4481 return -1;
4482 }
4483 #endif
4484
4485
4486
4487
4488
4489 #if !defined HAVE_GTK3 || defined HAVE_PGTK
4490 static void
4491 xg_gtk_scroll_destroy (GtkWidget *widget, gpointer data)
4492 {
4493 intptr_t id = (intptr_t) data;
4494 xg_remove_widget_from_map (id);
4495 }
4496 #endif
4497
4498 #if defined HAVE_GTK3 && !defined HAVE_PGTK
4499 static void
4500 xg_scroll_bar_size_allocate_cb (GtkWidget *widget,
4501 GdkRectangle *allocation,
4502 gpointer user_data)
4503 {
4504 GdkEvent *event = gtk_get_current_event ();
4505 GdkEvent dummy;
4506
4507 if (event && event->any.type == GDK_CONFIGURE)
4508 x_scroll_bar_configure (event);
4509 else
4510 {
4511
4512 dummy.configure.send_event = FALSE;
4513 dummy.configure.x = allocation->x;
4514 dummy.configure.y = allocation->y;
4515 dummy.configure.width = allocation->width;
4516 dummy.configure.height = allocation->height;
4517 dummy.configure.window = gtk_widget_get_window (widget);
4518
4519 x_scroll_bar_configure (&dummy);
4520 }
4521 }
4522 #endif
4523
4524 static void
4525 xg_finish_scroll_bar_creation (struct frame *f,
4526 GtkWidget *wscroll,
4527 struct scroll_bar *bar,
4528 GCallback scroll_callback,
4529 GCallback end_callback,
4530 const char *scroll_bar_name)
4531 {
4532 GtkWidget *webox = gtk_event_box_new ();
4533 #ifdef HAVE_GTK3
4534 GtkCssProvider *foreground_provider;
4535 GtkCssProvider *background_provider;
4536 #endif
4537
4538 gtk_widget_set_name (wscroll, scroll_bar_name);
4539 #ifndef HAVE_GTK3
4540 gtk_range_set_update_policy (GTK_RANGE (wscroll), GTK_UPDATE_CONTINUOUS);
4541 #endif
4542 g_object_set_data (G_OBJECT (wscroll), XG_FRAME_DATA, (gpointer) f);
4543
4544 #if defined HAVE_GTK3 && !defined HAVE_PGTK
4545 g_signal_connect (G_OBJECT (webox), "size-allocate",
4546 G_CALLBACK (xg_scroll_bar_size_allocate_cb),
4547 NULL);
4548 #endif
4549
4550 #if defined HAVE_PGTK || !defined HAVE_GTK3
4551 ptrdiff_t scroll_id = xg_store_widget_in_map (wscroll);
4552
4553 g_signal_connect (G_OBJECT (wscroll),
4554 "destroy",
4555 G_CALLBACK (xg_gtk_scroll_destroy),
4556 (gpointer) scroll_id);
4557 #endif
4558
4559 g_signal_connect (G_OBJECT (wscroll),
4560 "change-value",
4561 scroll_callback,
4562 (gpointer) bar);
4563 g_signal_connect (G_OBJECT (wscroll),
4564 "button-release-event",
4565 end_callback,
4566 (gpointer) bar);
4567
4568
4569
4570
4571
4572
4573
4574 gtk_fixed_put (GTK_FIXED (f->output_data.xp->edit_widget), webox, -1, -1);
4575 gtk_container_add (GTK_CONTAINER (webox), wscroll);
4576
4577 xg_set_widget_bg (f, webox, FRAME_BACKGROUND_PIXEL (f));
4578
4579
4580
4581
4582
4583 gtk_widget_realize (webox);
4584 #ifdef HAVE_PGTK
4585 gtk_widget_show_all (webox);
4586 #elif defined HAVE_GTK3
4587 bar->x_window = GTK_WIDGET_TO_X_WIN (webox);
4588 gtk_widget_show_all (webox);
4589 #else
4590 GTK_WIDGET_TO_X_WIN (webox);
4591 #endif
4592
4593
4594 xg_set_cursor (webox, FRAME_DISPLAY_INFO (f)->xg_cursor);
4595
4596 #ifdef HAVE_GTK3
4597 GtkStyleContext *ctxt = gtk_widget_get_style_context (wscroll);
4598 foreground_provider = FRAME_OUTPUT_DATA (f)->scrollbar_foreground_css_provider;
4599 background_provider = FRAME_OUTPUT_DATA (f)->scrollbar_background_css_provider;
4600
4601 gtk_style_context_add_provider (ctxt, GTK_STYLE_PROVIDER (foreground_provider),
4602 GTK_STYLE_PROVIDER_PRIORITY_USER);
4603 gtk_style_context_add_provider (ctxt, GTK_STYLE_PROVIDER (background_provider),
4604 GTK_STYLE_PROVIDER_PRIORITY_USER);
4605
4606 #ifndef HAVE_PGTK
4607 gtk_widget_add_events (webox, GDK_STRUCTURE_MASK);
4608 gtk_widget_set_double_buffered (wscroll, FALSE);
4609 #endif
4610 #endif
4611
4612 #if defined HAVE_PGTK || !defined HAVE_GTK3
4613 bar->x_window = scroll_id;
4614 #endif
4615 }
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625 void
4626 xg_create_scroll_bar (struct frame *f,
4627 struct scroll_bar *bar,
4628 GCallback scroll_callback,
4629 GCallback end_callback,
4630 const char *scroll_bar_name)
4631 {
4632 GtkWidget *wscroll;
4633 #ifdef HAVE_GTK3
4634 GtkAdjustment *vadj;
4635 #else
4636 GtkObject *vadj;
4637 #endif
4638
4639
4640
4641 vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX,
4642 0.1, 0.1, 0.1);
4643
4644 wscroll = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT (vadj));
4645
4646 xg_finish_scroll_bar_creation (f, wscroll, bar, scroll_callback,
4647 end_callback, scroll_bar_name);
4648 bar->horizontal = 0;
4649 }
4650
4651
4652
4653
4654
4655
4656
4657 void
4658 xg_create_horizontal_scroll_bar (struct frame *f,
4659 struct scroll_bar *bar,
4660 GCallback scroll_callback,
4661 GCallback end_callback,
4662 const char *scroll_bar_name)
4663 {
4664 GtkWidget *wscroll;
4665 #ifdef HAVE_GTK3
4666 GtkAdjustment *hadj;
4667 #else
4668 GtkObject *hadj;
4669 #endif
4670
4671
4672
4673 hadj = gtk_adjustment_new (YG_SB_MIN, YG_SB_MIN, YG_SB_MAX,
4674 0.1, 0.1, 0.1);
4675
4676 wscroll = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (hadj));
4677
4678 xg_finish_scroll_bar_creation (f, wscroll, bar, scroll_callback,
4679 end_callback, scroll_bar_name);
4680 bar->horizontal = 1;
4681 }
4682
4683
4684
4685 void
4686 xg_remove_scroll_bar (struct frame *f, ptrdiff_t scrollbar_id)
4687 {
4688 GtkWidget *w = xg_get_widget_from_map (scrollbar_id,
4689 FRAME_X_DISPLAY (f));
4690 if (w)
4691 {
4692 GtkWidget *wparent = gtk_widget_get_parent (w);
4693 gtk_widget_destroy (w);
4694 gtk_widget_destroy (wparent);
4695 SET_FRAME_GARBAGED (f);
4696 }
4697 }
4698
4699
4700
4701
4702
4703
4704 void
4705 xg_update_scrollbar_pos (struct frame *f,
4706 ptrdiff_t scrollbar_id,
4707 int top,
4708 int left,
4709 int width,
4710 int height)
4711 {
4712 GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id,
4713 FRAME_X_DISPLAY (f));
4714 if (wscroll)
4715 {
4716 GtkWidget *wfixed = f->output_data.xp->edit_widget;
4717 GtkWidget *wparent = gtk_widget_get_parent (wscroll);
4718 #if !defined HAVE_PGTK && defined HAVE_GTK3
4719 GdkWindow *wdesc = gtk_widget_get_window (wparent);
4720 #endif
4721 gint msl;
4722 int scale = xg_get_scale (f);
4723
4724 top /= scale;
4725 left /= scale;
4726 height /= scale;
4727 width /= scale;
4728
4729
4730 int oldx = -1, oldy = -1, oldw, oldh;
4731 if (gtk_widget_get_parent (wparent) == wfixed)
4732 {
4733 gtk_container_child_get (GTK_CONTAINER (wfixed), wparent,
4734 "x", &oldx, "y", &oldy, NULL);
4735 gtk_widget_get_size_request (wscroll, &oldw, &oldh);
4736 }
4737
4738
4739 gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top);
4740 gtk_widget_style_get (wscroll, "min-slider-length", &msl, NULL);
4741 bool hidden = height < msl;
4742 if (hidden)
4743 {
4744
4745
4746 gtk_widget_hide (wparent);
4747 gtk_widget_hide (wscroll);
4748 }
4749 else
4750 {
4751 gtk_widget_show_all (wparent);
4752 gtk_widget_set_size_request (wscroll, width, height);
4753
4754 #if !defined HAVE_PGTK && defined HAVE_GTK3
4755 if (wdesc)
4756 {
4757 gdk_window_move_resize (wdesc, left, top, width, height);
4758 #if GTK_CHECK_VERSION (3, 20, 0)
4759 gtk_widget_queue_allocate (wparent);
4760 #endif
4761 }
4762 #endif
4763 }
4764
4765 if (oldx != -1 && oldw > 0 && oldh > 0)
4766 {
4767
4768 oldw += (scale - 1) * oldw;
4769 oldx -= (scale - 1) * oldw;
4770 #ifndef HAVE_PGTK
4771 x_clear_area (f, oldx, oldy, oldw, oldh);
4772 #else
4773 pgtk_clear_area (f, oldx, oldy, oldw, oldh);
4774 #endif
4775 }
4776
4777 if (!hidden)
4778 {
4779 GtkWidget *scrollbar = xg_get_widget_from_map (scrollbar_id,
4780 FRAME_X_DISPLAY (f));
4781 GtkWidget *webox = gtk_widget_get_parent (scrollbar);
4782
4783 #ifndef HAVE_PGTK
4784
4785 XLowerWindow (FRAME_X_DISPLAY (f), GTK_WIDGET_TO_X_WIN (webox));
4786 #else
4787 gdk_window_lower (gtk_widget_get_window (webox));
4788 #endif
4789 }
4790
4791
4792
4793
4794
4795 #ifndef HAVE_PGTK
4796 XSync (FRAME_X_DISPLAY (f), False);
4797 #else
4798 gdk_flush ();
4799 #endif
4800 SET_FRAME_GARBAGED (f);
4801 cancel_mouse_face (f);
4802 }
4803 }
4804
4805
4806
4807
4808
4809
4810
4811 void
4812 xg_update_horizontal_scrollbar_pos (struct frame *f,
4813 ptrdiff_t scrollbar_id,
4814 int top,
4815 int left,
4816 int width,
4817 int height)
4818 {
4819 GtkWidget *wscroll = xg_get_widget_from_map (scrollbar_id,
4820 FRAME_X_DISPLAY (f));
4821
4822 if (wscroll)
4823 {
4824 GtkWidget *wfixed = f->output_data.xp->edit_widget;
4825 GtkWidget *wparent = gtk_widget_get_parent (wscroll);
4826 #if !defined HAVE_PGTK && defined HAVE_GTK3
4827 GdkWindow *wdesc = gtk_widget_get_window (wparent);
4828 #endif
4829 gint msl;
4830 int scale = xg_get_scale (f);
4831
4832 top /= scale;
4833 left /= scale;
4834 height /= scale;
4835 width /= scale;
4836
4837
4838 int oldx = -1, oldy = -1, oldw, oldh;
4839 if (gtk_widget_get_parent (wparent) == wfixed)
4840 {
4841 gtk_container_child_get (GTK_CONTAINER (wfixed), wparent,
4842 "x", &oldx, "y", &oldy, NULL);
4843 gtk_widget_get_size_request (wscroll, &oldw, &oldh);
4844 }
4845
4846
4847 gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top);
4848 gtk_widget_style_get (wscroll, "min-slider-length", &msl, NULL);
4849 if (msl > width)
4850 {
4851
4852
4853 gtk_widget_hide (wparent);
4854 gtk_widget_hide (wscroll);
4855 }
4856 else
4857 {
4858 gtk_widget_show_all (wparent);
4859 gtk_widget_set_size_request (wscroll, width, height);
4860
4861 #if !defined HAVE_PGTK && defined HAVE_GTK3
4862 if (wdesc)
4863 {
4864 gdk_window_move_resize (wdesc, left, top, width, height);
4865 #if GTK_CHECK_VERSION (3, 20, 0)
4866 gtk_widget_queue_allocate (wparent);
4867 #endif
4868 }
4869 #endif
4870 }
4871 if (oldx != -1 && oldw > 0 && oldh > 0)
4872
4873 #ifndef HAVE_PGTK
4874 x_clear_area (f, oldx, oldy, oldw, oldh);
4875 #else
4876 pgtk_clear_area (f, oldx, oldy, oldw, oldh);
4877 #endif
4878
4879
4880
4881
4882
4883 {
4884 GtkWidget *scrollbar =
4885 xg_get_widget_from_map (scrollbar_id, FRAME_X_DISPLAY (f));
4886 GtkWidget *webox = gtk_widget_get_parent (scrollbar);
4887
4888 #ifndef HAVE_PGTK
4889
4890 XLowerWindow (FRAME_X_DISPLAY (f), GTK_WIDGET_TO_X_WIN (webox));
4891 #else
4892 gdk_window_lower (gtk_widget_get_window (webox));
4893 #endif
4894 }
4895
4896 #ifndef HAVE_PGTK
4897 XSync (FRAME_X_DISPLAY (f), False);
4898 #else
4899 gdk_flush ();
4900 #endif
4901 SET_FRAME_GARBAGED (f);
4902 cancel_mouse_face (f);
4903 }
4904 }
4905
4906
4907
4908
4909 static int
4910 int_gtk_range_get_value (GtkRange *range)
4911 {
4912 return gtk_range_get_value (range);
4913 }
4914
4915
4916
4917
4918
4919 void
4920 xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar,
4921 int portion,
4922 int position,
4923 int whole)
4924 {
4925 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
4926 GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window,
4927 FRAME_X_DISPLAY (f));
4928
4929
4930 if (wscroll && bar->dragging == -1)
4931 {
4932 GtkAdjustment *adj;
4933 gdouble shown;
4934 gdouble top;
4935 int size, value;
4936 int old_size;
4937 int new_step;
4938 bool changed = 0;
4939
4940 adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
4941
4942 if (scroll_bar_adjust_thumb_portion_p)
4943 {
4944
4945
4946
4947 portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
4948
4949
4950
4951 whole += portion;
4952 }
4953
4954 if (whole <= 0)
4955 top = 0, shown = 1;
4956 else
4957 {
4958 top = (gdouble) position / whole;
4959 shown = (gdouble) portion / whole;
4960 }
4961
4962 size = clip_to_bounds (1, shown * XG_SB_RANGE, XG_SB_RANGE);
4963 value = clip_to_bounds (XG_SB_MIN, top * XG_SB_RANGE, XG_SB_MAX - size);
4964
4965
4966 new_step = size / max (1, FRAME_LINES (f));
4967
4968 old_size = gtk_adjustment_get_page_size (adj);
4969 if (old_size != size)
4970 {
4971 int old_step = gtk_adjustment_get_step_increment (adj);
4972 if (old_step != new_step)
4973 {
4974 gtk_adjustment_set_page_size (adj, size);
4975 gtk_adjustment_set_step_increment (adj, new_step);
4976
4977 gtk_adjustment_set_page_increment (adj, size - size / 20);
4978 changed = 1;
4979 }
4980 }
4981
4982 if (changed || int_gtk_range_get_value (GTK_RANGE (wscroll)) != value)
4983 {
4984 block_input ();
4985
4986
4987
4988 xg_ignore_gtk_scrollbar = 1;
4989
4990 if (int_gtk_range_get_value (GTK_RANGE (wscroll)) != value)
4991 gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value);
4992 #if ! GTK_CHECK_VERSION (3, 18, 0)
4993 else if (changed)
4994 gtk_adjustment_changed (adj);
4995 #endif
4996
4997 xg_ignore_gtk_scrollbar = 0;
4998
4999 unblock_input ();
5000 }
5001 }
5002 }
5003
5004
5005
5006
5007 void
5008 xg_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar,
5009 int portion,
5010 int position,
5011 int whole)
5012 {
5013 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
5014 GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window,
5015 FRAME_X_DISPLAY (f));
5016
5017 if (wscroll && bar->dragging == -1)
5018 {
5019 GtkAdjustment *adj;
5020 int lower = 0;
5021 int upper = max (whole - 1, 0);
5022 int pagesize = min (upper, max (portion, 0));
5023 int value = max (0, min (position, upper - pagesize));
5024
5025
5026 int page_increment = 4;
5027 int step_increment = 1;
5028
5029 block_input ();
5030 adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
5031 gtk_adjustment_configure (adj, (gdouble) value, (gdouble) lower,
5032 (gdouble) upper, (gdouble) step_increment,
5033 (gdouble) page_increment, (gdouble) pagesize);
5034 #if ! GTK_CHECK_VERSION (3, 18, 0)
5035 gtk_adjustment_changed (adj);
5036 #endif
5037 unblock_input ();
5038 }
5039 }
5040
5041
5042
5043
5044
5045
5046 bool
5047 xg_event_is_for_scrollbar (struct frame *f, const EVENT *event,
5048 bool for_valuator)
5049 {
5050 bool retval = 0;
5051
5052 #ifdef HAVE_XINPUT2
5053 XIDeviceEvent *xev = (XIDeviceEvent *) event->xcookie.data;
5054 if (f && ((FRAME_DISPLAY_INFO (f)->supports_xi2
5055 && event->type == GenericEvent
5056 && (event->xgeneric.extension
5057 == FRAME_DISPLAY_INFO (f)->xi2_opcode)
5058 && (event->xgeneric.evtype == XI_ButtonPress
5059 && xev->detail < 4))
5060 || (event->type == ButtonPress
5061 && event->xbutton.button < 4)
5062 || for_valuator))
5063 #else
5064 if (f
5065 #ifndef HAVE_PGTK
5066 && event->type == ButtonPress && event->xbutton.button < 4
5067 #else
5068 && event->type == GDK_BUTTON_PRESS && event->button.button < 4
5069 #endif
5070 )
5071 #endif
5072 {
5073
5074 #ifndef HAVE_PGTK
5075 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
5076 #else
5077 GdkDisplay *gdpy = FRAME_X_DISPLAY (f);
5078 #endif
5079 GdkWindow *gwin;
5080 #ifdef HAVE_GTK3
5081 #if GTK_CHECK_VERSION (3, 20, 0)
5082 GdkDevice *gdev
5083 = gdk_seat_get_pointer (gdk_display_get_default_seat (gdpy));
5084 #else
5085 GdkDevice *gdev = gdk_device_manager_get_client_pointer
5086 (gdk_display_get_device_manager (gdpy));
5087 #endif
5088 gwin = gdk_device_get_window_at_position (gdev, NULL, NULL);
5089 #else
5090 gwin = gdk_display_get_window_at_pointer (gdpy, NULL, NULL);
5091 #endif
5092 retval = gwin != gtk_widget_get_window (f->output_data.xp->edit_widget);
5093 }
5094 #ifdef HAVE_XINPUT2
5095 else if (f && ((FRAME_DISPLAY_INFO (f)->supports_xi2
5096 && event->type == GenericEvent
5097 && (event->xgeneric.extension
5098 == FRAME_DISPLAY_INFO (f)->xi2_opcode)
5099 && ((event->xgeneric.evtype == XI_ButtonRelease
5100 && xev->detail < 4)
5101 || (event->xgeneric.evtype == XI_Motion)))
5102 || ((event->type == ButtonRelease
5103 && event->xbutton.button < 4)
5104 || event->type == MotionNotify)))
5105 #else
5106 else if (f
5107 #ifndef HAVE_PGTK
5108 && ((event->type == ButtonRelease && event->xbutton.button < 4)
5109 || event->type == MotionNotify)
5110 #else
5111 && ((event->type == GDK_BUTTON_RELEASE && event->button.button < 4)
5112 || event->type == GDK_MOTION_NOTIFY)
5113 #endif
5114 )
5115 #endif
5116 {
5117
5118 GtkWidget *w = gtk_grab_get_current ();
5119 retval = w != 0 && GTK_IS_SCROLLBAR (w);
5120 }
5121
5122 return retval;
5123 }
5124
5125
5126
5127
5128
5129 #ifdef USE_CAIRO
5130 static GtkPrintSettings *print_settings = NULL;
5131 static GtkPageSetup *page_setup = NULL;
5132
5133 void
5134 xg_page_setup_dialog (void)
5135 {
5136 GtkPageSetup *new_page_setup = NULL;
5137
5138 if (print_settings == NULL)
5139 print_settings = gtk_print_settings_new ();
5140 new_page_setup = gtk_print_run_page_setup_dialog (NULL, page_setup,
5141 print_settings);
5142 if (page_setup)
5143 g_object_unref (page_setup);
5144 page_setup = new_page_setup;
5145 }
5146
5147 Lisp_Object
5148 xg_get_page_setup (void)
5149 {
5150 Lisp_Object orientation_symbol;
5151
5152 if (page_setup == NULL)
5153 page_setup = gtk_page_setup_new ();
5154
5155 switch (gtk_page_setup_get_orientation (page_setup))
5156 {
5157 case GTK_PAGE_ORIENTATION_PORTRAIT:
5158 orientation_symbol = Qportrait;
5159 break;
5160 case GTK_PAGE_ORIENTATION_LANDSCAPE:
5161 orientation_symbol = Qlandscape;
5162 break;
5163 case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
5164 orientation_symbol = Qreverse_portrait;
5165 break;
5166 case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
5167 orientation_symbol = Qreverse_landscape;
5168 break;
5169 default:
5170 eassume (false);
5171 }
5172
5173 #define GETSETUP(f) make_float (f (page_setup, GTK_UNIT_POINTS))
5174 return
5175 list (Fcons (Qorientation, orientation_symbol),
5176 Fcons (Qwidth, GETSETUP (gtk_page_setup_get_page_width)),
5177 Fcons (Qheight, GETSETUP (gtk_page_setup_get_page_height)),
5178 Fcons (Qleft_margin, GETSETUP (gtk_page_setup_get_left_margin)),
5179 Fcons (Qright_margin, GETSETUP (gtk_page_setup_get_right_margin)),
5180 Fcons (Qtop_margin, GETSETUP (gtk_page_setup_get_top_margin)),
5181 Fcons (Qbottom_margin, GETSETUP (gtk_page_setup_get_bottom_margin)));
5182 #undef GETSETUP
5183 }
5184
5185 static void
5186 draw_page (GtkPrintOperation *operation, GtkPrintContext *context,
5187 gint page_nr, gpointer user_data)
5188 {
5189 Lisp_Object frames = *((Lisp_Object *) user_data);
5190 struct frame *f = XFRAME (Fnth (make_fixnum (page_nr), frames));
5191 cairo_t *cr = gtk_print_context_get_cairo_context (context);
5192
5193 #ifndef HAVE_PGTK
5194 x_cr_draw_frame (cr, f);
5195 #else
5196 pgtk_cr_draw_frame (cr, f);
5197 #endif
5198 }
5199
5200 void
5201 xg_print_frames_dialog (Lisp_Object frames)
5202 {
5203 GtkPrintOperation *print;
5204 GtkPrintOperationResult res;
5205
5206 print = gtk_print_operation_new ();
5207 if (print_settings != NULL)
5208 gtk_print_operation_set_print_settings (print, print_settings);
5209 if (page_setup != NULL)
5210 gtk_print_operation_set_default_page_setup (print, page_setup);
5211 gtk_print_operation_set_n_pages (print, list_length (frames));
5212 g_signal_connect (print, "draw-page", G_CALLBACK (draw_page), &frames);
5213 res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
5214 NULL, NULL);
5215 if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
5216 {
5217 if (print_settings != NULL)
5218 g_object_unref (print_settings);
5219 print_settings =
5220 g_object_ref (gtk_print_operation_get_print_settings (print));
5221 }
5222 g_object_unref (print);
5223 }
5224
5225 #endif
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235 #define XG_TOOL_BAR_IMAGE_DATA "emacs-tool-bar-image"
5236
5237
5238
5239 #define XG_TOOL_BAR_LAST_MODIFIER "emacs-tool-bar-modifier"
5240
5241
5242
5243
5244 #define XG_TOOL_BAR_STOCK_NAME "emacs-tool-bar-stock-name"
5245
5246
5247
5248 #define XG_TOOL_BAR_ICON_NAME "emacs-tool-bar-icon-name"
5249
5250
5251
5252
5253
5254
5255 static gboolean
5256 xg_tool_bar_button_cb (GtkWidget *widget,
5257 GdkEventButton *event,
5258 gpointer user_data)
5259 {
5260 intptr_t state = event->state;
5261 gpointer ptr = (gpointer) state;
5262 g_object_set_data (G_OBJECT (widget), XG_TOOL_BAR_LAST_MODIFIER, ptr);
5263 return FALSE;
5264 }
5265
5266
5267
5268
5269
5270
5271
5272 static void
5273 xg_tool_bar_callback (GtkWidget *w, gpointer client_data)
5274 {
5275 intptr_t idx = (intptr_t) client_data;
5276 gpointer gmod = g_object_get_data (G_OBJECT (w), XG_TOOL_BAR_LAST_MODIFIER);
5277 intptr_t mod = (intptr_t) gmod;
5278
5279 struct frame *f = g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
5280 Lisp_Object key, frame;
5281 struct input_event event;
5282 EVENT_INIT (event);
5283
5284 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
5285 return;
5286
5287 idx *= TOOL_BAR_ITEM_NSLOTS;
5288
5289 key = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_KEY);
5290 XSETFRAME (frame, f);
5291
5292 event.kind = TOOL_BAR_EVENT;
5293 event.frame_or_window = frame;
5294 event.arg = key;
5295
5296
5297
5298 #ifndef HAVE_PGTK
5299 event.modifiers = x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), mod);
5300 #else
5301 event.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), mod);
5302 #endif
5303 kbd_buffer_store_event (&event);
5304
5305
5306
5307 FRAME_TERMINAL (f)->focus_frame_hook (f, false);
5308 }
5309
5310 static GtkWidget *
5311 xg_get_tool_bar_widgets (GtkWidget *vb, GtkWidget **wimage)
5312 {
5313 GList *clist = gtk_container_get_children (GTK_CONTAINER (vb));
5314 GtkWidget *c1 = clist->data;
5315 GtkWidget *c2 = clist->next ? clist->next->data : NULL;
5316
5317 *wimage = GTK_IS_IMAGE (c1) ? c1 : c2;
5318 g_list_free (clist);
5319 return GTK_IS_LABEL (c1) ? c1 : c2;
5320 }
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332 static gboolean
5333 xg_tool_bar_help_callback (GtkWidget *w,
5334 GdkEventCrossing *event,
5335 gpointer client_data)
5336 {
5337 intptr_t idx = (intptr_t) client_data;
5338 struct frame *f = g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
5339 Lisp_Object help, frame;
5340
5341 if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
5342 return FALSE;
5343
5344 if (event->type == GDK_ENTER_NOTIFY)
5345 {
5346 idx *= TOOL_BAR_ITEM_NSLOTS;
5347 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_HELP);
5348
5349 if (NILP (help))
5350 help = AREF (f->tool_bar_items, idx + TOOL_BAR_ITEM_CAPTION);
5351 }
5352 else
5353 help = Qnil;
5354
5355 XSETFRAME (frame, f);
5356 kbd_buffer_store_help_event (frame, help);
5357
5358 return FALSE;
5359 }
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372 #ifndef HAVE_GTK3
5373 static gboolean
5374 xg_tool_bar_item_expose_callback (GtkWidget *w,
5375 GdkEventExpose *event,
5376 gpointer client_data)
5377 {
5378 gint width, height;
5379
5380 gdk_drawable_get_size (event->window, &width, &height);
5381 event->area.x -= width > event->area.width ? width-event->area.width : 0;
5382 event->area.y -= height > event->area.height ? height-event->area.height : 0;
5383
5384 event->area.x = max (0, event->area.x);
5385 event->area.y = max (0, event->area.y);
5386
5387 event->area.width = max (width, event->area.width);
5388 event->area.height = max (height, event->area.height);
5389
5390 return FALSE;
5391 }
5392 #endif
5393
5394
5395
5396 static void
5397 xg_pack_tool_bar (struct frame *f, Lisp_Object pos)
5398 {
5399 xp_output *x = f->output_data.xp;
5400 bool into_hbox = EQ (pos, Qleft) || EQ (pos, Qright);
5401 GtkWidget *top_widget = x->toolbar_widget;
5402
5403 gtk_orientable_set_orientation (GTK_ORIENTABLE (x->toolbar_widget),
5404 into_hbox
5405 ? GTK_ORIENTATION_VERTICAL
5406 : GTK_ORIENTATION_HORIZONTAL);
5407
5408 if (into_hbox)
5409 {
5410 gtk_box_pack_start (GTK_BOX (x->hbox_widget), top_widget,
5411 FALSE, FALSE, 0);
5412
5413 if (EQ (pos, Qleft))
5414 gtk_box_reorder_child (GTK_BOX (x->hbox_widget),
5415 top_widget,
5416 0);
5417 x->toolbar_in_hbox = true;
5418 }
5419 else
5420 {
5421 bool vbox_pos = x->menubar_widget != 0;
5422 gtk_box_pack_start (GTK_BOX (x->vbox_widget), top_widget,
5423 FALSE, FALSE, 0);
5424
5425 if (EQ (pos, Qtop))
5426 gtk_box_reorder_child (GTK_BOX (x->vbox_widget),
5427 top_widget,
5428 vbox_pos);
5429 x->toolbar_in_hbox = false;
5430 }
5431 x->toolbar_is_packed = true;
5432 }
5433
5434 static bool xg_update_tool_bar_sizes (struct frame *f);
5435
5436 static void
5437 tb_size_cb (GtkWidget *widget,
5438 GdkRectangle *allocation,
5439 gpointer user_data)
5440 {
5441
5442
5443
5444 struct frame *f = user_data;
5445
5446 if (xg_update_tool_bar_sizes (f))
5447 adjust_frame_size (f, -1, -1, 2, false, Qtool_bar_lines);
5448 }
5449
5450
5451
5452 static void
5453 xg_create_tool_bar (struct frame *f)
5454 {
5455 xp_output *x = f->output_data.xp;
5456 #ifdef HAVE_GTK3
5457 GtkStyleContext *gsty;
5458 #endif
5459 struct xg_frame_tb_info *tbinfo
5460 = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
5461 TB_INFO_KEY);
5462 if (! tbinfo)
5463 {
5464 tbinfo = xmalloc (sizeof (*tbinfo));
5465 tbinfo->last_tool_bar = Qnil;
5466 tbinfo->style = Qnil;
5467 tbinfo->hmargin = tbinfo->vmargin = 0;
5468 tbinfo->dir = GTK_TEXT_DIR_NONE;
5469 tbinfo->n_last_items = 0;
5470 g_object_set_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
5471 TB_INFO_KEY,
5472 tbinfo);
5473 }
5474
5475 x->toolbar_widget = gtk_toolbar_new ();
5476
5477 gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
5478
5479 gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
5480 gtk_orientable_set_orientation (GTK_ORIENTABLE (x->toolbar_widget),
5481 GTK_ORIENTATION_HORIZONTAL);
5482 g_signal_connect (x->toolbar_widget, "size-allocate",
5483 G_CALLBACK (tb_size_cb), f);
5484 #ifdef HAVE_GTK3
5485 gsty = gtk_widget_get_style_context (x->toolbar_widget);
5486 gtk_style_context_add_class (gsty, "primary-toolbar");
5487 #endif
5488 }
5489
5490
5491 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
5492
5493
5494
5495
5496 static Lisp_Object
5497 find_rtl_image (struct frame *f, Lisp_Object image, Lisp_Object rtl)
5498 {
5499 int i;
5500 Lisp_Object file, rtl_name;
5501
5502 rtl_name = Ffile_name_nondirectory (rtl);
5503
5504 for (i = 0; i < f->n_tool_bar_items; ++i)
5505 {
5506 Lisp_Object rtl_image = PROP (TOOL_BAR_ITEM_IMAGES);
5507 if (!NILP (file = file_for_image (rtl_image)))
5508 {
5509 file = call1 (intern ("file-name-sans-extension"),
5510 Ffile_name_nondirectory (file));
5511 if (! NILP (Fequal (file, rtl_name)))
5512 {
5513 image = rtl_image;
5514 break;
5515 }
5516 }
5517 }
5518
5519 return image;
5520 }
5521
5522 static GtkToolItem *
5523 xg_make_tool_item (struct frame *f,
5524 GtkWidget *wimage,
5525 GtkWidget **wbutton,
5526 const char *label,
5527 int i, bool horiz, bool text_image)
5528 {
5529 GtkToolItem *ti = gtk_tool_item_new ();
5530 GtkWidget *vb = gtk_box_new (horiz
5531 ? GTK_ORIENTATION_HORIZONTAL
5532 : GTK_ORIENTATION_VERTICAL,
5533 0);
5534 GtkWidget *wb = gtk_button_new ();
5535
5536 GtkWidget *weventbox = gtk_event_box_new ();
5537 #ifdef HAVE_GTK3
5538 GtkCssProvider *css_prov = gtk_css_provider_new ();
5539 GtkStyleContext *gsty;
5540
5541 gtk_css_provider_load_from_data (css_prov,
5542 "GtkEventBox {"
5543 " background-color: transparent;"
5544 "}",
5545 -1, NULL);
5546
5547 gsty = gtk_widget_get_style_context (weventbox);
5548 gtk_style_context_add_provider (gsty,
5549 GTK_STYLE_PROVIDER (css_prov),
5550 GTK_STYLE_PROVIDER_PRIORITY_USER);
5551 g_object_unref (css_prov);
5552 #endif
5553
5554 gtk_box_set_homogeneous (GTK_BOX (vb), FALSE);
5555
5556 if (wimage && !text_image)
5557 gtk_box_pack_start (GTK_BOX (vb), wimage, TRUE, TRUE, 0);
5558 if (label)
5559 gtk_box_pack_start (GTK_BOX (vb), gtk_label_new (label), TRUE, TRUE, 0);
5560 if (wimage && text_image)
5561 gtk_box_pack_start (GTK_BOX (vb), wimage, TRUE, TRUE, 0);
5562
5563 #if GTK_CHECK_VERSION (3, 20, 0)
5564 gtk_widget_set_focus_on_click (wb, FALSE);
5565 #else
5566 gtk_button_set_focus_on_click (GTK_BUTTON (wb), FALSE);
5567 #endif
5568 gtk_button_set_relief (GTK_BUTTON (wb), GTK_RELIEF_NONE);
5569 gtk_container_add (GTK_CONTAINER (wb), vb);
5570 gtk_container_add (GTK_CONTAINER (weventbox), wb);
5571 gtk_container_add (GTK_CONTAINER (ti), weventbox);
5572
5573 if (wimage || label)
5574 {
5575 intptr_t ii = i;
5576 gpointer gi = (gpointer) ii;
5577
5578 g_signal_connect (G_OBJECT (wb), "clicked",
5579 G_CALLBACK (xg_tool_bar_callback),
5580 gi);
5581
5582 g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f);
5583
5584 #ifndef HAVE_GTK3
5585
5586
5587 g_signal_connect (G_OBJECT (ti),
5588 "expose-event",
5589 G_CALLBACK (xg_tool_bar_item_expose_callback),
5590 0);
5591 #endif
5592 gtk_tool_item_set_homogeneous (ti, FALSE);
5593
5594
5595
5596
5597 g_signal_connect (wb, "button-release-event",
5598 G_CALLBACK (xg_tool_bar_button_cb),
5599 NULL);
5600
5601 g_object_set_data (G_OBJECT (wb), XG_FRAME_DATA, (gpointer)f);
5602
5603
5604
5605
5606
5607 g_signal_connect (G_OBJECT (weventbox),
5608 "enter-notify-event",
5609 G_CALLBACK (xg_tool_bar_help_callback),
5610 gi);
5611 g_signal_connect (G_OBJECT (weventbox),
5612 "leave-notify-event",
5613 G_CALLBACK (xg_tool_bar_help_callback),
5614 gi);
5615 }
5616
5617 if (wbutton) *wbutton = wb;
5618
5619 return ti;
5620 }
5621
5622 static bool
5623 is_box_type (GtkWidget *vb, bool is_horizontal)
5624 {
5625 #ifdef HAVE_GTK3
5626 bool ret = 0;
5627 if (GTK_IS_BOX (vb))
5628 {
5629 GtkOrientation ori = gtk_orientable_get_orientation (GTK_ORIENTABLE (vb));
5630 ret = (ori == GTK_ORIENTATION_HORIZONTAL && is_horizontal)
5631 || (ori == GTK_ORIENTATION_VERTICAL && ! is_horizontal);
5632 }
5633 return ret;
5634 #else
5635 return is_horizontal ? GTK_IS_VBOX (vb) : GTK_IS_HBOX (vb);
5636 #endif
5637 }
5638
5639
5640 static bool
5641 xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name,
5642 const char *icon_name, const struct image *img,
5643 const char *label, bool horiz)
5644 {
5645 gpointer old;
5646 GtkWidget *wimage;
5647 GtkWidget *vb = XG_BIN_CHILD (wbutton);
5648 GtkWidget *wlbl = xg_get_tool_bar_widgets (vb, &wimage);
5649
5650
5651 if (stock_name && wimage)
5652 {
5653 old = g_object_get_data (G_OBJECT (wimage),
5654 XG_TOOL_BAR_STOCK_NAME);
5655 if (!old || strcmp (old, stock_name))
5656 return 1;
5657 }
5658 else if (icon_name && wimage)
5659 {
5660 old = g_object_get_data (G_OBJECT (wimage),
5661 XG_TOOL_BAR_ICON_NAME);
5662 if (!old || strcmp (old, icon_name))
5663 return 1;
5664 }
5665 else if (wimage)
5666 {
5667 gpointer gold_img = g_object_get_data (G_OBJECT (wimage),
5668 XG_TOOL_BAR_IMAGE_DATA);
5669 #ifdef USE_CAIRO
5670 void *old_img = (void *) gold_img;
5671 if (old_img != img->cr_data)
5672 return 1;
5673 #else
5674 Pixmap old_img = (Pixmap) gold_img;
5675 if (old_img != img->pixmap)
5676 return 1;
5677 #endif
5678 }
5679
5680
5681 if (is_box_type (vb, horiz)
5682 || (label ? (wlbl == NULL) : (wlbl != NULL)))
5683 return 1;
5684
5685
5686 if (label && wlbl)
5687 gtk_label_set_text (GTK_LABEL (wlbl), label);
5688 return 0;
5689 }
5690
5691 static bool
5692 xg_update_tool_bar_sizes (struct frame *f)
5693 {
5694 xp_output *x = f->output_data.xp;
5695 GtkRequisition req;
5696 int nl = 0, nr = 0, nt = 0, nb = 0;
5697 GtkWidget *top_widget = x->toolbar_widget;
5698 int scale = xg_get_scale (f);
5699
5700 gtk_widget_get_preferred_size (GTK_WIDGET (top_widget), NULL, &req);
5701 if (x->toolbar_in_hbox)
5702 {
5703 int pos;
5704 gtk_container_child_get (GTK_CONTAINER (x->hbox_widget),
5705 top_widget,
5706 "position", &pos, NULL);
5707 if (pos == 0)
5708 nl = req.width * scale;
5709 else
5710 nr = req.width * scale;
5711 }
5712 else
5713 {
5714 int pos;
5715 gtk_container_child_get (GTK_CONTAINER (x->vbox_widget),
5716 top_widget,
5717 "position", &pos, NULL);
5718 if (pos == 0 || (pos == 1 && x->menubar_widget))
5719 nt = req.height * scale;
5720 else
5721 nb = req.height * scale;
5722 }
5723
5724 if (nl != FRAME_TOOLBAR_LEFT_WIDTH (f)
5725 || nr != FRAME_TOOLBAR_RIGHT_WIDTH (f)
5726 || nt != FRAME_TOOLBAR_TOP_HEIGHT (f)
5727 || nb != FRAME_TOOLBAR_BOTTOM_HEIGHT (f))
5728 {
5729 FRAME_TOOLBAR_RIGHT_WIDTH (f) = FRAME_TOOLBAR_LEFT_WIDTH (f)
5730 = FRAME_TOOLBAR_TOP_HEIGHT (f) = FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = 0;
5731 FRAME_TOOLBAR_LEFT_WIDTH (f) = nl;
5732 FRAME_TOOLBAR_RIGHT_WIDTH (f) = nr;
5733 FRAME_TOOLBAR_TOP_HEIGHT (f) = nt;
5734 FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = nb;
5735
5736 return true;
5737 }
5738 else
5739 return false;
5740 }
5741
5742 static char *
5743 find_icon_from_name (char *name,
5744 GtkIconTheme *icon_theme,
5745 char **icon_name)
5746 {
5747 #ifndef HAVE_GTK3
5748 GtkStockItem stock_item;
5749 #endif
5750
5751 if (name[0] == 'n' && name[1] == ':')
5752 {
5753 *icon_name = name + 2;
5754 name = NULL;
5755
5756 if (! gtk_icon_theme_has_icon (icon_theme, *icon_name))
5757 *icon_name = NULL;
5758 }
5759
5760 #ifndef HAVE_GTK3
5761 else if (gtk_stock_lookup (name, &stock_item))
5762 *icon_name = NULL;
5763 #endif
5764 else if (gtk_icon_theme_has_icon (icon_theme, name))
5765 {
5766 *icon_name = name;
5767 name = NULL;
5768 }
5769 else
5770 {
5771 name = NULL;
5772 *icon_name = NULL;
5773 }
5774
5775 return name;
5776 }
5777
5778
5779
5780
5781 void
5782 update_frame_tool_bar (struct frame *f)
5783 {
5784 int i, j;
5785 xp_output *x = f->output_data.xp;
5786 int hmargin = 0, vmargin = 0;
5787 GtkToolbar *wtoolbar;
5788 GtkToolItem *ti;
5789 GtkTextDirection dir;
5790 Lisp_Object style;
5791 bool text_image, horiz;
5792 struct xg_frame_tb_info *tbinfo;
5793 GdkScreen *screen;
5794 GtkIconTheme *icon_theme;
5795
5796
5797 if (! FRAME_GTK_WIDGET (f))
5798 return;
5799
5800 #ifdef HAVE_PGTK
5801 if (! FRAME_GTK_OUTER_WIDGET (f))
5802 return;
5803 #endif
5804
5805 block_input ();
5806
5807 if (RANGED_FIXNUMP (1, Vtool_bar_button_margin, INT_MAX))
5808 {
5809 hmargin = XFIXNAT (Vtool_bar_button_margin);
5810 vmargin = XFIXNAT (Vtool_bar_button_margin);
5811 }
5812 else if (CONSP (Vtool_bar_button_margin))
5813 {
5814 if (RANGED_FIXNUMP (1, XCAR (Vtool_bar_button_margin), INT_MAX))
5815 hmargin = XFIXNAT (XCAR (Vtool_bar_button_margin));
5816
5817 if (RANGED_FIXNUMP (1, XCDR (Vtool_bar_button_margin), INT_MAX))
5818 vmargin = XFIXNAT (XCDR (Vtool_bar_button_margin));
5819 }
5820
5821
5822
5823
5824
5825 hmargin = max (0, hmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
5826 vmargin = max (0, vmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN);
5827
5828 if (! x->toolbar_widget)
5829 xg_create_tool_bar (f);
5830
5831 wtoolbar = GTK_TOOLBAR (x->toolbar_widget);
5832 dir = gtk_widget_get_direction (GTK_WIDGET (wtoolbar));
5833
5834 style = Ftool_bar_get_system_style ();
5835 screen = gtk_widget_get_screen (GTK_WIDGET (wtoolbar));
5836 icon_theme = gtk_icon_theme_get_for_screen (screen);
5837
5838
5839 tbinfo = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
5840 TB_INFO_KEY);
5841
5842 if (! NILP (tbinfo->last_tool_bar) && ! NILP (f->tool_bar_items)
5843 && tbinfo->n_last_items == f->n_tool_bar_items
5844 && tbinfo->hmargin == hmargin && tbinfo->vmargin == vmargin
5845 && tbinfo->dir == dir
5846 && ! NILP (Fequal (tbinfo->style, style))
5847 && ! NILP (Fequal (tbinfo->last_tool_bar, f->tool_bar_items)))
5848 {
5849 unblock_input ();
5850 return;
5851 }
5852
5853 tbinfo->last_tool_bar = f->tool_bar_items;
5854 tbinfo->n_last_items = f->n_tool_bar_items;
5855 tbinfo->style = style;
5856 tbinfo->hmargin = hmargin;
5857 tbinfo->vmargin = vmargin;
5858 tbinfo->dir = dir;
5859
5860 text_image = EQ (style, Qtext_image_horiz);
5861 horiz = EQ (style, Qboth_horiz) || text_image;
5862
5863 for (i = j = 0; i < f->n_tool_bar_items; ++i)
5864 {
5865 bool enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
5866 bool selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
5867 int idx;
5868 ptrdiff_t img_id;
5869 int icon_size = 0;
5870 struct image *img = NULL;
5871 Lisp_Object image;
5872 Lisp_Object stock = Qnil;
5873 char *stock_name = NULL;
5874 char *icon_name = NULL;
5875 Lisp_Object rtl;
5876 GtkWidget *wbutton = NULL;
5877 Lisp_Object specified_file;
5878 bool vert_only = ! NILP (PROP (TOOL_BAR_ITEM_VERT_ONLY));
5879 Lisp_Object label
5880 = (EQ (style, Qimage) || (vert_only && horiz))
5881 ? Qnil
5882 : PROP (TOOL_BAR_ITEM_LABEL);
5883
5884 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), j);
5885
5886
5887 if (EQ (PROP (TOOL_BAR_ITEM_TYPE), Qt))
5888 {
5889 if (ti == NULL || !GTK_IS_SEPARATOR_TOOL_ITEM (ti))
5890 {
5891 if (ti)
5892 gtk_container_remove (GTK_CONTAINER (wtoolbar),
5893 GTK_WIDGET (ti));
5894 ti = gtk_separator_tool_item_new ();
5895 gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, j);
5896 }
5897 j++;
5898 continue;
5899 }
5900
5901
5902
5903 if (ti && GTK_IS_SEPARATOR_TOOL_ITEM (ti))
5904 {
5905 gtk_container_remove (GTK_CONTAINER (wtoolbar), GTK_WIDGET (ti));
5906 ti = NULL;
5907 }
5908
5909 if (ti) wbutton = XG_BIN_CHILD (XG_BIN_CHILD (ti));
5910
5911
5912 image = PROP (TOOL_BAR_ITEM_IMAGES);
5913 if (!valid_image_p (image))
5914 {
5915 if (ti)
5916 gtk_container_remove (GTK_CONTAINER (wtoolbar),
5917 GTK_WIDGET (ti));
5918 continue;
5919 }
5920
5921 specified_file = file_for_image (image);
5922 if (!NILP (specified_file) && !NILP (Ffboundp (Qx_gtk_map_stock)))
5923 stock = call1 (Qx_gtk_map_stock, specified_file);
5924
5925 if (CONSP (stock))
5926 {
5927 Lisp_Object tem;
5928 for (tem = stock; CONSP (tem); tem = XCDR (tem))
5929 if (! NILP (tem) && STRINGP (XCAR (tem)))
5930 {
5931 stock_name = find_icon_from_name (SSDATA (XCAR (tem)),
5932 icon_theme,
5933 &icon_name);
5934 if (stock_name || icon_name) break;
5935 }
5936 }
5937 else if (STRINGP (stock))
5938 {
5939 stock_name = find_icon_from_name (SSDATA (stock),
5940 icon_theme,
5941 &icon_name);
5942 }
5943
5944 if (stock_name || icon_name)
5945 icon_size = gtk_toolbar_get_icon_size (wtoolbar);
5946
5947 if (stock_name == NULL && icon_name == NULL)
5948 {
5949
5950
5951
5952 if (dir == GTK_TEXT_DIR_RTL
5953 && !NILP (rtl = PROP (TOOL_BAR_ITEM_RTL_IMAGE))
5954 && STRINGP (rtl))
5955 image = find_rtl_image (f, image, rtl);
5956
5957 if (VECTORP (image))
5958 {
5959 if (enabled_p)
5960 idx = (selected_p
5961 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
5962 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
5963 else
5964 idx = (selected_p
5965 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
5966 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
5967
5968 eassert (ASIZE (image) >= idx);
5969 image = AREF (image, idx);
5970 }
5971 else
5972 idx = -1;
5973
5974 img_id = lookup_image (f, image, -1);
5975 img = IMAGE_FROM_ID (f, img_id);
5976 prepare_image_for_display (f, img);
5977
5978 if (img->load_failed_p
5979 #ifdef USE_CAIRO
5980 || img->cr_data == NULL
5981 #else
5982 || img->pixmap == None
5983 #endif
5984 )
5985 {
5986 if (ti)
5987 gtk_container_remove (GTK_CONTAINER (wtoolbar),
5988 GTK_WIDGET (ti));
5989 continue;
5990 }
5991 }
5992
5993
5994
5995 if (ti && xg_tool_item_stale_p (wbutton, stock_name, icon_name, img,
5996 NILP (label)
5997 ? NULL
5998 : STRINGP (label) ? SSDATA (label) : "",
5999 horiz))
6000 {
6001 gtk_container_remove (GTK_CONTAINER (wtoolbar),
6002 GTK_WIDGET (ti));
6003 ti = NULL;
6004 }
6005
6006 if (ti == NULL)
6007 {
6008 GtkWidget *w;
6009
6010
6011
6012 if (EQ (style, Qtext))
6013 w = NULL;
6014 else if (stock_name)
6015 {
6016
6017 #ifdef HAVE_GTK3
6018 w = gtk_image_new_from_icon_name (stock_name, icon_size);
6019 #else
6020 w = gtk_image_new_from_stock (stock_name, icon_size);
6021 #endif
6022 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_STOCK_NAME,
6023 (gpointer) xstrdup (stock_name),
6024 (GDestroyNotify) xfree);
6025 }
6026 else if (icon_name)
6027 {
6028 w = gtk_image_new_from_icon_name (icon_name, icon_size);
6029 g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_ICON_NAME,
6030 (gpointer) xstrdup (icon_name),
6031 (GDestroyNotify) xfree);
6032 }
6033 else
6034 {
6035 w = xg_get_image_for_pixmap (f, img, x->widget, NULL);
6036 g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA,
6037 #ifdef USE_CAIRO
6038 (gpointer)img->cr_data
6039 #else
6040 (gpointer)img->pixmap
6041 #endif
6042 );
6043 }
6044
6045 #if GTK_CHECK_VERSION (3, 14, 0)
6046 if (w)
6047 {
6048 gtk_widget_set_margin_start (w, hmargin);
6049 gtk_widget_set_margin_end (w, hmargin);
6050 gtk_widget_set_margin_top (w, vmargin);
6051 gtk_widget_set_margin_bottom (w, vmargin);
6052 }
6053 #else
6054 if (w) gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin);
6055 #endif
6056 ti = xg_make_tool_item (f, w, &wbutton,
6057 NILP (label)
6058 ? NULL
6059 : STRINGP (label) ? SSDATA (label) : "",
6060 i, horiz, text_image);
6061 gtk_toolbar_insert (GTK_TOOLBAR (wtoolbar), ti, j);
6062 }
6063
6064 #undef PROP
6065
6066 gtk_widget_set_sensitive (wbutton, enabled_p);
6067 j++;
6068 }
6069
6070
6071 do
6072 {
6073 ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (wtoolbar), j);
6074 if (ti)
6075 gtk_container_remove (GTK_CONTAINER (wtoolbar), GTK_WIDGET (ti));
6076 } while (ti != NULL);
6077
6078 if (f->n_tool_bar_items != 0)
6079 {
6080 if (! x->toolbar_is_packed)
6081 xg_pack_tool_bar (f, FRAME_TOOL_BAR_POSITION (f));
6082 gtk_widget_show_all (x->toolbar_widget);
6083 if (xg_update_tool_bar_sizes (f))
6084
6085
6086 adjust_frame_size (f, -1, -1, 2, 0, Qtool_bar_lines);
6087
6088 f->tool_bar_resized = f->tool_bar_redisplayed;
6089 }
6090
6091 unblock_input ();
6092 }
6093
6094
6095
6096
6097 void
6098 free_frame_tool_bar (struct frame *f)
6099 {
6100 xp_output *x = f->output_data.xp;
6101
6102 if (x->toolbar_widget)
6103 {
6104 struct xg_frame_tb_info *tbinfo;
6105 GtkWidget *top_widget = x->toolbar_widget;
6106
6107 block_input ();
6108 if (x->toolbar_is_packed)
6109 {
6110 if (x->toolbar_in_hbox)
6111 gtk_container_remove (GTK_CONTAINER (x->hbox_widget),
6112 top_widget);
6113 else
6114 gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
6115 top_widget);
6116 }
6117 else
6118 gtk_widget_destroy (x->toolbar_widget);
6119
6120 x->toolbar_widget = 0;
6121 x->toolbar_widget = 0;
6122 x->toolbar_is_packed = false;
6123 FRAME_TOOLBAR_TOP_HEIGHT (f) = FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = 0;
6124 FRAME_TOOLBAR_LEFT_WIDTH (f) = FRAME_TOOLBAR_RIGHT_WIDTH (f) = 0;
6125
6126 tbinfo = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
6127 TB_INFO_KEY);
6128 if (tbinfo)
6129 {
6130 xfree (tbinfo);
6131 g_object_set_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
6132 TB_INFO_KEY,
6133 NULL);
6134 }
6135
6136 adjust_frame_size (f, -1, -1, 2, 0, Qtool_bar_lines);
6137
6138 unblock_input ();
6139 }
6140 }
6141
6142 void
6143 xg_change_toolbar_position (struct frame *f, Lisp_Object pos)
6144 {
6145 xp_output *x = f->output_data.xp;
6146 GtkWidget *top_widget = x->toolbar_widget;
6147
6148 if (! x->toolbar_widget || ! top_widget)
6149 return;
6150
6151 block_input ();
6152 g_object_ref (top_widget);
6153 if (x->toolbar_is_packed)
6154 {
6155 if (x->toolbar_in_hbox)
6156 gtk_container_remove (GTK_CONTAINER (x->hbox_widget),
6157 top_widget);
6158 else
6159 gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
6160 top_widget);
6161 }
6162
6163 xg_pack_tool_bar (f, pos);
6164 g_object_unref (top_widget);
6165
6166 if (xg_update_tool_bar_sizes (f))
6167 adjust_frame_size (f, -1, -1, 2, 0, Qtool_bar_lines);
6168
6169 unblock_input ();
6170 }
6171
6172
6173
6174
6175
6176
6177 void
6178 xg_initialize (void)
6179 {
6180 GtkBindingSet *binding_set;
6181 GtkSettings *settings;
6182
6183 #if HAVE_XFT
6184
6185
6186 XftInit (0);
6187 #endif
6188
6189 gdpy_def = NULL;
6190 xg_ignore_gtk_scrollbar = 0;
6191 xg_menu_cb_list.prev = xg_menu_cb_list.next =
6192 xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0;
6193
6194 #if defined HAVE_PGTK || !defined HAVE_GTK3
6195 id_to_widget.max_size = id_to_widget.used = 0;
6196 id_to_widget.widgets = 0;
6197 #endif
6198
6199 settings = gtk_settings_get_for_screen (gdk_display_get_default_screen
6200 (gdk_display_get_default ()));
6201 #ifndef HAVE_GTK3
6202
6203
6204
6205 gtk_settings_set_string_property (settings,
6206 "gtk-menu-bar-accel",
6207 "",
6208 EMACS_CLASS);
6209 #endif
6210
6211
6212
6213 #if GTK_CHECK_VERSION (3, 16, 0)
6214 g_object_set (settings, "gtk-key-theme-name", "Emacs", NULL);
6215 #else
6216 gtk_settings_set_string_property (settings,
6217 "gtk-key-theme-name",
6218 "Emacs",
6219 EMACS_CLASS);
6220 #endif
6221
6222
6223
6224 binding_set = gtk_binding_set_by_class (g_type_class_ref (GTK_TYPE_DIALOG));
6225 gtk_binding_entry_add_signal (binding_set, GDK_KEY_g, GDK_CONTROL_MASK,
6226 "close", 0);
6227
6228
6229 binding_set = gtk_binding_set_by_class (g_type_class_ref
6230 (GTK_TYPE_MENU_SHELL));
6231 gtk_binding_entry_add_signal (binding_set, GDK_KEY_g, GDK_CONTROL_MASK,
6232 "cancel", 0);
6233 update_theme_scrollbar_width ();
6234 update_theme_scrollbar_height ();
6235
6236 #ifdef HAVE_FREETYPE
6237 x_last_font_name = NULL;
6238 #endif
6239
6240 #ifdef HAVE_XWIDGETS
6241 xg_gtk_initialized = true;
6242 #endif
6243 }
6244
6245 #ifndef HAVE_PGTK
6246 static void
6247 xg_add_virtual_mods (struct x_display_info *dpyinfo, GdkEventKey *key)
6248 {
6249 guint modifiers = key->state;
6250
6251 if (modifiers & dpyinfo->meta_mod_mask)
6252 {
6253
6254
6255 if (!dpyinfo->alt_mod_mask)
6256 key->state |= GDK_MOD1_MASK;
6257 else
6258 key->state |= GDK_META_MASK;
6259 }
6260
6261 if (modifiers & dpyinfo->alt_mod_mask)
6262 key->state |= GDK_MOD1_MASK;
6263 if (modifiers & dpyinfo->super_mod_mask)
6264 key->state |= GDK_SUPER_MASK;
6265 if (modifiers & dpyinfo->hyper_mod_mask)
6266 key->state |= GDK_HYPER_MASK;
6267 }
6268
6269 static unsigned int
6270 xg_virtual_mods_to_x (struct x_display_info *dpyinfo, guint virtual)
6271 {
6272 unsigned int modifiers = virtual & ~(GDK_SUPER_MASK
6273 | GDK_META_MASK
6274 | GDK_HYPER_MASK
6275 | GDK_MOD2_MASK
6276 | GDK_MOD3_MASK
6277 | GDK_MOD4_MASK
6278 | GDK_MOD5_MASK);
6279
6280 if (virtual & GDK_META_MASK)
6281 modifiers |= dpyinfo->meta_mod_mask;
6282 if (virtual & GDK_SUPER_MASK)
6283 modifiers |= dpyinfo->super_mod_mask;
6284 if (virtual & GDK_HYPER_MASK)
6285 modifiers |= dpyinfo->hyper_mod_mask;
6286
6287 return modifiers;
6288 }
6289
6290 static void
6291 xg_im_context_commit (GtkIMContext *imc, gchar *str,
6292 gpointer user_data)
6293 {
6294 struct frame *f = user_data;
6295 struct input_event ie;
6296 #ifdef HAVE_XINPUT2
6297 struct xi_device_t *source;
6298 struct x_display_info *dpyinfo;
6299 #endif
6300
6301 EVENT_INIT (ie);
6302
6303
6304
6305
6306 ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
6307 ie.arg = decode_string_utf_8 (Qnil, str, strlen (str),
6308 Qnil, false, Qnil, Qnil);
6309
6310
6311 if (NILP (ie.arg))
6312 ie.arg = build_unibyte_string (str);
6313
6314 Fput_text_property (make_fixnum (0),
6315 make_fixnum (SCHARS (ie.arg)),
6316 Qcoding, Qt, ie.arg);
6317
6318 #ifdef HAVE_XINPUT2
6319 dpyinfo = FRAME_DISPLAY_INFO (f);
6320
6321
6322
6323 if (dpyinfo->pending_keystroke_time)
6324 {
6325 dpyinfo->pending_keystroke_time = 0;
6326 source = xi_device_from_id (dpyinfo,
6327 dpyinfo->pending_keystroke_source);
6328
6329 if (source)
6330 ie.device = source->name;
6331 }
6332 #endif
6333
6334 XSETFRAME (ie.frame_or_window, f);
6335 ie.modifiers = 0;
6336 ie.timestamp = 0;
6337
6338 kbd_buffer_store_event (&ie);
6339 }
6340
6341 static void
6342 xg_im_context_preedit_changed (GtkIMContext *imc, gpointer user_data)
6343 {
6344 PangoAttrList *list;
6345 gchar *str;
6346 gint cursor;
6347 struct input_event inev;
6348
6349 gtk_im_context_get_preedit_string (imc, &str, &list, &cursor);
6350
6351 EVENT_INIT (inev);
6352 inev.kind = PREEDIT_TEXT_EVENT;
6353 inev.arg = build_string_from_utf8 (str);
6354
6355 if (SCHARS (inev.arg))
6356 Fput_text_property (make_fixnum (min (SCHARS (inev.arg) - 1,
6357 max (0, cursor))),
6358 make_fixnum (min (SCHARS (inev.arg),
6359 max (0, cursor) + 1)),
6360 Qcursor, Qt, inev.arg);
6361
6362 kbd_buffer_store_event (&inev);
6363
6364 g_free (str);
6365 pango_attr_list_unref (list);
6366 }
6367
6368 static void
6369 xg_im_context_preedit_end (GtkIMContext *imc, gpointer user_data)
6370 {
6371 struct input_event inev;
6372
6373 EVENT_INIT (inev);
6374 inev.kind = PREEDIT_TEXT_EVENT;
6375 inev.arg = Qnil;
6376 kbd_buffer_store_event (&inev);
6377 }
6378
6379 static bool
6380 xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event,
6381 gpointer user_data)
6382 {
6383 Lisp_Object tail, tem;
6384 struct frame *f = NULL;
6385 union buffered_input_event inev;
6386 guint keysym = event->key.keyval;
6387 unsigned int xstate;
6388 gunichar uc;
6389 #ifdef HAVE_XINPUT2
6390 Time pending_keystroke_time;
6391 struct xi_device_t *source;
6392 #endif
6393
6394 FOR_EACH_FRAME (tail, tem)
6395 {
6396 if (FRAME_X_P (XFRAME (tem))
6397 && (FRAME_GTK_WIDGET (XFRAME (tem)) == widget))
6398 {
6399 f = XFRAME (tem);
6400 break;
6401 }
6402 }
6403
6404 if (!f)
6405 return true;
6406
6407 if (popup_activated ())
6408 return true;
6409
6410 #ifdef HAVE_XINPUT2
6411 pending_keystroke_time
6412 = FRAME_DISPLAY_INFO (f)->pending_keystroke_time;
6413
6414 if (event->key.time >= pending_keystroke_time)
6415 FRAME_DISPLAY_INFO (f)->pending_keystroke_time = 0;
6416 #endif
6417
6418 if (!x_gtk_use_native_input
6419 && !FRAME_DISPLAY_INFO (f)->prefer_native_input)
6420 return true;
6421
6422 EVENT_INIT (inev.ie);
6423 XSETFRAME (inev.ie.frame_or_window, f);
6424
6425 xstate = xg_virtual_mods_to_x (FRAME_DISPLAY_INFO (f),
6426 event->key.state);
6427
6428 inev.ie.modifiers
6429 |= x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), xstate);
6430 inev.ie.timestamp = event->key.time;
6431
6432 #ifdef HAVE_XINPUT2
6433 if (event->key.time == pending_keystroke_time)
6434 {
6435 source = xi_device_from_id (FRAME_DISPLAY_INFO (f),
6436 FRAME_DISPLAY_INFO (f)->pending_keystroke_source);
6437
6438 if (source)
6439 inev.ie.device = source->name;
6440 }
6441 #endif
6442
6443 if (event->key.is_modifier)
6444 goto done;
6445
6446 #ifndef HAVE_GTK3
6447
6448
6449 if (keysym >= GDK_KEY_Shift_L && keysym <= GDK_KEY_Hyper_R)
6450 goto done;
6451 #endif
6452
6453
6454
6455 if (keysym >= 32 && keysym < 128)
6456
6457 {
6458 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
6459 inev.ie.code = keysym;
6460 goto done;
6461 }
6462
6463
6464 if (keysym >= 0x01000000 && keysym <= 0x0110FFFF)
6465 {
6466 if (keysym < 0x01000080)
6467 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
6468 else
6469 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
6470 inev.ie.code = keysym & 0xFFFFFF;
6471 goto done;
6472 }
6473
6474
6475 if (((keysym >= GDK_KEY_BackSpace && keysym <= GDK_KEY_Escape)
6476 || keysym == GDK_KEY_Delete
6477 #ifdef GDK_KEY_ISO_Left_Tab
6478 || (keysym >= GDK_KEY_ISO_Left_Tab && keysym <= GDK_KEY_ISO_Enter)
6479 #endif
6480 || IsCursorKey (keysym)
6481 || IsMiscFunctionKey (keysym)
6482 #ifdef GDK_KEY_dead_circumflex
6483 || keysym == GDK_KEY_dead_circumflex
6484 #endif
6485 #ifdef GDK_KEY_dead_grave
6486 || keysym == GDK_KEY_dead_grave
6487 #endif
6488 #ifdef GDK_KEY_dead_tilde
6489 || keysym == GDK_KEY_dead_tilde
6490 #endif
6491 #ifdef GDK_KEY_dead_diaeresis
6492 || keysym == GDK_KEY_dead_diaeresis
6493 #endif
6494 #ifdef GDK_KEY_dead_macron
6495 || keysym == GDK_KEY_dead_macron
6496 #endif
6497 #ifdef GDK_KEY_dead_degree
6498 || keysym == GDK_KEY_dead_degree
6499 #endif
6500 #ifdef GDK_KEY_dead_acute
6501 || keysym == GDK_KEY_dead_acute
6502 #endif
6503 #ifdef GDK_KEY_dead_cedilla
6504 || keysym == GDK_KEY_dead_cedilla
6505 #endif
6506 #ifdef GDK_KEY_dead_breve
6507 || keysym == GDK_KEY_dead_breve
6508 #endif
6509 #ifdef GDK_KEY_dead_ogonek
6510 || keysym == GDK_KEY_dead_ogonek
6511 #endif
6512 #ifdef GDK_KEY_dead_caron
6513 || keysym == GDK_KEY_dead_caron
6514 #endif
6515 #ifdef GDK_KEY_dead_doubleacute
6516 || keysym == GDK_KEY_dead_doubleacute
6517 #endif
6518 #ifdef GDK_KEY_dead_abovedot
6519 || keysym == GDK_KEY_dead_abovedot
6520 #endif
6521 || IsKeypadKey (keysym)
6522 || IsFunctionKey (keysym)
6523
6524 || (keysym & (1 << 28))))
6525 {
6526 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
6527 inev.ie.code = keysym;
6528 goto done;
6529 }
6530
6531 uc = gdk_keyval_to_unicode (keysym);
6532
6533 if (uc)
6534 {
6535 inev.ie.kind = (SINGLE_BYTE_CHAR_P (uc)
6536 ? ASCII_KEYSTROKE_EVENT
6537 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
6538 inev.ie.code = uc;
6539 }
6540 else
6541 {
6542 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
6543 inev.ie.code = keysym;
6544 }
6545
6546 done:
6547 if (inev.ie.kind != NO_EVENT)
6548 {
6549 xg_pending_quit_event.kind = NO_EVENT;
6550 kbd_buffer_store_buffered_event (&inev, &xg_pending_quit_event);
6551 }
6552
6553 XNoOp (FRAME_X_DISPLAY (f));
6554 #ifdef USABLE_SIGIO
6555 raise (SIGIO);
6556 #endif
6557 return true;
6558 }
6559
6560 bool
6561 xg_filter_key (struct frame *frame, XEvent *xkey)
6562 {
6563 GdkEvent *xg_event = gdk_event_new ((xkey->type == KeyPress
6564 #ifdef HAVE_XINPUT2
6565 || (xkey->type == GenericEvent
6566 && xkey->xgeneric.evtype == XI_KeyPress)
6567 #endif
6568 ) ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
6569 GdkDisplay *dpy = gtk_widget_get_display (FRAME_GTK_WIDGET (frame));
6570 GdkKeymap *keymap = gdk_keymap_get_for_display (dpy);
6571 GdkModifierType consumed;
6572 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
6573 bool result;
6574
6575 xg_event->any.window = gtk_widget_get_window (FRAME_GTK_WIDGET (frame));
6576 g_object_ref (xg_event->any.window);
6577
6578 #if GTK_CHECK_VERSION (3, 20, 0)
6579 GdkSeat *seat = gdk_display_get_default_seat (dpy);
6580
6581 gdk_event_set_device (xg_event,
6582 gdk_seat_get_keyboard (seat));
6583 #elif GTK_CHECK_VERSION (3, 16, 0)
6584 GdkDeviceManager *manager = gdk_display_get_device_manager (dpy);
6585 GList *devices = gdk_device_manager_list_devices (manager,
6586 GDK_DEVICE_TYPE_MASTER);
6587 GdkDevice *device;
6588 GList *tem;
6589 for (tem = devices; tem; tem = tem->next)
6590 {
6591 device = GDK_DEVICE (tem->data);
6592
6593 if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
6594 {
6595 gdk_event_set_device (xg_event, device);
6596 break;
6597 }
6598 }
6599
6600 g_list_free (devices);
6601 #endif
6602
6603 #ifdef HAVE_XINPUT2
6604 if (xkey->type != GenericEvent)
6605 {
6606 #endif
6607 xg_event->key.hardware_keycode = xkey->xkey.keycode;
6608
6609 #ifdef HAVE_XKB
6610 if (dpyinfo->supports_xkb)
6611 xg_event->key.group = XkbGroupForCoreState (xkey->xkey.state);
6612 #endif
6613 xg_event->key.state = xkey->xkey.state;
6614 gdk_keymap_translate_keyboard_state (keymap,
6615 xkey->xkey.keycode,
6616 xkey->xkey.state,
6617 xg_event->key.group,
6618 &xg_event->key.keyval,
6619 NULL, NULL, &consumed);
6620 xg_add_virtual_mods (dpyinfo, &xg_event->key);
6621 xg_event->key.state &= ~consumed;
6622 xg_event->key.time = xkey->xkey.time;
6623 #if GTK_CHECK_VERSION (3, 6, 0)
6624 xg_event->key.is_modifier = gdk_x11_keymap_key_is_modifier (keymap,
6625 xg_event->key.hardware_keycode);
6626 #endif
6627 #ifdef HAVE_XINPUT2
6628 }
6629 else
6630 {
6631 XIDeviceEvent *xev = (XIDeviceEvent *) xkey->xcookie.data;
6632
6633 xg_event->key.hardware_keycode = xev->detail;
6634 xg_event->key.group = xev->group.effective;
6635 xg_event->key.state = xev->mods.effective;
6636 xg_event->key.time = xev->time;
6637 gdk_keymap_translate_keyboard_state (keymap,
6638 xev->detail,
6639 xev->mods.effective,
6640 xg_event->key.group,
6641 &xg_event->key.keyval,
6642 NULL, NULL, &consumed);
6643 xg_add_virtual_mods (dpyinfo, &xg_event->key);
6644 xg_event->key.state &= ~consumed;
6645 #if GTK_CHECK_VERSION (3, 6, 0)
6646 xg_event->key.is_modifier = gdk_x11_keymap_key_is_modifier (keymap,
6647 xg_event->key.hardware_keycode);
6648 #endif
6649 }
6650 #endif
6651
6652 result = gtk_im_context_filter_keypress (FRAME_X_OUTPUT (frame)->im_context,
6653 &xg_event->key);
6654
6655 gdk_event_free (xg_event);
6656
6657 return result;
6658 }
6659 #endif
6660
6661 #if GTK_CHECK_VERSION (3, 10, 0)
6662 static void
6663 xg_widget_style_updated (GtkWidget *widget, gpointer user_data)
6664 {
6665 struct frame *f = user_data;
6666
6667 if (f->alpha_background < 1.0)
6668 {
6669 #ifndef HAVE_PGTK
6670 XChangeProperty (FRAME_X_DISPLAY (f),
6671 FRAME_X_WINDOW (f),
6672 FRAME_DISPLAY_INFO (f)->Xatom_net_wm_opaque_region,
6673 XA_CARDINAL, 32, PropModeReplace,
6674 NULL, 0);
6675 #else
6676 if (FRAME_GTK_OUTER_WIDGET (f)
6677 && gtk_widget_get_realized (FRAME_GTK_OUTER_WIDGET (f)))
6678 gdk_window_set_opaque_region (gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f)),
6679 NULL);
6680 #endif
6681 }
6682 }
6683 #endif
6684 #endif