diff --git a/clutter/clutter/clutter-actor-private.h b/clutter/clutter/clutter-actor-private.h index d1adcd38f..16ab012b6 100644 --- a/clutter/clutter/clutter-actor-private.h +++ b/clutter/clutter/clutter-actor-private.h @@ -288,7 +288,10 @@ float clutter_actor_get_real_resource_scale ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self, CoglTexture *texture); -void clutter_actor_update_stage_views (ClutterActor *self); +void clutter_actor_update_stage_views (ClutterActor *self, + int phase); + +void clutter_actor_queue_immediate_relayout (ClutterActor *self); G_END_DECLS diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index e6a963139..86ffe2f1f 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -5903,6 +5903,25 @@ clutter_actor_real_has_overlaps (ClutterActor *self) return TRUE; } +static float +clutter_actor_real_calculate_resource_scale (ClutterActor *self, + int phase) +{ + ClutterActorPrivate *priv = self->priv; + GList *l; + float new_resource_scale = -1.f; + + for (l = priv->stage_views; l; l = l->next) + { + ClutterStageView *view = l->data; + + new_resource_scale = MAX (clutter_stage_view_get_scale (view), + new_resource_scale); + } + + return new_resource_scale; +} + static void clutter_actor_real_destroy (ClutterActor *actor) { @@ -5988,6 +6007,7 @@ clutter_actor_class_init (ClutterActorClass *klass) klass->get_accessible = clutter_actor_real_get_accessible; klass->get_paint_volume = clutter_actor_real_get_paint_volume; klass->has_overlaps = clutter_actor_real_has_overlaps; + klass->calculate_resource_scale = clutter_actor_real_calculate_resource_scale; klass->paint = clutter_actor_real_paint; klass->destroy = clutter_actor_real_destroy; @@ -16131,20 +16151,14 @@ out: } static void -update_resource_scale (ClutterActor *self) +update_resource_scale (ClutterActor *self, + int phase) { ClutterActorPrivate *priv = self->priv; - GList *l; - float new_resource_scale = -1.f; - float old_resource_scale; + float new_resource_scale, old_resource_scale; - for (l = priv->stage_views; l; l = l->next) - { - ClutterStageView *view = l->data; - - new_resource_scale = MAX (clutter_stage_view_get_scale (view), - new_resource_scale); - } + new_resource_scale = + CLUTTER_ACTOR_GET_CLASS (self)->calculate_resource_scale (self, phase); if (priv->resource_scale == new_resource_scale) return; @@ -16168,7 +16182,8 @@ update_resource_scale (ClutterActor *self) } void -clutter_actor_update_stage_views (ClutterActor *self) +clutter_actor_update_stage_views (ClutterActor *self, + gboolean use_max_scale) { ClutterActorPrivate *priv = self->priv; ClutterActor *child; @@ -16181,12 +16196,12 @@ clutter_actor_update_stage_views (ClutterActor *self) return; update_stage_views (self); - update_resource_scale (self); + update_resource_scale (self, use_max_scale); priv->needs_update_stage_views = FALSE; for (child = priv->first_child; child; child = child->priv->next_sibling) - clutter_actor_update_stage_views (child); + clutter_actor_update_stage_views (child, use_max_scale); } /** @@ -19710,3 +19725,17 @@ clutter_actor_has_accessible (ClutterActor *actor) return TRUE; } + +void +clutter_actor_queue_immediate_relayout (ClutterActor *self) +{ + ClutterStage *stage; + + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + clutter_actor_queue_relayout (self); + + stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self)); + if (stage) + clutter_stage_set_actor_needs_immediate_relayout (stage); +} diff --git a/clutter/clutter/clutter-actor.h b/clutter/clutter/clutter-actor.h index 9f795f6d3..67d327b5b 100644 --- a/clutter/clutter/clutter-actor.h +++ b/clutter/clutter/clutter-actor.h @@ -297,6 +297,8 @@ struct _ClutterActorClass ClutterTouchEvent *event); gboolean (* has_accessible) (ClutterActor *self); void (* resource_scale_changed) (ClutterActor *self); + float (* calculate_resource_scale) (ClutterActor *self, + int phase); /*< private >*/ /* padding for future expansion */ diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h index 5d785b644..2ce0cd05b 100644 --- a/clutter/clutter/clutter-stage-private.h +++ b/clutter/clutter/clutter-stage-private.h @@ -136,6 +136,8 @@ void clutter_stage_queue_actor_relayout (ClutterStage *stage, GList * clutter_stage_get_views_for_rect (ClutterStage *stage, const graphene_rect_t *rect); +void clutter_stage_set_actor_needs_immediate_relayout (ClutterStage *stage); + G_END_DECLS #endif /* __CLUTTER_STAGE_PRIVATE_H__ */ diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 99d218441..8d3fc8b80 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -146,6 +146,7 @@ struct _ClutterStagePrivate guint min_size_changed : 1; guint motion_events_enabled : 1; guint stage_was_relayout : 1; + guint actor_needs_immediate_relayout : 1; }; enum @@ -1354,8 +1355,34 @@ static void update_actor_stage_views (ClutterStage *stage) { ClutterActor *actor = CLUTTER_ACTOR (stage); + ClutterStagePrivate *priv = stage->priv; + int phase; - clutter_actor_update_stage_views (actor); + COGL_TRACE_BEGIN_SCOPED (ClutterStageUpdateActorStageViews, + "Actor stage-views"); + + /* If an actor needs an immediate relayout because its resource scale + * changed, we give it another chance to allocate correctly before + * the paint. + * + * We're doing the whole thing twice and pass the phase to + * clutter_actor_update_stage_views() to allow actors to detect loops: + * If the resource scale changes again after the relayout, the new + * allocation of an actor probably moved the actor onto another stage + * view, so if an actor sees phase == 1, it can choose a "final" scale. + */ + for (phase = 0; phase < 2; phase++) + { + clutter_actor_update_stage_views (actor, phase); + + if (!priv->actor_needs_immediate_relayout) + break; + + priv->actor_needs_immediate_relayout = FALSE; + _clutter_stage_maybe_relayout (actor); + } + + g_warn_if_fail (!priv->actor_needs_immediate_relayout); } /** @@ -1405,9 +1432,7 @@ _clutter_stage_do_update (ClutterStage *stage) if (stage_was_relayout) pointers = _clutter_stage_check_updated_pointers (stage); - COGL_TRACE_BEGIN (ClutterStageUpdateActorStageViews, "Actor stage-views"); update_actor_stage_views (stage); - COGL_TRACE_END (ClutterStageUpdateActorStageViews); COGL_TRACE_BEGIN (ClutterStagePaint, "Paint"); @@ -4115,3 +4140,11 @@ clutter_stage_get_views_for_rect (ClutterStage *stage, return views_for_rect; } + +void +clutter_stage_set_actor_needs_immediate_relayout (ClutterStage *stage) +{ + ClutterStagePrivate *priv = stage->priv; + + priv->actor_needs_immediate_relayout = TRUE; +}