]> Pileus Git - ~andy/gtk/blob - gtk/gtktimeline.c
ad2e7dfcd4c8bf28357a17052c52fe0054c6ca6b
[~andy/gtk] / gtk / gtktimeline.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2007 Carlos Garnacho <carlos@imendio.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <gtk/gtktimeline.h>
19 #include <gtk/gtktypebuiltins.h>
20 #include <gtk/gtksettings.h>
21 #include <math.h>
22
23 typedef struct GtkTimelinePriv GtkTimelinePriv;
24
25 struct GtkTimelinePriv
26 {
27   guint duration;
28
29   guint64 last_time;
30   gdouble elapsed_time;
31
32   gdouble progress;
33   gdouble last_progress;
34
35   GtkWidget *widget;
36   GdkFrameClock *frame_clock;
37   GdkScreen *screen;
38
39   guint update_id;
40
41   GtkTimelineProgressType progress_type;
42
43   guint animations_enabled : 1;
44   guint loop               : 1;
45   guint direction          : 1;
46   guint running            : 1;
47 };
48
49 enum {
50   PROP_0,
51   PROP_DURATION,
52   PROP_LOOP,
53   PROP_DIRECTION,
54   PROP_FRAME_CLOCK,
55   PROP_PROGRESS_TYPE,
56   PROP_SCREEN,
57   PROP_WIDGET
58 };
59
60 enum {
61   STARTED,
62   PAUSED,
63   FINISHED,
64   FRAME,
65   LAST_SIGNAL
66 };
67
68 static guint signals [LAST_SIGNAL] = { 0, };
69
70
71 static void gtk_timeline_start_running (GtkTimeline *timeline);
72 static void gtk_timeline_stop_running (GtkTimeline *timeline);
73
74 static void frame_clock_target_iface_init (GdkFrameClockTargetInterface *target);
75
76 static void  gtk_timeline_set_property  (GObject         *object,
77                                          guint            prop_id,
78                                          const GValue    *value,
79                                          GParamSpec      *pspec);
80 static void  gtk_timeline_get_property  (GObject         *object,
81                                          guint            prop_id,
82                                          GValue          *value,
83                                          GParamSpec      *pspec);
84 static void  gtk_timeline_finalize      (GObject *object);
85
86 static void  gtk_timeline_set_clock     (GdkFrameClockTarget *target,
87                                          GdkFrameClock       *frame_clock);
88
89 G_DEFINE_TYPE_WITH_CODE (GtkTimeline, gtk_timeline, G_TYPE_OBJECT,
90                          G_IMPLEMENT_INTERFACE (GDK_TYPE_FRAME_CLOCK_TARGET, frame_clock_target_iface_init))
91
92 static void
93 gtk_timeline_class_init (GtkTimelineClass *klass)
94 {
95   GObjectClass *object_class = G_OBJECT_CLASS (klass);
96
97   object_class->set_property = gtk_timeline_set_property;
98   object_class->get_property = gtk_timeline_get_property;
99   object_class->finalize = gtk_timeline_finalize;
100
101   g_object_class_install_property (object_class,
102                                    PROP_DURATION,
103                                    g_param_spec_uint ("duration",
104                                                       "Animation Duration",
105                                                       "Animation Duration",
106                                                       0, G_MAXUINT,
107                                                       0,
108                                                       G_PARAM_READWRITE));
109   g_object_class_install_property (object_class,
110                                    PROP_LOOP,
111                                    g_param_spec_boolean ("loop",
112                                                          "Loop",
113                                                          "Whether the timeline loops or not",
114                                                          FALSE,
115                                                          G_PARAM_READWRITE));
116   g_object_class_install_property (object_class,
117                                    PROP_FRAME_CLOCK,
118                                    g_param_spec_object ("paint-clock",
119                                                         "Frame Clock",
120                                                         "clock used for timing the animation (not needed if :widget is set)",
121                                                         GDK_TYPE_FRAME_CLOCK,
122                                                         G_PARAM_READWRITE));
123   g_object_class_install_property (object_class,
124                                    PROP_PROGRESS_TYPE,
125                                    g_param_spec_enum ("progress-type",
126                                                       "Progress Type",
127                                                       "Easing function for animation progress",
128                                                       GTK_TYPE_TIMELINE_PROGRESS_TYPE,
129                                                       GTK_TIMELINE_PROGRESS_EASE_OUT,
130                                                       G_PARAM_READWRITE));
131   g_object_class_install_property (object_class,
132                                    PROP_SCREEN,
133                                    g_param_spec_object ("screen",
134                                                         "Screen",
135                                                         "Screen to get the settings from (not needed if :widget is set)",
136                                                         GDK_TYPE_SCREEN,
137                                                         G_PARAM_READWRITE));
138   g_object_class_install_property (object_class,
139                                    PROP_WIDGET,
140                                    g_param_spec_object ("widget",
141                                                         "Widget",
142                                                         "Widget the timeline will be used with",
143                                                         GTK_TYPE_WIDGET,
144                                                         G_PARAM_READWRITE));
145
146   signals[STARTED] =
147     g_signal_new ("started",
148                   G_TYPE_FROM_CLASS (object_class),
149                   G_SIGNAL_RUN_LAST,
150                   G_STRUCT_OFFSET (GtkTimelineClass, started),
151                   NULL, NULL,
152                   g_cclosure_marshal_VOID__VOID,
153                   G_TYPE_NONE, 0);
154
155   signals[PAUSED] =
156     g_signal_new ("paused",
157                   G_TYPE_FROM_CLASS (object_class),
158                   G_SIGNAL_RUN_LAST,
159                   G_STRUCT_OFFSET (GtkTimelineClass, paused),
160                   NULL, NULL,
161                   g_cclosure_marshal_VOID__VOID,
162                   G_TYPE_NONE, 0);
163
164   signals[FINISHED] =
165     g_signal_new ("finished",
166                   G_TYPE_FROM_CLASS (object_class),
167                   G_SIGNAL_RUN_LAST,
168                   G_STRUCT_OFFSET (GtkTimelineClass, finished),
169                   NULL, NULL,
170                   g_cclosure_marshal_VOID__VOID,
171                   G_TYPE_NONE, 0);
172
173   signals[FRAME] =
174     g_signal_new ("frame",
175                   G_TYPE_FROM_CLASS (object_class),
176                   G_SIGNAL_RUN_LAST,
177                   G_STRUCT_OFFSET (GtkTimelineClass, frame),
178                   NULL, NULL,
179                   g_cclosure_marshal_VOID__DOUBLE,
180                   G_TYPE_NONE, 1,
181                   G_TYPE_DOUBLE);
182
183   g_type_class_add_private (klass, sizeof (GtkTimelinePriv));
184 }
185
186 static void
187 frame_clock_target_iface_init (GdkFrameClockTargetInterface *iface)
188 {
189   iface->set_clock = gtk_timeline_set_clock;
190 }
191
192 static void
193 gtk_timeline_init (GtkTimeline *timeline)
194 {
195   GtkTimelinePriv *priv;
196
197   priv = timeline->priv = G_TYPE_INSTANCE_GET_PRIVATE (timeline,
198                                                        GTK_TYPE_TIMELINE,
199                                                        GtkTimelinePriv);
200
201   priv->duration = 0.0;
202   priv->direction = GTK_TIMELINE_DIRECTION_FORWARD;
203   priv->progress_type = GTK_TIMELINE_PROGRESS_EASE_OUT;
204   priv->screen = gdk_screen_get_default ();
205
206   priv->last_progress = 0;
207 }
208
209 static void
210 gtk_timeline_set_property (GObject      *object,
211                            guint         prop_id,
212                            const GValue *value,
213                            GParamSpec   *pspec)
214 {
215   GtkTimeline *timeline;
216
217   timeline = GTK_TIMELINE (object);
218
219   switch (prop_id)
220     {
221     case PROP_DURATION:
222       gtk_timeline_set_duration (timeline, g_value_get_uint (value));
223       break;
224     case PROP_LOOP:
225       gtk_timeline_set_loop (timeline, g_value_get_boolean (value));
226       break;
227     case PROP_DIRECTION:
228       gtk_timeline_set_direction (timeline, g_value_get_enum (value));
229       break;
230     case PROP_FRAME_CLOCK:
231       gtk_timeline_set_frame_clock (timeline,
232                                     GDK_FRAME_CLOCK (g_value_get_object (value)));
233       break;
234     case PROP_PROGRESS_TYPE:
235       gtk_timeline_set_progress_type (timeline,
236                                       g_value_get_enum (value));
237       break;
238     case PROP_SCREEN:
239       gtk_timeline_set_screen (timeline,
240                                GDK_SCREEN (g_value_get_object (value)));
241       break;
242     case PROP_WIDGET:
243       gtk_timeline_set_widget (timeline,
244                                GTK_WIDGET (g_value_get_object (value)));
245       break;
246     default:
247       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
248     }
249 }
250
251 static void
252 gtk_timeline_get_property (GObject    *object,
253                            guint       prop_id,
254                            GValue     *value,
255                            GParamSpec *pspec)
256 {
257   GtkTimeline *timeline;
258   GtkTimelinePriv *priv;
259
260   timeline = GTK_TIMELINE (object);
261   priv = timeline->priv;
262
263   switch (prop_id)
264     {
265     case PROP_DURATION:
266       g_value_set_uint (value, priv->duration);
267       break;
268     case PROP_LOOP:
269       g_value_set_boolean (value, priv->loop);
270       break;
271     case PROP_DIRECTION:
272       g_value_set_enum (value, priv->direction);
273       break;
274     case PROP_FRAME_CLOCK:
275       g_value_set_object (value, priv->frame_clock);
276       break;
277     case PROP_PROGRESS_TYPE:
278       g_value_set_enum (value, priv->progress_type);
279       break;
280     case PROP_SCREEN:
281       g_value_set_object (value, priv->screen);
282       break;
283     case PROP_WIDGET:
284       g_value_set_object (value, priv->widget);
285       break;
286     default:
287       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
288     }
289 }
290
291 static void
292 gtk_timeline_finalize (GObject *object)
293 {
294   GtkTimelinePriv *priv;
295   GtkTimeline *timeline;
296
297   timeline = (GtkTimeline *) object;
298   priv = timeline->priv;
299
300   if (priv->running)
301     {
302       gtk_timeline_stop_running (timeline);
303       priv->running = FALSE;
304     }
305
306   G_OBJECT_CLASS (gtk_timeline_parent_class)->finalize (object);
307 }
308
309 /* Implementation of GdkFrameClockTarget method */
310 static void
311 gtk_timeline_set_clock (GdkFrameClockTarget *target,
312                         GdkFrameClock       *frame_clock)
313 {
314   gtk_timeline_set_frame_clock (GTK_TIMELINE (target),
315                                 frame_clock);
316 }
317
318 static gdouble
319 calculate_progress (gdouble                 linear_progress,
320                     GtkTimelineProgressType progress_type)
321 {
322   gdouble progress;
323
324   progress = linear_progress;
325
326   switch (progress_type)
327     {
328     case GTK_TIMELINE_PROGRESS_LINEAR:
329       break;
330     case GTK_TIMELINE_PROGRESS_EASE_IN_OUT:
331       progress *= 2;
332
333       if (progress < 1)
334         progress = pow (progress, 3) / 2;
335       else
336         progress = (pow (progress - 2, 3) + 2) / 2;
337
338       break;
339     case GTK_TIMELINE_PROGRESS_EASE:
340       progress = (sin ((progress - 0.5) * G_PI) + 1) / 2;
341       break;
342     case GTK_TIMELINE_PROGRESS_EASE_IN:
343       progress = pow (progress, 3);
344       break;
345     case GTK_TIMELINE_PROGRESS_EASE_OUT:
346       progress = pow (progress - 1, 3) + 1;
347       break;
348     default:
349       g_warning ("Timeline progress type not implemented");
350     }
351
352   return progress;
353 }
354
355 static void
356 gtk_timeline_on_update (GdkFrameClock *clock,
357                         GtkTimeline   *timeline)
358 {
359   GtkTimelinePriv *priv;
360   gdouble delta_progress, progress, adjust;
361   guint64 now;
362
363   /* the user may unref us during the signals, so save ourselves */
364   g_object_ref (timeline);
365
366   priv = timeline->priv;
367
368   now = gdk_frame_clock_get_frame_time (clock);
369   priv->elapsed_time = (now - priv->last_time) / 1000;
370   priv->last_time = now;
371
372   if (priv->animations_enabled)
373     {
374       delta_progress = (gdouble) priv->elapsed_time / priv->duration;
375       progress = priv->last_progress;
376
377       if (priv->direction == GTK_TIMELINE_DIRECTION_BACKWARD)
378         progress -= delta_progress;
379       else
380         progress += delta_progress;
381
382       priv->last_progress = progress;
383
384       /* When looping, if we go past the end, start that much into the
385        * next cycle */
386       if (progress < 0.0)
387         {
388           adjust = progress - ceil(progress);
389           progress = 0.0;
390         }
391       else if (progress > 1.0)
392         {
393           adjust = progress - floor(progress);
394           progress = 1.0;
395         }
396       else
397         adjust = 0.0;
398
399       progress = CLAMP (progress, 0., 1.);
400     }
401   else
402     progress = (priv->direction == GTK_TIMELINE_DIRECTION_FORWARD) ? 1.0 : 0.0;
403
404   priv->progress = progress;
405   g_signal_emit (timeline, signals [FRAME], 0,
406                  calculate_progress (progress, priv->progress_type));
407
408   if ((priv->direction == GTK_TIMELINE_DIRECTION_FORWARD && progress == 1.0) ||
409       (priv->direction == GTK_TIMELINE_DIRECTION_BACKWARD && progress == 0.0))
410     {
411       gboolean loop;
412
413       loop = priv->loop && priv->animations_enabled;
414
415       if (loop)
416         {
417           gtk_timeline_rewind (timeline);
418           priv->progress += adjust;
419         }
420       else
421         {
422           gtk_timeline_stop_running (timeline);
423           priv->running = FALSE;
424
425           g_signal_emit (timeline, signals [FINISHED], 0);
426           g_object_unref (timeline);
427           return;
428         }
429     }
430
431   g_object_unref (timeline);
432   gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
433 }
434
435 static void
436 gtk_timeline_start_updating (GtkTimeline *timeline)
437 {
438   GtkTimelinePriv *priv = timeline->priv;
439
440   g_assert (priv->running && priv->frame_clock && priv->update_id == 0);
441
442   priv->update_id = g_signal_connect (priv->frame_clock,
443                                       "update",
444                                       G_CALLBACK (gtk_timeline_on_update),
445                                       timeline);
446
447   gdk_frame_clock_request_phase (priv->frame_clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
448   priv->last_time = gdk_frame_clock_get_frame_time (priv->frame_clock);
449 }
450
451 static void
452 gtk_timeline_stop_updating (GtkTimeline *timeline)
453 {
454   GtkTimelinePriv *priv = timeline->priv;
455
456   g_assert (priv->running && priv->frame_clock && priv->update_id != 0);
457
458   g_signal_handler_disconnect (priv->frame_clock,
459                                priv->update_id);
460   priv->update_id = 0;
461 }
462
463 static void
464 gtk_timeline_start_running (GtkTimeline *timeline)
465 {
466   GtkTimelinePriv *priv = timeline->priv;
467
468   g_assert (priv->running);
469
470   if (priv->widget)
471     gtk_widget_add_frame_clock_target (priv->widget,
472                                        GDK_FRAME_CLOCK_TARGET (timeline));
473   else if (priv->frame_clock)
474     gtk_timeline_start_updating (timeline);
475 }
476
477 static void
478 gtk_timeline_stop_running (GtkTimeline *timeline)
479 {
480   GtkTimelinePriv *priv = timeline->priv;
481
482   g_assert (priv->running);
483
484   if (priv->widget)
485     gtk_widget_remove_frame_clock_target (priv->widget,
486                                           GDK_FRAME_CLOCK_TARGET (timeline));
487   else if (priv->frame_clock)
488     gtk_timeline_stop_updating (timeline);
489 }
490
491 /**
492  * gtk_timeline_new:
493  * @widget: a widget the timeline will be used with
494  * @duration: duration in milliseconds for the timeline
495  *
496  * Creates a new #GtkTimeline with the specified duration
497  *
498  * Return Value: the newly created #GtkTimeline
499  */
500 GtkTimeline *
501 gtk_timeline_new (GtkWidget *widget,
502                   guint      duration)
503 {
504   return g_object_new (GTK_TYPE_TIMELINE,
505                        "widget", widget,
506                        "duration", duration,
507                        NULL);
508 }
509
510 /**
511  * gtk_timeline_start:
512  * @timeline: A #GtkTimeline
513  *
514  * Runs the timeline from the current frame.
515  */
516 void
517 gtk_timeline_start (GtkTimeline *timeline)
518 {
519   GtkTimelinePriv *priv;
520   GtkSettings *settings;
521   gboolean enable_animations = FALSE;
522
523   g_return_if_fail (GTK_IS_TIMELINE (timeline));
524
525   priv = timeline->priv;
526
527   if (!priv->running)
528     {
529       if (priv->screen)
530         {
531           settings = gtk_settings_get_for_screen (priv->screen);
532           g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL);
533         }
534
535       priv->animations_enabled = enable_animations;
536
537       priv->running = TRUE;
538       gtk_timeline_start_running (timeline);
539
540       g_signal_emit (timeline, signals [STARTED], 0);
541     }
542 }
543
544 /**
545  * gtk_timeline_pause:
546  * @timeline: A #GtkTimeline
547  *
548  * Pauses the timeline.
549  */
550 void
551 gtk_timeline_pause (GtkTimeline *timeline)
552 {
553   GtkTimelinePriv *priv;
554
555   g_return_if_fail (GTK_IS_TIMELINE (timeline));
556
557   priv = timeline->priv;
558
559   if (priv->running)
560     {
561       gtk_timeline_stop_running (timeline);
562       priv->running = FALSE;
563
564       g_signal_emit (timeline, signals [PAUSED], 0);
565     }
566 }
567
568 /**
569  * gtk_timeline_rewind:
570  * @timeline: A #GtkTimeline
571  *
572  * Rewinds the timeline.
573  */
574 void
575 gtk_timeline_rewind (GtkTimeline *timeline)
576 {
577   GtkTimelinePriv *priv;
578
579   g_return_if_fail (GTK_IS_TIMELINE (timeline));
580
581   priv = timeline->priv;
582
583   if (gtk_timeline_get_direction (timeline) != GTK_TIMELINE_DIRECTION_FORWARD)
584     priv->progress = priv->last_progress = 1.;
585   else
586     priv->progress = priv->last_progress = 0.;
587
588   if (priv->running && priv->frame_clock)
589     priv->last_time = gdk_frame_clock_get_frame_time (priv->frame_clock);
590 }
591
592 /**
593  * gtk_timeline_is_running:
594  * @timeline: A #GtkTimeline
595  *
596  * Returns whether the timeline is running or not.
597  *
598  * Return Value: %TRUE if the timeline is running
599  */
600 gboolean
601 gtk_timeline_is_running (GtkTimeline *timeline)
602 {
603   GtkTimelinePriv *priv;
604
605   g_return_val_if_fail (GTK_IS_TIMELINE (timeline), FALSE);
606
607   priv = timeline->priv;
608
609   return priv->running;
610 }
611
612 /**
613  * gtk_timeline_get_elapsed_time:
614  * @timeline: A #GtkTimeline
615  *
616  * Returns the elapsed time since the last GtkTimeline::frame signal
617  *
618  * Return Value: elapsed time in milliseconds since the last frame
619  */
620 guint
621 gtk_timeline_get_elapsed_time (GtkTimeline *timeline)
622 {
623   GtkTimelinePriv *priv;
624
625   g_return_val_if_fail (GTK_IS_TIMELINE (timeline), 0);
626
627   priv = timeline->priv;
628   return priv->elapsed_time;
629 }
630
631 /**
632  * gtk_timeline_get_loop:
633  * @timeline: A #GtkTimeline
634  *
635  * Returns whether the timeline loops to the
636  * beginning when it has reached the end.
637  *
638  * Return Value: %TRUE if the timeline loops
639  */
640 gboolean
641 gtk_timeline_get_loop (GtkTimeline *timeline)
642 {
643   GtkTimelinePriv *priv;
644
645   g_return_val_if_fail (GTK_IS_TIMELINE (timeline), FALSE);
646
647   priv = timeline->priv;
648   return priv->loop;
649 }
650
651 /**
652  * gtk_timeline_set_loop:
653  * @timeline: A #GtkTimeline
654  * @loop: %TRUE to make the timeline loop
655  *
656  * Sets whether the timeline loops to the beginning
657  * when it has reached the end.
658  */
659 void
660 gtk_timeline_set_loop (GtkTimeline *timeline,
661                         gboolean     loop)
662 {
663   GtkTimelinePriv *priv;
664
665   g_return_if_fail (GTK_IS_TIMELINE (timeline));
666
667   priv = timeline->priv;
668
669   if (loop != priv->loop)
670     {
671       priv->loop = loop;
672       g_object_notify (G_OBJECT (timeline), "loop");
673     }
674 }
675
676 void
677 gtk_timeline_set_duration (GtkTimeline *timeline,
678                             guint        duration)
679 {
680   GtkTimelinePriv *priv;
681
682   g_return_if_fail (GTK_IS_TIMELINE (timeline));
683
684   priv = timeline->priv;
685
686   if (duration != priv->duration)
687     {
688       priv->duration = duration;
689       g_object_notify (G_OBJECT (timeline), "duration");
690     }
691 }
692
693 guint
694 gtk_timeline_get_duration (GtkTimeline *timeline)
695 {
696   GtkTimelinePriv *priv;
697
698   g_return_val_if_fail (GTK_IS_TIMELINE (timeline), 0);
699
700   priv = timeline->priv;
701
702   return priv->duration;
703 }
704
705 /**
706  * gtk_timeline_set_direction:
707  * @timeline: A #GtkTimeline
708  * @direction: direction
709  *
710  * Sets the direction of the timeline.
711  */
712 void
713 gtk_timeline_set_direction (GtkTimeline          *timeline,
714                              GtkTimelineDirection  direction)
715 {
716   GtkTimelinePriv *priv;
717
718   g_return_if_fail (GTK_IS_TIMELINE (timeline));
719
720   priv = timeline->priv;
721   priv->direction = direction;
722 }
723
724 /*
725  * gtk_timeline_get_direction:
726  * @timeline: A #GtkTimeline
727  *
728  * Returns the direction of the timeline.
729  *
730  * Return Value: direction
731  */
732 GtkTimelineDirection
733 gtk_timeline_get_direction (GtkTimeline *timeline)
734 {
735   GtkTimelinePriv *priv;
736
737   g_return_val_if_fail (GTK_IS_TIMELINE (timeline), GTK_TIMELINE_DIRECTION_FORWARD);
738
739   priv = timeline->priv;
740   return priv->direction;
741 }
742
743 void
744 gtk_timeline_set_frame_clock (GtkTimeline   *timeline,
745                               GdkFrameClock *frame_clock)
746 {
747   GtkTimelinePriv *priv;
748
749   g_return_if_fail (GTK_IS_TIMELINE (timeline));
750   g_return_if_fail (frame_clock == NULL || GDK_IS_FRAME_CLOCK (frame_clock));
751
752   priv = timeline->priv;
753
754   if (frame_clock == priv->frame_clock)
755     return;
756
757   if (priv->running && priv->frame_clock)
758     gtk_timeline_stop_updating (timeline);
759
760   if (priv->frame_clock)
761     g_object_unref (priv->frame_clock);
762
763   priv->frame_clock = frame_clock;
764
765   if (priv->frame_clock)
766     g_object_ref (priv->frame_clock);
767
768   if (priv->running && priv->frame_clock)
769     gtk_timeline_start_updating (timeline);
770
771   g_object_notify (G_OBJECT (timeline), "paint-clock");
772 }
773
774 /**
775  * gtk_timeline_get_frame_clock:
776  *
777  * Returns: (transfer none): 
778  */
779 GdkFrameClock *
780 gtk_timeline_get_frame_clock (GtkTimeline *timeline)
781 {
782   GtkTimelinePriv *priv;
783
784   g_return_val_if_fail (GTK_IS_TIMELINE (timeline), NULL);
785
786   priv = timeline->priv;
787   return priv->frame_clock;
788 }
789
790 void
791 gtk_timeline_set_screen (GtkTimeline *timeline,
792                          GdkScreen   *screen)
793 {
794   GtkTimelinePriv *priv;
795
796   g_return_if_fail (GTK_IS_TIMELINE (timeline));
797   g_return_if_fail (screen == NULL || GDK_IS_SCREEN (screen));
798
799   priv = timeline->priv;
800
801   if (screen == priv->screen)
802     return;
803
804   if (priv->screen)
805     g_object_unref (priv->screen);
806
807   priv->screen = screen;
808
809   if (priv->screen)
810     g_object_ref (priv->screen);
811
812   g_object_notify (G_OBJECT (timeline), "screen");
813 }
814
815 /**
816  * gtk_timeline_get_screen:
817  *
818  * Returns: (transfer none): 
819  */
820 GdkScreen *
821 gtk_timeline_get_screen (GtkTimeline *timeline)
822 {
823   GtkTimelinePriv *priv;
824
825   g_return_val_if_fail (GTK_IS_TIMELINE (timeline), NULL);
826
827   priv = timeline->priv;
828   return priv->screen;
829 }
830 void
831 gtk_timeline_set_widget (GtkTimeline *timeline,
832                          GtkWidget   *widget)
833 {
834   GtkTimelinePriv *priv;
835
836   g_return_if_fail (GTK_IS_TIMELINE (timeline));
837   g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
838
839   priv = timeline->priv;
840
841   if (widget == priv->widget)
842     return;
843
844   if (priv->running)
845     gtk_timeline_stop_running (timeline);
846
847   if (priv->widget)
848     g_object_unref (priv->widget);
849
850   priv->widget = widget;
851
852   if (priv->widget)
853     g_object_ref (widget);
854
855   if (priv->running)
856     gtk_timeline_start_running (timeline);
857
858   g_object_notify (G_OBJECT (timeline), "widget");
859 }
860
861 /**
862  * gtk_timeline_get_widget:
863  *
864  * Returns: (transfer none): 
865  */
866 GtkWidget *
867 gtk_timeline_get_widget (GtkTimeline *timeline)
868 {
869   GtkTimelinePriv *priv;
870
871   g_return_val_if_fail (GTK_IS_TIMELINE (timeline), NULL);
872
873   priv = timeline->priv;
874   return priv->widget;
875 }
876
877 gdouble
878 gtk_timeline_get_progress (GtkTimeline *timeline)
879 {
880   GtkTimelinePriv *priv;
881
882   g_return_val_if_fail (GTK_IS_TIMELINE (timeline), 0.);
883
884   priv = timeline->priv;
885   return calculate_progress (priv->progress, priv->progress_type);
886 }
887
888 GtkTimelineProgressType
889 gtk_timeline_get_progress_type (GtkTimeline *timeline)
890 {
891   GtkTimelinePriv *priv;
892
893   g_return_val_if_fail (GTK_IS_TIMELINE (timeline), GTK_TIMELINE_PROGRESS_LINEAR);
894
895   priv = timeline->priv;
896   return priv->progress_type;
897 }
898
899 void
900 gtk_timeline_set_progress_type (GtkTimeline             *timeline,
901                                 GtkTimelineProgressType  progress_type)
902 {
903   GtkTimelinePriv *priv;
904
905   g_return_if_fail (GTK_IS_TIMELINE (timeline));
906
907   priv = timeline->priv;
908   priv->progress_type = progress_type;
909 }