diff options
author | Matthias Clasen <mclasen@redhat.com> | 2008-05-29 14:33:49 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2008-05-29 14:33:49 +0000 |
commit | ee8253f908d2541321d72a0151fcfeb7446f7b8f (patch) | |
tree | aba76516a9370271ff86850367542c38b61a7d7b | |
parent | 24ac36693bebbd22416f91fc78c6fe189f953d94 (diff) | |
download | gtk+-ee8253f908d2541321d72a0151fcfeb7446f7b8f.tar.gz |
Bug 522084 – GIcon support for GtkIconTheme & GtkImage
2008-05-27 Matthias Clasen <mclasen@redhat.com>
Bug 522084 – GIcon support for GtkIconTheme & GtkImage
* gtk/gtkicontheme.[hc]: Add support for GIcon based lookups.
* gtk/gtkimage.[hc]: Allow setting an image from a GIcon.
* gtk/gtk.symbols: Additions
* tests/testimage.c: Add a GIcon test
svn path=/trunk/; revision=20236
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | gtk/gtk.symbols | 5 | ||||
-rw-r--r-- | gtk/gtkicontheme.c | 259 | ||||
-rw-r--r-- | gtk/gtkicontheme.h | 64 | ||||
-rw-r--r-- | gtk/gtkimage.c | 237 | ||||
-rw-r--r-- | gtk/gtkimage.h | 21 | ||||
-rw-r--r-- | tests/testimage.c | 17 |
7 files changed, 508 insertions, 104 deletions
@@ -1,3 +1,12 @@ +2008-05-27 Matthias Clasen <mclasen@redhat.com> + + Bug 522084 – GIcon support for GtkIconTheme & GtkImage + + * gtk/gtkicontheme.[hc]: Add support for GIcon based lookups. + * gtk/gtkimage.[hc]: Allow setting an image from a GIcon. + * gtk/gtk.symbols: Additions + * tests/testimage.c: Add a GIcon test + 2008-05-29 Michael Natterer <mitch@imendio.org> * gtk/Makefile.am diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 3b3c65cbb6..19cb6f13c2 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -1790,6 +1790,7 @@ gtk_icon_source_set_state_wildcarded #if IN_FILE(__GTK_ICON_THEME_C__) gtk_icon_info_copy gtk_icon_info_free +gtk_icon_info_new_for_pixbuf gtk_icon_info_get_attach_points gtk_icon_info_get_base_size gtk_icon_info_get_builtin_pixbuf @@ -1822,6 +1823,7 @@ gtk_icon_theme_list_contexts gtk_icon_theme_list_icons gtk_icon_theme_load_icon gtk_icon_theme_lookup_icon +gtk_icon_theme_lookup_by_gicon gtk_icon_theme_choose_icon gtk_icon_theme_new gtk_icon_theme_prepend_search_path PRIVATE @@ -1915,6 +1917,7 @@ gtk_image_get_pixbuf gtk_image_get_pixel_size gtk_image_get_pixmap gtk_image_get_stock +gtk_image_get_gicon gtk_image_get_storage_type gtk_image_get_type G_GNUC_CONST gtk_image_new @@ -1929,6 +1932,7 @@ gtk_image_new_from_image gtk_image_new_from_pixbuf gtk_image_new_from_pixmap gtk_image_new_from_stock +gtk_image_new_from_gicon gtk_image_set_from_animation gtk_image_set_from_file PRIVATE #ifdef G_OS_WIN32 @@ -1940,6 +1944,7 @@ gtk_image_set_from_image gtk_image_set_from_pixbuf gtk_image_set_from_pixmap gtk_image_set_from_stock +gtk_image_set_from_gicon gtk_image_set_pixel_size #endif #endif diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index 108f1f19aa..d970c98bce 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -113,6 +113,8 @@ struct _GtkIconInfo */ gchar *cp_filename; #endif + GLoadableIcon *loadable; + /* Cache pixbuf (if there is any) */ GdkPixbuf *cache_pixbuf; @@ -128,7 +130,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 +139,8 @@ struct _GtkIconInfo GdkPixbuf *pixbuf; GError *load_error; gdouble scale; + + guint ref_count; }; typedef struct @@ -1293,11 +1298,15 @@ choose_icon (GtkIconTheme *icon_theme, #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 @@ icon_info_new (void) 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_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; } @@ -2607,26 +2617,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 = 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 @@ 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); if (icon_info->pixbuf) g_object_unref (icon_info->pixbuf); if (icon_info->cache_pixbuf) @@ -2732,55 +2734,17 @@ 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) -{ - 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 @@ 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; } @@ -2816,7 +2825,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) { @@ -2838,17 +2849,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); @@ -2858,11 +2881,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); } @@ -2873,7 +2897,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 @@ -2900,7 +2923,10 @@ 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.) + * 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_check_reload (GdkDisplay *display) } } +/** + * 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.14 + */ +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.14 + */ +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 */ diff --git a/gtk/gtkicontheme.h b/gtk/gtkicontheme.h index 015000dc55..ec8154394c 100644 --- a/gtk/gtkicontheme.h +++ b/gtk/gtkicontheme.h @@ -73,15 +73,18 @@ struct _GtkIconThemeClass * @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.14. * * 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 () @@ -149,6 +152,11 @@ GdkPixbuf * gtk_icon_theme_load_icon (GtkIconTheme 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); @@ -156,29 +164,31 @@ char * gtk_icon_theme_get_example_icon_name (GtkIconTheme 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); - -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); - -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); +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); + +GtkIconInfo * gtk_icon_info_new_for_pixbuf (GtkIconTheme *icon_theme, + GdkPixbuf *pixbuf); + +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); /* Non-public methods */ void _gtk_icon_theme_check_reload (GdkDisplay *display); diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c index 43c442613d..07ce08fb58 100644 --- a/gtk/gtkimage.c +++ b/gtk/gtkimage.c @@ -94,7 +94,8 @@ enum PROP_PIXEL_SIZE, PROP_PIXBUF_ANIMATION, PROP_ICON_NAME, - PROP_STORAGE_TYPE + PROP_STORAGE_TYPE, + PROP_GICON }; G_DEFINE_TYPE (GtkImage, gtk_image, GTK_TYPE_MISC) @@ -231,6 +232,23 @@ gtk_image_class_init (GtkImageClass *class) NULL, GTK_PARAM_READWRITE)); + /** + * GtkImage:gicon: + * + * The GIcon displayed in the GtkImage. For themed icons, + * If the icon theme is changed, the image will be updated + * automatically. + * + * Since: 2.14 + */ + g_object_class_install_property (gobject_class, + PROP_GICON, + g_param_spec_object ("gicon", + P_("Icon"), + P_("The GIcon being displayed"), + G_TYPE_ICON, + GTK_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_STORAGE_TYPE, g_param_spec_enum ("storage-type", @@ -357,6 +375,10 @@ gtk_image_set_property (GObject *object, gtk_image_set_from_icon_name (image, g_value_get_string (value), image->icon_size); break; + case PROP_GICON: + gtk_image_set_from_gicon (image, g_value_get_object (value), + image->icon_size); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -445,6 +467,13 @@ gtk_image_get_property (GObject *object, g_value_set_string (value, image->data.name.icon_name); break; + case PROP_GICON: + if (image->storage_type != GTK_IMAGE_GICON) + g_value_set_object (value, NULL); + else + g_value_set_object (value, + image->data.gicon.icon); + break; case PROP_STORAGE_TYPE: g_value_set_enum (value, image->storage_type); break; @@ -687,6 +716,33 @@ gtk_image_new_from_icon_name (const gchar *icon_name, } /** + * gtk_image_new_from_gicon: + * @icon: an icon + * @size: a stock icon size + * + * Creates a #GtkImage displaying an icon from the current icon theme. + * If the icon name isn't known, a "broken image" icon will be + * displayed instead. If the current icon theme is changed, the icon + * will be updated appropriately. + * + * Return value: a new #GtkImage displaying the themed icon + * + * Since: 2.14 + **/ +GtkWidget* +gtk_image_new_from_gicon (GIcon *icon, + GtkIconSize size) +{ + GtkImage *image; + + image = g_object_new (GTK_TYPE_IMAGE, NULL); + + gtk_image_set_from_gicon (image, icon, size); + + return GTK_WIDGET (image); +} + +/** * gtk_image_set_from_pixmap: * @image: a #GtkImage * @pixmap: a #GdkPixmap or %NULL @@ -1052,6 +1108,50 @@ gtk_image_set_from_icon_name (GtkImage *image, } /** + * gtk_image_set_from_gicon: + * @image: a #GtkImage + * @icon: an icon + * @size: an icon size + * + * See gtk_image_new_from_gicon() for details. + * + * Since: 2.14 + **/ +void +gtk_image_set_from_gicon (GtkImage *image, + GIcon *icon, + GtkIconSize size) +{ + g_return_if_fail (GTK_IS_IMAGE (image)); + + g_object_freeze_notify (G_OBJECT (image)); + + /* in case icon == image->data.gicon.icon */ + if (icon) + g_object_ref (icon); + + gtk_image_clear (image); + + if (icon) + { + image->storage_type = GTK_IMAGE_GICON; + + image->data.gicon.icon = icon; + image->icon_size = size; + + /* Size is demand-computed in size request method + * if we're a icon theme image, since changing the + * style impacts the size request + */ + } + + g_object_notify (G_OBJECT (image), "gicon"); + g_object_notify (G_OBJECT (image), "icon-size"); + + g_object_thaw_notify (G_OBJECT (image)); +} + +/** * gtk_image_get_storage_type: * @image: a #GtkImage * @@ -1267,6 +1367,39 @@ gtk_image_get_icon_name (GtkImage *image, } /** + * gtk_image_get_gicon: + * @image: a #GtkImage + * @gicon: place to store a #GIcon + * @size: place to store an icon size + * + * Gets the #GIcon and size being displayed by the #GtkImage. + * The storage type of the image must be %GTK_IMAGE_EMPTY or + * %GTK_IMAGE_GICON (see gtk_image_get_storage_type()). + * The caller of this function does not own a reference to the + * returned #GIcon. + * + * Since: 2.14 + **/ +void +gtk_image_get_gicon (GtkImage *image, + GIcon **gicon, + GtkIconSize *size) +{ + g_return_if_fail (GTK_IS_IMAGE (image)); + g_return_if_fail (image->storage_type == GTK_IMAGE_GICON || + image->storage_type == GTK_IMAGE_EMPTY); + + if (image->storage_type == GTK_IMAGE_EMPTY) + image->data.gicon.icon = NULL; + + if (gicon) + *gicon = image->data.gicon.icon; + + if (size) + *size = image->icon_size; +} + +/** * gtk_image_new: * * Creates a new empty #GtkImage widget. @@ -1376,6 +1509,14 @@ icon_theme_changed (GtkImage *image) gtk_widget_queue_draw (GTK_WIDGET (image)); } + if (image->storage_type == GTK_IMAGE_GICON) + { + if (image->data.gicon.pixbuf) + g_object_unref (image->data.gicon.pixbuf); + image->data.gicon.pixbuf = NULL; + + gtk_widget_queue_draw (GTK_WIDGET (image)); + } } static void @@ -1459,6 +1600,59 @@ ensure_pixbuf_for_icon_name (GtkImage *image) } } +static void +ensure_pixbuf_for_gicon (GtkImage *image) +{ + GtkImagePrivate *priv; + GdkScreen *screen; + GtkIconTheme *icon_theme; + GtkSettings *settings; + gint width, height; + GError *error = NULL; + GtkIconInfo *info; + + g_return_if_fail (image->storage_type == GTK_IMAGE_GICON); + + priv = GTK_IMAGE_GET_PRIVATE (image); + screen = gtk_widget_get_screen (GTK_WIDGET (image)); + icon_theme = gtk_icon_theme_get_for_screen (screen); + settings = gtk_settings_get_for_screen (screen); + if (image->data.gicon.pixbuf == NULL) + { + if (priv->pixel_size != -1) + { + width = height = priv->pixel_size; + } + else if (!gtk_icon_size_lookup_for_settings (settings, + image->icon_size, + &width, &height)) + { + if (image->icon_size == -1) + width = height = 48; + else + { + g_warning ("Invalid icon size %d\n", image->icon_size); + width = height = 24; + } + } + + info = gtk_icon_theme_lookup_by_gicon (icon_theme, + image->data.gicon.icon, + MIN (width, height), 0); + image->data.gicon.pixbuf = gtk_icon_info_load_icon (info, &error); + if (image->data.gicon.pixbuf == NULL) + { + g_error_free (error); + image->data.gicon.pixbuf = + gtk_widget_render_icon (GTK_WIDGET (image), + GTK_STOCK_MISSING_IMAGE, + image->icon_size, + NULL); + } + } +} + + /* * Like gdk_rectangle_intersect (dest, src, dest), but make * sure that the origin of dest is moved by an "even" offset. @@ -1690,6 +1884,17 @@ gtk_image_expose (GtkWidget *widget, } break; + case GTK_IMAGE_GICON: + ensure_pixbuf_for_gicon (image); + pixbuf = image->data.gicon.pixbuf; + if (pixbuf) + { + g_object_ref (pixbuf); + image_bound.width = gdk_pixbuf_get_width (pixbuf); + image_bound.height = gdk_pixbuf_get_height (pixbuf); + } + break; + case GTK_IMAGE_EMPTY: g_assert_not_reached (); break; @@ -1778,6 +1983,7 @@ gtk_image_expose (GtkWidget *widget, case GTK_IMAGE_ANIMATION: case GTK_IMAGE_ICON_NAME: case GTK_IMAGE_EMPTY: + case GTK_IMAGE_GICON: g_assert_not_reached (); break; } @@ -1893,6 +2099,18 @@ gtk_image_reset (GtkImage *image) break; + case GTK_IMAGE_GICON: + if (image->data.gicon.icon) + g_object_unref (image->data.gicon.icon); + image->data.gicon.icon = NULL; + if (image->data.gicon.pixbuf) + g_object_unref (image->data.gicon.pixbuf); + image->data.gicon.pixbuf = NULL; + + g_object_notify (G_OBJECT (image), "gicon"); + + break; + case GTK_IMAGE_EMPTY: default: break; @@ -1963,6 +2181,12 @@ gtk_image_calc_size (GtkImage *image) pixbuf = image->data.name.pixbuf; if (pixbuf) g_object_ref (pixbuf); break; + case GTK_IMAGE_GICON: + ensure_pixbuf_for_gicon (image); + pixbuf = image->data.gicon.pixbuf; + if (pixbuf) + g_object_ref (pixbuf); + break; default: break; } @@ -2068,6 +2292,17 @@ gtk_image_set_pixel_size (GtkImage *image, gtk_image_update_size (image, pixel_size, pixel_size); } + if (image->storage_type == GTK_IMAGE_GICON) + { + if (image->data.gicon.pixbuf) + { + g_object_unref (image->data.gicon.pixbuf); + image->data.gicon.pixbuf = NULL; + } + + gtk_image_update_size (image, pixel_size, pixel_size); + } + g_object_notify (G_OBJECT (image), "pixel-size"); } } diff --git a/gtk/gtkimage.h b/gtk/gtkimage.h index 2fb0f61bd3..c4dacfeefa 100644 --- a/gtk/gtkimage.h +++ b/gtk/gtkimage.h @@ -33,6 +33,7 @@ #include <gdk/gdk.h> +#include <gio/gio.h> #include <gtk/gtkmisc.h> @@ -56,6 +57,7 @@ typedef struct _GtkImageStockData GtkImageStockData; typedef struct _GtkImageIconSetData GtkImageIconSetData; typedef struct _GtkImageAnimationData GtkImageAnimationData; typedef struct _GtkImageIconNameData GtkImageIconNameData; +typedef struct _GtkImageGIconData GtkImageGIconData; struct _GtkImagePixmapData { @@ -96,6 +98,13 @@ struct _GtkImageIconNameData guint theme_change_id; }; +struct _GtkImageGIconData +{ + GIcon *icon; + GdkPixbuf *pixbuf; + guint theme_change_id; +}; + typedef enum { GTK_IMAGE_EMPTY, @@ -105,7 +114,8 @@ typedef enum GTK_IMAGE_STOCK, GTK_IMAGE_ICON_SET, GTK_IMAGE_ANIMATION, - GTK_IMAGE_ICON_NAME + GTK_IMAGE_ICON_NAME, + GTK_IMAGE_GICON } GtkImageType; struct _GtkImage @@ -123,6 +133,7 @@ struct _GtkImage GtkImageIconSetData icon_set; GtkImageAnimationData anim; GtkImageIconNameData name; + GtkImageGIconData gicon; } data; /* Only used with GTK_IMAGE_PIXMAP, GTK_IMAGE_IMAGE */ @@ -165,6 +176,8 @@ GtkWidget* gtk_image_new_from_icon_set (GtkIconSet *icon_set, GtkWidget* gtk_image_new_from_animation (GdkPixbufAnimation *animation); GtkWidget* gtk_image_new_from_icon_name (const gchar *icon_name, GtkIconSize size); +GtkWidget* gtk_image_new_from_gicon (GIcon *icon, + GtkIconSize size); void gtk_image_clear (GtkImage *image); void gtk_image_set_from_pixmap (GtkImage *image, @@ -188,6 +201,9 @@ void gtk_image_set_from_animation (GtkImage *image, void gtk_image_set_from_icon_name (GtkImage *image, const gchar *icon_name, GtkIconSize size); +void gtk_image_set_from_gicon (GtkImage *image, + GIcon *icon, + GtkIconSize size); void gtk_image_set_pixel_size (GtkImage *image, gint pixel_size); @@ -210,6 +226,9 @@ GdkPixbufAnimation* gtk_image_get_animation (GtkImage *image); void gtk_image_get_icon_name (GtkImage *image, G_CONST_RETURN gchar **icon_name, GtkIconSize *size); +void gtk_image_get_gicon (GtkImage *image, + GIcon **gicon, + GtkIconSize *size); gint gtk_image_get_pixel_size (GtkImage *image); #ifndef GTK_DISABLE_DEPRECATED diff --git a/tests/testimage.c b/tests/testimage.c index 0e40f247b8..e9bd7d748c 100644 --- a/tests/testimage.c +++ b/tests/testimage.c @@ -18,6 +18,7 @@ */ #include <gtk/gtk.h> +#include <gio/gio.h> static void drag_begin (GtkWidget *widget, @@ -103,6 +104,8 @@ main (int argc, char **argv) GtkIconSource *iconsource; gchar *icon_name = "gnome-terminal"; gchar *anim_filename = NULL; + GIcon *icon; + GFile *file; gtk_init (&argc, &argv); @@ -173,6 +176,20 @@ main (int argc, char **argv) gtk_image_set_pixel_size (GTK_IMAGE (image), 30); gtk_table_attach_defaults (GTK_TABLE (table), image, 2, 3, 4, 5); + label = gtk_label_new ("GTK_IMAGE_GICON"); + gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 5, 6); + icon = g_themed_icon_new_with_default_fallbacks ("folder-remote"); + image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG); + g_object_unref (icon); + gtk_table_attach_defaults (GTK_TABLE (table), image, 1, 2, 5, 6); + file = g_file_new_for_path ("apple-red.png"); + icon = g_file_icon_new (file); + image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG); + g_object_unref (icon); + gtk_image_set_pixel_size (GTK_IMAGE (image), 30); + gtk_table_attach_defaults (GTK_TABLE (table), image, 2, 3, 5, 6); + + if (anim_filename) { label = gtk_label_new ("GTK_IMAGE_ANIMATION (from file)"); |