[gtk+] Fix handling of the geometry widget
- From: Owen Taylor <otaylor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] Fix handling of the geometry widget
- Date: Mon, 11 Oct 2010 18:16:18 +0000 (UTC)
commit 88cf5470290cd03ada031641cb6ee1c90df75e7d
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Sat Oct 9 22:15:34 2010 -0400
Fix handling of the geometry widget
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
gtk/Makefile.am | 1 +
gtk/gtkcontainer.c | 37 ++++++++-
gtk/gtkcontainer.h | 1 +
gtk/gtkprivate.h | 9 ++
gtk/gtksizegroup-private.h | 49 +++++++++++
gtk/gtksizegroup.c | 50 +++++++-----
gtk/gtksizegroup.h | 9 --
gtk/gtksizerequest.c | 2 +-
gtk/gtkwidget.c | 85 +++++++++++++++---
gtk/gtkwindow.c | 82 +++++++++++++-----
tests/Makefile.am | 6 ++
tests/testgeometry.c | 203 ++++++++++++++++++++++++++++++++++++++++++++
tests/testgtk.c | 168 ------------------------------------
13 files changed, 463 insertions(+), 239 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index fb040fd..29df0c9 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -382,6 +382,7 @@ gtk_private_h_sources = \
gtkrecentchooserdefault.h \
gtkrecentchooserprivate.h \
gtkrecentchooserutils.h \
+ gtksizegroup-private.h \
gtksocketprivate.h \
gtktextbtree.h \
gtktextbufferserialize.h\
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index 17473e5..75ac3f7 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -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)
{
diff --git a/gtk/gtkcontainer.h b/gtk/gtkcontainer.h
index 607baf6..57a80ae 100644
--- a/gtk/gtkcontainer.h
+++ b/gtk/gtkcontainer.h
@@ -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);
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index c0f14b4..d8fd0c0 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -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
index 0000000..3f80d3f
--- /dev/null
+++ b/gtk/gtksizegroup-private.h
@@ -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__ */
diff --git a/gtk/gtksizegroup.c b/gtk/gtksizegroup.c
index 1663f97..62ce9ea 100644
--- a/gtk/gtksizegroup.c
+++ b/gtk/gtksizegroup.c
@@ -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 {
diff --git a/gtk/gtksizegroup.h b/gtk/gtksizegroup.h
index d778f08..ff1b0b1 100644
--- a/gtk/gtksizegroup.h
+++ b/gtk/gtksizegroup.h
@@ -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__ */
diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c
index a30b241..c3d0398 100644
--- a/gtk/gtksizerequest.c
+++ b/gtk/gtksizerequest.c
@@ -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"
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index e3acd78..779a003 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -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);
}
@@ -8765,6 +8774,52 @@ gtk_widget_get_size_request (GtkWidget *widget,
}
/**
+ * _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
* @events: event mask
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 4103ef6..571484e 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -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,
+ ¤t_width, ¤t_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
{
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4fa4321..b607ad5 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -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
index 0000000..9d3f714
--- /dev/null
+++ b/tests/testgeometry.c
@@ -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 ();
+}
diff --git a/tests/testgtk.c b/tests/testgtk.c
index 89d648b..17136cf 100644
--- a/tests/testgtk.c
+++ b/tests/testgtk.c
@@ -1645,173 +1645,6 @@ create_statusbar (GtkWidget *widget)
}
/*
- * 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 },
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]