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
This commit is contained in:
@ -80,6 +80,7 @@ gdk_public_h_sources = \
|
|||||||
gdkkeysyms-compat.h \
|
gdkkeysyms-compat.h \
|
||||||
gdkmain.h \
|
gdkmain.h \
|
||||||
gdkpango.h \
|
gdkpango.h \
|
||||||
|
gdkframeclock.h \
|
||||||
gdkpixbuf.h \
|
gdkpixbuf.h \
|
||||||
gdkprivate.h \
|
gdkprivate.h \
|
||||||
gdkproperty.h \
|
gdkproperty.h \
|
||||||
@ -101,6 +102,7 @@ gdk_private_headers = \
|
|||||||
gdkdisplaymanagerprivate.h \
|
gdkdisplaymanagerprivate.h \
|
||||||
gdkdisplayprivate.h \
|
gdkdisplayprivate.h \
|
||||||
gdkdndprivate.h \
|
gdkdndprivate.h \
|
||||||
|
gdkframeclockidle.h \
|
||||||
gdkscreenprivate.h \
|
gdkscreenprivate.h \
|
||||||
gdkinternals.h \
|
gdkinternals.h \
|
||||||
gdkintl.h \
|
gdkintl.h \
|
||||||
@ -125,6 +127,8 @@ gdk_c_sources = \
|
|||||||
gdkkeys.c \
|
gdkkeys.c \
|
||||||
gdkkeyuni.c \
|
gdkkeyuni.c \
|
||||||
gdkoffscreenwindow.c \
|
gdkoffscreenwindow.c \
|
||||||
|
gdkframeclock.c \
|
||||||
|
gdkframeclockidle.c \
|
||||||
gdkpango.c \
|
gdkpango.c \
|
||||||
gdkpixbuf-drawable.c \
|
gdkpixbuf-drawable.c \
|
||||||
gdkrectangle.c \
|
gdkrectangle.c \
|
||||||
|
|||||||
287
gdk/gdkframeclock.c
Normal file
287
gdk/gdkframeclock.c
Normal file
@ -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);
|
||||||
|
}
|
||||||
77
gdk/gdkframeclock.h
Normal file
77
gdk/gdkframeclock.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/* 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__ */
|
||||||
182
gdk/gdkframeclockidle.c
Normal file
182
gdk/gdkframeclockidle.c
Normal file
@ -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;
|
||||||
|
}
|
||||||
68
gdk/gdkframeclockidle.h
Normal file
68
gdk/gdkframeclockidle.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/* 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;
|
gulong device_changed_handler_id;
|
||||||
|
|
||||||
guint num_offscreen_children;
|
guint num_offscreen_children;
|
||||||
|
|
||||||
|
GdkFrameClock *frame_clock; /* NULL to use from parent or default */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GDK_WINDOW_TYPE(d) (((GDK_WINDOW (d)))->window_type)
|
#define GDK_WINDOW_TYPE(d) (((GDK_WINDOW (d)))->window_type)
|
||||||
|
|||||||
278
gdk/gdkwindow.c
278
gdk/gdkwindow.c
@ -37,6 +37,7 @@
|
|||||||
#include "gdkdeviceprivate.h"
|
#include "gdkdeviceprivate.h"
|
||||||
#include "gdkvisualprivate.h"
|
#include "gdkvisualprivate.h"
|
||||||
#include "gdkmarshalers.h"
|
#include "gdkmarshalers.h"
|
||||||
|
#include "gdkframeclockidle.h"
|
||||||
#include "gdkwindowimpl.h"
|
#include "gdkwindowimpl.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@ -169,7 +170,8 @@ enum {
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_CURSOR
|
PROP_CURSOR,
|
||||||
|
PROP_FRAME_CLOCK
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
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 void _gdk_window_propagate_has_alpha_background (GdkWindow *window);
|
||||||
static cairo_surface_t *gdk_window_ref_impl_surface (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 guint signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
static gpointer parent_class = NULL;
|
static gpointer parent_class = NULL;
|
||||||
@ -388,6 +394,23 @@ gdk_window_class_init (GdkWindowClass *klass)
|
|||||||
GDK_TYPE_CURSOR,
|
GDK_TYPE_CURSOR,
|
||||||
G_PARAM_READWRITE));
|
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:
|
* GdkWindow::pick-embedded-child:
|
||||||
* @window: the window on which the signal is emitted
|
* @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));
|
gdk_window_set_cursor (window, g_value_get_object (value));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_FRAME_CLOCK:
|
||||||
|
gdk_window_set_frame_clock (window, g_value_get_object (value));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -620,6 +647,10 @@ gdk_window_get_property (GObject *object,
|
|||||||
g_value_set_object (value, gdk_window_get_cursor (window));
|
g_value_set_object (value, gdk_window_get_cursor (window));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_FRAME_CLOCK:
|
||||||
|
g_value_set_object (value, gdk_window_get_frame_clock (window));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -3778,7 +3809,7 @@ gdk_cairo_create (GdkWindow *window)
|
|||||||
/* Code for dirty-region queueing
|
/* Code for dirty-region queueing
|
||||||
*/
|
*/
|
||||||
static GSList *update_windows = NULL;
|
static GSList *update_windows = NULL;
|
||||||
static guint update_idle = 0;
|
static GdkFrameClock *_gdk_default_frame_clock = NULL;
|
||||||
static gboolean debug_updates = FALSE;
|
static gboolean debug_updates = FALSE;
|
||||||
|
|
||||||
static inline gboolean
|
static inline gboolean
|
||||||
@ -3877,12 +3908,25 @@ gdk_window_remove_update_window (GdkWindow *window)
|
|||||||
update_windows = g_slist_remove (update_windows, window);
|
update_windows = g_slist_remove (update_windows, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gdk_window_update_idle (gpointer data)
|
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
|
static gboolean
|
||||||
@ -3903,11 +3947,7 @@ gdk_window_schedule_update (GdkWindow *window)
|
|||||||
gdk_window_is_toplevel_frozen (window)))
|
gdk_window_is_toplevel_frozen (window)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!update_idle)
|
gdk_frame_clock_request_frame (gdk_window_get_frame_clock (window));
|
||||||
update_idle =
|
|
||||||
gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
|
|
||||||
gdk_window_update_idle,
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -4220,6 +4260,19 @@ after_process_all_updates (void)
|
|||||||
g_slist_free (displays);
|
g_slist_free (displays);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdk_window_process_all_updates:
|
||||||
|
*
|
||||||
|
* Calls gdk_window_process_updates() for all windows (see #GdkWindow)
|
||||||
|
* in the application.
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
gdk_window_process_all_updates (void)
|
||||||
|
{
|
||||||
|
gdk_window_process_all_updates_internal (FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
/* Currently it is not possible to override
|
/* Currently it is not possible to override
|
||||||
* gdk_window_process_all_updates in the same manner as
|
* gdk_window_process_all_updates in the same manner as
|
||||||
* gdk_window_process_updates and gdk_window_invalidate_maybe_recurse
|
* gdk_window_process_updates and gdk_window_invalidate_maybe_recurse
|
||||||
@ -4230,15 +4283,8 @@ after_process_all_updates (void)
|
|||||||
* displays and call the mehod.
|
* displays and call the mehod.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
static void
|
||||||
* gdk_window_process_all_updates:
|
gdk_window_process_all_updates_internal (gboolean default_clock_only)
|
||||||
*
|
|
||||||
* Calls gdk_window_process_updates() for all windows (see #GdkWindow)
|
|
||||||
* in the application.
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
void
|
|
||||||
gdk_window_process_all_updates (void)
|
|
||||||
{
|
{
|
||||||
GSList *old_update_windows = update_windows;
|
GSList *old_update_windows = update_windows;
|
||||||
GSList *tmp_list = update_windows;
|
GSList *tmp_list = update_windows;
|
||||||
@ -4250,18 +4296,13 @@ gdk_window_process_all_updates (void)
|
|||||||
/* We can't do this now since that would recurse, so
|
/* We can't do this now since that would recurse, so
|
||||||
delay it until after the recursion is done. */
|
delay it until after the recursion is done. */
|
||||||
got_recursive_update = TRUE;
|
got_recursive_update = TRUE;
|
||||||
update_idle = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
in_process_all_updates = TRUE;
|
in_process_all_updates = TRUE;
|
||||||
got_recursive_update = FALSE;
|
got_recursive_update = FALSE;
|
||||||
|
|
||||||
if (update_idle)
|
|
||||||
g_source_remove (update_idle);
|
|
||||||
|
|
||||||
update_windows = NULL;
|
update_windows = NULL;
|
||||||
update_idle = 0;
|
|
||||||
|
|
||||||
before_process_all_updates ();
|
before_process_all_updates ();
|
||||||
|
|
||||||
@ -4274,7 +4315,8 @@ gdk_window_process_all_updates (void)
|
|||||||
if (!GDK_WINDOW_DESTROYED (window))
|
if (!GDK_WINDOW_DESTROYED (window))
|
||||||
{
|
{
|
||||||
if (window->update_freeze_count ||
|
if (window->update_freeze_count ||
|
||||||
gdk_window_is_toplevel_frozen (window))
|
gdk_window_is_toplevel_frozen (window) ||
|
||||||
|
(default_clock_only && window->frame_clock != NULL))
|
||||||
gdk_window_add_update_window (window);
|
gdk_window_add_update_window (window);
|
||||||
else
|
else
|
||||||
gdk_window_process_updates_internal (window);
|
gdk_window_process_updates_internal (window);
|
||||||
@ -4296,31 +4338,20 @@ gdk_window_process_all_updates (void)
|
|||||||
redraw now so that it eventually happens,
|
redraw now so that it eventually happens,
|
||||||
otherwise we could miss an update if nothing
|
otherwise we could miss an update if nothing
|
||||||
else schedules an update. */
|
else schedules an update. */
|
||||||
if (got_recursive_update && !update_idle)
|
if (got_recursive_update)
|
||||||
update_idle =
|
gdk_window_schedule_update (NULL);
|
||||||
gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
|
|
||||||
gdk_window_update_idle,
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gdk_window_process_updates:
|
enum {
|
||||||
* @window: a #GdkWindow
|
PROCESS_UPDATES_NO_RECURSE,
|
||||||
* @update_children: whether to also process updates for child windows
|
PROCESS_UPDATES_WITH_ALL_CHILDREN,
|
||||||
*
|
PROCESS_UPDATES_WITH_SAME_CLOCK_CHILDREN
|
||||||
* Sends one or more expose events to @window. The areas in each
|
};
|
||||||
* expose event will cover the entire update area for the window (see
|
|
||||||
* gdk_window_invalidate_region() for details). Normally GDK calls
|
static void
|
||||||
* gdk_window_process_all_updates() on your behalf, so there's no
|
gdk_window_process_updates_with_mode (GdkWindow *window,
|
||||||
* need to call this function unless you want to force expose events
|
int recurse_mode)
|
||||||
* to be delivered immediately and synchronously (vs. the usual
|
|
||||||
* case, where GDK delivers them in an idle handler). Occasionally
|
|
||||||
* this is useful to produce nicer scrolling behavior, for example.
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
void
|
|
||||||
gdk_window_process_updates (GdkWindow *window,
|
|
||||||
gboolean update_children)
|
|
||||||
{
|
{
|
||||||
GdkWindow *impl_window;
|
GdkWindow *impl_window;
|
||||||
|
|
||||||
@ -4346,7 +4377,7 @@ gdk_window_process_updates (GdkWindow *window,
|
|||||||
gdk_window_remove_update_window ((GdkWindow *)impl_window);
|
gdk_window_remove_update_window ((GdkWindow *)impl_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update_children)
|
if (recurse_mode != PROCESS_UPDATES_NO_RECURSE)
|
||||||
{
|
{
|
||||||
/* process updates in reverse stacking order so composition or
|
/* process updates in reverse stacking order so composition or
|
||||||
* painting over achieves the desired effect for offscreen windows
|
* painting over achieves the desired effect for offscreen windows
|
||||||
@ -4358,8 +4389,14 @@ gdk_window_process_updates (GdkWindow *window,
|
|||||||
|
|
||||||
for (node = g_list_last (children); node; node = node->prev)
|
for (node = g_list_last (children); node; node = node->prev)
|
||||||
{
|
{
|
||||||
gdk_window_process_updates (node->data, TRUE);
|
GdkWindow *child = node->data;
|
||||||
g_object_unref (node->data);
|
if (recurse_mode == PROCESS_UPDATES_WITH_ALL_CHILDREN ||
|
||||||
|
(recurse_mode == PROCESS_UPDATES_WITH_SAME_CLOCK_CHILDREN &&
|
||||||
|
child->frame_clock == NULL))
|
||||||
|
{
|
||||||
|
gdk_window_process_updates (child, TRUE);
|
||||||
|
}
|
||||||
|
g_object_unref (child);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_list_free (children);
|
g_list_free (children);
|
||||||
@ -4368,6 +4405,33 @@ gdk_window_process_updates (GdkWindow *window,
|
|||||||
g_object_unref (window);
|
g_object_unref (window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdk_window_process_updates:
|
||||||
|
* @window: a #GdkWindow
|
||||||
|
* @update_children: whether to also process updates for child windows
|
||||||
|
*
|
||||||
|
* Sends one or more expose events to @window. The areas in each
|
||||||
|
* expose event will cover the entire update area for the window (see
|
||||||
|
* gdk_window_invalidate_region() for details). Normally GDK calls
|
||||||
|
* gdk_window_process_all_updates() on your behalf, so there's no
|
||||||
|
* need to call this function unless you want to force expose events
|
||||||
|
* to be delivered immediately and synchronously (vs. the usual
|
||||||
|
* case, where GDK delivers them in an idle handler). Occasionally
|
||||||
|
* this is useful to produce nicer scrolling behavior, for example.
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
gdk_window_process_updates (GdkWindow *window,
|
||||||
|
gboolean update_children)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GDK_IS_WINDOW (window));
|
||||||
|
|
||||||
|
return gdk_window_process_updates_with_mode (window,
|
||||||
|
update_children ?
|
||||||
|
PROCESS_UPDATES_WITH_ALL_CHILDREN :
|
||||||
|
PROCESS_UPDATES_NO_RECURSE);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gdk_window_invalidate_rect_full (GdkWindow *window,
|
gdk_window_invalidate_rect_full (GdkWindow *window,
|
||||||
const GdkRectangle *rect,
|
const GdkRectangle *rect,
|
||||||
@ -11535,3 +11599,113 @@ gdk_property_delete (GdkWindow *window,
|
|||||||
{
|
{
|
||||||
GDK_WINDOW_IMPL_GET_CLASS (window->impl)->delete_property (window, property);
|
GDK_WINDOW_IMPL_GET_CLASS (window->impl)->delete_property (window, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gdk_window_paint_on_clock (GdkFrameClock *clock,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
GdkWindow *window;
|
||||||
|
|
||||||
|
window = GDK_WINDOW (data);
|
||||||
|
|
||||||
|
/* Update window and any children on the same clock.
|
||||||
|
*/
|
||||||
|
gdk_window_process_updates_with_mode (window, PROCESS_UPDATES_WITH_SAME_CLOCK_CHILDREN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdk_window_set_frame_clock:
|
||||||
|
* @window: window to set frame clock on
|
||||||
|
* @clock: the clock
|
||||||
|
*
|
||||||
|
* Sets the frame clock for the window. The frame clock for a window
|
||||||
|
* cannot be changed while the window is mapped. Set the frame
|
||||||
|
* clock to #NULL to use the default frame clock. (By default the
|
||||||
|
* frame clock comes from the window's parent or is a global default
|
||||||
|
* frame clock.)
|
||||||
|
*
|
||||||
|
* Since: 3.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gdk_window_set_frame_clock (GdkWindow *window,
|
||||||
|
GdkFrameClock *clock)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GDK_IS_WINDOW (window));
|
||||||
|
g_return_if_fail (clock == NULL || GDK_IS_FRAME_CLOCK (clock));
|
||||||
|
g_return_if_fail (!GDK_WINDOW_IS_MAPPED (window));
|
||||||
|
|
||||||
|
if (clock == window->frame_clock)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If we are using our parent's clock, then the parent will repaint
|
||||||
|
* us when that clock fires. If we are using the default clock, then
|
||||||
|
* it does a gdk_window_process_all_updates() which will repaint us
|
||||||
|
* when the clock fires. If we are using our own clock, then we have
|
||||||
|
* to connect to "paint" on it ourselves and paint ourselves and
|
||||||
|
* any child windows.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (clock)
|
||||||
|
{
|
||||||
|
g_object_ref (clock);
|
||||||
|
g_signal_connect (G_OBJECT (clock),
|
||||||
|
"paint",
|
||||||
|
G_CALLBACK (gdk_window_paint_on_clock),
|
||||||
|
window);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->frame_clock)
|
||||||
|
{
|
||||||
|
g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
|
||||||
|
G_CALLBACK (gdk_window_paint_on_clock),
|
||||||
|
window);
|
||||||
|
g_object_unref (window->frame_clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
window->frame_clock = clock;
|
||||||
|
g_object_notify (G_OBJECT (window), "paint-clock");
|
||||||
|
|
||||||
|
/* We probably should recurse child windows and emit notify on their
|
||||||
|
* paint-clock properties also, and we should emit notify when a
|
||||||
|
* window is first parented.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdk_window_get_frame_clock:
|
||||||
|
* @window: window to get frame clock for
|
||||||
|
*
|
||||||
|
* Gets the frame clock for the window. The frame clock for a window
|
||||||
|
* never changes while the window is mapped. It may be changed at
|
||||||
|
* other times.
|
||||||
|
*
|
||||||
|
* Since: 3.0
|
||||||
|
* Return value: (transfer none): the frame clock
|
||||||
|
*/
|
||||||
|
GdkFrameClock*
|
||||||
|
gdk_window_get_frame_clock (GdkWindow *window)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
|
||||||
|
|
||||||
|
if (window->frame_clock != NULL)
|
||||||
|
{
|
||||||
|
/* Frame clock set explicitly on this window */
|
||||||
|
return window->frame_clock;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GdkWindow *parent;
|
||||||
|
|
||||||
|
/* parent's frame clock or default */
|
||||||
|
parent = gdk_window_get_effective_parent (window);
|
||||||
|
if (parent != NULL)
|
||||||
|
{
|
||||||
|
return gdk_window_get_frame_clock (parent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gdk_ensure_default_frame_clock ();
|
||||||
|
return _gdk_default_frame_clock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
#include <gdk/gdkversionmacros.h>
|
#include <gdk/gdkversionmacros.h>
|
||||||
#include <gdk/gdktypes.h>
|
#include <gdk/gdktypes.h>
|
||||||
#include <gdk/gdkevents.h>
|
#include <gdk/gdkevents.h>
|
||||||
|
#include <gdk/gdkframeclock.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
@ -901,6 +902,11 @@ void gdk_window_set_support_multidevice (GdkWindow *window,
|
|||||||
gboolean support_multidevice);
|
gboolean support_multidevice);
|
||||||
gboolean gdk_window_get_support_multidevice (GdkWindow *window);
|
gboolean gdk_window_get_support_multidevice (GdkWindow *window);
|
||||||
|
|
||||||
|
/* Frame clock */
|
||||||
|
void gdk_window_set_frame_clock (GdkWindow *window,
|
||||||
|
GdkFrameClock *clock);
|
||||||
|
GdkFrameClock* gdk_window_get_frame_clock (GdkWindow *window);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GDK_WINDOW_H__ */
|
#endif /* __GDK_WINDOW_H__ */
|
||||||
|
|||||||
@ -4777,6 +4777,54 @@ gtk_widget_queue_resize_no_redraw (GtkWidget *widget)
|
|||||||
_gtk_size_group_queue_resize (widget, 0);
|
_gtk_size_group_queue_resize (widget, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_widget_get_frame_clock:
|
||||||
|
* @widget: a #GtkWidget
|
||||||
|
*
|
||||||
|
* Obtains the frame clock for a widget. The frame clock is a global
|
||||||
|
* "ticker" that can be used to drive animations and repaints. The
|
||||||
|
* most common reason to get the frame clock is to call
|
||||||
|
* gdk_frame_clock_get_frame_time(), in order to get a time to use for
|
||||||
|
* animating. For example you might record the start of the animation
|
||||||
|
* with an initial value from gdk_frame_clock_get_frame_time(), and
|
||||||
|
* then update the animation by calling
|
||||||
|
* gdk_frame_clock_get_frame_time() again during each repaint.
|
||||||
|
*
|
||||||
|
* gdk_frame_clock_request_frame() will result in a new frame on the
|
||||||
|
* clock, but won't necessarily repaint any widgets. To repaint a
|
||||||
|
* widget, you have to use gtk_widget_queue_draw() which invalidates
|
||||||
|
* the widget (thus scheduling it to receive a draw on the next
|
||||||
|
* frame). gtk_widget_queue_draw() will also end up requesting a frame
|
||||||
|
* on the appropriate frame clock.
|
||||||
|
*
|
||||||
|
* A widget's frame clock will not change while the widget is
|
||||||
|
* mapped. Reparenting a widget (which implies a temporary unmap) can
|
||||||
|
* change the widget's frame clock.
|
||||||
|
*
|
||||||
|
* Unrealized widgets do not have a frame clock.
|
||||||
|
*
|
||||||
|
* Since: 3.0
|
||||||
|
* Return value: a #GdkFrameClock (or #NULL if widget is unrealized)
|
||||||
|
*/
|
||||||
|
GdkFrameClock*
|
||||||
|
gtk_widget_get_frame_clock (GtkWidget *widget)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
|
||||||
|
|
||||||
|
if (widget->priv->realized)
|
||||||
|
{
|
||||||
|
GdkWindow *window;
|
||||||
|
|
||||||
|
window = gtk_widget_get_window (widget);
|
||||||
|
g_assert (window != NULL);
|
||||||
|
return gdk_window_get_frame_clock (window);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gtk_widget_size_request:
|
* gtk_widget_size_request:
|
||||||
* @widget: a #GtkWidget
|
* @widget: a #GtkWidget
|
||||||
|
|||||||
@ -473,6 +473,8 @@ void gtk_widget_queue_draw_region (GtkWidget *widget,
|
|||||||
const cairo_region_t*region);
|
const cairo_region_t*region);
|
||||||
void gtk_widget_queue_resize (GtkWidget *widget);
|
void gtk_widget_queue_resize (GtkWidget *widget);
|
||||||
void gtk_widget_queue_resize_no_redraw (GtkWidget *widget);
|
void gtk_widget_queue_resize_no_redraw (GtkWidget *widget);
|
||||||
|
GdkFrameClock* gtk_widget_get_frame_clock (GtkWidget *widget);
|
||||||
|
|
||||||
GDK_DEPRECATED_IN_3_0_FOR(gtk_widget_get_preferred_size)
|
GDK_DEPRECATED_IN_3_0_FOR(gtk_widget_get_preferred_size)
|
||||||
void gtk_widget_size_request (GtkWidget *widget,
|
void gtk_widget_size_request (GtkWidget *widget,
|
||||||
GtkRequisition *requisition);
|
GtkRequisition *requisition);
|
||||||
|
|||||||
Reference in New Issue
Block a user