]> www.fi.muni.cz Git - evince.git/blob - libview/ev-timeline.c
[dualscreen] fix crash on ctrl+w and fix control window closing
[evince.git] / libview / ev-timeline.c
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
32 typedef struct EvTimelinePriv EvTimelinePriv;
33
34 struct EvTimelinePriv {
35         guint duration;
36         guint fps;
37         guint source_id;
38
39         GTimer *timer;
40
41         guint loop : 1;
42 };
43
44 enum {
45         PROP_0,
46         PROP_FPS,
47         PROP_DURATION,
48         PROP_LOOP
49 };
50
51 enum {
52         STARTED,
53         PAUSED,
54         FINISHED,
55         FRAME,
56         LAST_SIGNAL
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
66 ev_timeline_init (EvTimeline *timeline)
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
147 ev_timeline_run_frame (EvTimeline *timeline)
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
183 ev_timeline_real_start (EvTimeline *timeline)
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
207 ev_timeline_class_init (EvTimelineClass *class)
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_object_class_install_property (object_class,
227                                          PROP_DURATION,
228                                          g_param_spec_uint ("duration",
229                                                             "Animation Duration",
230                                                             "Animation Duration",
231                                                             0,
232                                                             G_MAXUINT,
233                                                             0,
234                                                             G_PARAM_READWRITE));
235         g_object_class_install_property (object_class,
236                                          PROP_LOOP,
237                                          g_param_spec_boolean ("loop",
238                                                                "Loop",
239                                                                "Whether the timeline loops or not",
240                                                                FALSE,
241                                                                G_PARAM_READWRITE));
242         signals[STARTED] =
243                 g_signal_new ("started",
244                               G_TYPE_FROM_CLASS (object_class),
245                               G_SIGNAL_RUN_LAST,
246                               G_STRUCT_OFFSET (EvTimelineClass, started),
247                               NULL, NULL,
248                               g_cclosure_marshal_VOID__VOID,
249                               G_TYPE_NONE, 0);
250
251         signals[PAUSED] =
252                 g_signal_new ("paused",
253                               G_TYPE_FROM_CLASS (object_class),
254                               G_SIGNAL_RUN_LAST,
255                               G_STRUCT_OFFSET (EvTimelineClass, paused),
256                               NULL, NULL,
257                               g_cclosure_marshal_VOID__VOID,
258                               G_TYPE_NONE, 0);
259
260         signals[FINISHED] =
261                 g_signal_new ("finished",
262                               G_TYPE_FROM_CLASS (object_class),
263                               G_SIGNAL_RUN_LAST,
264                               G_STRUCT_OFFSET (EvTimelineClass, finished),
265                               NULL, NULL,
266                               g_cclosure_marshal_VOID__VOID,
267                               G_TYPE_NONE, 0);
268
269         signals[FRAME] =
270                 g_signal_new ("frame",
271                               G_TYPE_FROM_CLASS (object_class),
272                               G_SIGNAL_RUN_LAST,
273                               G_STRUCT_OFFSET (EvTimelineClass, frame),
274                               NULL, NULL,
275                               g_cclosure_marshal_VOID__DOUBLE,
276                               G_TYPE_NONE, 1,
277                               G_TYPE_DOUBLE);
278
279         g_type_class_add_private (class, sizeof (EvTimelinePriv));
280 }
281
282 EvTimeline *
283 ev_timeline_new (guint duration)
284 {
285         return g_object_new (EV_TYPE_TIMELINE,
286                              "duration", duration,
287                              NULL);
288 }
289
290 void
291 ev_timeline_start (EvTimeline *timeline)
292 {
293         g_return_if_fail (EV_IS_TIMELINE (timeline));
294
295         EV_TIMELINE_GET_CLASS (timeline)->start (timeline);
296 }
297
298 void
299 ev_timeline_pause (EvTimeline *timeline)
300 {
301         EvTimelinePriv *priv;
302
303         g_return_if_fail (EV_IS_TIMELINE (timeline));
304
305         priv = EV_TIMELINE_GET_PRIV (timeline);
306
307         if (priv->source_id) {
308                 g_source_remove (priv->source_id);
309                 priv->source_id = 0;
310                 g_timer_stop (priv->timer);
311                 g_signal_emit (timeline, signals [PAUSED], 0);
312         }
313 }
314
315 void
316 ev_timeline_rewind (EvTimeline *timeline)
317 {
318         EvTimelinePriv *priv;
319
320         g_return_if_fail (EV_IS_TIMELINE (timeline));
321
322         priv = EV_TIMELINE_GET_PRIV (timeline);
323
324         /* destroy and re-create timer if neccesary  */
325         if (priv->timer) {
326                 g_timer_destroy (priv->timer);
327
328                 if (ev_timeline_is_running (timeline))
329                         priv->timer = g_timer_new ();
330                 else
331                         priv->timer = NULL;
332         }
333 }
334
335 gboolean
336 ev_timeline_is_running (EvTimeline *timeline)
337 {
338         EvTimelinePriv *priv;
339
340         g_return_val_if_fail (EV_IS_TIMELINE (timeline), FALSE);
341
342         priv = EV_TIMELINE_GET_PRIV (timeline);
343
344         return (priv->source_id != 0);
345 }
346
347 guint
348 ev_timeline_get_fps (EvTimeline *timeline)
349 {
350         EvTimelinePriv *priv;
351
352         g_return_val_if_fail (EV_IS_TIMELINE (timeline), 1);
353
354         priv = EV_TIMELINE_GET_PRIV (timeline);
355         return priv->fps;
356 }
357
358 void
359 ev_timeline_set_fps (EvTimeline *timeline,
360                      guint       fps)
361 {
362         EvTimelinePriv *priv;
363
364         g_return_if_fail (EV_IS_TIMELINE (timeline));
365
366         priv = EV_TIMELINE_GET_PRIV (timeline);
367
368         priv->fps = fps;
369
370         if (ev_timeline_is_running (timeline)) {
371                 g_source_remove (priv->source_id);
372                 priv->source_id = g_timeout_add (FRAME_INTERVAL (priv->fps),
373                                                  (GSourceFunc) ev_timeline_run_frame,
374                                                  timeline);
375         }
376
377         g_object_notify (G_OBJECT (timeline), "fps");
378 }
379
380 gboolean
381 ev_timeline_get_loop (EvTimeline *timeline)
382 {
383         EvTimelinePriv *priv;
384
385         g_return_val_if_fail (EV_IS_TIMELINE (timeline), FALSE);
386
387         priv = EV_TIMELINE_GET_PRIV (timeline);
388         return priv->loop;
389 }
390
391 void
392 ev_timeline_set_loop (EvTimeline *timeline,
393                       gboolean    loop)
394 {
395         EvTimelinePriv *priv;
396
397         g_return_if_fail (EV_IS_TIMELINE (timeline));
398
399         priv = EV_TIMELINE_GET_PRIV (timeline);
400         priv->loop = loop;
401
402         g_object_notify (G_OBJECT (timeline), "loop");
403 }
404
405 void
406 ev_timeline_set_duration (EvTimeline *timeline,
407                           guint       duration)
408 {
409         EvTimelinePriv *priv;
410
411         g_return_if_fail (EV_IS_TIMELINE (timeline));
412
413         priv = EV_TIMELINE_GET_PRIV (timeline);
414
415         priv->duration = duration;
416
417         g_object_notify (G_OBJECT (timeline), "duration");
418 }
419
420 guint
421 ev_timeline_get_duration (EvTimeline *timeline)
422 {
423         EvTimelinePriv *priv;
424
425         g_return_val_if_fail (EV_IS_TIMELINE (timeline), 0);
426
427         priv = EV_TIMELINE_GET_PRIV (timeline);
428
429         return priv->duration;
430 }
431
432 gdouble
433 ev_timeline_get_progress (EvTimeline *timeline)
434 {
435         EvTimelinePriv *priv;
436         gdouble         progress;
437         guint           elapsed_time;
438
439         g_return_val_if_fail (EV_IS_TIMELINE (timeline), 0.0);
440
441         priv = EV_TIMELINE_GET_PRIV (timeline);
442
443         if (!priv->timer)
444                 return 0.;
445
446         elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000);
447         progress = (gdouble) elapsed_time / priv->duration;
448
449         return CLAMP (progress, 0., 1.);
450 }