diff --git a/ChangeLog b/ChangeLog index 111101e22..0c3980994 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2006-12-08 Emmanuele Bassi + + * 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 * clutter/clutter-rectangle.c: Forgot to set the diff --git a/clutter/clutter-behaviour-opacity.c b/clutter/clutter-behaviour-opacity.c index fb3dfa4b2..3f257447a 100644 --- a/clutter/clutter-behaviour-opacity.c +++ b/clutter/clutter-behaviour-opacity.c @@ -78,37 +78,36 @@ enum 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 clutter_behaviour_alpha_notify (ClutterBehaviour *behave, guint32 alpha_value) { - clutter_behaviour_actors_foreach (behave, - (GFunc) opacity_frame_foreach, - CLUTTER_BEHAVIOUR_OPACITY (behave)); + GSList *actors, *l; + guint8 opacity; + 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 diff --git a/clutter/clutter-behaviour-path.c b/clutter/clutter-behaviour-path.c index d787a3244..41eecd2e7 100644 --- a/clutter/clutter-behaviour-path.c +++ b/clutter/clutter-behaviour-path.c @@ -184,9 +184,12 @@ path_total_length (ClutterBehaviourPath *behave) } static void -actor_apply_knot_foreach (ClutterActor *actor, - ClutterKnot *knot) +actor_apply_knot_foreach (ClutterBehaviour *behaviour, + ClutterActor *actor, + gpointer data) { + ClutterKnot *knot = data; + clutter_actor_set_position (actor, knot->x, knot->y); } @@ -217,7 +220,7 @@ path_alpha_to_position (ClutterBehaviourPath *behave, if (offset == 0) { clutter_behaviour_actors_foreach (behaviour, - (GFunc) actor_apply_knot_foreach, + actor_apply_knot_foreach, priv->knots->data); g_signal_emit (behave, path_signals[KNOT_REACHED], 0, @@ -245,7 +248,7 @@ path_alpha_to_position (ClutterBehaviourPath *behave, interpolate (knot, next, &new, t); clutter_behaviour_actors_foreach (behaviour, - (GFunc)actor_apply_knot_foreach, + actor_apply_knot_foreach, &new); g_signal_emit (behave, path_signals[KNOT_REACHED], 0, &new); diff --git a/clutter/clutter-behaviour-scale.c b/clutter/clutter-behaviour-scale.c index 09451d534..406fcd50e 100644 --- a/clutter/clutter-behaviour-scale.c +++ b/clutter/clutter-behaviour-scale.c @@ -81,30 +81,15 @@ enum }; static void -scale_frame_foreach (ClutterActor *actor, - ClutterBehaviourScale *behave) +scale_frame_foreach (ClutterBehaviour *behaviour, + ClutterActor *actor, + gpointer data) { - ClutterFixed scale, factor; - guint32 alpha; - ClutterBehaviourScalePrivate *priv; - ClutterBehaviour *_behave; - gint sw, sh, w, h; + ClutterBehaviourScalePrivate *priv; + gint sw, sh, w, h; + guint scale = GPOINTER_TO_UINT (data); - priv = CLUTTER_BEHAVIOUR_SCALE_GET_PRIVATE (behave); - _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; + priv = CLUTTER_BEHAVIOUR_SCALE (behaviour)->priv; clutter_actor_set_scalex (actor, scale, scale); @@ -143,9 +128,24 @@ static void clutter_behaviour_scale_alpha_notify (ClutterBehaviour *behave, 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, - (GFunc) scale_frame_foreach, - CLUTTER_BEHAVIOUR_SCALE (behave)); + scale_frame_foreach, + GUINT_TO_POINTER (scale)); } static void diff --git a/clutter/clutter-behaviour.c b/clutter/clutter-behaviour.c index c84d3335a..4f5913dca 100644 --- a/clutter/clutter-behaviour.c +++ b/clutter/clutter-behaviour.c @@ -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 clutter_behaviour_class_init (ClutterBehaviourClass *klass) @@ -163,6 +170,8 @@ clutter_behaviour_class_init (ClutterBehaviourClass *klass) G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE)); + klass->alpha_notify = clutter_behaviour_alpha_notify_unimplemented; + 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 clutter_behaviour_apply (ClutterBehaviour *behave, ClutterActor *actor) @@ -195,6 +214,16 @@ clutter_behaviour_apply (ClutterBehaviour *behave, 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 #ClutterActors to which + * @behave applies. This function removes a reference on the actor. + * + * Since: 0.2 + */ void clutter_behaviour_remove (ClutterBehaviour *behave, ClutterActor *actor) @@ -215,17 +244,47 @@ clutter_behaviour_remove (ClutterBehaviour *behave, 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 -clutter_behaviour_actors_foreach (ClutterBehaviour *behave, - GFunc func, - gpointer userdata) +clutter_behaviour_actors_foreach (ClutterBehaviour *behave, + ClutterBehaviourForeachFunc func, + gpointer data) { + GSList *l; + g_return_if_fail (CLUTTER_IS_BEHAVIOUR (behave)); 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* clutter_behaviour_get_alpha (ClutterBehaviour *behave) { @@ -243,16 +302,36 @@ notify_cb (GObject *object, klass = CLUTTER_BEHAVIOUR_GET_CLASS (behave); + CLUTTER_NOTE (BEHAVIOUR, "notify::alpha"); + if (klass->alpha_notify) { guint32 alpha_value; 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); } } +/** + * 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 clutter_behaviour_set_alpha (ClutterBehaviour *behave, ClutterAlpha *alpha) @@ -266,12 +345,17 @@ clutter_behaviour_set_alpha (ClutterBehaviour *behave, if (priv->notify_id) { + CLUTTER_NOTE (BEHAVIOUR, "removing previous notify-id (%d)", + priv->notify_id); + g_signal_handler_disconnect (priv->alpha, priv->notify_id); priv->notify_id = 0; } if (priv->alpha) { + CLUTTER_NOTE (BEHAVIOUR, "removing previous alpha object"); + g_object_unref (priv->alpha); priv->alpha = NULL; } @@ -284,5 +368,33 @@ clutter_behaviour_set_alpha (ClutterBehaviour *behave, priv->notify_id = g_signal_connect (priv->alpha, "notify::alpha", G_CALLBACK(notify_cb), 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); +} diff --git a/clutter/clutter-behaviour.h b/clutter/clutter-behaviour.h index 238f069a3..f4bc3a202 100644 --- a/clutter/clutter-behaviour.h +++ b/clutter/clutter-behaviour.h @@ -58,7 +58,20 @@ G_BEGIN_DECLS typedef struct _ClutterBehaviour ClutterBehaviour; typedef struct _ClutterBehaviourPrivate ClutterBehaviourPrivate; 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 { /*< private >*/ @@ -85,16 +98,17 @@ struct _ClutterBehaviourClass GType clutter_behaviour_get_type (void) G_GNUC_CONST; -void clutter_behaviour_apply (ClutterBehaviour *behave, - ClutterActor *actor); -void clutter_behaviour_remove (ClutterBehaviour *behave, - ClutterActor *actor); -void clutter_behaviour_actors_foreach (ClutterBehaviour *behave, - GFunc func, - gpointer data); -ClutterAlpha *clutter_behaviour_get_alpha (ClutterBehaviour *behave); -void clutter_behaviour_set_alpha (ClutterBehaviour *behave, - ClutterAlpha *alpha); +void clutter_behaviour_apply (ClutterBehaviour *behave, + ClutterActor *actor); +void clutter_behaviour_remove (ClutterBehaviour *behave, + ClutterActor *actor); +void clutter_behaviour_actors_foreach (ClutterBehaviour *behave, + ClutterBehaviourForeachFunc func, + gpointer data); +GSList * clutter_behaviour_get_actors (ClutterBehaviour *behave); +ClutterAlpha *clutter_behaviour_get_alpha (ClutterBehaviour *behave); +void clutter_behaviour_set_alpha (ClutterBehaviour *behave, + ClutterAlpha *alpha); G_END_DECLS diff --git a/clutter/clutter-version.h.in b/clutter/clutter-version.h.in index 35ae54c98..c5076c892 100644 --- a/clutter/clutter-version.h.in +++ b/clutter/clutter-version.h.in @@ -7,7 +7,9 @@ #define CLUTTER_VERSION @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) \ (CLUTTER_MAJOR_VERSION > (major) || \ diff --git a/doc/reference/clutter-sections.txt b/doc/reference/clutter-sections.txt index d3ee09af3..ece6a9168 100644 --- a/doc/reference/clutter-sections.txt +++ b/doc/reference/clutter-sections.txt @@ -68,7 +68,9 @@ ClutterBehaviour ClutterBehaviourClass clutter_behaviour_apply clutter_behaviour_remove +ClutterBehaviourForeachFunc clutter_behaviour_actors_foreach +clutter_behaviour_get_actors clutter_behaviour_get_alpha clutter_behaviour_set_alpha diff --git a/doc/reference/tmpl/clutter-behaviour.sgml b/doc/reference/tmpl/clutter-behaviour.sgml index 07f96a1b7..24ed86e86 100644 --- a/doc/reference/tmpl/clutter-behaviour.sgml +++ b/doc/reference/tmpl/clutter-behaviour.sgml @@ -60,6 +60,16 @@ ClutterBehaviour @actor: + + + + + +@behaviour: +@actor: +@data: + + @@ -70,6 +80,15 @@ ClutterBehaviour @data: + + + + + +@behave: +@Returns: + +