summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdk/gdkframeclock.c29
-rw-r--r--gdk/gdkframeclock.h34
-rw-r--r--gdk/gdkframeclockidle.c11
-rw-r--r--gtk/gtkstylecontext.c124
-rw-r--r--gtk/gtkwidget.c76
-rw-r--r--gtk/gtkwidget.h7
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__ */