]> Pileus Git - ~andy/gtk/blob - gdk/gdkframeclockidle.c
Add GdkFrameClock
[~andy/gtk] / gdk / gdkframeclockidle.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2010.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #include "config.h"
28
29 #include "gdkframeclockidle.h"
30 #include "gdk.h"
31
32 struct _GdkFrameClockIdlePrivate
33 {
34   GTimer *timer;
35   /* timer_base is used to avoid ever going backward */
36   guint64 timer_base;
37   guint64 frame_time;
38
39   guint idle_id;
40
41   unsigned int in_paint : 1;
42 };
43
44 static void gdk_frame_clock_idle_finalize             (GObject                *object);
45 static void gdk_frame_clock_idle_interface_init       (GdkFrameClockInterface *iface);
46
47 G_DEFINE_TYPE_WITH_CODE (GdkFrameClockIdle, gdk_frame_clock_idle, G_TYPE_OBJECT,
48                          G_IMPLEMENT_INTERFACE (GDK_TYPE_FRAME_CLOCK,
49                                                 gdk_frame_clock_idle_interface_init))
50
51 static void
52 gdk_frame_clock_idle_class_init (GdkFrameClockIdleClass *klass)
53 {
54   GObjectClass *gobject_class = (GObjectClass*) klass;
55
56   gobject_class->finalize     = gdk_frame_clock_idle_finalize;
57
58   g_type_class_add_private (klass, sizeof (GdkFrameClockIdlePrivate));
59 }
60
61 static void
62 gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
63 {
64   GdkFrameClockIdlePrivate *priv;
65
66   frame_clock_idle->priv = G_TYPE_INSTANCE_GET_PRIVATE (frame_clock_idle,
67                                                         GDK_TYPE_FRAME_CLOCK_IDLE,
68                                                         GdkFrameClockIdlePrivate);
69   priv = frame_clock_idle->priv;
70
71   priv->timer = g_timer_new ();
72 }
73
74 static void
75 gdk_frame_clock_idle_finalize (GObject *object)
76 {
77   GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (object)->priv;
78
79   g_timer_destroy (priv->timer);
80
81   G_OBJECT_CLASS (gdk_frame_clock_idle_parent_class)->finalize (object);
82 }
83
84 static guint64
85 compute_frame_time (GdkFrameClockIdle *idle)
86 {
87   GdkFrameClockIdlePrivate *priv = idle->priv;
88   guint64 computed_frame_time;
89   guint64 elapsed;
90
91   elapsed = ((guint64) (g_timer_elapsed (priv->timer, NULL) * 1000)) + priv->timer_base;
92   if (elapsed < priv->frame_time)
93     {
94       /* clock went backward. adapt to that by forevermore increasing
95        * timer_base.  For now, assume we've gone forward in time 1ms.
96        */
97       /* hmm. just fix GTimer? */
98       computed_frame_time = priv->frame_time + 1;
99       priv->timer_base += (priv->frame_time - elapsed) + 1;
100     }
101   else
102     {
103       computed_frame_time = elapsed;
104     }
105
106   return computed_frame_time;
107 }
108
109 static guint64
110 gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock)
111 {
112   GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv;
113   guint64 computed_frame_time;
114
115   /* can't change frame time during a paint */
116   if (priv->in_paint)
117     return priv->frame_time;
118
119   /* Outside a paint, pick something close to "now" */
120   computed_frame_time = compute_frame_time (GDK_FRAME_CLOCK_IDLE (clock));
121
122   /* 16ms is 60fps. We only update frame time that often because we'd
123    * like to try to keep animations on the same start times.
124    * get_frame_time() would normally be used outside of a paint to
125    * record an animation start time for example.
126    */
127   if ((computed_frame_time - priv->frame_time) > 16)
128     priv->frame_time = computed_frame_time;
129
130   return priv->frame_time;
131 }
132
133 static gboolean
134 gdk_frame_clock_paint_idle (void *data)
135 {
136   GdkFrameClock *clock = GDK_FRAME_CLOCK (data);
137   GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
138   GdkFrameClockIdlePrivate *priv = clock_idle->priv;
139
140   priv->idle_id = 0;
141
142   priv->in_paint = TRUE;
143   priv->frame_time = compute_frame_time (clock_idle);
144
145   gdk_frame_clock_paint (clock);
146
147   priv->in_paint = FALSE;
148
149   return FALSE;
150 }
151
152 static void
153 gdk_frame_clock_idle_request_frame (GdkFrameClock *clock)
154 {
155   GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv;
156
157   if (priv->idle_id == 0)
158     {
159       priv->idle_id = gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
160                                                  gdk_frame_clock_paint_idle,
161                                                  g_object_ref (clock),
162                                                  (GDestroyNotify) g_object_unref);
163
164       gdk_frame_clock_frame_requested (clock);
165     }
166 }
167
168 static gboolean
169 gdk_frame_clock_idle_get_frame_requested (GdkFrameClock *clock)
170 {
171   GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv;
172
173   return priv->idle_id != 0;
174 }
175
176 static void
177 gdk_frame_clock_idle_interface_init (GdkFrameClockInterface *iface)
178 {
179   iface->get_frame_time = gdk_frame_clock_idle_get_frame_time;
180   iface->request_frame = gdk_frame_clock_idle_request_frame;
181   iface->get_frame_requested = gdk_frame_clock_idle_get_frame_requested;
182 }