Timelines

Using g_timeout_add() to control an animation is complicated and does not work in concert with the rest of the operations Clutter must perform for each redraw cycle.

For this reason, Clutter provides ClutterTimeline, a class that allows scheduling animations with a definite duration. Timelines are advanced during the redraw cycle so that animations are ready to be performed at the right time. This also means that animations will not affect the event processing; it also means that if the animation is too complex it will be called with a longer delay, thus not blocking the whole UI.

A Timeline is created with:

clutter_timeline_new (duration_in_milliseconds);
    

The duration of the timeline then be modifed via the "duration" property or by using clutter_timeline_set_duration().

A timeline is started via clutter_timeline_start() and its playback further manipulated by the clutter_timeline_pause(), clutter_timeline_stop(), clutter_timeline_rewind() and clutter_timeline_skip() functions.

By attaching a handler to the timeline's "new-frame" signal a timeline can then be used to drive an animation by altering an actor's visual properties. The callback looks like:

void
on_new_frame (ClutterTimeline *timeline,
              gint             elapsed_msecs,
              gpointer         user_data)
{
}
    

The elapsed_msecs parameter is set to the amount of time elapsed since the beginning of the timeline, and its value is always between 0 and the "duration" value.

The function clutter_timeline_get_progress() can also be used to get a normalised value of the timeline's current position between 0 and 1.

Timelines can also be played in reverse by setting the direction using clutter_timeline_set_direction(), and can also have a one-time delay set before they begin playing by using the function clutter_timeline_set_delay().

Timelines can also control a pyshical simulation; the clutter_timeline_get_delta() function allows retrieving the number of milliseconds elapsed since the previous callback to ensure the physics engine to be able to take the actual time elapsed between iterations into account.

Example 19. Using a Timeline to drive an animation

Rewrite the example above with a ClutterTimeline instead of using g_timeout_add()

#include <clutter/clutter.h>

static void
on_new_frame (ClutterTimeline *timeline,
	      gint             elapsed_msecs,
	      ClutterActor    *actor)
{
  gdouble angle = 360 * clutter_timeline_get_progress (timeline);

  clutter_actor_set_rotation (actor, CLUTTER_Z_AXIS,
                              angle,
                              clutter_actor_get_width (actor) / 2,
			      clutter_actor_get_height (actor) / 2,
                              0);
}

  ...

  ClutterTimeline *timeline;

  timeline = clutter_timeline_new (1000); /* one second */
  clutter_timeline_set_loop (timeline, TRUE);
  g_signal_connect (timeline, "new-frame", G_CALLBACK (on_new_frame), actor);
  clutter_timeline_start (timeline);
      

Note

Multiple timelines can be sequenced in order by using a ClutterScore. See the ClutterScore documentation for more details on using this.