]> Pileus Git - ~andy/gtk/commitdiff
Added symbolic themable colors. Patch is a merged version of proposals
authorMichael Natterer <mitch@imendio.com>
Wed, 23 Nov 2005 10:33:58 +0000 (10:33 +0000)
committerMichael Natterer <mitch@src.gnome.org>
Wed, 23 Nov 2005 10:33:58 +0000 (10:33 +0000)
2005-11-23  Michael Natterer  <mitch@imendio.com>

Added symbolic themable colors. Patch is a merged version of
proposals from Matthias and maemo-gtk. Fixes bug #114355.

* configure.in: require glib >= 2.9.1 for refcountable hashtables.

* gtk/gtksettings.c: added property "color-scheme" which is a
string defining colors like "foreground:black\nbackground:grey".
Automatically provide a name->GdkColor hash table mapping for the
color scheme.

* gtk/gtkrc.[ch]: added list of color hashes that works like the
list of icon factories. Append the color scheme hash from
GtkSettings if it exists. Extended gtkrc syntax to allow defining
and referencing of logical colors. Also allow to modulate colors
in gtkrc by using arbitrary expressions of mix(), shade(),
lighter() and darker(). Added internal function
_gtk_rc_style_get_color_hashes().

* gtk/gtkstyle.[ch]: keep a private list of color hashes around.
Get the list from _gtk_rc_style_get_color_hashes(). Export
internal function _gtk_style_shade() (used by above color
expressions). Added public API gtk_style_lookup_color() which
looks up a logical color by name.

* gtk/gtk.symbols: add gtk_style_lookup_color

* tests/testgtkrc: use symbolic colors for making
the scrollbars red.

ChangeLog
ChangeLog.pre-2-10
configure.in
gtk/gtk.symbols
gtk/gtkrc.c
gtk/gtkrc.h
gtk/gtksettings.c
gtk/gtkstyle.c
gtk/gtkstyle.h
tests/testgtkrc

index e2128422056c719f4b96663a8ad7b739384441e9..cd8f5c72e01f14af90bef2056395fd87128cf1d0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+2005-11-23  Michael Natterer  <mitch@imendio.com>
+
+       Added symbolic themable colors. Patch is a merged version of
+       proposals from Matthias and maemo-gtk. Fixes bug #114355.
+
+       * configure.in: require glib >= 2.9.1 for refcountable hashtables.
+
+       * gtk/gtksettings.c: added property "color-scheme" which is a
+       string defining colors like "foreground:black\nbackground:grey".
+       Automatically provide a name->GdkColor hash table mapping for the
+       color scheme.
+
+       * gtk/gtkrc.[ch]: added list of color hashes that works like the
+       list of icon factories. Append the color scheme hash from
+       GtkSettings if it exists. Extended gtkrc syntax to allow defining
+       and referencing of logical colors. Also allow to modulate colors
+       in gtkrc by using arbitrary expressions of mix(), shade(),
+       lighter() and darker(). Added internal function
+       _gtk_rc_style_get_color_hashes().
+
+       * gtk/gtkstyle.[ch]: keep a private list of color hashes around.
+       Get the list from _gtk_rc_style_get_color_hashes(). Export
+       internal function _gtk_style_shade() (used by above color
+       expressions). Added public API gtk_style_lookup_color() which
+       looks up a logical color by name.
+
+       * gtk/gtk.symbols: add gtk_style_lookup_color
+
+       * tests/testgtkrc: use symbolic colors for making
+       the scrollbars red.
+
 2005-11-22  Michael Natterer  <mitch@imendio.com>
 
        Made button-press timeouts which work like key repeat timeouts
index e2128422056c719f4b96663a8ad7b739384441e9..cd8f5c72e01f14af90bef2056395fd87128cf1d0 100644 (file)
@@ -1,3 +1,34 @@
+2005-11-23  Michael Natterer  <mitch@imendio.com>
+
+       Added symbolic themable colors. Patch is a merged version of
+       proposals from Matthias and maemo-gtk. Fixes bug #114355.
+
+       * configure.in: require glib >= 2.9.1 for refcountable hashtables.
+
+       * gtk/gtksettings.c: added property "color-scheme" which is a
+       string defining colors like "foreground:black\nbackground:grey".
+       Automatically provide a name->GdkColor hash table mapping for the
+       color scheme.
+
+       * gtk/gtkrc.[ch]: added list of color hashes that works like the
+       list of icon factories. Append the color scheme hash from
+       GtkSettings if it exists. Extended gtkrc syntax to allow defining
+       and referencing of logical colors. Also allow to modulate colors
+       in gtkrc by using arbitrary expressions of mix(), shade(),
+       lighter() and darker(). Added internal function
+       _gtk_rc_style_get_color_hashes().
+
+       * gtk/gtkstyle.[ch]: keep a private list of color hashes around.
+       Get the list from _gtk_rc_style_get_color_hashes(). Export
+       internal function _gtk_style_shade() (used by above color
+       expressions). Added public API gtk_style_lookup_color() which
+       looks up a logical color by name.
+
+       * gtk/gtk.symbols: add gtk_style_lookup_color
+
+       * tests/testgtkrc: use symbolic colors for making
+       the scrollbars red.
+
 2005-11-22  Michael Natterer  <mitch@imendio.com>
 
        Made button-press timeouts which work like key repeat timeouts
index 3fb3599924763c0e92c2d6f6ec20be45110eb4e8..64ae6ff9457e54fcc1cb1b578a71c07d677aace4 100644 (file)
@@ -31,7 +31,7 @@ m4_define([gtk_api_version], [2.0])
 m4_define([gtk_binary_version], [2.4.0])
 
 # required versions of other packages
-m4_define([glib_required_version], [2.9.0])
+m4_define([glib_required_version], [2.9.1])
 m4_define([pango_required_version], [1.9.0])
 m4_define([atk_required_version], [1.0.1])
 m4_define([cairo_required_version], [0.9.2])
index da23d2989215570e96f4e4b9961b33f19493827c..97e88e44938ddaa9898aa52a4edfd1bb1a624534 100644 (file)
@@ -1068,6 +1068,7 @@ gtk_style_copy
 gtk_style_detach
 gtk_style_get_type G_GNUC_CONST
 gtk_style_lookup_icon_set
+gtk_style_lookup_color
 gtk_style_new
 gtk_style_render_icon
 gtk_style_set_background
index 8fbb01a1620dc7bced82795e7ec86c2c11952df9..41c8160d1bd8dc7a2dbabd5ca8ab5d8b5847a92a 100644 (file)
@@ -104,6 +104,18 @@ struct _GtkRcContext
 
   gint default_priority;
   GtkStyle *default_style;
+
+  gchar *colors;
+  GHashTable *color_hash;
+};
+
+#define GTK_RC_STYLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_RC_STYLE, GtkRcStylePrivate))
+
+typedef struct _GtkRcStylePrivate GtkRcStylePrivate;
+
+struct _GtkRcStylePrivate
+{
+  GSList *color_hashes;
 };
 
 static GtkRcContext *gtk_rc_context_get              (GtkSettings     *settings);
@@ -180,6 +192,13 @@ static guint       gtk_rc_parse_stock                (GtkRcContext    *context,
                                                      GScanner        *scanner,
                                                       GtkRcStyle      *rc_style,
                                                       GtkIconFactory  *factory);
+static guint       gtk_rc_parse_logical_color        (GScanner        *scanner,
+                                                      GtkRcStyle      *rc_style,
+                                                      GHashTable      *hash);
+static guint       gtk_rc_parse_color_full           (GScanner        *scanner,
+                                                      GtkRcStyle      *style,
+                                                      GdkColor        *color);
+
 static void        gtk_rc_clear_hash_node            (gpointer         key,
                                                       gpointer         data,
                                                       gpointer         user_data);
@@ -278,7 +297,8 @@ static const struct
   { "stock", GTK_RC_TOKEN_STOCK },
   { "im_module_file", GTK_RC_TOKEN_IM_MODULE_FILE },
   { "LTR", GTK_RC_TOKEN_LTR },
-  { "RTL", GTK_RC_TOKEN_RTL }
+  { "RTL", GTK_RC_TOKEN_RTL },
+  { "color", GTK_RC_TOKEN_COLOR }
 };
 
 static GHashTable *realized_style_ht = NULL;
@@ -553,6 +573,40 @@ gtk_rc_font_name_changed (GtkSettings  *settings,
   _gtk_rc_context_get_default_font_name (settings);
 }
 
+static void
+gtk_rc_color_scheme_changed (GtkSettings  *settings,
+                             GParamSpec   *pspec,
+                             GtkRcContext *context)
+{
+  gchar *colors;
+
+  g_object_get (settings,
+               "gtk-color-scheme", &colors,
+               NULL);
+
+  if (!colors && !context->colors)
+    return;
+
+  if (!colors || !context->colors ||
+      strcmp (colors, context->colors) != 0)
+    {
+      g_free (context->colors);
+      context->colors = g_strdup (colors);
+
+      if (context->color_hash)
+        g_hash_table_unref (context->color_hash);
+
+      context->color_hash = g_object_get_data (G_OBJECT (settings),
+                                               "gtk-color-scheme");
+      if (context->color_hash)
+        g_hash_table_ref (context->color_hash);
+
+      gtk_rc_reparse_all_for_settings (settings, TRUE);
+    }
+
+  g_free (colors);
+}
+
 static GtkRcContext *
 gtk_rc_context_get (GtkSettings *settings)
 {
@@ -572,8 +626,14 @@ gtk_rc_context_get (GtkSettings *settings)
                    "gtk-theme-name", &context->theme_name,
                    "gtk-key-theme-name", &context->key_theme_name,
                    "gtk-font-name", &context->font_name,
+                   "gtk-color-scheme", &context->colors,
                    NULL);
 
+      context->color_hash = g_object_get_data (G_OBJECT (settings),
+                                               "gtk-color-scheme");
+      if (context->color_hash)
+        g_hash_table_ref (context->color_hash);
+
       g_signal_connect (settings,
                        "notify::gtk-theme-name",
                        G_CALLBACK (gtk_rc_settings_changed),
@@ -586,8 +646,11 @@ gtk_rc_context_get (GtkSettings *settings)
                        "notify::gtk-font-name",
                        G_CALLBACK (gtk_rc_font_name_changed),
                        context);
+      g_signal_connect (settings,
+                       "notify::gtk-color-scheme",
+                       G_CALLBACK (gtk_rc_color_scheme_changed),
+                       context);
 
-      
       context->pixmap_path[0] = NULL;
 
       context->default_priority = GTK_PATH_PRIO_RC;
@@ -955,6 +1018,7 @@ gtk_rc_style_get_type (void)
 static void
 gtk_rc_style_init (GtkRcStyle *style)
 {
+  GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (style);
   guint i;
 
   style->name = NULL;
@@ -977,6 +1041,8 @@ gtk_rc_style_init (GtkRcStyle *style)
 
   style->rc_style_lists = NULL;
   style->icon_factories = NULL;
+
+  priv->color_hashes = NULL;
 }
 
 static void
@@ -992,6 +1058,8 @@ gtk_rc_style_class_init (GtkRcStyleClass *klass)
   klass->create_rc_style = gtk_rc_style_real_create_rc_style;
   klass->merge = gtk_rc_style_real_merge;
   klass->create_style = gtk_rc_style_real_create_style;
+
+  g_type_class_add_private (object_class, sizeof (GtkRcStylePrivate));
 }
 
 static void
@@ -999,10 +1067,12 @@ gtk_rc_style_finalize (GObject *object)
 {
   GSList *tmp_list1, *tmp_list2;
   GtkRcStyle *rc_style;
+  GtkRcStylePrivate *rc_priv;
   gint i;
 
   rc_style = GTK_RC_STYLE (object);
-  
+  rc_priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
+
   if (rc_style->name)
     g_free (rc_style->name);
   if (rc_style->font_desc)
@@ -1060,14 +1130,12 @@ gtk_rc_style_finalize (GObject *object)
       rc_style->rc_properties = NULL;
     }
 
-  tmp_list1 = rc_style->icon_factories;
-  while (tmp_list1)
-    {
-      g_object_unref (tmp_list1->data);
-      tmp_list1 = tmp_list1->next;
-    }
+  g_slist_foreach (rc_style->icon_factories, (GFunc) g_object_unref, NULL);
   g_slist_free (rc_style->icon_factories);
-  
+
+  g_slist_foreach (rc_priv->color_hashes, (GFunc) g_hash_table_unref, NULL);
+  g_slist_free (rc_priv->color_hashes);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -1126,6 +1194,14 @@ gtk_rc_style_real_create_rc_style (GtkRcStyle *style)
   return g_object_new (G_OBJECT_TYPE (style), NULL);
 }
 
+GSList *
+_gtk_rc_style_get_color_hashes (GtkRcStyle *rc_style)
+{
+  GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
+
+  return priv->color_hashes;
+}
+
 static gint
 gtk_rc_properties_cmp (gconstpointer bsearch_node1,
                       gconstpointer bsearch_node2)
@@ -2086,6 +2162,7 @@ gtk_rc_init_style (GtkRcContext *context,
     {
       GtkRcStyle *base_style = NULL;
       GtkRcStyle *proto_style;
+      GtkRcStylePrivate *proto_priv;
       GtkRcStyleClass *proto_style_class;
       GSList *tmp_styles;
       GType rc_style_type = GTK_TYPE_RC_STYLE;
@@ -2113,12 +2190,14 @@ gtk_rc_init_style (GtkRcContext *context,
       
       proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
       proto_style = proto_style_class->create_rc_style (base_style);
-      
+      proto_priv = GTK_RC_STYLE_GET_PRIVATE (proto_style);
+
       tmp_styles = rc_styles;
       while (tmp_styles)
        {
          GtkRcStyle *rc_style = tmp_styles->data;
-          GSList *factories;
+          GtkRcStylePrivate *rc_priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
+          GSList *concat_list;
           
          proto_style_class->merge (proto_style, rc_style);       
           
@@ -2126,23 +2205,16 @@ gtk_rc_init_style (GtkRcContext *context,
          if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
            rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
 
-          factories = g_slist_copy (rc_style->icon_factories);
-          if (factories)
-            {
-              GSList *iter;
-              
-              iter = factories;
-              while (iter != NULL)
-                {
-                  g_object_ref (iter->data);
-                  iter = g_slist_next (iter);
-                }
+          concat_list = g_slist_copy (rc_style->icon_factories);
+          g_slist_foreach (concat_list, (GFunc) g_object_ref, NULL);
+          proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
+                                                        concat_list);
 
-              proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
-                                                            factories);
+          concat_list = g_slist_copy (rc_priv->color_hashes);
+          g_slist_foreach (concat_list, (GFunc) g_hash_table_ref, NULL);
+          proto_priv->color_hashes = g_slist_concat (proto_priv->color_hashes,
+                                                     concat_list);
 
-            }
-          
          tmp_styles = tmp_styles->next;
        }
 
@@ -2519,10 +2591,12 @@ gtk_rc_parse_style (GtkRcContext *context,
   GtkRcStyle *rc_style;
   GtkRcStyle *orig_style;
   GtkRcStyle *parent_style;
+  GtkRcStylePrivate *rc_priv = NULL;
   guint token;
   gint i;
   GtkIconFactory *our_factory = NULL;
-  
+  GHashTable *our_hash = NULL;
+
   token = g_scanner_get_next_token (scanner);
   if (token != GTK_RC_TOKEN_STYLE)
     return GTK_RC_TOKEN_STYLE;
@@ -2537,12 +2611,6 @@ gtk_rc_parse_style (GtkRcContext *context,
   else
     orig_style = NULL;
 
-  /* If there's a list, its first member is always the factory belonging
-   * to this RcStyle
-   */
-  if (rc_style && rc_style->icon_factories)
-    our_factory = rc_style->icon_factories->data;
-  
   if (!rc_style)
     {
       rc_style = gtk_rc_style_new ();
@@ -2555,6 +2623,16 @@ gtk_rc_parse_style (GtkRcContext *context,
        rc_style->color_flags[i] = 0;
     }
 
+  rc_priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
+
+  /* If there's a list, its first member is always the factory belonging
+   * to this RcStyle
+   */
+  if (rc_style->icon_factories)
+    our_factory = rc_style->icon_factories->data;
+  if (rc_priv->color_hashes)
+    our_hash = rc_priv->color_hashes->data;
+
   token = g_scanner_peek_next_token (scanner);
   if (token == G_TOKEN_EQUAL_SIGN)
     {
@@ -2570,8 +2648,9 @@ gtk_rc_parse_style (GtkRcContext *context,
       parent_style = gtk_rc_style_find (context, scanner->value.v_string);
       if (parent_style)
        {
-          GSList *factories;
-          
+          GtkRcStylePrivate *parent_priv = GTK_RC_STYLE_GET_PRIVATE (parent_style);
+          GSList *concat_list;
+
          for (i = 0; i < 5; i++)
            {
              rc_style->color_flags[i] = parent_style->color_flags[i];
@@ -2625,20 +2704,48 @@ gtk_rc_parse_style (GtkRcContext *context,
                   rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories,
                                                               our_factory);
                 }
-              
+
+              concat_list = g_slist_copy (parent_style->icon_factories);
+              g_slist_foreach (concat_list, (GFunc) g_object_ref, NULL);
               rc_style->icon_factories = g_slist_concat (rc_style->icon_factories,
-                                                         g_slist_copy (parent_style->icon_factories));
-              
-              factories = parent_style->icon_factories;
-              while (factories != NULL)
+                                                         concat_list);
+            }
+
+          /* Also append parent's color hashes, adding a ref to them */
+          if (parent_priv->color_hashes != NULL)
+            {
+              /* See comment above .. */
+              if (our_hash == NULL)
                 {
-                  g_object_ref (factories->data);
-                  factories = factories->next;
+                  our_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                    g_free,
+                                                    (GDestroyNotify) gdk_color_free);
+                  rc_priv->color_hashes = g_slist_prepend (rc_priv->color_hashes,
+                                                           our_hash);
                 }
+
+              concat_list = g_slist_copy (parent_priv->color_hashes);
+              g_slist_foreach (concat_list, (GFunc) g_hash_table_ref, NULL);
+              rc_priv->color_hashes = g_slist_concat (rc_priv->color_hashes,
+                                                      concat_list);
             }
        }
     }
-  
+
+  /*  if we didn't get color hashes from our parent style, initialize
+   *  the list with the settings' color scheme (if it exists)
+   */
+  if (our_hash == NULL && context->color_hash != NULL)
+    {
+      our_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                        g_free,
+                                        (GDestroyNotify) gdk_color_free);
+      rc_priv->color_hashes = g_slist_prepend (rc_priv->color_hashes,
+                                               our_hash);
+      rc_priv->color_hashes = g_slist_append (rc_priv->color_hashes,
+                                              g_hash_table_ref (context->color_hash));
+    }
+
   token = g_scanner_get_next_token (scanner);
   if (token != G_TOKEN_LEFT_CURLY)
     {
@@ -2693,6 +2800,17 @@ gtk_rc_parse_style (GtkRcContext *context,
             }
           token = gtk_rc_parse_stock (context, scanner, rc_style, our_factory);
           break;
+        case GTK_RC_TOKEN_COLOR:
+          if (our_hash == NULL)
+            {
+              our_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                g_free,
+                                                (GDestroyNotify) gdk_color_free);
+              rc_priv->color_hashes = g_slist_prepend (rc_priv->color_hashes,
+                                                       our_hash);
+            }
+          token = gtk_rc_parse_logical_color (scanner, rc_style, our_hash);
+          break;
        case G_TOKEN_IDENTIFIER:
          if (is_c_identifier (scanner->next_value.v_identifier) &&
              scanner->next_value.v_identifier[0] >= 'A' &&
@@ -2700,7 +2818,7 @@ gtk_rc_parse_style (GtkRcContext *context,
            {
              GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
              gchar *name;
-             
+
              g_scanner_get_next_token (scanner); /* eat type name */
              prop.type_name = g_quark_from_string (scanner->value.v_identifier);
              if (g_scanner_get_next_token (scanner) != ':' ||
@@ -2832,7 +2950,7 @@ gtk_rc_parse_bg (GScanner   *scanner,
     return G_TOKEN_EQUAL_SIGN;
 
   style->color_flags[state] |= GTK_RC_BG;
-  return gtk_rc_parse_color (scanner, &style->bg[state]);
+  return gtk_rc_parse_color_full (scanner, style, &style->bg[state]);
 }
 
 static guint
@@ -2855,7 +2973,7 @@ gtk_rc_parse_fg (GScanner   *scanner,
     return G_TOKEN_EQUAL_SIGN;
   
   style->color_flags[state] |= GTK_RC_FG;
-  return gtk_rc_parse_color (scanner, &style->fg[state]);
+  return gtk_rc_parse_color_full (scanner, style, &style->fg[state]);
 }
 
 static guint
@@ -2878,7 +2996,7 @@ gtk_rc_parse_text (GScanner   *scanner,
     return G_TOKEN_EQUAL_SIGN;
   
   style->color_flags[state] |= GTK_RC_TEXT;
-  return gtk_rc_parse_color (scanner, &style->text[state]);
+  return gtk_rc_parse_color_full (scanner, style, &style->text[state]);
 }
 
 static guint
@@ -2901,7 +3019,7 @@ gtk_rc_parse_base (GScanner   *scanner,
     return G_TOKEN_EQUAL_SIGN;
 
   style->color_flags[state] |= GTK_RC_BASE;
-  return gtk_rc_parse_color (scanner, &style->base[state]);
+  return gtk_rc_parse_color_full (scanner, style, &style->base[state]);
 }
 
 static guint
@@ -3353,9 +3471,42 @@ gtk_rc_parse_priority (GScanner             *scanner,
   return G_TOKEN_NONE;
 }
 
+static gboolean
+lookup_color (GtkRcStyle *style,
+              const char *color_name,
+              GdkColor   *color)
+{
+  GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (style);
+  GSList *iter;
+
+  for (iter = priv->color_hashes; iter != NULL; iter = iter->next)
+    {
+      GHashTable *hash  = iter->data;
+      GdkColor   *match = g_hash_table_lookup (hash, color_name);
+
+      if (match)
+        {
+          color->red = match->red;
+          color->green = match->green;
+          color->blue = match->blue;
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
 guint
 gtk_rc_parse_color (GScanner *scanner,
                    GdkColor *color)
+{
+  return gtk_rc_parse_color_full (scanner, NULL, color);
+}
+
+static guint
+gtk_rc_parse_color_full (GScanner   *scanner,
+                         GtkRcStyle *style,
+                         GdkColor   *color)
 {
   guint token;
 
@@ -3369,7 +3520,10 @@ gtk_rc_parse_color (GScanner *scanner,
   switch (token)
     {
       gint token_int;
-      
+      GdkColor c1, c2;
+      gboolean negate;
+      gdouble l;
+
     case G_TOKEN_LEFT_CURLY:
       token = g_scanner_get_next_token (scanner);
       if (token == G_TOKEN_INT)
@@ -3414,13 +3568,134 @@ gtk_rc_parse_color (GScanner *scanner,
     case G_TOKEN_STRING:
       if (!gdk_color_parse (scanner->value.v_string, color))
        {
-         g_scanner_warn (scanner, "Invalid color constant '%s'",
-                         scanner->value.v_string);
-         return G_TOKEN_STRING;
+          g_scanner_warn (scanner, "Invalid color constant '%s'",
+                          scanner->value.v_string);
+          return G_TOKEN_STRING;
        }
+      return G_TOKEN_NONE;
+
+    case '@':
+      token = g_scanner_get_next_token (scanner);
+      if (token != G_TOKEN_IDENTIFIER)
+       return G_TOKEN_IDENTIFIER;
+
+      if (!style || !lookup_color (style, scanner->value.v_identifier, color))
+        {
+          g_scanner_warn (scanner, "Invalid symbolic color '%s'",
+                          scanner->value.v_identifier);
+          return G_TOKEN_IDENTIFIER;
+        }
+
+      return G_TOKEN_NONE;
+
+    case G_TOKEN_IDENTIFIER:
+      if (strcmp (scanner->value.v_identifier, "mix") == 0)
+        {
+          token = g_scanner_get_next_token (scanner);
+          if (token != G_TOKEN_LEFT_PAREN)
+            return G_TOKEN_LEFT_PAREN;
+
+          negate = FALSE;
+          if (g_scanner_peek_next_token (scanner) == '-')
+            {
+              g_scanner_get_next_token (scanner); /* eat sign */
+              negate = TRUE;
+            }
+
+          token = g_scanner_get_next_token (scanner);
+          if (token != G_TOKEN_FLOAT)
+            return G_TOKEN_FLOAT;
+
+          l = negate ? -scanner->value.v_float : scanner->value.v_float;
+
+          token = g_scanner_get_next_token (scanner);
+          if (token != G_TOKEN_COMMA)
+            return G_TOKEN_COMMA;
+
+          token = gtk_rc_parse_color_full (scanner, style, &c1);
+          if (token != G_TOKEN_NONE)
+            return token;
+
+         token = g_scanner_get_next_token (scanner);
+         if (token != G_TOKEN_COMMA)
+            return G_TOKEN_COMMA;
+
+         token = gtk_rc_parse_color_full (scanner, style, &c2);
+         if (token != G_TOKEN_NONE)
+            return token;
+
+         token = g_scanner_get_next_token (scanner);
+         if (token != G_TOKEN_RIGHT_PAREN)
+            return G_TOKEN_RIGHT_PAREN;
+
+         color->red   = l * c1.red   + (1.0 - l) * c2.red;
+         color->green = l * c1.green + (1.0 - l) * c2.green;
+         color->blue  = l * c1.blue  + (1.0 - l) * c2.blue;
+
+         return G_TOKEN_NONE;
+       }
+      else if (strcmp (scanner->value.v_identifier, "shade") == 0)
+        {
+         token = g_scanner_get_next_token (scanner);
+          if (token != G_TOKEN_LEFT_PAREN)
+            return G_TOKEN_LEFT_PAREN;
+
+          negate = FALSE;
+          if (g_scanner_peek_next_token (scanner) == '-')
+            {
+              g_scanner_get_next_token (scanner); /* eat sign */
+              negate = TRUE;
+            }
+
+          token = g_scanner_get_next_token (scanner);
+          if (token != G_TOKEN_FLOAT)
+            return G_TOKEN_FLOAT;
+
+          l = negate ? -scanner->value.v_float : scanner->value.v_float;
+
+          token = g_scanner_get_next_token (scanner);
+          if (token != G_TOKEN_COMMA)
+            return G_TOKEN_COMMA;
+
+          token = gtk_rc_parse_color_full (scanner, style, &c1);
+          if (token != G_TOKEN_NONE)
+            return token;
+
+          token = g_scanner_get_next_token (scanner);
+          if (token != G_TOKEN_RIGHT_PAREN)
+            return G_TOKEN_RIGHT_PAREN;
+
+          _gtk_style_shade (&c1, color, l);
+
+          return G_TOKEN_NONE;
+        }
+      else if (strcmp (scanner->value.v_identifier, "lighter") == 0 ||
+               strcmp (scanner->value.v_identifier, "darker") == 0)
+        {
+          if (scanner->value.v_identifier[0] == 'l')
+            l = 1.3;
+          else
+           l = 0.7;
+
+         token = g_scanner_get_next_token (scanner);
+          if (token != G_TOKEN_LEFT_PAREN)
+            return G_TOKEN_LEFT_PAREN;
+
+          token = gtk_rc_parse_color_full (scanner, style, &c1);
+          if (token != G_TOKEN_NONE)
+            return token;
+
+          token = g_scanner_get_next_token (scanner);
+          if (token != G_TOKEN_RIGHT_PAREN)
+            return G_TOKEN_RIGHT_PAREN;
+
+          _gtk_style_shade (&c1, color, l);
+
+          return G_TOKEN_NONE;
+        }
       else
-       return G_TOKEN_NONE;
-      
+        return G_TOKEN_IDENTIFIER;
+
     default:
       return G_TOKEN_STRING;
     }
@@ -3632,8 +3907,8 @@ gtk_rc_parse_path_pattern (GtkRcContext *context,
 }
 
 static guint
-gtk_rc_parse_stock_id (GScanner         *scanner,
-                       gchar    **stock_id)
+gtk_rc_parse_hash_key (GScanner  *scanner,
+                       gchar    **hash_key)
 {
   guint token;
   
@@ -3646,12 +3921,12 @@ gtk_rc_parse_stock_id (GScanner  *scanner,
   if (token != G_TOKEN_STRING)
     return G_TOKEN_STRING;
   
-  *stock_id = g_strdup (scanner->value.v_string);
+  *hash_key = g_strdup (scanner->value.v_string);
   
   token = g_scanner_get_next_token (scanner);
   if (token != G_TOKEN_RIGHT_BRACE)
     {
-      g_free (*stock_id);
+      g_free (*hash_key);
       return G_TOKEN_RIGHT_BRACE;
     }
   
@@ -3861,7 +4136,7 @@ gtk_rc_parse_stock (GtkRcContext   *context,
   if (token != GTK_RC_TOKEN_STOCK)
     return GTK_RC_TOKEN_STOCK;
   
-  token = gtk_rc_parse_stock_id (scanner, &stock_id);
+  token = gtk_rc_parse_hash_key (scanner, &stock_id);
   if (token != G_TOKEN_NONE)
     return token;
   
@@ -3920,6 +4195,46 @@ gtk_rc_parse_stock (GtkRcContext   *context,
   return G_TOKEN_NONE;
 }
 
+static guint
+gtk_rc_parse_logical_color (GScanner   *scanner,
+                            GtkRcStyle *rc_style,
+                            GHashTable *hash)
+{
+  gchar *color_id = NULL;
+  guint token;
+  GdkColor color;
+
+  token = g_scanner_get_next_token (scanner);
+  if (token != GTK_RC_TOKEN_COLOR)
+    return GTK_RC_TOKEN_COLOR;
+
+  token = gtk_rc_parse_hash_key (scanner, &color_id);
+  if (token != G_TOKEN_NONE)
+    return token;
+
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_EQUAL_SIGN)
+    {
+      g_free (color_id);
+      return G_TOKEN_EQUAL_SIGN;
+    }
+
+  token = gtk_rc_parse_color_full (scanner, rc_style, &color);
+  if (token != G_TOKEN_NONE)
+    {
+      g_free (color_id);
+      return token;
+    }
+
+  /* Because the hash is created with destroy functions,
+   * g_hash_table_insert will free any old values for us,
+   * if a mapping with the specified key already exists.
+   */
+  g_hash_table_insert (hash, color_id, gdk_color_copy (&color));
+
+  return G_TOKEN_NONE;
+}
+
 #ifdef G_OS_WIN32
 
 /* DLL ABI stability backward compatibility versions */
index 3fb2d0d3521dbade1e109c5519fff2a2e5c31531..ea6ff22235fa3105ab8b542b1bd36a6a0a5e9c95 100644 (file)
@@ -209,6 +209,7 @@ typedef enum {
   GTK_RC_TOKEN_STOCK,
   GTK_RC_TOKEN_LTR,
   GTK_RC_TOKEN_RTL,
+  GTK_RC_TOKEN_COLOR,
   GTK_RC_TOKEN_LAST
 } GtkRcTokenType;
 
@@ -237,6 +238,8 @@ const GtkRcProperty* _gtk_rc_style_lookup_rc_property (GtkRcStyle *rc_style,
                                                       GQuark      type_name,
                                                       GQuark      property_name);
 
+GSList     * _gtk_rc_style_get_color_hashes        (GtkRcStyle *rc_style);
+
 const gchar* _gtk_rc_context_get_default_font_name (GtkSettings *settings);
 
 G_END_DECLS
index 4193eadca0beedfa1f900f9abce16c1946480464..f57a056f27258c8bc2cf81e4b78d39e2523e0f97 100644 (file)
@@ -84,7 +84,8 @@ enum {
   PROP_SHOW_INPUT_METHOD_MENU,
   PROP_SHOW_UNICODE_MENU,
   PROP_TIMEOUT_INITIAL,
-  PROP_TIMEOUT_REPEAT
+  PROP_TIMEOUT_REPEAT,
+  PROP_COLOR_SCHEME
 };
 
 
@@ -107,6 +108,7 @@ static guint        settings_install_property_parser (GtkSettingsClass      *class,
                                                  GtkRcPropertyParser    parser);
 static void    settings_update_double_click      (GtkSettings           *settings);
 static void    settings_update_modules           (GtkSettings           *settings);
+static void    settings_update_color_scheme      (GtkSettings           *settings);
 
 #ifdef GDK_WINDOWING_X11
 static void    settings_update_cursor_theme      (GtkSettings           *settings);
@@ -416,7 +418,7 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                                               P_("Start timeout"),
                                                               P_("Starting value for timeouts, when button is pressed"),
                                                               0, G_MAXINT, DEFAULT_TIMEOUT_INITIAL,
-                                                              G_PARAM_READWRITE),
+                                                              GTK_PARAM_READWRITE),
                                             NULL);
 
   g_assert (result == PROP_TIMEOUT_INITIAL);
@@ -426,10 +428,20 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                                               P_("Repeat timeout"),
                                                               P_("Repeat value for timeouts, when button is pressed"),
                                                               0, G_MAXINT, DEFAULT_TIMEOUT_REPEAT,
-                                                              G_PARAM_READWRITE),
+                                                              GTK_PARAM_READWRITE),
                                             NULL);
 
   g_assert (result == PROP_TIMEOUT_REPEAT);
+
+  result = settings_install_property_parser (class,
+                                            g_param_spec_string ("gtk-color-scheme",
+                                                                 P_("Color scheme"),
+                                                                 P_("A palette of named colors for use in themes"),
+                                                                 "foreground:black\nbackground:gray",
+                                                                 GTK_PARAM_READWRITE),
+                                            NULL);
+
+  g_assert (result == PROP_COLOR_SCHEME);
 }
 
 static void
@@ -602,6 +614,9 @@ gtk_settings_notify (GObject    *object,
     case PROP_MODULES:
       settings_update_modules (settings);
       break;
+    case PROP_COLOR_SCHEME:
+      settings_update_color_scheme (settings);
+      break;
     case PROP_DOUBLE_CLICK_TIME:
     case PROP_DOUBLE_CLICK_DISTANCE:
       settings_update_double_click (settings);
@@ -1511,5 +1526,81 @@ settings_update_resolution (GtkSettings *settings)
 }
 #endif
 
+static GHashTable *
+gtk_color_table_from_string (const gchar *str)
+{
+  gchar *copy, *s, *p, *name;
+  GdkColor color;
+  GHashTable *colors;
+
+  colors = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+                                  (GDestroyNotify) gdk_color_free);
+
+  copy = g_strdup (str);
+
+  s = copy;
+  while (s && *s)
+    {
+      name = s;
+      p = strchr (s, ':');
+      if (p)
+        {
+          *p = '\0';
+          p++;
+        }
+      else
+        {
+          g_hash_table_destroy (colors);
+          colors = NULL;
+
+          break;
+        }
+
+      while (*p == ' ')
+        p++;
+
+      s = strchr (p, '\n');
+      if (s)
+        {
+          *s = '\0';
+          s++;
+        }
+
+      if (!gdk_color_parse (p, &color))
+        {
+          g_hash_table_destroy (colors);
+          colors = NULL;
+
+          break;
+        }
+
+      g_hash_table_insert (colors,
+                           g_strdup (name),
+                           gdk_color_copy (&color));
+    }
+
+  g_free (copy);
+
+  return colors;
+}
+
+static void
+settings_update_color_scheme (GtkSettings *settings)
+{
+  gchar *colors;
+  GHashTable *color_hash;
+
+  g_object_get (settings,
+                "gtk-color-scheme", &colors,
+                NULL);
+
+  color_hash = gtk_color_table_from_string (colors);
+
+  g_object_set_data_full (G_OBJECT (settings), "gtk-color-scheme",
+                          color_hash, (GDestroyNotify) g_hash_table_unref);
+
+  g_free (colors);
+}
+
 #define __GTK_SETTINGS_C__
 #include "gtkaliasdef.c"
index 8df20d2c8ed7027e063dc2e9db46ae360f1f630c..14a74050e886b46965be4cffda5d28dcfe2525a8 100644 (file)
@@ -50,6 +50,14 @@ typedef struct {
   GValue      value;
 } PropertyValue;
 
+#define GTK_STYLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_STYLE, GtkStylePrivate))
+
+typedef struct _GtkStylePrivate GtkStylePrivate;
+
+struct _GtkStylePrivate {
+  GSList *color_hashes;
+};
+
 /* --- prototypes --- */
 static void     gtk_style_init                 (GtkStyle       *style);
 static void     gtk_style_class_init           (GtkStyleClass  *klass);
@@ -305,9 +313,6 @@ static void gtk_default_draw_resize_grip (GtkStyle       *style,
                                           gint            width,
                                           gint            height);
 
-static void gtk_style_shade            (GdkColor        *a,
-                                        GdkColor        *b,
-                                        gdouble          k);
 static void rgb_to_hls                 (gdouble         *r,
                                         gdouble         *g,
                                         gdouble         *b);
@@ -534,7 +539,8 @@ gtk_style_class_init (GtkStyleClass *klass)
   klass->draw_layout = gtk_default_draw_layout;
   klass->draw_resize_grip = gtk_default_draw_resize_grip;
 
-  
+  g_type_class_add_private (object_class, sizeof (GtkStylePrivate));
+
   /**
    * GtkStyle::realize:
    * @style: the object which received the signal
@@ -596,6 +602,7 @@ static void
 gtk_style_finalize (GObject *object)
 {
   GtkStyle *style = GTK_STYLE (object);
+  GtkStylePrivate *priv = GTK_STYLE_GET_PRIVATE (style);
 
   g_return_if_fail (style->attach_count == 0);
 
@@ -625,18 +632,11 @@ gtk_style_finalize (GObject *object)
         }
     }
 
-  if (style->icon_factories)
-    {
-      GSList *tmp_list = style->icon_factories;
+  g_slist_foreach (style->icon_factories, (GFunc) g_object_unref, NULL);
+  g_slist_free (style->icon_factories);
 
-      while (tmp_list)
-       {
-         g_object_unref (tmp_list->data);
-         tmp_list = tmp_list->next;
-       }
-
-      g_slist_free (style->icon_factories);
-    }
+  g_slist_foreach (priv->color_hashes, (GFunc) g_hash_table_unref, NULL);
+  g_slist_free (priv->color_hashes);
 
   pango_font_description_free (style->font_desc);
   
@@ -895,6 +895,53 @@ gtk_style_lookup_icon_set (GtkStyle   *style,
   return gtk_icon_factory_lookup_default (stock_id);
 }
 
+/**
+ * gtk_style_lookup_color:
+ * @style: a #GtkStyle
+ * @color_name: the name of the logical color to look up
+ * @color: the #GdkColor to fill in
+ *
+ * Looks up @color_name in the style's logical color mappings,
+ * filling in @color and returning %TRUE if found, otherwise
+ * returning %FALSE. Do not cache the found mapping, because
+ * it depends on the #GtkStyle and might change when a theme
+ * switch occurs.
+ *
+ * Return value: %TRUE if the mapping was found.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gtk_style_lookup_color (GtkStyle   *style,
+                        const char *color_name,
+                        GdkColor   *color)
+{
+  GtkStylePrivate *priv;
+  GSList *iter;
+
+  g_return_val_if_fail (GTK_IS_STYLE (style), FALSE);
+  g_return_val_if_fail (color_name != NULL, FALSE);
+  g_return_val_if_fail (color != NULL, FALSE);
+
+  priv = GTK_STYLE_GET_PRIVATE (style);
+
+  for (iter = priv->color_hashes; iter != NULL; iter = iter->next)
+    {
+      GHashTable *hash    = iter->data;
+      GdkColor   *mapping = g_hash_table_lookup (hash, color_name);
+
+      if (mapping)
+        {
+          color->red = mapping->red;
+          color->green = mapping->green;
+          color->blue = mapping->blue;
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
 /**
  * gtk_draw_hline:
  * @style: a #GtkStyle
@@ -1613,6 +1660,7 @@ static void
 gtk_style_real_init_from_rc (GtkStyle   *style,
                             GtkRcStyle *rc_style)
 {
+  GtkStylePrivate *priv = GTK_STYLE_GET_PRIVATE (style);
   gint i;
 
   /* cache _should_ be still empty */
@@ -1638,19 +1686,11 @@ gtk_style_real_init_from_rc (GtkStyle   *style,
   if (rc_style->ythickness >= 0)
     style->ythickness = rc_style->ythickness;
 
-  if (rc_style->icon_factories)
-    {
-      GSList *iter;
+  style->icon_factories = g_slist_copy (rc_style->icon_factories);
+  g_slist_foreach (style->icon_factories, (GFunc) g_object_ref, NULL);
 
-      style->icon_factories = g_slist_copy (rc_style->icon_factories);
-      
-      iter = style->icon_factories;
-      while (iter != NULL)
-        {
-          g_object_ref (iter->data);
-          iter = g_slist_next (iter);
-        }
-    }
+  priv->color_hashes = g_slist_copy (_gtk_rc_style_get_color_hashes (rc_style));
+  g_slist_foreach (priv->color_hashes, (GFunc) g_hash_table_ref, NULL);
 }
 
 static gint
@@ -1773,9 +1813,9 @@ gtk_style_real_realize (GtkStyle *style)
 
   for (i = 0; i < 5; i++)
     {
-      gtk_style_shade (&style->bg[i], &style->light[i], LIGHTNESS_MULT);
-      gtk_style_shade (&style->bg[i], &style->dark[i], DARKNESS_MULT);
-      
+      _gtk_style_shade (&style->bg[i], &style->light[i], LIGHTNESS_MULT);
+      _gtk_style_shade (&style->bg[i], &style->dark[i], DARKNESS_MULT);
+
       style->mid[i].red = (style->light[i].red + style->dark[i].red) / 2;
       style->mid[i].green = (style->light[i].green + style->dark[i].green) / 2;
       style->mid[i].blue = (style->light[i].blue + style->dark[i].blue) / 2;
@@ -3396,7 +3436,7 @@ get_darkened_gc (GdkWindow *window,
 
   while (darken_count)
     {
-      gtk_style_shade (&src, &shaded, 0.93);
+      _gtk_style_shade (&src, &shaded, 0.93);
       src = shaded;
       --darken_count;
     }
@@ -4705,9 +4745,9 @@ gtk_default_draw_handle (GtkStyle      *style,
       if (state_type == GTK_STATE_SELECTED && widget && !GTK_WIDGET_HAS_FOCUS (widget))
        {
          GdkColor unfocused_light;
-      
-         gtk_style_shade (&style->base[GTK_STATE_ACTIVE], &unfocused_light,
-                          LIGHTNESS_MULT);
+
+         _gtk_style_shade (&style->base[GTK_STATE_ACTIVE], &unfocused_light,
+                            LIGHTNESS_MULT);
 
          light_gc = free_me = gdk_gc_new (window);
          gdk_gc_set_rgb_fg_color (light_gc, &unfocused_light);
@@ -5417,10 +5457,10 @@ gtk_default_draw_resize_grip (GtkStyle       *style,
     }
 }
 
-static void
-gtk_style_shade (GdkColor *a,
-                 GdkColor *b,
-                 gdouble   k)
+void
+_gtk_style_shade (GdkColor *a,
+                  GdkColor *b,
+                  gdouble   k)
 {
   gdouble red;
   gdouble green;
index 4ae3143459c212f50ca2167963a09dda0533cc21..e4f71c6f8da08045d0bafb8d1647398078d804f3 100644 (file)
@@ -452,8 +452,12 @@ void         gtk_style_apply_default_background (GtkStyle     *style,
                                              gint          width, 
                                              gint          height);
 
-GtkIconSet* gtk_style_lookup_icon_set (GtkStyle            *style,
-                                       const gchar         *stock_id);
+GtkIconSet* gtk_style_lookup_icon_set        (GtkStyle     *style,
+                                              const gchar  *stock_id);
+gboolean    gtk_style_lookup_color           (GtkStyle     *style,
+                                              const gchar  *color_name,
+                                              GdkColor     *color);
+
 GdkPixbuf*  gtk_style_render_icon     (GtkStyle            *style,
                                        const GtkIconSource *source,
                                        GtkTextDirection     direction,
@@ -461,6 +465,7 @@ GdkPixbuf*  gtk_style_render_icon     (GtkStyle            *style,
                                        GtkIconSize          size,
                                        GtkWidget           *widget,
                                        const gchar         *detail);
+
 #ifndef GTK_DISABLE_DEPRECATED
 void gtk_draw_hline      (GtkStyle        *style,
                          GdkWindow       *window,
@@ -852,7 +857,7 @@ void gtk_paint_resize_grip (GtkStyle                *style,
 
 GType      gtk_border_get_type (void) G_GNUC_CONST;
 GtkBorder *gtk_border_copy     (const GtkBorder *border_);
-void       gtk_border_free (   GtkBorder       *border_);
+void       gtk_border_free     (GtkBorder       *border_);
 
 /* --- private API --- */
 const GValue* _gtk_style_peek_property_value (GtkStyle           *style,
@@ -860,8 +865,12 @@ const GValue* _gtk_style_peek_property_value (GtkStyle           *style,
                                              GParamSpec         *pspec,
                                              GtkRcPropertyParser parser);
 
-void _gtk_style_init_for_settings (GtkStyle    *style,
-                                  GtkSettings *settings);
+void          _gtk_style_init_for_settings   (GtkStyle           *style,
+                                              GtkSettings        *settings);
+
+void          _gtk_style_shade               (GdkColor           *a,
+                                              GdkColor           *b,
+                                              gdouble             k);
 
 /* deprecated */
 #ifndef GTK_DISABLE_DEPRECATED
index dbe3acfa74773aa1ed26599941adfd1060c8eee9..f711ae79bdbae90c068a8f095f802f9c690058bf 100644 (file)
@@ -109,9 +109,17 @@ style "curve"
   fg[NORMAL] = { 58000, 0, 0 }                  # red
 }
 
-style "red-bar"
+style "red-bar-parent"
 {
-  bg[PRELIGHT] = { 0.95, .55, 0.55 }
+  color["my-red"] = "red"
+  color["my-other-red"] = { 0.95, .55, 0.55 }
+}
+
+style "red-bar" = "red-bar-parent"
+{
+  color["my-light-red"] = lighter (lighter (@my-red))
+
+  bg[PRELIGHT] = @my-light-red
 }
 
 # override testgtk2, introduce the green color in the button list