forked from AuroraMiddleware/gtk
gdk: Im[plement content deserializing
Add infrastructure to do GInputStream => GType conversions. Use that to implement gdk_clipboard_read_value() which reads into GValues.
This commit is contained in:
parent
970cb100af
commit
91910ba013
@ -32,6 +32,7 @@
|
||||
#include <gdk/gdkapplaunchcontext.h>
|
||||
#include <gdk/gdkcairo.h>
|
||||
#include <gdk/gdkclipboard.h>
|
||||
#include <gdk/gdkcontentdeserializer.h>
|
||||
#include <gdk/gdkcontentformats.h>
|
||||
#include <gdk/gdkcursor.h>
|
||||
#include <gdk/gdkdevice.h>
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "gdkclipboardprivate.h"
|
||||
|
||||
#include "gdkcontentdeserializer.h"
|
||||
#include "gdkcontentformats.h"
|
||||
#include "gdkdisplay.h"
|
||||
|
||||
@ -339,6 +340,125 @@ gdk_clipboard_read_finish (GdkClipboard *clipboard,
|
||||
return GDK_CLIPBOARD_GET_CLASS (clipboard)->read_finish (clipboard, out_mime_type, result, error);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_clipboard_read_value_done (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GTask *task = data;
|
||||
GError *error = NULL;
|
||||
const GValue *value;
|
||||
|
||||
value = gdk_content_deserialize_finish (result, &error);
|
||||
if (value == NULL)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_pointer (task, (gpointer) value, NULL);
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_clipboard_read_value_got_stream (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GInputStream *stream;
|
||||
GError *error = NULL;
|
||||
GTask *task = data;
|
||||
const char *mime_type;
|
||||
|
||||
stream = gdk_clipboard_read_finish (GDK_CLIPBOARD (source), &mime_type, result, &error);
|
||||
if (stream == NULL)
|
||||
{
|
||||
g_task_return_error (task, error);
|
||||
return;
|
||||
}
|
||||
|
||||
gdk_content_deserialize_async (stream,
|
||||
mime_type,
|
||||
GPOINTER_TO_SIZE (g_task_get_task_data (task)),
|
||||
g_task_get_priority (task),
|
||||
g_task_get_cancellable (task),
|
||||
gdk_clipboard_read_value_done,
|
||||
task);
|
||||
g_object_unref (stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_clipboard_read_value_async:
|
||||
* @clipboard: a #GdkClipboard
|
||||
* @type: a #GType to read
|
||||
* @io_priority: the [I/O priority][io-priority]
|
||||
* of the request.
|
||||
* @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
|
||||
* @callback: (scope async): callback to call when the request is satisfied
|
||||
* @user_data: (closure): the data to pass to callback function
|
||||
*
|
||||
* Asynchronously request the @clipboard contents converted to the given
|
||||
* @type. When the operation is finished @callback will be called.
|
||||
* You can then call gdk_clipboard_read_value_finish() to get the resulting
|
||||
* #GValue.
|
||||
*
|
||||
* For local clipboard contents that are available in the given #GType, the
|
||||
* value will be copied directly. Otherwise, GDK will try to use
|
||||
* gdk_content_deserialize_async() to convert the clipboard's data.
|
||||
**/
|
||||
void
|
||||
gdk_clipboard_read_value_async (GdkClipboard *clipboard,
|
||||
GType type,
|
||||
int io_priority,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GdkContentFormatsBuilder *builder;
|
||||
GdkContentFormats *formats;
|
||||
GTask *task;
|
||||
|
||||
builder = gdk_content_formats_builder_new ();
|
||||
gdk_content_formats_builder_add_gtype (builder, type);
|
||||
formats = gdk_content_formats_builder_free (builder);
|
||||
formats = gdk_content_formats_union_deserialize_mime_types (formats);
|
||||
|
||||
task = g_task_new (clipboard, cancellable, callback, user_data);
|
||||
g_task_set_priority (task, io_priority);
|
||||
g_task_set_source_tag (task, gdk_clipboard_read_value_async);
|
||||
g_task_set_task_data (task, GSIZE_TO_POINTER (type), NULL);
|
||||
|
||||
gdk_clipboard_read_internal (clipboard,
|
||||
formats,
|
||||
io_priority,
|
||||
cancellable,
|
||||
gdk_clipboard_read_value_got_stream,
|
||||
task);
|
||||
|
||||
gdk_content_formats_unref (formats);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_clipboard_read_value_finish:
|
||||
* @clipboard: a #GdkClipboard
|
||||
* @result: a #GAsyncResult
|
||||
* @error: a #GError location to store the error occurring, or %NULL to
|
||||
* ignore.
|
||||
*
|
||||
* Finishes an asynchronous clipboard read started with
|
||||
* gdk_clipboard_read_value_async().
|
||||
*
|
||||
* Returns: (transfer none): a #GValue containing the result.
|
||||
**/
|
||||
const GValue *
|
||||
gdk_clipboard_read_value_finish (GdkClipboard *clipboard,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (g_task_is_valid (res, clipboard), NULL);
|
||||
g_return_val_if_fail (g_task_get_source_tag (G_TASK (res)) == gdk_clipboard_read_value_async, NULL);
|
||||
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
GdkClipboard *
|
||||
gdk_clipboard_new (GdkDisplay *display)
|
||||
{
|
||||
@ -357,7 +477,9 @@ gdk_clipboard_claim_remote (GdkClipboard *clipboard,
|
||||
g_return_if_fail (formats != NULL);
|
||||
|
||||
gdk_content_formats_unref (priv->formats);
|
||||
priv->formats = gdk_content_formats_ref (formats);
|
||||
gdk_content_formats_ref (formats);
|
||||
formats = gdk_content_formats_union_deserialize_gtypes (formats);
|
||||
priv->formats = formats;
|
||||
g_object_notify_by_pspec (G_OBJECT (clipboard), properties[PROP_FORMATS]);
|
||||
if (priv->local)
|
||||
{
|
||||
|
@ -54,6 +54,17 @@ GInputStream * gdk_clipboard_read_finish (GdkClipboard *
|
||||
const char **out_mime_type,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
void gdk_clipboard_read_value_async (GdkClipboard *clipboard,
|
||||
GType type,
|
||||
int io_priority,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
const GValue * gdk_clipboard_read_value_finish (GdkClipboard *clipboard,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
487
gdk/gdkcontentdeserializer.c
Normal file
487
gdk/gdkcontentdeserializer.c
Normal file
@ -0,0 +1,487 @@
|
||||
/* 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 "gdkcontentformats.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
typedef struct _Deserializer Deserializer;
|
||||
|
||||
struct _Deserializer
|
||||
{
|
||||
const char * mime_type; /* interned */
|
||||
GType type;
|
||||
GdkContentDeserializeFunc deserialize;
|
||||
gpointer data;
|
||||
GDestroyNotify notify;
|
||||
};
|
||||
|
||||
GQueue deserializers = G_QUEUE_INIT;
|
||||
|
||||
static void init (void);
|
||||
|
||||
#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;
|
||||
GCancellable *cancellable;
|
||||
gpointer user_data;
|
||||
GAsyncReadyCallback callback;
|
||||
gpointer callback_data;
|
||||
|
||||
GError *error;
|
||||
gboolean returned;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
GValue *
|
||||
gdk_content_deserializer_get_value (GdkContentDeserializer *deserializer)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), NULL);
|
||||
|
||||
return &deserializer->value;
|
||||
}
|
||||
|
||||
GInputStream *
|
||||
gdk_content_deserializer_get_input_stream (GdkContentDeserializer *deserializer)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), NULL);
|
||||
|
||||
return deserializer->stream;
|
||||
}
|
||||
|
||||
int
|
||||
gdk_content_deserializer_get_priority (GdkContentDeserializer *deserializer)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), G_PRIORITY_DEFAULT);
|
||||
|
||||
return deserializer->priority;
|
||||
}
|
||||
|
||||
GCancellable *
|
||||
gdk_content_deserializer_get_cancellable (GdkContentDeserializer *deserializer)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), NULL);
|
||||
|
||||
return deserializer->cancellable;
|
||||
}
|
||||
|
||||
gpointer
|
||||
gdk_content_deserializer_get_user_data (GdkContentDeserializer *deserializer)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer), NULL);
|
||||
|
||||
return deserializer->user_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;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_content_deserializer_return_success (GdkContentDeserializer *deserializer)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_CONTENT_DESERIALIZER (deserializer));
|
||||
g_return_if_fail (!deserializer->returned);
|
||||
|
||||
deserializer->returned = TRUE;
|
||||
g_idle_add_full (deserializer->priority,
|
||||
gdk_content_deserializer_emit_callback,
|
||||
deserializer,
|
||||
g_object_unref);
|
||||
/* NB: the idle will destroy our reference */
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
init ();
|
||||
|
||||
deserializer = g_slice_new0 (Deserializer);
|
||||
|
||||
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);
|
||||
|
||||
init ();
|
||||
|
||||
mime_type = g_intern_string (mime_type);
|
||||
|
||||
for (l = g_queue_peek_head_link (&deserializers); l; l = l->next)
|
||||
{
|
||||
Deserializer *deserializer = l->data;
|
||||
|
||||
if (deserializer->mime_type == mime_type &&
|
||||
deserializer->type == type)
|
||||
return deserializer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GdkContentFormats *
|
||||
gdk_content_formats_union_deserialize_gtypes (GdkContentFormats *formats)
|
||||
{
|
||||
GdkContentFormatsBuilder *builder;
|
||||
GList *l;
|
||||
|
||||
g_return_val_if_fail (formats != NULL, NULL);
|
||||
|
||||
init ();
|
||||
|
||||
builder = gdk_content_formats_builder_new ();
|
||||
gdk_content_formats_builder_add_formats (builder, 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 (builder);
|
||||
}
|
||||
|
||||
GdkContentFormats *
|
||||
gdk_content_formats_union_deserialize_mime_types (GdkContentFormats *formats)
|
||||
{
|
||||
GdkContentFormatsBuilder *builder;
|
||||
GList *l;
|
||||
|
||||
g_return_val_if_fail (formats != NULL, NULL);
|
||||
|
||||
init ();
|
||||
|
||||
builder = gdk_content_formats_builder_new ();
|
||||
gdk_content_formats_builder_add_formats (builder, 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 (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);
|
||||
}
|
||||
|
||||
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 (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);
|
||||
}
|
||||
|
||||
const GValue *
|
||||
gdk_content_deserialize_finish (GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
GdkContentDeserializer *deserializer;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (result), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
deserializer = GDK_CONTENT_DESERIALIZER (result);
|
||||
|
||||
if (deserializer->error)
|
||||
{
|
||||
if (error)
|
||||
*error = g_error_copy (deserializer->error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &deserializer->value;
|
||||
}
|
||||
|
||||
/*** DESERIALIZERS ***/
|
||||
|
||||
static void
|
||||
pixbuf_deserializer_finish (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer deserializer)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
GError *error = NULL;
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error);
|
||||
if (pixbuf == NULL)
|
||||
{
|
||||
gdk_content_deserializer_return_error (deserializer, error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_value_take_object (gdk_content_deserializer_get_value (deserializer),
|
||||
pixbuf);
|
||||
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
|
||||
init (void)
|
||||
{
|
||||
static gboolean initialized = FALSE;
|
||||
GSList *formats, *f;
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
initialized = TRUE;
|
||||
|
||||
formats = gdk_pixbuf_get_formats ();
|
||||
|
||||
/* Make sure png comes first */
|
||||
for (f = formats; f; f = f->next)
|
||||
{
|
||||
GdkPixbufFormat *fmt = f->data;
|
||||
gchar *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);
|
||||
|
||||
g_free (name);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
for (f = formats; f; f = f->next)
|
||||
{
|
||||
GdkPixbufFormat *fmt = f->data;
|
||||
gchar **mimes, **m;
|
||||
|
||||
mimes = gdk_pixbuf_format_get_mime_types (fmt);
|
||||
for (m = mimes; *m; m++)
|
||||
{
|
||||
gdk_content_register_deserializer (*m,
|
||||
GDK_TYPE_PIXBUF,
|
||||
pixbuf_deserializer,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
g_strfreev (mimes);
|
||||
}
|
||||
|
||||
g_slist_free (formats);
|
||||
}
|
||||
|
90
gdk/gdkcontentdeserializer.h
Normal file
90
gdk/gdkcontentdeserializer.h
Normal file
@ -0,0 +1,90 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_CONTENT_DESERIALIZER_H__
|
||||
#define __GTK_CONTENT_DESERIALIZER_H__
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include <gdk/gdkversionmacros.h>
|
||||
#include <gdk/gdktypes.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_CONTENT_DESERIALIZER (gdk_content_deserializer_get_type ())
|
||||
#define GDK_CONTENT_DESERIALIZER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_CONTENT_DESERIALIZER, GdkContentDeserializer))
|
||||
#define GDK_IS_CONTENT_DESERIALIZER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_CONTENT_DESERIALIZER))
|
||||
|
||||
typedef struct _GdkContentDeserializer GdkContentDeserializer;
|
||||
|
||||
typedef void (* GdkContentDeserializeFunc) (GdkContentDeserializer *deserializer);
|
||||
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
GType gdk_content_deserializer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
const char * gdk_content_deserializer_get_mime_type (GdkContentDeserializer *deserializer);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
GType gdk_content_deserializer_get_gtype (GdkContentDeserializer *deserializer);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
GValue * gdk_content_deserializer_get_value (GdkContentDeserializer *deserializer);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
GInputStream * gdk_content_deserializer_get_input_stream (GdkContentDeserializer *deserializer);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
int gdk_content_deserializer_get_priority (GdkContentDeserializer *deserializer);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
GCancellable * gdk_content_deserializer_get_cancellable (GdkContentDeserializer *deserializer);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
gpointer gdk_content_deserializer_get_user_data (GdkContentDeserializer *deserializer);
|
||||
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
void gdk_content_deserializer_return_success (GdkContentDeserializer *deserializer);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
void gdk_content_deserializer_return_error (GdkContentDeserializer *deserializer,
|
||||
GError *error);
|
||||
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
GdkContentFormats * gdk_content_formats_union_deserialize_gtypes (GdkContentFormats *formats);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
GdkContentFormats * gdk_content_formats_union_deserialize_mime_types(GdkContentFormats *formats);
|
||||
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
void gdk_content_register_deserializer (const char *mime_type,
|
||||
GType type,
|
||||
GdkContentDeserializeFunc deserialize,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
void gdk_content_deserialize_async (GInputStream *stream,
|
||||
const char *mime_type,
|
||||
GType type,
|
||||
int io_priority,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GDK_AVAILABLE_IN_3_94
|
||||
const GValue * gdk_content_deserialize_finish (GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_CONTENT_DESERIALIZER_H__ */
|
@ -3,6 +3,7 @@ gdk_public_sources = files([
|
||||
'gdkapplaunchcontext.c',
|
||||
'gdkcairo.c',
|
||||
'gdkclipboard.c',
|
||||
'gdkcontentdeserializer.c',
|
||||
'gdkcontentformats.c',
|
||||
'gdkcursor.c',
|
||||
'gdkdevice.c',
|
||||
@ -43,6 +44,7 @@ gdk_public_headers = files([
|
||||
'gdkapplaunchcontext.h',
|
||||
'gdkcairo.h',
|
||||
'gdkclipboard.h',
|
||||
'gdkcontentdeserializer.h',
|
||||
'gdkcontentformats.h',
|
||||
'gdkcursor.h',
|
||||
'gdkdevice.h',
|
||||
|
@ -30,47 +30,22 @@ clipboard_changed_cb (GdkClipboard *clipboard,
|
||||
}
|
||||
|
||||
static void
|
||||
pixbuf_loaded_cb (GObject *stream,
|
||||
pixbuf_loaded_cb (GObject *clipboard,
|
||||
GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
const GValue *value;
|
||||
GError *error = NULL;
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error);
|
||||
if (pixbuf == NULL)
|
||||
value = gdk_clipboard_read_value_finish (GDK_CLIPBOARD (clipboard), res, &error);
|
||||
if (value == NULL)
|
||||
{
|
||||
g_print ("%s\n", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_image_set_from_pixbuf (data, pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
clipboard_read_pixbuf_cb (GObject *clipboard,
|
||||
GAsyncResult *result,
|
||||
gpointer image)
|
||||
{
|
||||
GInputStream *stream;
|
||||
GError *error = NULL;
|
||||
|
||||
stream = gdk_clipboard_read_finish (GDK_CLIPBOARD (clipboard),
|
||||
NULL,
|
||||
result,
|
||||
&error);
|
||||
if (stream)
|
||||
{
|
||||
gdk_pixbuf_new_from_stream_async (stream, NULL, pixbuf_loaded_cb, image);
|
||||
g_object_unref (stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("%s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
gtk_image_set_from_pixbuf (data, g_value_get_object (value));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -88,12 +63,12 @@ visible_child_changed_cb (GtkWidget *stack,
|
||||
{
|
||||
GtkWidget *image = gtk_stack_get_child_by_name (GTK_STACK (stack), "image");
|
||||
|
||||
gdk_clipboard_read_async (clipboard,
|
||||
(const gchar*[2]) { "image/png", NULL },
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
clipboard_read_pixbuf_cb,
|
||||
image);
|
||||
gdk_clipboard_read_value_async (clipboard,
|
||||
GDK_TYPE_PIXBUF,
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
pixbuf_loaded_cb,
|
||||
image);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user