diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 43ebb9eff1..14981733bb 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -411,6 +411,7 @@ gtk_private_h_sources = \
gtkcssnodeprivate.h \
gtkcssnodedeclarationprivate.h \
gtkcssnumbervalueprivate.h \
+ gtkcsspalettevalueprivate.h \
gtkcssparserprivate.h \
gtkcsspathnodeprivate.h \
gtkcsspositionvalueprivate.h \
@@ -661,6 +662,7 @@ gtk_base_c_sources = \
gtkcssnode.c \
gtkcssnodedeclaration.c \
gtkcssnumbervalue.c \
+ gtkcsspalettevalue.c \
gtkcssparser.c \
gtkcsspathnode.c \
gtkcsspositionvalue.c \
diff --git a/gtk/gtkcsscolorvalue.c b/gtk/gtkcsscolorvalue.c
index 7e78134580..6cd0cf0447 100644
--- a/gtk/gtkcsscolorvalue.c
+++ b/gtk/gtkcsscolorvalue.c
@@ -127,6 +127,8 @@ gtk_css_value_color_get_fallback (guint property_id,
provider,
style,
parent_style);
+ case GTK_CSS_PROPERTY_ICON_PALETTE:
+ return _gtk_css_value_ref (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_COLOR));
default:
if (property_id < GTK_CSS_PROPERTY_N_PROPERTIES)
g_warning ("No fallback color defined for property '%s'",
diff --git a/gtk/gtkcsspalettevalue.c b/gtk/gtkcsspalettevalue.c
new file mode 100644
index 0000000000..cf98968838
--- /dev/null
+++ b/gtk/gtkcsspalettevalue.c
@@ -0,0 +1,258 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ */
+
+#include "config.h"
+
+#include "gtkcssiconthemevalueprivate.h"
+
+#include "gtkcsscolorvalueprivate.h"
+#include "gtkcssrgbavalueprivate.h"
+
+struct _GtkCssValue {
+ GTK_CSS_VALUE_BASE
+ GHashTable *colors;
+};
+
+static GtkCssValue *default_palette;
+
+static GtkCssValue *gtk_css_palette_value_new_empty (void);
+
+static void
+gtk_css_palette_value_add_color (GtkCssValue *value,
+ const char *name,
+ GtkCssValue *color)
+{
+ g_hash_table_insert (value->colors, g_strdup (name), color);
+}
+
+static void
+gtk_css_value_palette_free (GtkCssValue *value)
+{
+ g_hash_table_unref (value->colors);
+
+ g_slice_free (GtkCssValue, value);
+}
+
+static GtkCssValue *
+gtk_css_value_palette_compute (GtkCssValue *specified,
+ guint property_id,
+ GtkStyleProviderPrivate *provider,
+ GtkCssStyle *style,
+ GtkCssStyle *parent_style)
+{
+ GHashTableIter iter;
+ gpointer name, value;
+ GtkCssValue *computed_color;
+ GtkCssValue *result;
+ gboolean changes = FALSE;
+
+ result = gtk_css_palette_value_new_empty ();
+
+ g_hash_table_iter_init (&iter, specified->colors);
+ while (g_hash_table_iter_next (&iter, &name, &value))
+ {
+ computed_color = _gtk_css_value_compute (value, property_id, provider, style, parent_style);
+ changes |= computed_color != value;
+ gtk_css_palette_value_add_color (result, name, computed_color);
+ }
+
+ if (!changes)
+ {
+ _gtk_css_value_unref (result);
+ result = _gtk_css_value_ref (specified);
+ }
+
+ return result;
+}
+
+static gboolean
+gtk_css_value_palette_equal (const GtkCssValue *value1,
+ const GtkCssValue *value2)
+{
+ gpointer name, color1, color2;
+ GHashTableIter iter;
+
+ if (g_hash_table_size (value1->colors) != g_hash_table_size (value2->colors))
+ return FALSE;
+
+ g_hash_table_iter_init (&iter, value1->colors);
+ while (g_hash_table_iter_next (&iter, &name, &color1))
+ {
+ color2 = g_hash_table_lookup (value2->colors, name);
+ if (color2 == NULL)
+ return FALSE;
+
+ if (!_gtk_css_value_equal (color1, color2))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GtkCssValue *
+gtk_css_value_palette_transition (GtkCssValue *start,
+ GtkCssValue *end,
+ guint property_id,
+ double progress)
+{
+ gpointer name, start_color, end_color;
+ GHashTableIter iter;
+ GtkCssValue *result, *transition;
+
+ /* XXX: For colors that are only in start or end but not both,
+ * we don't transition but just keep the value.
+ * That causes an abrupt transition to currentColor at the end.
+ */
+
+ result = gtk_css_palette_value_new_empty ();
+
+ g_hash_table_iter_init (&iter, start->colors);
+ while (g_hash_table_iter_next (&iter, &name, &start_color))
+ {
+ end_color = g_hash_table_lookup (end->colors, name);
+ if (end_color == NULL)
+ transition = _gtk_css_value_ref (start_color);
+ else
+ transition = _gtk_css_value_transition (start_color, end_color, property_id, progress);
+
+ gtk_css_palette_value_add_color (result, name, transition);
+ }
+
+ g_hash_table_iter_init (&iter, end->colors);
+ while (g_hash_table_iter_next (&iter, &name, &end_color))
+ {
+ start_color = g_hash_table_lookup (start->colors, name);
+ if (start_color != NULL)
+ continue;
+
+ gtk_css_palette_value_add_color (result, name, _gtk_css_value_ref (end_color));
+ }
+
+ return result;
+}
+
+static void
+gtk_css_value_palette_print (const GtkCssValue *value,
+ GString *string)
+{
+ GHashTableIter iter;
+ gpointer name, color;
+ gboolean first = TRUE;
+
+ if (value == default_palette)
+ {
+ g_string_append (string, "default");
+ return;
+ }
+
+ g_hash_table_iter_init (&iter, value->colors);
+ while (g_hash_table_iter_next (&iter, &name, &color))
+ {
+ if (first)
+ first = FALSE;
+ else
+ g_string_append (string, ", ");
+ g_string_append (string, name);
+ g_string_append_c (string, ' ');
+ _gtk_css_value_print (color, string);
+ }
+}
+
+static const GtkCssValueClass GTK_CSS_VALUE_PALETTE = {
+ gtk_css_value_palette_free,
+ gtk_css_value_palette_compute,
+ gtk_css_value_palette_equal,
+ gtk_css_value_palette_transition,
+ gtk_css_value_palette_print
+};
+
+static GtkCssValue *
+gtk_css_palette_value_new_empty (void)
+{
+ GtkCssValue *result;
+
+ result = _gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_PALETTE);
+ result->colors = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free,
+ (GDestroyNotify) _gtk_css_value_unref);
+
+ return result;
+}
+
+GtkCssValue *
+gtk_css_palette_value_new_default (void)
+{
+ if (default_palette == NULL)
+ {
+ default_palette = gtk_css_palette_value_new_empty ();
+ gtk_css_palette_value_add_color (default_palette, "error", _gtk_css_color_value_new_name ("error_color"));
+ gtk_css_palette_value_add_color (default_palette, "warning", _gtk_css_color_value_new_name ("warning_color"));
+ gtk_css_palette_value_add_color (default_palette, "success", _gtk_css_color_value_new_name ("success_color"));
+ }
+
+ return _gtk_css_value_ref (default_palette);
+}
+
+GtkCssValue *
+gtk_css_palette_value_parse (GtkCssParser *parser)
+{
+ GtkCssValue *result, *color;
+ char *ident;
+
+ if (_gtk_css_parser_try (parser, "default", TRUE))
+ return gtk_css_palette_value_new_default ();
+
+ result = gtk_css_palette_value_new_empty ();
+
+ do {
+ ident = _gtk_css_parser_try_ident (parser, TRUE);
+ if (ident == NULL)
+ {
+ _gtk_css_parser_error (parser, "expected color name");
+ _gtk_css_value_unref (result);
+ return NULL;
+ }
+
+ color = _gtk_css_color_value_parse (parser);
+ if (color == NULL)
+ {
+ g_free (ident);
+ _gtk_css_value_unref (result);
+ return NULL;
+ }
+
+ gtk_css_palette_value_add_color (result, ident, color);
+ g_free (ident);
+ } while (_gtk_css_parser_try (parser, ",", TRUE));
+
+ return result;
+}
+
+const GdkRGBA *
+gtk_css_palette_value_get_color (GtkCssValue *value,
+ const char *name)
+{
+ GtkCssValue *color;
+
+ g_return_val_if_fail (value->class == >K_CSS_VALUE_PALETTE, NULL);
+
+ color = g_hash_table_lookup (value->colors, name);
+ if (color == NULL)
+ return NULL;
+
+ return _gtk_css_rgba_value_get_rgba (color);
+}
diff --git a/gtk/gtkcsspalettevalueprivate.h b/gtk/gtkcsspalettevalueprivate.h
new file mode 100644
index 0000000000..b422494a8a
--- /dev/null
+++ b/gtk/gtkcsspalettevalueprivate.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2012 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Alexander Larsson
+ */
+
+#ifndef __GTK_CSS_PALETTE_VALUE_PRIVATE_H__
+#define __GTK_CSS_PALETTE_VALUE_PRIVATE_H__
+
+#include "gtkcssparserprivate.h"
+#include "gtkcssvalueprivate.h"
+
+G_BEGIN_DECLS
+
+GtkCssValue * gtk_css_palette_value_new_default (void);
+
+GtkCssValue * gtk_css_palette_value_parse (GtkCssParser *parser);
+
+const GdkRGBA * gtk_css_palette_value_get_color (GtkCssValue *value,
+ const char *color_name);
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_PALETTE_VALUE_PRIVATE_H__ */
diff --git a/gtk/gtkcssstylepropertyimpl.c b/gtk/gtkcssstylepropertyimpl.c
index 5c48ce8a5b..60030817eb 100644
--- a/gtk/gtkcssstylepropertyimpl.c
+++ b/gtk/gtkcssstylepropertyimpl.c
@@ -53,6 +53,7 @@
#include "gtkcssinitialvalueprivate.h"
#include "gtkcssenumvalueprivate.h"
#include "gtkcssnumbervalueprivate.h"
+#include "gtkcsspalettevalueprivate.h"
#include "gtkcsspositionvalueprivate.h"
#include "gtkcssrepeatvalueprivate.h"
#include "gtkcssrgbavalueprivate.h"
@@ -505,6 +506,13 @@ image_effect_parse (GtkCssStyleProperty *property,
return value;
}
+static GtkCssValue *
+icon_palette_parse (GtkCssStyleProperty *property,
+ GtkCssParser *parser)
+{
+ return gtk_css_palette_value_parse (parser);
+}
+
static GtkCssValue *
icon_style_parse (GtkCssStyleProperty *property,
GtkCssParser *parser)
@@ -1727,6 +1735,16 @@ _gtk_css_style_property_init_properties (void)
NULL,
NULL,
_gtk_css_icon_effect_value_new (GTK_CSS_ICON_EFFECT_NONE));
+ gtk_css_style_property_register ("-gtk-icon-palette",
+ GTK_CSS_PROPERTY_ICON_PALETTE,
+ G_TYPE_NONE,
+ GTK_STYLE_PROPERTY_ANIMATED | GTK_STYLE_PROPERTY_INHERIT,
+ GTK_CSS_AFFECTS_ICON,
+ icon_palette_parse,
+ NULL,
+ NULL,
+ gtk_css_palette_value_new_default ());
+
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_css_style_property_register ("engine",
diff --git a/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h
index 631b59376b..692bea9110 100644
--- a/gtk/gtkcsstypesprivate.h
+++ b/gtk/gtkcsstypesprivate.h
@@ -217,6 +217,7 @@ enum { /*< skip >*/
GTK_CSS_PROPERTY_ANIMATION_FILL_MODE,
GTK_CSS_PROPERTY_OPACITY,
GTK_CSS_PROPERTY_GTK_IMAGE_EFFECT,
+ GTK_CSS_PROPERTY_ICON_PALETTE,
GTK_CSS_PROPERTY_ENGINE,
GTK_CSS_PROPERTY_GTK_KEY_BINDINGS,
/* add more */
diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
index 38d5d36602..a440510139 100644
--- a/gtk/gtkicontheme.c
+++ b/gtk/gtkicontheme.c
@@ -38,6 +38,8 @@
#endif /* G_OS_WIN32 */
#include "gtkicontheme.h"
+#include "gtkcsspalettevalueprivate.h"
+#include "gtkcssrgbavalueprivate.h"
#include "gtkdebug.h"
#include "deprecated/gtkiconfactory.h"
#include "gtkiconcache.h"
@@ -45,6 +47,7 @@
#include "gtkmain.h"
#include "deprecated/gtknumerableiconprivate.h"
#include "gtksettingsprivate.h"
+#include "gtkstylecontextprivate.h"
#include "gtkprivate.h"
#undef GDK_DEPRECATED
@@ -4663,6 +4666,39 @@ gtk_icon_info_load_symbolic (GtkIconInfo *icon_info,
error);
}
+static void
+lookup_colors_from_style_context (GtkStyleContext *context,
+ GdkRGBA *color_out,
+ GdkRGBA *success_out,
+ GdkRGBA *warning_out,
+ GdkRGBA *error_out)
+{
+ GtkCssValue *palette, *color;
+ const GdkRGBA *lookup;
+
+ color = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR);
+ palette = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ICON_PALETTE);
+ *color_out = *_gtk_css_rgba_value_get_rgba (color);
+
+ lookup = gtk_css_palette_value_get_color (palette, "success");
+ if (lookup)
+ *success_out = *lookup;
+ else
+ *success_out = *color_out;
+
+ lookup = gtk_css_palette_value_get_color (palette, "warning");
+ if (lookup)
+ *warning_out = *lookup;
+ else
+ *warning_out = *color_out;
+
+ lookup = gtk_css_palette_value_get_color (palette, "error");
+ if (lookup)
+ *error_out = *lookup;
+ else
+ *error_out = *color_out;
+}
+
/**
* gtk_icon_info_load_symbolic_for_context:
* @icon_info: a #GtkIconInfo
@@ -4694,16 +4730,10 @@ gtk_icon_info_load_symbolic_for_context (GtkIconInfo *icon_info,
gboolean *was_symbolic,
GError **error)
{
- GdkRGBA *color = NULL;
GdkRGBA fg;
- GdkRGBA *fgp;
GdkRGBA success_color;
- GdkRGBA *success_colorp;
GdkRGBA warning_color;
- GdkRGBA *warning_colorp;
GdkRGBA error_color;
- GdkRGBA *error_colorp;
- GtkStateFlags state;
gboolean is_symbolic;
g_return_val_if_fail (icon_info != NULL, NULL);
@@ -4717,29 +4747,11 @@ gtk_icon_info_load_symbolic_for_context (GtkIconInfo *icon_info,
if (!is_symbolic)
return gtk_icon_info_load_icon (icon_info, error);
- fgp = success_colorp = warning_colorp = error_colorp = NULL;
-
- state = gtk_style_context_get_state (context);
- gtk_style_context_get (context, state, "color", &color, NULL);
- if (color)
- {
- fg = *color;
- fgp = &fg;
- gdk_rgba_free (color);
- }
-
- if (gtk_style_context_lookup_color (context, "success_color", &success_color))
- success_colorp = &success_color;
-
- if (gtk_style_context_lookup_color (context, "warning_color", &warning_color))
- warning_colorp = &warning_color;
-
- if (gtk_style_context_lookup_color (context, "error_color", &error_color))
- error_colorp = &error_color;
+ lookup_colors_from_style_context (context, &fg, &success_color, &warning_color, &error_color);
return gtk_icon_info_load_symbolic_internal (icon_info,
- fgp, success_colorp,
- warning_colorp, error_colorp,
+ &fg, &success_color,
+ &warning_color, &error_color,
TRUE,
error);
}
@@ -4991,43 +5003,19 @@ gtk_icon_info_load_symbolic_for_context_async (GtkIconInfo *icon_info,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GdkRGBA *color = NULL;
GdkRGBA fg;
- GdkRGBA *fgp;
GdkRGBA success_color;
- GdkRGBA *success_colorp;
GdkRGBA warning_color;
- GdkRGBA *warning_colorp;
GdkRGBA error_color;
- GdkRGBA *error_colorp;
- GtkStateFlags state;
g_return_if_fail (icon_info != NULL);
g_return_if_fail (context != NULL);
- fgp = success_colorp = warning_colorp = error_colorp = NULL;
-
- state = gtk_style_context_get_state (context);
- gtk_style_context_get (context, state, "color", &color, NULL);
- if (color)
- {
- fg = *color;
- fgp = &fg;
- gdk_rgba_free (color);
- }
-
- if (gtk_style_context_lookup_color (context, "success_color", &success_color))
- success_colorp = &success_color;
-
- if (gtk_style_context_lookup_color (context, "warning_color", &warning_color))
- warning_colorp = &warning_color;
-
- if (gtk_style_context_lookup_color (context, "error_color", &error_color))
- error_colorp = &error_color;
+ lookup_colors_from_style_context (context, &fg, &success_color, &warning_color, &error_color);
gtk_icon_info_load_symbolic_async (icon_info,
- fgp, success_colorp,
- warning_colorp, error_colorp,
+ &fg, &success_color,
+ &warning_color, &error_color,
cancellable, callback, user_data);
}