GdkFrameClock: Make the phase explicit when requesting the frame

Instead of having gdk_frame_clock_request_frame() have
gdk_frame_clock_request_phase() where we can say what phase we need.
This allows us to know if we get a frame-request during layout whether
it's just a request for drawing from the layout, or whether another
layout phase is needed.

https://bugzilla.gnome.org/show_bug.cgi?id=685460
This commit is contained in:
Owen W. Taylor 2012-10-03 19:38:40 -04:00
parent 7753883add
commit c4545cc5d4
6 changed files with 90 additions and 64 deletions

View File

@ -47,7 +47,7 @@
* for example.
*
* A frame clock is idle until someone requests a frame with
* gdk_frame_clock_request_frame(). At that time, the frame clock
* gdk_frame_clock_request_phase(). At that time, the frame clock
* emits its GdkFrameClock:frame-requested signal if no frame was
* already pending.
*
@ -203,7 +203,7 @@ gdk_frame_clock_get_frame_time (GdkFrameClock *clock)
}
/**
* gdk_frame_clock_request_frame:
* gdk_frame_clock_request_phase:
* @clock: the clock
*
* Asks the frame clock to paint a frame. The frame
@ -217,15 +217,17 @@ gdk_frame_clock_get_frame_time (GdkFrameClock *clock)
* Since: 3.0
*/
void
gdk_frame_clock_request_frame (GdkFrameClock *clock)
gdk_frame_clock_request_phase (GdkFrameClock *clock,
GdkFrameClockPhase phase)
{
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
GDK_FRAME_CLOCK_GET_IFACE (clock)->request_frame (clock);
GDK_FRAME_CLOCK_GET_IFACE (clock)->request_phase (clock, phase);
}
/**
* gdk_frame_clock_get_frame_requested:
* gdk_frame_clock_get_requested:
* @clock: the clock
*
* Gets whether a frame paint has been requested but has not been
@ -235,12 +237,12 @@ gdk_frame_clock_request_frame (GdkFrameClock *clock)
* Since: 3.0
* Return value: TRUE if a frame paint is pending
*/
gboolean
gdk_frame_clock_get_frame_requested (GdkFrameClock *clock)
GdkFrameClockPhase
gdk_frame_clock_get_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);
return GDK_FRAME_CLOCK_GET_IFACE (clock)->get_requested (clock);
}
/**
@ -281,28 +283,3 @@ gdk_frame_clock_frame_requested (GdkFrameClock *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[LAYOUT], 0);
g_signal_emit (G_OBJECT (clock),
signals[PAINT], 0);
g_signal_emit (G_OBJECT (clock),
signals[AFTER_PAINT], 0);
}

View File

@ -43,18 +43,28 @@ G_BEGIN_DECLS
typedef struct _GdkFrameClock GdkFrameClock;
typedef struct _GdkFrameClockInterface GdkFrameClockInterface;
typedef enum {
GDK_FRAME_CLOCK_PHASE_NONE = 0,
GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT = 1 << 0,
GDK_FRAME_CLOCK_PHASE_LAYOUT = 1 << 1,
GDK_FRAME_CLOCK_PHASE_PAINT = 1 << 2,
GDK_FRAME_CLOCK_PHASE_AFTER_PAINT = 1 << 3
} GdkFrameClockPhase;
struct _GdkFrameClockInterface
{
GTypeInterface base_iface;
guint64 (* get_frame_time) (GdkFrameClock *clock);
void (* request_frame) (GdkFrameClock *clock);
gboolean (* get_frame_requested) (GdkFrameClock *clock);
void (* request_phase) (GdkFrameClock *clock,
GdkFrameClockPhase phase);
GdkFrameClockPhase (* get_requested) (GdkFrameClock *clock);
/* signals */
/* void (* frame_requested) (GdkFrameClock *clock); */
/* void (* before_paint) (GdkFrameClock *clock); */
/* void (* layout) 1(GdkFrameClock *clock); */
/* void (* layout) (GdkFrameClock *clock); */
/* void (* paint) (GdkFrameClock *clock); */
/* void (* after_paint) (GdkFrameClock *clock); */
};
@ -62,8 +72,10 @@ struct _GdkFrameClockInterface
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);
void gdk_frame_clock_request_phase (GdkFrameClock *clock,
GdkFrameClockPhase phase);
GdkFrameClockPhase gdk_frame_clock_get_requested (GdkFrameClock *clock);
/* Convenience API */
void gdk_frame_clock_get_frame_time_val (GdkFrameClock *clock,
@ -71,7 +83,6 @@ void gdk_frame_clock_get_frame_time_val (GdkFrameClock *clock,
/* 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

View File

@ -38,9 +38,12 @@ struct _GdkFrameClockIdlePrivate
guint idle_id;
unsigned int in_paint : 1;
GdkFrameClockPhase requested;
GdkFrameClockPhase phase;
};
static gboolean gdk_frame_clock_paint_idle (void *data);
static void gdk_frame_clock_idle_finalize (GObject *object);
static void gdk_frame_clock_idle_interface_init (GdkFrameClockInterface *iface);
@ -113,7 +116,7 @@ gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock)
guint64 computed_frame_time;
/* can't change frame time during a paint */
if (priv->in_paint)
if (priv->phase != GDK_FRAME_CLOCK_PHASE_NONE)
return priv->frame_time;
/* Outside a paint, pick something close to "now" */
@ -130,6 +133,22 @@ gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock)
return priv->frame_time;
}
static void
maybe_start_idle (GdkFrameClockIdle *clock_idle)
{
GdkFrameClockIdlePrivate *priv = clock_idle->priv;
if (priv->idle_id == 0 && priv->requested != 0)
{
priv->idle_id = gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
gdk_frame_clock_paint_idle,
g_object_ref (clock_idle),
(GDestroyNotify) g_object_unref);
gdk_frame_clock_frame_requested (GDK_FRAME_CLOCK (clock_idle));
}
}
static gboolean
gdk_frame_clock_paint_idle (void *data)
{
@ -139,44 +158,60 @@ gdk_frame_clock_paint_idle (void *data)
priv->idle_id = 0;
priv->in_paint = TRUE;
priv->frame_time = compute_frame_time (clock_idle);
gdk_frame_clock_paint (clock);
priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
g_signal_emit_by_name (G_OBJECT (clock), "before-paint");
priv->phase = GDK_FRAME_CLOCK_PHASE_LAYOUT;
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT;
g_signal_emit_by_name (G_OBJECT (clock), "layout");
priv->phase = GDK_FRAME_CLOCK_PHASE_PAINT;
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_PAINT;
g_signal_emit_by_name (G_OBJECT (clock), "paint");
priv->phase = GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
g_signal_emit_by_name (G_OBJECT (clock), "after-paint");
priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
priv->in_paint = FALSE;
maybe_start_idle (clock_idle);
return FALSE;
}
static void
gdk_frame_clock_idle_request_frame (GdkFrameClock *clock)
gdk_frame_clock_idle_request_phase (GdkFrameClock *clock,
GdkFrameClockPhase phase)
{
GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv;
GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
GdkFrameClockIdlePrivate *priv = clock_idle->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);
}
priv->requested |= phase;
maybe_start_idle (clock_idle);
}
static gboolean
gdk_frame_clock_idle_get_frame_requested (GdkFrameClock *clock)
static GdkFrameClockPhase
gdk_frame_clock_idle_get_requested (GdkFrameClock *clock)
{
GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv;
return priv->idle_id != 0;
return priv->requested;
}
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;
iface->request_phase = gdk_frame_clock_idle_request_phase;
iface->get_requested = gdk_frame_clock_idle_get_requested;
}
GdkFrameClock *
_gdk_frame_clock_idle_new (void)
{
GdkFrameClockIdle *clock;
clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE, NULL);
return GDK_FRAME_CLOCK (clock);
}

View File

@ -3947,7 +3947,8 @@ gdk_window_schedule_update (GdkWindow *window)
gdk_window_is_toplevel_frozen (window)))
return;
gdk_frame_clock_request_frame (gdk_window_get_frame_clock (window));
gdk_frame_clock_request_phase (gdk_window_get_frame_clock (window),
GDK_FRAME_CLOCK_PHASE_PAINT);
}
void

View File

@ -1686,7 +1686,8 @@ gtk_container_idle_sizer (GdkFrameClock *clock,
}
else
{
gdk_frame_clock_request_frame (clock);
gdk_frame_clock_request_phase (clock,
GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
}
@ -1705,7 +1706,8 @@ gtk_container_start_idle_sizer (GtkContainer *container)
container->priv->resize_clock = clock;
container->priv->resize_handler = g_signal_connect (clock, "layout",
G_CALLBACK (gtk_container_idle_sizer), container);
gdk_frame_clock_request_frame (clock);
gdk_frame_clock_request_phase (clock,
GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
static void

View File

@ -4793,7 +4793,7 @@ gtk_widget_queue_resize_no_redraw (GtkWidget *widget)
* 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
* gdk_frame_clock_request_phase() 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