X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkicontheme.c;h=7a0a55771ba59e7b96efa9d2ce40864c6ebbd25a;hb=0e1041a8afe021ebc5aff25ad76e113af09ca021;hp=d6accc94fe736396b50e0e69d643c12168400144;hpb=11e2767fbdcac7a3ec97467a437ac3f4c989fa32;p=~andy%2Fgtk diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index d6accc94f..7a0a55771 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -33,17 +33,21 @@ #ifndef S_ISDIR #define S_ISDIR(mode) ((mode)&_S_IFDIR) #endif +#define WIN32_MEAN_AND_LEAN +#include +#include "win32/gdkwin32.h" #endif /* G_OS_WIN32 */ #include "gtkicontheme.h" +#include "gtkdebug.h" #include "gtkiconfactory.h" #include "gtkiconcache.h" #include "gtkbuiltincache.h" #include "gtkintl.h" #include "gtkmain.h" +#include "gtknumerableiconprivate.h" #include "gtksettings.h" #include "gtkprivate.h" -#include "gtkalias.h" #define DEFAULT_THEME_NAME "hicolor" @@ -107,12 +111,9 @@ struct _GtkIconInfo /* Information about the source */ gchar *filename; -#ifdef G_OS_WIN32 - /* System codepage version of filename, for DLL ABI backward - * compatibility functions. - */ - gchar *cp_filename; -#endif + GLoadableIcon *loadable; + GSList *emblem_infos; + /* Cache pixbuf (if there is any) */ GdkPixbuf *cache_pixbuf; @@ -128,7 +129,8 @@ struct _GtkIconInfo /* Parameters influencing the scaled icon */ gint desired_size; - gboolean raw_coordinates; + guint raw_coordinates : 1; + guint forced_size : 1; /* Cached information if we go ahead and try to load * the icon. @@ -136,6 +138,9 @@ struct _GtkIconInfo GdkPixbuf *pixbuf; GError *load_error; gdouble scale; + gboolean emblems_applied; + + guint ref_count; }; typedef struct @@ -161,6 +166,7 @@ typedef struct char *dir; char *subdir; + int subdir_index; GtkIconCache *cache; @@ -265,8 +271,8 @@ gtk_icon_theme_new (void) * * Gets the icon theme for the default screen. See * gtk_icon_theme_get_for_screen(). - * - * Return value: A unique #GtkIconTheme associated with + * + * Return value: (transfer none): A unique #GtkIconTheme associated with * the default screen. This icon theme is associated with * the screen and can be used as long as the screen * is open. Do not ref or unref it. @@ -291,8 +297,8 @@ gtk_icon_theme_get_default (void) * is usually a better choice than calling than gtk_icon_theme_new() * and setting the screen yourself; by using this function * a single icon theme object will be shared between users. - * - * Return value: A unique #GtkIconTheme associated with + * + * Return value: (transfer none): A unique #GtkIconTheme associated with * the given screen. This icon theme is associated with * the screen and can be used as long as the screen * is open. Do not ref or unref it. @@ -305,7 +311,6 @@ gtk_icon_theme_get_for_screen (GdkScreen *screen) GtkIconTheme *icon_theme; g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); - g_return_val_if_fail (!screen->closed, NULL); icon_theme = g_object_get_data (G_OBJECT (screen), "gtk-icon-theme"); if (!icon_theme) @@ -548,9 +553,10 @@ gtk_icon_theme_init (GtkIconTheme *icon_theme) GtkIconThemePrivate *priv; const gchar * const *xdg_data_dirs; int i, j; - - priv = g_type_instance_get_private ((GTypeInstance *)icon_theme, - GTK_TYPE_ICON_THEME); + + priv = G_TYPE_INSTANCE_GET_PRIVATE (icon_theme, + GTK_TYPE_ICON_THEME, + GtkIconThemePrivate); icon_theme->priv = priv; priv->custom_theme = FALSE; @@ -600,10 +606,7 @@ reset_styles_idle (gpointer user_data) priv = icon_theme->priv; if (priv->screen && priv->is_screen_singleton) - { - GtkSettings *settings = gtk_settings_get_for_screen (priv->screen); - gtk_rc_reset_styles (settings); - } + gtk_style_context_reset_widgets (priv->screen); priv->reset_styles_idle = 0; @@ -685,7 +688,8 @@ gtk_icon_theme_finalize (GObject *object) /** * gtk_icon_theme_set_search_path: * @icon_theme: a #GtkIconTheme - * @path: array of directories that are searched for icon themes + * @path: (array length=n_elements) (element-type filename): array of + * directories that are searched for icon themes * @n_elements: number of elements in @path. * * Sets the search path for the icon theme object. When looking @@ -734,19 +738,19 @@ gtk_icon_theme_set_search_path (GtkIconTheme *icon_theme, /** * gtk_icon_theme_get_search_path: * @icon_theme: a #GtkIconTheme - * @path: location to store a list of icon theme path directories or %NULL - * The stored value should be freed with g_strfreev(). - * @n_elements: location to store number of elements - * in @path, or %NULL - * + * @path: (allow-none) (array length=n_elements) (element-type filename) (out): + * location to store a list of icon theme path directories or %NULL. + * The stored value should be freed with g_strfreev(). + * @n_elements: location to store number of elements in @path, or %NULL + * * Gets the current search path. See gtk_icon_theme_set_search_path(). * * Since: 2.4 - **/ + */ void -gtk_icon_theme_get_search_path (GtkIconTheme *icon_theme, - gchar **path[], - gint *n_elements) +gtk_icon_theme_get_search_path (GtkIconTheme *icon_theme, + gchar **path[], + gint *n_elements) { GtkIconThemePrivate *priv; int i; @@ -770,7 +774,7 @@ gtk_icon_theme_get_search_path (GtkIconTheme *icon_theme, /** * gtk_icon_theme_append_search_path: * @icon_theme: a #GtkIconTheme - * @path: directory name to append to the icon path + * @path: (type filename): directory name to append to the icon path * * Appends a directory to the search path. * See gtk_icon_theme_set_search_path(). @@ -799,7 +803,7 @@ gtk_icon_theme_append_search_path (GtkIconTheme *icon_theme, /** * gtk_icon_theme_prepend_search_path: * @icon_theme: a #GtkIconTheme - * @path: directory name to prepend to the icon path + * @path: (type filename): directory name to prepend to the icon path * * Prepends a directory to the search path. * See gtk_icon_theme_set_search_path(). @@ -832,8 +836,8 @@ gtk_icon_theme_prepend_search_path (GtkIconTheme *icon_theme, /** * gtk_icon_theme_set_custom_theme: * @icon_theme: a #GtkIconTheme - * @theme_name: name of icon theme to use instead of configured theme, - * or %NULL to unset a previously set custom theme + * @theme_name: (allow-none): name of icon theme to use instead of + * configured theme, or %NULL to unset a previously set custom theme * * Sets the name of the icon theme that the #GtkIconTheme object uses * overriding system configuration. This function cannot be called @@ -1149,11 +1153,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", NULL, NULL, NULL }, - { ICON_THEME_DIR_THRESHOLD, 0, 20, 20, 20, 2, NULL, "20", NULL, NULL, NULL }, - { ICON_THEME_DIR_THRESHOLD, 0, 24, 24, 24, 2, NULL, "24", NULL, NULL, NULL }, - { ICON_THEME_DIR_THRESHOLD, 0, 32, 32, 32, 2, NULL, "32", NULL, NULL, NULL }, - { ICON_THEME_DIR_THRESHOLD, 0, 48, 48, 48, 2, NULL, "48", NULL, NULL, NULL } + { 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 } }; gint i; @@ -1167,6 +1171,7 @@ _gtk_icon_theme_ensure_builtin_cache (void) { dir = &(dirs[i]); dir->cache = _gtk_icon_cache_ref (_builtin_cache); + dir->subdir_index = _gtk_icon_cache_get_directory_index (dir->cache, dir->subdir); builtin_dirs = g_list_append (builtin_dirs, dir); } @@ -1202,23 +1207,6 @@ ensure_valid_themes (GtkIconTheme *icon_theme) if (was_valid) { g_signal_emit (icon_theme, signal_changed, 0); - - if (!priv->check_reload && priv->screen) - { - static GdkAtom atom_iconthemes = GDK_NONE; - GdkEvent *event = gdk_event_new (GDK_CLIENT_EVENT); - int i; - - if (!atom_iconthemes) - atom_iconthemes = gdk_atom_intern_static_string ("_GTK_LOAD_ICONTHEMES"); - - for (i = 0; i < 5; i++) - event->client.data.l[i] = 0; - event->client.data_format = 32; - event->client.message_type = atom_iconthemes; - - gdk_screen_broadcast_client_message (priv->screen, event); - } } } @@ -1234,7 +1222,7 @@ choose_icon (GtkIconTheme *icon_theme, GtkIconThemePrivate *priv; GList *l; GtkIconInfo *icon_info = NULL; - UnthemedIcon *unthemed_icon; + UnthemedIcon *unthemed_icon = NULL; gboolean allow_svg; gboolean use_builtin; gint i; @@ -1270,6 +1258,32 @@ choose_icon (GtkIconTheme *icon_theme, if (unthemed_icon) break; } +#ifdef G_OS_WIN32 + /* Still not found an icon, check if reference to a Win32 resource */ + if (!unthemed_icon) + { + gchar **resources; + HICON hIcon = NULL; + + resources = g_strsplit (icon_names[0], ",", 0); + if (resources[0]) + { + wchar_t *wfile = g_utf8_to_utf16 (resources[0], -1, NULL, NULL, NULL); + ExtractIconExW (wfile, resources[1] ? atoi (resources[1]) : 0, &hIcon, NULL, 1); + g_free (wfile); + } + + if (hIcon) + { + icon_info = icon_info_new (); + icon_info->cache_pixbuf = gdk_win32_icon_to_pixbuf_libgtk_only (hIcon); + DestroyIcon (hIcon); + icon_info->dir_type = ICON_THEME_DIR_UNTHEMED; + icon_info->dir_size = size; + } + g_strfreev (resources); + } +#endif if (unthemed_icon) { @@ -1285,17 +1299,17 @@ choose_icon (GtkIconTheme *icon_theme, 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); -#ifdef G_OS_WIN32 - icon_info->cp_filename = g_locale_from_utf8 (icon_info->filename, - -1, NULL, NULL, NULL); -#endif icon_info->dir_type = ICON_THEME_DIR_UNTHEMED; + icon_info->dir_size = size; } out: - if (icon_info) - icon_info->desired_size = size; + if (icon_info) + { + icon_info->desired_size = size; + icon_info->forced_size = (flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0; + } else { static gboolean check_for_default_theme = TRUE; @@ -1316,6 +1330,7 @@ choose_icon (GtkIconTheme *icon_theme, found = g_file_test (default_theme_path, G_FILE_TEST_IS_REGULAR); g_free (default_theme_path); } + if (!found) { g_warning (_("Could not find the icon '%s'. The '%s' theme\n" @@ -1373,7 +1388,7 @@ gtk_icon_theme_lookup_icon (GtkIconTheme *icon_theme, gchar *p; dashes = 0; - for (p = icon_name; *p; p++) + for (p = (gchar *) icon_name; *p; p++) if (*p == '-') dashes++; @@ -1387,13 +1402,13 @@ gtk_icon_theme_lookup_icon (GtkIconTheme *icon_theme, } names[dashes + 1] = NULL; - info = choose_icon (icon_theme, names, size, flags); + info = choose_icon (icon_theme, (const gchar **) names, size, flags); g_strfreev (names); } else { - gchar *names[2]; + const gchar *names[2]; names[0] = icon_name; names[1] = NULL; @@ -1407,7 +1422,8 @@ gtk_icon_theme_lookup_icon (GtkIconTheme *icon_theme, /** * gtk_icon_theme_choose_icon: * @icon_theme: a #GtkIconTheme - * @icon_names: %NULL-terminated array of icon names to lookup + * @icon_names: (array zero-terminated=1): %NULL-terminated array of + * icon names to lookup * @size: desired icon size * @flags: flags modifying the behavior of the icon lookup * @@ -1453,27 +1469,28 @@ gtk_icon_theme_error_quark (void) * @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(). + * exactly this size; see gtk_icon_info_load_icon(). * @flags: flags modifying the behavior of the icon lookup - * @error: Location to store error information on failure, or %NULL. - * + * @error: (allow-none): Location to store error information on failure, + * or %NULL. + * * Looks up an icon in an icon theme, 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 + * 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 + * returned by this function. Otherwise GTK+ may need to keep the old * icon theme loaded, which would be a waste of memory. - * - * Return value: 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. + * + * 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: 2.4 **/ @@ -1493,8 +1510,8 @@ gtk_icon_theme_load_icon (GtkIconTheme *icon_theme, (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); + icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, size, + flags | GTK_ICON_LOOKUP_USE_BUILTIN); if (!icon_info) { g_set_error (error, GTK_ICON_THEME_ERROR, GTK_ICON_THEME_NOT_FOUND, @@ -1529,7 +1546,8 @@ gtk_icon_theme_has_icon (GtkIconTheme *icon_theme, GList *l; g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), FALSE); - + g_return_val_if_fail (icon_name != NULL, FALSE); + priv = icon_theme->priv; ensure_valid_themes (icon_theme); @@ -1581,9 +1599,9 @@ add_size (gpointer key, * that the icon is available in a scalable format. The array * is zero-terminated. * - * Return value: An newly allocated array describing the sizes at - * which the icon is available. The array should be freed with g_free() - * when it is no longer needed. + * Return value: (array zero-terminated=1): An newly allocated array + * describing the sizes at which the icon is available. The array + * should be freed with g_free() when it is no longer needed. * * Since: 2.6 **/ @@ -1612,6 +1630,9 @@ gtk_icon_theme_get_icon_sizes (GtkIconTheme *icon_theme, { IconThemeDir *dir = d->data; + if (dir->type != ICON_THEME_DIR_SCALABLE && g_hash_table_lookup_extended (sizes, GINT_TO_POINTER (dir->size), NULL, NULL)) + continue; + suffix = theme_dir_get_icon_suffix (dir, icon_name, NULL); if (suffix != ICON_SUFFIX_NONE) { @@ -1627,6 +1648,9 @@ gtk_icon_theme_get_icon_sizes (GtkIconTheme *icon_theme, { IconThemeDir *dir = d->data; + if (dir->type != ICON_THEME_DIR_SCALABLE && g_hash_table_lookup_extended (sizes, GINT_TO_POINTER (dir->size), NULL, NULL)) + continue; + suffix = theme_dir_get_icon_suffix (dir, icon_name, NULL); if (suffix != ICON_SUFFIX_NONE) { @@ -1681,19 +1705,19 @@ add_key_to_list (gpointer key, /** * gtk_icon_theme_list_icons: * @icon_theme: a #GtkIconTheme - * @context: a string identifying a particular type of icon, - * or %NULL to list all icons. + * @context: (allow-none): a string identifying a particular type of + * icon, or %NULL to list all icons. * * Lists the icons in the current icon theme. Only a subset * of the icons can be listed by providing a context string. * The set of values for the context string is system dependent, * but will typically include such values as "Applications" and * "MimeTypes". - * - * Return value: a #GList list holding the names of all the - * icons in the theme. You must first free each element - * in the list with g_free(), then free the list itself - * with g_list_free(). + * + * Return value: (element-type utf8) (transfer full): a #GList list + * holding the names of all the icons in the theme. You must first + * free each element in the list with g_free(), then free the list + * itself with g_list_free(). * * Since: 2.4 **/ @@ -1752,10 +1776,10 @@ gtk_icon_theme_list_icons (GtkIconTheme *icon_theme, * Gets the list of contexts available within the current * hierarchy of icon themes * - * Return value: a #GList list holding the names of all the - * contexts in the theme. You must first free each element - * in the list with g_free(), then free the list itself - * with g_list_free(). + * Return value: (element-type utf8) (transfer full): a #GList list + * holding the names of all the contexts in the theme. You must first + * free each element in the list with g_free(), then free the list + * itself with g_list_free(). * * Since: 2.12 **/ @@ -2019,7 +2043,7 @@ theme_dir_get_icon_suffix (IconThemeDir *dir, { suffix = (IconSuffix)_gtk_icon_cache_get_icon_flags (dir->cache, icon_name, - dir->subdir); + dir->subdir_index); if (has_icon_file) *has_icon_file = suffix & HAS_ICON_FILE; @@ -2058,7 +2082,7 @@ theme_lookup_icon (IconTheme *theme, /* Builtin icons are logically part of the default theme and * are searched before other subdirectories of the default theme. */ - if (strcmp (theme->name, DEFAULT_THEME_NAME) == 0 && use_builtin) + if (use_builtin && strcmp (theme->name, DEFAULT_THEME_NAME) == 0) { closest_builtin = find_builtin_icon (icon_name, size, @@ -2078,7 +2102,7 @@ theme_lookup_icon (IconTheme *theme, { dir = l->data; - GTK_NOTE (ICONTHEME, + GTK_NOTE (ICONTHEME, g_print ("theme_lookup_icon dir %s\n", dir->dir)); suffix = theme_dir_get_icon_suffix (dir, icon_name, NULL); if (best_suffix (suffix, allow_svg) != ICON_SUFFIX_NONE) @@ -2160,17 +2184,10 @@ theme_lookup_icon (IconTheme *theme, file = g_strconcat (icon_name, string_from_suffix (suffix), NULL); icon_info->filename = g_build_filename (min_dir->dir, file, NULL); g_free (file); -#ifdef G_OS_WIN32 - icon_info->cp_filename = g_locale_from_utf8 (icon_info->filename, - -1, NULL, NULL, NULL); -#endif } else { icon_info->filename = NULL; -#ifdef G_OS_WIN32 - icon_info->cp_filename = NULL; -#endif } if (min_dir->icon_data != NULL) @@ -2178,7 +2195,7 @@ theme_lookup_icon (IconTheme *theme, if (icon_info->data == NULL && min_dir->cache != NULL) { - icon_info->data = _gtk_icon_cache_get_icon_data (min_dir->cache, icon_name, min_dir->subdir); + icon_info->data = _gtk_icon_cache_get_icon_data (min_dir->cache, icon_name, min_dir->subdir_index); if (icon_info->data) { if (min_dir->icon_data == NULL) @@ -2212,7 +2229,7 @@ theme_lookup_icon (IconTheme *theme, if (min_dir->cache) { icon_info->cache_pixbuf = _gtk_icon_cache_get_icon (min_dir->cache, icon_name, - min_dir->subdir); + min_dir->subdir_index); } icon_info->dir_type = min_dir->type; @@ -2274,7 +2291,7 @@ theme_list_contexts (IconTheme *theme, dir = l->data; context = g_quark_to_string (dir->context); - g_hash_table_replace (contexts, context, NULL); + g_hash_table_replace (contexts, (gpointer) context, NULL); l = l->next; } @@ -2520,10 +2537,14 @@ theme_subdir_load (GtkIconTheme *icon_theme, dir->icon_data = NULL; dir->subdir = g_strdup (subdir); if (dir_mtime->cache != NULL) - dir->cache = _gtk_icon_cache_ref (dir_mtime->cache); + { + dir->cache = _gtk_icon_cache_ref (dir_mtime->cache); + dir->subdir_index = _gtk_icon_cache_get_directory_index (dir->cache, dir->subdir); + } else { dir->cache = NULL; + dir->subdir_index = -1; scan_directory (icon_theme->priv, dir, full_dir); } @@ -2545,19 +2566,10 @@ icon_data_free (GtkIconData *icon_data) /* * GtkIconInfo */ -GType -gtk_icon_info_get_type (void) -{ - static GType our_type = 0; - - if (our_type == 0) - our_type = g_boxed_type_register_static (I_("GtkIconInfo"), - (GBoxedCopyFunc) gtk_icon_info_copy, - (GBoxedFreeFunc) gtk_icon_info_free); - - return our_type; -} +G_DEFINE_BOXED_TYPE (GtkIconInfo, gtk_icon_info, + gtk_icon_info_copy, + gtk_icon_info_free) static GtkIconInfo * icon_info_new (void) @@ -2565,6 +2577,7 @@ icon_info_new (void) GtkIconInfo *icon_info = g_slice_new0 (GtkIconInfo); icon_info->scale = -1.; + icon_info->ref_count = 1; return icon_info; } @@ -2578,7 +2591,7 @@ icon_info_new_builtin (BuiltinIcon *icon) icon_info->dir_type = ICON_THEME_DIR_THRESHOLD; icon_info->dir_size = icon->size; icon_info->threshold = 2; - + return icon_info; } @@ -2595,25 +2608,12 @@ icon_info_new_builtin (BuiltinIcon *icon) GtkIconInfo * gtk_icon_info_copy (GtkIconInfo *icon_info) { - GtkIconInfo *copy; g_return_val_if_fail (icon_info != NULL, NULL); - copy = memcpy (g_slice_new (GtkIconInfo), icon_info, sizeof (GtkIconInfo)); - if (copy->cache_pixbuf) - g_object_ref (copy->cache_pixbuf); - if (copy->pixbuf) - g_object_ref (copy->pixbuf); - if (copy->load_error) - copy->load_error = g_error_copy (copy->load_error); - if (copy->filename) - copy->filename = g_strdup (copy->filename); -#ifdef G_OS_WIN32 - if (copy->cp_filename) - copy->cp_filename = g_strdup (copy->cp_filename); -#endif + icon_info->ref_count++; - return copy; + return icon_info; } /** @@ -2629,10 +2629,15 @@ gtk_icon_info_free (GtkIconInfo *icon_info) { g_return_if_fail (icon_info != NULL); + icon_info->ref_count--; + if (icon_info->ref_count > 0) + return; + g_free (icon_info->filename); -#ifdef G_OS_WIN32 - g_free (icon_info->cp_filename); -#endif + if (icon_info->loadable) + g_object_unref (icon_info->loadable); + g_slist_foreach (icon_info->emblem_infos, (GFunc)gtk_icon_info_free, NULL); + g_slist_free (icon_info->emblem_infos); if (icon_info->pixbuf) g_object_unref (icon_info->pixbuf); if (icon_info->cache_pixbuf) @@ -2677,10 +2682,9 @@ gtk_icon_info_get_base_size (GtkIconInfo *icon_info) * no filename if a builtin icon is returned; in this * case, you should use gtk_icon_info_get_builtin_pixbuf(). * - * Return value: the filename for the icon, or %NULL - * if gtk_icon_info_get_builtin_pixbuf() should - * be used instead. The return value is owned by - * GTK+ and should not be modified or freed. + * Return value: (type filename): the filename for the icon, or %NULL + * if gtk_icon_info_get_builtin_pixbuf() should be used instead. The + * return value is owned by GTK+ and should not be modified or freed. * * Since: 2.4 **/ @@ -2700,8 +2704,8 @@ gtk_icon_info_get_filename (GtkIconInfo *icon_info) * GTK+ to use built in icon images, you must pass the * %GTK_ICON_LOOKUP_USE_BUILTIN to * gtk_icon_theme_lookup_icon(). - * - * Return value: the built-in image pixbuf, or %NULL. No + * + * Return value: (transfer none): the built-in image pixbuf, or %NULL. No * extra reference is added to the returned pixbuf, so if * you want to keep it around, you must use g_object_ref(). * The returned image must not be modified. @@ -2719,55 +2723,102 @@ gtk_icon_info_get_builtin_pixbuf (GtkIconInfo *icon_info) return icon_info->cache_pixbuf; } -static GdkPixbuf * -load_svg_at_size (const gchar *filename, - gint size, - GError **error) +static gboolean icon_info_ensure_scale_and_pixbuf (GtkIconInfo*, gboolean); + +/* Combine the icon with all emblems, the first emblem is placed + * in the southeast corner. Scale emblems to be at most 3/4 of the + * size of the icon itself. + */ +static void +apply_emblems (GtkIconInfo *info) { - GdkPixbuf *pixbuf = NULL; - GdkPixbufLoader *loader = NULL; - gchar *contents = NULL; - gsize length; - - if (!g_file_get_contents (filename, - &contents, &length, error)) - goto bail; - - loader = gdk_pixbuf_loader_new_with_type ("svg", error); - if (loader == NULL) - goto bail; + GdkPixbuf *icon = NULL; + gint w, h, pos; + GSList *l; - gdk_pixbuf_loader_set_size (loader, size, size); - - if (!gdk_pixbuf_loader_write (loader, contents, length, error)) + if (info->emblem_infos == NULL) + return; + + if (info->emblems_applied) + return; + + w = gdk_pixbuf_get_width (info->pixbuf); + h = gdk_pixbuf_get_height (info->pixbuf); + + for (l = info->emblem_infos, pos = 0; l; l = l->next, pos++) { - gdk_pixbuf_loader_close (loader, NULL); - goto bail; + GtkIconInfo *emblem_info = l->data; + + if (icon_info_ensure_scale_and_pixbuf (emblem_info, FALSE)) + { + GdkPixbuf *emblem = emblem_info->pixbuf; + gint ew, eh; + gint x = 0, y = 0; /* silence compiler */ + gdouble scale; + + ew = gdk_pixbuf_get_width (emblem); + eh = gdk_pixbuf_get_height (emblem); + if (ew >= w) + { + scale = 0.75; + ew = ew * 0.75; + eh = eh * 0.75; + } + else + scale = 1.0; + + switch (pos % 4) + { + case 0: + x = w - ew; + y = h - eh; + break; + case 1: + x = w - ew; + y = 0; + break; + case 2: + x = 0; + y = h - eh; + break; + case 3: + x = 0; + y = 0; + break; + } + + if (icon == NULL) + { + icon = gdk_pixbuf_copy (info->pixbuf); + if (icon == NULL) + break; + } + + gdk_pixbuf_composite (emblem, icon, x, y, ew, eh, x, y, + scale, scale, GDK_INTERP_BILINEAR, 255); + } + } + + if (icon) + { + g_object_unref (info->pixbuf); + info->pixbuf = icon; } - - if (!gdk_pixbuf_loader_close (loader, error)) - goto bail; - - pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader)); - - bail: - if (loader) - g_object_unref (loader); - g_free (contents); - - return pixbuf; + + info->emblems_applied = TRUE; } -/* This function contains the complicatd logic for deciding +/* This function contains the complicated logic for deciding * on the size at which to load the icon and loading it at * that size. */ static gboolean -icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, - gboolean scale_only) +icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, + gboolean scale_only) { int image_width, image_height; GdkPixbuf *source_pixbuf; + gboolean is_svg; /* First check if we already succeeded have the necessary * information (or failed earlier) @@ -2776,7 +2827,10 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, return TRUE; if (icon_info->pixbuf) - return TRUE; + { + apply_emblems (icon_info); + return TRUE; + } if (icon_info->load_error) return FALSE; @@ -2784,18 +2838,68 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, /* SVG icons are a special case - we just immediately scale them * to the desired size */ - if (icon_info->filename && g_str_has_suffix (icon_info->filename, ".svg")) + if (icon_info->filename && !icon_info->loadable) + { + GFile *file; + + file = g_file_new_for_path (icon_info->filename); + icon_info->loadable = G_LOADABLE_ICON (g_file_icon_new (file)); + g_object_unref (file); + } + + is_svg = FALSE; + if (G_IS_FILE_ICON (icon_info->loadable)) + { + GFile *file; + GFileInfo *file_info; + const gchar *content_type; + + file = g_file_icon_get_file (G_FILE_ICON (icon_info->loadable)); + file_info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + G_FILE_QUERY_INFO_NONE, + NULL, NULL); + if (file_info) + { + content_type = g_file_info_get_content_type (file_info); + + if (content_type && strcmp (content_type, "image/svg+xml") == 0) + is_svg = TRUE; + + g_object_unref (file_info); + } + } + + if (is_svg) { + GInputStream *stream; + icon_info->scale = icon_info->desired_size / 1000.; if (scale_only) return TRUE; - icon_info->pixbuf = load_svg_at_size (icon_info->filename, - icon_info->desired_size, - &icon_info->load_error); + stream = g_loadable_icon_load (icon_info->loadable, + icon_info->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, + TRUE, + NULL, + &icon_info->load_error); + g_object_unref (stream); + } - return icon_info->pixbuf != NULL; + if (!icon_info->pixbuf) + return FALSE; + + apply_emblems (icon_info); + + return TRUE; } /* In many cases, the scale can be determined without actual access @@ -2803,7 +2907,9 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, * for the directory where the icon is; the image size doesn't * matter in that case. */ - if (icon_info->dir_type == ICON_THEME_DIR_FIXED) + if (icon_info->forced_size) + icon_info->scale = -1; + else if (icon_info->dir_type == ICON_THEME_DIR_FIXED) icon_info->scale = 1.0; else if (icon_info->dir_type == ICON_THEME_DIR_THRESHOLD) { @@ -2825,17 +2931,29 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, /* At this point, we need to actually get the icon; either from the * builtin image or by loading the file */ + source_pixbuf = NULL; if (icon_info->cache_pixbuf) source_pixbuf = g_object_ref (icon_info->cache_pixbuf); else { + GInputStream *stream; - source_pixbuf = gdk_pixbuf_new_from_file (icon_info->filename, - &icon_info->load_error); - if (!source_pixbuf) - return FALSE; + stream = g_loadable_icon_load (icon_info->loadable, + icon_info->desired_size, + NULL, NULL, + &icon_info->load_error); + if (stream) + { + source_pixbuf = gdk_pixbuf_new_from_stream (stream, + NULL, + &icon_info->load_error); + g_object_unref (stream); + } } + if (!source_pixbuf) + return FALSE; + /* Do scale calculations that depend on the image size */ image_width = gdk_pixbuf_get_width (source_pixbuf); @@ -2845,11 +2963,12 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, { gint image_size = MAX (image_width, image_height); if (image_size > 0) - icon_info->scale = icon_info->desired_size / (gdouble)image_size; + icon_info->scale = (gdouble)icon_info->desired_size / (gdouble)image_size; else icon_info->scale = 1.0; - if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED) + if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED && + !icon_info->forced_size) icon_info->scale = MIN (icon_info->scale, 1.0); } @@ -2860,7 +2979,6 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, * extra complexity, we could keep the source pixbuf around * but not actually scale it until needed. */ - if (icon_info->scale == 1.0) icon_info->pixbuf = source_pixbuf; else @@ -2872,14 +2990,17 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, g_object_unref (source_pixbuf); } + apply_emblems (icon_info); + return TRUE; } /** * gtk_icon_info_load_icon: * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon() - * @error: location to store error information on failure, or %NULL. - * + * @error: (allow-none): location to store error information on failure, + * or %NULL. + * * Renders an icon previously looked up in an icon theme using * gtk_icon_theme_lookup_icon(); the size will be based on the size * passed to gtk_icon_theme_lookup_icon(). Note that the resulting @@ -2887,12 +3008,15 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, * that differ slightly from their nominal sizes, and in addition GTK+ * will avoid scaling icons that it considers sufficiently close to the * requested size or for which the source image would have to be scaled - * up too far. (This maintains sharpness.) - * - * Return value: 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. + * up too far. (This maintains sharpness.). This behaviour can be changed + * by passing the %GTK_ICON_LOOKUP_FORCE_SIZE flag when obtaining + * the #GtkIconInfo. If this flag has been specified, the pixbuf + * returned by this function will be scaled to the exact size. + * + * 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. * * Since: 2.4 **/ @@ -2900,8 +3024,6 @@ GdkPixbuf * gtk_icon_info_load_icon (GtkIconInfo *icon_info, GError **error) { - g_return_val_if_fail (icon_info != NULL, NULL); - g_return_val_if_fail (icon_info != NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); @@ -2910,17 +3032,360 @@ gtk_icon_info_load_icon (GtkIconInfo *icon_info, if (icon_info->load_error) g_propagate_error (error, icon_info->load_error); else - g_set_error (error, - GTK_ICON_THEME_ERROR, - GTK_ICON_THEME_NOT_FOUND, - _("Failed to load icon")); + g_set_error_literal (error, + GTK_ICON_THEME_ERROR, + GTK_ICON_THEME_NOT_FOUND, + _("Failed to load icon")); - return NULL; + return NULL; } return g_object_ref (icon_info->pixbuf); } +static gchar * +gdk_color_to_css (GdkColor *color) +{ + return g_strdup_printf ("rgb(%d,%d,%d)", + color->red >> 8, + color->green >> 8, + color->blue >> 8); +} + +static gchar * +gdk_rgba_to_css (const GdkRGBA *color) +{ + /* drop alpha for now, since librsvg does not understand rgba() */ + return g_strdup_printf ("rgb(%d,%d,%d)", + (gint)(color->red * 255), + (gint)(color->green * 255), + (gint)(color->blue * 255)); +} + +static GdkPixbuf * +_gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info, + const gchar *css_fg, + const gchar *css_success, + const gchar *css_warning, + const gchar *css_error, + GError **error) +{ + GInputStream *stream; + GdkPixbuf *pixbuf; + gchar *data; + gchar *success, *warning, *err; + + /* css_fg can't possibly have failed, otherwise + * that would mean we have a broken style */ + g_return_val_if_fail (css_fg != NULL, NULL); + + success = warning = err = NULL; + + if (!css_success) + { + GdkColor success_default_color = { 0, 0x4e00, 0x9a00, 0x0600 }; + success = gdk_color_to_css (&success_default_color); + } + if (!css_warning) + { + GdkColor warning_default_color = { 0, 0xf500, 0x7900, 0x3e00 }; + warning = gdk_color_to_css (&warning_default_color); + } + if (!css_error) + { + GdkColor error_default_color = { 0, 0xcc00, 0x0000, 0x0000 }; + err = gdk_color_to_css (&error_default_color); + } + + + data = g_strconcat ("\n" + "\n" + " \n" + " filename, "\"/>\n" + "", + NULL); + g_free (warning); + g_free (err); + g_free (success); + + 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, + TRUE, + NULL, + error); + g_object_unref (stream); + + return pixbuf; +} + +/** + * gtk_icon_info_load_symbolic: + * @icon_info: a #GtkIconInfo + * @fg: a #GdkRGBA representing the foreground color of the icon + * @success_color: (allow-none): a #GdkRGBA representing the warning color + * of the icon or %NULL to use the default color + * @warning_color: (allow-none): a #GdkRGBA representing the warning color + * of the icon or %NULL to use the default color + * @error_color: (allow-none): a #GdkRGBA representing the error color + * of the icon or %NULL to use the default color (allow-none) + * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the + * loaded icon was a symbolic one and whether the @fg color was + * applied to it. + * @error: (allow-none): location to store error information on failure, + * or %NULL. + * + * Loads an icon, modifying it to match the system colours for the foreground, + * success, warning and error colors provided. If the icon is not a symbolic + * one, the function will return the result from gtk_icon_info_load_icon(). + * + * This allows loading symbolic icons that will match the system theme. + * + * Unless you are implementing a widget, you will want to use + * g_themed_icon_new_with_default_fallbacks() to load the icon. + * + * As implementation details, the icon loaded needs to be of SVG type, + * contain the "symbolic" term as the last component of the icon name, + * and use the 'fg', 'success', 'warning' and 'error' CSS styles in the + * SVG file itself. + * + * See the Symbolic Icons spec + * for more information about symbolic icons. + * + * Return value: (transfer full): a #GdkPixbuf representing the loaded icon + * + * Since: 3.0 + **/ +GdkPixbuf * +gtk_icon_info_load_symbolic (GtkIconInfo *icon_info, + const GdkRGBA *fg, + const GdkRGBA *success_color, + const GdkRGBA *warning_color, + const GdkRGBA *error_color, + gboolean *was_symbolic, + GError **error) +{ + GdkPixbuf *pixbuf; + gchar *css_fg; + gchar *css_success; + gchar *css_warning; + gchar *css_error; + + g_return_val_if_fail (fg != NULL, NULL); + + if (!icon_info->filename || + !g_str_has_suffix (icon_info->filename, "-symbolic.svg")) + { + if (was_symbolic) + *was_symbolic = FALSE; + return gtk_icon_info_load_icon (icon_info, error); + } + + if (was_symbolic) + *was_symbolic = TRUE; + + css_fg = gdk_rgba_to_css (fg); + + css_success = css_warning = css_error = NULL; + + if (warning_color) + css_warning = gdk_rgba_to_css (warning_color); + + if (error_color) + css_error = gdk_rgba_to_css (error_color); + + if (success_color) + css_success = gdk_rgba_to_css (success_color); + + pixbuf = _gtk_icon_info_load_symbolic_internal (icon_info, + css_fg, css_success, + css_warning, css_error, + error); + g_free (css_fg); + g_free (css_warning); + g_free (css_success); + g_free (css_error); + + return pixbuf; +} + +/** + * gtk_icon_info_load_symbolic_for_context: + * @icon_info: a #GtkIconInfo + * @context: a #GtkStyleContext + * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the + * loaded icon was a symbolic one and whether the @fg color was + * applied to it. + * @error: (allow-none): location to store error information on failure, + * or %NULL. + * + * Loads an icon, modifying it to match the system colors for the foreground, + * success, warning and error colors provided. If the icon is not a symbolic + * one, the function will return the result from gtk_icon_info_load_icon(). + * This function uses the regular foreground color and the symbolic colors + * with the names "success_color", "warning_color" and "error_color" from + * the context. + * + * This allows loading symbolic icons that will match the system theme. + * + * See gtk_icon_info_load_symbolic() for more details. + * + * Return value: (transfer full): a #GdkPixbuf representing the loaded icon + * + * Since: 3.0 + **/ +GdkPixbuf * +gtk_icon_info_load_symbolic_for_context (GtkIconInfo *icon_info, + GtkStyleContext *context, + gboolean *was_symbolic, + GError **error) +{ + GdkPixbuf *pixbuf; + GdkRGBA *color = NULL; + GdkRGBA rgba; + gchar *css_fg = NULL, *css_success; + gchar *css_warning, *css_error; + GtkStateFlags state; + + if (!icon_info->filename || + !g_str_has_suffix (icon_info->filename, "-symbolic.svg")) + { + if (was_symbolic) + *was_symbolic = FALSE; + return gtk_icon_info_load_icon (icon_info, error); + } + + if (was_symbolic) + *was_symbolic = TRUE; + + state = gtk_style_context_get_state (context); + gtk_style_context_get (context, state, "color", &color, NULL); + if (color) + { + css_fg = gdk_rgba_to_css (color); + gdk_rgba_free (color); + } + + css_success = css_warning = css_error = NULL; + + if (gtk_style_context_lookup_color (context, "success_color", &rgba)) + css_success = gdk_rgba_to_css (&rgba); + + if (gtk_style_context_lookup_color (context, "warning_color", &rgba)) + css_warning = gdk_rgba_to_css (&rgba); + + if (gtk_style_context_lookup_color (context, "error_color", &rgba)) + css_error = gdk_rgba_to_css (&rgba); + + pixbuf = _gtk_icon_info_load_symbolic_internal (icon_info, + css_fg, css_success, + css_warning, css_error, + error); + + g_free (css_fg); + g_free (css_success); + g_free (css_warning); + g_free (css_error); + + return pixbuf; +} + +/** + * gtk_icon_info_load_symbolic_for_style: + * @icon_info: a #GtkIconInfo + * @style: a #GtkStyle to take the colors from + * @state: the widget state to use for colors + * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the + * loaded icon was a symbolic one and whether the @fg color was + * applied to it. + * @error: (allow-none): location to store error information on failure, + * or %NULL. + * + * Loads an icon, modifying it to match the system colours for the foreground, + * success, warning and error colors provided. If the icon is not a symbolic + * one, the function will return the result from gtk_icon_info_load_icon(). + * + * This allows loading symbolic icons that will match the system theme. + * + * See gtk_icon_info_load_symbolic() for more details. + * + * Return value: (transfer full): a #GdkPixbuf representing the loaded icon + * + * Since: 3.0 + * + * Deprecated: 3.0: Use gtk_icon_info_load_symbolic_for_context() instead + **/ +GdkPixbuf * +gtk_icon_info_load_symbolic_for_style (GtkIconInfo *icon_info, + GtkStyle *style, + GtkStateType state, + gboolean *was_symbolic, + GError **error) +{ + GdkPixbuf *pixbuf; + GdkColor success_color; + GdkColor warning_color; + GdkColor error_color; + GdkColor *fg; + gchar *css_fg, *css_success; + gchar *css_warning, *css_error; + + if (!icon_info->filename || + !g_str_has_suffix (icon_info->filename, "-symbolic.svg")) + { + if (was_symbolic) + *was_symbolic = FALSE; + return gtk_icon_info_load_icon (icon_info, error); + } + + if (was_symbolic) + *was_symbolic = TRUE; + + fg = &style->fg[state]; + css_fg = gdk_color_to_css (fg); + + css_success = css_warning = css_error = NULL; + + if (gtk_style_lookup_color (style, "success_color", &success_color)) + css_success = gdk_color_to_css (&success_color); + + if (gtk_style_lookup_color (style, "warning_color", &warning_color)) + css_warning = gdk_color_to_css (&warning_color); + + if (gtk_style_lookup_color (style, "error_color", &error_color)) + css_error = gdk_color_to_css (&error_color); + + pixbuf = _gtk_icon_info_load_symbolic_internal (icon_info, + css_fg, css_success, + css_warning, css_error, + error); + + g_free (css_fg); + g_free (css_success); + g_free (css_warning); + g_free (css_error); + + return pixbuf; +} + /** * gtk_icon_info_set_raw_coordinates: * @icon_info: a #GtkIconInfo @@ -2984,7 +3449,7 @@ icon_info_scale_point (GtkIconInfo *icon_info, /** * gtk_icon_info_get_embedded_rect: * @icon_info: a #GtkIconInfo - * @rectangle: #GdkRectangle in which to store embedded + * @rectangle: (out): #GdkRectangle in which to store embedded * rectangle coordinates; coordinates are only stored * when this function returns %TRUE. * @@ -3034,9 +3499,9 @@ gtk_icon_info_get_embedded_rect (GtkIconInfo *icon_info, /** * gtk_icon_info_get_attach_points: * @icon_info: a #GtkIconInfo - * @points: location to store pointer to an array of points, or %NULL + * @points: (allow-none) (array length=n_points) (out): location to store pointer to an array of points, or %NULL * free the array of points with g_free(). - * @n_points: location to store the number of points in @points, or %NULL + * @n_points: (allow-none): location to store the number of points in @points, or %NULL * * Fetches the set of attach points for an icon. An attach point * is a location in the icon that can be used as anchor points for attaching @@ -3267,96 +3732,145 @@ _gtk_icon_theme_check_reload (GdkDisplay *display) } } -#ifdef G_OS_WIN32 - -/* DLL ABI stability backward compatibility versions */ - -#undef gtk_icon_theme_set_search_path -void -gtk_icon_theme_set_search_path (GtkIconTheme *icon_theme, - const gchar *path[], - gint n_elements) +/** + * gtk_icon_theme_lookup_by_gicon: + * @icon_theme: a #GtkIconTheme + * @icon: the #GIcon to look up + * @size: desired icon size + * @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(). + * + * Return value: a #GtkIconInfo structure containing + * information about the icon, or %NULL if the icon + * wasn't found. Free with gtk_icon_info_free() + * + * Since: 2.14 + */ +GtkIconInfo * +gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme, + GIcon *icon, + gint size, + GtkIconLookupFlags flags) { - const gchar **utf8_path; - gint i; - - utf8_path = g_new (const gchar *, n_elements); + GtkIconInfo *info; - for (i = 0; i < n_elements; i++) - utf8_path[i] = g_locale_to_utf8 (path[i], -1, NULL, NULL, NULL); + g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL); + g_return_val_if_fail (G_IS_ICON (icon), NULL); - gtk_icon_theme_set_search_path_utf8 (icon_theme, utf8_path, n_elements); + if (G_IS_LOADABLE_ICON (icon)) + { + info = icon_info_new (); + info->loadable = G_LOADABLE_ICON (g_object_ref (icon)); - for (i = 0; i < n_elements; i++) - g_free ((gchar *) utf8_path[i]); + info->dir_type = ICON_THEME_DIR_UNTHEMED; + info->dir_size = size; + info->desired_size = size; + info->threshold = 2; + info->forced_size = (flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0; - g_free (utf8_path); -} - -#undef gtk_icon_theme_get_search_path + return info; + } + else if (G_IS_THEMED_ICON (icon)) + { + const gchar **names; -void -gtk_icon_theme_get_search_path (GtkIconTheme *icon_theme, - gchar **path[], - gint *n_elements) -{ - gint i, n; + names = (const gchar **)g_themed_icon_get_names (G_THEMED_ICON (icon)); + info = gtk_icon_theme_choose_icon (icon_theme, names, size, flags); - gtk_icon_theme_get_search_path_utf8 (icon_theme, path, &n); + return info; + } + else if (G_IS_EMBLEMED_ICON (icon)) + { + GIcon *base, *emblem; + GList *list, *l; + GtkIconInfo *emblem_info; - if (n_elements) - *n_elements = n; + if (GTK_IS_NUMERABLE_ICON (icon)) + _gtk_numerable_icon_set_background_icon_size (GTK_NUMERABLE_ICON (icon), size / 2); - if (path) - { - for (i = 0; i < n; i++) - { - gchar *tem = (*path)[i]; + base = g_emblemed_icon_get_icon (G_EMBLEMED_ICON (icon)); + info = gtk_icon_theme_lookup_by_gicon (icon_theme, base, size, flags); + if (info) + { + list = g_emblemed_icon_get_emblems (G_EMBLEMED_ICON (icon)); + for (l = list; l; l = l->next) + { + 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); + if (emblem_info) + info->emblem_infos = g_slist_prepend (info->emblem_infos, emblem_info); + } + } - (*path)[i] = g_locale_from_utf8 ((*path)[i], -1, NULL, NULL, NULL); - g_free (tem); - } + return info; } -} + else if (GDK_IS_PIXBUF (icon)) + { + GdkPixbuf *pixbuf; -#undef gtk_icon_theme_append_search_path + pixbuf = GDK_PIXBUF (icon); -void -gtk_icon_theme_append_search_path (GtkIconTheme *icon_theme, - const gchar *path) -{ - gchar *utf8_path = g_locale_from_utf8 (path, -1, NULL, NULL, NULL); + if ((flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0) + { + gint width, height, max; + gdouble scale; + GdkPixbuf *scaled; - gtk_icon_theme_append_search_path_utf8 (icon_theme, utf8_path); + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + max = MAX (width, height); + scale = (gdouble) size / (gdouble) max; - g_free (utf8_path); -} + scaled = gdk_pixbuf_scale_simple (pixbuf, + 0.5 + width * scale, + 0.5 + height * scale, + GDK_INTERP_BILINEAR); -#undef gtk_icon_theme_prepend_search_path + info = gtk_icon_info_new_for_pixbuf (icon_theme, scaled); -void -gtk_icon_theme_prepend_search_path (GtkIconTheme *icon_theme, - const gchar *path) -{ - gchar *utf8_path = g_locale_from_utf8 (path, -1, NULL, NULL, NULL); + g_object_unref (scaled); + } + else + { + info = gtk_icon_info_new_for_pixbuf (icon_theme, pixbuf); + } - gtk_icon_theme_prepend_search_path_utf8 (icon_theme, utf8_path); + return info; + } - g_free (utf8_path); + return NULL; } -#undef gtk_icon_info_get_filename - -G_CONST_RETURN gchar * -gtk_icon_info_get_filename (GtkIconInfo *icon_info) +/** + * gtk_icon_info_new_for_pixbuf: + * @icon_theme: a #GtkIconTheme + * @pixbuf: the pixbuf to wrap in a #GtkIconInfo + * + * Creates a #GtkIconInfo for a #GdkPixbuf. + * + * Returns: a #GtkIconInfo + * + * Since: 2.14 + */ +GtkIconInfo * +gtk_icon_info_new_for_pixbuf (GtkIconTheme *icon_theme, + GdkPixbuf *pixbuf) { - g_return_val_if_fail (icon_info != NULL, NULL); + GtkIconInfo *info; - return icon_info->cp_filename; -} + g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL); + g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); -#endif + info = icon_info_new (); + info->pixbuf = g_object_ref (pixbuf); + info->scale = 1.0; + info->dir_type = ICON_THEME_DIR_UNTHEMED; -#define __GTK_ICON_THEME_C__ -#include "gtkaliasdef.c" + return info; +}