Add an UPDATE phase and GdkFrameClockTarget, use for GtkStyleContext

Switch GtkStyleContext to using GdkFrameClock. To do this, add a new
UPDATE phase to GdkFrameClock.

Add a GdkFrameClockTarget interface with a single set_clock() method,
and use this to deal with the fact that GtkWidget only has a frame
clock when realized.

https://bugzilla.gnome.org/show_bug.cgi?id=685460
This commit is contained in:
Owen W. Taylor 2012-09-26 15:44:30 -04:00
parent 7dfa412188
commit 344a69880a
6 changed files with 228 additions and 55 deletions

View File

@ -28,6 +28,19 @@
#include "gdkframeclock.h"
G_DEFINE_INTERFACE (GdkFrameClockTarget, gdk_frame_clock_target, G_TYPE_OBJECT)
static void
gdk_frame_clock_target_default_init (GdkFrameClockTargetInterface *iface)
{
}
void gdk_frame_clock_target_set_clock (GdkFrameClockTarget *target,
GdkFrameClock *clock)
{
GDK_FRAME_CLOCK_TARGET_GET_IFACE (target)->set_clock (target, clock);
}
/**
* SECTION:frameclock
* @Short_description: Frame clock syncs painting to a window or display
@ -79,6 +92,7 @@ G_DEFINE_INTERFACE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
enum {
FRAME_REQUESTED,
BEFORE_PAINT,
UPDATE,
LAYOUT,
PAINT,
AFTER_PAINT,
@ -123,6 +137,21 @@ gdk_frame_clock_default_init (GdkFrameClockInterface *iface)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* GdkFrameClock::update:
* @clock: the frame clock emitting the signal
*
* FIXME.
*/
signals[UPDATE] =
g_signal_new (g_intern_static_string ("update"),
GDK_TYPE_FRAME_CLOCK,
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* GdkFrameClock::layout:
* @clock: the frame clock emitting the signal

View File

@ -35,20 +35,41 @@
G_BEGIN_DECLS
typedef struct _GdkFrameClock GdkFrameClock;
typedef struct _GdkFrameClockInterface GdkFrameClockInterface;
typedef struct _GdkFrameClockTarget GdkFrameClockTarget;
typedef struct _GdkFrameClockTargetInterface GdkFrameClockTargetInterface;
#define GDK_TYPE_FRAME_CLOCK_TARGET (gdk_frame_clock_target_get_type ())
#define GDK_FRAME_CLOCK_TARGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_FRAME_CLOCK_TARGET, GdkFrameClockTarget))
#define GDK_IS_FRAME_CLOCK_TARGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_FRAME_CLOCK_TARGET))
#define GDK_FRAME_CLOCK_TARGET_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GDK_TYPE_FRAME_CLOCK_TARGET, GdkFrameClockTargetInterface))
struct _GdkFrameClockTargetInterface
{
GTypeInterface base_iface;
void (*set_clock) (GdkFrameClockTarget *target,
GdkFrameClock *clock);
};
GType gdk_frame_clock_target_get_type (void) G_GNUC_CONST;
void gdk_frame_clock_target_set_clock (GdkFrameClockTarget *target,
GdkFrameClock *clock);
#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;
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
GDK_FRAME_CLOCK_PHASE_UPDATE = 1 << 1,
GDK_FRAME_CLOCK_PHASE_LAYOUT = 1 << 2,
GDK_FRAME_CLOCK_PHASE_PAINT = 1 << 3,
GDK_FRAME_CLOCK_PHASE_AFTER_PAINT = 1 << 4
} GdkFrameClockPhase;
struct _GdkFrameClockInterface
@ -67,6 +88,7 @@ struct _GdkFrameClockInterface
/* signals */
/* void (* frame_requested) (GdkFrameClock *clock); */
/* void (* before_paint) (GdkFrameClock *clock); */
/* void (* update) (GdkFrameClock *clock); */
/* void (* layout) (GdkFrameClock *clock); */
/* void (* paint) (GdkFrameClock *clock); */
/* void (* after_paint) (GdkFrameClock *clock); */

View File

@ -189,7 +189,16 @@ gdk_frame_clock_paint_idle (void *data)
* they don't get repeated if you freeze/thaw while
* in them. */
g_signal_emit_by_name (G_OBJECT (clock), "before-paint");
priv->phase = GDK_FRAME_CLOCK_PHASE_LAYOUT;
priv->phase = GDK_FRAME_CLOCK_PHASE_UPDATE;
}
case GDK_FRAME_CLOCK_PHASE_UPDATE:
if (priv->freeze_count == 0)
{
if (priv->requested & GDK_FRAME_CLOCK_PHASE_UPDATE)
{
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_UPDATE;
g_signal_emit_by_name (G_OBJECT (clock), "update");
}
}
case GDK_FRAME_CLOCK_PHASE_LAYOUT:
if (priv->freeze_count == 0)

View File

@ -358,20 +358,21 @@ struct _GtkStyleContextPrivate
GtkStyleCascade *cascade;
GtkStyleContext *animation_list_prev;
GtkStyleContext *animation_list_next;
GtkStyleContext *parent;
GSList *children;
GtkWidget *widget;
GtkWidget *widget;
GtkWidgetPath *widget_path;
GHashTable *style_data;
GtkStyleInfo *info;
GdkFrameClock *frame_clock;
guint frame_clock_update_id;
GtkCssChange relevant_changes;
GtkCssChange pending_changes;
const GtkBitmask *invalidating_context;
guint animating : 1;
guint invalid : 1;
};
@ -388,11 +389,11 @@ enum {
};
static guint signals[LAST_SIGNAL] = { 0 };
static GtkStyleContext *_running_animations = NULL;
guint _running_animations_timer_id = 0;
static void gtk_style_context_finalize (GObject *object);
static void frame_clock_target_iface_init (GdkFrameClockTargetInterface *target);
static void gtk_style_context_impl_set_property (GObject *object,
guint prop_id,
const GValue *value,
@ -404,7 +405,11 @@ static void gtk_style_context_impl_get_property (GObject *object,
static StyleData *style_data_lookup (GtkStyleContext *context);
G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
static void gtk_style_context_disconnect_update (GtkStyleContext *context);
static void gtk_style_context_connect_update (GtkStyleContext *context);
G_DEFINE_TYPE_WITH_CODE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_FRAME_CLOCK_TARGET, frame_clock_target_iface_init))
static void
gtk_style_context_real_changed (GtkStyleContext *context)
@ -469,6 +474,25 @@ gtk_style_context_class_init (GtkStyleContextClass *klass)
g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate));
}
static void
gtk_style_context_set_clock (GdkFrameClockTarget *target,
GdkFrameClock *clock)
{
GtkStyleContext *context = GTK_STYLE_CONTEXT (target);
GtkStyleContextPrivate *priv = context->priv;
gtk_style_context_disconnect_update (context);
priv->frame_clock = clock;
if (priv->animating)
gtk_style_context_connect_update (context);
}
static void
frame_clock_target_iface_init (GdkFrameClockTargetInterface *iface)
{
iface->set_clock = gtk_style_context_set_clock;
}
static StyleData *
style_data_new (void)
{
@ -724,19 +748,14 @@ gtk_style_context_init (GtkStyleContext *style_context)
_gtk_style_cascade_get_for_screen (priv->screen));
}
static gboolean
gtk_style_context_do_animations (gpointer unused)
static void
gtk_style_context_update (GdkFrameClock *clock,
GtkStyleContext *context)
{
GtkStyleContext *context;
_gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE);
for (context = _running_animations;
context != NULL;
context = context->priv->animation_list_next)
{
_gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE);
}
return TRUE;
/* A little blech to request one more than we need */
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
}
static gboolean
@ -744,8 +763,35 @@ gtk_style_context_is_animating (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv = context->priv;
return priv->animation_list_prev != NULL
|| _running_animations == context;
return priv->animating;
}
static void
gtk_style_context_disconnect_update (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv = context->priv;
if (priv->frame_clock && priv->frame_clock_update_id)
{
g_signal_handler_disconnect (priv->frame_clock,
priv->frame_clock_update_id);
priv->frame_clock_update_id = 0;
}
}
static void
gtk_style_context_connect_update (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv = context->priv;
if (priv->frame_clock && priv->frame_clock_update_id == 0)
{
priv->frame_clock_update_id = g_signal_connect (priv->frame_clock,
"update",
G_CALLBACK (gtk_style_context_update),
context);
gdk_frame_clock_request_phase (priv->frame_clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
}
}
static void
@ -756,25 +802,14 @@ gtk_style_context_stop_animating (GtkStyleContext *context)
if (!gtk_style_context_is_animating (context))
return;
if (priv->animation_list_prev == NULL)
priv->animating = FALSE;
gtk_style_context_disconnect_update (context);
if (priv->widget)
{
_running_animations = priv->animation_list_next;
if (_running_animations == NULL)
{
/* we were the last animation */
g_source_remove (_running_animations_timer_id);
_running_animations_timer_id = 0;
}
gtk_widget_remove_frame_clock_target (priv->widget,
GDK_FRAME_CLOCK_TARGET (context));
}
else
priv->animation_list_prev->priv->animation_list_next = priv->animation_list_next;
if (priv->animation_list_next)
priv->animation_list_next->priv->animation_list_prev = priv->animation_list_prev;
priv->animation_list_next = NULL;
priv->animation_list_prev = NULL;
}
static void
@ -785,18 +820,13 @@ gtk_style_context_start_animating (GtkStyleContext *context)
if (gtk_style_context_is_animating (context))
return;
if (_running_animations == NULL)
priv->animating = TRUE;
gtk_style_context_connect_update (context);
if (priv->widget)
{
_running_animations_timer_id = gdk_threads_add_timeout (25,
gtk_style_context_do_animations,
NULL);
_running_animations = context;
}
else
{
priv->animation_list_next = _running_animations;
_running_animations->priv->animation_list_prev = context;
_running_animations = context;
gtk_widget_add_frame_clock_target (priv->widget,
GDK_FRAME_CLOCK_TARGET (context));
}
}

View File

@ -409,6 +409,9 @@ struct _GtkWidgetPrivate
/* The widget's parent */
GtkWidget *parent;
/* Animations and other things to update on clock ticks */
GList *frame_clock_targets;
#ifdef G_ENABLE_DEBUG
/* Number of gtk_widget_push_verify_invariants () */
guint verifying_invariants_count;
@ -4533,6 +4536,7 @@ gtk_widget_realize (GtkWidget *widget)
{
GtkWidgetPrivate *priv;
cairo_region_t *region;
GList *tmp_list;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (widget->priv->anchored ||
@ -4588,6 +4592,12 @@ gtk_widget_realize (GtkWidget *widget)
if (GTK_IS_CONTAINER (widget))
_gtk_container_maybe_start_idle_sizer (GTK_CONTAINER (widget));
for (tmp_list = priv->frame_clock_targets; tmp_list; tmp_list = tmp_list->next)
{
GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (widget);
gdk_frame_clock_target_set_clock (tmp_list->data, frame_clock);
}
gtk_widget_pop_verify_invariants (widget);
}
}
@ -10533,6 +10543,10 @@ gtk_widget_real_destroy (GtkWidget *object)
gtk_grab_remove (widget);
g_list_foreach (priv->frame_clock_targets, (GFunc)g_object_unref, NULL);
g_list_free (priv->frame_clock_targets);
priv->frame_clock_targets = NULL;
if (priv->style)
g_object_unref (priv->style);
priv->style = gtk_widget_get_default_style ();
@ -14582,3 +14596,65 @@ gtk_widget_insert_action_group (GtkWidget *widget,
else
g_action_muxer_remove (muxer, name);
}
/**
* gtk_widget_add_frame_clock_target:
* @widget: a #GtkWidget
* @target: the #GdkClockTarget
*
* Associates a #GdkClockTarget with the widget. When the widget
* is realized and gets a #GdkFrameClock the clock target will be
* added to that frame clock.
*/
void
gtk_widget_add_frame_clock_target (GtkWidget *widget,
GdkFrameClockTarget *target)
{
GtkWidgetPrivate *priv;
priv = widget->priv;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (GDK_IS_FRAME_CLOCK_TARGET (target));
priv->frame_clock_targets = g_list_prepend (priv->frame_clock_targets, target);
g_object_ref (target);
if (gtk_widget_get_realized (widget))
{
GdkFrameClock *clock;
clock = gtk_widget_get_frame_clock (widget);
gdk_frame_clock_target_set_clock (target, clock);
}
}
/**
* gtk_widget_remove_frame_clock_target:
* @widget: a #GtkWidget
* @target: the #GdkClockTarget
*
* Removes a #GdkClockTarget previously added with
* gtk_widget_add_frame_clock_target.
*/
void
gtk_widget_remove_frame_clock_target (GtkWidget *widget,
GdkFrameClockTarget *target)
{
GtkWidgetPrivate *priv;
GList *tmp_list;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (GDK_IS_FRAME_CLOCK_TARGET (target));
priv = widget->priv;
tmp_list = g_list_find (priv->frame_clock_targets, target);
if (tmp_list == NULL)
return;
priv->frame_clock_targets = g_list_delete_link (priv->frame_clock_targets, tmp_list);
if (gtk_widget_get_realized (widget))
gdk_frame_clock_target_set_clock (target, NULL);
g_object_unref (target);
}

View File

@ -905,6 +905,13 @@ void gtk_widget_insert_action_group (GtkWidg
const gchar *name,
GActionGroup *group);
GDK_AVAILABLE_IN_3_2
void gtk_widget_add_frame_clock_target (GtkWidget *widget,
GdkFrameClockTarget *target);
GDK_AVAILABLE_IN_3_2
void gtk_widget_remove_frame_clock_target (GtkWidget *widget,
GdkFrameClockTarget *target);
G_END_DECLS
#endif /* __GTK_WIDGET_H__ */