summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog31
-rw-r--r--ChangeLog.pre-2-1031
-rw-r--r--configure.in2
-rw-r--r--gtk/gtk.symbols1
-rw-r--r--gtk/gtkrc.c435
-rw-r--r--gtk/gtkrc.h3
-rw-r--r--gtk/gtksettings.c97
-rw-r--r--gtk/gtkstyle.c116
-rw-r--r--gtk/gtkstyle.h19
-rw-r--r--tests/testgtkrc12
10 files changed, 638 insertions, 109 deletions
diff --git a/ChangeLog b/ChangeLog
index e21284220..cd8f5c72e 100644
--- 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
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index e21284220..cd8f5c72e 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -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
diff --git a/configure.in b/configure.in
index 3fb359992..64ae6ff94 100644
--- a/configure.in
+++ b/configure.in
@@ -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])
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index da23d2989..97e88e449 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -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
diff --git a/gtk/gtkrc.c b/gtk/gtkrc.c
index 8fbb01a16..41c8160d1 100644
--- a/gtk/gtkrc.c
+++ b/gtk/gtkrc.c
@@ -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,10 +3471,43 @@ 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;
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 *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 */
diff --git a/gtk/gtkrc.h b/gtk/gtkrc.h
index 3fb2d0d35..ea6ff2223 100644
--- a/gtk/gtkrc.h
+++ b/gtk/gtkrc.h
@@ -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
diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c
index 4193eadca..f57a056f2 100644
--- a/gtk/gtksettings.c
+++ b/gtk/gtksettings.c
@@ -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"
diff --git a/gtk/gtkstyle.c b/gtk/gtkstyle.c
index 8df20d2c8..14a74050e 100644
--- a/gtk/gtkstyle.c
+++ b/gtk/gtkstyle.c
@@ -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);
@@ -896,6 +896,53 @@ gtk_style_lookup_icon_set (GtkStyle *style,
}
/**
+ * 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
* @window: a #GdkWindow
@@ -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;
diff --git a/gtk/gtkstyle.h b/gtk/gtkstyle.h
index 4ae314345..e4f71c6f8 100644
--- a/gtk/gtkstyle.h
+++ b/gtk/gtkstyle.h
@@ -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
diff --git a/tests/testgtkrc b/tests/testgtkrc
index dbe3acfa7..f711ae79b 100644
--- a/tests/testgtkrc
+++ b/tests/testgtkrc
@@ -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