Add another callback-based provider

This one can be used in cases where data needs
to be served in multiple formats that may not
all be covered by content serializers.
This commit is contained in:
Matthias Clasen
2020-01-01 01:25:02 -05:00
parent 27460826b3
commit ad11933eee
2 changed files with 155 additions and 3 deletions

View File

@@ -367,3 +367,146 @@ gdk_content_provider_new_with_callback (GType type,
return GDK_CONTENT_PROVIDER (content);
}
#define GDK_TYPE_CONTENT_PROVIDER_CALLBACK2 (gdk_content_provider_callback2_get_type ())
#define GDK_CONTENT_PROVIDER_CALLBACK2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CONTENT_PROVIDER_CALLBACK2, GdkContentProviderCallback2))
typedef struct _GdkContentProviderCallback2 GdkContentProviderCallback2;
typedef struct _GdkContentProviderCallback2Class GdkContentProviderCallback2Class;
struct _GdkContentProviderCallback2
{
GdkContentProvider parent;
GdkContentFormats *formats;
GdkContentProviderGetBytesFunc func;
gpointer data;
};
struct _GdkContentProviderCallback2Class
{
GdkContentProviderClass parent_class;
};
GType gdk_content_provider_callback2_get_type (void) G_GNUC_CONST;
G_DEFINE_TYPE (GdkContentProviderCallback2, gdk_content_provider_callback2, GDK_TYPE_CONTENT_PROVIDER)
static GdkContentFormats *
gdk_content_provider_callback2_ref_formats (GdkContentProvider *provider)
{
GdkContentProviderCallback2 *callback = GDK_CONTENT_PROVIDER_CALLBACK2 (provider);
return gdk_content_formats_ref (callback->formats);
}
static void
gdk_content_provider_callback2_write_mime_type_done (GObject *stream,
GAsyncResult *result,
gpointer task)
{
GError *error = NULL;
if (!g_output_stream_write_all_finish (G_OUTPUT_STREAM (stream), result, NULL, &error))
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
gdk_content_provider_callback2_write_mime_type_async (GdkContentProvider *provider,
const char *mime_type,
GOutputStream *stream,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GdkContentProviderCallback2 *content = GDK_CONTENT_PROVIDER_CALLBACK2 (provider);
GTask *task;
GBytes *bytes;
task = g_task_new (content, cancellable, callback, user_data);
g_task_set_priority (task, io_priority);
g_task_set_source_tag (task, gdk_content_provider_callback2_write_mime_type_async);
if (!gdk_content_formats_contain_mime_type (content->formats, mime_type))
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("Cannot provide contents as “%s”"), mime_type);
g_object_unref (task);
return;
}
bytes = content->func (mime_type, content->data);
if (!bytes)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("Failed to get contents as “%s”"), mime_type);
g_object_unref (task);
return;
}
g_object_set_data_full (G_OBJECT (task), "bytes", bytes, (GDestroyNotify)g_bytes_unref);
g_output_stream_write_all_async (stream,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes),
io_priority,
cancellable,
gdk_content_provider_callback2_write_mime_type_done,
task);
}
static gboolean
gdk_content_provider_callback2_write_mime_type_finish (GdkContentProvider *provider,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, provider), FALSE);
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gdk_content_provider_callback2_write_mime_type_async, FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
gdk_content_provider_callback2_class_init (GdkContentProviderCallback2Class *class)
{
GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class);
provider_class->ref_formats = gdk_content_provider_callback2_ref_formats;
provider_class->write_mime_type_async = gdk_content_provider_callback2_write_mime_type_async;
provider_class->write_mime_type_finish = gdk_content_provider_callback2_write_mime_type_finish;
}
static void
gdk_content_provider_callback2_init (GdkContentProviderCallback2 *content)
{
}
/**
* gdk_content_provider_new_with_formats:
* @formats: formats to advertise
* @func: callback to populate a #GValue
* @data: data that gets passed to @func
*
* Create a content provider that provides data that is provided via a callback.
*
* Returns: a new #GdkContentProvider
**/
GdkContentProvider *
gdk_content_provider_new_with_formats (GdkContentFormats *formats,
GdkContentProviderGetBytesFunc func,
gpointer data)
{
GdkContentProviderCallback2 *content;
content = g_object_new (GDK_TYPE_CONTENT_PROVIDER_CALLBACK2, NULL);
content->formats = gdk_content_formats_ref (formats);
content->func = func;
content->data = data;
return GDK_CONTENT_PROVIDER (content);
}

View File

@@ -39,9 +39,18 @@ typedef void (*GdkContentProviderGetValueFunc) (GValue *value,
gpointer data);
GDK_AVAILABLE_IN_ALL
GdkContentProvider * gdk_content_provider_new_with_callback (GType type,
GdkContentProviderGetValueFunc func,
gpointer data);
GdkContentProvider * gdk_content_provider_new_with_callback (GType type,
GdkContentProviderGetValueFunc func,
gpointer data);
typedef GBytes * (*GdkContentProviderGetBytesFunc) (const char *mime_type,
gpointer data);
GDK_AVAILABLE_IN_ALL
GdkContentProvider * gdk_content_provider_new_with_formats (GdkContentFormats *formats,
GdkContentProviderGetBytesFunc func,
gpointer data);
G_END_DECLS
#endif /* __GDK_CONTENT_PROVIDER_IMPL_H__ */