I have committed the stream i/o api in gdk-pixbuf now, after adding GCancellable arguments and removing the closing of the streams, since that seemed pretty uncontroversial.
Here are new versions of the resurrect-pixbuf and iconinfo patches. I have added a iconinfo-from-pixbuf function. Caching is still not implemented, I'd like to do that separately. Does the iconinfo patch look ready to commit ?
Index: gdk-pixbuf/gdk-pixbuf.c =================================================================== --- gdk-pixbuf/gdk-pixbuf.c (revision 19372) +++ gdk-pixbuf/gdk-pixbuf.c (working copy) @@ -36,6 +36,7 @@ #include "gdk-pixbuf-alias.h" static void gdk_pixbuf_finalize (GObject *object); +static void gdk_pixbuf_dispose (GObject *object); static void gdk_pixbuf_set_property (GObject *object, guint prop_id, const GValue *value, @@ -59,6 +60,13 @@ PROP_PIXELS }; +enum { + RESURRECT, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + G_DEFINE_TYPE (GdkPixbuf, gdk_pixbuf, G_TYPE_OBJECT) static void @@ -71,10 +79,31 @@ { GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->dispose = gdk_pixbuf_dispose; object_class->finalize = gdk_pixbuf_finalize; object_class->set_property = gdk_pixbuf_set_property; object_class->get_property = gdk_pixbuf_get_property; + /** + * GdkPixbuf::resurrect: + * @pixbuf: the object on which the signal was emitted + * + * The ::resurrect signal gets emitted when the pixbuf is + * about to be disposed. A signal handler can call g_object_ref() + * on @pixbuf to keep it alive for caching purposes. + * + * Since: 2.16 + */ + signals[RESURRECT] = + g_signal_new (I_("resurrect"), + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + #define PIXBUF_PARAM_FLAGS G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|\ G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB /** @@ -183,6 +212,18 @@ } +static void +gdk_pixbuf_dispose (GObject *object) +{ + guint ref_count; + + ref_count = G_OBJECT (object)->ref_count; + + g_signal_emit (object, signals[RESURRECT], 0); + + G_OBJECT_CLASS (gdk_pixbuf_parent_class)->dispose (object); +} + /** * gdk_pixbuf_ref: * @pixbuf: A pixbuf.
Index: gtk/gtkicontheme.c =================================================================== --- gtk/gtkicontheme.c (revision 19372) +++ gtk/gtkicontheme.c (working copy) @@ -113,6 +113,8 @@ */ gchar *cp_filename; #endif + GLoadableIcon *loadable; + /* Cache pixbuf (if there is any) */ GdkPixbuf *cache_pixbuf; @@ -128,7 +130,8 @@ /* 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 +139,8 @@ GdkPixbuf *pixbuf; GError *load_error; gdouble scale; + + guint ref_count; }; typedef struct @@ -1293,11 +1298,15 @@ #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; @@ -2577,6 +2586,7 @@ GtkIconInfo *icon_info = g_slice_new0 (GtkIconInfo); icon_info->scale = -1.; + icon_info->ref_count = 1; return icon_info; } @@ -2590,7 +2600,7 @@ icon_info->dir_type = ICON_THEME_DIR_THRESHOLD; icon_info->dir_size = icon->size; icon_info->threshold = 2; - + return icon_info; } @@ -2607,26 +2617,12 @@ GtkIconInfo * gtk_icon_info_copy (GtkIconInfo *icon_info) { - GtkIconInfo *copy; g_return_val_if_fail (icon_info != NULL, NULL); - copy = g_slice_dup (GtkIconInfo, icon_info); + icon_info->ref_count++; - 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 - - return copy; + return icon_info; } /** @@ -2642,10 +2638,16 @@ { 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); if (icon_info->pixbuf) g_object_unref (icon_info->pixbuf); if (icon_info->cache_pixbuf) @@ -2732,55 +2734,17 @@ return icon_info->cache_pixbuf; } -static GdkPixbuf * -load_svg_at_size (const gchar *filename, - gint size, - GError **error) -{ - 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; - - gdk_pixbuf_loader_set_size (loader, size, size); - - if (!gdk_pixbuf_loader_write (loader, contents, length, error)) - { - gdk_pixbuf_loader_close (loader, NULL); - goto bail; - } - - 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; -} - -/* 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) @@ -2797,16 +2761,61 @@ /* 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; } @@ -2816,7 +2825,9 @@ * 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) { @@ -2838,17 +2849,29 @@ /* 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); @@ -2858,11 +2881,12 @@ { 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); } @@ -2873,7 +2897,6 @@ * 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 @@ -2900,7 +2923,10 @@ * 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.) + * 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: the rendered icon; this may be a newly created icon * or a new reference to an internal icon, so you must not modify @@ -3278,6 +3304,89 @@ } } +/** + * 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() or gtk_icon_info_load_at_size(). + * + * 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.16 + */ +GtkIconInfo * +gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme, + GIcon *icon, + gint size, + GtkIconLookupFlags flags) +{ + GtkIconInfo *info; + + g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL); + g_return_val_if_fail (G_IS_ICON (icon), NULL); + + if (G_IS_LOADABLE_ICON (icon)) + { + info = icon_info_new (); + info->loadable = G_LOADABLE_ICON (g_object_ref (icon)); + + 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; + + return info; + } + else if (G_IS_THEMED_ICON (icon)) + { + 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); + + return info; + } + + return NULL; +} + +/** + * gtk_icon_info_new_for_pixbuf: + * @icon_theme: a #GtkIconTheme + * @pixbuf: the pixbuf to wrap in a #GtkIconInfo + * + * Creates a #GtkIconInfo for a #GtkPixbuf. + * + * Returns: a #GtkIconInfo + * + * Since: 2.16 + */ +GtkIconInfo * +gtk_icon_info_new_for_pixbuf (GtkIconTheme *icon_theme, + GdkPixbuf *pixbuf) +{ + GtkIconInfo *info; + + g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL); + g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); + + info = icon_info_new (); + info->pixbuf = g_object_ref (pixbuf); + info->scale = 1.0; + info->dir_type = ICON_THEME_DIR_UNTHEMED; + + return info; +} + #ifdef G_OS_WIN32 /* DLL ABI stability backward compatibility versions */ Index: gtk/gtkicontheme.h =================================================================== --- gtk/gtkicontheme.h (revision 19372) +++ gtk/gtkicontheme.h (working copy) @@ -69,15 +69,18 @@ * @GTK_ICON_LOOKUP_GENERIC_FALLBACK: Try to shorten icon name at '-' * characters before looking at inherited themes. For more general * fallback, see gtk_icon_theme_choose_icon(). Since 2.12. + * @GTK_ICON_LOOKUP_FORCE_SIZE: Always return the icon scaled to the + * requested size. Since 2.16. * * Used to specify options for gtk_icon_theme_lookup_icon() **/ typedef enum { - GTK_ICON_LOOKUP_NO_SVG = 1 << 0, - GTK_ICON_LOOKUP_FORCE_SVG = 1 << 1, - GTK_ICON_LOOKUP_USE_BUILTIN = 1 << 2, - GTK_ICON_LOOKUP_GENERIC_FALLBACK = 1 << 3 + GTK_ICON_LOOKUP_NO_SVG = 1 << 0, + GTK_ICON_LOOKUP_FORCE_SVG = 1 << 1, + GTK_ICON_LOOKUP_USE_BUILTIN = 1 << 2, + GTK_ICON_LOOKUP_GENERIC_FALLBACK = 1 << 3, + GTK_ICON_LOOKUP_FORCE_SIZE = 1 << 4 } GtkIconLookupFlags; #define GTK_ICON_THEME_ERROR gtk_icon_theme_error_quark () @@ -145,6 +148,11 @@ GtkIconLookupFlags flags, GError **error); +GtkIconInfo * gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme, + GIcon *icon, + gint size, + GtkIconLookupFlags flags); + GList * gtk_icon_theme_list_icons (GtkIconTheme *icon_theme, const gchar *context); GList * gtk_icon_theme_list_contexts (GtkIconTheme *icon_theme); @@ -152,29 +160,31 @@ gboolean gtk_icon_theme_rescan_if_needed (GtkIconTheme *icon_theme); -void gtk_icon_theme_add_builtin_icon (const gchar *icon_name, - gint size, - GdkPixbuf *pixbuf); +void gtk_icon_theme_add_builtin_icon (const gchar *icon_name, + gint size, + GdkPixbuf *pixbuf); -GType gtk_icon_info_get_type (void) G_GNUC_CONST; -GtkIconInfo *gtk_icon_info_copy (GtkIconInfo *icon_info); -void gtk_icon_info_free (GtkIconInfo *icon_info); +GType gtk_icon_info_get_type (void) G_GNUC_CONST; +GtkIconInfo * gtk_icon_info_copy (GtkIconInfo *icon_info); +void gtk_icon_info_free (GtkIconInfo *icon_info); -gint gtk_icon_info_get_base_size (GtkIconInfo *icon_info); -G_CONST_RETURN gchar *gtk_icon_info_get_filename (GtkIconInfo *icon_info); -GdkPixbuf * gtk_icon_info_get_builtin_pixbuf (GtkIconInfo *icon_info); -GdkPixbuf * gtk_icon_info_load_icon (GtkIconInfo *icon_info, - GError **error); +GtkIconInfo * gtk_icon_info_new_for_pixbuf (GtkIconTheme *icon_theme, + GdkPixbuf *pixbuf); -void gtk_icon_info_set_raw_coordinates (GtkIconInfo *icon_info, - gboolean raw_coordinates); +gint gtk_icon_info_get_base_size (GtkIconInfo *icon_info); +G_CONST_RETURN gchar *gtk_icon_info_get_filename (GtkIconInfo *icon_info); +GdkPixbuf * gtk_icon_info_get_builtin_pixbuf (GtkIconInfo *icon_info); +GdkPixbuf * gtk_icon_info_load_icon (GtkIconInfo *icon_info, + GError **error); +void gtk_icon_info_set_raw_coordinates (GtkIconInfo *icon_info, + gboolean raw_coordinates); -gboolean gtk_icon_info_get_embedded_rect (GtkIconInfo *icon_info, - GdkRectangle *rectangle); -gboolean gtk_icon_info_get_attach_points (GtkIconInfo *icon_info, - GdkPoint **points, - gint *n_points); -G_CONST_RETURN gchar *gtk_icon_info_get_display_name (GtkIconInfo *icon_info); +gboolean gtk_icon_info_get_embedded_rect (GtkIconInfo *icon_info, + GdkRectangle *rectangle); +gboolean gtk_icon_info_get_attach_points (GtkIconInfo *icon_info, + GdkPoint **points, + gint *n_points); +G_CONST_RETURN gchar *gtk_icon_info_get_display_name (GtkIconInfo *icon_info); /* Non-public methods */ void _gtk_icon_theme_check_reload (GdkDisplay *display);
_______________________________________________ gtk-devel-list mailing list gtk-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-devel-list