1 From 75299b2806b1bed9e14081f2e108afb39e31896e Mon Sep 17 00:00:00 2001
2 From: Carlos Garnacho <carlos@lanedo.com>
3 Date: Fri, 10 May 2013 18:06:00 +0200
4 Subject: [PATCH 58/68] icontheme: Add support for high resolution icons
6 An optional OutputScale integer key has been added to index.theme
7 subdirs description, so icon themes may provide icons that are
8 more suitable to render at a (typically 2x) integer upscaled
9 resolution. This way it is possible to make eg. a 16x16@2x icon has a
10 real size of 32x32, but contains a similar level of detail to the
11 16x16 icon so things don't look any more cluttered on high-dpi
14 The pixbuf lookup has changed so it prefers a minimal scale change
15 that yields the minimal real size difference, so if looking up for
16 a 16x16 icon at 2x, it would first prefer 16x16@2x, then 32x32, and
17 then any other icon that's closest to match
19 There is now *_for_scale() variants for all GtkIconTheme ways
20 to directly or indirectly fetch a GdkPixbuf.
22 gtk/gtkicontheme.c | 152 ++++++++++++++++++++++++++++++++++++++++------------
23 gtk/gtkicontheme.h | 17 +++++-
24 2 files changed, 135 insertions(+), 34 deletions(-)
26 diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
27 index bf81546..500f0ab 100644
28 --- a/gtk/gtkicontheme.c
29 +++ b/gtk/gtkicontheme.c
30 @@ -168,6 +168,7 @@ typedef struct
38 @@ -206,6 +207,7 @@ static void theme_destroy (IconTheme *theme);
39 static GtkIconInfo *theme_lookup_icon (IconTheme *theme,
40 const char *icon_name,
44 gboolean use_default_icons);
45 static void theme_list_icons (IconTheme *theme,
46 @@ -1161,11 +1163,11 @@ _gtk_icon_theme_ensure_builtin_cache (void)
48 static IconThemeDir dirs[5] =
50 - { ICON_THEME_DIR_THRESHOLD, 0, 16, 16, 16, 2, NULL, "16", -1, NULL, NULL, NULL },
51 - { ICON_THEME_DIR_THRESHOLD, 0, 20, 20, 20, 2, NULL, "20", -1, NULL, NULL, NULL },
52 - { ICON_THEME_DIR_THRESHOLD, 0, 24, 24, 24, 2, NULL, "24", -1, NULL, NULL, NULL },
53 - { ICON_THEME_DIR_THRESHOLD, 0, 32, 32, 32, 2, NULL, "32", -1, NULL, NULL, NULL },
54 - { ICON_THEME_DIR_THRESHOLD, 0, 48, 48, 48, 2, NULL, "48", -1, NULL, NULL, NULL }
55 + { ICON_THEME_DIR_THRESHOLD, 0, 16, 16, 16, 2, 1, NULL, "16", -1, NULL, NULL, NULL },
56 + { ICON_THEME_DIR_THRESHOLD, 0, 20, 20, 20, 2, 1, NULL, "20", -1, NULL, NULL, NULL },
57 + { ICON_THEME_DIR_THRESHOLD, 0, 24, 24, 24, 2, 1, NULL, "24", -1, NULL, NULL, NULL },
58 + { ICON_THEME_DIR_THRESHOLD, 0, 32, 32, 32, 2, 1, NULL, "32", -1, NULL, NULL, NULL },
59 + { ICON_THEME_DIR_THRESHOLD, 0, 48, 48, 48, 2, 1, NULL, "48", -1, NULL, NULL, NULL }
63 @@ -1242,6 +1244,7 @@ static GtkIconInfo *
64 choose_icon (GtkIconTheme *icon_theme,
65 const gchar *icon_names[],
68 GtkIconLookupFlags flags)
70 GtkIconThemePrivate *priv;
71 @@ -1271,7 +1274,7 @@ choose_icon (GtkIconTheme *icon_theme,
73 for (i = 0; icon_names[i]; i++)
75 - icon_info = theme_lookup_icon (theme, icon_names[i], size, allow_svg, use_builtin);
76 + icon_info = theme_lookup_icon (theme, icon_names[i], size, scale, allow_svg, use_builtin);
80 @@ -1400,12 +1403,32 @@ gtk_icon_theme_lookup_icon (GtkIconTheme *icon_theme,
82 GtkIconLookupFlags flags)
84 + g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
85 + g_return_val_if_fail (icon_name != NULL, NULL);
86 + g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
87 + (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
89 + GTK_NOTE (ICONTHEME,
90 + g_print ("gtk_icon_theme_lookup_icon %s\n", icon_name));
92 + return gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name,
97 +gtk_icon_theme_lookup_icon_for_scale (GtkIconTheme *icon_theme,
98 + const gchar *icon_name,
101 + GtkIconLookupFlags flags)
105 g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
106 g_return_val_if_fail (icon_name != NULL, NULL);
107 g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
108 (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
109 + g_return_val_if_fail (scale >= 1, NULL);
112 g_print ("gtk_icon_theme_lookup_icon %s\n", icon_name));
113 @@ -1431,7 +1454,7 @@ gtk_icon_theme_lookup_icon (GtkIconTheme *icon_theme,
115 names[dashes + 1] = NULL;
117 - info = choose_icon (icon_theme, (const gchar **) names, size, flags);
118 + info = choose_icon (icon_theme, (const gchar **) names, size, scale, flags);
122 @@ -1442,7 +1465,7 @@ gtk_icon_theme_lookup_icon (GtkIconTheme *icon_theme,
123 names[0] = icon_name;
126 - info = choose_icon (icon_theme, names, size, flags);
127 + info = choose_icon (icon_theme, names, size, scale, flags);
131 @@ -1483,9 +1506,26 @@ gtk_icon_theme_choose_icon (GtkIconTheme *icon_theme,
132 g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
133 (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
135 - return choose_icon (icon_theme, icon_names, size, flags);
136 + return choose_icon (icon_theme, icon_names, size, 1, flags);
140 +gtk_icon_theme_choose_icon_for_scale (GtkIconTheme *icon_theme,
141 + const gchar *icon_names[],
144 + GtkIconLookupFlags flags)
146 + g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
147 + g_return_val_if_fail (icon_names != NULL, NULL);
148 + g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
149 + (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
150 + g_return_val_if_fail (scale >= 1, NULL);
152 + return choose_icon (icon_theme, icon_names, size, scale, flags);
158 gtk_icon_theme_error_quark (void)
159 @@ -1529,6 +1569,24 @@ gtk_icon_theme_load_icon (GtkIconTheme *icon_theme,
160 GtkIconLookupFlags flags,
163 + g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
164 + g_return_val_if_fail (icon_name != NULL, NULL);
165 + g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
166 + (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
167 + g_return_val_if_fail (error == NULL || *error == NULL, NULL);
169 + return gtk_icon_theme_load_icon_for_scale (icon_theme, icon_name,
170 + size, 1, flags, error);
174 +gtk_icon_theme_load_icon_for_scale (GtkIconTheme *icon_theme,
175 + const gchar *icon_name,
178 + GtkIconLookupFlags flags,
181 GtkIconInfo *icon_info;
182 GdkPixbuf *pixbuf = NULL;
184 @@ -1537,9 +1595,10 @@ gtk_icon_theme_load_icon (GtkIconTheme *icon_theme,
185 g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
186 (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
187 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
189 - icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, size,
190 - flags | GTK_ICON_LOOKUP_USE_BUILTIN);
191 + g_return_val_if_fail (scale >= 1, NULL);
193 + icon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name, size, scale,
194 + flags | GTK_ICON_LOOKUP_USE_BUILTIN);
197 g_set_error (error, GTK_ICON_THEME_ERROR, GTK_ICON_THEME_NOT_FOUND,
198 @@ -1976,31 +2035,42 @@ theme_dir_destroy (IconThemeDir *dir)
202 -theme_dir_size_difference (IconThemeDir *dir, int size, gboolean *smaller)
203 +theme_dir_size_difference (IconThemeDir *dir,
209 + int scaled_size, scaled_dir_size;
212 + scaled_size = size * scale;
213 + scaled_dir_size = dir->size * dir->scale;
214 + *scale_diff = abs (scale - dir->scale);
218 case ICON_THEME_DIR_FIXED:
219 - *smaller = size < dir->size;
220 - return abs (size - dir->size);
221 + *smaller = scaled_size < scaled_dir_size;
222 + return abs (scaled_size - scaled_dir_size);
224 case ICON_THEME_DIR_SCALABLE:
225 - *smaller = size < dir->min_size;
226 - if (size < dir->min_size)
227 - return dir->min_size - size;
228 - if (size > dir->max_size)
229 - return size - dir->max_size;
231 + *smaller = scaled_size < (dir->min_size * dir->scale);
232 + if (scaled_size < (dir->min_size * dir->scale))
233 + return (dir->min_size * dir->scale) - scaled_size;
234 + if (size > (dir->max_size * dir->scale))
235 + return scaled_size - (dir->max_size * dir->scale);
238 case ICON_THEME_DIR_THRESHOLD:
239 - min = dir->size - dir->threshold;
240 - max = dir->size + dir->threshold;
241 - *smaller = size < min;
246 + min = (dir->size - dir->threshold) * dir->scale;
247 + max = (dir->size + dir->threshold) * dir->scale;
248 + *smaller = scaled_size < min;
249 + if (scaled_size < min)
250 + return min - scaled_size;
251 + if (scaled_size > max)
252 + return scaled_size - max;
255 case ICON_THEME_DIR_UNTHEMED:
256 @@ -2091,6 +2161,7 @@ static GtkIconInfo *
257 theme_lookup_icon (IconTheme *theme,
258 const char *icon_name,
262 gboolean use_builtin)
264 @@ -2098,11 +2169,13 @@ theme_lookup_icon (IconTheme *theme,
265 IconThemeDir *dir, *min_dir;
267 int min_difference, difference;
268 + int min_scale_diff, scale_diff;
269 BuiltinIcon *closest_builtin = NULL;
270 gboolean smaller, has_larger, match;
273 min_difference = G_MAXINT;
274 + min_scale_diff = G_MAXINT;
278 @@ -2135,9 +2208,10 @@ theme_lookup_icon (IconTheme *theme,
279 suffix = theme_dir_get_icon_suffix (dir, icon_name, NULL);
280 if (best_suffix (suffix, allow_svg) != ICON_SUFFIX_NONE)
282 - difference = theme_dir_size_difference (dir, size, &smaller);
283 + difference = theme_dir_size_difference (dir, size, scale,
284 + &smaller, &scale_diff);
286 - if (difference == 0)
287 + if (difference == 0 && scale_diff == 0)
289 if (dir->type == ICON_THEME_DIR_SCALABLE)
291 @@ -2156,13 +2230,15 @@ theme_lookup_icon (IconTheme *theme,
292 * going and look for a closer match
294 difference = abs (size - dir->size);
295 - if (!match || difference < min_difference)
297 + (scale_diff <= min_scale_diff && difference < min_difference))
300 min_difference = difference;
301 + min_scale_diff = scale_diff;
304 - if (difference == 0)
305 + if (difference == 0 && scale_diff == 0)
309 @@ -2171,18 +2247,20 @@ theme_lookup_icon (IconTheme *theme,
313 - if (difference < min_difference || smaller)
314 + if ((scale_diff <= min_scale_diff && difference < min_difference) || (scale_diff == 0 && smaller))
316 min_difference = difference;
317 + min_scale_diff = scale_diff;
319 has_larger = smaller;
324 - if (difference < min_difference && smaller)
325 + if ((scale_diff <= min_scale_diff && difference < min_difference) && (scale_diff == 0 && smaller))
327 min_difference = difference;
328 + min_scale_diff = scale_diff;
332 @@ -2484,6 +2562,7 @@ theme_subdir_load (GtkIconTheme *icon_theme,
334 GError *error = NULL;
335 IconThemeDirMtime *dir_mtime;
338 size = g_key_file_get_integer (theme_file, subdir, "Size", &error);
340 @@ -2543,6 +2622,11 @@ theme_subdir_load (GtkIconTheme *icon_theme,
344 + if (g_key_file_has_key (theme_file, subdir, "OutputScale", NULL))
345 + scale = g_key_file_get_integer (theme_file, subdir, "OutputScale", NULL);
349 for (d = icon_theme->priv->dir_mtimes; d; d = d->next)
351 dir_mtime = (IconThemeDirMtime *)d->data;
352 @@ -2571,6 +2655,8 @@ theme_subdir_load (GtkIconTheme *icon_theme,
354 dir->icon_data = NULL;
355 dir->subdir = g_strdup (subdir);
356 + dir->scale = scale;
358 if (dir_mtime->cache != NULL)
360 dir->cache = _gtk_icon_cache_ref (dir_mtime->cache);
361 diff --git a/gtk/gtkicontheme.h b/gtk/gtkicontheme.h
362 index 3611c74..9b29f96 100644
363 --- a/gtk/gtkicontheme.h
364 +++ b/gtk/gtkicontheme.h
365 @@ -141,16 +141,31 @@ GtkIconInfo * gtk_icon_theme_lookup_icon (GtkIconTheme
366 const gchar *icon_name,
368 GtkIconLookupFlags flags);
369 +GtkIconInfo * gtk_icon_theme_lookup_icon_for_scale (GtkIconTheme *icon_theme,
370 + const gchar *icon_name,
373 + GtkIconLookupFlags flags);
374 GtkIconInfo * gtk_icon_theme_choose_icon (GtkIconTheme *icon_theme,
375 const gchar *icon_names[],
377 GtkIconLookupFlags flags);
378 +GtkIconInfo * gtk_icon_theme_choose_icon_for_scale (GtkIconTheme *icon_theme,
379 + const gchar *icon_names[],
382 + GtkIconLookupFlags flags);
383 GdkPixbuf * gtk_icon_theme_load_icon (GtkIconTheme *icon_theme,
384 const gchar *icon_name,
386 GtkIconLookupFlags flags,
389 +GdkPixbuf * gtk_icon_theme_load_icon_for_scale (GtkIconTheme *icon_theme,
390 + const gchar *icon_name,
393 + GtkIconLookupFlags flags,
395 GtkIconInfo * gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme,
399 1.7.10.2 (Apple Git-33)