/* GTK - The GIMP Toolkit
* Copyright ( C ) 2017 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 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 < http : //www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gio/gio.h>
#include "gdkcontentdeserializer.h"
#include "gdkcontentformatsprivate.h"
#include "filetransferportalprivate.h"
#include "gdktexture.h"
#include "gdkrgbaprivate.h"
#include "gdkprivate.h"
#include "loaders/gdkpngprivate.h"
#include "loaders/gdktiffprivate.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
/**
* GdkContentDeserializer :
*
* Deserializes content received via inter - application data transfers .
*
* The ` GdkContentDeserializer ` transforms serialized content that is
* identified by a mime type into an object identified by a GType .
*
* GTK provides serializers and deserializers for common data types
* such as text , colors , images or file lists . To register your own
* deserialization functions , use [ func @ content_register_deserializer ] .
*
* Also see [ class @ Gdk . ContentSerializer ] .
*/
typedef struct _Deserializer Deserializer;
struct _Deserializer
{
const char * mime_type; /* interned */
GType type;
GdkContentDeserializeFunc deserialize;
gpointer data;
GDestroyNotify notify;
};
GQueue deserializers = G_QUEUE_INIT;
#define GDK_CONTENT_DESERIALIZER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_CONTENT_DESERIALIZER, GdkContentDeserializerClass))
#define GDK_IS_CONTENT_DESERIALIZER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_CONTENT_DESERIALIZER))
#define GDK_CONTENT_DESERIALIZER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_CONTENT_DESERIALIZER, GdkContentDeserializerClass))
typedef struct _GdkContentDeserializerClass GdkContentDeserializerClass;
struct _GdkContentDeserializer
{
GObject parent_instance;
const char *mime_type; /* interned */
GValue value;
GInputStream *stream;
int priority;
gboolean returned;
GCancellable *cancellable;
gpointer user_data;
GAsyncReadyCallback callback;
gpointer callback_data;
gpointer task_data;
GDestroyNotify task_notify;
GError *error;
};
struct _GdkContentDeserializerClass
{
GObjectClass parent_class;
};
static gpointer
gdk_content_deserializer_async_result_get_user_data (GAsyncResult *res)
{
return GDK_CONTENT_DESERIALIZER (res)->callback_data;
}
static GObject *
gdk_content_deserializer_async_result_get_source_object (GAsyncResult *res)
{
return NULL;
}
static void
gdk_content_deserializer_async_result_iface_init (GAsyncResultIface *iface)
{
iface->get_user_data = gdk_content_deserializer_async_result_get_user_data;
iface->get_source_object = gdk_content_deserializer_async_result_get_source_object;
}
G_DEFINE_TYPE_WITH_CODE (GdkContentDeserializer, gdk_content_deserializer, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, gdk_content_deserializer_async_result_iface_init))
static void
gdk_content_deserializer_finalize (GObject *object)
{
GdkContentDeserializer *deserializer = GDK_CONTENT_DESERIALIZER (object);
g_value_unset (&deserializer->value);
g_clear_object (&deserializer->stream);
g_clear_object (&deserializer->cancellable);
g_clear_error (&deserializer->error);
if (deserializer->task_notify)
deserializer->task_notify (deserializer->task_data);
G_OBJECT_CLASS (gdk_content_deserializer_parent_class)->finalize (object);
}
static void
gdk_content_deserializer_class_init (GdkContentDeserializerClass *content_deserializer_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (content_deserializer_class);
object_class->finalize = gdk_content_deserializer_finalize;
}
static void
gdk_content_deserializer_init (GdkContentDeserializer *content_deserializer)
{
}
static void
gdk_content_deserializer_run (const char *mime_type,
GType type,
GInputStream *stream,
int priority,
GCancellable *cancellable,
GdkContentDeserializeFunc deserialize_func,
gpointer user_data,
GAsyncReadyCallback callback,
gpointer callback_data)
{
GdkContentDeserializer *deserializer;
deserializer = g_object_new (GDK_TYPE_CONTENT_DESERIALIZER, NULL);
deserializer->mime_type = mime_type;
g_value_init (&deserializer->value, type);
deserializer->stream = g_object_ref (stream);
deserializer->priority = priority;
if (cancellable)
deserializer->cancellable = g_object_ref (cancellable);
deserializer->user_data = user_data;
deserializer->callback = callback;
deserializer->callback_data = callback_data;
deserialize_func (deserializer);
}
/**
* gdk_content_deserializer_get_mime_type :
* @ deserializer : a ` GdkContentDeserializer `
*
* Gets the mime type to deserialize from .
*
* Returns : ( transfer none ) : the mime type for the current operation
*/
const char *
gdk_content_deserializer_get_mime_type (GdkContentDeserializer *deserializer)
{
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), NULL);
return deserializer->mime_type;
}
/**
* gdk_content_deserializer_get_gtype :
* @ deserializer : a ` GdkContentDeserializer `
*
* Gets the ` GType ` to create an instance of .
*
* Returns : the ` GType ` for the current operation
*/
GType
gdk_content_deserializer_get_gtype (GdkContentDeserializer *deserializer)
{
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), G_TYPE_INVALID);
return G_VALUE_TYPE (&deserializer->value);
}
/**
* gdk_content_deserializer_get_value :
* @ deserializer : a ` GdkContentDeserializer `
*
* Gets the ` GValue ` to store the deserialized object in .
*
* Returns : ( transfer none ) : the ` GValue ` for the current operation
*/
GValue *
gdk_content_deserializer_get_value (GdkContentDeserializer *deserializer)
{
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), NULL);
return &deserializer->value;
}
/**
* gdk_content_deserializer_get_input_stream :
* @ deserializer : a ` GdkContentDeserializer `
*
* Gets the input stream for the current operation .
*
* This is the stream that was passed to [ func @ Gdk . content_deserialize_async ] .
*
* Returns : ( transfer none ) : the input stream for the current operation
*/
GInputStream *
gdk_content_deserializer_get_input_stream (GdkContentDeserializer *deserializer)
{
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), NULL);
return deserializer->stream;
}
/**
* gdk_content_deserializer_get_priority :
* @ deserializer : a ` GdkContentDeserializer `
*
* Gets the I / O priority for the current operation .
*
* This is the priority that was passed to [ func @ Gdk . content_deserialize_async ] .
*
* Returns : the I / O priority for the current operation
*/
int
gdk_content_deserializer_get_priority (GdkContentDeserializer *deserializer)
{
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), G_PRIORITY_DEFAULT);
return deserializer->priority;
}
/**
* gdk_content_deserializer_get_cancellable :
* @ deserializer : a ` GdkContentDeserializer `
*
* Gets the cancellable for the current operation .
*
* This is the ` GCancellable ` that was passed to [ func @ Gdk . content_deserialize_async ] .
*
* Returns : ( transfer none ) ( nullable ) : the cancellable for the current operation
*/
GCancellable *
gdk_content_deserializer_get_cancellable (GdkContentDeserializer *deserializer)
{
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), NULL);
return deserializer->cancellable;
}
/**
* gdk_content_deserializer_get_user_data :
* @ deserializer : a ` GdkContentDeserializer `
*
* Gets the user data that was passed when the deserializer was registered .
*
* Returns : ( transfer none ) : the user data for this deserializer
*/
gpointer
gdk_content_deserializer_get_user_data (GdkContentDeserializer *deserializer)
{
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), NULL);
return deserializer->user_data;
}
/**
* gdk_content_deserializer_set_task_data :
* @ deserializer : a ` GdkContentDeserializer `
* @ data : data to associate with this operation
* @ notify : destroy notify for @ data
*
* Associate data with the current deserialization operation .
*/
void
gdk_content_deserializer_set_task_data (GdkContentDeserializer *deserializer,
gpointer data,
GDestroyNotify notify)
{
g_return_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer));
if (deserializer->task_notify)
deserializer->task_notify (deserializer->task_data);
deserializer->task_data = data;
deserializer->task_notify = notify;
}
/**
* gdk_content_deserializer_get_task_data :
* @ deserializer : a ` GdkContentDeserializer `
*
* Gets the data that was associated with the current operation .
*
* See [ method @ Gdk . ContentDeserializer . set_task_data ] .
*
* Returns : ( transfer none ) : the task data for @ deserializer
*/
gpointer
gdk_content_deserializer_get_task_data (GdkContentDeserializer *deserializer)
{
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), NULL);
return deserializer->task_data;
}
static gboolean
gdk_content_deserializer_emit_callback (gpointer data)
{
GdkContentDeserializer *deserializer = data;
if (deserializer->callback)
{
deserializer->callback (NULL, G_ASYNC_RESULT (deserializer), deserializer->callback_data);
}
return G_SOURCE_REMOVE;
}
/**
* gdk_content_deserializer_return_success :
* @ deserializer : a ` GdkContentDeserializer `
*
* Indicate that the deserialization has been successfully completed .
*/
void
gdk_content_deserializer_return_success (GdkContentDeserializer *deserializer)
{
g_return_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer));
g_return_if_fail (!deserializer->returned);
guint source_id;
deserializer->returned = TRUE ;
source_id = g_idle_add_full (deserializer->priority,
gdk_content_deserializer_emit_callback,
deserializer,
g_object_unref);
gdk_source_set_static_name_by_id (source_id, "[gtk] gdk_content_deserializer_emit_callback" );
/* NB: the idle will destroy our reference */
}
/**
* gdk_content_deserializer_return_error :
* @ deserializer : a ` GdkContentDeserializer `
* @ error : ( transfer full ) : a ` GError `
*
* Indicate that the deserialization has ended with an error .
*
* This function consumes @ error .
*/
void
gdk_content_deserializer_return_error (GdkContentDeserializer *deserializer,
GError *error)
{
g_return_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer));
g_return_if_fail (!deserializer->returned);
g_return_if_fail (error != NULL);
deserializer->error = error;
/* FIXME: naming */
gdk_content_deserializer_return_success (deserializer);
}
/**
* gdk_content_register_deserializer :
* @ mime_type : the mime type which the function can deserialize from
* @ type : the type of objects that the function creates
* @ deserialize : the callback
* @ data : data that @ deserialize can access
* @ notify : destroy notify for @ data
*
* Registers a function to deserialize object of a given type .
*
* Since 4 . 20 , when looking up a deserializer to use , GTK will
* use the last registered deserializer for a given mime type ,
* so applications can override the built - in deserializers .
*/
void
gdk_content_register_deserializer (const char *mime_type,
GType type,
GdkContentDeserializeFunc deserialize,
gpointer data,
GDestroyNotify notify)
{
Deserializer *deserializer;
g_return_if_fail (mime_type != NULL);
g_return_if_fail (deserialize != NULL);
deserializer = g_new0 (Deserializer, 1 );
deserializer->mime_type = g_intern_string (mime_type);
deserializer->type = type;
deserializer->deserialize = deserialize;
deserializer->data = data;
deserializer->notify = notify;
g_queue_push_tail (&deserializers, deserializer);
}
static Deserializer *
lookup_deserializer (const char *mime_type,
GType type)
{
GList *l;
g_return_val_if_fail (mime_type != NULL, NULL);
mime_type = g_intern_string (mime_type);
for (l = g_queue_peek_tail_link (&deserializers); l; l = l->prev)
{
Deserializer *deserializer = l->data;
if (deserializer->mime_type == mime_type &&
deserializer->type == type)
return deserializer;
}
return NULL;
}
/**
* gdk_content_formats_union_deserialize_gtypes :
* @ formats : ( transfer full ) : a ` GdkContentFormats `
*
* Add GTypes for mime types in @ formats for which deserializers are
* registered .
*
* Return : a new ` GdkContentFormats `
*/
GdkContentFormats *
gdk_content_formats_union_deserialize_gtypes (GdkContentFormats *formats)
{
GdkContentFormatsBuilder *builder;
GList *l;
g_return_val_if_fail (formats != NULL, NULL);
builder = gdk_content_formats_builder_new ();
gdk_content_formats_builder_add_formats (builder, formats);
if (!gdk_content_formats_is_empty (formats))
{
for (l = g_queue_peek_head_link (&deserializers); l; l = l->next)
{
Deserializer *deserializer = l->data;
if (gdk_content_formats_contain_mime_type (formats, deserializer->mime_type))
gdk_content_formats_builder_add_gtype (builder, deserializer->type);
}
}
gdk_content_formats_unref (formats);
return gdk_content_formats_builder_free_to_formats (builder);
}
/**
* gdk_content_formats_union_deserialize_mime_types :
* @ formats : ( transfer full ) : a ` GdkContentFormats `
*
* Add mime types for GTypes in @ formats for which deserializers are
* registered .
*
* Return : a new ` GdkContentFormats `
*/
GdkContentFormats *
gdk_content_formats_union_deserialize_mime_types (GdkContentFormats *formats)
{
GdkContentFormatsBuilder *builder;
GList *l;
g_return_val_if_fail (formats != NULL, NULL);
builder = gdk_content_formats_builder_new ();
gdk_content_formats_builder_add_formats (builder, formats);
if (!gdk_content_formats_is_empty (formats))
{
for (l = g_queue_peek_head_link (&deserializers); l; l = l->next)
{
Deserializer *deserializer = l->data;
if (gdk_content_formats_contain_gtype (formats, deserializer->type))
gdk_content_formats_builder_add_mime_type (builder, deserializer->mime_type);
}
}
gdk_content_formats_unref (formats);
return gdk_content_formats_builder_free_to_formats (builder);
}
static void
deserialize_not_found (GdkContentDeserializer *deserializer)
{
GError *error = g_error_new (G_IO_ERROR,
G_IO_ERROR_NOT_FOUND,
"Could not convert data from %s to %s" ,
gdk_content_deserializer_get_mime_type (deserializer),
g_type_name (gdk_content_deserializer_get_gtype (deserializer)));
gdk_content_deserializer_return_error (deserializer, error);
}
/**
* gdk_content_deserialize_async :
* @ stream : a ` GInputStream ` to read the serialized content from
* @ mime_type : the mime type to deserialize from
* @ type : the GType to deserialize from
* @ io_priority : the I / O priority of the operation
* @ cancellable : ( nullable ) : optional ` GCancellable ` object
* @ callback : ( scope async ) ( closure user_data ) : callback to call when the operation is done
* @ user_data : data to pass to the callback function
*
* Reads content from the given input stream and deserialize it , asynchronously .
*
* The default I / O priority is ` G_PRIORITY_DEFAULT ` ( i . e . 0 ) , and lower numbers
* indicate a higher priority .
*/
void
gdk_content_deserialize_async (GInputStream *stream,
const char *mime_type,
GType type,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
Deserializer *deserializer;
g_return_if_fail (G_IS_INPUT_STREAM (stream));
g_return_if_fail (mime_type != NULL);
g_return_if_fail (G_TYPE_IS_VALUE_TYPE (type));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
g_return_if_fail (callback != NULL);
deserializer = lookup_deserializer (mime_type, type);
gdk_content_deserializer_run (mime_type,
type,
stream,
io_priority,
cancellable,
deserializer ? deserializer->deserialize : deserialize_not_found,
deserializer ? deserializer->data : NULL,
callback,
user_data);
}
/**
* gdk_content_deserialize_finish :
* @ result : the ` GAsyncResult `
* @ value : ( out ) : return location for the result of the operation
* @ error : return location for an error
*
* Finishes a content deserialization operation .
*
* Returns : % TRUE if the operation was successful . In this case ,
* @ value is set . % FALSE if an error occurred . In this case ,
* @ error is set
*/
gboolean
gdk_content_deserialize_finish (GAsyncResult *result,
GValue *value,
GError **error)
{
GdkContentDeserializer *deserializer;
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (result), FALSE );
g_return_val_if_fail (error == NULL || *error == NULL, FALSE );
deserializer = GDK_CONTENT_DESERIALIZER (result);
if (G_VALUE_TYPE (value) == 0 )
g_value_init (value, G_VALUE_TYPE (&deserializer->value));
else
g_return_val_if_fail (G_VALUE_HOLDS (value, G_VALUE_TYPE (&deserializer->value)), FALSE );
if (deserializer->error)
{
if (error)
*error = g_error_copy (deserializer->error);
return FALSE ;
}
g_value_copy (&deserializer->value, value);
return TRUE ;
}
/*** DESERIALIZERS ***/
static void
pixbuf_deserializer_finish (GObject *source,
GAsyncResult *res,
gpointer deserializer)
{
GdkPixbuf *pixbuf;
GValue *value;
GError *error = NULL;
pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error);
if (pixbuf == NULL)
{
gdk_content_deserializer_return_error (deserializer, error);
return ;
}
value = gdk_content_deserializer_get_value (deserializer);
if (G_VALUE_HOLDS (value, GDK_TYPE_PIXBUF))
{
g_value_take_object (value, pixbuf);
}
else if (G_VALUE_HOLDS (value, GDK_TYPE_TEXTURE))
{
GdkTexture *texture;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
texture = gdk_texture_new_for_pixbuf (pixbuf);
G_GNUC_END_IGNORE_DEPRECATIONS
g_object_unref (pixbuf);
g_value_take_object (value, texture);
}
else
{
g_assert_not_reached ();
}
gdk_content_deserializer_return_success (deserializer);
}
static void
pixbuf_deserializer (GdkContentDeserializer *deserializer)
{
gdk_pixbuf_new_from_stream_async (gdk_content_deserializer_get_input_stream (deserializer),
gdk_content_deserializer_get_cancellable (deserializer),
pixbuf_deserializer_finish,
deserializer);
}
static void
texture_deserializer_finish (GObject *source,
GAsyncResult *result,
gpointer deserializer)
{
GOutputStream *stream = G_OUTPUT_STREAM (source);
GBytes *bytes;
GError *error = NULL;
GdkTexture *texture = NULL;
gssize written;
written = g_output_stream_splice_finish (stream, result, &error);
if (written < 0 )
{
gdk_content_deserializer_return_error (deserializer, error);
return ;
}
bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (stream));
texture = gdk_texture_new_from_bytes (bytes, &error);
g_bytes_unref (bytes);
if (texture == NULL)
{
gdk_content_deserializer_return_error (deserializer, error);
return ;
}
g_value_take_object (gdk_content_deserializer_get_value (deserializer), texture);
gdk_content_deserializer_return_success (deserializer);
}
static void
texture_deserializer (GdkContentDeserializer *deserializer)
{
GOutputStream *output;
output = g_memory_output_stream_new_resizable ();
g_output_stream_splice_async (output,
gdk_content_deserializer_get_input_stream (deserializer),
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE
| G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
gdk_content_deserializer_get_priority (deserializer),
gdk_content_deserializer_get_cancellable (deserializer),
texture_deserializer_finish,
deserializer);
g_object_unref (output);
}
static void
string_deserializer_finish (GObject *source,
GAsyncResult *result,
gpointer deserializer)
{
GOutputStream *stream = G_OUTPUT_STREAM (source);
GError *error = NULL;
gssize written;
written = g_output_stream_splice_finish (stream, result, &error);
if (written < 0 )
{
gdk_content_deserializer_return_error (deserializer, error);
return ;
}
else if (written == 0 )
{
/* Never return NULL, we only return that on error */
g_value_set_static_string (gdk_content_deserializer_get_value (deserializer), "" );
}
else
{
GOutputStream *mem_stream = g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (stream));
/* write a terminating NULL byte */
if (g_output_stream_write (mem_stream, "" , 1 , NULL, &error) < 0 ||
!g_output_stream_close (mem_stream, NULL, &error))
{
gdk_content_deserializer_return_error (deserializer, error);
return ;
}
g_value_take_string (gdk_content_deserializer_get_value (deserializer),
g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (mem_stream)));
}
gdk_content_deserializer_return_success (deserializer);
}
static void
string_deserializer (GdkContentDeserializer *deserializer)
{
GOutputStream *output, *filter;
GCharsetConverter *converter;
GError *error = NULL;
converter = g_charset_converter_new ("utf-8" ,
gdk_content_deserializer_get_user_data (deserializer),
&error);
if (converter == NULL)
{
gdk_content_deserializer_return_error (deserializer, error);
return ;
}
g_charset_converter_set_use_fallback (converter, TRUE );
output = g_memory_output_stream_new_resizable ();
filter = g_converter_output_stream_new (output, G_CONVERTER (converter));
g_object_unref (output);
g_object_unref (converter);
g_output_stream_splice_async (filter,
gdk_content_deserializer_get_input_stream (deserializer),
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
gdk_content_deserializer_get_priority (deserializer),
gdk_content_deserializer_get_cancellable (deserializer),
string_deserializer_finish,
deserializer);
g_object_unref (filter);
}
static void
file_uri_deserializer_finish (GObject *source,
GAsyncResult *result,
gpointer deserializer)
{
GOutputStream *stream = G_OUTPUT_STREAM (source);
GError *error = NULL;
gssize written;
GValue *value;
char *str;
char **uris;
written = g_output_stream_splice_finish (stream, result, &error);
if (written < 0 )
{
gdk_content_deserializer_return_error (deserializer, error);
return ;
}
/* write terminating NULL */
if (g_output_stream_write (stream, "" , 1 , NULL, &error) < 0 ||
!g_output_stream_close (stream, NULL, &error))
{
gdk_content_deserializer_return_error (deserializer, error);
return ;
}
str = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (stream));
uris = g_uri_list_extract_uris (str);
g_free (str);
value = gdk_content_deserializer_get_value (deserializer);
if (G_VALUE_HOLDS (value, G_TYPE_FILE))
{
if (uris[0 ] != NULL)
g_value_take_object (value, g_file_new_for_uri (uris[0 ]));
}
else
{
GSList *l = NULL;
gsize i;
for (i = 0 ; uris[i] != NULL; i++)
l = g_slist_prepend (l, g_file_new_for_uri (uris[i]));
g_value_take_boxed (value, g_slist_reverse (l));
}
g_strfreev (uris);
gdk_content_deserializer_return_success (deserializer);
}
static void
file_uri_deserializer (GdkContentDeserializer *deserializer)
{
GOutputStream *output;
output = g_memory_output_stream_new_resizable ();
g_output_stream_splice_async (output,
gdk_content_deserializer_get_input_stream (deserializer),
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
gdk_content_deserializer_get_priority (deserializer),
gdk_content_deserializer_get_cancellable (deserializer),
file_uri_deserializer_finish,
deserializer);
g_object_unref (output);
}
static void
color_deserializer_finish (GObject *source,
GAsyncResult *result,
gpointer deserializer)
{
GOutputStream *stream = G_OUTPUT_STREAM (source);
GError *error = NULL;
gssize written;
written = g_output_stream_splice_finish (stream, result, &error);
if (written < 0 )
{
gdk_content_deserializer_return_error (deserializer, error);
return ;
}
else if (written == 0 )
{
GdkRGBA black = GDK_RGBA ("000" );
/* Never return NULL, we only return that on error */
g_value_set_boxed (gdk_content_deserializer_get_value (deserializer), &black);
}
else
{
guint16 *data;
GdkRGBA rgba;
data = (guint16 *)g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (stream));
rgba.red = data[0 ] / 65535 .0 ;
rgba.green = data[1 ] / 65535 .0 ;
rgba.blue = data[2 ] / 65535 .0 ;
rgba.alpha = data[3 ] / 65535 .0 ;
g_value_set_boxed (gdk_content_deserializer_get_value (deserializer), &rgba);
}
gdk_content_deserializer_return_success (deserializer);
}
static void
color_deserializer (GdkContentDeserializer *deserializer)
{
GOutputStream *output;
guint16 *data;
data = g_new0 (guint16, 4 );
output = g_memory_output_stream_new (data, 4 * sizeof (guint16), NULL, g_free);
g_output_stream_splice_async (output,
gdk_content_deserializer_get_input_stream (deserializer),
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
gdk_content_deserializer_get_priority (deserializer),
gdk_content_deserializer_get_cancellable (deserializer),
color_deserializer_finish,
deserializer);
g_object_unref (output);
}
void
gdk_content_init_deserializers (void )
{
static gboolean initialized = FALSE ;
GSList *formats, *f;
const char *charset;
if (initialized)
return ;
initialized = TRUE ;
/* Textures */
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);
gdk_content_register_deserializer ("image/jpeg" ,
GDK_TYPE_TEXTURE,
texture_deserializer,
NULL,
NULL);
formats = gdk_pixbuf_get_formats ();
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++)
{
/* Turning pngs, jpegs and tiffs into textures is handled above */
if (!g_str_equal (name, "png" ) &&
!g_str_equal (name, "jpeg" ) &&
!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);
/* Files */
gdk_content_register_deserializer ("text/uri-list" ,
GDK_TYPE_FILE_LIST,
file_uri_deserializer,
NULL,
NULL);
gdk_content_register_deserializer ("text/uri-list" ,
G_TYPE_FILE,
file_uri_deserializer,
NULL,
NULL);
#if defined (G_OS_UNIX) && !defined (__APPLE__)
file_transfer_portal_register ();
#endif
/* Strings */
gdk_content_register_deserializer ("text/plain;charset=utf-8" ,
G_TYPE_STRING,
string_deserializer,
(gpointer) "utf-8" ,
NULL);
if (!g_get_charset (&charset))
{
char *mime = g_strdup_printf ("text/plain;charset=%s" , charset);
gdk_content_register_deserializer (mime,
G_TYPE_STRING,
string_deserializer,
(gpointer) charset,
g_free);
g_free (mime);
}
gdk_content_register_deserializer ("text/plain" ,
G_TYPE_STRING,
string_deserializer,
(gpointer) "ASCII" ,
NULL);
/* Colors */
gdk_content_register_deserializer ("application/x-color" ,
GDK_TYPE_RGBA,
color_deserializer,
NULL,
NULL);
}
Messung V0.5 in Prozent C=98 H=95 G=96
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-07-02)
¤
*© Formatika GbR, Deutschland