From: Matthias Clasen Date: Fri, 3 Jan 2020 05:14:49 +0000 (-0500) Subject: Add an async read function for selection X-Git-Tag: archive/raspbian/4.4.1+ds1-2+rpi1^2~18^2~20^2~354^2~127 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=c290bd63676bb1a05fccd8154b6a953275531318;p=gtk4.git Add an async read function for selection This is meant as a replacement for ::drag-data-received in cases where a #GtkSelectionData object is still needed, such as when using GtkTreeModel DND support. --- diff --git a/gtk/gtkdragdest.c b/gtk/gtkdragdest.c index d079c198d3..22e7519537 100644 --- a/gtk/gtkdragdest.c +++ b/gtk/gtkdragdest.c @@ -34,6 +34,7 @@ #include "gtktypebuiltins.h" #include "gtkeventcontroller.h" #include "gtkmarshalers.h" +#include "gtkselectionprivate.h" static void @@ -794,3 +795,144 @@ gtk_drag_unhighlight (GtkWidget *widget) gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE); } + + +static void +gtk_drag_get_data_got_data (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GTask *task = data; + gssize written; + GError *error = NULL; + guchar *bytes; + gsize size; + GtkSelectionData *sdata; + GtkDropTarget *dest; + GdkDrop *drop; + GdkDisplay *display; + + written = g_output_stream_splice_finish (G_OUTPUT_STREAM (source), result, &error); + if (written < 0) + { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + bytes = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (source)); + size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (source)); + + dest = GTK_DROP_TARGET (g_task_get_source_object (task)); + drop = GDK_DROP (g_object_get_data (G_OBJECT (task), "drop")); + display = GDK_DISPLAY (g_object_get_data (G_OBJECT (task), "display")); + + sdata = g_slice_new0 (GtkSelectionData); + sdata->target = g_task_get_task_data (task); + sdata->type = g_task_get_task_data (task); + sdata->format = 8; + sdata->length = size; + sdata->data = bytes ? bytes : (guchar *)g_strdup (""); + sdata->display = display; + + set_drop (dest, drop); + g_task_return_pointer (task, sdata, NULL); + set_drop (dest, NULL); + + g_object_unref (task); +} + +static void +gtk_drag_get_data_got_stream (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GTask *task = data; + GInputStream *input_stream; + GOutputStream *output_stream; + GError *error = NULL; + const char *mime_type; + + input_stream = gdk_drop_read_finish (GDK_DROP (source), result, &mime_type, &error); + if (input_stream == NULL) + { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + g_task_set_task_data (task, (gpointer)g_intern_string (mime_type), NULL); + + output_stream = g_memory_output_stream_new_resizable (); + g_output_stream_splice_async (output_stream, + input_stream, + G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, + G_PRIORITY_DEFAULT, + NULL, + gtk_drag_get_data_got_data, + task); + g_object_unref (output_stream); + g_object_unref (input_stream); +} + +/** + * gtk_drop_target_read_selection: + * @dest: a #GtkDropTarget + * @target: the data format to read + * @cancellable: (nullable): a cancellable + * @callback: callback to call on completion + * @user_data: data to pass to @callback + * + * Asynchronously reads the dropped data from an ongoing + * drag on a #GtkDropTarget, and returns the data in a + * #GtkSelectionData object. + * + * This function is meant for cases where a #GtkSelectionData + * object is needed, such as when using the #GtkTreeModel DND + * support. In most other cases, the #GdkDrop async read + * APIs that return in input stream or #GValue are more + * convenient and should be preferred. + */ +void +gtk_drop_target_read_selection (GtkDropTarget *dest, + GdkAtom target, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + g_return_if_fail (GTK_IS_DROP_TARGET (dest)); + + task = g_task_new (dest, NULL, callback, user_data); + g_object_set_data_full (G_OBJECT (task), "drop", g_object_ref (dest->drop), g_object_unref); + if (dest->widget) + g_object_set_data (G_OBJECT (task), "display", gtk_widget_get_display (dest->widget)); + + gdk_drop_read_async (dest->drop, + (const char *[2]) { target, NULL }, + G_PRIORITY_DEFAULT, + NULL, + gtk_drag_get_data_got_stream, + task); +} + +/** + * gtk_drop_target_read_selection_finish: + * @dest: a #GtkDropTarget + * @result: a #GAsyncResult + * @error: (allow-none): location to store error information on failure, or %NULL + * + * Finishes an async drop read operation, see gtk_drop_target_read_selection(). + * + * Returns: (nullable) (transfer full): the #GtkSelectionData, or %NULL + */ +GtkSelectionData * +gtk_drop_target_read_selection_finish (GtkDropTarget *dest, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} diff --git a/gtk/gtkdragdest.h b/gtk/gtkdragdest.h index 5c48fd7227..24190d8120 100644 --- a/gtk/gtkdragdest.h +++ b/gtk/gtkdragdest.h @@ -125,6 +125,18 @@ GtkWidget *gtk_drop_target_get_target (GtkDropTarget *dest); GDK_AVAILABLE_IN_ALL const char *gtk_drop_target_find_mimetype (GtkDropTarget *dest); +GDK_AVAILABLE_IN_ALL +void gtk_drop_target_read_selection (GtkDropTarget *dest, + GdkAtom target, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer data); +GDK_AVAILABLE_IN_ALL +GtkSelectionData *gtk_drop_target_read_selection_finish + (GtkDropTarget *dest, + GAsyncResult *result, + GError **error); + GDK_AVAILABLE_IN_ALL void gtk_drag_highlight (GtkWidget *widget);