]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkwindow.c
gtk: fix C99-style variable declarations in various sources
[~andy/gtk] / gtk / gtkwindow.c
index 0703592e1373416eb489b5158c25d84092d8b61c..0621701be9a619385bd299f6699c3d8bd7a73179 100644 (file)
@@ -48,6 +48,7 @@
 #include "gtkmarshalers.h"
 #include "gtkplug.h"
 #include "gtkbuildable.h"
+#include "gtkwidgetprivate.h"
 
 #ifdef GDK_WINDOWING_X11
 #include "x11/gdkx.h"
@@ -112,9 +113,10 @@ struct _GtkWindowPrivate
   GdkWindow             *frame;
   GdkWindowTypeHint      gdk_type_hint;
 
+  GtkApplication        *application;
+
   gdouble  opacity;
 
-  gboolean   has_resize_grip;
   GdkWindow *grip_window;
 
   gchar   *startup_id;
@@ -129,11 +131,6 @@ struct _GtkWindowPrivate
   guint    frame_top;
   guint    keys_changed_handler;
 
-  /* Don't use this value, it's only used for determining when
-   * to fire notify events on the "resize-grip-visible" property.
-   */
-  gboolean resize_grip_visible;
-
   guint16  configure_request_count;
 
   /* The following flags are initially TRUE (before a window is mapped).
@@ -175,9 +172,17 @@ struct _GtkWindowPrivate
   guint    stick_initially           : 1;
   guint    transient_parent_group    : 1;
   guint    type                      : 4; /* GtkWindowType */
-  guint    type_hint                 : 3; /* GdkWindowTypeHint if the hint is one of the original eight. If not, then
-                                          * it contains GDK_WINDOW_TYPE_HINT_NORMAL */
+  guint    type_hint                 : 3; /* GdkWindowTypeHint if the hint is
+                                           * one of the original eight. If not,
+                                           * then it contains
+                                           * GDK_WINDOW_TYPE_HINT_NORMAL
+                                           */
   guint    urgent                    : 1;
+  guint    has_resize_grip           : 1;
+  guint    resize_grip_visible       : 1;  /* don't use, just for "resize-
+                                            * grip-visible" notification
+                                            */
+
 };
 
 enum {
@@ -220,7 +225,7 @@ enum {
   PROP_OPACITY,
   PROP_HAS_RESIZE_GRIP,
   PROP_RESIZE_GRIP_VISIBLE,
-
+  PROP_APPLICATION,
   /* Readonly properties */
   PROP_IS_ACTIVE,
   PROP_HAS_TOPLEVEL_FOCUS,
@@ -280,11 +285,15 @@ struct _GtkWindowGeometryInfo
    */
   guint          position_constraints_changed : 1;
 
-  /* if true, default_width, height come from gtk_window_parse_geometry,
-   * and thus should be multiplied by the increments and affect the
-   * geometry widget only
+  /* if true, default_width, height should be multiplied by the
+   * increments and affect the geometry widget only
    */
   guint          default_is_geometry : 1;
+
+  /* if true, resize_width, height should be multiplied by the
+   * increments and affect the geometry widget only
+   */
+  guint          resize_is_geometry : 1;
   
   GtkWindowLastGeometryInfo last;
 };
@@ -336,6 +345,8 @@ static gint gtk_window_focus_in_event     (GtkWidget         *widget,
                                           GdkEventFocus     *event);
 static gint gtk_window_focus_out_event    (GtkWidget         *widget,
                                           GdkEventFocus     *event);
+static void gtk_window_style_set          (GtkWidget         *widget,
+                                           GtkStyle          *style);
 static gint gtk_window_client_event      (GtkWidget         *widget,
                                           GdkEventClient    *event);
 static gboolean gtk_window_state_event    (GtkWidget          *widget,
@@ -343,6 +354,8 @@ static gboolean gtk_window_state_event    (GtkWidget          *widget,
 static void gtk_window_check_resize       (GtkContainer      *container);
 static gint gtk_window_focus              (GtkWidget        *widget,
                                           GtkDirectionType  direction);
+static void gtk_window_move_focus         (GtkWidget         *widget,
+                                           GtkDirectionType   dir);
 static void gtk_window_real_set_focus     (GtkWindow         *window,
                                           GtkWidget         *focus);
 static void gtk_window_direction_changed  (GtkWidget         *widget,
@@ -352,8 +365,6 @@ static void gtk_window_state_changed      (GtkWidget         *widget,
 
 static void gtk_window_real_activate_default (GtkWindow         *window);
 static void gtk_window_real_activate_focus   (GtkWindow         *window);
-static void gtk_window_move_focus            (GtkWindow         *window,
-                                              GtkDirectionType   dir);
 static void gtk_window_keys_changed          (GtkWindow         *window);
 static gint gtk_window_draw                  (GtkWidget         *widget,
                                              cairo_t           *cr);
@@ -520,9 +531,10 @@ extract_time_from_startup_id (const gchar* startup_id)
       /* Skip past the "_TIME" part */
       timestr += 5;
 
+      end = NULL;
       errno = 0;
-      timestamp = strtoul (timestr, &end, 0);
-      if (end != timestr && errno == 0)
+      timestamp = g_ascii_strtoull (timestr, &end, 0);
+      if (errno == 0 && end != timestr)
         retval = timestamp;
     }
 
@@ -576,12 +588,14 @@ gtk_window_class_init (GtkWindowClass *klass)
   widget_class->focus_out_event = gtk_window_focus_out_event;
   widget_class->client_event = gtk_window_client_event;
   widget_class->focus = gtk_window_focus;
+  widget_class->move_focus = gtk_window_move_focus;
   widget_class->draw = gtk_window_draw;
   widget_class->get_preferred_width = gtk_window_get_preferred_width;
   widget_class->get_preferred_height = gtk_window_get_preferred_height;
   widget_class->window_state_event = gtk_window_state_event;
   widget_class->direction_changed = gtk_window_direction_changed;
   widget_class->state_changed = gtk_window_state_changed;
+  widget_class->style_set = gtk_window_style_set;
 
   container_class->check_resize = gtk_window_check_resize;
 
@@ -590,7 +604,6 @@ gtk_window_class_init (GtkWindowClass *klass)
 
   klass->activate_default = gtk_window_real_activate_default;
   klass->activate_focus = gtk_window_real_activate_focus;
-  klass->move_focus = gtk_window_move_focus;
   klass->keys_changed = gtk_window_keys_changed;
 
   g_type_class_add_private (gobject_class, sizeof (GtkWindowPrivate));
@@ -927,7 +940,6 @@ gtk_window_class_init (GtkWindowClass *klass)
                                                        1.0,
                                                        GTK_PARAM_READWRITE));
 
-
   /* Style properties.
    */
   gtk_widget_class_install_style_property (widget_class,
@@ -945,6 +957,24 @@ gtk_window_class_init (GtkWindowClass *klass)
 
   /* Signals
    */
+  /**
+   * GtkWindow:application:
+   *
+   * The #GtkApplication associated with the window.
+   *
+   * The application will be kept alive for at least as long as the
+   * window is open.
+   *
+   * Since: 3.0
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_APPLICATION,
+                                   g_param_spec_object ("application",
+                                                        P_("GtkApplication"),
+                                                        P_("The GtkApplication for the window"),
+                                                        GTK_TYPE_APPLICATION,
+                                                        GTK_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   window_signals[SET_FOCUS] =
     g_signal_new (I_("set-focus"),
                   G_TYPE_FROM_CLASS (gobject_class),
@@ -1209,6 +1239,9 @@ gtk_window_set_property (GObject      *object,
     case PROP_HAS_RESIZE_GRIP:
       gtk_window_set_has_resize_grip (window, g_value_get_boolean (value));
       break;
+    case PROP_APPLICATION:
+      gtk_window_set_application (window, g_value_get_object (value));
+      break;
     case PROP_MNEMONICS_VISIBLE:
       gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value));
       break;
@@ -1324,6 +1357,9 @@ gtk_window_get_property (GObject      *object,
     case PROP_RESIZE_GRIP_VISIBLE:
       g_value_set_boolean (value, gtk_window_resize_grip_is_visible (window));
       break;
+    case PROP_APPLICATION:
+      g_value_set_object (value, gtk_window_get_application (window));
+      break;
     case PROP_MNEMONICS_VISIBLE:
       g_value_set_boolean (value, priv->mnemonics_visible);
       break;
@@ -2588,6 +2624,78 @@ gtk_window_get_opacity (GtkWindow *window)
   return window->priv->opacity;
 }
 
+/**
+ * gtk_window_get_application:
+ * @window: a #GtkWindow
+ *
+ * Gets the #GtkApplication associated with the window (if any).
+ *
+ * Return value: a #GtkApplication, or %NULL
+ *
+ * Since: 3.0
+ **/
+GtkApplication *
+gtk_window_get_application (GtkWindow *window)
+{
+  g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
+
+  return window->priv->application;
+}
+
+static void
+gtk_window_release_application (GtkWindow *window)
+{
+  if (window->priv->application)
+    {
+      GtkApplication *application;
+
+      /* steal reference into temp variable */
+      application = window->priv->application;
+      window->priv->application = NULL;
+
+      gtk_application_remove_window (application, window);
+      g_object_unref (application);
+    }
+}
+
+/**
+ * gtk_window_set_application:
+ * @window: a #GtkWindow
+ * @application: a #GtkApplication, or %NULL
+ *
+ * Sets or unsets the #GtkApplication associated with the window.
+ *
+ * The application will be kept alive for at least as long as the window
+ * is open.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_window_set_application (GtkWindow      *window,
+                            GtkApplication *application)
+{
+  GtkWindowPrivate *priv;
+
+  g_return_if_fail (GTK_IS_WINDOW (window));
+
+  priv = window->priv;
+  if (priv->application != application)
+    {
+      gtk_window_release_application (window);
+
+      priv->application = application;
+
+      if (priv->application != NULL)
+        {
+          g_object_ref (priv->application);
+
+          gtk_application_add_window (priv->application, window);
+        }
+
+      g_object_notify (G_OBJECT (window), "application");
+    }
+}
+
 /**
  * gtk_window_set_type_hint:
  * @window: a #GtkWindow
@@ -3028,7 +3136,7 @@ gtk_window_set_geometry_hints (GtkWindow       *window,
     {
       gtk_window_set_gravity (window, geometry->win_gravity);
     }
-  
+
   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
 }
 
@@ -3304,6 +3412,8 @@ gtk_window_realize_icon (GtkWindow *window)
     }
 
   info->realized = TRUE;
+
+  gdk_window_set_icon_list (gtk_widget_get_window (widget), icon_list);
   
   if (info->using_themed_icon) 
     {
@@ -3927,6 +4037,30 @@ gtk_window_set_default_size (GtkWindow   *window,
   gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height, FALSE);
 }
 
+/**
+ * gtk_window_set_default_geometry:
+ * @window: a #GtkWindow
+ * @width: width in resize increments, or -1 to unset the default width
+ * @height: height in resize increments, or -1 to unset the default height
+ *
+ * Like gtk_window_set_default_size(), but @width and @height are interpreted
+ * in terms of the base size and increment set with
+ * gtk_window_set_geometry_hints.
+ *
+ * Since: 3.0
+ */
+void
+gtk_window_set_default_geometry (GtkWindow *window,
+                                gint       width,
+                                gint       height)
+{
+  g_return_if_fail (GTK_IS_WINDOW (window));
+  g_return_if_fail (width >= -1);
+  g_return_if_fail (height >= -1);
+
+  gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height, TRUE);
+}
+
 /**
  * gtk_window_get_default_size:
  * @window: a #GtkWindow
@@ -3991,6 +4125,39 @@ gtk_window_resize (GtkWindow *window,
 
   info->resize_width = width;
   info->resize_height = height;
+  info->resize_is_geometry = FALSE;
+
+  gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
+}
+
+/**
+ * gtk_window_resize_to_geometry:
+ * @window: a #GtkWindow
+ * @width: width in resize increments to resize the window to
+ * @height: height in resize increments to resize the window to
+ *
+ * Like gtk_window_resize(), but @width and @height are interpreted
+ * in terms of the base size and increment set with
+ * gtk_window_set_geometry_hints.
+ *
+ * Since: 3.0
+ */
+void
+gtk_window_resize_to_geometry (GtkWindow *window,
+                              gint       width,
+                              gint       height)
+{
+  GtkWindowGeometryInfo *info;
+
+  g_return_if_fail (GTK_IS_WINDOW (window));
+  g_return_if_fail (width > 0);
+  g_return_if_fail (height > 0);
+
+  info = gtk_window_get_geometry_info (window, TRUE);
+
+  info->resize_width = width;
+  info->resize_height = height;
+  info->resize_is_geometry = TRUE;
 
   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
 }
@@ -4421,6 +4588,7 @@ gtk_window_finalize (GObject *object)
   g_free (priv->wmclass_name);
   g_free (priv->wmclass_class);
   g_free (priv->wm_role);
+  gtk_window_release_application (window);
 
   mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
   if (mnemonic_hash)
@@ -4528,7 +4696,7 @@ gtk_window_show (GtkWidget *widget)
   /* Try to make sure that we have some focused widget
    */
   if (!priv->focus_widget && !GTK_IS_PLUG (window))
-    gtk_window_move_focus (window, GTK_DIR_TAB_FORWARD);
+    gtk_window_move_focus (widget, GTK_DIR_TAB_FORWARD);
   
   if (priv->modal)
     gtk_grab_add (widget);
@@ -4730,7 +4898,11 @@ gtk_window_realize (GtkWidget *widget)
       allocation.height == 1)
     {
       GtkRequisition requisition;
-      GtkAllocation allocation = { 0, 0, 200, 200 };
+
+      allocation.x = 0;
+      allocation.y = 0;
+      allocation.width = 200;
+      allocation.height = 200;
 
       gtk_widget_get_preferred_size (widget, &requisition, NULL);
       if (requisition.width || requisition.height)
@@ -4784,7 +4956,7 @@ gtk_window_realize (GtkWidget *widget)
                               GDK_BUTTON_RELEASE_MASK);
       
       attributes_mask = GDK_WA_VISUAL;
-      
+
       priv->frame = gdk_window_new (gtk_widget_get_root_window (widget),
                                      &attributes, attributes_mask);
                                                 
@@ -4944,7 +5116,49 @@ gtk_window_unrealize (GtkWidget *widget)
 static GdkWindowEdge
 get_grip_edge (GtkWidget *widget)
 {
-  return gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR ? GDK_WINDOW_EDGE_SOUTH_EAST : GDK_WINDOW_EDGE_SOUTH_WEST;
+  return gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR
+         ? GDK_WINDOW_EDGE_SOUTH_EAST
+         : GDK_WINDOW_EDGE_SOUTH_WEST;
+}
+
+static gboolean
+get_drag_edge (GtkWidget     *widget,
+               GdkWindowEdge *edge)
+{
+  GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
+  gboolean hresizable;
+  gboolean vresizable;
+  GtkTextDirection dir;
+  GtkWindowGeometryInfo *info;
+
+  hresizable = TRUE;
+  vresizable = TRUE;
+
+  info = priv->geometry_info;
+  if (info)
+    {
+      GdkWindowHints flags = info->last.flags;
+      GdkGeometry *geometry = &info->last.geometry;
+
+      if ((flags & GDK_HINT_MIN_SIZE) && (flags & GDK_HINT_MAX_SIZE))
+        {
+          hresizable = geometry->min_width < geometry->max_width;
+          vresizable = geometry->min_height < geometry->max_height;
+        }
+    }
+
+  dir = gtk_widget_get_direction (widget);
+
+  if (hresizable && vresizable)
+    *edge = dir == GTK_TEXT_DIR_LTR ? GDK_WINDOW_EDGE_SOUTH_EAST : GDK_WINDOW_EDGE_SOUTH_WEST;
+  else if (hresizable)
+    *edge = dir == GTK_TEXT_DIR_LTR ? GDK_WINDOW_EDGE_EAST : GDK_WINDOW_EDGE_WEST;
+  else if (vresizable)
+    *edge = GDK_WINDOW_EDGE_SOUTH;
+  else
+    return FALSE;
+
+  return TRUE;
 }
 
 static void
@@ -4952,22 +5166,41 @@ set_grip_cursor (GtkWindow *window)
 {
   GtkWidget *widget = GTK_WIDGET (window);
   GtkWindowPrivate *priv = window->priv;
-  GdkWindowEdge edge;
-  GdkDisplay *display;
-  GdkCursorType cursor_type;
-  GdkCursor *cursor;
 
   if (priv->grip_window == NULL)
     return;
 
   if (gtk_widget_is_sensitive (widget))
     {
-      edge = get_grip_edge (widget);
+      GdkWindowEdge edge;
+      GdkDisplay *display;
+      GdkCursorType cursor_type;
+      GdkCursor *cursor;
 
-      if (edge == GDK_WINDOW_EDGE_SOUTH_EAST)
-        cursor_type = GDK_BOTTOM_RIGHT_CORNER;
-      else
-        cursor_type = GDK_BOTTOM_LEFT_CORNER;
+      cursor_type = GDK_LEFT_PTR;
+
+      if (get_drag_edge (widget, &edge))
+        {
+          switch (edge)
+            {
+            case GDK_WINDOW_EDGE_EAST:
+              cursor_type = GDK_RIGHT_SIDE;
+              break;
+            case GDK_WINDOW_EDGE_SOUTH_EAST:
+              cursor_type = GDK_BOTTOM_RIGHT_CORNER;
+              break;
+            case GDK_WINDOW_EDGE_SOUTH:
+              cursor_type = GDK_BOTTOM_SIDE;
+              break;
+            case GDK_WINDOW_EDGE_SOUTH_WEST:
+              cursor_type = GDK_BOTTOM_LEFT_CORNER;
+              break;
+            case GDK_WINDOW_EDGE_WEST:
+              cursor_type = GDK_LEFT_SIDE;
+              break;
+            default: ;
+            }
+        }
 
       display = gtk_widget_get_display (widget);
       cursor = gdk_cursor_new_for_display (display, cursor_type);
@@ -5017,6 +5250,7 @@ set_grip_shape (GtkWindow *window)
   cairo_surface_destroy (surface);
 
   gdk_window_shape_combine_region (priv->grip_window, region, 0, 0);
+  cairo_region_destroy (region);
 }
 
 static void
@@ -5061,11 +5295,14 @@ gtk_window_size_allocate (GtkWidget     *widget,
       gtk_widget_size_allocate (child, &child_allocation);
     }
 
-  if (gtk_widget_get_realized (widget) && priv->frame)
+  if (gtk_widget_get_realized (widget))
     {
-      gdk_window_resize (priv->frame,
-                        allocation->width + priv->frame_left + priv->frame_right,
-                        allocation->height + priv->frame_top + priv->frame_bottom);
+      if (priv->frame)
+        gdk_window_resize (priv->frame,
+                           allocation->width + priv->frame_left + priv->frame_right,
+                           allocation->height + priv->frame_top + priv->frame_bottom);
+      update_grip_visibility (window);
+      set_grip_position (window);
     }
 }
 
@@ -5220,10 +5457,28 @@ gtk_window_state_changed (GtkWidget    *widget,
 {
   GtkWindow *window = GTK_WINDOW (widget);
 
-  set_grip_cursor (window);
   update_grip_visibility (window);
 }
 
+static void
+gtk_window_style_set (GtkWidget *widget,
+                      GtkStyle  *style)
+{
+  GtkWindow *window = GTK_WINDOW (widget);
+  GtkWindowPrivate *priv = window->priv;
+  GdkRectangle rect;
+
+  if (priv->grip_window != NULL && gtk_window_get_resize_grip_area (window, &rect))
+    {
+      gdk_window_move_resize (priv->grip_window,
+                              rect.x, rect.y,
+                              rect.width, rect.height);
+
+      set_grip_shape (window);
+      gtk_widget_queue_resize (widget);
+    }
+}
+
 static void
 resize_grip_create_window (GtkWindow *window)
 {
@@ -5261,7 +5516,6 @@ resize_grip_create_window (GtkWindow *window)
 
   gdk_window_raise (priv->grip_window);
 
-  set_grip_cursor (window);
   set_grip_shape (window);
   update_grip_visibility (window);
 }
@@ -5328,9 +5582,14 @@ update_grip_visibility (GtkWindow *window)
   if (priv->grip_window != NULL)
     {
       if (val)
-        gdk_window_show (priv->grip_window);
+        {
+          gdk_window_show (priv->grip_window);
+          set_grip_cursor (window);
+        }
       else
-        gdk_window_hide (priv->grip_window);
+        {
+          gdk_window_hide (priv->grip_window);
+        }
     }
 
   if (priv->resize_grip_visible != val)
@@ -5354,21 +5613,34 @@ update_grip_visibility (GtkWindow *window)
 gboolean
 gtk_window_resize_grip_is_visible (GtkWindow *window)
 {
+  GtkWidget *widget;
+  GtkWindowPrivate *priv;
+  GdkWindowEdge edge;
+
   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
 
-  if (!window->priv->resizable)
+  priv = window->priv;
+  widget = GTK_WIDGET (window);
+
+  if (priv->type == GTK_WINDOW_POPUP)
     return FALSE;
 
-  if (gtk_widget_get_realized (GTK_WIDGET (window)))
+  if (!priv->resizable)
+    return FALSE;
+
+  if (gtk_widget_get_realized (widget))
     {
       GdkWindowState state;
 
-      state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
+      state = gdk_window_get_state (gtk_widget_get_window (widget));
 
       if (state & GDK_WINDOW_STATE_MAXIMIZED || state & GDK_WINDOW_STATE_FULLSCREEN)
         return FALSE;
     }
 
+  if (!get_drag_edge (widget, &edge))
+    return FALSE;
+
   return window->priv->has_resize_grip;
 }
 
@@ -5376,7 +5648,7 @@ gtk_window_resize_grip_is_visible (GtkWindow *window)
  * gtk_window_get_has_resize_grip:
  * @window: a #GtkWindow
  *
- * Determines whether the window may has a resize grip.
+ * Determines whether the window may have a resize grip.
  *
  * Returns: %TRUE if the window has a resize grip.
  *
@@ -5587,14 +5859,20 @@ gtk_window_button_press_event (GtkWidget *widget,
                                GdkEventButton *event)
 {
   GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
+  GdkWindowEdge edge;
 
   if (event->window == priv->grip_window)
-    gtk_window_begin_resize_drag (GTK_WINDOW (widget),
-                                  get_grip_edge (widget),
-                                  event->button,
-                                  event->x_root,
-                                  event->y_root,
-                                  event->time);
+    {
+      if (get_drag_edge (widget, &edge))
+        gtk_window_begin_resize_drag (GTK_WINDOW (widget),
+                                      edge,
+                                      event->button,
+                                      event->x_root,
+                                      event->y_root,
+                                      event->time);
+
+      return TRUE;
+    }
 
   return FALSE;
 }
@@ -5611,16 +5889,6 @@ gtk_window_real_activate_focus (GtkWindow *window)
   gtk_window_activate_focus (window);
 }
 
-static void
-gtk_window_move_focus (GtkWindow       *window,
-                       GtkDirectionType dir)
-{
-  gtk_widget_child_focus (GTK_WIDGET (window), dir);
-  
-  if (!gtk_container_get_focus_child (GTK_CONTAINER (window)))
-    gtk_window_set_focus (window, NULL);
-}
-
 static gint
 gtk_window_enter_notify_event (GtkWidget        *widget,
                               GdkEventCrossing *event)
@@ -5847,6 +6115,16 @@ gtk_window_focus (GtkWidget        *widget,
   return FALSE;
 }
 
+static void
+gtk_window_move_focus (GtkWidget       *widget,
+                       GtkDirectionType dir)
+{
+  gtk_widget_child_focus (widget, dir);
+
+  if (! gtk_container_get_focus_child (GTK_CONTAINER (widget)))
+    gtk_window_set_focus (GTK_WINDOW (widget), NULL);
+}
+
 static void
 gtk_window_real_set_focus (GtkWindow *window,
                           GtkWidget *focus)
@@ -6046,11 +6324,48 @@ _gtk_window_unset_focus_and_default (GtkWindow *window,
  * Functions related to resizing *
  *********************************/
 
+static void
+geometry_size_to_pixels (GdkGeometry *geometry,
+                        guint        flags,
+                        guint       *width,
+                        guint       *height)
+{
+  gint base_width = 0;
+  gint base_height = 0;
+  gint min_width = 0;
+  gint min_height = 0;
+  gint width_inc = 1;
+  gint height_inc = 1;
+
+  if (flags & GDK_HINT_BASE_SIZE)
+    {
+      base_width = geometry->base_width;
+      base_height = geometry->base_height;
+    }
+  if (flags & GDK_HINT_MIN_SIZE)
+    {
+      min_width = geometry->min_width;
+      min_height = geometry->min_height;
+    }
+  if (flags & GDK_HINT_RESIZE_INC)
+    {
+      width_inc = geometry->width_inc;
+      height_inc = geometry->height_inc;
+    }
+
+  if (width)
+    *width = MAX (*width * width_inc + base_width, min_width);
+  if (height)
+    *height = MAX (*height * height_inc + base_height, min_height);
+}
+
 /* This function doesn't constrain to geometry hints */
 static void 
-gtk_window_compute_configure_request_size (GtkWindow *window,
-                                           guint     *width,
-                                           guint     *height)
+gtk_window_compute_configure_request_size (GtkWindow   *window,
+                                           GdkGeometry *geometry,
+                                           guint        flags,
+                                           guint       *width,
+                                           guint       *height)
 {
   GtkWindowPrivate *priv = window->priv;
   GtkRequisition requisition;
@@ -6083,44 +6398,16 @@ gtk_window_compute_configure_request_size (GtkWindow *window,
        /* Override requisition with default size */
 
        if (info)
-         {
-          gint base_width = 0;
-          gint base_height = 0;
-          gint min_width = 0;
-          gint min_height = 0;
-          gint width_inc = 1;
-          gint height_inc = 1;
-          
-          if (info->default_is_geometry &&
-              (info->default_width > 0 || info->default_height > 0))
-            {
-              GdkGeometry geometry;
-              guint flags;
-              
-              gtk_window_compute_hints (window, &geometry, &flags);
-
-              if (flags & GDK_HINT_BASE_SIZE)
-                {
-                  base_width = geometry.base_width;
-                  base_height = geometry.base_height;
-                }
-              if (flags & GDK_HINT_MIN_SIZE)
-                {
-                  min_width = geometry.min_width;
-                  min_height = geometry.min_height;
-                }
-              if (flags & GDK_HINT_RESIZE_INC)
-                {
-                  width_inc = geometry.width_inc;
-                  height_inc = geometry.height_inc;
-                }
-            }
-            
+        {
           if (info->default_width > 0)
-            *width = MAX (info->default_width * width_inc + base_width, min_width);
-          
+            *width = info->default_width;
           if (info->default_height > 0)
-            *height = MAX (info->default_height * height_inc + base_height, min_height);
+            *height = info->default_height;
+
+          if (info->default_is_geometry)
+            geometry_size_to_pixels (geometry, flags,
+                                     info->default_width > 0 ? width : NULL,
+                                     info->default_height > 0 ? height : NULL);
          }
     }
   else
@@ -6138,10 +6425,14 @@ gtk_window_compute_configure_request_size (GtkWindow *window,
   if (info)
     {
       if (info->resize_width > 0)
-        *width = info->resize_width;
-
+       *width = info->resize_width;
       if (info->resize_height > 0)
-        *height = info->resize_height;
+       *height = info->resize_height;
+
+      if (info->resize_is_geometry)
+       geometry_size_to_pixels (geometry, flags,
+                                info->resize_width > 0 ? width : NULL,
+                                info->resize_height > 0 ? height : NULL);
     }
 
   /* Don't ever request zero width or height, its not supported by
@@ -6293,9 +6584,11 @@ gtk_window_compute_configure_request (GtkWindow    *window,
 
   screen = gtk_window_check_screen (window);
 
-  gtk_window_compute_configure_request_size (window, (guint *)&w, (guint *)&h);
-  
   gtk_window_compute_hints (window, &new_geometry, &new_flags);
+  gtk_window_compute_configure_request_size (window,
+                                            &new_geometry, new_flags,
+                                            (guint *)&w, (guint *)&h);
+
   gtk_window_constrain_size (window,
                              &new_geometry, new_flags,
                              w, h,
@@ -6713,12 +7006,8 @@ gtk_window_move_resize (GtkWindow *window)
       /* gtk_window_configure_event() filled in widget->allocation */
       gtk_widget_size_allocate (widget, &allocation);
 
-      if (priv->grip_window != NULL)
-        {
-          set_grip_position (window);
-          set_grip_cursor (window);
-          set_grip_shape (window);
-        }
+      set_grip_position (window);
+      update_grip_visibility (window);
 
       gdk_window_process_updates (gdk_window, TRUE);
 
@@ -7010,28 +7299,52 @@ gtk_window_compute_hints (GtkWindow   *window,
   
   if (geometry_info && geometry_info->widget)
     {
-      GtkRequisition requisition;
-      GtkRequisition child_requisition;
-
-      /* FIXME: This really isn't right. It gets the min size wrong and forces
-       * callers to do horrible hacks like set a huge usize on the child requisition
-       * to get the base size right. We really want to find the answers to:
-       *
-       *  - If the geometry widget was infinitely big, how much extra space
-       *    would be needed for the stuff around it.
+      /* If the geometry widget is set, then the hints really apply to that
+       * widget. This is pretty much meaningless unless the window layout
+       * is such that the rest of the window adds fixed size borders to
+       * the geometry widget. Our job is to figure the size of the borders;
+       * We do that by asking how big the toplevel would be if the
+       * geometry widget was *really big*.
        *
-       *  - If the geometry widget was infinitely small, how big would the
-       *    window still have to be.
+       *  +----------+
+       *  |AAAAAAAAA | At small sizes, the minimum sizes of widgets
+       *  |GGGGG    B| in the border can confuse things
+       *  |GGGGG    B|
+       *  |         B|
+       *  +----------+
        *
-       * Finding these answers would be a bit of a mess here. (Bug #68668)
+       *  +-----------+
+       *  |AAAAAAAAA  | When the geometry widget is large, things are
+       *  |GGGGGGGGGGB| clearer.
+       *  |GGGGGGGGGGB|
+       *  |GGGGGGGGGG |
+       *  +-----------+
        */
-      gtk_widget_get_preferred_size (geometry_info->widget,
-                                     &child_requisition, NULL);
+#define TEMPORARY_SIZE 10000 /* 10,000 pixels should be bigger than real widget sizes */
+      GtkRequisition requisition;
+      int current_width, current_height;
 
+      _gtk_widget_override_size_request (geometry_info->widget,
+                                        TEMPORARY_SIZE, TEMPORARY_SIZE,
+                                        &current_width, &current_height);
       gtk_widget_get_preferred_size (widget,
                                      &requisition, NULL);
-      extra_width = requisition.width - child_requisition.width;
-      extra_height = requisition.height - child_requisition.height;
+      _gtk_widget_restore_size_request (geometry_info->widget,
+                                       current_width, current_height);
+
+      extra_width = requisition.width - TEMPORARY_SIZE;
+      extra_height = requisition.height - TEMPORARY_SIZE;
+
+      if (extra_width < 0 || extra_width < 0)
+       {
+         g_warning("Toplevel size doesn't seem to directly depend on the "
+                   "size of the geometry widget from gtk_window_set_geometry_hints(). "
+                   "The geometry widget might not be in the window, or it might not "
+                   "be packed into the window appropriately");
+         extra_width = MAX(extra_width, 0);
+         extra_height = MAX(extra_height, 0);
+       }
+#undef TEMPORARY_SIZE
     }
 
   /* We don't want to set GDK_HINT_POS in here, we just set it
@@ -7044,27 +7357,39 @@ gtk_window_compute_hints (GtkWindow   *window,
       new_geometry->base_width += extra_width;
       new_geometry->base_height += extra_height;
     }
-  else if (!(*new_flags & GDK_HINT_MIN_SIZE) &&
-          (*new_flags & GDK_HINT_RESIZE_INC) &&
-          ((extra_width != 0) || (extra_height != 0)))
+  else
     {
+      /* For simplicity, we always set the base hint, even when we
+       * don't expect it to have any visible effect.
+       * (Note: geometry_size_to_pixels() depends on this.)
+       */
       *new_flags |= GDK_HINT_BASE_SIZE;
-      
+
       new_geometry->base_width = extra_width;
       new_geometry->base_height = extra_height;
+
+      /* As for X, if BASE_SIZE is not set but MIN_SIZE is set, then the
+       * base size is the minimum size */
+      if (*new_flags & GDK_HINT_MIN_SIZE)
+       {
+         if (new_geometry->min_width > 0)
+           new_geometry->base_width += new_geometry->min_width;
+         if (new_geometry->min_height > 0)
+           new_geometry->base_height += new_geometry->min_height;
+       }
     }
-  
+
   if (*new_flags & GDK_HINT_MIN_SIZE)
     {
       if (new_geometry->min_width < 0)
        new_geometry->min_width = requisition.width;
       else
-        new_geometry->min_width += extra_width;
+        new_geometry->min_width = MAX (requisition.width, new_geometry->min_width + extra_width);
 
       if (new_geometry->min_height < 0)
        new_geometry->min_height = requisition.height;
       else
-       new_geometry->min_height += extra_height;
+       new_geometry->min_height = MAX (requisition.height, new_geometry->min_height + extra_height);
     }
   else
     {
@@ -7121,7 +7446,7 @@ gtk_window_draw (GtkWidget *widget,
   if (GTK_WIDGET_CLASS (gtk_window_parent_class)->draw)
     ret = GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr);
 
-  if (priv->has_resize_grip &&
+  if (priv->grip_window != NULL &&
       gtk_cairo_should_draw_window (cr, priv->grip_window))
     {
       GdkRectangle rect;
@@ -7240,10 +7565,11 @@ gtk_window_set_frame_dimensions (GtkWindow *window,
 
   if (gtk_widget_get_realized (widget) && priv->frame)
     {
-      gtk_widget_get_allocation (widget, &allocation);
+         gint width, height;
+         gtk_widget_get_allocation (widget, &allocation);
 
-      gint width = allocation.width + left + right;
-      gint height = allocation.height + top + bottom;
+      width = allocation.width + left + right;
+      height = allocation.height + top + bottom;
       gdk_window_resize (priv->frame, width, height);
       gtk_decorated_window_move_resize_window (window,
                                               left, top,
@@ -7777,14 +8103,18 @@ gtk_window_set_resizable (GtkWindow *window,
 
   priv = window->priv;
 
-  priv->resizable = (resizable != FALSE);
+  resizable = (resizable != FALSE);
+
+  if (priv->resizable != resizable)
+    {
+      priv->resizable = (resizable != FALSE);
 
-  g_object_notify (G_OBJECT (window), "resizable");
+      update_grip_visibility (window);
 
-  if (priv->grip_window != NULL)
-    update_grip_visibility (window);
+      gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
 
-  gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
+      g_object_notify (G_OBJECT (window), "resizable");
+    }
 }
 
 /**
@@ -8739,7 +9069,7 @@ gtk_XParseGeometry (const char   *string,
  *   gtk_init (&argc, &argv);
  *   
  *   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- *   vbox = gtk_vbox_new (FALSE, 0);
+ *   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
  *   
  *   gtk_container_add (GTK_CONTAINER (window), vbox);
  *   fill_with_content (vbox);
@@ -8773,6 +9103,7 @@ gtk_window_parse_geometry (GtkWindow   *window,
 {
   gint result, x = 0, y = 0;
   guint w, h;
+  GtkWidget *child;
   GdkGravity grav;
   gboolean size_set, pos_set;
   GdkScreen *screen;
@@ -8780,6 +9111,12 @@ gtk_window_parse_geometry (GtkWindow   *window,
   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
   g_return_val_if_fail (geometry != NULL, FALSE);
 
+  child = gtk_bin_get_child (GTK_BIN (window));
+  if (!child || !gtk_widget_get_visible (child))
+    g_warning ("gtk_window_parse_geometry() called on a window with no "
+              "visible children; the window should be set up before "
+              "gtk_window_parse_geometry() is called.");
+
   screen = gtk_window_check_screen (window);
   
   result = gtk_XParseGeometry (geometry, &x, &y, &w, &h);