clutter: Add private API to support resource scale affecting layout
For ClutterText, the resource scale the text is drawn with affects the size of the allocation: ClutterText will choose a font scale based on the resource scale, and that font scale can lead to a slight difference in size compared to the unscaled font. We currently handle that by queuing a relayout inside the "resource-scale-changed" signal handler. This solution is a bit problematic though since it will take one more allocation cycle until the allocation is actually updated after a scale-change, so the actor is painted using the wrong allocation for one frame. Also the current solution can lead to relayout loops in a few cases, for example if a ClutterText is located near the edge on a 1x scaled monitor and is moved to intersect a 2x scaled monitor: Now the resource scale will change to 2 and a new allocation box is calculated; if this allocation box is slightly smaller than the old one because of the new font scale, the allocation won't intersect the 2x scaled monitor again and the resource scale switches back to 1. Now the allocation gets larger again and intersects the 2x scaled monitor again. This commit introduces a way to properly support those actors: In case an actors resource scale might affect its allocation, it should call the private function clutter_actor_queue_immediate_relayout(). This will make sure the actor gets a relayout before the upcoming paint happens afte every resource scale change. Also potential relayout loops can be handled by the actors themselves using a "phase" argument that's passed to implementations of the calculate_resource_scale() vfunc. The new API is private because resource scales are not meant to be used in a way where the scale affects the allocation. With ClutterText and the current behavior of Pango, that can't be avoid though, so we need it anyway. https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1276
This commit is contained in:
parent
98df2dbd05
commit
280429bac8
@ -288,7 +288,10 @@ float clutter_actor_get_real_resource_scale
|
|||||||
ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self,
|
ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self,
|
||||||
CoglTexture *texture);
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
|
@ -5903,6 +5903,25 @@ clutter_actor_real_has_overlaps (ClutterActor *self)
|
|||||||
return TRUE;
|
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
|
static void
|
||||||
clutter_actor_real_destroy (ClutterActor *actor)
|
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_accessible = clutter_actor_real_get_accessible;
|
||||||
klass->get_paint_volume = clutter_actor_real_get_paint_volume;
|
klass->get_paint_volume = clutter_actor_real_get_paint_volume;
|
||||||
klass->has_overlaps = clutter_actor_real_has_overlaps;
|
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->paint = clutter_actor_real_paint;
|
||||||
klass->destroy = clutter_actor_real_destroy;
|
klass->destroy = clutter_actor_real_destroy;
|
||||||
|
|
||||||
@ -16131,20 +16151,14 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_resource_scale (ClutterActor *self)
|
update_resource_scale (ClutterActor *self,
|
||||||
|
int phase)
|
||||||
{
|
{
|
||||||
ClutterActorPrivate *priv = self->priv;
|
ClutterActorPrivate *priv = self->priv;
|
||||||
GList *l;
|
float new_resource_scale, old_resource_scale;
|
||||||
float new_resource_scale = -1.f;
|
|
||||||
float old_resource_scale;
|
|
||||||
|
|
||||||
for (l = priv->stage_views; l; l = l->next)
|
new_resource_scale =
|
||||||
{
|
CLUTTER_ACTOR_GET_CLASS (self)->calculate_resource_scale (self, phase);
|
||||||
ClutterStageView *view = l->data;
|
|
||||||
|
|
||||||
new_resource_scale = MAX (clutter_stage_view_get_scale (view),
|
|
||||||
new_resource_scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->resource_scale == new_resource_scale)
|
if (priv->resource_scale == new_resource_scale)
|
||||||
return;
|
return;
|
||||||
@ -16168,7 +16182,8 @@ update_resource_scale (ClutterActor *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
clutter_actor_update_stage_views (ClutterActor *self)
|
clutter_actor_update_stage_views (ClutterActor *self,
|
||||||
|
gboolean use_max_scale)
|
||||||
{
|
{
|
||||||
ClutterActorPrivate *priv = self->priv;
|
ClutterActorPrivate *priv = self->priv;
|
||||||
ClutterActor *child;
|
ClutterActor *child;
|
||||||
@ -16181,12 +16196,12 @@ clutter_actor_update_stage_views (ClutterActor *self)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
update_stage_views (self);
|
update_stage_views (self);
|
||||||
update_resource_scale (self);
|
update_resource_scale (self, use_max_scale);
|
||||||
|
|
||||||
priv->needs_update_stage_views = FALSE;
|
priv->needs_update_stage_views = FALSE;
|
||||||
|
|
||||||
for (child = priv->first_child; child; child = child->priv->next_sibling)
|
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;
|
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);
|
||||||
|
}
|
||||||
|
@ -297,6 +297,8 @@ struct _ClutterActorClass
|
|||||||
ClutterTouchEvent *event);
|
ClutterTouchEvent *event);
|
||||||
gboolean (* has_accessible) (ClutterActor *self);
|
gboolean (* has_accessible) (ClutterActor *self);
|
||||||
void (* resource_scale_changed) (ClutterActor *self);
|
void (* resource_scale_changed) (ClutterActor *self);
|
||||||
|
float (* calculate_resource_scale) (ClutterActor *self,
|
||||||
|
int phase);
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
/* padding for future expansion */
|
/* padding for future expansion */
|
||||||
|
@ -136,6 +136,8 @@ void clutter_stage_queue_actor_relayout (ClutterStage *stage,
|
|||||||
GList * clutter_stage_get_views_for_rect (ClutterStage *stage,
|
GList * clutter_stage_get_views_for_rect (ClutterStage *stage,
|
||||||
const graphene_rect_t *rect);
|
const graphene_rect_t *rect);
|
||||||
|
|
||||||
|
void clutter_stage_set_actor_needs_immediate_relayout (ClutterStage *stage);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __CLUTTER_STAGE_PRIVATE_H__ */
|
#endif /* __CLUTTER_STAGE_PRIVATE_H__ */
|
||||||
|
@ -146,6 +146,7 @@ struct _ClutterStagePrivate
|
|||||||
guint min_size_changed : 1;
|
guint min_size_changed : 1;
|
||||||
guint motion_events_enabled : 1;
|
guint motion_events_enabled : 1;
|
||||||
guint stage_was_relayout : 1;
|
guint stage_was_relayout : 1;
|
||||||
|
guint actor_needs_immediate_relayout : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -1354,8 +1355,34 @@ static void
|
|||||||
update_actor_stage_views (ClutterStage *stage)
|
update_actor_stage_views (ClutterStage *stage)
|
||||||
{
|
{
|
||||||
ClutterActor *actor = CLUTTER_ACTOR (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)
|
if (stage_was_relayout)
|
||||||
pointers = _clutter_stage_check_updated_pointers (stage);
|
pointers = _clutter_stage_check_updated_pointers (stage);
|
||||||
|
|
||||||
COGL_TRACE_BEGIN (ClutterStageUpdateActorStageViews, "Actor stage-views");
|
|
||||||
update_actor_stage_views (stage);
|
update_actor_stage_views (stage);
|
||||||
COGL_TRACE_END (ClutterStageUpdateActorStageViews);
|
|
||||||
|
|
||||||
COGL_TRACE_BEGIN (ClutterStagePaint, "Paint");
|
COGL_TRACE_BEGIN (ClutterStagePaint, "Paint");
|
||||||
|
|
||||||
@ -4115,3 +4140,11 @@ clutter_stage_get_views_for_rect (ClutterStage *stage,
|
|||||||
|
|
||||||
return views_for_rect;
|
return views_for_rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clutter_stage_set_actor_needs_immediate_relayout (ClutterStage *stage)
|
||||||
|
{
|
||||||
|
ClutterStagePrivate *priv = stage->priv;
|
||||||
|
|
||||||
|
priv->actor_needs_immediate_relayout = TRUE;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user