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 "gdkframeclockidle.h"
32 struct _GdkFrameClockIdlePrivate
35 /* timer_base is used to avoid ever going backward */
41 GdkFrameClockPhase requested;
42 GdkFrameClockPhase phase;
45 static gboolean gdk_frame_clock_paint_idle (void *data);
47 static void gdk_frame_clock_idle_finalize (GObject *object);
48 static void gdk_frame_clock_idle_interface_init (GdkFrameClockInterface *iface);
50 G_DEFINE_TYPE_WITH_CODE (GdkFrameClockIdle, gdk_frame_clock_idle, G_TYPE_OBJECT,
51 G_IMPLEMENT_INTERFACE (GDK_TYPE_FRAME_CLOCK,
52 gdk_frame_clock_idle_interface_init))
55 gdk_frame_clock_idle_class_init (GdkFrameClockIdleClass *klass)
57 GObjectClass *gobject_class = (GObjectClass*) klass;
59 gobject_class->finalize = gdk_frame_clock_idle_finalize;
61 g_type_class_add_private (klass, sizeof (GdkFrameClockIdlePrivate));
65 gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
67 GdkFrameClockIdlePrivate *priv;
69 frame_clock_idle->priv = G_TYPE_INSTANCE_GET_PRIVATE (frame_clock_idle,
70 GDK_TYPE_FRAME_CLOCK_IDLE,
71 GdkFrameClockIdlePrivate);
72 priv = frame_clock_idle->priv;
74 priv->timer = g_timer_new ();
78 gdk_frame_clock_idle_finalize (GObject *object)
80 GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (object)->priv;
82 g_timer_destroy (priv->timer);
84 G_OBJECT_CLASS (gdk_frame_clock_idle_parent_class)->finalize (object);
88 compute_frame_time (GdkFrameClockIdle *idle)
90 GdkFrameClockIdlePrivate *priv = idle->priv;
91 guint64 computed_frame_time;
94 elapsed = ((guint64) (g_timer_elapsed (priv->timer, NULL) * 1000)) + priv->timer_base;
95 if (elapsed < priv->frame_time)
97 /* clock went backward. adapt to that by forevermore increasing
98 * timer_base. For now, assume we've gone forward in time 1ms.
100 /* hmm. just fix GTimer? */
101 computed_frame_time = priv->frame_time + 1;
102 priv->timer_base += (priv->frame_time - elapsed) + 1;
106 computed_frame_time = elapsed;
109 return computed_frame_time;
113 gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock)
115 GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv;
116 guint64 computed_frame_time;
118 /* can't change frame time during a paint */
119 if (priv->phase != GDK_FRAME_CLOCK_PHASE_NONE)
120 return priv->frame_time;
122 /* Outside a paint, pick something close to "now" */
123 computed_frame_time = compute_frame_time (GDK_FRAME_CLOCK_IDLE (clock));
125 /* 16ms is 60fps. We only update frame time that often because we'd
126 * like to try to keep animations on the same start times.
127 * get_frame_time() would normally be used outside of a paint to
128 * record an animation start time for example.
130 if ((computed_frame_time - priv->frame_time) > 16)
131 priv->frame_time = computed_frame_time;
133 return priv->frame_time;
137 maybe_start_idle (GdkFrameClockIdle *clock_idle)
139 GdkFrameClockIdlePrivate *priv = clock_idle->priv;
141 if (priv->idle_id == 0 && priv->requested != 0)
143 priv->idle_id = gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
144 gdk_frame_clock_paint_idle,
145 g_object_ref (clock_idle),
146 (GDestroyNotify) g_object_unref);
148 gdk_frame_clock_frame_requested (GDK_FRAME_CLOCK (clock_idle));
153 gdk_frame_clock_paint_idle (void *data)
155 GdkFrameClock *clock = GDK_FRAME_CLOCK (data);
156 GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
157 GdkFrameClockIdlePrivate *priv = clock_idle->priv;
161 priv->frame_time = compute_frame_time (clock_idle);
163 priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
164 priv->requested &= ~GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
165 g_signal_emit_by_name (G_OBJECT (clock), "before-paint");
166 priv->phase = GDK_FRAME_CLOCK_PHASE_LAYOUT;
167 priv->requested &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT;
168 g_signal_emit_by_name (G_OBJECT (clock), "layout");
169 priv->phase = GDK_FRAME_CLOCK_PHASE_PAINT;
170 priv->requested &= ~GDK_FRAME_CLOCK_PHASE_PAINT;
171 g_signal_emit_by_name (G_OBJECT (clock), "paint");
172 priv->phase = GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
173 priv->requested &= ~GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
174 g_signal_emit_by_name (G_OBJECT (clock), "after-paint");
175 priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
177 maybe_start_idle (clock_idle);
183 gdk_frame_clock_idle_request_phase (GdkFrameClock *clock,
184 GdkFrameClockPhase phase)
186 GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
187 GdkFrameClockIdlePrivate *priv = clock_idle->priv;
189 priv->requested |= phase;
190 maybe_start_idle (clock_idle);
193 static GdkFrameClockPhase
194 gdk_frame_clock_idle_get_requested (GdkFrameClock *clock)
196 GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv;
198 return priv->requested;
202 gdk_frame_clock_idle_interface_init (GdkFrameClockInterface *iface)
204 iface->get_frame_time = gdk_frame_clock_idle_get_frame_time;
205 iface->request_phase = gdk_frame_clock_idle_request_phase;
206 iface->get_requested = gdk_frame_clock_idle_get_requested;
210 _gdk_frame_clock_idle_new (void)
212 GdkFrameClockIdle *clock;
214 clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE, NULL);
216 return GDK_FRAME_CLOCK (clock);