/* * Copyright © 2018 Benjamin Otte * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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, see . * * Authors: Benjamin Otte */ #include "config.h" #include "gtkpicture.h" #include "gtkcssnodeprivate.h" #include "gtkcssnumbervalueprivate.h" #include "gtkcssstyleprivate.h" #include "gtkintl.h" #include "gtkprivate.h" #include "gtkscalerprivate.h" #include "gtksnapshot.h" #include "gtkwidgetprivate.h" /** * GtkPicture: * * The `GtkPicture` widget displays a `GdkPaintable`. * * ![An example GtkPicture](picture.png) * * Many convenience functions are provided to make pictures simple to use. * For example, if you want to load an image from a file, and then display * it, there’s a convenience function to do this: * * ```c * GtkWidget *widget = gtk_picture_new_for_filename ("myfile.png"); * ``` * * If the file isn’t loaded successfully, the picture will contain a * “broken image” icon similar to that used in many web browsers. * If you want to handle errors in loading the file yourself, * for example by displaying an error message, then load the image with * [ctor@Gdk.Texture.new_from_file], then create the `GtkPicture` with * [ctor@Gtk.Picture.new_for_paintable]. * * Sometimes an application will want to avoid depending on external data * files, such as image files. See the documentation of `GResource` for details. * In this case, [ctor@Gtk.Picture.new_for_resource] and * [method@Gtk.Picture.set_resource] should be used. * * `GtkPicture` displays an image at its natural size. See [class@Gtk.Image] * if you want to display a fixed-size image, such as an icon. * * ## Sizing the paintable * * You can influence how the paintable is displayed inside the `GtkPicture`. * By turning off [property@Gtk.Picture:keep-aspect-ratio] you can allow the * paintable to get stretched. [property@Gtk.Picture:can-shrink] can be unset * to make sure that paintables are never made smaller than their ideal size - * but be careful if you do not know the size of the paintable in use (like * when displaying user-loaded images). This can easily cause the picture to * grow larger than the screen. And [property@GtkWidget:halign] and * [property@GtkWidget:valign] can be used to make sure the paintable doesn't * fill all available space but is instead displayed at its original size. * * ## CSS nodes * * `GtkPicture` has a single CSS node with the name `picture`. * * ## Accessibility * * `GtkPicture` uses the `GTK_ACCESSIBLE_ROLE_IMG` role. */ enum { PROP_0, PROP_PAINTABLE, PROP_FILE, PROP_ALTERNATIVE_TEXT, PROP_KEEP_ASPECT_RATIO, PROP_CAN_SHRINK, NUM_PROPERTIES }; struct _GtkPicture { GtkWidget parent_instance; GdkPaintable *paintable; GFile *file; char *alternative_text; guint keep_aspect_ratio : 1; guint can_shrink : 1; }; struct _GtkPictureClass { GtkWidgetClass parent_class; }; static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; G_DEFINE_TYPE (GtkPicture, gtk_picture, GTK_TYPE_WIDGET) static void gtk_picture_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { GtkPicture *self = GTK_PICTURE (widget); double ratio; int x, y, width, height; double w, h; if (self->paintable == NULL) return; width = gtk_widget_get_width (widget); height = gtk_widget_get_height (widget); ratio = gdk_paintable_get_intrinsic_aspect_ratio (self->paintable); if (!self->keep_aspect_ratio || ratio == 0) { gdk_paintable_snapshot (self->paintable, snapshot, width, height); } else { double picture_ratio = (double) width / height; if (ratio > picture_ratio) { w = width; h = width / ratio; } else { w = height * ratio; h = height; } x = (width - ceil (w)) / 2; y = floor(height - ceil (h)) / 2; gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y)); gdk_paintable_snapshot (self->paintable, snapshot, w, h); gtk_snapshot_restore (snapshot); } } static GtkSizeRequestMode gtk_picture_get_request_mode (GtkWidget *widget) { return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; } static void gtk_picture_measure (GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline) { GtkPicture *self = GTK_PICTURE (widget); GtkCssStyle *style; double min_width, min_height, nat_width, nat_height; double default_size; if (self->paintable == NULL) { *minimum = 0; *natural = 0; return; } style = gtk_css_node_get_style (gtk_widget_get_css_node (widget)); default_size = _gtk_css_number_value_get (style->icon->icon_size, 100); if (self->can_shrink) { min_width = min_height = 0; } else { gdk_paintable_compute_concrete_size (self->paintable, 0, 0, default_size, default_size, &min_width, &min_height); } if (orientation == GTK_ORIENTATION_HORIZONTAL) { gdk_paintable_compute_concrete_size (self->paintable, 0, for_size < 0 ? 0 : for_size, default_size, default_size, &nat_width, &nat_height); *minimum = ceil (min_width); *natural = ceil (nat_width); } else { gdk_paintable_compute_concrete_size (self->paintable, for_size < 0 ? 0 : for_size, 0, default_size, default_size, &nat_width, &nat_height); *minimum = ceil (min_height); *natural = ceil (nat_height); } } static void gtk_picture_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GtkPicture *self = GTK_PICTURE (object); switch (prop_id) { case PROP_PAINTABLE: gtk_picture_set_paintable (self, g_value_get_object (value)); break; case PROP_FILE: gtk_picture_set_file (self, g_value_get_object (value)); break; case PROP_ALTERNATIVE_TEXT: gtk_picture_set_alternative_text (self, g_value_get_string (value)); break; case PROP_KEEP_ASPECT_RATIO: gtk_picture_set_keep_aspect_ratio (self, g_value_get_boolean (value)); break; case PROP_CAN_SHRINK: gtk_picture_set_can_shrink (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gtk_picture_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GtkPicture *self = GTK_PICTURE (object); switch (prop_id) { case PROP_PAINTABLE: g_value_set_object (value, self->paintable); break; case PROP_FILE: g_value_set_object (value, self->file); break; case PROP_ALTERNATIVE_TEXT: g_value_set_string (value, self->alternative_text); break; case PROP_KEEP_ASPECT_RATIO: g_value_set_boolean (value, self->keep_aspect_ratio); break; case PROP_CAN_SHRINK: g_value_set_boolean (value, self->can_shrink); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gtk_picture_dispose (GObject *object) { GtkPicture *self = GTK_PICTURE (object); gtk_picture_set_paintable (self, NULL); g_clear_object (&self->file); g_clear_pointer (&self->alternative_text, g_free); G_OBJECT_CLASS (gtk_picture_parent_class)->dispose (object); }; static void gtk_picture_class_init (GtkPictureClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); gobject_class->set_property = gtk_picture_set_property; gobject_class->get_property = gtk_picture_get_property; gobject_class->dispose = gtk_picture_dispose; widget_class->snapshot = gtk_picture_snapshot; widget_class->get_request_mode = gtk_picture_get_request_mode; widget_class->measure = gtk_picture_measure; /** * GtkPicture:paintable: (attributes org.gtk.Property.get=gtk_picture_get_paintable org.gtk.Property.set=gtk_picture_set_paintable) * * The `GdkPaintable` to be displayed by this `GtkPicture`. */ properties[PROP_PAINTABLE] = g_param_spec_object ("paintable", P_("Paintable"), P_("The GdkPaintable to display"), GDK_TYPE_PAINTABLE, GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); /** * GtkPicture:file: (attributes org.gtk.Property.get=gtk_picture_get_file org.gtk.Property.set=gtk_picture_set_file) * * The `GFile` that is displayed or %NULL if none. */ properties[PROP_FILE] = g_param_spec_object ("file", P_("File"), P_("File to load and display"), G_TYPE_FILE, GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); /** * GtkPicture:alternative-text: (attributes org.gtk.Property.get=gtk_picture_get_alternative_text org.gtk.Property.set=gtk_picture_set_alternative_text) * * The alternative textual description for the picture. */ properties[PROP_ALTERNATIVE_TEXT] = g_param_spec_string ("alternative-text", P_("Alternative text"), P_("The alternative textual description"), NULL, GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); /** * GtkPicture:keep-aspect-ratio: (attributes org.gtk.Property.get=gtk_picture_get_keep_aspect_ratio org.gtk.Property.set=gtk_picture_set_keep_aspect_ratio) * * Whether the GtkPicture will render its contents trying to preserve the aspect * ratio. */ properties[PROP_KEEP_ASPECT_RATIO] = g_param_spec_boolean ("keep-aspect-ratio", P_("Keep aspect ratio"), P_("Render contents respecting the aspect ratio"), TRUE, GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); /** * GtkPicture:can-shrink: (attributes org.gtk.Property.get=gtk_picture_get_can_shrink org.gtk.Property.set=gtk_picture_set_can_shrink) * * If the `GtkPicture` can be made smaller than the natural size of its contents. */ properties[PROP_CAN_SHRINK] = g_param_spec_boolean ("can-shrink", P_("Can shrink"), P_("Allow self to be smaller than contents"), TRUE, GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); gtk_widget_class_set_css_name (widget_class, I_("picture")); gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_IMG); } static void gtk_picture_init (GtkPicture *self) { self->can_shrink = TRUE; self->keep_aspect_ratio = TRUE; } /** * gtk_picture_new: * * Creates a new empty `GtkPicture` widget. * * Returns: a newly created `GtkPicture` widget. */ GtkWidget* gtk_picture_new (void) { return g_object_new (GTK_TYPE_PICTURE, NULL); } /** * gtk_picture_new_for_paintable: * @paintable: (nullable): a `GdkPaintable`, or %NULL * * Creates a new `GtkPicture` displaying @paintable. * * The `GtkPicture` will track changes to the @paintable and update * its size and contents in response to it. * * Returns: a new `GtkPicture` */ GtkWidget* gtk_picture_new_for_paintable (GdkPaintable *paintable) { g_return_val_if_fail (paintable == NULL || GDK_IS_PAINTABLE (paintable), NULL); return g_object_new (GTK_TYPE_PICTURE, "paintable", paintable, NULL); } /** * gtk_picture_new_for_pixbuf: * @pixbuf: (nullable): a `GdkPixbuf`, or %NULL * * Creates a new `GtkPicture` displaying @pixbuf. * * This is a utility function that calls [ctor@Gtk.Picture.new_for_paintable], * See that function for details. * * The pixbuf must not be modified after passing it to this function. * * Returns: a new `GtkPicture` */ GtkWidget* gtk_picture_new_for_pixbuf (GdkPixbuf *pixbuf) { GtkWidget *result; GdkPaintable *paintable; g_return_val_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf), NULL); if (pixbuf) paintable = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (pixbuf)); else paintable = NULL; result = gtk_picture_new_for_paintable (paintable); if (paintable) g_object_unref (paintable); return result; } /** * gtk_picture_new_for_file: * @file: (nullable): a `GFile` * * Creates a new `GtkPicture` displaying the given @file. * * If the file isn’t found or can’t be loaded, the resulting * `GtkPicture` is empty. * * If you need to detect failures to load the file, use * [ctor@Gdk.Texture.new_from_file] to load the file yourself, * then create the `GtkPicture` from the texture. * * Returns: a new `GtkPicture` */ GtkWidget* gtk_picture_new_for_file (GFile *file) { g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL); return g_object_new (GTK_TYPE_PICTURE, "file", file, NULL); } /** * gtk_picture_new_for_filename: * @filename: (type filename) (nullable): a filename * * Creates a new `GtkPicture` displaying the file @filename. * * This is a utility function that calls [ctor@Gtk.Picture.new_for_file]. * See that function for details. * * Returns: a new `GtkPicture` */ GtkWidget* gtk_picture_new_for_filename (const char *filename) { GtkWidget *result; GFile *file; if (filename) file = g_file_new_for_path (filename); else file = NULL; result = gtk_picture_new_for_file (file); if (file) g_object_unref (file); return result; } /** * gtk_picture_new_for_resource: * @resource_path: (nullable): resource path to play back * * Creates a new `GtkPicture` displaying the resource at @resource_path. * * This is a utility function that calls [ctor@Gtk.Picture.new_for_file]. * See that function for details. * * Returns: a new `GtkPicture` */ GtkWidget * gtk_picture_new_for_resource (const char *resource_path) { GtkWidget *result; GFile *file; if (resource_path) { char *uri, *escaped; escaped = g_uri_escape_string (resource_path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE); uri = g_strconcat ("resource://", escaped, NULL); g_free (escaped); file = g_file_new_for_uri (uri); g_free (uri); } else { file = NULL; } result = gtk_picture_new_for_file (file); if (file) g_object_unref (file); return result; } typedef struct { int scale_factor; } LoaderData; static void on_loader_size_prepared (GdkPixbufLoader *loader, int width, int height, gpointer user_data) { LoaderData *loader_data = user_data; GdkPixbufFormat *format; /* Let the regular icon helper code path handle non-scalable pictures */ format = gdk_pixbuf_loader_get_format (loader); if (!gdk_pixbuf_format_is_scalable (format)) { loader_data->scale_factor = 1; return; } gdk_pixbuf_loader_set_size (loader, width * loader_data->scale_factor, height * loader_data->scale_factor); } static GdkPaintable * load_scalable_with_loader (GFile *file, int scale_factor) { GdkPixbufLoader *loader; GBytes *bytes; GdkPixbufAnimation *animation; GdkPaintable *result, *scaler; LoaderData loader_data; result = NULL; loader = gdk_pixbuf_loader_new (); loader_data.scale_factor = scale_factor; g_signal_connect (loader, "size-prepared", G_CALLBACK (on_loader_size_prepared), &loader_data); bytes = g_file_load_bytes (file, NULL, NULL, NULL); if (bytes == NULL) goto out1; if (!gdk_pixbuf_loader_write_bytes (loader, bytes, NULL)) goto out2; if (!gdk_pixbuf_loader_close (loader, NULL)) goto out2; animation = gdk_pixbuf_loader_get_animation (loader); if (animation == NULL) goto out2; result = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (gdk_pixbuf_animation_get_static_image (animation))); scaler = gtk_scaler_new (result, loader_data.scale_factor); g_object_unref (result); result = scaler; out2: g_bytes_unref (bytes); out1: gdk_pixbuf_loader_close (loader, NULL); g_object_unref (loader); return result; } /** * gtk_picture_set_file: (attributes org.gtk.Method.set_property=file) * @self: a `GtkPicture` * @file: (nullable): a `GFile` or %NULL * * Makes @self load and display @file. * * See [ctor@Gtk.Picture.new_for_file] for details. */ void gtk_picture_set_file (GtkPicture *self, GFile *file) { GdkPaintable *paintable; g_return_if_fail (GTK_IS_PICTURE (self)); g_return_if_fail (file == NULL || G_IS_FILE (file)); if (self->file == file) return; g_object_freeze_notify (G_OBJECT (self)); g_set_object (&self->file, file); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILE]); paintable = load_scalable_with_loader (file, gtk_widget_get_scale_factor (GTK_WIDGET (self))); gtk_picture_set_paintable (self, paintable); g_clear_object (&paintable); g_object_thaw_notify (G_OBJECT (self)); } /** * gtk_picture_get_file: (attributes org.gtk.Method.get_property=file) * @self: a `GtkPicture` * * Gets the `GFile` currently displayed if @self is displaying a file. * * If @self is not displaying a file, for example when * [method@Gtk.Picture.set_paintable] was used, then %NULL is returned. * * Returns: (nullable) (transfer none): The `GFile` displayed by @self. */ GFile * gtk_picture_get_file (GtkPicture *self) { g_return_val_if_fail (GTK_IS_PICTURE (self), FALSE); return self->file; } /** * gtk_picture_set_filename: * @self: a `GtkPicture` * @filename: (nullable): the filename to play * * Makes @self load and display the given @filename. * * This is a utility function that calls [method@Gtk.Picture.set_file]. */ void gtk_picture_set_filename (GtkPicture *self, const char *filename) { GFile *file; g_return_if_fail (GTK_IS_PICTURE (self)); if (filename) file = g_file_new_for_path (filename); else file = NULL; gtk_picture_set_file (self, file); if (file) g_object_unref (file); } /** * gtk_picture_set_resource: * @self: a `GtkPicture` * @resource_path: (nullable): the resource to set * * Makes @self load and display the resource at the given * @resource_path. * * This is a utility function that calls [method@Gtk.Picture.set_file]. */ void gtk_picture_set_resource (GtkPicture *self, const char *resource_path) { GFile *file; g_return_if_fail (GTK_IS_PICTURE (self)); if (resource_path) { char *uri, *escaped; escaped = g_uri_escape_string (resource_path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE); uri = g_strconcat ("resource://", escaped, NULL); g_free (escaped); file = g_file_new_for_uri (uri); g_free (uri); } else { file = NULL; } gtk_picture_set_file (self, file); if (file) g_object_unref (file); } /** * gtk_picture_set_pixbuf: * @self: a `GtkPicture` * @pixbuf: (nullable): a `GdkPixbuf` or %NULL * * Sets a `GtkPicture` to show a `GdkPixbuf`. * * See [ctor@Gtk.Picture.new_for_pixbuf] for details. * * This is a utility function that calls [method@Gtk.Picture.set_paintable]. */ void gtk_picture_set_pixbuf (GtkPicture *self, GdkPixbuf *pixbuf) { GdkTexture *texture; g_return_if_fail (GTK_IS_PICTURE (self)); g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf)); if (pixbuf) texture = gdk_texture_new_for_pixbuf (pixbuf); else texture = NULL; gtk_picture_set_paintable (self, GDK_PAINTABLE (texture)); if (texture) g_object_unref (texture); } static void gtk_picture_paintable_invalidate_contents (GdkPaintable *paintable, GtkPicture *self) { gtk_widget_queue_draw (GTK_WIDGET (self)); } static void gtk_picture_paintable_invalidate_size (GdkPaintable *paintable, GtkPicture *self) { gtk_widget_queue_resize (GTK_WIDGET (self)); } /** * gtk_picture_set_paintable: (attributes org.gtk.Method.set_property=paintable) * @self: a `GtkPicture` * @paintable: (nullable): a `GdkPaintable` or %NULL * * Makes @self display the given @paintable. * * If @paintable is %NULL, nothing will be displayed. * * See [ctor@Gtk.Picture.new_for_paintable] for details. */ void gtk_picture_set_paintable (GtkPicture *self, GdkPaintable *paintable) { g_return_if_fail (GTK_IS_PICTURE (self)); g_return_if_fail (paintable == NULL || GDK_IS_PAINTABLE (paintable)); if (self->paintable == paintable) return; g_object_freeze_notify (G_OBJECT (self)); if (paintable) g_object_ref (paintable); if (self->paintable) { const guint flags = gdk_paintable_get_flags (self->paintable); if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0) g_signal_handlers_disconnect_by_func (self->paintable, gtk_picture_paintable_invalidate_contents, self); if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0) g_signal_handlers_disconnect_by_func (self->paintable, gtk_picture_paintable_invalidate_size, self); g_object_unref (self->paintable); } self->paintable = paintable; if (paintable) { const guint flags = gdk_paintable_get_flags (paintable); if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0) g_signal_connect (paintable, "invalidate-contents", G_CALLBACK (gtk_picture_paintable_invalidate_contents), self); if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0) g_signal_connect (paintable, "invalidate-size", G_CALLBACK (gtk_picture_paintable_invalidate_size), self); } gtk_widget_queue_resize (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PAINTABLE]); g_object_thaw_notify (G_OBJECT (self)); } /** * gtk_picture_get_paintable: (attributes org.gtk.Method.get_property=paintable) * @self: a `GtkPicture` * * Gets the `GdkPaintable` being displayed by the `GtkPicture`. * * Returns: (nullable) (transfer none): the displayed paintable, or %NULL if * the picture is empty */ GdkPaintable * gtk_picture_get_paintable (GtkPicture *self) { g_return_val_if_fail (GTK_IS_PICTURE (self), NULL); return self->paintable; } /** * gtk_picture_set_keep_aspect_ratio: (attributes org.gtk.Method.set_property=keep-aspect-ratio) * @self: a `GtkPicture` * @keep_aspect_ratio: whether to keep aspect ratio * * If set to %TRUE, the @self will render its contents according to * their aspect ratio. * * That means that empty space may show up at the top/bottom or * left/right of @self. * * If set to %FALSE or if the contents provide no aspect ratio, * the contents will be stretched over the picture's whole area. */ void gtk_picture_set_keep_aspect_ratio (GtkPicture *self, gboolean keep_aspect_ratio) { g_return_if_fail (GTK_IS_PICTURE (self)); if (self->keep_aspect_ratio == keep_aspect_ratio) return; self->keep_aspect_ratio = keep_aspect_ratio; g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_KEEP_ASPECT_RATIO]); } /** * gtk_picture_get_keep_aspect_ratio: (attributes org.gtk.Method.get_property=keep-aspect-ratio) * @self: a `GtkPicture` * * Returns whether the `GtkPicture` preserves its contents aspect ratio. * * Returns: %TRUE if the self tries to keep the contents' aspect ratio */ gboolean gtk_picture_get_keep_aspect_ratio (GtkPicture *self) { g_return_val_if_fail (GTK_IS_PICTURE (self), TRUE); return self->keep_aspect_ratio; } /** * gtk_picture_set_can_shrink: (attributes org.gtk.Method.set_property=can-shrink) * @self: a `GtkPicture` * @can_shrink: if @self can be made smaller than its contents * * If set to %TRUE, the @self can be made smaller than its contents. * * The contents will then be scaled down when rendering. * * If you want to still force a minimum size manually, consider using * [method@Gtk.Widget.set_size_request]. * * Also of note is that a similar function for growing does not exist * because the grow behavior can be controlled via * [method@Gtk.Widget.set_halign] and [method@Gtk.Widget.set_valign]. */ void gtk_picture_set_can_shrink (GtkPicture *self, gboolean can_shrink) { g_return_if_fail (GTK_IS_PICTURE (self)); if (self->can_shrink == can_shrink) return; self->can_shrink = can_shrink; g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CAN_SHRINK]); } /** * gtk_picture_get_can_shrink: (attributes org.gtk.Method.get_property=can-shrink) * @self: a `GtkPicture` * * Returns whether the `GtkPicture` respects its contents size. * * Returns: %TRUE if the picture can be made smaller than its contents */ gboolean gtk_picture_get_can_shrink (GtkPicture *self) { g_return_val_if_fail (GTK_IS_PICTURE (self), FALSE); return self->can_shrink; } /** * gtk_picture_set_alternative_text: (attributes org.gtk.Method.set_property=alternative-text) * @self: a `GtkPicture` * @alternative_text: (nullable): a textual description of the contents * * Sets an alternative textual description for the picture contents. * * It is equivalent to the "alt" attribute for images on websites. * * This text will be made available to accessibility tools. * * If the picture cannot be described textually, set this property to %NULL. */ void gtk_picture_set_alternative_text (GtkPicture *self, const char *alternative_text) { g_return_if_fail (GTK_IS_PICTURE (self)); if (g_strcmp0 (self->alternative_text, alternative_text) == 0) return; g_free (self->alternative_text); self->alternative_text = g_strdup (alternative_text); gtk_accessible_update_property (GTK_ACCESSIBLE (self), GTK_ACCESSIBLE_PROPERTY_DESCRIPTION, alternative_text, -1); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ALTERNATIVE_TEXT]); } /** * gtk_picture_get_alternative_text: (attributes org.gtk.Method.get_property=alternative-text) * @self: a `GtkPicture` * * Gets the alternative textual description of the picture. * * The returned string will be %NULL if the picture cannot be described textually. * * Returns: (nullable) (transfer none): the alternative textual description of @self. */ const char * gtk_picture_get_alternative_text (GtkPicture *self) { g_return_val_if_fail (GTK_IS_PICTURE (self), NULL); return self->alternative_text; }