[libadwaita/wip/exalm/avatar-paintable: 3/3] avatar: Replace image load func with paintables
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libadwaita/wip/exalm/avatar-paintable: 3/3] avatar: Replace image load func with paintables
- Date: Mon, 26 Apr 2021 09:58:31 +0000 (UTC)
commit 39312ba6c703ef2bb08e16ea77de245329423765
Author: Alexander Mikhaylenko <alexm gnome org>
Date: Mon Apr 26 14:49:37 2021 +0500
avatar: Replace image load func with paintables
Introduce #AdwAvatar:custom-image. The original motivation for having image
load functions was to make it work with HiDPI which paintables already can
do.
Since then, libhandy has introduced a GLoadableIcon-based API to allow
async loading, but paintables are generic enough that it should be possible
to implement it as well.
examples/adw-demo-window.c | 42 +++--------
src/adw-avatar.c | 180 ++++++++++++++++-----------------------------
src/adw-avatar.h | 22 +-----
3 files changed, 78 insertions(+), 166 deletions(-)
---
diff --git a/examples/adw-demo-window.c b/examples/adw-demo-window.c
index 90f8572..54bac18 100644
--- a/examples/adw-demo-window.c
+++ b/examples/adw-demo-window.c
@@ -234,37 +234,7 @@ avatar_file_remove_cb (AdwDemoWindow *self)
gtk_label_set_label (self->avatar_file_chooser_label, _("(None)"));
gtk_widget_set_sensitive (GTK_WIDGET (self->avatar_remove_button), FALSE);
- adw_avatar_set_image_load_func (self->avatar, NULL, NULL, NULL);
-}
-
-static GdkPixbuf *
-avatar_load_file (int size, AdwDemoWindow *self)
-{
- g_autoptr (GError) error = NULL;
- g_autoptr (GdkPixbuf) pixbuf = NULL;
- g_autoptr (GFile) file = NULL;
- g_autofree char *filename = NULL;
- int width, height;
-
- g_assert (ADW_IS_DEMO_WINDOW (self));
-
- file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (self->avatar_file_chooser));
- filename = g_file_get_path (file);
-
- gdk_pixbuf_get_file_info (filename, &width, &height);
-
- pixbuf = gdk_pixbuf_new_from_file_at_scale (filename,
- (width <= height) ? size : -1,
- (width >= height) ? size : -1,
- TRUE,
- &error);
- if (error != NULL) {
- g_critical ("Failed to create pixbuf from file: %s", error->message);
-
- return NULL;
- }
-
- return g_steal_pointer (&pixbuf);
+ adw_avatar_set_custom_image (self->avatar, NULL);
}
static void
@@ -273,6 +243,8 @@ avatar_file_chooser_response_cb (AdwDemoWindow *self,
{
g_autoptr (GFile) file = NULL;
g_autoptr (GFileInfo) info = NULL;
+ g_autoptr (GdkTexture) texture = NULL;
+ g_autoptr (GError) error = NULL;
g_assert (ADW_IS_DEMO_WINDOW (self));
@@ -291,7 +263,13 @@ avatar_file_chooser_response_cb (AdwDemoWindow *self,
g_file_info_get_display_name (info));
gtk_widget_set_sensitive (GTK_WIDGET (self->avatar_remove_button), TRUE);
- adw_avatar_set_image_load_func (self->avatar, (AdwAvatarImageLoadFunc) avatar_load_file, self, NULL);
+
+ texture = gdk_texture_new_from_file (file, &error);
+
+ if (error)
+ g_critical ("Failed to create texture from file: %s", error->message);
+
+ adw_avatar_set_custom_image (self->avatar, texture ? GDK_PAINTABLE (texture) : NULL);
}
static void
diff --git a/src/adw-avatar.c b/src/adw-avatar.c
index 3eaa201..4a67d4b 100644
--- a/src/adw-avatar.c
+++ b/src/adw-avatar.c
@@ -29,34 +29,7 @@
* The color is picked based on the hash of the #AdwAvatar:text.
* If #AdwAvatar:show-initials is set to %FALSE, `avatar-default-symbolic` is
* shown in place of the initials.
- * Use adw_avatar_set_image_load_func () to set a custom image.
- * Create a #AdwAvatarImageLoadFunc similar to this example:
- *
- * |[<!-- language="C" -->
- * static GdkPixbuf *
- * image_load_func (int size, gpointer user_data)
- * {
- * g_autoptr (GError) error = NULL;
- * g_autoptr (GdkPixbuf) pixbuf = NULL;
- * g_autofree char *file = gtk_file_chooser_get_filename ("avatar.png");
- * int width, height;
- *
- * gdk_pixbuf_get_file_info (file, &width, &height);
- *
- * pixbuf = gdk_pixbuf_new_from_file_at_scale (file,
- * (width <= height) ? size : -1,
- * (width >= height) ? size : -1,
- * TRUE,
- * error);
- * if (error != NULL) {
- * g_critical ("Failed to create pixbuf from file: %s", error->message);
- *
- * return NULL;
- * }
- *
- * return pixbuf;
- * }
- * ]|
+ * Use #AdwAvatar:custom-image to set a custom image.
*
* # CSS nodes
*
@@ -79,12 +52,7 @@ struct _AdwAvatar
gboolean show_initials;
guint color_class;
int size;
- GdkTexture *texture;
- int round_image_size;
-
- AdwAvatarImageLoadFunc load_image_func;
- gpointer load_image_func_target;
- GDestroyNotify load_image_func_target_destroy_notify;
+ GdkPaintable *custom_paintable;
};
G_DEFINE_TYPE (AdwAvatar, adw_avatar, GTK_TYPE_WIDGET);
@@ -94,6 +62,7 @@ enum {
PROP_ICON_NAME,
PROP_TEXT,
PROP_SHOW_INITIALS,
+ PROP_CUSTOM_IMAGE,
PROP_SIZE,
PROP_LAST_PROP,
};
@@ -130,7 +99,7 @@ extract_initials_from_text (const char *text)
static void
update_visibility (AdwAvatar *self)
{
- gboolean has_custom_image = self->texture != NULL;
+ gboolean has_custom_image = self->custom_paintable != NULL;
gboolean has_initials = self->show_initials && self->text && strlen (self->text);
gtk_widget_set_visible (GTK_WIDGET (self->label), !has_custom_image && has_initials);
@@ -138,53 +107,6 @@ update_visibility (AdwAvatar *self)
gtk_widget_set_visible (GTK_WIDGET (self->custom_image), has_custom_image);
}
-static void
-update_custom_image (AdwAvatar *self,
- int width,
- int height,
- int scale_factor)
-{
- g_autoptr (GdkPixbuf) pixbuf = NULL;
- int new_size;
-
- new_size = MIN (width, height) * scale_factor;
-
- if (self->round_image_size != new_size && self->texture != NULL) {
- self->round_image_size = -1;
- }
- g_clear_object (&self->texture);
-
- if (self->load_image_func != NULL && self->texture == NULL) {
- pixbuf = self->load_image_func (new_size, self->load_image_func_target);
- if (pixbuf != NULL) {
- if (width != height) {
- GdkPixbuf *subpixbuf;
-
- subpixbuf = gdk_pixbuf_new_subpixbuf (pixbuf,
- (width - new_size) / 2,
- (height - new_size) / 2,
- new_size,
- new_size);
-
- g_object_unref (pixbuf);
-
- pixbuf = subpixbuf;
- }
-
- self->texture = gdk_texture_new_for_pixbuf (pixbuf);
- self->round_image_size = new_size;
- }
- }
-
- if (self->texture)
- gtk_widget_add_css_class (self->gizmo, "image");
- else
- gtk_widget_remove_css_class (self->gizmo, "image");
-
- gtk_image_set_from_paintable (self->custom_image, GDK_PAINTABLE (self->texture));
- update_visibility (self);
-}
-
static void
set_class_color (AdwAvatar *self)
{
@@ -212,7 +134,7 @@ update_initials (AdwAvatar *self)
{
g_autofree char *initials = NULL;
- if (self->texture != NULL ||
+ if (self->custom_paintable != NULL ||
!self->show_initials ||
self->text == NULL ||
strlen (self->text) == 0)
@@ -242,7 +164,7 @@ update_font_size (AdwAvatar *self)
double new_font_size;
PangoAttrList *attributes;
- if (self->texture != NULL ||
+ if (self->custom_paintable != NULL ||
!self->show_initials ||
self->text == NULL ||
strlen (self->text) == 0)
@@ -291,7 +213,11 @@ adw_avatar_get_property (GObject *object,
g_value_set_boolean (value, adw_avatar_get_show_initials (self));
break;
- case PROP_SIZE:
+ case PROP_CUSTOM_IMAGE:
+ g_value_set_object (value, adw_avatar_get_custom_image (self));
+ break;
+
+ case PROP_SIZE:
g_value_set_int (value, adw_avatar_get_size (self));
break;
@@ -322,6 +248,10 @@ adw_avatar_set_property (GObject *object,
adw_avatar_set_show_initials (self, g_value_get_boolean (value));
break;
+ case PROP_CUSTOM_IMAGE:
+ adw_avatar_set_custom_image (self, g_value_get_object (value));
+ break;
+
case PROP_SIZE:
adw_avatar_set_size (self, g_value_get_int (value));
break;
@@ -353,10 +283,7 @@ adw_avatar_finalize (GObject *object)
g_clear_pointer (&self->icon_name, g_free);
g_clear_pointer (&self->text, g_free);
- g_clear_object (&self->texture);
-
- if (self->load_image_func_target_destroy_notify != NULL)
- self->load_image_func_target_destroy_notify (self->load_image_func_target);
+ g_clear_object (&self->custom_paintable);
G_OBJECT_CLASS (adw_avatar_parent_class)->finalize (object);
}
@@ -420,6 +347,18 @@ adw_avatar_class_init (AdwAvatarClass *klass)
FALSE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+ /**
+ * AdwAvatar:custom-image:
+ *
+ * Since: 1.0
+ */
+ props[PROP_CUSTOM_IMAGE] =
+ g_param_spec_object ("custom-image",
+ "Custom image",
+ "TODO we need a blurb",
+ GDK_TYPE_PAINTABLE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
/**
* AdwAvatar:size:
*
@@ -464,7 +403,6 @@ adw_avatar_init (AdwAvatar *self)
update_icon (self);
update_visibility (self);
- g_signal_connect (self, "notify::scale-factor", G_CALLBACK (update_custom_image), NULL);
g_signal_connect (self, "notify::root", G_CALLBACK (update_font_size), NULL);
}
@@ -641,37 +579,53 @@ adw_avatar_set_show_initials (AdwAvatar *self,
}
/**
- * adw_avatar_set_image_load_func:
+ * adw_avatar_get_custom_image
+ * @self: a #AdwAvatar
+ *
+ * Returns a TODO
+ *
+ * Returns: (nullable) (transfer none): TODO
+ *
+ * Since: 1.0
+ */
+GdkPaintable *
+adw_avatar_get_custom_image (AdwAvatar *self)
+{
+ g_return_val_if_fail (ADW_IS_AVATAR (self), NULL);
+
+ return self->custom_paintable;
+}
+
+/**
+ * adw_avatar_set_custom_image:
* @self: a #AdwAvatar
- * @load_image: (closure user_data) (nullable): callback to set a custom image
- * @user_data: (nullable): user data passed to @load_image
- * @destroy: (nullable): destroy notifier for @user_data
+ * @custom_image: (nullable) (transfer none): TODO
*
- * A callback which is called when the custom image need to be reloaded for some
- * reason (e.g. scale-factor changes).
+ * TODO
*
* Since: 1.0
*/
void
-adw_avatar_set_image_load_func (AdwAvatar *self,
- AdwAvatarImageLoadFunc load_image,
- gpointer user_data,
- GDestroyNotify destroy)
+adw_avatar_set_custom_image (AdwAvatar *self,
+ GdkPaintable *custom_image)
{
g_return_if_fail (ADW_IS_AVATAR (self));
- g_return_if_fail (user_data != NULL || (user_data == NULL && destroy == NULL));
+ g_return_if_fail (GDK_IS_PAINTABLE (custom_image) || custom_image == NULL);
- if (self->load_image_func_target_destroy_notify != NULL)
- self->load_image_func_target_destroy_notify (self->load_image_func_target);
+ if (self->custom_paintable == custom_image)
+ return;
- self->load_image_func = load_image;
- self->load_image_func_target = user_data;
- self->load_image_func_target_destroy_notify = destroy;
+ g_set_object (&self->custom_paintable, custom_image);
- update_custom_image (self,
- gtk_widget_get_width (GTK_WIDGET (self)),
- gtk_widget_get_height (GTK_WIDGET (self)),
- gtk_widget_get_scale_factor (GTK_WIDGET (self)));
+ if (self->custom_paintable)
+ gtk_widget_add_css_class (self->gizmo, "image");
+ else
+ gtk_widget_remove_css_class (self->gizmo, "image");
+
+ gtk_image_set_from_paintable (self->custom_image, custom_image);
+ update_visibility (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CUSTOM_IMAGE]);
}
/**
@@ -722,10 +676,6 @@ adw_avatar_set_size (AdwAvatar *self,
gtk_widget_remove_css_class (self->gizmo, "contrasted");
update_font_size (self);
- update_custom_image (self,
- gtk_widget_get_width (GTK_WIDGET (self)),
- gtk_widget_get_height (GTK_WIDGET (self)),
- gtk_widget_get_scale_factor (GTK_WIDGET (self)));
gtk_widget_queue_resize (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SIZE]);
@@ -758,8 +708,6 @@ adw_avatar_draw_to_pixbuf (AdwAvatar *self,
g_return_val_if_fail (size > 0, NULL);
g_return_val_if_fail (scale_factor > 0, NULL);
- update_custom_image (self, size, size, scale_factor);
-
snapshot = gtk_snapshot_new ();
GTK_WIDGET_GET_CLASS (self)->snapshot (GTK_WIDGET (self), snapshot);
diff --git a/src/adw-avatar.h b/src/adw-avatar.h
index 6069122..ab5682e 100644
--- a/src/adw-avatar.h
+++ b/src/adw-avatar.h
@@ -22,20 +22,6 @@ G_BEGIN_DECLS
ADW_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (AdwAvatar, adw_avatar, ADW, AVATAR, GtkWidget)
-/**
- * AdwAvatarImageLoadFunc:
- * @size: the required size of the avatar
- * @user_data: (closure): user data
- *
- * The returned #GdkPixbuf is expected to be square with width and height set
- * to @size. The image is cropped to a circle without any scaling or transformation.
- *
- * Returns: (nullable) (transfer full): the #GdkPixbuf to use as a custom avatar
- * or %NULL to fallback to the generated avatar.
- */
-typedef GdkPixbuf *(*AdwAvatarImageLoadFunc) (int size,
- gpointer user_data);
-
ADW_AVAILABLE_IN_ALL
GtkWidget *adw_avatar_new (int size,
const char *text,
@@ -60,10 +46,10 @@ void adw_avatar_set_show_initials (AdwAvatar *self,
gboolean show_initials);
ADW_AVAILABLE_IN_ALL
-void adw_avatar_set_image_load_func (AdwAvatar *self,
- AdwAvatarImageLoadFunc load_image,
- gpointer user_data,
- GDestroyNotify destroy);
+GdkPaintable *adw_avatar_get_custom_image (AdwAvatar *self);
+ADW_AVAILABLE_IN_ALL
+void adw_avatar_set_custom_image (AdwAvatar *self,
+ GdkPaintable *custom_image);
ADW_AVAILABLE_IN_ALL
int adw_avatar_get_size (AdwAvatar *self);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]