diff options
Diffstat (limited to 'gtk/gtkicontheme.c')
-rw-r--r-- | gtk/gtkicontheme.c | 473 |
1 files changed, 359 insertions, 114 deletions
diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index 2414257034..566688dad0 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -55,6 +55,10 @@ #include "deprecated/gtkstyle.h" +/* this is in case round() is not provided by the compiler, + * such as in the case of C89 compilers, like MSVC + */ +#include "fallback-c89.c" /** * SECTION:gtkicontheme @@ -208,6 +212,7 @@ struct _GtkIconThemePrivate typedef struct { gchar **icon_names; gint size; + gint scale; GtkIconLookupFlags flags; } IconInfoKey; @@ -252,11 +257,13 @@ struct _GtkIconInfo */ IconThemeDirType dir_type; gint dir_size; + gint dir_scale; gint threshold; /* Parameters influencing the scaled icon */ gint desired_size; + gint desired_scale; guint raw_coordinates : 1; guint forced_size : 1; guint emblems_applied : 1; @@ -294,6 +301,7 @@ typedef struct int min_size; int max_size; int threshold; + int scale; char *dir; char *subdir; @@ -332,6 +340,7 @@ static void theme_destroy (IconTheme *theme); static GtkIconInfo *theme_lookup_icon (IconTheme *theme, const char *icon_name, int size, + gint scale, gboolean allow_svg, gboolean use_default_icons); static void theme_list_icons (IconTheme *theme, @@ -367,8 +376,8 @@ static IconSuffix suffix_from_name (const char *name); static BuiltinIcon *find_builtin_icon (const gchar *icon_name, gint size, - gint *min_difference_p, - gboolean *has_larger_p); + gint scale, + gint *min_difference_p); static void remove_from_lru_cache (GtkIconTheme *icon_theme, GtkIconInfo *icon_info); @@ -390,7 +399,8 @@ icon_info_key_hash (gconstpointer _key) h ^= g_str_hash (key->icon_names[i]); h ^= key->size * 0x10001; - h ^= key->flags * 0x1000010; + h ^= key->scale * 0x1000010; + h ^= key->flags * 0x100000100; return h; } @@ -406,6 +416,9 @@ icon_info_key_equal (gconstpointer _a, if (a->size != b->size) return FALSE; + if (a->scale != b->scale) + return FALSE; + if (a->flags != b->flags) return FALSE; @@ -1342,11 +1355,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; @@ -1574,6 +1587,7 @@ static GtkIconInfo * choose_icon (GtkIconTheme *icon_theme, const gchar *icon_names[], gint size, + gint scale, GtkIconLookupFlags flags) { GtkIconThemePrivate *priv; @@ -1591,6 +1605,7 @@ choose_icon (GtkIconTheme *icon_theme, key.icon_names = (char **)icon_names; key.size = size; + key.scale = scale; key.flags = flags; icon_info = g_hash_table_lookup (priv->info_cache, &key); @@ -1628,7 +1643,7 @@ choose_icon (GtkIconTheme *icon_theme, for (l = priv->themes; l; l = l->next) { IconTheme *theme = l->data; - icon_info = theme_lookup_icon (theme, icon_names[0], size, allow_svg, use_builtin); + icon_info = theme_lookup_icon (theme, icon_names[0], size, scale, allow_svg, use_builtin); if (icon_info) goto out; } @@ -1640,7 +1655,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; } @@ -1674,6 +1689,7 @@ choose_icon (GtkIconTheme *icon_theme, DestroyIcon (hIcon); icon_info->dir_type = ICON_THEME_DIR_UNTHEMED; icon_info->dir_size = size; + icon_info->dir_scale = 1; } g_strfreev (resources); } @@ -1698,16 +1714,19 @@ choose_icon (GtkIconTheme *icon_theme, icon_info->dir_type = ICON_THEME_DIR_UNTHEMED; icon_info->dir_size = size; + icon_info->dir_scale = 1; } out: if (icon_info) { icon_info->desired_size = size; + icon_info->desired_scale = scale; icon_info->forced_size = (flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0; icon_info->key.icon_names = g_strdupv ((char **)icon_names); icon_info->key.size = size; + icon_info->key.scale = scale; icon_info->key.flags = flags; icon_info->in_cache = icon_theme; DEBUG_CACHE (("adding %p (%s %d 0x%x) to cache (cache size %d)\n", @@ -1777,12 +1796,51 @@ 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); +} + +/** + * gtk_icon_theme_lookup_icon_for_scale: + * @icon_theme: a #GtkIconTheme + * @icon_name: the name of the icon to lookup + * @size: desired icon size + * @scale: the desired scale + * @flags: flags modifying the behavior of the icon lookup + * + * Looks up a named icon for a particular window scale and returns a + * structure containing information such as the filename of the + * icon. The icon can then be rendered into a pixbuf using + * gtk_icon_info_load_icon(). (gtk_icon_theme_load_icon() combines + * these two steps if all you need is the pixbuf.) + * + * Return value: (transfer full): a #GtkIconInfo object containing + * information about the icon, or %NULL if the icon wasn't found. + * + * Since: 3.10 + */ +GtkIconInfo * +gtk_icon_theme_lookup_icon_for_scale (GtkIconTheme *icon_theme, + const gchar *icon_name, + gint size, + gint 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)); @@ -1808,7 +1866,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); } @@ -1819,7 +1877,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; @@ -1859,9 +1917,50 @@ 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); } +/** + * gtk_icon_theme_choose_icon_for_scale: + * @icon_theme: a #GtkIconTheme + * @icon_names: (array zero-terminated=1): %NULL-terminated array of + * icon names to lookup + * @size: desired icon size + * @scale: desired scale + * @flags: flags modifying the behavior of the icon lookup + * + * Looks up a named icon for a particular window scale and returns a + * structure containing information such as the filename of the + * icon. The icon can then be rendered into a pixbuf using + * gtk_icon_info_load_icon(). (gtk_icon_theme_load_icon() combines + * these two steps if all you need is the pixbuf.) + * + * If @icon_names contains more than one name, this function + * tries them all in the given order before falling back to + * inherited icon themes. + * + * Return value: (transfer full): a #GtkIconInfo object containing information + * about the icon, or %NULL if the icon wasn't found. + * + * Since: 3.10 + */ +GtkIconInfo * +gtk_icon_theme_choose_icon_for_scale (GtkIconTheme *icon_theme, + const gchar *icon_names[], + gint size, + gint 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) @@ -1906,6 +2005,56 @@ 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); +} + +/** + * gtk_icon_theme_load_icon_for_scale: + * @icon_theme: a #GtkIconTheme + * @icon_name: the name of the icon to lookup + * @size: the desired icon size. The resulting icon may not be + * exactly this size; see gtk_icon_info_load_icon(). + * @scale: desired scale + * @flags: flags modifying the behavior of the icon lookup + * @error: (allow-none): Location to store error information on failure, + * or %NULL. + * + * Looks up an icon in an icon theme for a particular window scale, + * scales it to the given size and renders it into a pixbuf. This is a + * convenience function; if more details about the icon are needed, + * use gtk_icon_theme_lookup_icon() followed by + * gtk_icon_info_load_icon(). + * + * Note that you probably want to listen for icon theme changes and + * update the icon. This is usually done by connecting to the + * GtkWidget::style-set signal. If for some reason you do not want to + * update the icon when the icon theme changes, you should consider + * using gdk_pixbuf_copy() to make a private copy of the pixbuf + * returned by this function. Otherwise GTK+ may need to keep the old + * icon theme loaded, which would be a waste of memory. + * + * Return value: (transfer full): the rendered icon; this may be a + * newly created icon or a new reference to an internal icon, so + * you must not modify the icon. Use g_object_unref() to release + * your reference to the icon. %NULL if the icon isn't found. + * + * Since: 3.10 + **/ +GdkPixbuf * +gtk_icon_theme_load_icon_for_scale (GtkIconTheme *icon_theme, + const gchar *icon_name, + gint size, + gint scale, + GtkIconLookupFlags flags, + GError **error) +{ GtkIconInfo *icon_info; GdkPixbuf *pixbuf = NULL; @@ -1914,9 +2063,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, @@ -2352,31 +2502,35 @@ 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, + gint scale) { + int scaled_size, scaled_dir_size; int min, max; + + scaled_size = size * scale; + scaled_dir_size = dir->size * dir->scale; + switch (dir->type) { case ICON_THEME_DIR_FIXED: - *smaller = size < dir->size; - return abs (size - 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; + 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; + if (scaled_size < min) + return min - scaled_size; + if (scaled_size > max) + return scaled_size - max; return 0; break; case ICON_THEME_DIR_UNTHEMED: @@ -2463,10 +2617,75 @@ theme_dir_get_icon_suffix (IconThemeDir *dir, return suffix; } +/* returns TRUE if dir_a is a better match */ +static gboolean +compare_dir_matches (IconThemeDir *dir_a, int difference_a, + IconThemeDir *dir_b, int difference_b, + int requested_size, int requested_scale) +{ + int diff_a; + int diff_b; + + if (difference_a == 0) + { + if (difference_b != 0) + return TRUE; + + /* a and b both exact matches */ + } + else + { + /* If scaling, *always* prefer downscaling */ + if (dir_a->size >= requested_size && + dir_b->size < requested_size) + return TRUE; + + if (dir_a->size < requested_size && + dir_b->size >= requested_size) + return FALSE; + + /* Otherwise prefer the closest match */ + + if (difference_a < difference_b) + return TRUE; + + if (difference_a > difference_b) + return FALSE; + + /* same pixel difference */ + } + + if (dir_a->scale == requested_scale && + dir_b->scale != requested_scale) + return TRUE; + + if (dir_a->scale != requested_scale && + dir_b->scale == requested_scale) + return FALSE; + + /* a and b both match the scale */ + + if (dir_a->type != ICON_THEME_DIR_SCALABLE && + dir_b->type == ICON_THEME_DIR_SCALABLE) + return TRUE; + + if (dir_a->type == ICON_THEME_DIR_SCALABLE && + dir_b->type != ICON_THEME_DIR_SCALABLE) + return FALSE; + + /* a and b both are scalable */ + + diff_a = abs (requested_size * requested_scale - dir_a->size * dir_a->scale); + diff_b = abs (requested_size * requested_scale - dir_b->size * dir_b->scale); + + return diff_a <= diff_b; +} + static GtkIconInfo * theme_lookup_icon (IconTheme *theme, const char *icon_name, int size, + gint scale, gboolean allow_svg, gboolean use_builtin) { @@ -2475,13 +2694,10 @@ theme_lookup_icon (IconTheme *theme, char *file; int min_difference, difference; BuiltinIcon *closest_builtin = NULL; - gboolean smaller, has_larger, match; IconSuffix suffix; min_difference = G_MAXINT; min_dir = NULL; - has_larger = FALSE; - match = FALSE; /* Builtin icons are logically part of the default theme and * are searched before other subdirectories of the default theme. @@ -2489,9 +2705,8 @@ theme_lookup_icon (IconTheme *theme, if (use_builtin && strcmp (theme->name, DEFAULT_THEME_NAME) == 0) { closest_builtin = find_builtin_icon (icon_name, - size, - &min_difference, - &has_larger); + size, scale, + &min_difference); if (min_difference == 0) return icon_info_new_builtin (closest_builtin); @@ -2511,57 +2726,14 @@ 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); - - if (difference == 0) + difference = theme_dir_size_difference (dir, size, scale); + if (min_dir == NULL || + compare_dir_matches (dir, difference, + min_dir, min_difference, + size, scale)) { - if (dir->type == ICON_THEME_DIR_SCALABLE) - { - /* don't pick scalable if we already found - * a matching non-scalable dir - */ - if (!match) - { - min_dir = dir; - break; - } - } - else - { - /* for a matching non-scalable dir keep - * going and look for a closer match - */ - difference = abs (size - dir->size); - if (!match || difference < min_difference) - { - match = TRUE; - min_difference = difference; - min_dir = dir; - } - if (difference == 0) - break; - } - } - - if (!match) - { - if (!has_larger) - { - if (difference < min_difference || smaller) - { - min_difference = difference; - min_dir = dir; - has_larger = smaller; - } - } - else - { - if (difference < min_difference && smaller) - { - min_difference = difference; - min_dir = dir; - } - } + min_dir = dir; + min_difference = difference; } } @@ -2640,6 +2812,7 @@ theme_lookup_icon (IconTheme *theme, icon_info->dir_type = min_dir->type; icon_info->dir_size = min_dir->size; + icon_info->dir_scale = min_dir->scale; icon_info->threshold = min_dir->threshold; return icon_info; @@ -2858,6 +3031,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) @@ -2905,6 +3079,11 @@ theme_subdir_load (GtkIconTheme *icon_theme, else threshold = 2; + 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; @@ -2933,6 +3112,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); @@ -3048,8 +3229,10 @@ icon_info_dup (GtkIconInfo *icon_info) dup->data = icon_data_dup (icon_info->data); dup->dir_type = icon_info->dir_type; dup->dir_size = icon_info->dir_size; + dup->dir_scale = icon_info->dir_scale; dup->threshold = icon_info->threshold; dup->desired_size = icon_info->desired_size; + dup->desired_scale = icon_info->desired_scale; dup->raw_coordinates = icon_info->raw_coordinates; dup->forced_size = icon_info->forced_size; dup->emblems_applied = icon_info->emblems_applied; @@ -3065,6 +3248,7 @@ icon_info_new_builtin (BuiltinIcon *icon) icon_info->cache_pixbuf = g_object_ref (icon->pixbuf); icon_info->dir_type = ICON_THEME_DIR_THRESHOLD; icon_info->dir_size = icon->size; + icon_info->dir_scale = 1; icon_info->threshold = 2; return icon_info; @@ -3158,7 +3342,10 @@ gtk_icon_info_class_init (GtkIconInfoClass *klass) * to a larger icon. These icons will be given * the same base size as the larger icons to which * they are attached. - * + * + * Note that for scaled icons the base size does + * not include the base scale. + * * Return value: the base size, or 0, if no base * size is known for the icon. * @@ -3173,6 +3360,27 @@ gtk_icon_info_get_base_size (GtkIconInfo *icon_info) } /** + * gtk_icon_info_get_base_scale: + * @icon_info: a #GtkIconInfo + * + * Gets the base scale for the icon. The base scale is a scale for the + * icon that was specified by the icon theme creator. For instance an + * icon drawn for a high-dpi screen with window-scale 2 for a base + * size of 32 will be 64 pixels tall and have a base_scale of 2. + * + * Return value: the base scale. + * + * Since: 3.10 + **/ +gint +gtk_icon_info_get_base_scale (GtkIconInfo *icon_info) +{ + g_return_val_if_fail (icon_info != NULL, 0); + + return icon_info->dir_scale; +} + +/** * gtk_icon_info_get_filename: * @icon_info: a #GtkIconInfo * @@ -3332,6 +3540,7 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, gboolean scale_only) { int image_width, image_height; + int scaled_desired_size; GdkPixbuf *source_pixbuf; gboolean is_svg; @@ -3356,6 +3565,8 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, if (icon_info->icon_file && !icon_info->loadable) icon_info->loadable = G_LOADABLE_ICON (g_file_icon_new (icon_info->icon_file)); + scaled_desired_size = icon_info->desired_size * icon_info->desired_scale; + is_svg = FALSE; if (G_IS_FILE_ICON (icon_info->loadable)) { @@ -3383,20 +3594,21 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, { GInputStream *stream; - icon_info->scale = icon_info->desired_size / 1000.; + icon_info->scale = scaled_desired_size / 1000.; if (scale_only) return TRUE; - + + /* TODO: We should have a load_at_scale */ stream = g_loadable_icon_load (icon_info->loadable, - icon_info->desired_size, + scaled_desired_size, NULL, NULL, &icon_info->load_error); if (stream) { icon_info->pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, - icon_info->desired_size, - icon_info->desired_size, + scaled_desired_size, + scaled_desired_size, TRUE, NULL, &icon_info->load_error); @@ -3419,19 +3631,19 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, if (icon_info->forced_size) icon_info->scale = -1; else if (icon_info->dir_type == ICON_THEME_DIR_FIXED) - icon_info->scale = 1.0; + icon_info->scale = round((gdouble) scaled_desired_size / (icon_info->dir_size * icon_info->dir_scale)); else if (icon_info->dir_type == ICON_THEME_DIR_THRESHOLD) { - if (icon_info->desired_size >= icon_info->dir_size - icon_info->threshold && - icon_info->desired_size <= icon_info->dir_size + icon_info->threshold) - icon_info->scale = 1.0; + if (scaled_desired_size >= (icon_info->dir_size - icon_info->threshold) * icon_info->dir_scale && + scaled_desired_size <= (icon_info->dir_size + icon_info->threshold) * icon_info->dir_scale) + icon_info->scale = round((gdouble) scaled_desired_size / (icon_info->dir_size * icon_info->dir_scale)); else if (icon_info->dir_size > 0) - icon_info->scale =(gdouble) icon_info->desired_size / icon_info->dir_size; + icon_info->scale =(gdouble) scaled_desired_size / (icon_info->dir_size * icon_info->dir_scale); } else if (icon_info->dir_type == ICON_THEME_DIR_SCALABLE) { if (icon_info->dir_size > 0) - icon_info->scale = (gdouble) icon_info->desired_size / icon_info->dir_size; + icon_info->scale = (gdouble) scaled_desired_size / (icon_info->dir_size * icon_info->dir_scale); } if (icon_info->scale >= 0. && scale_only) @@ -3447,8 +3659,9 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, { GInputStream *stream; + /* TODO: We should have a load_at_scale */ stream = g_loadable_icon_load (icon_info->loadable, - icon_info->desired_size, + scaled_desired_size, NULL, NULL, &icon_info->load_error); if (stream) @@ -3472,7 +3685,7 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, { gint image_size = MAX (image_width, image_height); if (image_size > 0) - icon_info->scale = (gdouble)icon_info->desired_size / (gdouble)image_size; + icon_info->scale = (gdouble)scaled_desired_size / (gdouble)image_size; else icon_info->scale = 1.0; @@ -3887,8 +4100,8 @@ _gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info, stream = g_memory_input_stream_new_from_data (data, -1, g_free); pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, - icon_info->desired_size, - icon_info->desired_size, + icon_info->desired_size * icon_info->desired_scale, + icon_info->desired_size * icon_info->desired_scale, TRUE, NULL, error); @@ -4740,8 +4953,8 @@ gtk_icon_theme_add_builtin_icon (const gchar *icon_name, static BuiltinIcon * find_builtin_icon (const gchar *icon_name, gint size, - gint *min_difference_p, - gboolean *has_larger_p) + gint scale, + gint *min_difference_p) { GSList *icons = NULL; gint min_difference = G_MAXINT; @@ -4751,6 +4964,8 @@ find_builtin_icon (const gchar *icon_name, if (!icon_theme_builtin_icons) return NULL; + size *= scale; + icons = g_hash_table_lookup (icon_theme_builtin_icons, icon_name); while (icons) @@ -4798,8 +5013,6 @@ find_builtin_icon (const gchar *icon_name, if (min_difference_p) *min_difference_p = min_difference; - if (has_larger_p) - *has_larger_p = has_larger; return min_icon; } @@ -4828,6 +5041,37 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme, gint size, GtkIconLookupFlags flags) { + return gtk_icon_theme_lookup_by_gicon_for_scale (icon_theme, icon, + size, 1, flags); +} + + +/** + * gtk_icon_theme_lookup_by_gicon_for_scale: + * @icon_theme: a #GtkIconTheme + * @icon: the #GIcon to look up + * @size: desired icon size + * @scale: the desired scale + * @flags: flags modifying the behavior of the icon lookup + * + * Looks up an icon and returns a structure containing + * information such as the filename of the icon. + * The icon can then be rendered into a pixbuf using + * gtk_icon_info_load_icon_for_scale (). + * + * Return value: (transfer full): a #GtkIconInfo structure containing + * information about the icon, or %NULL if the icon + * wasn't found. Unref with g_object_unref() + * + * Since: 2.14 + */ +GtkIconInfo * +gtk_icon_theme_lookup_by_gicon_for_scale (GtkIconTheme *icon_theme, + GIcon *icon, + gint size, + gint scale, + GtkIconLookupFlags flags) +{ GtkIconInfo *info; g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL); @@ -4851,6 +5095,7 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme, info->dir_type = ICON_THEME_DIR_UNTHEMED; info->dir_size = size; info->desired_size = size; + info->desired_scale = scale; info->threshold = 2; info->forced_size = (flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0; @@ -4861,7 +5106,7 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme, const gchar **names; names = (const gchar **)g_themed_icon_get_names (G_THEMED_ICON (icon)); - info = gtk_icon_theme_choose_icon (icon_theme, names, size, flags); + info = gtk_icon_theme_choose_icon_for_scale (icon_theme, names, size, scale, flags); return info; } @@ -4875,7 +5120,7 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme, _gtk_numerable_icon_set_background_icon_size (GTK_NUMERABLE_ICON (icon), size / 2); base = g_emblemed_icon_get_icon (G_EMBLEMED_ICON (icon)); - base_info = gtk_icon_theme_lookup_by_gicon (icon_theme, base, size, flags); + base_info = gtk_icon_theme_lookup_by_gicon_for_scale (icon_theme, base, size, scale, flags); if (base_info) { info = icon_info_dup (base_info); @@ -4886,7 +5131,7 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme, { emblem = g_emblem_get_icon (G_EMBLEM (l->data)); /* always force size for emblems */ - emblem_info = gtk_icon_theme_lookup_by_gicon (icon_theme, emblem, size / 2, flags | GTK_ICON_LOOKUP_FORCE_SIZE); + emblem_info = gtk_icon_theme_lookup_by_gicon_for_scale (icon_theme, emblem, size / 2, scale, flags | GTK_ICON_LOOKUP_FORCE_SIZE); if (emblem_info) info->emblem_infos = g_slist_prepend (info->emblem_infos, emblem_info); } @@ -4905,17 +5150,17 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme, if ((flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0) { gint width, height, max; - gdouble scale; + gdouble pixbuf_scale; GdkPixbuf *scaled; width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); max = MAX (width, height); - scale = (gdouble) size / (gdouble) max; + pixbuf_scale = (gdouble) size * scale / (gdouble) max; scaled = gdk_pixbuf_scale_simple (pixbuf, - 0.5 + width * scale, - 0.5 + height * scale, + 0.5 + width * pixbuf_scale, + 0.5 + height * pixbuf_scale, GDK_INTERP_BILINEAR); info = gtk_icon_info_new_for_pixbuf (icon_theme, scaled); |