[gtk+] Use GdkFrameClock for relayout



commit 7753883add412a4bbc6b49b9bc7ef037c5a34c36
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Tue Sep 18 09:00:57 2012 -0400

    Use GdkFrameClock for relayout
    
    Add a ::layout signal to GdkFrameClock and use it instead of an idle
    handler to drive the restyling and relayout of containers.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=685460

 gdk/gdkframeclock.c       |   21 +++++++++++
 gdk/gdkframeclock.h       |    1 +
 gtk/gtkcontainer.c        |   83 ++++++++++++++++++++++++--------------------
 gtk/gtkcontainerprivate.h |    1 +
 gtk/gtkwidget.c           |    3 ++
 5 files changed, 71 insertions(+), 38 deletions(-)
---
diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c
index 6b23ce6..ca54840 100644
--- a/gdk/gdkframeclock.c
+++ b/gdk/gdkframeclock.c
@@ -79,6 +79,7 @@ G_DEFINE_INTERFACE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
 enum {
   FRAME_REQUESTED,
   BEFORE_PAINT,
+  LAYOUT,
   PAINT,
   AFTER_PAINT,
   LAST_SIGNAL
@@ -123,6 +124,23 @@ gdk_frame_clock_default_init (GdkFrameClockInterface *iface)
                   G_TYPE_NONE, 0);
 
   /**
+   * GdkFrameClock::layout:
+   * @clock: the frame clock emitting the signal
+   *
+   * This signal is emitted immediately before the paint signal and
+   * indicates that the frame time has been updated, and signal
+   * handlers should perform any preparatory work before painting.
+   */
+  signals[LAYOUT] =
+    g_signal_new (g_intern_static_string ("layout"),
+                  GDK_TYPE_FRAME_CLOCK,
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  /**
    * GdkFrameClock::paint:
    * @clock: the frame clock emitting the signal
    *
@@ -280,6 +298,9 @@ gdk_frame_clock_paint (GdkFrameClock *clock)
                  signals[BEFORE_PAINT], 0);
 
   g_signal_emit (G_OBJECT (clock),
+                 signals[LAYOUT], 0);
+
+  g_signal_emit (G_OBJECT (clock),
                  signals[PAINT], 0);
 
   g_signal_emit (G_OBJECT (clock),
diff --git a/gdk/gdkframeclock.h b/gdk/gdkframeclock.h
index 62124e2..043a890 100644
--- a/gdk/gdkframeclock.h
+++ b/gdk/gdkframeclock.h
@@ -54,6 +54,7 @@ struct _GdkFrameClockInterface
   /* signals */
   /* void (* frame_requested)    (GdkFrameClock *clock); */
   /* void (* before_paint)       (GdkFrameClock *clock); */
+  /* void (* layout)             1(GdkFrameClock *clock); */
   /* void (* paint)              (GdkFrameClock *clock); */
   /* void (* after_paint)        (GdkFrameClock *clock); */
 };
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index 4377a5f..938887e 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -236,6 +236,9 @@ struct _GtkContainerPrivate
 {
   GtkWidget *focus_child;
 
+  guint resize_handler;
+  GdkFrameClock *resize_clock;
+
   guint border_width : 16;
 
   guint has_focus_chain    : 1;
@@ -344,8 +347,6 @@ 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;
-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;
@@ -1357,10 +1358,15 @@ gtk_container_destroy (GtkWidget *widget)
 
   if (priv->resize_pending)
     _gtk_container_dequeue_resize_handler (container);
+
   if (priv->restyle_pending)
+    priv->restyle_pending = FALSE;
+
+  if (priv->resize_handler)
     {
-      container_restyle_queue = g_slist_remove (container_restyle_queue, container);
-      priv->restyle_pending = FALSE;
+      g_signal_handler_disconnect (priv->resize_clock, priv->resize_handler);
+      priv->resize_handler = 0;
+      priv->resize_clock = NULL;
     }
 
   if (priv->focus_child)
@@ -1553,7 +1559,6 @@ _gtk_container_dequeue_resize_handler (GtkContainer *container)
   g_return_if_fail (GTK_IS_CONTAINER (container));
   g_return_if_fail (container->priv->resize_pending);
 
-  container_resize_queue = g_slist_remove (container_resize_queue, container);
   container->priv->resize_pending = FALSE;
 }
 
@@ -1630,12 +1635,10 @@ gtk_container_set_reallocate_redraws (GtkContainer *container,
   container->priv->reallocate_redraws = needs_redraws ? TRUE : FALSE;
 }
 
-static gboolean
-gtk_container_idle_sizer (gpointer data)
+static void
+gtk_container_idle_sizer (GdkFrameClock *clock,
+                         GtkContainer  *container)
 {
-  GSList *slist;
-  gint64 current_time;
-
   /* 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,
@@ -1646,16 +1649,13 @@ gtk_container_idle_sizer (gpointer data)
    * 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 ();
-  slist = container_restyle_queue;
-  container_restyle_queue = NULL;
-  while (slist)
+  if (container->priv->restyle_pending)
     {
-      GSList *next = slist->next;
-      GtkContainer *container = slist->data;
       GtkBitmask *empty;
+      gint64 current_time;
 
       empty = _gtk_bitmask_new ();
+      current_time = g_get_monotonic_time ();
 
       container->priv->restyle_pending = FALSE;
       _gtk_style_context_validate (gtk_widget_get_style_context (GTK_WIDGET (container)),
@@ -1663,8 +1663,6 @@ gtk_container_idle_sizer (gpointer data)
                                    0,
                                    empty);
 
-      g_slist_free_1 (slist);
-      slist = next;
       _gtk_bitmask_free (empty);
     }
 
@@ -1674,35 +1672,40 @@ gtk_container_idle_sizer (gpointer data)
    * than trying to explicitely work around them with some extra flags,
    * since it doesn't cause any actual harm.
    */
-  while (container_resize_queue)
+  if (container->priv->resize_pending)
     {
-      GtkContainer *container;
-
-      slist = container_resize_queue;
-      container_resize_queue = slist->next;
-      container = slist->data;
-      g_slist_free_1 (slist);
-
       container->priv->resize_pending = FALSE;
       gtk_container_check_resize (container);
     }
 
-  gdk_window_process_all_updates ();
-
-  return container_resize_queue != NULL || container_restyle_queue != NULL;
+  if (!container->priv->restyle_pending && !container->priv->resize_pending)
+    {
+      g_signal_handler_disconnect (clock, container->priv->resize_handler);
+      container->priv->resize_handler = 0;
+      container->priv->resize_clock = NULL;
+    }
+  else
+    {
+      gdk_frame_clock_request_frame (clock);
+    }
 }
 
 static void
 gtk_container_start_idle_sizer (GtkContainer *container)
 {
-  /* already started */
-  if (container_resize_queue != NULL ||
-      container_restyle_queue != NULL)
+  GdkFrameClock *clock;
+
+  if (container->priv->resize_handler != 0)
+    return;
+
+  clock = gtk_widget_get_frame_clock (GTK_WIDGET (container));
+  if (clock == NULL)
     return;
 
-  gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE,
-                             gtk_container_idle_sizer,
-                             NULL, NULL);
+  container->priv->resize_clock = clock;
+  container->priv->resize_handler = g_signal_connect (clock, "layout",
+                                                     G_CALLBACK (gtk_container_idle_sizer), container);
+  gdk_frame_clock_request_frame (clock);
 }
 
 static void
@@ -1725,7 +1728,6 @@ gtk_container_queue_resize_handler (GtkContainer *container)
             {
               container->priv->resize_pending = TRUE;
               gtk_container_start_idle_sizer (container);
-              container_resize_queue = g_slist_prepend (container_resize_queue, container);
             }
           break;
 
@@ -1780,8 +1782,6 @@ _gtk_container_queue_restyle (GtkContainer *container)
     return;
 
   gtk_container_start_idle_sizer (container);
-
-  container_restyle_queue = g_slist_prepend (container_restyle_queue, container);
   priv->restyle_pending = TRUE;
 }
 
@@ -1816,6 +1816,13 @@ _gtk_container_resize_invalidate (GtkContainer *container)
 }
 
 void
+_gtk_container_maybe_start_idle_sizer (GtkContainer *container)
+{
+  if (container->priv->restyle_pending || container->priv->resize_pending)
+    gtk_container_start_idle_sizer (container);
+}
+
+void
 gtk_container_check_resize (GtkContainer *container)
 {
   g_return_if_fail (GTK_IS_CONTAINER (container));
diff --git a/gtk/gtkcontainerprivate.h b/gtk/gtkcontainerprivate.h
index f12148b..cd4bc5b 100644
--- a/gtk/gtkcontainerprivate.h
+++ b/gtk/gtkcontainerprivate.h
@@ -39,6 +39,7 @@ GList *  _gtk_container_focus_sort             (GtkContainer     *container,
                                                 GtkWidget        *old_focus);
 gboolean _gtk_container_get_reallocate_redraws (GtkContainer *container);
 
+void      _gtk_container_maybe_start_idle_sizer (GtkContainer *container);
 
 G_END_DECLS
 
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index a3509c4..e1cf124 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -4585,6 +4585,9 @@ gtk_widget_realize (GtkWidget *widget)
       _gtk_widget_enable_device_events (widget);
       gtk_widget_update_devices_mask (widget, TRUE);
 
+      if (GTK_IS_CONTAINER (widget))
+        _gtk_container_maybe_start_idle_sizer (GTK_CONTAINER (widget));
+
       gtk_widget_pop_verify_invariants (widget);
     }
 }


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