diff options
-rw-r--r-- | gtk/gtkcellrendererpixbuf.c | 3 | ||||
-rw-r--r-- | gtk/gtkentry.c | 1 | ||||
-rw-r--r-- | gtk/gtkiconhelper.c | 85 | ||||
-rw-r--r-- | gtk/gtkiconhelperprivate.h | 3 | ||||
-rw-r--r-- | gtk/gtkimage.c | 137 | ||||
-rw-r--r-- | gtk/gtkimage.h | 12 | ||||
-rw-r--r-- | gtk/gtkimagedefinition.c | 40 | ||||
-rw-r--r-- | gtk/gtkimagedefinitionprivate.h | 2 |
8 files changed, 270 insertions, 13 deletions
diff --git a/gtk/gtkcellrendererpixbuf.c b/gtk/gtkcellrendererpixbuf.c index 3d0efa9054..cd042c9a70 100644 --- a/gtk/gtkcellrendererpixbuf.c +++ b/gtk/gtkcellrendererpixbuf.c @@ -297,6 +297,9 @@ notify_storage_type (GtkCellRendererPixbuf *cellpixbuf, case GTK_IMAGE_TEXTURE: g_object_notify (G_OBJECT (cellpixbuf), "texture"); break; + case GTK_IMAGE_PAINTABLE: + g_object_notify (G_OBJECT (cellpixbuf), "paintable"); + break; case GTK_IMAGE_ICON_NAME: g_object_notify (G_OBJECT (cellpixbuf), "icon-name"); break; diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index d038aeaf6e..1275820484 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -6556,6 +6556,7 @@ gtk_entry_clear_icon (GtkEntry *entry, break; case GTK_IMAGE_SURFACE: + case GTK_IMAGE_PAINTABLE: case GTK_IMAGE_EMPTY: default: g_assert_not_reached (); diff --git a/gtk/gtkiconhelper.c b/gtk/gtkiconhelper.c index ddc58e803b..3f9eee4454 100644 --- a/gtk/gtkiconhelper.c +++ b/gtk/gtkiconhelper.c @@ -269,6 +269,16 @@ ensure_paintable_from_texture (GtkIconHelper *self, } static GdkPaintable * +ensure_paintable_from_paintable (GtkIconHelper *self, + GdkPaintable *paintable, + int *scale) +{ + *scale = 1; + + return g_object_ref (paintable); +} + +static GdkPaintable * ensure_paintable_for_gicon (GtkIconHelper *self, GtkCssStyle *style, GtkTextDirection dir, @@ -326,6 +336,11 @@ gtk_icon_helper_load_paintable (GtkIconHelper *self, symbolic = FALSE; break; + case GTK_IMAGE_PAINTABLE: + paintable = ensure_paintable_from_paintable (self, gtk_image_definition_get_paintable (self->def), &scale); + symbolic = FALSE; + break; + case GTK_IMAGE_ICON_NAME: scale = gtk_widget_get_scale_factor (self->owner); if (self->use_fallback) @@ -379,6 +394,43 @@ gtk_icon_helper_ensure_paintable (GtkIconHelper *self) self->texture_is_symbolic = symbolic; } +static void +get_size_for_paintable (GtkIconHelper *self, + GdkPaintable *paintable, + int *width_out, + int *height_out) +{ + int width = gdk_paintable_get_intrinsic_width (paintable); + int height = gdk_paintable_get_intrinsic_height (paintable); + + if (width == 0) + { + if (height != 0) + { + double ar = gdk_paintable_get_intrinsic_aspect_ratio (paintable); + + if (ar > 0) + width = ceil (height * ar); + } + } + else + { + if (height == 0) + { + double ar = gdk_paintable_get_intrinsic_aspect_ratio (paintable); + + if (ar > 0) + height = ceil (width / ar); + } + } + + if (width == 0 || height == 0) + ensure_icon_size (self, &width, &height); + + *width_out = width; + *height_out = height; +} + void _gtk_icon_helper_get_size (GtkIconHelper *self, gint *width_out, @@ -413,6 +465,14 @@ _gtk_icon_helper_get_size (GtkIconHelper *self, } break; + case GTK_IMAGE_PAINTABLE: + { + GdkPaintable *paintable = gtk_image_definition_get_paintable (self->def); + + get_size_for_paintable (self, paintable, &width, &height); + } + break; + case GTK_IMAGE_EMPTY: default: break; @@ -425,17 +485,7 @@ _gtk_icon_helper_get_size (GtkIconHelper *self, if (self->paintable != NULL) { - width = gdk_paintable_get_intrinsic_width (self->paintable); - height = gdk_paintable_get_intrinsic_height (self->paintable); - if (width == 0 || height == 0) - { - ensure_icon_size (self, &width, &height); - } - else - { - width = (width + self->texture_scale - 1) / self->texture_scale; - height = (height + self->texture_scale - 1) / self->texture_scale; - } + get_size_for_paintable (self, self->paintable, &width, &height); } else { @@ -487,6 +537,13 @@ _gtk_icon_helper_set_texture (GtkIconHelper *self, gtk_icon_helper_take_definition (self, gtk_image_definition_new_texture (texture)); } +void +_gtk_icon_helper_set_paintable (GtkIconHelper *self, + GdkPaintable *paintable) +{ + gtk_icon_helper_take_definition (self, gtk_image_definition_new_paintable (paintable)); +} + gboolean _gtk_icon_helper_set_pixel_size (GtkIconHelper *self, gint pixel_size) @@ -555,6 +612,12 @@ _gtk_icon_helper_peek_texture (GtkIconHelper *self) return gtk_image_definition_get_texture (self->def); } +GdkPaintable * +_gtk_icon_helper_peek_paintable (GtkIconHelper *self) +{ + return gtk_image_definition_get_paintable (self->def); +} + const gchar * _gtk_icon_helper_get_icon_name (GtkIconHelper *self) { diff --git a/gtk/gtkiconhelperprivate.h b/gtk/gtkiconhelperprivate.h index 6c39294cae..6fd794b70b 100644 --- a/gtk/gtkiconhelperprivate.h +++ b/gtk/gtkiconhelperprivate.h @@ -69,6 +69,8 @@ void _gtk_icon_helper_set_surface (GtkIconHelper *self, cairo_surface_t *surface); void _gtk_icon_helper_set_texture (GtkIconHelper *self, GdkTexture *texture); +void _gtk_icon_helper_set_paintable (GtkIconHelper *self, + GdkPaintable *paintable); gboolean _gtk_icon_helper_set_pixel_size (GtkIconHelper *self, gint pixel_size); @@ -82,6 +84,7 @@ gboolean _gtk_icon_helper_get_use_fallback (GtkIconHelper *self); GIcon *_gtk_icon_helper_peek_gicon (GtkIconHelper *self); cairo_surface_t *_gtk_icon_helper_peek_surface (GtkIconHelper *self); GdkTexture *_gtk_icon_helper_peek_texture (GtkIconHelper *self); +GdkPaintable *_gtk_icon_helper_peek_paintable (GtkIconHelper *self); GtkImageDefinition *gtk_icon_helper_get_definition (GtkIconHelper *self); const gchar *_gtk_icon_helper_get_icon_name (GtkIconHelper *self); diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c index 31ae0a4d38..7deb8b70d3 100644 --- a/gtk/gtkimage.c +++ b/gtk/gtkimage.c @@ -119,6 +119,7 @@ enum { PROP_0, PROP_SURFACE, + PROP_PAINTABLE, PROP_TEXTURE, PROP_FILE, PROP_ICON_SIZE, @@ -161,6 +162,13 @@ gtk_image_class_init (GtkImageClass *class) CAIRO_GOBJECT_TYPE_SURFACE, GTK_PARAM_READWRITE); + image_props[PROP_PAINTABLE] = + g_param_spec_object ("paintable", + P_("Paintable"), + P_("A GdkPaintable to display"), + GDK_TYPE_PAINTABLE, + GTK_PARAM_READWRITE); + image_props[PROP_TEXTURE] = g_param_spec_object ("texture", P_("Texture"), @@ -284,6 +292,8 @@ gtk_image_finalize (GObject *object) GtkImage *image = GTK_IMAGE (object); GtkImagePrivate *priv = gtk_image_get_instance_private (image); + gtk_image_clear (image); + gtk_icon_helper_destroy (&priv->icon_helper); g_free (priv->filename); @@ -306,6 +316,9 @@ gtk_image_set_property (GObject *object, case PROP_SURFACE: gtk_image_set_from_surface (image, g_value_get_boxed (value)); break; + case PROP_PAINTABLE: + gtk_image_set_from_paintable (image, g_value_get_object (value)); + break; case PROP_TEXTURE: gtk_image_set_from_texture (image, g_value_get_object (value)); break; @@ -353,6 +366,9 @@ gtk_image_get_property (GObject *object, case PROP_SURFACE: g_value_set_boxed (value, _gtk_icon_helper_peek_surface (&priv->icon_helper)); break; + case PROP_PAINTABLE: + g_value_set_object (value, _gtk_icon_helper_peek_paintable (&priv->icon_helper)); + break; case PROP_TEXTURE: g_value_set_object (value, _gtk_icon_helper_peek_texture (&priv->icon_helper)); break; @@ -480,6 +496,32 @@ gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf) } /** + * gtk_image_new_from_paintable: + * @paintable: (allow-none): a #GdkPaintable, or %NULL + * + * Creates a new #GtkImage displaying @paintable. + * The #GtkImage does not assume a reference to the + * paintable; you still need to unref it if you own references. + * #GtkImage will add its own reference rather than adopting yours. + * + * The #GtkImage will track changes to the @paintable and update + * its size and contents in response to it. + * + * Returns: a new #GtkImage + **/ +GtkWidget* +gtk_image_new_from_paintable (GdkPaintable *paintable) +{ + GtkImage *image; + + image = g_object_new (GTK_TYPE_IMAGE, NULL); + + gtk_image_set_from_paintable (image, paintable); + + return GTK_WIDGET (image); +} + +/** * gtk_image_new_from_texture: * @texture: (allow-none): a #GdkTexture, or %NULL * @@ -945,6 +987,64 @@ gtk_image_set_from_surface (GtkImage *image, g_object_thaw_notify (G_OBJECT (image)); } +static void +gtk_image_paintable_invalidate_contents (GdkPaintable *paintable, + GtkImage *image) +{ + gtk_widget_queue_draw (GTK_WIDGET (image)); +} + +static void +gtk_image_paintable_invalidate_size (GdkPaintable *paintable, + GtkImage *image) +{ + GtkImagePrivate *priv = gtk_image_get_instance_private (image); + + gtk_icon_helper_invalidate (&priv->icon_helper); +} + +/** + * gtk_image_set_from_paintable: + * @image: a #GtkImage + * @paintable: (nullable): a #GdkPaintable or %NULL + * + * See gtk_image_new_from_paintable() for details. + **/ +void +gtk_image_set_from_paintable (GtkImage *image, + GdkPaintable *paintable) +{ + GtkImagePrivate *priv = gtk_image_get_instance_private (image); + + g_return_if_fail (GTK_IS_IMAGE (image)); + g_return_if_fail (paintable == NULL || GDK_IS_PAINTABLE (paintable)); + + g_object_freeze_notify (G_OBJECT (image)); + + if (paintable) + g_object_ref (paintable); + + gtk_image_clear (image); + + if (paintable) + { + _gtk_icon_helper_set_paintable (&priv->icon_helper, paintable); + g_signal_connect (paintable, + "invalidate-contents", + G_CALLBACK (gtk_image_paintable_invalidate_contents), + image); + g_signal_connect (paintable, + "invalidate-size", + G_CALLBACK (gtk_image_paintable_invalidate_size), + image); + g_object_unref (paintable); + } + + g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_PAINTABLE]); + + g_object_thaw_notify (G_OBJECT (image)); +} + /** * gtk_image_set_from_texture: * @image: a #GtkImage @@ -1023,6 +1123,29 @@ gtk_image_get_surface (GtkImage *image) } /** + * gtk_image_get_paintable: + * @image: a #GtkImage + * + * Gets the image #GdkPaintable being displayed by the #GtkImage. + * The storage type of the image must be %GTK_IMAGE_EMPTY or + * %GTK_IMAGE_PAINTABLE (see gtk_image_get_storage_type()). + * The caller of this function does not own a reference to the + * returned paintable. + * + * Returns: (nullable) (transfer none): the displayed paintable, or %NULL if + * the image is empty + **/ +GdkPaintable * +gtk_image_get_paintable (GtkImage *image) +{ + GtkImagePrivate *priv = gtk_image_get_instance_private (image); + + g_return_val_if_fail (GTK_IS_IMAGE (image), NULL); + + return _gtk_icon_helper_peek_paintable (&priv->icon_helper); +} + +/** * gtk_image_get_texture: * @image: a #GtkImage * @@ -1205,6 +1328,9 @@ gtk_image_notify_for_storage_type (GtkImage *image, case GTK_IMAGE_TEXTURE: g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_TEXTURE]); break; + case GTK_IMAGE_PAINTABLE: + g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_PAINTABLE]); + break; case GTK_IMAGE_EMPTY: default: break; @@ -1277,6 +1403,17 @@ gtk_image_clear (GtkImage *image) g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_RESOURCE]); } + if (storage_type == GTK_IMAGE_PAINTABLE) + { + GdkPaintable *paintable = _gtk_icon_helper_peek_paintable (&priv->icon_helper); + g_signal_handlers_disconnect_by_func (paintable, + gtk_image_paintable_invalidate_contents, + image); + g_signal_handlers_disconnect_by_func (paintable, + gtk_image_paintable_invalidate_size, + image); + } + _gtk_icon_helper_clear (&priv->icon_helper); g_object_thaw_notify (G_OBJECT (image)); diff --git a/gtk/gtkimage.h b/gtk/gtkimage.h index 45ac3f8fd2..10ce7da730 100644 --- a/gtk/gtkimage.h +++ b/gtk/gtkimage.h @@ -59,6 +59,8 @@ typedef struct _GtkImageClass GtkImageClass; * This image type was added in GTK+ 3.10 * @GTK_IMAGE_TEXTURE: the widget contains a #GdkTexture. * This image type was added in GTK+ 3.94 + * @GTK_IMAGE_PAINTABLE: the widget contains a #GdkPaintable. + * This image type was added in GTK+ 3.96 * * Describes the image data representation used by a #GtkImage. If you * want to get the image from the widget, you can only get the @@ -74,7 +76,8 @@ typedef enum GTK_IMAGE_ICON_NAME, GTK_IMAGE_GICON, GTK_IMAGE_SURFACE, - GTK_IMAGE_TEXTURE + GTK_IMAGE_TEXTURE, + GTK_IMAGE_PAINTABLE } GtkImageType; /** @@ -113,6 +116,8 @@ GtkWidget* gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf); GDK_AVAILABLE_IN_ALL GtkWidget* gtk_image_new_from_texture (GdkTexture *texture); GDK_AVAILABLE_IN_ALL +GtkWidget* gtk_image_new_from_paintable (GdkPaintable *paintable); +GDK_AVAILABLE_IN_ALL GtkWidget* gtk_image_new_from_icon_name (const gchar *icon_name); GDK_AVAILABLE_IN_ALL GtkWidget* gtk_image_new_from_gicon (GIcon *icon); @@ -134,6 +139,9 @@ GDK_AVAILABLE_IN_ALL void gtk_image_set_from_texture (GtkImage *image, GdkTexture *texture); GDK_AVAILABLE_IN_ALL +void gtk_image_set_from_paintable (GtkImage *image, + GdkPaintable *paintable); +GDK_AVAILABLE_IN_ALL void gtk_image_set_from_icon_name (GtkImage *image, const gchar *icon_name); GDK_AVAILABLE_IN_ALL @@ -156,6 +164,8 @@ GDK_AVAILABLE_IN_ALL cairo_surface_t *gtk_image_get_surface (GtkImage *image); GDK_AVAILABLE_IN_ALL GdkTexture *gtk_image_get_texture (GtkImage *image); +GDK_AVAILABLE_IN_ALL +GdkPaintable *gtk_image_get_paintable (GtkImage *image); GDK_AVAILABLE_IN_ALL const char *gtk_image_get_icon_name (GtkImage *image); diff --git a/gtk/gtkimagedefinition.c b/gtk/gtkimagedefinition.c index 6c45ca4305..561b2b296e 100644 --- a/gtk/gtkimagedefinition.c +++ b/gtk/gtkimagedefinition.c @@ -24,6 +24,7 @@ typedef struct _GtkImageDefinitionIconName GtkImageDefinitionIconName; typedef struct _GtkImageDefinitionGIcon GtkImageDefinitionGIcon; typedef struct _GtkImageDefinitionSurface GtkImageDefinitionSurface; typedef struct _GtkImageDefinitionTexture GtkImageDefinitionTexture; +typedef struct _GtkImageDefinitionPaintable GtkImageDefinitionPaintable; struct _GtkImageDefinitionEmpty { GtkImageType type; @@ -58,6 +59,13 @@ struct _GtkImageDefinitionTexture { GdkTexture *texture; }; +struct _GtkImageDefinitionPaintable { + GtkImageType type; + gint ref_count; + + GdkPaintable *paintable; +}; + union _GtkImageDefinition { GtkImageType type; @@ -66,6 +74,7 @@ union _GtkImageDefinition GtkImageDefinitionGIcon gicon; GtkImageDefinitionSurface surface; GtkImageDefinitionTexture texture; + GtkImageDefinitionPaintable paintable; }; GtkImageDefinition * @@ -84,7 +93,8 @@ gtk_image_definition_alloc (GtkImageType type) sizeof (GtkImageDefinitionIconName), sizeof (GtkImageDefinitionGIcon), sizeof (GtkImageDefinitionSurface), - sizeof (GtkImageDefinitionTexture) + sizeof (GtkImageDefinitionTexture), + sizeof (GtkImageDefinitionPaintable) }; GtkImageDefinition *def; @@ -154,6 +164,20 @@ gtk_image_definition_new_texture (GdkTexture *texture) } GtkImageDefinition * +gtk_image_definition_new_paintable (GdkPaintable *paintable) +{ + GtkImageDefinition *def; + + if (paintable == NULL) + return NULL; + + def = gtk_image_definition_alloc (GTK_IMAGE_PAINTABLE); + def->paintable.paintable = g_object_ref (paintable); + + return def; +} + +GtkImageDefinition * gtk_image_definition_ref (GtkImageDefinition *def) { def->empty.ref_count++; @@ -181,6 +205,9 @@ gtk_image_definition_unref (GtkImageDefinition *def) case GTK_IMAGE_TEXTURE: g_object_unref (def->texture.texture); break; + case GTK_IMAGE_PAINTABLE: + g_object_unref (def->paintable.paintable); + break; case GTK_IMAGE_ICON_NAME: g_free (def->icon_name.icon_name); break; @@ -208,6 +235,7 @@ gtk_image_definition_get_scale (const GtkImageDefinition *def) case GTK_IMAGE_EMPTY: case GTK_IMAGE_SURFACE: case GTK_IMAGE_TEXTURE: + case GTK_IMAGE_PAINTABLE: case GTK_IMAGE_ICON_NAME: case GTK_IMAGE_GICON: return 1; @@ -249,3 +277,13 @@ gtk_image_definition_get_texture (const GtkImageDefinition *def) return def->texture.texture; } + +GdkPaintable * +gtk_image_definition_get_paintable (const GtkImageDefinition *def) +{ + if (def->type != GTK_IMAGE_PAINTABLE) + return NULL; + + return def->paintable.paintable; +} + diff --git a/gtk/gtkimagedefinitionprivate.h b/gtk/gtkimagedefinitionprivate.h index 2dac974ee8..8cdb26c9e6 100644 --- a/gtk/gtkimagedefinitionprivate.h +++ b/gtk/gtkimagedefinitionprivate.h @@ -30,6 +30,7 @@ GtkImageDefinition * gtk_image_definition_new_icon_name (const char GtkImageDefinition * gtk_image_definition_new_gicon (GIcon *gicon); GtkImageDefinition * gtk_image_definition_new_surface (cairo_surface_t *surface); GtkImageDefinition * gtk_image_definition_new_texture (GdkTexture *texture); +GtkImageDefinition * gtk_image_definition_new_paintable (GdkPaintable *paintable); GtkImageDefinition * gtk_image_definition_ref (GtkImageDefinition *def); void gtk_image_definition_unref (GtkImageDefinition *def); @@ -40,6 +41,7 @@ const gchar * gtk_image_definition_get_icon_name (const GtkImageD GIcon * gtk_image_definition_get_gicon (const GtkImageDefinition *def); cairo_surface_t * gtk_image_definition_get_surface (const GtkImageDefinition *def); GdkTexture * gtk_image_definition_get_texture (const GtkImageDefinition *def); +GdkPaintable * gtk_image_definition_get_paintable (const GtkImageDefinition *def); G_END_DECLS |