mutter/clutter/clutter-actor-meta.c
Emmanuele Bassi 7c627e1e03 actor-meta: Disconnect on actor destroy
When destroying an Actor the various ActorMeta instance should already
be disposed - unless something is holding a reference to them, in which
case we should use the ::destroy signal to unset the ActorMeta:actor
back pointer.
2010-05-25 11:13:03 +01:00

480 lines
12 KiB
C

/**
* SECTION:clutter-actor-meta
* @Title: ClutterActorMeta
* @Short_Description: Base class of actor modifiers
*
* #ClutterActorMeta is an abstract class providing a common API for
* modifiers of #ClutterActor
*
* A #ClutterActorMeta can only be owned by a single #ClutterActor at
* any time
*
* #ClutterActorMeta is available since Clutter 1.4
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-actor-meta-private.h"
#include "clutter-debug.h"
#include "clutter-private.h"
struct _ClutterActorMetaPrivate
{
ClutterActor *actor;
guint destroy_id;
gchar *name;
guint is_enabled : 1;
};
enum
{
PROP_0,
PROP_ACTOR,
PROP_NAME,
PROP_ENABLED
};
G_DEFINE_ABSTRACT_TYPE (ClutterActorMeta,
clutter_actor_meta,
G_TYPE_INITIALLY_UNOWNED);
static void
on_actor_destroy (ClutterActor *actor,
ClutterActorMeta *meta)
{
meta->priv->actor = NULL;
}
static void
clutter_actor_meta_real_set_actor (ClutterActorMeta *meta,
ClutterActor *actor)
{
if (meta->priv->actor == actor)
return;
if (meta->priv->destroy_id != 0)
g_signal_handler_disconnect (meta->priv->actor, meta->priv->destroy_id);
meta->priv->actor = actor;
if (meta->priv->actor != NULL)
meta->priv->destroy_id = g_signal_connect (meta->priv->actor, "destroy",
G_CALLBACK (on_actor_destroy),
meta);
}
static void
clutter_actor_meta_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
switch (prop_id)
{
case PROP_NAME:
clutter_actor_meta_set_name (meta, g_value_get_string (value));
break;
case PROP_ENABLED:
clutter_actor_meta_set_enabled (meta, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_actor_meta_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
switch (prop_id)
{
case PROP_ACTOR:
g_value_set_object (value, meta->priv->actor);
break;
case PROP_NAME:
g_value_set_string (value, meta->priv->name);
break;
case PROP_ENABLED:
g_value_set_boolean (value, meta->priv->is_enabled);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_actor_meta_finalize (GObject *gobject)
{
ClutterActorMetaPrivate *priv = CLUTTER_ACTOR_META (gobject)->priv;
if (priv->destroy_id != 0 && priv->actor != NULL)
g_signal_handler_disconnect (priv->actor, priv->destroy_id);
g_free (priv->name);
G_OBJECT_CLASS (clutter_actor_meta_parent_class)->finalize (gobject);
}
void
clutter_actor_meta_class_init (ClutterActorMetaClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (ClutterActorMetaPrivate));
klass->set_actor = clutter_actor_meta_real_set_actor;
gobject_class->set_property = clutter_actor_meta_set_property;
gobject_class->get_property = clutter_actor_meta_get_property;
gobject_class->finalize = clutter_actor_meta_finalize;
/**
* ClutterActorMeta:actor:
*
* The #ClutterActor attached to the #ClutterActorMeta instance
*
* Since: 1.4
*/
pspec = g_param_spec_object ("actor",
"Actor",
"The actor attached to the meta",
CLUTTER_TYPE_ACTOR,
CLUTTER_PARAM_READABLE);
g_object_class_install_property (gobject_class, PROP_ACTOR, pspec);
/**
* ClutterActorMeta:name:
*
* The unique name to access the #ClutterActorMeta
*
* Since: 1.4
*/
pspec = g_param_spec_string ("name",
"Name",
"The name of the meta",
NULL,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_NAME, pspec);
/**
* ClutterActorMeta:enabled:
*
* Whether or not the #ClutterActorMeta is enabled
*
* Since: 1.4
*/
pspec = g_param_spec_boolean ("enabled",
"Enabled",
"Whether the meta is enabled",
TRUE,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_ENABLED, pspec);
}
void
clutter_actor_meta_init (ClutterActorMeta *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
CLUTTER_TYPE_ACTOR_META,
ClutterActorMetaPrivate);
self->priv->is_enabled = TRUE;
}
/**
* clutter_actor_meta_set_name:
* @meta: a #ClutterActorMeta
* @name: the name of @meta
*
* Sets the name of @meta
*
* The name can be used to identify the #ClutterActorMeta instance
*
* Since: 1.4
*/
void
clutter_actor_meta_set_name (ClutterActorMeta *meta,
const gchar *name)
{
g_return_if_fail (CLUTTER_IS_ACTOR_META (meta));
if (g_strcmp0 (meta->priv->name, name) == 0)
return;
g_free (meta->priv->name);
meta->priv->name = g_strdup (name);
g_object_notify (G_OBJECT (meta), "name");
}
/**
* clutter_actor_meta_get_name:
* @meta: a #ClutterActorMeta
*
* Retrieves the name set using clutter_actor_meta_set_name()
*
* Return value: (transfer none): the name of the #ClutterActorMeta
* instance, or %NULL if none was set. The returned string is owned
* by the #ClutterActorMeta instance and it should not be modified
* or freed
*
* Since: 1.4
*/
G_CONST_RETURN gchar *
clutter_actor_meta_get_name (ClutterActorMeta *meta)
{
g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), NULL);
return meta->priv->name;
}
/**
* clutter_actor_meta_set_enabled:
* @meta: a #ClutterActorMeta
* @is_enabled: whether @meta is enabled
*
* Sets whether @meta should be enabled or not
*
* Since: 1.4
*/
void
clutter_actor_meta_set_enabled (ClutterActorMeta *meta,
gboolean is_enabled)
{
g_return_if_fail (CLUTTER_IS_ACTOR_META (meta));
is_enabled = !!is_enabled;
if (meta->priv->is_enabled == is_enabled)
return;
meta->priv->is_enabled = is_enabled;
g_object_notify (G_OBJECT (meta), "enabled");
}
/**
* clutter_actor_meta_get_enabled:
* @meta: a #ClutterActorMeta
*
* Retrieves whether @meta is enabled
*
* Return value: %TRUE if the #ClutterActorMeta instance is enabled
*
* Since: 1.4
*/
gboolean
clutter_actor_meta_get_enabled (ClutterActorMeta *meta)
{
g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), FALSE);
return meta->priv->is_enabled;
}
/*
* _clutter_actor_meta_set_actor
* @meta: a #ClutterActorMeta
* @actor: a #ClutterActor or %NULL
*
* Sets or unsets a back pointer to the #ClutterActor that owns
* the @meta
*
* Since: 1.4
*/
void
_clutter_actor_meta_set_actor (ClutterActorMeta *meta,
ClutterActor *actor)
{
g_return_if_fail (CLUTTER_IS_ACTOR_META (meta));
g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
CLUTTER_ACTOR_META_GET_CLASS (meta)->set_actor (meta, actor);
}
/**
* clutter_actor_meta_get_actor:
* @meta: a #ClutterActorMeta
*
* Retrieves a pointer to the #ClutterActor that owns @meta
*
* Return value: (transfer none): a pointer to a #ClutterActor or %NULL
*
* Since: 1.4
*/
ClutterActor *
clutter_actor_meta_get_actor (ClutterActorMeta *meta)
{
g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), NULL);
return meta->priv->actor;
}
/*
* ClutterMetaGroup: a collection of ClutterActorMeta instances
*/
G_DEFINE_TYPE (ClutterMetaGroup, _clutter_meta_group, G_TYPE_OBJECT);
static void
_clutter_meta_group_dispose (GObject *gobject)
{
_clutter_meta_group_clear_metas (CLUTTER_META_GROUP (gobject));
G_OBJECT_CLASS (_clutter_meta_group_parent_class)->dispose (gobject);
}
static void
_clutter_meta_group_class_init (ClutterMetaGroupClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = _clutter_meta_group_dispose;
}
static void
_clutter_meta_group_init (ClutterMetaGroup *self)
{
}
/*
* _clutter_meta_group_add_meta:
* @group: a #ClutterMetaGroup
* @meta: a #ClutterActorMeta to add
*
* Adds @meta to @group
*
* This function will remove the floating reference of @meta or, if the
* floating reference has already been sunk, add a reference to it
*/
void
_clutter_meta_group_add_meta (ClutterMetaGroup *group,
ClutterActorMeta *meta)
{
if (meta->priv->actor != NULL)
{
g_warning ("The meta of type '%s' with name '%s' is "
"already attached to actor '%s'",
G_OBJECT_TYPE_NAME (meta),
meta->priv->name != NULL
? meta->priv->name
: "<unknown>",
clutter_actor_get_name (meta->priv->actor) != NULL
? clutter_actor_get_name (meta->priv->actor)
: G_OBJECT_TYPE_NAME (meta->priv->actor));
return;
}
group->meta = g_list_append (group->meta, meta);
g_object_ref_sink (meta);
_clutter_actor_meta_set_actor (meta, group->actor);
}
/*
* _clutter_meta_group_remove_meta:
* @group: a #ClutterMetaGroup
* @meta: a #ClutterActorMeta to remove
*
* Removes @meta from @group and releases the reference being held on it
*/
void
_clutter_meta_group_remove_meta (ClutterMetaGroup *group,
ClutterActorMeta *meta)
{
if (meta->priv->actor != group->actor)
{
g_warning ("The meta of type '%s' with name '%s' is not "
"attached to the actor '%s'",
G_OBJECT_TYPE_NAME (meta),
meta->priv->name != NULL
? meta->priv->name
: "<unknown>",
clutter_actor_get_name (group->actor) != NULL
? clutter_actor_get_name (group->actor)
: G_OBJECT_TYPE_NAME (group->actor));
return;
}
_clutter_actor_meta_set_actor (meta, NULL);
group->meta = g_list_remove (group->meta, meta);
g_object_unref (meta);
}
/*
* _clutter_meta_group_peek_metas:
* @group: a #ClutterMetaGroup
*
* Returns a pointer to the #ClutterActorMeta list
*
* Return value: a const pointer to the #GList of #ClutterActorMeta
*/
G_CONST_RETURN GList *
_clutter_meta_group_peek_metas (ClutterMetaGroup *group)
{
return group->meta;
}
/*
* _clutter_meta_group_clear_metas:
* @group: a #ClutterMetaGroup
*
* Clears @group of all #ClutterActorMeta instances and releases
* the reference on them
*/
void
_clutter_meta_group_clear_metas (ClutterMetaGroup *group)
{
g_list_foreach (group->meta, (GFunc) _clutter_actor_meta_set_actor, NULL);
g_list_foreach (group->meta, (GFunc) g_object_unref, NULL);
g_list_free (group->meta);
group->meta = NULL;
}
/*
* _clutter_meta_group_get_meta:
* @group: a #ClutterMetaGroup
* @name: the name of the #ClutterActorMeta to retrieve
*
* Retrieves a named #ClutterActorMeta from @group
*
* Return value: a #ClutterActorMeta for the given name, or %NULL
*/
ClutterActorMeta *
_clutter_meta_group_get_meta (ClutterMetaGroup *group,
const gchar *name)
{
GList *l;
for (l = group->meta; l != NULL; l = l->next)
{
ClutterActorMeta *meta = l->data;
if (g_strcmp0 (meta->priv->name, name) == 0)
return meta;
}
return NULL;
}