[gtk/dnd-gestures-2: 142/242] Add an async read function for selection



commit de5aac0422675ed01633dde7bbc23bc8bd39e3b1
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Jan 3 00:14:49 2020 -0500

    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.

 gtk/gtkdragdest.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkdragdest.h |  12 +++++
 2 files changed, 154 insertions(+)
---
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);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]