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/gdkframeclockidle.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/gdkframeclockidle.c')
-rw-r--r-- | gdk/gdkframeclockidle.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c new file mode 100644 index 0000000000..ff20632e70 --- /dev/null +++ b/gdk/gdkframeclockidle.c @@ -0,0 +1,182 @@ +/* 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 "gdkframeclockidle.h" +#include "gdk.h" + +struct _GdkFrameClockIdlePrivate +{ + GTimer *timer; + /* timer_base is used to avoid ever going backward */ + guint64 timer_base; + guint64 frame_time; + + guint idle_id; + + unsigned int in_paint : 1; +}; + +static void gdk_frame_clock_idle_finalize (GObject *object); +static void gdk_frame_clock_idle_interface_init (GdkFrameClockInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GdkFrameClockIdle, gdk_frame_clock_idle, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GDK_TYPE_FRAME_CLOCK, + gdk_frame_clock_idle_interface_init)) + +static void +gdk_frame_clock_idle_class_init (GdkFrameClockIdleClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass*) klass; + + gobject_class->finalize = gdk_frame_clock_idle_finalize; + + g_type_class_add_private (klass, sizeof (GdkFrameClockIdlePrivate)); +} + +static void +gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle) +{ + GdkFrameClockIdlePrivate *priv; + + frame_clock_idle->priv = G_TYPE_INSTANCE_GET_PRIVATE (frame_clock_idle, + GDK_TYPE_FRAME_CLOCK_IDLE, + GdkFrameClockIdlePrivate); + priv = frame_clock_idle->priv; + + priv->timer = g_timer_new (); +} + +static void +gdk_frame_clock_idle_finalize (GObject *object) +{ + GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (object)->priv; + + g_timer_destroy (priv->timer); + + G_OBJECT_CLASS (gdk_frame_clock_idle_parent_class)->finalize (object); +} + +static guint64 +compute_frame_time (GdkFrameClockIdle *idle) +{ + GdkFrameClockIdlePrivate *priv = idle->priv; + guint64 computed_frame_time; + guint64 elapsed; + + elapsed = ((guint64) (g_timer_elapsed (priv->timer, NULL) * 1000)) + priv->timer_base; + if (elapsed < priv->frame_time) + { + /* clock went backward. adapt to that by forevermore increasing + * timer_base. For now, assume we've gone forward in time 1ms. + */ + /* hmm. just fix GTimer? */ + computed_frame_time = priv->frame_time + 1; + priv->timer_base += (priv->frame_time - elapsed) + 1; + } + else + { + computed_frame_time = elapsed; + } + + return computed_frame_time; +} + +static guint64 +gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock) +{ + GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv; + guint64 computed_frame_time; + + /* can't change frame time during a paint */ + if (priv->in_paint) + return priv->frame_time; + + /* Outside a paint, pick something close to "now" */ + computed_frame_time = compute_frame_time (GDK_FRAME_CLOCK_IDLE (clock)); + + /* 16ms is 60fps. We only update frame time that often because we'd + * like to try to keep animations on the same start times. + * get_frame_time() would normally be used outside of a paint to + * record an animation start time for example. + */ + if ((computed_frame_time - priv->frame_time) > 16) + priv->frame_time = computed_frame_time; + + return priv->frame_time; +} + +static gboolean +gdk_frame_clock_paint_idle (void *data) +{ + GdkFrameClock *clock = GDK_FRAME_CLOCK (data); + GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock); + GdkFrameClockIdlePrivate *priv = clock_idle->priv; + + priv->idle_id = 0; + + priv->in_paint = TRUE; + priv->frame_time = compute_frame_time (clock_idle); + + gdk_frame_clock_paint (clock); + + priv->in_paint = FALSE; + + return FALSE; +} + +static void +gdk_frame_clock_idle_request_frame (GdkFrameClock *clock) +{ + GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv; + + if (priv->idle_id == 0) + { + priv->idle_id = gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW, + gdk_frame_clock_paint_idle, + g_object_ref (clock), + (GDestroyNotify) g_object_unref); + + gdk_frame_clock_frame_requested (clock); + } +} + +static gboolean +gdk_frame_clock_idle_get_frame_requested (GdkFrameClock *clock) +{ + GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv; + + return priv->idle_id != 0; +} + +static void +gdk_frame_clock_idle_interface_init (GdkFrameClockInterface *iface) +{ + iface->get_frame_time = gdk_frame_clock_idle_get_frame_time; + iface->request_frame = gdk_frame_clock_idle_request_frame; + iface->get_frame_requested = gdk_frame_clock_idle_get_frame_requested; +} |