actor: re-work unrealize to work with composite actors

Unrealizing an actor is a recursive process that needs to traverse the
children of an actor to ensure they are also unrealized. This maintains
the invariant that if any given actor is marked as unrealized then you
know that all its children have also been unrealized.

The previous implementation would use the container interface's
foreach_with_internals vfunc to explicitly traverse the children of
container actors but this didn't consider composite actors that aren't
containers.

Since clutter-actor now maintains an explicit list of children we can
also handle composite actors that aren't containers using
_clutter_actor_traverse.
This commit is contained in:
Robert Bragg 2010-10-20 18:26:01 +01:00 committed by Chris Lord
parent 4bda674732
commit 4752cc38b2

View File

@ -1441,11 +1441,6 @@ clutter_actor_real_unrealize (ClutterActor *self)
{ {
/* we must be unmapped (implying our children are also unmapped) */ /* we must be unmapped (implying our children are also unmapped) */
g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
if (CLUTTER_IS_CONTAINER (self))
clutter_container_foreach_with_internals (CLUTTER_CONTAINER (self),
CLUTTER_CALLBACK (clutter_actor_unrealize_not_hiding),
NULL);
} }
/** /**
@ -1499,6 +1494,34 @@ clutter_actor_unrealize (ClutterActor *self)
clutter_actor_unrealize_not_hiding (self); clutter_actor_unrealize_not_hiding (self);
} }
static ClutterActorTraverseVisitFlags
unrealize_actor_before_children_cb (ClutterActor *self,
int depth,
void *user_data)
{
/* If an actor is already unrealized we know its children have also
* already been unrealized... */
if (!CLUTTER_ACTOR_IS_REALIZED (self))
return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
g_signal_emit (self, actor_signals[UNREALIZE], 0);
return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
}
static ClutterActorTraverseVisitFlags
unrealize_actor_after_children_cb (ClutterActor *self,
int depth,
void *user_data)
{
/* We want to unset the realized flag only _after_
* child actors are unrealized, to maintain invariants.
*/
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
_clutter_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
}
/* /*
* clutter_actor_unrealize_not_hiding: * clutter_actor_unrealize_not_hiding:
* @self: A #ClutterActor * @self: A #ClutterActor
@ -1526,25 +1549,11 @@ clutter_actor_unrealize (ClutterActor *self)
static void static void
clutter_actor_unrealize_not_hiding (ClutterActor *self) clutter_actor_unrealize_not_hiding (ClutterActor *self)
{ {
/* All callers of clutter_actor_unrealize_not_hiding() should have _clutter_actor_traverse (self,
* taken care of unmapping the actor first. This means CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
* all our children should also be unmapped. unrealize_actor_before_children_cb,
*/ unrealize_actor_after_children_cb,
g_assert (!CLUTTER_ACTOR_IS_MAPPED (self)); NULL);
if (!CLUTTER_ACTOR_IS_REALIZED (self))
return;
/* The default handler for the signal should recursively unrealize
* child actors. We want to unset the realized flag only _after_
* child actors are unrealized, to maintain invariants.
*/
g_signal_emit (self, actor_signals[UNREALIZE], 0);
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
_clutter_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
} }
/* /*