Various fixes to ClutterTimeline

Emit the ClutterTimeline::new-frame signal only if we arrive there with an
active timeout source. Also, make sure to take a reference on the timeout
when emitting signals.

If the timeline is advancing of zero frames, bump it up to one frame. (bug
471, Rob Bradford)

If the user called clutter_timeline_pause() while in the ::new-frame handler
the timeout is removed and the timeline is reset, while the correct behaviour
should be to simply return. (#371, Johan Bilien)

If we skipped the last frames and we ended up over the frame number, emit
the ::new-frame signal with the last frame before emitting the ::completed
signal.

Remove the call to clutter_timeline_stop() when reaching the end of the
timeline: it was used just to remove the timeout source and it emitted the
::paused signal, which doesn't make any sense. Also rewind the timeline
after emitting the ::completed signal, so that calling get_current_frame()
in the ::completed signal handlers still work.
This commit is contained in:
Emmanuele Bassi 2007-08-19 19:09:20 +00:00
parent c8a0faab73
commit 92910e3e2f

View File

@ -399,26 +399,44 @@ timeline_timeout_func (gpointer data)
GTimeVal timeval; GTimeVal timeval;
gint n_frames; gint n_frames;
gulong msecs; gulong msecs;
gboolean retval = TRUE;
priv = timeline->priv; priv = timeline->priv;
CLUTTER_TIMESTAMP (SCHEDULER, "Timeline:%p activated\n", timeline); if (!timeline)
{
CLUTTER_NOTE (SCHEDULER,
"The timeline [%p] has been disposed",
timeline);
return FALSE;
}
if (!priv->timeout_id)
{
CLUTTER_NOTE (SCHEDULER,
"The timeline [%p] has been removed",
timeline);
return FALSE;
}
g_object_ref (timeline);
/* Figure out potential frame skips */ /* Figure out potential frame skips */
g_get_current_time (&timeval); g_get_current_time (&timeval);
/* Fire off signal */ CLUTTER_TIMESTAMP (SCHEDULER, "Timeline [%p] activated (cur: %d)\n",
g_signal_emit (timeline, timeline_signals[NEW_FRAME], timeline,
0, priv->current_frame_num); priv->current_frame_num);
/* Signal frees timeline ? */ /* Fire off signal */
if (timeline == NULL) g_signal_emit (timeline, timeline_signals[NEW_FRAME], 0,
return FALSE; priv->current_frame_num);
/* Signal removes source ? */ /* Signal removes source ? */
if (!priv->timeout_id) if (!priv->timeout_id)
{ {
clutter_timeline_stop (timeline); g_object_unref (timeline);
return FALSE; return FALSE;
} }
@ -428,16 +446,18 @@ timeline_timeout_func (gpointer data)
* of frames to advance accordingly. * of frames to advance accordingly.
*/ */
msecs = ((timeval.tv_sec - priv->start_frame_secs) * 1000) msecs = ((timeval.tv_sec - priv->start_frame_secs) * 1000)
+ (timeval.tv_usec / 1000); + (timeval.tv_usec / 1000);
n_frames = (msecs - priv->last_frame_msecs ) / (1000 / priv->fps); n_frames = (msecs - priv->last_frame_msecs)
if (n_frames < 0) / (1000 / priv->fps);
if (n_frames <= 0)
n_frames = 1; n_frames = 1;
else if (n_frames > 1)
if (n_frames > 1)
{ {
CLUTTER_TIMESTAMP (SCHEDULER, CLUTTER_TIMESTAMP (SCHEDULER,
"Timeline %p, skipping %i frames\n", "Timeline [%p], skipping %d frames\n",
timeline, n_frames); timeline,
n_frames);
} }
} }
else else
@ -457,28 +477,54 @@ timeline_timeout_func (gpointer data)
/* Handle loop or stop */ /* Handle loop or stop */
if (priv->current_frame_num > priv->n_frames) if (priv->current_frame_num > priv->n_frames)
{ {
guint frame_diff;
CLUTTER_NOTE (SCHEDULER,
"Timeline [%p] completed (cur: %d, tot: %d, drop: %d)",
timeline,
priv->current_frame_num,
priv->n_frames,
n_frames - 1);
frame_diff = priv->current_frame_num - priv->n_frames;
priv->current_frame_num = priv->n_frames; priv->current_frame_num = priv->n_frames;
if (n_frames > 1) /* if we skipped some frame to get here let's see whether we still need
* to emit the last new-frame signal with the last frame
*/
if (frame_diff)
{ {
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);
} }
if (priv->loop) if (priv->loop)
{ {
g_signal_emit (timeline, timeline_signals[COMPLETED], 0);
clutter_timeline_rewind (timeline); clutter_timeline_rewind (timeline);
g_signal_emit (timeline, timeline_signals[COMPLETED], 0);
retval = TRUE;
} }
else else
{ {
clutter_timeline_stop (timeline); if (priv->timeout_id)
g_signal_emit (timeline, timeline_signals[COMPLETED], 0); {
return FALSE; timeout_remove (priv->timeout_id);
priv->timeout_id = 0;
}
priv->last_frame_msecs = 0;
g_signal_emit (timeline, timeline_signals[COMPLETED], 0);
clutter_timeline_rewind (timeline);
retval = FALSE;
} }
} }
return TRUE; g_object_unref (timeline);
return retval;
} }
static gboolean static gboolean
@ -559,7 +605,6 @@ clutter_timeline_pause (ClutterTimeline *timeline)
priv->timeout_id = 0; priv->timeout_id = 0;
} }
priv->timeout_id = 0;
priv->last_frame_msecs = 0; priv->last_frame_msecs = 0;
g_signal_emit (timeline, timeline_signals[PAUSED], 0); g_signal_emit (timeline, timeline_signals[PAUSED], 0);