mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 03:22:04 +00:00
2007-12-04 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-score.[ch]: Reimplement ClutterScore using a N-ary tree to store the timelines. Remove clutter_score_add(): the same functionality can be achieved by passing a NULL parent to clutter_score_append(). * tests/test-score.c: Update ClutterScore test unit, and add debug printouts.
This commit is contained in:
parent
094c5f77b8
commit
51a0d5a80f
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
||||
2007-12-04 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* clutter/clutter-score.[ch]: Reimplement ClutterScore using
|
||||
a N-ary tree to store the timelines. Remove clutter_score_add():
|
||||
the same functionality can be achieved by passing a NULL
|
||||
parent to clutter_score_append().
|
||||
|
||||
* tests/test-score.c: Update ClutterScore test unit, and add
|
||||
debug printouts.
|
||||
|
||||
2007-12-04 Øyvind Kolås <pippin@o-hand.com>
|
||||
|
||||
* clutter/clutter-shader.c: (bind_glsl_shader): use gchar instead of
|
||||
|
@ -427,12 +427,14 @@ clutter_rectangle_set_color
|
||||
clutter_redraw
|
||||
clutter_rotate_axis_get_type
|
||||
clutter_rotate_direction_get_type
|
||||
clutter_score_add
|
||||
clutter_score_append
|
||||
clutter_score_get_loop
|
||||
clutter_score_get_timeline
|
||||
clutter_score_get_type
|
||||
clutter_score_is_playing
|
||||
clutter_score_list_timelines
|
||||
clutter_score_new
|
||||
clutter_score_remove
|
||||
clutter_score_remove_all
|
||||
clutter_score_rewind
|
||||
clutter_score_start
|
||||
|
@ -23,26 +23,6 @@
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* IDEAS:
|
||||
* API;
|
||||
* - add()
|
||||
* + an new timeline to beginning of score
|
||||
* - append (timeline_existing, timeline_new, delay)
|
||||
* + appends a new timeline to an existing one
|
||||
*
|
||||
* ScoreEntry
|
||||
* {
|
||||
* Timeline *base;
|
||||
* GList *next_timelines; - to start on completion of base,
|
||||
* (points to score entries)
|
||||
* Callback id;
|
||||
* delay
|
||||
* }
|
||||
*
|
||||
* start()/stop(),remove(),remove_all() ?
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:clutter-score
|
||||
* @short_description: Sequencing multiple #ClutterTimelines in order
|
||||
@ -62,34 +42,48 @@
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-debug.h"
|
||||
|
||||
G_DEFINE_TYPE (ClutterScore, clutter_score, G_TYPE_OBJECT);
|
||||
typedef struct _ClutterScoreEntry ClutterScoreEntry;
|
||||
|
||||
typedef struct ClutterScoreEntry
|
||||
struct _ClutterScoreEntry
|
||||
{
|
||||
ClutterTimeline *timeline;
|
||||
gulong handler_id;
|
||||
GSList *child_entries;
|
||||
guint id;
|
||||
|
||||
/* signal handler id */
|
||||
gulong completed_id;
|
||||
|
||||
ClutterScore *score;
|
||||
}
|
||||
ClutterScoreEntry;
|
||||
|
||||
/* pointer back to the tree structure */
|
||||
GNode *node;
|
||||
};
|
||||
|
||||
#define CLUTTER_SCORE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_SCORE, ClutterScorePrivate))
|
||||
|
||||
struct _ClutterScorePrivate
|
||||
{
|
||||
GSList *entries;
|
||||
GNode *root;
|
||||
|
||||
GHashTable *running_timelines;
|
||||
guint paused :1;
|
||||
|
||||
guint last_id;
|
||||
|
||||
guint is_paused : 1;
|
||||
guint loop : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_LOOP
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NEW_TIMELINE,
|
||||
TIMELINE_STARTED,
|
||||
TIMELINE_COMPLETED,
|
||||
|
||||
STARTED,
|
||||
PAUSED,
|
||||
COMPLETED,
|
||||
@ -97,23 +91,19 @@ enum
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static int score_signals[LAST_SIGNAL] = { 0 };
|
||||
G_DEFINE_TYPE (ClutterScore, clutter_score, G_TYPE_OBJECT);
|
||||
|
||||
static void start_entry (ClutterScoreEntry *entry);
|
||||
static int score_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
/* Object */
|
||||
|
||||
static void
|
||||
clutter_score_set_property (GObject *object,
|
||||
clutter_score_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ClutterScore *score;
|
||||
ClutterScorePrivate *priv;
|
||||
|
||||
score = CLUTTER_SCORE(object);
|
||||
priv = score->priv;
|
||||
ClutterScorePrivate *priv = CLUTTER_SCORE_GET_PRIVATE (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
@ -121,22 +111,18 @@ clutter_score_set_property (GObject *object,
|
||||
priv->loop = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_score_get_property (GObject *object,
|
||||
clutter_score_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ClutterScore *score;
|
||||
ClutterScorePrivate *priv;
|
||||
|
||||
score = CLUTTER_SCORE(object);
|
||||
priv = score->priv;
|
||||
ClutterScorePrivate *priv = CLUTTER_SCORE_GET_PRIVATE (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
@ -144,7 +130,7 @@ clutter_score_get_property (GObject *object,
|
||||
g_value_set_boolean (value, priv->loop);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -154,7 +140,9 @@ clutter_score_finalize (GObject *object)
|
||||
{
|
||||
ClutterScorePrivate *priv = CLUTTER_SCORE (object)->priv;
|
||||
|
||||
if (priv->running_timelines)
|
||||
g_hash_table_destroy (priv->running_timelines);
|
||||
|
||||
G_OBJECT_CLASS (clutter_score_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -173,70 +161,152 @@ clutter_score_dispose (GObject *object)
|
||||
static void
|
||||
clutter_score_class_init (ClutterScoreClass *klass)
|
||||
{
|
||||
GObjectClass *object_class;
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class = (GObjectClass*) klass;
|
||||
|
||||
object_class->set_property = clutter_score_set_property;
|
||||
object_class->get_property = clutter_score_get_property;
|
||||
object_class->finalize = clutter_score_finalize;
|
||||
object_class->dispose = clutter_score_dispose;
|
||||
gobject_class->set_property = clutter_score_set_property;
|
||||
gobject_class->get_property = clutter_score_get_property;
|
||||
gobject_class->finalize = clutter_score_finalize;
|
||||
gobject_class->dispose = clutter_score_dispose;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (ClutterScorePrivate));
|
||||
|
||||
/**
|
||||
* ClutterScore:loop:
|
||||
*
|
||||
* Whether the #ClutterScore should restart once finished.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_LOOP,
|
||||
g_param_spec_boolean ("loop",
|
||||
"Loop",
|
||||
"Whether the score should restart once finished",
|
||||
FALSE,
|
||||
CLUTTER_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ClutterScore::new-timeline:
|
||||
* ClutterScore::timeline-started:
|
||||
* @score: the score which received the signal
|
||||
* @timeline: the current timeline
|
||||
*
|
||||
* The ::new-timeline signal is emitted each time a new timeline in the
|
||||
* score is reached.
|
||||
* The ::timeline-started signal is emitted each time a new timeline
|
||||
* inside a #ClutterScore starts playing.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
score_signals[NEW_TIMELINE] =
|
||||
g_signal_new ("new-timeline",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
score_signals[TIMELINE_STARTED] =
|
||||
g_signal_new ("timeline-started",
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterScoreClass, new_timeline),
|
||||
G_STRUCT_OFFSET (ClutterScoreClass, timeline_started),
|
||||
NULL, NULL,
|
||||
clutter_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE,
|
||||
1, CLUTTER_TYPE_TIMELINE);
|
||||
/**
|
||||
* ClutterScore::timeline-completed:
|
||||
* @score: the score which received the signal
|
||||
* @timeline: the completed timeline
|
||||
*
|
||||
* The ::timeline-completed signal is emitted each time a timeline
|
||||
* inside a #ClutterScore terminates.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
score_signals[TIMELINE_COMPLETED] =
|
||||
g_signal_new ("timeline-completed",
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterScoreClass, timeline_completed),
|
||||
NULL, NULL,
|
||||
clutter_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_TIMELINE);
|
||||
/**
|
||||
* ClutterScore::completed:
|
||||
* @score: the score which received the signal
|
||||
*
|
||||
* The ::completed signal is emitted each time a #ClutterScore terminates.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
score_signals[COMPLETED] =
|
||||
g_signal_new ("completed",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterScoreClass, completed),
|
||||
NULL, NULL,
|
||||
clutter_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
/**
|
||||
* ClutterScore::started:
|
||||
* @score: the score which received the signal
|
||||
*
|
||||
* The ::started signal is emitted each time a #ClutterScore starts playing.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
score_signals[STARTED] =
|
||||
g_signal_new ("started",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterScoreClass, started),
|
||||
NULL, NULL,
|
||||
clutter_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
/**
|
||||
* ClutterScore::paused:
|
||||
* @score: the score which received the signal
|
||||
*
|
||||
* The ::paused signal is emitted each time a #ClutterScore
|
||||
* is paused.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
score_signals[PAUSED] =
|
||||
g_signal_new ("paused",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ClutterScoreClass, paused),
|
||||
NULL, NULL,
|
||||
clutter_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_score_init (ClutterScore *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
CLUTTER_TYPE_SCORE,
|
||||
ClutterScorePrivate);
|
||||
ClutterScorePrivate *priv;
|
||||
|
||||
self->priv->running_timelines = g_hash_table_new(NULL, NULL);
|
||||
self->priv = priv = CLUTTER_SCORE_GET_PRIVATE (self);
|
||||
|
||||
/* sentinel */
|
||||
priv->root = g_node_new (NULL);
|
||||
|
||||
priv->running_timelines = NULL;
|
||||
|
||||
priv->is_paused = FALSE;
|
||||
priv->loop = FALSE;
|
||||
|
||||
priv->last_id = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_score_new:
|
||||
*
|
||||
* Creates a new #ClutterScore. A #ClutterScore is an object that can
|
||||
* hold multiple #ClutterTimeline<!-- -->s in a sequential order.
|
||||
*
|
||||
* Return value: the newly created #ClutterScore. Use g_object_unref()
|
||||
* when done.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
ClutterScore *
|
||||
clutter_score_new (void)
|
||||
{
|
||||
return g_object_new (CLUTTER_TYPE_SCORE, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -282,76 +352,108 @@ clutter_score_get_loop (ClutterScore *score)
|
||||
*
|
||||
* Query state of a #ClutterScore instance.
|
||||
*
|
||||
* Return Value: TRUE if score is currently playing, FALSE if not.
|
||||
* Return Value: %TRUE if score is currently playing
|
||||
*/
|
||||
gboolean
|
||||
clutter_score_is_playing (ClutterScore *score)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_SCORE (score), FALSE);
|
||||
|
||||
/* FIXME: paused state currently counts as playing */
|
||||
if (score->priv->is_paused)
|
||||
return FALSE;
|
||||
|
||||
return !!g_hash_table_size (score->priv->running_timelines);
|
||||
return (g_hash_table_size (score->priv->running_timelines) != 0);
|
||||
}
|
||||
|
||||
/* forward declaration */
|
||||
static void start_entry (ClutterScoreEntry *entry);
|
||||
|
||||
static void
|
||||
start_children_entries (GNode *node,
|
||||
gpointer data)
|
||||
{
|
||||
ClutterScoreEntry *entry = node->data;
|
||||
|
||||
start_entry (entry);
|
||||
}
|
||||
|
||||
static void
|
||||
on_timeline_finish (ClutterTimeline *timeline,
|
||||
ClutterScoreEntry *entry)
|
||||
{
|
||||
GSList *item;
|
||||
ClutterScorePrivate *priv = entry->score->priv;
|
||||
|
||||
g_hash_table_remove (entry->score->priv->running_timelines,
|
||||
GINT_TO_POINTER(entry->handler_id));
|
||||
g_hash_table_remove (priv->running_timelines,
|
||||
GINT_TO_POINTER (entry->id));
|
||||
|
||||
g_signal_handler_disconnect (timeline, entry->handler_id);
|
||||
g_signal_handler_disconnect (timeline, entry->completed_id);
|
||||
entry->completed_id = 0;
|
||||
|
||||
CLUTTER_NOTE (SCHEDULER,
|
||||
"completed %p %li\n",
|
||||
entry->timeline, entry->handler_id);
|
||||
CLUTTER_NOTE (SCHEDULER, "timeline [%p] (%d) completed",
|
||||
entry->timeline,
|
||||
entry->id);
|
||||
|
||||
for (item = entry->child_entries; item != NULL; item = item->next)
|
||||
g_signal_emit (entry->score, score_signals[TIMELINE_COMPLETED], 0,
|
||||
entry->timeline);
|
||||
|
||||
/* start every child */
|
||||
if (entry->node->children)
|
||||
{
|
||||
ClutterScoreEntry *child_entry = item->data;
|
||||
start_entry (child_entry);
|
||||
g_node_children_foreach (entry->node,
|
||||
G_TRAVERSE_ALL,
|
||||
start_children_entries,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (clutter_score_is_playing (entry->score) == FALSE)
|
||||
/* score has finished - fire 'completed' signal */
|
||||
if (g_hash_table_size (priv->running_timelines) == 0)
|
||||
{
|
||||
/* Score has finished - fire 'completed' signal */
|
||||
/* Also check if looped etc */
|
||||
CLUTTER_NOTE (SCHEDULER, "looks like we finished\n");
|
||||
CLUTTER_NOTE (SCHEDULER, "looks like we finished");
|
||||
|
||||
g_signal_emit (entry->score, score_signals[COMPLETED], 0);
|
||||
|
||||
clutter_score_stop (entry->score);
|
||||
|
||||
if (priv->loop)
|
||||
clutter_score_start (entry->score);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
start_entry (ClutterScoreEntry *entry)
|
||||
{
|
||||
entry->handler_id = g_signal_connect (entry->timeline,
|
||||
"completed",
|
||||
G_CALLBACK (on_timeline_finish),
|
||||
ClutterScorePrivate *priv = entry->score->priv;
|
||||
|
||||
entry->completed_id =
|
||||
g_signal_connect (entry->timeline,
|
||||
"completed", G_CALLBACK (on_timeline_finish),
|
||||
entry);
|
||||
|
||||
CLUTTER_NOTE (SCHEDULER,
|
||||
"started %p %li\n", entry->timeline, entry->handler_id);
|
||||
CLUTTER_NOTE (SCHEDULER, "timeline [%p] (%d) started",
|
||||
entry->timeline,
|
||||
entry->id);
|
||||
|
||||
g_hash_table_insert (entry->score->priv->running_timelines,
|
||||
GINT_TO_POINTER(entry->handler_id),
|
||||
if (G_UNLIKELY (priv->running_timelines == NULL))
|
||||
priv->running_timelines = g_hash_table_new (NULL, NULL);
|
||||
|
||||
g_hash_table_insert (priv->running_timelines,
|
||||
GINT_TO_POINTER (entry->id),
|
||||
entry);
|
||||
|
||||
clutter_timeline_start (entry->timeline);
|
||||
|
||||
g_signal_emit (entry->score, score_signals[NEW_TIMELINE],
|
||||
0, entry->timeline);
|
||||
g_signal_emit (entry->score, score_signals[TIMELINE_STARTED], 0,
|
||||
entry->timeline);
|
||||
}
|
||||
|
||||
void
|
||||
on_foreach_running_timeline_start (gpointer key,
|
||||
static void
|
||||
foreach_running_timeline_start (gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
clutter_timeline_start (CLUTTER_TIMELINE(value));
|
||||
ClutterScoreEntry *entry = value;
|
||||
|
||||
clutter_timeline_start (entry->timeline);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -365,36 +467,37 @@ on_foreach_running_timeline_start (gpointer key,
|
||||
void
|
||||
clutter_score_start (ClutterScore *score)
|
||||
{
|
||||
GSList *item;
|
||||
ClutterScorePrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_SCORE (score));
|
||||
|
||||
priv = score->priv;
|
||||
|
||||
if (priv->paused)
|
||||
if (priv->is_paused)
|
||||
{
|
||||
g_hash_table_foreach (priv->running_timelines,
|
||||
(GHFunc)on_foreach_running_timeline_start,
|
||||
foreach_running_timeline_start,
|
||||
NULL);
|
||||
priv->paused = 0;
|
||||
priv->is_paused = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (item = priv->entries; item != NULL; item = item->next)
|
||||
{
|
||||
ClutterScoreEntry *entry = item->data;
|
||||
start_entry (entry);
|
||||
}
|
||||
g_node_children_foreach (priv->root,
|
||||
G_TRAVERSE_ALL,
|
||||
start_children_entries,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
on_foreach_running_timeline_stop (gpointer key,
|
||||
static gboolean
|
||||
foreach_running_timeline_stop (gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
clutter_timeline_stop (((ClutterScoreEntry*)value)->timeline);
|
||||
ClutterScoreEntry *entry = value;
|
||||
|
||||
clutter_timeline_stop (entry->timeline);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -415,8 +518,10 @@ clutter_score_stop (ClutterScore *score)
|
||||
priv = score->priv;
|
||||
|
||||
g_hash_table_foreach_remove (priv->running_timelines,
|
||||
(GHRFunc)on_foreach_running_timeline_stop,
|
||||
foreach_running_timeline_stop,
|
||||
NULL);
|
||||
g_hash_table_destroy (priv->running_timelines);
|
||||
priv->running_timelines = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -440,12 +545,14 @@ clutter_score_rewind (ClutterScore *score)
|
||||
clutter_score_start (score);
|
||||
}
|
||||
|
||||
void
|
||||
on_foreach_running_timeline_pause (gpointer key,
|
||||
static void
|
||||
foreach_running_timeline_pause (gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
clutter_timeline_pause (((ClutterScoreEntry*)value)->timeline);
|
||||
ClutterScoreEntry *entry = value;
|
||||
|
||||
clutter_timeline_pause (entry->timeline);
|
||||
}
|
||||
|
||||
void
|
||||
@ -457,131 +564,278 @@ clutter_score_pause (ClutterScore *score)
|
||||
|
||||
priv = score->priv;
|
||||
|
||||
if (priv->paused || !clutter_score_is_playing (score))
|
||||
if (!clutter_score_is_playing (score))
|
||||
return;
|
||||
|
||||
g_hash_table_foreach (priv->running_timelines,
|
||||
(GHFunc)on_foreach_running_timeline_pause,
|
||||
foreach_running_timeline_pause,
|
||||
NULL);
|
||||
|
||||
priv->paused = 1;
|
||||
priv->is_paused = TRUE;
|
||||
|
||||
g_signal_emit (score, score_signals[PAUSED], 0);
|
||||
}
|
||||
|
||||
static ClutterScoreEntry*
|
||||
find_entry (GSList *list, ClutterTimeline *timeline)
|
||||
typedef enum {
|
||||
FIND_BY_TIMELINE,
|
||||
FIND_BY_ID,
|
||||
REMOVE_BY_ID,
|
||||
LIST_TIMELINES
|
||||
} TraverseAction;
|
||||
|
||||
typedef struct {
|
||||
TraverseAction action;
|
||||
|
||||
ClutterScore *score;
|
||||
|
||||
union {
|
||||
ClutterTimeline *timeline;
|
||||
guint id;
|
||||
ClutterScoreEntry *entry;
|
||||
} d;
|
||||
|
||||
gpointer result;
|
||||
} TraverseClosure;
|
||||
|
||||
static gboolean
|
||||
destroy_entry (GNode *node,
|
||||
G_GNUC_UNUSED gpointer data)
|
||||
{
|
||||
GSList *item;
|
||||
ClutterScoreEntry *res = NULL;
|
||||
ClutterScoreEntry *entry = node->data;
|
||||
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
|
||||
for (item = list; item != NULL && res == NULL; item = item->next)
|
||||
if (G_LIKELY (entry != NULL))
|
||||
{
|
||||
ClutterScoreEntry *entry = item->data;
|
||||
if (entry->completed_id)
|
||||
g_signal_handler_disconnect (entry->timeline, entry->completed_id);
|
||||
|
||||
g_assert (entry != NULL);
|
||||
g_object_unref (entry->timeline);
|
||||
g_slice_free (ClutterScoreEntry, entry);
|
||||
|
||||
if (entry->timeline == timeline)
|
||||
return entry;
|
||||
|
||||
if (entry->child_entries)
|
||||
res = find_entry (entry->child_entries, timeline);
|
||||
node->data = NULL;
|
||||
}
|
||||
|
||||
return res;
|
||||
/* continue */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
traverse_children (GNode *node,
|
||||
gpointer data)
|
||||
{
|
||||
TraverseClosure *closure = data;
|
||||
ClutterScoreEntry *entry = node->data;
|
||||
gboolean retval = FALSE;
|
||||
|
||||
/* root */
|
||||
if (!entry)
|
||||
return TRUE;
|
||||
|
||||
switch (closure->action)
|
||||
{
|
||||
case FIND_BY_TIMELINE:
|
||||
if (closure->d.timeline == entry->timeline)
|
||||
{
|
||||
closure->result = node;
|
||||
retval = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case FIND_BY_ID:
|
||||
if (closure->d.id == entry->id)
|
||||
{
|
||||
closure->result = node;
|
||||
retval = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case REMOVE_BY_ID:
|
||||
if (closure->d.id == entry->id)
|
||||
{
|
||||
if (entry->completed_id)
|
||||
g_signal_handler_disconnect (entry->timeline, entry->completed_id);
|
||||
|
||||
g_object_unref (entry->timeline);
|
||||
|
||||
g_node_traverse (node,
|
||||
G_POST_ORDER,
|
||||
G_TRAVERSE_ALL,
|
||||
-1,
|
||||
destroy_entry, NULL);
|
||||
|
||||
g_slice_free (ClutterScoreEntry, entry);
|
||||
|
||||
closure->result = node;
|
||||
retval = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case LIST_TIMELINES:
|
||||
retval = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static GNode *
|
||||
find_entry_by_timeline (ClutterScore *score,
|
||||
ClutterTimeline *timeline)
|
||||
{
|
||||
ClutterScorePrivate *priv = score->priv;
|
||||
TraverseClosure closure;
|
||||
|
||||
closure.action = FIND_BY_TIMELINE;
|
||||
closure.score = score;
|
||||
closure.d.timeline = timeline;
|
||||
closure.result = NULL;
|
||||
|
||||
g_node_traverse (priv->root,
|
||||
G_POST_ORDER,
|
||||
G_TRAVERSE_ALL,
|
||||
-1,
|
||||
traverse_children, &closure);
|
||||
|
||||
if (closure.result)
|
||||
return closure.result;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GNode *
|
||||
find_entry_by_id (ClutterScore *score,
|
||||
guint id)
|
||||
{
|
||||
ClutterScorePrivate *priv = score->priv;
|
||||
TraverseClosure closure;
|
||||
|
||||
closure.action = FIND_BY_ID;
|
||||
closure.score = score;
|
||||
closure.d.id = id;
|
||||
closure.result = NULL;
|
||||
|
||||
g_node_traverse (priv->root,
|
||||
G_POST_ORDER,
|
||||
G_TRAVERSE_ALL,
|
||||
-1,
|
||||
traverse_children, &closure);
|
||||
|
||||
if (closure.result)
|
||||
return closure.result;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_score_append:
|
||||
* @score: A #ClutterScore
|
||||
* @timeline_existing: A #ClutterTimeline in the score
|
||||
* @timeline_new: A new #ClutterTimeline to start when #timeline_existing has
|
||||
* completed,
|
||||
* @score: a #ClutterScore
|
||||
* @parent: a #ClutterTimeline in the score or %NULL
|
||||
* @timeline: a #ClutterTimeline
|
||||
*
|
||||
* Appends a new timeline to an one existing in the score.
|
||||
* Appends a timeline to another one existing in the score; the newly
|
||||
* appended timeline will be started when @parent is complete.
|
||||
*
|
||||
* If @parent is %NULL, the new #ClutterTimeline will be started when
|
||||
* clutter_score_start() is called.
|
||||
*
|
||||
* Return value: the id of the newly added timeline, to be used with
|
||||
* clutter_score_get_timeline() and clutter_score_remove().
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
void
|
||||
guint
|
||||
clutter_score_append (ClutterScore *score,
|
||||
ClutterTimeline *timeline_existing,
|
||||
ClutterTimeline *timeline_new)
|
||||
ClutterTimeline *parent,
|
||||
ClutterTimeline *timeline)
|
||||
{
|
||||
ClutterScorePrivate *priv;
|
||||
ClutterScoreEntry *entry, *entry_new;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_SCORE (score), 0);
|
||||
g_return_val_if_fail (parent == NULL || CLUTTER_IS_TIMELINE (parent), 0);
|
||||
g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0);
|
||||
|
||||
priv = score->priv;
|
||||
|
||||
/* Appends a timeline to the end of another */
|
||||
if ((entry = find_entry (priv->entries, timeline_existing)) != NULL)
|
||||
if (!parent)
|
||||
{
|
||||
entry_new = g_new0(ClutterScoreEntry, 1);
|
||||
entry_new->timeline = g_object_ref (timeline_new);
|
||||
entry_new->score = score;
|
||||
ClutterScoreEntry *entry;
|
||||
|
||||
entry->child_entries = g_slist_append (entry->child_entries, entry_new);
|
||||
entry = g_slice_new (ClutterScoreEntry);
|
||||
|
||||
clutter_timeline_stop (timeline_new); /* stop it */
|
||||
entry->timeline = g_object_ref (timeline);
|
||||
entry->id = priv->last_id;
|
||||
entry->completed_id = 0;
|
||||
entry->score = score;
|
||||
|
||||
entry->node = g_node_append_data (priv->root, entry);
|
||||
|
||||
priv->last_id += 1;
|
||||
|
||||
return entry->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
GNode *node;
|
||||
ClutterScoreEntry *entry;
|
||||
|
||||
node = find_entry_by_timeline (score, parent);
|
||||
if (G_UNLIKELY (!node))
|
||||
{
|
||||
g_warning ("Unable to find the parent timeline inside the score.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
entry = g_slice_new (ClutterScoreEntry);
|
||||
entry->timeline = g_object_ref (timeline);
|
||||
entry->id = priv->last_id;
|
||||
entry->completed_id = 0;
|
||||
entry->score = score;
|
||||
|
||||
entry->node = g_node_append_data (node, entry);
|
||||
|
||||
priv->last_id += 1;
|
||||
|
||||
return entry->id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_score_add:
|
||||
* @score: A #ClutterScore
|
||||
* @timeline: A #ClutterTimeline
|
||||
* clutter_score_remove:
|
||||
* @score: a #ClutterScore
|
||||
* @id: the id of the timeline to remove
|
||||
*
|
||||
* Adds a new initial timeline to start when the score is started.
|
||||
* Removes the #ClutterTimeline with the given id inside @score. If
|
||||
* the timeline has other timelines attached to it, those are removed
|
||||
* as well.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
void
|
||||
clutter_score_add (ClutterScore *score,
|
||||
ClutterTimeline *timeline)
|
||||
clutter_score_remove (ClutterScore *score,
|
||||
guint id)
|
||||
{
|
||||
ClutterScorePrivate *priv;
|
||||
ClutterScoreEntry *entry;
|
||||
TraverseClosure closure;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_SCORE (score));
|
||||
g_return_if_fail (id > 0);
|
||||
|
||||
priv = score->priv;
|
||||
|
||||
/* Added timelines are always started first */
|
||||
entry = g_new0(ClutterScoreEntry, 1);
|
||||
entry->timeline = g_object_ref (timeline);
|
||||
entry->score = score;
|
||||
score->priv->entries = g_slist_append (score->priv->entries, entry);
|
||||
closure.action = REMOVE_BY_ID;
|
||||
closure.score = score;
|
||||
closure.d.id = id;
|
||||
closure.result = NULL;
|
||||
|
||||
clutter_timeline_stop (timeline); /* stop it */
|
||||
|
||||
CLUTTER_NOTE (SCHEDULER, "added timeline %p\n", entry->timeline);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_entries (GSList *list)
|
||||
{
|
||||
GSList *item;
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
for (item = list; item != NULL; item = item->next)
|
||||
{
|
||||
ClutterScoreEntry *entry = item->data;
|
||||
|
||||
g_object_unref (entry->timeline);
|
||||
|
||||
if (entry->child_entries)
|
||||
remove_entries (entry->child_entries);
|
||||
|
||||
g_slist_free (entry->child_entries);
|
||||
g_free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
clutter_score_remove (ClutterScore *score,
|
||||
ClutterTimeline *timeline_parent,
|
||||
ClutterTimeline *timeline)
|
||||
{
|
||||
g_node_traverse (priv->root,
|
||||
G_POST_ORDER,
|
||||
G_TRAVERSE_ALL,
|
||||
-1,
|
||||
traverse_children, &closure);
|
||||
|
||||
if (closure.result)
|
||||
g_node_destroy (closure.result);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -595,21 +849,66 @@ clutter_score_remove (ClutterScore *score,
|
||||
void
|
||||
clutter_score_remove_all (ClutterScore *score)
|
||||
{
|
||||
ClutterScorePrivate *priv;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_SCORE (score));
|
||||
|
||||
/* this will take care of the running timelines */
|
||||
clutter_score_stop (score);
|
||||
remove_entries (score->priv->entries);
|
||||
|
||||
priv = score->priv;
|
||||
|
||||
g_node_traverse (priv->root,
|
||||
G_POST_ORDER,
|
||||
G_TRAVERSE_ALL,
|
||||
-1,
|
||||
destroy_entry, NULL);
|
||||
g_node_destroy (priv->root);
|
||||
|
||||
/* sentinel */
|
||||
priv->root = g_node_new (NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_score_new:
|
||||
*
|
||||
* Creates a new #ClutterScore.
|
||||
*
|
||||
* Return value: the newly created #ClutterScore
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
ClutterScore *
|
||||
clutter_score_new (void)
|
||||
ClutterTimeline *
|
||||
clutter_score_get_timeline (ClutterScore *score,
|
||||
guint id)
|
||||
{
|
||||
return g_object_new (CLUTTER_TYPE_SCORE, NULL);
|
||||
GNode *node;
|
||||
ClutterScoreEntry *entry;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_SCORE (score), NULL);
|
||||
g_return_val_if_fail (id > 0, NULL);
|
||||
|
||||
node = find_entry_by_id (score, id);
|
||||
if (G_UNLIKELY (!node))
|
||||
return NULL;
|
||||
|
||||
entry = node->data;
|
||||
|
||||
return entry->timeline;
|
||||
}
|
||||
|
||||
GSList *
|
||||
clutter_score_list_timelines (ClutterScore *score)
|
||||
{
|
||||
ClutterScorePrivate *priv;
|
||||
TraverseClosure closure;
|
||||
GSList *retval;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_SCORE (score), NULL);
|
||||
|
||||
priv = score->priv;
|
||||
|
||||
closure.action = LIST_TIMELINES;
|
||||
closure.result = NULL;
|
||||
|
||||
g_node_traverse (priv->root,
|
||||
G_POST_ORDER,
|
||||
G_TRAVERSE_ALL,
|
||||
-1,
|
||||
traverse_children, &closure);
|
||||
|
||||
retval = closure.result;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -23,41 +23,24 @@
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _HAVE_CLUTTER_SCORE_H
|
||||
#define _HAVE_CLUTTER_SCORE_H
|
||||
#ifndef __CLUTTER_SCORE_H__
|
||||
#define __CLUTTER_SCORE_H__
|
||||
|
||||
/* clutter-score.h */
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter-timeline.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_SCORE clutter_score_get_type()
|
||||
#define CLUTTER_TYPE_SCORE (clutter_score_get_type ())
|
||||
|
||||
#define CLUTTER_SCORE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
|
||||
CLUTTER_TYPE_SCORE, ClutterScore))
|
||||
|
||||
#define CLUTTER_SCORE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), \
|
||||
CLUTTER_TYPE_SCORE, ClutterScoreClass))
|
||||
|
||||
#define CLUTTER_IS_SCORE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
|
||||
CLUTTER_TYPE_SCORE))
|
||||
|
||||
#define CLUTTER_IS_SCORE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
CLUTTER_TYPE_SCORE))
|
||||
|
||||
#define CLUTTER_SCORE_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
|
||||
CLUTTER_TYPE_SCORE, ClutterScoreClass))
|
||||
#define CLUTTER_SCORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_SCORE, ClutterScore))
|
||||
#define CLUTTER_SCORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_SCORE, ClutterScoreClass))
|
||||
#define CLUTTER_IS_SCORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SCORE))
|
||||
#define CLUTTER_IS_SCORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SCORE))
|
||||
#define CLUTTER_SCORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SCORE, ClutterScoreClass))
|
||||
|
||||
typedef struct _ClutterScore ClutterScore;
|
||||
typedef struct _ClutterScoreClass ClutterScoreClass;
|
||||
typedef struct _ClutterScorePrivate ClutterScorePrivate;
|
||||
typedef struct _ClutterScoreClass ClutterScoreClass;
|
||||
|
||||
struct _ClutterScore
|
||||
{
|
||||
@ -68,13 +51,21 @@ struct _ClutterScore
|
||||
|
||||
struct _ClutterScoreClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*new_timeline) (ClutterScore *score, ClutterTimeline *timeline);
|
||||
void (*started) (ClutterScore *score);
|
||||
void (*completed) (ClutterScore *score);
|
||||
void (*paused) (ClutterScore *score);
|
||||
/*< public >*/
|
||||
void (* timeline_started) (ClutterScore *score,
|
||||
ClutterTimeline *timeline);
|
||||
void (* timeline_completed) (ClutterScore *score,
|
||||
ClutterTimeline *timeline);
|
||||
|
||||
void (* started) (ClutterScore *score);
|
||||
void (* completed) (ClutterScore *score);
|
||||
void (* paused) (ClutterScore *score);
|
||||
|
||||
/*< private >*/
|
||||
/* padding for future expansion */
|
||||
void (*_clutter_score_1) (void);
|
||||
void (*_clutter_score_2) (void);
|
||||
void (*_clutter_score_3) (void);
|
||||
@ -84,48 +75,27 @@ struct _ClutterScoreClass
|
||||
|
||||
GType clutter_score_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterScore *clutter_score_new (void);
|
||||
|
||||
void
|
||||
clutter_score_set_loop (ClutterScore *score,
|
||||
ClutterScore * clutter_score_new (void);
|
||||
void clutter_score_set_loop (ClutterScore *score,
|
||||
gboolean loop);
|
||||
gboolean clutter_score_get_loop (ClutterScore *score);
|
||||
gboolean clutter_score_is_playing (ClutterScore *score);
|
||||
|
||||
gboolean
|
||||
clutter_score_get_loop (ClutterScore *score);
|
||||
|
||||
void
|
||||
clutter_score_rewind (ClutterScore *score);
|
||||
|
||||
gboolean
|
||||
clutter_score_is_playing (ClutterScore *score);
|
||||
|
||||
void
|
||||
clutter_score_start (ClutterScore *score);
|
||||
|
||||
void
|
||||
clutter_score_stop (ClutterScore *score);
|
||||
|
||||
void
|
||||
clutter_score_pause (ClutterScore *score);
|
||||
|
||||
void
|
||||
clutter_score_append (ClutterScore *score,
|
||||
ClutterTimeline *timeline_existing,
|
||||
ClutterTimeline *timeline_new);
|
||||
|
||||
void
|
||||
clutter_score_add (ClutterScore *score,
|
||||
guint clutter_score_append (ClutterScore *score,
|
||||
ClutterTimeline *parent,
|
||||
ClutterTimeline *timeline);
|
||||
void clutter_score_remove (ClutterScore *score,
|
||||
guint id);
|
||||
void clutter_score_remove_all (ClutterScore *score);
|
||||
ClutterTimeline *clutter_score_get_timeline (ClutterScore *score,
|
||||
guint id);
|
||||
GSList * clutter_score_list_timelines (ClutterScore *score);
|
||||
|
||||
void
|
||||
clutter_score_remove (ClutterScore *score,
|
||||
ClutterTimeline *timeline_parent,
|
||||
ClutterTimeline *timeline);
|
||||
|
||||
void
|
||||
clutter_score_remove_all (ClutterScore *score);
|
||||
|
||||
void clutter_score_start (ClutterScore *score);
|
||||
void clutter_score_stop (ClutterScore *score);
|
||||
void clutter_score_pause (ClutterScore *score);
|
||||
void clutter_score_rewind (ClutterScore *score);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
#endif /* __CLUTTER_SCORE_H__ */
|
||||
|
@ -1,3 +1,9 @@
|
||||
2007-12-04 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* clutter.types:
|
||||
* clutter-docs.sgml:
|
||||
* clutter-sections.txt: Fix ClutterScore symbols.
|
||||
|
||||
2007-11-30 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* clutter-sections.txt: Update with the newly added API.
|
||||
|
@ -106,6 +106,7 @@
|
||||
<title>Base classes</title>
|
||||
|
||||
<xi:include href="xml/clutter-timeline.xml"/>
|
||||
<xi:include href="xml/clutter-score.xml"/>
|
||||
<xi:include href="xml/clutter-alpha.xml"/>
|
||||
<xi:include href="xml/clutter-behaviour.xml"/>
|
||||
</chapter>
|
||||
|
@ -1212,12 +1212,15 @@ clutter_model_iter_get_type
|
||||
ClutterScore
|
||||
ClutterScoreClass
|
||||
clutter_score_new
|
||||
clutter_score_add
|
||||
clutter_score_set_loop
|
||||
clutter_score_get_loop
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_score_append
|
||||
clutter_score_remove
|
||||
clutter_score_remove_all
|
||||
clutter_score_set_loop
|
||||
clutter_score_get_loop
|
||||
clutter_score_get_timeline
|
||||
clutter_score_list_timelines
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_score_start
|
||||
|
@ -24,3 +24,4 @@ clutter_script_get_type
|
||||
clutter_scriptable_get_type
|
||||
clutter_model_get_type
|
||||
clutter_model_iter_get_type
|
||||
clutter_score_get_type
|
||||
|
@ -2,6 +2,38 @@
|
||||
#include <stdlib.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
static gint level = 1;
|
||||
|
||||
static void
|
||||
on_timeline_started (ClutterScore *score,
|
||||
ClutterTimeline *timeline)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < level; i++)
|
||||
g_print (" ");
|
||||
|
||||
g_print ("Started timeline: `%s'\n",
|
||||
g_object_get_data (G_OBJECT (timeline), "timeline-name"));
|
||||
|
||||
level += 1;
|
||||
}
|
||||
|
||||
static void
|
||||
on_timeline_completed (ClutterScore *score,
|
||||
ClutterTimeline *timeline)
|
||||
{
|
||||
gint i;
|
||||
|
||||
level -= 1;
|
||||
|
||||
for (i = 0; i < level; i++)
|
||||
g_print (" ");
|
||||
|
||||
g_print ("Completed timeline: `%s'\n",
|
||||
g_object_get_data (G_OBJECT (timeline), "timeline-name"));
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@ -14,12 +46,38 @@ main (int argc, char **argv)
|
||||
clutter_init (&argc, &argv);
|
||||
|
||||
timeline_1 = clutter_timeline_new (10, 120);
|
||||
g_object_set_data_full (G_OBJECT (timeline_1),
|
||||
"timeline-name", g_strdup ("Timeline 1"),
|
||||
g_free);
|
||||
|
||||
timeline_2 = clutter_timeline_clone (timeline_1);
|
||||
g_object_set_data_full (G_OBJECT (timeline_2),
|
||||
"timeline-name", g_strdup ("Timeline 2"),
|
||||
g_free);
|
||||
|
||||
timeline_3 = clutter_timeline_clone (timeline_1);
|
||||
g_object_set_data_full (G_OBJECT (timeline_3),
|
||||
"timeline-name", g_strdup ("Timeline 3"),
|
||||
g_free);
|
||||
|
||||
timeline_4 = clutter_timeline_clone (timeline_1);
|
||||
g_object_set_data_full (G_OBJECT (timeline_4),
|
||||
"timeline-name", g_strdup ("Timeline 4"),
|
||||
g_free);
|
||||
|
||||
|
||||
score = clutter_score_new();
|
||||
clutter_score_add (score, timeline_1);
|
||||
g_signal_connect (score, "timeline-started",
|
||||
G_CALLBACK (on_timeline_started),
|
||||
NULL);
|
||||
g_signal_connect (score, "timeline-completed",
|
||||
G_CALLBACK (on_timeline_completed),
|
||||
NULL);
|
||||
g_signal_connect (score, "completed",
|
||||
G_CALLBACK (clutter_main_quit),
|
||||
NULL);
|
||||
|
||||
clutter_score_append (score, NULL, timeline_1);
|
||||
clutter_score_append (score, timeline_1, timeline_2);
|
||||
clutter_score_append (score, timeline_1, timeline_3);
|
||||
clutter_score_append (score, timeline_3, timeline_4);
|
||||
@ -32,6 +90,7 @@ main (int argc, char **argv)
|
||||
g_object_unref (timeline_1);
|
||||
g_object_unref (timeline_2);
|
||||
g_object_unref (timeline_3);
|
||||
g_object_unref (timeline_4);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user