summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2012-04-10 15:37:35 +0200
committerBenjamin Otte <otte@redhat.com>2012-04-17 08:59:22 +0200
commita2408088240d25157f56f85dd0dcdef6fc063682 (patch)
tree3e58e562f68ac341faa062bf99b1996157eafb6a /gtk
parent50fdb6a13ff39c31d189756497d240627c4c1669 (diff)
downloadgtk+-a2408088240d25157f56f85dd0dcdef6fc063682.tar.gz
stylecontext: Add an animating framework
The design principles were: - synchronized If multiple style contexts are animating, they should all do an animation step at the same time. - degrades well Even when there's thousands of style contexts all animating at the same time, the animation steps don't starve the CPU. This is achieved by making sure the timeout is really fast. It just sets a bunch of flags. - no hidden bottlenecks Turning animatability on or off on a style context is O(1). So far it is unused.
Diffstat (limited to 'gtk')
-rw-r--r--gtk/gtkcsstypes.c4
-rw-r--r--gtk/gtkcsstypesprivate.h5
-rw-r--r--gtk/gtkstylecontext.c83
3 files changed, 89 insertions, 3 deletions
diff --git a/gtk/gtkcsstypes.c b/gtk/gtkcsstypes.c
index f83880afab..b69b0fecca 100644
--- a/gtk/gtkcsstypes.c
+++ b/gtk/gtkcsstypes.c
@@ -56,7 +56,8 @@ _gtk_css_change_for_sibling (GtkCssChange match)
{ GTK_CSS_CHANGE_NAME, GTK_CSS_CHANGE_SIBLING_NAME },
{ GTK_CSS_CHANGE_POSITION, GTK_CSS_CHANGE_SIBLING_POSITION },
{ GTK_CSS_CHANGE_STATE, GTK_CSS_CHANGE_SIBLING_STATE },
- { GTK_CSS_CHANGE_SOURCE, 0 }
+ { GTK_CSS_CHANGE_SOURCE, 0 },
+ { GTK_CSS_CHANGE_ANIMATE, 0 }
};
return gtk_css_change_translate (match, table, G_N_ELEMENTS (table));
@@ -75,6 +76,7 @@ _gtk_css_change_for_child (GtkCssChange match)
{ GTK_CSS_CHANGE_SIBLING_POSITION, GTK_CSS_CHANGE_PARENT_SIBLING_POSITION },
{ GTK_CSS_CHANGE_SIBLING_STATE, GTK_CSS_CHANGE_PARENT_SIBLING_STATE },
{ GTK_CSS_CHANGE_SOURCE, 0 },
+ { GTK_CSS_CHANGE_ANIMATE, 0 }
};
return gtk_css_change_translate (match, table, G_N_ELEMENTS (table));
diff --git a/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h
index 8890a5cce9..b0db18d0b9 100644
--- a/gtk/gtkcsstypesprivate.h
+++ b/gtk/gtkcsstypesprivate.h
@@ -43,10 +43,11 @@ typedef enum { /*< skip >*/
GTK_CSS_CHANGE_PARENT_SIBLING_POSITION = (1 << 14),
GTK_CSS_CHANGE_PARENT_SIBLING_STATE = (1 << 15),
/* add more */
- GTK_CSS_CHANGE_SOURCE = (1 << 16)
+ GTK_CSS_CHANGE_SOURCE = (1 << 16),
+ GTK_CSS_CHANGE_ANIMATE = (1 << 17)
} GtkCssChange;
-#define GTK_CSS_CHANGE_ANY ((1 << 17) - 1)
+#define GTK_CSS_CHANGE_ANY ((1 << 18) - 1)
#define GTK_CSS_CHANGE_ANY_SELF (GTK_CSS_CHANGE_CLASS | GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_STATE)
#define GTK_CSS_CHANGE_ANY_SIBLING (GTK_CSS_CHANGE_SIBLING_CLASS | GTK_CSS_CHANGE_SIBLING_NAME | \
GTK_CSS_CHANGE_SIBLING_POSITION | GTK_CSS_CHANGE_SIBLING_STATE)
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index 0ac8eb3a96..8375328f94 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -350,6 +350,9 @@ struct _GtkStyleContextPrivate
GtkStyleCascade *cascade;
+ GtkStyleContext *animation_list_prev;
+ GtkStyleContext *animation_list_next;
+
GtkStyleContext *parent;
GSList *children;
GtkWidget *widget;
@@ -379,6 +382,8 @@ 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);
@@ -675,6 +680,82 @@ gtk_style_context_init (GtkStyleContext *style_context)
_gtk_style_cascade_get_for_screen (priv->screen));
}
+static gboolean
+gtk_style_context_do_animations (gpointer unused)
+{
+ GtkStyleContext *context;
+
+ for (context = _running_animations;
+ context != NULL;
+ context = context->priv->animation_list_next)
+ {
+ _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gtk_style_context_is_animating (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv = context->priv;
+
+ return priv->animation_list_prev != NULL
+ || _running_animations == context;
+}
+
+static void
+gtk_style_context_stop_animating (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv = context->priv;
+
+ if (!gtk_style_context_is_animating (context))
+ return;
+
+ if (priv->animation_list_prev == NULL)
+ {
+ _running_animations = priv->animation_list_next;
+
+ if (_running_animations == NULL)
+ {
+ /* we were the last animation */
+ g_source_remove (_running_animations_timer_id);
+ _running_animations_timer_id = 0;
+ }
+ }
+ 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 G_GNUC_UNUSED
+gtk_style_context_start_animating (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv = context->priv;
+
+ 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->animation_list_next = _running_animations;
+ _running_animations->priv->animation_list_prev = context;
+ _running_animations = context;
+ }
+}
+
static void
gtk_style_context_finalize (GObject *object)
{
@@ -684,6 +765,8 @@ gtk_style_context_finalize (GObject *object)
style_context = GTK_STYLE_CONTEXT (object);
priv = style_context->priv;
+ gtk_style_context_stop_animating (style_context);
+
/* children hold a reference to us */
g_assert (priv->children == NULL);