diff options
author | Ryan Lortie <desrt@moonpix.lan> | 2013-02-26 16:01:32 -0500 |
---|---|---|
committer | Ryan Lortie <desrt@desrt.ca> | 2013-04-21 16:39:14 -0400 |
commit | aa0f928631d7c3877633337960c10963fb6eaecd (patch) | |
tree | 390a033e7d659c04ff6e3ebc2b3b538a06f1e51d /gdk-pixbuf/gdk-pixbuf.c | |
parent | cb0d6bef7f241d21f6efd6af377cab3a33b7de09 (diff) | |
download | gdk-pixbuf-aa0f928631d7c3877633337960c10963fb6eaecd.tar.gz |
Fix GIcon implementation
The "new rules" for GIcon say that we must support serialisation via
g_icon_serialize() and loadability via GLoadableIcon, so implement both
of those.
Serialise GdkPixbuf by emitting a GVariant that will result in a
png-encoded GBytesIcon when deserialized. The GLoadableIcon interface
is similar: we return a stream that will read out as a png.
Test the serialisation by round-tripping an image through this process
and ensuring that it is pixel-perfect.
https://bugzilla.gnome.org/show_bug.cgi?id=688820
Diffstat (limited to 'gdk-pixbuf/gdk-pixbuf.c')
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf.c | 104 |
1 files changed, 102 insertions, 2 deletions
diff --git a/gdk-pixbuf/gdk-pixbuf.c b/gdk-pixbuf/gdk-pixbuf.c index 3eaa91b57..0e13f27a2 100644 --- a/gdk-pixbuf/gdk-pixbuf.c +++ b/gdk-pixbuf/gdk-pixbuf.c @@ -135,10 +135,11 @@ enum }; static void gdk_pixbuf_icon_iface_init (GIconIface *iface); +static void gdk_pixbuf_loadable_icon_iface_init (GLoadableIconIface *iface); G_DEFINE_TYPE_WITH_CODE (GdkPixbuf, gdk_pixbuf, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_ICON, - gdk_pixbuf_icon_iface_init)) + G_IMPLEMENT_INTERFACE (G_TYPE_ICON, gdk_pixbuf_icon_iface_init) + G_IMPLEMENT_INTERFACE (G_TYPE_LOADABLE_ICON, gdk_pixbuf_loadable_icon_iface_init)) static void gdk_pixbuf_init (GdkPixbuf *pixbuf) @@ -292,11 +293,110 @@ gdk_pixbuf_unref (GdkPixbuf *pixbuf) g_object_unref (pixbuf); } +static GBytes * +gdk_pixbuf_make_bytes (GdkPixbuf *pixbuf, + GError **error) +{ + gchar *buffer; + gsize size; + + if (!gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &size, "png", error, NULL)) + return NULL; + + return g_bytes_new_take (buffer, size); +} + +static GVariant * +gdk_pixbuf_serialize (GIcon *icon) +{ + GError *error = NULL; + GVariant *result; + GBytes *bytes; + + bytes = gdk_pixbuf_make_bytes (GDK_PIXBUF (icon), &error); + if (!bytes) + { + g_critical ("Unable to serialise GdkPixbuf to png (via g_icon_serialize()): %s", error->message); + g_error_free (error); + return NULL; + } + result = g_variant_new_from_bytes (G_VARIANT_TYPE_BYTESTRING, bytes, TRUE); + g_bytes_unref (bytes); + + return g_variant_new ("(sv)", "bytes", result); +} + +static GInputStream * +gdk_pixbuf_load (GLoadableIcon *icon, + int size, + char **type, + GCancellable *cancellable, + GError **error) +{ + GInputStream *stream; + GBytes *bytes; + + bytes = gdk_pixbuf_make_bytes (GDK_PIXBUF (icon), error); + if (!bytes) + return NULL; + + stream = g_memory_input_stream_new_from_bytes (bytes); + g_bytes_unref (bytes); + + if (type) + *type = g_strdup ("image/png"); + + return stream; +} + +static void +gdk_pixbuf_load_async (GLoadableIcon *icon, + int size, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (icon, cancellable, callback, user_data); + g_task_return_pointer (task, icon, NULL); + g_object_unref (task); +} + +static GInputStream * +gdk_pixbuf_load_finish (GLoadableIcon *icon, + GAsyncResult *res, + char **type, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (res, icon), NULL); + + if (!g_task_propagate_pointer (G_TASK (res), error)) + return NULL; + + return gdk_pixbuf_load (icon, 0, type, NULL, error); +} + +static void +gdk_pixbuf_loadable_icon_iface_init (GLoadableIconIface *iface) +{ + iface->load = gdk_pixbuf_load; + + /* In theory encoding a png could be time-consuming but we're talking + * about icons here, so assume it's probably going to be OK and handle + * the async variant of the call in-thread instead of having the + * default implementation dispatch it to a worker. + */ + iface->load_async = gdk_pixbuf_load_async; + iface->load_finish = gdk_pixbuf_load_finish; +} + static void gdk_pixbuf_icon_iface_init (GIconIface *iface) { iface->hash = (guint (*) (GIcon *)) g_direct_hash; iface->equal = (gboolean (*) (GIcon *, GIcon *)) g_direct_equal; + iface->serialize = gdk_pixbuf_serialize; } /* Used as the destroy notification function for gdk_pixbuf_new() */ |