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;
- GtkTextDirection direction;
+ GdkFrameClock *frame_clock;
+ guint frame_clock_update_id;
GtkCssChange relevant_changes;
GtkCssChange pending_changes;
const GtkBitmask *invalidating_context;
+ guint animating : 1;
guint invalid : 1;
};
PROP_0,
PROP_SCREEN,
PROP_DIRECTION,
+ PROP_FRAME_CLOCK,
PROP_PARENT
};
};
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 StyleData *style_data_lookup (GtkStyleContext *context);
+static void gtk_style_context_disconnect_update (GtkStyleContext *context);
+static void gtk_style_context_connect_update (GtkStyleContext *context);
+
G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
static void
P_("The associated GdkScreen"),
GDK_TYPE_SCREEN,
GTK_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_FRAME_CLOCK,
+ g_param_spec_object ("paint-clock",
+ P_("FrameClock"),
+ P_("The associated GdkFrameClock"),
+ GDK_TYPE_FRAME_CLOCK,
+ GTK_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_DIRECTION,
g_param_spec_enum ("direction",
(GDestroyNotify) style_info_free,
(GDestroyNotify) style_data_unref);
- priv->direction = GTK_TEXT_DIR_LTR;
-
priv->screen = gdk_screen_get_default ();
priv->relevant_changes = GTK_CSS_CHANGE_ANY;
/* Create default info store */
priv->info = style_info_new ();
+ priv->info->state_flags = GTK_STATE_FLAG_DIR_LTR;
gtk_style_context_set_cascade (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);
+}
+
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;
+ gdk_frame_clock_end_updating (priv->frame_clock);
}
-
- 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_begin_updating (priv->frame_clock);
+ }
}
static void
if (!gtk_style_context_is_animating (context))
return;
- if (priv->animation_list_prev == NULL)
- {
- _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;
- }
- }
- 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->animating = FALSE;
- priv->animation_list_next = NULL;
- priv->animation_list_prev = NULL;
+ gtk_style_context_disconnect_update (context);
}
static void
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->animation_list_next = _running_animations;
- _running_animations->priv->animation_list_prev = context;
- _running_animations = context;
- }
+ priv->animating = TRUE;
+
+ gtk_style_context_connect_update (context);
}
static gboolean
g_value_get_object (value));
break;
case PROP_DIRECTION:
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
gtk_style_context_set_direction (style_context,
g_value_get_enum (value));
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+ break;
+ case PROP_FRAME_CLOCK:
+ gtk_style_context_set_frame_clock (style_context,
+ g_value_get_object (value));
break;
case PROP_PARENT:
gtk_style_context_set_parent (style_context,
g_value_set_object (value, priv->screen);
break;
case PROP_DIRECTION:
- g_value_set_enum (value, priv->direction);
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+ g_value_set_enum (value, gtk_style_context_get_direction (style_context));
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+ break;
+ case PROP_FRAME_CLOCK:
+ g_value_set_object (value, priv->frame_clock);
break;
case PROP_PARENT:
g_value_set_object (value, priv->parent);
gtk_style_context_set_state (GtkStyleContext *context,
GtkStateFlags flags)
{
+ GtkStateFlags old_flags;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ old_flags = context->priv->info->state_flags;
+ if (old_flags == flags)
+ return;
+
context->priv->info->state_flags = flags;
+
+ if (((old_flags ^ flags) & (GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL)) &&
+ !gtk_style_context_is_saved (context))
+ g_object_notify (G_OBJECT (context), "direction");
gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_STATE);
}
return priv->screen;
}
+/**
+ * gtk_style_context_set_frame_clock:
+ * @context: a #GdkFrameClock
+ * @frame_clock: a #GdkFrameClock
+ *
+ * Attaches @context to the given frame clock.
+ *
+ * The frame clock is used for the timing of animations.
+ *
+ * If you are using a #GtkStyleContext returned from
+ * gtk_widget_get_style_context(), you do not need to
+ * call this yourself.
+ *
+ * Since: 3.8
+ **/
+void
+gtk_style_context_set_frame_clock (GtkStyleContext *context,
+ GdkFrameClock *frame_clock)
+{
+ GtkStyleContextPrivate *priv;
+
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ g_return_if_fail (frame_clock == NULL || GDK_IS_FRAME_CLOCK (frame_clock));
+
+ priv = context->priv;
+ if (priv->frame_clock == frame_clock)
+ return;
+
+ if (priv->animating)
+ gtk_style_context_disconnect_update (context);
+
+ if (priv->frame_clock)
+ g_object_unref (priv->frame_clock);
+ priv->frame_clock = frame_clock;
+ if (priv->frame_clock)
+ g_object_ref (priv->frame_clock);
+
+ if (priv->animating)
+ gtk_style_context_connect_update (context);
+
+ g_object_notify (G_OBJECT (context), "paint-clock");
+}
+
+/**
+ * gtk_style_context_get_frame_clock:
+ * @context: a #GtkStyleContext
+ *
+ * Returns the #GdkFrameClock to which @context is attached.
+ *
+ * Returns: (transfer none): a #GdkFrameClock, or %NULL
+ * if @context does not have an attached frame clock.
+ * Since: 3.8
+ **/
+GdkFrameClock *
+gtk_style_context_get_frame_clock (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
+
+ priv = context->priv;
+ return priv->frame_clock;
+}
+
/**
* gtk_style_context_set_direction:
* @context: a #GtkStyleContext
* call this yourself.
*
* Since: 3.0
+ *
+ * Deprecated: 3.8: Use gtk_style_context_set_state() with
+ * #GTK_STATE_FLAG_DIR_LTR and #GTK_STATE_FLAG_DIR_RTL
+ * instead.
**/
void
gtk_style_context_set_direction (GtkStyleContext *context,
GtkTextDirection direction)
{
- GtkStyleContextPrivate *priv;
+ GtkStateFlags state;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
- priv->direction = direction;
+ state = gtk_style_context_get_state (context);
+ state &= ~(GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL);
- g_object_notify (G_OBJECT (context), "direction");
+ switch (direction)
+ {
+ case GTK_TEXT_DIR_LTR:
+ state |= GTK_STATE_FLAG_DIR_LTR;
+ break;
+
+ case GTK_TEXT_DIR_RTL:
+ state |= GTK_STATE_FLAG_DIR_RTL;
+ break;
+
+ case GTK_TEXT_DIR_NONE:
+ default:
+ break;
+ }
+
+ gtk_style_context_set_state (context, state);
}
/**
* Returns: the widget direction
*
* Since: 3.0
+ *
+ * Deprecated: 3.8: Use gtk_style_context_get_state() and
+ * check for #GTK_STATE_FLAG_DIR_LTR and
+ * #GTK_STATE_FLAG_DIR_RTL instead.
**/
GtkTextDirection
gtk_style_context_get_direction (GtkStyleContext *context)
{
- GtkStyleContextPrivate *priv;
+ GtkStateFlags state;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), GTK_TEXT_DIR_LTR);
- priv = context->priv;
- return priv->direction;
+ state = gtk_style_context_get_state (context);
+
+ if (state & GTK_STATE_FLAG_DIR_LTR)
+ return GTK_TEXT_DIR_LTR;
+ else if (state & GTK_STATE_FLAG_DIR_RTL)
+ return GTK_TEXT_DIR_RTL;
+ else
+ return GTK_TEXT_DIR_NONE;
}
/**
_gtk_bitmask_free (animation_changes);
}
- if (!_gtk_bitmask_is_empty (changes) || (change & GTK_CSS_CHANGE_FORCE_INVALIDATE))
- gtk_style_context_do_invalidate (context, changes);
+ if (change & GTK_CSS_CHANGE_FORCE_INVALIDATE)
+ {
+ GtkBitmask *full = _gtk_bitmask_new ();
+ full = _gtk_bitmask_invert_range (full,
+ 0,
+ _gtk_css_style_property_get_n_properties ());
+ gtk_style_context_do_invalidate (context, full);
+ _gtk_bitmask_free (full);
+ }
+ else if (!_gtk_bitmask_is_empty (changes))
+ {
+ gtk_style_context_do_invalidate (context, changes);
+ }
change = _gtk_css_change_for_child (change);
for (list = priv->children; list; list = list->next)
{
GtkStyleContextPrivate *priv;
StyleData *data;
- PangoFontDescription *description;
+ PangoFontDescription *description, *previous;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
/* Yuck, fonts are created on-demand but we don't return a ref.
* Do bad things to achieve this requirement */
gtk_style_context_get (context, state, "font", &description, NULL);
- g_object_set_data_full (G_OBJECT (data->store),
- "font-cache-for-get_font",
- description,
- (GDestroyNotify) pango_font_description_free);
+
+ previous = g_object_get_data (G_OBJECT (data->store), "font-cache-for-get_font");
+
+ if (previous)
+ {
+ pango_font_description_merge (previous, description, TRUE);
+ pango_font_description_free (description);
+ description = previous;
+ }
+ else
+ {
+ g_object_set_data_full (G_OBJECT (data->store),
+ "font-cache-for-get_font",
+ description,
+ (GDestroyNotify) pango_font_description_free);
+ }
return description;
}