Commit 77bac0d6 authored by Owen W. Taylor's avatar Owen W. Taylor

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
parent 001f960a
......@@ -80,6 +80,7 @@ gdk_public_h_sources = \
gdkkeysyms-compat.h \
gdkmain.h \
gdkpango.h \
gdkframeclock.h \
gdkpixbuf.h \
gdkprivate.h \
gdkproperty.h \
......@@ -101,6 +102,7 @@ gdk_private_headers = \
gdkdisplaymanagerprivate.h \
gdkdisplayprivate.h \
gdkdndprivate.h \
gdkframeclockidle.h \
gdkscreenprivate.h \
gdkinternals.h \
gdkintl.h \
......@@ -125,6 +127,8 @@ gdk_c_sources = \
gdkkeys.c \
gdkkeyuni.c \
gdkoffscreenwindow.c \
gdkframeclock.c \
gdkframeclockidle.c \
gdkpango.c \
gdkpixbuf-drawable.c \
gdkrectangle.c \
......
/* 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);
}
/* 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/.
*/
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#ifndef __GDK_FRAME_CLOCK_H__
#define __GDK_FRAME_CLOCK_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define GDK_TYPE_FRAME_CLOCK (gdk_frame_clock_get_type ())
#define GDK_FRAME_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_FRAME_CLOCK, GdkFrameClock))
#define GDK_IS_FRAME_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_FRAME_CLOCK))
#define GDK_FRAME_CLOCK_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GDK_TYPE_FRAME_CLOCK, GdkFrameClockInterface))
typedef struct _GdkFrameClock GdkFrameClock;
typedef struct _GdkFrameClockInterface GdkFrameClockInterface;
struct _GdkFrameClockInterface
{
GTypeInterface base_iface;
guint64 (* get_frame_time) (GdkFrameClock *clock);
void (* request_frame) (GdkFrameClock *clock);
gboolean (* get_frame_requested) (GdkFrameClock *clock);
/* signals */
/* void (* frame_requested) (GdkFrameClock *clock); */
/* void (* before_paint) (GdkFrameClock *clock); */
/* void (* paint) (GdkFrameClock *clock); */
/* void (* after_paint) (GdkFrameClock *clock); */
};
GType gdk_frame_clock_get_type (void) G_GNUC_CONST;
guint64 gdk_frame_clock_get_frame_time (GdkFrameClock *clock);
void gdk_frame_clock_request_frame (GdkFrameClock *clock);
gboolean gdk_frame_clock_get_frame_requested (GdkFrameClock *clock);
/* Convenience API */
void gdk_frame_clock_get_frame_time_val (GdkFrameClock *clock,
GTimeVal *timeval);
/* Signal emitters (used in frame clock implementations) */
void gdk_frame_clock_frame_requested (GdkFrameClock *clock);
void gdk_frame_clock_paint (GdkFrameClock *clock);
G_END_DECLS
#endif /* __GDK_FRAME_CLOCK_H__ */
/* 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;
}
/* 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/.
*/
/* Uninstalled header, internal to GDK */
#ifndef __GDK_FRAME_CLOCK_IDLE_H__
#define __GDK_FRAME_CLOCK_IDLE_H__
#include <gdk/gdkframeclock.h>
G_BEGIN_DECLS
#define GDK_TYPE_FRAME_CLOCK_IDLE (gdk_frame_clock_idle_get_type ())
#define GDK_FRAME_CLOCK_IDLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_FRAME_CLOCK_IDLE, GdkFrameClockIdle))
#define GDK_FRAME_CLOCK_IDLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_FRAME_CLOCK_IDLE, GdkFrameClockIdleClass))
#define GDK_IS_FRAME_CLOCK_IDLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_FRAME_CLOCK_IDLE))
#define GDK_IS_FRAME_CLOCK_IDLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_FRAME_CLOCK_IDLE))
#define GDK_FRAME_CLOCK_IDLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_FRAME_CLOCK_IDLE, GdkFrameClockIdleClass))
typedef struct _GdkFrameClockIdle GdkFrameClockIdle;
typedef struct _GdkFrameClockIdlePrivate GdkFrameClockIdlePrivate;
typedef struct _GdkFrameClockIdleClass GdkFrameClockIdleClass;
struct _GdkFrameClockIdle
{
GObject parent_instance;
/*< private >*/
GdkFrameClockIdlePrivate *priv;
};
struct _GdkFrameClockIdleClass
{
GObjectClass parent_class;
};
GType gdk_frame_clock_idle_get_type (void) G_GNUC_CONST;
void _gdk_frame_clock_idle_freeze_updates (GdkFrameClockIdle *clock_idle);
void _gdk_frame_clock_idle_thaw_updates (GdkFrameClockIdle *clock_idle);
G_END_DECLS
#endif /* __GDK_FRAME_CLOCK_IDLE_H__ */
......@@ -265,6 +265,8 @@ struct _GdkWindow
gulong device_changed_handler_id;
guint num_offscreen_children;
GdkFrameClock *frame_clock; /* NULL to use from parent or default */
};
#define GDK_WINDOW_TYPE(d) (((GDK_WINDOW (d)))->window_type)
......
......@@ -37,6 +37,7 @@
#include "gdkdeviceprivate.h"
#include "gdkvisualprivate.h"
#include "gdkmarshalers.h"
#include "gdkframeclockidle.h"
#include "gdkwindowimpl.h"
#include <math.h>
......@@ -169,7 +170,8 @@ enum {
enum {
PROP_0,
PROP_CURSOR
PROP_CURSOR,
PROP_FRAME_CLOCK
};
typedef enum {
......@@ -238,6 +240,10 @@ static void gdk_window_invalidate_rect_full (GdkWindow *window,
static void _gdk_window_propagate_has_alpha_background (GdkWindow *window);
static cairo_surface_t *gdk_window_ref_impl_surface (GdkWindow *window);
static void gdk_window_process_all_updates_internal (gboolean default_clock_only);
static void gdk_ensure_default_frame_clock (void);
static guint signals[LAST_SIGNAL] = { 0 };
static gpointer parent_class = NULL;
......@@ -388,6 +394,23 @@ gdk_window_class_init (GdkWindowClass *klass)
GDK_TYPE_CURSOR,
G_PARAM_READWRITE));
/**
* GdkWindow:paint-clock:
*
* The frame clock for a #GdkWindow, see #GdkFrameClock
*
* The frame clock remains the same for the lifetime of the window.
*
* Since: 3.0
*/
g_object_class_install_property (object_class,
PROP_FRAME_CLOCK,
g_param_spec_object ("paint-clock",
P_("Frame clock"),
P_("Frame clock"),
GDK_TYPE_FRAME_CLOCK,
G_PARAM_READWRITE));
/**
* GdkWindow::pick-embedded-child:
* @window: the window on which the signal is emitted
......@@ -600,6 +623,10 @@ gdk_window_set_property (GObject *object,
gdk_window_set_cursor (window, g_value_get_object (value));
break;
case PROP_FRAME_CLOCK:
gdk_window_set_frame_clock (window, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -620,6 +647,10 @@ gdk_window_get_property (GObject *object,
g_value_set_object (value, gdk_window_get_cursor (window));
break;
case PROP_FRAME_CLOCK:
g_value_set_object (value, gdk_window_get_frame_clock (window));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -3778,7 +3809,7 @@ gdk_cairo_create (GdkWindow *window)
/* Code for dirty-region queueing
*/
static GSList *update_windows = NULL;
static guint update_idle = 0;
static GdkFrameClock *_gdk_default_frame_clock = NULL;
static gboolean debug_updates = FALSE;
static inline gboolean
......@@ -3877,12 +3908,25 @@ gdk_window_remove_update_window (GdkWindow *window)
update_windows = g_slist_remove (update_windows, window);
}
static gboolean
gdk_window_update_idle (gpointer data)
static void
gdk_window_paint_default_clock_updates (gpointer data)
{
gdk_window_process_all_updates ();
gdk_window_process_all_updates_internal (TRUE);
}
return FALSE;
static void
gdk_ensure_default_frame_clock (void)
{
if (_gdk_default_frame_clock == NULL)
{
_gdk_default_frame_clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE,
NULL);
g_signal_connect (G_OBJECT (_gdk_default_frame_clock),
"paint",
G_CALLBACK (gdk_window_paint_default_clock_updates),
NULL);
}
}
static gboolean
......@@ -3903,11 +3947,7 @@ gdk_window_schedule_update (GdkWindow *window)
gdk_window_is_toplevel_frozen (window)))
return;
if (!update_idle)
</