diff options
-rw-r--r-- | ChangeLog | 31 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 31 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | gtk/gtk.symbols | 1 | ||||
-rw-r--r-- | gtk/gtkrc.c | 435 | ||||
-rw-r--r-- | gtk/gtkrc.h | 3 | ||||
-rw-r--r-- | gtk/gtksettings.c | 97 | ||||
-rw-r--r-- | gtk/gtkstyle.c | 116 | ||||
-rw-r--r-- | gtk/gtkstyle.h | 19 | ||||
-rw-r--r-- | tests/testgtkrc | 12 |
10 files changed, 638 insertions, 109 deletions
@@ -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 e212842205..cd8f5c72e0 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 3fb3599924..64ae6ff945 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 da23d29892..97e88e4493 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 8fbb01a162..41c8160d1b 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 3fb2d0d352..ea6ff22235 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 4193eadca0..f57a056f27 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 8df20d2c8e..14a74050e8 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 4ae3143459..e4f71c6f8d 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 dbe3acfa74..f711ae79bd 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 |