From 585a1fae4f347d979c55f2848cd3afba7dc32c2e Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 23 Mar 2012 03:01:16 +0100 Subject: [PATCH] stylecontext: Really queue style changes Instead of instantly applying a new style, just mark the context as invalid. Only apply the new style at layout time. --- gtk/gtkcontainer.c | 17 ++++++++- gtk/gtkstylecontext.c | 71 ++++++++++++++++++++++++++++++++---- gtk/gtkstylecontextprivate.h | 2 + 3 files changed, 81 insertions(+), 9 deletions(-) diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index 275ee28c1f..6253ab79fd 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -46,6 +46,7 @@ #include "gtkwindow.h" #include "gtkassistant.h" #include "gtkintl.h" +#include "gtkstylecontextprivate.h" #include "gtkwidgetpath.h" #include "a11y/gtkcontaineraccessible.h" @@ -1641,15 +1642,28 @@ gtk_container_get_resize_container (GtkContainer *container) static gboolean gtk_container_idle_sizer (gpointer data) { + GSList *slist; + /* 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, * since it doesn't cause any actual harm. */ + + /* We validate the style contexts in a single loop before even trying + * to handle resizes instead of doing validations inline. + * This is mostly necessary for compatibility reasons with old code, + * because size_allocate functions often change styles and so could + * cause infinite loops in this function. + */ + for (slist = container_resize_queue; slist; slist = slist->next) + { + _gtk_style_context_validate (gtk_widget_get_style_context (slist->data), 0); + } + while (container_resize_queue) { - GSList *slist; GtkWidget *widget; slist = container_resize_queue; @@ -1714,6 +1728,7 @@ _gtk_container_queue_resize_internal (GtkContainer *container, break; case GTK_RESIZE_IMMEDIATE: + _gtk_style_context_validate (gtk_widget_get_style_context (GTK_WIDGET (resize_container)), 0); gtk_container_check_resize (resize_container); break; diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index 9828314edc..2d0c2da3b5 100644 --- a/gtk/gtkstylecontext.c +++ b/gtk/gtkstylecontext.c @@ -381,9 +381,11 @@ struct _GtkStyleContextPrivate GtkTextDirection direction; GtkCssChange relevant_changes; + GtkCssChange pending_changes; guint animations_invalidated : 1; guint invalidating_context : 1; + guint invalid : 1; }; enum { @@ -1022,6 +1024,28 @@ style_data_lookup (GtkStyleContext *context, return data; } +static void +gtk_style_context_set_invalid (GtkStyleContext *context, + gboolean invalid) +{ + GtkStyleContextPrivate *priv; + + priv = context->priv; + + if (priv->invalid == invalid) + return; + + priv->invalid = invalid; + + if (invalid) + { + if (priv->widget) + gtk_widget_queue_resize (priv->widget); + if (priv->parent) + gtk_style_context_set_invalid (priv->parent, TRUE); + } +} + /* returns TRUE if someone called gtk_style_context_save() but hasn't * called gtk_style_context_restore() yet. * In those situations we don't invalidate the context when somebody @@ -1624,6 +1648,8 @@ gtk_style_context_set_parent (GtkStyleContext *context, { parent->priv->children = g_slist_prepend (parent->priv->children, context); g_object_ref (parent); + if (priv->invalid) + gtk_style_context_set_invalid (parent, TRUE); } if (priv->parent) @@ -3243,19 +3269,24 @@ store_animation_region (GtkStyleContext *context, } void -_gtk_style_context_queue_invalidate (GtkStyleContext *context, - GtkCssChange change) +_gtk_style_context_validate (GtkStyleContext *context, + GtkCssChange change) { GtkStyleContextPrivate *priv; + GSList *list; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - g_return_if_fail (change != 0); priv = context->priv; - if (priv->widget == NULL && priv->widget_path == NULL) + change |= priv->pending_changes; + + if (!priv->invalid && change == 0) return; + priv->pending_changes = 0; + gtk_style_context_set_invalid (context, FALSE); + /* Try to avoid invalidating if we can */ if (change & GTK_STYLE_CONTEXT_RADICAL_CHANGE) { @@ -3277,12 +3308,36 @@ _gtk_style_context_queue_invalidate (GtkStyleContext *context, gtk_widget_path_unref (path); } - - if ((priv->relevant_changes & change) == 0) - return; } - gtk_style_context_invalidate (context); + if (priv->relevant_changes & change) + { + gtk_style_context_invalidate (context); + } + + change = _gtk_css_change_for_child (change); + for (list = priv->children; list; list = list->next) + { + _gtk_style_context_validate (list->data, change); + } +} + +void +_gtk_style_context_queue_invalidate (GtkStyleContext *context, + GtkCssChange change) +{ + GtkStyleContextPrivate *priv; + + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); + g_return_if_fail (change != 0); + + priv = context->priv; + + if (priv->widget == NULL && priv->widget_path == NULL) + return; + + priv->pending_changes |= change; + gtk_style_context_set_invalid (context, TRUE); } /** diff --git a/gtk/gtkstylecontextprivate.h b/gtk/gtkstylecontextprivate.h index 41789cdd0c..759929ec62 100644 --- a/gtk/gtkstylecontextprivate.h +++ b/gtk/gtkstylecontextprivate.h @@ -35,6 +35,8 @@ const GValue * _gtk_style_context_peek_style_property (GtkStyleContext *c GType widget_type, GtkStateFlags state, GParamSpec *pspec); +void _gtk_style_context_validate (GtkStyleContext *context, + GtkCssChange change); void _gtk_style_context_queue_invalidate (GtkStyleContext *context, GtkCssChange change); void _gtk_style_context_invalidate_animation_areas (GtkStyleContext *context);