diff options
author | Alexander Larsson <alexl@redhat.com> | 2014-07-30 18:05:48 +0200 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2014-08-03 02:20:18 +0200 |
commit | 1d68801ade1f7c7d9f5d3319b62fa8f474daf9f0 (patch) | |
tree | 74845113212660099f1a83051fc35281b327a67a /gtk | |
parent | 50ba3c72bb58e280809c2eb9523f89992b2cd320 (diff) | |
download | gtk+-1d68801ade1f7c7d9f5d3319b62fa8f474daf9f0.tar.gz |
icon-theme: Support recolorable .symbolic.png files
If an icon theme has a file called "foo-symbolic.symbolic.png" which
was converted from svg using gtk-encode-symbolic-svg we will read
it in an recolor, allowing symbolic icons without using librsvg.
https://bugzilla.gnome.org/show_bug.cgi?id=730450
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtkicontheme.c | 230 |
1 files changed, 203 insertions, 27 deletions
diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index e4e30d76b9..79ee9087f2 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -151,7 +151,8 @@ typedef enum ICON_SUFFIX_XPM = 1 << 0, ICON_SUFFIX_SVG = 1 << 1, ICON_SUFFIX_PNG = 1 << 2, - HAS_ICON_FILE = 1 << 3 + HAS_ICON_FILE = 1 << 3, + ICON_SUFFIX_SYMBOLIC_PNG = 1 << 4 } IconSuffix; #define INFO_CACHE_LRU_SIZE 32 @@ -1251,6 +1252,9 @@ strip_suffix (const gchar *filename) { const gchar *dot; + if (g_str_has_suffix (filename, ".symbolic.png")) + return g_strndup (filename, strlen(filename)-13); + dot = strrchr (filename, '.'); if (dot == NULL) @@ -1633,7 +1637,8 @@ icon_uri_is_symbolic (const gchar *icon_name) { return g_str_has_suffix (icon_name, "-symbolic.svg") || g_str_has_suffix (icon_name, "-symbolic-ltr.svg") - || g_str_has_suffix (icon_name, "-symbolic-rtl.svg"); + || g_str_has_suffix (icon_name, "-symbolic-rtl.svg") + || g_str_has_suffix (icon_name, ".symbolic.png"); } static GtkIconInfo * @@ -1765,7 +1770,7 @@ real_choose_icon (GtkIconTheme *icon_theme, if (allow_svg && unthemed_icon->svg_filename && (!unthemed_icon->no_svg_filename || - suffix_from_name (unthemed_icon->no_svg_filename) != ICON_SUFFIX_PNG)) + suffix_from_name (unthemed_icon->no_svg_filename) < ICON_SUFFIX_PNG)) icon_info->filename = g_strdup (unthemed_icon->svg_filename); else if (unthemed_icon->no_svg_filename) icon_info->filename = g_strdup (unthemed_icon->no_svg_filename); @@ -2824,6 +2829,8 @@ string_from_suffix (IconSuffix suffix) return ".svg"; case ICON_SUFFIX_PNG: return ".png"; + case ICON_SUFFIX_SYMBOLIC_PNG: + return ".symbolic.png"; default: g_assert_not_reached(); } @@ -2835,7 +2842,9 @@ suffix_from_name (const gchar *name) { IconSuffix retval; - if (g_str_has_suffix (name, ".png")) + if (g_str_has_suffix (name, ".symbolic.png")) + retval = ICON_SUFFIX_SYMBOLIC_PNG; + else if (g_str_has_suffix (name, ".png")) retval = ICON_SUFFIX_PNG; else if (g_str_has_suffix (name, ".svg")) retval = ICON_SUFFIX_SVG; @@ -2851,7 +2860,9 @@ static IconSuffix best_suffix (IconSuffix suffix, gboolean allow_svg) { - if ((suffix & ICON_SUFFIX_PNG) != 0) + if ((suffix & ICON_SUFFIX_SYMBOLIC_PNG) != 0) + return ICON_SUFFIX_SYMBOLIC_PNG; + else if ((suffix & ICON_SUFFIX_PNG) != 0) return ICON_SUFFIX_PNG; else if (allow_svg && ((suffix & ICON_SUFFIX_SVG) != 0)) return ICON_SUFFIX_SVG; @@ -2866,7 +2877,7 @@ theme_dir_get_icon_suffix (IconThemeDir *dir, const gchar *icon_name, gboolean *has_icon_file) { - IconSuffix suffix; + IconSuffix suffix, symbolic_suffix; if (dir->cache) { @@ -2874,6 +2885,19 @@ theme_dir_get_icon_suffix (IconThemeDir *dir, icon_name, dir->subdir_index); + if (icon_name_is_symbolic (icon_name)) + { + /* Look for foo-symbolic.symbolic.png, as the cache only stores the ".png" suffix */ + char *icon_name_with_prefix = g_strconcat (icon_name, ".symbolic", NULL); + symbolic_suffix = (IconSuffix)_gtk_icon_cache_get_icon_flags (dir->cache, + icon_name_with_prefix, + dir->subdir_index); + g_free (icon_name_with_prefix); + + if (symbolic_suffix & ICON_SUFFIX_PNG) + suffix = ICON_SUFFIX_SYMBOLIC_PNG; + } + if (has_icon_file) *has_icon_file = suffix & HAS_ICON_FILE; @@ -4211,15 +4235,142 @@ symbolic_cache_get_proxy (SymbolicPixbufCache *symbolic_cache, return symbolic_cache->proxy_pixbuf; } +static void +rgba_to_pixel(const GdkRGBA *rgba, + guint8 pixel[4]) +{ + pixel[0] = rgba->red * 255; + pixel[1] = rgba->green * 255; + pixel[2] = rgba->blue * 255; + pixel[3] = rgba->alpha * 255; +} static GdkPixbuf * -gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info, - const GdkRGBA *fg, - const GdkRGBA *success_color, - const GdkRGBA *warning_color, - const GdkRGBA *error_color, - gboolean use_cache, - GError **error) +color_symbolic_pixbuf (GdkPixbuf *symbolic, + const GdkRGBA *fg_color, + const GdkRGBA *success_color, + const GdkRGBA *warning_color, + const GdkRGBA *error_color) +{ + int width, height, x, y, src_stride, dst_stride; + guchar *src_data, *dst_data; + guchar *src_row, *dst_row; + GdkPixbuf *colored; + guint8 fg_pixel[4], success_pixel[4], warning_pixel[4], error_pixel[4]; + + rgba_to_pixel (fg_color, fg_pixel); + rgba_to_pixel (success_color, success_pixel); + rgba_to_pixel (warning_color, warning_pixel); + rgba_to_pixel (error_color, error_pixel); + + width = gdk_pixbuf_get_width (symbolic); + height = gdk_pixbuf_get_height (symbolic); + + colored = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); + + src_stride = gdk_pixbuf_get_rowstride (symbolic); + src_data = gdk_pixbuf_get_pixels (symbolic); + + dst_data = gdk_pixbuf_get_pixels (colored); + dst_stride = gdk_pixbuf_get_rowstride (colored); + + for (y = 0; y < height; y++) + { + src_row = src_data + src_stride * y; + dst_row = dst_data + dst_stride * y; + for (x = 0; x < width; x++) + { + guint r, g, b, a; + int c1, c2, c3, c4; + + a = src_row[3]; + dst_row[3] = a; + + if (a == 0) + { + dst_row[0] = 0; + dst_row[1] = 0; + dst_row[2] = 0; + } + else + { + c2 = src_row[0]; + c3 = src_row[1]; + c4 = src_row[2]; + + if (c2 == 0 && c3 == 0 && c4 == 0) + { + dst_row[0] = fg_pixel[0]; + dst_row[1] = fg_pixel[1]; + dst_row[2] = fg_pixel[2]; + } + else + { + c1 = 255 - c2 - c3 - c4; + + r = fg_pixel[0] * c1 + success_pixel[0] * c2 + warning_pixel[0] * c3 + error_pixel[0] * c4; + g = fg_pixel[1] * c1 + success_pixel[1] * c2 + warning_pixel[1] * c3 + error_pixel[1] * c4; + b = fg_pixel[2] * c1 + success_pixel[2] * c2 + warning_pixel[2] * c3 + error_pixel[2] * c4; + + dst_row[0] = r / 255; + dst_row[1] = g / 255; + dst_row[2] = b / 255; + } + } + + src_row += 4; + dst_row += 4; + } + } + + return colored; +} + +static GdkPixbuf * +gtk_icon_info_load_symbolic_png (GtkIconInfo *icon_info, + const GdkRGBA *fg, + const GdkRGBA *success_color, + const GdkRGBA *warning_color, + const GdkRGBA *error_color, + GError **error) +{ + GdkRGBA fg_default = { 0.7450980392156863, 0.7450980392156863, 0.7450980392156863, 1.0}; + GdkRGBA success_default = { 0.3046921492332342,0.6015716792553597, 0.023437857633325704, 1.0}; + GdkRGBA warning_default = {0.9570458533607996, 0.47266346227206835, 0.2421911955443656, 1.0 }; + GdkRGBA error_default = { 0.796887159533074, 0 ,0, 1.0 }; + + if (!icon_info_ensure_scale_and_pixbuf (icon_info)) + { + if (icon_info->load_error) + { + if (error) + *error = g_error_copy (icon_info->load_error); + } + else + { + g_set_error_literal (error, + GTK_ICON_THEME_ERROR, + GTK_ICON_THEME_NOT_FOUND, + _("Failed to load icon")); + } + + return NULL; + } + + return color_symbolic_pixbuf (icon_info->pixbuf, + fg ? fg : &fg_default, + success_color ? success_color : &success_default, + warning_color ? warning_color : &warning_default, + error_color ? error_color : &error_default); +} + +static GdkPixbuf * +gtk_icon_info_load_symbolic_svg (GtkIconInfo *icon_info, + const GdkRGBA *fg, + const GdkRGBA *success_color, + const GdkRGBA *warning_color, + const GdkRGBA *error_color, + GError **error) { GInputStream *stream; GdkPixbuf *pixbuf; @@ -4231,20 +4382,6 @@ gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info, gchar *size; gchar *file_data, *escaped_file_data; gsize file_len; - SymbolicPixbufCache *symbolic_cache; - - if (use_cache) - { - symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache, - fg, success_color, warning_color, error_color); - if (symbolic_cache) - return symbolic_cache_get_proxy (symbolic_cache, icon_info); - } - - /* css_fg can't possibly have failed, otherwise - * that would mean we have a broken style - */ - g_return_val_if_fail (fg != NULL, NULL); css_fg = gdk_rgba_to_string (fg); @@ -4338,6 +4475,45 @@ gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info, error); g_object_unref (stream); + return pixbuf; +} + + + +static GdkPixbuf * +gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info, + const GdkRGBA *fg, + const GdkRGBA *success_color, + const GdkRGBA *warning_color, + const GdkRGBA *error_color, + gboolean use_cache, + GError **error) +{ + GdkPixbuf *pixbuf; + SymbolicPixbufCache *symbolic_cache; + char *icon_uri; + + if (use_cache) + { + symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache, + fg, success_color, warning_color, error_color); + if (symbolic_cache) + return symbolic_cache_get_proxy (symbolic_cache, icon_info); + } + + /* css_fg can't possibly have failed, otherwise + * that would mean we have a broken style + */ + g_return_val_if_fail (fg != NULL, NULL); + + icon_uri = g_file_get_uri (icon_info->icon_file); + if (g_str_has_suffix (icon_uri, ".symbolic.png")) + pixbuf = gtk_icon_info_load_symbolic_png (icon_info, fg, success_color, warning_color, error_color, error); + else + pixbuf = gtk_icon_info_load_symbolic_svg (icon_info, fg, success_color, warning_color, error_color, error); + + g_free (icon_uri); + if (pixbuf != NULL) { GdkPixbuf *icon; |