root/src/gtkutil.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. emacs_menu_bar_init
  2. emacs_menu_bar_class_init
  3. emacs_menu_bar_get_preferred_width
  4. emacs_menu_bar_new
  5. xg_set_screen
  6. xg_display_open
  7. xg_get_gdk_scale
  8. xg_get_scale
  9. xg_display_close
  10. xg_create_default_cursor
  11. xg_get_pixbuf_from_pix_and_mask
  12. xg_get_pixbuf_from_surface
  13. file_for_image
  14. xg_get_image_for_pixmap
  15. xg_set_cursor
  16. xg_list_insert
  17. xg_list_remove
  18. get_utf8_string
  19. xg_check_special_colors
  20. hierarchy_ch_cb
  21. qttip_cb
  22. xg_prepare_tooltip
  23. xg_show_tooltip
  24. xg_hide_tooltip
  25. xg_show_tooltip
  26. xg_hide_tooltip
  27. my_log_handler
  28. xg_is_menu_window
  29. xg_set_geometry
  30. xg_frame_resized
  31. xg_frame_set_char_size
  32. xg_height_or_width_changed
  33. xg_win_to_widget
  34. xg_set_widget_bg
  35. style_changed_cb
  36. delete_cb
  37. xg_create_frame_widgets
  38. xg_create_frame_outer_widgets
  39. xg_free_frame_widgets
  40. xg_wm_set_size_hint
  41. xg_set_background_color
  42. xg_set_undecorated
  43. xg_frame_restack
  44. xg_set_skip_taskbar
  45. xg_set_no_focus_on_map
  46. xg_set_no_accept_focus
  47. xg_set_override_redirect
  48. xg_set_frame_icon
  49. get_dialog_title
  50. dialog_delete_callback
  51. create_dialog
  52. xg_dialog_response_cb
  53. pop_down_dialog
  54. xg_maybe_add_timer
  55. xg_dialog_run
  56. xg_uses_old_file_dialog
  57. xg_get_file_name_from_chooser
  58. xg_toggle_visibility_cb
  59. xg_toggle_notify_cb
  60. xg_get_file_with_chooser
  61. xg_get_file_name_from_selector
  62. xg_get_file_with_selection
  63. xg_get_file_name
  64. xg_weight_to_symbol
  65. xg_style_to_symbol
  66. xg_font_filter
  67. xg_get_font
  68. make_cl_data
  69. update_cl_data
  70. unref_cl_data
  71. xg_mark_data
  72. menuitem_destroy_callback
  73. menuitem_highlight_callback
  74. menu_destroy_callback
  75. make_widget_for_menu_item
  76. make_menu_item
  77. xg_create_one_menuitem
  78. menu_bar_button_pressed_cb
  79. create_menus
  80. xg_create_widget
  81. xg_get_menu_item_label
  82. xg_item_label_same_p
  83. xg_destroy_widgets
  84. xg_update_menubar
  85. xg_update_menu_item
  86. xg_update_toggle_item
  87. xg_update_radio_item
  88. xg_update_submenu
  89. xg_modify_menubar_widgets
  90. menubar_map_cb
  91. xg_update_frame_menubar
  92. free_frame_menubar
  93. xg_event_is_for_menubar
  94. xg_store_widget_in_map
  95. xg_remove_widget_from_map
  96. xg_get_widget_from_map
  97. find_scrollbar_cb
  98. xg_get_widget_from_map
  99. update_theme_scrollbar_width
  100. update_theme_scrollbar_height
  101. xg_get_default_scrollbar_width
  102. xg_get_default_scrollbar_height
  103. xg_get_scroll_id_for_window
  104. xg_gtk_scroll_destroy
  105. xg_scroll_bar_size_allocate_cb
  106. xg_finish_scroll_bar_creation
  107. xg_create_scroll_bar
  108. xg_create_horizontal_scroll_bar
  109. xg_remove_scroll_bar
  110. xg_update_scrollbar_pos
  111. xg_update_horizontal_scrollbar_pos
  112. int_gtk_range_get_value
  113. xg_set_toolkit_scroll_bar_thumb
  114. xg_set_toolkit_horizontal_scroll_bar_thumb
  115. xg_event_is_for_scrollbar
  116. xg_page_setup_dialog
  117. xg_get_page_setup
  118. draw_page
  119. xg_print_frames_dialog
  120. xg_tool_bar_button_cb
  121. xg_tool_bar_callback
  122. xg_get_tool_bar_widgets
  123. xg_tool_bar_help_callback
  124. xg_tool_bar_item_expose_callback
  125. xg_pack_tool_bar
  126. tb_size_cb
  127. xg_create_tool_bar
  128. find_rtl_image
  129. xg_make_tool_item
  130. is_box_type
  131. xg_tool_item_stale_p
  132. xg_update_tool_bar_sizes
  133. find_icon_from_name
  134. update_frame_tool_bar
  135. free_frame_tool_bar
  136. xg_change_toolbar_position
  137. xg_initialize
  138. xg_add_virtual_mods
  139. xg_virtual_mods_to_x
  140. xg_im_context_commit
  141. xg_im_context_preedit_changed
  142. xg_im_context_preedit_end
  143. xg_widget_key_press_event_cb
  144. xg_filter_key
  145. xg_widget_style_updated

     1 /* Functions for creating and updating GTK widgets.
     2 
     3 Copyright (C) 2003-2023 Free Software Foundation, Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify
     8 it under the terms of the GNU General Public License as published by
     9 the Free Software Foundation, either version 3 of the License, or (at
    10 your option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    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 /* HAVE_GTK3 */
   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;        /* Used to make sure xwidget calls are possible */
   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                       Display handling functions
   189  ***********************************************************************/
   190 
   191 /* Keep track of the default display, or NULL if there is none.  Emacs
   192    may close all its displays.  */
   193 
   194 static GdkDisplay *gdpy_def;
   195 
   196 /* When the GTK widget W is to be created on a display for F that
   197    is not the default display, set the display for W.
   198    W can be a GtkMenu or a GtkWindow widget.  */
   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 /* Open a display named by DISPLAY_NAME.  The display is returned in *DPY.
   229    *DPY is set to NULL if the display can't be opened.
   230 
   231    Returns non-zero if display could be opened, zero if display could not
   232    be opened, and less than zero if the GTK version doesn't support
   233    multiple displays.  */
   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 ();  /* See comment in x_display_ok, xterm.c.  */
   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 /* Scaling/HiDPI functions. */
   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 /* Close display DPY.  */
   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   /* If this is the default display, try to change it before closing.
   309      If there is no other display to use, gdpy_def is set to NULL, and
   310      the next call to xg_display_open resets the default display.  */
   311   if (gdk_display_get_default () == gdpy)
   312     {
   313       struct x_display_info *dpyinfo;
   314       GdkDisplay *gdpy_new = NULL;
   315 
   316       /* Find another display.  */
   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   /* If this is the default display, try to change it before closing.
   333      If there is no other display to use, gdpy_def is set to NULL, and
   334      the next call to xg_display_open resets the default display.  */
   335   if (gdk_display_get_default () == gdpy)
   336     {
   337       struct pgtk_display_info *dpyinfo;
   338       GdkDisplay *gdpy_new = NULL;
   339 
   340       /* Find another display.  */
   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                       Utility functions
   359  ***********************************************************************/
   360 
   361 /* Create and return the cursor to be used for popup menus and
   362    scroll bars on display DPY.  */
   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 /* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel.  */
   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  /* USE_CAIRO && !HAVE_GTK3 */
   476 
   477 #endif /* !HAVE_PGTK */
   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 /* For the image defined in IMG, make and return a GtkImage.  For displays with
   495    8 planes or less we must make a GdkPixbuf and apply the mask manually.
   496    Otherwise the highlighting and dimming the tool bar code in GTK does
   497    will look bad.  For display with more than 8 planes we just use the
   498    pixmap and mask directly.  For monochrome displays, GTK doesn't seem
   499    able to use external pixmaps, it looks bad whatever we do.
   500    The image is defined on the display where frame F is.
   501    WIDGET is used to find the GdkColormap to use for the GdkPixbuf.
   502    If OLD_WIDGET is NULL, a new widget is constructed and returned.
   503    If OLD_WIDGET is not NULL, that widget is modified.  */
   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   /* If we have a file, let GTK do all the image handling.
   518      This seems to be the only way to make insensitive and activated icons
   519      look good in all cases.  */
   520   Lisp_Object specified_file = file_for_image (img->spec);
   521   Lisp_Object file;
   522 
   523   /* We already loaded the image once before calling this
   524      function, so this only fails if the image file has been removed.
   525      In that case, use the pixmap already loaded.  */
   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   /* No file, do the image handling ourselves.  This will look very bad
   540      on a monochrome display, and sometimes bad on all displays with
   541      certain themes.  */
   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  /* !HAVE_GTK3 */
   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  /* !HAVE_GTK3 */
   569     }
   570 #else
   571   /* This is a workaround to make icons look good on pseudo color
   572      displays.  Apparently GTK expects the images to have an alpha
   573      channel.  If they don't, insensitive and activated icons will
   574      look bad.  This workaround does not work on monochrome displays,
   575      and is strictly not needed on true color/static color displays (i.e.
   576      16 bits and higher).  But we do it anyway so we get a pixbuf that is
   577      not associated with the img->pixmap.  The img->pixmap may be removed
   578      by clearing the image cache and then the tool bar redraw fails, since
   579      Gtk+ assumes the pixmap is always there.  */
   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 /* Set CURSOR on W and all widgets W contain.  We must do like this
   598    for scroll bars and menu because they create widgets internally,
   599    and it is those widgets that are visible.  */
   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   /* The scroll bar widget has more than one GDK window (had to look at
   610      the source to figure this out), and there is no way to set cursor
   611      on widgets in GTK.  So we must set the cursor for all GDK windows.
   612      Ditto for menus.  */
   613 
   614   for ( ; children; children = g_list_next (children))
   615     gdk_window_set_cursor (GDK_WINDOW (children->data), cursor);
   616 }
   617 
   618 /* Insert NODE into linked LIST.  */
   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 /* Remove NODE from linked LIST.  */
   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 /* Allocate and return a utf8 version of STR.  If STR is already
   650    utf8 or NULL, just return a copy of STR.
   651    A new string is allocated and the caller must free the result
   652    with g_free.  */
   653 
   654 static char *
   655 get_utf8_string (const char *str)
   656 {
   657   char *utf8_str;
   658 
   659   if (!str) return NULL;
   660 
   661   /* If not UTF-8, try current locale.  */
   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       /* Probably some control characters in str.  Escape them. */
   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 /* Check for special colors used in face spec for region face.
   731    The colors are fetched from the Gtk+ theme.
   732    Return true if color was found, false if not.  */
   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       /* FIXME: Retrieving the background color is deprecated in
   776          GTK+ 3.16.  New versions of GTK+ don't use the concept of a
   777          single background color any more, so we shouldn't query for
   778          it.  */
   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                               Tooltips
   815  ***********************************************************************/
   816 
   817 #ifndef HAVE_PGTK
   818 
   819 /* Gtk+ calls this callback when the parent of our tooltip dummy changes.
   820    We use that to pop down the tooltip.  This happens if Gtk+ for some
   821    reason wants to change or hide the tooltip.  */
   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 /* Callback called when Gtk+ thinks a tooltip should be displayed.
   837    We use it to get the tooltip window and the tooltip widget so
   838    we can manipulate the ourselves.
   839 
   840    Return FALSE ensures that the tooltip is not shown.  */
   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       /* Change stupid Gtk+ default line wrapping.  */
   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       /* ATK needs an empty title for some reason.  */
   877       gtk_window_set_title (x->ttip_window, "");
   878       /* Realize so we can safely get screen later on.  */
   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 /* Prepare a tooltip to be shown, i.e. calculate WIDTH and HEIGHT.
   890    Return true if a system tooltip is available.  */
   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       /* Record that we disabled it so it can be enabled again.  */
   921       g_object_set_data (G_OBJECT (x->ttip_window), "restore-tt",
   922                          (gpointer)f);
   923     }
   924 
   925   /* Prevent Gtk+ from hiding tooltip on mouse move and such.  */
   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   /* Put our dummy widget in so we can get callbacks for unrealize and
   931      hierarchy-changed.  */
   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 /* Show the tooltip at ROOT_X and ROOT_Y.
   944    xg_prepare_tooltip must have been called before this function.  */
   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 /* Hide tooltip if shown.  Do nothing if not shown.
   968    Return true if tip was hidden, false if not (i.e. not using
   969    system tooltips).  */
   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  /* HAVE_PGTK */
   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  /* HAVE_PGTK */
  1016 
  1017 
  1018 /***********************************************************************
  1019     General functions for creating widgets, resizing, events, e.t.c.
  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 /* Make a geometry string and pass that to GTK.  It seems this is the
  1054    only way to get geometry position right if the user explicitly
  1055    asked for a position when starting Emacs.
  1056    F is the frame we shall set geometry for.  */
  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           /* Handle negative positions without consulting
  1069              gtk_window_parse_geometry (Bug#25851).  The position will
  1070              be off by scrollbar width + window manager decorations.  */
  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           /* GTK works in scaled pixels, so convert from X pixels.  */
  1090           gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
  1091                            f->left_pos / scale, f->top_pos / scale);
  1092 
  1093           /* Reset size hint flags.  */
  1094           f->size_hint_flags &= ~ (XNegative | YNegative);
  1095 # if ! GTK_CHECK_VERSION (3, 22, 0)
  1096         }
  1097       else
  1098         {
  1099           /* GTK works in scaled pixels, so convert from X pixels.  */
  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           /* Silence warning about visible children.  */
  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 /** Function to handle resize of native frame F to WIDTH and HEIGHT
  1133     pixels after we got a ConfigureNotify event.  */
  1134 void
  1135 xg_frame_resized (struct frame *f, int width, int height)
  1136 {
  1137   /* Ignore case where size of native rectangle didn't change.  */
  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 /** Resize the outer window of frame F.  WIDTH and HEIGHT are the new
  1166     native pixel sizes of F.  */
  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   /* Do this before resize, as we don't know yet if we will be resized.  */
  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   /* Resize the top level widget so rows and columns remain constant.
  1205 
  1206      When the frame is fullheight and we only want to change the width
  1207      or it is fullwidth and we only want to change the height we should
  1208      be able to preserve the fullscreen property.  However, due to the
  1209      fact that we have to send a resize request anyway, the window
  1210      manager will abolish it.  At least the respective size should
  1211      remain unchanged but giving the frame back its normal size will
  1212      be broken ... */
  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   /* We can not call change_frame_size for a mapped frame,
  1321      we can not set pixel width/height either.  The window manager may
  1322      override our resize request, XMonad does this all the time.
  1323      The best we can do is try to sync, so lisp code sees the updated
  1324      size as fast as possible.
  1325      For unmapped windows, we can set rows/cols.  When
  1326      the frame is mapped again we will (hopefully) get the correct size.  */
  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       /* Must call this to flush out events */
  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         /* Try to restore fullscreen state.  */
  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 /* Handle height/width changes (i.e. add/remove/move menu/toolbar).
  1364    The policy is to keep the number of editable lines.  */
  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 /* Convert an X Window WSESC on display DPY to its corresponding GtkWidget.
  1380    Must be done like this, because GtkWidget:s can have "hidden"
  1381    X Window that aren't accessible.
  1382 
  1383    Return 0 if no widget match WDESC.  */
  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 /* Set the background of widget W to PIXEL.  */
  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       /* The format is always longer than the resulting string.  */
  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 /* Callback called when the gtk theme changes.
  1450    We notify lisp code so it can fix faces used for region for example.  */
  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   /* Theme doesn't change often, so intern is called seldom.  */
  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   /* If scroll bar width changed, we need set the new size on all frames
  1482      on this display.  */
  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 /* Called when a delete-event occurs on WIDGET.  */
  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 /* Create and set up the GTK widgets for frame F.
  1519    Return true if creation succeeded.  */
  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  /* gtk_plug not found. */
  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   /* gtk_window_set_has_resize_grip is a Gtk+ 3.0 function but Ubuntu
  1562      has backported it to Gtk+ 2.0 and they add the resize grip for
  1563      Gtk+ 2.0 applications also.  But it has a bug that makes Emacs loop
  1564      forever, so disable the grip.  */
  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   /* Use same names as the Xt port does.  I.e. Emacs.pane.emacs by default */
  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   /* If this frame has a title or name, set it in the title bar.  */
  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   /* We don't want this widget double buffered, because we draw on it
  1629      with regular X drawing primitives, so from a GTK/GDK point of
  1630      view, the widget is totally blank.  When an expose comes, this
  1631      will make the widget blank, and then Emacs redraws it.  This flickers
  1632      a lot, so we turn off double buffering.  */
  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   /* Add callback to do nothing on WM_DELETE_WINDOW.  The default in
  1646      GTK is to destroy the widget.  We want Emacs to do that instead.  */
  1647   g_signal_connect (G_OBJECT (wtop), "delete-event",
  1648                     G_CALLBACK (delete_cb), f);
  1649 #endif
  1650 
  1651   /* Convert our geometry parameters into a geometry string
  1652      and specify it.
  1653      GTK will itself handle calculating the real position this way.  */
  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   /* Must realize the windows so the X window gets created.  It is used
  1693      by callers of this function.  */
  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   /* Since GTK clears its window by filling with the background color,
  1700      we must keep X and GTK background in sync.  */
  1701   xg_set_widget_bg (f, wfixed, FRAME_BACKGROUND_PIXEL (f));
  1702 
  1703 #ifndef HAVE_GTK3
  1704   /* Also, do not let any background pixmap to be set, this looks very
  1705      bad as Emacs overwrites the background pixmap with its own idea
  1706      of background color.  */
  1707   style = gtk_widget_get_modifier_style (wfixed);
  1708 
  1709   /* Must use g_strdup because gtk_widget_modify_style does g_free.  */
  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   /* Steal a tool tip window we can move ourselves.  */
  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     /* Only connect this signal once per screen.  */
  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   /* Use same names as the Xt port does.  I.e. Emacs.pane.emacs by default */
  1796   gtk_widget_set_name (wtop, EMACS_CLASS);
  1797   gtk_widget_set_name (wvbox, "pane");
  1798 
  1799   /* If this frame has a title or name, set it in the title bar.  */
  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   /* Convert our geometry parameters into a geometry string
  1831      and specify it.
  1832      GTK will itself handle calculating the real position this way.  */
  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   /* Steal a tool tip window we can move ourselves.  */
  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     /* Only connect this signal once per screen.  */
  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       /* x_free_frame_resources should have taken care of it */
  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; /* Set to avoid XDestroyWindow in xterm.c */
  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           /* Remove ttip_lbl from ttip_widget's custom slot before
  1904              destroying it, to avoid double-free (Bug#41239).  */
  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 /* Set the normal size hints for the window manager, for frame F.
  1914    FLAGS is the flags word to use--or 0 meaning preserve the flags
  1915    that the window now has.
  1916    If USER_POSITION, set the User Position
  1917    flag (this is useful when FLAGS is 0).  */
  1918 
  1919 void
  1920 xg_wm_set_size_hint (struct frame *f, long int flags, bool user_position)
  1921 {
  1922   /* Must use GTK routines here, otherwise GTK resets the size hints
  1923      to its own defaults.  */
  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   /* Don't set size hints during initialization; that apparently leads
  1932      to a race condition.  See the thread at
  1933      https://lists.gnu.org/r/emacs-devel/2008-10/msg00033.html  */
  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       /* Don't set hints when maximized or fullscreen.  Apparently KWin and
  1949          Gtk3 don't get along and the frame shrinks (!).
  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   /* Use one row/col here so base_height/width does not become zero.
  1972      Gtk+ and/or Unity on Ubuntu 12.04 can't handle it.
  1973      Obviously this makes the row/col value displayed off by 1.  */
  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   /* These currently have a one to one mapping with the X values, but I
  1984      don't think we should rely on that.  */
  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 /* Change background color of a frame.
  2041    Since GTK uses the background color to clear the window, we must
  2042    keep the GTK and X colors in sync.
  2043    F is the frame to change,
  2044    BG is the pixel value to change to.  */
  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 /* Change the frame's decoration (title bar + resize borders).  This
  2071    might not work with all window managers.  */
  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 /* Restack F1 below F2, above if ABOVE_FLAG is true.  This might not
  2090    work with all window managers.  */
  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 /* Don't show frame in taskbar, don't ALT-TAB to it.  */
  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 /* Don't give frame focus.  */
  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 /* Set the frame icon to ICON_PIXMAP/MASK.  This must be done with GTK
  2193    functions so GTK does not overwrite the icon.  */
  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                       Dialog functions
  2214  ***********************************************************************/
  2215 /* Return the dialog title to use for a dialog of type KEY.
  2216    This is the encoding used by lwlib.  We use the same for GTK.  */
  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 /* Callback for dialogs that get WM_DELETE_WINDOW.  We pop down
  2249    the dialog, but return TRUE so the event does not propagate further
  2250    in GTK.  This prevents GTK from destroying the dialog widget automatically
  2251    and we can always destroy the widget manually, regardless of how
  2252    it was popped down (button press or WM_DELETE_WINDOW).
  2253    W is the dialog widget.
  2254    EVENT is the GdkEvent that represents WM_DELETE_WINDOW (not used).
  2255    user_data is NULL (not used).
  2256 
  2257    Returns TRUE to end propagation of event.  */
  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 /* Create a popup dialog window.  See also xg_create_widget below.
  2267    WV is a widget_value describing the dialog.
  2268    SELECT_CB is the callback to use when a button has been pressed.
  2269    DEACTIVATE_CB is the callback to use when the dialog pops down.
  2270 
  2271    Returns the GTK dialog widget.  */
  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   /* If the number of buttons is greater than 4, make two rows of buttons
  2290      instead.  This looks better.  */
  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           /* This is the text part of the dialog.  */
  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           /* Try to make dialog look better.  Must realize first so
  2356              the widget can calculate the size it needs.  */
  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           /* This is one button to add to the dialog.  */
  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 /* Function that is called when the file or font dialogs pop down.
  2398    W is the dialog widget, RESPONSE is the response code.
  2399    USER_DATA is what we passed in to g_signal_connect.  */
  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 /*  Destroy the dialog.  This makes it pop down.  */
  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 /* If there are any emacs timers pending, add a timeout to main loop in DATA.
  2430    Pass DATA as gpointer so we can use this as a callback.  */
  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 /* Pops up a modal dialog W and waits for response.
  2453    We don't use gtk_dialog_run because we want to process emacs timers.
  2454    The dialog W is not destroyed when this function returns.  */
  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   /* Don't destroy the widget if closed by the window manager close button.  */
  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                       File dialog functions
  2495  ***********************************************************************/
  2496 /* Return true if the old file selection dialog is being used.  */
  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 /* Return the selected file for file chooser dialog W.
  2512    The returned string must be free:d.  */
  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 /* Callback called when the "Show hidden files" toggle is pressed.
  2521    WIDGET is the toggle widget, DATA is the file chooser dialog.  */
  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 /* Callback called when a property changes in a file chooser.
  2534    GOBJECT is the file chooser dialog, ARG1 describes the property.
  2535    USER_DATA is the toggle widget in the file chooser dialog.
  2536    We use this to update the "Show hidden files" toggle when the user
  2537    changes that property by right clicking in the file list.  */
  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 /* Read a file name from the user using a file chooser dialog.
  2562    F is the current frame.
  2563    PROMPT is a prompt to show to the user.  May not be NULL.
  2564    DEFAULT_FILENAME is a default selection to be displayed.  May be NULL.
  2565    If MUSTMATCH_P, the returned file name must be an existing
  2566    file.  (Actually, this only has cosmetic effects, the user can
  2567    still enter a non-existing file.)  *FUNC is set to a function that
  2568    can be used to retrieve the selected file name from the returned widget.
  2569 
  2570    Returns the created widget.  */
  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       /* Gtk+ 2.10 has the file name text entry box integrated in the dialog.
  2619          Show the C-l help text only for versions < 2.10.  */
  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       /* File chooser does not understand ~/... in the file name.  It must be
  2643          an absolute name starting with /.  */
  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 /* Return the selected file for file selector dialog W.
  2672    The returned string must be free:d.  */
  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 /* Create a file selection dialog.
  2682    F is the current frame.
  2683    PROMPT is a prompt to show to the user.  May not be NULL.
  2684    DEFAULT_FILENAME is a default selection to be displayed.  May be NULL.
  2685    If MUSTMATCH_P, the returned file name must be an existing
  2686    file.  *FUNC is set to a function that can be used to retrieve the
  2687    selected file name from the returned widget.
  2688 
  2689    Returns the created widget.  */
  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       /* The selection_entry part of filesel is not documented.  */
  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 /* HAVE_GTK_FILE_SELECTION_NEW */
  2719 
  2720 /* Read a file name from the user using a file dialog, either the old
  2721    file selection dialog, or the new file chooser dialog.  Which to use
  2722    depends on what the GTK version used has, and what the value of
  2723    gtk-use-old-file-dialog.
  2724    F is the current frame.
  2725    PROMPT is a prompt to show to the user.  May not be NULL.
  2726    DEFAULT_FILENAME is a default selection to be displayed.  May be NULL.
  2727    If MUSTMATCH_P, the returned file name must be an existing
  2728    file.
  2729 
  2730    Returns a file name or NULL if no file was selected.
  2731    The returned string must be freed by the caller.  */
  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 /* not HAVE_GTK_FILE_SELECTION_NEW */
  2760   w = xg_get_file_with_chooser (f, prompt, default_filename,
  2761                                 mustmatch_p, only_dir_p, &func);
  2762 #endif /* not HAVE_GTK_FILE_SELECTION_NEW */
  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                       GTK font chooser
  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                  /* 100 */
  2787      : w <= PANGO_WEIGHT_ULTRALIGHT ? Qultra_light   /* 200 */
  2788      : w <= PANGO_WEIGHT_LIGHT ? Qlight              /* 300 */
  2789 #if PANGO_VERSION_CHECK(1, 36, 7)
  2790      : w <= PANGO_WEIGHT_SEMILIGHT ? Qsemi_light     /* 350 */
  2791 #endif
  2792      : w <= PANGO_WEIGHT_BOOK ? Qbook                /* 380 */
  2793      : w <= PANGO_WEIGHT_NORMAL ? Qnormal            /* 400 */
  2794      : w <= PANGO_WEIGHT_MEDIUM ? Qmedium            /* 500 */
  2795      : w <= PANGO_WEIGHT_SEMIBOLD ? Qsemi_bold       /* 600 */
  2796      : w <= PANGO_WEIGHT_BOLD ? Qbold                /* 700 */
  2797      : w <= PANGO_WEIGHT_ULTRABOLD ? Qultra_bold     /* 800 */
  2798      : w <= PANGO_WEIGHT_HEAVY ? Qblack              /* 900 */
  2799      : Qultra_heavy);                                /* 1000 */
  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 /* HAVE_GTK3 */
  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 /* Pop up a GTK font selector and return the name of the font the user
  2832    selects, as a C string.  The returned font name follows GTK's own
  2833    format:
  2834 
  2835    `FAMILY [VALUE1 VALUE2] SIZE'
  2836 
  2837    This can be parsed using font_parse_fcname in font.c.
  2838    DEFAULT_NAME, if non-zero, is the default font name.  */
  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       /* Convert fontconfig names to Gtk names, i.e. remove - before
  2861          number */
  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       /* Use the GTK3 font chooser.  */
  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 /* Use old font selector, which just returns the font name.  */
  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 /* HAVE_GTK3 */
  2926     }
  2927 
  2928   gtk_widget_destroy (w);
  2929   return font;
  2930 }
  2931 #endif /* HAVE_FREETYPE */
  2932 
  2933 
  2934 
  2935 /***********************************************************************
  2936                         Menu functions.
  2937  ***********************************************************************/
  2938 
  2939 /* The name of menu items that can be used for customization.  Since GTK
  2940    RC files are very crude and primitive, we have to set this on all
  2941    menu item names so a user can easily customize menu items.  */
  2942 
  2943 #define MENU_ITEM_NAME "emacs-menuitem"
  2944 
  2945 
  2946 /* Linked list of all allocated struct xg_menu_cb_data.  Used for marking
  2947    during GC.  The next member points to the items.  */
  2948 static xg_list_node xg_menu_cb_list;
  2949 
  2950 /* Linked list of all allocated struct xg_menu_item_cb_data.  Used for marking
  2951    during GC.  The next member points to the items.  */
  2952 static xg_list_node xg_menu_item_cb_list;
  2953 
  2954 /* Allocate and initialize CL_DATA if NULL, otherwise increase ref_count.
  2955    F is the frame CL_DATA will be initialized for.
  2956    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
  2957 
  2958    The menu bar and all sub menus under the menu bar in a frame
  2959    share the same structure, hence the reference count.
  2960 
  2961    Returns CL_DATA if CL_DATA is not NULL,  or a pointer to a newly
  2962    allocated xg_menu_cb_data if CL_DATA is NULL.  */
  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 /* Update CL_DATA with values from frame F and with HIGHLIGHT_CB.
  2985    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
  2986 
  2987    When the menu bar is updated, menu items may have been added and/or
  2988    removed, so menu_bar_vector and menu_bar_items_used change.  We must
  2989    then update CL_DATA since it is used to determine which menu
  2990    item that is invoked in the menu.
  2991    HIGHLIGHT_CB could change, there is no check that the same
  2992    function is given when modifying a menu bar as was given when
  2993    creating the menu bar.  */
  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 /* Decrease reference count for CL_DATA.
  3010    If reference count is zero, free CL_DATA.  */
  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 /* Function that marks all lisp data during GC.  */
  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 /* Callback called when a menu item is destroyed.  Used to free data.
  3074    W is the widget that is being destroyed (not used).
  3075    CLIENT_DATA points to the xg_menu_item_cb_data associated with the W.  */
  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 /* Callback called when the pointer enters/leaves a menu item.
  3089    W is the parent of the menu item.
  3090    EVENT is either an enter event or leave event.
  3091    CLIENT_DATA is not used.
  3092 
  3093    Returns FALSE to tell GTK to keep processing this event.  */
  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 /* Callback called when a menu is destroyed.  Used to free data.
  3121    W is the widget that is being destroyed (not used).
  3122    CLIENT_DATA points to the xg_menu_cb_data associated with W.  */
  3123 
  3124 static void
  3125 menu_destroy_callback (GtkWidget *w, gpointer client_data)
  3126 {
  3127   unref_cl_data (client_data);
  3128 }
  3129 
  3130 /* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both
  3131    must be non-NULL) and can be inserted into a menu item.
  3132 
  3133    Returns the GtkHBox.  */
  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 /* Make and return a menu item widget with the key to the right.
  3167    UTF8_LABEL is the text for the menu item (GTK uses UTF8 internally).
  3168    UTF8_KEY is the text representing the key binding.
  3169    ITEM is the widget_value describing the menu item.
  3170 
  3171    GROUP is an in/out parameter.  If the menu item to be created is not
  3172    part of any radio menu group, *GROUP contains NULL on entry and exit.
  3173    If the menu item to be created is part of a radio menu group, on entry
  3174    *GROUP contains the group to use, or NULL if this is the first item
  3175    in the group.  On exit, *GROUP contains the radio item group.
  3176 
  3177    Unfortunately, keys don't line up as nicely as in Motif,
  3178    but the macOS version doesn't either, so I guess that is OK.  */
  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   /* It has been observed that some menu items have a NULL name field.
  3190      This will lead to this function being called with a NULL utf8_label.
  3191      GTK crashes on that so we set a blank label.  Why there is a NULL
  3192      name remains to be investigated.  */
  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 /* Create a menu item widget, and connect the callbacks.
  3232    ITEM describes the menu item.
  3233    F is the frame the created menu belongs to.
  3234    SELECT_CB is the callback to use when a menu item is selected.
  3235    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
  3236    CL_DATA points to the callback data to be used for this menu.
  3237    GROUP is an in/out parameter.  If the menu item to be created is not
  3238    part of any radio menu group, *GROUP contains NULL on entry and exit.
  3239    If the menu item to be created is part of a radio menu group, on entry
  3240    *GROUP contains the group to use, or NULL if this is the first item
  3241    in the group.  On exit, *GROUP contains the radio item group.
  3242 
  3243    Returns the created GtkWidget.  */
  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   /* Put cb_data in widget, so we can get at it when modifying menubar  */
  3281   g_object_set_data (G_OBJECT (w), XG_ITEM_DATA, cb_data);
  3282 
  3283   /* final item, not a submenu  */
  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 /* Create a full menu tree specified by DATA.
  3314    F is the frame the created menu belongs to.
  3315    SELECT_CB is the callback to use when a menu item is selected.
  3316    DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
  3317    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
  3318    If POP_UP_P, create a popup menu.
  3319    If MENU_BAR_P, create a menu bar.
  3320    TOPMENU is the topmost GtkWidget that others shall be placed under.
  3321    It may be NULL, in that case we create the appropriate widget
  3322    (menu bar or menu item depending on POP_UP_P and MENU_BAR_P)
  3323    CL_DATA is the callback data we shall use for this menu, or NULL
  3324    if we haven't set the first callback yet.
  3325    NAME is the name to give to the top level menu if this function
  3326    creates it.  May be NULL to not set any name.
  3327 
  3328    Returns the top level GtkWidget.  This is TOPLEVEL if TOPLEVEL is
  3329    not NULL.
  3330 
  3331    This function calls itself to create submenus.  */
  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         /* Connect this to the menu instead of items so we get enter/leave for
  3356            disabled items also.  TODO:  Still does not get enter/leave for
  3357            disabled items in detached menus.  */
  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           /* Set width of menu bar to a small value so it doesn't enlarge
  3380              a small initial frame size.  The width will be set to the
  3381              width of the frame later on when it is added to a container.
  3382              height -1: Natural height.  */
  3383           gtk_widget_set_size_request (wmenu, 1, -1);
  3384         }
  3385 
  3386       /* Put cl_data on the top menu for easier access.  */
  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           /* A title for a popup.  We do the same as GTK does when
  3415              creating titles, but it does not look good.  */
  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           /* GTK only have one separator type.  */
  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           /* Create a possibly empty submenu for menu bar items, since some
  3439              themes don't highlight items correctly without it. */
  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 /* Create a menubar, popup menu or dialog, depending on the TYPE argument.
  3464    TYPE can be "menubar", "popup" for popup menu, or "dialog" for a dialog
  3465    with some text and buttons.
  3466    F is the frame the created item belongs to.
  3467    NAME is the name to use for the top widget.
  3468    VAL is a widget_value structure describing items to be created.
  3469    SELECT_CB is the callback to use when a menu item is selected or
  3470    a dialog button is pressed.
  3471    DEACTIVATE_CB is the callback to use when an item is deactivated.
  3472    For a menu, when a sub menu is not shown anymore, for a dialog it is
  3473    called when the dialog is popped down.
  3474    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
  3475 
  3476    Returns the widget created.  */
  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       /* Set the cursor to an arrow for popup menus when they are mapped.
  3511          This is done by default for menu bar menus.  */
  3512       if (pop_up_p)
  3513         {
  3514           /* Must realize so the GdkWindow inside the widget is created.  */
  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 /* Return the label for menu item WITEM.  */
  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 /* Return true if the menu item WITEM has the text LABEL.  */
  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 /* Destroy widgets in LIST.  */
  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       /* Destroying the widget will remove it from the container it is in.  */
  3566       gtk_widget_destroy (w);
  3567     }
  3568 }
  3569 
  3570 /* Update the top level names in MENUBAR (i.e. not submenus).
  3571    F is the frame the menu bar belongs to.
  3572    *LIST is a list with the current menu bar names (menu item widgets).
  3573    ITER is the item within *LIST that shall be updated.
  3574    POS is the numerical position, starting at 0, of ITER in *LIST.
  3575    VAL describes what the menu bar shall look like after the update.
  3576    SELECT_CB is the callback to use when a menu item is selected.
  3577    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
  3578    CL_DATA points to the callback data to be used for this menu bar.
  3579 
  3580    This function calls itself to walk through the menu bar names.  */
  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       /* Item(s) have been removed.  Remove all remaining items.  */
  3599       xg_destroy_widgets (iter);
  3600 
  3601       /* Add a blank entry so the menubar doesn't collapse to nothing. */
  3602       gtk_menu_shell_insert (GTK_MENU_SHELL (menubar),
  3603                              gtk_menu_item_new_with_label (""),
  3604                              0);
  3605       /* All updated.  */
  3606       val = 0;
  3607       iter = 0;
  3608     }
  3609   else if (! iter && val)
  3610     {
  3611       /* Item(s) added.  Add all new items in one call.  */
  3612       create_menus (val, f, select_cb, deactivate_cb, highlight_cb,
  3613                     0, 1, menubar, cl_data, 0);
  3614 
  3615       /* All updated.  */
  3616       val = 0;
  3617       iter = 0;
  3618     }
  3619   /* Below this neither iter or val is NULL */
  3620   else if (xg_item_label_same_p (GTK_MENU_ITEM (iter->data), val->name))
  3621     {
  3622       /* This item is still the same, check next item.  */
  3623       val = val->next;
  3624       iter = g_list_next (iter);
  3625       ++pos;
  3626     }
  3627   else /* This item is changed.  */
  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       /* See if the changed entry (val) is present later in the menu bar  */
  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       /* See if the current entry (iter) is present later in the
  3646          specification for the new menu bar.  */
  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           /*  This corresponds to:
  3655                 Current:  A B C
  3656                 New:      A C
  3657               Remove B.  */
  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           /* Must get new list since the old changed.  */
  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           /*  This corresponds to:
  3671                 Current:  A B C
  3672                 New:      A X C
  3673               Rename B to X.  This might seem to be a strange thing to do,
  3674               since if there is a menu under B it will be totally wrong for X.
  3675               But consider editing a C file.  Then there is a C-mode menu
  3676               (corresponds to B above).
  3677               If then doing C-x C-f the minibuf menu (X above) replaces the
  3678               C-mode menu.  When returning from the minibuffer, we get
  3679               back the C-mode menu.  Thus we do:
  3680                 Rename B to X (C-mode to minibuf menu)
  3681                 Rename X to B (minibuf to C-mode menu).
  3682               If the X menu hasn't been invoked, the menu under B
  3683               is up to date when leaving the minibuffer.  */
  3684           GtkLabel *wlabel = GTK_LABEL (XG_BIN_CHILD (witem));
  3685           char *utf8_label = get_utf8_string (val->name);
  3686 
  3687           /* GTK menu items don't notice when their labels have been
  3688              changed from underneath them, so we have to explicitly
  3689              use g_object_notify to tell listeners (e.g., a GMenuModel
  3690              bridge that might be loaded) that the item's label has
  3691              changed.  */
  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           /*  This corresponds to:
  3702                 Current:  A B C
  3703                 New:      A X B C
  3704               Insert X.  */
  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           /* Create a possibly empty submenu for menu bar items, since some
  3716              themes don't highlight items correctly without it. */
  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 /* if (val_in_menubar && iter_in_new_menubar) */
  3734         {
  3735           int nr = pos;
  3736           /*  This corresponds to:
  3737                 Current:  A B C
  3738                 New:      A C B
  3739               Move C before B  */
  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   /* Update the rest of the menu bar.  */
  3757   xg_update_menubar (menubar, f, list, iter, pos, val,
  3758                      select_cb, deactivate_cb, highlight_cb, cl_data);
  3759 }
  3760 
  3761 /* Update the menu item W so it corresponds to VAL.
  3762    SELECT_CB is the callback to use when a menu item is selected.
  3763    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
  3764    CL_DATA is the data to set in the widget for menu invocation.  */
  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   /* See if W is a menu item with a key.  See make_menu_item above.  */
  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           /* Remove the key and keep just the label.  */
  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 /* Just a label.  */
  3808     {
  3809       wlbl = GTK_LABEL (wchild);
  3810 
  3811       /* Check if there is now a key.  */
  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       /* We assume the callback functions don't change.  */
  3857       if (val->call_data && ! val->contents)
  3858         {
  3859           /* This item shall have a select callback.  */
  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) /* See comment in xg_update_menubar.  */
  3873     g_object_notify (G_OBJECT (w), "label");
  3874 }
  3875 
  3876 /* Update the toggle menu item W so it corresponds to VAL.  */
  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 /* Update the radio menu item W so it corresponds to VAL.  */
  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 /* Update the sub menu SUBMENU and all its children so it corresponds to VAL.
  3893    SUBMENU may be NULL, in that case a new menu is created.
  3894    F is the frame the menu bar belongs to.
  3895    VAL describes the contents of the menu bar.
  3896    SELECT_CB is the callback to use when a menu item is selected.
  3897    DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
  3898    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
  3899    CL_DATA is the call back data to use for any newly created items.
  3900 
  3901    Returns the updated submenu widget, that is SUBMENU unless SUBMENU
  3902    was NULL.  */
  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     /* Remember first radio button in a group.  If we get a mismatch in
  3929        a radio group we must rebuild the whole group so that the connections
  3930        in GTK becomes correct.  */
  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             /* Not a submenu anymore.  */
  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             /* If this item just became a submenu, we must set it.  */
  3984             if (nsub != sub)
  3985               gtk_menu_item_set_submenu (witem, nsub);
  3986           }
  3987       }
  3988     else
  3989       {
  3990         /* Structural difference.  Remove everything from here and down
  3991            in SUBMENU.  */
  3992         break;
  3993       }
  3994   }
  3995 
  3996   /* Remove widgets from first structural change.  */
  3997   if (iter)
  3998     {
  3999       /* If we are adding new menu items below, we must remove from
  4000          first radio button so that radio groups become correct.  */
  4001       if (cur && first_radio) xg_destroy_widgets (first_radio);
  4002       else xg_destroy_widgets (iter);
  4003     }
  4004 
  4005   if (cur)
  4006     {
  4007       /* More items added.  Create them.  */
  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 /* Update the MENUBAR.
  4026    F is the frame the menu bar belongs to.
  4027    VAL describes the contents of the menu bar.
  4028    If DEEP_P, rebuild all but the top level menu names in
  4029    the MENUBAR.  If DEEP_P is zero, just rebuild the names in the menubar.
  4030    SELECT_CB is the callback to use when a menu item is selected.
  4031    DEACTIVATE_CB is the callback to use when a sub menu is not shown anymore.
  4032    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.  */
  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       /* Update all sub menus.
  4055          We must keep the submenus (GTK menu item widgets) since the
  4056          X Window in the XEvent that activates the menu are those widgets.  */
  4057 
  4058       /* Update cl_data, menu_item things in F may have changed.  */
  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           /* Find sub menu that corresponds to val and update it.  */
  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           /* sub may still be NULL.  If we just updated non deep and added
  4087              a new menu bar item, it has no sub menu yet.  So we set the
  4088              newly created sub menu under witem.  */
  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 /* Callback called when the menu bar W is mapped.
  4102    Used to find the height of the menu bar if we didn't get it
  4103    after showing the widget.  */
  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 /* Recompute all the widgets of frame F, when the menu bar has been
  4120    changed.  */
  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; /* Already done this, happens for frames created invisible.  */
  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 /* Get rid of the menu bar of frame F, and free its storage.
  4166    This is used when deleting a frame, and when turning off the menu bar.  */
  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        /* The menubar and its children shall be deleted when removed from
  4179           the container.  */
  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) /* XI_ButtonPress or XI_ButtonRelease or a touch event.  */
  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                       Scroll bar functions
  4274  ***********************************************************************/
  4275 
  4276 
  4277 /* Setting scroll bar values invokes the callback.  Use this variable
  4278    to indicate that callback should do nothing.  */
  4279 
  4280 bool xg_ignore_gtk_scrollbar;
  4281 
  4282 /* Width and height of scroll bars for the current theme.  */
  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 /* Xlib's `Window' fits in 32 bits.  But we want to store pointers, and they
  4289    may be larger than 32 bits.  Keep a mapping from integer index to widget
  4290    pointers to get around the 32 bit limitation.  */
  4291 
  4292 static struct
  4293 {
  4294   GtkWidget **widgets;
  4295   ptrdiff_t max_size;
  4296   ptrdiff_t used;
  4297 } id_to_widget;
  4298 
  4299 /* Grow this much every time we need to allocate more  */
  4300 
  4301 #define ID_TO_WIDGET_INCR  32
  4302 
  4303 /* Store the widget pointer W in id_to_widget and return the integer index.  */
  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   /* Just loop over the array and find a free place.  After all,
  4326      how many scroll bars are we creating?  Should be a small number.
  4327      The check above guarantees we will find a free place.  */
  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   /* Should never end up here  */
  4340   emacs_abort ();
  4341 }
  4342 
  4343 /* Remove pointer at IDX from id_to_widget.
  4344    Called when scroll bar is destroyed.  */
  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 /* Get the widget pointer at IDX from id_to_widget. */
  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   /* Apparently there's no default height for themes.  */
  4459   return scroll_bar_width_for_theme * xg_get_scale (f);
  4460 }
  4461 
  4462 #ifndef HAVE_GTK3
  4463 /* Return the scrollbar id for X Window WID on display DPY.
  4464    Return -1 if WID not in id_to_widget.  */
  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 /* Callback invoked when scroll bar WIDGET is destroyed.
  4486    DATA is the index into id_to_widget for WIDGET.
  4487    We free pointer to last scroll bar values here and remove the index.  */
  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       /* These are the only fields used by x_scroll_bar_configure.  */
  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   /* The scroll bar widget does not draw on a window of its own.  Instead
  4569      it draws on the parent window, in this case the edit widget.  So
  4570      whenever the edit widget is cleared, the scroll bar needs to redraw
  4571      also, which causes flicker.  Put an event box between the edit widget
  4572      and the scroll bar, so the scroll bar instead draws itself on the
  4573      event box window.  */
  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   /* N.B. The event box doesn't become a real X11 window until we ask
  4580      for its XID via GTK_WIDGET_TO_X_WIN.  If the event box is not a
  4581      real X window, it and its scroll-bar child try to draw on the
  4582      Emacs main window, which we draw over using Xlib.  */
  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   /* Set the cursor to an arrow.  */
  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 /* Create a scroll bar widget for frame F.  Store the scroll bar
  4618    in BAR.
  4619    SCROLL_CALLBACK is the callback to invoke when the value of the
  4620    bar changes.
  4621    END_CALLBACK is the callback to invoke when scrolling ends.
  4622    SCROLL_BAR_NAME is the name we use for the scroll bar.  Can be used
  4623    to set resources for the widget.  */
  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   /* Page, step increment values are not so important here, they
  4640      will be corrected in x_set_toolkit_scroll_bar_thumb. */
  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 /* Create a horizontal scroll bar widget for frame F.  Store the scroll
  4652    bar in BAR.  SCROLL_CALLBACK is the callback to invoke when the value
  4653    of the bar changes.  END_CALLBACK is the callback to invoke when
  4654    scrolling ends.  SCROLL_BAR_NAME is the name we use for the scroll
  4655    bar.  Can be used to set resources for the widget.  */
  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   /* Page, step increment values are not so important here, they
  4672      will be corrected in x_set_toolkit_scroll_bar_thumb. */
  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 /* Remove the scroll bar represented by SCROLLBAR_ID from the frame F.  */
  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 /* Update the position of the vertical scroll bar represented by SCROLLBAR_ID
  4700    in frame F.
  4701    TOP/LEFT are the new pixel positions where the bar shall appear.
  4702    WIDTH, HEIGHT is the size in pixels the bar shall have.  */
  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       /* Clear out old position.  */
  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       /* Move and resize to new values.  */
  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           /* No room.  Hide scroll bar as some themes output a warning if
  4745              the height is less than the min size.  */
  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           /* Clear under old scroll bar position.  */
  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           /* Don't obscure any child frames.  */
  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       /* GTK does not redraw until the main loop is entered again, but
  4792          if there are no X events pending we will not enter it.  So we sync
  4793          here to get some events.  */
  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 /* Update the position of the horizontal scroll bar represented by SCROLLBAR_ID
  4807    in frame F.
  4808    TOP/LEFT are the new pixel positions where the bar shall appear.
  4809    WIDTH, HEIGHT is the size in pixels the bar shall have.  */
  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       /* Clear out old position.  */
  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       /* Move and resize to new values.  */
  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           /* No room.  Hide scroll bar as some themes output a warning if
  4852              the width is less than the min size.  */
  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         /* Clear under old scroll bar position.  */
  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       /* GTK does not redraw until the main loop is entered again, but
  4880          if there are no X events pending we will not enter it.  So we sync
  4881          here to get some events.  */
  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         /* Don't obscure any child frames.  */
  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 /* Get the current value of the range, truncated to an integer.  */
  4908 
  4909 static int
  4910 int_gtk_range_get_value (GtkRange *range)
  4911 {
  4912   return gtk_range_get_value (range);
  4913 }
  4914 
  4915 
  4916 /* Set the thumb size and position of scroll bar BAR.  We are currently
  4917    displaying PORTION out of a whole WHOLE, and our position POSITION.  */
  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           /* We do the same as for MOTIF in xterm.c, use 30 chars per
  4945              line rather than the real portion value.  This makes the
  4946              thumb less likely to resize and that looks better.  */
  4947           portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
  4948 
  4949           /* When the thumb is at the bottom, position == whole.
  4950              So we need to increase `whole' to make space for the thumb.  */
  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       /* Assume all lines are of equal size.  */
  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               /* Assume a page increment is about 95% of the page size  */
  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         /* gtk_range_set_value invokes the callback.  Set
  4987            ignore_gtk_scrollbar to make the callback do nothing  */
  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 /* Set the thumb size and position of horizontal scroll bar BAR.  We are
  5005    currently displaying PORTION out of a whole WHOLE, and our position
  5006    POSITION.  */
  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       /* These should be set to something more <portion, whole>
  5025          related.  */
  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 /* Return true if EVENT is for a scroll bar in frame F.
  5042    When the same X window is used for several Gtk+ widgets, we cannot
  5043    say for sure based on the X window alone if an event is for the
  5044    frame.  This function does additional checks.  */
  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 /* HAVE_XINPUT2 */
  5072     {
  5073       /* Check if press occurred outside the edit widget.  */
  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 /* HAVE_XINPUT2 */
  5116     {
  5117       /* If we are releasing or moving the scroll bar, it has the grab.  */
  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                                Printing
  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  /* USE_CAIRO */
  5226 
  5227 
  5228 
  5229 /***********************************************************************
  5230                       Tool bar functions
  5231  ***********************************************************************/
  5232 /* The key for the data we put in the GtkImage widgets.  The data is
  5233    the image used by Emacs.  We use this to see if we need to update
  5234    the GtkImage with a new image.  */
  5235 #define XG_TOOL_BAR_IMAGE_DATA "emacs-tool-bar-image"
  5236 
  5237 /* The key for storing the latest modifiers so the activate callback can
  5238    get them.  */
  5239 #define XG_TOOL_BAR_LAST_MODIFIER "emacs-tool-bar-modifier"
  5240 
  5241 /* The key for the data we put in the GtkImage widgets.  The data is
  5242    the stock name used by Emacs.  We use this to see if we need to update
  5243    the GtkImage with a new image.  */
  5244 #define XG_TOOL_BAR_STOCK_NAME "emacs-tool-bar-stock-name"
  5245 
  5246 /* As above, but this is used for named theme widgets, as opposed to
  5247    stock items.  */
  5248 #define XG_TOOL_BAR_ICON_NAME "emacs-tool-bar-icon-name"
  5249 
  5250 /* Callback function invoked when a tool bar item is pressed.
  5251    W is the button widget in the tool bar that got pressed,
  5252    CLIENT_DATA is an integer that is the index of the button in the
  5253    tool bar.  0 is the first button.  */
  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 /* Callback function invoked when a tool bar item is pressed.
  5268    W is the button widget in the tool bar that got pressed,
  5269    CLIENT_DATA is an integer that is the index of the button in the
  5270    tool bar.  0 is the first button.  */
  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   /* Convert between the modifier bits GDK uses and the modifier bits
  5296      Emacs uses.  This assumes GDK and X masks are the same, which they are when
  5297      this is written.  */
  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   /* Return focus to the frame after we have clicked on a detached
  5306      tool bar button. */
  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 /* This callback is called when the mouse enters or leaves a tool bar item.
  5324    It is used for displaying and hiding the help text.
  5325    W is the tool bar item, a button.
  5326    EVENT is either an enter event or leave event.
  5327    CLIENT_DATA is an integer that is the index of the button in the
  5328    tool bar.  0 is the first button.
  5329 
  5330    Returns FALSE to tell GTK to keep processing this event.  */
  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 /* This callback is called when a tool bar item shall be redrawn.
  5363    It modifies the expose event so that the GtkImage widget redraws the
  5364    whole image.  This to overcome a bug that makes GtkImage draw the image
  5365    in the wrong place when it tries to redraw just a part of the image.
  5366    W is the GtkImage to be redrawn.
  5367    EVENT is the expose event for W.
  5368    CLIENT_DATA is unused.
  5369 
  5370    Returns FALSE to tell GTK to keep processing this event.  */
  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 /* Attach a tool bar to frame F.  */
  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   /* When tool bar is created it has one preferred size.  But when size is
  5442      allocated between widgets, it may get another.  So we must update
  5443      size hints if tool bar size changes.  Seen on Fedora 18 at least.  */
  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 /* Create a tool bar for frame F.  */
  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 /* Find the right-to-left image named by RTL in the tool bar images for F.
  5494    Returns IMAGE if RTL is not found.  */
  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   /* The eventbox is here so we can have tooltips on disabled items.  */
  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       /* Catch expose events to overcome an annoying redraw bug, see
  5586          comment for xg_tool_bar_item_expose_callback.  */
  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       /* Callback to save modifier mask (Shift/Control, etc).  GTK makes
  5595          no distinction based on modifiers in the activate callback,
  5596          so we have to do it ourselves.  */
  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       /* Use enter/leave notify to show help.  We use the events
  5604          rather than the GtkButton specific signals "enter" and
  5605          "leave", so we can have only one callback.  The event
  5606          will tell us what kind of event it is.  */
  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   /* Check if the tool icon matches.  */
  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   /* Check button configuration and label.  */
  5681   if (is_box_type (vb, horiz)
  5682       || (label ? (wlbl == NULL) : (wlbl != NULL)))
  5683     return 1;
  5684 
  5685   /* Ensure label is correct.  */
  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 /* Update the tool bar for frame F.  Add new buttons and remove old.  */
  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   /* The natural size (i.e. when GTK uses 0 as margin) looks best,
  5822      so take DEFAULT_TOOL_BAR_BUTTON_MARGIN to mean "default for GTK",
  5823      i.e. zero.  This means that margins less than
  5824      DEFAULT_TOOL_BAR_BUTTON_MARGIN has no effect.  */
  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   /* Are we up to date? */
  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       /* If this is a separator, use a gtk separator item.  */
  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       /* Otherwise, the tool-bar item is an ordinary button.  */
  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       /* Ignore invalid image specifications.  */
  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           /* No stock image, or stock item not known.  Try regular
  5950              image.  If image is a vector, choose it according to the
  5951              button state.  */
  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       /* If there is an existing widget, check if it's stale; if so,
  5994          remove it and make a new tool item from scratch.  */
  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           /* Save the image so we can see if an update is needed the
  6011              next time we call xg_tool_item_match_p.  */
  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   /* Remove buttons not longer needed.  */
  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         /* It's not entirely clear whether here we want a treatment
  6085            similar to that for frames with internal tool bar.  */
  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 /* Deallocate all resources for the tool bar on frame F.
  6095    Remove the tool bar.  */
  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                       Initializing
  6176 ***********************************************************************/
  6177 void
  6178 xg_initialize (void)
  6179 {
  6180   GtkBindingSet *binding_set;
  6181   GtkSettings *settings;
  6182 
  6183 #if HAVE_XFT
  6184   /* Work around a bug with corrupted data if libXft gets unloaded.  This way
  6185      we keep it permanently linked in.  */
  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   /* Remove F10 as a menu accelerator, it does not mix well with Emacs key
  6203      bindings.  It doesn't seem to be any way to remove properties,
  6204      so we set it to "" which in means "no key".  */
  6205   gtk_settings_set_string_property (settings,
  6206                                     "gtk-menu-bar-accel",
  6207                                     "",
  6208                                     EMACS_CLASS);
  6209 #endif
  6210 
  6211   /* Make GTK text input widgets use Emacs style keybindings.  This is
  6212      Emacs after all.  */
  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   /* Make dialogs close on C-g.  Since file dialog inherits from
  6223      dialog, this works for them also.  */
  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   /* Make menus close on C-g.  */
  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       /* GDK always assumes Mod1 is alt, but that's no reason for
  6254          us to make that mistake as well.  */
  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   /* This used to use g_utf8_to_ucs4_fast, which led to bad results
  6303      when STR wasn't actually a UTF-8 string, which some input method
  6304      modules commit.  */
  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   /* STR is invalid and not really encoded in UTF-8.  */
  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   /* There is no timestamp associated with commit events, so use the
  6322      device that sent the last event to be filtered.  */
  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   /* FIXME: event->key.is_modifier is not accurate on GTK 2.  */
  6448 
  6449   if (keysym >= GDK_KEY_Shift_L && keysym <= GDK_KEY_Hyper_R)
  6450     goto done;
  6451 #endif
  6452 
  6453   /* First deal with keysyms which have defined
  6454      translations to characters.  */
  6455   if (keysym >= 32 && keysym < 128)
  6456     /* Avoid explicitly decoding each ASCII character.  */
  6457     {
  6458       inev.ie.kind = ASCII_KEYSTROKE_EVENT;
  6459       inev.ie.code = keysym;
  6460       goto done;
  6461     }
  6462 
  6463   /* Keysyms directly mapped to Unicode characters.  */
  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   /* Random non-modifier sorts of keysyms.  */
  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)  /* 0xff50 <= x < 0xff60 */
  6481        || IsMiscFunctionKey (keysym)    /* 0xff60 <= x < VARIES */
  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)  /* 0xff80 <= x < 0xffbe */
  6522        || IsFunctionKey (keysym)        /* 0xffbe <= x < 0xffe1 */
  6523        /* Any "vendor-specific" key is ok.  */
  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 /* USE_GTK */

/* [<][>][^][v][top][bottom][index][help] */