use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / gtkutil.c
index 4771d34..fcb4224 100644 (file)
@@ -1,6 +1,6 @@
 /* Functions for creating and updating GTK widgets.
 
-Copyright (C) 2003-2013 Free Software Foundation, Inc.
+Copyright (C) 2003-2014 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -35,6 +35,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "keyboard.h"
 #include "charset.h"
 #include "coding.h"
+#include "font.h"
+
 #include <gdk/gdkkeysyms.h>
 #include "xsettings.h"
 
@@ -70,13 +72,14 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #define gtk_adjustment_get_step_increment(w) ((w)->step_increment)
 #define gtk_adjustment_set_step_increment(w, s) ((w)->step_increment = (s))
 #endif
-#if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 11
+#if GTK_CHECK_VERSION (2, 12, 0)
 #define remove_submenu(w) gtk_menu_item_set_submenu ((w), NULL)
 #else
 #define remove_submenu(w) gtk_menu_item_remove_submenu ((w))
 #endif
 
-#if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 2)
+#ifdef HAVE_FREETYPE
+#if GTK_CHECK_VERSION (3, 2, 0)
 #define USE_NEW_GTK_FONT_CHOOSER 1
 #else
 #define USE_NEW_GTK_FONT_CHOOSER 0
@@ -87,6 +90,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #define  gtk_font_chooser_set_font(x, y) \
   gtk_font_selection_dialog_set_font_name (x, y)
 #endif
+#endif /* HAVE_FREETYPE */
 
 #ifndef HAVE_GTK3
 #ifdef USE_GTK_TOOLTIP
@@ -136,7 +140,7 @@ static GdkDisplay *gdpy_def;
    W can be a GtkMenu or a GtkWindow widget.  */
 
 static void
-xg_set_screen (GtkWidget *w, FRAME_PTR f)
+xg_set_screen (GtkWidget *w, struct frame *f)
 {
   if (FRAME_X_DISPLAY (f) != DEFAULT_GDK_DISPLAY ())
     {
@@ -202,7 +206,7 @@ xg_display_close (Display *dpy)
       gdpy_def = gdpy_new;
     }
 
-#if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 10
+#if GTK_CHECK_VERSION (2, 0, 0) && ! GTK_CHECK_VERSION (2, 10, 0)
   /* GTK 2.2-2.8 has a bug that makes gdk_display_close crash (bug
      http://bugzilla.gnome.org/show_bug.cgi?id=85715).  This way we
      can continue running, but there will be memory leaks.  */
@@ -217,57 +221,6 @@ xg_display_close (Display *dpy)
 /***********************************************************************
                       Utility functions
  ***********************************************************************/
-/* The next two variables and functions are taken from lwlib.  */
-static widget_value *widget_value_free_list;
-static int malloc_cpt;
-
-/* Allocate a widget_value structure, either by taking one from the
-   widget_value_free_list or by malloc:ing a new one.
-
-   Return a pointer to the allocated structure.  */
-
-widget_value *
-malloc_widget_value (void)
-{
-  widget_value *wv;
-  if (widget_value_free_list)
-    {
-      wv = widget_value_free_list;
-      widget_value_free_list = wv->free_list;
-      wv->free_list = 0;
-    }
-  else
-    {
-      wv = xmalloc (sizeof *wv);
-      malloc_cpt++;
-    }
-  memset (wv, 0, sizeof (widget_value));
-  return wv;
-}
-
-/* This is analogous to free.  It frees only what was allocated
-   by malloc_widget_value, and no substructures.  */
-
-void
-free_widget_value (widget_value *wv)
-{
-  if (wv->free_list)
-    emacs_abort ();
-
-  if (malloc_cpt > 25)
-    {
-      /* When the number of already allocated cells is too big,
-        We free it.  */
-      xfree (wv);
-      malloc_cpt--;
-    }
-  else
-    {
-      wv->free_list = widget_value_free_list;
-      widget_value_free_list = wv;
-    }
-}
-
 
 /* Create and return the cursor to be used for popup menus and
    scroll bars on display DPY.  */
@@ -280,7 +233,7 @@ xg_create_default_cursor (Display *dpy)
 }
 
 static GdkPixbuf *
-xg_get_pixbuf_from_pixmap (FRAME_PTR f, Pixmap pix)
+xg_get_pixbuf_from_pixmap (struct frame *f, Pixmap pix)
 {
   int iunused;
   GdkPixbuf *tmp_buf;
@@ -311,7 +264,7 @@ xg_get_pixbuf_from_pixmap (FRAME_PTR f, Pixmap pix)
 /* Apply GMASK to GPIX and return a GdkPixbuf with an alpha channel.  */
 
 static GdkPixbuf *
-xg_get_pixbuf_from_pix_and_mask (FRAME_PTR f,
+xg_get_pixbuf_from_pix_and_mask (struct frame *f,
                                  Pixmap pix,
                                  Pixmap mask)
 {
@@ -387,7 +340,7 @@ file_for_image (Lisp_Object image)
    If OLD_WIDGET is not NULL, that widget is modified.  */
 
 static GtkWidget *
-xg_get_image_for_pixmap (FRAME_PTR f,
+xg_get_image_for_pixmap (struct frame *f,
                          struct image *img,
                          GtkWidget *widget,
                          GtkImage *old_widget)
@@ -545,7 +498,7 @@ get_utf8_string (const char *str)
       len = strlen (str);
       if ((min (PTRDIFF_MAX, SIZE_MAX) - len - 1) / 4 < nr_bad)
        memory_full (SIZE_MAX);
-      up = utf8_str = xmalloc (len + nr_bad * 4 + 1);
+      up = utf8_str = xmalloc_atomic (len + nr_bad * 4 + 1);
       p = (unsigned char *)str;
 
       while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
@@ -596,14 +549,17 @@ xg_check_special_colors (struct frame *f,
     GtkStyleContext *gsty
       = gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
     GdkRGBA col;
-    char buf[sizeof "rgbi://" + 3 * (DBL_MAX_10_EXP + sizeof "-1.000000" - 1)];
+    char buf[sizeof "rgb://rrrr/gggg/bbbb"];
     int state = GTK_STATE_FLAG_SELECTED|GTK_STATE_FLAG_FOCUSED;
     if (get_fg)
       gtk_style_context_get_color (gsty, state, &col);
     else
       gtk_style_context_get_background_color (gsty, state, &col);
 
-    sprintf (buf, "rgbi:%lf/%lf/%lf", col.red, col.green, col.blue);
+    sprintf (buf, "rgb:%04x/%04x/%04x",
+             (int)(col.red * 65535),
+             (int)(col.green * 65535),
+             (int)(col.blue * 65535));
     success_p = (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
                              buf, color)
                 != 0);
@@ -641,7 +597,7 @@ hierarchy_ch_cb (GtkWidget *widget,
                  GtkWidget *previous_toplevel,
                  gpointer   user_data)
 {
-  FRAME_PTR f = (FRAME_PTR) user_data;
+  struct frame *f = user_data;
   struct x_output *x = f->output_data.x;
   GtkWidget *top = gtk_widget_get_toplevel (x->ttip_lbl);
 
@@ -663,7 +619,7 @@ qttip_cb (GtkWidget  *widget,
           GtkTooltip *tooltip,
           gpointer    user_data)
 {
-  FRAME_PTR f = (FRAME_PTR) user_data;
+  struct frame *f = user_data;
   struct x_output *x = f->output_data.x;
   if (x->ttip_widget == NULL)
     {
@@ -707,7 +663,7 @@ qttip_cb (GtkWidget  *widget,
    Return true if a system tooltip is available.  */
 
 bool
-xg_prepare_tooltip (FRAME_PTR f,
+xg_prepare_tooltip (struct frame *f,
                     Lisp_Object string,
                     int *width,
                     int *height)
@@ -764,7 +720,7 @@ xg_prepare_tooltip (FRAME_PTR f,
    xg_prepare_tooltip must have been called before this function.  */
 
 void
-xg_show_tooltip (FRAME_PTR f, int root_x, int root_y)
+xg_show_tooltip (struct frame *f, int root_x, int root_y)
 {
 #ifdef USE_GTK_TOOLTIP
   struct x_output *x = f->output_data.x;
@@ -783,7 +739,7 @@ xg_show_tooltip (FRAME_PTR f, int root_x, int root_y)
    system tooltips).  */
 
 bool
-xg_hide_tooltip (FRAME_PTR f)
+xg_hide_tooltip (struct frame *f)
 {
   bool ret = 0;
 #ifdef USE_GTK_TOOLTIP
@@ -827,7 +783,7 @@ my_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
    F is the frame we shall set geometry for.  */
 
 static void
-xg_set_geometry (FRAME_PTR f)
+xg_set_geometry (struct frame *f)
 {
   if (f->size_hint_flags & (USPosition | PPosition))
     {
@@ -865,34 +821,28 @@ xg_set_geometry (FRAME_PTR f)
    and use a GtkFixed widget, this doesn't happen automatically.  */
 
 static void
-xg_clear_under_internal_border (FRAME_PTR f)
+xg_clear_under_internal_border (struct frame *f)
 {
   if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
     {
       GtkWidget *wfixed = f->output_data.x->edit_widget;
+
       gtk_widget_queue_draw (wfixed);
       gdk_window_process_all_updates ();
-      x_clear_area (FRAME_X_DISPLAY (f),
-                    FRAME_X_WINDOW (f),
-                    0, 0,
-                    FRAME_PIXEL_WIDTH (f),
-                    FRAME_INTERNAL_BORDER_WIDTH (f), 0);
-      x_clear_area (FRAME_X_DISPLAY (f),
-                    FRAME_X_WINDOW (f),
-                    0, 0,
-                    FRAME_INTERNAL_BORDER_WIDTH (f),
-                    FRAME_PIXEL_HEIGHT (f), 0);
-      x_clear_area (FRAME_X_DISPLAY (f),
-                    FRAME_X_WINDOW (f),
-                    0, FRAME_PIXEL_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
-                    FRAME_PIXEL_WIDTH (f),
-                    FRAME_INTERNAL_BORDER_WIDTH (f), 0);
-      x_clear_area (FRAME_X_DISPLAY (f),
-                    FRAME_X_WINDOW (f),
-                    FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
-                    0,
-                    FRAME_INTERNAL_BORDER_WIDTH (f),
-                    FRAME_PIXEL_HEIGHT (f), 0);
+
+      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, 0,
+                   FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f));
+
+      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, 0,
+                   FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
+
+      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0,
+                   FRAME_PIXEL_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
+                   FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f));
+
+      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                   FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
+                   0, FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
     }
 }
 
@@ -903,9 +853,9 @@ xg_clear_under_internal_border (FRAME_PTR f)
    PIXELWIDTH, PIXELHEIGHT is the new size in pixels.  */
 
 void
-xg_frame_resized (FRAME_PTR f, int pixelwidth, int pixelheight)
+xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight)
 {
-  int rows, columns;
+  int width, height;
 
   if (pixelwidth == -1 && pixelheight == -1)
     {
@@ -917,11 +867,11 @@ xg_frame_resized (FRAME_PTR f, int pixelwidth, int pixelheight)
     }
 
 
-  rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
-  columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
+  width = FRAME_PIXEL_TO_TEXT_WIDTH (f, pixelwidth);
+  height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelheight);
 
-  if (columns != FRAME_COLS (f)
-      || rows != FRAME_LINES (f)
+  if (width != FRAME_TEXT_WIDTH (f)
+      || height != FRAME_TEXT_HEIGHT (f)
       || pixelwidth != FRAME_PIXEL_WIDTH (f)
       || pixelheight != FRAME_PIXEL_HEIGHT (f))
     {
@@ -929,7 +879,7 @@ xg_frame_resized (FRAME_PTR f, int pixelwidth, int pixelheight)
       FRAME_PIXEL_HEIGHT (f) = pixelheight;
 
       xg_clear_under_internal_border (f);
-      change_frame_size (f, rows, columns, 0, 1, 0);
+      change_frame_size (f, width, height, 0, 1, 0, 1);
       SET_FRAME_GARBAGED (f);
       cancel_mouse_face (f);
     }
@@ -939,38 +889,23 @@ xg_frame_resized (FRAME_PTR f, int pixelwidth, int pixelheight)
    COLUMNS/ROWS is the size the edit area shall have after the resize.  */
 
 void
-xg_frame_set_char_size (FRAME_PTR f, int cols, int rows)
+xg_frame_set_char_size (struct frame *f, int width, int height)
 {
-  int pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows)
-    + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
-  int pixelwidth;
+  int pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
+  int pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
 
   if (FRAME_PIXEL_HEIGHT (f) == 0)
     return;
 
-  /* Take into account the size of the scroll bar.  Always use the
-     number of columns occupied by the scroll bar here otherwise we
-     might end up with a frame width that is not a multiple of the
-     frame's character width which is bad for vertically split
-     windows.  */
-  f->scroll_bar_actual_width
-    = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
-
-  compute_fringe_widths (f, 0);
-
-  /* FRAME_TEXT_COLS_TO_PIXEL_WIDTH uses scroll_bar_actual_width, so call it
-     after calculating that value.  */
-  pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols)
-    + FRAME_TOOLBAR_WIDTH (f);
-
-
   /* Do this before resize, as we don't know yet if we will be resized.  */
   xg_clear_under_internal_border (f);
 
   /* Must resize our top level widget.  Font size may have changed,
      but not rows/cols.  */
   gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-                     pixelwidth, pixelheight);
+                     pixelwidth + FRAME_TOOLBAR_WIDTH (f),
+                    pixelheight + FRAME_TOOLBAR_HEIGHT (f)
+                    + FRAME_MENUBAR_HEIGHT (f));
   x_wm_set_size_hint (f, 0, 0);
 
   SET_FRAME_GARBAGED (f);
@@ -991,18 +926,14 @@ xg_frame_set_char_size (FRAME_PTR f, int cols, int rows)
       x_wait_for_event (f, ConfigureNotify);
     }
   else
-    {
-      change_frame_size (f, rows, cols, 0, 1, 0);
-      FRAME_PIXEL_WIDTH (f) = pixelwidth;
-      FRAME_PIXEL_HEIGHT (f) = pixelheight;
-     }
+    change_frame_size (f, width, height, 0, 1, 0, 1);
 }
 
 /* Handle height/width changes (i.e. add/remove/move menu/toolbar).
    The policy is to keep the number of editable lines.  */
 
 static void
-xg_height_or_width_changed (FRAME_PTR f)
+xg_height_or_width_changed (struct frame *f)
 {
   gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
                      FRAME_TOTAL_PIXEL_WIDTH (f),
@@ -1042,7 +973,7 @@ xg_win_to_widget (Display *dpy, Window wdesc)
 /* Set the background of widget W to PIXEL.  */
 
 static void
-xg_set_widget_bg (FRAME_PTR f, GtkWidget *w, long unsigned int pixel)
+xg_set_widget_bg (struct frame *f, GtkWidget *w, unsigned long pixel)
 {
 #ifdef HAVE_GTK3
   GdkRGBA bg;
@@ -1073,7 +1004,7 @@ style_changed_cb (GObject *go,
                   gpointer user_data)
 {
   struct input_event event;
-  GdkDisplay *gdpy = (GdkDisplay *) user_data;
+  GdkDisplay *gdpy = user_data;
   const char *display_name = gdk_display_get_name (gdpy);
   Display *dpy = GDK_DISPLAY_XDISPLAY (gdpy);
 
@@ -1093,11 +1024,13 @@ style_changed_cb (GObject *go,
       Lisp_Object rest, frame;
       FOR_EACH_FRAME (rest, frame)
         {
-          FRAME_PTR f = XFRAME (frame);
-          if (FRAME_X_DISPLAY (f) == dpy)
+          struct frame *f = XFRAME (frame);
+          if (FRAME_LIVE_P (f)
+              && FRAME_X_P (f)
+              && FRAME_X_DISPLAY (f) == dpy)
             {
               x_set_scroll_bar_default_width (f);
-              xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
+              xg_frame_set_char_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f));
             }
         }
     }
@@ -1113,7 +1046,7 @@ delete_cb (GtkWidget *widget,
 #ifdef HAVE_GTK3
   /* The event doesn't arrive in the normal event loop.  Send event
      here.  */
-  FRAME_PTR f = (FRAME_PTR) user_data;
+  struct frame *f = user_data;
   struct input_event ie;
 
   EVENT_INIT (ie);
@@ -1129,7 +1062,7 @@ delete_cb (GtkWidget *widget,
    Return true if creation succeeded.  */
 
 bool
-xg_create_frame_widgets (FRAME_PTR f)
+xg_create_frame_widgets (struct frame *f)
 {
   GtkWidget *wtop;
   GtkWidget *wvbox, *whbox;
@@ -1153,7 +1086,8 @@ xg_create_frame_widgets (FRAME_PTR f)
      has backported it to Gtk+ 2.0 and they add the resize grip for
      Gtk+ 2.0 applications also.  But it has a bug that makes Emacs loop
      forever, so disable the grip.  */
-#if GTK_MAJOR_VERSION < 3 && defined (HAVE_GTK_WINDOW_SET_HAS_RESIZE_GRIP)
+#if (! GTK_CHECK_VERSION (3, 0, 0) \
+     && defined HAVE_GTK_WINDOW_SET_HAS_RESIZE_GRIP)
   gtk_window_set_has_resize_grip (GTK_WINDOW (wtop), FALSE);
 #endif
 
@@ -1297,7 +1231,7 @@ xg_create_frame_widgets (FRAME_PTR f)
 }
 
 void
-xg_free_frame_widgets (FRAME_PTR f)
+xg_free_frame_widgets (struct frame *f)
 {
   if (FRAME_GTK_OUTER_WIDGET (f))
     {
@@ -1329,7 +1263,7 @@ xg_free_frame_widgets (FRAME_PTR f)
    flag (this is useful when FLAGS is 0).  */
 
 void
-x_wm_set_size_hint (FRAME_PTR f, long int flags, bool user_position)
+x_wm_set_size_hint (struct frame *f, long int flags, bool user_position)
 {
   /* Must use GTK routines here, otherwise GTK resets the size hints
      to its own defaults.  */
@@ -1338,6 +1272,7 @@ x_wm_set_size_hint (FRAME_PTR f, long int flags, bool user_position)
   int base_width, base_height;
   int min_rows = 0, min_cols = 0;
   int win_gravity = f->win_gravity;
+  Lisp_Object fs_state, frame;
 
   /* Don't set size hints during initialization; that apparently leads
      to a race condition.  See the thread at
@@ -1345,6 +1280,16 @@ x_wm_set_size_hint (FRAME_PTR f, long int flags, bool user_position)
   if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
     return;
 
+  XSETFRAME (frame, f);
+  fs_state = Fframe_parameter (frame, Qfullscreen);
+  if (EQ (fs_state, Qmaximized) || EQ (fs_state, Qfullboth))
+    {
+      /* Don't set hints when maximized or fullscreen.  Apparently KWin and
+         Gtk3 don't get along and the frame shrinks (!).
+      */
+      return;
+    }
+
   if (flags)
     {
       memset (&size_hints, 0, sizeof (size_hints));
@@ -1358,8 +1303,8 @@ x_wm_set_size_hint (FRAME_PTR f, long int flags, bool user_position)
   hint_flags = f->output_data.x->hint_flags;
 
   hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
-  size_hints.width_inc = FRAME_COLUMN_WIDTH (f);
-  size_hints.height_inc = FRAME_LINE_HEIGHT (f);
+  size_hints.width_inc = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
+  size_hints.height_inc = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
 
   hint_flags |= GDK_HINT_BASE_SIZE;
   /* Use one row/col here so base_height/width does not become zero.
@@ -1368,14 +1313,14 @@ x_wm_set_size_hint (FRAME_PTR f, long int flags, bool user_position)
   base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 1)
     + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
 
-  check_frame_size (f, &min_rows, &min_cols);
+  check_frame_size (f, &min_cols, &min_rows, 0);
   if (min_cols > 0) --min_cols; /* We used one col in base_width = ... 1); */
   if (min_rows > 0) --min_rows; /* We used one row in base_height = ... 1); */
 
   size_hints.base_width = base_width;
   size_hints.base_height = base_height;
-  size_hints.min_width  = base_width + min_cols * size_hints.width_inc;
-  size_hints.min_height = base_height + min_rows * size_hints.height_inc;
+  size_hints.min_width  = base_width + min_cols * FRAME_COLUMN_WIDTH (f);;
+  size_hints.min_height = base_height + min_rows * FRAME_LINE_HEIGHT (f);
 
   /* These currently have a one to one mapping with the X values, but I
      don't think we should rely on that.  */
@@ -1429,7 +1374,7 @@ x_wm_set_size_hint (FRAME_PTR f, long int flags, bool user_position)
    BG is the pixel value to change to.  */
 
 void
-xg_set_background_color (FRAME_PTR f, long unsigned int bg)
+xg_set_background_color (struct frame *f, unsigned long bg)
 {
   if (FRAME_GTK_WIDGET (f))
     {
@@ -1444,7 +1389,7 @@ xg_set_background_color (FRAME_PTR f, long unsigned int bg)
    functions so GTK does not overwrite the icon.  */
 
 void
-xg_set_frame_icon (FRAME_PTR f, Pixmap icon_pixmap, Pixmap icon_mask)
+xg_set_frame_icon (struct frame *f, Pixmap icon_pixmap, Pixmap icon_mask)
 {
   GdkPixbuf *gp = xg_get_pixbuf_from_pix_and_mask (f,
                                                    icon_pixmap,
@@ -1639,7 +1584,7 @@ xg_dialog_response_cb (GtkDialog *w,
                       gint response,
                       gpointer user_data)
 {
-  struct xg_dialog_data *dd = (struct xg_dialog_data *)user_data;
+  struct xg_dialog_data *dd = user_data;
   dd->response = response;
   g_main_loop_quit (dd->loop);
 }
@@ -1647,10 +1592,10 @@ xg_dialog_response_cb (GtkDialog *w,
 
 /*  Destroy the dialog.  This makes it pop down.  */
 
-static Lisp_Object
-pop_down_dialog (Lisp_Object arg)
+static void
+pop_down_dialog (void *arg)
 {
-  struct xg_dialog_data *dd = XSAVE_POINTER (arg, 0);
+  struct xg_dialog_data *dd = arg;
 
   block_input ();
   if (dd->w) gtk_widget_destroy (dd->w);
@@ -1660,8 +1605,6 @@ pop_down_dialog (Lisp_Object arg)
   g_main_loop_unref (dd->loop);
 
   unblock_input ();
-
-  return Qnil;
 }
 
 /* If there are any emacs timers pending, add a timeout to main loop in DATA.
@@ -1670,16 +1613,16 @@ pop_down_dialog (Lisp_Object arg)
 static gboolean
 xg_maybe_add_timer (gpointer data)
 {
-  struct xg_dialog_data *dd = (struct xg_dialog_data *) data;
-  EMACS_TIME next_time = timer_check ();
+  struct xg_dialog_data *dd = data;
+  struct timespec next_time = timer_check ();
 
   dd->timerid = 0;
 
-  if (EMACS_TIME_VALID_P (next_time))
+  if (timespec_valid_p (next_time))
     {
-      time_t s = EMACS_SECS (next_time);
-      int per_ms = EMACS_TIME_RESOLUTION / 1000;
-      int ms = (EMACS_NSECS (next_time) + per_ms - 1) / per_ms;
+      time_t s = next_time.tv_sec;
+      int per_ms = TIMESPEC_RESOLUTION / 1000;
+      int ms = (next_time.tv_nsec + per_ms - 1) / per_ms;
       if (s <= ((guint) -1 - ms) / 1000)
        dd->timerid = g_timeout_add (s * 1000 + ms, xg_maybe_add_timer, dd);
     }
@@ -1692,9 +1635,9 @@ xg_maybe_add_timer (gpointer data)
    The dialog W is not destroyed when this function returns.  */
 
 static int
-xg_dialog_run (FRAME_PTR f, GtkWidget *w)
+xg_dialog_run (struct frame *f, GtkWidget *w)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   struct xg_dialog_data dd;
 
   xg_set_screen (w, f);
@@ -1716,13 +1659,13 @@ xg_dialog_run (FRAME_PTR f, GtkWidget *w)
   g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL);
   gtk_widget_show (w);
 
-  record_unwind_protect (pop_down_dialog, make_save_pointer (&dd));
+  record_unwind_protect_ptr (pop_down_dialog, &dd);
 
   (void) xg_maybe_add_timer (&dd);
   g_main_loop_run (dd.loop);
 
   dd.w = 0;
-  unbind_to (count, Qnil);
+  dynwind_end ();
 
   return dd.response;
 }
@@ -1752,7 +1695,13 @@ typedef char * (*xg_get_file_func) (GtkWidget *);
 static char *
 xg_get_file_name_from_chooser (GtkWidget *w)
 {
-  return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w));
+  char *s1, *s2;
+  s1 = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w));
+  if (! s1)
+    return NULL;
+  s2 = xstrdup (s1);
+  g_free (s1);
+  return s2;
 }
 
 /* Callback called when the "Show hidden files" toggle is pressed.
@@ -1812,7 +1761,7 @@ xg_toggle_notify_cb (GObject *gobject, GParamSpec *arg1, gpointer user_data)
    Returns the created widget.  */
 
 static GtkWidget *
-xg_get_file_with_chooser (FRAME_PTR f,
+xg_get_file_with_chooser (struct frame *f,
                          char *prompt,
                          char *default_filename,
                          bool mustmatch_p, bool only_dir_p,
@@ -1920,7 +1869,7 @@ static char *
 xg_get_file_name_from_selector (GtkWidget *w)
 {
   GtkFileSelection *filesel = GTK_FILE_SELECTION (w);
-  return xstrdup ((char*) gtk_file_selection_get_filename (filesel));
+  return xstrdup (gtk_file_selection_get_filename (filesel));
 }
 
 /* Create a file selection dialog.
@@ -1934,7 +1883,7 @@ xg_get_file_name_from_selector (GtkWidget *w)
    Returns the created widget.  */
 
 static GtkWidget *
-xg_get_file_with_selection (FRAME_PTR f,
+xg_get_file_with_selection (struct frame *f,
                             char *prompt,
                             char *default_filename,
                             bool mustmatch_p, bool only_dir_p,
@@ -1976,7 +1925,7 @@ xg_get_file_with_selection (FRAME_PTR f,
    The returned string must be freed by the caller.  */
 
 char *
-xg_get_file_name (FRAME_PTR f,
+xg_get_file_name (struct frame *f,
                   char *prompt,
                   char *default_filename,
                   bool mustmatch_p,
@@ -2038,7 +1987,6 @@ xg_get_file_name (FRAME_PTR f,
 
 
 static char *x_last_font_name;
-extern Lisp_Object Qxft;
 
 /* Pop up a GTK font selector and return the name of the font the user
    selects, as a C string.  The returned font name follows GTK's own
@@ -2050,7 +1998,7 @@ extern Lisp_Object Qxft;
    DEFAULT_NAME, if non-zero, is the default font name.  */
 
 Lisp_Object
-xg_get_font (FRAME_PTR f, const char *default_name)
+xg_get_font (struct frame *f, const char *default_name)
 {
   GtkWidget *w;
   int done = 0;
@@ -2113,8 +2061,7 @@ xg_get_font (FRAME_PTR f, const char *default_name)
          font = Ffont_spec (8, args);
 
          pango_font_description_free (desc);
-         xfree (x_last_font_name);
-         x_last_font_name = xstrdup (name);
+         dupstring (&x_last_font_name, name);
        }
 
 #else /* Use old font selector, which just returns the font name.  */
@@ -2168,11 +2115,11 @@ static xg_list_node xg_menu_item_cb_list;
    allocated xg_menu_cb_data if CL_DATA is NULL.  */
 
 static xg_menu_cb_data *
-make_cl_data (xg_menu_cb_data *cl_data, FRAME_PTR f, GCallback highlight_cb)
+make_cl_data (xg_menu_cb_data *cl_data, struct frame *f, GCallback highlight_cb)
 {
   if (! cl_data)
     {
-      cl_data = xmalloc (sizeof *cl_data);
+      cl_data = xmalloc_uncollectable (sizeof *cl_data);
       cl_data->f = f;
       cl_data->menu_bar_vector = f->menu_bar_vector;
       cl_data->menu_bar_items_used = f->menu_bar_items_used;
@@ -2200,7 +2147,7 @@ make_cl_data (xg_menu_cb_data *cl_data, FRAME_PTR f, GCallback highlight_cb)
 
 static void
 update_cl_data (xg_menu_cb_data *cl_data,
-                FRAME_PTR f,
+                struct frame *f,
                 GCallback highlight_cb)
 {
   if (cl_data)
@@ -2229,44 +2176,6 @@ unref_cl_data (xg_menu_cb_data *cl_data)
     }
 }
 
-/* Function that marks all lisp data during GC.  */
-
-void
-xg_mark_data (void)
-{
-  xg_list_node *iter;
-  Lisp_Object rest, frame;
-
-  for (iter = xg_menu_cb_list.next; iter; iter = iter->next)
-    mark_object (((xg_menu_cb_data *) iter)->menu_bar_vector);
-
-  for (iter = xg_menu_item_cb_list.next; iter; iter = iter->next)
-    {
-      xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data *) iter;
-
-      if (! NILP (cb_data->help))
-        mark_object (cb_data->help);
-    }
-
-  FOR_EACH_FRAME (rest, frame)
-    {
-      FRAME_PTR f = XFRAME (frame);
-
-      if (FRAME_X_P (f) && FRAME_GTK_OUTER_WIDGET (f))
-        {
-          struct xg_frame_tb_info *tbinfo
-            = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
-                                 TB_INFO_KEY);
-          if (tbinfo)
-            {
-              mark_object (tbinfo->last_tool_bar);
-              mark_object (tbinfo->style);
-            }
-        }
-    }
-}
-
-
 /* Callback called when a menu item is destroyed.  Used to free data.
    W is the widget that is being destroyed (not used).
    CLIENT_DATA points to the xg_menu_item_cb_data associated with the W.  */
@@ -2276,7 +2185,7 @@ menuitem_destroy_callback (GtkWidget *w, gpointer client_data)
 {
   if (client_data)
     {
-      xg_menu_item_cb_data *data = (xg_menu_item_cb_data*) client_data;
+      xg_menu_item_cb_data *data = client_data;
       xg_list_remove (&xg_menu_item_cb_list, &data->ptrs);
       xfree (data);
     }
@@ -2300,8 +2209,7 @@ menuitem_highlight_callback (GtkWidget *w,
 
   ev.crossing = *event;
   subwidget = gtk_get_event_widget (&ev);
-  data = (xg_menu_item_cb_data *) g_object_get_data (G_OBJECT (subwidget),
-                                                     XG_ITEM_DATA);
+  data = g_object_get_data (G_OBJECT (subwidget), XG_ITEM_DATA);
   if (data)
     {
       if (! NILP (data->help) && data->cl_data->highlight_cb)
@@ -2322,7 +2230,7 @@ menuitem_highlight_callback (GtkWidget *w,
 static void
 menu_destroy_callback (GtkWidget *w, gpointer client_data)
 {
-  unref_cl_data ((xg_menu_cb_data*) client_data);
+  unref_cl_data (client_data);
 }
 
 /* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both
@@ -2422,9 +2330,12 @@ static int xg_detached_menus;
 /* Return true if there are detached menus.  */
 
 bool
-xg_have_tear_offs (void)
+xg_have_tear_offs (struct frame *f)
 {
-  return xg_detached_menus > 0;
+  /* If the frame's menubar height is zero, the menu bar is probably
+     being redirected outside the window to some kind of global menu;
+     this situation is the moral equivalent of a tear-off.  */
+  return FRAME_MENUBAR_HEIGHT (f) == 0 || xg_detached_menus > 0;
 }
 
 /* Callback invoked when a detached menu window is removed.  Here we
@@ -2457,9 +2368,9 @@ tearoff_activate (GtkWidget *widget, gpointer client_data)
 }
 #else /* ! HAVE_GTK_TEAROFF_MENU_ITEM_NEW */
 bool
-xg_have_tear_offs (void)
+xg_have_tear_offs (struct frame *f)
 {
-  return false;
+  return FRAME_MENUBAR_HEIGHT (f) == 0;
 }
 #endif /* ! HAVE_GTK_TEAROFF_MENU_ITEM_NEW */
 
@@ -2479,7 +2390,7 @@ xg_have_tear_offs (void)
 
 static GtkWidget *
 xg_create_one_menuitem (widget_value *item,
-                        FRAME_PTR f,
+                        struct frame *f,
                         GCallback select_cb,
                         GCallback highlight_cb,
                         xg_menu_cb_data *cl_data,
@@ -2550,7 +2461,7 @@ xg_create_one_menuitem (widget_value *item,
 
 static GtkWidget *
 create_menus (widget_value *data,
-              FRAME_PTR f,
+              struct frame *f,
               GCallback select_cb,
               GCallback deactivate_cb,
               GCallback highlight_cb,
@@ -2693,9 +2604,9 @@ create_menus (widget_value *data,
    Returns the widget created.  */
 
 GtkWidget *
-xg_create_widget (const char *type, const char *name, FRAME_PTR f, widget_value *val,
-                  GCallback select_cb, GCallback deactivate_cb,
-                 GCallback highlight_cb)
+xg_create_widget (const char *type, const char *name, struct frame *f,
+                 widget_value *val, GCallback select_cb,
+                 GCallback deactivate_cb, GCallback highlight_cb)
 {
   GtkWidget *w = 0;
   bool menu_bar_p = strcmp (type, "menubar") == 0;
@@ -2731,7 +2642,7 @@ xg_create_widget (const char *type, const char *name, FRAME_PTR f, widget_value
         {
           /* Must realize so the GdkWindow inside the widget is created.  */
           gtk_widget_realize (w);
-          xg_set_cursor (w, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
+          xg_set_cursor (w, FRAME_DISPLAY_INFO (f)->xg_cursor);
         }
     }
   else
@@ -2801,7 +2712,7 @@ xg_destroy_widgets (GList *list)
 
 static void
 xg_update_menubar (GtkWidget *menubar,
-                  FRAME_PTR f,
+                  struct frame *f,
                   GList **list,
                   GList *iter,
                   int pos,
@@ -2905,7 +2816,13 @@ xg_update_menubar (GtkWidget *menubar,
           char *utf8_label = get_utf8_string (val->name);
           GtkWidget *submenu = gtk_menu_item_get_submenu (witem);
 
+          /* GTK menu items don't notice when their labels have been
+             changed from underneath them, so we have to explicitly
+             use g_object_notify to tell listeners (e.g., a GMenuModel
+             bridge that might be loaded) that the item's label has
+             changed.  */
           gtk_label_set_text (wlabel, utf8_label);
+          g_object_notify (G_OBJECT (witem), "label");
 
 #ifdef HAVE_GTK_TEAROFF_MENU_ITEM_NEW
           /* If this item has a submenu that has been detached, change
@@ -2942,6 +2859,7 @@ xg_update_menubar (GtkWidget *menubar,
                                              select_cb, deactivate_cb,
                                              highlight_cb,
                                              0, 0, 0, 0, cl_data, 0);
+
           gtk_widget_set_name (w, MENU_ITEM_NAME);
           gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), w, pos);
           gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
@@ -3001,6 +2919,7 @@ xg_update_menu_item (widget_value *val,
   const char *old_label = 0;
   const char *old_key = 0;
   xg_menu_item_cb_data *cb_data;
+  bool label_changed = false;
 
   wchild = XG_BIN_CHILD (w);
   utf8_label = get_utf8_string (val->name);
@@ -3045,15 +2964,20 @@ xg_update_menu_item (widget_value *val,
         }
     }
 
-
   if (wkey) old_key = gtk_label_get_label (wkey);
   if (wlbl) old_label = gtk_label_get_label (wlbl);
 
   if (wkey && utf8_key && (! old_key || strcmp (utf8_key, old_key) != 0))
-    gtk_label_set_text (wkey, utf8_key);
+    {
+      label_changed = true;
+      gtk_label_set_text (wkey, utf8_key);
+    }
 
   if (! old_label || strcmp (utf8_label, old_label) != 0)
-    gtk_label_set_text (wlbl, utf8_label);
+    {
+      label_changed = true;
+      gtk_label_set_text (wlbl, utf8_label);
+    }
 
   if (utf8_key) g_free (utf8_key);
   if (utf8_label) g_free (utf8_label);
@@ -3063,8 +2987,7 @@ xg_update_menu_item (widget_value *val,
   else if (val->enabled && ! gtk_widget_get_sensitive (w))
     gtk_widget_set_sensitive (w, TRUE);
 
-  cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (w),
-                                                       XG_ITEM_DATA);
+  cb_data = g_object_get_data (G_OBJECT (w), XG_ITEM_DATA);
   if (cb_data)
     {
       cb_data->call_data = val->call_data;
@@ -3086,6 +3009,9 @@ xg_update_menu_item (widget_value *val,
           cb_data->select_id = 0;
         }
     }
+
+  if (label_changed) /* See comment in xg_update_menubar.  */
+    g_object_notify (G_OBJECT (w), "label");
 }
 
 /* Update the toggle menu item W so it corresponds to VAL.  */
@@ -3118,7 +3044,7 @@ xg_update_radio_item (widget_value *val, GtkWidget *w)
 
 static GtkWidget *
 xg_update_submenu (GtkWidget *submenu,
-                  FRAME_PTR f,
+                  struct frame *f,
                   widget_value *val,
                   GCallback select_cb,
                   GCallback deactivate_cb,
@@ -3260,8 +3186,8 @@ xg_update_submenu (GtkWidget *submenu,
    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.  */
 
 void
-xg_modify_menubar_widgets (GtkWidget *menubar, FRAME_PTR f, widget_value *val,
-                          bool deep_p,
+xg_modify_menubar_widgets (GtkWidget *menubar, struct frame *f,
+                          widget_value *val, bool deep_p,
                            GCallback select_cb, GCallback deactivate_cb,
                           GCallback highlight_cb)
 {
@@ -3270,8 +3196,7 @@ xg_modify_menubar_widgets (GtkWidget *menubar, FRAME_PTR f, widget_value *val,
 
   if (! list) return;
 
-  cl_data = (xg_menu_cb_data*) g_object_get_data (G_OBJECT (menubar),
-                                                  XG_FRAME_DATA);
+  cl_data = g_object_get_data (G_OBJECT (menubar), XG_FRAME_DATA);
 
   xg_update_menubar (menubar, f, &list, list, 0, val->contents,
                      select_cb, deactivate_cb, highlight_cb, cl_data);
@@ -3335,7 +3260,7 @@ static void
 menubar_map_cb (GtkWidget *w, gpointer user_data)
 {
   GtkRequisition req;
-  FRAME_PTR f = (FRAME_PTR) user_data;
+  struct frame *f = user_data;
   gtk_widget_get_preferred_size (w, NULL, &req);
   if (FRAME_MENUBAR_HEIGHT (f) != req.height)
     {
@@ -3348,7 +3273,7 @@ menubar_map_cb (GtkWidget *w, gpointer user_data)
    changed.  */
 
 void
-xg_update_frame_menubar (FRAME_PTR f)
+xg_update_frame_menubar (struct frame *f)
 {
   struct x_output *x = f->output_data.x;
   GtkRequisition req;
@@ -3369,11 +3294,6 @@ xg_update_frame_menubar (FRAME_PTR f)
   gtk_widget_show_all (x->menubar_widget);
   gtk_widget_get_preferred_size (x->menubar_widget, NULL, &req);
 
-  /* If menu bar doesn't know its height yet, cheat a little so the frame
-     doesn't jump so much when resized later in menubar_map_cb.  */
-  if (req.height == 0)
-    req.height = 23;
-
   if (FRAME_MENUBAR_HEIGHT (f) != req.height)
     {
       FRAME_MENUBAR_HEIGHT (f) = req.height;
@@ -3386,7 +3306,7 @@ xg_update_frame_menubar (FRAME_PTR f)
    This is used when deleting a frame, and when turning off the menu bar.  */
 
 void
-free_frame_menubar (FRAME_PTR f)
+free_frame_menubar (struct frame *f)
 {
   struct x_output *x = f->output_data.x;
 
@@ -3405,7 +3325,7 @@ free_frame_menubar (FRAME_PTR f)
 }
 
 bool
-xg_event_is_for_menubar (FRAME_PTR f, XEvent *event)
+xg_event_is_for_menubar (struct frame *f, const XEvent *event)
 {
   struct x_output *x = f->output_data.x;
   GList *iter;
@@ -3618,7 +3538,7 @@ xg_gtk_scroll_destroy (GtkWidget *widget, gpointer data)
    to set resources for the widget.  */
 
 void
-xg_create_scroll_bar (FRAME_PTR f,
+xg_create_scroll_bar (struct frame *f,
                       struct scroll_bar *bar,
                       GCallback scroll_callback,
                       GCallback end_callback,
@@ -3672,7 +3592,7 @@ xg_create_scroll_bar (FRAME_PTR f,
 
 
   /* Set the cursor to an arrow.  */
-  xg_set_cursor (webox, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
+  xg_set_cursor (webox, FRAME_DISPLAY_INFO (f)->xg_cursor);
 
   bar->x_window = scroll_id;
 }
@@ -3680,7 +3600,7 @@ xg_create_scroll_bar (FRAME_PTR f,
 /* Remove the scroll bar represented by SCROLLBAR_ID from the frame F.  */
 
 void
-xg_remove_scroll_bar (FRAME_PTR f, ptrdiff_t scrollbar_id)
+xg_remove_scroll_bar (struct frame *f, ptrdiff_t scrollbar_id)
 {
   GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
   if (w)
@@ -3698,7 +3618,7 @@ xg_remove_scroll_bar (FRAME_PTR f, ptrdiff_t scrollbar_id)
    WIDTH, HEIGHT is the size in pixels the bar shall have.  */
 
 void
-xg_update_scrollbar_pos (FRAME_PTR f,
+xg_update_scrollbar_pos (struct frame *f,
                          ptrdiff_t scrollbar_id,
                          int top,
                          int left,
@@ -3741,14 +3661,11 @@ xg_update_scrollbar_pos (FRAME_PTR f,
       gtk_widget_queue_draw (wfixed);
       gdk_window_process_all_updates ();
       if (oldx != -1 && oldw > 0 && oldh > 0)
-        {
-          /* Clear under old scroll bar position.  This must be done after
-             the gtk_widget_queue_draw and gdk_window_process_all_updates
-             above.  */
-          x_clear_area (FRAME_X_DISPLAY (f),
-                        FRAME_X_WINDOW (f),
-                        oldx, oldy, oldw, oldh, 0);
-        }
+       /* Clear under old scroll bar position.  This must be done after
+          the gtk_widget_queue_draw and gdk_window_process_all_updates
+          above.  */
+       x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                     oldx, oldy, oldw, oldh);
 
       /* GTK does not redraw until the main loop is entered again, but
          if there are no X events pending we will not enter it.  So we sync
@@ -3780,9 +3697,9 @@ xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar,
 {
   GtkWidget *wscroll = xg_get_widget_from_map (bar->x_window);
 
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+  struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
 
-  if (wscroll && NILP (bar->dragging))
+  if (wscroll && bar->dragging == -1)
     {
       GtkAdjustment *adj;
       gdouble shown;
@@ -3860,7 +3777,7 @@ xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar,
    frame.  This function does additional checks.  */
 
 bool
-xg_event_is_for_scrollbar (FRAME_PTR f, XEvent *event)
+xg_event_is_for_scrollbar (struct frame *f, const XEvent *event)
 {
   bool retval = 0;
 
@@ -3945,7 +3862,7 @@ xg_tool_bar_callback (GtkWidget *w, gpointer client_data)
   gpointer gmod = g_object_get_data (G_OBJECT (w), XG_TOOL_BAR_LAST_MODIFIER);
   intptr_t mod = (intptr_t) gmod;
 
-  FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
+  struct frame *f = g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
   Lisp_Object key, frame;
   struct input_event event;
   EVENT_INIT (event);
@@ -3971,12 +3888,12 @@ xg_tool_bar_callback (GtkWidget *w, gpointer client_data)
   /* Convert between the modifier bits GDK uses and the modifier bits
      Emacs uses.  This assumes GDK and X masks are the same, which they are when
      this is written.  */
-  event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), mod);
+  event.modifiers = x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), mod);
   kbd_buffer_store_event (&event);
 
-   /* Return focus to the frame after we have clicked on a detached
-      tool bar button. */
-   Fx_focus_frame (frame);
+  /* Return focus to the frame after we have clicked on a detached
+     tool bar button. */
+  x_focus_frame (f);
 }
 
 /* Callback function invoked when a tool bar item is pressed in a detached
@@ -4018,8 +3935,8 @@ static GtkWidget *
 xg_get_tool_bar_widgets (GtkWidget *vb, GtkWidget **wimage)
 {
   GList *clist = gtk_container_get_children (GTK_CONTAINER (vb));
-  GtkWidget *c1 = (GtkWidget *) clist->data;
-  GtkWidget *c2 = clist->next ? (GtkWidget *) clist->next->data : NULL;
+  GtkWidget *c1 = clist->data;
+  GtkWidget *c2 = clist->next ? clist->next->data : NULL;
 
   *wimage = GTK_IS_IMAGE (c1) ? c1 : c2;
   g_list_free (clist);
@@ -4148,7 +4065,7 @@ xg_tool_bar_detach_callback (GtkHandleBox *wbox,
                              GtkWidget *w,
                              gpointer client_data)
 {
-  FRAME_PTR f = (FRAME_PTR) client_data;
+  struct frame *f = client_data;
 
   g_object_set (G_OBJECT (w), "show-arrow", !x_gtk_whole_detached_tool_bar,
                NULL);
@@ -4185,7 +4102,7 @@ xg_tool_bar_attach_callback (GtkHandleBox *wbox,
                              GtkWidget *w,
                              gpointer client_data)
 {
-  FRAME_PTR f = (FRAME_PTR) client_data;
+  struct frame *f = client_data;
   g_object_set (G_OBJECT (w), "show-arrow", TRUE, NULL);
 
   if (f)
@@ -4223,7 +4140,7 @@ xg_tool_bar_help_callback (GtkWidget *w,
                            gpointer client_data)
 {
   intptr_t idx = (intptr_t) client_data;
-  FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
+  struct frame *f = g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
   Lisp_Object help, frame;
 
   if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
@@ -4296,7 +4213,7 @@ xg_tool_bar_item_expose_callback (GtkWidget *w,
 /* Attach a tool bar to frame F.  */
 
 static void
-xg_pack_tool_bar (FRAME_PTR f, Lisp_Object pos)
+xg_pack_tool_bar (struct frame *f, Lisp_Object pos)
 {
   struct x_output *x = f->output_data.x;
   bool into_hbox = EQ (pos, Qleft) || EQ (pos, Qright);
@@ -4353,10 +4270,25 @@ xg_pack_tool_bar (FRAME_PTR f, Lisp_Object pos)
   x->toolbar_is_packed = true;
 }
 
+static bool xg_update_tool_bar_sizes (struct frame *f);
+
+static void
+tb_size_cb (GtkWidget    *widget,
+            GdkRectangle *allocation,
+            gpointer      user_data)
+{
+  /* When tool bar is created it has one preferred size.  But when size is
+     allocated between widgets, it may get another.  So we must update
+     size hints if tool bar size changes.  Seen on Fedora 18 at least.  */
+  struct frame *f = user_data;
+  if (xg_update_tool_bar_sizes (f))
+    xg_height_or_width_changed (f);
+}
+
 /* Create a tool bar for frame F.  */
 
 static void
-xg_create_tool_bar (FRAME_PTR f)
+xg_create_tool_bar (struct frame *f)
 {
   struct x_output *x = f->output_data.x;
 #if GTK_CHECK_VERSION (3, 3, 6)
@@ -4384,6 +4316,8 @@ xg_create_tool_bar (FRAME_PTR f)
 
   gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
   toolbar_set_orientation (x->toolbar_widget, GTK_ORIENTATION_HORIZONTAL);
+  g_signal_connect (x->toolbar_widget, "size-allocate",
+                    G_CALLBACK (tb_size_cb), f);
 #if GTK_CHECK_VERSION (3, 3, 6)
   gsty = gtk_widget_get_style_context (x->toolbar_widget);
   gtk_style_context_add_class (gsty, "primary-toolbar");
@@ -4397,7 +4331,7 @@ xg_create_tool_bar (FRAME_PTR f)
    Returns IMAGE if RTL is not found.  */
 
 static Lisp_Object
-find_rtl_image (FRAME_PTR f, Lisp_Object image, Lisp_Object rtl)
+find_rtl_image (struct frame *f, Lisp_Object image, Lisp_Object rtl)
 {
   int i;
   Lisp_Object file, rtl_name;
@@ -4425,7 +4359,7 @@ find_rtl_image (FRAME_PTR f, Lisp_Object image, Lisp_Object rtl)
 }
 
 static GtkToolItem *
-xg_make_tool_item (FRAME_PTR f,
+xg_make_tool_item (struct frame *f,
                    GtkWidget *wimage,
                    GtkWidget **wbutton,
                    const char *label,
@@ -4588,7 +4522,7 @@ xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name,
 }
 
 static bool
-xg_update_tool_bar_sizes (FRAME_PTR f)
+xg_update_tool_bar_sizes (struct frame *f)
 {
   struct x_output *x = f->output_data.x;
   GtkRequisition req;
@@ -4636,7 +4570,7 @@ xg_update_tool_bar_sizes (FRAME_PTR f)
 /* Update the tool bar for frame F.  Add new buttons and remove old.  */
 
 void
-update_frame_tool_bar (FRAME_PTR f)
+update_frame_tool_bar (struct frame *f)
 {
   int i, j;
   struct x_output *x = f->output_data.x;
@@ -4859,15 +4793,15 @@ update_frame_tool_bar (FRAME_PTR f)
             {
               w = gtk_image_new_from_stock (stock_name, icon_size);
               g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_STOCK_NAME,
-                                      (gpointer) xstrdup (stock_name),
-                                      (GDestroyNotify) xfree);
+                                      (gpointer) g_strdup (stock_name),
+                                      (GDestroyNotify) g_free);
             }
           else if (icon_name)
             {
               w = gtk_image_new_from_icon_name (icon_name, icon_size);
               g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_ICON_NAME,
-                                      (gpointer) xstrdup (icon_name),
-                                      (GDestroyNotify) xfree);
+                                      (gpointer) g_strdup (icon_name),
+                                      (GDestroyNotify) g_free);
             }
           else
             {
@@ -4911,7 +4845,7 @@ update_frame_tool_bar (FRAME_PTR f)
    Remove the tool bar.  */
 
 void
-free_frame_tool_bar (FRAME_PTR f)
+free_frame_tool_bar (struct frame *f)
 {
   struct x_output *x = f->output_data.x;
 
@@ -4958,7 +4892,7 @@ free_frame_tool_bar (FRAME_PTR f)
 }
 
 void
-xg_change_toolbar_position (FRAME_PTR f, Lisp_Object pos)
+xg_change_toolbar_position (struct frame *f, Lisp_Object pos)
 {
   struct x_output *x = f->output_data.x;
   GtkWidget *top_widget = TOOLBAR_TOP_WIDGET (x);
@@ -5018,10 +4952,10 @@ xg_initialize (void)
                                           (gdk_display_get_default ()));
   /* Remove F10 as a menu accelerator, it does not mix well with Emacs key
      bindings.  It doesn't seem to be any way to remove properties,
-     so we set it to VoidSymbol which in X means "no key".  */
+     so we set it to "" which in means "no key".  */
   gtk_settings_set_string_property (settings,
                                     "gtk-menu-bar-accel",
-                                    "VoidSymbol",
+                                    "",
                                     EMACS_CLASS);
 
   /* Make GTK text input widgets use Emacs style keybindings.  This is