]> code.delx.au - gnu-emacs/blobdiff - src/gtkutil.c
(redraw_overlapping_rows): Fix detection of
[gnu-emacs] / src / gtkutil.c
index d3a0c7e7596626414691ce37f0bd123a95a1ae47..6d73c0358f070da317403e8e022f5ce9c42d853a 100644 (file)
@@ -1,13 +1,13 @@
 /* Functions for creating and updating GTK widgets.
 /* Functions for creating and updating GTK widgets.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
      Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
      Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,11 +15,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
-#include "config.h"
+#include <config.h>
 
 #ifdef USE_GTK
 #include <string.h>
 
 #ifdef USE_GTK
 #include <string.h>
@@ -38,6 +36,9 @@ Boston, MA 02110-1301, USA.  */
 #include "coding.h"
 #include <gdk/gdkkeysyms.h>
 
 #include "coding.h"
 #include <gdk/gdkkeysyms.h>
 
+#ifdef HAVE_XFT
+#include <X11/Xft/Xft.h>
+#endif
 
 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
   (FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
 
 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
   (FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
@@ -52,13 +53,11 @@ Boston, MA 02110-1301, USA.  */
 
 #ifdef HAVE_GTK_MULTIDISPLAY
 
 
 #ifdef HAVE_GTK_MULTIDISPLAY
 
-/* Gtk does not work well without any display open.  Emacs may close
-   all its displays.  In that case, keep a display around just for
-   the purpose of having one.  */
+/* Keep track of the default display, or NULL if there is none.  Emacs
+   may close all its displays.  */
 
 static GdkDisplay *gdpy_def;
 
 
 static GdkDisplay *gdpy_def;
 
-
 /* Return the GdkDisplay that corresponds to the X display DPY.  */
 
 static GdkDisplay *
 /* Return the GdkDisplay that corresponds to the X display DPY.  */
 
 static GdkDisplay *
@@ -120,8 +119,14 @@ xg_display_open (display_name, dpy)
   GdkDisplay *gdpy;
 
   gdpy = gdk_display_open (display_name);
   GdkDisplay *gdpy;
 
   gdpy = gdk_display_open (display_name);
-  *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
+  if (!gdpy_def && gdpy)
+    {
+      gdpy_def = gdpy;
+      gdk_display_manager_set_default_display (gdk_display_manager_get (),
+                                              gdpy);
+    }
 
 
+  *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
   return gdpy != NULL;
 
 #else /* not HAVE_GTK_MULTIDISPLAY */
   return gdpy != NULL;
 
 #else /* not HAVE_GTK_MULTIDISPLAY */
@@ -139,40 +144,30 @@ xg_display_close (Display *dpy)
 #ifdef HAVE_GTK_MULTIDISPLAY
   GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
 
 #ifdef HAVE_GTK_MULTIDISPLAY
   GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
 
-  /* If this is the default display, we must change it before calling
-     dispose, otherwise it will crash on some Gtk+ versions.  */
+  /* If this is the default display, try to change it before closing.
+     If there is no other display to use, gdpy_def is set to NULL, and
+     the next call to xg_display_open resets the default display.  */
   if (gdk_display_get_default () == gdpy)
     {
       struct x_display_info *dpyinfo;
   if (gdk_display_get_default () == gdpy)
     {
       struct x_display_info *dpyinfo;
-      Display *new_dpy = 0;
-      GdkDisplay *gdpy_new;
+      GdkDisplay *gdpy_new = NULL;
 
       /* Find another display.  */
       for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
         if (dpyinfo->display != dpy)
           {
 
       /* Find another display.  */
       for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
         if (dpyinfo->display != dpy)
           {
-            new_dpy = dpyinfo->display;
+           gdpy_new = gdk_x11_lookup_xdisplay (dpyinfo->display);
+           gdk_display_manager_set_default_display (gdk_display_manager_get (),
+                                                    gdpy_new);
             break;
           }
             break;
           }
-
-      if (new_dpy)
-        gdpy_new = gdk_x11_lookup_xdisplay (new_dpy);
-      else
-        {
-          if (!gdpy_def)
-            gdpy_def = gdk_display_open (gdk_display_get_name (gdpy));
-          gdpy_new = gdpy_def;
-        }
-
-      gdk_display_manager_set_default_display (gdk_display_manager_get (),
-                                               gdpy_new);
+      gdpy_def = gdpy_new;
     }
 
     }
 
-  /* 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.  */
-
 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 10
 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 10
+  /* 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.  */
   g_object_run_dispose (G_OBJECT (gdpy));
 #else
   /* This seems to be fixed in GTK 2.10. */
   g_object_run_dispose (G_OBJECT (gdpy));
 #else
   /* This seems to be fixed in GTK 2.10. */
@@ -232,7 +227,7 @@ free_widget_value (wv)
     {
       /* When the number of already allocated cells is too big,
         We free it.  */
     {
       /* When the number of already allocated cells is too big,
         We free it.  */
-      free (wv);
+      xfree (wv);
       malloc_cpt--;
     }
   else
       malloc_cpt--;
     }
   else
@@ -530,7 +525,7 @@ get_utf8_string (str)
   if (!g_utf8_validate (str, -1, NULL))
     utf8_str = g_locale_to_utf8 (str, -1, 0, 0, 0);
 
   if (!g_utf8_validate (str, -1, NULL))
     utf8_str = g_locale_to_utf8 (str, -1, 0, 0, 0);
 
-  if (!utf8_str) 
+  if (!utf8_str)
     {
       /* Probably some control characters in str.  Escape them. */
       size_t nr_bad = 0;
     {
       /* Probably some control characters in str.  Escape them. */
       size_t nr_bad = 0;
@@ -550,7 +545,7 @@ get_utf8_string (str)
           error = NULL;
         }
 
           error = NULL;
         }
 
-      if (error) 
+      if (error)
         {
           g_error_free (error);
           error = NULL;
         {
           g_error_free (error);
           error = NULL;
@@ -573,12 +568,12 @@ get_utf8_string (str)
           error = NULL;
         }
 
           error = NULL;
         }
 
-      if (cp) 
+      if (cp)
         {
           strcat (utf8_str, cp);
           g_free (cp);
         }
         {
           strcat (utf8_str, cp);
           g_free (cp);
         }
-      if (error) 
+      if (error)
         {
           g_error_free (error);
           error = NULL;
         {
           g_error_free (error);
           error = NULL;
@@ -603,68 +598,46 @@ xg_set_geometry (f)
      FRAME_PTR f;
 {
   if (f->size_hint_flags & USPosition)
      FRAME_PTR f;
 {
   if (f->size_hint_flags & USPosition)
-  {
-    int left = f->left_pos;
-    int xneg = f->size_hint_flags & XNegative;
-    int top = f->top_pos;
-    int yneg = f->size_hint_flags & YNegative;
-    char geom_str[32];
-
-    if (xneg)
-      left = -left;
-    if (yneg)
-      top = -top;
-
-    sprintf (geom_str, "=%dx%d%c%d%c%d",
-             FRAME_PIXEL_WIDTH (f),
-             FRAME_TOTAL_PIXEL_HEIGHT (f),
-             (xneg ? '-' : '+'), left,
-             (yneg ? '-' : '+'), top);
-
-    if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-                                    geom_str))
-      fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
-  } else if (f->size_hint_flags & PPosition) {
+    {
+      int left = f->left_pos;
+      int xneg = f->size_hint_flags & XNegative;
+      int top = f->top_pos;
+      int yneg = f->size_hint_flags & YNegative;
+      char geom_str[32];
+
+      if (xneg)
+        left = -left;
+      if (yneg)
+        top = -top;
+
+      sprintf (geom_str, "=%dx%d%c%d%c%d",
+               FRAME_PIXEL_WIDTH (f),
+               FRAME_TOTAL_PIXEL_HEIGHT (f),
+               (xneg ? '-' : '+'), left,
+               (yneg ? '-' : '+'), top);
+
+      if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+                                      geom_str))
+        fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
+    }
+  else if (f->size_hint_flags & PPosition)
     gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
                      f->left_pos, f->top_pos);
     gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
                      f->left_pos, f->top_pos);
-  }
 }
 
 
 }
 
 
-/* Resize the outer window of frame F after chainging the height.
-   This happend when the menu bar or the tool bar is added or removed.
-   COLUMNS/ROWS is the size the edit area shall have after the resize.  */
-
-static void
-xg_resize_outer_widget (f, columns, rows)
-     FRAME_PTR f;
-     int columns;
-     int rows;
-{
-  /* If we are not mapped yet, set geometry once again, as window
-     height now have changed.  */
-  if (! GTK_WIDGET_MAPPED (FRAME_GTK_OUTER_WIDGET (f)))
-    xg_set_geometry (f);
-
-  xg_frame_set_char_size (f, columns, rows);
-  gdk_window_process_all_updates ();
-}
-
-/* Function to handle resize of our widgets.  Since Emacs has some layouts
-   that does not fit well with GTK standard containers, we do most layout
-   manually.
+/* Function to handle resize of our frame.  As we have a Gtk+ tool bar
+   and a Gtk+ menu bar, we get resize events for the edit part of the
+   frame only.  We let Gtk+ deal with the Gtk+ parts.
    F is the frame to resize.
    PIXELWIDTH, PIXELHEIGHT is the new size in pixels.  */
 
 void
    F is the frame to resize.
    PIXELWIDTH, PIXELHEIGHT is the new size in pixels.  */
 
 void
-xg_resize_widgets (f, pixelwidth, pixelheight)
+xg_frame_resized (f, pixelwidth, pixelheight)
      FRAME_PTR f;
      int pixelwidth, pixelheight;
 {
      FRAME_PTR f;
      int pixelwidth, pixelheight;
 {
-  int mbheight = FRAME_MENUBAR_HEIGHT (f);
-  int tbheight = FRAME_TOOLBAR_HEIGHT (f);
-  int rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, (pixelheight
-                                                  - mbheight - tbheight));
+  int rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
   int columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
 
   if (FRAME_GTK_WIDGET (f)
   int columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
 
   if (FRAME_GTK_WIDGET (f)
@@ -673,16 +646,8 @@ xg_resize_widgets (f, pixelwidth, pixelheight)
           || pixelwidth != FRAME_PIXEL_WIDTH (f)
          || pixelheight != FRAME_PIXEL_HEIGHT (f)))
     {
           || pixelwidth != FRAME_PIXEL_WIDTH (f)
          || pixelheight != FRAME_PIXEL_HEIGHT (f)))
     {
-      struct x_output *x = f->output_data.x;
-      GtkAllocation all;
-
-      all.y = mbheight + tbheight;
-      all.x = 0;
-
-      all.width = pixelwidth;
-      all.height = pixelheight - mbheight - tbheight;
-
-      gtk_widget_size_allocate (x->edit_widget, &all);
+      FRAME_PIXEL_WIDTH (f) = pixelwidth;
+      FRAME_PIXEL_HEIGHT (f) = pixelheight;
 
       change_frame_size (f, rows, columns, 0, 1, 0);
       SET_FRAME_GARBAGED (f);
 
       change_frame_size (f, rows, columns, 0, 1, 0);
       SET_FRAME_GARBAGED (f);
@@ -690,8 +655,51 @@ xg_resize_widgets (f, pixelwidth, pixelheight)
     }
 }
 
     }
 }
 
+/* Process all pending events on the display for frame F.  */
+
+static void
+flush_and_sync (f)
+     FRAME_PTR f;
+{
+  gdk_window_process_all_updates ();
+  x_sync (f);
+  while (gtk_events_pending ())
+    {
+      gtk_main_iteration ();
+      gdk_window_process_all_updates ();
+      x_sync (f);
+    }
+}
+
+/* Turn wm hints for resize off on frame F */
+
+static void
+x_wm_size_hint_off (f)
+     FRAME_PTR f;
+{
+  GdkGeometry size_hints;
+  gint hint_flags = 0;
+  memset (&size_hints, 0, sizeof (size_hints));
+  hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
+  size_hints.width_inc = 1;
+  size_hints.height_inc = 1;
+  hint_flags |= GDK_HINT_BASE_SIZE;
+  size_hints.base_width = 1;
+  size_hints.base_height = 1;
+  size_hints.min_width  = 1;
+  size_hints.min_height = 1;
+  gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+                                 NULL,
+                                 &size_hints,
+                                 hint_flags);
+  /* Make sure these get set again in next call to x_wm_set_size_hint. */
+  f->output_data.x->hint_flags &= ~hint_flags;
+  flush_and_sync (f);
+}
 
 
-/* Update our widget size to be COLS/ROWS characters for frame F.  */
+/* Resize the outer window of frame F after chainging the height.
+   This happend when the menu bar or the tool bar is added or removed.
+   COLUMNS/ROWS is the size the edit area shall have after the resize.  */
 
 void
 xg_frame_set_char_size (f, cols, rows)
 
 void
 xg_frame_set_char_size (f, cols, rows)
@@ -703,6 +711,9 @@ xg_frame_set_char_size (f, cols, rows)
     + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
   int pixelwidth;
 
     + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
   int pixelwidth;
 
+  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
   /* 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
@@ -718,13 +729,15 @@ xg_frame_set_char_size (f, cols, rows)
   pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
 
   /* Must resize our top level widget.  Font size may have changed,
   pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
 
   /* Must resize our top level widget.  Font size may have changed,
-     but not rows/cols.  */
+     but not rows/cols.
+     Turn wm hints (min/max size and size increments) of temporarly.
+     It interferes too much, when for example adding or removing the
+     menu/tool bar.  */
+  x_wm_size_hint_off (f);
   gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
                      pixelwidth, pixelheight);
   gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
                      pixelwidth, pixelheight);
-  xg_resize_widgets (f, pixelwidth, pixelheight);
+  flush_and_sync (f);
   x_wm_set_size_hint (f, 0, 0);
   x_wm_set_size_hint (f, 0, 0);
-  SET_FRAME_GARBAGED (f);
-  cancel_mouse_face (f);
 }
 
 /* Convert an X Window WSESC on display DPY to its corresponding GtkWidget.
 }
 
 /* Convert an X Window WSESC on display DPY to its corresponding GtkWidget.
@@ -832,17 +845,6 @@ xg_create_frame_widgets (f)
   if (FRAME_EXTERNAL_TOOL_BAR (f))
     update_frame_tool_bar (f);
 
   if (FRAME_EXTERNAL_TOOL_BAR (f))
     update_frame_tool_bar (f);
 
-  /* The tool bar is created but first there are no items in it.
-     This causes it to be zero height.  Later items are added, but then
-     the frame is already mapped, so there is a "jumping" resize.
-     This makes geometry handling difficult, for example -0-0 will end
-     up in the wrong place as tool bar height has not been taken into account.
-     So we cheat a bit by setting a height that is what it will have
-     later on when tool bar items are added.  */
-  if (FRAME_EXTERNAL_TOOL_BAR (f) && f->n_tool_bar_items == 0)
-    FRAME_TOOLBAR_HEIGHT (f) = 38;
-
-
   /* We don't want this widget double buffered, because we draw on it
      with regular X drawing primitives, so from a GTK/GDK point of
      view, the widget is totally blank.  When an expose comes, this
   /* We don't want this widget double buffered, because we draw on it
      with regular X drawing primitives, so from a GTK/GDK point of
      view, the widget is totally blank.  When an expose comes, this
@@ -899,8 +901,10 @@ xg_create_frame_widgets (f)
   gtk_widget_modify_style (wfixed, style);
 
   /* GTK does not set any border, and they look bad with GTK.  */
   gtk_widget_modify_style (wfixed, style);
 
   /* GTK does not set any border, and they look bad with GTK.  */
+  /* That they look bad is no excuse for imposing this here.  --Stef
+     It should be done by providing the proper default in Fx_create_Frame.
   f->border_width = 0;
   f->border_width = 0;
-  f->internal_border_width = 0;
+  f->internal_border_width = 0; */
 
   UNBLOCK_INPUT;
 
 
   UNBLOCK_INPUT;
 
@@ -919,95 +923,99 @@ x_wm_set_size_hint (f, flags, user_position)
      long flags;
      int user_position;
 {
      long flags;
      int user_position;
 {
-  if (FRAME_GTK_OUTER_WIDGET (f))
-  {
-    /* Must use GTK routines here, otherwise GTK resets the size hints
-       to its own defaults.  */
-    GdkGeometry size_hints;
-    gint hint_flags = 0;
-    int base_width, base_height;
-    int min_rows = 0, min_cols = 0;
-    int win_gravity = f->win_gravity;
-
-    if (flags)
-      {
-        memset (&size_hints, 0, sizeof (size_hints));
-        f->output_data.x->size_hints = size_hints;
-        f->output_data.x->hint_flags = hint_flags;
-      }
-     else
-       flags = f->size_hint_flags;
-
-    size_hints = f->output_data.x->size_hints;
-    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);
-
-    hint_flags |= GDK_HINT_BASE_SIZE;
-    base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
-    base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0)
-      + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
-
-    check_frame_size (f, &min_rows, &min_cols);
-
-    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;
-
-
-    /* These currently have a one to one mapping with the X values, but I
-       don't think we should rely on that.  */
-    hint_flags |= GDK_HINT_WIN_GRAVITY;
-    size_hints.win_gravity = 0;
-    if (win_gravity == NorthWestGravity)
-      size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
-    else if (win_gravity == NorthGravity)
-      size_hints.win_gravity = GDK_GRAVITY_NORTH;
-    else if (win_gravity == NorthEastGravity)
-      size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
-    else if (win_gravity == WestGravity)
-      size_hints.win_gravity = GDK_GRAVITY_WEST;
-    else if (win_gravity == CenterGravity)
-      size_hints.win_gravity = GDK_GRAVITY_CENTER;
-    else if (win_gravity == EastGravity)
-      size_hints.win_gravity = GDK_GRAVITY_EAST;
-    else if (win_gravity == SouthWestGravity)
-      size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
-    else if (win_gravity == SouthGravity)
-      size_hints.win_gravity = GDK_GRAVITY_SOUTH;
-    else if (win_gravity == SouthEastGravity)
-      size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
-    else if (win_gravity == StaticGravity)
-      size_hints.win_gravity = GDK_GRAVITY_STATIC;
-
-    if (flags & PPosition) hint_flags |= GDK_HINT_POS;
-    if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS;
-    if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE;
-
-    if (user_position)
-      {
-        hint_flags &= ~GDK_HINT_POS;
-        hint_flags |= GDK_HINT_USER_POS;
-      }
+  /* Don't set size hints during initialization; that apparently leads
+     to a race condition.  See the thread at
+     http://lists.gnu.org/archive/html/emacs-devel/2008-10/msg00033.html  */
+  if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
+    return;
+
+  /* Must use GTK routines here, otherwise GTK resets the size hints
+     to its own defaults.  */
+  GdkGeometry size_hints;
+  gint hint_flags = 0;
+  int base_width, base_height;
+  int min_rows = 0, min_cols = 0;
+  int win_gravity = f->win_gravity;
 
 
-    BLOCK_INPUT;
+  if (flags)
+    {
+      memset (&size_hints, 0, sizeof (size_hints));
+      f->output_data.x->size_hints = size_hints;
+      f->output_data.x->hint_flags = hint_flags;
+    }
+  else
+    flags = f->size_hint_flags;
 
 
-    gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-                                   FRAME_GTK_OUTER_WIDGET (f),
-                                   &size_hints,
-                                   hint_flags);
+  size_hints = f->output_data.x->size_hints;
+  hint_flags = f->output_data.x->hint_flags;
 
 
-    f->output_data.x->size_hints = size_hints;
-    f->output_data.x->hint_flags = hint_flags;
-    UNBLOCK_INPUT;
-  }
+  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);
+
+  hint_flags |= GDK_HINT_BASE_SIZE;
+  base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
+  base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0)
+    + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
+
+  check_frame_size (f, &min_rows, &min_cols);
+
+  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;
+
+  /* These currently have a one to one mapping with the X values, but I
+     don't think we should rely on that.  */
+  hint_flags |= GDK_HINT_WIN_GRAVITY;
+  size_hints.win_gravity = 0;
+  if (win_gravity == NorthWestGravity)
+    size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
+  else if (win_gravity == NorthGravity)
+    size_hints.win_gravity = GDK_GRAVITY_NORTH;
+  else if (win_gravity == NorthEastGravity)
+    size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
+  else if (win_gravity == WestGravity)
+    size_hints.win_gravity = GDK_GRAVITY_WEST;
+  else if (win_gravity == CenterGravity)
+    size_hints.win_gravity = GDK_GRAVITY_CENTER;
+  else if (win_gravity == EastGravity)
+    size_hints.win_gravity = GDK_GRAVITY_EAST;
+  else if (win_gravity == SouthWestGravity)
+    size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
+  else if (win_gravity == SouthGravity)
+    size_hints.win_gravity = GDK_GRAVITY_SOUTH;
+  else if (win_gravity == SouthEastGravity)
+    size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
+  else if (win_gravity == StaticGravity)
+    size_hints.win_gravity = GDK_GRAVITY_STATIC;
+
+  if (flags & PPosition) hint_flags |= GDK_HINT_POS;
+  if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS;
+  if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE;
+
+  if (user_position)
+    {
+      hint_flags &= ~GDK_HINT_POS;
+      hint_flags |= GDK_HINT_USER_POS;
+    }
+
+  if (hint_flags != f->output_data.x->hint_flags
+      || memcmp (&size_hints,
+                &f->output_data.x->size_hints,
+                sizeof (size_hints)) != 0)
+    {
+      BLOCK_INPUT;
+      gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+                                    NULL, &size_hints, hint_flags);
+      f->output_data.x->size_hints = size_hints;
+      f->output_data.x->hint_flags = hint_flags;
+      UNBLOCK_INPUT;
+    }
 }
 
 /* Change background color of a frame.
 }
 
 /* Change background color of a frame.
-   Since GTK uses the background colour to clear the window, we must
+   Since GTK uses the background color to clear the window, we must
    keep the GTK and X colors in sync.
    F is the frame to change,
    BG is the pixel value to change to.  */
    keep the GTK and X colors in sync.
    F is the frame to change,
    BG is the pixel value to change to.  */
@@ -1247,12 +1255,12 @@ xg_uses_old_file_dialog ()
 }
 
 
 }
 
 
-/* Function that is called when the file dialog pops down.
+/* Function that is called when the file or font dialogs pop down.
    W is the dialog widget, RESPONSE is the response code.
    USER_DATA is what we passed in to g_signal_connect (pointer to int).  */
 
 static void
    W is the dialog widget, RESPONSE is the response code.
    USER_DATA is what we passed in to g_signal_connect (pointer to int).  */
 
 static void
-xg_file_response_cb (w,
+xg_dialog_response_cb (w,
                      response,
                      user_data)
      GtkDialog *w;
                      response,
                      user_data)
      GtkDialog *w;
@@ -1267,7 +1275,7 @@ xg_file_response_cb (w,
 /*  Destroy the dialog.  This makes it pop down.  */
 
 static Lisp_Object
 /*  Destroy the dialog.  This makes it pop down.  */
 
 static Lisp_Object
-pop_down_file_dialog (arg)
+pop_down_dialog (arg)
      Lisp_Object arg;
 {
   struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
      Lisp_Object arg;
 {
   struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
@@ -1388,8 +1396,8 @@ xg_get_file_with_chooser (f, prompt, default_filename,
   wbox = gtk_vbox_new (FALSE, 0);
   gtk_widget_show (wbox);
   wtoggle = gtk_check_button_new_with_label ("Show hidden files.");
   wbox = gtk_vbox_new (FALSE, 0);
   gtk_widget_show (wbox);
   wtoggle = gtk_check_button_new_with_label ("Show hidden files.");
-  
-  if (x_gtk_show_hidden_files) 
+
+  if (x_gtk_show_hidden_files)
     {
       g_object_set (G_OBJECT (filewin), "show-hidden", TRUE, NULL);
       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), TRUE);
     {
       g_object_set (G_OBJECT (filewin), "show-hidden", TRUE, NULL);
       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), TRUE);
@@ -1410,7 +1418,7 @@ xg_get_file_with_chooser (f, prompt, default_filename,
       strcat (message, "\nIf you don't like this file selector, use the "
               "corresponding\nkey binding or customize "
               "use-file-dialog to turn it off.");
       strcat (message, "\nIf you don't like this file selector, use the "
               "corresponding\nkey binding or customize "
               "use-file-dialog to turn it off.");
-    
+
       wmessage = gtk_label_new (message);
       gtk_widget_show (wmessage);
     }
       wmessage = gtk_label_new (message);
       gtk_widget_show (wmessage);
     }
@@ -1433,7 +1441,7 @@ xg_get_file_with_chooser (f, prompt, default_filename,
          an absolute name starting with /.  */
       if (default_filename[0] != '/')
         file = Fexpand_file_name (file, Qnil);
          an absolute name starting with /.  */
       if (default_filename[0] != '/')
         file = Fexpand_file_name (file, Qnil);
-      
+
       utf8_filename = SSDATA (ENCODE_UTF_8 (file));
       if (! NILP (Ffile_directory_p (file)))
         gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filewin),
       utf8_filename = SSDATA (ENCODE_UTF_8 (file));
       if (! NILP (Ffile_directory_p (file)))
         gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filewin),
@@ -1577,7 +1585,7 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
 
   g_signal_connect (G_OBJECT (w),
                     "response",
 
   g_signal_connect (G_OBJECT (w),
                     "response",
-                    G_CALLBACK (xg_file_response_cb),
+                    G_CALLBACK (xg_dialog_response_cb),
                     &filesel_done);
 
   /* Don't destroy the widget if closed by the window manager close button.  */
                     &filesel_done);
 
   /* Don't destroy the widget if closed by the window manager close button.  */
@@ -1585,7 +1593,7 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
 
   gtk_widget_show (w);
 
 
   gtk_widget_show (w);
 
-  record_unwind_protect (pop_down_file_dialog, make_save_value (w, 0));
+  record_unwind_protect (pop_down_dialog, make_save_value (w, 0));
   while (! filesel_done)
     {
       x_menu_wait_for_event (0);
   while (! filesel_done)
     {
       x_menu_wait_for_event (0);
@@ -1604,14 +1612,80 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p)
   return fn;
 }
 
   return fn;
 }
 
+#ifdef HAVE_FREETYPE
+/* 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
+   format:
+
+   `FAMILY [VALUE1 VALUE2] SIZE'
+
+   This can be parsed using font_parse_fcname in font.c.
+   DEFAULT_NAME, if non-zero, is the default font name.  */
+
+char *
+xg_get_font_name (f, default_name)
+     FRAME_PTR f;
+     char *default_name;
+{
+  GtkWidget *w = 0;
+  int count = SPECPDL_INDEX ();
+  char *fontname = NULL;
+  int done = 0;
+
+#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+  sigblock (sigmask (__SIGRTMIN));
+#endif /* HAVE_GTK_AND_PTHREAD */
+
+  w = gtk_font_selection_dialog_new ("Pick a font");
+  if (default_name)
+    gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (w),
+                                             default_name);
+
+  xg_set_screen (w, f);
+  gtk_widget_set_name (w, "emacs-fontdialog");
+  gtk_window_set_transient_for (GTK_WINDOW (w),
+                                GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
+  gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
+  gtk_window_set_modal (GTK_WINDOW (w), TRUE);
+
+  g_signal_connect (G_OBJECT (w), "response",
+                   G_CALLBACK (xg_dialog_response_cb), &done);
+
+  /* Don't destroy the widget if closed by the window manager close button.  */
+  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_value (w, 0));
+  while (!done)
+    {
+      x_menu_wait_for_event (0);
+      gtk_main_iteration ();
+    }
+
+#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+  sigunblock (sigmask (__SIGRTMIN));
+#endif
+
+  if (done == GTK_RESPONSE_OK)
+    fontname = gtk_font_selection_dialog_get_font_name
+      ((GtkFontSelectionDialog *) w);
+
+  unbind_to (count, Qnil);
+
+  return fontname;
+}
+#endif /* HAVE_FREETYPE */
+
+
 \f
 /***********************************************************************
                        Menu functions.
  ***********************************************************************/
 
 \f
 /***********************************************************************
                        Menu functions.
  ***********************************************************************/
 
-/* The name of menu items that can be used for citomization.  Since GTK
+/* The name of menu items that can be used for customization.  Since GTK
    RC files are very crude and primitive, we have to set this on all
    RC files are very crude and primitive, we have to set this on all
-   menu item names so a user can easily cutomize menu items.  */
+   menu item names so a user can easily customize menu items.  */
 
 #define MENU_ITEM_NAME "emacs-menuitem"
 
 
 #define MENU_ITEM_NAME "emacs-menuitem"
 
@@ -2055,34 +2129,6 @@ xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group)
   return w;
 }
 
   return w;
 }
 
-/* Callback called when keyboard traversal (started by x-menu-bar-open) ends.
-   WMENU is the menu for which traversal has been done.  DATA points to the
-   frame for WMENU.  We must release grabs, some bad interaction between GTK
-   and Emacs makes the menus keep the grabs.  */
-
-static void
-menu_nav_ended (wmenu, data)
-     GtkMenuShell *wmenu;
-     gpointer data;
-{
-  FRAME_PTR f = (FRAME_PTR) data;
-
-  if (FRAME_X_OUTPUT (f)->menubar_widget)
-    {
-      GtkMenuShell *w = GTK_MENU_SHELL (FRAME_X_OUTPUT (f)->menubar_widget);
-      Display *dpy = FRAME_X_DISPLAY (f);
-
-      BLOCK_INPUT;
-      gtk_menu_shell_deactivate (w);
-      gtk_menu_shell_deselect (w);
-
-      XUngrabKeyboard (dpy, CurrentTime);
-      XUngrabPointer (dpy, CurrentTime);
-      UNBLOCK_INPUT;
-    }
-}
-
-
 static GtkWidget *create_menus P_ ((widget_value *, FRAME_PTR, GCallback,
                                    GCallback, GCallback, int, int, int,
                                    GtkWidget *, xg_menu_cb_data *, char *));
 static GtkWidget *create_menus P_ ((widget_value *, FRAME_PTR, GCallback,
                                    GCallback, GCallback, int, int, int,
                                    GtkWidget *, xg_menu_cb_data *, char *));
@@ -2148,12 +2194,6 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb,
       }
       else wmenu = gtk_menu_bar_new ();
 
       }
       else wmenu = gtk_menu_bar_new ();
 
-      /* Fix up grabs after keyboard traversal ends.  */
-      g_signal_connect (G_OBJECT (wmenu),
-                        "selection-done",
-                        G_CALLBACK (menu_nav_ended),
-                        f);
-
       /* Put cl_data on the top menu for easier access.  */
       cl_data = make_cl_data (cl_data, f, highlight_cb);
       g_object_set_data (G_OBJECT (wmenu), XG_FRAME_DATA, (gpointer)cl_data);
       /* Put cl_data on the top menu for easier access.  */
       cl_data = make_cl_data (cl_data, f, highlight_cb);
       g_object_set_data (G_OBJECT (wmenu), XG_FRAME_DATA, (gpointer)cl_data);
@@ -2373,7 +2413,7 @@ xg_destroy_widgets (list)
 
 static void
 xg_update_menubar (menubar, f, list, iter, pos, val,
 
 static void
 xg_update_menubar (menubar, f, list, iter, pos, val,
-                   select_cb, highlight_cb, cl_data)
+                   select_cb, deactivate_cb, highlight_cb, cl_data)
      GtkWidget *menubar;
      FRAME_PTR f;
      GList **list;
      GtkWidget *menubar;
      FRAME_PTR f;
      GList **list;
@@ -2381,6 +2421,7 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
      int pos;
      widget_value *val;
      GCallback select_cb;
      int pos;
      widget_value *val;
      GCallback select_cb;
+     GCallback deactivate_cb;
      GCallback highlight_cb;
      xg_menu_cb_data *cl_data;
 {
      GCallback highlight_cb;
      xg_menu_cb_data *cl_data;
 {
@@ -2398,7 +2439,7 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
   else if (! iter && val)
     {
       /* Item(s) added.  Add all new items in one call.  */
   else if (! iter && val)
     {
       /* Item(s) added.  Add all new items in one call.  */
-      create_menus (val, f, select_cb, 0, highlight_cb,
+      create_menus (val, f, select_cb, deactivate_cb, highlight_cb,
                     0, 1, 0, menubar, cl_data, 0);
 
       /* All updated.  */
                     0, 1, 0, menubar, cl_data, 0);
 
       /* All updated.  */
@@ -2505,7 +2546,8 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
           /* Create a possibly empty submenu for menu bar items, since some
              themes don't highlight items correctly without it. */
           GtkWidget *submenu = create_menus (NULL, f,
           /* Create a possibly empty submenu for menu bar items, since some
              themes don't highlight items correctly without it. */
           GtkWidget *submenu = create_menus (NULL, f,
-                                             select_cb, NULL, highlight_cb,
+                                             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);
                                              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);
@@ -2543,13 +2585,13 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
 
   /* Update the rest of the menu bar.  */
   xg_update_menubar (menubar, f, list, iter, pos, val,
 
   /* Update the rest of the menu bar.  */
   xg_update_menubar (menubar, f, list, iter, pos, val,
-                     select_cb, highlight_cb, cl_data);
+                     select_cb, deactivate_cb, highlight_cb, cl_data);
 }
 
 /* Update the menu item W so it corresponds to VAL.
    SELECT_CB is the callback to use when a menu item is selected.
    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
 }
 
 /* Update the menu item W so it corresponds to VAL.
    SELECT_CB is the callback to use when a menu item is selected.
    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
-   CL_DATA is the data to set in the widget for menu invokation.  */
+   CL_DATA is the data to set in the widget for menu invocation.  */
 
 static void
 xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
 
 static void
 xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
@@ -2848,7 +2890,7 @@ xg_modify_menubar_widgets (menubar, f, val, deep_p,
                                                   XG_FRAME_DATA);
 
   xg_update_menubar (menubar, f, &list, list, 0, val->contents,
                                                   XG_FRAME_DATA);
 
   xg_update_menubar (menubar, f, &list, list, 0, val->contents,
-                     select_cb, highlight_cb, cl_data);
+                     select_cb, deactivate_cb, highlight_cb, cl_data);
 
   if (deep_p)
     {
 
   if (deep_p)
     {
@@ -2927,7 +2969,7 @@ xg_update_frame_menubar (f)
 
   /* The height has changed, resize outer widget and set columns
      rows to what we had before adding the menu bar.  */
 
   /* The height has changed, resize outer widget and set columns
      rows to what we had before adding the menu bar.  */
-  xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
+  xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
 
   SET_FRAME_GARBAGED (f);
   UNBLOCK_INPUT;
 
   SET_FRAME_GARBAGED (f);
   UNBLOCK_INPUT;
@@ -2956,7 +2998,7 @@ free_frame_menubar (f)
 
       /* The height has changed, resize outer widget and set columns
          rows to what we had before removing the menu bar.  */
 
       /* The height has changed, resize outer widget and set columns
          rows to what we had before removing the menu bar.  */
-      xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
+      xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
 
       SET_FRAME_GARBAGED (f);
       UNBLOCK_INPUT;
 
       SET_FRAME_GARBAGED (f);
       UNBLOCK_INPUT;
@@ -3090,12 +3132,12 @@ xg_gtk_scroll_destroy (widget, data)
   int id = (int) (EMACS_INT) data; /* The EMACS_INT cast avoids a warning. */
 
   p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
   int id = (int) (EMACS_INT) data; /* The EMACS_INT cast avoids a warning. */
 
   p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
-  if (p) xfree (p);
+  xfree (p);
   xg_remove_widget_from_map (id);
 }
 
 /* Callback for button press/release events.  Used to start timer so that
   xg_remove_widget_from_map (id);
 }
 
 /* Callback for button press/release events.  Used to start timer so that
-   the scroll bar repetition timer in GTK gets handeled.
+   the scroll bar repetition timer in GTK gets handled.
    Also, sets bar->dragging to Qnil when dragging (button release) is done.
    WIDGET is the scroll bar widget the event is for (not used).
    EVENT contains the event.
    Also, sets bar->dragging to Qnil when dragging (button release) is done.
    WIDGET is the scroll bar widget the event is for (not used).
    EVENT contains the event.
@@ -3411,17 +3453,21 @@ xg_tool_bar_callback (w, client_data)
      to `(tool_bar)', see keyboard.c.  */
   event.kind = TOOL_BAR_EVENT;
   event.frame_or_window = frame;
      to `(tool_bar)', see keyboard.c.  */
   event.kind = TOOL_BAR_EVENT;
   event.frame_or_window = frame;
-  event.arg = frame;    
-  kbd_buffer_store_event (&event);      
-  
-  event.kind = TOOL_BAR_EVENT;          
+  event.arg = frame;
+  kbd_buffer_store_event (&event);
+
+  event.kind = TOOL_BAR_EVENT;
   event.frame_or_window = frame;
   event.arg = key;
   /* Convert between the modifier bits GDK uses and the modifier bits
   event.frame_or_window = frame;
   event.arg = key;
   /* Convert between the modifier bits GDK uses and the modifier bits
-     Emacs uses.  This assumes GDK an X masks are the same, which they are when
+     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);
   kbd_buffer_store_event (&event);
      this is written.  */
   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);
 }
 
 /* Callback function invoked when a tool bar item is pressed in a detached
 }
 
 /* Callback function invoked when a tool bar item is pressed in a detached
@@ -3439,6 +3485,8 @@ xg_tool_bar_proxy_callback (w, client_data)
   GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
                                                       XG_TOOL_BAR_PROXY_BUTTON));
   xg_tool_bar_callback (wbutton, client_data);
   GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
                                                       XG_TOOL_BAR_PROXY_BUTTON));
   xg_tool_bar_callback (wbutton, client_data);
+  FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (wbutton),
+                                               XG_FRAME_DATA);
 }
 
 /* This callback is called when a tool item should create a proxy item,
 }
 
 /* This callback is called when a tool item should create a proxy item,
@@ -3456,7 +3504,7 @@ xg_tool_bar_menu_proxy (toolitem, user_data)
   GtkWidget *wmenuitem = gtk_image_menu_item_new ();
   GtkWidget *wmenuimage;
 
   GtkWidget *wmenuitem = gtk_image_menu_item_new ();
   GtkWidget *wmenuimage;
 
-  if (gtk_button_get_use_stock (wbutton)) 
+  if (gtk_button_get_use_stock (wbutton))
     wmenuimage = gtk_image_new_from_stock (gtk_button_get_label (wbutton),
                                            GTK_ICON_SIZE_MENU);
   else
     wmenuimage = gtk_image_new_from_stock (gtk_button_get_label (wbutton),
                                            GTK_ICON_SIZE_MENU);
   else
@@ -3481,7 +3529,7 @@ xg_tool_bar_menu_proxy (toolitem, user_data)
       else if (store_type == GTK_IMAGE_PIXBUF)
         {
           gint width, height;
       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))
           if (settings &&
               gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
                                                  &width, &height))
@@ -3500,7 +3548,7 @@ xg_tool_bar_menu_proxy (toolitem, user_data)
               abort ();
             }
         }
               abort ();
             }
         }
-      else if (store_type == GTK_IMAGE_ICON_NAME) 
+      else if (store_type == GTK_IMAGE_ICON_NAME)
         {
           const gchar *icon_name;
           GtkIconSize icon_size;
         {
           const gchar *icon_name;
           GtkIconSize icon_size;
@@ -3560,7 +3608,7 @@ xg_tool_bar_detach_callback (wbox, w, client_data)
 
       /* The height has changed, resize outer widget and set columns
          rows to what we had before detaching the tool bar.  */
 
       /* The height has changed, resize outer widget and set columns
          rows to what we had before detaching the tool bar.  */
-      xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
+      xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
     }
 }
 
     }
 }
 
@@ -3591,7 +3639,7 @@ xg_tool_bar_attach_callback (wbox, w, client_data)
 
       /* The height has changed, resize outer widget and set columns
          rows to what we had before attaching the tool bar.  */
 
       /* The height has changed, resize outer widget and set columns
          rows to what we had before attaching the tool bar.  */
-      xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
+      xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
     }
 }
 
     }
 }
 
@@ -3668,22 +3716,20 @@ xg_tool_bar_item_expose_callback (w, event, client_data)
   return FALSE;
 }
 
   return FALSE;
 }
 
-#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
-
-
-/* Create a tool bar for frame F.  */
+/* Attach a tool bar to frame F.  */
 
 static void
 
 static void
-xg_create_tool_bar (f)
+xg_pack_tool_bar (f)
      FRAME_PTR f;
 {
   struct x_output *x = f->output_data.x;
      FRAME_PTR f;
 {
   struct x_output *x = f->output_data.x;
-  GtkRequisition req;
   int vbox_pos = x->menubar_widget ? 1 : 0;
 
   int vbox_pos = x->menubar_widget ? 1 : 0;
 
-  x->toolbar_widget = gtk_toolbar_new ();
   x->handlebox_widget = gtk_handle_box_new ();
   x->handlebox_widget = gtk_handle_box_new ();
-  x->toolbar_detached = 0;
+  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);
 
   gtk_container_add (GTK_CONTAINER (x->handlebox_widget),
                      x->toolbar_widget);
@@ -3693,6 +3739,20 @@ xg_create_tool_bar (f)
 
   gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->handlebox_widget,
                          vbox_pos);
 
   gtk_box_reorder_child (GTK_BOX (x->vbox_widget), x->handlebox_widget,
                          vbox_pos);
+  gtk_widget_show_all (x->handlebox_widget);
+}
+
+/* Create a tool bar for frame F.  */
+
+static void
+xg_create_tool_bar (f)
+     FRAME_PTR f;
+{
+  struct x_output *x = f->output_data.x;
+  GtkRequisition req;
+
+  x->toolbar_widget = gtk_toolbar_new ();
+  x->toolbar_detached = 0;
 
   gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
 
 
   gtk_widget_set_name (x->toolbar_widget, "emacs-toolbar");
 
@@ -3706,23 +3766,10 @@ xg_create_tool_bar (f)
   gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
   gtk_toolbar_set_orientation (GTK_TOOLBAR (x->toolbar_widget),
                                GTK_ORIENTATION_HORIZONTAL);
   gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS);
   gtk_toolbar_set_orientation (GTK_TOOLBAR (x->toolbar_widget),
                                GTK_ORIENTATION_HORIZONTAL);
+}
 
 
-  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_widget_show_all (x->handlebox_widget);
-
-  gtk_widget_size_request (x->toolbar_widget, &req);
-  FRAME_TOOLBAR_HEIGHT (f) = req.height;
-
-  /* The height has changed, resize outer widget and set columns
-     rows to what we had before adding the tool bar.  */
-  xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
 
 
-  SET_FRAME_GARBAGED (f);
-}
+#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
 
 /* Find the right-to-left image named by RTL in the tool bar images for F.
    Returns IMAGE if RTL is not found.  */
 
 /* Find the right-to-left image named by RTL in the tool bar images for F.
    Returns IMAGE if RTL is not found.  */
@@ -3743,7 +3790,7 @@ find_rtl_image (f, image, rtl)
   for (i = 0; i < f->n_tool_bar_items; ++i)
     {
       Lisp_Object rtl_image = PROP (TOOL_BAR_ITEM_IMAGES);
   for (i = 0; i < f->n_tool_bar_items; ++i)
     {
       Lisp_Object rtl_image = PROP (TOOL_BAR_ITEM_IMAGES);
-      if (!NILP (file = file_for_image (rtl_image))) 
+      if (!NILP (file = file_for_image (rtl_image)))
         {
           file = call1 (intern ("file-name-sans-extension"),
                        Ffile_name_nondirectory (file));
         {
           file = call1 (intern ("file-name-sans-extension"),
                        Ffile_name_nondirectory (file));
@@ -3771,6 +3818,7 @@ update_frame_tool_bar (f)
   GtkToolbar *wtoolbar;
   GtkToolItem *ti;
   GtkTextDirection dir;
   GtkToolbar *wtoolbar;
   GtkToolItem *ti;
   GtkTextDirection dir;
+  int pack_tool_bar = x->handlebox_widget == NULL;
 
   if (! FRAME_GTK_WIDGET (f))
     return;
 
   if (! FRAME_GTK_WIDGET (f))
     return;
@@ -3818,7 +3866,7 @@ update_frame_tool_bar (f)
       int icon_size = 0;
       struct image *img = NULL;
       Lisp_Object image;
       int icon_size = 0;
       struct image *img = NULL;
       Lisp_Object image;
-      Lisp_Object stock;
+      Lisp_Object stock = Qnil;
       GtkStockItem stock_item;
       char *stock_name = NULL;
       char *icon_name = NULL;
       GtkStockItem stock_item;
       char *stock_name = NULL;
       char *icon_name = NULL;
@@ -3868,7 +3916,7 @@ update_frame_tool_bar (f)
             }
           else if (gtk_stock_lookup (SSDATA (stock), &stock_item))
               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 
+          else
             {
               stock = Qnil;
               stock_name = NULL;
             {
               stock = Qnil;
               stock_name = NULL;
@@ -3908,7 +3956,7 @@ update_frame_tool_bar (f)
           img_id = lookup_image (f, image);
           img = IMAGE_FROM_ID (f, img_id);
           prepare_image_for_display (f, img);
           img_id = lookup_image (f, image);
           img = IMAGE_FROM_ID (f, img_id);
           prepare_image_for_display (f, img);
-      
+
           if (img->load_failed_p || img->pixmap == None)
             {
                 if (ti)
           if (img->load_failed_p || img->pixmap == None)
             {
                 if (ti)
@@ -3940,7 +3988,7 @@ update_frame_tool_bar (f)
                                       (gpointer) xstrdup (stock_name),
                                       (GDestroyNotify) xfree);
             }
                                       (gpointer) xstrdup (stock_name),
                                       (GDestroyNotify) xfree);
             }
-          else if (icon_name) 
+          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,
             {
               w = gtk_image_new_from_icon_name (icon_name, icon_size);
               g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_ICON_NAME,
@@ -3991,7 +4039,7 @@ update_frame_tool_bar (f)
 
           gtk_widget_set_sensitive (wbutton, enabled_p);
           gtk_tool_item_set_homogeneous (ti, FALSE);
 
           gtk_widget_set_sensitive (wbutton, enabled_p);
           gtk_tool_item_set_homogeneous (ti, FALSE);
-          
+
           /* Callback to save modifyer mask (Shift/Control, etc).  GTK makes
              no distinction based on modifiers in the activate callback,
              so we have to do it ourselves.  */
           /* Callback to save modifyer mask (Shift/Control, etc).  GTK makes
              no distinction based on modifiers in the activate callback,
              so we have to do it ourselves.  */
@@ -4077,12 +4125,19 @@ update_frame_tool_bar (f)
       if (ti) gtk_widget_hide_all (GTK_WIDGET (ti));
     } while (ti != NULL);
 
       if (ti) gtk_widget_hide_all (GTK_WIDGET (ti));
     } while (ti != NULL);
 
+  new_req.height = 0;
   gtk_widget_size_request (GTK_WIDGET (wtoolbar), &new_req);
   gtk_widget_size_request (GTK_WIDGET (wtoolbar), &new_req);
-  if (old_req.height != new_req.height
+
+  if (pack_tool_bar && f->n_tool_bar_items != 0)
+    xg_pack_tool_bar (f);
+
+  if (new_req.height != 0
+      && f->n_tool_bar_items != 0
+      && old_req.height != new_req.height
       && ! FRAME_X_OUTPUT (f)->toolbar_detached)
     {
       FRAME_TOOLBAR_HEIGHT (f) = new_req.height;
       && ! FRAME_X_OUTPUT (f)->toolbar_detached)
     {
       FRAME_TOOLBAR_HEIGHT (f) = new_req.height;
-      xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
+      xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
     }
 
   UNBLOCK_INPUT;
     }
 
   UNBLOCK_INPUT;
@@ -4099,18 +4154,23 @@ free_frame_tool_bar (f)
 
   if (x->toolbar_widget)
     {
 
   if (x->toolbar_widget)
     {
+      int is_packed = x->handlebox_widget != 0;
       BLOCK_INPUT;
       BLOCK_INPUT;
-      gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
-                            x->handlebox_widget);
+      /* 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)
+        gtk_container_remove (GTK_CONTAINER (x->vbox_widget),
+                              x->handlebox_widget);
+      else
+        gtk_widget_destroy (x->toolbar_widget);
+
       x->toolbar_widget = 0;
       x->handlebox_widget = 0;
       FRAME_TOOLBAR_HEIGHT (f) = 0;
 
       /* The height has changed, resize outer widget and set columns
          rows to what we had before removing the tool bar.  */
       x->toolbar_widget = 0;
       x->handlebox_widget = 0;
       FRAME_TOOLBAR_HEIGHT (f) = 0;
 
       /* The height has changed, resize outer widget and set columns
          rows to what we had before removing the tool bar.  */
-      xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
-
-      SET_FRAME_GARBAGED (f);
+      xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
       UNBLOCK_INPUT;
     }
 }
       UNBLOCK_INPUT;
     }
 }