diff options
author | Owen W. Taylor <otaylor@fishsoup.net> | 2012-10-03 18:34:01 -0400 |
---|---|---|
committer | Owen W. Taylor <otaylor@fishsoup.net> | 2013-02-14 17:19:47 -0500 |
commit | 77bac0d6ae2cbbe9a41ea36e705cc12f36df4cbc (patch) | |
tree | 2a50c8e9a30f11ea29399f88ef6a1bca600ada07 /gdk/gdkframeclock.c | |
parent | 001f960a433a68124ce1cf49207c81fde646b57a (diff) | |
download | gtk+-77bac0d6ae2cbbe9a41ea36e705cc12f36df4cbc.tar.gz |
Add GdkFrameClock
Add an object GdkFrameClock that we associate with a GdkWindow.
This tracks when the window needs to be repainted, and will also
be used for other operations in the future like relayout and
updating animations.
Based on a patch from Havoc Pennington:
https://mail.gnome.org/archives/gtk-devel-list/2010-October/msg00004.html
https://bugzilla.gnome.org/show_bug.cgi?id=685460
Diffstat (limited to 'gdk/gdkframeclock.c')
-rw-r--r-- | gdk/gdkframeclock.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c new file mode 100644 index 0000000000..6b23ce6321 --- /dev/null +++ b/gdk/gdkframeclock.c @@ -0,0 +1,287 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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. + */ + +/* + * Modified by the GTK+ Team and others 1997-2010. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include "gdkframeclock.h" + +/** + * SECTION:frameclock + * @Short_description: Frame clock syncs painting to a window or display + * @Title: Frame clock + * + * A #GdkFrameClock tells the application when to repaint a window. + * This may be synced to the vertical refresh rate of the monitor, for + * example. Even when the frame clock uses a simple timer rather than + * a hardware-based vertical sync, the frame clock helps because it + * ensures everything paints at the same time (reducing the total + * number of frames). The frame clock can also automatically stop + * painting when it knows the frames will not be visible, or scale back + * animation framerates. + * + * #GdkFrameClock is designed to be compatible with an OpenGL-based + * implementation or with mozRequestAnimationFrame in Firefox, + * for example. + * + * A frame clock is idle until someone requests a frame with + * gdk_frame_clock_request_frame(). At that time, the frame clock + * emits its GdkFrameClock:frame-requested signal if no frame was + * already pending. + * + * At some later time after the frame is requested, the frame clock + * MAY indicate that a frame should be painted. To paint a frame the + * clock will: Emit GdkFrameClock:before-paint; update the frame time + * in the default handler for GdkFrameClock:before-paint; emit + * GdkFrameClock:paint; emit GdkFrameClock:after-paint. The app + * should paint in a handler for the paint signal. + * + * If a given frame is not painted (the clock is idle), the frame time + * should still update to a conceptual "last frame." i.e. the frame + * time will keep moving forward roughly with wall clock time. + * + * The frame time is in milliseconds. However, it should not be + * thought of as having any particular relationship to wall clock + * time. Unlike wall clock time, it "snaps" to conceptual frame times + * so is low-resolution; it is guaranteed to never move backward (so + * say you reset your computer clock, the frame clock will not reset); + * and the frame clock is allowed to drift. For example nicer + * results when painting with vertical refresh sync may be obtained by + * painting as rapidly as possible, but always incrementing the frame + * time by the frame length on each frame. This results in a frame + * time that doesn't have a lot to do with wall clock time. + */ + +G_DEFINE_INTERFACE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT) + +enum { + FRAME_REQUESTED, + BEFORE_PAINT, + PAINT, + AFTER_PAINT, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void +gdk_frame_clock_default_init (GdkFrameClockInterface *iface) +{ + /** + * GdkFrameClock::frame-requested: + * @clock: the frame clock emitting the signal + * + * This signal is emitted when a frame is not pending, and + * gdk_frame_clock_request_frame() is called to request a frame. + */ + signals[FRAME_REQUESTED] = + g_signal_new (g_intern_static_string ("frame-requested"), + GDK_TYPE_FRAME_CLOCK, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * GdkFrameClock::before-paint: + * @clock: the frame clock emitting the signal + * + * This signal is emitted immediately before the paint signal and + * indicates that the frame time has been updated, and signal + * handlers should perform any preparatory work before painting. + */ + signals[BEFORE_PAINT] = + g_signal_new (g_intern_static_string ("before-paint"), + GDK_TYPE_FRAME_CLOCK, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * GdkFrameClock::paint: + * @clock: the frame clock emitting the signal + * + * Signal handlers for this signal should paint the window, screen, + * or whatever they normally paint. + */ + signals[PAINT] = + g_signal_new (g_intern_static_string ("paint"), + GDK_TYPE_FRAME_CLOCK, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * GdkFrameClock::after-paint: + * @clock: the frame clock emitting the signal + * + * This signal is emitted immediately after the paint signal and + * allows signal handlers to do anything they'd like to do after + * painting has been completed. This is a relatively good time to do + * "expensive" processing in order to get it done in between frames. + */ + signals[AFTER_PAINT] = + g_signal_new (g_intern_static_string ("after-paint"), + GDK_TYPE_FRAME_CLOCK, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +/** + * gdk_frame_clock_get_frame_time: + * @clock: the clock + * + * Gets the time that should currently be used for animations. Inside + * a paint, it's the time used to compute the animation position of + * everything in a frame. Outside a paint, it's the time of the + * conceptual "previous frame," which may be either the actual + * previous frame time, or if that's too old, an updated time. + * + * The returned time has no relationship to wall clock time. It + * increases roughly at 1 millisecond per wall clock millisecond, and + * it never decreases, but its value is only meaningful relative to + * previous frame clock times. + * + * + * Since: 3.0 + * Return value: a timestamp in milliseconds + */ +guint64 +gdk_frame_clock_get_frame_time (GdkFrameClock *clock) +{ + g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), 0); + + return GDK_FRAME_CLOCK_GET_IFACE (clock)->get_frame_time (clock); +} + +/** + * gdk_frame_clock_request_frame: + * @clock: the clock + * + * Asks the frame clock to paint a frame. The frame + * may or may not ever be painted (the frame clock may + * stop itself for whatever reason), but the goal in + * normal circumstances would be to paint the frame + * at the next expected frame time. For example + * if the clock is running at 60fps the frame would + * ideally be painted within 1000/60=16 milliseconds. + * + * Since: 3.0 + */ +void +gdk_frame_clock_request_frame (GdkFrameClock *clock) +{ + g_return_if_fail (GDK_IS_FRAME_CLOCK (clock)); + + GDK_FRAME_CLOCK_GET_IFACE (clock)->request_frame (clock); +} + +/** + * gdk_frame_clock_get_frame_requested: + * @clock: the clock + * + * Gets whether a frame paint has been requested but has not been + * performed. + * + * + * Since: 3.0 + * Return value: TRUE if a frame paint is pending + */ +gboolean +gdk_frame_clock_get_frame_requested (GdkFrameClock *clock) +{ + g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), FALSE); + + return GDK_FRAME_CLOCK_GET_IFACE (clock)->get_frame_requested (clock); +} + +/** + * gdk_frame_clock_get_frame_time_val: + * @clock: the clock + * @timeval: #GTimeVal to fill in with frame time + * + * Like gdk_frame_clock_get_frame_time() but returns the time as a + * #GTimeVal which may be handy with some APIs (such as + * #GdkPixbufAnimation). + */ +void +gdk_frame_clock_get_frame_time_val (GdkFrameClock *clock, + GTimeVal *timeval) +{ + guint64 time_ms; + + g_return_if_fail (GDK_IS_FRAME_CLOCK (clock)); + + time_ms = gdk_frame_clock_get_frame_time (clock); + + timeval->tv_sec = time_ms / 1000; + timeval->tv_usec = (time_ms % 1000) * 1000; +} + +/** + * gdk_frame_clock_frame_requested: + * @clock: the clock + * + * Emits the frame-requested signal. Used in implementations of the + * #GdkFrameClock interface. + */ +void +gdk_frame_clock_frame_requested (GdkFrameClock *clock) +{ + g_return_if_fail (GDK_IS_FRAME_CLOCK (clock)); + + g_signal_emit (G_OBJECT (clock), + signals[FRAME_REQUESTED], 0); +} + +/** + * gdk_frame_clock_paint: + * @clock: the clock + * + * Emits the before-paint, paint, and after-paint signals. Used in + * implementations of the #GdkFrameClock interface. + */ +void +gdk_frame_clock_paint (GdkFrameClock *clock) +{ + g_return_if_fail (GDK_IS_FRAME_CLOCK (clock)); + + g_signal_emit (G_OBJECT (clock), + signals[BEFORE_PAINT], 0); + + g_signal_emit (G_OBJECT (clock), + signals[PAINT], 0); + + g_signal_emit (G_OBJECT (clock), + signals[AFTER_PAINT], 0); +} |