Do not cause more size requisitions than necessary

Bug 1499 - clutter_actor_notify_if_geometry_changed causes sync
           layout cycles

Whenever clutter_actor_set_{width,height,x,y,size...} is used, extra
synchronous size requests are triggered in
clutter_actor_notify_if_geometry_changed.

If the get_preferred_width() and get_preferred_height() implementations
are particularly costly (e.g. ClutterText) this will result in a performance
impact.

To avoid excessive allocation or requisition cycles we use the
cached values and flags. If we don't have an allocation, we assume
that we need to notify all the properties; if we don't have a size
requisition we notify only width and height; finally, if we do have
a valid allocation we notify only on the changed values.
This commit is contained in:
Emmanuele Bassi 2009-03-13 14:14:00 +00:00
parent 786161c75f
commit 72f9646804

View File

@ -797,25 +797,55 @@ static inline void
clutter_actor_notify_if_geometry_changed (ClutterActor *self,
const ClutterActorBox *old)
{
ClutterUnit xu, yu;
ClutterUnit widthu, heightu;
clutter_actor_get_positionu (self, &xu, &yu);
clutter_actor_get_sizeu (self, &widthu, &heightu);
ClutterActorPrivate *priv = self->priv;
g_object_freeze_notify (G_OBJECT (self));
if (xu != old->x1)
g_object_notify (G_OBJECT (self), "x");
/* to avoid excessive requisition or allocation cycles we
* use the cached values.
*
* - if we don't have an allocation we assume that we need
* to notify anyway
* - if we don't have a width or a height request we notify
* width and height
* - if we have a valid allocation then we check the old
* bounding box with the current allocation and we notify
* the changes
*/
if (priv->needs_allocation)
{
g_object_notify (G_OBJECT (self), "x");
g_object_notify (G_OBJECT (self), "y");
g_object_notify (G_OBJECT (self), "width");
g_object_notify (G_OBJECT (self), "height");
}
else if (priv->needs_width_request || priv->needs_height_request)
{
g_object_notify (G_OBJECT (self), "width");
g_object_notify (G_OBJECT (self), "height");
}
else
{
ClutterUnit xu, yu;
ClutterUnit widthu, heightu;
if (yu != old->y1)
g_object_notify (G_OBJECT (self), "y");
xu = priv->allocation.x1;
yu = priv->allocation.y1;
widthu = priv->allocation.x2 - priv->allocation.x1;
heightu = priv->allocation.y2 - priv->allocation.y1;
if (widthu != (old->x2 - old->x1))
g_object_notify (G_OBJECT (self), "width");
if (xu != old->x1)
g_object_notify (G_OBJECT (self), "x");
if (heightu != (old->y2 - old->y1))
g_object_notify (G_OBJECT (self), "height");
if (yu != old->y1)
g_object_notify (G_OBJECT (self), "y");
if (widthu != (old->x2 - old->x1))
g_object_notify (G_OBJECT (self), "width");
if (heightu != (old->y2 - old->y1))
g_object_notify (G_OBJECT (self), "height");
}
g_object_thaw_notify (G_OBJECT (self));
}