clutter/timeline: Wait for stage if no frame clock is available

When picking which frame clock to use, we traverse up in the actor
hierarchy until a suitable frame clock is found. ClutterTimeline
also listens to the 'stage-views-changed' to make sure it's always
attached to the correct frame clock.

However, there is one special situation where neither of them would
work: when the stage doesn't have a frame clock yet, and the actor
of the timeline is outside any stage view. When that happens, the
returned frame clock is NULL, and 'stage-views-changed' is never
emitted by the actor.

Monitor the stage for stage view changes when the frame clock is
NULL.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1285
This commit is contained in:
Georges Basile Stavracas Neto 2020-07-01 13:09:27 -03:00 committed by Jonas Ådahl
parent 1ecdaa646f
commit 5b0a7b3a33

View File

@ -117,6 +117,8 @@ struct _ClutterTimelinePrivate
ClutterActor *actor;
gulong actor_destroy_handler_id;
gulong actor_stage_views_handler_id;
gulong stage_stage_views_handler_id;
ClutterActor *stage;
guint delay_id;
@ -207,6 +209,8 @@ enum
static guint timeline_signals[LAST_SIGNAL] = { 0, };
static void update_frame_clock (ClutterTimeline *timeline);
static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterTimeline, clutter_timeline, G_TYPE_OBJECT,
@ -366,17 +370,53 @@ set_frame_clock_internal (ClutterTimeline *timeline,
maybe_add_timeline (timeline);
}
static void
on_stage_stage_views_changed (ClutterActor *stage,
ClutterTimeline *timeline)
{
ClutterTimelinePrivate *priv = timeline->priv;
g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
priv->stage = NULL;
update_frame_clock (timeline);
}
static void
update_frame_clock (ClutterTimeline *timeline)
{
ClutterTimelinePrivate *priv = timeline->priv;
ClutterFrameClock *frame_clock;
ClutterFrameClock *frame_clock = NULL;
ClutterActor *stage;
if (!priv->actor)
goto out;
if (priv->actor)
frame_clock = clutter_actor_pick_frame_clock (priv->actor);
else
frame_clock = NULL;
if (frame_clock)
{
g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
goto out;
}
stage = clutter_actor_get_stage (priv->actor);
if (!stage)
{
if (priv->is_playing)
g_warning ("Timelines with detached actors are not supported");
goto out;
}
if (priv->stage_stage_views_handler_id > 0)
goto out;
priv->stage_stage_views_handler_id =
g_signal_connect (stage, "stage-views-changed",
G_CALLBACK (on_stage_stage_views_changed),
timeline);
priv->stage = stage;
out:
set_frame_clock_internal (timeline, frame_clock);
}
@ -406,6 +446,8 @@ clutter_timeline_set_actor (ClutterTimeline *timeline,
{
g_clear_signal_handler (&priv->actor_destroy_handler_id, priv->actor);
g_clear_signal_handler (&priv->actor_stage_views_handler_id, priv->actor);
g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
priv->stage = NULL;
priv->actor = NULL;
if (priv->is_playing)
@ -690,6 +732,7 @@ clutter_timeline_dispose (GObject *object)
{
g_clear_signal_handler (&priv->actor_destroy_handler_id, priv->actor);
g_clear_signal_handler (&priv->actor_stage_views_handler_id, priv->actor);
g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
priv->actor = NULL;
}