actor: Keep track of clones

Instead of using signal notifications, we should be able to keep track
of the clones of an actor from within ClutterActor itself, using private
API. There's no point in pretending that people can actually create a
Clone class out of tree, given the amount of invariants we have to punch
through in order to implement a proper replicator node of the scene
graph, so we can just skip the signal emissions and just do the right
thing at the right time.
This commit is contained in:
Emmanuele Bassi 2013-03-07 18:09:33 +00:00
parent c32973158d
commit 028baa99a0
3 changed files with 91 additions and 26 deletions

View File

@ -312,6 +312,13 @@ ClutterActorAlign _clutter_actor_get_effective_x_align
void _clutter_actor_handle_event (ClutterActor *actor,
const ClutterEvent *event);
void _clutter_actor_attach_clone (ClutterActor *actor,
ClutterActor *clone);
void _clutter_actor_detach_clone (ClutterActor *actor,
ClutterActor *clone);
void _clutter_actor_queue_redraw_on_clones (ClutterActor *actor);
void _clutter_actor_queue_relayout_on_clones (ClutterActor *actor);
G_END_DECLS
#endif /* __CLUTTER_ACTOR_PRIVATE_H__ */

View File

@ -771,7 +771,10 @@ struct _ClutterActorPrivate
gchar *debug_name;
#endif
/* bitfields */
/* a set of clones of the actor */
GHashTable *clones;
/* bitfields: KEEP AT THE END */
/* fixed position and sizes */
guint position_set : 1;
@ -2548,6 +2551,8 @@ _clutter_actor_signal_queue_redraw (ClutterActor *self,
* receive the signal so it can queue its own redraw.
*/
_clutter_actor_queue_redraw_on_clones (self);
/* calls klass->queue_redraw in default handler */
g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
}
@ -5805,6 +5810,12 @@ clutter_actor_dispose (GObject *object)
g_clear_object (&priv->content);
}
if (priv->clones != NULL)
{
g_hash_table_unref (priv->clones);
priv->clones = NULL;
}
G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
}
@ -8791,6 +8802,8 @@ _clutter_actor_queue_only_relayout (ClutterActor *self)
}
#endif /* CLUTTER_ENABLE_DEBUG */
_clutter_actor_queue_relayout_on_clones (self);
g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
}
@ -20128,3 +20141,68 @@ clutter_actor_get_child_transform (ClutterActor *self,
else
clutter_matrix_init_identity (transform);
}
void
_clutter_actor_attach_clone (ClutterActor *actor,
ClutterActor *clone)
{
ClutterActorPrivate *priv = actor->priv;
g_assert (clone != NULL);
if (priv->clones == NULL)
priv->clones = g_hash_table_new (NULL, NULL);
g_hash_table_add (priv->clones, clone);
}
void
_clutter_actor_detach_clone (ClutterActor *actor,
ClutterActor *clone)
{
ClutterActorPrivate *priv = actor->priv;
g_assert (clone != NULL);
if (priv->clones == NULL ||
g_hash_table_lookup (priv->clones, clone) == NULL)
return;
g_hash_table_remove (priv->clones, clone);
if (g_hash_table_size (priv->clones) == 0)
{
g_hash_table_unref (priv->clones);
priv->clones = NULL;
}
}
void
_clutter_actor_queue_redraw_on_clones (ClutterActor *self)
{
ClutterActorPrivate *priv = self->priv;
GHashTableIter iter;
gpointer key;
if (priv->clones == NULL)
return;
g_hash_table_iter_init (&iter, priv->clones);
while (g_hash_table_iter_next (&iter, &key, NULL))
clutter_actor_queue_redraw (key);
}
void
_clutter_actor_queue_relayout_on_clones (ClutterActor *self)
{
ClutterActorPrivate *priv = self->priv;
GHashTableIter iter;
gpointer key;
if (priv->clones == NULL)
return;
g_hash_table_iter_init (&iter, priv->clones);
while (g_hash_table_iter_next (&iter, &key, NULL))
clutter_actor_queue_relayout (key);
}

View File

@ -377,35 +377,18 @@ clutter_clone_new (ClutterActor *source)
return g_object_new (CLUTTER_TYPE_CLONE, "source", source, NULL);
}
static void
clone_source_queue_redraw_cb (ClutterActor *source,
ClutterActor *origin,
ClutterClone *self)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
static void
clone_source_queue_relayout_cb (ClutterActor *source,
ClutterClone *self)
{
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
}
static void
clutter_clone_set_source_internal (ClutterClone *self,
ClutterActor *source)
{
ClutterClonePrivate *priv = self->priv;
if (priv->clone_source == source)
return;
if (priv->clone_source != NULL)
{
g_signal_handlers_disconnect_by_func (priv->clone_source,
G_CALLBACK (clone_source_queue_redraw_cb),
self);
g_signal_handlers_disconnect_by_func (priv->clone_source,
G_CALLBACK (clone_source_queue_relayout_cb),
self);
_clutter_actor_detach_clone (priv->clone_source, CLUTTER_ACTOR (self));
g_object_unref (priv->clone_source);
priv->clone_source = NULL;
}
@ -413,10 +396,7 @@ clutter_clone_set_source_internal (ClutterClone *self,
if (source != NULL)
{
priv->clone_source = g_object_ref (source);
g_signal_connect (priv->clone_source, "queue-redraw",
G_CALLBACK (clone_source_queue_redraw_cb), self);
g_signal_connect (priv->clone_source, "queue-relayout",
G_CALLBACK (clone_source_queue_relayout_cb), self);
_clutter_actor_attach_clone (priv->clone_source, CLUTTER_ACTOR (self));
}
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SOURCE]);