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