[libhandy] avatar: Add hdy_avatar_draw_to_pixbuf_async
- From: Adrien Plazas <aplazas src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libhandy] avatar: Add hdy_avatar_draw_to_pixbuf_async
- Date: Thu, 11 Feb 2021 09:11:36 +0000 (UTC)
commit 7497ca34634adcea3b4a4c38fde0672b57a9bd1d
Author: Julian Sparber <julian sparber net>
Date: Wed Feb 10 19:40:11 2021 +0100
avatar: Add hdy_avatar_draw_to_pixbuf_async
This function allows to draw an avatar to a pixbuf while loading the
custom avatar async, if there isn't any custom avatar the async call
will return quickly.
debian/libhandy-1-0.symbols | 2 +
src/hdy-avatar.c | 138 ++++++++++++++++++++++++++++++++++++++++++++
src/hdy-avatar.h | 10 ++++
tests/test-avatar.c | 28 +++++++++
4 files changed, 178 insertions(+)
---
diff --git a/debian/libhandy-1-0.symbols b/debian/libhandy-1-0.symbols
index c4f095ad..ad355761 100644
--- a/debian/libhandy-1-0.symbols
+++ b/debian/libhandy-1-0.symbols
@@ -19,6 +19,8 @@ libhandy-1.so.0 libhandy-1-0 #MINVER#
hdy_application_window_get_type@LIBHANDY_1_0 0.80.0
hdy_application_window_new@LIBHANDY_1_0 0.80.0
hdy_avatar_draw_to_pixbuf@LIBHANDY_1_0 1.1.0
+ hdy_avatar_draw_to_pixbuf_async@LIBHANDY_1_0 1.1.0
+ hdy_avatar_draw_to_pixbuf_finish@LIBHANDY_1_0 1.1.0
hdy_avatar_get_icon_name@LIBHANDY_1_0 0.85.0
hdy_avatar_get_show_initials@LIBHANDY_1_0 0.80.0
hdy_avatar_get_size@LIBHANDY_1_0 0.80.0
diff --git a/src/hdy-avatar.c b/src/hdy-avatar.c
index bacbf741..8e78172a 100644
--- a/src/hdy-avatar.c
+++ b/src/hdy-avatar.c
@@ -73,6 +73,17 @@ enum {
};
static GParamSpec *props[PROP_LAST_PROP];
+typedef struct {
+ gint size;
+ gint scale_factor;
+} SizeData;
+
+static void
+size_data_free (SizeData *data)
+{
+ g_slice_free (SizeData, data);
+}
+
static void
load_icon_async (GLoadableIcon *icon,
gint size,
@@ -327,6 +338,27 @@ load_from_gicon_async_for_display_cb (GLoadableIcon *icon,
}
}
+static void
+load_from_gicon_async_for_export_cb (GLoadableIcon *icon,
+ GAsyncResult *res,
+ gpointer *user_data)
+{
+ GTask *task = G_TASK (user_data);
+ g_autoptr (GError) error = NULL;
+ g_autoptr (GdkPixbuf) pixbuf = NULL;
+
+ pixbuf = load_from_gicon_async_finish (res, &error);
+
+ if (!g_error_matches (error, HDY_AVATAR_ICON_ERROR, HDY_AVATAR_ICON_ERROR_EMPTY) &&
+ !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_warning ("Failed to load icon: %s", error->message);
+ }
+
+ g_task_return_pointer (task,
+ g_steal_pointer (&pixbuf),
+ g_object_unref);
+}
+
static void
load_icon_async (GLoadableIcon *icon,
gint size,
@@ -1224,6 +1256,112 @@ hdy_avatar_draw_to_pixbuf (HdyAvatar *self,
bounds.height * scale_factor);
}
+/**
+ * hdy_avatar_draw_to_pixbuf_async:
+ * @self: a #HdyAvatar
+ * @size: The size of the pixbuf
+ * @scale_factor: The scale factor
+ * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the avatar is generated
+ * @user_data: (closure): the data to pass to callback function
+
+ * Renders asynchronously @self into a pixbuf at @size and @scale_factor.
+ * This can be used to export the fallback avatar.
+ *
+ * Since: 1.1
+ */
+void
+hdy_avatar_draw_to_pixbuf_async (HdyAvatar *self,
+ gint size,
+ gint scale_factor,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task = NULL;
+ gint scaled_size = size * scale_factor;
+ SizeData *data;
+
+ g_return_if_fail (HDY_IS_AVATAR (self));
+ g_return_if_fail (size > 0);
+ g_return_if_fail (scale_factor > 0);
+
+ data = g_slice_new (SizeData);
+ data->size = size;
+ data->scale_factor = scale_factor;
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, hdy_avatar_draw_to_pixbuf_async);
+ g_task_set_task_data (task, data, (GDestroyNotify) size_data_free);
+
+ if (get_icon (self) &&
+ (!self->round_image ||
+ gdk_pixbuf_get_width (self->round_image) != scaled_size ||
+ is_scaled (self->round_image)))
+ load_icon_async (get_icon (self),
+ scaled_size,
+ cancellable,
+ (GAsyncReadyCallback) load_from_gicon_async_for_export_cb,
+ task);
+ else
+ g_task_return_pointer (task, NULL, NULL);
+}
+
+/**
+ * hdy_avatar_draw_to_pixbuf_finish:
+ * @self: a #HdyAvatar
+ * @async_result: a #GAsyncResult
+ *
+ * Finishes an asynchronous draw of an avatar to a pixbuf.
+ *
+ * Returns: (transfer full): a #GdkPixbuf
+ *
+ * Since: 1.1
+ */
+GdkPixbuf *
+hdy_avatar_draw_to_pixbuf_finish (HdyAvatar *self,
+ GAsyncResult *async_result)
+{
+ GTask *task;
+ g_autoptr (GdkPixbuf) pixbuf_from_icon = NULL;
+ g_autoptr (GdkPixbuf) custom_image = NULL;
+ g_autoptr (cairo_surface_t) surface = NULL;
+ g_autoptr (cairo_t) cr = NULL;
+ SizeData *data;
+ GtkStyleContext *context;
+ GtkAllocation bounds;
+
+ g_return_val_if_fail (G_IS_TASK (async_result), NULL);
+
+ task = G_TASK (async_result);
+
+ g_warn_if_fail (g_task_get_source_tag (task) == hdy_avatar_draw_to_pixbuf_async);
+
+ data = g_task_get_task_data (task);
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (self));
+ gtk_render_background_get_clip (context, 0, 0, data->size, data->size, &bounds);
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ bounds.width * data->scale_factor,
+ bounds.height * data->scale_factor);
+ cairo_surface_set_device_scale (surface, data->scale_factor, data->scale_factor);
+ cr = cairo_create (surface);
+
+ cairo_translate (cr, -bounds.x, -bounds.y);
+
+ pixbuf_from_icon = g_task_propagate_pointer (task, NULL);
+ custom_image = update_custom_image (get_icon (self),
+ pixbuf_from_icon,
+ NULL,
+ data->size * data->scale_factor);
+ draw_for_size (self, cr, custom_image, data->size, data->size, data->scale_factor);
+
+ return gdk_pixbuf_get_from_surface (surface, 0, 0,
+ bounds.width * data->scale_factor,
+ bounds.height * data->scale_factor);
+}
+
/**
* hdy_avatar_get_loadable_icon:
* @self: a #HdyAvatar
diff --git a/src/hdy-avatar.h b/src/hdy-avatar.h
index 2d3d7cbe..b2c83489 100644
--- a/src/hdy-avatar.h
+++ b/src/hdy-avatar.h
@@ -74,6 +74,16 @@ GdkPixbuf *hdy_avatar_draw_to_pixbuf (HdyAvatar *self,
gint size,
gint scale_factor);
HDY_AVAILABLE_IN_1_1
+void hdy_avatar_draw_to_pixbuf_async (HdyAvatar *self,
+ gint size,
+ gint scale_factor,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+HDY_AVAILABLE_IN_1_1
+GdkPixbuf *hdy_avatar_draw_to_pixbuf_finish (HdyAvatar *self,
+ GAsyncResult *async_result);
+HDY_AVAILABLE_IN_1_1
GLoadableIcon *hdy_avatar_get_loadable_icon (HdyAvatar *self);
HDY_AVAILABLE_IN_1_1
void hdy_avatar_set_loadable_icon (HdyAvatar *self,
diff --git a/tests/test-avatar.c b/tests/test-avatar.c
index b8475e03..edba33e9 100644
--- a/tests/test-avatar.c
+++ b/tests/test-avatar.c
@@ -215,6 +215,33 @@ test_hdy_avatar_draw_to_pixbuf (void)
g_assert_cmpint (gdk_pixbuf_get_height (pixbuf), ==, TEST_SIZE * 2);
}
+static void
+draw_to_pixbuf_async (HdyAvatar *avatar,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr (GdkPixbuf) pixbuf = hdy_avatar_draw_to_pixbuf_finish (avatar, res);
+
+ g_assert_cmpint (gdk_pixbuf_get_width (pixbuf), ==, TEST_SIZE * 2);
+ g_assert_cmpint (gdk_pixbuf_get_height (pixbuf), ==, TEST_SIZE * 2);
+ g_object_unref (avatar);
+}
+
+static void
+test_hdy_avatar_draw_to_pixbuf_async (void)
+{
+ HdyAvatar *avatar = NULL;
+
+ avatar = g_object_ref_sink (HDY_AVATAR (hdy_avatar_new (TEST_SIZE, NULL, TRUE)));
+
+ hdy_avatar_draw_to_pixbuf_async (avatar,
+ TEST_SIZE * 2,
+ 1,
+ NULL,
+ (GAsyncReadyCallback) draw_to_pixbuf_async,
+ NULL);
+}
+
static void
test_hdy_avatar_loadable_icon (void)
{
@@ -251,6 +278,7 @@ main (gint argc,
g_test_add_func ("/Handy/Avatar/text", test_hdy_avatar_text);
g_test_add_func ("/Handy/Avatar/size", test_hdy_avatar_size);
g_test_add_func ("/Handy/Avatar/draw_to_pixbuf", test_hdy_avatar_draw_to_pixbuf);
+ g_test_add_func ("/Handy/Avatar/draw_to_pixbuf_async", test_hdy_avatar_draw_to_pixbuf_async);
g_test_add_func ("/Handy/Avatar/loadable_icon", test_hdy_avatar_loadable_icon);
return g_test_run ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]