Color schemes for GTK+



Color schemes for GTK+
----------------------

This is a proposal to add support for color schemes ("recolorable 
themes") to GTK+. The proposal has two parts, a desktop-wide set
of named colors, and support for named colors in rc files.


1) Add a setting gtk-color-scheme, which holds a string specifying
a set of named colors, in the following format: 

name1: color1
name2: color2
...

E.g 

 "foreground: black\nbackground: #0a0a0a\n"

Color names must be acceptable as identifiers in the gtkrc syntax,
color specifications must be in the format accepted by
gdk_color_parse().

This setting is available in string form, but GTK+ converts it to 
a hash table mapping names to GdkColors. This hash table is attached
as object data to the settings object, and can be obtained with

 g_object_get_data (G_OBJECT (settings), "gtk-color-scheme")
 
In this way, theme engines have access to the color scheme.


2a) Extend the gtkrc syntax to allow named colors. Where a color 
is expected in a gtkrc file, a named color can be specified as

 @name

This resolves to the color named "name" in the current color scheme.
What color names are allowed depends on the color scheme, although it
is expected that there will be a small set of standard color names,
which can be assumed to be present in every color scheme (this is the
set of colors that a "color scheme capplet" would allow users to 
change).


2b) In order to ensure that gtkrc files continue to work in the absence 
of a color scheme setting (e.g. when no settings manager is running), 
the rc file syntax is further extended to allow rc files to specify
default values for the named colors it uses, in the following form:

colors 
{
  name1 = color1
  name2 = color2
  ...
}

E.g.

colors
{
  foreground = "black"
  background = "#0a0a0a"
}

Note that rc files can define and use named colors which are not
present in the color scheme, e.g.

colors
{
  foreground = "black"
  light-foreground = lighter (@foreground)
}


2c) Allow "color expressions" in rc files, to enable themes to derive
color variations from the colors in the color scheme. The following
expressions are initially proposed:

 mix (factor, color1, color2)

Compute a new color by mixing color1 and color2. The factor 
determines how close the new color will be to color1. A factor of 
1.0 will give pure color1, a factor of 0.0 will give pure color2. 
Factors in between will give a mixture.

 shade (factor, color)

Compute a lighter or darker variant of color, by first converting the
color to the HLS color space and then modifying the L (lightness)
coordinate. A factor of 1.0 leaves the color unchanged, smaller 
factors yield darker colors, larger factors yield lighter colors.
 
 lighter (color)   is a shorthand for shade (1.3, color)
 darker (color)    is a shorthand for shade (0.7, color)
 
E.g:
  
 mix (0.5, "red", "blue")
 shade (1.5, mix (0.3, "#0abbc0", { 0.3, 0.5, 0.9 }))
 lighter (@foreground)


The attached patch implements all parts of this proposal.


Comments appreciated, Matthias 

Index: gtk/gtkrc.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkrc.c,v
retrieving revision 1.160
diff -u -r1.160 gtkrc.c
--- gtk/gtkrc.c	6 Apr 2005 13:49:28 -0000	1.160
+++ gtk/gtkrc.c	7 Jun 2005 21:09:14 -0000
@@ -104,6 +104,9 @@
 
   gint default_priority;
   GtkStyle *default_style;
+
+  gchar *colors;
+  GHashTable *color_hash;
 };
 
 static GtkRcContext *gtk_rc_context_get              (GtkSettings     *settings);
@@ -143,13 +146,22 @@
 						      GScanner        *scanner);
 static guint       gtk_rc_parse_assignment           (GScanner        *scanner,
 						      GtkRcProperty   *prop);
-static guint       gtk_rc_parse_bg                   (GScanner        *scanner,
+static guint       gtk_rc_parse_color_full           (GtkRcContext *context,
+                                                      GScanner     *scanner,
+		                                      GdkColor     *color);
+static guint       gtk_rc_parse_colors               (GtkRcContext    *context,
+						      GScanner        *scanner);
+static guint       gtk_rc_parse_bg                   (GtkRcContext    *context,
+                                                      GScanner        *scanner,
                                                       GtkRcStyle      *style);
-static guint       gtk_rc_parse_fg                   (GScanner        *scanner,
+static guint       gtk_rc_parse_fg                   (GtkRcContext    *context,
+                                                      GScanner        *scanner,
                                                       GtkRcStyle      *style);
-static guint       gtk_rc_parse_text                 (GScanner        *scanner,
+static guint       gtk_rc_parse_text                 (GtkRcContext    *context,
+                                                      GScanner        *scanner,
                                                       GtkRcStyle      *style);
-static guint       gtk_rc_parse_base                 (GScanner        *scanner,
+static guint       gtk_rc_parse_base                 (GtkRcContext    *context,
+                                                      GScanner        *scanner,
                                                       GtkRcStyle      *style);
 static guint       gtk_rc_parse_xthickness           (GScanner        *scanner,
                                                       GtkRcStyle      *style);
@@ -278,7 +290,8 @@
   { "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 },
+  { "colors", GTK_RC_TOKEN_COLORS }
 };
 
 static GHashTable *realized_style_ht = NULL;
@@ -553,6 +566,65 @@
   _gtk_rc_context_get_default_font_name (settings);
 }
 
+static void
+copy_color_entry (gpointer key,
+                  gpointer value,
+                  gpointer data)
+{
+  gchar *name = key;
+  GdkColor *color = value;
+  GHashTable *colors = data;
+
+  g_hash_table_insert (colors,
+                       g_strdup (name),
+                       gdk_color_copy (color));
+}
+
+static GHashTable *
+copy_color_scheme (GHashTable *color_scheme)
+{
+  GHashTable *copy;
+
+  copy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+                                (GDestroyNotify)gdk_color_free);
+  
+  if (color_scheme)
+    g_hash_table_foreach (color_scheme, copy_color_entry, copy);
+
+  return copy;
+}
+
+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 = colors;
+
+      if (context->color_hash)
+        g_hash_table_destroy (context->color_hash);
+      
+      context->color_hash = 
+        copy_color_scheme (g_object_get_data (G_OBJECT (settings), 
+                                              "gtk-color-scheme"));
+
+      gtk_rc_reparse_all_for_settings (settings, TRUE);
+    }
+}
+
 static GtkRcContext *
 gtk_rc_context_get (GtkSettings *settings)
 {
@@ -572,8 +644,13 @@
 		    "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 = 
+        copy_color_scheme (g_object_get_data (G_OBJECT (settings), 
+                                              "gtk-color-scheme"));
+  
       g_signal_connect (settings,
 			"notify::gtk-theme-name",
 			G_CALLBACK (gtk_rc_settings_changed),
@@ -586,7 +663,10 @@
 			"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;
 
@@ -2479,6 +2559,10 @@
 	  g_scanner_get_next_token (scanner);
 	  return G_TOKEN_IDENTIFIER;
 	}
+
+    case GTK_RC_TOKEN_COLORS:
+      return gtk_rc_parse_colors (context, scanner);
+      
     default:
       g_scanner_get_next_token (scanner);
       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
@@ -2649,16 +2733,16 @@
       switch (token)
 	{
 	case GTK_RC_TOKEN_BG:
-	  token = gtk_rc_parse_bg (scanner, rc_style);
+	  token = gtk_rc_parse_bg (context, scanner, rc_style);
 	  break;
 	case GTK_RC_TOKEN_FG:
-	  token = gtk_rc_parse_fg (scanner, rc_style);
+	  token = gtk_rc_parse_fg (context, scanner, rc_style);
 	  break;
 	case GTK_RC_TOKEN_TEXT:
-	  token = gtk_rc_parse_text (scanner, rc_style);
+	  token = gtk_rc_parse_text (context, scanner, rc_style);
 	  break;
 	case GTK_RC_TOKEN_BASE:
-	  token = gtk_rc_parse_base (scanner, rc_style);
+	  token = gtk_rc_parse_base (context, scanner, rc_style);
 	  break;
 	case GTK_RC_TOKEN_XTHICKNESS:
 	  token = gtk_rc_parse_xthickness (scanner, rc_style);
@@ -2810,8 +2894,9 @@
 }
 
 static guint
-gtk_rc_parse_bg (GScanner   *scanner,
-		 GtkRcStyle *style)
+gtk_rc_parse_bg (GtkRcContext *context,
+                 GScanner     *scanner,
+		 GtkRcStyle   *style)
 {
   GtkStateType state;
   guint token;
@@ -2829,12 +2914,13 @@
     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 (context, scanner, &style->bg[state]);
 }
 
 static guint
-gtk_rc_parse_fg (GScanner   *scanner,
-		 GtkRcStyle *style)
+gtk_rc_parse_fg (GtkRcContext *context,
+                 GScanner     *scanner,
+		 GtkRcStyle   *style)
 {
   GtkStateType state;
   guint token;
@@ -2852,12 +2938,13 @@
     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 (context, scanner, &style->fg[state]);
 }
 
 static guint
-gtk_rc_parse_text (GScanner   *scanner,
-		   GtkRcStyle *style)
+gtk_rc_parse_text (GtkRcContext *context,
+                   GScanner     *scanner,
+		   GtkRcStyle   *style)
 {
   GtkStateType state;
   guint token;
@@ -2875,12 +2962,13 @@
     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 (context, scanner, &style->text[state]);
 }
 
 static guint
-gtk_rc_parse_base (GScanner   *scanner,
-		   GtkRcStyle *style)
+gtk_rc_parse_base (GtkRcContext *context,
+                   GScanner     *scanner,
+		   GtkRcStyle   *style)
 {
   GtkStateType state;
   guint token;
@@ -2898,7 +2986,7 @@
     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 (context, scanner, &style->base[state]);
 }
 
 static guint
@@ -3354,6 +3442,14 @@
 gtk_rc_parse_color (GScanner *scanner,
 		    GdkColor *color)
 {
+  return gtk_rc_parse_color_full (NULL, scanner, color);
+}
+
+static guint
+gtk_rc_parse_color_full (GtkRcContext *context,
+                         GScanner     *scanner,
+		         GdkColor     *color)
+{
   guint token;
 
   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
@@ -3366,6 +3462,9 @@
   switch (token)
     {
       gint token_int;
+      GdkColor *col, c1, c2;
+      gboolean negate;
+      gdouble l;
       
     case G_TOKEN_LEFT_CURLY:
       token = g_scanner_get_next_token (scanner);
@@ -3418,9 +3517,190 @@
       else
 	return G_TOKEN_NONE;
       
+    case '@': 
+      token = g_scanner_get_next_token (scanner);
+      if (token != G_TOKEN_IDENTIFIER)
+	return G_TOKEN_IDENTIFIER;
+
+      if (!context || !context->color_hash ||
+          !(col = g_hash_table_lookup (context->color_hash, 
+                                       scanner->value.v_identifier)))
+        {
+          g_scanner_warn (scanner, "Invalid symbolic color '%s'", 
+                          scanner->value.v_identifier);
+          return G_TOKEN_IDENTIFIER;
+        } 
+
+      color->red = col->red;
+      color->green = col->green;
+      color->blue = col->blue;
+
+      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 (context, scanner, &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 (context, scanner, &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 (context, scanner, &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 (context, scanner, &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_IDENTIFIER;
+
     default:
       return G_TOKEN_STRING;
     }
+}
+
+static guint
+gtk_rc_parse_colors (GtkRcContext *context, 
+                     GScanner     *scanner)
+{
+  guint token;
+
+  token = g_scanner_get_next_token (scanner);
+  if (token != GTK_RC_TOKEN_COLORS)
+    return GTK_RC_TOKEN_COLORS;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_LEFT_CURLY)
+    return G_TOKEN_LEFT_CURLY;
+
+  g_scanner_peek_next_token (scanner);
+  while (scanner->next_token != G_TOKEN_RIGHT_CURLY)
+    {
+      gchar *name;
+      GdkColor color;
+
+      if (scanner->next_token != G_TOKEN_IDENTIFIER)
+        return G_TOKEN_IDENTIFIER;
+
+      g_scanner_get_next_token (scanner);
+      name = g_strdup (scanner->value.v_identifier);
+      
+      token = g_scanner_get_next_token (scanner);
+      if (token != G_TOKEN_EQUAL_SIGN)
+        {
+          g_free (name);
+          return G_TOKEN_EQUAL_SIGN;
+        }
+
+      token = gtk_rc_parse_color_full (context, scanner, &color);
+      if (token != G_TOKEN_NONE)
+        {
+          g_free (name);
+          return token;
+        }
+
+      if (!g_hash_table_lookup (context->color_hash, name))
+        g_hash_table_insert (context->color_hash, 
+                             g_strdup (name),
+                             gdk_color_copy (&color));
+
+      g_free (name);
+      g_scanner_peek_next_token (scanner);
+    }
+  g_scanner_get_next_token (scanner);
+  
+  return G_TOKEN_NONE;
 }
 
 static guint
Index: gtk/gtkrc.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkrc.h,v
retrieving revision 1.43
diff -u -r1.43 gtkrc.h
--- gtk/gtkrc.h	20 Mar 2005 07:01:22 -0000	1.43
+++ gtk/gtkrc.h	7 Jun 2005 21:09:14 -0000
@@ -209,6 +209,7 @@
   GTK_RC_TOKEN_STOCK,
   GTK_RC_TOKEN_LTR,
   GTK_RC_TOKEN_RTL,
+  GTK_RC_TOKEN_COLORS,
   GTK_RC_TOKEN_LAST
 } GtkRcTokenType;
 
Index: gtk/gtkstyle.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkstyle.c,v
retrieving revision 1.179
diff -u -r1.179 gtkstyle.c
--- gtk/gtkstyle.c	25 May 2005 10:22:37 -0000	1.179
+++ gtk/gtkstyle.c	7 Jun 2005 21:09:15 -0000
@@ -304,9 +304,6 @@
                                           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);
@@ -1759,8 +1756,8 @@
 
   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;
@@ -3391,7 +3388,7 @@
 
   while (darken_count)
     {
-      gtk_style_shade (&src, &shaded, 0.93);
+      _gtk_style_shade (&src, &shaded, 0.93);
       src = shaded;
       --darken_count;
     }
@@ -4701,7 +4698,7 @@
 	{
 	  GdkColor unfocused_light;
       
-	  gtk_style_shade (&style->base[GTK_STATE_ACTIVE], &unfocused_light,
+	  _gtk_style_shade (&style->base[GTK_STATE_ACTIVE], &unfocused_light,
 			   LIGHTNESS_MULT);
 
 	  light_gc = free_me = gdk_gc_new (window);
@@ -5396,8 +5393,8 @@
     }
 }
 
-static void
-gtk_style_shade (GdkColor *a,
+void
+_gtk_style_shade (GdkColor *a,
                  GdkColor *b,
                  gdouble   k)
 {
Index: gtk/gtkstyle.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkstyle.h,v
retrieving revision 1.48
diff -u -r1.48 gtkstyle.h
--- gtk/gtkstyle.h	20 Mar 2005 07:01:22 -0000	1.48
+++ gtk/gtkstyle.h	7 Jun 2005 21:09:15 -0000
@@ -863,6 +863,10 @@
 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
 #define gtk_style_apply_default_pixmap(s,gw,st,a,x,y,w,h) gtk_style_apply_default_background (s,gw,1,st,a,x,y,w,h)
Index: gtk/gtksettings.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtksettings.c,v
retrieving revision 1.63
diff -u -r1.63 gtksettings.c
--- gtk/gtksettings.c	22 Mar 2005 02:14:55 -0000	1.63
+++ gtk/gtksettings.c	7 Jun 2005 21:09:15 -0000
@@ -73,7 +73,8 @@
   PROP_XFT_RGBA,
   PROP_XFT_DPI,
 #endif
-  PROP_ALTERNATIVE_BUTTON_ORDER
+  PROP_ALTERNATIVE_BUTTON_ORDER,
+  PROP_COLOR_SCHEME
 };
 
 
@@ -96,7 +97,7 @@
 						  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);
 
 
 /* --- variables --- */
@@ -436,6 +437,16 @@
 								   GTK_PARAM_READWRITE),
                                              NULL);
   g_assert (result == PROP_ALTERNATIVE_BUTTON_ORDER);
+
+  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
@@ -612,6 +623,9 @@
     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);
@@ -1294,7 +1308,7 @@
   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (property_value), FALSE);
 
-  scanner = gtk_rc_scanner_new ();
+ scanner = gtk_rc_scanner_new ();
   g_scanner_input_text (scanner, gstring->str, gstring->len);
 
   if (get_braced_int (scanner, TRUE, FALSE, &border.left) &&
@@ -1311,6 +1325,86 @@
   return success;
 }
 
+#if 0
+static GHashTable *
+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 gboolean 
+settings_parse_color_scheme (const GParamSpec *pspec,
+			     const GString    *gstring,
+			     GValue           *property_value)
+{
+  GHashTable *colors;
+
+  g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
+  g_return_val_if_fail (G_VALUE_HOLDS_POINTER (property_value), FALSE);
+
+  colors = color_table_from_string (gstring->str);
+  if (colors)
+    {  
+      g_value_set_pointer (property_value, colors);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+#endif
+
 void
 _gtk_settings_handle_event (GdkEventSetting *event)
 {
@@ -1323,7 +1417,7 @@
 static void
 reset_rc_values_foreach (GQuark    key_id,
 			 gpointer  data,
-			 gpointer  user_data)
+			gpointer  user_data)
 {
   GtkSettingsValuePrivate *qvalue = data;
   GSList **to_reset = user_data;
@@ -1405,6 +1499,83 @@
   
   g_free (modules);
 }
+
+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, g_hash_table_destroy);
+   
+  g_free (colors);
+}
+
 
 #define __GTK_SETTINGS_C__
 #include "gtkaliasdef.c"


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