]> Pileus Git - ~andy/gtk/commitdiff
Fix handling of the geometry widget
authorOwen W. Taylor <otaylor@fishsoup.net>
Sun, 10 Oct 2010 02:15:34 +0000 (22:15 -0400)
committerOwen W. Taylor <otaylor@fishsoup.net>
Mon, 11 Oct 2010 18:05:29 +0000 (14:05 -0400)
The geometry widget feature of gtk_window_set_geometry_hints() has
never really worked right because the calculation that GTK+ did to
compute the base size of the window only worked when the geometry
widget had a larger minimum size than anything else in the window.

Setup:
* Move the GtkSizeGroup private functions to a new private header
  gtksizegroup-private.h
* Add the possibilty to pass flags to _gtk_size_group_queue_resize(),
  with the flag GTK_QUEUE_RESIZE_INVALIDATE_ONLY to suppress adding
  the widget's toplevel to the resize queue.
* _gtk_container_resize_invalidate() is added to implement that feature
* _gtk_widget_override_size_request()/_gtk_widget_restore_size_request()
  allow temporarily forcing a large minimum size on the geometry
  widget without creating resize loops.

GtkWindow:
* Compute the extra width/height around the geometry widget
  correctly; print a warning if the computation fails.
* Always make the minimum size at least the natural minimum
  size of the toplevel; GTK+ now fails badly with underallocation.
* Always set the base size hint; we were failing to set it
  properly when the specified minimum size was overriden, but
  it's harmless to always set it.

Tests:
* New test 'testgeometry' that replaces the 'gridded geometry' test
  from testgtk. The new test is roughly similar but creates a bunch
  of windows showing different possibilities.
* The testgtk test is removed. No need to have both.

https://bugzilla.gnome.org/show_bug.cgi?id=68668

13 files changed:
gtk/Makefile.am
gtk/gtkcontainer.c
gtk/gtkcontainer.h
gtk/gtkprivate.h
gtk/gtksizegroup-private.h [new file with mode: 0644]
gtk/gtksizegroup.c
gtk/gtksizegroup.h
gtk/gtksizerequest.c
gtk/gtkwidget.c
gtk/gtkwindow.c
tests/Makefile.am
tests/testgeometry.c [new file with mode: 0644]
tests/testgtk.c

index fb040fd085d2f72bafc970624a6c6550ff18f329..29df0c90e758532d2c0ee7767885130d7aac0b09 100644 (file)
@@ -382,6 +382,7 @@ gtk_private_h_sources =             \
        gtkrecentchooserdefault.h \
        gtkrecentchooserprivate.h \
        gtkrecentchooserutils.h \
+       gtksizegroup-private.h  \
        gtksocketprivate.h      \
        gtktextbtree.h          \
        gtktextbufferserialize.h\
index 17473e514cfda799bdbec1d5b5158107447b9b6d..75ac3f70a70818e8fa97980a4463c1b652c7d365 100644 (file)
@@ -1609,8 +1609,9 @@ gtk_container_idle_sizer (gpointer data)
   return FALSE;
 }
 
-void
-_gtk_container_queue_resize (GtkContainer *container)
+static void
+_gtk_container_queue_resize_internal (GtkContainer *container,
+                                     gboolean      invalidate_only)
 {
   GtkContainerPrivate *priv;
   GtkContainer *resize_container;
@@ -1637,7 +1638,7 @@ _gtk_container_queue_resize (GtkContainer *container)
       widget = parent;
     }
       
-  if (resize_container)
+  if (resize_container && !invalidate_only)
     {
       if (gtk_widget_get_visible (GTK_WIDGET (resize_container)) &&
           (gtk_widget_is_toplevel (GTK_WIDGET (resize_container)) ||
@@ -1677,6 +1678,36 @@ _gtk_container_queue_resize (GtkContainer *container)
     }
 }
 
+/**
+ * _gtk_container_queue_resize:
+ * @container: a #GtkContainer
+ *
+ * Determines the "resize container" in the hierarchy above this container
+ * (typically the toplevel, but other containers can be set as resize
+ * containers with gtk_container_set_resize_mode()), marks the container
+ * and all parents up to and including the resize container as needing
+ * to have sizes recompted, and if necessary adds the resize container
+ * to the queue of containers that will be resized out at idle.
+ */
+void
+_gtk_container_queue_resize (GtkContainer *container)
+{
+  _gtk_container_queue_resize_internal (container, FALSE);
+}
+
+/**
+ * _gtk_container_resize_invalidate:
+ * @container: a #GtkContainer
+ *
+ * Invalidates cached sizes like _gtk_container_queue_resize() but doesn't
+ * actually queue the resize container for resize.
+ */
+void
+_gtk_container_resize_invalidate (GtkContainer *container)
+{
+  _gtk_container_queue_resize_internal (container, TRUE);
+}
+
 void
 gtk_container_check_resize (GtkContainer *container)
 {
index 607baf6f7d88194bf6fe87c313eb7200897ad462..57a80aed3c882e6bdf7a3d530d531eb7ecd06e87 100644 (file)
@@ -210,6 +210,7 @@ void    gtk_container_class_handle_border_width (GtkContainerClass *klass);
 
 /* Non-public methods */
 void   _gtk_container_queue_resize          (GtkContainer *container);
+void   _gtk_container_resize_invalidate     (GtkContainer *container);
 void    _gtk_container_clear_resize_widgets   (GtkContainer *container);
 gchar* _gtk_container_child_composite_name   (GtkContainer *container,
                                              GtkWidget    *child);
index c0f14b4f328dc4abab8ccc3f2e0fb968e5ff311a..d8fd0c021b5830126e85f129768d3325029d18a2 100644 (file)
@@ -55,6 +55,15 @@ gboolean     _gtk_widget_get_height_request_needed (GtkWidget *widget);
 void         _gtk_widget_set_height_request_needed (GtkWidget *widget,
                                                     gboolean   height_request_needed);
 
+void _gtk_widget_override_size_request (GtkWidget *widget,
+                                       int        width,
+                                       int        height,
+                                       int       *old_width,
+                                       int       *old_height);
+void _gtk_widget_restore_size_request  (GtkWidget *widget,
+                                       int        old_width,
+                                       int        old_height);
+
 #ifdef G_OS_WIN32
 
 const gchar *_gtk_get_datadir ();
diff --git a/gtk/gtksizegroup-private.h b/gtk/gtksizegroup-private.h
new file mode 100644 (file)
index 0000000..3f80d3f
--- /dev/null
@@ -0,0 +1,49 @@
+/* GTK - The GIMP Toolkit
+ * gtksizegroup-private.h:
+ * Copyright (C) 2000-2010 Red Hat Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_SIZE_GROUP_PRIVATE_H__
+#define __GTK_SIZE_GROUP_PRIVATE_H__
+
+#include <gtk/gtksizegroup.h>
+
+/**
+ * GtkQueueResizeFlags:
+ * @GTK_QUEUE_RESIZE_INVALIDATE_ONLY: invalidate all cached sizes
+ *  as we would normally do when a widget is queued for resize,
+ *  but don't actually add the toplevel resize container to the
+ *  resize queue. Useful if we want to change the size of a widget
+ *  see how that would affect the overall layout, then restore
+ *  the old size.
+ *
+ * Flags that affect the operation of queueing a widget for resize.
+ */
+typedef enum
+{
+  GTK_QUEUE_RESIZE_INVALIDATE_ONLY = 1 << 0
+} GtkQueueResizeFlags;
+
+void _gtk_size_group_bump_requisition (GtkWidget           *widget,
+                                       GtkSizeGroupMode     mode,
+                                       gint                *minimum,
+                                       gint                *natural);
+void _gtk_size_group_queue_resize     (GtkWidget           *widget,
+                                       GtkQueueResizeFlags  flags);
+
+#endif /* __GTK_SIZE_GROUP_PRIVATE_H__ */
index 1663f97326c23ceeb197fab4df9017b5040d44e0..62ce9ea7e203669f18505eeb05b242f424081837 100644 (file)
@@ -23,7 +23,7 @@
 #include "gtkcontainer.h"
 #include "gtkintl.h"
 #include "gtkprivate.h"
-#include "gtksizegroup.h"
+#include "gtksizegroup-private.h"
 #include "gtkbuildable.h"
 
 
@@ -182,19 +182,27 @@ add_widget_to_closure (GtkWidget       *widget,
 }
 
 static void
-real_queue_resize (GtkWidget *widget)
+real_queue_resize (GtkWidget          *widget,
+                  GtkQueueResizeFlags flags)
 {
-  GtkWidget *parent;
+  GtkWidget *container;
 
   _gtk_widget_set_alloc_needed (widget, TRUE);
   _gtk_widget_set_width_request_needed (widget, TRUE);
   _gtk_widget_set_height_request_needed (widget, TRUE);
 
-  parent = gtk_widget_get_parent (widget);
-  if (parent)
-    _gtk_container_queue_resize (GTK_CONTAINER (parent));
-  else if (gtk_widget_is_toplevel (widget) && GTK_IS_CONTAINER (widget))
-    _gtk_container_queue_resize (GTK_CONTAINER (widget));
+  container = gtk_widget_get_parent (widget);
+  if (!container &&
+      gtk_widget_is_toplevel (widget) && GTK_IS_CONTAINER (widget))
+    container = widget;
+
+  if (container)
+    {
+      if (flags & GTK_QUEUE_RESIZE_INVALIDATE_ONLY)
+       _gtk_container_resize_invalidate (GTK_CONTAINER (container));
+      else
+       _gtk_container_queue_resize (GTK_CONTAINER (container));
+    }
 }
 
 static void
@@ -214,8 +222,9 @@ reset_group_sizes (GSList *groups)
 }
 
 static void
-queue_resize_on_widget (GtkWidget *widget,
-                       gboolean   check_siblings)
+queue_resize_on_widget (GtkWidget          *widget,
+                       gboolean            check_siblings,
+                       GtkQueueResizeFlags flags)
 {
   GtkWidget *parent = widget;
   GSList *tmp_list;
@@ -228,7 +237,7 @@ queue_resize_on_widget (GtkWidget *widget,
       
       if (widget == parent && !check_siblings)
        {
-         real_queue_resize (widget);
+         real_queue_resize (widget, flags);
           parent = gtk_widget_get_parent (parent);
          continue;
        }
@@ -237,7 +246,7 @@ queue_resize_on_widget (GtkWidget *widget,
       if (!widget_groups)
        {
          if (widget == parent)
-           real_queue_resize (widget);
+           real_queue_resize (widget, flags);
 
           parent = gtk_widget_get_parent (parent);
          continue;
@@ -258,14 +267,14 @@ queue_resize_on_widget (GtkWidget *widget,
          if (tmp_list->data == parent)
            {
              if (widget == parent)
-               real_queue_resize (parent);
+               real_queue_resize (parent, flags);
            }
          else if (tmp_list->data == widget)
             {
               g_warning ("A container and its child are part of this SizeGroup");
             }
          else
-           queue_resize_on_widget (tmp_list->data, FALSE);
+           queue_resize_on_widget (tmp_list->data, FALSE, flags);
 
          tmp_list = tmp_list->next;
        }
@@ -288,14 +297,14 @@ queue_resize_on_widget (GtkWidget *widget,
          if (tmp_list->data == parent)
            {
              if (widget == parent)
-               real_queue_resize (parent);
+               real_queue_resize (parent, flags);
            }
          else if (tmp_list->data == widget)
             {
               g_warning ("A container and its child are part of this SizeGroup");
             }
          else
-           queue_resize_on_widget (tmp_list->data, FALSE);
+           queue_resize_on_widget (tmp_list->data, FALSE, flags);
 
          tmp_list = tmp_list->next;
        }
@@ -308,12 +317,12 @@ queue_resize_on_widget (GtkWidget *widget,
 }
 
 static void
-queue_resize_on_group (GtkSizeGroup *size_group)
+queue_resize_on_group (GtkSizeGroup       *size_group)
 {
   GtkSizeGroupPrivate *priv = size_group->priv;
 
   if (priv->widgets)
-    queue_resize_on_widget (priv->widgets->data, TRUE);
+    queue_resize_on_widget (priv->widgets->data, TRUE, 0);
 }
 
 static void
@@ -806,11 +815,12 @@ _gtk_size_group_bump_requisition (GtkWidget        *widget,
  * Queue a resize on a widget, and on all other widgets grouped with this widget.
  **/
 void
-_gtk_size_group_queue_resize (GtkWidget *widget)
+_gtk_size_group_queue_resize (GtkWidget           *widget,
+                             GtkQueueResizeFlags  flags)
 {
   initialize_size_group_quarks ();
 
-  queue_resize_on_widget (widget, TRUE);
+  queue_resize_on_widget (widget, TRUE, flags);
 }
 
 typedef struct {
index d778f088112abe1f83f5b2971a716e7f02716a0f..ff1b0b10f98e7dc8c1fda6151bdd9c53c6233736 100644 (file)
@@ -92,15 +92,6 @@ void             gtk_size_group_remove_widget (GtkSizeGroup     *size_group,
                                               GtkWidget        *widget);
 GSList *         gtk_size_group_get_widgets   (GtkSizeGroup     *size_group);
 
-
-
-void _gtk_size_group_bump_requisition      (GtkWidget        *widget,
-                                           GtkSizeGroupMode  mode,
-                                           gint             *minimum,
-                                           gint             *natural);
-void _gtk_size_group_queue_resize          (GtkWidget        *widget);
-
-
 G_END_DECLS
 
 #endif /* __GTK_SIZE_GROUP_H__ */
index a30b2418e0f6728423c2ef8b4669d7d660a53b37..c3d0398fac439ced08594922a79d839d6fd04f2c 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <config.h>
 #include "gtksizerequest.h"
-#include "gtksizegroup.h"
+#include "gtksizegroup-private.h"
 #include "gtkdebug.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
index e3acd7826609305020483ce0968c6942b72ae9e1..779a00380fe8819b658de711940295dfca128d82 100644 (file)
@@ -40,7 +40,7 @@
 #include "gtkrc.h"
 #include "gtkselection.h"
 #include "gtksettings.h"
-#include "gtksizegroup.h"
+#include "gtksizegroup-private.h"
 #include "gtkwidget.h"
 #include "gtkwindow.h"
 #include "gtkbindings.h"
@@ -563,9 +563,10 @@ static void             gtk_widget_real_adjust_size_request     (GtkWidget
 static void             gtk_widget_real_adjust_size_allocation  (GtkWidget         *widget,
                                                                  GtkAllocation     *allocation);
 
-static void gtk_widget_set_usize_internal (GtkWidget *widget,
-                                          gint       width,
-                                          gint       height);
+static void gtk_widget_set_usize_internal (GtkWidget          *widget,
+                                          gint                width,
+                                          gint                height,
+                                          GtkQueueResizeFlags flags);
 
 static void gtk_widget_add_events_internal (GtkWidget *widget,
                                             GdkDevice *device,
@@ -3022,10 +3023,10 @@ gtk_widget_set_property (GObject         *object,
       gtk_container_add (GTK_CONTAINER (g_value_get_object (value)), widget);
       break;
     case PROP_WIDTH_REQUEST:
-      gtk_widget_set_usize_internal (widget, g_value_get_int (value), -2);
+      gtk_widget_set_usize_internal (widget, g_value_get_int (value), -2, 0);
       break;
     case PROP_HEIGHT_REQUEST:
-      gtk_widget_set_usize_internal (widget, -2, g_value_get_int (value));
+      gtk_widget_set_usize_internal (widget, -2, g_value_get_int (value), 0);
       break;
     case PROP_VISIBLE:
       gtk_widget_set_visible (widget, g_value_get_boolean (value));
@@ -4207,7 +4208,7 @@ gtk_widget_queue_resize (GtkWidget *widget)
   if (gtk_widget_get_realized (widget))
     gtk_widget_queue_shallow_draw (widget);
       
-  _gtk_size_group_queue_resize (widget);
+  _gtk_size_group_queue_resize (widget, 0);
 }
 
 /**
@@ -4224,7 +4225,7 @@ gtk_widget_queue_resize_no_redraw (GtkWidget *widget)
 {
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
-  _gtk_size_group_queue_resize (widget);
+  _gtk_size_group_queue_resize (widget, 0);
 }
 
 /**
@@ -8643,9 +8644,10 @@ gtk_widget_error_bell (GtkWidget *widget)
 }
 
 static void
-gtk_widget_set_usize_internal (GtkWidget *widget,
-                              gint       width,
-                              gint       height)
+gtk_widget_set_usize_internal (GtkWidget          *widget,
+                              gint                width,
+                              gint                height,
+                              GtkQueueResizeFlags flags)
 {
   GtkWidgetAuxInfo *aux_info;
   gboolean changed = FALSE;
@@ -8656,19 +8658,26 @@ gtk_widget_set_usize_internal (GtkWidget *widget,
   
   if (width > -2 && aux_info->width != width)
     {
-      g_object_notify (G_OBJECT (widget), "width-request");
+      if ((flags & GTK_QUEUE_RESIZE_INVALIDATE_ONLY) == 0)
+       g_object_notify (G_OBJECT (widget), "width-request");
       aux_info->width = width;
       changed = TRUE;
     }
   if (height > -2 && aux_info->height != height)
     {
-      g_object_notify (G_OBJECT (widget), "height-request");  
+      if ((flags & GTK_QUEUE_RESIZE_INVALIDATE_ONLY) == 0)
+       g_object_notify (G_OBJECT (widget), "height-request");
       aux_info->height = height;
       changed = TRUE;
     }
   
   if (gtk_widget_get_visible (widget) && changed)
-    gtk_widget_queue_resize (widget);
+    {
+      if ((flags & GTK_QUEUE_RESIZE_INVALIDATE_ONLY) == 0)
+       gtk_widget_queue_resize (widget);
+      else
+       _gtk_size_group_queue_resize (widget, GTK_QUEUE_RESIZE_INVALIDATE_ONLY);
+    }
 
   g_object_thaw_notify (G_OBJECT (widget));
 }
@@ -8728,7 +8737,7 @@ gtk_widget_set_size_request (GtkWidget *widget,
   if (height == 0)
     height = 1;
   
-  gtk_widget_set_usize_internal (widget, width, height);
+  gtk_widget_set_usize_internal (widget, width, height, 0);
 }
 
 
@@ -8764,6 +8773,52 @@ gtk_widget_get_size_request (GtkWidget *widget,
     *height = aux_info->height;
 }
 
+/**
+ * _gtk_widget_override_size_request:
+ * @widget: a #GtkWidget
+ * @width: new forced minimum width
+ * @height: new forced minimum height
+ * @old_width: location to store previous forced minimum width
+ * @old_width: location to store previous forced minumum height
+ *
+ * Temporarily establishes a forced minimum size for a widget; this
+ * is used by GtkWindow when calculating the size to add to the
+ * window's geometry widget. Cached sizes for the widget and its
+ * parents are invalidated, so that subsequent calls to the size
+ * negotiation machinery produce the overriden result, but the
+ * widget is not queued for relayout or redraw. The old size must
+ * be restored with _gtk_widget_restore_size_request() or things
+ * will go screwy.
+ */
+void
+_gtk_widget_override_size_request (GtkWidget *widget,
+                                  int        width,
+                                  int        height,
+                                  int       *old_width,
+                                  int       *old_height)
+{
+  gtk_widget_get_size_request (widget, old_width, old_height);
+  gtk_widget_set_usize_internal (widget, width, height,
+                                GTK_QUEUE_RESIZE_INVALIDATE_ONLY);
+}
+
+/**
+ * _gtk_widget_restore_size_request:
+ * @widget: a #GtkWidget
+ * @old_width: saved forced minimum size
+ * @old_height: saved forced minimum size
+ *
+ * Undoes the operation of_gtk_widget_override_size_request().
+ */
+void
+_gtk_widget_restore_size_request (GtkWidget *widget,
+                                 int        old_width,
+                                 int        old_height)
+{
+  gtk_widget_set_usize_internal (widget, old_width, old_height,
+                                GTK_QUEUE_RESIZE_INVALIDATE_ONLY);
+}
+
 /**
  * gtk_widget_set_events:
  * @widget: a #GtkWidget
index 4103ef67c85aa74eedca26f2ad86dafd5c762b01..571484eb9ea436186de82887732a2f0fa26465b5 100644 (file)
@@ -47,6 +47,7 @@
 #include "gtkicontheme.h"
 #include "gtkmarshalers.h"
 #include "gtkplug.h"
+#include "gtkprivate.h"
 #include "gtkbuildable.h"
 
 #ifdef GDK_WINDOWING_X11
@@ -7021,28 +7022,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 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 big, how much extra space
-       *    would be needed for the stuff around it.
+       *  +----------+
+       *  |AAAAAAAAA | At small sizes, the minimum sizes of widgets
+       *  |GGGGG    B| in the border can confuse things
+       *  |GGGGG    B|
+       *  |         B|
+       *  +----------+
        *
-       *  - If the geometry widget was infinitely small, how big would the
-       *    window still have to be.
-       *
-       * 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
@@ -7055,27 +7080,38 @@ 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.
+       */
       *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
     {
index 4fa4321218e2cf34786a789b9960da97dbac23d6..b607ad53ebee9022bd7d859d09fa1495cd64fe96 100644 (file)
@@ -47,6 +47,7 @@ noinst_PROGRAMS =  $(TEST_PROGS)      \
        testfilechooser                 \
        testfilechooserbutton           \
        testframe                       \
+       testgeometry                    \
        testgtk                         \
        testheightforwidth              \
        testiconview                    \
@@ -136,6 +137,7 @@ testerrors_DEPENDENCIES = $(TEST_DEPS)
 testfilechooser_DEPENDENCIES = $(TEST_DEPS)
 testfilechooserbutton_DEPENDENCIES = $(TEST_DEPS)
 testframe_DEPENDENCIES = $(TEST_DEPS)
+testgeometry_DEPENDENCIES = $(TEST_DEPS)
 testgtk_DEPENDENCIES = $(TEST_DEPS)
 testinput_DEPENDENCIES = $(TEST_DEPS)
 testimage_DEPENDENCIES = $(TEST_DEPS)
@@ -201,6 +203,7 @@ testerrors_LDADD = $(LDADDS)
 testfilechooser_LDADD = $(LDADDS)
 testfilechooserbutton_LDADD = $(LDADDS)
 testframe_LDADD = $(LDADDS)
+testgeometry_LDADD = $(LDADDS)
 testgtk_LDADD = $(LDADDS)
 testheightforwidth_LDADD = $(LDADDS)
 testicontheme_LDADD = $(LDADDS)
@@ -322,6 +325,9 @@ testbuttons_SOURCES =               \
 testframe_SOURCES =            \
        testframe.c
 
+testgeometry_SOURCES =                 \
+       testgeometry.c
+
 testiconview_SOURCES =                 \
        testiconview.c          \
        prop-editor.c
diff --git a/tests/testgeometry.c b/tests/testgeometry.c
new file mode 100644 (file)
index 0000000..9d3f714
--- /dev/null
@@ -0,0 +1,203 @@
+/* testgeometry.c
+ * Author: Owen Taylor <otaylor@redhat.com>
+ * Copyright © 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+#define GRID_SIZE 20
+#define BORDER 6
+
+static int window_count = 0;
+const char *geometry_string;
+
+static void
+on_window_destroy (GtkWidget *widget)
+{
+  window_count--;
+  if (window_count == 0)
+    gtk_main_quit();
+}
+
+static gboolean
+on_drawing_area_draw (GtkWidget *drawing_area,
+                     cairo_t   *cr,
+                     gpointer   data)
+{
+  int width = gtk_widget_get_allocated_width (drawing_area);
+  int height = gtk_widget_get_allocated_height (drawing_area);
+  int x, y;
+  int border = 0;
+  GdkWindowHints mask = GPOINTER_TO_UINT(data);
+
+  cairo_set_source_rgb (cr, 1, 1, 1);
+  cairo_paint (cr);
+
+  if ((mask & GDK_HINT_BASE_SIZE) != 0)
+    border = BORDER;
+
+  cairo_set_source_rgb (cr, 0, 0, 0);
+  for (y = 0; y < height - 2 * border; y += GRID_SIZE)
+    for (x = 0; x < width - 2 * border; x += GRID_SIZE)
+      if (((x + y) / GRID_SIZE) % 2 == 0)
+       {
+         cairo_rectangle (cr, border + x, border + y, GRID_SIZE, GRID_SIZE);
+         cairo_fill (cr);
+       }
+
+  if (border > 0)
+    {
+      cairo_set_source_rgb (cr, 0, 0, 1);
+      cairo_save (cr);
+      cairo_set_line_width (cr, border);
+      cairo_rectangle (cr,
+                      border / 2., border / 2., width - border, height - border);
+      cairo_stroke (cr);
+    }
+
+  return FALSE;
+}
+
+static void
+create_window (GdkWindowHints  mask)
+{
+  GtkWidget *window;
+  GtkWidget *drawing_area;
+  GtkWidget *table;
+  GtkWidget *label;
+  GdkGeometry geometry;
+  GString *label_text = g_string_new (NULL);
+  int border = 0;
+
+  if ((mask & GDK_HINT_RESIZE_INC) != 0)
+    g_string_append (label_text, "Gridded\n");
+  if ((mask & GDK_HINT_BASE_SIZE) != 0)
+    g_string_append (label_text, "Base\n");
+  if ((mask & GDK_HINT_MIN_SIZE) != 0)
+    {
+      g_string_append (label_text, "Minimum\n");
+      if ((mask & GDK_HINT_BASE_SIZE) == 0)
+       g_string_append (label_text, "(base=min)\n");
+    }
+  if ((mask & GDK_HINT_MAX_SIZE) != 0)
+    g_string_append (label_text, "Maximum\n");
+
+  if (label_text->len > 0)
+    g_string_erase (label_text, label_text->len - 1, 1);
+  else
+    g_string_append (label_text, "No Options");
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  g_signal_connect (window, "destroy",
+                   G_CALLBACK (on_window_destroy), NULL);
+
+  table = gtk_table_new (0, 0, FALSE);
+  gtk_container_set_border_width (GTK_CONTAINER (table), 10);
+
+  label = gtk_label_new (label_text->str);
+  gtk_table_attach (GTK_TABLE (table), label,
+                   0, 1,                  0, 1,
+                   GTK_EXPAND | GTK_FILL, GTK_FILL,
+                   0,                     0);
+
+  label = gtk_label_new ("A\nB\nC\nD\nE");
+  gtk_table_attach (GTK_TABLE (table), label,
+                   1, 2,              1, 2,
+                   GTK_FILL,          GTK_EXPAND | GTK_FILL,
+                   0,                 0);
+
+  drawing_area = gtk_drawing_area_new ();
+  g_signal_connect (drawing_area, "draw",
+                   G_CALLBACK (on_drawing_area_draw),
+                   GUINT_TO_POINTER (mask));
+  gtk_table_attach (GTK_TABLE (table), drawing_area,
+                   0, 1,                  1, 2,
+                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
+                   0,                     0);
+
+  gtk_container_add (GTK_CONTAINER (window), table);
+
+  if ((mask & GDK_HINT_BASE_SIZE) != 0)
+    {
+      border = BORDER;
+      geometry.base_width = border * 2;
+      geometry.base_height = border * 2;
+    }
+
+  if ((mask & GDK_HINT_RESIZE_INC) != 0)
+    {
+      geometry.width_inc = GRID_SIZE;
+      geometry.height_inc = GRID_SIZE;
+    }
+
+  if ((mask & GDK_HINT_MIN_SIZE) != 0)
+    {
+      geometry.min_width = 5 * GRID_SIZE + 2 * border;
+      geometry.min_height = 5 * GRID_SIZE + 2 * border;
+    }
+
+  if ((mask & GDK_HINT_MAX_SIZE) != 0)
+    {
+      geometry.max_width = 15 * GRID_SIZE + 2 * border;
+      geometry.max_height = 15 * GRID_SIZE + 2 * border;
+    }
+
+  /* Contents must be set up before gtk_window_parse_geometry() */
+  gtk_widget_show_all (table);
+
+  gtk_window_set_geometry_hints (GTK_WINDOW (window),
+                                drawing_area,
+                                &geometry,
+                                mask);
+
+  if ((mask & GDK_HINT_RESIZE_INC) != 0)
+    {
+      if (geometry_string)
+       gtk_window_parse_geometry (GTK_WINDOW (window), geometry_string);
+    }
+
+  gtk_widget_show (window);
+  window_count++;
+}
+
+int
+main(int argc, char **argv)
+{
+  GError *error;
+  GOptionEntry options[] = {
+    { "geometry", 'g', 0, G_OPTION_ARG_STRING, &geometry_string, "Window geometry (only for gridded windows)", "GEOMETRY" },
+    { NULL }
+  };
+
+  if (!gtk_init_with_args (&argc, &argv, "", options, NULL, &error))
+    {
+      g_print ("Failed to parse args: %s\n", error->message);
+      g_error_free (error);
+      return 1;
+    }
+
+  create_window (GDK_HINT_MIN_SIZE);
+  create_window (GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE);
+  create_window (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
+  create_window (GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE);
+  create_window (GDK_HINT_RESIZE_INC | GDK_HINT_MAX_SIZE);
+  create_window (GDK_HINT_RESIZE_INC | GDK_HINT_BASE_SIZE);
+  create_window (GDK_HINT_RESIZE_INC | GDK_HINT_BASE_SIZE | GDK_HINT_MIN_SIZE);
+
+  gtk_main ();
+}
index 89d648b6960f3d491e7096d3ae5855eb6cc74188..17136cfc57b160d24bd01dd2a0beb17833572daf 100644 (file)
@@ -1644,173 +1644,6 @@ create_statusbar (GtkWidget *widget)
     gtk_widget_destroy (window);
 }
 
-/*
- * Gridded geometry
- */
-#define GRID_SIZE 20
-#define DEFAULT_GEOMETRY "10x10"
-
-static gboolean
-gridded_geometry_draw (GtkWidget *widget,
-                       cairo_t   *cr)
-{
-  GtkStateType state;
-  GtkStyle *style;
-  int i, j, width, height;
-
-  style = gtk_widget_get_style (widget);
-  state = gtk_widget_get_state (widget);
-  width = gtk_widget_get_allocated_width (widget);
-  height = gtk_widget_get_allocated_height (widget);
-
-  gdk_cairo_set_source_color (cr, &style->base[state]);
-  cairo_paint (cr);
-
-  for (i = 0 ; i * GRID_SIZE < width; i++)
-    for (j = 0 ; j * GRID_SIZE < height; j++)
-      {
-       if ((i + j) % 2 == 0)
-         cairo_rectangle (cr, i * GRID_SIZE, j * GRID_SIZE, GRID_SIZE, GRID_SIZE);
-      }
-
-  gdk_cairo_set_source_color (cr, &style->text[state]);
-  cairo_fill (cr);
-
-  return FALSE;
-}
-
-static void
-gridded_geometry_subresponse (GtkDialog *dialog,
-                             gint       response_id,
-                             gchar     *geometry_string)
-{
-  if (response_id == GTK_RESPONSE_NONE)
-    {
-      gtk_widget_destroy (GTK_WIDGET (dialog));
-    }
-  else
-    {
-      if (!gtk_window_parse_geometry (GTK_WINDOW (dialog), geometry_string))
-       {
-         g_print ("Can't parse geometry string %s\n", geometry_string);
-         gtk_window_parse_geometry (GTK_WINDOW (dialog), DEFAULT_GEOMETRY);
-       }
-    }
-}
-
-static void
-gridded_geometry_response (GtkDialog *dialog,
-                          gint       response_id,
-                          GtkEntry  *entry)
-{
-  if (response_id == GTK_RESPONSE_NONE)
-    {
-      gtk_widget_destroy (GTK_WIDGET (dialog));
-    }
-  else
-    {
-      gchar *geometry_string = g_strdup (gtk_entry_get_text (entry));
-      gchar *title = g_strdup_printf ("Gridded window at: %s", geometry_string);
-      GtkWidget *content_area;
-      GtkWidget *window;
-      GtkWidget *drawing_area;
-      GtkWidget *box;
-      GdkGeometry geometry;
-      
-      window = gtk_dialog_new_with_buttons (title,
-                                            NULL, 0,
-                                            "Reset", 1,
-                                            GTK_STOCK_CLOSE, GTK_RESPONSE_NONE,
-                                            NULL);
-
-      gtk_window_set_screen (GTK_WINDOW (window), 
-                            gtk_widget_get_screen (GTK_WIDGET (dialog)));
-      g_free (title);
-      g_signal_connect (window, "response",
-                       G_CALLBACK (gridded_geometry_subresponse), geometry_string);
-
-      content_area = gtk_dialog_get_content_area (GTK_DIALOG (window));
-
-      box = gtk_vbox_new (FALSE, 0);
-      gtk_box_pack_start (GTK_BOX (content_area), box, TRUE, TRUE, 0);
-      
-      gtk_container_set_border_width (GTK_CONTAINER (box), 7);
-      
-      drawing_area = gtk_drawing_area_new ();
-      g_signal_connect (drawing_area, "draw",
-                       G_CALLBACK (gridded_geometry_draw), NULL);
-      gtk_box_pack_start (GTK_BOX (box), drawing_area, TRUE, TRUE, 0);
-
-      /* Gross hack to work around bug 68668... if we set the size request
-       * large enough, then  the current
-       *
-       *   request_of_window - request_of_geometry_widget
-       *
-       * method of getting the base size works more or less works.
-       */
-      gtk_widget_set_size_request (drawing_area, 2000, 2000);
-
-      geometry.base_width = 0;
-      geometry.base_height = 0;
-      geometry.min_width = 2 * GRID_SIZE;
-      geometry.min_height = 2 * GRID_SIZE;
-      geometry.width_inc = GRID_SIZE;
-      geometry.height_inc = GRID_SIZE;
-
-      gtk_window_set_geometry_hints (GTK_WINDOW (window), drawing_area,
-                                    &geometry,
-                                    GDK_HINT_BASE_SIZE | GDK_HINT_MIN_SIZE | GDK_HINT_RESIZE_INC);
-
-      if (!gtk_window_parse_geometry (GTK_WINDOW (window), geometry_string))
-       {
-         g_print ("Can't parse geometry string %s\n", geometry_string);
-         gtk_window_parse_geometry (GTK_WINDOW (window), DEFAULT_GEOMETRY);
-       }
-
-      gtk_widget_show_all (window);
-    }
-}
-
-static void 
-create_gridded_geometry (GtkWidget *widget)
-{
-  static GtkWidget *window = NULL;
-  gpointer window_ptr;
-  GtkWidget *content_area;
-  GtkWidget *entry;
-  GtkWidget *label;
-
-  if (!window)
-    {
-      window = gtk_dialog_new_with_buttons ("Gridded Geometry",
-                                            NULL, 0,
-                                           "Create", 1,
-                                            GTK_STOCK_CLOSE, GTK_RESPONSE_NONE,
-                                            NULL);
-      
-      gtk_window_set_screen (GTK_WINDOW (window),
-                            gtk_widget_get_screen (widget));
-
-      content_area = gtk_dialog_get_content_area (GTK_DIALOG (window));
-
-      label = gtk_label_new ("Geometry string:");
-      gtk_box_pack_start (GTK_BOX (content_area), label, FALSE, FALSE, 0);
-
-      entry = gtk_entry_new ();
-      gtk_entry_set_text (GTK_ENTRY (entry), DEFAULT_GEOMETRY);
-      gtk_box_pack_start (GTK_BOX (content_area), entry, FALSE, FALSE, 0);
-
-      g_signal_connect (window, "response",
-                       G_CALLBACK (gridded_geometry_response), entry);
-      window_ptr = &window;
-      g_object_add_weak_pointer (G_OBJECT (window), window_ptr);
-
-      gtk_widget_show_all (window);
-    }
-  else
-    gtk_widget_destroy (window);
-}
-
 /*
  * GtkHandleBox
  */
@@ -10152,7 +9985,6 @@ struct {
   { "flipping", create_flipping },
   { "focus", create_focus },
   { "font selection", create_font_selection },
-  { "gridded geometry", create_gridded_geometry },
   { "handle box", create_handle_box },
   { "image", create_image },
   { "key lookup", create_key_lookup },