[gtk+] container: Redo style validation handling



commit 04c85a5b3bfe5ed276eb0530ce7bddd55dc7c204
Author: Benjamin Otte <otte redhat com>
Date:   Fri Apr 13 17:27:47 2012 +0200

    container: Redo style validation handling
    
    Instead of using 1 global queue for both resizes and style validation,
    use 2 queues. This makes the code a lot simpler and fixes a bug where we
    could accidentally stop restylying for very delayed restyles.

 gtk/gtkcontainer.c        |   84 +++++++++++++++++++++++++++++++++------------
 gtk/gtkcontainerprivate.h |    2 +-
 gtk/gtkstylecontext.c     |    2 +-
 3 files changed, 64 insertions(+), 24 deletions(-)
---
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index ad76313..856df7d 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -240,6 +240,7 @@ struct _GtkContainerPrivate
   guint has_focus_chain    : 1;
   guint reallocate_redraws : 1;
   guint resize_pending     : 1;
+  guint restyle_pending    : 1;
   guint resize_mode        : 2;
   guint request_mode       : 2;
 };
@@ -343,6 +344,7 @@ 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;
+static GSList               *container_restyle_queue = NULL;
 static guint                 container_signals[LAST_SIGNAL] = { 0 };
 static GtkWidgetClass       *parent_class = NULL;
 extern GParamSpecPool       *_gtk_widget_child_property_pool;
@@ -1354,6 +1356,11 @@ gtk_container_destroy (GtkWidget *widget)
 
   if (priv->resize_pending)
     _gtk_container_dequeue_resize_handler (container);
+  if (priv->restyle_pending)
+    {
+      container_restyle_queue = g_slist_remove (container_restyle_queue, container);
+      priv->restyle_pending = FALSE;
+    }
 
   if (priv->focus_child)
     {
@@ -1628,27 +1635,35 @@ gtk_container_idle_sizer (gpointer data)
   GSList *slist;
   gint64 current_time;
 
-  /* 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.
+   * because both style_updated and size_allocate functions often change
+   * styles and so could cause infinite loops in this function.
+   *
+   * It's important to note that even an invalid style context returns
+   * sane values. So the result of an invalid style context will never be
+   * a program crash, but only a wrong layout or rendering.
    */
   current_time = g_get_monotonic_time ();
-  for (slist = container_resize_queue; slist; slist = slist->next)
+  slist = container_restyle_queue;
+  container_restyle_queue = NULL;
+  for (; slist; slist = slist->next)
     {
-      _gtk_style_context_validate (gtk_widget_get_style_context (slist->data),
+      GtkContainer *container = slist->data;
+
+      container->priv->restyle_pending = FALSE;
+      _gtk_style_context_validate (gtk_widget_get_style_context (GTK_WIDGET (container)),
                                    current_time,
                                    0);
     }
 
+  /* 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.
+   */
   while (container_resize_queue)
     {
       GtkContainer *container;
@@ -1664,11 +1679,24 @@ gtk_container_idle_sizer (gpointer data)
 
   gdk_window_process_all_updates ();
 
-  return FALSE;
+  return container_resize_queue != NULL || container_restyle_queue != NULL;
 }
 
-void
-_gtk_container_queue_resize_handler (GtkContainer *container)
+static void
+gtk_container_start_idle_sizer (GtkContainer *container)
+{
+  /* already started */
+  if (container_resize_queue != NULL ||
+      container_restyle_queue != NULL)
+    return;
+
+  gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE,
+                             gtk_container_idle_sizer,
+                             NULL, NULL);
+}
+
+static void
+gtk_container_queue_resize_handler (GtkContainer *container)
 {
   GtkWidget *widget;
 
@@ -1686,18 +1714,12 @@ _gtk_container_queue_resize_handler (GtkContainer *container)
           if (!container->priv->resize_pending)
             {
               container->priv->resize_pending = TRUE;
-              if (container_resize_queue == NULL)
-                gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE,
-                                           gtk_container_idle_sizer,
-                                           NULL, NULL);
+              gtk_container_start_idle_sizer (container);
               container_resize_queue = g_slist_prepend (container_resize_queue, container);
             }
           break;
 
         case GTK_RESIZE_IMMEDIATE:
-          _gtk_style_context_validate (gtk_widget_get_style_context (widget),
-                                       g_get_monotonic_time (),
-                                       0);
           gtk_container_check_resize (container);
 
         case GTK_RESIZE_PARENT:
@@ -1732,7 +1754,25 @@ _gtk_container_queue_resize_internal (GtkContainer *container,
   while (widget);
 
   if (widget && !invalidate_only)
-    _gtk_container_queue_resize_handler (GTK_CONTAINER (widget));
+    gtk_container_queue_resize_handler (GTK_CONTAINER (widget));
+}
+
+void
+_gtk_container_queue_restyle (GtkContainer *container)
+{
+  GtkContainerPrivate *priv;
+
+  g_return_if_fail (GTK_CONTAINER (container));
+
+  priv = container->priv;
+
+  if (priv->restyle_pending)
+    return;
+
+  gtk_container_start_idle_sizer (container);
+
+  container_restyle_queue = g_slist_prepend (container_restyle_queue, container);
+  priv->restyle_pending = TRUE;
 }
 
 /**
diff --git a/gtk/gtkcontainerprivate.h b/gtk/gtkcontainerprivate.h
index 81b485d..f12148b 100644
--- a/gtk/gtkcontainerprivate.h
+++ b/gtk/gtkcontainerprivate.h
@@ -27,11 +27,11 @@ G_BEGIN_DECLS
 
 GList *  _gtk_container_get_all_children       (GtkContainer *container);
 void     _gtk_container_queue_resize           (GtkContainer *container);
+void     _gtk_container_queue_restyle          (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);
-void     _gtk_container_queue_resize_handler   (GtkContainer *container);
 void     _gtk_container_dequeue_resize_handler (GtkContainer *container);
 GList *  _gtk_container_focus_sort             (GtkContainer     *container,
                                                 GList            *children,
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index cf79e11..f18c8ab 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -1029,7 +1029,7 @@ gtk_style_context_set_invalid (GtkStyleContext *context,
       if (priv->parent)
         gtk_style_context_set_invalid (priv->parent, TRUE);
       else if (GTK_IS_RESIZE_CONTAINER (priv->widget))
-        _gtk_container_queue_resize_handler (GTK_CONTAINER (priv->widget));
+        _gtk_container_queue_restyle (GTK_CONTAINER (priv->widget));
     }
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]