400 lines
16 KiB
Diff
400 lines
16 KiB
Diff
|
From 75299b2806b1bed9e14081f2e108afb39e31896e Mon Sep 17 00:00:00 2001
|
||
|
From: Carlos Garnacho <carlos@lanedo.com>
|
||
|
Date: Fri, 10 May 2013 18:06:00 +0200
|
||
|
Subject: [PATCH 58/68] icontheme: Add support for high resolution icons
|
||
|
|
||
|
An optional OutputScale integer key has been added to index.theme
|
||
|
subdirs description, so icon themes may provide icons that are
|
||
|
more suitable to render at a (typically 2x) integer upscaled
|
||
|
resolution. This way it is possible to make eg. a 16x16@2x icon has a
|
||
|
real size of 32x32, but contains a similar level of detail to the
|
||
|
16x16 icon so things don't look any more cluttered on high-dpi
|
||
|
screens.
|
||
|
|
||
|
The pixbuf lookup has changed so it prefers a minimal scale change
|
||
|
that yields the minimal real size difference, so if looking up for
|
||
|
a 16x16 icon at 2x, it would first prefer 16x16@2x, then 32x32, and
|
||
|
then any other icon that's closest to match
|
||
|
|
||
|
There is now *_for_scale() variants for all GtkIconTheme ways
|
||
|
to directly or indirectly fetch a GdkPixbuf.
|
||
|
---
|
||
|
gtk/gtkicontheme.c | 152 ++++++++++++++++++++++++++++++++++++++++------------
|
||
|
gtk/gtkicontheme.h | 17 +++++-
|
||
|
2 files changed, 135 insertions(+), 34 deletions(-)
|
||
|
|
||
|
diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
|
||
|
index bf81546..500f0ab 100644
|
||
|
--- a/gtk/gtkicontheme.c
|
||
|
+++ b/gtk/gtkicontheme.c
|
||
|
@@ -168,6 +168,7 @@ typedef struct
|
||
|
int min_size;
|
||
|
int max_size;
|
||
|
int threshold;
|
||
|
+ int scale;
|
||
|
|
||
|
char *dir;
|
||
|
char *subdir;
|
||
|
@@ -206,6 +207,7 @@ static void theme_destroy (IconTheme *theme);
|
||
|
static GtkIconInfo *theme_lookup_icon (IconTheme *theme,
|
||
|
const char *icon_name,
|
||
|
int size,
|
||
|
+ gdouble scale,
|
||
|
gboolean allow_svg,
|
||
|
gboolean use_default_icons);
|
||
|
static void theme_list_icons (IconTheme *theme,
|
||
|
@@ -1161,11 +1163,11 @@ _gtk_icon_theme_ensure_builtin_cache (void)
|
||
|
IconThemeDir *dir;
|
||
|
static IconThemeDir dirs[5] =
|
||
|
{
|
||
|
- { ICON_THEME_DIR_THRESHOLD, 0, 16, 16, 16, 2, NULL, "16", -1, NULL, NULL, NULL },
|
||
|
- { ICON_THEME_DIR_THRESHOLD, 0, 20, 20, 20, 2, NULL, "20", -1, NULL, NULL, NULL },
|
||
|
- { ICON_THEME_DIR_THRESHOLD, 0, 24, 24, 24, 2, NULL, "24", -1, NULL, NULL, NULL },
|
||
|
- { ICON_THEME_DIR_THRESHOLD, 0, 32, 32, 32, 2, NULL, "32", -1, NULL, NULL, NULL },
|
||
|
- { ICON_THEME_DIR_THRESHOLD, 0, 48, 48, 48, 2, NULL, "48", -1, NULL, NULL, NULL }
|
||
|
+ { ICON_THEME_DIR_THRESHOLD, 0, 16, 16, 16, 2, 1, NULL, "16", -1, NULL, NULL, NULL },
|
||
|
+ { ICON_THEME_DIR_THRESHOLD, 0, 20, 20, 20, 2, 1, NULL, "20", -1, NULL, NULL, NULL },
|
||
|
+ { ICON_THEME_DIR_THRESHOLD, 0, 24, 24, 24, 2, 1, NULL, "24", -1, NULL, NULL, NULL },
|
||
|
+ { ICON_THEME_DIR_THRESHOLD, 0, 32, 32, 32, 2, 1, NULL, "32", -1, NULL, NULL, NULL },
|
||
|
+ { ICON_THEME_DIR_THRESHOLD, 0, 48, 48, 48, 2, 1, NULL, "48", -1, NULL, NULL, NULL }
|
||
|
};
|
||
|
gint i;
|
||
|
|
||
|
@@ -1242,6 +1244,7 @@ static GtkIconInfo *
|
||
|
choose_icon (GtkIconTheme *icon_theme,
|
||
|
const gchar *icon_names[],
|
||
|
gint size,
|
||
|
+ gdouble scale,
|
||
|
GtkIconLookupFlags flags)
|
||
|
{
|
||
|
GtkIconThemePrivate *priv;
|
||
|
@@ -1271,7 +1274,7 @@ choose_icon (GtkIconTheme *icon_theme,
|
||
|
|
||
|
for (i = 0; icon_names[i]; i++)
|
||
|
{
|
||
|
- icon_info = theme_lookup_icon (theme, icon_names[i], size, allow_svg, use_builtin);
|
||
|
+ icon_info = theme_lookup_icon (theme, icon_names[i], size, scale, allow_svg, use_builtin);
|
||
|
if (icon_info)
|
||
|
goto out;
|
||
|
}
|
||
|
@@ -1400,12 +1403,32 @@ gtk_icon_theme_lookup_icon (GtkIconTheme *icon_theme,
|
||
|
gint size,
|
||
|
GtkIconLookupFlags flags)
|
||
|
{
|
||
|
+ g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
|
||
|
+ g_return_val_if_fail (icon_name != NULL, NULL);
|
||
|
+ g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
|
||
|
+ (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
|
||
|
+
|
||
|
+ GTK_NOTE (ICONTHEME,
|
||
|
+ g_print ("gtk_icon_theme_lookup_icon %s\n", icon_name));
|
||
|
+
|
||
|
+ return gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name,
|
||
|
+ size, 1, flags);
|
||
|
+}
|
||
|
+
|
||
|
+GtkIconInfo *
|
||
|
+gtk_icon_theme_lookup_icon_for_scale (GtkIconTheme *icon_theme,
|
||
|
+ const gchar *icon_name,
|
||
|
+ gint size,
|
||
|
+ gdouble scale,
|
||
|
+ GtkIconLookupFlags flags)
|
||
|
+{
|
||
|
GtkIconInfo *info;
|
||
|
|
||
|
g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
|
||
|
g_return_val_if_fail (icon_name != NULL, NULL);
|
||
|
g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
|
||
|
(flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
|
||
|
+ g_return_val_if_fail (scale >= 1, NULL);
|
||
|
|
||
|
GTK_NOTE (ICONTHEME,
|
||
|
g_print ("gtk_icon_theme_lookup_icon %s\n", icon_name));
|
||
|
@@ -1431,7 +1454,7 @@ gtk_icon_theme_lookup_icon (GtkIconTheme *icon_theme,
|
||
|
}
|
||
|
names[dashes + 1] = NULL;
|
||
|
|
||
|
- info = choose_icon (icon_theme, (const gchar **) names, size, flags);
|
||
|
+ info = choose_icon (icon_theme, (const gchar **) names, size, scale, flags);
|
||
|
|
||
|
g_strfreev (names);
|
||
|
}
|
||
|
@@ -1442,7 +1465,7 @@ gtk_icon_theme_lookup_icon (GtkIconTheme *icon_theme,
|
||
|
names[0] = icon_name;
|
||
|
names[1] = NULL;
|
||
|
|
||
|
- info = choose_icon (icon_theme, names, size, flags);
|
||
|
+ info = choose_icon (icon_theme, names, size, scale, flags);
|
||
|
}
|
||
|
|
||
|
return info;
|
||
|
@@ -1483,9 +1506,26 @@ gtk_icon_theme_choose_icon (GtkIconTheme *icon_theme,
|
||
|
g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
|
||
|
(flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
|
||
|
|
||
|
- return choose_icon (icon_theme, icon_names, size, flags);
|
||
|
+ return choose_icon (icon_theme, icon_names, size, 1, flags);
|
||
|
+}
|
||
|
+
|
||
|
+GtkIconInfo *
|
||
|
+gtk_icon_theme_choose_icon_for_scale (GtkIconTheme *icon_theme,
|
||
|
+ const gchar *icon_names[],
|
||
|
+ gint size,
|
||
|
+ gdouble scale,
|
||
|
+ GtkIconLookupFlags flags)
|
||
|
+{
|
||
|
+ g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
|
||
|
+ g_return_val_if_fail (icon_names != NULL, NULL);
|
||
|
+ g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
|
||
|
+ (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
|
||
|
+ g_return_val_if_fail (scale >= 1, NULL);
|
||
|
+
|
||
|
+ return choose_icon (icon_theme, icon_names, size, scale, flags);
|
||
|
}
|
||
|
|
||
|
+
|
||
|
/* Error quark */
|
||
|
GQuark
|
||
|
gtk_icon_theme_error_quark (void)
|
||
|
@@ -1529,6 +1569,24 @@ gtk_icon_theme_load_icon (GtkIconTheme *icon_theme,
|
||
|
GtkIconLookupFlags flags,
|
||
|
GError **error)
|
||
|
{
|
||
|
+ g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
|
||
|
+ g_return_val_if_fail (icon_name != NULL, NULL);
|
||
|
+ g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
|
||
|
+ (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
|
||
|
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||
|
+
|
||
|
+ return gtk_icon_theme_load_icon_for_scale (icon_theme, icon_name,
|
||
|
+ size, 1, flags, error);
|
||
|
+}
|
||
|
+
|
||
|
+GdkPixbuf *
|
||
|
+gtk_icon_theme_load_icon_for_scale (GtkIconTheme *icon_theme,
|
||
|
+ const gchar *icon_name,
|
||
|
+ gint size,
|
||
|
+ gdouble scale,
|
||
|
+ GtkIconLookupFlags flags,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
GtkIconInfo *icon_info;
|
||
|
GdkPixbuf *pixbuf = NULL;
|
||
|
|
||
|
@@ -1537,9 +1595,10 @@ gtk_icon_theme_load_icon (GtkIconTheme *icon_theme,
|
||
|
g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
|
||
|
(flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
|
||
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||
|
-
|
||
|
- icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, size,
|
||
|
- flags | GTK_ICON_LOOKUP_USE_BUILTIN);
|
||
|
+ g_return_val_if_fail (scale >= 1, NULL);
|
||
|
+
|
||
|
+ icon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name, size, scale,
|
||
|
+ flags | GTK_ICON_LOOKUP_USE_BUILTIN);
|
||
|
if (!icon_info)
|
||
|
{
|
||
|
g_set_error (error, GTK_ICON_THEME_ERROR, GTK_ICON_THEME_NOT_FOUND,
|
||
|
@@ -1976,31 +2035,42 @@ theme_dir_destroy (IconThemeDir *dir)
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
-theme_dir_size_difference (IconThemeDir *dir, int size, gboolean *smaller)
|
||
|
+theme_dir_size_difference (IconThemeDir *dir,
|
||
|
+ int size,
|
||
|
+ gdouble scale,
|
||
|
+ gboolean *smaller,
|
||
|
+ gint *scale_diff)
|
||
|
{
|
||
|
+ int scaled_size, scaled_dir_size;
|
||
|
int min, max;
|
||
|
+
|
||
|
+ scaled_size = size * scale;
|
||
|
+ scaled_dir_size = dir->size * dir->scale;
|
||
|
+ *scale_diff = abs (scale - dir->scale);
|
||
|
+
|
||
|
switch (dir->type)
|
||
|
{
|
||
|
case ICON_THEME_DIR_FIXED:
|
||
|
- *smaller = size < dir->size;
|
||
|
- return abs (size - dir->size);
|
||
|
+ *smaller = scaled_size < scaled_dir_size;
|
||
|
+ return abs (scaled_size - scaled_dir_size);
|
||
|
break;
|
||
|
case ICON_THEME_DIR_SCALABLE:
|
||
|
- *smaller = size < dir->min_size;
|
||
|
- if (size < dir->min_size)
|
||
|
- return dir->min_size - size;
|
||
|
- if (size > dir->max_size)
|
||
|
- return size - dir->max_size;
|
||
|
+ *scale_diff = 0;
|
||
|
+ *smaller = scaled_size < (dir->min_size * dir->scale);
|
||
|
+ if (scaled_size < (dir->min_size * dir->scale))
|
||
|
+ return (dir->min_size * dir->scale) - scaled_size;
|
||
|
+ if (size > (dir->max_size * dir->scale))
|
||
|
+ return scaled_size - (dir->max_size * dir->scale);
|
||
|
return 0;
|
||
|
break;
|
||
|
case ICON_THEME_DIR_THRESHOLD:
|
||
|
- min = dir->size - dir->threshold;
|
||
|
- max = dir->size + dir->threshold;
|
||
|
- *smaller = size < min;
|
||
|
- if (size < min)
|
||
|
- return min - size;
|
||
|
- if (size > max)
|
||
|
- return size - max;
|
||
|
+ min = (dir->size - dir->threshold) * dir->scale;
|
||
|
+ max = (dir->size + dir->threshold) * dir->scale;
|
||
|
+ *smaller = scaled_size < min;
|
||
|
+ if (scaled_size < min)
|
||
|
+ return min - scaled_size;
|
||
|
+ if (scaled_size > max)
|
||
|
+ return scaled_size - max;
|
||
|
return 0;
|
||
|
break;
|
||
|
case ICON_THEME_DIR_UNTHEMED:
|
||
|
@@ -2091,6 +2161,7 @@ static GtkIconInfo *
|
||
|
theme_lookup_icon (IconTheme *theme,
|
||
|
const char *icon_name,
|
||
|
int size,
|
||
|
+ gdouble scale,
|
||
|
gboolean allow_svg,
|
||
|
gboolean use_builtin)
|
||
|
{
|
||
|
@@ -2098,11 +2169,13 @@ theme_lookup_icon (IconTheme *theme,
|
||
|
IconThemeDir *dir, *min_dir;
|
||
|
char *file;
|
||
|
int min_difference, difference;
|
||
|
+ int min_scale_diff, scale_diff;
|
||
|
BuiltinIcon *closest_builtin = NULL;
|
||
|
gboolean smaller, has_larger, match;
|
||
|
IconSuffix suffix;
|
||
|
|
||
|
min_difference = G_MAXINT;
|
||
|
+ min_scale_diff = G_MAXINT;
|
||
|
min_dir = NULL;
|
||
|
has_larger = FALSE;
|
||
|
match = FALSE;
|
||
|
@@ -2135,9 +2208,10 @@ theme_lookup_icon (IconTheme *theme,
|
||
|
suffix = theme_dir_get_icon_suffix (dir, icon_name, NULL);
|
||
|
if (best_suffix (suffix, allow_svg) != ICON_SUFFIX_NONE)
|
||
|
{
|
||
|
- difference = theme_dir_size_difference (dir, size, &smaller);
|
||
|
+ difference = theme_dir_size_difference (dir, size, scale,
|
||
|
+ &smaller, &scale_diff);
|
||
|
|
||
|
- if (difference == 0)
|
||
|
+ if (difference == 0 && scale_diff == 0)
|
||
|
{
|
||
|
if (dir->type == ICON_THEME_DIR_SCALABLE)
|
||
|
{
|
||
|
@@ -2156,13 +2230,15 @@ theme_lookup_icon (IconTheme *theme,
|
||
|
* going and look for a closer match
|
||
|
*/
|
||
|
difference = abs (size - dir->size);
|
||
|
- if (!match || difference < min_difference)
|
||
|
+ if (!match ||
|
||
|
+ (scale_diff <= min_scale_diff && difference < min_difference))
|
||
|
{
|
||
|
match = TRUE;
|
||
|
min_difference = difference;
|
||
|
+ min_scale_diff = scale_diff;
|
||
|
min_dir = dir;
|
||
|
}
|
||
|
- if (difference == 0)
|
||
|
+ if (difference == 0 && scale_diff == 0)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
@@ -2171,18 +2247,20 @@ theme_lookup_icon (IconTheme *theme,
|
||
|
{
|
||
|
if (!has_larger)
|
||
|
{
|
||
|
- if (difference < min_difference || smaller)
|
||
|
+ if ((scale_diff <= min_scale_diff && difference < min_difference) || (scale_diff == 0 && smaller))
|
||
|
{
|
||
|
min_difference = difference;
|
||
|
+ min_scale_diff = scale_diff;
|
||
|
min_dir = dir;
|
||
|
has_larger = smaller;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
- if (difference < min_difference && smaller)
|
||
|
+ if ((scale_diff <= min_scale_diff && difference < min_difference) && (scale_diff == 0 && smaller))
|
||
|
{
|
||
|
min_difference = difference;
|
||
|
+ min_scale_diff = scale_diff;
|
||
|
min_dir = dir;
|
||
|
}
|
||
|
}
|
||
|
@@ -2484,6 +2562,7 @@ theme_subdir_load (GtkIconTheme *icon_theme,
|
||
|
char *full_dir;
|
||
|
GError *error = NULL;
|
||
|
IconThemeDirMtime *dir_mtime;
|
||
|
+ int scale;
|
||
|
|
||
|
size = g_key_file_get_integer (theme_file, subdir, "Size", &error);
|
||
|
if (error)
|
||
|
@@ -2543,6 +2622,11 @@ theme_subdir_load (GtkIconTheme *icon_theme,
|
||
|
error = NULL;
|
||
|
}
|
||
|
|
||
|
+ if (g_key_file_has_key (theme_file, subdir, "OutputScale", NULL))
|
||
|
+ scale = g_key_file_get_integer (theme_file, subdir, "OutputScale", NULL);
|
||
|
+ else
|
||
|
+ scale = 1;
|
||
|
+
|
||
|
for (d = icon_theme->priv->dir_mtimes; d; d = d->next)
|
||
|
{
|
||
|
dir_mtime = (IconThemeDirMtime *)d->data;
|
||
|
@@ -2571,6 +2655,8 @@ theme_subdir_load (GtkIconTheme *icon_theme,
|
||
|
dir->dir = full_dir;
|
||
|
dir->icon_data = NULL;
|
||
|
dir->subdir = g_strdup (subdir);
|
||
|
+ dir->scale = scale;
|
||
|
+
|
||
|
if (dir_mtime->cache != NULL)
|
||
|
{
|
||
|
dir->cache = _gtk_icon_cache_ref (dir_mtime->cache);
|
||
|
diff --git a/gtk/gtkicontheme.h b/gtk/gtkicontheme.h
|
||
|
index 3611c74..9b29f96 100644
|
||
|
--- a/gtk/gtkicontheme.h
|
||
|
+++ b/gtk/gtkicontheme.h
|
||
|
@@ -141,16 +141,31 @@ GtkIconInfo * gtk_icon_theme_lookup_icon (GtkIconTheme
|
||
|
const gchar *icon_name,
|
||
|
gint size,
|
||
|
GtkIconLookupFlags flags);
|
||
|
+GtkIconInfo * gtk_icon_theme_lookup_icon_for_scale (GtkIconTheme *icon_theme,
|
||
|
+ const gchar *icon_name,
|
||
|
+ gint size,
|
||
|
+ gdouble scale,
|
||
|
+ GtkIconLookupFlags flags);
|
||
|
GtkIconInfo * gtk_icon_theme_choose_icon (GtkIconTheme *icon_theme,
|
||
|
const gchar *icon_names[],
|
||
|
gint size,
|
||
|
GtkIconLookupFlags flags);
|
||
|
+GtkIconInfo * gtk_icon_theme_choose_icon_for_scale (GtkIconTheme *icon_theme,
|
||
|
+ const gchar *icon_names[],
|
||
|
+ gint size,
|
||
|
+ gdouble scale,
|
||
|
+ GtkIconLookupFlags flags);
|
||
|
GdkPixbuf * gtk_icon_theme_load_icon (GtkIconTheme *icon_theme,
|
||
|
const gchar *icon_name,
|
||
|
gint size,
|
||
|
GtkIconLookupFlags flags,
|
||
|
GError **error);
|
||
|
-
|
||
|
+GdkPixbuf * gtk_icon_theme_load_icon_for_scale (GtkIconTheme *icon_theme,
|
||
|
+ const gchar *icon_name,
|
||
|
+ gint size,
|
||
|
+ gdouble scale,
|
||
|
+ GtkIconLookupFlags flags,
|
||
|
+ GError **error);
|
||
|
GtkIconInfo * gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme,
|
||
|
GIcon *icon,
|
||
|
gint size,
|
||
|
--
|
||
|
1.7.10.2 (Apple Git-33)
|