mirror of
https://github.com/brl/mutter.git
synced 2024-11-26 10:00:45 -05:00
2008-03-18 Emmanuele Bassi <ebassi@openedhand.com>
* clutter.symbols: Add new symbols * clutter/clutter-score.[ch]: Use the newly added marker API on the timelines to implement attaching timelines at specific points, using either milliseconds or frames. * tests/test-score.c (main): Test the new API.
This commit is contained in:
parent
43d9d579b4
commit
b6b9dd7c65
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
|||||||
|
2008-03-18 Emmanuele Bassi <ebassi@openedhand.com>
|
||||||
|
|
||||||
|
* clutter.symbols: Add new symbols
|
||||||
|
|
||||||
|
* clutter/clutter-score.[ch]: Use the newly added marker API
|
||||||
|
on the timelines to implement attaching timelines at specific
|
||||||
|
points, using either milliseconds or frames.
|
||||||
|
|
||||||
|
* tests/test-score.c (main): Test the new API.
|
||||||
|
|
||||||
2008-03-18 Emmanuele Bassi <ebassi@openedhand.com>
|
2008-03-18 Emmanuele Bassi <ebassi@openedhand.com>
|
||||||
|
|
||||||
* clutter/clutter-marshal.list: Add signature for the
|
* clutter/clutter-marshal.list: Add signature for the
|
||||||
|
@ -442,6 +442,8 @@ clutter_redraw
|
|||||||
clutter_rotate_axis_get_type
|
clutter_rotate_axis_get_type
|
||||||
clutter_rotate_direction_get_type
|
clutter_rotate_direction_get_type
|
||||||
clutter_score_append
|
clutter_score_append
|
||||||
|
clutter_score_append_at_frame
|
||||||
|
clutter_score_append_at_time
|
||||||
clutter_score_get_loop
|
clutter_score_get_loop
|
||||||
clutter_score_get_timeline
|
clutter_score_get_timeline
|
||||||
clutter_score_get_type
|
clutter_score_get_type
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
* For example, this code will start two #ClutterTimeline<!-- -->s after
|
* For example, this code will start two #ClutterTimeline<!-- -->s after
|
||||||
* a third timeline terminates:
|
* a third timeline terminates:
|
||||||
*
|
*
|
||||||
* <informalexample><programlisting>
|
* |[
|
||||||
* ClutterTimeline *timeline_1, *timeline_2, *timeline_3;
|
* ClutterTimeline *timeline_1, *timeline_2, *timeline_3;
|
||||||
* ClutterScore *score;
|
* ClutterScore *score;
|
||||||
*
|
*
|
||||||
@ -52,12 +52,17 @@
|
|||||||
* clutter_score_append (score, timeline_1, timeline_3);
|
* clutter_score_append (score, timeline_1, timeline_3);
|
||||||
*
|
*
|
||||||
* clutter_score_start ();
|
* clutter_score_start ();
|
||||||
* </programlisting></informalexample>
|
* ]|
|
||||||
*
|
*
|
||||||
* A #ClutterScore takes a reference on the timelines it manages.
|
* A #ClutterScore takes a reference on the timelines it manages.
|
||||||
*
|
*
|
||||||
* New timelines can be added to the #ClutterScore using
|
* New timelines can be appended to the #ClutterScore using
|
||||||
* clutter_score_append() and removed using clutter_score_remove().
|
* clutter_score_append() and removed using clutter_score_remove().
|
||||||
|
* Timelines can either be appended at the end of other timelines
|
||||||
|
* or at the beginning of the score using clutter_score_append().
|
||||||
|
* Timelines can also be appeneded at a specific position, expressed
|
||||||
|
* in either millisecond or frame number, of the parent timeline,
|
||||||
|
* using clutter_score_append_at_time() or clutter_score_append_at_frame().
|
||||||
*
|
*
|
||||||
* The score can be cleared using clutter_score_remove_all().
|
* The score can be cleared using clutter_score_remove_all().
|
||||||
*
|
*
|
||||||
@ -81,15 +86,29 @@
|
|||||||
#include "clutter-private.h"
|
#include "clutter-private.h"
|
||||||
#include "clutter-debug.h"
|
#include "clutter-debug.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SCORE_ENTRY_TIME,
|
||||||
|
SCORE_ENTRY_FRAME,
|
||||||
|
SCORE_ENTRY_APPEND
|
||||||
|
} ClutterScoreEntryType;
|
||||||
|
|
||||||
typedef struct _ClutterScoreEntry ClutterScoreEntry;
|
typedef struct _ClutterScoreEntry ClutterScoreEntry;
|
||||||
|
|
||||||
struct _ClutterScoreEntry
|
struct _ClutterScoreEntry
|
||||||
{
|
{
|
||||||
ClutterTimeline *timeline;
|
ClutterScoreEntryType type;
|
||||||
guint id;
|
|
||||||
|
|
||||||
/* signal handler id */
|
gchar *id;
|
||||||
gulong completed_id;
|
|
||||||
|
ClutterTimeline *timeline;
|
||||||
|
ClutterTimeline *parent;
|
||||||
|
|
||||||
|
guint msecs;
|
||||||
|
guint frame;
|
||||||
|
|
||||||
|
/* signal handlers id */
|
||||||
|
guint complete_id;
|
||||||
|
guint marker_id;
|
||||||
|
|
||||||
ClutterScore *score;
|
ClutterScore *score;
|
||||||
|
|
||||||
@ -130,6 +149,8 @@ enum
|
|||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline void clutter_score_clear (ClutterScore *score);
|
||||||
|
|
||||||
G_DEFINE_TYPE (ClutterScore, clutter_score, G_TYPE_OBJECT);
|
G_DEFINE_TYPE (ClutterScore, clutter_score, G_TYPE_OBJECT);
|
||||||
|
|
||||||
static int score_signals[LAST_SIGNAL] = { 0 };
|
static int score_signals[LAST_SIGNAL] = { 0 };
|
||||||
@ -177,26 +198,14 @@ clutter_score_get_property (GObject *gobject,
|
|||||||
static void
|
static void
|
||||||
clutter_score_finalize (GObject *object)
|
clutter_score_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
ClutterScorePrivate *priv = CLUTTER_SCORE (object)->priv;
|
ClutterScore *score = CLUTTER_SCORE (object);
|
||||||
|
|
||||||
if (priv->running_timelines)
|
clutter_score_stop (score);
|
||||||
g_hash_table_destroy (priv->running_timelines);
|
clutter_score_clear (score);
|
||||||
|
|
||||||
G_OBJECT_CLASS (clutter_score_parent_class)->finalize (object);
|
G_OBJECT_CLASS (clutter_score_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
clutter_score_dispose (GObject *object)
|
|
||||||
{
|
|
||||||
ClutterScore *self = CLUTTER_SCORE(object);
|
|
||||||
ClutterScorePrivate *priv;
|
|
||||||
|
|
||||||
priv = self->priv;
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (clutter_score_parent_class)->dispose (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_score_class_init (ClutterScoreClass *klass)
|
clutter_score_class_init (ClutterScoreClass *klass)
|
||||||
{
|
{
|
||||||
@ -205,7 +214,6 @@ clutter_score_class_init (ClutterScoreClass *klass)
|
|||||||
gobject_class->set_property = clutter_score_set_property;
|
gobject_class->set_property = clutter_score_set_property;
|
||||||
gobject_class->get_property = clutter_score_get_property;
|
gobject_class->get_property = clutter_score_get_property;
|
||||||
gobject_class->finalize = clutter_score_finalize;
|
gobject_class->finalize = clutter_score_finalize;
|
||||||
gobject_class->dispose = clutter_score_dispose;
|
|
||||||
|
|
||||||
g_type_class_add_private (klass, sizeof (ClutterScorePrivate));
|
g_type_class_add_private (klass, sizeof (ClutterScorePrivate));
|
||||||
|
|
||||||
@ -411,6 +419,178 @@ clutter_score_is_playing (ClutterScore *score)
|
|||||||
return (g_hash_table_size (score->priv->running_timelines) != 0);
|
return (g_hash_table_size (score->priv->running_timelines) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FIND_BY_TIMELINE,
|
||||||
|
FIND_BY_ID,
|
||||||
|
REMOVE_BY_ID,
|
||||||
|
LIST_TIMELINES
|
||||||
|
} TraverseAction;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TraverseAction action;
|
||||||
|
|
||||||
|
ClutterScore *score;
|
||||||
|
|
||||||
|
/* parameters */
|
||||||
|
union {
|
||||||
|
ClutterTimeline *timeline;
|
||||||
|
const gchar *id;
|
||||||
|
ClutterScoreEntry *entry;
|
||||||
|
} d;
|
||||||
|
|
||||||
|
gpointer result;
|
||||||
|
} TraverseClosure;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
destroy_entry (GNode *node,
|
||||||
|
G_GNUC_UNUSED gpointer data)
|
||||||
|
{
|
||||||
|
ClutterScoreEntry *entry = node->data;
|
||||||
|
|
||||||
|
if (G_LIKELY (entry != NULL))
|
||||||
|
{
|
||||||
|
if (entry->marker_id)
|
||||||
|
{
|
||||||
|
g_signal_handler_disconnect (entry->parent, entry->marker_id);
|
||||||
|
entry->marker_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->complete_id)
|
||||||
|
{
|
||||||
|
g_signal_handler_disconnect (entry->timeline, entry->complete_id);
|
||||||
|
entry->complete_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (entry->timeline);
|
||||||
|
g_free (entry->id);
|
||||||
|
g_slice_free (ClutterScoreEntry, entry);
|
||||||
|
|
||||||
|
node->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* continue */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* multi-purpose traversal function for the N-ary tree used by the score */
|
||||||
|
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 (strcmp (closure->d.id, entry->id) == 0)
|
||||||
|
{
|
||||||
|
closure->result = node;
|
||||||
|
retval = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMOVE_BY_ID:
|
||||||
|
if (strcmp (closure->d.id, entry->id) == 0)
|
||||||
|
{
|
||||||
|
if (entry->complete_id)
|
||||||
|
{
|
||||||
|
g_signal_handler_disconnect (entry->timeline, entry->complete_id);
|
||||||
|
entry->complete_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->marker_id)
|
||||||
|
{
|
||||||
|
g_signal_handler_disconnect (entry->timeline, entry->marker_id);
|
||||||
|
entry->marker_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (entry->timeline);
|
||||||
|
g_free (entry->id);
|
||||||
|
|
||||||
|
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:
|
||||||
|
closure->result = g_slist_prepend (closure->result, entry->timeline);
|
||||||
|
retval = FALSE;
|
||||||
|
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,
|
||||||
|
const gchar *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;
|
||||||
|
}
|
||||||
|
|
||||||
/* forward declaration */
|
/* forward declaration */
|
||||||
static void start_entry (ClutterScoreEntry *entry);
|
static void start_entry (ClutterScoreEntry *entry);
|
||||||
|
|
||||||
@ -424,18 +604,42 @@ start_children_entries (GNode *node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_timeline_finish (ClutterTimeline *timeline,
|
on_timeline_marker (ClutterTimeline *timeline,
|
||||||
ClutterScoreEntry *entry)
|
const gchar *marker_name,
|
||||||
|
gint frame_num,
|
||||||
|
ClutterScoreEntry *entry)
|
||||||
|
{
|
||||||
|
GNode *parent;
|
||||||
|
CLUTTER_NOTE (SCHEDULER, "timeline [%p] marker ('%s') reached",
|
||||||
|
entry->timeline,
|
||||||
|
entry->id);
|
||||||
|
|
||||||
|
parent = find_entry_by_timeline (entry->score, timeline);
|
||||||
|
if (!parent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* start every child */
|
||||||
|
if (parent->children)
|
||||||
|
{
|
||||||
|
g_node_children_foreach (parent,
|
||||||
|
G_TRAVERSE_ALL,
|
||||||
|
start_children_entries,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_timeline_completed (ClutterTimeline *timeline,
|
||||||
|
ClutterScoreEntry *entry)
|
||||||
{
|
{
|
||||||
ClutterScorePrivate *priv = entry->score->priv;
|
ClutterScorePrivate *priv = entry->score->priv;
|
||||||
|
|
||||||
g_hash_table_remove (priv->running_timelines,
|
g_hash_table_remove (priv->running_timelines, entry->id);
|
||||||
GINT_TO_POINTER (entry->id));
|
|
||||||
|
|
||||||
g_signal_handler_disconnect (timeline, entry->completed_id);
|
g_signal_handler_disconnect (timeline, entry->complete_id);
|
||||||
entry->completed_id = 0;
|
entry->complete_id = 0;
|
||||||
|
|
||||||
CLUTTER_NOTE (SCHEDULER, "timeline [%p] (%d) completed",
|
CLUTTER_NOTE (SCHEDULER, "timeline [%p] ('%s') completed",
|
||||||
entry->timeline,
|
entry->timeline,
|
||||||
entry->id);
|
entry->id);
|
||||||
|
|
||||||
@ -470,21 +674,22 @@ start_entry (ClutterScoreEntry *entry)
|
|||||||
{
|
{
|
||||||
ClutterScorePrivate *priv = entry->score->priv;
|
ClutterScorePrivate *priv = entry->score->priv;
|
||||||
|
|
||||||
entry->completed_id =
|
if (clutter_timeline_is_playing (entry->timeline))
|
||||||
g_signal_connect (entry->timeline,
|
return;
|
||||||
"completed", G_CALLBACK (on_timeline_finish),
|
|
||||||
entry);
|
|
||||||
|
|
||||||
CLUTTER_NOTE (SCHEDULER, "timeline [%p] (%d) started",
|
entry->complete_id = g_signal_connect (entry->timeline,
|
||||||
|
"completed",
|
||||||
|
G_CALLBACK (on_timeline_completed),
|
||||||
|
entry);
|
||||||
|
|
||||||
|
CLUTTER_NOTE (SCHEDULER, "timeline [%p] ('%s') started",
|
||||||
entry->timeline,
|
entry->timeline,
|
||||||
entry->id);
|
entry->id);
|
||||||
|
|
||||||
if (G_UNLIKELY (priv->running_timelines == NULL))
|
if (G_UNLIKELY (priv->running_timelines == NULL))
|
||||||
priv->running_timelines = g_hash_table_new (NULL, NULL);
|
priv->running_timelines = g_hash_table_new (g_str_hash, g_str_equal);
|
||||||
|
|
||||||
g_hash_table_insert (priv->running_timelines,
|
g_hash_table_insert (priv->running_timelines, entry->id, entry);
|
||||||
GINT_TO_POINTER (entry->id),
|
|
||||||
entry);
|
|
||||||
|
|
||||||
clutter_timeline_start (entry->timeline);
|
clutter_timeline_start (entry->timeline);
|
||||||
|
|
||||||
@ -499,7 +704,8 @@ foreach_running_timeline_start (gpointer key,
|
|||||||
{
|
{
|
||||||
ClutterScoreEntry *entry = value;
|
ClutterScoreEntry *entry = value;
|
||||||
|
|
||||||
clutter_timeline_start (entry->timeline);
|
if (!clutter_timeline_is_playing (entry->timeline))
|
||||||
|
clutter_timeline_start (entry->timeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -564,11 +770,14 @@ clutter_score_stop (ClutterScore *score)
|
|||||||
|
|
||||||
priv = score->priv;
|
priv = score->priv;
|
||||||
|
|
||||||
g_hash_table_foreach_remove (priv->running_timelines,
|
if (priv->running_timelines)
|
||||||
foreach_running_timeline_stop,
|
{
|
||||||
NULL);
|
g_hash_table_foreach_remove (priv->running_timelines,
|
||||||
g_hash_table_destroy (priv->running_timelines);
|
foreach_running_timeline_stop,
|
||||||
priv->running_timelines = NULL;
|
NULL);
|
||||||
|
g_hash_table_destroy (priv->running_timelines);
|
||||||
|
priv->running_timelines = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -633,161 +842,23 @@ clutter_score_pause (ClutterScore *score)
|
|||||||
g_signal_emit (score, score_signals[PAUSED], 0);
|
g_signal_emit (score, score_signals[PAUSED], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
static inline void
|
||||||
FIND_BY_TIMELINE,
|
clutter_score_clear (ClutterScore *score)
|
||||||
FIND_BY_ID,
|
|
||||||
REMOVE_BY_ID,
|
|
||||||
LIST_TIMELINES
|
|
||||||
} TraverseAction;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
TraverseAction action;
|
|
||||||
|
|
||||||
ClutterScore *score;
|
|
||||||
|
|
||||||
/* parameters */
|
|
||||||
union {
|
|
||||||
ClutterTimeline *timeline;
|
|
||||||
guint id;
|
|
||||||
ClutterScoreEntry *entry;
|
|
||||||
} d;
|
|
||||||
|
|
||||||
gpointer result;
|
|
||||||
} TraverseClosure;
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
destroy_entry (GNode *node,
|
|
||||||
G_GNUC_UNUSED gpointer data)
|
|
||||||
{
|
|
||||||
ClutterScoreEntry *entry = node->data;
|
|
||||||
|
|
||||||
if (G_LIKELY (entry != NULL))
|
|
||||||
{
|
|
||||||
if (entry->completed_id)
|
|
||||||
g_signal_handler_disconnect (entry->timeline, entry->completed_id);
|
|
||||||
|
|
||||||
g_object_unref (entry->timeline);
|
|
||||||
g_slice_free (ClutterScoreEntry, entry);
|
|
||||||
|
|
||||||
node->data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* continue */
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* multi-purpose traversal function for the N-ary tree used by the score */
|
|
||||||
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:
|
|
||||||
closure->result = g_slist_prepend (closure->result, entry->timeline);
|
|
||||||
retval = FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GNode *
|
|
||||||
find_entry_by_timeline (ClutterScore *score,
|
|
||||||
ClutterTimeline *timeline)
|
|
||||||
{
|
{
|
||||||
ClutterScorePrivate *priv = score->priv;
|
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_node_traverse (priv->root,
|
||||||
G_POST_ORDER,
|
G_POST_ORDER,
|
||||||
G_TRAVERSE_ALL,
|
G_TRAVERSE_ALL,
|
||||||
-1,
|
-1,
|
||||||
traverse_children, &closure);
|
destroy_entry, NULL);
|
||||||
|
g_node_destroy (priv->root);
|
||||||
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:
|
* clutter_score_append:
|
||||||
* @score: a #ClutterScore
|
* @score: a #ClutterScore
|
||||||
|
* @id: a unique string identifying the timeline
|
||||||
* @parent: a #ClutterTimeline in the score or %NULL
|
* @parent: a #ClutterTimeline in the score or %NULL
|
||||||
* @timeline: a #ClutterTimeline
|
* @timeline: a #ClutterTimeline
|
||||||
*
|
*
|
||||||
@ -799,21 +870,20 @@ find_entry_by_id (ClutterScore *score,
|
|||||||
*
|
*
|
||||||
* #ClutterScore will take a reference on @timeline.
|
* #ClutterScore will take a reference on @timeline.
|
||||||
*
|
*
|
||||||
* Return value: the id of the newly added timeline, to be used with
|
* Since: 0.8
|
||||||
* clutter_score_get_timeline() and clutter_score_remove().
|
|
||||||
*
|
|
||||||
* Since: 0.6
|
|
||||||
*/
|
*/
|
||||||
guint
|
void
|
||||||
clutter_score_append (ClutterScore *score,
|
clutter_score_append (ClutterScore *score,
|
||||||
|
const gchar *id,
|
||||||
ClutterTimeline *parent,
|
ClutterTimeline *parent,
|
||||||
ClutterTimeline *timeline)
|
ClutterTimeline *timeline)
|
||||||
{
|
{
|
||||||
ClutterScorePrivate *priv;
|
ClutterScorePrivate *priv;
|
||||||
|
|
||||||
g_return_val_if_fail (CLUTTER_IS_SCORE (score), 0);
|
g_return_if_fail (CLUTTER_IS_SCORE (score));
|
||||||
g_return_val_if_fail (parent == NULL || CLUTTER_IS_TIMELINE (parent), 0);
|
g_return_if_fail (id != NULL);
|
||||||
g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), 0);
|
g_return_if_fail (parent == NULL || CLUTTER_IS_TIMELINE (parent));
|
||||||
|
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
|
||||||
|
|
||||||
priv = score->priv;
|
priv = score->priv;
|
||||||
|
|
||||||
@ -822,17 +892,14 @@ clutter_score_append (ClutterScore *score,
|
|||||||
ClutterScoreEntry *entry;
|
ClutterScoreEntry *entry;
|
||||||
|
|
||||||
entry = g_slice_new (ClutterScoreEntry);
|
entry = g_slice_new (ClutterScoreEntry);
|
||||||
|
entry->type = SCORE_ENTRY_APPEND;
|
||||||
entry->timeline = g_object_ref (timeline);
|
entry->timeline = g_object_ref (timeline);
|
||||||
entry->id = priv->last_id;
|
entry->parent = NULL;
|
||||||
entry->completed_id = 0;
|
entry->id = g_strdup (id);
|
||||||
|
entry->marker_id = 0;
|
||||||
entry->score = score;
|
entry->score = score;
|
||||||
|
|
||||||
entry->node = g_node_append_data (priv->root, entry);
|
entry->node = g_node_append_data (priv->root, entry);
|
||||||
|
|
||||||
priv->last_id += 1;
|
|
||||||
|
|
||||||
return entry->id;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -843,23 +910,159 @@ clutter_score_append (ClutterScore *score,
|
|||||||
if (G_UNLIKELY (!node))
|
if (G_UNLIKELY (!node))
|
||||||
{
|
{
|
||||||
g_warning ("Unable to find the parent timeline inside the score.");
|
g_warning ("Unable to find the parent timeline inside the score.");
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = g_slice_new (ClutterScoreEntry);
|
entry = g_slice_new (ClutterScoreEntry);
|
||||||
|
entry->type = SCORE_ENTRY_APPEND;
|
||||||
entry->timeline = g_object_ref (timeline);
|
entry->timeline = g_object_ref (timeline);
|
||||||
entry->id = priv->last_id;
|
entry->parent = parent;
|
||||||
entry->completed_id = 0;
|
entry->id = g_strdup (id);
|
||||||
|
entry->marker_id = 0;
|
||||||
entry->score = score;
|
entry->score = score;
|
||||||
|
|
||||||
entry->node = g_node_append_data (node, entry);
|
entry->node = g_node_append_data (node, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
priv->last_id += 1;
|
/**
|
||||||
|
* clutter_score_append_at_time:
|
||||||
|
* @score: a #ClutterScore
|
||||||
|
* @id: a unique string identifying the timeline
|
||||||
|
* @parent: the parent #ClutterTimeline
|
||||||
|
* @msecs: the time on @parent where the new timeline should
|
||||||
|
* be appended, in milliseconds
|
||||||
|
* @timeline: the #ClutterTimeline to append
|
||||||
|
*
|
||||||
|
* Appends @timeline at the given position on the @parent timeline,
|
||||||
|
* expressed in milliseconds.
|
||||||
|
*
|
||||||
|
* This function implicitly creates a timeline marker (see
|
||||||
|
* clutter_timeline_add_marker_at_time()) with the given @id on
|
||||||
|
* @parent.
|
||||||
|
*
|
||||||
|
* If you want to append @timeline at the end of @parent, use
|
||||||
|
* clutter_score_append().
|
||||||
|
*
|
||||||
|
* Since: 0.8
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_score_append_at_time (ClutterScore *score,
|
||||||
|
const gchar *id,
|
||||||
|
ClutterTimeline *parent,
|
||||||
|
guint msecs,
|
||||||
|
ClutterTimeline *timeline)
|
||||||
|
{
|
||||||
|
ClutterScorePrivate *priv;
|
||||||
|
GNode *node;
|
||||||
|
ClutterScoreEntry *entry;
|
||||||
|
gchar *marker_reached_signal;
|
||||||
|
|
||||||
return entry->id;
|
g_return_if_fail (CLUTTER_IS_SCORE (score));
|
||||||
|
g_return_if_fail (id != NULL);
|
||||||
|
g_return_if_fail (CLUTTER_IS_TIMELINE (parent));
|
||||||
|
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
|
||||||
|
|
||||||
|
priv = score->priv;
|
||||||
|
|
||||||
|
node = find_entry_by_timeline (score, parent);
|
||||||
|
if (G_UNLIKELY (!node))
|
||||||
|
{
|
||||||
|
g_warning ("Unable to find the parent timeline inside the score.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
entry = g_slice_new (ClutterScoreEntry);
|
||||||
|
entry->type = SCORE_ENTRY_TIME;
|
||||||
|
entry->timeline = g_object_ref (timeline);
|
||||||
|
entry->parent = parent;
|
||||||
|
entry->msecs = msecs;
|
||||||
|
entry->id = g_strdup (id);
|
||||||
|
entry->score = score;
|
||||||
|
|
||||||
|
clutter_timeline_add_marker_at_time (entry->parent,
|
||||||
|
entry->id,
|
||||||
|
entry->msecs);
|
||||||
|
|
||||||
|
marker_reached_signal = g_strdup_printf ("marker-reached::%s", entry->id);
|
||||||
|
entry->marker_id = g_signal_connect (entry->parent,
|
||||||
|
marker_reached_signal,
|
||||||
|
G_CALLBACK (on_timeline_marker),
|
||||||
|
entry);
|
||||||
|
|
||||||
|
entry->node = g_node_append_data (node, entry);
|
||||||
|
|
||||||
|
g_free (marker_reached_signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_score_append_at_frame:
|
||||||
|
* @score: a #ClutterScore
|
||||||
|
* @id: a unique string identifying the timeline
|
||||||
|
* @parent: the parent #ClutterTimeline
|
||||||
|
* @msecs: the frame of @parent where the new timeline should
|
||||||
|
* be appended to
|
||||||
|
* @timeline: the #ClutterTimeline to append
|
||||||
|
*
|
||||||
|
* Appends @timeline at the given position on the @parent timeline,
|
||||||
|
* expressed as a frame number.
|
||||||
|
*
|
||||||
|
* This function implicitly creates a timeline marker (see
|
||||||
|
* clutter_timeline_add_marker_at_frame()) with the given @id
|
||||||
|
* on @parent.
|
||||||
|
*
|
||||||
|
* If you want to append @timeline at the end of @parent, use
|
||||||
|
* clutter_score_append().
|
||||||
|
*
|
||||||
|
* Since: 0.8
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_score_append_at_frame (ClutterScore *score,
|
||||||
|
const gchar *id,
|
||||||
|
ClutterTimeline *parent,
|
||||||
|
guint frame,
|
||||||
|
ClutterTimeline *timeline)
|
||||||
|
{
|
||||||
|
ClutterScorePrivate *priv;
|
||||||
|
GNode *node;
|
||||||
|
ClutterScoreEntry *entry;
|
||||||
|
gchar *marker_reached_signal;
|
||||||
|
|
||||||
|
g_return_if_fail (CLUTTER_IS_SCORE (score));
|
||||||
|
g_return_if_fail (id != NULL);
|
||||||
|
g_return_if_fail (CLUTTER_IS_TIMELINE (parent));
|
||||||
|
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
|
||||||
|
|
||||||
|
priv = score->priv;
|
||||||
|
|
||||||
|
node = find_entry_by_timeline (score, parent);
|
||||||
|
if (G_UNLIKELY (!node))
|
||||||
|
{
|
||||||
|
g_warning ("Unable to find the parent timeline inside the score.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = g_slice_new (ClutterScoreEntry);
|
||||||
|
entry->type = SCORE_ENTRY_TIME;
|
||||||
|
entry->timeline = g_object_ref (timeline);
|
||||||
|
entry->parent = parent;
|
||||||
|
entry->frame = frame;
|
||||||
|
entry->id = g_strdup (id);
|
||||||
|
entry->score = score;
|
||||||
|
|
||||||
|
clutter_timeline_add_marker_at_frame (entry->parent,
|
||||||
|
entry->id,
|
||||||
|
entry->frame);
|
||||||
|
|
||||||
|
marker_reached_signal = g_strdup_printf ("marker-reached::%s", entry->id);
|
||||||
|
entry->marker_id = g_signal_connect (entry->parent,
|
||||||
|
marker_reached_signal,
|
||||||
|
G_CALLBACK (on_timeline_marker),
|
||||||
|
entry);
|
||||||
|
|
||||||
|
entry->node = g_node_append_data (node, entry);
|
||||||
|
|
||||||
|
g_free (marker_reached_signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -871,11 +1074,11 @@ clutter_score_append (ClutterScore *score,
|
|||||||
* the timeline has other timelines attached to it, those are removed
|
* the timeline has other timelines attached to it, those are removed
|
||||||
* as well.
|
* as well.
|
||||||
*
|
*
|
||||||
* Since: 0.6
|
* Since: 0.8
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
clutter_score_remove (ClutterScore *score,
|
clutter_score_remove (ClutterScore *score,
|
||||||
guint id)
|
const gchar *id)
|
||||||
{
|
{
|
||||||
ClutterScorePrivate *priv;
|
ClutterScorePrivate *priv;
|
||||||
TraverseClosure closure;
|
TraverseClosure closure;
|
||||||
@ -915,17 +1118,13 @@ clutter_score_remove_all (ClutterScore *score)
|
|||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_SCORE (score));
|
g_return_if_fail (CLUTTER_IS_SCORE (score));
|
||||||
|
|
||||||
|
priv = score->priv;
|
||||||
|
|
||||||
/* this will take care of the running timelines */
|
/* this will take care of the running timelines */
|
||||||
clutter_score_stop (score);
|
clutter_score_stop (score);
|
||||||
|
|
||||||
priv = score->priv;
|
/* destroy all the contents of the tree */
|
||||||
|
clutter_score_clear (score);
|
||||||
g_node_traverse (priv->root,
|
|
||||||
G_POST_ORDER,
|
|
||||||
G_TRAVERSE_ALL,
|
|
||||||
-1,
|
|
||||||
destroy_entry, NULL);
|
|
||||||
g_node_destroy (priv->root);
|
|
||||||
|
|
||||||
/* recreate the sentinel */
|
/* recreate the sentinel */
|
||||||
priv->root = g_node_new (NULL);
|
priv->root = g_node_new (NULL);
|
||||||
@ -941,11 +1140,11 @@ clutter_score_remove_all (ClutterScore *score)
|
|||||||
* Return value: the requested timeline, or %NULL. This function does
|
* Return value: the requested timeline, or %NULL. This function does
|
||||||
* not increase the reference count on the returned #ClutterTimeline
|
* not increase the reference count on the returned #ClutterTimeline
|
||||||
*
|
*
|
||||||
* Since: 0.6
|
* Since: 0.8
|
||||||
*/
|
*/
|
||||||
ClutterTimeline *
|
ClutterTimeline *
|
||||||
clutter_score_get_timeline (ClutterScore *score,
|
clutter_score_get_timeline (ClutterScore *score,
|
||||||
guint id)
|
const gchar *id)
|
||||||
{
|
{
|
||||||
GNode *node;
|
GNode *node;
|
||||||
ClutterScoreEntry *entry;
|
ClutterScoreEntry *entry;
|
||||||
|
@ -76,25 +76,37 @@ struct _ClutterScoreClass
|
|||||||
GType clutter_score_get_type (void) G_GNUC_CONST;
|
GType clutter_score_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
ClutterScore * clutter_score_new (void);
|
ClutterScore * clutter_score_new (void);
|
||||||
void clutter_score_set_loop (ClutterScore *score,
|
|
||||||
gboolean loop);
|
|
||||||
gboolean clutter_score_get_loop (ClutterScore *score);
|
|
||||||
|
|
||||||
guint clutter_score_append (ClutterScore *score,
|
void clutter_score_set_loop (ClutterScore *score,
|
||||||
ClutterTimeline *parent,
|
gboolean loop);
|
||||||
ClutterTimeline *timeline);
|
gboolean clutter_score_get_loop (ClutterScore *score);
|
||||||
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_start (ClutterScore *score);
|
void clutter_score_append_at_time (ClutterScore *score,
|
||||||
void clutter_score_stop (ClutterScore *score);
|
const gchar *id,
|
||||||
void clutter_score_pause (ClutterScore *score);
|
ClutterTimeline *parent,
|
||||||
void clutter_score_rewind (ClutterScore *score);
|
guint msecs,
|
||||||
gboolean clutter_score_is_playing (ClutterScore *score);
|
ClutterTimeline *timeline);
|
||||||
|
void clutter_score_append_at_frame (ClutterScore *score,
|
||||||
|
const gchar *id,
|
||||||
|
ClutterTimeline *parent,
|
||||||
|
guint frame,
|
||||||
|
ClutterTimeline *timeline);
|
||||||
|
void clutter_score_append (ClutterScore *score,
|
||||||
|
const gchar *id,
|
||||||
|
ClutterTimeline *parent,
|
||||||
|
ClutterTimeline *timeline);
|
||||||
|
void clutter_score_remove (ClutterScore *score,
|
||||||
|
const gchar *id);
|
||||||
|
void clutter_score_remove_all (ClutterScore *score);
|
||||||
|
ClutterTimeline *clutter_score_get_timeline (ClutterScore *score,
|
||||||
|
const gchar *id);
|
||||||
|
GSList * clutter_score_list_timelines (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);
|
||||||
|
gboolean clutter_score_is_playing (ClutterScore *score);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
@ -42,31 +42,35 @@ main (int argc, char **argv)
|
|||||||
ClutterTimeline *timeline_2;
|
ClutterTimeline *timeline_2;
|
||||||
ClutterTimeline *timeline_3;
|
ClutterTimeline *timeline_3;
|
||||||
ClutterTimeline *timeline_4;
|
ClutterTimeline *timeline_4;
|
||||||
|
ClutterTimeline *timeline_5;
|
||||||
GSList *timelines;
|
GSList *timelines;
|
||||||
guint t1, t2, t3, t4;
|
|
||||||
|
|
||||||
clutter_init (&argc, &argv);
|
clutter_init (&argc, &argv);
|
||||||
|
|
||||||
timeline_1 = clutter_timeline_new (10, 120);
|
timeline_1 = clutter_timeline_new_for_duration (1000);
|
||||||
g_object_set_data_full (G_OBJECT (timeline_1),
|
g_object_set_data_full (G_OBJECT (timeline_1),
|
||||||
"timeline-name", g_strdup ("Timeline 1"),
|
"timeline-name", g_strdup ("Timeline 1"),
|
||||||
g_free);
|
g_free);
|
||||||
|
|
||||||
timeline_2 = clutter_timeline_clone (timeline_1);
|
timeline_2 = clutter_timeline_new_for_duration (1000);
|
||||||
g_object_set_data_full (G_OBJECT (timeline_2),
|
g_object_set_data_full (G_OBJECT (timeline_2),
|
||||||
"timeline-name", g_strdup ("Timeline 2"),
|
"timeline-name", g_strdup ("Timeline 2"),
|
||||||
g_free);
|
g_free);
|
||||||
|
|
||||||
timeline_3 = clutter_timeline_clone (timeline_1);
|
timeline_3 = clutter_timeline_new_for_duration (1000);
|
||||||
g_object_set_data_full (G_OBJECT (timeline_3),
|
g_object_set_data_full (G_OBJECT (timeline_3),
|
||||||
"timeline-name", g_strdup ("Timeline 3"),
|
"timeline-name", g_strdup ("Timeline 3"),
|
||||||
g_free);
|
g_free);
|
||||||
|
|
||||||
timeline_4 = clutter_timeline_clone (timeline_1);
|
timeline_4 = clutter_timeline_new_for_duration (1000);
|
||||||
g_object_set_data_full (G_OBJECT (timeline_4),
|
g_object_set_data_full (G_OBJECT (timeline_4),
|
||||||
"timeline-name", g_strdup ("Timeline 4"),
|
"timeline-name", g_strdup ("Timeline 4"),
|
||||||
g_free);
|
g_free);
|
||||||
|
|
||||||
|
timeline_5 = clutter_timeline_new_for_duration (1000);
|
||||||
|
g_object_set_data_full (G_OBJECT (timeline_5),
|
||||||
|
"timeline-name", g_strdup ("Timeline 5"),
|
||||||
|
g_free);
|
||||||
|
|
||||||
score = clutter_score_new();
|
score = clutter_score_new();
|
||||||
g_signal_connect (score, "timeline-started",
|
g_signal_connect (score, "timeline-started",
|
||||||
@ -79,13 +83,15 @@ main (int argc, char **argv)
|
|||||||
G_CALLBACK (clutter_main_quit),
|
G_CALLBACK (clutter_main_quit),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
t1 = clutter_score_append (score, NULL, timeline_1);
|
clutter_score_append (score, "line-0", NULL, timeline_1);
|
||||||
t2 = clutter_score_append (score, timeline_1, timeline_2);
|
clutter_score_append (score, "line-1", timeline_1, timeline_2);
|
||||||
t3 = clutter_score_append (score, timeline_1, timeline_3);
|
clutter_score_append (score, "line-2", timeline_1, timeline_3);
|
||||||
t4 = clutter_score_append (score, timeline_3, timeline_4);
|
clutter_score_append (score, "line-3", timeline_3, timeline_4);
|
||||||
|
|
||||||
|
clutter_score_append_at_time (score, "line-4", timeline_2, 500, timeline_5);
|
||||||
|
|
||||||
timelines = clutter_score_list_timelines (score);
|
timelines = clutter_score_list_timelines (score);
|
||||||
g_assert (4 == g_slist_length (timelines));
|
g_assert (5 == g_slist_length (timelines));
|
||||||
g_slist_free (timelines);
|
g_slist_free (timelines);
|
||||||
|
|
||||||
clutter_score_start (score);
|
clutter_score_start (score);
|
||||||
@ -96,6 +102,7 @@ main (int argc, char **argv)
|
|||||||
g_object_unref (timeline_2);
|
g_object_unref (timeline_2);
|
||||||
g_object_unref (timeline_3);
|
g_object_unref (timeline_3);
|
||||||
g_object_unref (timeline_4);
|
g_object_unref (timeline_4);
|
||||||
|
g_object_unref (timeline_5);
|
||||||
g_object_unref (score);
|
g_object_unref (score);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
Loading…
Reference in New Issue
Block a user