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); }