X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkimage.c;h=d373b51b709d81586f61af595b9504d836775b3e;hb=1865b9a1116d166c9abc5c75f5d01270574007c5;hp=cd16a9c4dc42975b38ae2183f8eb2c216f6edc72;hpb=8f6a014de4c5ddbb562209aeeb4c977a063a7468;p=~andy%2Fgtk diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c index cd16a9c4d..d373b51b7 100644 --- a/gtk/gtkimage.c +++ b/gtk/gtkimage.c @@ -12,9 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -25,16 +23,22 @@ */ #include "config.h" + #include #include #include "gtkcontainer.h" -#include "gtkimage.h" +#include "gtkiconhelperprivate.h" +#include "gtkimageprivate.h" #include "gtkiconfactory.h" #include "gtkstock.h" #include "gtkicontheme.h" +#include "gtksizerequest.h" #include "gtkintl.h" #include "gtkprivate.h" +#include "gtktypebuiltins.h" + +#include "a11y/gtkimageaccessible.h" /** * SECTION:gtkimage @@ -120,77 +124,58 @@ * * Sometimes an application will want to avoid depending on external data * files, such as image files. GTK+ comes with a program to avoid this, - * called gdk-pixbuf-csource. This program + * called gdk-pixbuf-csource. This library * allows you to convert an image into a C variable declaration, which * can then be loaded into a #GdkPixbuf using * gdk_pixbuf_new_from_inline(). */ -struct _GtkImagePriv +struct _GtkImagePrivate { - GtkIconSize icon_size; /* Only used with GTK_IMAGE_STOCK, GTK_IMAGE_ICON_SET, GTK_IMAGE_ICON_NAME */ - GtkImageType storage_type; - GdkBitmap *mask; /* Only used with GTK_IMAGE_PIXMAP, GTK_IMAGE_IMAGE */ - - union - { - GtkImagePixmapData pixmap; - GtkImageImageData image; - GtkImagePixbufData pixbuf; - GtkImageStockData stock; - GtkImageIconSetData icon_set; - GtkImageAnimationData anim; - GtkImageIconNameData name; - GtkImageGIconData gicon; - } data; - - gboolean was_symbolic; + GtkIconHelper *icon_helper; + + gint animation_timeout; + GdkPixbufAnimationIter *animation_iter; + gchar *filename; /* Only used with GTK_IMAGE_ANIMATION, GTK_IMAGE_PIXBUF */ - gint last_rendered_state; /* a GtkStateType, with -1 meaning an invalid state, - * only used with GTK_IMAGE_GICON, GTK_IMAGE_ICON_NAME */ - gint pixel_size; - guint need_calc_size : 1; + gchar *resource_path; /* Only used with GTK_IMAGE_PIXBUF */ }; #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON -static gint gtk_image_expose (GtkWidget *widget, - GdkEventExpose *event); -static void gtk_image_unmap (GtkWidget *widget); -static void gtk_image_unrealize (GtkWidget *widget); -static void gtk_image_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_image_style_set (GtkWidget *widget, - GtkStyle *prev_style); -static void gtk_image_screen_changed (GtkWidget *widget, - GdkScreen *prev_screen); -static void gtk_image_destroy (GtkObject *object); -static void gtk_image_reset (GtkImage *image); -static void gtk_image_calc_size (GtkImage *image); - -static void gtk_image_update_size (GtkImage *image, - gint image_width, - gint image_height); - -static void gtk_image_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_image_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); - -static void icon_theme_changed (GtkImage *image); +static gint gtk_image_draw (GtkWidget *widget, + cairo_t *cr); +static void gtk_image_unmap (GtkWidget *widget); +static void gtk_image_unrealize (GtkWidget *widget); +static void gtk_image_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural); +static void gtk_image_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural); + +static void gtk_image_style_updated (GtkWidget *widget); +static void gtk_image_screen_changed (GtkWidget *widget, + GdkScreen *prev_screen); +static void gtk_image_finalize (GObject *object); +static void gtk_image_reset (GtkImage *image); + +static void gtk_image_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_image_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static void icon_theme_changed (GtkImage *image); enum { PROP_0, PROP_PIXBUF, - PROP_PIXMAP, - PROP_IMAGE, - PROP_MASK, PROP_FILE, PROP_STOCK, PROP_ICON_SET, @@ -199,7 +184,9 @@ enum PROP_PIXBUF_ANIMATION, PROP_ICON_NAME, PROP_STORAGE_TYPE, - PROP_GICON + PROP_GICON, + PROP_RESOURCE, + PROP_USE_FALLBACK }; G_DEFINE_TYPE (GtkImage, gtk_image, GTK_TYPE_MISC) @@ -208,25 +195,21 @@ static void gtk_image_class_init (GtkImageClass *class) { GObjectClass *gobject_class; - GtkObjectClass *object_class; GtkWidgetClass *widget_class; gobject_class = G_OBJECT_CLASS (class); gobject_class->set_property = gtk_image_set_property; gobject_class->get_property = gtk_image_get_property; - - object_class = GTK_OBJECT_CLASS (class); - - object_class->destroy = gtk_image_destroy; + gobject_class->finalize = gtk_image_finalize; widget_class = GTK_WIDGET_CLASS (class); - - widget_class->expose_event = gtk_image_expose; - widget_class->size_request = gtk_image_size_request; + widget_class->draw = gtk_image_draw; + widget_class->get_preferred_width = gtk_image_get_preferred_width; + widget_class->get_preferred_height = gtk_image_get_preferred_height; widget_class->unmap = gtk_image_unmap; widget_class->unrealize = gtk_image_unrealize; - widget_class->style_set = gtk_image_style_set; + widget_class->style_updated = gtk_image_style_updated; widget_class->screen_changed = gtk_image_screen_changed; g_object_class_install_property (gobject_class, @@ -237,30 +220,6 @@ gtk_image_class_init (GtkImageClass *class) GDK_TYPE_PIXBUF, GTK_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, - PROP_PIXMAP, - g_param_spec_object ("pixmap", - P_("Pixmap"), - P_("A GdkPixmap to display"), - GDK_TYPE_PIXMAP, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, - PROP_IMAGE, - g_param_spec_object ("image", - P_("Image"), - P_("A GdkImage to display"), - GDK_TYPE_IMAGE, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, - PROP_MASK, - g_param_spec_object ("mask", - P_("Mask"), - P_("Mask bitmap to use with GdkImage or GdkPixmap"), - GDK_TYPE_PIXMAP, - GTK_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_FILE, g_param_spec_string ("file", @@ -352,7 +311,22 @@ gtk_image_class_init (GtkImageClass *class) P_("The GIcon being displayed"), G_TYPE_ICON, GTK_PARAM_READWRITE)); - + + /** + * GtkImage:resource: + * + * A path to a resource file to display. + * + * Since: 3.8 + */ + g_object_class_install_property (gobject_class, + PROP_RESOURCE, + g_param_spec_string ("resource", + P_("Resource"), + P_("The resource path being displayed"), + NULL, + GTK_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_STORAGE_TYPE, g_param_spec_enum ("storage-type", @@ -362,39 +336,56 @@ gtk_image_class_init (GtkImageClass *class) GTK_IMAGE_EMPTY, GTK_PARAM_READABLE)); - g_type_class_add_private (object_class, sizeof (GtkImagePriv)); + /** + * GtkImage:use-fallback: + * + * Whether the icon displayed in the GtkImage will use + * standard icon names fallback. The value of this property + * is only relevant for images of type %GTK_IMAGE_ICON_NAME + * and %GTK_IMAGE_GICON. + * + * Since: 3.0 + */ + g_object_class_install_property (gobject_class, + PROP_USE_FALLBACK, + g_param_spec_boolean ("use-fallback", + P_("Use Fallback"), + P_("Whether to use icon names fallback"), + FALSE, + GTK_PARAM_READWRITE)); + + g_type_class_add_private (class, sizeof (GtkImagePrivate)); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_IMAGE_ACCESSIBLE); } static void gtk_image_init (GtkImage *image) { - GtkImagePriv *priv; + GtkImagePrivate *priv; image->priv = G_TYPE_INSTANCE_GET_PRIVATE (image, GTK_TYPE_IMAGE, - GtkImagePriv); + GtkImagePrivate); priv = image->priv; gtk_widget_set_has_window (GTK_WIDGET (image), FALSE); - - priv->storage_type = GTK_IMAGE_EMPTY; - priv->icon_size = DEFAULT_ICON_SIZE; - priv->mask = NULL; - - priv->pixel_size = -1; + priv->icon_helper = _gtk_icon_helper_new (); priv->filename = NULL; } static void -gtk_image_destroy (GtkObject *object) +gtk_image_finalize (GObject *object) { GtkImage *image = GTK_IMAGE (object); - gtk_image_reset (image); + g_clear_object (&image->priv->icon_helper); - GTK_OBJECT_CLASS (gtk_image_parent_class)->destroy (object); -} + g_free (image->priv->filename); + + G_OBJECT_CLASS (gtk_image_parent_class)->finalize (object); +}; static void gtk_image_set_property (GObject *object, @@ -403,7 +394,11 @@ gtk_image_set_property (GObject *object, GParamSpec *pspec) { GtkImage *image = GTK_IMAGE (object); - GtkImagePriv *priv = image->priv; + GtkImagePrivate *priv = image->priv; + GtkIconSize icon_size = _gtk_icon_helper_get_icon_size (priv->icon_helper); + + if (icon_size == GTK_ICON_SIZE_INVALID) + icon_size = DEFAULT_ICON_SIZE; switch (prop_id) { @@ -411,70 +406,19 @@ gtk_image_set_property (GObject *object, gtk_image_set_from_pixbuf (image, g_value_get_object (value)); break; - case PROP_PIXMAP: - gtk_image_set_from_pixmap (image, - g_value_get_object (value), - priv->mask); - break; - case PROP_IMAGE: - gtk_image_set_from_image (image, - g_value_get_object (value), - priv->mask); - break; - case PROP_MASK: - if (priv->storage_type == GTK_IMAGE_PIXMAP) - gtk_image_set_from_pixmap (image, - priv->data.pixmap.pixmap, - g_value_get_object (value)); - else if (priv->storage_type == GTK_IMAGE_IMAGE) - gtk_image_set_from_image (image, - priv->data.image.image, - g_value_get_object (value)); - else - { - GdkBitmap *mask; - - mask = g_value_get_object (value); - - if (mask) - g_object_ref (mask); - - gtk_image_clear (image); - - priv->mask = mask; - } - break; case PROP_FILE: gtk_image_set_from_file (image, g_value_get_string (value)); break; case PROP_STOCK: gtk_image_set_from_stock (image, g_value_get_string (value), - priv->icon_size); + icon_size); break; case PROP_ICON_SET: gtk_image_set_from_icon_set (image, g_value_get_boxed (value), - priv->icon_size); + icon_size); break; case PROP_ICON_SIZE: - if (priv->storage_type == GTK_IMAGE_STOCK) - gtk_image_set_from_stock (image, - priv->data.stock.stock_id, - g_value_get_int (value)); - else if (priv->storage_type == GTK_IMAGE_ICON_SET) - gtk_image_set_from_icon_set (image, - priv->data.icon_set.icon_set, - g_value_get_int (value)); - else if (priv->storage_type == GTK_IMAGE_ICON_NAME) - gtk_image_set_from_icon_name (image, - priv->data.name.icon_name, - g_value_get_int (value)); - else if (priv->storage_type == GTK_IMAGE_GICON) - gtk_image_set_from_gicon (image, - priv->data.gicon.icon, - g_value_get_int (value)); - else - /* Save to be used when STOCK, ICON_SET, ICON_NAME or GICON property comes in */ - priv->icon_size = g_value_get_int (value); + _gtk_icon_helper_set_icon_size (priv->icon_helper, g_value_get_int (value)); break; case PROP_PIXEL_SIZE: gtk_image_set_pixel_size (image, g_value_get_int (value)); @@ -485,11 +429,18 @@ gtk_image_set_property (GObject *object, break; case PROP_ICON_NAME: gtk_image_set_from_icon_name (image, g_value_get_string (value), - priv->icon_size); + icon_size); break; case PROP_GICON: gtk_image_set_from_gicon (image, g_value_get_object (value), - priv->icon_size); + icon_size); + break; + case PROP_RESOURCE: + gtk_image_set_from_resource (image, g_value_get_string (value)); + break; + + case PROP_USE_FALLBACK: + _gtk_icon_helper_set_use_fallback (priv->icon_helper, g_value_get_boolean (value)); break; default: @@ -505,88 +456,46 @@ gtk_image_get_property (GObject *object, GParamSpec *pspec) { GtkImage *image = GTK_IMAGE (object); - GtkImagePriv *priv = image->priv; + GtkImagePrivate *priv = image->priv; - /* The "getter" functions whine if you try to get the wrong - * storage type. This function is instead robust against that, - * so that GUI builders don't have to jump through hoops - * to avoid g_warning - */ - switch (prop_id) { case PROP_PIXBUF: - if (priv->storage_type != GTK_IMAGE_PIXBUF) - g_value_set_object (value, NULL); - else - g_value_set_object (value, - gtk_image_get_pixbuf (image)); - break; - case PROP_PIXMAP: - if (priv->storage_type != GTK_IMAGE_PIXMAP) - g_value_set_object (value, NULL); - else - g_value_set_object (value, - priv->data.pixmap.pixmap); - break; - case PROP_MASK: - g_value_set_object (value, priv->mask); - break; - case PROP_IMAGE: - if (priv->storage_type != GTK_IMAGE_IMAGE) - g_value_set_object (value, NULL); - else - g_value_set_object (value, - priv->data.image.image); + g_value_set_object (value, _gtk_icon_helper_peek_pixbuf (priv->icon_helper)); break; case PROP_FILE: g_value_set_string (value, priv->filename); break; case PROP_STOCK: - if (priv->storage_type != GTK_IMAGE_STOCK) - g_value_set_string (value, NULL); - else - g_value_set_string (value, - priv->data.stock.stock_id); + g_value_set_string (value, _gtk_icon_helper_get_stock_id (priv->icon_helper)); break; case PROP_ICON_SET: - if (priv->storage_type != GTK_IMAGE_ICON_SET) - g_value_set_boxed (value, NULL); - else - g_value_set_boxed (value, - priv->data.icon_set.icon_set); + g_value_set_boxed (value, _gtk_icon_helper_peek_icon_set (priv->icon_helper)); break; case PROP_ICON_SIZE: - g_value_set_int (value, priv->icon_size); + g_value_set_int (value, _gtk_icon_helper_get_icon_size (priv->icon_helper)); break; case PROP_PIXEL_SIZE: - g_value_set_int (value, priv->pixel_size); + g_value_set_int (value, _gtk_icon_helper_get_pixel_size (priv->icon_helper)); break; case PROP_PIXBUF_ANIMATION: - if (priv->storage_type != GTK_IMAGE_ANIMATION) - g_value_set_object (value, NULL); - else - g_value_set_object (value, - priv->data.anim.anim); + g_value_set_object (value, _gtk_icon_helper_peek_animation (priv->icon_helper)); break; case PROP_ICON_NAME: - if (priv->storage_type != GTK_IMAGE_ICON_NAME) - g_value_set_string (value, NULL); - else - g_value_set_string (value, - priv->data.name.icon_name); + g_value_set_string (value, _gtk_icon_helper_get_icon_name (priv->icon_helper)); break; case PROP_GICON: - if (priv->storage_type != GTK_IMAGE_GICON) - g_value_set_object (value, NULL); - else - g_value_set_object (value, - priv->data.gicon.icon); + g_value_set_object (value, _gtk_icon_helper_peek_gicon (priv->icon_helper)); + break; + case PROP_RESOURCE: + g_value_set_string (value, priv->resource_path); + break; + case PROP_USE_FALLBACK: + g_value_set_boolean (value, _gtk_icon_helper_get_use_fallback (priv->icon_helper)); break; case PROP_STORAGE_TYPE: - g_value_set_enum (value, priv->storage_type); + g_value_set_enum (value, _gtk_icon_helper_get_storage_type (priv->icon_helper)); break; - default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -595,62 +504,45 @@ gtk_image_get_property (GObject *object, /** - * gtk_image_new_from_pixmap: - * @pixmap: (allow-none): a #GdkPixmap, or %NULL - * @mask: (allow-none): a #GdkBitmap, or %NULL - * - * Creates a #GtkImage widget displaying @pixmap with a @mask. - * A #GdkPixmap is a server-side image buffer in the pixel format of the - * current display. The #GtkImage does not assume a reference to the - * pixmap or mask; you still need to unref them if you own references. - * #GtkImage will add its own reference rather than adopting yours. + * gtk_image_new_from_file: + * @filename: (type filename): a filename * - * Return value: a new #GtkImage - **/ -GtkWidget* -gtk_image_new_from_pixmap (GdkPixmap *pixmap, - GdkBitmap *mask) -{ - GtkImage *image; - - image = g_object_new (GTK_TYPE_IMAGE, NULL); - - gtk_image_set_from_pixmap (image, pixmap, mask); - - return GTK_WIDGET (image); -} - -/** - * gtk_image_new_from_image: - * @image: (allow-none): a #GdkImage, or %NULL - * @mask: (allow-none): a #GdkBitmap, or %NULL + * Creates a new #GtkImage displaying the file @filename. If the file + * isn't found or can't be loaded, the resulting #GtkImage will + * display a "broken image" icon. This function never returns %NULL, + * it always returns a valid #GtkImage widget. * - * Creates a #GtkImage widget displaying a @image with a @mask. - * A #GdkImage is a client-side image buffer in the pixel format of the - * current display. The #GtkImage does not assume a reference to the - * image or mask; you still need to unref them if you own references. - * #GtkImage will add its own reference rather than adopting yours. + * If the file contains an animation, the image will contain an + * animation. + * + * If you need to detect failures to load the file, use + * gdk_pixbuf_new_from_file() to load the file yourself, then create + * the #GtkImage from the pixbuf. (Or for animations, use + * gdk_pixbuf_animation_new_from_file()). + * + * The storage type (gtk_image_get_storage_type()) of the returned + * image is not defined, it will be whatever is appropriate for + * displaying the file. * * Return value: a new #GtkImage **/ GtkWidget* -gtk_image_new_from_image (GdkImage *gdk_image, - GdkBitmap *mask) +gtk_image_new_from_file (const gchar *filename) { GtkImage *image; image = g_object_new (GTK_TYPE_IMAGE, NULL); - gtk_image_set_from_image (image, gdk_image, mask); + gtk_image_set_from_file (image, filename); return GTK_WIDGET (image); } /** - * gtk_image_new_from_file: - * @filename: a filename - * - * Creates a new #GtkImage displaying the file @filename. If the file + * gtk_image_new_from_resource: + * @resource_path: a resource path + * + * Creates a new #GtkImage displaying the resource file @resource_path. If the file * isn't found or can't be loaded, the resulting #GtkImage will * display a "broken image" icon. This function never returns %NULL, * it always returns a valid #GtkImage widget. @@ -666,17 +558,19 @@ gtk_image_new_from_image (GdkImage *gdk_image, * The storage type (gtk_image_get_storage_type()) of the returned * image is not defined, it will be whatever is appropriate for * displaying the file. - * + * * Return value: a new #GtkImage + * + * Since: 3.4 **/ GtkWidget* -gtk_image_new_from_file (const gchar *filename) +gtk_image_new_from_resource (const gchar *resource_path) { GtkImage *image; image = g_object_new (GTK_TYPE_IMAGE, NULL); - gtk_image_set_from_file (image, filename); + gtk_image_set_from_resource (image, resource_path); return GTK_WIDGET (image); } @@ -852,173 +746,117 @@ gtk_image_new_from_gicon (GIcon *icon, } /** - * gtk_image_set_from_pixmap: + * gtk_image_set_from_file: * @image: a #GtkImage - * @pixmap: (allow-none): a #GdkPixmap or %NULL - * @mask: (allow-none): a #GdkBitmap or %NULL + * @filename: (type filename) (allow-none): a filename or %NULL * - * See gtk_image_new_from_pixmap() for details. + * See gtk_image_new_from_file() for details. **/ void -gtk_image_set_from_pixmap (GtkImage *image, - GdkPixmap *pixmap, - GdkBitmap *mask) +gtk_image_set_from_file (GtkImage *image, + const gchar *filename) { - GtkImagePriv *priv; - + GtkImagePrivate *priv; + GdkPixbufAnimation *anim; + g_return_if_fail (GTK_IS_IMAGE (image)); - g_return_if_fail (pixmap == NULL || - GDK_IS_PIXMAP (pixmap)); - g_return_if_fail (mask == NULL || - GDK_IS_PIXMAP (mask)); priv = image->priv; g_object_freeze_notify (G_OBJECT (image)); - if (pixmap) - g_object_ref (pixmap); - - if (mask) - g_object_ref (mask); - gtk_image_clear (image); - priv->mask = mask; - - if (pixmap) + if (filename == NULL) { - int width; - int height; - - priv->storage_type = GTK_IMAGE_PIXMAP; - - priv->data.pixmap.pixmap = pixmap; - - gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height); - - gtk_image_update_size (image, width, height); + priv->filename = NULL; + g_object_thaw_notify (G_OBJECT (image)); + return; } - g_object_notify (G_OBJECT (image), "pixmap"); - g_object_notify (G_OBJECT (image), "mask"); - - g_object_thaw_notify (G_OBJECT (image)); -} - -/** - * gtk_image_set_from_image: - * @image: a #GtkImage - * @gdk_image: (allow-none): a #GdkImage or %NULL - * @mask: (allow-none): a #GdkBitmap or %NULL - * - * See gtk_image_new_from_image() for details. - **/ -void -gtk_image_set_from_image (GtkImage *image, - GdkImage *gdk_image, - GdkBitmap *mask) -{ - GtkImagePriv *priv; - - g_return_if_fail (GTK_IS_IMAGE (image)); - g_return_if_fail (gdk_image == NULL || - GDK_IS_IMAGE (gdk_image)); - g_return_if_fail (mask == NULL || - GDK_IS_PIXMAP (mask)); - - priv = image->priv; - - g_object_freeze_notify (G_OBJECT (image)); - - if (gdk_image) - g_object_ref (gdk_image); - - if (mask) - g_object_ref (mask); - - gtk_image_clear (image); + anim = gdk_pixbuf_animation_new_from_file (filename, NULL); - if (gdk_image) + if (anim == NULL) { - priv->storage_type = GTK_IMAGE_IMAGE; + gtk_image_set_from_stock (image, + GTK_STOCK_MISSING_IMAGE, + DEFAULT_ICON_SIZE); + g_object_thaw_notify (G_OBJECT (image)); + return; + } - priv->data.image.image = gdk_image; - priv->mask = mask; + /* We could just unconditionally set_from_animation, + * but it's nicer for memory if we toss the animation + * if it's just a single pixbuf + */ - gtk_image_update_size (image, gdk_image->width, gdk_image->height); - } + if (gdk_pixbuf_animation_is_static_image (anim)) + gtk_image_set_from_pixbuf (image, + gdk_pixbuf_animation_get_static_image (anim)); else - { - /* Clean up the mask if gdk_image was NULL */ - if (mask) - g_object_unref (mask); - } + gtk_image_set_from_animation (image, anim); + + g_object_unref (anim); - g_object_notify (G_OBJECT (image), "image"); - g_object_notify (G_OBJECT (image), "mask"); + priv->filename = g_strdup (filename); g_object_thaw_notify (G_OBJECT (image)); } /** - * gtk_image_set_from_file: + * gtk_image_set_from_resource: * @image: a #GtkImage - * @filename: (allow-none): a filename or %NULL + * @resource_path: (allow-none): a resource path or %NULL * - * See gtk_image_new_from_file() for details. + * See gtk_image_new_from_resource() for details. **/ void -gtk_image_set_from_file (GtkImage *image, - const gchar *filename) +gtk_image_set_from_resource (GtkImage *image, + const gchar *resource_path) { - GtkImagePriv *priv; - GdkPixbufAnimation *anim; - + GtkImagePrivate *priv; + GdkPixbufAnimation *animation; + g_return_if_fail (GTK_IS_IMAGE (image)); priv = image->priv; g_object_freeze_notify (G_OBJECT (image)); - + gtk_image_clear (image); - if (filename == NULL) + if (resource_path == NULL) { - priv->filename = NULL; g_object_thaw_notify (G_OBJECT (image)); return; } - anim = gdk_pixbuf_animation_new_from_file (filename, NULL); + animation = gdk_pixbuf_animation_new_from_resource (resource_path, NULL); - if (anim == NULL) + if (animation == NULL) { gtk_image_set_from_stock (image, GTK_STOCK_MISSING_IMAGE, - GTK_ICON_SIZE_BUTTON); + DEFAULT_ICON_SIZE); g_object_thaw_notify (G_OBJECT (image)); return; } - /* We could just unconditionally set_from_animation, - * but it's nicer for memory if we toss the animation - * if it's just a single pixbuf - */ + priv->resource_path = g_strdup (resource_path); - if (gdk_pixbuf_animation_is_static_image (anim)) - gtk_image_set_from_pixbuf (image, - gdk_pixbuf_animation_get_static_image (anim)); + if (gdk_pixbuf_animation_is_static_image (animation)) + gtk_image_set_from_pixbuf (image, gdk_pixbuf_animation_get_static_image (animation)); else - gtk_image_set_from_animation (image, anim); + gtk_image_set_from_animation (image, animation); - g_object_unref (anim); + g_object_notify (G_OBJECT (image), "resource"); + + g_object_unref (animation); - priv->filename = g_strdup (filename); - g_object_thaw_notify (G_OBJECT (image)); } + /** * gtk_image_set_from_pixbuf: * @image: a #GtkImage @@ -1030,7 +868,7 @@ void gtk_image_set_from_pixbuf (GtkImage *image, GdkPixbuf *pixbuf) { - GtkImagePriv *priv; + GtkImagePrivate *priv; g_return_if_fail (GTK_IS_IMAGE (image)); g_return_if_fail (pixbuf == NULL || @@ -1040,21 +878,10 @@ gtk_image_set_from_pixbuf (GtkImage *image, g_object_freeze_notify (G_OBJECT (image)); - if (pixbuf) - g_object_ref (pixbuf); - gtk_image_clear (image); if (pixbuf != NULL) - { - priv->storage_type = GTK_IMAGE_PIXBUF; - - priv->data.pixbuf.pixbuf = pixbuf; - - gtk_image_update_size (image, - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf)); - } + _gtk_icon_helper_set_pixbuf (priv->icon_helper, pixbuf); g_object_notify (G_OBJECT (image), "pixbuf"); @@ -1074,7 +901,7 @@ gtk_image_set_from_stock (GtkImage *image, const gchar *stock_id, GtkIconSize size) { - GtkImagePriv *priv; + GtkImagePrivate *priv; gchar *new_id; g_return_if_fail (GTK_IS_IMAGE (image)); @@ -1083,22 +910,13 @@ gtk_image_set_from_stock (GtkImage *image, g_object_freeze_notify (G_OBJECT (image)); - /* in case stock_id == priv->data.stock.stock_id */ new_id = g_strdup (stock_id); - gtk_image_clear (image); if (new_id) { - priv->storage_type = GTK_IMAGE_STOCK; - - priv->data.stock.stock_id = new_id; - priv->icon_size = size; - - /* Size is demand-computed in size request method - * if we're a stock image, since changing the - * style impacts the size request - */ + _gtk_icon_helper_set_stock_id (priv->icon_helper, new_id, size); + g_free (new_id); } g_object_notify (G_OBJECT (image), "stock"); @@ -1120,14 +938,14 @@ gtk_image_set_from_icon_set (GtkImage *image, GtkIconSet *icon_set, GtkIconSize size) { - GtkImagePriv *priv; + GtkImagePrivate *priv; g_return_if_fail (GTK_IS_IMAGE (image)); priv = image->priv; g_object_freeze_notify (G_OBJECT (image)); - + if (icon_set) gtk_icon_set_ref (icon_set); @@ -1135,14 +953,8 @@ gtk_image_set_from_icon_set (GtkImage *image, if (icon_set) { - priv->storage_type = GTK_IMAGE_ICON_SET; - - priv->data.icon_set.icon_set = icon_set; - priv->icon_size = size; - - /* Size is demand-computed in size request method - * if we're an icon set - */ + _gtk_icon_helper_set_icon_set (priv->icon_helper, icon_set, size); + gtk_icon_set_unref (icon_set); } g_object_notify (G_OBJECT (image), "icon-set"); @@ -1163,7 +975,7 @@ void gtk_image_set_from_animation (GtkImage *image, GdkPixbufAnimation *animation) { - GtkImagePriv *priv; + GtkImagePrivate *priv; g_return_if_fail (GTK_IS_IMAGE (image)); g_return_if_fail (animation == NULL || @@ -1180,15 +992,8 @@ gtk_image_set_from_animation (GtkImage *image, if (animation != NULL) { - priv->storage_type = GTK_IMAGE_ANIMATION; - - priv->data.anim.anim = animation; - priv->data.anim.frame_timeout = 0; - priv->data.anim.iter = NULL; - - gtk_image_update_size (image, - gdk_pixbuf_animation_get_width (animation), - gdk_pixbuf_animation_get_height (animation)); + _gtk_icon_helper_set_animation (priv->icon_helper, animation); + g_object_unref (animation); } g_object_notify (G_OBJECT (image), "pixbuf-animation"); @@ -1211,8 +1016,8 @@ gtk_image_set_from_icon_name (GtkImage *image, const gchar *icon_name, GtkIconSize size) { + GtkImagePrivate *priv; gchar *new_name; - GtkImagePriv *priv; g_return_if_fail (GTK_IS_IMAGE (image)); @@ -1220,22 +1025,13 @@ gtk_image_set_from_icon_name (GtkImage *image, g_object_freeze_notify (G_OBJECT (image)); - /* in case icon_name == priv->data.name.icon_name */ new_name = g_strdup (icon_name); - gtk_image_clear (image); if (new_name) { - priv->storage_type = GTK_IMAGE_ICON_NAME; - - priv->data.name.icon_name = new_name; - priv->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 - */ + _gtk_icon_helper_set_icon_name (priv->icon_helper, new_name, size); + g_free (new_name); } g_object_notify (G_OBJECT (image), "icon-name"); @@ -1259,7 +1055,7 @@ gtk_image_set_from_gicon (GtkImage *image, GIcon *icon, GtkIconSize size) { - GtkImagePriv *priv; + GtkImagePrivate *priv; g_return_if_fail (GTK_IS_IMAGE (image)); @@ -1267,23 +1063,15 @@ gtk_image_set_from_gicon (GtkImage *image, g_object_freeze_notify (G_OBJECT (image)); - /* in case icon == priv->data.gicon.icon */ if (icon) g_object_ref (icon); - + gtk_image_clear (image); if (icon) { - priv->storage_type = GTK_IMAGE_GICON; - - priv->data.gicon.icon = icon; - priv->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 - */ + _gtk_icon_helper_set_gicon (priv->icon_helper, icon, size); + g_object_unref (icon); } g_object_notify (G_OBJECT (image), "gicon"); @@ -1307,77 +1095,7 @@ gtk_image_get_storage_type (GtkImage *image) { g_return_val_if_fail (GTK_IS_IMAGE (image), GTK_IMAGE_EMPTY); - return image->priv->storage_type; -} - -/** - * gtk_image_get_pixmap: - * @image: a #GtkImage - * @pixmap: (out) (transfer none) (allow-none): location to store the - * pixmap, or %NULL - * @mask: (out) (transfer none) (allow-none): location to store the - * mask, or %NULL - * - * Gets the pixmap and mask being displayed by the #GtkImage. - * The storage type of the image must be %GTK_IMAGE_EMPTY or - * %GTK_IMAGE_PIXMAP (see gtk_image_get_storage_type()). - * The caller of this function does not own a reference to the - * returned pixmap and mask. - **/ -void -gtk_image_get_pixmap (GtkImage *image, - GdkPixmap **pixmap, - GdkBitmap **mask) -{ - GtkImagePriv *priv; - - g_return_if_fail (GTK_IS_IMAGE (image)); - - priv = image->priv; - - g_return_if_fail (priv->storage_type == GTK_IMAGE_PIXMAP || - priv->storage_type == GTK_IMAGE_EMPTY); - - if (pixmap) - *pixmap = priv->data.pixmap.pixmap; - - if (mask) - *mask = priv->mask; -} - -/** - * gtk_image_get_image: - * @image: a #GtkImage - * @gdk_image: (out) (transfer none) (allow-none): return location for - * a #GtkImage, or %NULL - * @mask: (out) (transfer none) (allow-none): return location for a - * #GdkBitmap, or %NULL - * - * Gets the #GdkImage and mask being displayed by the #GtkImage. - * The storage type of the image must be %GTK_IMAGE_EMPTY or - * %GTK_IMAGE_IMAGE (see gtk_image_get_storage_type()). - * The caller of this function does not own a reference to the - * returned image and mask. - **/ -void -gtk_image_get_image (GtkImage *image, - GdkImage **gdk_image, - GdkBitmap **mask) -{ - GtkImagePriv *priv; - - g_return_if_fail (GTK_IS_IMAGE (image)); - - priv = image->priv; - - g_return_if_fail (priv->storage_type == GTK_IMAGE_IMAGE || - priv->storage_type == GTK_IMAGE_EMPTY); - - if (gdk_image) - *gdk_image = priv->data.image.image; - - if (mask) - *mask = priv->mask; + return _gtk_icon_helper_get_storage_type (image->priv->icon_helper); } /** @@ -1396,19 +1114,9 @@ gtk_image_get_image (GtkImage *image, GdkPixbuf* gtk_image_get_pixbuf (GtkImage *image) { - GtkImagePriv *priv; - g_return_val_if_fail (GTK_IS_IMAGE (image), NULL); - priv = image->priv; - - g_return_val_if_fail (priv->storage_type == GTK_IMAGE_PIXBUF || - priv->storage_type == GTK_IMAGE_EMPTY, NULL); - - if (priv->storage_type == GTK_IMAGE_EMPTY) - priv->data.pixbuf.pixbuf = NULL; - - return priv->data.pixbuf.pixbuf; + return _gtk_icon_helper_peek_pixbuf (image->priv->icon_helper); } /** @@ -1430,23 +1138,17 @@ gtk_image_get_stock (GtkImage *image, gchar **stock_id, GtkIconSize *size) { - GtkImagePriv *priv; + GtkImagePrivate *priv; g_return_if_fail (GTK_IS_IMAGE (image)); priv = image->priv; - g_return_if_fail (priv->storage_type == GTK_IMAGE_STOCK || - priv->storage_type == GTK_IMAGE_EMPTY); - - if (priv->storage_type == GTK_IMAGE_EMPTY) - priv->data.stock.stock_id = NULL; - if (stock_id) - *stock_id = priv->data.stock.stock_id; + *stock_id = (gchar *) _gtk_icon_helper_get_stock_id (priv->icon_helper); if (size) - *size = priv->icon_size; + *size = _gtk_icon_helper_get_icon_size (priv->icon_helper); } /** @@ -1466,20 +1168,17 @@ gtk_image_get_icon_set (GtkImage *image, GtkIconSet **icon_set, GtkIconSize *size) { - GtkImagePriv *priv; + GtkImagePrivate *priv; g_return_if_fail (GTK_IS_IMAGE (image)); priv = image->priv; - g_return_if_fail (priv->storage_type == GTK_IMAGE_ICON_SET || - priv->storage_type == GTK_IMAGE_EMPTY); - if (icon_set) - *icon_set = priv->data.icon_set.icon_set; + *icon_set = _gtk_icon_helper_peek_icon_set (priv->icon_helper); if (size) - *size = priv->icon_size; + *size = _gtk_icon_helper_get_icon_size (priv->icon_helper); } /** @@ -1498,20 +1197,13 @@ gtk_image_get_icon_set (GtkImage *image, GdkPixbufAnimation* gtk_image_get_animation (GtkImage *image) { - GtkImagePriv *priv; + GtkImagePrivate *priv; g_return_val_if_fail (GTK_IS_IMAGE (image), NULL); priv = image->priv; - g_return_val_if_fail (priv->storage_type == GTK_IMAGE_ANIMATION || - priv->storage_type == GTK_IMAGE_EMPTY, - NULL); - - if (priv->storage_type == GTK_IMAGE_EMPTY) - priv->data.anim.anim = NULL; - - return priv->data.anim.anim; + return _gtk_icon_helper_peek_animation (priv->icon_helper); } /** @@ -1531,27 +1223,21 @@ gtk_image_get_animation (GtkImage *image) * Since: 2.6 **/ void -gtk_image_get_icon_name (GtkImage *image, - G_CONST_RETURN gchar **icon_name, - GtkIconSize *size) +gtk_image_get_icon_name (GtkImage *image, + const gchar **icon_name, + GtkIconSize *size) { - GtkImagePriv *priv; + GtkImagePrivate *priv; g_return_if_fail (GTK_IS_IMAGE (image)); priv = image->priv; - g_return_if_fail (priv->storage_type == GTK_IMAGE_ICON_NAME || - priv->storage_type == GTK_IMAGE_EMPTY); - - if (priv->storage_type == GTK_IMAGE_EMPTY) - priv->data.name.icon_name = NULL; - if (icon_name) - *icon_name = priv->data.name.icon_name; + *icon_name = _gtk_icon_helper_get_icon_name (priv->icon_helper); if (size) - *size = priv->icon_size; + *size = _gtk_icon_helper_get_icon_size (priv->icon_helper); } /** @@ -1575,23 +1261,17 @@ gtk_image_get_gicon (GtkImage *image, GIcon **gicon, GtkIconSize *size) { - GtkImagePriv *priv; + GtkImagePrivate *priv; g_return_if_fail (GTK_IS_IMAGE (image)); priv = image->priv; - g_return_if_fail (priv->storage_type == GTK_IMAGE_GICON || - priv->storage_type == GTK_IMAGE_EMPTY); - - if (priv->storage_type == GTK_IMAGE_EMPTY) - priv->data.gicon.icon = NULL; - if (gicon) - *gicon = priv->data.gicon.icon; + *gicon = _gtk_icon_helper_peek_gicon (priv->icon_helper); if (size) - *size = priv->icon_size; + *size = _gtk_icon_helper_get_icon_size (priv->icon_helper); } /** @@ -1610,23 +1290,18 @@ gtk_image_new (void) static void gtk_image_reset_anim_iter (GtkImage *image) { - GtkImagePriv *priv = image->priv; + GtkImagePrivate *priv = image->priv; - if (priv->storage_type == GTK_IMAGE_ANIMATION) + if (gtk_image_get_storage_type (image) == GTK_IMAGE_ANIMATION) { /* Reset the animation */ - - if (priv->data.anim.frame_timeout) + if (priv->animation_timeout) { - g_source_remove (priv->data.anim.frame_timeout); - priv->data.anim.frame_timeout = 0; + g_source_remove (priv->animation_timeout); + priv->animation_timeout = 0; } - if (priv->data.anim.iter) - { - g_object_unref (priv->data.anim.iter); - priv->data.anim.iter = NULL; - } + g_clear_object (&priv->animation_iter); } } @@ -1650,609 +1325,125 @@ static gint animation_timeout (gpointer data) { GtkImage *image = GTK_IMAGE (data); - GtkImagePriv *priv = image->priv; + GtkImagePrivate *priv = image->priv; int delay; - priv->data.anim.frame_timeout = 0; + priv->animation_timeout = 0; - gdk_pixbuf_animation_iter_advance (priv->data.anim.iter, NULL); + gdk_pixbuf_animation_iter_advance (priv->animation_iter, NULL); - delay = gdk_pixbuf_animation_iter_get_delay_time (priv->data.anim.iter); + delay = gdk_pixbuf_animation_iter_get_delay_time (priv->animation_iter); if (delay >= 0) { - priv->data.anim.frame_timeout = - gdk_threads_add_timeout (delay, animation_timeout, image); + GtkWidget *widget = GTK_WIDGET (image); - gtk_widget_queue_draw (GTK_WIDGET (image)); + priv->animation_timeout = + gdk_threads_add_timeout (delay, animation_timeout, image); - if (gtk_widget_is_drawable (GTK_WIDGET (image))) - gdk_window_process_updates (GTK_WIDGET (image)->window, TRUE); + gtk_widget_queue_draw (widget); } return FALSE; } -static void -icon_theme_changed (GtkImage *image) +static GdkPixbuf * +get_animation_frame (GtkImage *image) { - GtkImagePriv *priv = image->priv; + GtkImagePrivate *priv = image->priv; - if (priv->storage_type == GTK_IMAGE_ICON_NAME) + if (priv->animation_iter == NULL) { - if (priv->data.name.pixbuf) - g_object_unref (priv->data.name.pixbuf); - priv->data.name.pixbuf = NULL; + int delay; - gtk_widget_queue_draw (GTK_WIDGET (image)); - } - if (priv->storage_type == GTK_IMAGE_GICON) - { - if (priv->data.gicon.pixbuf) - g_object_unref (priv->data.gicon.pixbuf); - priv->data.gicon.pixbuf = NULL; + priv->animation_iter = + gdk_pixbuf_animation_get_iter (_gtk_icon_helper_peek_animation (priv->icon_helper), NULL); - gtk_widget_queue_draw (GTK_WIDGET (image)); + delay = gdk_pixbuf_animation_iter_get_delay_time (priv->animation_iter); + if (delay >= 0) + priv->animation_timeout = + gdk_threads_add_timeout (delay, animation_timeout, image); } -} -static void -ensure_pixbuf_for_icon_name (GtkImage *image, - GtkStateType state) -{ - GtkImagePriv *priv = image->priv; - GdkScreen *screen; - GtkIconTheme *icon_theme; - GtkSettings *settings; - gint width, height; - gint *sizes, *s, dist; - GtkIconInfo *info; - GtkIconLookupFlags flags; - - g_return_if_fail (priv->storage_type == GTK_IMAGE_ICON_NAME); - - screen = gtk_widget_get_screen (GTK_WIDGET (image)); - icon_theme = gtk_icon_theme_get_for_screen (screen); - settings = gtk_settings_get_for_screen (screen); - flags = GTK_ICON_LOOKUP_USE_BUILTIN; - if (priv->data.name.pixbuf == NULL || - (priv->was_symbolic && priv->last_rendered_state != state)) - { - priv->last_rendered_state = state; - if (priv->data.name.pixbuf) - { - g_object_unref (priv->data.name.pixbuf); - priv->data.name.pixbuf = NULL; - } - if (priv->pixel_size != -1) - { - width = height = priv->pixel_size; - flags |= GTK_ICON_LOOKUP_FORCE_SIZE; - } - else if (!gtk_icon_size_lookup_for_settings (settings, - priv->icon_size, - &width, &height)) - { - if (priv->icon_size == -1) - { - /* Find an available size close to 48 */ - sizes = gtk_icon_theme_get_icon_sizes (icon_theme, priv->data.name.icon_name); - dist = 100; - width = height = 48; - for (s = sizes; *s; s++) - { - if (*s == -1) - { - width = height = 48; - break; - } - if (*s < 48) - { - if (48 - *s < dist) - { - width = height = *s; - dist = 48 - *s; - } - } - else - { - if (*s - 48 < dist) - { - width = height = *s; - dist = *s - 48; - } - } - } - g_free (sizes); - } - else - { - g_warning ("Invalid icon size %d\n", priv->icon_size); - width = height = 24; - } - } - - info = gtk_icon_theme_lookup_icon (icon_theme, - priv->data.name.icon_name, - MIN (width, height), flags); - if (info) - { - GtkStyle *style; - gboolean was_symbolic; - - style = gtk_widget_get_style (GTK_WIDGET (image)); - priv->data.name.pixbuf = - gtk_icon_info_load_symbolic_for_style (info, - style, state, - &was_symbolic, - NULL); - priv->was_symbolic = was_symbolic; - gtk_icon_info_free (info); - } - - if (priv->data.name.pixbuf == NULL) - { - priv->data.name.pixbuf = - gtk_widget_render_icon (GTK_WIDGET (image), - GTK_STOCK_MISSING_IMAGE, - priv->icon_size, - NULL); - priv->was_symbolic = FALSE; - } - } + /* don't advance the anim iter here, or we could get frame changes between two + * exposes of different areas. + */ + return g_object_ref (gdk_pixbuf_animation_iter_get_pixbuf (priv->animation_iter)); } static void -ensure_pixbuf_for_gicon (GtkImage *image, - GtkStateType state) +gtk_image_get_preferred_size (GtkImage *image, + gint *width_out, + gint *height_out) { - GtkImagePriv *priv = image->priv; - GdkScreen *screen; - GtkIconTheme *icon_theme; - GtkSettings *settings; + GtkImagePrivate *priv = image->priv; gint width, height; - GtkIconInfo *info; - GtkIconLookupFlags flags; + GtkBorder border; + GtkStyleContext *context; - g_return_if_fail (priv->storage_type == GTK_IMAGE_GICON); + context = gtk_widget_get_style_context (GTK_WIDGET (image)); + _gtk_icon_helper_get_size (priv->icon_helper, context, &width, &height); + _gtk_misc_get_padding_and_border (GTK_MISC (image), &border); - screen = gtk_widget_get_screen (GTK_WIDGET (image)); - icon_theme = gtk_icon_theme_get_for_screen (screen); - settings = gtk_settings_get_for_screen (screen); - flags = GTK_ICON_LOOKUP_USE_BUILTIN; - if (priv->data.gicon.pixbuf == NULL || - (priv->was_symbolic && priv->last_rendered_state != state)) - { - priv->last_rendered_state = state; - if (priv->data.gicon.pixbuf) - { - g_object_unref (priv->data.gicon.pixbuf); - priv->data.gicon.pixbuf = NULL; - } - if (priv->pixel_size != -1) - { - width = height = priv->pixel_size; - flags |= GTK_ICON_LOOKUP_FORCE_SIZE; - } - else if (!gtk_icon_size_lookup_for_settings (settings, - priv->icon_size, - &width, &height)) - { - if (priv->icon_size == -1) - width = height = 48; - else - { - g_warning ("Invalid icon size %d\n", priv->icon_size); - width = height = 24; - } - } - - info = gtk_icon_theme_lookup_by_gicon (icon_theme, - priv->data.gicon.icon, - MIN (width, height), flags); - if (info) - { - GtkStyle *style; - gboolean was_symbolic; - - style = gtk_widget_get_style (GTK_WIDGET (image)); - priv->data.gicon.pixbuf = - gtk_icon_info_load_symbolic_for_style (info, - style, state, - &was_symbolic, - NULL); - priv->was_symbolic = was_symbolic; - gtk_icon_info_free (info); - } - - if (priv->data.gicon.pixbuf == NULL) - { - priv->data.gicon.pixbuf = - gtk_widget_render_icon (GTK_WIDGET (image), - GTK_STOCK_MISSING_IMAGE, - priv->icon_size, - NULL); - priv->was_symbolic = FALSE; - } - } -} - - -/* - * Like gdk_rectangle_intersect (dest, src, dest), but make - * sure that the origin of dest is moved by an "even" offset. - * If necessary grow the intersection by one row or column - * to achieve this. - * - * This is necessary since we can't pass alignment information - * for the pixelation pattern down to gdk_pixbuf_saturate_and_pixelate(), - * thus we have to makesure that the subimages are properly aligned. - */ -static gboolean -rectangle_intersect_even (GdkRectangle *src, - GdkRectangle *dest) -{ - gboolean isect; - gint x, y; - - x = dest->x; - y = dest->y; - isect = gdk_rectangle_intersect (dest, src, dest); + width += border.left + border.right; + height += border.top + border.bottom; - if ((dest->x - x + dest->y - y) % 2 != 0) - { - if (dest->x > x) - { - dest->x--; - dest->width++; - } - else - { - dest->y--; - dest->height++; - } - } - - return isect; + if (width_out) + *width_out = width; + if (height_out) + *height_out = height; } static gint -gtk_image_expose (GtkWidget *widget, - GdkEventExpose *event) +gtk_image_draw (GtkWidget *widget, + cairo_t *cr) { GtkImage *image; - GtkImagePriv *priv; + GtkImagePrivate *priv; + GtkMisc *misc; + GtkStyleContext *context; + gint x, y, width, height; + gfloat xalign, yalign; + GtkBorder border; g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); image = GTK_IMAGE (widget); + misc = GTK_MISC (image); priv = image->priv; - - if (gtk_widget_get_mapped (widget) && - priv->storage_type != GTK_IMAGE_EMPTY) - { - GtkMisc *misc; - GdkRectangle area, image_bound; - gint x, y, mask_x, mask_y; - gint xpad, ypad; - gfloat xalign, yalign; - GdkBitmap *mask; - GdkPixbuf *pixbuf; - GtkStateType state; - gboolean needs_state_transform; - - misc = GTK_MISC (widget); - area = event->area; - - /* For stock items and icon sets, we lazily calculate - * the size; we might get here between a queue_resize() - * and size_request() if something explicitely forces - * a redraw. - */ - if (priv->need_calc_size) - gtk_image_calc_size (image); - - if (!gdk_rectangle_intersect (&area, &widget->allocation, &area)) - return FALSE; - - gtk_misc_get_alignment (misc, &xalign, &yalign); - gtk_misc_get_padding (misc, &xpad, &ypad); - - if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR) - xalign = 1.0 - xalign; - - x = floor (widget->allocation.x + xpad - + ((widget->allocation.width - widget->requisition.width) * xalign)); - y = floor (widget->allocation.y + ypad - + ((widget->allocation.height - widget->requisition.height) * yalign)); - mask_x = x; - mask_y = y; - - image_bound.x = x; - image_bound.y = y; - image_bound.width = 0; - image_bound.height = 0; - - mask = NULL; - pixbuf = NULL; - needs_state_transform = gtk_widget_get_state (widget) != GTK_STATE_NORMAL; - - switch (priv->storage_type) - { - case GTK_IMAGE_PIXMAP: - mask = priv->mask; - gdk_drawable_get_size (priv->data.pixmap.pixmap, - &image_bound.width, - &image_bound.height); - if (rectangle_intersect_even (&area, &image_bound) && - needs_state_transform) - { - pixbuf = gdk_pixbuf_get_from_drawable (NULL, - priv->data.pixmap.pixmap, - gtk_widget_get_colormap (widget), - image_bound.x - x, image_bound.y - y, - 0, 0, - image_bound.width, - image_bound.height); - - x = image_bound.x; - y = image_bound.y; - } - - break; - - case GTK_IMAGE_IMAGE: - mask = priv->mask; - image_bound.width = priv->data.image.image->width; - image_bound.height = priv->data.image.image->height; - - if (rectangle_intersect_even (&area, &image_bound) && - needs_state_transform) - { - pixbuf = gdk_pixbuf_get_from_image (NULL, - priv->data.image.image, - gtk_widget_get_colormap (widget), - image_bound.x - x, image_bound.y - y, - 0, 0, - image_bound.width, - image_bound.height); - - x = image_bound.x; - y = image_bound.y; - } - break; - - case GTK_IMAGE_PIXBUF: - image_bound.width = gdk_pixbuf_get_width (priv->data.pixbuf.pixbuf); - image_bound.height = gdk_pixbuf_get_height (priv->data.pixbuf.pixbuf); - - if (rectangle_intersect_even (&area, &image_bound) && - needs_state_transform) - { - pixbuf = gdk_pixbuf_new_subpixbuf (priv->data.pixbuf.pixbuf, - image_bound.x - x, image_bound.y - y, - image_bound.width, image_bound.height); - - x = image_bound.x; - y = image_bound.y; - } - else - { - pixbuf = priv->data.pixbuf.pixbuf; - g_object_ref (pixbuf); - } - break; - - case GTK_IMAGE_STOCK: - pixbuf = gtk_widget_render_icon (widget, - priv->data.stock.stock_id, - priv->icon_size, - NULL); - if (pixbuf) - { - image_bound.width = gdk_pixbuf_get_width (pixbuf); - image_bound.height = gdk_pixbuf_get_height (pixbuf); - } - - /* already done */ - needs_state_transform = FALSE; - break; - - case GTK_IMAGE_ICON_SET: - pixbuf = - gtk_icon_set_render_icon (priv->data.icon_set.icon_set, - widget->style, - gtk_widget_get_direction (widget), - gtk_widget_get_state (widget), - priv->icon_size, - widget, - NULL); - - if (pixbuf) - { - image_bound.width = gdk_pixbuf_get_width (pixbuf); - image_bound.height = gdk_pixbuf_get_height (pixbuf); - } - - /* already done */ - needs_state_transform = FALSE; - break; - - case GTK_IMAGE_ANIMATION: - { - if (priv->data.anim.iter == NULL) - { - priv->data.anim.iter = gdk_pixbuf_animation_get_iter (priv->data.anim.anim, NULL); - - if (gdk_pixbuf_animation_iter_get_delay_time (priv->data.anim.iter) >= 0) - priv->data.anim.frame_timeout = - gdk_threads_add_timeout (gdk_pixbuf_animation_iter_get_delay_time (priv->data.anim.iter), - animation_timeout, - image); - } - - image_bound.width = gdk_pixbuf_animation_get_width (priv->data.anim.anim); - image_bound.height = gdk_pixbuf_animation_get_height (priv->data.anim.anim); - - /* don't advance the anim iter here, or we could get frame changes between two - * exposes of different areas. - */ - - pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (priv->data.anim.iter); - g_object_ref (pixbuf); - } - break; - - case GTK_IMAGE_ICON_NAME: - state = gtk_widget_get_state (widget); - if (state == GTK_STATE_INSENSITIVE) - { - ensure_pixbuf_for_icon_name (image, GTK_STATE_NORMAL); - } - else - { - ensure_pixbuf_for_icon_name (image, state); - /* Already done by the loading function? */ - if (priv->was_symbolic) - needs_state_transform = FALSE; - } - pixbuf = priv->data.name.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_GICON: - state = gtk_widget_get_state (widget); - if (state == GTK_STATE_INSENSITIVE) - { - ensure_pixbuf_for_gicon (image, GTK_STATE_NORMAL); - } - else - { - ensure_pixbuf_for_gicon (image, state); - /* Already done by the loading function? */ - if (priv->was_symbolic) - needs_state_transform = FALSE; - } - pixbuf = priv->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; - } - if (rectangle_intersect_even (&area, &image_bound)) - { - if (pixbuf) - { - if (needs_state_transform) - { - GtkIconSource *source; - GdkPixbuf *rendered; - - source = gtk_icon_source_new (); - gtk_icon_source_set_pixbuf (source, pixbuf); - /* The size here is arbitrary; since size isn't - * wildcarded in the souce, it isn't supposed to be - * scaled by the engine function - */ - gtk_icon_source_set_size (source, - GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_icon_source_set_size_wildcarded (source, FALSE); - - rendered = gtk_style_render_icon (widget->style, - source, - gtk_widget_get_direction (widget), - gtk_widget_get_state (widget), - /* arbitrary */ - (GtkIconSize)-1, - widget, - "gtk-image"); - - gtk_icon_source_free (source); - - g_object_unref (pixbuf); - pixbuf = rendered; - } - - if (pixbuf) - { - cairo_t *cr = gdk_cairo_create (widget->window); - gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y); - gdk_cairo_rectangle (cr, &image_bound); - cairo_fill (cr); - cairo_destroy (cr); - } - } - else - { - cairo_t *cr; - cairo_pattern_t *mask_pattern; - - switch (priv->storage_type) - { - case GTK_IMAGE_PIXMAP: - cr = gdk_cairo_create (widget->window); - - if (mask) - { - /* hack to get the mask pattern */ - gdk_cairo_set_source_pixmap (cr, mask, mask_x, mask_y); - mask_pattern = cairo_get_source (cr); - cairo_pattern_reference (mask_pattern); - - gdk_cairo_set_source_pixmap (cr, priv->data.pixmap.pixmap, x, y); - gdk_cairo_rectangle (cr, &image_bound); - cairo_clip (cr); - cairo_mask (cr, mask_pattern); - } - else - { - gdk_cairo_set_source_pixmap (cr, priv->data.pixmap.pixmap, x, y); - gdk_cairo_rectangle (cr, &image_bound); - cairo_fill (cr); - } - - cairo_destroy (cr); - break; - - case GTK_IMAGE_IMAGE: - gdk_draw_image (widget->window, - widget->style->black_gc, - priv->data.image.image, - image_bound.x - x, image_bound.y - y, - image_bound.x, image_bound.y, - image_bound.width, image_bound.height); - break; - - case GTK_IMAGE_PIXBUF: - case GTK_IMAGE_STOCK: - case GTK_IMAGE_ICON_SET: - case GTK_IMAGE_ANIMATION: - case GTK_IMAGE_ICON_NAME: - case GTK_IMAGE_EMPTY: - case GTK_IMAGE_GICON: - g_assert_not_reached (); - break; - } - } - } /* if rectangle intersects */ - - if (pixbuf) - g_object_unref (pixbuf); - - } /* if widget is drawable */ + context = gtk_widget_get_style_context (widget); + + gtk_render_background (context, cr, + 0, 0, + gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget)); + gtk_render_frame (context, cr, + 0, 0, + gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget)); + + gtk_misc_get_alignment (misc, &xalign, &yalign); + gtk_image_get_preferred_size (image, &width, &height); + _gtk_misc_get_padding_and_border (misc, &border); + + if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR) + xalign = 1.0 - xalign; + + x = floor ((gtk_widget_get_allocated_width (widget) - width) * xalign) + border.left; + y = floor ((gtk_widget_get_allocated_height (widget) - height) * yalign) + border.top; + + if (gtk_image_get_storage_type (image) == GTK_IMAGE_ANIMATION) + { + GdkPixbuf *pixbuf = get_animation_frame (image); + gtk_render_icon (context, cr, + pixbuf, + x, y); + g_object_unref (pixbuf); + } + else + { + _gtk_icon_helper_draw (priv->icon_helper, + context, cr, + x, y); + } return FALSE; } @@ -2260,112 +1451,41 @@ gtk_image_expose (GtkWidget *widget, static void gtk_image_reset (GtkImage *image) { - GtkImagePriv *priv = image->priv; + GtkImagePrivate *priv = image->priv; + GtkImageType storage_type; g_object_freeze_notify (G_OBJECT (image)); + storage_type = gtk_image_get_storage_type (image); - if (priv->storage_type != GTK_IMAGE_EMPTY) + if (storage_type != GTK_IMAGE_EMPTY) g_object_notify (G_OBJECT (image), "storage-type"); - if (priv->mask) - { - g_object_unref (priv->mask); - priv->mask = NULL; - g_object_notify (G_OBJECT (image), "mask"); - } - - if (priv->icon_size != DEFAULT_ICON_SIZE) - { - priv->icon_size = DEFAULT_ICON_SIZE; - g_object_notify (G_OBJECT (image), "icon-size"); - } + g_object_notify (G_OBJECT (image), "icon-size"); - switch (priv->storage_type) + switch (storage_type) { - case GTK_IMAGE_PIXMAP: - - if (priv->data.pixmap.pixmap) - g_object_unref (priv->data.pixmap.pixmap); - priv->data.pixmap.pixmap = NULL; - - g_object_notify (G_OBJECT (image), "pixmap"); - - break; - - case GTK_IMAGE_IMAGE: - - if (priv->data.image.image) - g_object_unref (priv->data.image.image); - priv->data.image.image = NULL; - - g_object_notify (G_OBJECT (image), "image"); - - break; - case GTK_IMAGE_PIXBUF: - - if (priv->data.pixbuf.pixbuf) - g_object_unref (priv->data.pixbuf.pixbuf); - g_object_notify (G_OBJECT (image), "pixbuf"); - break; - case GTK_IMAGE_STOCK: - - g_free (priv->data.stock.stock_id); - - priv->data.stock.stock_id = NULL; - g_object_notify (G_OBJECT (image), "stock"); break; - case GTK_IMAGE_ICON_SET: - if (priv->data.icon_set.icon_set) - gtk_icon_set_unref (priv->data.icon_set.icon_set); - priv->data.icon_set.icon_set = NULL; - g_object_notify (G_OBJECT (image), "icon-set"); break; - case GTK_IMAGE_ANIMATION: - gtk_image_reset_anim_iter (image); - - if (priv->data.anim.anim) - g_object_unref (priv->data.anim.anim); - priv->data.anim.anim = NULL; - + gtk_image_reset_anim_iter (image); g_object_notify (G_OBJECT (image), "pixbuf-animation"); - break; - case GTK_IMAGE_ICON_NAME: - g_free (priv->data.name.icon_name); - priv->data.name.icon_name = NULL; - if (priv->data.name.pixbuf) - g_object_unref (priv->data.name.pixbuf); - priv->data.name.pixbuf = NULL; - g_object_notify (G_OBJECT (image), "icon-name"); - break; - case GTK_IMAGE_GICON: - if (priv->data.gicon.icon) - g_object_unref (priv->data.gicon.icon); - priv->data.gicon.icon = NULL; - if (priv->data.gicon.pixbuf) - g_object_unref (priv->data.gicon.pixbuf); - priv->data.gicon.pixbuf = NULL; - g_object_notify (G_OBJECT (image), "gicon"); - break; - case GTK_IMAGE_EMPTY: default: break; - } if (priv->filename) @@ -2375,9 +1495,14 @@ gtk_image_reset (GtkImage *image) g_object_notify (G_OBJECT (image), "file"); } - priv->storage_type = GTK_IMAGE_EMPTY; + if (priv->resource_path) + { + g_free (priv->resource_path); + priv->resource_path = NULL; + g_object_notify (G_OBJECT (image), "resource"); + } - memset (&priv->data, '\0', sizeof (priv->data)); + _gtk_icon_helper_clear (priv->icon_helper); g_object_thaw_notify (G_OBJECT (image)); } @@ -2393,99 +1518,49 @@ gtk_image_reset (GtkImage *image) void gtk_image_clear (GtkImage *image) { - GtkImagePriv *priv = image->priv; - - priv->need_calc_size = 1; - gtk_image_reset (image); - gtk_image_update_size (image, 0, 0); + + if (gtk_widget_get_visible (GTK_WIDGET (image))) + gtk_widget_queue_resize (GTK_WIDGET (image)); } static void -gtk_image_calc_size (GtkImage *image) +gtk_image_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) { - GtkWidget *widget = GTK_WIDGET (image); - GtkImagePriv *priv = image->priv; - GdkPixbuf *pixbuf = NULL; - - priv->need_calc_size = 0; - - /* We update stock/icon set on every size request, because - * the theme could have affected the size; for other kinds of - * image, we just update the requisition when the image data - * is set. - */ - switch (priv->storage_type) - { - case GTK_IMAGE_STOCK: - pixbuf = gtk_widget_render_icon (widget, - priv->data.stock.stock_id, - priv->icon_size, - NULL); - break; - - case GTK_IMAGE_ICON_SET: - pixbuf = gtk_icon_set_render_icon (priv->data.icon_set.icon_set, - widget->style, - gtk_widget_get_direction (widget), - gtk_widget_get_state (widget), - priv->icon_size, - widget, - NULL); - break; - case GTK_IMAGE_ICON_NAME: - ensure_pixbuf_for_icon_name (image, GTK_STATE_NORMAL); - pixbuf = priv->data.name.pixbuf; - if (pixbuf) g_object_ref (pixbuf); - break; - case GTK_IMAGE_GICON: - ensure_pixbuf_for_gicon (image, GTK_STATE_NORMAL); - pixbuf = priv->data.gicon.pixbuf; - if (pixbuf) - g_object_ref (pixbuf); - break; - default: - break; - } + gint width; - if (pixbuf) - { - gint xpad, ypad; - - gtk_misc_get_padding (GTK_MISC (image), &xpad, &ypad); + gtk_image_get_preferred_size (GTK_IMAGE (widget), &width, NULL); + *minimum = *natural = width; +} - widget->requisition.width = gdk_pixbuf_get_width (pixbuf) + xpad * 2; - widget->requisition.height = gdk_pixbuf_get_height (pixbuf) + ypad * 2; +static void +gtk_image_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + gint height; - g_object_unref (pixbuf); - } + gtk_image_get_preferred_size (GTK_IMAGE (widget), NULL, &height); + *minimum = *natural = height; } static void -gtk_image_size_request (GtkWidget *widget, - GtkRequisition *requisition) +icon_theme_changed (GtkImage *image) { - GtkImage *image; - - image = GTK_IMAGE (widget); + GtkImagePrivate *priv = image->priv; - gtk_image_calc_size (image); - - /* Chain up to default that simply reads current requisition */ - GTK_WIDGET_CLASS (gtk_image_parent_class)->size_request (widget, requisition); + _gtk_icon_helper_invalidate (priv->icon_helper); + gtk_widget_queue_draw (GTK_WIDGET (image)); } static void -gtk_image_style_set (GtkWidget *widget, - GtkStyle *prev_style) +gtk_image_style_updated (GtkWidget *widget) { - GtkImage *image; + GTK_WIDGET_CLASS (gtk_image_parent_class)->style_updated (widget); - image = GTK_IMAGE (widget); - - GTK_WIDGET_CLASS (gtk_image_parent_class)->style_set (widget, prev_style); - - icon_theme_changed (image); + icon_theme_changed (GTK_IMAGE (widget)); } static void @@ -2502,25 +1577,21 @@ gtk_image_screen_changed (GtkWidget *widget, icon_theme_changed (image); } - -static void -gtk_image_update_size (GtkImage *image, - gint image_width, - gint image_height) +void +_gtk_image_gicon_data_clear (GtkImageGIconData *data) { - GtkWidget *widget = GTK_WIDGET (image); - gint xpad, ypad; - - gtk_misc_get_padding (GTK_MISC (image), &xpad, &ypad); - - widget->requisition.width = image_width + xpad * 2; - widget->requisition.height = image_height + ypad * 2; - - if (gtk_widget_get_visible (widget)) - gtk_widget_queue_resize (widget); + if (data->pixbuf) + { + g_object_unref (data->pixbuf); + data->pixbuf = NULL; + } + if (data->icon) + { + g_object_unref (data->icon); + data->icon = NULL; + } } - /** * gtk_image_set_pixel_size: * @image: a #GtkImage @@ -2536,38 +1607,21 @@ void gtk_image_set_pixel_size (GtkImage *image, gint pixel_size) { - GtkImagePriv *priv; + GtkImagePrivate *priv; + gint old_pixel_size; g_return_if_fail (GTK_IS_IMAGE (image)); priv = image->priv; + old_pixel_size = gtk_image_get_pixel_size (image); - if (priv->pixel_size != pixel_size) + if (pixel_size != old_pixel_size) { - priv->pixel_size = pixel_size; - - if (priv->storage_type == GTK_IMAGE_ICON_NAME) - { - if (priv->data.name.pixbuf) - { - g_object_unref (priv->data.name.pixbuf); - priv->data.name.pixbuf = NULL; - } - - gtk_image_update_size (image, pixel_size, pixel_size); - } - - if (priv->storage_type == GTK_IMAGE_GICON) - { - if (priv->data.gicon.pixbuf) - { - g_object_unref (priv->data.gicon.pixbuf); - priv->data.gicon.pixbuf = NULL; - } - - gtk_image_update_size (image, pixel_size, pixel_size); - } - + _gtk_icon_helper_set_pixel_size (priv->icon_helper, pixel_size); + + if (gtk_widget_get_visible (GTK_WIDGET (image))) + gtk_widget_queue_resize (GTK_WIDGET (image)); + g_object_notify (G_OBJECT (image), "pixel-size"); } } @@ -2587,37 +1641,5 @@ gtk_image_get_pixel_size (GtkImage *image) { g_return_val_if_fail (GTK_IS_IMAGE (image), -1); - return image->priv->pixel_size; -} - -#if defined (G_OS_WIN32) && !defined (_WIN64) - -#undef gtk_image_new_from_file - -GtkWidget* -gtk_image_new_from_file (const gchar *filename) -{ - gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL); - GtkWidget *retval; - - retval = gtk_image_new_from_file_utf8 (utf8_filename); - - g_free (utf8_filename); - - return retval; -} - -#undef gtk_image_set_from_file - -void -gtk_image_set_from_file (GtkImage *image, - const gchar *filename) -{ - gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL); - - gtk_image_set_from_file_utf8 (image, utf8_filename); - - g_free (utf8_filename); + return _gtk_icon_helper_get_pixel_size (image->priv->icon_helper); } - -#endif