summaryrefslogtreecommitdiff
path: root/gtk/gtkcontainer.c
diff options
context:
space:
mode:
authorTim Janik <timj@gtk.org>1998-06-24 06:25:14 +0000
committerTim Janik <timj@src.gnome.org>1998-06-24 06:25:14 +0000
commitdbce6083ef090a3971be3397f899d770b368c5e2 (patch)
tree1e2999ef5f7257a49d6df0acbe4e8dd06c7d3a5a /gtk/gtkcontainer.c
parent00362c03f732591722343789fb22d9f6e371eafb (diff)
downloadgtk+-dbce6083ef090a3971be3397f899d770b368c5e2.tar.gz
added a frame with radio buttons to select the resize_mode for the
Wed Jun 24 07:47:29 1998 Tim Janik <timj@gtk.org> * gtk/testgtk.c (create_idle_test): added a frame with radio buttons to select the resize_mode for the idle-labels container. * gtk/gtkframe.h: * gtk/gtkframe.c: GtkType and macro corrections. * gtk/gtkradiobutton.c (gtk_radio_button_set_arg): new function to support radio grouping. Tue Jun 23 08:01:09 1998 Tim Janik <timj@gtk.org> * gtk/gtkcontainer.c (gtk_container_set_resize_mode): queue a resize unconditionally if resize_mode has changed. * gtk/gtkscrolledwindow.c (gtk_scrolled_window_init): set GTK_RESIZE_QUEUE on the scrolled window. (gtk_scrolled_window_construct): set GTK_RESIZE_PARENT for the vieport. Tue Jun 23 04:20:30 1998 Tim Janik <timj@gtk.org> * gtk/gtkcontainer.h: * gtk/gtkcontainer.c: (GTK_IS_RESIZE_CONTAINER): new macro to find out if a given gtkobject is a container with resize_mode==GTK_RESIZE_PARENT. (gtk_container_queue_resize): new function to queue a container for a *size* reallocation (doesn't affect its position, and thus its parent is left untouched usually). (gtk_container_get_resize_container): new function to retrive the next most resize container which is not itself queued for a resize. (gtk_container_idle_sizer): new function to carefully process the container_resize_queue since it can change during invokation of gtk_container_check_resize(). (gtk_container_resize_children): total rework of this function to properly handle resize containers. makes a lot of assumptions whitch are stated in the comments. * gtk/gtkcontainer.c: (gtk_container_real_check_resize): only requeue ourselves if we are not a resize container. (gtk_container_clear_resize_widgets): care for automatic deletion of our resize_widgets list on size_allocate through a handler connection. * gtk/gtkwindow.c (gtk_window_shutdown): new functionm to reset the focus and default widget of a window, so to take the burden from gtk_widget_unparent. * gtk/gtkviewport.c: removed gtk_viewport_check_resize, which tried to be clever, but actually messed up the resize_children logic and caused unneccessary allocations on its whole branch. besides this, it messed up the display by not invoking a redraw after the allocation. * gtk/gtktable.c (gtk_table_set_child_arg): reverted recent change, so that it is the child again that is queued for a resize. (gtk_table_attach): likewise. (gtk_table_remove): likewise.
Diffstat (limited to 'gtk/gtkcontainer.c')
-rw-r--r--gtk/gtkcontainer.c274
1 files changed, 229 insertions, 45 deletions
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index a92a259190..ac4a713478 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -20,6 +20,7 @@
#include "gtkcontainer.h"
#include "gtkprivate.h"
#include "gtksignal.h"
+#include "gtkmain.h"
#include <stdarg.h>
@@ -129,6 +130,7 @@ static const gchar *vadjustment_key = "gtk-vadjustment";
static guint vadjustment_key_id = 0;
static const gchar *hadjustment_key = "gtk-hadjustment";
static guint hadjustment_key_id = 0;
+static GSList *container_resize_queue = NULL;
GtkType
gtk_container_get_type (void)
@@ -680,6 +682,11 @@ gtk_container_destroy (GtkObject *object)
container = GTK_CONTAINER (object);
+ if (GTK_CONTAINER_RESIZE_PENDING (container))
+ {
+ container_resize_queue = g_slist_remove (container_resize_queue, container);
+ GTK_PRIVATE_UNSET_FLAG (container, GTK_RESIZE_PENDING);
+ }
gtk_container_clear_resize_widgets (container);
gtk_container_foreach (container,
@@ -809,6 +816,11 @@ gtk_container_clear_resize_widgets (GtkContainer *container)
node = container->resize_widgets;
+ if (node)
+ gtk_signal_disconnect_by_func (GTK_OBJECT (container),
+ GTK_SIGNAL_FUNC (gtk_container_clear_resize_widgets),
+ NULL);
+
while (node)
{
GtkWidget *widget = node->data;
@@ -837,16 +849,136 @@ gtk_container_set_resize_mode (GtkContainer *container,
{
container->resize_mode = resize_mode;
- if (container->resize_widgets != NULL)
+ if (resize_mode == GTK_RESIZE_IMMEDIATE)
+ gtk_container_check_resize (container);
+ else
{
- if (resize_mode == GTK_RESIZE_IMMEDIATE)
- gtk_container_check_resize (container);
- else if (resize_mode == GTK_RESIZE_PARENT)
+ gtk_container_clear_resize_widgets (container);
+ gtk_widget_queue_resize (GTK_WIDGET (container));
+ }
+ }
+}
+
+gint
+gtk_container_need_resize (GtkContainer *container)
+{
+ gtk_container_check_resize (container);
+ return FALSE;
+}
+
+static GtkContainer*
+gtk_container_get_resize_container (GtkContainer *container)
+{
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET (container);
+
+ while (widget->parent)
+ {
+ widget = widget->parent;
+ if (GTK_IS_RESIZE_CONTAINER (widget) && !GTK_WIDGET_RESIZE_NEEDED (widget))
+ break;
+ }
+
+ return GTK_IS_RESIZE_CONTAINER (widget) ? (GtkContainer*) widget : NULL;
+}
+
+static gboolean
+gtk_container_idle_sizer (gpointer data)
+{
+ /* we may be invoked with a container_resize_queue of NULL, because
+ * queue_resize could have been adding an extra idle function while
+ * the queue still got processed. we better just ignore such case
+ * than trying to explicitely work around them with some extra flags,
+ * sine it doesn't cause any actual harm.
+ */
+ while (container_resize_queue)
+ {
+ GSList *slist;
+ GtkWidget *widget;
+
+ slist = container_resize_queue;
+ container_resize_queue = slist->next;
+ widget = slist->data;
+ g_slist_free_1 (slist);
+
+ GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING);
+ gtk_container_check_resize (GTK_CONTAINER (widget));
+ }
+
+ return FALSE;
+}
+
+void
+gtk_container_queue_resize (GtkContainer *container)
+{
+ GtkContainer *resize_container;
+
+ g_return_if_fail (container != NULL);
+ g_return_if_fail (GTK_IS_CONTAINER (container));
+
+ if (GTK_OBJECT_DESTROYED (container) ||
+ GTK_WIDGET_RESIZE_NEEDED (container))
+ return;
+
+ if (GTK_IS_RESIZE_CONTAINER (container))
+ gtk_container_clear_resize_widgets (container);
+
+ resize_container = gtk_container_get_resize_container (container);
+
+ if (resize_container)
+ {
+ if (GTK_WIDGET_VISIBLE (resize_container))
+ {
+ switch (resize_container->resize_mode)
{
- gtk_container_clear_resize_widgets (container);
- gtk_widget_queue_resize (GTK_WIDGET (container));
+ case GTK_RESIZE_QUEUE:
+ if (!GTK_CONTAINER_RESIZE_PENDING (resize_container))
+ {
+ GTK_PRIVATE_SET_FLAG (resize_container, GTK_RESIZE_PENDING);
+ if (container_resize_queue == NULL)
+ gtk_idle_add_priority (GTK_PRIORITY_INTERNAL - 1,
+ gtk_container_idle_sizer,
+ NULL);
+ container_resize_queue = g_slist_prepend (container_resize_queue, resize_container);
+ }
+
+ GTK_PRIVATE_SET_FLAG (container, GTK_RESIZE_NEEDED);
+ if (!resize_container->resize_widgets)
+ gtk_signal_connect (GTK_OBJECT (resize_container),
+ "size_allocate",
+ GTK_SIGNAL_FUNC (gtk_container_clear_resize_widgets),
+ NULL);
+ resize_container->resize_widgets =
+ g_slist_prepend (resize_container->resize_widgets, container);
+ break;
+
+ case GTK_RESIZE_IMMEDIATE:
+ GTK_PRIVATE_SET_FLAG (container, GTK_RESIZE_NEEDED);
+ if (!resize_container->resize_widgets)
+ gtk_signal_connect (GTK_OBJECT (resize_container),
+ "size_allocate",
+ GTK_SIGNAL_FUNC (gtk_container_clear_resize_widgets),
+ NULL);
+ resize_container->resize_widgets =
+ g_slist_prepend (resize_container->resize_widgets, container);
+ gtk_container_check_resize (resize_container);
+ break;
+
+ case GTK_RESIZE_PARENT:
+ /* Ignore */
+ break;
}
}
+ else
+ {
+ /* We need to let hidden toplevels know that something
+ * changed while they where hidden. For other resize containers,
+ * they will get resized when they are shown.
+ */
+ if (GTK_WIDGET_TOPLEVEL (resize_container))
+ gtk_container_check_resize (resize_container);
+ }
}
}
@@ -859,30 +991,29 @@ gtk_container_check_resize (GtkContainer *container)
gtk_signal_emit (GTK_OBJECT (container), container_signals[CHECK_RESIZE]);
}
-gint
-gtk_container_need_resize (GtkContainer *container)
-{
- gtk_container_check_resize (container);
- return FALSE;
-}
-
static void
gtk_container_real_check_resize (GtkContainer *container)
{
GtkWidget *widget;
-
+
g_return_if_fail (container != NULL);
g_return_if_fail (GTK_IS_CONTAINER (container));
-
+
widget = GTK_WIDGET (container);
-
+
gtk_widget_size_request (widget, &widget->requisition);
- if ((widget->requisition.width > widget->allocation.width) ||
- (widget->requisition.height > widget->allocation.height))
+ if (widget->requisition.width > widget->allocation.width ||
+ widget->requisition.height > widget->allocation.height)
{
- gtk_container_clear_resize_widgets (container);
- gtk_widget_queue_resize (widget);
+ if (GTK_IS_RESIZE_CONTAINER (container))
+ {
+ gtk_widget_size_allocate (GTK_WIDGET (container),
+ &GTK_WIDGET (container)->allocation);
+ gtk_widget_queue_draw (GTK_WIDGET (container));
+ }
+ else
+ gtk_widget_queue_resize (widget);
}
else
{
@@ -905,23 +1036,77 @@ void
gtk_container_resize_children (GtkContainer *container)
{
GtkWidget *widget;
+ GtkWidget *resize_container;
GSList *resize_widgets;
GSList *resize_containers;
GSList *node;
+ /* resizing invariants:
+ * toplevels have *always* resize_mode != GTK_RESIZE_PARENT set.
+ * containers with resize_mode==GTK_RESIZE_PARENT have to have resize_widgets
+ * set to NULL.
+ * containers that are flagged RESIZE_NEEDED must have resize_widgets set to
+ * NULL, or are toplevels (thus have ->parent set to NULL).
+ * widgets that are in some container->resize_widgets list must be flagged with
+ * RESIZE_NEEDED.
+ * widgets that have RESIZE_NEEDED set must be referenced in some
+ * GTK_IS_RESIZE_CONTAINER (container)->resize_widgets list.
+ * containers that have an idle sizer pending must be flagged with
+ * RESIZE_PENDING.
+ */
+
g_return_if_fail (container != NULL);
g_return_if_fail (GTK_IS_CONTAINER (container));
+ /* we first check out if we actually need to perform a resize,
+ * which is not the case if we got another container queued for
+ * a resize in our anchestry. also we can skip the whole
+ * resize_widgets checks if we are a toplevel and NEED_RESIZE.
+ * this code implies that our allocation is sufficient for our
+ * requisition, since otherwise we would NEED_RESIZE.
+ */
+ resize_container = GTK_WIDGET (container);
+ while (resize_container)
+ {
+ if (GTK_WIDGET_RESIZE_NEEDED (resize_container))
+ break;
+ resize_container = resize_container->parent;
+ }
+ if (resize_container)
+ {
+ /* queue_resize and size_allocate both clear our
+ * resize_widgets list.
+ */
+ if (resize_container->parent)
+ gtk_container_queue_resize (container);
+ else
+ {
+ gtk_widget_size_allocate (GTK_WIDGET (container),
+ &GTK_WIDGET (container)->allocation);
+ gtk_widget_queue_draw (GTK_WIDGET (container));
+ }
+ return;
+ }
+
+ resize_container = GTK_WIDGET (container);
+
+ /* we now walk the anchestry for all resize widgets as long
+ * as they are our children and as long as their allocation
+ * is insufficient, since we don't need to reallocate below that.
+ */
resize_widgets = container->resize_widgets;
+ if (resize_widgets)
+ gtk_signal_disconnect_by_func (GTK_OBJECT (container),
+ GTK_SIGNAL_FUNC (gtk_container_clear_resize_widgets),
+ NULL);
container->resize_widgets = NULL;
-
for (node = resize_widgets; node; node = node->next)
{
widget = node->data;
-
+
GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
-
- while (widget && widget->parent &&
+
+ while (widget->parent != resize_container &&
((widget->allocation.width < widget->requisition.width) ||
(widget->allocation.height < widget->requisition.height)))
widget = widget->parent;
@@ -929,41 +1114,39 @@ gtk_container_resize_children (GtkContainer *container)
GTK_PRIVATE_SET_FLAG (widget, GTK_RESIZE_NEEDED);
node->data = widget;
}
-
+
+ /* for the newly setup resize_widgets list, we now walk each widget's
+ * anchestry to sort those widgets out that have RESIZE_NEEDED parents.
+ * we can safely stop the walk if we are the parent, since we checked
+ * our own anchestry already.
+ */
resize_containers = NULL;
-
for (node = resize_widgets; node; node = node->next)
{
- GtkWidget *resize_container;
-
+ GtkWidget *parent;
+
widget = node->data;
if (!GTK_WIDGET_RESIZE_NEEDED (widget))
continue;
- resize_container = widget->parent;
+ parent = widget->parent;
- if (resize_container)
+ while (parent != resize_container)
{
- GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
- widget = resize_container->parent;
-
- while (widget)
+ if (GTK_WIDGET_RESIZE_NEEDED (parent))
{
- if (GTK_WIDGET_RESIZE_NEEDED (widget))
- {
- GTK_PRIVATE_UNSET_FLAG (resize_container, GTK_RESIZE_NEEDED);
- resize_container = widget;
- }
- widget = widget->parent;
+ GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
+ widget = parent;
}
+ parent = parent->parent;
}
- else
- resize_container = widget;
- if (!g_slist_find (resize_containers, resize_container))
- resize_containers = g_slist_prepend (resize_containers,
- resize_container);
+ if (!g_slist_find (resize_containers, widget))
+ {
+ resize_containers = g_slist_prepend (resize_containers, widget);
+ gtk_widget_ref (widget);
+ }
}
g_slist_free (resize_widgets);
@@ -974,6 +1157,7 @@ gtk_container_resize_children (GtkContainer *container)
GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
gtk_widget_size_allocate (widget, &widget->allocation);
gtk_widget_queue_draw (widget);
+ gtk_widget_unref (widget);
}
g_slist_free (resize_containers);
}