revert changes

This commit is contained in:
Emmanuele Bassi
2006-09-08 20:57:31 +00:00
parent ba32170d94
commit 4dea33e123
7 changed files with 475 additions and 1070 deletions

View File

@ -31,154 +31,156 @@
#include "config.h"
#include <string.h>
#include <gobject/gobjectnotifyqueue.c>
#include "clutter-actor.h"
#include "clutter-behaviour.h"
#include "clutter-marshal.h"
struct _ClutterBehaviourPrivate
{
ClutterAlpha *alpha;
G_DEFINE_TYPE (ClutterBehaviour, clutter_behaviour, G_TYPE_OBJECT);
GSList *actors;
struct ClutterBehaviourPrivate
{
GObject *object;
GParamSpec *param_spec;
guint notify_id;
GSList *actors;
};
enum
{
PROP_0,
PROP_ALPHA
PROP_OBJECT,
PROP_PROPERTY
};
enum
{
NOTIFY_BEHAVIOUR,
enum {
SIGNAL_PROPERTY_CHANGE,
SIGNAL_LAST
};
static GObjectClass *clutter_behaviour_parent_class = NULL;
static GParamSpecPool *pspec_pool = NULL;
static GObjectNotifyContext property_notify_context = { 0, };
static guint behaviour_signals[SIGNAL_LAST] = { 0, };
static GQuark quark_property_bridge = 0;
static guint signals[SIGNAL_LAST];
#define CLUTTER_BEHAVIOUR_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
CLUTTER_TYPE_BEHAVIOUR, \
ClutterBehaviourPrivate))
static void
clutter_behaviour_dispatch_property_changed (ClutterBehaviour *behaviour,
guint n_pspecs,
GParamSpec **pspecs)
static void
_clutter_behaviour_dispose (GObject *object)
{
guint i;
ClutterBehaviour *self = CLUTTER_BEHAVIOUR(object);
for (i = 0; i < n_pspecs; i++)
if (self->priv)
{
g_signal_emit (behaviour,
behaviour_signals[NOTIFY_BEHAVIOUR],
g_quark_from_string (pspecs[i]->name),
pspecs[i]);
}
}
/* FIXME: remove all actors */
static void
clutter_behaviour_base_finalize (ClutterBehaviourClass *klass)
{
GList *list, *node;
list = g_param_spec_pool_list_owned (pspec_pool,
G_OBJECT_CLASS_TYPE (klass));
for (node = list; node != NULL; node = node->next)
{
GParamSpec *pspec = node->data;
g_param_spec_pool_remove (pspec_pool, pspec);
g_param_spec_unref (pspec);
clutter_behaviour_set_object (self, NULL);
}
g_list_free (list);
G_OBJECT_CLASS (clutter_behaviour_parent_class)->dispose (object);
}
static void
clutter_behaviour_finalize (GObject *object)
_clutter_behaviour_finalize (GObject *object)
{
ClutterBehaviour *self = CLUTTER_BEHAVIOUR (object);
ClutterBehaviour *self = CLUTTER_BEHAVIOUR(object);
if (self->priv->alpha)
g_object_unref (self->priv->alpha);
if (self->priv->actors)
if (self->priv)
{
g_slist_foreach (self->priv->actors,
(GFunc) g_object_unref,
NULL);
g_slist_free (self->priv->actors);
g_free(self->priv);
self->priv = NULL;
}
G_OBJECT_CLASS (clutter_behaviour_parent_class)->finalize (object);
}
static void
clutter_behaviour_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
_clutter_behaviour_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterBehaviour *behaviour;
behaviour = CLUTTER_BEHAVIOUR(object);
switch (prop_id)
{
case PROP_OBJECT:
clutter_behaviour_set_object (behaviour, g_value_get_object (value));
break;
case PROP_PROPERTY:
clutter_behaviour_set_property (behaviour, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
}
static void
clutter_behaviour_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
_clutter_behaviour_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterBehaviour *behaviour;
ClutterBehaviourPrivate *priv;
behaviour = CLUTTER_BEHAVIOUR(object);
priv = CLUTTER_BEHAVIOUR_GET_PRIVATE(behaviour);
switch (prop_id)
{
case PROP_OBJECT:
g_value_set_object (value, priv->object);
break;
case PROP_PROPERTY:
g_value_set_string (value, priv->param_spec->name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
property_notify_dispatcher (GObject *object,
guint n_pspecs,
GParamSpec **pspecs)
{
CLUTTER_BEHAVIOUR_GET_CLASS (object)->dispatch_property_changed (CLUTTER_BEHAVIOUR (object), n_pspecs, pspecs);
}
static void
clutter_behaviour_class_init (ClutterBehaviourClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class = (GObjectClass*) klass;
clutter_behaviour_parent_class = g_type_class_peek_parent (klass);
pspec_pool = g_param_spec_pool_new (FALSE);
property_notify_context.quark_notify_queue =
g_quark_from_static_string ("ClutterBehaviour-notify-queue");
property_notify_context.dispatcher =
property_notify_dispatcher;
quark_property_bridge = g_quark_from_static_string ("clutter-property-bridge");
object_class->finalize = _clutter_behaviour_finalize;
object_class->dispose = _clutter_behaviour_dispose;
object_class->set_property = _clutter_behaviour_set_property;
object_class->get_property = _clutter_behaviour_get_property;
object_class->finalize = clutter_behaviour_finalize;
object_class->set_property = clutter_behaviour_set_property;
object_class->get_property = clutter_behaviour_get_property;
g_object_class_install_property
(object_class, PROP_OBJECT,
g_param_spec_object ("object",
"Object",
"Object whose property to monitor",
G_TYPE_OBJECT,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
klass->dispatch_property_changed = clutter_behaviour_dispatch_property_changed;
g_object_class_install_property
(object_class, PROP_PROPERTY,
g_param_spec_string ("property",
"Property",
"Property to monitor",
NULL,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
signals[SIGNAL_PROPERTY_CHANGE] =
g_signal_new ("property-change",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterBehaviourClass, property_change),
NULL, NULL,
clutter_marshal_VOID__OBJECT_POINTER,
G_TYPE_NONE,
2, G_TYPE_OBJECT, G_TYPE_POINTER);
g_type_class_add_private (object_class, sizeof (ClutterBehaviourPrivate));
}
@ -189,415 +191,157 @@ clutter_behaviour_init (ClutterBehaviour *self)
ClutterBehaviourPrivate *priv;
self->priv = priv = CLUTTER_BEHAVIOUR_GET_PRIVATE (self);
priv->actors = NULL;
}
GType
clutter_behaviour_get_type (void)
ClutterBehaviour*
clutter_behaviour_new (GObject *object,
const char *property)
{
static GType behaviour_type = 0;
ClutterBehaviour *behave;
if (G_UNLIKELY (behaviour_type == 0))
{
const GTypeInfo behaviour_info =
{
sizeof (ClutterBehaviourClass),
NULL, /* base init */
(GBaseFinalizeFunc) clutter_behaviour_base_finalize,
(GClassInitFunc) clutter_behaviour_class_init,
NULL,
NULL,
sizeof (ClutterBehaviour),
0,
(GInstanceInitFunc) clutter_behaviour_init,
NULL,
};
behave = g_object_new (CLUTTER_TYPE_BEHAVIOUR,
"object", object,
"property", property,
NULL);
behaviour_type =
g_type_register_static (G_TYPE_OBJECT, "ClutterBehaviour",
&behaviour_info,
G_TYPE_FLAG_ABSTRACT);
}
return behaviour_type;
}
/**
* clutter_behaviour_apply:
* @behaviour: a #ClutterBehaviour
* @actor: a #ClutterActor
*
* Applies @behaviour to @actor.
*
* This function holds a reference on @actor.
*
* Since: 0.2
*/
void
clutter_behaviour_apply (ClutterBehaviour *behaviour,
ClutterActor *actor)
{
g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behaviour));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
if (g_slist_find (behaviour->priv->actors, actor))
{
g_warning ("The behaviour of type `%s' has already been "
"applied to the actor of type `%s'",
G_OBJECT_TYPE_NAME (behaviour),
G_OBJECT_TYPE_NAME (actor));
return;
}
g_object_ref (behaviour);
g_object_freeze_notify (G_OBJECT (behaviour));
g_object_ref (actor);
behaviour->priv->actors = g_slist_append (behaviour->priv->actors, actor);
g_object_thaw_notify (G_OBJECT (behaviour));
g_object_unref (behaviour);
}
/**
* clutter_behaviour_remove:
* @behaviour: a #ClutterBehaviour
* @actor: a #ClutterActor
*
* Removes @behaviour from the list of behaviours
* applied to @actor.
*
* This function removes a reference on @actor.
*
* Since: 0.2
*/
void
clutter_behaviour_remove (ClutterBehaviour *behaviour,
ClutterActor *actor)
{
g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behaviour));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
g_object_ref (behaviour);
g_object_freeze_notify (G_OBJECT (behaviour));
if (g_slist_find (behaviour->priv->actors, (gconstpointer) actor))
{
behaviour->priv->actors = g_slist_remove (behaviour->priv->actors, actor);
g_object_unref (actor);
}
else
{
g_warning ("The behaviour of type `%s' was not applied "
"to the actor of type `%s'",
G_OBJECT_TYPE_NAME (behaviour),
G_OBJECT_TYPE_NAME (actor));
}
g_object_thaw_notify (G_OBJECT (behaviour));
g_object_unref (behaviour);
}
/**
* clutter_behaviour_actors_foreach:
* @behaviour: a #ClutterBehaviour
* @func: the function you want to apply to all #ClutterActor objects
* @data: data to be passed to @func
*
* Applies @func to all the actors bound to @behaviour.
*
* Since: 0.2
*/
void
clutter_behaviour_actors_foreach (ClutterBehaviour *behaviour,
GFunc func,
gpointer data)
{
g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behaviour));
g_return_if_fail (func != NULL);
g_slist_foreach (behaviour->priv->actors, func, data);
}
/**
* clutter_behaviour_get_actors:
* @behaviour: a #ClutterBehaviour
*
* Gets the list of all #ClutterActor objects bound to @behaviour.
*
* Return value: a GSList with all the actors. The elements of
* the list are owned by the #ClutterBehaviour and should not
* be freed or modified. You should free the list when done.
*
* Since: 0.2
*/
GSList *
clutter_behaviour_get_actors (ClutterBehaviour *behaviour)
{
GSList *retval, *l;
g_return_val_if_fail (CLUTTER_IS_ACTOR (behaviour), NULL);
retval = NULL;
for (l = behaviour->priv->actors; l != NULL; l = l->next)
retval = g_slist_prepend (retval, l->data);
return g_slist_reverse (retval);
}
typedef struct
{
GType actor_type;
gchar *actor_property;
ClutterAlphaTransform transform_func;
} BridgeData;
static void
bridge_data_free (BridgeData *data)
{
g_free (data->actor_property);
g_slice_free (BridgeData, data);
}
static void
clutter_behaviour_apply_value (ClutterBehaviour *behaviour,
GType actor_type,
const gchar *actor_property,
const GValue *value)
{
GSList *l;
for (l = behaviour->priv->actors; l != NULL; l = l->next)
{
ClutterActor *actor = l->data;
if (G_OBJECT_TYPE (actor) == actor_type)
{
g_object_set_property (G_OBJECT (actor),
actor_property,
value);
}
}
}
static void
alpha_notify_func (ClutterAlpha *alpha,
GParamSpec *alpha_pspec,
ClutterBehaviour *behaviour)
{
ClutterBehaviourClass *klass;
GParamSpec **pspecs;
guint n_pspecs, i;
GValue alpha_value = { 0, };
klass = CLUTTER_BEHAVIOUR_GET_CLASS (behaviour);
g_value_init (&alpha_value, G_TYPE_UINT);
g_value_set_uint (&alpha_value, clutter_alpha_get_value (alpha));
pspecs = clutter_behaviour_class_list_properties (klass, &n_pspecs);
for (i = 0; i < n_pspecs; i++)
{
BridgeData *data;
GParamSpec *redirect;
GValue transform_value = { 0, };
gboolean res;
redirect = g_param_spec_get_redirect_target (pspecs[i]);
if (!redirect)
redirect = pspecs[i];
data = g_param_spec_get_qdata (redirect, quark_property_bridge);
g_assert (data != NULL);
res = data->transform_func (behaviour, redirect,
&alpha_value,
&transform_value);
if (!res)
continue;
clutter_behaviour_apply_value (behaviour,
data->actor_type,
data->actor_property,
&transform_value);
}
g_free (pspecs);
return behave;
}
void
clutter_behaviour_set_alpha (ClutterBehaviour *behaviour,
ClutterAlpha *alpha)
clutter_behaviour_apply (ClutterBehaviour *behave, ClutterActor *actor)
{
ClutterBehaviourPrivate *priv;
g_return_if_fail (actor != NULL);
g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behaviour));
g_return_if_fail (alpha == NULL || CLUTTER_IS_ALPHA (alpha));
priv = behaviour->priv;
if (priv->alpha == alpha)
if (g_slist_find (behave->priv->actors, (gconstpointer)actor))
return;
g_object_ref (behaviour);
if (priv->alpha)
{
g_signal_handlers_disconnect_by_func (priv->alpha,
alpha_notify_func,
behaviour);
g_object_unref (priv->alpha);
priv->alpha = NULL;
}
if (alpha)
{
priv->alpha = alpha;
g_object_ref_sink (priv->alpha);
g_signal_connect (priv->alpha, "notify::alpha",
G_CALLBACK (alpha_notify_func),
behaviour);
}
g_object_notify (G_OBJECT (behaviour), "alpha");
g_object_unref (behaviour);
g_object_ref (actor);
behave->priv->actors = g_slist_append (behave->priv->actors, actor);
}
ClutterAlpha *
clutter_behaviour_get_alpha (ClutterBehaviour *behaviour)
{
g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR (behaviour), NULL);
if (behaviour->priv->alpha)
return g_object_ref (behaviour->priv->alpha);
return NULL;
}
/**
* clutter_behaviour_class_bind_property:
* @klass: a #ClutterBehaviourClass
* @actor_type: the type of the actor's class
* @actor_property: the name of the actor's class property
* @pspec: a #GParamSpec
*
* FIXME
*
* Since: 0.2
*/
void
clutter_behaviour_class_bind_property (ClutterBehaviourClass *klass,
GType actor_type,
const gchar *actor_property,
ClutterAlphaTransform func)
clutter_behaviour_remove (ClutterBehaviour *behave, ClutterActor *actor)
{
GParamSpec *overridden, *pspec;
GObjectClass *actor_class;
BridgeData *bridge_data;
g_return_if_fail (actor != NULL);
g_return_if_fail (CLUTTER_IS_BEHAVIOUR_CLASS (klass));
g_return_if_fail (actor_type != G_TYPE_INVALID);
g_return_if_fail (actor_property != NULL);
g_return_if_fail (func != NULL);
actor_class = g_type_class_ref (actor_type);
if (!actor_class)
if (g_slist_find (behave->priv->actors, (gconstpointer)actor))
{
g_warning (G_STRLOC ": unable to find class `%s'",
g_type_name (actor_type));
return;
g_object_unref (actor);
behave->priv->actors = g_slist_remove (behave->priv->actors, actor);
}
pspec = g_object_class_find_property (actor_class, actor_property);
if (!pspec)
{
g_warning (G_STRLOC ": objects of class `%s' do not have a "
"property called `%s'",
g_type_name (actor_type),
actor_property);
}
g_type_class_unref (actor_class);
overridden = g_param_spec_override (pspec->name, pspec);
bridge_data = g_slice_new (BridgeData);
bridge_data->actor_type = actor_type;
bridge_data->actor_property = g_strdup (actor_property);
bridge_data->transform_func = func;
g_param_spec_ref (overridden);
g_param_spec_set_qdata_full (overridden, quark_property_bridge,
bridge_data,
(GDestroyNotify) bridge_data_free);
g_param_spec_pool_insert (pspec_pool, overridden, G_OBJECT_CLASS_TYPE (klass));
}
/**
* clutter_behaviour_class_list_properties:
* @klass: a #ClutterBehaviourClass
* @n_pspecs: return location for the number of properties found
*
* FIXME
*
* Return value: an allocated list of #GParamSpec objects. Use
* g_free() on the returned value when done.
*
* Since: 0.2
*/
GParamSpec **
clutter_behaviour_class_list_properties (ClutterBehaviourClass *klass,
guint *n_pspecs)
void
clutter_behaviour_remove_all (ClutterBehaviour *behave)
{
GParamSpec **pspecs;
guint n;
pspecs = g_param_spec_pool_list (pspec_pool,
G_OBJECT_CLASS_TYPE (klass),
&n);
if (n_pspecs)
*n_pspecs = n;
return pspecs;
/* tofix */
}
/**
* clutter_behaviour_class_find_property:
* @klass: a #ClutterBehaviourClass
* @property_name: the name of the property
*
* FIXME
*
* Return value: a #GParamSpec or %NULL
*
* Since: 0.2
*/
GParamSpec *
clutter_behaviour_class_find_property (ClutterBehaviourClass *klass,
const gchar *property_name)
void
clutter_behaviour_actors_foreach (ClutterBehaviour *behave,
GFunc func,
gpointer userdata)
{
GParamSpec *pspec;
GParamSpec *redirect;
g_slist_foreach (behave->priv->actors, func, userdata);
}
g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_CLASS (klass), NULL);
g_return_val_if_fail (property_name != NULL, NULL);
GObject*
clutter_behaviour_get_object (ClutterBehaviour *behave)
{
return behave->priv->object;
}
pspec = g_param_spec_pool_lookup (pspec_pool,
property_name,
G_OBJECT_CLASS_TYPE (klass),
TRUE);
if (pspec)
void
clutter_behaviour_set_object (ClutterBehaviour *behave,
GObject *object)
{
ClutterBehaviourPrivate *priv;
const char *property;
priv = CLUTTER_BEHAVIOUR_GET_PRIVATE(behave);
if (priv->object)
{
redirect = g_param_spec_get_redirect_target (pspec);
if (redirect)
return redirect;
else
return pspec;
property = clutter_behaviour_get_property (behave);
clutter_behaviour_set_property (behave, NULL);
g_object_unref(priv->object);
priv->object = NULL;
}
else
property = NULL;
if (object)
{
priv->object = g_object_ref(object);
if (property)
clutter_behaviour_set_property (behave, property);
}
}
const char *
clutter_behaviour_get_property (ClutterBehaviour *behave)
{
if (behave->priv->param_spec)
return behave->priv->param_spec->name;
else
return NULL;
}
GParamSpec *
clutter_behaviour_get_param_spec (ClutterBehaviour *behave)
{
return behave->priv->param_spec;
}
static void
notify_cb (GObject *object,
GParamSpec *param_spec,
ClutterBehaviour *behave)
{
g_signal_emit (behave,
signals[SIGNAL_PROPERTY_CHANGE],
0,
object,
param_spec);
}
void
clutter_behaviour_set_property (ClutterBehaviour *behave,
const char *property)
{
g_return_if_fail (behave->priv->object);
if (behave->priv->notify_id)
{
g_signal_handler_disconnect (behave->priv->object,
behave->priv->notify_id);
behave->priv->notify_id = 0;
}
behave->priv->param_spec = NULL;
if (property)
{
guint signal_id;
GClosure *closure;
behave->priv->param_spec =
g_object_class_find_property (G_OBJECT_GET_CLASS (behave->priv->object),
property);
g_return_if_fail (behave->priv->param_spec);
signal_id = g_signal_lookup ("notify",
G_OBJECT_TYPE (behave->priv->object));
closure = g_cclosure_new ((GCallback) notify_cb, behave, NULL);
behave->priv->notify_id =
g_signal_connect_closure_by_id (behave->priv->object,
signal_id,
g_quark_from_string (property),
closure,
FALSE);
}
}