X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkstylecontext.c;h=ad182f2be3967d5ac44995fb347cffe784519cd0;hb=5e2c23214564f7dcc687fa8467020eeb6b9407a9;hp=e37edd5511732eaeda426be14f97bd1e19f536e1;hpb=a770f0c3ebf3f0dfdb0a7de7b81cd522c5dcae8e;p=~andy%2Fgtk diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index e37edd551..ad182f2be 100644 --- a/gtk/gtkstylecontext.c +++ b/gtk/gtkstylecontext.c @@ -24,7 +24,8 @@ #include "gtkstylecontextprivate.h" #include "gtkcontainerprivate.h" -#include "gtkcssanimatedvaluesprivate.h" +#include "gtkcsscolorvalueprivate.h" +#include "gtkcsscornervalueprivate.h" #include "gtkcssenginevalueprivate.h" #include "gtkcssnumbervalueprivate.h" #include "gtkcssrgbavalueprivate.h" @@ -36,7 +37,6 @@ #include "gtkwidget.h" #include "gtkwindow.h" #include "gtkprivate.h" -#include "gtksymboliccolorprivate.h" #include "gtkiconfactory.h" #include "gtkwidgetpath.h" #include "gtkwidgetprivate.h" @@ -45,6 +45,9 @@ #include "gtksettings.h" #include "gtksettingsprivate.h" +#include "deprecated/gtkgradientprivate.h" +#include "deprecated/gtksymboliccolorprivate.h" + /** * SECTION:gtkstylecontext * @Short_description: Rendering UI elements @@ -355,22 +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; - GtkTextDirection direction; + GdkFrameClock *frame_clock; + guint frame_clock_update_id; GtkCssChange relevant_changes; GtkCssChange pending_changes; - guint invalidating_context : 1; + const GtkBitmask *invalidating_context; + guint animating : 1; guint invalid : 1; }; @@ -378,6 +380,7 @@ enum { PROP_0, PROP_SCREEN, PROP_DIRECTION, + PROP_FRAME_CLOCK, PROP_PARENT }; @@ -387,8 +390,6 @@ 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); @@ -400,10 +401,11 @@ static void gtk_style_context_impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -static GtkSymbolicColor * - gtk_style_context_color_lookup_func (gpointer contextp, - const char *name); +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) @@ -443,6 +445,13 @@ gtk_style_context_class_init (GtkStyleContextClass *klass) 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", @@ -526,7 +535,7 @@ style_data_unref (StyleData *data) static gboolean style_data_is_animating (StyleData *style_data) { - return GTK_IS_CSS_ANIMATED_VALUES (style_data->store); + return !_gtk_css_computed_values_is_static (style_data->store); } static GtkStyleInfo * @@ -714,40 +723,59 @@ gtk_style_context_init (GtkStyleContext *style_context) (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; +} + +static void +gtk_style_context_disconnect_update (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv = context->priv; - for (context = _running_animations; - context != NULL; - context = context->priv->animation_list_next) + 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 @@ -758,25 +786,9 @@ 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; - - 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 @@ -787,19 +799,44 @@ 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; - } + priv->animating = TRUE; + + gtk_style_context_connect_update (context); +} + +static gboolean +gtk_style_context_should_animate (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv; + StyleData *data; + gboolean animate; + + priv = context->priv; + + if (priv->widget == NULL) + return FALSE; + + if (!gtk_widget_get_mapped (priv->widget)) + return FALSE; + + data = style_data_lookup (context); + if (!style_data_is_animating (data)) + return FALSE; + + g_object_get (gtk_widget_get_settings (context->priv->widget), + "gtk-enable-animations", &animate, + NULL); + + return animate; +} + +void +_gtk_style_context_update_animating (GtkStyleContext *context) +{ + if (gtk_style_context_should_animate (context)) + gtk_style_context_start_animating (context); else - { - priv->animation_list_next = _running_animations; - _running_animations->priv->animation_list_prev = context; - _running_animations = context; - } + gtk_style_context_stop_animating (context); } static void @@ -811,7 +848,7 @@ gtk_style_context_finalize (GObject *object) style_context = GTK_STYLE_CONTEXT (object); priv = style_context->priv; - _gtk_style_context_stop_animations (style_context); + gtk_style_context_stop_animating (style_context); /* children hold a reference to us */ g_assert (priv->children == NULL); @@ -848,8 +885,14 @@ gtk_style_context_impl_set_property (GObject *object, 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, @@ -879,7 +922,12 @@ gtk_style_context_impl_get_property (GObject *object, 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); @@ -891,19 +939,17 @@ gtk_style_context_impl_get_property (GObject *object, } static GtkWidgetPath * -create_query_path (GtkStyleContext *context) +create_query_path (GtkStyleContext *context, + GtkStyleInfo *info) { GtkStyleContextPrivate *priv; GtkWidgetPath *path; - GtkStyleInfo *info; guint i, pos; priv = context->priv; path = priv->widget ? _gtk_widget_create_path (priv->widget) : gtk_widget_path_copy (priv->widget_path); pos = gtk_widget_path_length (path) - 1; - info = priv->info; - /* Set widget regions */ for (i = 0; i < info->regions->len; i++) { @@ -931,7 +977,7 @@ create_query_path (GtkStyleContext *context) static void build_properties (GtkStyleContext *context, GtkCssComputedValues *values, - GtkStateFlags state, + GtkStyleInfo *info, const GtkBitmask *relevant_changes) { GtkStyleContextPrivate *priv; @@ -941,15 +987,18 @@ build_properties (GtkStyleContext *context, priv = context->priv; - path = create_query_path (context); + path = create_query_path (context, info); lookup = _gtk_css_lookup_new (relevant_changes); - if (_gtk_css_matcher_init (&matcher, path, state)) + if (_gtk_css_matcher_init (&matcher, path, info->state_flags)) _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), &matcher, lookup); - _gtk_css_lookup_resolve (lookup, context, values); + _gtk_css_lookup_resolve (lookup, + GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), + values, + priv->parent ? style_data_lookup (priv->parent)->store : NULL); _gtk_css_lookup_free (lookup); gtk_widget_path_free (path); @@ -985,7 +1034,7 @@ style_data_lookup (GtkStyleContext *context) style_info_copy (info), data); - build_properties (context, data->store, info->state_flags, NULL); + build_properties (context, data->store, info, NULL); return data; } @@ -1089,7 +1138,7 @@ _gtk_style_context_set_widget (GtkStyleContext *context, context->priv->widget = widget; - _gtk_style_context_stop_animations (context); + _gtk_style_context_update_animating (context); _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY_SELF); } @@ -1444,9 +1493,18 @@ void 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); } @@ -2186,17 +2244,6 @@ _gtk_style_context_peek_property (GtkStyleContext *context, return _gtk_css_computed_values_get_value (data->store, property_id); } -double -_gtk_style_context_get_number (GtkStyleContext *context, - guint property_id, - double one_hundred_percent) -{ - GtkCssValue *value; - - value = _gtk_style_context_peek_property (context, property_id); - return _gtk_css_number_value_get (value, one_hundred_percent); -} - const GValue * _gtk_style_context_peek_style_property (GtkStyleContext *context, GType widget_type, @@ -2248,6 +2295,8 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context, widget_path, state, pspec, &pcache->value)) { + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + /* Resolve symbolic colors to GdkColor/GdkRGBA */ if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR) { @@ -2263,7 +2312,7 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context, else g_value_init (&pcache->value, GDK_TYPE_COLOR); - if (_gtk_style_context_resolve_color (context, color, &rgba)) + if (_gtk_style_context_resolve_color (context, _gtk_symbolic_color_get_css_value (color), &rgba, NULL)) { if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA) g_value_set_boxed (&pcache->value, &rgba); @@ -2284,6 +2333,8 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context, gtk_symbolic_color_unref (color); } + G_GNUC_END_IGNORE_DEPRECATIONS; + if (priv->widget) gtk_widget_path_free (widget_path); @@ -2574,6 +2625,70 @@ gtk_style_context_get_screen (GtkStyleContext *context) 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 @@ -2586,19 +2701,38 @@ gtk_style_context_get_screen (GtkStyleContext *context) * 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); + + 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; + } - g_object_notify (G_OBJECT (context), "direction"); + gtk_style_context_set_state (context, state); } /** @@ -2610,16 +2744,26 @@ gtk_style_context_set_direction (GtkStyleContext *context, * 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; } /** @@ -2667,35 +2811,11 @@ gtk_style_context_get_junction_sides (GtkStyleContext *context) return context->priv->info->junction_sides; } -static GtkSymbolicColor * -gtk_style_context_color_lookup_func (gpointer contextp, - const char *name) -{ - GtkStyleContext *context = contextp; - - return _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade), name); -} - -GtkCssValue * -_gtk_style_context_resolve_color_value (GtkStyleContext *context, - GtkCssValue *current, - GtkCssValue *color) -{ - g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE); - g_return_val_if_fail (current != NULL, FALSE); - g_return_val_if_fail (color != NULL, FALSE); - - return _gtk_symbolic_color_resolve_full ((GtkSymbolicColor *) color, - current, - gtk_style_context_color_lookup_func, - context); -} - - gboolean -_gtk_style_context_resolve_color (GtkStyleContext *context, - GtkSymbolicColor *color, - GdkRGBA *result) +_gtk_style_context_resolve_color (GtkStyleContext *context, + GtkCssValue *color, + GdkRGBA *result, + GtkCssDependencies *dependencies) { GtkCssValue *val; @@ -2703,10 +2823,11 @@ _gtk_style_context_resolve_color (GtkStyleContext *context, g_return_val_if_fail (color != NULL, FALSE); g_return_val_if_fail (result != NULL, FALSE); - val = _gtk_symbolic_color_resolve_full (color, - _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR), - gtk_style_context_color_lookup_func, - context); + val = _gtk_css_color_value_resolve (color, + GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade), + _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR), + GTK_CSS_DEPENDS_ON_COLOR, + dependencies); if (val == NULL) return FALSE; @@ -2730,17 +2851,17 @@ gtk_style_context_lookup_color (GtkStyleContext *context, const gchar *color_name, GdkRGBA *color) { - GtkSymbolicColor *sym_color; + GtkCssValue *value; g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE); g_return_val_if_fail (color_name != NULL, FALSE); g_return_val_if_fail (color != NULL, FALSE); - sym_color = gtk_style_context_color_lookup_func (context, color_name); - if (sym_color == NULL) + value = _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade), color_name); + if (value == NULL) return FALSE; - return _gtk_style_context_resolve_color (context, sym_color, color); + return _gtk_style_context_resolve_color (context, value, color, NULL); } /** @@ -2925,36 +3046,53 @@ gtk_style_context_clear_cache (GtkStyleContext *context) } static void -gtk_style_context_do_invalidate (GtkStyleContext *context) +gtk_style_context_update_cache (GtkStyleContext *context, + const GtkBitmask *parent_changes) { GtkStyleContextPrivate *priv; + GHashTableIter iter; + gpointer key, value; - g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); + if (_gtk_bitmask_is_empty (parent_changes)) + return; priv = context->priv; - /* Avoid reentrancy */ - if (priv->invalidating_context) - return; + g_hash_table_iter_init (&iter, priv->style_data); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + GtkStyleInfo *info = key; + StyleData *data = value; + GtkBitmask *changes; - priv->invalidating_context = TRUE; + changes = _gtk_css_computed_values_compute_dependencies (data->store, parent_changes); - g_signal_emit (context, signals[CHANGED], 0); + if (!_gtk_bitmask_is_empty (changes)) + build_properties (context, data->store, info, changes); - priv->invalidating_context = FALSE; + _gtk_bitmask_free (changes); + } } -void -_gtk_style_context_stop_animations (GtkStyleContext *context) +static void +gtk_style_context_do_invalidate (GtkStyleContext *context, + const GtkBitmask *changes) { + GtkStyleContextPrivate *priv; + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - if (!gtk_style_context_is_animating (context)) + priv = context->priv; + + /* Avoid reentrancy */ + if (priv->invalidating_context) return; - style_info_set_data (context->priv->info, NULL); + priv->invalidating_context = changes; + + g_signal_emit (context, signals[CHANGED], 0); - gtk_style_context_stop_animating (context); + priv->invalidating_context = NULL; } static GtkBitmask * @@ -2966,66 +3104,15 @@ gtk_style_context_update_animations (GtkStyleContext *context, style_data = style_data_lookup (context); - differences = _gtk_css_animated_values_advance (GTK_CSS_ANIMATED_VALUES (style_data->store), + differences = _gtk_css_computed_values_advance (style_data->store, timestamp); - if (_gtk_css_animated_values_is_finished (GTK_CSS_ANIMATED_VALUES (style_data->store))) - _gtk_style_context_stop_animations (context); + if (_gtk_css_computed_values_is_static (style_data->store)) + _gtk_style_context_update_animating (context); return differences; } -static gboolean -gtk_style_context_should_animate (GtkStyleContext *context) -{ - GtkStyleContextPrivate *priv; - gboolean animate; - - priv = context->priv; - - if (priv->widget == NULL) - return FALSE; - - if (!gtk_widget_get_mapped (priv->widget)) - return FALSE; - - g_object_get (gtk_widget_get_settings (context->priv->widget), - "gtk-enable-animations", &animate, - NULL); - - return animate; -} - -static void -gtk_style_context_start_animations (GtkStyleContext *context, - GtkCssComputedValues *previous, - gint64 timestamp) -{ - StyleData *animated; - - if (!gtk_style_context_should_animate (context)) - { - gtk_style_context_stop_animating (context); - return; - } - - animated = style_data_new (); - animated->store = _gtk_css_animated_values_new (style_data_lookup (context)->store, - previous, - timestamp); - - if (_gtk_css_animated_values_is_finished (GTK_CSS_ANIMATED_VALUES (animated->store))) - { - style_data_unref (animated); - gtk_style_context_stop_animating (context); - return; - } - - style_info_set_data (context->priv->info, animated); - style_data_unref (animated); - gtk_style_context_start_animating (context); -} - static gboolean gtk_style_context_needs_full_revalidate (GtkStyleContext *context, GtkCssChange change) @@ -3042,12 +3129,15 @@ gtk_style_context_needs_full_revalidate (GtkStyleContext *context, if (priv->relevant_changes == GTK_CSS_CHANGE_ANY) { GtkWidgetPath *path; - GtkCssMatcher matcher; + GtkCssMatcher matcher, superset; - path = create_query_path (context); + path = create_query_path (context, priv->info); if (_gtk_css_matcher_init (&matcher, path, priv->info->state_flags)) - priv->relevant_changes = _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), - &matcher); + { + _gtk_css_matcher_superset_init (&superset, &matcher, GTK_STYLE_CONTEXT_RADICAL_CHANGE & ~GTK_CSS_CHANGE_SOURCE); + priv->relevant_changes = _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), + &superset); + } else priv->relevant_changes = 0; @@ -3063,6 +3153,27 @@ gtk_style_context_needs_full_revalidate (GtkStyleContext *context, return FALSE; } +static gboolean +gtk_style_context_should_create_transitions (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv; + gboolean animate; + + priv = context->priv; + + if (priv->widget == NULL) + return FALSE; + + if (!gtk_widget_get_mapped (priv->widget)) + return FALSE; + + g_object_get (gtk_widget_get_settings (context->priv->widget), + "gtk-enable-animations", &animate, + NULL); + + return animate; +} + void _gtk_style_context_validate (GtkStyleContext *context, gint64 timestamp, @@ -3112,23 +3223,37 @@ _gtk_style_context_validate (GtkStyleContext *context, if (current == NULL || gtk_style_context_needs_full_revalidate (context, change)) { + StyleData *data; + if ((priv->relevant_changes & change) & ~GTK_STYLE_CONTEXT_CACHED_CHANGE) - gtk_style_context_clear_cache (context); + { + gtk_style_context_clear_cache (context); + } else - style_info_set_data (info, NULL); - - if (current) { - StyleData *data; + gtk_style_context_update_cache (context, parent_changes); + style_info_set_data (info, NULL); + } - gtk_style_context_start_animations (context, current->store, timestamp); - change &= ~GTK_CSS_CHANGE_ANIMATE; + data = style_data_lookup (context); - data = style_data_lookup (context); + _gtk_css_computed_values_create_animations (data->store, + priv->parent ? style_data_lookup (priv->parent)->store : NULL, + timestamp, + GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), + current && gtk_style_context_should_create_transitions (context) ? current->store : NULL); + if (_gtk_css_computed_values_is_static (data->store)) + change &= ~GTK_CSS_CHANGE_ANIMATE; + else + change |= GTK_CSS_CHANGE_ANIMATE; + _gtk_style_context_update_animating (context); + if (current) + { changes = _gtk_css_computed_values_get_difference (data->store, current->store); - style_data_unref (current); + /* In the case where we keep the cache, we want unanimated values */ + _gtk_css_computed_values_cancel_animations (current->store); } else { @@ -3138,14 +3263,14 @@ _gtk_style_context_validate (GtkStyleContext *context, } else { - changes = _gtk_bitmask_copy (parent_changes); - changes = _gtk_bitmask_intersect (changes, current->store->depends_on_parent); - if (_gtk_bitmask_get (changes, GTK_CSS_PROPERTY_COLOR)) - changes = _gtk_bitmask_union (changes, current->store->depends_on_color); - if (_gtk_bitmask_get (changes, GTK_CSS_PROPERTY_FONT_SIZE)) - changes = _gtk_bitmask_union (changes, current->store->depends_on_font_size); + changes = _gtk_css_computed_values_compute_dependencies (current->store, parent_changes); + + gtk_style_context_update_cache (context, parent_changes); } + if (current) + style_data_unref (current); + if (change & GTK_CSS_CHANGE_ANIMATE && gtk_style_context_is_animating (context)) { @@ -3156,8 +3281,19 @@ _gtk_style_context_validate (GtkStyleContext *context, _gtk_bitmask_free (animation_changes); } - if (!_gtk_bitmask_is_empty (changes)) - gtk_style_context_do_invalidate (context); + 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) @@ -3206,10 +3342,25 @@ _gtk_style_context_queue_invalidate (GtkStyleContext *context, void gtk_style_context_invalidate (GtkStyleContext *context) { + GtkBitmask *changes; + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); gtk_style_context_clear_cache (context); - gtk_style_context_do_invalidate (context); + + changes = _gtk_bitmask_new (); + changes = _gtk_bitmask_invert_range (changes, + 0, + _gtk_css_style_property_get_n_properties ()); + gtk_style_context_do_invalidate (context, changes); + _gtk_bitmask_free (changes); +} + +static gboolean +corner_value_is_right_angle (GtkCssValue *value) +{ + return _gtk_css_corner_value_get_x (value, 100) <= 0.0 && + _gtk_css_corner_value_get_y (value, 100) <= 0.0; } /** @@ -3226,31 +3377,33 @@ void gtk_style_context_set_background (GtkStyleContext *context, GdkWindow *window) { - GtkStateFlags state; - cairo_pattern_t *pattern; - GdkRGBA *color; + const GdkRGBA *color; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (GDK_IS_WINDOW (window)); - state = gtk_style_context_get_state (context); - gtk_style_context_get (context, state, - "background-image", &pattern, - NULL); - if (pattern) - { - gdk_window_set_background_pattern (window, pattern); - cairo_pattern_destroy (pattern); - return; - } + /* This is a sophisitcated optimization. + * If we know the GDK window's background will be opaque, we mark + * it as opaque. This is so GDK can do all the optimizations it does + * for opaque windows and be fast. + * This is mainly used when scrolling. + * + * We could indeed just set black instead of the color we have. + */ + color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BACKGROUND_COLOR)); - gtk_style_context_get (context, state, - "background-color", &color, - NULL); - if (color) + if (color->alpha >= 1.0 && + corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS)) && + corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS)) && + corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS)) && + corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS))) { gdk_window_set_background_rgba (window, color); - gdk_rgba_free (color); + } + else + { + GdkRGBA transparent = { 0.0, 0.0, 0.0, 0.0 }; + gdk_window_set_background_rgba (window, &transparent); } } @@ -3460,6 +3613,9 @@ gtk_style_context_get_margin (GtkStyleContext *context, * freed. * * Since: 3.0 + * + * Deprecated: 3.8: Use gtk_style_context_get() for "font" or + * subproperties instead. **/ const PangoFontDescription * gtk_style_context_get_font (GtkStyleContext *context, @@ -3467,7 +3623,7 @@ gtk_style_context_get_font (GtkStyleContext *context, { GtkStyleContextPrivate *priv; StyleData *data; - PangoFontDescription *description; + PangoFontDescription *description, *previous; g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); @@ -3478,15 +3634,24 @@ gtk_style_context_get_font (GtkStyleContext *context, /* Yuck, fonts are created on-demand but we don't return a ref. * Do bad things to achieve this requirement */ - description = g_object_get_data (G_OBJECT (data->store), "font-cache-for-get_font"); - if (description == NULL) + gtk_style_context_get (context, state, "font", &description, NULL); + + 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 { - 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); } + return description; } @@ -4493,6 +4658,26 @@ gtk_draw_insertion_cursor (GtkWidget *widget, draw_arrow); } +/** + * _gtk_style_context_get_changes: + * @context: the context to query + * + * Queries the context for the changes for the currently executing + * GtkStyleContext::invalidate signal. If no signal is currently + * emitted, this function returns %NULL. + * + * FIXME 4.0: Make this part of the signal. + * + * Returns: %NULL or the currently invalidating changes + **/ +const GtkBitmask * +_gtk_style_context_get_changes (GtkStyleContext *context) +{ + g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); + + return context->priv->invalidating_context; +} + static AtkAttributeSet * add_attribute (AtkAttributeSet *attributes, AtkTextAttribute attr, @@ -4547,3 +4732,21 @@ _gtk_style_context_get_attributes (AtkAttributeSet *attributes, return attributes; } + +cairo_pattern_t * +gtk_gradient_resolve_for_context (GtkGradient *gradient, + GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv = context->priv; + GtkCssDependencies ignored = 0; + + g_return_val_if_fail (gradient != NULL, NULL); + g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); + + return _gtk_gradient_resolve_full (gradient, + GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), + style_data_lookup (context)->store, + priv->parent ? style_data_lookup (priv->parent)->store : NULL, + &ignored); +} +