X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkstylecontext.c;h=ad182f2be3967d5ac44995fb347cffe784519cd0;hb=5e2c23214564f7dcc687fa8467020eeb6b9407a9;hp=d3f3df7925453a70791a447cf51c3c9ae5535414;hpb=83be7e5dbd33a22f809dc78d4aaab951b290d710;p=~andy%2Fgtk diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index d3f3df792..ad182f2be 100644 --- a/gtk/gtkstylecontext.c +++ b/gtk/gtkstylecontext.c @@ -23,8 +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" @@ -32,14 +37,16 @@ #include "gtkwidget.h" #include "gtkwindow.h" #include "gtkprivate.h" -#include "gtksymboliccolorprivate.h" -#include "gtkcssnumbervalueprivate.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 @@ -304,7 +311,7 @@ /* When these change we do a full restyling. Otherwise we try to figure out * if we need to change things. */ -#define GTK_STYLE_CONTEXT_RADICAL_CHANGE (GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_CLASS) +#define GTK_STYLE_CONTEXT_RADICAL_CHANGE (GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_CLASS | GTK_CSS_CHANGE_SOURCE) /* When these change we don't clear the cache. This takes more memory but makes * things go faster. */ #define GTK_STYLE_CONTEXT_CACHED_CHANGE (GTK_CSS_CHANGE_STATE) @@ -330,6 +337,7 @@ struct PropertyValue struct GtkStyleInfo { + GtkStyleInfo *next; GArray *style_classes; GArray *regions; GtkJunctionSides junction_sides; @@ -341,6 +349,7 @@ struct StyleData { GtkCssComputedValues *store; GArray *property_cache; + guint ref_count; }; struct _GtkStyleContextPrivate @@ -351,19 +360,19 @@ struct _GtkStyleContextPrivate GtkStyleContext *parent; GSList *children; - GtkWidget *widget; + GtkWidget *widget; GtkWidgetPath *widget_path; GHashTable *style_data; - GSList *info_stack; - - GtkThemingEngine *theming_engine; + GtkStyleInfo *info; - GtkTextDirection direction; + GdkFrameClock *frame_clock; + guint frame_clock_update_id; GtkCssChange relevant_changes; GtkCssChange pending_changes; - guint invalidating_context : 1; + const GtkBitmask *invalidating_context; + guint animating : 1; guint invalid : 1; }; @@ -371,6 +380,7 @@ enum { PROP_0, PROP_SCREEN, PROP_DIRECTION, + PROP_FRAME_CLOCK, PROP_PARENT }; @@ -391,10 +401,11 @@ static void gtk_style_context_impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -static GtkSymbolicColor * - gtk_style_context_color_lookup_func (gpointer contextp, - const char *name); +static StyleData *style_data_lookup (GtkStyleContext *context); + +static void gtk_style_context_disconnect_update (GtkStyleContext *context); +static void gtk_style_context_connect_update (GtkStyleContext *context); G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT) @@ -434,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", @@ -461,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) { @@ -473,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; @@ -495,9 +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; - copy->data = info->data; + style_info_set_data (copy, info->data); return copy; } @@ -563,50 +668,51 @@ style_info_equal (gconstpointer elem1, return TRUE; } -static StyleData * -style_data_new (void) +static void +gtk_style_context_cascade_changed (GtkStyleCascade *cascade, + GtkStyleContext *context) { - StyleData *data; - - data = g_slice_new0 (StyleData); - - return data; + _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_SOURCE); } static void -clear_property_cache (StyleData *data) +gtk_style_context_set_cascade (GtkStyleContext *context, + GtkStyleCascade *cascade) { - guint i; + GtkStyleContextPrivate *priv; - if (!data->property_cache) + priv = context->priv; + + if (priv->cascade == cascade) return; - for (i = 0; i < data->property_cache->len; i++) + if (cascade) { - PropertyValue *node = &g_array_index (data->property_cache, PropertyValue, i); - - g_param_spec_unref (node->pspec); - g_value_unset (&node->value); + g_object_ref (cascade); + g_signal_connect (cascade, + "-gtk-private-changed", + G_CALLBACK (gtk_style_context_cascade_changed), + context); } - g_array_free (data->property_cache, TRUE); - data->property_cache = NULL; -} + if (priv->cascade) + { + g_signal_handlers_disconnect_by_func (priv->cascade, + gtk_style_context_cascade_changed, + context); + g_object_unref (priv->cascade); + } -static void -style_data_free (StyleData *data) -{ - g_object_unref (data->store); - clear_property_cache (data); + priv->cascade = cascade; - g_slice_free (StyleData, data); + if (cascade) + gtk_style_context_cascade_changed (cascade, context); } static void gtk_style_context_init (GtkStyleContext *style_context) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; priv = style_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (style_context, GTK_TYPE_STYLE_CONTEXT, @@ -615,19 +721,122 @@ gtk_style_context_init (GtkStyleContext *style_context) priv->style_data = g_hash_table_new_full (style_info_hash, style_info_equal, (GDestroyNotify) style_info_free, - (GDestroyNotify) style_data_free); - priv->theming_engine = g_object_ref ((gpointer) gtk_theming_engine_load (NULL)); - - priv->direction = GTK_TEXT_DIR_LTR; + (GDestroyNotify) style_data_unref); priv->screen = gdk_screen_get_default (); - priv->cascade = _gtk_style_cascade_get_for_screen (priv->screen); - g_object_ref (priv->cascade); priv->relevant_changes = GTK_CSS_CHANGE_ANY; /* Create default info store */ - info = style_info_new (); - priv->info_stack = g_slist_prepend (priv->info_stack, info); + priv->info = style_info_new (); + priv->info->state_flags = GTK_STATE_FLAG_DIR_LTR; + + gtk_style_context_set_cascade (style_context, + _gtk_style_cascade_get_for_screen (priv->screen)); +} + +static void +gtk_style_context_update (GdkFrameClock *clock, + GtkStyleContext *context) +{ + _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE); +} + +static gboolean +gtk_style_context_is_animating (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv = context->priv; + + return priv->animating; +} + +static void +gtk_style_context_disconnect_update (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv = context->priv; + + if (priv->frame_clock && priv->frame_clock_update_id) + { + 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); + } +} + +static void +gtk_style_context_connect_update (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv = context->priv; + + if (priv->frame_clock && priv->frame_clock_update_id == 0) + { + priv->frame_clock_update_id = g_signal_connect (priv->frame_clock, + "update", + G_CALLBACK (gtk_style_context_update), + context); + gdk_frame_clock_begin_updating (priv->frame_clock); + } +} + +static void +gtk_style_context_stop_animating (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv = context->priv; + + if (!gtk_style_context_is_animating (context)) + return; + + priv->animating = FALSE; + + gtk_style_context_disconnect_update (context); +} + +static void +gtk_style_context_start_animating (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv = context->priv; + + if (gtk_style_context_is_animating (context)) + return; + + priv->animating = TRUE; + + gtk_style_context_connect_update (context); +} + +static gboolean +gtk_style_context_should_animate (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv; + StyleData *data; + gboolean animate; + + priv = context->priv; + + if (priv->widget == NULL) + return FALSE; + + if (!gtk_widget_get_mapped (priv->widget)) + return FALSE; + + data = style_data_lookup (context); + if (!style_data_is_animating (data)) + return FALSE; + + g_object_get (gtk_widget_get_settings (context->priv->widget), + "gtk-enable-animations", &animate, + NULL); + + return animate; +} + +void +_gtk_style_context_update_animating (GtkStyleContext *context) +{ + if (gtk_style_context_should_animate (context)) + gtk_style_context_start_animating (context); + else + gtk_style_context_stop_animating (context); } static void @@ -639,22 +848,22 @@ gtk_style_context_finalize (GObject *object) style_context = GTK_STYLE_CONTEXT (object); priv = style_context->priv; + gtk_style_context_stop_animating (style_context); + /* children hold a reference to us */ g_assert (priv->children == NULL); gtk_style_context_set_parent (style_context, NULL); + gtk_style_context_set_cascade (style_context, NULL); + if (priv->widget_path) gtk_widget_path_free (priv->widget_path); g_hash_table_destroy (priv->style_data); - g_object_unref (priv->cascade); - - g_slist_free_full (priv->info_stack, (GDestroyNotify) style_info_free); - - 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); } @@ -676,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, @@ -707,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); @@ -718,44 +938,18 @@ gtk_style_context_impl_get_property (GObject *object, } } -static void -build_properties (GtkStyleContext *context, - StyleData *style_data, - GtkWidgetPath *path, - GtkStateFlags state) -{ - GtkStyleContextPrivate *priv; - GtkCssMatcher matcher; - GtkCssLookup *lookup; - - priv = context->priv; - - _gtk_css_matcher_init (&matcher, path, state); - lookup = _gtk_css_lookup_new (); - - _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), - &matcher, - lookup); - - style_data->store = _gtk_css_computed_values_new (); - _gtk_css_lookup_resolve (lookup, context, style_data->store); - _gtk_css_lookup_free (lookup); -} - static GtkWidgetPath * -create_query_path (GtkStyleContext *context) +create_query_path (GtkStyleContext *context, + GtkStyleInfo *info) { GtkStyleContextPrivate *priv; GtkWidgetPath *path; - GtkStyleInfo *info; guint i, pos; priv = context->priv; - path = gtk_widget_path_copy (priv->widget ? gtk_widget_get_path (priv->widget) : priv->widget_path); + path = priv->widget ? _gtk_widget_create_path (priv->widget) : gtk_widget_path_copy (priv->widget_path); pos = gtk_widget_path_length (path) - 1; - info = priv->info_stack->data; - /* Set widget regions */ for (i = 0; i < info->regions->len; i++) { @@ -780,14 +974,45 @@ create_query_path (GtkStyleContext *context) return path; } +static void +build_properties (GtkStyleContext *context, + GtkCssComputedValues *values, + GtkStyleInfo *info, + const GtkBitmask *relevant_changes) +{ + GtkStyleContextPrivate *priv; + GtkCssMatcher matcher; + GtkWidgetPath *path; + GtkCssLookup *lookup; + + priv = context->priv; + + path = create_query_path (context, info); + lookup = _gtk_css_lookup_new (relevant_changes); + + if (_gtk_css_matcher_init (&matcher, path, info->state_flags)) + _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), + &matcher, + lookup); + + _gtk_css_lookup_resolve (lookup, + GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), + values, + priv->parent ? style_data_lookup (priv->parent)->store : NULL); + + _gtk_css_lookup_free (lookup); + gtk_widget_path_free (path); +} + static StyleData * style_data_lookup (GtkStyleContext *context) { GtkStyleContextPrivate *priv; GtkStyleInfo *info; + StyleData *data; priv = context->priv; - info = priv->info_stack->data; + info = priv->info; /* Current data in use is cached, just return it */ if (info->data) @@ -795,32 +1020,40 @@ style_data_lookup (GtkStyleContext *context) g_assert (priv->widget != NULL || priv->widget_path != NULL); - info->data = g_hash_table_lookup (priv->style_data, info); - - if (!info->data) + data = g_hash_table_lookup (priv->style_data, info); + if (data) { - GtkWidgetPath *path; + style_info_set_data (info, data); + return data; + } - path = create_query_path (context); + 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); - info->data = style_data_new (); - g_hash_table_insert (priv->style_data, - style_info_copy (info), - info->data); + build_properties (context, data->store, info, NULL); - build_properties (context, info->data, path, info->state_flags); + return data; +} - gtk_widget_path_free (path); - } +static StyleData * +style_data_lookup_for_state (GtkStyleContext *context, + GtkStateFlags state) +{ + StyleData *data; - if (priv->theming_engine) - g_object_unref (priv->theming_engine); + if (context->priv->info->state_flags == state) + return style_data_lookup (context); - priv->theming_engine = g_object_ref ( - _gtk_css_engine_value_get_engine ( - _gtk_css_computed_values_get_value (info->data->store, GTK_CSS_PROPERTY_ENGINE))); + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); + data = style_data_lookup (context); + gtk_style_context_restore (context); - return info->data; + return data; } static void @@ -840,8 +1073,8 @@ gtk_style_context_set_invalid (GtkStyleContext *context, { if (priv->parent) gtk_style_context_set_invalid (priv->parent, TRUE); - else if (priv->widget) - gtk_widget_queue_resize (priv->widget); + else if (GTK_IS_RESIZE_CONTAINER (priv->widget)) + _gtk_container_queue_restyle (GTK_CONTAINER (priv->widget)); } } @@ -853,7 +1086,7 @@ gtk_style_context_set_invalid (GtkStyleContext *context, static gboolean gtk_style_context_is_saved (GtkStyleContext *context) { - return context->priv->info_stack->next != NULL; + return context->priv->info->next != NULL; } static void @@ -861,15 +1094,15 @@ gtk_style_context_queue_invalidate_internal (GtkStyleContext *context, GtkCssChange change) { GtkStyleContextPrivate *priv = context->priv; - GtkStyleInfo *info = priv->info_stack->data; + GtkStyleInfo *info = priv->info; if (gtk_style_context_is_saved (context)) { - info->data = NULL; + style_info_set_data (info, NULL); } else { - _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_STATE); + _gtk_style_context_queue_invalidate (context, change); /* XXX: We need to invalidate siblings here somehow */ } } @@ -905,6 +1138,8 @@ _gtk_style_context_set_widget (GtkStyleContext *context, context->priv->widget = widget; + _gtk_style_context_update_animating (context); + _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY_SELF); } @@ -919,6 +1154,10 @@ _gtk_style_context_set_widget (GtkStyleContext *context, * %GTK_STYLE_PROVIDER_PRIORITY_USER * * Adds a style provider to @context, to be used in style construction. + * Note that a style provider added by this function only affects + * the style of the widget to which @context belongs. If you want + * to affect the style of all widgets, use + * gtk_style_context_add_provider_for_screen(). * * If both priorities are the same, A #GtkStyleProvider * added through this function takes precedence over another added @@ -944,13 +1183,14 @@ gtk_style_context_add_provider (GtkStyleContext *context, new_cascade = _gtk_style_cascade_new (); _gtk_style_cascade_set_parent (new_cascade, priv->cascade); - g_object_unref (priv->cascade); - priv->cascade = new_cascade; + _gtk_style_cascade_add_provider (new_cascade, provider, priority); + gtk_style_context_set_cascade (context, new_cascade); + g_object_unref (new_cascade); + } + else + { + _gtk_style_cascade_add_provider (priv->cascade, provider, priority); } - - _gtk_style_cascade_add_provider (priv->cascade, provider, priority); - - gtk_style_context_invalidate (context); } /** @@ -1024,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. @@ -1045,6 +1284,7 @@ gtk_style_context_add_provider_for_screen (GdkScreen *screen, g_return_if_fail (GDK_IS_SCREEN (screen)); g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider)); + g_return_if_fail (!GTK_IS_SETTINGS (provider) || _gtk_settings_get_screen (GTK_SETTINGS (provider)) == screen); cascade = _gtk_style_cascade_get_for_screen (screen); _gtk_style_cascade_add_provider (cascade, provider, priority); @@ -1067,6 +1307,7 @@ gtk_style_context_remove_provider_for_screen (GdkScreen *screen, g_return_if_fail (GDK_IS_SCREEN (screen)); g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider)); + g_return_if_fail (!GTK_IS_SETTINGS (provider)); cascade = _gtk_style_cascade_get_for_screen (screen); _gtk_style_cascade_remove_provider (cascade, provider); @@ -1164,11 +1405,8 @@ gtk_style_context_get_property (GtkStyleContext *context, return; } - gtk_style_context_save (context); - gtk_style_context_set_state (context, state); - data = style_data_lookup (context); + data = style_data_lookup_for_state (context, state); _gtk_style_property_query (prop, value, gtk_style_context_query_func, data->store); - gtk_style_context_restore (context); } /** @@ -1255,14 +1493,18 @@ void gtk_style_context_set_state (GtkStyleContext *context, GtkStateFlags flags) { - GtkStyleContextPrivate *priv; - GtkStyleInfo *info; - + GtkStateFlags old_flags; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - priv = context->priv; - info = priv->info_stack->data; - info->state_flags = flags; + old_flags = context->priv->info->state_flags; + if (old_flags == flags) + return; + + context->priv->info->state_flags = flags; + + if (((old_flags ^ flags) & (GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL)) && + !gtk_style_context_is_saved (context)) + g_object_notify (G_OBJECT (context), "direction"); gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_STATE); } @@ -1280,15 +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; + return context->priv->info->state_flags; } /** @@ -1467,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); } /** @@ -1492,26 +1729,19 @@ 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 (); } } @@ -1646,8 +1876,7 @@ gtk_style_context_add_class (GtkStyleContext *context, priv = context->priv; class_quark = g_quark_from_string (class_name); - g_assert (priv->info_stack != NULL); - info = priv->info_stack->data; + info = priv->info; if (!style_class_find (info->style_classes, class_quark, &position)) { @@ -1685,8 +1914,7 @@ gtk_style_context_remove_class (GtkStyleContext *context, priv = context->priv; - g_assert (priv->info_stack != NULL); - info = priv->info_stack->data; + info = priv->info; if (style_class_find (info->style_classes, class_quark, &position)) { @@ -1726,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; @@ -1760,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++) { @@ -1799,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++) { @@ -1884,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)) { @@ -1928,8 +2152,7 @@ gtk_style_context_remove_region (GtkStyleContext *context, priv = context->priv; - g_assert (priv->info_stack != NULL); - info = priv->info_stack->data; + info = priv->info; if (region_find (info->regions, region_quark, &position)) { @@ -1976,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)) { @@ -2022,17 +2244,6 @@ _gtk_style_context_peek_property (GtkStyleContext *context, return _gtk_css_computed_values_get_value (data->store, property_id); } -double -_gtk_style_context_get_number (GtkStyleContext *context, - guint property_id, - double one_hundred_percent) -{ - GtkCssValue *value; - - value = _gtk_style_context_peek_property (context, property_id); - return _gtk_css_number_value_get (value, one_hundred_percent); -} - const GValue * _gtk_style_context_peek_style_property (GtkStyleContext *context, GType widget_type, @@ -2046,10 +2257,7 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context, priv = context->priv; - gtk_style_context_save (context); - gtk_style_context_set_state (context, state); - data = style_data_lookup (context); - gtk_style_context_restore (context); + data = style_data_lookup_for_state (context, state); key.widget_type = widget_type; key.state = state; @@ -2081,11 +2289,14 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context, if (priv->widget || priv->widget_path) { + GtkWidgetPath *widget_path = priv->widget ? _gtk_widget_create_path (priv->widget) : priv->widget_path; + if (gtk_style_provider_get_style_property (GTK_STYLE_PROVIDER (priv->cascade), - priv->widget ? gtk_widget_get_path (priv->widget) - : priv->widget_path, + widget_path, state, pspec, &pcache->value)) { + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + /* Resolve symbolic colors to GdkColor/GdkRGBA */ if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR) { @@ -2101,7 +2312,7 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context, else g_value_init (&pcache->value, GDK_TYPE_COLOR); - if (_gtk_style_context_resolve_color (context, color, &rgba)) + if (_gtk_style_context_resolve_color (context, _gtk_symbolic_color_get_css_value (color), &rgba, NULL)) { if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA) g_value_set_boxed (&pcache->value, &rgba); @@ -2122,8 +2333,16 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context, gtk_symbolic_color_unref (color); } + G_GNUC_END_IGNORE_DEPRECATIONS; + + if (priv->widget) + gtk_widget_path_free (widget_path); + return &pcache->value; } + + if (priv->widget) + gtk_widget_path_free (widget_path); } /* not supplied by any provider, revert to default */ @@ -2375,9 +2594,7 @@ gtk_style_context_set_screen (GtkStyleContext *context, if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen)) { - g_object_unref (priv->cascade); - priv->cascade = _gtk_style_cascade_get_for_screen (screen); - g_object_ref (priv->cascade); + gtk_style_context_set_cascade (context, _gtk_style_cascade_get_for_screen (screen)); } else { @@ -2387,8 +2604,6 @@ gtk_style_context_set_screen (GtkStyleContext *context, priv->screen = screen; g_object_notify (G_OBJECT (context), "screen"); - - gtk_style_context_invalidate (context); } /** @@ -2410,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 @@ -2422,19 +2701,38 @@ gtk_style_context_get_screen (GtkStyleContext *context) * call this yourself. * * Since: 3.0 + * + * Deprecated: 3.8: Use gtk_style_context_set_state() with + * #GTK_STATE_FLAG_DIR_LTR and #GTK_STATE_FLAG_DIR_RTL + * instead. **/ void gtk_style_context_set_direction (GtkStyleContext *context, GtkTextDirection direction) { - GtkStyleContextPrivate *priv; + GtkStateFlags state; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - priv = context->priv; - priv->direction = direction; + state = gtk_style_context_get_state (context); + state &= ~(GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL); + + switch (direction) + { + case GTK_TEXT_DIR_LTR: + state |= GTK_STATE_FLAG_DIR_LTR; + break; + + case GTK_TEXT_DIR_RTL: + state |= GTK_STATE_FLAG_DIR_RTL; + break; - g_object_notify (G_OBJECT (context), "direction"); + case GTK_TEXT_DIR_NONE: + default: + break; + } + + gtk_style_context_set_state (context, state); } /** @@ -2446,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; } /** @@ -2480,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; } /** @@ -2503,45 +2806,16 @@ gtk_style_context_set_junction_sides (GtkStyleContext *context, GtkJunctionSides gtk_style_context_get_junction_sides (GtkStyleContext *context) { - GtkStyleContextPrivate *priv; - GtkStyleInfo *info; - g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0); - priv = context->priv; - info = priv->info_stack->data; - return info->junction_sides; -} - -static GtkSymbolicColor * -gtk_style_context_color_lookup_func (gpointer contextp, - const char *name) -{ - GtkStyleContext *context = contextp; - - return _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade), name); + return context->priv->info->junction_sides; } -GtkCssValue * -_gtk_style_context_resolve_color_value (GtkStyleContext *context, - GtkCssValue *current, - GtkSymbolicColor *color) -{ - g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE); - g_return_val_if_fail (current != NULL, FALSE); - g_return_val_if_fail (color != NULL, FALSE); - - return _gtk_symbolic_color_resolve_full (color, - current, - gtk_style_context_color_lookup_func, - context); -} - - gboolean -_gtk_style_context_resolve_color (GtkStyleContext *context, - GtkSymbolicColor *color, - GdkRGBA *result) +_gtk_style_context_resolve_color (GtkStyleContext *context, + GtkCssValue *color, + GdkRGBA *result, + GtkCssDependencies *dependencies) { GtkCssValue *val; @@ -2549,10 +2823,11 @@ _gtk_style_context_resolve_color (GtkStyleContext *context, g_return_val_if_fail (color != NULL, FALSE); g_return_val_if_fail (result != NULL, FALSE); - val = _gtk_symbolic_color_resolve_full (color, - _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR), - gtk_style_context_color_lookup_func, - context); + val = _gtk_css_color_value_resolve (color, + GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade), + _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR), + GTK_CSS_DEPENDS_ON_COLOR, + dependencies); if (val == NULL) return FALSE; @@ -2576,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); } /** @@ -2756,8 +3031,52 @@ gtk_style_context_pop_animatable_region (GtkStyleContext *context) } static void -gtk_style_context_do_invalidate (GtkStyleContext *context, - gboolean clear_caches) +gtk_style_context_clear_cache (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv; + GtkStyleInfo *info; + + priv = context->priv; + + for (info = priv->info; info; info = info->next) + { + style_info_set_data (info, NULL); + } + g_hash_table_remove_all (priv->style_data); +} + +static void +gtk_style_context_update_cache (GtkStyleContext *context, + const GtkBitmask *parent_changes) +{ + GtkStyleContextPrivate *priv; + GHashTableIter iter; + gpointer key, value; + + if (_gtk_bitmask_is_empty (parent_changes)) + return; + + priv = context->priv; + + g_hash_table_iter_init (&iter, priv->style_data); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + GtkStyleInfo *info = key; + StyleData *data = value; + GtkBitmask *changes; + + changes = _gtk_css_computed_values_compute_dependencies (data->store, parent_changes); + + if (!_gtk_bitmask_is_empty (changes)) + build_properties (context, data->store, info, changes); + + _gtk_bitmask_free (changes); + } +} + +static void +gtk_style_context_do_invalidate (GtkStyleContext *context, + const GtkBitmask *changes) { GtkStyleContextPrivate *priv; @@ -2769,30 +3088,102 @@ gtk_style_context_do_invalidate (GtkStyleContext *context, if (priv->invalidating_context) return; - priv->invalidating_context = TRUE; + priv->invalidating_context = changes; - if (clear_caches) - { - GSList *list; + 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); + + differences = _gtk_css_computed_values_advance (style_data->store, + timestamp); + + if (_gtk_css_computed_values_is_static (style_data->store)) + _gtk_style_context_update_animating (context); + + return differences; +} - for (list = priv->info_stack; list; list = list->next) +static gboolean +gtk_style_context_needs_full_revalidate (GtkStyleContext *context, + GtkCssChange change) +{ + GtkStyleContextPrivate *priv = context->priv; + + /* Try to avoid invalidating if we can */ + if (change & GTK_STYLE_CONTEXT_RADICAL_CHANGE) + { + priv->relevant_changes = GTK_CSS_CHANGE_ANY; + } + else + { + if (priv->relevant_changes == GTK_CSS_CHANGE_ANY) { - GtkStyleInfo *info = list->data; - info->data = NULL; + GtkWidgetPath *path; + GtkCssMatcher matcher, superset; + + path = create_query_path (context, priv->info); + if (_gtk_css_matcher_init (&matcher, path, priv->info->state_flags)) + { + _gtk_css_matcher_superset_init (&superset, &matcher, GTK_STYLE_CONTEXT_RADICAL_CHANGE & ~GTK_CSS_CHANGE_SOURCE); + priv->relevant_changes = _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), + &superset); + } + else + priv->relevant_changes = 0; + + priv->relevant_changes &= ~GTK_STYLE_CONTEXT_RADICAL_CHANGE; + + gtk_widget_path_unref (path); } - g_hash_table_remove_all (priv->style_data); } - g_signal_emit (context, signals[CHANGED], 0); + if (priv->relevant_changes & change) + return TRUE; + else + return FALSE; +} - priv->invalidating_context = FALSE; +static gboolean +gtk_style_context_should_create_transitions (GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv; + gboolean animate; + + priv = context->priv; + + if (priv->widget == NULL) + return FALSE; + + if (!gtk_widget_get_mapped (priv->widget)) + return FALSE; + + g_object_get (gtk_widget_get_settings (context->priv->widget), + "gtk-enable-animations", &animate, + NULL); + + return animate; } void -_gtk_style_context_validate (GtkStyleContext *context, - GtkCssChange change) +_gtk_style_context_validate (GtkStyleContext *context, + gint64 timestamp, + GtkCssChange change, + const GtkBitmask *parent_changes) { GtkStyleContextPrivate *priv; + GtkStyleInfo *info; + StyleData *current; + GtkBitmask *changes; GSList *list; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); @@ -2800,50 +3191,117 @@ _gtk_style_context_validate (GtkStyleContext *context, priv = context->priv; change |= priv->pending_changes; + + /* If you run your application with + * GTK_DEBUG=no-css-cache + * every invalidation will purge the cache and completely query + * everything anew form the cache. This is slow (in particular + * when animating), but useful for figuring out bugs. + * + * We achieve that by pretending that everything that could have + * changed has and so we of course totally need to redo everything. + * + * Note that this also completely revalidates child widgets all + * the time. + */ + if (G_UNLIKELY (gtk_get_debug_flags () & GTK_DEBUG_NO_CSS_CACHE)) + change = GTK_CSS_CHANGE_ANY; - if (!priv->invalid && change == 0) + if (!priv->invalid && change == 0 && _gtk_bitmask_is_empty (parent_changes)) return; priv->pending_changes = 0; gtk_style_context_set_invalid (context, FALSE); - /* Try to avoid invalidating if we can */ - if (change & GTK_STYLE_CONTEXT_RADICAL_CHANGE) - { - priv->relevant_changes = GTK_CSS_CHANGE_ANY; - } + info = priv->info; + if (info->data) + current = style_data_ref (info->data); else + current = NULL; + + /* Try to avoid invalidating if we can */ + if (current == NULL || + gtk_style_context_needs_full_revalidate (context, change)) { - if (priv->relevant_changes == GTK_CSS_CHANGE_ANY) + StyleData *data; + + if ((priv->relevant_changes & change) & ~GTK_STYLE_CONTEXT_CACHED_CHANGE) { - GtkWidgetPath *path; - GtkCssMatcher matcher; + gtk_style_context_clear_cache (context); + } + else + { + gtk_style_context_update_cache (context, parent_changes); + style_info_set_data (info, NULL); + } - path = create_query_path (context); - _gtk_css_matcher_init (&matcher, path, ((GtkStyleInfo *) priv->info_stack->data)->state_flags); + data = style_data_lookup (context); - priv->relevant_changes = _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), - &matcher); - priv->relevant_changes &= ~GTK_STYLE_CONTEXT_RADICAL_CHANGE; + _gtk_css_computed_values_create_animations (data->store, + priv->parent ? style_data_lookup (priv->parent)->store : NULL, + timestamp, + GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), + current && gtk_style_context_should_create_transitions (context) ? current->store : NULL); + if (_gtk_css_computed_values_is_static (data->store)) + change &= ~GTK_CSS_CHANGE_ANIMATE; + else + change |= GTK_CSS_CHANGE_ANIMATE; + _gtk_style_context_update_animating (context); - gtk_widget_path_unref (path); + if (current) + { + changes = _gtk_css_computed_values_get_difference (data->store, current->store); + + /* In the case where we keep the cache, we want unanimated values */ + _gtk_css_computed_values_cancel_animations (current->store); + } + else + { + changes = _gtk_bitmask_new (); + changes = _gtk_bitmask_invert_range (changes, 0, _gtk_css_style_property_get_n_properties ()); } } + else + { + changes = _gtk_css_computed_values_compute_dependencies (current->store, parent_changes); - if (priv->relevant_changes & change) + 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)) { - GtkStyleInfo *info = priv->info_stack->data; - gboolean clear_cache = ((priv->relevant_changes & change) & ~GTK_STYLE_CONTEXT_CACHED_CHANGE) != 0; + GtkBitmask *animation_changes; + + animation_changes = gtk_style_context_update_animations (context, timestamp); + changes = _gtk_bitmask_union (changes, animation_changes); + _gtk_bitmask_free (animation_changes); + } - info->data = NULL; - gtk_style_context_do_invalidate (context, clear_cache); + if (change & GTK_CSS_CHANGE_FORCE_INVALIDATE) + { + GtkBitmask *full = _gtk_bitmask_new (); + full = _gtk_bitmask_invert_range (full, + 0, + _gtk_css_style_property_get_n_properties ()); + gtk_style_context_do_invalidate (context, full); + _gtk_bitmask_free (full); + } + else if (!_gtk_bitmask_is_empty (changes)) + { + gtk_style_context_do_invalidate (context, changes); } change = _gtk_css_change_for_child (change); for (list = priv->children; list; list = list->next) { - _gtk_style_context_validate (list->data, change); + _gtk_style_context_validate (list->data, timestamp, change, changes); } + + _gtk_bitmask_free (changes); } void @@ -2857,11 +3315,15 @@ _gtk_style_context_queue_invalidate (GtkStyleContext *context, priv = context->priv; - if (priv->widget == NULL && priv->widget_path == NULL) - return; - - priv->pending_changes |= change; - gtk_style_context_set_invalid (context, TRUE); + if (priv->widget != NULL) + { + priv->pending_changes |= change; + gtk_style_context_set_invalid (context, TRUE); + } + else if (priv->widget_path == NULL) + { + gtk_style_context_invalidate (context); + } } /** @@ -2880,9 +3342,25 @@ _gtk_style_context_queue_invalidate (GtkStyleContext *context, void gtk_style_context_invalidate (GtkStyleContext *context) { + GtkBitmask *changes; + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - gtk_style_context_do_invalidate (context, TRUE); + gtk_style_context_clear_cache (context); + + changes = _gtk_bitmask_new (); + changes = _gtk_bitmask_invert_range (changes, + 0, + _gtk_css_style_property_get_n_properties ()); + gtk_style_context_do_invalidate (context, changes); + _gtk_bitmask_free (changes); +} + +static gboolean +corner_value_is_right_angle (GtkCssValue *value) +{ + return _gtk_css_corner_value_get_x (value, 100) <= 0.0 && + _gtk_css_corner_value_get_y (value, 100) <= 0.0; } /** @@ -2899,31 +3377,33 @@ void gtk_style_context_set_background (GtkStyleContext *context, GdkWindow *window) { - GtkStateFlags state; - cairo_pattern_t *pattern; - GdkRGBA *color; + const GdkRGBA *color; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (GDK_IS_WINDOW (window)); - state = gtk_style_context_get_state (context); - gtk_style_context_get (context, state, - "background-image", &pattern, - NULL); - if (pattern) - { - gdk_window_set_background_pattern (window, pattern); - cairo_pattern_destroy (pattern); - return; - } + /* This is a sophisitcated optimization. + * If we know the GDK window's background will be opaque, we mark + * it as opaque. This is so GDK can do all the optimizations it does + * for opaque windows and be fast. + * This is mainly used when scrolling. + * + * We could indeed just set black instead of the color we have. + */ + color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BACKGROUND_COLOR)); - gtk_style_context_get (context, state, - "background-color", &color, - NULL); - if (color) + if (color->alpha >= 1.0 && + corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS)) && + corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS)) && + corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS)) && + corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS))) { gdk_window_set_background_rgba (window, color); - gdk_rgba_free (color); + } + else + { + GdkRGBA transparent = { 0.0, 0.0, 0.0, 0.0 }; + gdk_window_set_background_rgba (window, &transparent); } } @@ -3133,6 +3613,9 @@ gtk_style_context_get_margin (GtkStyleContext *context, * freed. * * Since: 3.0 + * + * Deprecated: 3.8: Use gtk_style_context_get() for "font" or + * subproperties instead. **/ const PangoFontDescription * gtk_style_context_get_font (GtkStyleContext *context, @@ -3140,29 +3623,35 @@ gtk_style_context_get_font (GtkStyleContext *context, { GtkStyleContextPrivate *priv; StyleData *data; - PangoFontDescription *description; + PangoFontDescription *description, *previous; g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); priv = context->priv; g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL); - gtk_style_context_save (context); - gtk_style_context_set_state (context, state); - data = style_data_lookup (context); - gtk_style_context_restore (context); + 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; } @@ -3248,8 +3737,8 @@ gtk_render_check (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3257,14 +3746,14 @@ gtk_render_check (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); @@ -3298,8 +3787,8 @@ gtk_render_option (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3307,13 +3796,13 @@ gtk_render_option (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); @@ -3345,8 +3834,8 @@ gtk_render_arrow (GtkStyleContext *context, gdouble y, gdouble size) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3354,16 +3843,16 @@ gtk_render_arrow (GtkStyleContext *context, if (size <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); gtk_style_context_save (context); gtk_style_context_add_class (context, GTK_STYLE_CLASS_ARROW); - _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); @@ -3399,8 +3888,8 @@ gtk_render_background (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3408,13 +3897,13 @@ gtk_render_background (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); } @@ -3450,8 +3939,8 @@ gtk_render_frame (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3459,13 +3948,13 @@ gtk_render_frame (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); } @@ -3498,8 +3987,8 @@ gtk_render_expander (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3507,13 +3996,13 @@ gtk_render_expander (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); } @@ -3543,8 +4032,8 @@ gtk_render_focus (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3552,13 +4041,13 @@ gtk_render_focus (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); } @@ -3582,23 +4071,23 @@ gtk_render_layout (GtkStyleContext *context, gdouble y, PangoLayout *layout) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; PangoRectangle extents; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (PANGO_IS_LAYOUT (layout)); g_return_if_fail (cr != NULL); - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); pango_layout_get_extents (layout, &extents, NULL); - _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); } @@ -3624,19 +4113,19 @@ gtk_render_line (GtkStyleContext *context, gdouble x1, gdouble y1) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _gtk_theming_engine_set_context (priv->theming_engine, context); - engine_class->render_line (priv->theming_engine, cr, x0, y0, x1, y1); + _gtk_theming_engine_set_context (engine, context); + engine_class->render_line (engine, cr, x0, y0, x1, y1); cairo_restore (cr); } @@ -3671,8 +4160,8 @@ gtk_render_slider (GtkStyleContext *context, gdouble height, GtkOrientation orientation) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3680,13 +4169,13 @@ gtk_render_slider (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); } @@ -3726,8 +4215,8 @@ gtk_render_frame_gap (GtkStyleContext *context, gdouble xy0_gap, gdouble xy1_gap) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3743,13 +4232,13 @@ gtk_render_frame_gap (GtkStyleContext *context, else g_return_if_fail (xy1_gap <= width); - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); @@ -3786,8 +4275,8 @@ gtk_render_extension (GtkStyleContext *context, gdouble height, GtkPositionType gap_side) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3795,13 +4284,13 @@ gtk_render_extension (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); } @@ -3834,8 +4323,8 @@ gtk_render_handle (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3843,13 +4332,13 @@ gtk_render_handle (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); } @@ -3877,8 +4366,8 @@ gtk_render_activity (GtkStyleContext *context, gdouble width, gdouble height) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); @@ -3886,13 +4375,13 @@ gtk_render_activity (GtkStyleContext *context, if (width <= 0 || height <= 0) return; - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); } @@ -3916,18 +4405,18 @@ gtk_render_icon_pixbuf (GtkStyleContext *context, const GtkIconSource *source, GtkIconSize size) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL); g_return_val_if_fail (source != NULL, NULL); - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); - _gtk_theming_engine_set_context (priv->theming_engine, context); - return engine_class->render_icon_pixbuf (priv->theming_engine, source, size); + _gtk_theming_engine_set_context (engine, context); + return engine_class->render_icon_pixbuf (engine, source, size); } /** @@ -3949,19 +4438,19 @@ gtk_render_icon (GtkStyleContext *context, gdouble x, gdouble y) { - GtkStyleContextPrivate *priv; GtkThemingEngineClass *engine_class; + GtkThemingEngine *engine; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); - priv = context->priv; - engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine); + engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE)); + engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine); cairo_save (cr); - _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); } @@ -4169,6 +4658,26 @@ gtk_draw_insertion_cursor (GtkWidget *widget, draw_arrow); } +/** + * _gtk_style_context_get_changes: + * @context: the context to query + * + * Queries the context for the changes for the currently executing + * GtkStyleContext::invalidate signal. If no signal is currently + * emitted, this function returns %NULL. + * + * FIXME 4.0: Make this part of the signal. + * + * Returns: %NULL or the currently invalidating changes + **/ +const GtkBitmask * +_gtk_style_context_get_changes (GtkStyleContext *context) +{ + g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); + + return context->priv->invalidating_context; +} + static AtkAttributeSet * add_attribute (AtkAttributeSet *attributes, AtkTextAttribute attr, @@ -4223,3 +4732,21 @@ _gtk_style_context_get_attributes (AtkAttributeSet *attributes, return attributes; } + +cairo_pattern_t * +gtk_gradient_resolve_for_context (GtkGradient *gradient, + GtkStyleContext *context) +{ + GtkStyleContextPrivate *priv = context->priv; + GtkCssDependencies ignored = 0; + + g_return_val_if_fail (gradient != NULL, NULL); + g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); + + return _gtk_gradient_resolve_full (gradient, + GTK_STYLE_PROVIDER_PRIVATE (priv->cascade), + style_data_lookup (context)->store, + priv->parent ? style_data_lookup (priv->parent)->store : NULL, + &ignored); +} +