#include "gtkstylecontextprivate.h"
#include "gtkcontainerprivate.h"
-#include "gtkcssanimatedvaluesprivate.h"
+#include "gtkcsscolorvalueprivate.h"
#include "gtkcssenginevalueprivate.h"
#include "gtkcssnumbervalueprivate.h"
#include "gtkcssrgbavalueprivate.h"
#include "gtkwidget.h"
#include "gtkwindow.h"
#include "gtkprivate.h"
-#include "gtksymboliccolorprivate.h"
#include "gtkiconfactory.h"
#include "gtkwidgetpath.h"
#include "gtkwidgetprivate.h"
#include "gtksettings.h"
#include "gtksettingsprivate.h"
+#include "deprecated/gtkgradientprivate.h"
+#include "deprecated/gtksymboliccolorprivate.h"
+
/**
* SECTION:gtkstylecontext
* @Short_description: Rendering UI elements
GtkCssChange relevant_changes;
GtkCssChange pending_changes;
- guint invalidating_context : 1;
+ const GtkBitmask *invalidating_context;
guint invalid : 1;
};
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);
G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
static gboolean
style_data_is_animating (StyleData *style_data)
{
- return GTK_IS_CSS_ANIMATED_VALUES (style_data->store);
+ return !_gtk_css_computed_values_is_static (style_data->store);
}
static GtkStyleInfo *
}
}
+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
gtk_style_context_finalize (GObject *object)
{
style_context = GTK_STYLE_CONTEXT (object);
priv = style_context->priv;
- _gtk_style_context_stop_animations (style_context);
+ gtk_style_context_stop_animating (style_context);
/* children hold a reference to us */
g_assert (priv->children == NULL);
}
}
-static void
-build_properties (GtkStyleContext *context,
- StyleData *style_data,
- GtkWidgetPath *path,
- GtkStateFlags state)
-{
- GtkStyleContextPrivate *priv;
- GtkCssMatcher matcher;
- GtkCssLookup *lookup;
-
- priv = context->priv;
-
- lookup = _gtk_css_lookup_new ();
-
- if (_gtk_css_matcher_init (&matcher, path, state))
- _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 = priv->widget ? _gtk_widget_create_path (priv->widget) : gtk_widget_path_copy (priv->widget_path);
pos = gtk_widget_path_length (path) - 1;
- info = priv->info;
-
/* Set widget regions */
for (i = 0; i < info->regions->len; i++)
{
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;
- GtkWidgetPath *path;
GtkStyleInfo *info;
StyleData *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);
- build_properties (context, data, path, info->state_flags);
-
- gtk_widget_path_free (path);
+ build_properties (context, data->store, info, NULL);
return data;
}
context->priv->widget = widget;
- _gtk_style_context_stop_animations (context);
+ _gtk_style_context_update_animating (context);
_gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY_SELF);
}
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)
{
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);
gtk_symbolic_color_unref (color);
}
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+
if (priv->widget)
gtk_widget_path_free (widget_path);
return context->priv->info->junction_sides;
}
-static GtkSymbolicColor *
-gtk_style_context_color_lookup_func (gpointer contextp,
- const char *name)
-{
- GtkStyleContext *context = contextp;
-
- return _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade), name);
-}
-
-GtkCssValue *
-_gtk_style_context_resolve_color_value (GtkStyleContext *context,
- GtkCssValue *current,
- GtkCssValue *color)
-{
- g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
- g_return_val_if_fail (current != NULL, FALSE);
- g_return_val_if_fail (color != NULL, FALSE);
-
- return _gtk_symbolic_color_resolve_full ((GtkSymbolicColor *) color,
- current,
- gtk_style_context_color_lookup_func,
- context);
-}
-
-
gboolean
-_gtk_style_context_resolve_color (GtkStyleContext *context,
- GtkSymbolicColor *color,
- GdkRGBA *result)
+_gtk_style_context_resolve_color (GtkStyleContext *context,
+ GtkCssValue *color,
+ GdkRGBA *result,
+ GtkCssDependencies *dependencies)
{
GtkCssValue *val;
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;
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);
}
/**
}
static void
-gtk_style_context_do_invalidate (GtkStyleContext *context)
+gtk_style_context_update_cache (GtkStyleContext *context,
+ const GtkBitmask *parent_changes)
{
GtkStyleContextPrivate *priv;
+ GHashTableIter iter;
+ gpointer key, value;
- g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ if (_gtk_bitmask_is_empty (parent_changes))
+ return;
priv = context->priv;
- /* Avoid reentrancy */
- if (priv->invalidating_context)
- return;
+ g_hash_table_iter_init (&iter, priv->style_data);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ GtkStyleInfo *info = key;
+ StyleData *data = value;
+ GtkBitmask *changes;
- priv->invalidating_context = TRUE;
+ changes = _gtk_css_computed_values_compute_dependencies (data->store, parent_changes);
- g_signal_emit (context, signals[CHANGED], 0);
+ if (!_gtk_bitmask_is_empty (changes))
+ build_properties (context, data->store, info, changes);
- priv->invalidating_context = FALSE;
+ _gtk_bitmask_free (changes);
+ }
}
-void
-_gtk_style_context_stop_animations (GtkStyleContext *context)
+static void
+gtk_style_context_do_invalidate (GtkStyleContext *context,
+ const GtkBitmask *changes)
{
+ GtkStyleContextPrivate *priv;
+
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- if (!gtk_style_context_is_animating (context))
+ priv = context->priv;
+
+ /* Avoid reentrancy */
+ if (priv->invalidating_context)
return;
- style_info_set_data (context->priv->info, NULL);
+ priv->invalidating_context = changes;
- gtk_style_context_stop_animating (context);
+ g_signal_emit (context, signals[CHANGED], 0);
+
+ priv->invalidating_context = NULL;
}
static GtkBitmask *
style_data = style_data_lookup (context);
- differences = _gtk_css_animated_values_advance (GTK_CSS_ANIMATED_VALUES (style_data->store),
+ differences = _gtk_css_computed_values_advance (style_data->store,
timestamp);
- if (_gtk_css_animated_values_is_finished (GTK_CSS_ANIMATED_VALUES (style_data->store)))
- _gtk_style_context_stop_animations (context);
+ if (_gtk_css_computed_values_is_static (style_data->store))
+ _gtk_style_context_update_animating (context);
return differences;
}
static gboolean
-gtk_style_context_should_animate (GtkStyleContext *context)
+gtk_style_context_needs_full_revalidate (GtkStyleContext *context,
+ GtkCssChange change)
+{
+ GtkStyleContextPrivate *priv = context->priv;
+
+ /* Try to avoid invalidating if we can */
+ if (change & GTK_STYLE_CONTEXT_RADICAL_CHANGE)
+ {
+ priv->relevant_changes = GTK_CSS_CHANGE_ANY;
+ }
+ else
+ {
+ if (priv->relevant_changes == GTK_CSS_CHANGE_ANY)
+ {
+ GtkWidgetPath *path;
+ GtkCssMatcher matcher, superset;
+
+ path = create_query_path (context, priv->info);
+ if (_gtk_css_matcher_init (&matcher, path, priv->info->state_flags))
+ {
+ _gtk_css_matcher_superset_init (&superset, &matcher, GTK_STYLE_CONTEXT_RADICAL_CHANGE & ~GTK_CSS_CHANGE_SOURCE);
+ priv->relevant_changes = _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
+ &superset);
+ }
+ else
+ priv->relevant_changes = 0;
+
+ priv->relevant_changes &= ~GTK_STYLE_CONTEXT_RADICAL_CHANGE;
+
+ gtk_widget_path_unref (path);
+ }
+ }
+
+ if (priv->relevant_changes & change)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static gboolean
+gtk_style_context_should_create_transitions (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv;
gboolean animate;
return animate;
}
-static void
-gtk_style_context_start_animations (GtkStyleContext *context,
- GtkCssComputedValues *previous,
- gint64 timestamp)
-{
- StyleData *animated;
-
- if (!gtk_style_context_should_animate (context))
- {
- gtk_style_context_stop_animating (context);
- return;
- }
-
- animated = style_data_new ();
- animated->store = _gtk_css_animated_values_new (style_data_lookup (context)->store,
- previous,
- timestamp);
-
- if (_gtk_css_animated_values_is_finished (GTK_CSS_ANIMATED_VALUES (animated->store)))
- {
- style_data_unref (animated);
- gtk_style_context_stop_animating (context);
- return;
- }
-
- style_info_set_data (context->priv->info, animated);
- style_data_unref (animated);
- gtk_style_context_start_animating (context);
-}
-
void
-_gtk_style_context_validate (GtkStyleContext *context,
- gint64 timestamp,
- 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;
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
- {
- if (priv->relevant_changes == GTK_CSS_CHANGE_ANY)
- {
- GtkWidgetPath *path;
- GtkCssMatcher matcher;
-
- path = create_query_path (context);
- if (_gtk_css_matcher_init (&matcher, path, priv->info->state_flags))
- priv->relevant_changes = _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
- &matcher);
- else
- priv->relevant_changes = 0;
+ current = NULL;
- priv->relevant_changes &= ~GTK_STYLE_CONTEXT_RADICAL_CHANGE;
-
- gtk_widget_path_unref (path);
- }
- }
-
- if (priv->relevant_changes & change)
+ /* Try to avoid invalidating if we can */
+ if (current == NULL ||
+ gtk_style_context_needs_full_revalidate (context, change))
{
- GtkStyleInfo *info = priv->info;
- StyleData *current;
-
- if (info->data)
- current = style_data_ref (info->data);
- else
- current = NULL;
+ StyleData *data;
if ((priv->relevant_changes & change) & ~GTK_STYLE_CONTEXT_CACHED_CHANGE)
- gtk_style_context_clear_cache (context);
+ {
+ gtk_style_context_clear_cache (context);
+ }
else
- style_info_set_data (info, NULL);
-
- if (current)
{
- StyleData *data;
+ gtk_style_context_update_cache (context, parent_changes);
+ style_info_set_data (info, NULL);
+ }
- gtk_style_context_start_animations (context, current->store, timestamp);
- change &= ~GTK_CSS_CHANGE_ANIMATE;
+ data = style_data_lookup (context);
- data = style_data_lookup (context);
+ _gtk_css_computed_values_create_animations (data->store,
+ priv->parent ? style_data_lookup (priv->parent)->store : NULL,
+ timestamp,
+ GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
+ current && gtk_style_context_should_create_transitions (context) ? current->store : NULL);
+ if (_gtk_css_computed_values_is_static (data->store))
+ change &= ~GTK_CSS_CHANGE_ANIMATE;
+ else
+ change |= GTK_CSS_CHANGE_ANIMATE;
+ _gtk_style_context_update_animating (context);
+ if (current)
+ {
changes = _gtk_css_computed_values_get_difference (data->store, current->store);
- style_data_unref (current);
+ /* In the case where we keep the cache, we want unanimated values */
+ _gtk_css_computed_values_cancel_animations (current->store);
}
else
{
}
}
else
- changes = _gtk_bitmask_new ();
+ {
+ 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))
_gtk_bitmask_free (animation_changes);
}
- if (!_gtk_bitmask_is_empty (changes))
- gtk_style_context_do_invalidate (context);
+ 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);
+ _gtk_style_context_validate (list->data, timestamp, change, changes);
}
_gtk_bitmask_free (changes);
void
gtk_style_context_invalidate (GtkStyleContext *context)
{
+ GtkBitmask *changes;
+
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
gtk_style_context_clear_cache (context);
- gtk_style_context_do_invalidate (context);
+
+ changes = _gtk_bitmask_new ();
+ changes = _gtk_bitmask_invert_range (changes,
+ 0,
+ _gtk_css_style_property_get_n_properties ());
+ gtk_style_context_do_invalidate (context, changes);
+ _gtk_bitmask_free (changes);
}
/**
GdkWindow *window)
{
GtkStateFlags state;
- cairo_pattern_t *pattern;
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;
- }
gtk_style_context_get (context, state,
"background-color", &color,
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);
+}
+