mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 14:31:10 +00:00
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.
This commit is contained in:
parent
50fdb6a13f
commit
a240808824
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user