mirror of
https://github.com/brl/mutter.git
synced 2024-11-23 00:20:42 -05:00
2008-03-18 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-marshal.list: Add signature for the ::marker-reached signal marshaller. * clutter/clutter-timeline.[ch]: Add timeline marker API; using markers it is possible to add a unique identifier to a particular frame of the timeline, and receive a signal notification when reaching that particular marker while playing the timeline. (#641) * tests/test-timeline.c: Update the test case to check for the marker-reached signal emission. * clutter.symbols: Add new symbols.
This commit is contained in:
parent
b6cc7c1249
commit
be97c496b6
16
ChangeLog
16
ChangeLog
@ -1,3 +1,19 @@
|
|||||||
|
2008-03-18 Emmanuele Bassi <ebassi@openedhand.com>
|
||||||
|
|
||||||
|
* clutter/clutter-marshal.list: Add signature for the
|
||||||
|
::marker-reached signal marshaller.
|
||||||
|
|
||||||
|
* clutter/clutter-timeline.[ch]: Add timeline marker API;
|
||||||
|
using markers it is possible to add a unique identifier to
|
||||||
|
a particular frame of the timeline, and receive a signal
|
||||||
|
notification when reaching that particular marker while
|
||||||
|
playing the timeline. (#641)
|
||||||
|
|
||||||
|
* tests/test-timeline.c: Update the test case to check for
|
||||||
|
the marker-reached signal emission.
|
||||||
|
|
||||||
|
* clutter.symbols: Add new symbols.
|
||||||
|
|
||||||
2008-03-10 Øyvind Kolås <pippin@o-hand.com>
|
2008-03-10 Øyvind Kolås <pippin@o-hand.com>
|
||||||
|
|
||||||
* tests/test-shader.c: improved readability of fragment shader
|
* tests/test-shader.c: improved readability of fragment shader
|
||||||
|
@ -541,7 +541,10 @@ clutter_threads_enter
|
|||||||
clutter_threads_init
|
clutter_threads_init
|
||||||
clutter_threads_leave
|
clutter_threads_leave
|
||||||
clutter_threads_set_lock_functions
|
clutter_threads_set_lock_functions
|
||||||
|
clutter_timeline_add_marker_at_frame
|
||||||
|
clutter_timeline_add_marker_at_time
|
||||||
clutter_timeline_advance
|
clutter_timeline_advance
|
||||||
|
clutter_timeline_advance_to_marker
|
||||||
clutter_timeline_clone
|
clutter_timeline_clone
|
||||||
clutter_timeline_get_current_frame
|
clutter_timeline_get_current_frame
|
||||||
clutter_timeline_get_delay
|
clutter_timeline_get_delay
|
||||||
@ -553,9 +556,11 @@ clutter_timeline_get_n_frames
|
|||||||
clutter_timeline_get_speed
|
clutter_timeline_get_speed
|
||||||
clutter_timeline_get_type
|
clutter_timeline_get_type
|
||||||
clutter_timeline_is_playing
|
clutter_timeline_is_playing
|
||||||
|
clutter_timeline_list_markers
|
||||||
clutter_timeline_new
|
clutter_timeline_new
|
||||||
clutter_timeline_new_for_duration
|
clutter_timeline_new_for_duration
|
||||||
clutter_timeline_pause
|
clutter_timeline_pause
|
||||||
|
clutter_timeline_remove_marker
|
||||||
clutter_timeline_rewind
|
clutter_timeline_rewind
|
||||||
clutter_timeline_set_delay
|
clutter_timeline_set_delay
|
||||||
clutter_timeline_set_direction
|
clutter_timeline_set_direction
|
||||||
|
@ -7,4 +7,5 @@ VOID:BOXED
|
|||||||
VOID:OBJECT
|
VOID:OBJECT
|
||||||
VOID:VOID
|
VOID:VOID
|
||||||
VOID:OBJECT,POINTER
|
VOID:OBJECT,POINTER
|
||||||
|
VOID:STRING,UINT
|
||||||
BOOLEAN:BOXED
|
BOOLEAN:BOXED
|
||||||
|
@ -76,9 +76,18 @@ struct _ClutterTimelinePrivate
|
|||||||
GTimeVal prev_frame_timeval;
|
GTimeVal prev_frame_timeval;
|
||||||
guint msecs_delta;
|
guint msecs_delta;
|
||||||
|
|
||||||
|
GHashTable *markers_by_frame;
|
||||||
|
GHashTable *markers_by_name;
|
||||||
|
|
||||||
guint loop : 1;
|
guint loop : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gchar *name;
|
||||||
|
guint frame_num;
|
||||||
|
GQuark quark;
|
||||||
|
} TimelineMarker;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
@ -97,6 +106,7 @@ enum
|
|||||||
STARTED,
|
STARTED,
|
||||||
PAUSED,
|
PAUSED,
|
||||||
COMPLETED,
|
COMPLETED,
|
||||||
|
MARKER_REACHED,
|
||||||
|
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
@ -163,6 +173,31 @@ timeout_remove (guint tag)
|
|||||||
g_source_remove (tag);
|
g_source_remove (tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TimelineMarker *
|
||||||
|
timeline_marker_new (const gchar *name,
|
||||||
|
guint frame_num)
|
||||||
|
{
|
||||||
|
TimelineMarker *marker = g_slice_new0 (TimelineMarker);
|
||||||
|
|
||||||
|
marker->name = g_strdup (name);
|
||||||
|
marker->quark = g_quark_from_string (marker->name);
|
||||||
|
marker->frame_num = frame_num;
|
||||||
|
|
||||||
|
return marker;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
timeline_marker_free (gpointer data)
|
||||||
|
{
|
||||||
|
if (G_LIKELY (data))
|
||||||
|
{
|
||||||
|
TimelineMarker *marker = data;
|
||||||
|
|
||||||
|
g_free (marker->name);
|
||||||
|
g_slice_free (TimelineMarker, marker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Object */
|
/* Object */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -244,6 +279,11 @@ clutter_timeline_get_property (GObject *object,
|
|||||||
static void
|
static void
|
||||||
clutter_timeline_finalize (GObject *object)
|
clutter_timeline_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
|
ClutterTimelinePrivate *priv = CLUTTER_TIMELINE (object)->priv;
|
||||||
|
|
||||||
|
g_hash_table_destroy (priv->markers_by_frame);
|
||||||
|
g_hash_table_destroy (priv->markers_by_name);
|
||||||
|
|
||||||
G_OBJECT_CLASS (clutter_timeline_parent_class)->finalize (object);
|
G_OBJECT_CLASS (clutter_timeline_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,18 +476,66 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
|
|||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
clutter_marshal_VOID__VOID,
|
clutter_marshal_VOID__VOID,
|
||||||
G_TYPE_NONE, 0);
|
G_TYPE_NONE, 0);
|
||||||
|
/**
|
||||||
|
* ClutterTimeline::marker-reached:
|
||||||
|
* @timeline: the #ClutterTimeline which received the signal
|
||||||
|
* @marker_name: the name of the marker reached
|
||||||
|
* @frame_num: the frame number
|
||||||
|
*
|
||||||
|
* The ::marker-reached signal is emitted each time a timeline
|
||||||
|
* reaches a marker set with clutter_timeline_add_marker_at_frame()
|
||||||
|
* or clutter_timeline_add_marker_at_time(). This signal is
|
||||||
|
* detailed with the name of the marker as well, so it is
|
||||||
|
* possible to connect a callback to the ::marker-reached signal
|
||||||
|
* for a specific marker with:
|
||||||
|
*
|
||||||
|
* <informalexample><programlisting>
|
||||||
|
* clutter_timeline_add_marker_at_frame (timeline, "foo", 24);
|
||||||
|
* clutter_timeline_add_marker_at_frame (timeline, "bar", 48);
|
||||||
|
*
|
||||||
|
* g_signal_connect (timeline, "marker-reached",
|
||||||
|
* G_CALLBACK (each_marker_reached), NULL);
|
||||||
|
* g_signal_connect (timeline, "marker-reached::foo",
|
||||||
|
* G_CALLBACK (foo_marker_reached), NULL);
|
||||||
|
* g_signal_connect (timeline, "marker-reached::bar",
|
||||||
|
* G_CALLBACK (bar_marker_reached), NULL);
|
||||||
|
* </programlisting></informalexample>
|
||||||
|
*
|
||||||
|
* In the example, the first callback will be invoked for both
|
||||||
|
* the "foo" and "bar" marker, while the second and third callbacks
|
||||||
|
* will be invoked for the "foo" or "bar" markers, respectively.
|
||||||
|
*
|
||||||
|
* Since: 0.8
|
||||||
|
*/
|
||||||
|
timeline_signals[MARKER_REACHED] =
|
||||||
|
g_signal_new ("marker-reached",
|
||||||
|
G_TYPE_FROM_CLASS (object_class),
|
||||||
|
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS,
|
||||||
|
G_STRUCT_OFFSET (ClutterTimelineClass, marker_reached),
|
||||||
|
NULL, NULL,
|
||||||
|
clutter_marshal_VOID__STRING_UINT,
|
||||||
|
G_TYPE_NONE, 2,
|
||||||
|
G_TYPE_STRING,
|
||||||
|
G_TYPE_UINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_timeline_init (ClutterTimeline *self)
|
clutter_timeline_init (ClutterTimeline *self)
|
||||||
{
|
{
|
||||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
ClutterTimelinePrivate *priv;
|
||||||
|
|
||||||
|
self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||||
CLUTTER_TYPE_TIMELINE,
|
CLUTTER_TYPE_TIMELINE,
|
||||||
ClutterTimelinePrivate);
|
ClutterTimelinePrivate);
|
||||||
|
|
||||||
self->priv->fps = clutter_get_default_frame_rate ();
|
priv->fps = clutter_get_default_frame_rate ();
|
||||||
self->priv->n_frames = 0;
|
priv->n_frames = 0;
|
||||||
self->priv->msecs_delta = 0;
|
priv->msecs_delta = 0;
|
||||||
|
|
||||||
|
priv->markers_by_frame = g_hash_table_new (NULL, NULL);
|
||||||
|
priv->markers_by_name = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
|
NULL,
|
||||||
|
timeline_marker_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -490,12 +578,10 @@ timeline_timeout_func (gpointer data)
|
|||||||
priv->skipped_frames = n_frames - 1;
|
priv->skipped_frames = n_frames - 1;
|
||||||
|
|
||||||
if (priv->skipped_frames)
|
if (priv->skipped_frames)
|
||||||
{
|
|
||||||
CLUTTER_TIMESTAMP (SCHEDULER,
|
CLUTTER_TIMESTAMP (SCHEDULER,
|
||||||
"Timeline [%p], skipping %d frames\n",
|
"Timeline [%p], skipping %d frames\n",
|
||||||
timeline,
|
timeline,
|
||||||
priv->skipped_frames);
|
priv->skipped_frames);
|
||||||
}
|
|
||||||
|
|
||||||
priv->prev_frame_timeval = timeval;
|
priv->prev_frame_timeval = timeval;
|
||||||
|
|
||||||
@ -513,9 +599,31 @@ timeline_timeout_func (gpointer data)
|
|||||||
(priv->current_frame_num <= 0))
|
(priv->current_frame_num <= 0))
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
|
gint i;
|
||||||
|
|
||||||
/* Fire off signal */
|
/* Fire off signal */
|
||||||
g_signal_emit (timeline, timeline_signals[NEW_FRAME],
|
g_signal_emit (timeline, timeline_signals[NEW_FRAME], 0,
|
||||||
0, priv->current_frame_num);
|
priv->current_frame_num);
|
||||||
|
|
||||||
|
for (i = priv->skipped_frames; i >= 0; i--)
|
||||||
|
{
|
||||||
|
gint frame_num = priv->current_frame_num - i;
|
||||||
|
GSList *markers, *l;
|
||||||
|
|
||||||
|
markers = g_hash_table_lookup (priv->markers_by_frame,
|
||||||
|
GUINT_TO_POINTER (frame_num));
|
||||||
|
for (l = markers; l; l = l->next)
|
||||||
|
{
|
||||||
|
TimelineMarker *marker = l->data;
|
||||||
|
|
||||||
|
CLUTTER_NOTE (SCHEDULER, "Marker `%s' reached", marker->name);
|
||||||
|
|
||||||
|
g_signal_emit (timeline, timeline_signals[MARKER_REACHED],
|
||||||
|
marker->quark,
|
||||||
|
marker->name,
|
||||||
|
marker->frame_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Signal pauses timeline ? */
|
/* Signal pauses timeline ? */
|
||||||
if (!priv->timeout_id)
|
if (!priv->timeout_id)
|
||||||
@ -527,26 +635,24 @@ timeline_timeout_func (gpointer data)
|
|||||||
g_object_unref (timeline);
|
g_object_unref (timeline);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
else /* Handle loop or stop */
|
else
|
||||||
{
|
{
|
||||||
|
/* Handle loop or stop */
|
||||||
ClutterTimelineDirection saved_direction = priv->direction;
|
ClutterTimelineDirection saved_direction = priv->direction;
|
||||||
guint overflow_frame_num = priv->current_frame_num;
|
guint overflow_frame_num = priv->current_frame_num;
|
||||||
gint end_frame;
|
gint end_frame;
|
||||||
|
|
||||||
/* In case the signal handlers want to take a peek... */
|
/* In case the signal handlers want to take a peek... */
|
||||||
if (priv->direction == CLUTTER_TIMELINE_FORWARD)
|
if (priv->direction == CLUTTER_TIMELINE_FORWARD)
|
||||||
{
|
|
||||||
priv->current_frame_num = priv->n_frames;
|
priv->current_frame_num = priv->n_frames;
|
||||||
}
|
|
||||||
else if (priv->direction == CLUTTER_TIMELINE_BACKWARD)
|
else if (priv->direction == CLUTTER_TIMELINE_BACKWARD)
|
||||||
{
|
|
||||||
priv->current_frame_num = 0;
|
priv->current_frame_num = 0;
|
||||||
}
|
|
||||||
end_frame = priv->current_frame_num;
|
end_frame = priv->current_frame_num;
|
||||||
|
|
||||||
/* Fire off signal */
|
/* Fire off signal */
|
||||||
g_signal_emit (timeline, timeline_signals[NEW_FRAME],
|
g_signal_emit (timeline, timeline_signals[NEW_FRAME], 0,
|
||||||
0, priv->current_frame_num);
|
priv->current_frame_num);
|
||||||
|
|
||||||
/* Did the signal handler modify the current_frame_num */
|
/* Did the signal handler modify the current_frame_num */
|
||||||
if (priv->current_frame_num != end_frame)
|
if (priv->current_frame_num != end_frame)
|
||||||
@ -558,7 +664,6 @@ timeline_timeout_func (gpointer data)
|
|||||||
/* Note: If the new-frame signal handler paused the timeline
|
/* Note: If the new-frame signal handler paused the timeline
|
||||||
* on the last frame we will still go ahead and send the
|
* on the last frame we will still go ahead and send the
|
||||||
* completed signal */
|
* completed signal */
|
||||||
|
|
||||||
CLUTTER_NOTE (SCHEDULER,
|
CLUTTER_NOTE (SCHEDULER,
|
||||||
"Timeline [%p] completed (cur: %d, tot: %d, drop: %d)",
|
"Timeline [%p] completed (cur: %d, tot: %d, drop: %d)",
|
||||||
timeline,
|
timeline,
|
||||||
@ -577,6 +682,7 @@ timeline_timeout_func (gpointer data)
|
|||||||
timeout_remove (priv->timeout_id);
|
timeout_remove (priv->timeout_id);
|
||||||
priv->timeout_id = 0;
|
priv->timeout_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_signal_emit (timeline, timeline_signals[COMPLETED], 0);
|
g_signal_emit (timeline, timeline_signals[COMPLETED], 0);
|
||||||
|
|
||||||
/* Again check to see if the user has manually played with
|
/* Again check to see if the user has manually played with
|
||||||
@ -603,8 +709,10 @@ timeline_timeout_func (gpointer data)
|
|||||||
|
|
||||||
/* Or if the direction changed, we try and bounce */
|
/* Or if the direction changed, we try and bounce */
|
||||||
if (priv->direction != saved_direction)
|
if (priv->direction != saved_direction)
|
||||||
priv->current_frame_num =
|
{
|
||||||
priv->n_frames - priv->current_frame_num;
|
priv->current_frame_num = priv->n_frames
|
||||||
|
- priv->current_frame_num;
|
||||||
|
}
|
||||||
|
|
||||||
g_object_unref (timeline);
|
g_object_unref (timeline);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -612,8 +720,10 @@ timeline_timeout_func (gpointer data)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
clutter_timeline_rewind (timeline);
|
clutter_timeline_rewind (timeline);
|
||||||
|
|
||||||
priv->prev_frame_timeval.tv_sec = 0;
|
priv->prev_frame_timeval.tv_sec = 0;
|
||||||
priv->prev_frame_timeval.tv_usec = 0;
|
priv->prev_frame_timeval.tv_usec = 0;
|
||||||
|
|
||||||
g_object_unref (timeline);
|
g_object_unref (timeline);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -1297,3 +1407,246 @@ clutter_timeline_get_delta (ClutterTimeline *timeline,
|
|||||||
|
|
||||||
return priv->skipped_frames + 1;
|
return priv->skipped_frames + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
clutter_timeline_add_marker_internal (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name,
|
||||||
|
guint frame_num)
|
||||||
|
{
|
||||||
|
ClutterTimelinePrivate *priv = timeline->priv;
|
||||||
|
TimelineMarker *marker;
|
||||||
|
GSList *markers;
|
||||||
|
|
||||||
|
marker = g_hash_table_lookup (priv->markers_by_name, marker_name);
|
||||||
|
if (G_UNLIKELY (marker))
|
||||||
|
{
|
||||||
|
g_warning ("A marker named `%s' already exists on frame %d",
|
||||||
|
marker->name,
|
||||||
|
marker->frame_num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
marker = timeline_marker_new (marker_name, frame_num);
|
||||||
|
g_hash_table_insert (priv->markers_by_name, marker->name, marker);
|
||||||
|
|
||||||
|
markers = g_hash_table_lookup (priv->markers_by_frame,
|
||||||
|
GUINT_TO_POINTER (frame_num));
|
||||||
|
if (!markers)
|
||||||
|
{
|
||||||
|
markers = g_slist_prepend (NULL, marker);
|
||||||
|
g_hash_table_insert (priv->markers_by_frame,
|
||||||
|
GUINT_TO_POINTER (frame_num),
|
||||||
|
markers);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
markers = g_slist_prepend (markers, marker);
|
||||||
|
g_hash_table_replace (priv->markers_by_frame,
|
||||||
|
GUINT_TO_POINTER (frame_num),
|
||||||
|
markers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_timeline_add_marker_at_frame:
|
||||||
|
* @timeline: a #ClutterTimeline
|
||||||
|
* @marker_name: the unique name for this marker
|
||||||
|
* @frame_num: the marker's frame
|
||||||
|
*
|
||||||
|
* Adds a named marker at @frame_num. Markers are unique string identifiers
|
||||||
|
* for a specific frame. Once @timeline reaches @frame_num, it will emit
|
||||||
|
* a ::marker-reached signal for each marker attached to that frame.
|
||||||
|
*
|
||||||
|
* A marker can be removed with clutter_timeline_remove_marker(). The
|
||||||
|
* timeline can be advanced to a marker using
|
||||||
|
* clutter_timeline_advance_to_marker().
|
||||||
|
*
|
||||||
|
* Since: 0.8
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_timeline_add_marker_at_frame (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name,
|
||||||
|
guint frame_num)
|
||||||
|
{
|
||||||
|
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
|
||||||
|
g_return_if_fail (marker_name != NULL);
|
||||||
|
g_return_if_fail (frame_num <= clutter_timeline_get_n_frames (timeline));
|
||||||
|
|
||||||
|
clutter_timeline_add_marker_internal (timeline, marker_name, frame_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_timeline_add_marker_at_time:
|
||||||
|
* @timeline: a #ClutterTimeline
|
||||||
|
* @marker_name: the unique name for this marker
|
||||||
|
* @msecs: position of the marker in milliseconds
|
||||||
|
*
|
||||||
|
* Time-based variant of clutter_timeline_add_marker_at_frame().
|
||||||
|
*
|
||||||
|
* Adds a named marker at @msecs.
|
||||||
|
*
|
||||||
|
* Since: 0.8
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_timeline_add_marker_at_time (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name,
|
||||||
|
guint msecs)
|
||||||
|
{
|
||||||
|
guint frame_num;
|
||||||
|
|
||||||
|
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
|
||||||
|
g_return_if_fail (marker_name != NULL);
|
||||||
|
g_return_if_fail (msecs <= clutter_timeline_get_duration (timeline));
|
||||||
|
|
||||||
|
frame_num = msecs * timeline->priv->fps / 1000;
|
||||||
|
|
||||||
|
clutter_timeline_add_marker_internal (timeline, marker_name, frame_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_timeline_list_markers:
|
||||||
|
* @timeline: a #ClutterTimeline
|
||||||
|
* @frame_num: the frame number to check, or -1
|
||||||
|
* @n_markers: the number of markers returned
|
||||||
|
*
|
||||||
|
* Retrieves the list of markers at @frame_num. If @frame_num is a
|
||||||
|
* negative integer, all the markers attached to @timeline will be
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* Return value: a newly allocated, %NULL terminated string array
|
||||||
|
* containing the names of the markers. Use g_strfreev() when
|
||||||
|
* done.
|
||||||
|
*
|
||||||
|
* Since: 0.8
|
||||||
|
*/
|
||||||
|
gchar **
|
||||||
|
clutter_timeline_list_markers (ClutterTimeline *timeline,
|
||||||
|
gint frame_num,
|
||||||
|
guint *n_markers)
|
||||||
|
{
|
||||||
|
ClutterTimelinePrivate *priv;
|
||||||
|
gchar **retval = NULL;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL);
|
||||||
|
|
||||||
|
priv = timeline->priv;
|
||||||
|
|
||||||
|
if (frame_num < 0)
|
||||||
|
{
|
||||||
|
GList *markers, *l;
|
||||||
|
|
||||||
|
markers = g_hash_table_get_keys (priv->markers_by_name);
|
||||||
|
retval = g_new0 (gchar*, g_list_length (markers) + 1);
|
||||||
|
|
||||||
|
for (i = 0, l = markers; l != NULL; i++, l = l->next)
|
||||||
|
retval[i] = g_strdup (l->data);
|
||||||
|
|
||||||
|
g_list_free (markers);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GSList *markers, *l;
|
||||||
|
|
||||||
|
markers = g_hash_table_lookup (priv->markers_by_frame,
|
||||||
|
GUINT_TO_POINTER (frame_num));
|
||||||
|
retval = g_new0 (gchar*, g_slist_length (markers) + 1);
|
||||||
|
|
||||||
|
for (i = 0, l = markers; l != NULL; i++, l = l->next)
|
||||||
|
retval[i] = g_strdup (l->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n_markers)
|
||||||
|
*n_markers = i;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_timeline_advance_to_marker:
|
||||||
|
* @timeline: a #ClutterTimeline
|
||||||
|
* @marker_name: the name of the marker
|
||||||
|
*
|
||||||
|
* Advances @timeline to the frame of the given @marker_name.
|
||||||
|
*
|
||||||
|
* Since: 0.8
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_timeline_advance_to_marker (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name)
|
||||||
|
{
|
||||||
|
ClutterTimelinePrivate *priv;
|
||||||
|
TimelineMarker *marker;
|
||||||
|
|
||||||
|
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
|
||||||
|
g_return_if_fail (marker_name != NULL);
|
||||||
|
|
||||||
|
priv = timeline->priv;
|
||||||
|
|
||||||
|
marker = g_hash_table_lookup (priv->markers_by_name, marker_name);
|
||||||
|
if (!marker)
|
||||||
|
{
|
||||||
|
g_warning ("No marker named `%s' found.", marker_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clutter_timeline_advance (timeline, marker->frame_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_timeline_remove_marker:
|
||||||
|
* @timeline: a #ClutterTimeline
|
||||||
|
* @marker_name: the name of the marker to remove
|
||||||
|
*
|
||||||
|
* Removes @marker_name, if found, from @timeline.
|
||||||
|
*
|
||||||
|
* Since: 0.8
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_timeline_remove_marker (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name)
|
||||||
|
{
|
||||||
|
ClutterTimelinePrivate *priv;
|
||||||
|
TimelineMarker *marker;
|
||||||
|
GSList *markers;
|
||||||
|
|
||||||
|
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
|
||||||
|
g_return_if_fail (marker_name != NULL);
|
||||||
|
|
||||||
|
priv = timeline->priv;
|
||||||
|
|
||||||
|
marker = g_hash_table_lookup (priv->markers_by_name, marker_name);
|
||||||
|
if (!marker)
|
||||||
|
{
|
||||||
|
g_warning ("No marker named `%s' found.", marker_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove from the list of markers at the same frame */
|
||||||
|
markers = g_hash_table_lookup (priv->markers_by_frame,
|
||||||
|
GUINT_TO_POINTER (marker->frame_num));
|
||||||
|
if (G_LIKELY (markers))
|
||||||
|
{
|
||||||
|
markers = g_slist_remove (markers, marker);
|
||||||
|
if (!markers)
|
||||||
|
{
|
||||||
|
/* no markers left, remove the slot */
|
||||||
|
g_hash_table_remove (priv->markers_by_frame,
|
||||||
|
GUINT_TO_POINTER (marker->frame_num));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
g_hash_table_replace (priv->markers_by_frame,
|
||||||
|
GUINT_TO_POINTER (marker->frame_num),
|
||||||
|
markers);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* uh-oh, dangling marker; this should never happen */
|
||||||
|
g_warning ("Dangling marker %s at frame %d",
|
||||||
|
marker->name,
|
||||||
|
marker->frame_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this will take care of freeing the marker as well */
|
||||||
|
g_hash_table_remove (priv->markers_by_name, marker_name);
|
||||||
|
}
|
||||||
|
@ -26,14 +26,12 @@
|
|||||||
#ifndef _HAVE_CLUTTER_TIMELINE_H
|
#ifndef _HAVE_CLUTTER_TIMELINE_H
|
||||||
#define _HAVE_CLUTTER_TIMELINE_H
|
#define _HAVE_CLUTTER_TIMELINE_H
|
||||||
|
|
||||||
/* clutter-timeline.h */
|
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
#include <clutter/clutter-fixed.h>
|
#include <clutter/clutter-fixed.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define CLUTTER_TYPE_TIMELINE clutter_timeline_get_type()
|
#define CLUTTER_TYPE_TIMELINE (clutter_timeline_get_type ())
|
||||||
|
|
||||||
#define CLUTTER_TIMELINE(obj) \
|
#define CLUTTER_TIMELINE(obj) \
|
||||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
|
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
|
||||||
@ -93,6 +91,10 @@ struct _ClutterTimelineClass
|
|||||||
void (*new_frame) (ClutterTimeline *timeline,
|
void (*new_frame) (ClutterTimeline *timeline,
|
||||||
gint frame_num);
|
gint frame_num);
|
||||||
|
|
||||||
|
void (*marker_reached) (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name,
|
||||||
|
gint frame_num);
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
void (*_clutter_timeline_1) (void);
|
void (*_clutter_timeline_1) (void);
|
||||||
void (*_clutter_timeline_2) (void);
|
void (*_clutter_timeline_2) (void);
|
||||||
@ -141,6 +143,20 @@ guint clutter_timeline_get_delay (ClutterTimeline *timeli
|
|||||||
guint clutter_timeline_get_delta (ClutterTimeline *timeline,
|
guint clutter_timeline_get_delta (ClutterTimeline *timeline,
|
||||||
guint *msecs);
|
guint *msecs);
|
||||||
|
|
||||||
|
void clutter_timeline_add_marker_at_frame (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name,
|
||||||
|
guint frame_num);
|
||||||
|
void clutter_timeline_add_marker_at_time (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name,
|
||||||
|
guint msecs);
|
||||||
|
void clutter_timeline_remove_marker (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name);
|
||||||
|
gchar ** clutter_timeline_list_markers (ClutterTimeline *timeline,
|
||||||
|
gint frame_num,
|
||||||
|
guint *n_markers) G_GNUC_MALLOC;
|
||||||
|
void clutter_timeline_advance_to_marker (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif /* _HAVE_CLUTTER_TIMELINE_H */
|
||||||
|
@ -38,22 +38,65 @@ timeline_3_new_frame_cb (ClutterTimeline *timeline, gint frame_no)
|
|||||||
g_debug ("3: Doing frame %d.", frame_no);
|
g_debug ("3: Doing frame %d.", frame_no);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
timeline_1_marker_reached (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name,
|
||||||
|
guint frame_num)
|
||||||
|
{
|
||||||
|
g_print ("1: Marker `%s' (%d) reached\n", marker_name, frame_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
timeline_2_marker_reached (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name,
|
||||||
|
guint frame_num)
|
||||||
|
{
|
||||||
|
g_print ("2: Marker `%s' (%d) reached\n", marker_name, frame_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
timeline_3_marker_reached (ClutterTimeline *timeline,
|
||||||
|
const gchar *marker_name,
|
||||||
|
guint frame_num)
|
||||||
|
{
|
||||||
|
g_print ("2: Marker `%s' (%d) reached\n", marker_name, frame_num);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
ClutterTimeline *timeline_1;
|
ClutterTimeline *timeline_1;
|
||||||
ClutterTimeline *timeline_2;
|
ClutterTimeline *timeline_2;
|
||||||
ClutterTimeline *timeline_3;
|
ClutterTimeline *timeline_3;
|
||||||
|
gchar **markers;
|
||||||
|
gsize n_markers;
|
||||||
|
|
||||||
clutter_init (&argc, &argv);
|
clutter_init (&argc, &argv);
|
||||||
|
|
||||||
timeline_1 = clutter_timeline_new (10, 120);
|
timeline_1 = clutter_timeline_new (10, 120);
|
||||||
|
clutter_timeline_add_marker_at_frame (timeline_1, "foo", 5);
|
||||||
|
clutter_timeline_add_marker_at_frame (timeline_1, "bar", 5);
|
||||||
|
clutter_timeline_add_marker_at_frame (timeline_1, "baz", 5);
|
||||||
|
markers = clutter_timeline_list_markers (timeline_1, 5, &n_markers);
|
||||||
|
g_assert (markers != NULL);
|
||||||
|
g_assert (n_markers == 3);
|
||||||
|
g_strfreev (markers);
|
||||||
|
|
||||||
timeline_2 = clutter_timeline_clone (timeline_1);
|
timeline_2 = clutter_timeline_clone (timeline_1);
|
||||||
|
clutter_timeline_add_marker_at_frame (timeline_2, "bar", 2);
|
||||||
|
markers = clutter_timeline_list_markers (timeline_2, -1, &n_markers);
|
||||||
|
g_assert (markers != NULL);
|
||||||
|
g_assert (n_markers == 1);
|
||||||
|
g_assert (strcmp (markers[0], "bar") == 0);
|
||||||
|
g_strfreev (markers);
|
||||||
|
|
||||||
timeline_3 = clutter_timeline_clone (timeline_1);
|
timeline_3 = clutter_timeline_clone (timeline_1);
|
||||||
clutter_timeline_set_direction (timeline_3, CLUTTER_TIMELINE_BACKWARD);
|
clutter_timeline_set_direction (timeline_3, CLUTTER_TIMELINE_BACKWARD);
|
||||||
|
clutter_timeline_add_marker_at_frame (timeline_3, "baz", 8);
|
||||||
|
|
||||||
|
g_signal_connect (timeline_1,
|
||||||
|
"marker-reached", G_CALLBACK (timeline_1_marker_reached),
|
||||||
|
NULL);
|
||||||
g_signal_connect (timeline_1,
|
g_signal_connect (timeline_1,
|
||||||
"new-frame", G_CALLBACK (timeline_1_new_frame_cb),
|
"new-frame", G_CALLBACK (timeline_1_new_frame_cb),
|
||||||
NULL);
|
NULL);
|
||||||
@ -61,6 +104,9 @@ main (int argc, char **argv)
|
|||||||
"completed", G_CALLBACK (timeline_1_complete),
|
"completed", G_CALLBACK (timeline_1_complete),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
g_signal_connect (timeline_2,
|
||||||
|
"marker-reached::bar", G_CALLBACK (timeline_1_marker_reached),
|
||||||
|
NULL);
|
||||||
g_signal_connect (timeline_2,
|
g_signal_connect (timeline_2,
|
||||||
"new-frame", G_CALLBACK (timeline_2_new_frame_cb),
|
"new-frame", G_CALLBACK (timeline_2_new_frame_cb),
|
||||||
NULL);
|
NULL);
|
||||||
@ -68,6 +114,9 @@ main (int argc, char **argv)
|
|||||||
"completed", G_CALLBACK (timeline_2_complete),
|
"completed", G_CALLBACK (timeline_2_complete),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
g_signal_connect (timeline_3,
|
||||||
|
"marker-reached", G_CALLBACK (timeline_1_marker_reached),
|
||||||
|
NULL);
|
||||||
g_signal_connect (timeline_3,
|
g_signal_connect (timeline_3,
|
||||||
"new-frame", G_CALLBACK (timeline_3_new_frame_cb),
|
"new-frame", G_CALLBACK (timeline_3_new_frame_cb),
|
||||||
NULL);
|
NULL);
|
||||||
|
Loading…
Reference in New Issue
Block a user