The Animatable interface was created specifically for the Animation
class. It turns out that it might be fairly useful to others - such as
ClutterAnimator and ClutterState.
The newly-added API in this cycle for querying and accessing custom
properties should not require that we pass a ClutterAnimation to the
implementations: the Animatable itself should be enough.
This is necessary to allow language bindings to wrap
clutter_actor_animate() correctly and do type validation and
demarshalling between native values and GValues; an Animation instance
is not available until the animate() call returns, and validation must
be performed before that happens.
There is nothing we can do about the animate_property() virtual
function - but in that case we might want to be able to access the
animation from an Animatable implementation to get the Interval for
the property, just like ClutterActor does in order to animate
ClutterActorMeta objects.
The marshallers we use for the signals are declared in a private header,
and it stands to reason that they should also be hidden in the shared
object by using the common '_' prefix. We are also using some direct
g_cclosure_marshal_* symbol from GLib, instead of consistently use the
clutter_marshal_* symbol.
The Animation class should use the Animatable API for custom properties
to override finding a property definition, getting the initial state and
setting the final state of an object.
GLib 2.24 (but starting from the 2.23.2 unstable release) added a new
macro for collecting GValues from a va_list.
The newly added G_VALUE_COLLECT_INIT() macro should be used in place
of initializing the GValue and calling G_VALUE_COLLECT(), and improves
the collection performances by avoiding multiple checks, free and
initialization calls.
The signal-swapped-after:: modifier for signal connection inside the
clutter_actor_animate* variadic arguments functions is not mentioned in
the documentation.
• Remove one unused variable.
• We ignore the result of get_timeline_internal() so we need to tell
the compiler that - though a better solution would be to split the
timeline implicit creation into its own function.
Instead of taking a string and duplicating the "is it a string or an
integer" check in both Alpha and Animation, the function in
ClutterScript that resolves the animation mode values should take a
JsonNode and do all the checks it needs.
Be more drastic if the internal state is broken, and assert() if the
expected Alpha and Timeline instances we need are not valid. This
usually implies a library bug or a massive heap corruption.
The Animation code does transformation of values between type A and A'
after checking for compatibility using g_value_type_compatible(). This
is incorrect: compatibility means that the two types can be copied. The
correct conversion should follow:
if (compatible (type (A), type (A')))
copy (A, A');
else
if (transformable (type (A), type (A')))
transform (A, A');
else
error("Unable to trasform type A in A'");
The transformation might still fail, so we need to check for errors
there as well as a fall-through case.
We should not just check for compatibility, but also for the ability to
transform a GValue of type A into another of type A'.
Usually compatibility is enough, especially if types can be
introspected beforehand; some times, though, we also need to check for
transformability as a type can provide the transformation functions
necessary for the operation.
Actors, unlike objects, can effectively go away whilst being
animated - usually because of an explicit destoy().
The Animation created by clutter_actor_animate() and friends
should keep a weak reference on the actor and eventually
get rid of the animation itself in case the actor goes away
whilst being animated.
Both ClutterAlpha:mode and ClutterAnimation:mode can be defined using:
• an integer id
• the "nick" field of the AnimationMode GEnumValue
• a custom, tweener-like string
All these methods should be documented.
Like in ClutterAlpha, ClutterAnimation:mode must be overridden when
parsing a Script definition, as we accept both a numeric id and the
string id for easing modes.
The old code checked whether the property began with 'signal-' and
then checked for 'signal-swapped' and 'signal-after'. This prevented
you from animating a property called for example 'signal-strength'.
The check for the prefix is now in a separate function which also adds
a 'signal-swapped-after' prefix for completeness.
Fixes bug:
http://bugzilla.openedhand.com/show_bug.cgi?id=1798
Currently, to update a property inside an animation you have to
get the interval for that property and then call the set_final_value()
method.
We can provide a simpler, bind()-like method for the convenience of
the developers that just validates everything and then calls the
Interval.set_final_value().
If the timeline is running backwards, the completed signal handler should
set the final state from the interval's initial value.
Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
In case we are skipping too many frames, we should force the animation
instance to apply the final state of the animated interval inside the
::completed signal handler.
In order to chain up animations using clutter_actor_animate() and
friends you have to use an idle handler that guarantees that the
main loop spins at least once after the animation pointer has been
detached from the actor.
This has several drawbacks, first and foremost the fact that the
slice of the main loop for the idle handler might be starved by
other operations, like redrawing. This inevitably leads to tricks
with priorities and the like, contributing to the overall complexity.
Instead, we should guarantee that the animation instance created by
clutter_actor_animate() is valid for the ::completed signal until
it reaches its default handler; after that, the animation is detached
from the actor and destroyed. This means that it's possible to
create a new animation after the first is complete by simply using
g_signal_connect_after().
This unfortunately makes it impossible to keep a reference to the
animation pointer attached to the actor by using g_object_ref(); a
way to "fix" this would be to have a clutter_animation_attach()
and a clutter_animation_detach() pair of methods that allow attaching
any animation to an actor. This might overcomplicate what it is
the simple animation API, though, so it's currently not implemented
and left for future versions.
The test-easing interactive demo has been modified to show how
the animation queuing works by adding a command line switch that
recenters the animated actor once the first animation has ended.
Continuing in the tradition on making clutter_actor_animate() the
next g_object_connect(), here's the addition of the signal-after::
and signal-swapped:: modifiers for the automagic signal connection
arguments.
Fixes bug:
http://bugzilla.openedhand.com/show_bug.cgi?id=1646
The Animation should be referenced during the notification of the
alpha value, since the callback is invoked depending on the Alpha
and it won't vivify the Animation instance for us.
Fixes bug:
http://bugzilla.openedhand.com/show_bug.cgi?id=1537
The commit 2c95b378 prevents clutter_animation_setup_property from being
called with fixed:: property names. This patch adds a additional
parameter "is_fixed" to clutter_animation_setup_property instead of
searching for "fixed::" in property_name.
Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
Notifications should be fired off from both the internal timeline and
the wrapping animation here, so notifiers should be frozen around these
property setters.
Signed-off-by: Jonas Bonn <jonas@southpole.se>
Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
Just a couple of final cleanups after the reimplementation of the
Animation model.
i) _set_mode does not need to set the timeline on the alpha
ii) freeze notifications around the setting of a new alpha
Signed-off-by: Jonas Bonn <jonas@southpole.se>
Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
After long deliberation, the Animation class handling of the
:mode, :duration and :loop properties, as well as the conditions
for creating the Alpha and Timeline instances, came out as far too
complicated for their own good.
This is a rework of the API/parameters matrix and behaviour:
- :mode accessors will create an Alpha, if needed
- :duration and :loop accessors will create an Alpha and a Timeline
if needed
- :alpha will set or unset the Alpha
- :timeline will set or unset the Timeline
Plus, more documentation on the Animation class itself.
Many thanks to Jonas Bonn <jonas@southpole.se> for the feedback
and the ideas.
The Animatable interface implementation will always have the computed
value applied, whilst the non-Animatable objects go through the
interval validation first to avoid incurring in assertions and
warnings.
The Animatable::animate_property() should also be able to validate the
property it's supposed to interpolate, and eventually discard it. This
requires adding a return value to the virtual function (and its wrapper
function).
The Animation code will then apply the computed value only if the
animate_property() returns TRUE -- unifying the code path with the
non-Animatable objects.
The Animation class should proxy the :mode, :duration and :loop
properties whenever possible, to avoid them going out of sync when
changed using the Alpha and Timeline instances directly.
Currently, if Timeline:duration is changed, querying Animation:duration
will yield the old value, but the animation itself (being driven by
the Timeline) will use the Timeline's :duration new value. This holds
for the :loop and :mode properties as well.
Instead, the getters for the Animation's :duration, :loop and
:mode properties should ask the relevant object -- if any. The
loop, duration and mode values inside AnimationPrivate should only
be used if no Timeline or no Alpha instances are available, or
when creating new instances.
The Animation should not directly manipulate a Timeline instance,
but it should defer to the Alpha all handling of the timeline.
This means that:
- set_duration() and set_loop() will either create a Timeline or
will set the :duration and :loop properties on the Timeline; if
the Timeline must be created, and no Alpha instance is available,
then a new Alpha instance will be created as well and the newly
create Timeline will be assigned to the Alpha
- if set_mode() on an Animation instance without an Alpha, the
Alpha will be created; a Timeline will also be created
- set_alpha() will replace the Alpha; if the new Alpha does not
have a Timeline associated then a Timeline will be created using
the current :duration and :loop properties of Animation; otherwise,
if the replaced Alpha had a timeline, the timeline will be
transferred to the new one
The timeline created when calling set_timeline(NULL) is referenced
even though we implicitly own it. When the Animation is destroyed,
the timeline is then leaked.
Thanks to: Richard Heatley <richard.heatley@starleaf.com>
Fixes bug:
http://bugzilla.openedhand.com/show_bug.cgi?id=1548
ClutterAnimation currently inherits the initial floating reference
semantics from GInitiallyUnowned. An Animation is, though, meant to
be used as a top-level object, like a Timeline or a Behaviour, and
not "owned" by another object. For this reason, the initial floating
reference does not make any sense.
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
The clutter_actor_animate*() family of functions should only connect
to the Animation::completed signal once, during the construction of
the Animation object attached to the Actor. Otherwise, the completed
signal handler will be run multiple times, and will try to unref()
the Animation for each call -- leading to a segmentation fault.
The Animation class is missing a ::started signal matching the
::completed one. A ::started signal is useful for debugging,
initial state set up, and checks.
Bug 1535 - Complete animation always unrefs ClutterAnimation (even
after g_object_ref_sink)
Animations created through clutter_animation_new() should not
automagically unref themselves by default on ::complete. We
only want that behaviour for Animations created by the
clutter_actor_animate* family of functions, since those provide
the automagic memory management.
Added support for registering a handler for the completed signal
directly amongst the varargs making it easier to attach code
to be executed when animations complete.