X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkstylecontext.c;h=f5d1e86ea5a888f1a11729c50a188ad0b805d756;hb=56bcb1933f6de613e5d8689e23420d47b65425c3;hp=e0c8ebfe82d71b0bb79d5de32b19ffe6560b7514;hpb=461803e4075854c4d905bbebd1caf13658bac397;p=~andy%2Fgtk diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index e0c8ebfe8..f5d1e86ea 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,14 +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 @@ -300,11 +309,16 @@ * */ -typedef struct GtkStyleProviderData GtkStyleProviderData; +/* 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 | 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) + typedef struct GtkStyleInfo GtkStyleInfo; typedef struct GtkRegion GtkRegion; typedef struct PropertyValue PropertyValue; -typedef struct AnimationInfo AnimationInfo; typedef struct StyleData StyleData; struct GtkRegion @@ -313,12 +327,6 @@ struct GtkRegion GtkRegionFlags flags; }; -struct GtkStyleProviderData -{ - GtkStyleProvider *provider; - guint priority; -}; - struct PropertyValue { GType widget_type; @@ -329,67 +337,50 @@ struct PropertyValue struct GtkStyleInfo { + GtkStyleInfo *next; GArray *style_classes; GArray *regions; GtkJunctionSides junction_sides; GtkStateFlags state_flags; + StyleData *data; }; struct StyleData { GtkCssComputedValues *store; - GSList *icon_factories; 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 { GdkScreen *screen; - GList *providers; - GList *providers_last; + GtkStyleCascade *cascade; GtkStyleContext *parent; + GSList *children; + GtkWidget *widget; GtkWidgetPath *widget_path; GHashTable *style_data; - GSList *info_stack; - StyleData *current_data; - GtkStateFlags current_state; - - GSList *animation_regions; - GSList *animations; + GtkStyleInfo *info; - GtkThemingEngine *theming_engine; + GdkFrameClock *frame_clock; + guint frame_clock_update_id; - GtkTextDirection direction; + GtkCssChange relevant_changes; + GtkCssChange pending_changes; - guint animations_invalidated : 1; - guint invalidating_context : 1; + const GtkBitmask *invalidating_context; + guint animating : 1; + guint invalid : 1; }; enum { PROP_0, PROP_SCREEN, PROP_DIRECTION, + PROP_FRAME_CLOCK, PROP_PARENT }; @@ -400,8 +391,6 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; -static GQuark provider_list_quark = 0; - static void gtk_style_context_finalize (GObject *object); static void gtk_style_context_impl_set_property (GObject *object, @@ -412,13 +401,23 @@ 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 +gtk_style_context_real_changed (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv = context->priv; + + if (priv->widget) + _gtk_widget_style_context_invalidated (priv->widget); +} + static void gtk_style_context_class_init (GtkStyleContextClass *klass) { @@ -428,6 +427,8 @@ gtk_style_context_class_init (GtkStyleContextClass *klass) object_class->set_property = gtk_style_context_impl_set_property; object_class->get_property = gtk_style_context_impl_get_property; + klass->changed = gtk_style_context_real_changed; + signals[CHANGED] = g_signal_new (I_("changed"), G_TYPE_FROM_CLASS (object_class), @@ -444,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", @@ -471,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) { @@ -483,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; @@ -505,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; } @@ -572,52 +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; -} - -static void -style_data_free (StyleData *data) -{ - g_object_unref (data->store); - clear_property_cache (data); + if (priv->cascade) + { + g_signal_handlers_disconnect_by_func (priv->cascade, + gtk_style_context_cascade_changed, + context); + g_object_unref (priv->cascade); + } - g_slist_free_full (data->icon_factories, g_object_unref); + 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, @@ -626,192 +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->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; -static GtkStyleProviderData * -style_provider_data_new (GtkStyleProvider *provider, - guint priority) -{ - GtkStyleProviderData *data; - - data = g_slice_new (GtkStyleProviderData); - data->provider = g_object_ref (provider); - data->priority = priority; - - return data; + gtk_style_context_set_cascade (style_context, + _gtk_style_cascade_get_for_screen (priv->screen)); } static void -style_provider_data_free (GtkStyleProviderData *data) +gtk_style_context_update (GdkFrameClock *clock, + GtkStyleContext *context) { - g_object_unref (data->provider); - g_slice_free (GtkStyleProviderData, data); + _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE); } -static void -animation_info_free (AnimationInfo *info) +static gboolean +gtk_style_context_is_animating (GtkStyleContext *context) { - g_object_unref (info->timeline); - g_object_unref (info->window); - - if (info->invalidation_region) - cairo_region_destroy (info->invalidation_region); + 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 @@ -819,31 +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_list_free_full (priv->providers, (GDestroyNotify) style_provider_data_free); - - 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); } @@ -865,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, @@ -896,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); @@ -907,140 +938,18 @@ gtk_style_context_impl_get_property (GObject *object, } } -static GList * -find_next_candidate (GList *local, - GList *global) -{ - if (local && global) - { - GtkStyleProviderData *local_data, *global_data; - - local_data = local->data; - global_data = global->data; - - if (local_data->priority < global_data->priority) - return global; - else - return local; - } - else if (local) - return local; - else if (global) - return global; - - return NULL; -} - -static void -build_properties (GtkStyleContext *context, - StyleData *style_data, - GtkWidgetPath *path, - GtkStateFlags state) -{ - GtkStyleContextPrivate *priv; - GList *elem, *list, *global_list = NULL; - GtkCssLookup *lookup; - - priv = context->priv; - list = priv->providers_last; - - if (priv->screen) - { - global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark); - global_list = g_list_last (global_list); - } - - lookup = _gtk_css_lookup_new (); - - while ((elem = find_next_candidate (list, global_list)) != NULL) - { - GtkStyleProviderData *data; - GtkStyleProperties *provider_style; - - data = elem->data; - - if (elem == list) - list = list->prev; - else - global_list = global_list->prev; - - if (GTK_IS_STYLE_PROVIDER_PRIVATE (data->provider)) - { - _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (data->provider), - path, - state, - lookup); - } - else - { - provider_style = gtk_style_provider_get_style (data->provider, path); - - if (provider_style) - { - _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (provider_style), - path, - state, - lookup); - g_object_unref (provider_style); - } - } - } - - style_data->store = _gtk_css_computed_values_new (); - _gtk_css_lookup_resolve (lookup, context, style_data->store); - _gtk_css_lookup_free (lookup); -} - -static void -build_icon_factories (GtkStyleContext *context, - StyleData *style_data, - GtkWidgetPath *path) -{ - GtkStyleContextPrivate *priv; - GList *elem, *list, *global_list = NULL; - - priv = context->priv; - list = priv->providers_last; - - if (priv->screen) - { - global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark); - global_list = g_list_last (global_list); - } - - while ((elem = find_next_candidate (list, global_list)) != NULL) - { - GtkIconFactory *factory; - GtkStyleProviderData *data; - - data = elem->data; - - if (elem == list) - list = list->prev; - else - global_list = global_list->prev; - - factory = gtk_style_provider_get_icon_factory (data->provider, path); - - if (factory) - style_data->icon_factories = g_slist_prepend (style_data->icon_factories, factory); - } -} - 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_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++) { @@ -1065,141 +974,137 @@ create_query_path (GtkStyleContext *context) return path; } -static StyleData * -style_data_lookup (GtkStyleContext *context, - GtkStateFlags state) +static void +build_properties (GtkStyleContext *context, + GtkCssComputedValues *values, + GtkStyleInfo *info, + const GtkBitmask *relevant_changes) { GtkStyleContextPrivate *priv; - StyleData *data; - gboolean state_mismatch; - GtkCssValue *v; + GtkCssMatcher matcher; + GtkWidgetPath *path; + GtkCssLookup *lookup; priv = context->priv; - state_mismatch = ((GtkStyleInfo *) priv->info_stack->data)->state_flags != state; - /* Current data in use is cached, just return it */ - if (priv->current_data && priv->current_state == state) - return priv->current_data; + path = create_query_path (context, info); + lookup = _gtk_css_lookup_new (relevant_changes); - g_assert (priv->widget_path != NULL); + if (_gtk_css_matcher_init (&matcher, path, info->state_flags)) + _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), + &matcher, + lookup); - if (G_UNLIKELY (state_mismatch)) - { - gtk_style_context_save (context); - gtk_style_context_set_state (context, state); - } + _gtk_css_lookup_resolve (lookup, + GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), + values, + priv->parent ? style_data_lookup (priv->parent)->store : NULL); - priv->current_data = g_hash_table_lookup (priv->style_data, priv->info_stack->data); - priv->current_state = state; + _gtk_css_lookup_free (lookup); + gtk_widget_path_free (path); +} - if (!priv->current_data) - { - GtkWidgetPath *path; +static StyleData * +style_data_lookup (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv; + GtkStyleInfo *info; + StyleData *data; - priv->current_data = style_data_new (); - g_hash_table_insert (priv->style_data, - style_info_copy (priv->info_stack->data), - priv->current_data); + priv = context->priv; + info = priv->info; - path = create_query_path (context); + /* Current data in use is cached, just return it */ + if (info->data) + return info->data; - build_properties (context, priv->current_data, path, state); - build_icon_factories (context, priv->current_data, path); + g_assert (priv->widget != NULL || priv->widget_path != NULL); - gtk_widget_path_free (path); + data = g_hash_table_lookup (priv->style_data, info); + if (data) + { + style_info_set_data (info, data); + return data; } - data = priv->current_data; + 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->theming_engine) - g_object_unref (priv->theming_engine); - - 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 (G_UNLIKELY (state_mismatch)) - gtk_style_context_restore (context); + build_properties (context, data->store, info, NULL); return data; } -static void -style_provider_add (GList **list, - GtkStyleProvider *provider, - guint priority) +static StyleData * +style_data_lookup_for_state (GtkStyleContext *context, + GtkStateFlags state) { - GtkStyleProviderData *new_data; - gboolean added = FALSE; - GList *l = *list; - - new_data = style_provider_data_new (provider, priority); - - while (l) - { - GtkStyleProviderData *data; + StyleData *data; - data = l->data; + if (context->priv->info->state_flags == state) + return style_data_lookup (context); - /* Provider was already attached to the style - * context, remove in order to add the new data - */ - if (data->provider == provider) - { - GList *link; + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); + data = style_data_lookup (context); + gtk_style_context_restore (context); - link = l; - l = l->next; + return data; +} - /* Remove and free link */ - *list = g_list_remove_link (*list, link); - style_provider_data_free (link->data); - g_list_free_1 (link); +static void +gtk_style_context_set_invalid (GtkStyleContext *context, + gboolean invalid) +{ + GtkStyleContextPrivate *priv; + + priv = context->priv; - continue; - } + if (priv->invalid == invalid) + return; - if (!added && - data->priority > priority) - { - *list = g_list_insert_before (*list, l, new_data); - added = TRUE; - } + priv->invalid = invalid; - l = l->next; + if (invalid) + { + if (priv->parent) + gtk_style_context_set_invalid (priv->parent, TRUE); + else if (GTK_IS_RESIZE_CONTAINER (priv->widget)) + _gtk_container_queue_restyle (GTK_CONTAINER (priv->widget)); } - - if (!added) - *list = g_list_append (*list, new_data); } +/* returns TRUE if someone called gtk_style_context_save() but hasn't + * called gtk_style_context_restore() yet. + * In those situations we don't invalidate the context when somebody + * changes state/regions/classes. + */ static gboolean -style_provider_remove (GList **list, - GtkStyleProvider *provider) +gtk_style_context_is_saved (GtkStyleContext *context) { - GList *l = *list; - - while (l) - { - GtkStyleProviderData *data; - - data = l->data; - - if (data->provider == provider) - { - *list = g_list_remove_link (*list, l); - style_provider_data_free (l->data); - g_list_free_1 (l); + return context->priv->info->next != NULL; +} - return TRUE; - } +static void +gtk_style_context_queue_invalidate_internal (GtkStyleContext *context, + GtkCssChange change) +{ + GtkStyleContextPrivate *priv = context->priv; + GtkStyleInfo *info = priv->info; - l = l->next; + if (gtk_style_context_is_saved (context)) + { + style_info_set_data (info, NULL); + } + else + { + _gtk_style_context_queue_invalidate (context, change); + /* XXX: We need to invalidate siblings here somehow */ } - - return FALSE; } /** @@ -1224,6 +1129,20 @@ gtk_style_context_new (void) return g_object_new (GTK_TYPE_STYLE_CONTEXT, NULL); } +void +_gtk_style_context_set_widget (GtkStyleContext *context, + GtkWidget *widget) +{ + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); + g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget)); + + context->priv->widget = widget; + + _gtk_style_context_update_animating (context); + + _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY_SELF); +} + /** * gtk_style_context_add_provider: * @context: a #GtkStyleContext @@ -1235,6 +1154,10 @@ gtk_style_context_new (void) * %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 @@ -1253,10 +1176,21 @@ gtk_style_context_add_provider (GtkStyleContext *context, g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider)); priv = context->priv; - style_provider_add (&priv->providers, provider, priority); - priv->providers_last = g_list_last (priv->providers); - gtk_style_context_invalidate (context); + if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen)) + { + GtkStyleCascade *new_cascade; + + new_cascade = _gtk_style_cascade_new (); + _gtk_style_cascade_set_parent (new_cascade, priv->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); + } } /** @@ -1279,12 +1213,10 @@ gtk_style_context_remove_provider (GtkStyleContext *context, priv = context->priv; - if (style_provider_remove (&priv->providers, provider)) - { - priv->providers_last = g_list_last (priv->providers); + if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen)) + return; - gtk_style_context_invalidate (context); - } + _gtk_style_cascade_remove_provider (priv->cascade, provider); } /** @@ -1332,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. @@ -1349,21 +1280,14 @@ gtk_style_context_add_provider_for_screen (GdkScreen *screen, GtkStyleProvider *provider, guint priority) { - GList *providers, *list; + GtkStyleCascade *cascade; g_return_if_fail (GDK_IS_SCREEN (screen)); - g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider)); - - if (G_UNLIKELY (!provider_list_quark)) - provider_list_quark = g_quark_from_static_string ("gtk-provider-list-quark"); - - list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark); - style_provider_add (&list, provider, priority); - - if (list != providers) - g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list); + 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); - gtk_style_context_reset_widgets (screen); + cascade = _gtk_style_cascade_get_for_screen (screen); + _gtk_style_cascade_add_provider (cascade, provider, priority); } /** @@ -1379,23 +1303,14 @@ void gtk_style_context_remove_provider_for_screen (GdkScreen *screen, GtkStyleProvider *provider) { - GList *providers, *list; + GtkStyleCascade *cascade; 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)); - if (G_UNLIKELY (!provider_list_quark)) - return; - - list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark); - - if (style_provider_remove (&list, provider)) - { - if (list != providers) - g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list); - - gtk_style_context_reset_widgets (screen); - } + cascade = _gtk_style_cascade_get_for_screen (screen); + _gtk_style_cascade_remove_provider (cascade, provider); } /** @@ -1430,13 +1345,13 @@ gtk_style_context_get_section (GtkStyleContext *context, g_return_val_if_fail (property != NULL, NULL); priv = context->priv; - g_return_val_if_fail (priv->widget_path != NULL, NULL); + g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL); prop = _gtk_style_property_lookup (property); 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))); } @@ -1470,14 +1385,13 @@ gtk_style_context_get_property (GtkStyleContext *context, GtkStyleContextPrivate *priv; GtkStyleProperty *prop; StyleData *data; - GtkCssValue *v; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (property != NULL); g_return_if_fail (value != NULL); priv = context->priv; - g_return_if_fail (priv->widget_path != NULL); + g_return_if_fail (priv->widget != NULL || priv->widget_path != NULL); prop = _gtk_style_property_lookup (property); if (prop == NULL) @@ -1491,10 +1405,8 @@ gtk_style_context_get_property (GtkStyleContext *context, return; } - data = style_data_lookup (context, state); - v = _gtk_style_property_query (prop, gtk_style_context_query_func, data->store); - _gtk_css_value_init_gvalue (v, value); - _gtk_css_value_unref (v); + data = style_data_lookup_for_state (context, state); + _gtk_style_property_query (prop, value, gtk_style_context_query_func, data->store); } /** @@ -1581,14 +1493,20 @@ 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); } /** @@ -1604,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; } /** @@ -1649,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; } @@ -1705,6 +1583,7 @@ gtk_style_context_set_path (GtkStyleContext *context, g_return_if_fail (path != NULL); priv = context->priv; + g_return_if_fail (priv->widget == NULL); if (priv->widget_path) { @@ -1715,7 +1594,7 @@ gtk_style_context_set_path (GtkStyleContext *context, if (path) priv->widget_path = gtk_widget_path_copy (path); - gtk_style_context_invalidate (context); + _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY); } /** @@ -1734,7 +1613,10 @@ gtk_style_context_get_path (GtkStyleContext *context) GtkStyleContextPrivate *priv; priv = context->priv; - return priv->widget_path; + if (priv->widget) + return gtk_widget_get_path (priv->widget); + else + return priv->widget_path; } /** @@ -1767,15 +1649,23 @@ gtk_style_context_set_parent (GtkStyleContext *context, return; if (parent) - g_object_ref (parent); + { + parent->priv->children = g_slist_prepend (parent->priv->children, context); + g_object_ref (parent); + if (priv->invalid) + gtk_style_context_set_invalid (parent, TRUE); + } if (priv->parent) - g_object_unref (priv->parent); + { + priv->parent->priv->children = g_slist_remove (priv->parent->priv->children, context); + g_object_unref (priv->parent); + } priv->parent = parent; g_object_notify (G_OBJECT (context), "parent"); - gtk_style_context_invalidate (context); + _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY_PARENT | GTK_CSS_CHANGE_ANY_SIBLING); } /** @@ -1813,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); } /** @@ -1838,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 @@ -1994,15 +1876,13 @@ 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)) { g_array_insert_val (info->style_classes, position, class_quark); - /* Unset current data, as it likely changed due to the class change */ - priv->current_data = NULL; + gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS); } } @@ -2034,15 +1914,13 @@ 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)) { g_array_remove_index (info->style_classes, position); - /* Unset current data, as it likely changed due to the class change */ - priv->current_data = NULL; + gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS); } } @@ -2076,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; @@ -2110,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++) { @@ -2149,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++) { @@ -2234,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)) { @@ -2246,8 +2120,7 @@ gtk_style_context_add_region (GtkStyleContext *context, g_array_insert_val (info->regions, position, region); - /* Unset current data, as it likely changed due to the region change */ - priv->current_data = NULL; + gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION); } } @@ -2279,15 +2152,13 @@ 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)) { g_array_remove_index (info->regions, position); - /* Unset current data, as it likely changed due to the region change */ - priv->current_data = NULL; + gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION); } } @@ -2328,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)) { @@ -2367,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)); - - return _gtk_css_computed_values_get_value_by_name (data->store, property_name); -} + StyleData *data = style_data_lookup (context); -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 * @@ -2393,12 +2252,12 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context, { GtkStyleContextPrivate *priv; PropertyValue *pcache, key = { 0 }; - GList *global_list = NULL; StyleData *data; 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; @@ -2428,73 +2287,62 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context, g_param_spec_ref (pcache->pspec); g_value_init (&pcache->value, G_PARAM_SPEC_VALUE_TYPE (pspec)); - if (priv->screen) - { - global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark); - global_list = g_list_last (global_list); - } - - if (priv->widget_path) + if (priv->widget || priv->widget_path) { - GList *list, *global, *elem; + GtkWidgetPath *widget_path = priv->widget ? _gtk_widget_create_path (priv->widget) : priv->widget_path; - list = priv->providers_last; - global = global_list; - - while ((elem = find_next_candidate (list, global)) != NULL) + if (gtk_style_provider_get_style_property (GTK_STYLE_PROVIDER (priv->cascade), + widget_path, + state, pspec, &pcache->value)) { - GtkStyleProviderData *provider_data; - - provider_data = elem->data; - - if (elem == list) - list = list->prev; - else - global = global->prev; + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; - if (gtk_style_provider_get_style_property (provider_data->provider, - priv->widget_path, state, - pspec, &pcache->value)) + /* Resolve symbolic colors to GdkColor/GdkRGBA */ + if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR) { - /* Resolve symbolic colors to GdkColor/GdkRGBA */ - if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR) - { - GtkSymbolicColor *color; - GdkRGBA rgba; + GtkSymbolicColor *color; + GdkRGBA rgba; + + color = g_value_dup_boxed (&pcache->value); - color = g_value_dup_boxed (&pcache->value); + g_value_unset (&pcache->value); - g_value_unset (&pcache->value); + if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA) + g_value_init (&pcache->value, GDK_TYPE_RGBA); + else + g_value_init (&pcache->value, GDK_TYPE_COLOR); + 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_init (&pcache->value, GDK_TYPE_RGBA); + g_value_set_boxed (&pcache->value, &rgba); else - g_value_init (&pcache->value, GDK_TYPE_COLOR); - - if (_gtk_style_context_resolve_color (context, color, &rgba)) { - if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA) - g_value_set_boxed (&pcache->value, &rgba); - else - { - GdkColor rgb; - - rgb.red = rgba.red * 65535. + 0.5; - rgb.green = rgba.green * 65535. + 0.5; - rgb.blue = rgba.blue * 65535. + 0.5; - - g_value_set_boxed (&pcache->value, &rgb); - } - } - else - g_param_value_set_default (pspec, &pcache->value); + GdkColor rgb; - gtk_symbolic_color_unref (color); + rgb.red = rgba.red * 65535. + 0.5; + rgb.green = rgba.green * 65535. + 0.5; + rgb.blue = rgba.blue * 65535. + 0.5; + + g_value_set_boxed (&pcache->value, &rgb); + } } + else + g_param_value_set_default (pspec, &pcache->value); - return &pcache->value; + 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 */ @@ -2532,17 +2380,24 @@ gtk_style_context_get_style_property (GtkStyleContext *context, priv = context->priv; - if (!priv->widget_path) - return; + if (priv->widget) + { + widget_type = G_OBJECT_TYPE (priv->widget); + } + else + { + if (!priv->widget_path) + return; - widget_type = gtk_widget_path_get_object_type (priv->widget_path); + widget_type = gtk_widget_path_get_object_type (priv->widget_path); - if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET)) - { - g_warning ("%s: can't get style properties for non-widget class `%s'", - G_STRLOC, - g_type_name (widget_type)); - return; + if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET)) + { + g_warning ("%s: can't get style properties for non-widget class `%s'", + G_STRLOC, + g_type_name (widget_type)); + return; + } } widget_class = g_type_class_ref (widget_type); @@ -2597,17 +2452,24 @@ gtk_style_context_get_style_valist (GtkStyleContext *context, prop_name = va_arg (args, const gchar *); priv = context->priv; - if (!priv->widget_path) - return; + if (priv->widget) + { + widget_type = G_OBJECT_TYPE (priv->widget); + } + else + { + if (!priv->widget_path) + return; - widget_type = gtk_widget_path_get_object_type (priv->widget_path); + widget_type = gtk_widget_path_get_object_type (priv->widget_path); - if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET)) - { - g_warning ("%s: can't get style properties for non-widget class `%s'", - G_STRLOC, - g_type_name (widget_type)); - return; + if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET)) + { + g_warning ("%s: can't get style properties for non-widget class `%s'", + G_STRLOC, + g_type_name (widget_type)); + return; + } } state = gtk_style_context_get_state (context); @@ -2629,7 +2491,7 @@ gtk_style_context_get_style_valist (GtkStyleContext *context, G_STRLOC, g_type_name (widget_type), prop_name); - continue; + break; } peek_value = _gtk_style_context_peek_style_property (context, widget_type, @@ -2644,6 +2506,7 @@ gtk_style_context_get_style_valist (GtkStyleContext *context, G_VALUE_TYPE_NAME (peek_value), error); g_free (error); + break; } prop_name = va_arg (args, const gchar *); @@ -2690,28 +2553,12 @@ gtk_style_context_lookup_icon_set (GtkStyleContext *context, const gchar *stock_id) { GtkStyleContextPrivate *priv; - StyleData *data; - GSList *list; g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); g_return_val_if_fail (stock_id != NULL, NULL); priv = context->priv; - g_return_val_if_fail (priv->widget_path != NULL, NULL); - - data = style_data_lookup (context, 0); - - for (list = data->icon_factories; list; list = list->next) - { - GtkIconFactory *factory; - GtkIconSet *icon_set; - - factory = list->data; - icon_set = gtk_icon_factory_lookup (factory, stock_id); - - if (icon_set) - return icon_set; - } + g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL); return gtk_icon_factory_lookup_default (stock_id); } @@ -2745,11 +2592,18 @@ gtk_style_context_set_screen (GtkStyleContext *context, if (priv->screen == screen) return; + if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen)) + { + gtk_style_context_set_cascade (context, _gtk_style_cascade_get_for_screen (screen)); + } + else + { + _gtk_style_cascade_set_parent (priv->cascade, _gtk_style_cascade_get_for_screen (screen)); + } + priv->screen = screen; g_object_notify (G_OBJECT (context), "screen"); - - gtk_style_context_invalidate (context); } /** @@ -2771,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 @@ -2783,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); } /** @@ -2807,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; } /** @@ -2841,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; } /** @@ -2864,78 +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) -{ - GtkSymbolicColor *sym_color; - GtkStyleContext *context = contextp; - GtkStyleContextPrivate *priv = context->priv; - GList *elem, *list, *global_list = NULL; - - list = priv->providers_last; - if (priv->screen) - { - global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark); - global_list = g_list_last (global_list); - } - - sym_color = NULL; - - while (sym_color == NULL && - (elem = find_next_candidate (list, global_list)) != NULL) - { - GtkStyleProviderData *data; - - data = elem->data; - - if (elem == list) - list = list->prev; - else - global_list = global_list->prev; - - if (GTK_IS_STYLE_PROVIDER_PRIVATE (data->provider)) - { - sym_color = _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (data->provider), - name); - } - else - { - /* If somebody hits this code path, shout at them */ - sym_color = NULL; - } - } - - return sym_color; -} - -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; @@ -2943,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; } @@ -2969,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); } /** @@ -3034,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_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; - } + 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); } /** @@ -3152,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; } /** @@ -3222,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, @@ -3229,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); - } } /** @@ -3267,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); } /** @@ -3289,150 +3021,298 @@ 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)); +} + +static void +gtk_style_context_clear_cache (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv; + GtkStyleInfo *info; priv = context->priv; - priv->animation_regions = g_slist_delete_link (priv->animation_regions, - priv->animation_regions); + + for (info = priv->info; info; info = info->next) + { + style_info_set_data (info, NULL); + } + g_hash_table_remove_all (priv->style_data); } -void -_gtk_style_context_invalidate_animation_areas (GtkStyleContext *context) +static void +gtk_style_context_update_cache (GtkStyleContext *context, + const GtkBitmask *parent_changes) { GtkStyleContextPrivate *priv; - GSList *l; + GHashTableIter iter; + gpointer key, value; + + if (_gtk_bitmask_is_empty (parent_changes)) + return; priv = context->priv; - for (l = priv->animations; l; l = l->next) + g_hash_table_iter_init (&iter, priv->style_data); + while (g_hash_table_iter_next (&iter, &key, &value)) { - AnimationInfo *info; + GtkStyleInfo *info = key; + StyleData *data = value; + GtkBitmask *changes; - info = l->data; + changes = _gtk_css_computed_values_compute_dependencies (data->store, parent_changes); - /* 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; - } - } + if (!_gtk_bitmask_is_empty (changes)) + build_properties (context, data->store, info, changes); - priv->animations_invalidated = TRUE; + _gtk_bitmask_free (changes); + } } -void -_gtk_style_context_coalesce_animation_areas (GtkStyleContext *context, - GtkWidget *widget) +static void +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; - l = priv->animations; + priv->invalidating_context = changes; - while (l) - { - AnimationInfo *info; - gint rel_x, rel_y; - GSList *cur; - guint i; + g_signal_emit (context, signals[CHANGED], 0); + + priv->invalidating_context = NULL; +} + +static GtkBitmask * +gtk_style_context_update_animations (GtkStyleContext *context, + gint64 timestamp) +{ + GtkBitmask *differences; + StyleData *style_data; + + style_data = style_data_lookup (context); - cur = l; - info = cur->data; - l = l->next; + differences = _gtk_css_computed_values_advance (style_data->store, + timestamp); - if (info->invalidation_region) - continue; + if (_gtk_css_computed_values_is_static (style_data->store)) + _gtk_style_context_update_animating (context); - if (info->rectangles->len == 0) - continue; + return differences; +} - info->invalidation_region = cairo_region_create (); - _gtk_widget_get_translation_to_window (widget, info->window, &rel_x, &rel_y); +static gboolean +gtk_style_context_needs_full_revalidate (GtkStyleContext *context, + GtkCssChange change) +{ + GtkStyleContextPrivate *priv = context->priv; - for (i = 0; i < info->rectangles->len; i++) + /* 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) { - cairo_rectangle_int_t *rect; + GtkWidgetPath *path; + GtkCssMatcher matcher, superset; - rect = &g_array_index (info->rectangles, cairo_rectangle_int_t, i); + 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; - /* These are widget relative coordinates, - * so have them inverted to be window relative - */ - rect->x -= rel_x; - rect->y -= rel_y; + priv->relevant_changes &= ~GTK_STYLE_CONTEXT_RADICAL_CHANGE; - cairo_region_union_rectangle (info->invalidation_region, rect); + gtk_widget_path_unref (path); } - - g_array_remove_range (info->rectangles, 0, info->rectangles->len); } - priv->animations_invalidated = FALSE; + if (priv->relevant_changes & change) + return TRUE; + else + return FALSE; } -static void -store_animation_region (GtkStyleContext *context, - gdouble x, - gdouble y, - gdouble width, - gdouble height) +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, + GtkCssChange change, + const GtkBitmask *parent_changes) { GtkStyleContextPrivate *priv; - GSList *l; + GtkStyleInfo *info; + StyleData *current; + GtkBitmask *changes; + GSList *list; + + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); priv = context->priv; - if (!priv->animations_invalidated) + 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 && _gtk_bitmask_is_empty (parent_changes)) return; - for (l = priv->animations; l; l = l->next) - { - AnimationInfo *info; + priv->pending_changes = 0; + gtk_style_context_set_invalid (context, FALSE); - info = l->data; + info = priv->info; + if (info->data) + current = style_data_ref (info->data); + else + current = NULL; - /* The animation doesn't need updating - * the invalidation area, bail out. - */ - if (info->invalidation_region) - continue; + /* Try to avoid invalidating if we can */ + if (current == NULL || + gtk_style_context_needs_full_revalidate (context, change)) + { + StyleData *data; - if (context_has_animatable_region (context, info->region_id)) + if ((priv->relevant_changes & change) & ~GTK_STYLE_CONTEXT_CACHED_CHANGE) + { + gtk_style_context_clear_cache (context); + } + else { - cairo_rectangle_int_t rect; + gtk_style_context_update_cache (context, parent_changes); + style_info_set_data (info, NULL); + } - rect.x = (gint) x; - rect.y = (gint) y; - rect.width = (gint) width; - rect.height = (gint) height; + data = style_data_lookup (context); - g_array_append_val (info->rectangles, rect); + _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 (!info->parent_regions) - { - GSList *parent_regions; + if (current) + { + changes = _gtk_css_computed_values_get_difference (data->store, current->store); - parent_regions = g_slist_find (priv->animation_regions, info->region_id); - info->parent_regions = g_slist_copy (parent_regions); - } + /* 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 (current) + style_data_unref (current); + + if (change & GTK_CSS_CHANGE_ANIMATE && + gtk_style_context_is_animating (context)) + { + GtkBitmask *animation_changes; + + animation_changes = gtk_style_context_update_animations (context, timestamp); + changes = _gtk_bitmask_union (changes, animation_changes); + _gtk_bitmask_free (animation_changes); + } + + if (!_gtk_bitmask_is_empty (changes) || (change & GTK_CSS_CHANGE_FORCE_INVALIDATE)) + 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, timestamp, change, changes); + } + + _gtk_bitmask_free (changes); +} + +void +_gtk_style_context_queue_invalidate (GtkStyleContext *context, + GtkCssChange change) +{ + GtkStyleContextPrivate *priv; + + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); + g_return_if_fail (change != 0); + + priv = context->priv; + + 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); + } } /** @@ -3451,24 +3331,25 @@ store_animation_region (GtkStyleContext *context, void gtk_style_context_invalidate (GtkStyleContext *context) { - GtkStyleContextPrivate *priv; + GtkBitmask *changes; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - priv = context->priv; - - /* Avoid reentrancy */ - if (priv->invalidating_context) - return; - - priv->invalidating_context = TRUE; + gtk_style_context_clear_cache (context); - g_hash_table_remove_all (priv->style_data); - priv->current_data = NULL; - - g_signal_emit (context, signals[CHANGED], 0); + 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); +} - priv->invalidating_context = FALSE; +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; } /** @@ -3485,31 +3366,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); } } @@ -3719,6 +3602,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, @@ -3726,26 +3612,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_path != NULL, NULL); + 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; } @@ -3831,8 +3726,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); @@ -3840,15 +3735,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); @@ -3882,8 +3776,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); @@ -3891,15 +3785,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); @@ -3931,8 +3823,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); @@ -3940,18 +3832,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); @@ -3987,8 +3877,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); @@ -3996,15 +3886,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); } @@ -4040,8 +3928,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); @@ -4049,15 +3937,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); } @@ -4090,8 +3976,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); @@ -4099,15 +3985,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); } @@ -4137,8 +4021,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); @@ -4146,15 +4030,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); } @@ -4178,29 +4060,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); } @@ -4226,19 +4102,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); } @@ -4273,8 +4149,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); @@ -4282,15 +4158,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); } @@ -4330,8 +4204,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); @@ -4347,15 +4221,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); @@ -4392,8 +4264,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); @@ -4401,15 +4273,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); } @@ -4442,8 +4312,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); @@ -4451,15 +4321,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); } @@ -4487,8 +4355,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); @@ -4496,15 +4364,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); } @@ -4528,18 +4394,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); } /** @@ -4561,24 +4427,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); } @@ -4786,6 +4647,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, @@ -4840,3 +4721,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); +} +