1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
29 #include "gdkframeclock.h"
33 * @Short_description: Frame clock syncs painting to a window or display
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.
45 * #GdkFrameClock is designed to be compatible with an OpenGL-based
46 * implementation or with mozRequestAnimationFrame in Firefox,
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
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.
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.
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.
77 G_DEFINE_INTERFACE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
91 static guint signals[LAST_SIGNAL];
94 gdk_frame_clock_default_init (GdkFrameClockInterface *iface)
97 * GdkFrameClock::frame-requested:
98 * @clock: the frame clock emitting the signal
100 * This signal is emitted when a frame is not pending, and
101 * gdk_frame_clock_request_frame() is called to request a frame.
103 signals[FRAME_REQUESTED] =
104 g_signal_new (g_intern_static_string ("frame-requested"),
105 GDK_TYPE_FRAME_CLOCK,
109 g_cclosure_marshal_VOID__VOID,
113 * GdkFrameClock::flush-events:
114 * @clock: the frame clock emitting the signal
118 signals[FLUSH_EVENTS] =
119 g_signal_new (g_intern_static_string ("flush-events"),
120 GDK_TYPE_FRAME_CLOCK,
124 g_cclosure_marshal_VOID__VOID,
128 * GdkFrameClock::before-paint:
129 * @clock: the frame clock emitting the signal
131 * This signal is emitted immediately before the paint signal and
132 * indicates that the frame time has been updated, and signal
133 * handlers should perform any preparatory work before painting.
135 signals[BEFORE_PAINT] =
136 g_signal_new (g_intern_static_string ("before-paint"),
137 GDK_TYPE_FRAME_CLOCK,
141 g_cclosure_marshal_VOID__VOID,
145 * GdkFrameClock::update:
146 * @clock: the frame clock emitting the signal
151 g_signal_new (g_intern_static_string ("update"),
152 GDK_TYPE_FRAME_CLOCK,
156 g_cclosure_marshal_VOID__VOID,
160 * GdkFrameClock::layout:
161 * @clock: the frame clock emitting the signal
163 * This signal is emitted immediately before the paint signal and
164 * indicates that the frame time has been updated, and signal
165 * handlers should perform any preparatory work before painting.
168 g_signal_new (g_intern_static_string ("layout"),
169 GDK_TYPE_FRAME_CLOCK,
173 g_cclosure_marshal_VOID__VOID,
177 * GdkFrameClock::paint:
178 * @clock: the frame clock emitting the signal
180 * Signal handlers for this signal should paint the window, screen,
181 * or whatever they normally paint.
184 g_signal_new (g_intern_static_string ("paint"),
185 GDK_TYPE_FRAME_CLOCK,
189 g_cclosure_marshal_VOID__VOID,
193 * GdkFrameClock::after-paint:
194 * @clock: the frame clock emitting the signal
196 * This signal is emitted immediately after the paint signal and
197 * allows signal handlers to do anything they'd like to do after
198 * painting has been completed. This is a relatively good time to do
199 * "expensive" processing in order to get it done in between frames.
201 signals[AFTER_PAINT] =
202 g_signal_new (g_intern_static_string ("after-paint"),
203 GDK_TYPE_FRAME_CLOCK,
207 g_cclosure_marshal_VOID__VOID,
211 * GdkFrameClock::resume-events:
212 * @clock: the frame clock emitting the signal
216 signals[RESUME_EVENTS] =
217 g_signal_new (g_intern_static_string ("resume-events"),
218 GDK_TYPE_FRAME_CLOCK,
222 g_cclosure_marshal_VOID__VOID,
227 * gdk_frame_clock_get_frame_time:
230 * Gets the time that should currently be used for animations. Inside
231 * a paint, it's the time used to compute the animation position of
232 * everything in a frame. Outside a paint, it's the time of the
233 * conceptual "previous frame," which may be either the actual
234 * previous frame time, or if that's too old, an updated time.
236 * The returned time has no relationship to wall clock time. It
237 * increases roughly at 1 millisecond per wall clock millisecond, and
238 * it never decreases, but its value is only meaningful relative to
239 * previous frame clock times.
243 * Return value: a timestamp in milliseconds
246 gdk_frame_clock_get_frame_time (GdkFrameClock *clock)
248 g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), 0);
250 return GDK_FRAME_CLOCK_GET_IFACE (clock)->get_frame_time (clock);
254 * gdk_frame_clock_request_phase:
257 * Asks the frame clock to paint a frame. The frame
258 * may or may not ever be painted (the frame clock may
259 * stop itself for whatever reason), but the goal in
260 * normal circumstances would be to paint the frame
261 * at the next expected frame time. For example
262 * if the clock is running at 60fps the frame would
263 * ideally be painted within 1000/60=16 milliseconds.
268 gdk_frame_clock_request_phase (GdkFrameClock *clock,
269 GdkFrameClockPhase phase)
271 g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
273 GDK_FRAME_CLOCK_GET_IFACE (clock)->request_phase (clock, phase);
278 gdk_frame_clock_freeze (GdkFrameClock *clock)
280 g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
282 GDK_FRAME_CLOCK_GET_IFACE (clock)->freeze (clock);
287 gdk_frame_clock_thaw (GdkFrameClock *clock)
289 g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
291 GDK_FRAME_CLOCK_GET_IFACE (clock)->thaw (clock);
295 * gdk_frame_clock_get_history:
298 * Gets the #GdkFrameHistory for the frame clock.
301 * Return value: (transfer none): the frame history object
304 gdk_frame_clock_get_history (GdkFrameClock *clock)
306 g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), NULL);
308 return GDK_FRAME_CLOCK_GET_IFACE (clock)->get_history (clock);
312 * gdk_frame_clock_get_requested:
315 * Gets whether a frame paint has been requested but has not been
320 * Return value: TRUE if a frame paint is pending
323 gdk_frame_clock_get_requested (GdkFrameClock *clock)
325 g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), FALSE);
327 return GDK_FRAME_CLOCK_GET_IFACE (clock)->get_requested (clock);
331 * gdk_frame_clock_get_frame_time_val:
333 * @timeval: #GTimeVal to fill in with frame time
335 * Like gdk_frame_clock_get_frame_time() but returns the time as a
336 * #GTimeVal which may be handy with some APIs (such as
337 * #GdkPixbufAnimation).
340 gdk_frame_clock_get_frame_time_val (GdkFrameClock *clock,
345 g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
347 time_ms = gdk_frame_clock_get_frame_time (clock);
349 timeval->tv_sec = time_ms / 1000;
350 timeval->tv_usec = (time_ms % 1000) * 1000;
354 * gdk_frame_clock_frame_requested:
357 * Emits the frame-requested signal. Used in implementations of the
358 * #GdkFrameClock interface.
361 gdk_frame_clock_frame_requested (GdkFrameClock *clock)
363 g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
365 g_signal_emit (G_OBJECT (clock),
366 signals[FRAME_REQUESTED], 0);
370 gdk_frame_clock_get_current_frame_timings (GdkFrameClock *clock)
372 GdkFrameHistory *history;
373 gint64 frame_counter;
375 g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), 0);
377 history = gdk_frame_clock_get_history (clock);
378 frame_counter = gdk_frame_history_get_frame_counter (history);
379 return gdk_frame_history_get_timings (history, frame_counter);
383 #define DEFAULT_REFRESH_INTERVAL 16667 /* 16.7ms (1/60th second) */
384 #define MAX_HISTORY_AGE 150000 /* 150ms */
387 gdk_frame_clock_get_refresh_info (GdkFrameClock *clock,
389 gint64 *refresh_interval_return,
390 gint64 *presentation_time_return)
392 GdkFrameHistory *history;
393 gint64 frame_counter;
395 g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
397 history = gdk_frame_clock_get_history (clock);
398 frame_counter = gdk_frame_history_get_frame_counter (history);
400 if (presentation_time_return)
401 *presentation_time_return = 0;
402 if (refresh_interval_return)
403 *refresh_interval_return = DEFAULT_REFRESH_INTERVAL;
407 GdkFrameTimings *timings = gdk_frame_history_get_timings (history, frame_counter);
408 gint64 presentation_time;
409 gint64 refresh_interval;
414 refresh_interval = gdk_frame_timings_get_refresh_interval (timings);
415 presentation_time = gdk_frame_timings_get_presentation_time (timings);
417 if (presentation_time != 0)
419 if (presentation_time > base_time - MAX_HISTORY_AGE &&
420 presentation_time_return)
422 if (refresh_interval == 0)
423 refresh_interval = DEFAULT_REFRESH_INTERVAL;
425 if (refresh_interval_return)
426 *refresh_interval_return = refresh_interval;
428 while (presentation_time < base_time)
429 presentation_time += refresh_interval;
431 if (presentation_time_return)
432 *presentation_time_return = presentation_time;