]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktimeline.c
GtkScrolledWindow: use GdkFrameClock for kinetic scrolling
[~andy/gtk] / gtk / gtktimeline.c
index 4053da94f859a03843a74a2a39502b2ed68aa47f..ad2e7dfcd4c8bf28357a17052c52fe0054c6ca6b 100644 (file)
@@ -12,9 +12,7 @@
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <gtk/gtktimeline.h>
 #include <gtk/gtksettings.h>
 #include <math.h>
 
-#define MSECS_PER_SEC 1000
-#define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes)
-#define DEFAULT_FPS 30
-
 typedef struct GtkTimelinePriv GtkTimelinePriv;
 
 struct GtkTimelinePriv
 {
   guint duration;
-  guint fps;
-  guint source_id;
 
-  GTimer *timer;
+  guint64 last_time;
+  gdouble elapsed_time;
 
   gdouble progress;
   gdouble last_progress;
 
+  GtkWidget *widget;
+  GdkFrameClock *frame_clock;
   GdkScreen *screen;
 
+  guint update_id;
+
   GtkTimelineProgressType progress_type;
 
   guint animations_enabled : 1;
   guint loop               : 1;
   guint direction          : 1;
+  guint running            : 1;
 };
 
 enum {
   PROP_0,
-  PROP_FPS,
   PROP_DURATION,
   PROP_LOOP,
   PROP_DIRECTION,
-  PROP_SCREEN
+  PROP_FRAME_CLOCK,
+  PROP_PROGRESS_TYPE,
+  PROP_SCREEN,
+  PROP_WIDGET
 };
 
 enum {
@@ -68,6 +68,11 @@ enum {
 static guint signals [LAST_SIGNAL] = { 0, };
 
 
+static void gtk_timeline_start_running (GtkTimeline *timeline);
+static void gtk_timeline_stop_running (GtkTimeline *timeline);
+
+static void frame_clock_target_iface_init (GdkFrameClockTargetInterface *target);
+
 static void  gtk_timeline_set_property  (GObject         *object,
                                          guint            prop_id,
                                          const GValue    *value,
@@ -76,29 +81,23 @@ static void  gtk_timeline_get_property  (GObject         *object,
                                          guint            prop_id,
                                          GValue          *value,
                                          GParamSpec      *pspec);
-static void  _gtk_timeline_finalize     (GObject *object);
-
+static void  gtk_timeline_finalize      (GObject *object);
 
-G_DEFINE_TYPE (GtkTimeline, _gtk_timeline, G_TYPE_OBJECT)
+static void  gtk_timeline_set_clock     (GdkFrameClockTarget *target,
+                                         GdkFrameClock       *frame_clock);
 
+G_DEFINE_TYPE_WITH_CODE (GtkTimeline, gtk_timeline, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GDK_TYPE_FRAME_CLOCK_TARGET, frame_clock_target_iface_init))
 
 static void
-_gtk_timeline_class_init (GtkTimelineClass *klass)
+gtk_timeline_class_init (GtkTimelineClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
   object_class->set_property = gtk_timeline_set_property;
   object_class->get_property = gtk_timeline_get_property;
-  object_class->finalize = _gtk_timeline_finalize;
+  object_class->finalize = gtk_timeline_finalize;
 
-  g_object_class_install_property (object_class,
-                                   PROP_FPS,
-                                   g_param_spec_uint ("fps",
-                                                      "FPS",
-                                                      "Frames per second for the timeline",
-                                                      1, G_MAXUINT,
-                                                      DEFAULT_FPS,
-                                                      G_PARAM_READWRITE));
   g_object_class_install_property (object_class,
                                    PROP_DURATION,
                                    g_param_spec_uint ("duration",
@@ -114,13 +113,35 @@ _gtk_timeline_class_init (GtkTimelineClass *klass)
                                                          "Whether the timeline loops or not",
                                                          FALSE,
                                                          G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_FRAME_CLOCK,
+                                   g_param_spec_object ("paint-clock",
+                                                        "Frame Clock",
+                                                        "clock used for timing the animation (not needed if :widget is set)",
+                                                        GDK_TYPE_FRAME_CLOCK,
+                                                        G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_PROGRESS_TYPE,
+                                   g_param_spec_enum ("progress-type",
+                                                      "Progress Type",
+                                                      "Easing function for animation progress",
+                                                      GTK_TYPE_TIMELINE_PROGRESS_TYPE,
+                                                      GTK_TIMELINE_PROGRESS_EASE_OUT,
+                                                      G_PARAM_READWRITE));
   g_object_class_install_property (object_class,
                                    PROP_SCREEN,
                                    g_param_spec_object ("screen",
                                                         "Screen",
-                                                        "Screen to get the settings from",
+                                                        "Screen to get the settings from (not needed if :widget is set)",
                                                         GDK_TYPE_SCREEN,
                                                         G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_WIDGET,
+                                   g_param_spec_object ("widget",
+                                                        "Widget",
+                                                        "Widget the timeline will be used with",
+                                                        GTK_TYPE_WIDGET,
+                                                        G_PARAM_READWRITE));
 
   signals[STARTED] =
     g_signal_new ("started",
@@ -163,7 +184,13 @@ _gtk_timeline_class_init (GtkTimelineClass *klass)
 }
 
 static void
-_gtk_timeline_init (GtkTimeline *timeline)
+frame_clock_target_iface_init (GdkFrameClockTargetInterface *iface)
+{
+  iface->set_clock = gtk_timeline_set_clock;
+}
+
+static void
+gtk_timeline_init (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
 
@@ -171,9 +198,9 @@ _gtk_timeline_init (GtkTimeline *timeline)
                                                        GTK_TYPE_TIMELINE,
                                                        GtkTimelinePriv);
 
-  priv->fps = DEFAULT_FPS;
   priv->duration = 0.0;
   priv->direction = GTK_TIMELINE_DIRECTION_FORWARD;
+  priv->progress_type = GTK_TIMELINE_PROGRESS_EASE_OUT;
   priv->screen = gdk_screen_get_default ();
 
   priv->last_progress = 0;
@@ -186,28 +213,35 @@ gtk_timeline_set_property (GObject      *object,
                            GParamSpec   *pspec)
 {
   GtkTimeline *timeline;
-  GtkTimelinePriv *priv;
 
   timeline = GTK_TIMELINE (object);
-  priv = timeline->priv;
 
   switch (prop_id)
     {
-    case PROP_FPS:
-      _gtk_timeline_set_fps (timeline, g_value_get_uint (value));
-      break;
     case PROP_DURATION:
-      _gtk_timeline_set_duration (timeline, g_value_get_uint (value));
+      gtk_timeline_set_duration (timeline, g_value_get_uint (value));
       break;
     case PROP_LOOP:
-      _gtk_timeline_set_loop (timeline, g_value_get_boolean (value));
+      gtk_timeline_set_loop (timeline, g_value_get_boolean (value));
       break;
     case PROP_DIRECTION:
-      _gtk_timeline_set_direction (timeline, g_value_get_enum (value));
+      gtk_timeline_set_direction (timeline, g_value_get_enum (value));
+      break;
+    case PROP_FRAME_CLOCK:
+      gtk_timeline_set_frame_clock (timeline,
+                                    GDK_FRAME_CLOCK (g_value_get_object (value)));
+      break;
+    case PROP_PROGRESS_TYPE:
+      gtk_timeline_set_progress_type (timeline,
+                                      g_value_get_enum (value));
       break;
     case PROP_SCREEN:
-      _gtk_timeline_set_screen (timeline,
-                                GDK_SCREEN (g_value_get_object (value)));
+      gtk_timeline_set_screen (timeline,
+                               GDK_SCREEN (g_value_get_object (value)));
+      break;
+    case PROP_WIDGET:
+      gtk_timeline_set_widget (timeline,
+                               GTK_WIDGET (g_value_get_object (value)));
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -228,9 +262,6 @@ gtk_timeline_get_property (GObject    *object,
 
   switch (prop_id)
     {
-    case PROP_FPS:
-      g_value_set_uint (value, priv->fps);
-      break;
     case PROP_DURATION:
       g_value_set_uint (value, priv->duration);
       break;
@@ -240,16 +271,25 @@ gtk_timeline_get_property (GObject    *object,
     case PROP_DIRECTION:
       g_value_set_enum (value, priv->direction);
       break;
+    case PROP_FRAME_CLOCK:
+      g_value_set_object (value, priv->frame_clock);
+      break;
+    case PROP_PROGRESS_TYPE:
+      g_value_set_enum (value, priv->progress_type);
+      break;
     case PROP_SCREEN:
       g_value_set_object (value, priv->screen);
       break;
+    case PROP_WIDGET:
+      g_value_set_object (value, priv->widget);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
 }
 
 static void
-_gtk_timeline_finalize (GObject *object)
+gtk_timeline_finalize (GObject *object)
 {
   GtkTimelinePriv *priv;
   GtkTimeline *timeline;
@@ -257,16 +297,22 @@ _gtk_timeline_finalize (GObject *object)
   timeline = (GtkTimeline *) object;
   priv = timeline->priv;
 
-  if (priv->source_id)
+  if (priv->running)
     {
-      g_source_remove (priv->source_id);
-      priv->source_id = 0;
+      gtk_timeline_stop_running (timeline);
+      priv->running = FALSE;
     }
 
-  if (priv->timer)
-    g_timer_destroy (priv->timer);
+  G_OBJECT_CLASS (gtk_timeline_parent_class)->finalize (object);
+}
 
-  G_OBJECT_CLASS (_gtk_timeline_parent_class)->finalize (object);
+/* Implementation of GdkFrameClockTarget method */
+static void
+gtk_timeline_set_clock (GdkFrameClockTarget *target,
+                        GdkFrameClock       *frame_clock)
+{
+  gtk_timeline_set_frame_clock (GTK_TIMELINE (target),
+                                frame_clock);
 }
 
 static gdouble
@@ -306,21 +352,26 @@ calculate_progress (gdouble                 linear_progress,
   return progress;
 }
 
-static gboolean
-gtk_timeline_run_frame (GtkTimeline *timeline)
+static void
+gtk_timeline_on_update (GdkFrameClock *clock,
+                        GtkTimeline   *timeline)
 {
   GtkTimelinePriv *priv;
-  gdouble delta_progress, progress;
-  guint elapsed_time;
+  gdouble delta_progress, progress, adjust;
+  guint64 now;
+
+  /* the user may unref us during the signals, so save ourselves */
+  g_object_ref (timeline);
 
   priv = timeline->priv;
 
-  elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000);
-  g_timer_start (priv->timer);
+  now = gdk_frame_clock_get_frame_time (clock);
+  priv->elapsed_time = (now - priv->last_time) / 1000;
+  priv->last_time = now;
 
   if (priv->animations_enabled)
     {
-      delta_progress = (gdouble) elapsed_time / priv->duration;
+      delta_progress = (gdouble) priv->elapsed_time / priv->duration;
       progress = priv->last_progress;
 
       if (priv->direction == GTK_TIMELINE_DIRECTION_BACKWARD)
@@ -330,6 +381,21 @@ gtk_timeline_run_frame (GtkTimeline *timeline)
 
       priv->last_progress = progress;
 
+      /* When looping, if we go past the end, start that much into the
+       * next cycle */
+      if (progress < 0.0)
+        {
+          adjust = progress - ceil(progress);
+          progress = 0.0;
+        }
+      else if (progress > 1.0)
+        {
+          adjust = progress - floor(progress);
+          progress = 1.0;
+        }
+      else
+        adjust = 0.0;
+
       progress = CLAMP (progress, 0., 1.);
     }
   else
@@ -342,47 +408,102 @@ gtk_timeline_run_frame (GtkTimeline *timeline)
   if ((priv->direction == GTK_TIMELINE_DIRECTION_FORWARD && progress == 1.0) ||
       (priv->direction == GTK_TIMELINE_DIRECTION_BACKWARD && progress == 0.0))
     {
-      if (!priv->loop)
+      gboolean loop;
+
+      loop = priv->loop && priv->animations_enabled;
+
+      if (loop)
         {
-          if (priv->source_id)
-            {
-              g_source_remove (priv->source_id);
-              priv->source_id = 0;
-            }
-          g_timer_stop (priv->timer);
-          g_signal_emit (timeline, signals [FINISHED], 0);
-          return FALSE;
+          gtk_timeline_rewind (timeline);
+          priv->progress += adjust;
         }
       else
-        _gtk_timeline_rewind (timeline);
+        {
+          gtk_timeline_stop_running (timeline);
+          priv->running = FALSE;
+
+          g_signal_emit (timeline, signals [FINISHED], 0);
+          g_object_unref (timeline);
+          return;
+        }
     }
 
-  return TRUE;
+  g_object_unref (timeline);
+  gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
+}
+
+static void
+gtk_timeline_start_updating (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv = timeline->priv;
+
+  g_assert (priv->running && priv->frame_clock && priv->update_id == 0);
+
+  priv->update_id = g_signal_connect (priv->frame_clock,
+                                      "update",
+                                      G_CALLBACK (gtk_timeline_on_update),
+                                      timeline);
+
+  gdk_frame_clock_request_phase (priv->frame_clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
+  priv->last_time = gdk_frame_clock_get_frame_time (priv->frame_clock);
+}
+
+static void
+gtk_timeline_stop_updating (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv = timeline->priv;
+
+  g_assert (priv->running && priv->frame_clock && priv->update_id != 0);
+
+  g_signal_handler_disconnect (priv->frame_clock,
+                               priv->update_id);
+  priv->update_id = 0;
+}
+
+static void
+gtk_timeline_start_running (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv = timeline->priv;
+
+  g_assert (priv->running);
+
+  if (priv->widget)
+    gtk_widget_add_frame_clock_target (priv->widget,
+                                       GDK_FRAME_CLOCK_TARGET (timeline));
+  else if (priv->frame_clock)
+    gtk_timeline_start_updating (timeline);
+}
+
+static void
+gtk_timeline_stop_running (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv = timeline->priv;
+
+  g_assert (priv->running);
+
+  if (priv->widget)
+    gtk_widget_remove_frame_clock_target (priv->widget,
+                                          GDK_FRAME_CLOCK_TARGET (timeline));
+  else if (priv->frame_clock)
+    gtk_timeline_stop_updating (timeline);
 }
 
 /**
  * gtk_timeline_new:
+ * @widget: a widget the timeline will be used with
  * @duration: duration in milliseconds for the timeline
  *
- * Creates a new #GtkTimeline with the specified number of frames.
+ * Creates a new #GtkTimeline with the specified duration
  *
  * Return Value: the newly created #GtkTimeline
- **/
-GtkTimeline *
-_gtk_timeline_new (guint duration)
-{
-  return g_object_new (GTK_TYPE_TIMELINE,
-                       "duration", duration,
-                       NULL);
-}
-
+ */
 GtkTimeline *
-_gtk_timeline_new_for_screen (guint      duration,
-                              GdkScreen *screen)
+gtk_timeline_new (GtkWidget *widget,
+                  guint      duration)
 {
   return g_object_new (GTK_TYPE_TIMELINE,
+                       "widget", widget,
                        "duration", duration,
-                       "screen", screen,
                        NULL);
 }
 
@@ -391,9 +512,9 @@ _gtk_timeline_new_for_screen (guint      duration,
  * @timeline: A #GtkTimeline
  *
  * Runs the timeline from the current frame.
- **/
+ */
 void
-_gtk_timeline_start (GtkTimeline *timeline)
+gtk_timeline_start (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
   GtkSettings *settings;
@@ -403,33 +524,20 @@ _gtk_timeline_start (GtkTimeline *timeline)
 
   priv = timeline->priv;
 
-  if (!priv->source_id)
+  if (!priv->running)
     {
-      if (priv->timer)
-        g_timer_continue (priv->timer);
-      else
-        priv->timer = g_timer_new ();
-
-      /* sanity check */
-      g_assert (priv->fps > 0);
-
       if (priv->screen)
         {
           settings = gtk_settings_get_for_screen (priv->screen);
           g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL);
         }
 
-      priv->animations_enabled = (enable_animations == TRUE);
+      priv->animations_enabled = enable_animations;
 
-      g_signal_emit (timeline, signals [STARTED], 0);
+      priv->running = TRUE;
+      gtk_timeline_start_running (timeline);
 
-      if (enable_animations)
-        priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps),
-                                                   (GSourceFunc) gtk_timeline_run_frame,
-                                                   timeline);
-      else
-        priv->source_id = gdk_threads_add_idle ((GSourceFunc) gtk_timeline_run_frame,
-                                                timeline);
+      g_signal_emit (timeline, signals [STARTED], 0);
     }
 }
 
@@ -438,9 +546,9 @@ _gtk_timeline_start (GtkTimeline *timeline)
  * @timeline: A #GtkTimeline
  *
  * Pauses the timeline.
- **/
+ */
 void
-_gtk_timeline_pause (GtkTimeline *timeline)
+gtk_timeline_pause (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
 
@@ -448,11 +556,11 @@ _gtk_timeline_pause (GtkTimeline *timeline)
 
   priv = timeline->priv;
 
-  if (priv->source_id)
+  if (priv->running)
     {
-      g_timer_stop (priv->timer);
-      g_source_remove (priv->source_id);
-      priv->source_id = 0;
+      gtk_timeline_stop_running (timeline);
+      priv->running = FALSE;
+
       g_signal_emit (timeline, signals [PAUSED], 0);
     }
 }
@@ -462,9 +570,9 @@ _gtk_timeline_pause (GtkTimeline *timeline)
  * @timeline: A #GtkTimeline
  *
  * Rewinds the timeline.
- **/
+ */
 void
-_gtk_timeline_rewind (GtkTimeline *timeline)
+gtk_timeline_rewind (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
 
@@ -472,19 +580,13 @@ _gtk_timeline_rewind (GtkTimeline *timeline)
 
   priv = timeline->priv;
 
-  if (_gtk_timeline_get_direction (timeline) != GTK_TIMELINE_DIRECTION_FORWARD)
+  if (gtk_timeline_get_direction (timeline) != GTK_TIMELINE_DIRECTION_FORWARD)
     priv->progress = priv->last_progress = 1.;
   else
     priv->progress = priv->last_progress = 0.;
 
-  /* reset timer */
-  if (priv->timer)
-    {
-      g_timer_start (priv->timer);
-
-      if (!priv->source_id)
-        g_timer_stop (priv->timer);
-    }
+  if (priv->running && priv->frame_clock)
+    priv->last_time = gdk_frame_clock_get_frame_time (priv->frame_clock);
 }
 
 /**
@@ -494,9 +596,9 @@ _gtk_timeline_rewind (GtkTimeline *timeline)
  * Returns whether the timeline is running or not.
  *
  * Return Value: %TRUE if the timeline is running
- **/
+ */
 gboolean
-_gtk_timeline_is_running (GtkTimeline *timeline)
+gtk_timeline_is_running (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
 
@@ -504,58 +606,26 @@ _gtk_timeline_is_running (GtkTimeline *timeline)
 
   priv = timeline->priv;
 
-  return (priv->source_id != 0);
+  return priv->running;
 }
 
 /**
- * gtk_timeline_get_fps:
+ * gtk_timeline_get_elapsed_time:
  * @timeline: A #GtkTimeline
  *
- * Returns the number of frames per second.
+ * Returns the elapsed time since the last GtkTimeline::frame signal
  *
- * Return Value: frames per second
- **/
+ * Return Value: elapsed time in milliseconds since the last frame
+ */
 guint
-_gtk_timeline_get_fps (GtkTimeline *timeline)
-{
-  GtkTimelinePriv *priv;
-
-  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), 1);
-
-  priv = timeline->priv;
-  return priv->fps;
-}
-
-/**
- * gtk_timeline_set_fps:
- * @timeline: A #GtkTimeline
- * @fps: frames per second
- *
- * Sets the number of frames per second that
- * the timeline will play.
- **/
-void
-_gtk_timeline_set_fps (GtkTimeline *timeline,
-                      guint        fps)
+gtk_timeline_get_elapsed_time (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
 
-  g_return_if_fail (GTK_IS_TIMELINE (timeline));
-  g_return_if_fail (fps > 0);
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), 0);
 
   priv = timeline->priv;
-
-  priv->fps = fps;
-
-  if (_gtk_timeline_is_running (timeline))
-    {
-      g_source_remove (priv->source_id);
-      priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps),
-                                                 (GSourceFunc) gtk_timeline_run_frame,
-                                                 timeline);
-    }
-
-  g_object_notify (G_OBJECT (timeline), "fps");
+  return priv->elapsed_time;
 }
 
 /**
@@ -566,9 +636,9 @@ _gtk_timeline_set_fps (GtkTimeline *timeline,
  * beginning when it has reached the end.
  *
  * Return Value: %TRUE if the timeline loops
- **/
+ */
 gboolean
-_gtk_timeline_get_loop (GtkTimeline *timeline)
+gtk_timeline_get_loop (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
 
@@ -585,9 +655,9 @@ _gtk_timeline_get_loop (GtkTimeline *timeline)
  *
  * Sets whether the timeline loops to the beginning
  * when it has reached the end.
- **/
+ */
 void
-_gtk_timeline_set_loop (GtkTimeline *timeline,
+gtk_timeline_set_loop (GtkTimeline *timeline,
                         gboolean     loop)
 {
   GtkTimelinePriv *priv;
@@ -604,7 +674,7 @@ _gtk_timeline_set_loop (GtkTimeline *timeline,
 }
 
 void
-_gtk_timeline_set_duration (GtkTimeline *timeline,
+gtk_timeline_set_duration (GtkTimeline *timeline,
                             guint        duration)
 {
   GtkTimelinePriv *priv;
@@ -621,7 +691,7 @@ _gtk_timeline_set_duration (GtkTimeline *timeline,
 }
 
 guint
-_gtk_timeline_get_duration (GtkTimeline *timeline)
+gtk_timeline_get_duration (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
 
@@ -638,9 +708,9 @@ _gtk_timeline_get_duration (GtkTimeline *timeline)
  * @direction: direction
  *
  * Sets the direction of the timeline.
- **/
+ */
 void
-_gtk_timeline_set_direction (GtkTimeline          *timeline,
+gtk_timeline_set_direction (GtkTimeline          *timeline,
                              GtkTimelineDirection  direction)
 {
   GtkTimelinePriv *priv;
@@ -651,16 +721,16 @@ _gtk_timeline_set_direction (GtkTimeline          *timeline,
   priv->direction = direction;
 }
 
-/**
+/*
  * gtk_timeline_get_direction:
  * @timeline: A #GtkTimeline
  *
  * Returns the direction of the timeline.
  *
  * Return Value: direction
- **/
+ */
 GtkTimelineDirection
-_gtk_timeline_get_direction (GtkTimeline *timeline)
+gtk_timeline_get_direction (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
 
@@ -671,26 +741,84 @@ _gtk_timeline_get_direction (GtkTimeline *timeline)
 }
 
 void
-_gtk_timeline_set_screen (GtkTimeline *timeline,
-                          GdkScreen   *screen)
+gtk_timeline_set_frame_clock (GtkTimeline   *timeline,
+                              GdkFrameClock *frame_clock)
 {
   GtkTimelinePriv *priv;
 
   g_return_if_fail (GTK_IS_TIMELINE (timeline));
-  g_return_if_fail (GDK_IS_SCREEN (screen));
+  g_return_if_fail (frame_clock == NULL || GDK_IS_FRAME_CLOCK (frame_clock));
 
   priv = timeline->priv;
 
+  if (frame_clock == priv->frame_clock)
+    return;
+
+  if (priv->running && priv->frame_clock)
+    gtk_timeline_stop_updating (timeline);
+
+  if (priv->frame_clock)
+    g_object_unref (priv->frame_clock);
+
+  priv->frame_clock = frame_clock;
+
+  if (priv->frame_clock)
+    g_object_ref (priv->frame_clock);
+
+  if (priv->running && priv->frame_clock)
+    gtk_timeline_start_updating (timeline);
+
+  g_object_notify (G_OBJECT (timeline), "paint-clock");
+}
+
+/**
+ * gtk_timeline_get_frame_clock:
+ *
+ * Returns: (transfer none): 
+ */
+GdkFrameClock *
+gtk_timeline_get_frame_clock (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), NULL);
+
+  priv = timeline->priv;
+  return priv->frame_clock;
+}
+
+void
+gtk_timeline_set_screen (GtkTimeline *timeline,
+                         GdkScreen   *screen)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_if_fail (GTK_IS_TIMELINE (timeline));
+  g_return_if_fail (screen == NULL || GDK_IS_SCREEN (screen));
+
+  priv = timeline->priv;
+
+  if (screen == priv->screen)
+    return;
+
   if (priv->screen)
     g_object_unref (priv->screen);
 
-  priv->screen = g_object_ref (screen);
+  priv->screen = screen;
+
+  if (priv->screen)
+    g_object_ref (priv->screen);
 
   g_object_notify (G_OBJECT (timeline), "screen");
 }
 
+/**
+ * gtk_timeline_get_screen:
+ *
+ * Returns: (transfer none): 
+ */
 GdkScreen *
-_gtk_timeline_get_screen (GtkTimeline *timeline)
+gtk_timeline_get_screen (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
 
@@ -699,9 +827,55 @@ _gtk_timeline_get_screen (GtkTimeline *timeline)
   priv = timeline->priv;
   return priv->screen;
 }
+void
+gtk_timeline_set_widget (GtkTimeline *timeline,
+                         GtkWidget   *widget)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_if_fail (GTK_IS_TIMELINE (timeline));
+  g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
+
+  priv = timeline->priv;
+
+  if (widget == priv->widget)
+    return;
+
+  if (priv->running)
+    gtk_timeline_stop_running (timeline);
+
+  if (priv->widget)
+    g_object_unref (priv->widget);
+
+  priv->widget = widget;
+
+  if (priv->widget)
+    g_object_ref (widget);
+
+  if (priv->running)
+    gtk_timeline_start_running (timeline);
+
+  g_object_notify (G_OBJECT (timeline), "widget");
+}
+
+/**
+ * gtk_timeline_get_widget:
+ *
+ * Returns: (transfer none): 
+ */
+GtkWidget *
+gtk_timeline_get_widget (GtkTimeline *timeline)
+{
+  GtkTimelinePriv *priv;
+
+  g_return_val_if_fail (GTK_IS_TIMELINE (timeline), NULL);
+
+  priv = timeline->priv;
+  return priv->widget;
+}
 
 gdouble
-_gtk_timeline_get_progress (GtkTimeline *timeline)
+gtk_timeline_get_progress (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
 
@@ -712,7 +886,7 @@ _gtk_timeline_get_progress (GtkTimeline *timeline)
 }
 
 GtkTimelineProgressType
-_gtk_timeline_get_progress_type (GtkTimeline *timeline)
+gtk_timeline_get_progress_type (GtkTimeline *timeline)
 {
   GtkTimelinePriv *priv;
 
@@ -723,8 +897,8 @@ _gtk_timeline_get_progress_type (GtkTimeline *timeline)
 }
 
 void
-_gtk_timeline_set_progress_type (GtkTimeline             *timeline,
-                                 GtkTimelineProgressType  progress_type)
+gtk_timeline_set_progress_type (GtkTimeline             *timeline,
+                                GtkTimelineProgressType  progress_type)
 {
   GtkTimelinePriv *priv;