2006-12-08 Emmanuele Bassi <ebassi@openedhand.com>

* clutter/clutter-behaviour.h: Add a function prototype
	for the foreach function: we need something more specific
	than GFunc; add clutter_behaviour_get_actors(), used to
	get a list of the actors.

	* clutter/clutter-behaviour.c: Add debugging notes; add
	a warning for behaviour implementations missing the
	alpha_notify vfunc; add api documentation

	* clutter/clutter-behaviour-opacity.c:
	* clutter/clutter-behaviour-path.c:
	* clutter/clutter-behaviour-scale.c: Reimplement the
	alpha_notify functions using the new foreach function
	and, where possible, by directly iterating on the
	actors: this shaves off the number of recalculations
	of the property/alpha values, and the number of
	functions.
This commit is contained in:
Emmanuele Bassi 2006-12-08 16:12:52 +00:00
parent a56ea84dd5
commit aa623df78f
9 changed files with 242 additions and 71 deletions

View File

@ -1,3 +1,23 @@
2006-12-08 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-behaviour.h: Add a function prototype
for the foreach function: we need something more specific
than GFunc; add clutter_behaviour_get_actors(), used to
get a list of the actors.
* clutter/clutter-behaviour.c: Add debugging notes; add
a warning for behaviour implementations missing the
alpha_notify vfunc; add api documentation
* clutter/clutter-behaviour-opacity.c:
* clutter/clutter-behaviour-path.c:
* clutter/clutter-behaviour-scale.c: Reimplement the
alpha_notify functions using the new foreach function
and, where possible, by directly iterating on the
actors: this shaves off the number of recalculations
of the property/alpha values, and the number of
functions.
2006-12-05 Emmanuele Bassi <ebassi@openedhand.com> 2006-12-05 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-rectangle.c: Forgot to set the * clutter/clutter-rectangle.c: Forgot to set the

View File

@ -78,37 +78,36 @@ enum
PROP_OPACITY_END PROP_OPACITY_END
}; };
static void
opacity_frame_foreach (ClutterActor *actor,
ClutterBehaviourOpacity *behave)
{
guint32 alpha;
guint8 opacity;
ClutterBehaviourOpacityPrivate *priv;
ClutterBehaviour *_behave;
priv = CLUTTER_BEHAVIOUR_OPACITY_GET_PRIVATE (behave);
_behave = CLUTTER_BEHAVIOUR (behave);
alpha = clutter_alpha_get_alpha (clutter_behaviour_get_alpha (_behave));
opacity = (alpha * (priv->opacity_end - priv->opacity_start))
/ CLUTTER_ALPHA_MAX_ALPHA;
opacity += priv->opacity_start;
CLUTTER_NOTE (BEHAVIOUR, "alpha %i opacity %i\n", alpha, opacity);
clutter_actor_set_opacity (actor, opacity);
}
static void static void
clutter_behaviour_alpha_notify (ClutterBehaviour *behave, clutter_behaviour_alpha_notify (ClutterBehaviour *behave,
guint32 alpha_value) guint32 alpha_value)
{ {
clutter_behaviour_actors_foreach (behave, GSList *actors, *l;
(GFunc) opacity_frame_foreach, guint8 opacity;
CLUTTER_BEHAVIOUR_OPACITY (behave)); ClutterBehaviourOpacityPrivate *priv;
priv = CLUTTER_BEHAVIOUR_OPACITY (behave)->priv;
actors = clutter_behaviour_get_actors (behave);
if (!actors)
return;
opacity = alpha_value
* (priv->opacity_end - priv->opacity_start)
/ CLUTTER_ALPHA_MAX_ALPHA;
CLUTTER_NOTE (BEHAVIOUR, "alpha: %i, opacity: %i",
alpha_value,
opacity);
for (l = actors; l; l = l->next)
{
ClutterActor *actor = l->data;
clutter_actor_set_opacity (actor, opacity);
}
g_slist_free (actors);
} }
static void static void

View File

@ -184,9 +184,12 @@ path_total_length (ClutterBehaviourPath *behave)
} }
static void static void
actor_apply_knot_foreach (ClutterActor *actor, actor_apply_knot_foreach (ClutterBehaviour *behaviour,
ClutterKnot *knot) ClutterActor *actor,
gpointer data)
{ {
ClutterKnot *knot = data;
clutter_actor_set_position (actor, knot->x, knot->y); clutter_actor_set_position (actor, knot->x, knot->y);
} }
@ -217,7 +220,7 @@ path_alpha_to_position (ClutterBehaviourPath *behave,
if (offset == 0) if (offset == 0)
{ {
clutter_behaviour_actors_foreach (behaviour, clutter_behaviour_actors_foreach (behaviour,
(GFunc) actor_apply_knot_foreach, actor_apply_knot_foreach,
priv->knots->data); priv->knots->data);
g_signal_emit (behave, path_signals[KNOT_REACHED], 0, g_signal_emit (behave, path_signals[KNOT_REACHED], 0,
@ -245,7 +248,7 @@ path_alpha_to_position (ClutterBehaviourPath *behave,
interpolate (knot, next, &new, t); interpolate (knot, next, &new, t);
clutter_behaviour_actors_foreach (behaviour, clutter_behaviour_actors_foreach (behaviour,
(GFunc)actor_apply_knot_foreach, actor_apply_knot_foreach,
&new); &new);
g_signal_emit (behave, path_signals[KNOT_REACHED], 0, &new); g_signal_emit (behave, path_signals[KNOT_REACHED], 0, &new);

View File

@ -81,30 +81,15 @@ enum
}; };
static void static void
scale_frame_foreach (ClutterActor *actor, scale_frame_foreach (ClutterBehaviour *behaviour,
ClutterBehaviourScale *behave) ClutterActor *actor,
gpointer data)
{ {
ClutterFixed scale, factor; ClutterBehaviourScalePrivate *priv;
guint32 alpha; gint sw, sh, w, h;
ClutterBehaviourScalePrivate *priv; guint scale = GPOINTER_TO_UINT (data);
ClutterBehaviour *_behave;
gint sw, sh, w, h;
priv = CLUTTER_BEHAVIOUR_SCALE_GET_PRIVATE (behave); priv = CLUTTER_BEHAVIOUR_SCALE (behaviour)->priv;
_behave = CLUTTER_BEHAVIOUR (behave);
alpha = clutter_alpha_get_alpha (clutter_behaviour_get_alpha (_behave));
/* FIXME: use all fixed if possible
factor = CLUTTER_FIXED_DIV(CLUTTER_INT_TO_FIXED(alpha/2),
CLUTTER_INT_TO_FIXED(CLUTTER_ALPHA_MAX_ALPHA/2));
*/
factor = CLUTTER_FLOAT_TO_FIXED ((gdouble) alpha / CLUTTER_ALPHA_MAX_ALPHA);
scale = CLUTTER_FIXED_MUL (factor, (priv->scale_end - priv->scale_begin));
scale += priv->scale_begin;
clutter_actor_set_scalex (actor, scale, scale); clutter_actor_set_scalex (actor, scale, scale);
@ -143,9 +128,24 @@ static void
clutter_behaviour_scale_alpha_notify (ClutterBehaviour *behave, clutter_behaviour_scale_alpha_notify (ClutterBehaviour *behave,
guint32 alpha_value) guint32 alpha_value)
{ {
ClutterFixed scale, factor;
ClutterBehaviourScalePrivate *priv;
priv = CLUTTER_BEHAVIOUR_SCALE (behave)->priv;
/* FIXME: use all fixed if possible
factor = CLUTTER_FIXED_DIV(CLUTTER_INT_TO_FIXED(alpha/2),
CLUTTER_INT_TO_FIXED(CLUTTER_ALPHA_MAX_ALPHA/2));
*/
factor = CLUTTER_FLOAT_TO_FIXED ((gdouble) alpha_value / CLUTTER_ALPHA_MAX_ALPHA);
scale = CLUTTER_FIXED_MUL (factor, (priv->scale_end - priv->scale_begin));
scale += priv->scale_begin;
clutter_behaviour_actors_foreach (behave, clutter_behaviour_actors_foreach (behave,
(GFunc) scale_frame_foreach, scale_frame_foreach,
CLUTTER_BEHAVIOUR_SCALE (behave)); GUINT_TO_POINTER (scale));
} }
static void static void

View File

@ -144,6 +144,13 @@ clutter_behaviour_get_property (GObject *object,
} }
} }
static void
clutter_behaviour_alpha_notify_unimplemented (ClutterBehaviour *behaviour,
guint32 alpha_value)
{
g_warning ("ClutterBehaviourClass::alpha_notify not implemented for `%s'",
g_type_name (G_TYPE_FROM_INSTANCE (behaviour)));
}
static void static void
clutter_behaviour_class_init (ClutterBehaviourClass *klass) clutter_behaviour_class_init (ClutterBehaviourClass *klass)
@ -163,6 +170,8 @@ clutter_behaviour_class_init (ClutterBehaviourClass *klass)
G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT |
CLUTTER_PARAM_READWRITE)); CLUTTER_PARAM_READWRITE));
klass->alpha_notify = clutter_behaviour_alpha_notify_unimplemented;
g_type_class_add_private (klass, sizeof (ClutterBehaviourPrivate)); g_type_class_add_private (klass, sizeof (ClutterBehaviourPrivate));
} }
@ -175,6 +184,16 @@ clutter_behaviour_init (ClutterBehaviour *self)
} }
/**
* clutter_behaviour_apply:
* @behave: a #ClutterBehaviour
* @actor: a #ClutterActor
*
* Applies @behave to @actor. This function adds a reference on
* the actor.
*
* Since: 0.2
*/
void void
clutter_behaviour_apply (ClutterBehaviour *behave, clutter_behaviour_apply (ClutterBehaviour *behave,
ClutterActor *actor) ClutterActor *actor)
@ -195,6 +214,16 @@ clutter_behaviour_apply (ClutterBehaviour *behave,
behave->priv->actors = g_slist_prepend (behave->priv->actors, actor); behave->priv->actors = g_slist_prepend (behave->priv->actors, actor);
} }
/**
* clutter_behaviour_remove:
* @behave: a #ClutterBehaviour
* @actor: a #ClutterActor
*
* Removes @actor from the list of #ClutterActor<!-- -->s to which
* @behave applies. This function removes a reference on the actor.
*
* Since: 0.2
*/
void void
clutter_behaviour_remove (ClutterBehaviour *behave, clutter_behaviour_remove (ClutterBehaviour *behave,
ClutterActor *actor) ClutterActor *actor)
@ -215,17 +244,47 @@ clutter_behaviour_remove (ClutterBehaviour *behave,
behave->priv->actors = g_slist_remove (behave->priv->actors, actor); behave->priv->actors = g_slist_remove (behave->priv->actors, actor);
} }
/**
* clutter_behaviour_actors_foreach:
* @behave: a #ClutterBehaviour
* @func: a function called for each actor
* @data: optional data to be passed to the function, or %NULL
*
* Calls @func for every actor driven by @behave.
*
* Since: 0.2
*/
void void
clutter_behaviour_actors_foreach (ClutterBehaviour *behave, clutter_behaviour_actors_foreach (ClutterBehaviour *behave,
GFunc func, ClutterBehaviourForeachFunc func,
gpointer userdata) gpointer data)
{ {
GSList *l;
g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behave)); g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behave));
g_return_if_fail (func != NULL); g_return_if_fail (func != NULL);
g_slist_foreach (behave->priv->actors, func, userdata); for (l = behave->priv->actors; l != NULL; l = l->next)
{
ClutterActor *actor = l->data;
g_assert (CLUTTER_IS_ACTOR (actor));
func (behave, actor, data);
}
} }
/**
* clutter_behaviour_get_alpha:
* @behave: a #ClutterBehaviour
*
* Retrieves the #ClutterAlpha object bound to @behave.
*
* Return value: a #ClutterAlpha object, or %NULL if no alpha
* object has been bound to this behaviour.
*
* Since: 0.2
*/
ClutterAlpha* ClutterAlpha*
clutter_behaviour_get_alpha (ClutterBehaviour *behave) clutter_behaviour_get_alpha (ClutterBehaviour *behave)
{ {
@ -243,16 +302,36 @@ notify_cb (GObject *object,
klass = CLUTTER_BEHAVIOUR_GET_CLASS (behave); klass = CLUTTER_BEHAVIOUR_GET_CLASS (behave);
CLUTTER_NOTE (BEHAVIOUR, "notify::alpha");
if (klass->alpha_notify) if (klass->alpha_notify)
{ {
guint32 alpha_value; guint32 alpha_value;
alpha_value = clutter_alpha_get_alpha (behave->priv->alpha); alpha_value = clutter_alpha_get_alpha (behave->priv->alpha);
CLUTTER_NOTE (BEHAVIOUR, "calling %s::alpha_notify (%p, %d)",
g_type_name (G_TYPE_FROM_CLASS (klass)),
behave, alpha_value);
klass->alpha_notify (behave, alpha_value); klass->alpha_notify (behave, alpha_value);
} }
} }
/**
* clutter_behaviour_set_alpha:
* @behave: a #ClutterBehaviour
* @alpha: a #ClutterAlpha or %NULL to unset a previously set alpha
*
* Binds @alpha to a #ClutterBehaviour. The #ClutterAlpha object
* is what makes a behaviour work: for each tick of the timeline
* used by #ClutterAlpha a new value of the alpha parameter is
* computed by the alpha function; the value should be used by
* the #ClutterBehaviour to update one or more properties of the
* actors to which the behaviour applies.
*
* Since: 0.2
*/
void void
clutter_behaviour_set_alpha (ClutterBehaviour *behave, clutter_behaviour_set_alpha (ClutterBehaviour *behave,
ClutterAlpha *alpha) ClutterAlpha *alpha)
@ -266,12 +345,17 @@ clutter_behaviour_set_alpha (ClutterBehaviour *behave,
if (priv->notify_id) if (priv->notify_id)
{ {
CLUTTER_NOTE (BEHAVIOUR, "removing previous notify-id (%d)",
priv->notify_id);
g_signal_handler_disconnect (priv->alpha, priv->notify_id); g_signal_handler_disconnect (priv->alpha, priv->notify_id);
priv->notify_id = 0; priv->notify_id = 0;
} }
if (priv->alpha) if (priv->alpha)
{ {
CLUTTER_NOTE (BEHAVIOUR, "removing previous alpha object");
g_object_unref (priv->alpha); g_object_unref (priv->alpha);
priv->alpha = NULL; priv->alpha = NULL;
} }
@ -284,5 +368,33 @@ clutter_behaviour_set_alpha (ClutterBehaviour *behave,
priv->notify_id = g_signal_connect (priv->alpha, "notify::alpha", priv->notify_id = g_signal_connect (priv->alpha, "notify::alpha",
G_CALLBACK(notify_cb), G_CALLBACK(notify_cb),
behave); behave);
CLUTTER_NOTE (BEHAVIOUR, "setting new alpha object (%p, notify:%d)",
priv->alpha, priv->notify_id);
} }
} }
/**
* clutter_behaviour_get_actors:
* @behaviour: a #ClutterBehaviour
*
* Retrieves all the actors to which @behaviour applies.
*
* Return value: a list of actors. You should free the returned list
* with g_slist_free() when finished using it.
*
* Since: 0.2
*/
GSList *
clutter_behaviour_get_actors (ClutterBehaviour *behaviour)
{
GSList *retval, *l;
g_return_val_if_fail (CLUTTER_BEHAVIOUR (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);
}

View File

@ -58,7 +58,20 @@ G_BEGIN_DECLS
typedef struct _ClutterBehaviour ClutterBehaviour; typedef struct _ClutterBehaviour ClutterBehaviour;
typedef struct _ClutterBehaviourPrivate ClutterBehaviourPrivate; typedef struct _ClutterBehaviourPrivate ClutterBehaviourPrivate;
typedef struct _ClutterBehaviourClass ClutterBehaviourClass; typedef struct _ClutterBehaviourClass ClutterBehaviourClass;
/**
* ClutterBehaviourFunction:
* @behaviour: the #ClutterBehaviour
* @actor: an actor driven by @behaviour
* @data: optional data passed to the function
*
* This function is passed to clutter_behaviour_foreach_actor() and
* will be called for each actor driven by @behaviour.
*/
typedef void (*ClutterBehaviourForeachFunc) (ClutterBehaviour *behaviour,
ClutterActor *actor,
gpointer data);
struct _ClutterBehaviour struct _ClutterBehaviour
{ {
/*< private >*/ /*< private >*/
@ -85,16 +98,17 @@ struct _ClutterBehaviourClass
GType clutter_behaviour_get_type (void) G_GNUC_CONST; GType clutter_behaviour_get_type (void) G_GNUC_CONST;
void clutter_behaviour_apply (ClutterBehaviour *behave, void clutter_behaviour_apply (ClutterBehaviour *behave,
ClutterActor *actor); ClutterActor *actor);
void clutter_behaviour_remove (ClutterBehaviour *behave, void clutter_behaviour_remove (ClutterBehaviour *behave,
ClutterActor *actor); ClutterActor *actor);
void clutter_behaviour_actors_foreach (ClutterBehaviour *behave, void clutter_behaviour_actors_foreach (ClutterBehaviour *behave,
GFunc func, ClutterBehaviourForeachFunc func,
gpointer data); gpointer data);
ClutterAlpha *clutter_behaviour_get_alpha (ClutterBehaviour *behave); GSList * clutter_behaviour_get_actors (ClutterBehaviour *behave);
void clutter_behaviour_set_alpha (ClutterBehaviour *behave, ClutterAlpha *clutter_behaviour_get_alpha (ClutterBehaviour *behave);
ClutterAlpha *alpha); void clutter_behaviour_set_alpha (ClutterBehaviour *behave,
ClutterAlpha *alpha);
G_END_DECLS G_END_DECLS

View File

@ -7,7 +7,9 @@
#define CLUTTER_VERSION @CLUTTER_VERSION@ #define CLUTTER_VERSION @CLUTTER_VERSION@
#define CLUTTER_VERSION_S "@CLUTTER_VERSION@" #define CLUTTER_VERSION_S "@CLUTTER_VERSION@"
#define CLUTTER_VERSION_HEX 0x@CLUTTER_MAJOR_VERSION@0@CLUTTER_MINOR_VERSION@0@CLUTTER_MICRO_VERSION@ #define CLUTTER_VERSION_HEX ((CLUTTER_MAJOR_VERSION << 24) | \
(CLUTTER_MINOR_VERSION << 16) | \
(CLUTTER_MICRO_VERSION << 8))
#define CLUTTER_CHECK_VERSION(major,minor,micro) \ #define CLUTTER_CHECK_VERSION(major,minor,micro) \
(CLUTTER_MAJOR_VERSION > (major) || \ (CLUTTER_MAJOR_VERSION > (major) || \

View File

@ -68,7 +68,9 @@ ClutterBehaviour
ClutterBehaviourClass ClutterBehaviourClass
clutter_behaviour_apply clutter_behaviour_apply
clutter_behaviour_remove clutter_behaviour_remove
ClutterBehaviourForeachFunc
clutter_behaviour_actors_foreach clutter_behaviour_actors_foreach
clutter_behaviour_get_actors
clutter_behaviour_get_alpha clutter_behaviour_get_alpha
clutter_behaviour_set_alpha clutter_behaviour_set_alpha
<SUBSECTION Standard> <SUBSECTION Standard>

View File

@ -60,6 +60,16 @@ ClutterBehaviour
@actor: @actor:
<!-- ##### USER_FUNCTION ClutterBehaviourForeachFunc ##### -->
<para>
</para>
@behaviour:
@actor:
@data:
<!-- ##### FUNCTION clutter_behaviour_actors_foreach ##### --> <!-- ##### FUNCTION clutter_behaviour_actors_foreach ##### -->
<para> <para>
@ -70,6 +80,15 @@ ClutterBehaviour
@data: @data:
<!-- ##### FUNCTION clutter_behaviour_get_actors ##### -->
<para>
</para>
@behave:
@Returns:
<!-- ##### FUNCTION clutter_behaviour_get_alpha ##### --> <!-- ##### FUNCTION clutter_behaviour_get_alpha ##### -->
<para> <para>