[timeline] Limit timelines to 1000 frames per second

Since we are using milliseconds granularity to integrate timelines
with the GLib main loop, we cannot allow values of the :fps
property bigger than 1000. This means validating the fps value both
in the GParamSpec and the clutter_timeline_set_speed() accessor
function.

This should also fix floating point exceptions when trying to
perform "n_frames = milliseconds / (1000 / fps)".

See bug 1354:

  http://bugzilla.openedhand.com/show_bug.cgi?id=1354
This commit is contained in:
Emmanuele Bassi 2009-01-23 17:14:39 +00:00
parent 81f642d4b7
commit 1e071ed859

View File

@ -351,6 +351,7 @@ static void
clutter_timeline_class_init (ClutterTimelineClass *klass) clutter_timeline_class_init (ClutterTimelineClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
timeline_pool_init (); timeline_pool_init ();
@ -364,42 +365,45 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
/** /**
* ClutterTimeline:fps: * ClutterTimeline:fps:
* *
* Timeline frames per second. Because of the nature of the main * Number of frames per second. Because of the nature of the main
* loop used by Clutter this is to be considered a best approximation. * loop used by Clutter, we can only accept a granularity of one
* frame per millisecond.
*
* This value is to be considered a best approximation.
*/ */
g_object_class_install_property (object_class, pspec = g_param_spec_uint ("fps",
PROP_FPS,
g_param_spec_uint ("fps",
"Frames Per Second", "Frames Per Second",
"Timeline frames per second", "Frames per second",
1, G_MAXUINT, 1, 1000,
60, 60,
CLUTTER_PARAM_READWRITE)); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_FPS, pspec);
/** /**
* ClutterTimeline:num-frames: * ClutterTimeline:num-frames:
* *
* Total number of frames for the timeline. * Total number of frames for the timeline.
*/ */
g_object_class_install_property (object_class, pspec = g_param_spec_uint ("num-frames",
PROP_NUM_FRAMES, "Total number of frames",
g_param_spec_uint ("num-frames",
"Total number of frames", "Total number of frames",
"Timelines total number of frames",
1, G_MAXUINT, 1, G_MAXUINT,
1, 1,
CLUTTER_PARAM_READWRITE)); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_NUM_FRAMES, pspec);
/** /**
* ClutterTimeline:loop: * ClutterTimeline:loop:
* *
* Whether the timeline should automatically rewind and restart. * Whether the timeline should automatically rewind and restart.
*/ */
g_object_class_install_property (object_class, pspec = g_param_spec_boolean ("loop",
PROP_LOOP,
g_param_spec_boolean ("loop",
"Loop", "Loop",
"Should the timeline automatically restart", "Should the timeline automatically restart",
FALSE, FALSE,
CLUTTER_PARAM_READWRITE)); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_LOOP, pspec);
/** /**
* ClutterTimeline:delay: * ClutterTimeline:delay:
* *
@ -408,14 +412,14 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
* *
* Since: 0.4 * Since: 0.4
*/ */
g_object_class_install_property (object_class, pspec = g_param_spec_uint ("delay",
PROP_DELAY,
g_param_spec_uint ("delay",
"Delay", "Delay",
"Delay before start", "Delay before start",
0, G_MAXUINT, 0, G_MAXUINT,
0, 0,
CLUTTER_PARAM_READWRITE)); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_DELAY, pspec);
/** /**
* ClutterTimeline:duration: * ClutterTimeline:duration:
* *
@ -424,14 +428,14 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
* *
* Since: 0.6 * Since: 0.6
*/ */
g_object_class_install_property (object_class, pspec = g_param_spec_uint ("duration",
PROP_DURATION,
g_param_spec_uint ("duration",
"Duration", "Duration",
"Duration of the timeline in milliseconds", "Duration of the timeline in milliseconds",
0, G_MAXUINT, 0, G_MAXUINT,
1000, 1000,
CLUTTER_PARAM_READWRITE)); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_DURATION, pspec);
/** /**
* ClutterTimeline:direction: * ClutterTimeline:direction:
* *
@ -440,14 +444,13 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
* *
* Since: 0.6 * Since: 0.6
*/ */
g_object_class_install_property (object_class, pspec = g_param_spec_enum ("direction",
PROP_DIRECTION,
g_param_spec_enum ("direction",
"Direction", "Direction",
"Direction of the timeline", "Direction of the timeline",
CLUTTER_TYPE_TIMELINE_DIRECTION, CLUTTER_TYPE_TIMELINE_DIRECTION,
CLUTTER_TIMELINE_FORWARD, CLUTTER_TIMELINE_FORWARD,
CLUTTER_PARAM_READWRITE)); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_DIRECTION, pspec);
/** /**
* ClutterTimeline::new-frame: * ClutterTimeline::new-frame:
@ -547,7 +550,8 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
timeline_signals[MARKER_REACHED] = timeline_signals[MARKER_REACHED] =
g_signal_new ("marker-reached", g_signal_new ("marker-reached",
G_TYPE_FROM_CLASS (object_class), G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS, G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE |
G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS,
G_STRUCT_OFFSET (ClutterTimelineClass, marker_reached), G_STRUCT_OFFSET (ClutterTimelineClass, marker_reached),
NULL, NULL, NULL, NULL,
clutter_marshal_VOID__STRING_INT, clutter_marshal_VOID__STRING_INT,
@ -612,7 +616,7 @@ timeline_timeout_func (gpointer data)
ClutterTimeline *timeline = data; ClutterTimeline *timeline = data;
ClutterTimelinePrivate *priv; ClutterTimelinePrivate *priv;
GTimeVal timeval; GTimeVal timeval;
guint n_frames; guint n_frames, speed;
gulong msecs; gulong msecs;
priv = timeline->priv; priv = timeline->priv;
@ -639,7 +643,11 @@ timeline_timeout_func (gpointer data)
msecs = (timeval.tv_sec - priv->prev_frame_timeval.tv_sec) * 1000; msecs = (timeval.tv_sec - priv->prev_frame_timeval.tv_sec) * 1000;
msecs += (timeval.tv_usec - priv->prev_frame_timeval.tv_usec) / 1000; msecs += (timeval.tv_usec - priv->prev_frame_timeval.tv_usec) / 1000;
priv->msecs_delta = msecs; priv->msecs_delta = msecs;
n_frames = msecs / (1000 / priv->fps);
/* we need to avoid fps > 1000 */
speed = MAX (1000 / priv->fps, 1);
n_frames = msecs / speed;
if (n_frames == 0) if (n_frames == 0)
n_frames = 1; n_frames = 1;
@ -1089,10 +1097,11 @@ clutter_timeline_set_n_frames (ClutterTimeline *timeline,
/** /**
* clutter_timeline_set_speed: * clutter_timeline_set_speed:
* @timeline: A #ClutterTimeline * @timeline: A #ClutterTimeline
* @fps: New speed of timeline as frames per second * @fps: New speed of timeline as frames per second,
* between 1 and 1000
* *
* Set the speed in frames per second of the timeline. * Set the speed in frames per second of the timeline.
**/ */
void void
clutter_timeline_set_speed (ClutterTimeline *timeline, clutter_timeline_set_speed (ClutterTimeline *timeline,
guint fps) guint fps)
@ -1100,7 +1109,7 @@ clutter_timeline_set_speed (ClutterTimeline *timeline,
ClutterTimelinePrivate *priv; ClutterTimelinePrivate *priv;
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline)); g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
g_return_if_fail (fps > 0); g_return_if_fail (fps > 0 && fps <= 1000);
priv = timeline->priv; priv = timeline->priv;