[gtk+/wip/frame-synchronization: 823/857] Add an UPDATE phase and GdkFrameClockTarget, use for GtkStyleContext



commit 59bb3d3a8c33637b0de49c8ea6af3b6c84cc6d3f
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Wed Sep 26 15:44:30 2012 -0400

    Add an UPDATE phase and GdkFrameClockTarget, use for GtkStyleContext
    
    Switch GtkStyleContext to using GdkFrameClock. To do this, add a new
    UPDATE phase to GdkFrameClock.
    
    Add a GdkFrameClockTarget interface with a single set_clock() method,
    and use this to deal with the fact that GtkWidget only has a frame
    clock when realized.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=685460

 gdk/gdkframeclock.c     |   29 +++++++++++
 gdk/gdkframeclock.h     |   34 +++++++++++--
 gdk/gdkframeclockidle.c |   11 ++++-
 gtk/gtkstylecontext.c   |  124 +++++++++++++++++++++++++++++------------------
 gtk/gtkwidget.c         |   76 +++++++++++++++++++++++++++++
 gtk/gtkwidget.h         |    7 +++
 6 files changed, 227 insertions(+), 54 deletions(-)
---
diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c
index d385123..569ab6b 100644
--- a/gdk/gdkframeclock.c
+++ b/gdk/gdkframeclock.c
@@ -28,6 +28,19 @@
 
 #include "gdkframeclock.h"
 
+G_DEFINE_INTERFACE (GdkFrameClockTarget, gdk_frame_clock_target, G_TYPE_OBJECT)
+
+static void
+gdk_frame_clock_target_default_init (GdkFrameClockTargetInterface *iface)
+{
+}
+
+void gdk_frame_clock_target_set_clock (GdkFrameClockTarget *target,
+                                       GdkFrameClock       *clock)
+{
+  GDK_FRAME_CLOCK_TARGET_GET_IFACE (target)->set_clock (target, clock);
+}
+
 /**
  * SECTION:frameclock
  * @Short_description: Frame clock syncs painting to a window or display
@@ -79,6 +92,7 @@ G_DEFINE_INTERFACE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
 enum {
   FRAME_REQUESTED,
   BEFORE_PAINT,
+  UPDATE,
   LAYOUT,
   PAINT,
   AFTER_PAINT,
@@ -124,6 +138,21 @@ gdk_frame_clock_default_init (GdkFrameClockInterface *iface)
                   G_TYPE_NONE, 0);
 
   /**
+   * GdkFrameClock::update:
+   * @clock: the frame clock emitting the signal
+   *
+   * FIXME.
+   */
+  signals[UPDATE] =
+    g_signal_new (g_intern_static_string ("update"),
+                  GDK_TYPE_FRAME_CLOCK,
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  /**
    * GdkFrameClock::layout:
    * @clock: the frame clock emitting the signal
    *
diff --git a/gdk/gdkframeclock.h b/gdk/gdkframeclock.h
index a733b55..ae44573 100644
--- a/gdk/gdkframeclock.h
+++ b/gdk/gdkframeclock.h
@@ -35,20 +35,41 @@
 
 G_BEGIN_DECLS
 
+typedef struct _GdkFrameClock                GdkFrameClock;
+typedef struct _GdkFrameClockInterface       GdkFrameClockInterface;
+typedef struct _GdkFrameClockTarget          GdkFrameClockTarget;
+typedef struct _GdkFrameClockTargetInterface GdkFrameClockTargetInterface;
+
+#define GDK_TYPE_FRAME_CLOCK_TARGET             (gdk_frame_clock_target_get_type ())
+#define GDK_FRAME_CLOCK_TARGET(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_FRAME_CLOCK_TARGET, GdkFrameClockTarget))
+#define GDK_IS_FRAME_CLOCK_TARGET(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_FRAME_CLOCK_TARGET))
+#define GDK_FRAME_CLOCK_TARGET_GET_IFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GDK_TYPE_FRAME_CLOCK_TARGET, GdkFrameClockTargetInterface))
+
+struct _GdkFrameClockTargetInterface
+{
+  GTypeInterface base_iface;
+
+  void (*set_clock) (GdkFrameClockTarget *target,
+                     GdkFrameClock       *clock);
+};
+
+GType gdk_frame_clock_target_get_type (void) G_GNUC_CONST;
+
+void gdk_frame_clock_target_set_clock (GdkFrameClockTarget *target,
+                                       GdkFrameClock       *clock);
+
 #define GDK_TYPE_FRAME_CLOCK             (gdk_frame_clock_get_type ())
 #define GDK_FRAME_CLOCK(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_FRAME_CLOCK, GdkFrameClock))
 #define GDK_IS_FRAME_CLOCK(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_FRAME_CLOCK))
 #define GDK_FRAME_CLOCK_GET_IFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GDK_TYPE_FRAME_CLOCK, GdkFrameClockInterface))
 
-typedef struct _GdkFrameClock          GdkFrameClock;
-typedef struct _GdkFrameClockInterface GdkFrameClockInterface;
-
 typedef enum {
   GDK_FRAME_CLOCK_PHASE_NONE         = 0,
   GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT = 1 << 0,
-  GDK_FRAME_CLOCK_PHASE_LAYOUT       = 1 << 1,
-  GDK_FRAME_CLOCK_PHASE_PAINT        = 1 << 2,
-  GDK_FRAME_CLOCK_PHASE_AFTER_PAINT  = 1 << 3
+  GDK_FRAME_CLOCK_PHASE_UPDATE       = 1 << 1,
+  GDK_FRAME_CLOCK_PHASE_LAYOUT       = 1 << 2,
+  GDK_FRAME_CLOCK_PHASE_PAINT        = 1 << 3,
+  GDK_FRAME_CLOCK_PHASE_AFTER_PAINT  = 1 << 4
 } GdkFrameClockPhase;
 
 struct _GdkFrameClockInterface
@@ -67,6 +88,7 @@ struct _GdkFrameClockInterface
   /* signals */
   /* void (* frame_requested)    (GdkFrameClock *clock); */
   /* void (* before_paint)       (GdkFrameClock *clock); */
+  /* void (* update)             (GdkFrameClock *clock); */
   /* void (* layout)             (GdkFrameClock *clock); */
   /* void (* paint)              (GdkFrameClock *clock); */
   /* void (* after_paint)        (GdkFrameClock *clock); */
diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c
index a0b82f0..bf68fd1 100644
--- a/gdk/gdkframeclockidle.c
+++ b/gdk/gdkframeclockidle.c
@@ -189,7 +189,16 @@ gdk_frame_clock_paint_idle (void *data)
            * they don't get repeated if you freeze/thaw while
            * in them. */
 	  g_signal_emit_by_name (G_OBJECT (clock), "before-paint");
-	  priv->phase = GDK_FRAME_CLOCK_PHASE_LAYOUT;
+	  priv->phase = GDK_FRAME_CLOCK_PHASE_UPDATE;
+	}
+    case GDK_FRAME_CLOCK_PHASE_UPDATE:
+      if (priv->freeze_count == 0)
+	{
+          if (priv->requested & GDK_FRAME_CLOCK_PHASE_UPDATE)
+            {
+              priv->requested &= ~GDK_FRAME_CLOCK_PHASE_UPDATE;
+              g_signal_emit_by_name (G_OBJECT (clock), "update");
+            }
 	}
     case GDK_FRAME_CLOCK_PHASE_LAYOUT:
       if (priv->freeze_count == 0)
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index 876105c..343cf1f 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -358,20 +358,21 @@ struct _GtkStyleContextPrivate
 
   GtkStyleCascade *cascade;
 
-  GtkStyleContext *animation_list_prev;
-  GtkStyleContext *animation_list_next;
-
   GtkStyleContext *parent;
   GSList *children;
-  GtkWidget *widget;            
+  GtkWidget *widget;
   GtkWidgetPath *widget_path;
   GHashTable *style_data;
   GtkStyleInfo *info;
 
+  GdkFrameClock *frame_clock;
+  guint frame_clock_update_id;
+
   GtkCssChange relevant_changes;
   GtkCssChange pending_changes;
 
   const GtkBitmask *invalidating_context;
+  guint animating : 1;
   guint invalid : 1;
 };
 
@@ -388,11 +389,11 @@ enum {
 };
 
 static guint signals[LAST_SIGNAL] = { 0 };
-static GtkStyleContext *_running_animations = NULL;
-guint _running_animations_timer_id = 0;
 
 static void gtk_style_context_finalize (GObject *object);
 
+static void frame_clock_target_iface_init (GdkFrameClockTargetInterface *target);
+
 static void gtk_style_context_impl_set_property (GObject      *object,
                                                  guint         prop_id,
                                                  const GValue *value,
@@ -404,7 +405,11 @@ static void gtk_style_context_impl_get_property (GObject      *object,
 static StyleData *style_data_lookup             (GtkStyleContext *context);
 
 
-G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
+static void gtk_style_context_disconnect_update (GtkStyleContext *context);
+static void gtk_style_context_connect_update    (GtkStyleContext *context);
+
+G_DEFINE_TYPE_WITH_CODE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GDK_TYPE_FRAME_CLOCK_TARGET, frame_clock_target_iface_init))
 
 static void
 gtk_style_context_real_changed (GtkStyleContext *context)
@@ -469,6 +474,25 @@ gtk_style_context_class_init (GtkStyleContextClass *klass)
   g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate));
 }
 
+static void
+gtk_style_context_set_clock (GdkFrameClockTarget *target,
+                             GdkFrameClock       *clock)
+{
+  GtkStyleContext *context = GTK_STYLE_CONTEXT (target);
+  GtkStyleContextPrivate *priv = context->priv;
+
+  gtk_style_context_disconnect_update (context);
+  priv->frame_clock = clock;
+  if (priv->animating)
+    gtk_style_context_connect_update (context);
+}
+
+static void
+frame_clock_target_iface_init (GdkFrameClockTargetInterface *iface)
+{
+  iface->set_clock = gtk_style_context_set_clock;
+}
+
 static StyleData *
 style_data_new (void)
 {
@@ -724,28 +748,50 @@ gtk_style_context_init (GtkStyleContext *style_context)
                                  _gtk_style_cascade_get_for_screen (priv->screen));
 }
 
+static void
+gtk_style_context_update (GdkFrameClock  *clock,
+                          GtkStyleContext *context)
+{
+  _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE);
+
+  /* A little blech to request one more than we need */
+  gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
+}
+
 static gboolean
-gtk_style_context_do_animations (gpointer unused)
+gtk_style_context_is_animating (GtkStyleContext *context)
 {
-  GtkStyleContext *context;
+  GtkStyleContextPrivate *priv = context->priv;
+
+  return priv->animating;
+}
 
-  for (context = _running_animations;
-       context != NULL;
-       context = context->priv->animation_list_next)
+static void
+gtk_style_context_disconnect_update (GtkStyleContext *context)
+{
+  GtkStyleContextPrivate *priv = context->priv;
+
+  if (priv->frame_clock && priv->frame_clock_update_id)
     {
-      _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE);
+      g_signal_handler_disconnect (priv->frame_clock,
+                                   priv->frame_clock_update_id);
+      priv->frame_clock_update_id = 0;
     }
-
-  return TRUE;
 }
 
-static gboolean
-gtk_style_context_is_animating (GtkStyleContext *context)
+static void
+gtk_style_context_connect_update (GtkStyleContext *context)
 {
   GtkStyleContextPrivate *priv = context->priv;
 
-  return priv->animation_list_prev != NULL
-      || _running_animations == context;
+  if (priv->frame_clock && priv->frame_clock_update_id == 0)
+    {
+      priv->frame_clock_update_id = g_signal_connect (priv->frame_clock,
+                                                      "update",
+                                                      G_CALLBACK (gtk_style_context_update),
+                                                      context);
+      gdk_frame_clock_request_phase (priv->frame_clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
+    }
 }
 
 static void
@@ -756,25 +802,14 @@ gtk_style_context_stop_animating (GtkStyleContext *context)
   if (!gtk_style_context_is_animating (context))
     return;
 
-  if (priv->animation_list_prev == NULL)
-    {
-      _running_animations = priv->animation_list_next;
+  priv->animating = FALSE;
 
-      if (_running_animations == NULL)
-        {
-          /* we were the last animation */
-          g_source_remove (_running_animations_timer_id);
-          _running_animations_timer_id = 0;
-        }
+  gtk_style_context_disconnect_update (context);
+  if (priv->widget)
+    {
+      gtk_widget_remove_frame_clock_target (priv->widget,
+                                            GDK_FRAME_CLOCK_TARGET (context));
     }
-  else
-    priv->animation_list_prev->priv->animation_list_next = priv->animation_list_next;
-
-  if (priv->animation_list_next)
-    priv->animation_list_next->priv->animation_list_prev = priv->animation_list_prev;
-
-  priv->animation_list_next = NULL;
-  priv->animation_list_prev = NULL;
 }
 
 static void
@@ -785,18 +820,13 @@ gtk_style_context_start_animating (GtkStyleContext *context)
   if (gtk_style_context_is_animating (context))
     return;
 
-  if (_running_animations == NULL)
-    {
-      _running_animations_timer_id = gdk_threads_add_timeout (25,
-                                                              gtk_style_context_do_animations,
-                                                              NULL);
-      _running_animations = context;
-    }
-  else
+  priv->animating = TRUE;
+
+  gtk_style_context_connect_update (context);
+  if (priv->widget)
     {
-      priv->animation_list_next = _running_animations;
-      _running_animations->priv->animation_list_prev = context;
-      _running_animations = context;
+      gtk_widget_add_frame_clock_target (priv->widget,
+                                         GDK_FRAME_CLOCK_TARGET (context));
     }
 }
 
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 63fbcae..1c7e538 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -409,6 +409,9 @@ struct _GtkWidgetPrivate
   /* The widget's parent */
   GtkWidget *parent;
 
+  /* Animations and other things to update on clock ticks */
+  GList *frame_clock_targets;
+
 #ifdef G_ENABLE_DEBUG
   /* Number of gtk_widget_push_verify_invariants () */
   guint verifying_invariants_count;
@@ -4533,6 +4536,7 @@ gtk_widget_realize (GtkWidget *widget)
 {
   GtkWidgetPrivate *priv;
   cairo_region_t *region;
+  GList *tmp_list;
 
   g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (widget->priv->anchored ||
@@ -4588,6 +4592,12 @@ gtk_widget_realize (GtkWidget *widget)
       if (GTK_IS_CONTAINER (widget))
         _gtk_container_maybe_start_idle_sizer (GTK_CONTAINER (widget));
 
+      for (tmp_list = priv->frame_clock_targets; tmp_list; tmp_list = tmp_list->next)
+        {
+          GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (widget);
+          gdk_frame_clock_target_set_clock (tmp_list->data, frame_clock);
+        }
+
       gtk_widget_pop_verify_invariants (widget);
     }
 }
@@ -10533,6 +10543,10 @@ gtk_widget_real_destroy (GtkWidget *object)
 
   gtk_grab_remove (widget);
 
+  g_list_foreach (priv->frame_clock_targets, (GFunc)g_object_unref, NULL);
+  g_list_free (priv->frame_clock_targets);
+  priv->frame_clock_targets = NULL;
+
   if (priv->style)
     g_object_unref (priv->style);
   priv->style = gtk_widget_get_default_style ();
@@ -14582,3 +14596,65 @@ gtk_widget_insert_action_group (GtkWidget    *widget,
   else
     g_action_muxer_remove (muxer, name);
 }
+
+/**
+ * gtk_widget_add_frame_clock_target:
+ * @widget: a #GtkWidget
+ * @target: the #GdkClockTarget
+ *
+ * Associates a #GdkClockTarget with the widget. When the widget
+ * is realized and gets a #GdkFrameClock the clock target will be
+ * added to that frame clock.
+ */
+void
+gtk_widget_add_frame_clock_target (GtkWidget           *widget,
+                                   GdkFrameClockTarget *target)
+{
+  GtkWidgetPrivate *priv;
+  priv = widget->priv;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (GDK_IS_FRAME_CLOCK_TARGET (target));
+
+  priv->frame_clock_targets = g_list_prepend (priv->frame_clock_targets, target);
+  g_object_ref (target);
+
+  if (gtk_widget_get_realized (widget))
+    {
+      GdkFrameClock *clock;
+      clock = gtk_widget_get_frame_clock (widget);
+      gdk_frame_clock_target_set_clock (target, clock);
+    }
+}
+
+/**
+ * gtk_widget_remove_frame_clock_target:
+ * @widget: a #GtkWidget
+ * @target: the #GdkClockTarget
+ *
+ * Removes a #GdkClockTarget previously added with
+ * gtk_widget_add_frame_clock_target.
+ */
+void
+gtk_widget_remove_frame_clock_target (GtkWidget          *widget,
+                                      GdkFrameClockTarget *target)
+{
+  GtkWidgetPrivate *priv;
+  GList *tmp_list;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (GDK_IS_FRAME_CLOCK_TARGET (target));
+
+  priv = widget->priv;
+
+  tmp_list = g_list_find (priv->frame_clock_targets, target);
+  if (tmp_list == NULL)
+    return;
+
+  priv->frame_clock_targets = g_list_delete_link (priv->frame_clock_targets, tmp_list);
+
+  if (gtk_widget_get_realized (widget))
+    gdk_frame_clock_target_set_clock (target, NULL);
+
+  g_object_unref (target);
+}
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index a8572e6..9f12bf9 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -905,6 +905,13 @@ void                    gtk_widget_insert_action_group                  (GtkWidg
                                                                          const gchar  *name,
                                                                          GActionGroup *group);
 
+GDK_AVAILABLE_IN_3_2
+void gtk_widget_add_frame_clock_target (GtkWidget           *widget,
+                                        GdkFrameClockTarget *target);
+GDK_AVAILABLE_IN_3_2
+void gtk_widget_remove_frame_clock_target (GtkWidget           *widget,
+                                           GdkFrameClockTarget *target);
+
 G_END_DECLS
 
 #endif /* __GTK_WIDGET_H__ */


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