diff --git a/gdk/gdkcontentdeserializer.c b/gdk/gdkcontentdeserializer.c index 4959b5af4d..6731b47e24 100644 --- a/gdk/gdkcontentdeserializer.c +++ b/gdk/gdkcontentdeserializer.c @@ -25,6 +25,8 @@ #include "filetransferportalprivate.h" #include "gdktexture.h" #include "gdkrgbaprivate.h" +#include "loaders/gdkpngprivate.h" +#include "loaders/gdktiffprivate.h" #include @@ -655,6 +657,88 @@ pixbuf_deserializer (GdkContentDeserializer *deserializer) deserializer); } +static void +texture_deserializer_finish (GObject *source, + GAsyncResult *res, + gpointer data) +{ + GdkContentDeserializer *deserializer = GDK_CONTENT_DESERIALIZER (source); + GdkTexture *texture; + GValue *value; + GError *error = NULL; + + texture = g_task_propagate_pointer (G_TASK (res), &error); + if (texture == NULL) + { + gdk_content_deserializer_return_error (deserializer, error); + return; + } + + value = gdk_content_deserializer_get_value (deserializer); + g_value_take_object (value, texture); + gdk_content_deserializer_return_success (deserializer); +} + +static GBytes * +read_all_data (GInputStream *source, + GError **error) +{ + GOutputStream *output; + gssize size; + GBytes *bytes; + + output = g_memory_output_stream_new (NULL, 0, g_realloc, g_free); + size = g_output_stream_splice (output, source, 0, NULL, error); + if (size == -1) + { + g_object_unref (output); + return NULL; + } + + g_output_stream_close (output, NULL, NULL); + bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (output)); + g_object_unref (output); + + return bytes; +} + +static void +deserialize_texture_in_thread (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + GdkContentDeserializer *deserializer = source_object; + GBytes *bytes; + GError *error = NULL; + GdkTexture *texture = NULL; + + bytes = read_all_data (gdk_content_deserializer_get_input_stream (deserializer), &error); + if (bytes) + { + texture = gdk_texture_new_from_bytes (bytes, &error); + g_bytes_unref (bytes); + } + + if (texture) + g_task_return_pointer (task, texture, g_object_unref); + else + g_task_return_error (task, error); +} + +static void +texture_deserializer (GdkContentDeserializer *deserializer) +{ + GTask *task; + + task = g_task_new (deserializer, + gdk_content_deserializer_get_cancellable (deserializer), + texture_deserializer_finish, + NULL); + g_task_run_in_thread (task, deserialize_texture_in_thread); + g_object_unref (task); +} + static void string_deserializer_finish (GObject *source, GAsyncResult *result, @@ -863,48 +947,65 @@ init (void) initialized = TRUE; + gdk_content_register_deserializer ("image/png", + GDK_TYPE_TEXTURE, + texture_deserializer, + NULL, + NULL); + + gdk_content_register_deserializer ("image/tiff", + GDK_TYPE_TEXTURE, + texture_deserializer, + NULL, + NULL); + formats = gdk_pixbuf_get_formats (); /* Make sure png comes first */ for (f = formats; f; f = f->next) { GdkPixbufFormat *fmt = f->data; - char *name; - + char *name; + name = gdk_pixbuf_format_get_name (fmt); if (g_str_equal (name, "png")) - { - formats = g_slist_delete_link (formats, f); - formats = g_slist_prepend (formats, fmt); + { + formats = g_slist_delete_link (formats, f); + formats = g_slist_prepend (formats, fmt); - g_free (name); - - break; - } + g_free (name); + break; + } g_free (name); - } + } for (f = formats; f; f = f->next) { GdkPixbufFormat *fmt = f->data; char **mimes, **m; + char *name; + name = gdk_pixbuf_format_get_name (fmt); mimes = gdk_pixbuf_format_get_mime_types (fmt); for (m = mimes; *m; m++) - { - gdk_content_register_deserializer (*m, - GDK_TYPE_TEXTURE, - pixbuf_deserializer, - NULL, - NULL); + { + /* Turning pngs and tiffs into textures is handled above */ + if (!g_str_equal (name, "png") && + !g_str_equal (name, "tiff")) + gdk_content_register_deserializer (*m, + GDK_TYPE_TEXTURE, + pixbuf_deserializer, + NULL, + NULL); gdk_content_register_deserializer (*m, GDK_TYPE_PIXBUF, pixbuf_deserializer, NULL, NULL); - } + } g_strfreev (mimes); + g_free (name); } g_slist_free (formats); diff --git a/gdk/gdkcontentserializer.c b/gdk/gdkcontentserializer.c index bc9deeb8d5..316f6ad9c0 100644 --- a/gdk/gdkcontentserializer.c +++ b/gdk/gdkcontentserializer.c @@ -26,6 +26,9 @@ #include "filetransferportalprivate.h" #include "gdktextureprivate.h" #include "gdkrgba.h" +#include "loaders/gdkpngprivate.h" +#include "loaders/gdktiffprivate.h" +#include "gdkmemorytextureprivate.h" #include #include @@ -606,6 +609,7 @@ gdk_content_serialize_finish (GAsyncResult *result, /*** SERIALIZERS ***/ + static void pixbuf_serializer_finish (GObject *source, GAsyncResult *res, @@ -658,6 +662,82 @@ pixbuf_serializer (GdkContentSerializer *serializer) g_object_unref (pixbuf); } +static void +texture_serializer_finish (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + GdkContentSerializer *serializer = GDK_CONTENT_SERIALIZER (source); + GError *error = NULL; + + if (!g_task_propagate_boolean (G_TASK (res), &error)) + gdk_content_serializer_return_error (serializer, error); + else + gdk_content_serializer_return_success (serializer); +} + +static void +serialize_texture_in_thread (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + GdkContentSerializer *serializer = source_object; + const GValue *value; + GdkTexture *texture; + GBytes *bytes = NULL; + GError *error = NULL; + gboolean result = FALSE; + + value = gdk_content_serializer_get_value (serializer); + texture = g_value_get_object (value); + + if (strcmp (gdk_content_serializer_get_mime_type (serializer), "image/png") == 0) + bytes = gdk_save_png (texture); + else if (strcmp (gdk_content_serializer_get_mime_type (serializer), "image/tiff") == 0) + bytes = gdk_save_tiff (texture); + else + g_assert_not_reached (); + + if (bytes) + { + GInputStream *input = g_memory_input_stream_new_from_bytes (bytes); + gssize spliced; + + spliced = g_output_stream_splice (gdk_content_serializer_get_output_stream (serializer), + input, + G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE, + gdk_content_serializer_get_cancellable (serializer), + &error); + g_object_unref (input); + g_bytes_unref (bytes); + + result = spliced != -1; + } + else + g_set_error_literal (&error, + G_IO_ERROR, G_IO_ERROR_FAILED, + "Saving png failed"); + + if (result) + g_task_return_boolean (task, result); + else + g_task_return_error (task, error); +} + +static void +texture_serializer (GdkContentSerializer *serializer) +{ + GTask *task; + + task = g_task_new (serializer, + gdk_content_serializer_get_cancellable (serializer), + texture_serializer_finish, + NULL); + g_task_run_in_thread (task, serialize_texture_in_thread); + g_object_unref (task); +} + static void string_serializer_finish (GObject *source, GAsyncResult *result, @@ -877,51 +957,66 @@ init (void) initialized = TRUE; + gdk_content_register_serializer (GDK_TYPE_TEXTURE, + "image/png", + texture_serializer, + NULL, NULL); + + gdk_content_register_serializer (GDK_TYPE_TEXTURE, + "image/tiff", + texture_serializer, + NULL, NULL); + formats = gdk_pixbuf_get_formats (); /* Make sure png comes first */ for (f = formats; f; f = f->next) { GdkPixbufFormat *fmt = f->data; - char *name; - + char *name; + name = gdk_pixbuf_format_get_name (fmt); if (g_str_equal (name, "png")) - { - formats = g_slist_delete_link (formats, f); - formats = g_slist_prepend (formats, fmt); + { + formats = g_slist_delete_link (formats, f); + formats = g_slist_prepend (formats, fmt); - g_free (name); - - break; - } + g_free (name); + break; + } g_free (name); - } + } for (f = formats; f; f = f->next) { GdkPixbufFormat *fmt = f->data; char **mimes, **m; + char *name; if (!gdk_pixbuf_format_is_writable (fmt)) - continue; + continue; + name = gdk_pixbuf_format_get_name (fmt); mimes = gdk_pixbuf_format_get_mime_types (fmt); for (m = mimes; *m; m++) - { - gdk_content_register_serializer (GDK_TYPE_TEXTURE, - *m, - pixbuf_serializer, - gdk_pixbuf_format_get_name (fmt), - g_free); + { + /* Turning textures into pngs or tiffs is handled above */ + if (!g_str_equal (name, "png") && + !g_str_equal (name, "tiff")) + gdk_content_register_serializer (GDK_TYPE_TEXTURE, + *m, + pixbuf_serializer, + gdk_pixbuf_format_get_name (fmt), + g_free); gdk_content_register_serializer (GDK_TYPE_PIXBUF, *m, pixbuf_serializer, gdk_pixbuf_format_get_name (fmt), g_free); - } + } g_strfreev (mimes); + g_free (name); } g_slist_free (formats);