]> Pileus Git - ~andy/gtk/blob - gdk/gdkframeclock.c
GdkFrameClock: Make the phase explicit when requesting the frame
[~andy/gtk] / gdk / gdkframeclock.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 "gdkframeclock.h"
30
31 /**
32  * SECTION:frameclock
33  * @Short_description: Frame clock syncs painting to a window or display
34  * @Title: Frame clock
35  *
36  * A #GdkFrameClock tells the application when to repaint a window.
37  * This may be synced to the vertical refresh rate of the monitor, for
38  * example. Even when the frame clock uses a simple timer rather than
39  * a hardware-based vertical sync, the frame clock helps because it
40  * ensures everything paints at the same time (reducing the total
41  * number of frames). The frame clock can also automatically stop
42  * painting when it knows the frames will not be visible, or scale back
43  * animation framerates.
44  *
45  * #GdkFrameClock is designed to be compatible with an OpenGL-based
46  * implementation or with mozRequestAnimationFrame in Firefox,
47  * for example.
48  *
49  * A frame clock is idle until someone requests a frame with
50  * gdk_frame_clock_request_phase(). At that time, the frame clock
51  * emits its GdkFrameClock:frame-requested signal if no frame was
52  * already pending.
53  *
54  * At some later time after the frame is requested, the frame clock
55  * MAY indicate that a frame should be painted. To paint a frame the
56  * clock will: Emit GdkFrameClock:before-paint; update the frame time
57  * in the default handler for GdkFrameClock:before-paint; emit
58  * GdkFrameClock:paint; emit GdkFrameClock:after-paint.  The app
59  * should paint in a handler for the paint signal.
60  *
61  * If a given frame is not painted (the clock is idle), the frame time
62  * should still update to a conceptual "last frame." i.e. the frame
63  * time will keep moving forward roughly with wall clock time.
64  *
65  * The frame time is in milliseconds. However, it should not be
66  * thought of as having any particular relationship to wall clock
67  * time. Unlike wall clock time, it "snaps" to conceptual frame times
68  * so is low-resolution; it is guaranteed to never move backward (so
69  * say you reset your computer clock, the frame clock will not reset);
70  * and the frame clock is allowed to drift. For example nicer
71  * results when painting with vertical refresh sync may be obtained by
72  * painting as rapidly as possible, but always incrementing the frame
73  * time by the frame length on each frame. This results in a frame
74  * time that doesn't have a lot to do with wall clock time.
75  */
76
77 G_DEFINE_INTERFACE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
78
79 enum {
80   FRAME_REQUESTED,
81   BEFORE_PAINT,
82   LAYOUT,
83   PAINT,
84   AFTER_PAINT,
85   LAST_SIGNAL
86 };
87
88 static guint signals[LAST_SIGNAL];
89
90 static void
91 gdk_frame_clock_default_init (GdkFrameClockInterface *iface)
92 {
93   /**
94    * GdkFrameClock::frame-requested:
95    * @clock: the frame clock emitting the signal
96    *
97    * This signal is emitted when a frame is not pending, and
98    * gdk_frame_clock_request_frame() is called to request a frame.
99    */
100   signals[FRAME_REQUESTED] =
101     g_signal_new (g_intern_static_string ("frame-requested"),
102                   GDK_TYPE_FRAME_CLOCK,
103                   G_SIGNAL_RUN_LAST,
104                   0,
105                   NULL, NULL,
106                   g_cclosure_marshal_VOID__VOID,
107                   G_TYPE_NONE, 0);
108
109   /**
110    * GdkFrameClock::before-paint:
111    * @clock: the frame clock emitting the signal
112    *
113    * This signal is emitted immediately before the paint signal and
114    * indicates that the frame time has been updated, and signal
115    * handlers should perform any preparatory work before painting.
116    */
117   signals[BEFORE_PAINT] =
118     g_signal_new (g_intern_static_string ("before-paint"),
119                   GDK_TYPE_FRAME_CLOCK,
120                   G_SIGNAL_RUN_LAST,
121                   0,
122                   NULL, NULL,
123                   g_cclosure_marshal_VOID__VOID,
124                   G_TYPE_NONE, 0);
125
126   /**
127    * GdkFrameClock::layout:
128    * @clock: the frame clock emitting the signal
129    *
130    * This signal is emitted immediately before the paint signal and
131    * indicates that the frame time has been updated, and signal
132    * handlers should perform any preparatory work before painting.
133    */
134   signals[LAYOUT] =
135     g_signal_new (g_intern_static_string ("layout"),
136                   GDK_TYPE_FRAME_CLOCK,
137                   G_SIGNAL_RUN_LAST,
138                   0,
139                   NULL, NULL,
140                   g_cclosure_marshal_VOID__VOID,
141                   G_TYPE_NONE, 0);
142
143   /**
144    * GdkFrameClock::paint:
145    * @clock: the frame clock emitting the signal
146    *
147    * Signal handlers for this signal should paint the window, screen,
148    * or whatever they normally paint.
149    */
150   signals[PAINT] =
151     g_signal_new (g_intern_static_string ("paint"),
152                   GDK_TYPE_FRAME_CLOCK,
153                   G_SIGNAL_RUN_LAST,
154                   0,
155                   NULL, NULL,
156                   g_cclosure_marshal_VOID__VOID,
157                   G_TYPE_NONE, 0);
158
159   /**
160    * GdkFrameClock::after-paint:
161    * @clock: the frame clock emitting the signal
162    *
163    * This signal is emitted immediately after the paint signal and
164    * allows signal handlers to do anything they'd like to do after
165    * painting has been completed. This is a relatively good time to do
166    * "expensive" processing in order to get it done in between frames.
167    */
168   signals[AFTER_PAINT] =
169     g_signal_new (g_intern_static_string ("after-paint"),
170                   GDK_TYPE_FRAME_CLOCK,
171                   G_SIGNAL_RUN_LAST,
172                   0,
173                   NULL, NULL,
174                   g_cclosure_marshal_VOID__VOID,
175                   G_TYPE_NONE, 0);
176 }
177
178 /**
179  * gdk_frame_clock_get_frame_time:
180  * @clock: the clock
181  *
182  * Gets the time that should currently be used for animations.  Inside
183  * a paint, it's the time used to compute the animation position of
184  * everything in a frame. Outside a paint, it's the time of the
185  * conceptual "previous frame," which may be either the actual
186  * previous frame time, or if that's too old, an updated time.
187  *
188  * The returned time has no relationship to wall clock time.  It
189  * increases roughly at 1 millisecond per wall clock millisecond, and
190  * it never decreases, but its value is only meaningful relative to
191  * previous frame clock times.
192  *
193  *
194  * Since: 3.0
195  * Return value: a timestamp in milliseconds
196  */
197 guint64
198 gdk_frame_clock_get_frame_time (GdkFrameClock *clock)
199 {
200   g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), 0);
201
202   return GDK_FRAME_CLOCK_GET_IFACE (clock)->get_frame_time (clock);
203 }
204
205 /**
206  * gdk_frame_clock_request_phase:
207  * @clock: the clock
208  *
209  * Asks the frame clock to paint a frame. The frame
210  * may or may not ever be painted (the frame clock may
211  * stop itself for whatever reason), but the goal in
212  * normal circumstances would be to paint the frame
213  * at the next expected frame time. For example
214  * if the clock is running at 60fps the frame would
215  * ideally be painted within 1000/60=16 milliseconds.
216  *
217  * Since: 3.0
218  */
219 void
220 gdk_frame_clock_request_phase (GdkFrameClock      *clock,
221                                GdkFrameClockPhase  phase)
222 {
223   g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
224
225   GDK_FRAME_CLOCK_GET_IFACE (clock)->request_phase (clock, phase);
226 }
227
228
229 /**
230  * gdk_frame_clock_get_requested:
231  * @clock: the clock
232  *
233  * Gets whether a frame paint has been requested but has not been
234  * performed.
235  *
236  *
237  * Since: 3.0
238  * Return value: TRUE if a frame paint is pending
239  */
240 GdkFrameClockPhase
241 gdk_frame_clock_get_requested (GdkFrameClock *clock)
242 {
243   g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), FALSE);
244
245   return GDK_FRAME_CLOCK_GET_IFACE (clock)->get_requested (clock);
246 }
247
248 /**
249  * gdk_frame_clock_get_frame_time_val:
250  * @clock: the clock
251  * @timeval: #GTimeVal to fill in with frame time
252  *
253  * Like gdk_frame_clock_get_frame_time() but returns the time as a
254  * #GTimeVal which may be handy with some APIs (such as
255  * #GdkPixbufAnimation).
256  */
257 void
258 gdk_frame_clock_get_frame_time_val (GdkFrameClock *clock,
259                                     GTimeVal      *timeval)
260 {
261   guint64 time_ms;
262
263   g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
264
265   time_ms = gdk_frame_clock_get_frame_time (clock);
266
267   timeval->tv_sec = time_ms / 1000;
268   timeval->tv_usec = (time_ms % 1000) * 1000;
269 }
270
271 /**
272  * gdk_frame_clock_frame_requested:
273  * @clock: the clock
274  *
275  * Emits the frame-requested signal. Used in implementations of the
276  * #GdkFrameClock interface.
277  */
278 void
279 gdk_frame_clock_frame_requested (GdkFrameClock *clock)
280 {
281   g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
282
283   g_signal_emit (G_OBJECT (clock),
284                  signals[FRAME_REQUESTED], 0);
285 }