Based on  3f4c6d52d345999938bc2d4a53246af4c61ef176 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Dj=C3=A4rv?= <jan.h.d@swipnet.se>
Date: Sat, 18 Oct 2014 18:19:53 +0200
Subject: [PATCH] Handle deprecated Gtk+ stuff for version <= 3.10

* lisp/term/x-win.el (x-gtk-stock-map): Add icon names suggested as
replacements to stock names before stock names in a list.
Cdr may be a list, each name is tried in turn until one is found.

* src/gtkutil.c (XG_TEXT_CANCEL, XG_TEXT_OPEN, XG_TEXT_OK): New defines
to handle Gtk versions.
(xg_get_file_with_chooser): Use them.
(xg_have_tear_offs, tearoff_remove, tearoff_activate): Remove
(create_menus): Remove teroff argument and code.
Remove call to gtk_menu_set_title.
(xg_update_menubar, xg_update_submenu): Remove tearoff code.  Adjust
args to create_menus.
(xg_tool_bar_menu_proxy, xg_tool_bar_detach_callback)
(xg_tool_bar_attach_callback, TOOLBAR_TOP_WIDGET): Remove.
(xg_pack_tool_bar): Replace TOOLBAR_TOP_WIDGET, remove detach code.
(xg_make_tool_item): Remove detach code.
(xg_update_tool_bar_sizes): Replace TOOLBAR_TOP_WIDGET.
(find_icon_from_name): New function.
(update_frame_tool_bar): Remove GtkStockItem code, move to
find_icon_from_name.  Let stock be a list of icon names to try.
Only use gtk_image_new_from_stock on Gtk+ < 3.10.
Replace TOOLBAR_TOP_WIDGET.
(free_frame_tool_bar, xg_change_toolbar_position ): Replace
TOOLBAR_TOP_WIDGET.
(xg_initialize): Remove tearoff code.

* src/gtkutil.h (xg_have_tear_offs): Remove declaration.

* src/xmenu.c (set_frame_menubar): Remove GTK block that calls
xg_have_tear_offs.

* src/xterm.h (handlebox_widget): Remove.

---
 lisp/term/x-win.el |   63 ++--
 src/gtkutil.c      |  681 ++++++++++++++++++++---------------------------------
 src/gtkutil.h      |   12 
 src/xmenu.c        |    6 
 src/xterm.h        |    3 
 5 files changed, 298 insertions(+), 467 deletions(-)

--- lisp/term/x-win.el
+++ lisp/term/x-win.el	2016-12-22 11:56:02.799059569 +0000
@@ -1468,47 +1468,47 @@ Request data types in the order specifie
   (mapcar (lambda (arg)
 	    (cons (purecopy (car arg)) (purecopy (cdr arg))))
   '(
-    ("etc/images/new" . "gtk-new")
-    ("etc/images/open" . "gtk-open")
+    ("etc/images/new" . ("document-new" "gtk-new"))
+    ("etc/images/open" . ("document-open" "gtk-open"))
     ("etc/images/diropen" . "n:system-file-manager")
-    ("etc/images/close" . "gtk-close")
-    ("etc/images/save" . "gtk-save")
-    ("etc/images/saveas" . "gtk-save-as")
-    ("etc/images/undo" . "gtk-undo")
-    ("etc/images/cut" . "gtk-cut")
-    ("etc/images/copy" . "gtk-copy")
-    ("etc/images/paste" . "gtk-paste")
-    ("etc/images/search" . "gtk-find")
-    ("etc/images/print" . "gtk-print")
-    ("etc/images/preferences" . "gtk-preferences")
-    ("etc/images/help" . "gtk-help")
-    ("etc/images/left-arrow" . "gtk-go-back")
-    ("etc/images/right-arrow" . "gtk-go-forward")
-    ("etc/images/home" . "gtk-home")
-    ("etc/images/jump-to" . "gtk-jump-to")
+    ("etc/images/close" . ("window-close" "gtk-close"))
+    ("etc/images/save" . ("document-save" "gtk-save"))
+    ("etc/images/saveas" . ("document-save-as" "gtk-save-as"))
+    ("etc/images/undo" . ("edit-undo" "gtk-undo"))
+    ("etc/images/cut" . ("edit-cut" "gtk-cut"))
+    ("etc/images/copy" . ("edit-copy" "gtk-copy"))
+    ("etc/images/paste" . ("edit-paste" "gtk-paste"))
+    ("etc/images/search" . ("edit-find" "gtk-find"))
+    ("etc/images/print" . ("document-print" "gtk-print"))
+    ("etc/images/preferences" . ("preferences-system" "gtk-preferences"))
+    ("etc/images/help" . ("help-browser" "gtk-help"))
+    ("etc/images/left-arrow" . ("go-previous" "gtk-go-back"))
+    ("etc/images/right-arrow" . ("go-next" "gtk-go-forward"))
+    ("etc/images/home" . ("go-home" "gtk-home"))
+    ("etc/images/jump-to" . ("go-jump" "gtk-jump-to"))
     ("etc/images/index" . "gtk-index")
-    ("etc/images/search" . "gtk-find")
-    ("etc/images/exit" . "gtk-quit")
+    ("etc/images/exit" . ("application-exit" "gtk-quit"))
     ("etc/images/cancel" . "gtk-cancel")
-    ("etc/images/info" . "gtk-info")
+    ("etc/images/info" . ("dialog-information" "gtk-info"))
     ("etc/images/bookmark_add" . "n:bookmark_add")
     ;; Used in Gnus and/or MH-E:
     ("etc/images/attach" . "gtk-attach")
     ("etc/images/connect" . "gtk-connect")
     ("etc/images/contact" . "gtk-contact")
-    ("etc/images/delete" . "gtk-delete")
-    ("etc/images/describe" . "gtk-properties")
+    ("etc/images/delete" . ("edit-delete" "gtk-delete"))
+    ("etc/images/describe" . ("ocument-properties" "gtk-properties"))
     ("etc/images/disconnect" . "gtk-disconnect")
     ;; ("etc/images/exit" . "gtk-exit")
     ("etc/images/lock-broken" . "gtk-lock_broken")
     ("etc/images/lock-ok" . "gtk-lock_ok")
     ("etc/images/lock" . "gtk-lock")
     ("etc/images/next-page" . "gtk-next-page")
-    ("etc/images/refresh" . "gtk-refresh")
-    ("etc/images/sort-ascending" . "gtk-sort-ascending")
+    ("etc/images/refresh" . ("view-refresh" "gtk-refresh"))
+    ("etc/images/sort-ascending" . ("view-sort-ascending" "gtk-sort-ascending"))
     ("etc/images/sort-column-ascending" . "gtk-sort-column-ascending")
     ("etc/images/sort-criteria" . "gtk-sort-criteria")
-    ("etc/images/sort-descending" . "gtk-sort-descending")
+    ("etc/images/sort-descending" . ("view-sort-descending"
+				     "gtk-sort-descending"))
     ("etc/images/sort-row-ascending" . "gtk-sort-row-ascending")
     ("images/gnus/toggle-subscription" . "gtk-task-recurring")
     ("images/mail/compose" . "gtk-mail-compose")
@@ -1525,8 +1525,8 @@ Request data types in the order specifie
     ("images/mail/spam" . "gtk-spam")
     ;; Used for GDB Graphical Interface
     ("images/gud/break" . "gtk-no")
-    ("images/gud/recstart" . "gtk-media-record")
-    ("images/gud/recstop" . "gtk-media-stop")
+    ("images/gud/recstart" . ("media-record" "gtk-media-record"))
+    ("images/gud/recstop" . ("media-playback-stop" "gtk-media-stop"))
     ;; No themed versions available:
     ;; mail/preview (combining stock_mail and stock_zoom)
     ;; mail/save    (combining stock_mail, stock_save and stock_convert)
@@ -1535,9 +1535,12 @@ Request data types in the order specifie
 Emacs must be compiled with the Gtk+ toolkit for this to have any effect.
 A value that begins with n: denotes a named icon instead of a stock icon."
   :version "22.2"
-  :type '(choice (repeat (choice symbol
-				 (cons (string :tag "Emacs icon")
-				       (string :tag "Stock/named")))))
+  :type '(choice (repeat
+		  (choice symbol
+			  (cons (string :tag "Emacs icon")
+				(choice (group (string :tag "Named")
+					       (string :tag "Stock"))
+					(string :tag "Stock/named"))))))
   :group 'x)
 
 (defcustom icon-map-list '(x-gtk-stock-map)
--- src/gtkutil.c
+++ src/gtkutil.c	2016-12-22 11:56:02.799059569 +0000
@@ -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
 #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
 #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,17 @@ along with GNU Emacs.  If not, see <http
 #define  gtk_font_chooser_set_font(x, y) \
   gtk_font_selection_dialog_set_font_name (x, y)
 #endif
+#endif /* HAVE_FREETYPE */
+
+#if GTK_CHECK_VERSION (3, 10, 0)
+#define XG_TEXT_CANCEL "Cancel"
+#define XG_TEXT_OK     "OK"
+#define XG_TEXT_OPEN   "Open"
+#else
+#define XG_TEXT_CANCEL GTK_STOCK_CANCEL
+#define XG_TEXT_OK     GTK_STOCK_OK
+#define XG_TEXT_OPEN   GTK_STOCK_OPEN
+#endif
 
 #ifndef HAVE_GTK3
 #ifdef USE_GTK_TOOLTIP
@@ -202,7 +216,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.  */
@@ -596,14 +610,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);
@@ -813,6 +830,14 @@ xg_hide_tooltip (FRAME_PTR f)
     General functions for creating widgets, resizing, events, e.t.c.
  ***********************************************************************/
 
+static void
+my_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
+		const gchar *msg, gpointer user_data)
+{
+  if (!strstr (msg, "visible children"))
+    fprintf (stderr, "XX %s-WARNING **: %s\n", log_domain, msg);
+}
+
 /* Make a geometry string and pass that to GTK.  It seems this is the
    only way to get geometry position right if the user explicitly
    asked for a position when starting Emacs.
@@ -828,6 +853,7 @@ xg_set_geometry (FRAME_PTR f)
       int top = f->top_pos;
       int yneg = f->size_hint_flags & YNegative;
       char geom_str[sizeof "=x--" + 4 * INT_STRLEN_BOUND (int)];
+      guint id;
 
       if (xneg)
         left = -left;
@@ -840,9 +866,15 @@ xg_set_geometry (FRAME_PTR f)
                (xneg ? '-' : '+'), left,
                (yneg ? '-' : '+'), top);
 
+      /* Silence warning about visible children.  */
+      id = g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
+                              | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
+
       if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
                                       geom_str))
         fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
+
+      g_log_remove_handler ("Gtk", id);
     }
 }
 
@@ -855,29 +887,23 @@ xg_clear_under_internal_border (FRAME_PT
   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), 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);
     }
 }
 
@@ -948,7 +974,6 @@ xg_frame_set_char_size (FRAME_PTR f, int
   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);
 
@@ -968,7 +993,7 @@ xg_frame_set_char_size (FRAME_PTR f, int
      size as fast as possible.
      For unmapped windows, we can set rows/cols.  When
      the frame is mapped again we will (hopefully) get the correct size.  */
-  if (f->async_visible)
+  if (FRAME_VISIBLE_P (f))
     {
       /* Must call this to flush out events */
       (void)gtk_events_pending ();
@@ -1027,7 +1052,7 @@ xg_win_to_widget (Display *dpy, Window w
 /* 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 (FRAME_PTR f, GtkWidget *w, unsigned long pixel)
 {
 #ifdef HAVE_GTK3
   GdkRGBA bg;
@@ -1058,7 +1083,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);
 
@@ -1079,7 +1104,9 @@ style_changed_cb (GObject *go,
       FOR_EACH_FRAME (rest, frame)
         {
           FRAME_PTR f = XFRAME (frame);
-          if (FRAME_X_DISPLAY (f) == dpy)
+          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));
@@ -1138,7 +1165,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
 
@@ -1323,6 +1351,7 @@ x_wm_set_size_hint (FRAME_PTR f, long in
   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
@@ -1330,6 +1359,16 @@ x_wm_set_size_hint (FRAME_PTR f, long in
   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));
@@ -1353,14 +1392,14 @@ x_wm_set_size_hint (FRAME_PTR f, long in
   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);
   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.  */
@@ -1414,7 +1453,7 @@ x_wm_set_size_hint (FRAME_PTR f, long in
    BG is the pixel value to change to.  */
 
 void
-xg_set_background_color (FRAME_PTR f, long unsigned int bg)
+xg_set_background_color (FRAME_PTR f, unsigned long bg)
 {
   if (FRAME_GTK_WIDGET (f))
     {
@@ -1624,7 +1663,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);
 }
@@ -1816,9 +1855,9 @@ xg_get_file_with_chooser (FRAME_PTR f,
     action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
 
   filewin = gtk_file_chooser_dialog_new (prompt, gwin, action,
-                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                         XG_TEXT_CANCEL, GTK_RESPONSE_CANCEL,
                                          (mustmatch_p || only_dir_p ?
-                                          GTK_STOCK_OPEN : GTK_STOCK_OK),
+                                          XG_TEXT_OPEN : XG_TEXT_OK),
                                          GTK_RESPONSE_OK,
                                          NULL);
   gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filewin), TRUE);
@@ -1906,7 +1945,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.
@@ -2262,7 +2301,7 @@ menuitem_destroy_callback (GtkWidget *w,
 {
   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);
     }
@@ -2286,8 +2325,7 @@ menuitem_highlight_callback (GtkWidget *
 
   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)
@@ -2308,7 +2346,7 @@ menuitem_highlight_callback (GtkWidget *
 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
@@ -2401,46 +2439,6 @@ make_menu_item (const char *utf8_label,
   return w;
 }
 
-static int xg_detached_menus;
-
-/* Return true if there are detached menus.  */
-
-bool
-xg_have_tear_offs (void)
-{
-  return xg_detached_menus > 0;
-}
-
-/* Callback invoked when a detached menu window is removed.  Here we
-   decrease the xg_detached_menus count.
-   WIDGET is the top level window that is removed (the parent of the menu).
-   CLIENT_DATA is not used.  */
-
-static void
-tearoff_remove (GtkWidget *widget, gpointer client_data)
-{
-  if (xg_detached_menus > 0) --xg_detached_menus;
-}
-
-/* Callback invoked when a menu is detached.  It increases the
-   xg_detached_menus count.
-   WIDGET is the GtkTearoffMenuItem.
-   CLIENT_DATA is not used.  */
-
-static void
-tearoff_activate (GtkWidget *widget, gpointer client_data)
-{
-  GtkWidget *menu = gtk_widget_get_parent (widget);
-  if (gtk_menu_get_tearoff_state (GTK_MENU (menu)))
-    {
-      ++xg_detached_menus;
-      g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
-                        "destroy",
-                        G_CALLBACK (tearoff_remove), 0);
-    }
-}
-
-
 /* Create a menu item widget, and connect the callbacks.
    ITEM describes the menu item.
    F is the frame the created menu belongs to.
@@ -2511,7 +2509,6 @@ xg_create_one_menuitem (widget_value *it
    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
    If POP_UP_P, create a popup menu.
    If MENU_BAR_P, create a menu bar.
-   If ADD_TEAROFF_P, add a tearoff menu item.  Ignored if MENU_BAR_P.
    TOPMENU is the topmost GtkWidget that others shall be placed under.
    It may be NULL, in that case we create the appropriate widget
    (menu bar or menu item depending on POP_UP_P and MENU_BAR_P)
@@ -2533,7 +2530,6 @@ create_menus (widget_value *data,
               GCallback highlight_cb,
               bool pop_up_p,
               bool menu_bar_p,
-              bool add_tearoff_p,
               GtkWidget *topmenu,
               xg_menu_cb_data *cl_data,
               const char *name)
@@ -2584,15 +2580,6 @@ create_menus (widget_value *data,
                           "selection-done", deactivate_cb, 0);
     }
 
-  if (! menu_bar_p && add_tearoff_p)
-    {
-      GtkWidget *tearoff = gtk_tearoff_menu_item_new ();
-      gtk_menu_shell_append (GTK_MENU_SHELL (wmenu), tearoff);
-
-      g_signal_connect (G_OBJECT (tearoff), "activate",
-                        G_CALLBACK (tearoff_activate), 0);
-    }
-
   for (item = data; item; item = item->next)
     {
       GtkWidget *w;
@@ -2606,7 +2593,6 @@ create_menus (widget_value *data,
           group = NULL;
           utf8_label = get_utf8_string (item->name);
 
-          gtk_menu_set_title (GTK_MENU (wmenu), utf8_label);
           w = gtk_menu_item_new_with_label (utf8_label);
           gtk_widget_set_sensitive (w, FALSE);
           if (utf8_label) g_free (utf8_label);
@@ -2637,7 +2623,6 @@ create_menus (widget_value *data,
                                                  highlight_cb,
                                                  0,
                                                  0,
-                                                 add_tearoff_p,
                                                  0,
                                                  cl_data,
                                                  0);
@@ -2668,9 +2653,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, FRAME_PTR f,
+		  widget_value *val, GCallback select_cb,
+		  GCallback deactivate_cb, GCallback highlight_cb)
 {
   GtkWidget *w = 0;
   bool menu_bar_p = strcmp (type, "menubar") == 0;
@@ -2695,7 +2680,6 @@ xg_create_widget (const char *type, cons
                         highlight_cb,
                         pop_up_p,
                         menu_bar_p,
-                        menu_bar_p,
                         0,
                         0,
                         name);
@@ -2805,7 +2789,7 @@ xg_update_menubar (GtkWidget *menubar,
     {
       /* Item(s) added.  Add all new items in one call.  */
       create_menus (val, f, select_cb, deactivate_cb, highlight_cb,
-                    0, 1, 0, menubar, cl_data, 0);
+                    0, 1, menubar, cl_data, 0);
 
       /* All updated.  */
       val = 0;
@@ -2880,13 +2864,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);
-
-          /* If this item has a submenu that has been detached, change
-             the title in the WM decorations also.  */
-          if (submenu && gtk_menu_get_tearoff_state (GTK_MENU (submenu)))
-            /* Set the title of the detached window.  */
-            gtk_menu_set_title (GTK_MENU (submenu), utf8_label);
+          g_object_notify (G_OBJECT (witem), "label");
 
           if (utf8_label) g_free (utf8_label);
           iter = g_list_next (iter);
@@ -2914,7 +2898,8 @@ xg_update_menubar (GtkWidget *menubar,
           GtkWidget *submenu = create_menus (NULL, f,
                                              select_cb, deactivate_cb,
                                              highlight_cb,
-                                             0, 0, 0, 0, cl_data, 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);
@@ -2974,6 +2959,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);
@@ -3018,15 +3004,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);
@@ -3036,8 +3027,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;
@@ -3059,6 +3049,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.  */
@@ -3114,15 +3107,6 @@ xg_update_submenu (GtkWidget *submenu,
   {
     GtkWidget *w = GTK_WIDGET (iter->data);
 
-    /* Skip tearoff items, they have no counterpart in val.  */
-    if (GTK_IS_TEAROFF_MENU_ITEM (w))
-      {
-        has_tearoff_p = 1;
-        iter = g_list_next (iter);
-        if (iter) w = GTK_WIDGET (iter->data);
-        else break;
-      }
-
     /* Remember first radio button in a group.  If we get a mismatch in
        a radio group we must rebuild the whole group so that the connections
        in GTK becomes correct.  */
@@ -3210,7 +3194,6 @@ xg_update_submenu (GtkWidget *submenu,
                              highlight_cb,
                              0,
                              0,
-                             ! has_tearoff_p,
                              submenu,
                              cl_data,
                              0);
@@ -3231,8 +3214,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, FRAME_PTR f,
+			   widget_value *val, bool deep_p,
                            GCallback select_cb, GCallback deactivate_cb,
 			   GCallback highlight_cb)
 {
@@ -3241,8 +3224,7 @@ xg_modify_menubar_widgets (GtkWidget *me
 
   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);
@@ -3340,11 +3322,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;
@@ -3376,7 +3353,7 @@ free_frame_menubar (FRAME_PTR f)
 }
 
 bool
-xg_event_is_for_menubar (FRAME_PTR f, XEvent *event)
+xg_event_is_for_menubar (FRAME_PTR f, const XEvent *event)
 {
   struct x_output *x = f->output_data.x;
   GList *iter;
@@ -3712,14 +3689,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, 0);
 
       /* 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
@@ -3753,7 +3727,7 @@ xg_set_toolkit_scroll_bar_thumb (struct
 
   FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
 
-  if (wscroll && NILP (bar->dragging))
+  if (wscroll && bar->dragging == -1)
     {
       GtkAdjustment *adj;
       gdouble shown;
@@ -3765,13 +3739,17 @@ xg_set_toolkit_scroll_bar_thumb (struct
 
       adj = gtk_range_get_adjustment (GTK_RANGE (wscroll));
 
-      /* We do the same as for MOTIF in xterm.c, assume 30 chars per line
-         rather than the real portion value.  This makes the thumb less likely
-         to resize and that looks better.  */
-      portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
-      /* When the thumb is at the bottom, position == whole.
-         So we need to increase `whole' to make space for the thumb.  */
-      whole += portion;
+      if (1)
+        {
+          /* We do the same as for MOTIF in xterm.c, use 30 chars per
+             line rather than the real portion value.  This makes the
+             thumb less likely to resize and that looks better.  */
+          portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
+
+          /* When the thumb is at the bottom, position == whole.
+             So we need to increase `whole' to make space for the thumb.  */
+          whole += portion;
+        }
 
       if (whole <= 0)
         top = 0, shown = 1;
@@ -3781,13 +3759,8 @@ xg_set_toolkit_scroll_bar_thumb (struct
           shown = (gdouble) portion / whole;
         }
 
-      size = shown * XG_SB_RANGE;
-      size = min (size, XG_SB_RANGE);
-      size = max (size, 1);
-
-      value = top * XG_SB_RANGE;
-      value = min (value, XG_SB_MAX - size);
-      value = max (value, XG_SB_MIN);
+      size = clip_to_bounds (1, shown * XG_SB_RANGE, XG_SB_RANGE);
+      value = clip_to_bounds (XG_SB_MIN, top * XG_SB_RANGE, XG_SB_MAX - size);
 
       /* Assume all lines are of equal size.  */
       new_step = size / max (1, FRAME_LINES (f));
@@ -3832,7 +3805,7 @@ xg_set_toolkit_scroll_bar_thumb (struct
    frame.  This function does additional checks.  */
 
 bool
-xg_event_is_for_scrollbar (FRAME_PTR f, XEvent *event)
+xg_event_is_for_scrollbar (FRAME_PTR f, const XEvent *event)
 {
   bool retval = 0;
 
@@ -3917,7 +3890,7 @@ xg_tool_bar_callback (GtkWidget *w, gpoi
   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);
+  FRAME_PTR f = g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
   Lisp_Object key, frame;
   struct input_event event;
   EVENT_INIT (event);
@@ -3946,9 +3919,9 @@ xg_tool_bar_callback (GtkWidget *w, gpoi
   event.modifiers = x_x_to_emacs_modifiers (FRAME_X_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. */
+  Fx_focus_frame (frame);
 }
 
 /* Callback function invoked when a tool bar item is pressed in a detached
@@ -3990,8 +3963,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);
@@ -3999,187 +3972,6 @@ xg_get_tool_bar_widgets (GtkWidget *vb,
 }
 
 
-/* This callback is called when a tool item should create a proxy item,
-   such as for the overflow menu.  Also called when the tool bar is detached.
-   If we don't create a proxy menu item, the detached tool bar will be
-   blank.  */
-
-static gboolean
-xg_tool_bar_menu_proxy (GtkToolItem *toolitem, gpointer user_data)
-{
-  GtkButton *wbutton = GTK_BUTTON (XG_BIN_CHILD (XG_BIN_CHILD (toolitem)));
-  GtkWidget *vb = XG_BIN_CHILD (wbutton);
-  GtkWidget *c1;
-  GtkLabel *wlbl = GTK_LABEL (xg_get_tool_bar_widgets (vb, &c1));
-  GtkImage *wimage = GTK_IMAGE (c1);
-  GtkWidget *wmenuitem = gtk_image_menu_item_new_with_label
-    (wlbl ? gtk_label_get_text (wlbl) : "");
-  GtkWidget *wmenuimage;
-
-
-  if (gtk_button_get_use_stock (wbutton))
-    wmenuimage = gtk_image_new_from_stock (gtk_button_get_label (wbutton),
-                                           GTK_ICON_SIZE_MENU);
-  else
-    {
-      GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (wbutton));
-      GtkImageType store_type = gtk_image_get_storage_type (wimage);
-
-      g_object_set (G_OBJECT (settings), "gtk-menu-images", TRUE, NULL);
-
-      if (store_type == GTK_IMAGE_STOCK)
-        {
-          gchar *stock_id;
-          gtk_image_get_stock (wimage, &stock_id, NULL);
-          wmenuimage = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
-        }
-      else if (store_type == GTK_IMAGE_ICON_SET)
-        {
-          GtkIconSet *icon_set;
-          gtk_image_get_icon_set (wimage, &icon_set, NULL);
-          wmenuimage = gtk_image_new_from_icon_set (icon_set,
-                                                    GTK_ICON_SIZE_MENU);
-        }
-      else if (store_type == GTK_IMAGE_PIXBUF)
-        {
-          gint width, height;
-
-          if (settings &&
-              gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
-                                                 &width, &height))
-            {
-              GdkPixbuf *src_pixbuf, *dest_pixbuf;
-
-              src_pixbuf = gtk_image_get_pixbuf (wimage);
-              dest_pixbuf = gdk_pixbuf_scale_simple (src_pixbuf, width, height,
-                                                     GDK_INTERP_BILINEAR);
-
-              wmenuimage = gtk_image_new_from_pixbuf (dest_pixbuf);
-            }
-          else
-            {
-              fprintf (stderr, "internal error: GTK_IMAGE_PIXBUF failed\n");
-              emacs_abort ();
-            }
-        }
-      else if (store_type == GTK_IMAGE_ICON_NAME)
-        {
-          const gchar *icon_name;
-          GtkIconSize icon_size;
-
-          gtk_image_get_icon_name (wimage, &icon_name, &icon_size);
-          wmenuimage = gtk_image_new_from_icon_name (icon_name,
-                                                     GTK_ICON_SIZE_MENU);
-        }
-      else
-        {
-          fprintf (stderr, "internal error: store_type is %d\n", store_type);
-          emacs_abort ();
-        }
-    }
-  if (wmenuimage)
-    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (wmenuitem), wmenuimage);
-
-  g_signal_connect (G_OBJECT (wmenuitem),
-                    "activate",
-                    G_CALLBACK (xg_tool_bar_proxy_callback),
-                    user_data);
-
-
-  g_object_set_data (G_OBJECT (wmenuitem), XG_TOOL_BAR_PROXY_BUTTON,
-                     (gpointer) wbutton);
-  gtk_tool_item_set_proxy_menu_item (toolitem, "Emacs toolbar item", wmenuitem);
-  gtk_widget_set_sensitive (wmenuitem,
-                            gtk_widget_get_sensitive (GTK_WIDGET (wbutton)));
-
-  /* Use enter/leave notify to show help.  We use the events
-     rather than the GtkButton specific signals "enter" and
-     "leave", so we can have only one callback.  The event
-     will tell us what kind of event it is.  */
-  g_signal_connect (G_OBJECT (wmenuitem),
-                    "enter-notify-event",
-                    G_CALLBACK (xg_tool_bar_proxy_help_callback),
-                    user_data);
-  g_signal_connect (G_OBJECT (wmenuitem),
-                    "leave-notify-event",
-                    G_CALLBACK (xg_tool_bar_proxy_help_callback),
-                    user_data);
-
-  return TRUE;
-}
-
-/* This callback is called when a tool bar is detached.  We must set
-   the height of the tool bar to zero when this happens so frame sizes
-   are correctly calculated.
-   WBOX is the handle box widget that enables detach/attach of the tool bar.
-   W is the tool bar widget.
-   CLIENT_DATA is a pointer to the frame the tool bar belongs to.  */
-
-static void
-xg_tool_bar_detach_callback (GtkHandleBox *wbox,
-                             GtkWidget *w,
-                             gpointer client_data)
-{
-  FRAME_PTR f = (FRAME_PTR) client_data;
-
-  g_object_set (G_OBJECT (w), "show-arrow", !x_gtk_whole_detached_tool_bar,
-		NULL);
-
-  if (f)
-    {
-      GtkRequisition req, req2;
-      FRAME_X_OUTPUT (f)->toolbar_detached = 1;
-      gtk_widget_get_preferred_size (GTK_WIDGET (wbox), NULL, &req);
-      gtk_widget_get_preferred_size (w, NULL, &req2);
-      req.width -= req2.width;
-      req.height -= req2.height;
-      if (FRAME_TOOLBAR_TOP_HEIGHT (f) != 0)
-        FRAME_TOOLBAR_TOP_HEIGHT (f) = req.height;
-      else if (FRAME_TOOLBAR_BOTTOM_HEIGHT (f) != 0)
-        FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = req.height;
-      else if (FRAME_TOOLBAR_RIGHT_WIDTH (f) != 0)
-        FRAME_TOOLBAR_RIGHT_WIDTH (f) = req.width;
-      else if (FRAME_TOOLBAR_LEFT_WIDTH (f) != 0)
-        FRAME_TOOLBAR_LEFT_WIDTH (f) = req.width;
-      xg_height_or_width_changed (f);
-    }
-}
-
-/* This callback is called when a tool bar is reattached.  We must set
-   the height of the tool bar when this happens so frame sizes
-   are correctly calculated.
-   WBOX is the handle box widget that enables detach/attach of the tool bar.
-   W is the tool bar widget.
-   CLIENT_DATA is a pointer to the frame the tool bar belongs to.  */
-
-static void
-xg_tool_bar_attach_callback (GtkHandleBox *wbox,
-                             GtkWidget *w,
-                             gpointer client_data)
-{
-  FRAME_PTR f = (FRAME_PTR) client_data;
-  g_object_set (G_OBJECT (w), "show-arrow", TRUE, NULL);
-
-  if (f)
-    {
-      GtkRequisition req, req2;
-      FRAME_X_OUTPUT (f)->toolbar_detached = 0;
-      gtk_widget_get_preferred_size (GTK_WIDGET (wbox), NULL, &req);
-      gtk_widget_get_preferred_size (w, NULL, &req2);
-      req.width += req2.width;
-      req.height += req2.height;
-      if (FRAME_TOOLBAR_TOP_HEIGHT (f) != 0)
-        FRAME_TOOLBAR_TOP_HEIGHT (f) = req.height;
-      else if (FRAME_TOOLBAR_BOTTOM_HEIGHT (f) != 0)
-        FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = req.height;
-      else if (FRAME_TOOLBAR_RIGHT_WIDTH (f) != 0)
-        FRAME_TOOLBAR_RIGHT_WIDTH (f) = req.width;
-      else if (FRAME_TOOLBAR_LEFT_WIDTH (f) != 0)
-        FRAME_TOOLBAR_LEFT_WIDTH (f) = req.width;
-      xg_height_or_width_changed (f);
-    }
-}
-
 /* This callback is called when the mouse enters or leaves a tool bar item.
    It is used for displaying and hiding the help text.
    W is the tool bar item, a button.
@@ -4195,7 +3987,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);
+  FRAME_PTR 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))
@@ -4259,6 +4051,8 @@ xg_tool_bar_item_expose_callback (GtkWid
   gtk_toolbar_set_orientation (GTK_TOOLBAR (w), o)
 #endif
 
+#define TOOLBAR_TOP_WIDGET(x) ((x)->toolbar_widget)
+
 /* Attach a tool bar to frame F.  */
 
 static void
@@ -4266,49 +4060,52 @@ xg_pack_tool_bar (FRAME_PTR f, Lisp_Obje
 {
   struct x_output *x = f->output_data.x;
   bool into_hbox = EQ (pos, Qleft) || EQ (pos, Qright);
+  GtkWidget *top_widget = x->toolbar_widget;
 
   toolbar_set_orientation (x->toolbar_widget,
                            into_hbox
                            ? GTK_ORIENTATION_VERTICAL
                            : GTK_ORIENTATION_HORIZONTAL);
-  if (!x->handlebox_widget)
-    {
-      x->handlebox_widget = gtk_handle_box_new ();
-      g_signal_connect (G_OBJECT (x->handlebox_widget), "child-detached",
-                        G_CALLBACK (xg_tool_bar_detach_callback), f);
-      g_signal_connect (G_OBJECT (x->handlebox_widget), "child-attached",
-                        G_CALLBACK (xg_tool_bar_attach_callback), f);
-      gtk_container_add (GTK_CONTAINER (x->handlebox_widget),
-                         x->toolbar_widget);
-    }
 
   if (into_hbox)
     {
-      gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (x->handlebox_widget),
-                                          GTK_POS_TOP);
-      gtk_box_pack_start (GTK_BOX (x->hbox_widget), x->handlebox_widget,
+      gtk_box_pack_start (GTK_BOX (x->hbox_widget), top_widget,
                           FALSE, FALSE, 0);
 
       if (EQ (pos, Qleft))
         gtk_box_reorder_child (GTK_BOX (x->hbox_widget),
-                               x->handlebox_widget,
+                               top_widget,
                                0);
-      x->toolbar_in_hbox = 1;
+      x->toolbar_in_hbox = true;
     }
   else
     {
       bool vbox_pos = x->menubar_widget != 0;
-      gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (x->handlebox_widget),
-                                          GTK_POS_LEFT);
-      gtk_box_pack_start (GTK_BOX (x->vbox_widget), x->handlebox_widget,
+      gtk_box_pack_start (GTK_BOX (x->vbox_widget), top_widget,
                           FALSE, FALSE, 0);
 
       if (EQ (pos, Qtop))
         gtk_box_reorder_child (GTK_BOX (x->vbox_widget),
-                               x->handlebox_widget,
+                               top_widget,
                                vbox_pos);
-      x->toolbar_in_hbox = 0;
+      x->toolbar_in_hbox = false;
     }
+  x->toolbar_is_packed = true;
+}
+
+static bool xg_update_tool_bar_sizes (FRAME_PTR 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.  */
+  FRAME_PTR f = user_data;
+  if (xg_update_tool_bar_sizes (f))
+    xg_height_or_width_changed (f);
 }
 
 /* Create a tool bar for frame F.  */
@@ -4337,12 +4134,13 @@ xg_create_tool_bar (FRAME_PTR f)
     }
 
   x->toolbar_widget = gtk_toolbar_new ();
-  x->toolbar_detached = 0;
 
   gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
 
   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");
@@ -4435,10 +4233,6 @@ xg_make_tool_item (FRAME_PTR f,
       intptr_t ii = i;
       gpointer gi = (gpointer) ii;
 
-      g_signal_connect (G_OBJECT (ti), "create-menu-proxy",
-                        G_CALLBACK (xg_tool_bar_menu_proxy),
-                        gi);
-
       g_signal_connect (G_OBJECT (wb), "clicked",
                         G_CALLBACK (xg_tool_bar_callback),
                         gi);
@@ -4552,13 +4346,14 @@ xg_update_tool_bar_sizes (FRAME_PTR f)
   struct x_output *x = f->output_data.x;
   GtkRequisition req;
   int nl = 0, nr = 0, nt = 0, nb = 0;
+  GtkWidget *top_widget = x->toolbar_widget;
 
-  gtk_widget_get_preferred_size (GTK_WIDGET (x->handlebox_widget), NULL, &req);
+  gtk_widget_get_preferred_size (GTK_WIDGET (top_widget), NULL, &req);
   if (x->toolbar_in_hbox)
     {
       int pos;
       gtk_container_child_get (GTK_CONTAINER (x->hbox_widget),
-                               x->handlebox_widget,
+                               top_widget,
                                "position", &pos, NULL);
       if (pos == 0) nl = req.width;
       else nr = req.width;
@@ -4567,7 +4362,7 @@ xg_update_tool_bar_sizes (FRAME_PTR f)
     {
       int pos;
       gtk_container_child_get (GTK_CONTAINER (x->vbox_widget),
-                               x->handlebox_widget,
+                               top_widget,
                                "position", &pos, NULL);
       if (pos == 0 || (pos == 1 && x->menubar_widget)) nt = req.height;
       else nb = req.height;
@@ -4590,6 +4385,42 @@ xg_update_tool_bar_sizes (FRAME_PTR f)
   return 0;
 }
 
+static char *
+find_icon_from_name (char *name,
+                     GtkIconTheme *icon_theme,
+                     char **icon_name)
+{
+#if ! GTK_CHECK_VERSION (3, 10, 0)
+  GtkStockItem stock_item;
+#endif
+
+  if (name[0] == 'n' && name[1] == ':')
+    {
+      *icon_name = name + 2;
+      name = NULL;
+
+      if (! gtk_icon_theme_has_icon (icon_theme, *icon_name))
+        *icon_name = NULL;
+    }
+
+#if ! GTK_CHECK_VERSION (3, 10, 0)
+  else if (gtk_stock_lookup (name, &stock_item))
+    *icon_name = NULL;
+#endif
+  else if (gtk_icon_theme_has_icon (icon_theme, name))
+    {
+      *icon_name = name;
+      name = NULL;
+    }
+  else
+    {
+      name = NULL;
+      *icon_name = NULL;
+    }
+
+  return name;
+}
+
 
 /* Update the tool bar for frame F.  Add new buttons and remove old.  */
 
@@ -4602,10 +4433,12 @@ update_frame_tool_bar (FRAME_PTR f)
   GtkToolbar *wtoolbar;
   GtkToolItem *ti;
   GtkTextDirection dir;
-  bool pack_tool_bar = x->handlebox_widget == NULL;
   Lisp_Object style;
   bool text_image, horiz;
   struct xg_frame_tb_info *tbinfo;
+  GdkScreen *screen;
+  GtkIconTheme *icon_theme;
+
 
   if (! FRAME_GTK_WIDGET (f))
     return;
@@ -4640,6 +4473,8 @@ update_frame_tool_bar (FRAME_PTR f)
   dir = gtk_widget_get_direction (GTK_WIDGET (wtoolbar));
 
   style = Ftool_bar_get_system_style ();
+  screen = gtk_widget_get_screen (GTK_WIDGET (wtoolbar));
+  icon_theme = gtk_icon_theme_get_for_screen (screen);
 
   /* Are we up to date? */
   tbinfo = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
@@ -4676,7 +4511,6 @@ update_frame_tool_bar (FRAME_PTR f)
       struct image *img = NULL;
       Lisp_Object image;
       Lisp_Object stock = Qnil;
-      GtkStockItem stock_item;
       char *stock_name = NULL;
       char *icon_name = NULL;
       Lisp_Object rtl;
@@ -4730,32 +4564,28 @@ update_frame_tool_bar (FRAME_PTR f)
       if (!NILP (specified_file) && !NILP (Ffboundp (Qx_gtk_map_stock)))
         stock = call1 (Qx_gtk_map_stock, specified_file);
 
-      if (STRINGP (stock))
+      if (CONSP (stock)) 
         {
-          stock_name = SSDATA (stock);
-          if (stock_name[0] == 'n' && stock_name[1] == ':')
-            {
-              GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (wtoolbar));
-              GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (screen);
-
-              icon_name = stock_name + 2;
-              stock_name = NULL;
-              stock = Qnil;
-
-              if (! gtk_icon_theme_has_icon (icon_theme, icon_name))
-                icon_name = NULL;
-              else
-                icon_size = gtk_toolbar_get_icon_size (wtoolbar);
-            }
-          else if (gtk_stock_lookup (SSDATA (stock), &stock_item))
-            icon_size = gtk_toolbar_get_icon_size (wtoolbar);
-          else
-            {
-              stock = Qnil;
-              stock_name = NULL;
-            }
+          Lisp_Object tem;
+          for (tem = stock; CONSP (tem); tem = XCDR (tem))
+            if (! NILP (tem) && STRINGP (XCAR (tem)))
+              {
+                stock_name = find_icon_from_name (SSDATA (XCAR (tem)),
+                                                  icon_theme,
+                                                  &icon_name);
+                if (stock_name || icon_name) break;
+              }
+        }
+      else if (STRINGP (stock))
+        {
+          stock_name = find_icon_from_name (SSDATA (stock),
+                                            icon_theme,
+                                            &icon_name);
         }
 
+      if (stock_name || icon_name)
+        icon_size = gtk_toolbar_get_icon_size (wtoolbar);
+
       if (stock_name == NULL && icon_name == NULL)
         {
           /* No stock image, or stock item not known.  Try regular
@@ -4816,7 +4646,12 @@ update_frame_tool_bar (FRAME_PTR f)
 	    w = NULL;
 	  else if (stock_name)
             {
+
+#if GTK_CHECK_VERSION (3, 10, 0)
+              w = gtk_image_new_from_icon_name (stock_name, icon_size);
+#else
               w = gtk_image_new_from_stock (stock_name, icon_size);
+#endif
               g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_STOCK_NAME,
                                       (gpointer) xstrdup (stock_name),
                                       (GDestroyNotify) xfree);
@@ -4856,9 +4691,9 @@ update_frame_tool_bar (FRAME_PTR f)
 
   if (f->n_tool_bar_items != 0)
     {
-      if (pack_tool_bar)
+      if (! x->toolbar_is_packed)
         xg_pack_tool_bar (f, f->tool_bar_position);
-      gtk_widget_show_all (GTK_WIDGET (x->handlebox_widget));
+      gtk_widget_show_all (x->toolbar_widget);
       if (xg_update_tool_bar_sizes (f))
         xg_height_or_width_changed (f);
     }
@@ -4877,24 +4712,24 @@ free_frame_tool_bar (FRAME_PTR f)
   if (x->toolbar_widget)
     {
       struct xg_frame_tb_info *tbinfo;
-      bool is_packed = x->handlebox_widget != 0;
+      GtkWidget *top_widget = x->toolbar_widget;
+
       block_input ();
-      /* We may have created the toolbar_widget in xg_create_tool_bar, but
-         not the x->handlebox_widget which is created in xg_pack_tool_bar.  */
-      if (is_packed)
+      if (x->toolbar_is_packed)
         {
           if (x->toolbar_in_hbox)
             gtk_container_remove (GTK_CONTAINER (x->hbox_widget),
-                                  x->handlebox_widget);
+                                  top_widget);
           else
             gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
-                                  x->handlebox_widget);
+                                  top_widget);
         }
       else
         gtk_widget_destroy (x->toolbar_widget);
 
       x->toolbar_widget = 0;
-      x->handlebox_widget = 0;
+      x->toolbar_widget = 0;
+      x->toolbar_is_packed = false;
       FRAME_TOOLBAR_TOP_HEIGHT (f) = FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = 0;
       FRAME_TOOLBAR_LEFT_WIDTH (f) = FRAME_TOOLBAR_RIGHT_WIDTH (f) = 0;
 
@@ -4918,20 +4753,25 @@ void
 xg_change_toolbar_position (FRAME_PTR f, Lisp_Object pos)
 {
   struct x_output *x = f->output_data.x;
+  GtkWidget *top_widget = x->toolbar_widget;
 
-  if (! x->toolbar_widget || ! x->handlebox_widget)
+  if (! x->toolbar_widget || ! top_widget)
     return;
 
   block_input ();
-  g_object_ref (x->handlebox_widget);
-  if (x->toolbar_in_hbox)
-    gtk_container_remove (GTK_CONTAINER (x->hbox_widget),
-                          x->handlebox_widget);
-  else
-    gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
-                          x->handlebox_widget);
+  g_object_ref (top_widget);
+  if (x->toolbar_is_packed)
+    {
+      if (x->toolbar_in_hbox)
+        gtk_container_remove (GTK_CONTAINER (x->hbox_widget),
+                              top_widget);
+      else
+        gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
+                              top_widget);
+    }
+
   xg_pack_tool_bar (f, pos);
-  g_object_unref (x->handlebox_widget);
+  g_object_unref (top_widget);
   if (xg_update_tool_bar_sizes (f))
     xg_height_or_width_changed (f);
 
@@ -4957,7 +4797,6 @@ xg_initialize (void)
 
   gdpy_def = NULL;
   xg_ignore_gtk_scrollbar = 0;
-  xg_detached_menus = 0;
   xg_menu_cb_list.prev = xg_menu_cb_list.next =
     xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0;
 
@@ -4968,10 +4807,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
--- src/gtkutil.h
+++ src/gtkutil.h	2016-12-22 11:56:38.674339118 +0000
@@ -1,6 +1,6 @@
 /* Definitions and headers for 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.
 
@@ -74,8 +74,6 @@ typedef struct xg_menu_item_cb_data_
 
 } xg_menu_item_cb_data;
 
-struct _widget_value;
-
 extern struct _widget_value *malloc_widget_value (void);
 extern void free_widget_value (struct _widget_value *);
 
@@ -107,9 +105,7 @@ extern void xg_modify_menubar_widgets (G
 
 extern void xg_update_frame_menubar (FRAME_PTR f);
 
-extern bool xg_event_is_for_menubar (FRAME_PTR f, XEvent *event);
-
-extern bool xg_have_tear_offs (void);
+extern bool xg_event_is_for_menubar (FRAME_PTR f, const XEvent *event);
 
 extern ptrdiff_t xg_get_scroll_id_for_window (Display *dpy, Window wid);
 
@@ -131,7 +127,7 @@ extern void xg_set_toolkit_scroll_bar_th
                                              int portion,
                                              int position,
                                              int whole);
-extern bool xg_event_is_for_scrollbar (FRAME_PTR f, XEvent *event);
+extern bool xg_event_is_for_scrollbar (FRAME_PTR , const XEvent *);
 extern int xg_get_default_scrollbar_width (void);
 
 extern void update_frame_tool_bar (FRAME_PTR f);
@@ -151,7 +147,7 @@ extern GdkCursor * xg_create_default_cur
 extern bool xg_create_frame_widgets (FRAME_PTR f);
 extern void xg_free_frame_widgets (FRAME_PTR f);
 extern void xg_set_background_color (FRAME_PTR f, unsigned long bg);
-extern bool xg_check_special_colors (struct frame *f,
+extern bool xg_check_special_colors (FRAME_PTR f,
 				     const char *color_name,
 				     XColor *color);
 
--- src/xmenu.c
+++ src/xmenu.c	2016-12-22 11:56:02.799059569 +0000
@@ -956,12 +956,6 @@ set_frame_menubar (FRAME_PTR f, bool fir
       f->output_data.x->saved_menu_event->type = 0;
     }
 
-#ifdef USE_GTK
-  /* If we have detached menus, we must update deep so detached menus
-     also gets updated.  */
-  deep_p = deep_p || xg_have_tear_offs ();
-#endif
-
   if (deep_p)
     {
       /* Make a widget-value tree representing the entire menu trees.  */
--- src/xterm.h
+++ src/xterm.h	2016-12-22 11:56:02.803059489 +0000
@@ -474,12 +474,11 @@ struct x_output
   GtkWidget *menubar_widget;
   /* The tool bar in this frame  */
   GtkWidget *toolbar_widget;
-  /* The handle box that makes the tool bar detachable.  */
-  GtkWidget *handlebox_widget;
   /* Non-zero if the tool bar is detached.  */
   int toolbar_detached;
   /* Non-zero if tool bar is packed into the hbox widget (i.e. vertical).  */
   int toolbar_in_hbox;
+  int toolbar_is_packed;
 
   /* The last size hints set.  */
   GdkGeometry size_hints;
