X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkstylecontext.c;h=f2c79c8d2e893425e5df7562e0cc2b727ac38fad;hb=HEAD;hp=d74232c61188b9c1f5c9040adc5e96f3d5a7f13d;hpb=5ac9ba714ae480b8abfa918448ec07e5bf330da0;p=~andy%2Fgtk diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index d74232c61..f2c79c8d2 100644 --- a/gtk/gtkstylecontext.c +++ b/gtk/gtkstylecontext.c @@ -23,6 +23,13 @@ #include #include "gtkstylecontextprivate.h" +#include "gtkcontainerprivate.h" +#include "gtkcsscolorvalueprivate.h" +#include "gtkcsscornervalueprivate.h" +#include "gtkcssenginevalueprivate.h" +#include "gtkcssnumbervalueprivate.h" +#include "gtkcssrgbavalueprivate.h" +#include "gtkdebug.h" #include "gtkstylepropertiesprivate.h" #include "gtktypebuiltins.h" #include "gtkthemingengineprivate.h" @@ -30,15 +37,16 @@ #include "gtkwidget.h" #include "gtkwindow.h" #include "gtkprivate.h" -#include "gtksymboliccolorprivate.h" -#include "gtkanimationdescription.h" -#include "gtktimeline.h" #include "gtkiconfactory.h" #include "gtkwidgetpath.h" #include "gtkwidgetprivate.h" #include "gtkstylecascadeprivate.h" #include "gtkstyleproviderprivate.h" #include "gtksettings.h" +#include "gtksettingsprivate.h" + +#include "deprecated/gtkgradientprivate.h" +#include "deprecated/gtksymboliccolorprivate.h" /** * SECTION:gtkstylecontext @@ -303,7 +311,7 @@ /* When these change we do a full restyling. Otherwise we try to figure out * if we need to change things. */ -#define GTK_STYLE_CONTEXT_RADICAL_CHANGE (GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_CLASS) +#define GTK_STYLE_CONTEXT_RADICAL_CHANGE (GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_CLASS | GTK_CSS_CHANGE_SOURCE) /* When these change we don't clear the cache. This takes more memory but makes * things go faster. */ #define GTK_STYLE_CONTEXT_CACHED_CHANGE (GTK_CSS_CHANGE_STATE) @@ -311,7 +319,6 @@ typedef struct GtkStyleInfo GtkStyleInfo; typedef struct GtkRegion GtkRegion; typedef struct PropertyValue PropertyValue; -typedef struct AnimationInfo AnimationInfo; typedef struct StyleData StyleData; struct GtkRegion @@ -330,35 +337,19 @@ struct PropertyValue struct GtkStyleInfo { + GtkStyleInfo *next; GArray *style_classes; GArray *regions; GtkJunctionSides junction_sides; GtkStateFlags state_flags; + StyleData *data; }; struct StyleData { GtkCssComputedValues *store; GArray *property_cache; -}; - -struct AnimationInfo -{ - GtkTimeline *timeline; - - gpointer region_id; - - /* Region stack (until region_id) at the time of - * rendering, this is used for nested cancellation. - */ - GSList *parent_regions; - - GdkWindow *window; - GtkStateType state; - gboolean target_value; - - cairo_region_t *invalidation_region; - GArray *rectangles; + guint ref_count; }; struct _GtkStyleContextPrivate @@ -369,25 +360,19 @@ struct _GtkStyleContextPrivate GtkStyleContext *parent; GSList *children; - GtkWidget *widget; + GtkWidget *widget; GtkWidgetPath *widget_path; GHashTable *style_data; - GSList *info_stack; - StyleData *current_data; - GtkStateFlags current_state; - - GSList *animation_regions; - GSList *animations; - - GtkThemingEngine *theming_engine; + GtkStyleInfo *info; - GtkTextDirection direction; + GdkFrameClock *frame_clock; + guint frame_clock_update_id; GtkCssChange relevant_changes; GtkCssChange pending_changes; - guint animations_invalidated : 1; - guint invalidating_context : 1; + const GtkBitmask *invalidating_context; + guint animating : 1; guint invalid : 1; }; @@ -395,6 +380,7 @@ enum { PROP_0, PROP_SCREEN, PROP_DIRECTION, + PROP_FRAME_CLOCK, PROP_PARENT }; @@ -415,11 +401,12 @@ 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) static void @@ -458,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", @@ -485,6 +479,65 @@ gtk_style_context_class_init (GtkStyleContextClass *klass) g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate)); } +static StyleData * +style_data_new (void) +{ + StyleData *data; + + data = g_slice_new0 (StyleData); + data->ref_count = 1; + + return data; +} + +static void +clear_property_cache (StyleData *data) +{ + guint i; + + if (!data->property_cache) + return; + + for (i = 0; i < data->property_cache->len; i++) + { + PropertyValue *node = &g_array_index (data->property_cache, PropertyValue, i); + + g_param_spec_unref (node->pspec); + g_value_unset (&node->value); + } + + g_array_free (data->property_cache, TRUE); + data->property_cache = NULL; +} + +static StyleData * +style_data_ref (StyleData *style_data) +{ + style_data->ref_count++; + + return style_data; +} + +static void +style_data_unref (StyleData *data) +{ + data->ref_count--; + + if (data->ref_count > 0) + return; + + g_object_unref (data->store); + clear_property_cache (data); + + g_slice_free (StyleData, data); +} + +static gboolean +style_data_is_animating (StyleData *style_data) +{ + return !_gtk_css_computed_values_is_static (style_data->store); +} + static GtkStyleInfo * style_info_new (void) { @@ -497,16 +550,43 @@ style_info_new (void) return info; } +static void +style_info_set_data (GtkStyleInfo *info, + StyleData *data) +{ + if (info->data == data) + return; + + if (data) + style_data_ref (data); + + if (info->data) + style_data_unref (info->data); + + info->data = data; +} + static void style_info_free (GtkStyleInfo *info) { + style_info_set_data (info, NULL); g_array_free (info->style_classes, TRUE); g_array_free (info->regions, TRUE); g_slice_free (GtkStyleInfo, info); } static GtkStyleInfo * -style_info_copy (const GtkStyleInfo *info) +style_info_pop (GtkStyleInfo *info) +{ + GtkStyleInfo *next = info->next; + + style_info_free (info); + + return next; +} + +static GtkStyleInfo * +style_info_copy (GtkStyleInfo *info) { GtkStyleInfo *copy; @@ -519,8 +599,10 @@ style_info_copy (const GtkStyleInfo *info) info->regions->data, info->regions->len); + copy->next = info; copy->junction_sides = info->junction_sides; copy->state_flags = info->state_flags; + style_info_set_data (copy, info->data); return copy; } @@ -586,50 +668,51 @@ style_info_equal (gconstpointer elem1, return TRUE; } -static StyleData * -style_data_new (void) +static void +gtk_style_context_cascade_changed (GtkStyleCascade *cascade, + GtkStyleContext *context) { - StyleData *data; - - data = g_slice_new0 (StyleData); - - return data; + _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_SOURCE); } static void -clear_property_cache (StyleData *data) +gtk_style_context_set_cascade (GtkStyleContext *context, + GtkStyleCascade *cascade) { - guint i; + GtkStyleContextPrivate *priv; - if (!data->property_cache) + priv = context->priv; + + if (priv->cascade == cascade) return; - for (i = 0; i < data->property_cache->len; i++) + if (cascade) { - PropertyValue *node = &g_array_index (data->property_cache, PropertyValue, i); - - g_param_spec_unref (node->pspec); - g_value_unset (&node->value); + g_object_ref (cascade); + g_signal_connect (cascade, + "-gtk-private-changed", + G_CALLBACK (gtk_style_context_cascade_changed), + context); } - g_array_free (data->property_cache, TRUE); - data->property_cache = NULL; -} + if (priv->cascade) + { + g_signal_handlers_disconnect_by_func (priv->cascade, + gtk_style_context_cascade_changed, + context); + g_object_unref (priv->cascade); + } -static void -style_data_free (StyleData *data) -{ - g_object_unref (data->store); - clear_property_cache (data); + priv->cascade = cascade; - g_slice_free (StyleData, data); + if (cascade) + gtk_style_context_cascade_changed (cascade, context); } static void gtk_style_context_init (GtkStyleContext *style_context) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; priv = style_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (style_context, GTK_TYPE_STYLE_CONTEXT, @@ -638,175 +721,122 @@ gtk_style_context_init (GtkStyleContext *style_context) priv->style_data = g_hash_table_new_full (style_info_hash, style_info_equal, (GDestroyNotify) style_info_free, - (GDestroyNotify) style_data_free); - priv->theming_engine = g_object_ref ((gpointer) gtk_theming_engine_load (NULL)); - - priv->direction = GTK_TEXT_DIR_LTR; + (GDestroyNotify) style_data_unref); priv->screen = gdk_screen_get_default (); - priv->cascade = _gtk_style_cascade_get_for_screen (priv->screen); - g_object_ref (priv->cascade); priv->relevant_changes = GTK_CSS_CHANGE_ANY; /* Create default info store */ - info = style_info_new (); - priv->info_stack = g_slist_prepend (priv->info_stack, info); + 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 -animation_info_free (AnimationInfo *info) +gtk_style_context_update (GdkFrameClock *clock, + GtkStyleContext *context) { - g_object_unref (info->timeline); - g_object_unref (info->window); + _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE); +} - if (info->invalidation_region) - cairo_region_destroy (info->invalidation_region); +static gboolean +gtk_style_context_is_animating (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv = context->priv; - g_array_free (info->rectangles, TRUE); - g_slist_free (info->parent_regions); - g_slice_free (AnimationInfo, info); + return priv->animating; } -static AnimationInfo * -animation_info_lookup_by_timeline (GtkStyleContext *context, - GtkTimeline *timeline) +static void +gtk_style_context_disconnect_update (GtkStyleContext *context) { - GtkStyleContextPrivate *priv; - AnimationInfo *info; - GSList *l; - - priv = context->priv; + GtkStyleContextPrivate *priv = context->priv; - for (l = priv->animations; l; l = l->next) + if (priv->frame_clock && priv->frame_clock_update_id) { - info = l->data; - - if (info->timeline == timeline) - return info; + 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 NULL; } static void -timeline_frame_cb (GtkTimeline *timeline, - gdouble progress, - gpointer user_data) +gtk_style_context_connect_update (GtkStyleContext *context) { - GtkStyleContextPrivate *priv; - GtkStyleContext *context; - AnimationInfo *info; - - context = user_data; - priv = context->priv; - info = animation_info_lookup_by_timeline (context, timeline); - - g_assert (info != NULL); + GtkStyleContextPrivate *priv = context->priv; - /* Cancel transition if window is gone */ - if (gdk_window_is_destroyed (info->window) || - !gdk_window_is_visible (info->window)) + if (priv->frame_clock && priv->frame_clock_update_id == 0) { - priv->animations = g_slist_remove (priv->animations, info); - animation_info_free (info); - return; + 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); } - - if (info->invalidation_region && - !cairo_region_is_empty (info->invalidation_region)) - gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE); - else - gdk_window_invalidate_rect (info->window, NULL, TRUE); } static void -timeline_finished_cb (GtkTimeline *timeline, - gpointer user_data) +gtk_style_context_stop_animating (GtkStyleContext *context) { - GtkStyleContextPrivate *priv; - GtkStyleContext *context; - AnimationInfo *info; - - context = user_data; - priv = context->priv; - info = animation_info_lookup_by_timeline (context, timeline); - - g_assert (info != NULL); + GtkStyleContextPrivate *priv = context->priv; - priv->animations = g_slist_remove (priv->animations, info); + if (!gtk_style_context_is_animating (context)) + return; - /* Invalidate one last time the area, so the final content is painted */ - if (info->invalidation_region && - !cairo_region_is_empty (info->invalidation_region)) - gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE); - else - gdk_window_invalidate_rect (info->window, NULL, TRUE); + priv->animating = FALSE; - animation_info_free (info); + gtk_style_context_disconnect_update (context); } -static AnimationInfo * -animation_info_new (GtkStyleContext *context, - gpointer region_id, - guint duration, - GtkTimelineProgressType progress_type, - gboolean loop, - GtkStateType state, - gboolean target_value, - GdkWindow *window) +static void +gtk_style_context_start_animating (GtkStyleContext *context) { - AnimationInfo *info; - - info = g_slice_new0 (AnimationInfo); - - info->rectangles = g_array_new (FALSE, FALSE, sizeof (cairo_rectangle_int_t)); - info->timeline = _gtk_timeline_new (duration); - info->window = g_object_ref (window); - info->state = state; - info->target_value = target_value; - info->region_id = region_id; - - _gtk_timeline_set_progress_type (info->timeline, progress_type); - _gtk_timeline_set_loop (info->timeline, loop); - - if (!loop && !target_value) - { - _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD); - _gtk_timeline_rewind (info->timeline); - } + GtkStyleContextPrivate *priv = context->priv; - g_signal_connect (info->timeline, "frame", - G_CALLBACK (timeline_frame_cb), context); - g_signal_connect (info->timeline, "finished", - G_CALLBACK (timeline_finished_cb), context); + if (gtk_style_context_is_animating (context)) + return; - _gtk_timeline_start (info->timeline); + priv->animating = TRUE; - return info; + gtk_style_context_connect_update (context); } -static AnimationInfo * -animation_info_lookup (GtkStyleContext *context, - gpointer region_id, - GtkStateType state) +static gboolean +gtk_style_context_should_animate (GtkStyleContext *context) { GtkStyleContextPrivate *priv; - GSList *l; + StyleData *data; + gboolean animate; priv = context->priv; - for (l = priv->animations; l; l = l->next) - { - AnimationInfo *info; + if (priv->widget == NULL) + return FALSE; - info = l->data; + if (!gtk_widget_get_mapped (priv->widget)) + return FALSE; - if (info->state == state && - info->region_id == region_id) - return info; - } + data = style_data_lookup (context); + if (!style_data_is_animating (data)) + return FALSE; - return NULL; + 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 + gtk_style_context_stop_animating (context); } static void @@ -814,34 +844,26 @@ gtk_style_context_finalize (GObject *object) { GtkStyleContextPrivate *priv; GtkStyleContext *style_context; - GSList *l; style_context = GTK_STYLE_CONTEXT (object); priv = style_context->priv; + gtk_style_context_stop_animating (style_context); + /* children hold a reference to us */ g_assert (priv->children == NULL); gtk_style_context_set_parent (style_context, NULL); + gtk_style_context_set_cascade (style_context, NULL); + if (priv->widget_path) gtk_widget_path_free (priv->widget_path); g_hash_table_destroy (priv->style_data); - g_object_unref (priv->cascade); - - g_slist_free_full (priv->info_stack, (GDestroyNotify) style_info_free); - - g_slist_free (priv->animation_regions); - - for (l = priv->animations; l; l = l->next) - animation_info_free ((AnimationInfo *) l->data); - - g_slist_free (priv->animations); - - if (priv->theming_engine) - g_object_unref (priv->theming_engine); + while (priv->info) + priv->info = style_info_pop (priv->info); G_OBJECT_CLASS (gtk_style_context_parent_class)->finalize (object); } @@ -863,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, @@ -894,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); @@ -905,44 +938,18 @@ gtk_style_context_impl_get_property (GObject *object, } } -static void -build_properties (GtkStyleContext *context, - StyleData *style_data, - GtkWidgetPath *path, - GtkStateFlags state) -{ - GtkStyleContextPrivate *priv; - GtkCssMatcher matcher; - GtkCssLookup *lookup; - - priv = context->priv; - - _gtk_css_matcher_init (&matcher, path, state); - lookup = _gtk_css_lookup_new (); - - _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), - &matcher, - lookup); - - style_data->store = _gtk_css_computed_values_new (); - _gtk_css_lookup_resolve (lookup, context, style_data->store); - _gtk_css_lookup_free (lookup); -} - 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 = gtk_widget_path_copy (priv->widget ? gtk_widget_get_path (priv->widget) : priv->widget_path); + 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_stack->data; - /* Set widget regions */ for (i = 0; i < info->regions->len; i++) { @@ -967,62 +974,84 @@ create_query_path (GtkStyleContext *context) return path; } +static void +build_properties (GtkStyleContext *context, + GtkCssComputedValues *values, + GtkStyleInfo *info, + const GtkBitmask *relevant_changes) +{ + GtkStyleContextPrivate *priv; + GtkCssMatcher matcher; + GtkWidgetPath *path; + GtkCssLookup *lookup; + + priv = context->priv; + + path = create_query_path (context, info); + lookup = _gtk_css_lookup_new (relevant_changes); + + 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, + 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); +} + static StyleData * -style_data_lookup (GtkStyleContext *context, - GtkStateFlags state) +style_data_lookup (GtkStyleContext *context) { GtkStyleContextPrivate *priv; + GtkStyleInfo *info; StyleData *data; - gboolean state_mismatch; - GtkCssValue *v; priv = context->priv; - state_mismatch = ((GtkStyleInfo *) priv->info_stack->data)->state_flags != state; + info = priv->info; /* Current data in use is cached, just return it */ - if (priv->current_data && priv->current_state == state) - return priv->current_data; + if (info->data) + return info->data; g_assert (priv->widget != NULL || priv->widget_path != NULL); - if (G_UNLIKELY (state_mismatch)) + data = g_hash_table_lookup (priv->style_data, info); + if (data) { - gtk_style_context_save (context); - gtk_style_context_set_state (context, state); + style_info_set_data (info, data); + return data; } - priv->current_data = g_hash_table_lookup (priv->style_data, priv->info_stack->data); - priv->current_state = state; + data = style_data_new (); + data->store = _gtk_css_computed_values_new (); + style_info_set_data (info, data); + g_hash_table_insert (priv->style_data, + style_info_copy (info), + data); - if (!priv->current_data) - { - GtkWidgetPath *path; - - path = create_query_path (context); - - priv->current_data = style_data_new (); - g_hash_table_insert (priv->style_data, - style_info_copy (priv->info_stack->data), - priv->current_data); - - build_properties (context, priv->current_data, path, state); + build_properties (context, data->store, info, NULL); - gtk_widget_path_free (path); - } - - data = priv->current_data; + return data; +} - if (priv->theming_engine) - g_object_unref (priv->theming_engine); +static StyleData * +style_data_lookup_for_state (GtkStyleContext *context, + GtkStateFlags state) +{ + StyleData *data; - v = _gtk_css_computed_values_get_value_by_name (priv->current_data->store, "engine"); - if (v) - priv->theming_engine = _gtk_css_value_dup_object (v); - else - priv->theming_engine = g_object_ref (gtk_theming_engine_load (NULL)); + if (context->priv->info->state_flags == state) + return style_data_lookup (context); - if (G_UNLIKELY (state_mismatch)) - gtk_style_context_restore (context); + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); + data = style_data_lookup (context); + gtk_style_context_restore (context); return data; } @@ -1042,9 +1071,9 @@ gtk_style_context_set_invalid (GtkStyleContext *context, if (invalid) { - if (priv->widget) - gtk_widget_queue_resize (priv->widget); - if (priv->parent) + if (GTK_IS_RESIZE_CONTAINER (priv->widget)) + _gtk_container_queue_restyle (GTK_CONTAINER (priv->widget)); + else if (priv->parent) gtk_style_context_set_invalid (priv->parent, TRUE); } } @@ -1057,7 +1086,7 @@ gtk_style_context_set_invalid (GtkStyleContext *context, static gboolean gtk_style_context_is_saved (GtkStyleContext *context) { - return context->priv->info_stack->next != NULL; + return context->priv->info->next != NULL; } static void @@ -1065,12 +1094,15 @@ gtk_style_context_queue_invalidate_internal (GtkStyleContext *context, GtkCssChange change) { GtkStyleContextPrivate *priv = context->priv; + GtkStyleInfo *info = priv->info; - priv->current_data = NULL; - - if (!gtk_style_context_is_saved (context)) + if (gtk_style_context_is_saved (context)) { - _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_STATE); + style_info_set_data (info, NULL); + } + else + { + _gtk_style_context_queue_invalidate (context, change); /* XXX: We need to invalidate siblings here somehow */ } } @@ -1106,6 +1138,8 @@ _gtk_style_context_set_widget (GtkStyleContext *context, context->priv->widget = widget; + _gtk_style_context_update_animating (context); + _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY_SELF); } @@ -1120,6 +1154,10 @@ _gtk_style_context_set_widget (GtkStyleContext *context, * %GTK_STYLE_PROVIDER_PRIORITY_USER * * Adds a style provider to @context, to be used in style construction. + * Note that a style provider added by this function only affects + * the style of the widget to which @context belongs. If you want + * to affect the style of all widgets, use + * gtk_style_context_add_provider_for_screen(). * * If both priorities are the same, A #GtkStyleProvider * added through this function takes precedence over another added @@ -1145,13 +1183,14 @@ gtk_style_context_add_provider (GtkStyleContext *context, new_cascade = _gtk_style_cascade_new (); _gtk_style_cascade_set_parent (new_cascade, priv->cascade); - g_object_unref (priv->cascade); - priv->cascade = new_cascade; + _gtk_style_cascade_add_provider (new_cascade, provider, priority); + gtk_style_context_set_cascade (context, new_cascade); + g_object_unref (new_cascade); + } + else + { + _gtk_style_cascade_add_provider (priv->cascade, provider, priority); } - - _gtk_style_cascade_add_provider (priv->cascade, provider, priority); - - gtk_style_context_invalidate (context); } /** @@ -1225,8 +1264,7 @@ gtk_style_context_reset_widgets (GdkScreen *screen) * %GTK_STYLE_PROVIDER_PRIORITY_USER * * Adds a global style provider to @screen, which will be used - * in style construction for all #GtkStyleContexts under - * @screen. + * in style construction for all #GtkStyleContexts under @screen. * * GTK+ uses this to make styling information from #GtkSettings * available. @@ -1246,6 +1284,7 @@ gtk_style_context_add_provider_for_screen (GdkScreen *screen, g_return_if_fail (GDK_IS_SCREEN (screen)); g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider)); + g_return_if_fail (!GTK_IS_SETTINGS (provider) || _gtk_settings_get_screen (GTK_SETTINGS (provider)) == screen); cascade = _gtk_style_cascade_get_for_screen (screen); _gtk_style_cascade_add_provider (cascade, provider, priority); @@ -1268,6 +1307,7 @@ gtk_style_context_remove_provider_for_screen (GdkScreen *screen, g_return_if_fail (GDK_IS_SCREEN (screen)); g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider)); + g_return_if_fail (!GTK_IS_SETTINGS (provider)); cascade = _gtk_style_cascade_get_for_screen (screen); _gtk_style_cascade_remove_provider (cascade, provider); @@ -1311,7 +1351,7 @@ gtk_style_context_get_section (GtkStyleContext *context, if (!GTK_IS_CSS_STYLE_PROPERTY (prop)) return NULL; - data = style_data_lookup (context, gtk_style_context_get_state (context)); + data = style_data_lookup (context); return _gtk_css_computed_values_get_section (data->store, _gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop))); } @@ -1365,7 +1405,7 @@ gtk_style_context_get_property (GtkStyleContext *context, return; } - data = style_data_lookup (context, state); + data = style_data_lookup_for_state (context, state); _gtk_style_property_query (prop, value, gtk_style_context_query_func, data->store); } @@ -1453,14 +1493,18 @@ void gtk_style_context_set_state (GtkStyleContext *context, GtkStateFlags flags) { - GtkStyleContextPrivate *priv; - GtkStyleInfo *info; - + GtkStateFlags old_flags; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - priv = context->priv; - info = priv->info_stack->data; - info->state_flags = flags; + 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); } @@ -1478,31 +1522,9 @@ gtk_style_context_set_state (GtkStyleContext *context, GtkStateFlags gtk_style_context_get_state (GtkStyleContext *context) { - GtkStyleContextPrivate *priv; - GtkStyleInfo *info; - g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0); - priv = context->priv; - info = priv->info_stack->data; - - return info->state_flags; -} - -static gboolean -context_has_animatable_region (GtkStyleContext *context, - gpointer region_id) -{ - GtkStyleContextPrivate *priv; - - /* NULL region_id means everything - * rendered through the style context - */ - if (!region_id) - return TRUE; - - priv = context->priv; - return g_slist_find (priv->animation_regions, region_id) != NULL; + return context->priv->info->state_flags; } /** @@ -1523,34 +1545,16 @@ context_has_animatable_region (GtkStyleContext *context, * Returns: %TRUE if there is a running transition animation for @state. * * Since: 3.0 + * + * Deprecated: 3.6: This function always returns %FALSE **/ gboolean gtk_style_context_state_is_running (GtkStyleContext *context, GtkStateType state, gdouble *progress) { - GtkStyleContextPrivate *priv; - AnimationInfo *info; - GSList *l; - g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE); - priv = context->priv; - - for (l = priv->animations; l; l = l->next) - { - info = l->data; - - if (info->state == state && - context_has_animatable_region (context, info->region_id)) - { - if (progress) - *progress = _gtk_timeline_get_progress (info->timeline); - - return TRUE; - } - } - return FALSE; } @@ -1699,16 +1703,17 @@ void gtk_style_context_save (GtkStyleContext *context) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); priv = context->priv; - g_assert (priv->info_stack != NULL); - - info = style_info_copy (priv->info_stack->data); - priv->info_stack = g_slist_prepend (priv->info_stack, info); + priv->info = style_info_copy (priv->info); + /* Need to unset animations here because we can not know what style + * class potential transitions came from once we save(). + */ + if (priv->info->data && style_data_is_animating (priv->info->data)) + style_info_set_data (priv->info, NULL); } /** @@ -1724,29 +1729,20 @@ void gtk_style_context_restore (GtkStyleContext *context) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); priv = context->priv; - if (priv->info_stack) - { - info = priv->info_stack->data; - priv->info_stack = g_slist_remove (priv->info_stack, info); - style_info_free (info); - } + priv->info = style_info_pop (priv->info); - if (!priv->info_stack) + if (!priv->info) { g_warning ("Unpaired gtk_style_context_restore() call"); /* Create default region */ - info = style_info_new (); - priv->info_stack = g_slist_prepend (priv->info_stack, info); + priv->info = style_info_new (); } - - priv->current_data = NULL; } static gboolean @@ -1880,8 +1876,7 @@ gtk_style_context_add_class (GtkStyleContext *context, priv = context->priv; class_quark = g_quark_from_string (class_name); - g_assert (priv->info_stack != NULL); - info = priv->info_stack->data; + info = priv->info; if (!style_class_find (info->style_classes, class_quark, &position)) { @@ -1919,8 +1914,7 @@ gtk_style_context_remove_class (GtkStyleContext *context, priv = context->priv; - g_assert (priv->info_stack != NULL); - info = priv->info_stack->data; + info = priv->info; if (style_class_find (info->style_classes, class_quark, &position)) { @@ -1960,8 +1954,7 @@ gtk_style_context_has_class (GtkStyleContext *context, priv = context->priv; - g_assert (priv->info_stack != NULL); - info = priv->info_stack->data; + info = priv->info; if (style_class_find (info->style_classes, class_quark, NULL)) return TRUE; @@ -1994,8 +1987,7 @@ gtk_style_context_list_classes (GtkStyleContext *context) priv = context->priv; - g_assert (priv->info_stack != NULL); - info = priv->info_stack->data; + info = priv->info; for (i = 0; i < info->style_classes->len; i++) { @@ -2033,8 +2025,7 @@ gtk_style_context_list_regions (GtkStyleContext *context) priv = context->priv; - g_assert (priv->info_stack != NULL); - info = priv->info_stack->data; + info = priv->info; for (i = 0; i < info->regions->len; i++) { @@ -2118,8 +2109,7 @@ gtk_style_context_add_region (GtkStyleContext *context, priv = context->priv; region_quark = g_quark_from_string (region_name); - g_assert (priv->info_stack != NULL); - info = priv->info_stack->data; + info = priv->info; if (!region_find (info->regions, region_quark, &position)) { @@ -2162,8 +2152,7 @@ gtk_style_context_remove_region (GtkStyleContext *context, priv = context->priv; - g_assert (priv->info_stack != NULL); - info = priv->info_stack->data; + info = priv->info; if (region_find (info->regions, region_quark, &position)) { @@ -2210,8 +2199,7 @@ gtk_style_context_has_region (GtkStyleContext *context, priv = context->priv; - g_assert (priv->info_stack != NULL); - info = priv->info_stack->data; + info = priv->info; if (region_find (info->regions, region_quark, &position)) { @@ -2249,22 +2237,11 @@ style_property_values_cmp (gconstpointer bsearch_node1, GtkCssValue * _gtk_style_context_peek_property (GtkStyleContext *context, - const char *property_name) + guint property_id) { - StyleData *data = style_data_lookup (context, gtk_style_context_get_state (context)); + StyleData *data = style_data_lookup (context); - return _gtk_css_computed_values_get_value_by_name (data->store, property_name); -} - -double -_gtk_style_context_get_number (GtkStyleContext *context, - const char *property_name, - double one_hundred_percent) -{ - GtkCssValue *value; - - value = _gtk_style_context_peek_property (context, property_name); - return _gtk_css_number_get (_gtk_css_value_get_number (value), one_hundred_percent); + return _gtk_css_computed_values_get_value (data->store, property_id); } const GValue * @@ -2279,7 +2256,8 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context, guint i; priv = context->priv; - data = style_data_lookup (context, state); + + data = style_data_lookup_for_state (context, state); key.widget_type = widget_type; key.state = state; @@ -2311,11 +2289,14 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context, if (priv->widget || priv->widget_path) { + GtkWidgetPath *widget_path = priv->widget ? _gtk_widget_create_path (priv->widget) : priv->widget_path; + if (gtk_style_provider_get_style_property (GTK_STYLE_PROVIDER (priv->cascade), - priv->widget ? gtk_widget_get_path (priv->widget) - : priv->widget_path, + 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) { @@ -2331,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); @@ -2352,8 +2333,16 @@ _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); + return &pcache->value; } + + if (priv->widget) + gtk_widget_path_free (widget_path); } /* not supplied by any provider, revert to default */ @@ -2605,9 +2594,7 @@ gtk_style_context_set_screen (GtkStyleContext *context, if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen)) { - g_object_unref (priv->cascade); - priv->cascade = _gtk_style_cascade_get_for_screen (screen); - g_object_ref (priv->cascade); + gtk_style_context_set_cascade (context, _gtk_style_cascade_get_for_screen (screen)); } else { @@ -2617,8 +2604,6 @@ gtk_style_context_set_screen (GtkStyleContext *context, priv->screen = screen; g_object_notify (G_OBJECT (context), "screen"); - - gtk_style_context_invalidate (context); } /** @@ -2640,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 @@ -2652,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); - 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); } /** @@ -2676,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; } /** @@ -2710,14 +2788,9 @@ void gtk_style_context_set_junction_sides (GtkStyleContext *context, GtkJunctionSides sides) { - GtkStyleContextPrivate *priv; - GtkStyleInfo *info; - g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - priv = context->priv; - info = priv->info_stack->data; - info->junction_sides = sides; + context->priv->info->junction_sides = sides; } /** @@ -2733,42 +2806,16 @@ gtk_style_context_set_junction_sides (GtkStyleContext *context, GtkJunctionSides gtk_style_context_get_junction_sides (GtkStyleContext *context) { - GtkStyleContextPrivate *priv; - GtkStyleInfo *info; - g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0); - priv = context->priv; - info = priv->info_stack->data; - return 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, - GtkSymbolicColor *color) -{ - g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE); - g_return_val_if_fail (color != NULL, FALSE); - - return _gtk_symbolic_color_resolve_full (color, - gtk_style_context_color_lookup_func, - context); + return context->priv->info->junction_sides; } - 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; @@ -2776,13 +2823,15 @@ _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_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; - *result = *_gtk_css_value_get_rgba (val); + *result = *_gtk_css_rgba_value_get_rgba (val); _gtk_css_value_unref (val); return TRUE; } @@ -2802,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); } /** @@ -2867,105 +2916,20 @@ gtk_style_context_lookup_color (GtkStyleContext *context, * is why the style places the transition under the :hover pseudo-class. * * Since: 3.0 + * + * Deprecated: 3.6: This function does nothing. **/ void gtk_style_context_notify_state_change (GtkStyleContext *context, GdkWindow *window, - gpointer region_id, - GtkStateType state, - gboolean state_value) -{ - GtkStyleContextPrivate *priv; - GtkAnimationDescription *desc; - AnimationInfo *info; - GtkStateFlags flags; - GtkCssValue *v; - StyleData *data; - - g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - g_return_if_fail (GDK_IS_WINDOW (window)); - g_return_if_fail (state > GTK_STATE_NORMAL && state <= GTK_STATE_FOCUSED); - - priv = context->priv; - g_return_if_fail (priv->widget != NULL || priv->widget_path != NULL); - - state_value = (state_value == TRUE); - - switch (state) - { - case GTK_STATE_ACTIVE: - flags = GTK_STATE_FLAG_ACTIVE; - break; - case GTK_STATE_PRELIGHT: - flags = GTK_STATE_FLAG_PRELIGHT; - break; - case GTK_STATE_SELECTED: - flags = GTK_STATE_FLAG_SELECTED; - break; - case GTK_STATE_INSENSITIVE: - flags = GTK_STATE_FLAG_INSENSITIVE; - break; - case GTK_STATE_INCONSISTENT: - flags = GTK_STATE_FLAG_INCONSISTENT; - break; - case GTK_STATE_FOCUSED: - flags = GTK_STATE_FLAG_FOCUSED; - break; - case GTK_STATE_NORMAL: - default: - flags = 0; - break; - } - - /* Find out if there is any animation description for the given - * state, it will fallback to the normal state as well if necessary. - */ - data = style_data_lookup (context, flags); - v = _gtk_css_computed_values_get_value_by_name (data->store, "transition"); - if (!v) - return; - desc = _gtk_css_value_get_boxed (v); - if (!desc) - return; - - if (_gtk_animation_description_get_duration (desc) == 0) - return; - - info = animation_info_lookup (context, region_id, state); - - if (info && - info->target_value != state_value) - { - /* Target values are the opposite */ - if (!_gtk_timeline_get_loop (info->timeline)) - { - /* Reverse the animation */ - if (_gtk_timeline_get_direction (info->timeline) == GTK_TIMELINE_DIRECTION_FORWARD) - _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD); - else - _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_FORWARD); - - info->target_value = state_value; - } - else - { - /* Take it out of its looping state */ - _gtk_timeline_set_loop (info->timeline, FALSE); - } - } - else if (!info && - (!_gtk_animation_description_get_loop (desc) || - state_value)) - { - info = animation_info_new (context, region_id, - _gtk_animation_description_get_duration (desc), - _gtk_animation_description_get_progress_type (desc), - _gtk_animation_description_get_loop (desc), - state, state_value, window); - - priv->animations = g_slist_prepend (priv->animations, info); - priv->animations_invalidated = TRUE; - } + gpointer region_id, + GtkStateType state, + gboolean state_value) +{ + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (state > GTK_STATE_NORMAL && state <= GTK_STATE_FOCUSED); + g_return_if_fail (context->priv->widget != NULL || context->priv->widget_path != NULL); } /** @@ -2985,60 +2949,14 @@ gtk_style_context_notify_state_change (GtkStyleContext *context, * animatable regions. * * Since: 3.0 + * + * Deprecated: 3.6: This function does nothing. **/ void gtk_style_context_cancel_animations (GtkStyleContext *context, gpointer region_id) { - GtkStyleContextPrivate *priv; - AnimationInfo *info; - GSList *l; - g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - - priv = context->priv; - l = priv->animations; - - while (l) - { - info = l->data; - l = l->next; - - if (!region_id || - info->region_id == region_id || - g_slist_find (info->parent_regions, region_id)) - { - priv->animations = g_slist_remove (priv->animations, info); - animation_info_free (info); - } - } -} - -static gboolean -is_parent_of (GdkWindow *parent, - GdkWindow *child) -{ - GtkWidget *child_widget, *parent_widget; - GdkWindow *window; - - gdk_window_get_user_data (child, (gpointer *) &child_widget); - gdk_window_get_user_data (parent, (gpointer *) &parent_widget); - - if (child_widget != parent_widget && - !gtk_widget_is_ancestor (child_widget, parent_widget)) - return FALSE; - - window = child; - - while (window) - { - if (window == parent) - return TRUE; - - window = gdk_window_get_parent (window); - } - - return FALSE; } /** @@ -3055,6 +2973,8 @@ is_parent_of (GdkWindow *parent, * with it. * * Since: 3.0 + * + * Deprecated: 3.6: This function does nothing. **/ void gtk_style_context_scroll_animations (GtkStyleContext *context, @@ -3062,26 +2982,8 @@ gtk_style_context_scroll_animations (GtkStyleContext *context, gint dx, gint dy) { - GtkStyleContextPrivate *priv; - AnimationInfo *info; - GSList *l; - g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (GDK_IS_WINDOW (window)); - - priv = context->priv; - l = priv->animations; - - while (l) - { - info = l->data; - l = l->next; - - if (info->invalidation_region && - (window == info->window || - is_parent_of (window, info->window))) - cairo_region_translate (info->invalidation_region, dx, dy); - } } /** @@ -3100,18 +3002,15 @@ gtk_style_context_scroll_animations (GtkStyleContext *context, * can uniquely identify rendered elements subject to a state transition. * * Since: 3.0 + * + * Deprecated: 3.6: This function does nothing. **/ void gtk_style_context_push_animatable_region (GtkStyleContext *context, gpointer region_id) { - GtkStyleContextPrivate *priv; - g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (region_id != NULL); - - priv = context->priv; - priv->animation_regions = g_slist_prepend (priv->animation_regions, region_id); } /** @@ -3122,182 +3021,169 @@ gtk_style_context_push_animatable_region (GtkStyleContext *context, * See gtk_style_context_push_animatable_region(). * * Since: 3.0 + * + * Deprecated: 3.6: This function does nothing. **/ void gtk_style_context_pop_animatable_region (GtkStyleContext *context) { - GtkStyleContextPrivate *priv; - g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - - priv = context->priv; - priv->animation_regions = g_slist_delete_link (priv->animation_regions, - priv->animation_regions); } -void -_gtk_style_context_invalidate_animation_areas (GtkStyleContext *context) +static void +gtk_style_context_clear_cache (GtkStyleContext *context) { GtkStyleContextPrivate *priv; - GSList *l; + GtkStyleInfo *info; priv = context->priv; - for (l = priv->animations; l; l = l->next) + for (info = priv->info; info; info = info->next) { - AnimationInfo *info; - - info = l->data; - - /* A NULL invalidation region means it has to be recreated on - * the next expose event, this happens usually after a widget - * allocation change, so the next expose after it will update - * the invalidation region. - */ - if (info->invalidation_region) - { - cairo_region_destroy (info->invalidation_region); - info->invalidation_region = NULL; - } + style_info_set_data (info, NULL); } - - priv->animations_invalidated = TRUE; + g_hash_table_remove_all (priv->style_data); } -void -_gtk_style_context_coalesce_animation_areas (GtkStyleContext *context, - GtkWidget *widget) +static void +gtk_style_context_update_cache (GtkStyleContext *context, + const GtkBitmask *parent_changes) { GtkStyleContextPrivate *priv; - GSList *l; - - priv = context->priv; + GHashTableIter iter; + gpointer key, value; - if (!priv->animations_invalidated) + if (_gtk_bitmask_is_empty (parent_changes)) return; - l = priv->animations; + priv = context->priv; - while (l) + g_hash_table_iter_init (&iter, priv->style_data); + while (g_hash_table_iter_next (&iter, &key, &value)) { - AnimationInfo *info; - gint rel_x, rel_y; - GSList *cur; - guint i; + GtkStyleInfo *info = key; + StyleData *data = value; + GtkBitmask *changes; - cur = l; - info = cur->data; - l = l->next; + changes = _gtk_css_computed_values_compute_dependencies (data->store, parent_changes); - if (info->invalidation_region) - continue; + if (!_gtk_bitmask_is_empty (changes)) + build_properties (context, data->store, info, changes); - if (info->rectangles->len == 0) - continue; - - info->invalidation_region = cairo_region_create (); - _gtk_widget_get_translation_to_window (widget, info->window, &rel_x, &rel_y); - - for (i = 0; i < info->rectangles->len; i++) - { - cairo_rectangle_int_t *rect; - - rect = &g_array_index (info->rectangles, cairo_rectangle_int_t, i); - - /* These are widget relative coordinates, - * so have them inverted to be window relative - */ - rect->x -= rel_x; - rect->y -= rel_y; - - cairo_region_union_rectangle (info->invalidation_region, rect); - } - - g_array_remove_range (info->rectangles, 0, info->rectangles->len); + _gtk_bitmask_free (changes); } - - priv->animations_invalidated = FALSE; } static void -store_animation_region (GtkStyleContext *context, - gdouble x, - gdouble y, - gdouble width, - gdouble height) +gtk_style_context_do_invalidate (GtkStyleContext *context, + const GtkBitmask *changes) { GtkStyleContextPrivate *priv; - GSList *l; + + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); priv = context->priv; - if (!priv->animations_invalidated) + /* Avoid reentrancy */ + if (priv->invalidating_context) return; - for (l = priv->animations; l; l = l->next) - { - AnimationInfo *info; + priv->invalidating_context = changes; + + g_signal_emit (context, signals[CHANGED], 0); - info = l->data; + priv->invalidating_context = NULL; +} - /* The animation doesn't need updating - * the invalidation area, bail out. - */ - if (info->invalidation_region) - continue; +static GtkBitmask * +gtk_style_context_update_animations (GtkStyleContext *context, + gint64 timestamp) +{ + GtkBitmask *differences; + StyleData *style_data; + + style_data = style_data_lookup (context); - if (context_has_animatable_region (context, info->region_id)) - { - cairo_rectangle_int_t rect; + differences = _gtk_css_computed_values_advance (style_data->store, + timestamp); - rect.x = (gint) x; - rect.y = (gint) y; - rect.width = (gint) width; - rect.height = (gint) height; + if (_gtk_css_computed_values_is_static (style_data->store)) + _gtk_style_context_update_animating (context); - g_array_append_val (info->rectangles, rect); + return differences; +} - if (!info->parent_regions) - { - GSList *parent_regions; +static gboolean +gtk_style_context_needs_full_revalidate (GtkStyleContext *context, + GtkCssChange change) +{ + GtkStyleContextPrivate *priv = context->priv; + + /* Try to avoid invalidating if we can */ + if (change & GTK_STYLE_CONTEXT_RADICAL_CHANGE) + { + priv->relevant_changes = GTK_CSS_CHANGE_ANY; + } + else + { + if (priv->relevant_changes == GTK_CSS_CHANGE_ANY) + { + GtkWidgetPath *path; + GtkCssMatcher matcher, superset; - parent_regions = g_slist_find (priv->animation_regions, info->region_id); - info->parent_regions = g_slist_copy (parent_regions); + path = create_query_path (context, priv->info); + if (_gtk_css_matcher_init (&matcher, path, priv->info->state_flags)) + { + _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; + + priv->relevant_changes &= ~GTK_STYLE_CONTEXT_RADICAL_CHANGE; + + gtk_widget_path_unref (path); } } + + if (priv->relevant_changes & change) + return TRUE; + else + return FALSE; } -static void -gtk_style_context_do_invalidate (GtkStyleContext *context, - gboolean clear_caches) +static gboolean +gtk_style_context_should_create_transitions (GtkStyleContext *context) { GtkStyleContextPrivate *priv; - - g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); + gboolean animate; priv = context->priv; - /* Avoid reentrancy */ - if (priv->invalidating_context) - return; - - priv->invalidating_context = TRUE; + if (priv->widget == NULL) + return FALSE; - if (clear_caches) - g_hash_table_remove_all (priv->style_data); - priv->current_data = NULL; + if (!gtk_widget_get_mapped (priv->widget)) + return FALSE; - g_signal_emit (context, signals[CHANGED], 0); + g_object_get (gtk_widget_get_settings (context->priv->widget), + "gtk-enable-animations", &animate, + NULL); - priv->invalidating_context = FALSE; + return animate; } void -_gtk_style_context_validate (GtkStyleContext *context, - GtkCssChange change) +_gtk_style_context_validate (GtkStyleContext *context, + gint64 timestamp, + GtkCssChange change, + const GtkBitmask *parent_changes) { GtkStyleContextPrivate *priv; + GtkStyleInfo *info; + StyleData *current; + GtkBitmask *changes; GSList *list; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); @@ -3305,48 +3191,117 @@ _gtk_style_context_validate (GtkStyleContext *context, priv = context->priv; change |= priv->pending_changes; + + /* If you run your application with + * GTK_DEBUG=no-css-cache + * every invalidation will purge the cache and completely query + * everything anew form the cache. This is slow (in particular + * when animating), but useful for figuring out bugs. + * + * We achieve that by pretending that everything that could have + * changed has and so we of course totally need to redo everything. + * + * Note that this also completely revalidates child widgets all + * the time. + */ + if (G_UNLIKELY (gtk_get_debug_flags () & GTK_DEBUG_NO_CSS_CACHE)) + change = GTK_CSS_CHANGE_ANY; - if (!priv->invalid && change == 0) + if (!priv->invalid && change == 0 && _gtk_bitmask_is_empty (parent_changes)) return; priv->pending_changes = 0; gtk_style_context_set_invalid (context, FALSE); - /* Try to avoid invalidating if we can */ - if (change & GTK_STYLE_CONTEXT_RADICAL_CHANGE) - { - priv->relevant_changes = GTK_CSS_CHANGE_ANY; - } + info = priv->info; + if (info->data) + current = style_data_ref (info->data); else + current = NULL; + + /* Try to avoid invalidating if we can */ + if (current == NULL || + gtk_style_context_needs_full_revalidate (context, change)) { - if (priv->relevant_changes == GTK_CSS_CHANGE_ANY) + StyleData *data; + + if ((priv->relevant_changes & change) & ~GTK_STYLE_CONTEXT_CACHED_CHANGE) { - GtkWidgetPath *path; - GtkCssMatcher matcher; + gtk_style_context_clear_cache (context); + } + else + { + gtk_style_context_update_cache (context, parent_changes); + style_info_set_data (info, NULL); + } - path = create_query_path (context); - _gtk_css_matcher_init (&matcher, path, priv->current_state); + data = style_data_lookup (context); - priv->relevant_changes = _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), - &matcher); - priv->relevant_changes &= ~GTK_STYLE_CONTEXT_RADICAL_CHANGE; + _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); - gtk_widget_path_unref (path); + if (current) + { + changes = _gtk_css_computed_values_get_difference (data->store, current->store); + + /* In the case where we keep the cache, we want unanimated values */ + _gtk_css_computed_values_cancel_animations (current->store); + } + else + { + changes = _gtk_bitmask_new (); + changes = _gtk_bitmask_invert_range (changes, 0, _gtk_css_style_property_get_n_properties ()); } } + else + { + changes = _gtk_css_computed_values_compute_dependencies (current->store, parent_changes); + + gtk_style_context_update_cache (context, parent_changes); + } - if (priv->relevant_changes & change) + if (current) + style_data_unref (current); + + if (change & GTK_CSS_CHANGE_ANIMATE && + gtk_style_context_is_animating (context)) { - gboolean clear_cache = ((priv->relevant_changes & change) & ~GTK_STYLE_CONTEXT_CACHED_CHANGE) != 0; + GtkBitmask *animation_changes; - gtk_style_context_do_invalidate (context, clear_cache); + animation_changes = gtk_style_context_update_animations (context, timestamp); + changes = _gtk_bitmask_union (changes, animation_changes); + _gtk_bitmask_free (animation_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) { - _gtk_style_context_validate (list->data, change); + _gtk_style_context_validate (list->data, timestamp, change, changes); } + + _gtk_bitmask_free (changes); } void @@ -3360,11 +3315,15 @@ _gtk_style_context_queue_invalidate (GtkStyleContext *context, priv = context->priv; - if (priv->widget == NULL && priv->widget_path == NULL) - return; - - priv->pending_changes |= change; - gtk_style_context_set_invalid (context, TRUE); + if (priv->widget != NULL) + { + priv->pending_changes |= change; + gtk_style_context_set_invalid (context, TRUE); + } + else if (priv->widget_path == NULL) + { + gtk_style_context_invalidate (context); + } } /** @@ -3383,9 +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_do_invalidate (context, TRUE); + gtk_style_context_clear_cache (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; } /** @@ -3402,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); } } @@ -3636,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, @@ -3643,26 +3623,35 @@ 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); priv = context->priv; g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL); - data = style_data_lookup (context, state); + data = style_data_lookup_for_state (context, state); /* 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; } @@ -3748,8 +3737,8 @@ gtk_render_check (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3757,15 +3746,14 @@ gtk_render_check (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, x, y, width, height); - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_check (priv->theming_engine, cr, + _gtk_theming_engine_set_context (engine, context); + engine_class->render_check (engine, cr, x, y, width, height); cairo_restore (cr); @@ -3799,8 +3787,8 @@ gtk_render_option (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3808,15 +3796,13 @@ gtk_render_option (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, x, y, width, height); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_option (priv->theming_engine, cr, + _gtk_theming_engine_set_context (engine, context); + engine_class->render_option (engine, cr, x, y, width, height); cairo_restore (cr); @@ -3848,8 +3834,8 @@ gtk_render_arrow (GtkStyleContext *context, gdouble y, gdouble size) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3857,18 +3843,16 @@ gtk_render_arrow (GtkStyleContext *context, if (size <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); gtk_style_context_save (context); gtk_style_context_add_class (context, GTK_STYLE_CLASS_ARROW); - store_animation_region (context, x, y, size, size); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_arrow (priv->theming_engine, cr, + _gtk_theming_engine_set_context (engine, context); + engine_class->render_arrow (engine, cr, angle, x, y, size); gtk_style_context_restore (context); @@ -3904,8 +3888,8 @@ gtk_render_background (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3913,15 +3897,13 @@ gtk_render_background (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, x, y, width, height); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_background (priv->theming_engine, cr, x, y, width, height); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_background (engine, cr, x, y, width, height); cairo_restore (cr); } @@ -3957,8 +3939,8 @@ gtk_render_frame (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3966,15 +3948,13 @@ gtk_render_frame (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, x, y, width, height); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_frame (priv->theming_engine, cr, x, y, width, height); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_frame (engine, cr, x, y, width, height); cairo_restore (cr); } @@ -4007,8 +3987,8 @@ gtk_render_expander (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -4016,15 +3996,13 @@ gtk_render_expander (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, x, y, width, height); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_expander (priv->theming_engine, cr, x, y, width, height); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_expander (engine, cr, x, y, width, height); cairo_restore (cr); } @@ -4054,8 +4032,8 @@ gtk_render_focus (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -4063,15 +4041,13 @@ gtk_render_focus (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, x, y, width, height); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_focus (priv->theming_engine, cr, x, y, width, height); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_focus (engine, cr, x, y, width, height); cairo_restore (cr); } @@ -4095,29 +4071,23 @@ gtk_render_layout (GtkStyleContext *context, gdouble y, PangoLayout *layout) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; PangoRectangle extents; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (PANGO_IS_LAYOUT (layout)); g_return_if_fail (cr != NULL); - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); pango_layout_get_extents (layout, &extents, NULL); - store_animation_region (context, - x + extents.x, - y + extents.y, - extents.width, - extents.height); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_layout (priv->theming_engine, cr, x, y, layout); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_layout (engine, cr, x, y, layout); cairo_restore (cr); } @@ -4143,19 +4113,19 @@ gtk_render_line (GtkStyleContext *context, gdouble x1, gdouble y1) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_line (priv->theming_engine, cr, x0, y0, x1, y1); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_line (engine, cr, x0, y0, x1, y1); cairo_restore (cr); } @@ -4190,8 +4160,8 @@ gtk_render_slider (GtkStyleContext *context, gdouble height, GtkOrientation orientation) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -4199,15 +4169,13 @@ gtk_render_slider (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, x, y, width, height); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_slider (priv->theming_engine, cr, x, y, width, height, orientation); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_slider (engine, cr, x, y, width, height, orientation); cairo_restore (cr); } @@ -4247,8 +4215,8 @@ gtk_render_frame_gap (GtkStyleContext *context, gdouble xy0_gap, gdouble xy1_gap) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -4264,15 +4232,13 @@ gtk_render_frame_gap (GtkStyleContext *context, else g_return_if_fail (xy1_gap <= width); - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, x, y, width, height); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_frame_gap (priv->theming_engine, cr, + _gtk_theming_engine_set_context (engine, context); + engine_class->render_frame_gap (engine, cr, x, y, width, height, gap_side, xy0_gap, xy1_gap); @@ -4309,8 +4275,8 @@ gtk_render_extension (GtkStyleContext *context, gdouble height, GtkPositionType gap_side) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -4318,15 +4284,13 @@ gtk_render_extension (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, x, y, width, height); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_extension (priv->theming_engine, cr, x, y, width, height, gap_side); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_extension (engine, cr, x, y, width, height, gap_side); cairo_restore (cr); } @@ -4359,8 +4323,8 @@ gtk_render_handle (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -4368,15 +4332,13 @@ gtk_render_handle (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, x, y, width, height); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_handle (priv->theming_engine, cr, x, y, width, height); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_handle (engine, cr, x, y, width, height); cairo_restore (cr); } @@ -4404,8 +4366,8 @@ gtk_render_activity (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -4413,15 +4375,13 @@ gtk_render_activity (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, x, y, width, height); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_activity (priv->theming_engine, cr, x, y, width, height); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_activity (engine, cr, x, y, width, height); cairo_restore (cr); } @@ -4445,18 +4405,18 @@ gtk_render_icon_pixbuf (GtkStyleContext *context, const GtkIconSource *source, GtkIconSize size) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL); g_return_val_if_fail (source != NULL, NULL); - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); - _gtk_theming_engine_set_context (priv->theming_engine, context); - return engine_class->render_icon_pixbuf (priv->theming_engine, source, size); + _gtk_theming_engine_set_context (engine, context); + return engine_class->render_icon_pixbuf (engine, source, size); } /** @@ -4478,24 +4438,19 @@ gtk_render_icon (GtkStyleContext *context, gdouble x, gdouble y) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - store_animation_region (context, - x, y, - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf)); - - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_icon (priv->theming_engine, cr, pixbuf, x, y); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_icon (engine, cr, pixbuf, x, y); cairo_restore (cr); } @@ -4703,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, @@ -4757,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); +} +