[gtk+] css: Introduct -gtk-icon-palette



commit 7fa37e4bf886745e8e7b07b6653513ac4c5172d3
Author: Benjamin Otte <otte redhat com>
Date:   Thu Dec 3 00:33:51 2015 +0100

    css: Introduct -gtk-icon-palette
    
    This borrows heavily from the CSS4 fonts draft's font-palette, currently
    found at https://drafts.csswg.org/css-fonts-4/#font-palette-control
    
    The palette is mainly meant to trigger invalidations when colors used for
    symbolic icons change, to potentially allow extending supported colors
    in symbolic icons and to recolor all colors of a symbolic icon, not just
    the main one.
    
    The syntax for the property goes like this:
    Name:        -gtk-icon-palette
    Value:       default | name <color> [ , name <color> ]*
    Initial:     default
    Applies to:  all elements with icons
    Inherited:   yes
    Animatable:  yes, each color animated separately
    
    The property defines a list of named colors to be used when looking up
    icons. If a name is not defined, the value of the current "color"
    property is used. Which names are relevant depends on the icons in use.
    Currently symbolic icons make use of the names "success", "warning" and
    "error".
    
    "default" is the current behavior of the GTK when coloring symbolic
    icons and is equal to the string
      success @success_color, warning @warning_color, error @error_color
    
    Animation is crudely implemented by animating colors that are in both
    palettes that are animated and otherwise keeping the color from the
    palette that defined it. Note that this can cause a sharp cut at the
    beginning or end of the animation when the color goes away and will
    therefore be replaced with the color property.
    
    You can see an example of animations at
    http://gfycat.com/CautiousPeacefulIaerismetalmark

 gtk/Makefile.am                 |    2 +
 gtk/gtkcsscolorvalue.c          |    2 +
 gtk/gtkcsspalettevalue.c        |  258 +++++++++++++++++++++++++++++++++++++++
 gtk/gtkcsspalettevalueprivate.h |   37 ++++++
 gtk/gtkcssstylepropertyimpl.c   |   18 +++
 gtk/gtkcsstypesprivate.h        |    1 +
 gtk/gtkicontheme.c              |   96 +++++++--------
 7 files changed, 360 insertions(+), 54 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 43ebb9e..1498173 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 7e78134..6cd0cf0 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 0000000..cf98968
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#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, &GTK_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 == &GTK_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 0000000..b422494
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Alexander Larsson <alexl gnome org>
+ */
+
+#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 5c48ce8..6003081 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"
@@ -506,6 +507,13 @@ image_effect_parse (GtkCssStyleProperty *property,
 }
 
 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 631b593..692bea9 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 38d5d36..a440510 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);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]