Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ev-timeline.c
Go to the documentation of this file.
1 /* ev-timeline.c
2  * this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2007 Carlos Garnacho <carlos@imendio.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #include <glib.h>
23 #include <math.h>
24 #include <gdk/gdk.h>
25 #include "ev-timeline.h"
26 
27 #define EV_TIMELINE_GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EV_TYPE_TIMELINE, EvTimelinePriv))
28 #define MSECS_PER_SEC 1000
29 #define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes)
30 #define DEFAULT_FPS 30
31 
33 
35  guint duration;
36  guint fps;
37  guint source_id;
38 
39  GTimer *timer;
40 
41  guint loop : 1;
42 };
43 
44 enum {
49 };
50 
51 enum {
57 };
58 
59 static guint signals [LAST_SIGNAL] = { 0, };
60 
61 
62 G_DEFINE_TYPE (EvTimeline, ev_timeline, G_TYPE_OBJECT)
63 
64 
65 static void
67 {
68  EvTimelinePriv *priv;
69 
70  priv = EV_TIMELINE_GET_PRIV (timeline);
71 
72  priv->fps = DEFAULT_FPS;
73  priv->duration = 0;
74 }
75 
76 static void
77 ev_timeline_set_property (GObject *object,
78  guint prop_id,
79  const GValue *value,
80  GParamSpec *pspec)
81 {
82  EvTimeline *timeline;
83 
84  timeline = EV_TIMELINE (object);
85 
86  switch (prop_id) {
87  case PROP_FPS:
88  ev_timeline_set_fps (timeline, g_value_get_uint (value));
89  break;
90  case PROP_DURATION:
91  ev_timeline_set_duration (timeline, g_value_get_uint (value));
92  break;
93  case PROP_LOOP:
94  ev_timeline_set_loop (timeline, g_value_get_boolean (value));
95  break;
96  default:
97  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
98  }
99 }
100 
101 static void
102 ev_timeline_get_property (GObject *object,
103  guint prop_id,
104  GValue *value,
105  GParamSpec *pspec)
106 {
107  EvTimeline *timeline;
108  EvTimelinePriv *priv;
109 
110  timeline = EV_TIMELINE (object);
111  priv = EV_TIMELINE_GET_PRIV (timeline);
112 
113  switch (prop_id) {
114  case PROP_FPS:
115  g_value_set_uint (value, priv->fps);
116  break;
117  case PROP_DURATION:
118  g_value_set_uint (value, priv->duration);
119  break;
120  case PROP_LOOP:
121  g_value_set_boolean (value, priv->loop);
122  break;
123  default:
124  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
125  }
126 }
127 
128 static void
129 ev_timeline_finalize (GObject *object)
130 {
131  EvTimelinePriv *priv;
132 
133  priv = EV_TIMELINE_GET_PRIV (object);
134 
135  if (priv->source_id) {
136  g_source_remove (priv->source_id);
137  priv->source_id = 0;
138  }
139 
140  if (priv->timer)
141  g_timer_destroy (priv->timer);
142 
143  G_OBJECT_CLASS (ev_timeline_parent_class)->finalize (object);
144 }
145 
146 static gboolean
148 {
149  EvTimelinePriv *priv;
150  gdouble progress;
151  guint elapsed_time;
152 
153  gdk_threads_enter ();
154 
155  priv = EV_TIMELINE_GET_PRIV (timeline);
156 
157  elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000);
158  progress = (gdouble) elapsed_time / priv->duration;
159  progress = CLAMP (progress, 0., 1.);
160 
161  g_signal_emit (timeline, signals [FRAME], 0, progress);
162 
163  if (progress >= 1.0) {
164  if (!priv->loop) {
165  if (priv->source_id) {
166  g_source_remove (priv->source_id);
167  priv->source_id = 0;
168  }
169 
170  g_signal_emit (timeline, signals [FINISHED], 0);
171  return FALSE;
172  } else {
173  ev_timeline_rewind (timeline);
174  }
175  }
176 
177  gdk_threads_leave ();
178 
179  return TRUE;
180 }
181 
182 static void
184 {
185  EvTimelinePriv *priv;
186 
187  priv = EV_TIMELINE_GET_PRIV (timeline);
188 
189  if (!priv->source_id) {
190  if (priv->timer)
191  g_timer_continue (priv->timer);
192  else
193  priv->timer = g_timer_new ();
194 
195  /* sanity check */
196  g_assert (priv->fps > 0);
197 
198  g_signal_emit (timeline, signals [STARTED], 0);
199 
200  priv->source_id = g_timeout_add (FRAME_INTERVAL (priv->fps),
201  (GSourceFunc) ev_timeline_run_frame,
202  timeline);
203  }
204 }
205 
206 static void
208 {
209  GObjectClass *object_class = G_OBJECT_CLASS (class);
210 
211  object_class->set_property = ev_timeline_set_property;
212  object_class->get_property = ev_timeline_get_property;
213  object_class->finalize = ev_timeline_finalize;
214 
215  class->start = ev_timeline_real_start;
216 
217  g_object_class_install_property (object_class,
218  PROP_FPS,
219  g_param_spec_uint ("fps",
220  "FPS",
221  "Frames per second for the timeline",
222  1,
223  G_MAXUINT,
224  DEFAULT_FPS,
225  G_PARAM_READWRITE |
226  G_PARAM_STATIC_STRINGS));
227  g_object_class_install_property (object_class,
229  g_param_spec_uint ("duration",
230  "Animation Duration",
231  "Animation Duration",
232  0,
233  G_MAXUINT,
234  0,
235  G_PARAM_READWRITE |
236  G_PARAM_STATIC_STRINGS));
237  g_object_class_install_property (object_class,
238  PROP_LOOP,
239  g_param_spec_boolean ("loop",
240  "Loop",
241  "Whether the timeline loops or not",
242  FALSE,
243  G_PARAM_READWRITE |
244  G_PARAM_STATIC_STRINGS));
245  signals[STARTED] =
246  g_signal_new ("started",
247  G_TYPE_FROM_CLASS (object_class),
248  G_SIGNAL_RUN_LAST,
249  G_STRUCT_OFFSET (EvTimelineClass, started),
250  NULL, NULL,
251  g_cclosure_marshal_VOID__VOID,
252  G_TYPE_NONE, 0);
253 
254  signals[PAUSED] =
255  g_signal_new ("paused",
256  G_TYPE_FROM_CLASS (object_class),
257  G_SIGNAL_RUN_LAST,
258  G_STRUCT_OFFSET (EvTimelineClass, paused),
259  NULL, NULL,
260  g_cclosure_marshal_VOID__VOID,
261  G_TYPE_NONE, 0);
262 
263  signals[FINISHED] =
264  g_signal_new ("finished",
265  G_TYPE_FROM_CLASS (object_class),
266  G_SIGNAL_RUN_LAST,
267  G_STRUCT_OFFSET (EvTimelineClass, finished),
268  NULL, NULL,
269  g_cclosure_marshal_VOID__VOID,
270  G_TYPE_NONE, 0);
271 
272  signals[FRAME] =
273  g_signal_new ("frame",
274  G_TYPE_FROM_CLASS (object_class),
275  G_SIGNAL_RUN_LAST,
276  G_STRUCT_OFFSET (EvTimelineClass, frame),
277  NULL, NULL,
278  g_cclosure_marshal_VOID__DOUBLE,
279  G_TYPE_NONE, 1,
280  G_TYPE_DOUBLE);
281 
282  g_type_class_add_private (class, sizeof (EvTimelinePriv));
283 }
284 
285 EvTimeline *
286 ev_timeline_new (guint duration)
287 {
288  return g_object_new (EV_TYPE_TIMELINE,
289  "duration", duration,
290  NULL);
291 }
292 
293 void
295 {
296  g_return_if_fail (EV_IS_TIMELINE (timeline));
297 
298  EV_TIMELINE_GET_CLASS (timeline)->start (timeline);
299 }
300 
301 void
303 {
304  EvTimelinePriv *priv;
305 
306  g_return_if_fail (EV_IS_TIMELINE (timeline));
307 
308  priv = EV_TIMELINE_GET_PRIV (timeline);
309 
310  if (priv->source_id) {
311  g_source_remove (priv->source_id);
312  priv->source_id = 0;
313  g_timer_stop (priv->timer);
314  g_signal_emit (timeline, signals [PAUSED], 0);
315  }
316 }
317 
318 void
320 {
321  EvTimelinePriv *priv;
322 
323  g_return_if_fail (EV_IS_TIMELINE (timeline));
324 
325  priv = EV_TIMELINE_GET_PRIV (timeline);
326 
327  /* destroy and re-create timer if neccesary */
328  if (priv->timer) {
329  g_timer_destroy (priv->timer);
330 
331  if (ev_timeline_is_running (timeline))
332  priv->timer = g_timer_new ();
333  else
334  priv->timer = NULL;
335  }
336 }
337 
338 gboolean
340 {
341  EvTimelinePriv *priv;
342 
343  g_return_val_if_fail (EV_IS_TIMELINE (timeline), FALSE);
344 
345  priv = EV_TIMELINE_GET_PRIV (timeline);
346 
347  return (priv->source_id != 0);
348 }
349 
350 guint
352 {
353  EvTimelinePriv *priv;
354 
355  g_return_val_if_fail (EV_IS_TIMELINE (timeline), 1);
356 
357  priv = EV_TIMELINE_GET_PRIV (timeline);
358  return priv->fps;
359 }
360 
361 void
363  guint fps)
364 {
365  EvTimelinePriv *priv;
366 
367  g_return_if_fail (EV_IS_TIMELINE (timeline));
368 
369  priv = EV_TIMELINE_GET_PRIV (timeline);
370 
371  priv->fps = fps;
372 
373  if (ev_timeline_is_running (timeline)) {
374  g_source_remove (priv->source_id);
375  priv->source_id = g_timeout_add (FRAME_INTERVAL (priv->fps),
376  (GSourceFunc) ev_timeline_run_frame,
377  timeline);
378  }
379 
380  g_object_notify (G_OBJECT (timeline), "fps");
381 }
382 
383 gboolean
385 {
386  EvTimelinePriv *priv;
387 
388  g_return_val_if_fail (EV_IS_TIMELINE (timeline), FALSE);
389 
390  priv = EV_TIMELINE_GET_PRIV (timeline);
391  return priv->loop;
392 }
393 
394 void
396  gboolean loop)
397 {
398  EvTimelinePriv *priv;
399 
400  g_return_if_fail (EV_IS_TIMELINE (timeline));
401 
402  priv = EV_TIMELINE_GET_PRIV (timeline);
403  priv->loop = loop;
404 
405  g_object_notify (G_OBJECT (timeline), "loop");
406 }
407 
408 void
410  guint duration)
411 {
412  EvTimelinePriv *priv;
413 
414  g_return_if_fail (EV_IS_TIMELINE (timeline));
415 
416  priv = EV_TIMELINE_GET_PRIV (timeline);
417 
418  priv->duration = duration;
419 
420  g_object_notify (G_OBJECT (timeline), "duration");
421 }
422 
423 guint
425 {
426  EvTimelinePriv *priv;
427 
428  g_return_val_if_fail (EV_IS_TIMELINE (timeline), 0);
429 
430  priv = EV_TIMELINE_GET_PRIV (timeline);
431 
432  return priv->duration;
433 }
434 
435 gdouble
437 {
438  EvTimelinePriv *priv;
439  gdouble progress;
440  guint elapsed_time;
441 
442  g_return_val_if_fail (EV_IS_TIMELINE (timeline), 0.0);
443 
444  priv = EV_TIMELINE_GET_PRIV (timeline);
445 
446  if (!priv->timer)
447  return 0.;
448 
449  elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000);
450  progress = (gdouble) elapsed_time / priv->duration;
451 
452  return CLAMP (progress, 0., 1.);
453 }