Commit a2408088 authored by Benjamin Otte's avatar Benjamin Otte

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.
parent 50fdb6a1
......@@ -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));
......
......@@ -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)
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment