Index: gtk/gtk.symbols
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtk.symbols,v
retrieving revision 1.72
diff -u -p -r1.72 gtk.symbols
--- gtk/gtk.symbols	21 Nov 2005 16:01:48 -0000	1.72
+++ gtk/gtk.symbols	22 Nov 2005 18:41:12 -0000
@@ -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: gtk/gtkrc.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkrc.c,v
retrieving revision 1.166
diff -u -p -r1.166 gtkrc.c
--- gtk/gtkrc.c	4 Nov 2005 12:24:36 -0000	1.166
+++ gtk/gtkrc.c	22 Nov 2005 18:41:12 -0000
@@ -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   
 						      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  *
   _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 *setting
 		    "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 *setting
 			"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->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 (GtkRc
   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);
+
+          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);
 
-              proto_style->icon_factories = g_slist_concat (proto_style->icon_factories,
-                                                            factories);
-
-            }
-          
 	  tmp_styles = tmp_styles->next;
 	}
 
@@ -2519,10 +2591,12 @@ gtk_rc_parse_style (GtkRcContext *contex
   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 *contex
   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 *contex
 	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 *contex
       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 *contex
                   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 *contex
             }
           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 *contex
 	    {
 	      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,10 +3471,43 @@ gtk_rc_parse_priority (GScanner	        
   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;
 
   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
@@ -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 
 }
 
 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	 *scanne
   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   *cont
   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;
   
@@ -3916,6 +4191,46 @@ gtk_rc_parse_stock (GtkRcContext   *cont
     }
   
   g_free (stock_id);
+
+  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;
 }
Index: gtk/gtkrc.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkrc.h,v
retrieving revision 1.43
diff -u -p -r1.43 gtkrc.h
--- gtk/gtkrc.h	20 Mar 2005 07:01:22 -0000	1.43
+++ gtk/gtkrc.h	22 Nov 2005 18:41:12 -0000
@@ -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;
 
@@ -236,6 +237,8 @@ struct _GtkRcProperty
 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);
 
Index: gtk/gtksettings.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtksettings.c,v
retrieving revision 1.79
diff -u -p -r1.79 gtksettings.c
--- gtk/gtksettings.c	22 Nov 2005 12:40:15 -0000	1.79
+++ gtk/gtksettings.c	22 Nov 2005 18:41:12 -0000
@@ -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_p
 						  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 (GtkSettingsClas
  							       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 (GtkSettingsClas
  							       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);
@@ -1510,6 +1525,82 @@ settings_update_resolution (GtkSettings 
   gdk_screen_set_resolution (settings->screen, dpi);
 }
 #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: gtk/gtkstyle.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkstyle.c,v
retrieving revision 1.186
diff -u -p -r1.186 gtkstyle.c
--- gtk/gtkstyle.c	5 Oct 2005 13:23:21 -0000	1.186
+++ gtk/gtkstyle.c	22 Nov 2005 18:41:13 -0000
@@ -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
                                           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 *kla
   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;
-
-      while (tmp_list)
-	{
-	  g_object_unref (tmp_list->data);
-	  tmp_list = tmp_list->next;
-	}
+  g_slist_foreach (style->icon_factories, (GFunc) g_object_unref, NULL);
+  g_slist_free (style->icon_factories);
 
-      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);
   
@@ -896,6 +896,51 @@ gtk_style_lookup_icon_set (GtkStyle   *s
 }
 
 /**
+ * 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.
+ **/
+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
  * @window: a #GdkWindow
@@ -1613,6 +1658,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 +1684,11 @@ gtk_style_real_init_from_rc (GtkStyle   
   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 +1811,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 +3434,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 +4743,9 @@ gtk_default_draw_handle (GtkStyle      *
       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 +5455,10 @@ gtk_default_draw_resize_grip (GtkStyle  
     }
 }
 
-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: gtk/gtkstyle.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkstyle.h,v
retrieving revision 1.48
diff -u -p -r1.48 gtkstyle.h
--- gtk/gtkstyle.h	20 Mar 2005 07:01:22 -0000	1.48
+++ gtk/gtkstyle.h	22 Nov 2005 18:41:13 -0000
@@ -452,8 +452,12 @@ void	  gtk_style_apply_default_backgroun
 					      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     (G
                                        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		*s
 
 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_v
 					      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: tests/testgtkrc
===================================================================
RCS file: /cvs/gnome/gtk+/tests/testgtkrc,v
retrieving revision 1.58
diff -u -p -r1.58 testgtkrc
--- tests/testgtkrc	17 Mar 2005 01:54:40 -0000	1.58
+++ tests/testgtkrc	22 Nov 2005 18:41:13 -0000
@@ -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
