diff options
-rw-r--r-- | gdk/gdkframeclock.c | 29 | ||||
-rw-r--r-- | gdk/gdkframeclock.h | 34 | ||||
-rw-r--r-- | gdk/gdkframeclockidle.c | 11 | ||||
-rw-r--r-- | gtk/gtkstylecontext.c | 124 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 76 | ||||
-rw-r--r-- | gtk/gtkwidget.h | 7 |
6 files changed, 227 insertions, 54 deletions
diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c index d385123842..569ab6b52e 100644 --- a/gdk/gdkframeclock.c +++ b/gdk/gdkframeclock.c @@ -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, @@ -124,6 +138,21 @@ gdk_frame_clock_default_init (GdkFrameClockInterface *iface) 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 * diff --git a/gdk/gdkframeclock.h b/gdk/gdkframeclock.h index a733b558a9..ae445737df 100644 --- a/gdk/gdkframeclock.h +++ b/gdk/gdkframeclock.h @@ -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); */ diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c index a0b82f08e6..bf68fd1b64 100644 --- a/gdk/gdkframeclockidle.c +++ b/gdk/gdkframeclockidle.c @@ -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) diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index 876105cf54..343cf1f1bc 100644 --- a/gtk/gtkstylecontext.c +++ b/gtk/gtkstylecontext.c @@ -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,28 +748,50 @@ gtk_style_context_init (GtkStyleContext *style_context) _gtk_style_cascade_get_for_screen (priv->screen)); } +static void +gtk_style_context_update (GdkFrameClock *clock, + GtkStyleContext *context) +{ + _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE); + + /* A little blech to request one more than we need */ + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE); +} + static gboolean -gtk_style_context_do_animations (gpointer unused) +gtk_style_context_is_animating (GtkStyleContext *context) { - GtkStyleContext *context; + GtkStyleContextPrivate *priv = context->priv; + + return priv->animating; +} - for (context = _running_animations; - context != NULL; - context = context->priv->animation_list_next) +static void +gtk_style_context_disconnect_update (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv = context->priv; + + if (priv->frame_clock && priv->frame_clock_update_id) { - _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE); + g_signal_handler_disconnect (priv->frame_clock, + priv->frame_clock_update_id); + priv->frame_clock_update_id = 0; } - - return TRUE; } -static gboolean -gtk_style_context_is_animating (GtkStyleContext *context) +static void +gtk_style_context_connect_update (GtkStyleContext *context) { GtkStyleContextPrivate *priv = context->priv; - return priv->animation_list_prev != NULL - || _running_animations == context; + 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) - { - _running_animations = priv->animation_list_next; + priv->animating = FALSE; - if (_running_animations == NULL) - { - /* we were the last animation */ - g_source_remove (_running_animations_timer_id); - _running_animations_timer_id = 0; - } + gtk_style_context_disconnect_update (context); + if (priv->widget) + { + 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) - { - _running_animations_timer_id = gdk_threads_add_timeout (25, - gtk_style_context_do_animations, - NULL); - _running_animations = context; - } - else + priv->animating = TRUE; + + gtk_style_context_connect_update (context); + if (priv->widget) { - 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)); } } diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 63fbcae40b..1c7e538245 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -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); +} diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index a8572e69d1..9f12bf94cb 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -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__ */ |