From c4f27b1556b65464fd1f53749d32db9adab97942 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 7 Oct 2009 16:41:25 +0100 Subject: [PATCH] actor: Add a NO_LAYOUT flag for actors Some actor implementation might avoid imposing any layout on their children. The Actor base class usually assumes some sort of layout management is in place, so it will queue relayouts when, for instance, an actor is shown or is hidden. If the parent of the actor does not impose any layout, though, showing or hiding one of its children will not affect the layout of the others. An example of this kind of container is ClutterGroup. By adding a new Actor flag, CLUTTER_ACTOR_NO_LAYOUT, and by making the Group actor set it on itself, the Actor base class can now decide whether or not to queue a relayout. The flag is not meant to be used by application code, and should only be set when implementing a new container. http://bugzilla.openedhand.com/show_bug.cgi?id=1838 --- clutter/clutter-actor.c | 37 +++++++++++++++++++++++++++---------- clutter/clutter-actor.h | 15 ++++++++++----- clutter/clutter-group.c | 6 ++++++ 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index fcab0b6a1..bfb4d8496 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -74,8 +74,8 @@ * clutter_actor_set_width(); or it can have a preferred width and * height, which then allows a layout manager to implicitly size and * position it by "allocating" an area for an actor. This allows for - * actors to be manipulate in both a fixed or static parent container - * (i.e. children of #ClutterGroup) and a more automatic or dynamic + * actors to be manipulated in both a fixed (or static) parent container + * (i.e. children of #ClutterGroup) and a more automatic (or dynamic) * layout based parent container. * * When accessing the position and size of an actor, the simple accessors @@ -880,6 +880,7 @@ clutter_actor_real_map (ClutterActor *self) g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED); + /* notify on parent mapped before potentially mapping * children, so apps see a top-down notification. */ @@ -993,20 +994,29 @@ clutter_actor_real_show (ClutterActor *self) ClutterActorPrivate *priv = self->priv; CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE); + /* we notify on the "visible" flag in the clutter_actor_show() * wrapper so the entire show signal emission completes first * (?) */ clutter_actor_update_map_state (self, MAP_STATE_CHECK); - /* While an actor is hidden the parent may not have allocated/requested - * so we need to start from scratch and avoid the short-circuiting - * in clutter_actor_queue_relayout(). + /* we queue a relayout unless the actor is inside a + * container that explicitly told us not to */ - priv->needs_width_request = FALSE; - priv->needs_height_request = FALSE; - priv->needs_allocation = FALSE; - clutter_actor_queue_relayout (self); + if (priv->parent_actor && + (!(priv->parent_actor->flags & CLUTTER_ACTOR_NO_LAYOUT))) + { + /* While an actor is hidden the parent may not have + * allocated/requested so we need to start from scratch + * and avoid the short-circuiting in + * clutter_actor_queue_relayout(). + */ + priv->needs_width_request = FALSE; + priv->needs_height_request = FALSE; + priv->needs_allocation = FALSE; + clutter_actor_queue_relayout (self); + } } } @@ -1081,6 +1091,8 @@ clutter_actor_real_hide (ClutterActor *self) { if (CLUTTER_ACTOR_IS_VISIBLE (self)) { + ClutterActorPrivate *priv = self->priv; + CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE); /* we notify on the "visible" flag in the clutter_actor_hide() @@ -1089,7 +1101,12 @@ clutter_actor_real_hide (ClutterActor *self) */ clutter_actor_update_map_state (self, MAP_STATE_CHECK); - clutter_actor_queue_relayout (self); + /* we queue a relayout unless the actor is inside a + * container that explicitly told us not to + */ + if (priv->parent_actor && + (!(priv->parent_actor->flags & CLUTTER_ACTOR_NO_LAYOUT))) + clutter_actor_queue_relayout (priv->parent_actor); } } diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index 2f190a5ed..e1622dd85 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -93,21 +93,26 @@ typedef void (*ClutterCallback) (ClutterActor *actor, /** * ClutterActorFlags: - * @CLUTTER_ACTOR_MAPPED: the actor will be painted (is visible, and inside a toplevel, and all parents visible) + * @CLUTTER_ACTOR_MAPPED: the actor will be painted (is visible, and inside + * a toplevel, and all parents visible) * @CLUTTER_ACTOR_REALIZED: the resources associated to the actor have been * allocated * @CLUTTER_ACTOR_REACTIVE: the actor 'reacts' to mouse events emmitting event * signals * @CLUTTER_ACTOR_VISIBLE: the actor has been shown by the application program + * @CLUTTER_ACTOR_NO_LAYOUT: the actor provides an explicit layout management + * policy for its children; this flag will prevent Clutter from automatic + * queueing of relayout and will defer all layouting to the actor itself * * Flags used to signal the state of an actor. */ typedef enum { - CLUTTER_ACTOR_MAPPED = 1 << 1, - CLUTTER_ACTOR_REALIZED = 1 << 2, - CLUTTER_ACTOR_REACTIVE = 1 << 3, - CLUTTER_ACTOR_VISIBLE = 1 << 4 + CLUTTER_ACTOR_MAPPED = 1 << 1, + CLUTTER_ACTOR_REALIZED = 1 << 2, + CLUTTER_ACTOR_REACTIVE = 1 << 3, + CLUTTER_ACTOR_VISIBLE = 1 << 4, + CLUTTER_ACTOR_NO_LAYOUT = 1 << 5 } ClutterActorFlags; /** diff --git a/clutter/clutter-group.c b/clutter/clutter-group.c index ef3a5a22c..a0ef32c05 100644 --- a/clutter/clutter-group.c +++ b/clutter/clutter-group.c @@ -441,6 +441,12 @@ clutter_group_init (ClutterGroup *self) self->priv->layout = clutter_fixed_layout_new (); g_object_ref_sink (self->priv->layout); + + /* signal Clutter that we don't impose any layout on + * our children, so we can shave off some relayout + * operations + */ + CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_NO_LAYOUT); } /**