[gtk+] dnd: Introduce gdk_drop_read_async() and use it



commit 803cbd576f6597f4b851c6f1b7ded98691525e5a
Author: Benjamin Otte <otte redhat com>
Date:   Sun Dec 10 01:05:37 2017 +0100

    dnd: Introduce gdk_drop_read_async() and use it
    
    This is the replacement for selection usage.
    
    Backend implementations for X11 (missing support for backwards compat
    formats like COMPOUND_TEXT) and Wayland are included.
    
    GTK code should be adapted to use gdk_drop_read_*() functions instead
    of gtk_drag_get_data().

 gdk/gdkdnd.c                 |   80 +++++++++++++++++++++++
 gdk/gdkdnd.h                 |   13 ++++
 gdk/gdkdndprivate.h          |   10 +++
 gdk/wayland/gdkdnd-wayland.c |   81 +++++++++++++++++++++++
 gdk/x11/gdkclipboard-x11.c   |    2 +-
 gdk/x11/gdkclipboard-x11.h   |    1 +
 gdk/x11/gdkdnd-x11.c         |  144 ++++++++++++++++++++++++++++++++++++++++--
 gtk/gtkdnd.c                 |  137 +++++++++++++++++++++++++++++++++++-----
 8 files changed, 447 insertions(+), 21 deletions(-)
---
diff --git a/gdk/gdkdnd.c b/gdk/gdkdnd.c
index ead7bdf..577ff73 100644
--- a/gdk/gdkdnd.c
+++ b/gdk/gdkdnd.c
@@ -310,6 +310,40 @@ gdk_drag_context_finalize (GObject *object)
 }
 
 static void
+gdk_drag_context_read_local_async (GdkDragContext      *context,
+                                   GdkContentFormats   *formats,
+                                   int                  io_priority,
+                                   GCancellable        *cancellable,
+                                   GAsyncReadyCallback  callback,
+                                   gpointer             user_data)
+{
+  GTask *task;
+
+  task = g_task_new (context, cancellable, callback, user_data);
+  g_task_set_priority (task, io_priority);
+  g_task_set_source_tag (task, gdk_drag_context_read_local_async);
+
+  g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                                 _("Reading not implemented."));
+  g_object_unref (task);
+}
+
+static GInputStream *
+gdk_drag_context_read_local_finish (GdkDragContext  *context,
+                                    const char     **out_mime_type,
+                                    GAsyncResult    *result,
+                                    GError         **error)
+{
+  g_return_val_if_fail (g_task_is_valid (result, context), NULL);
+  g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gdk_drag_context_read_local_async, NULL);
+
+  if (out_mime_type)
+    *out_mime_type = g_task_get_task_data (G_TASK (result));
+
+  return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+static void
 gdk_drag_context_class_init (GdkDragContextClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -637,6 +671,52 @@ gdk_drag_get_selection (GdkDragContext *context)
   return GDK_DRAG_CONTEXT_GET_CLASS (context)->get_selection (context);
 }
 
+void
+gdk_drop_read_async (GdkDragContext      *context,
+                     const char         **mime_types,
+                     int                  io_priority,
+                     GCancellable        *cancellable,
+                     GAsyncReadyCallback  callback,
+                     gpointer             user_data)
+{
+  GdkContentFormats *formats;
+
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (mime_types != NULL && mime_types[0] != NULL);
+  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+  g_return_if_fail (callback != NULL);
+
+  formats = gdk_content_formats_new (mime_types, g_strv_length ((char **) mime_types));
+
+  GDK_DRAG_CONTEXT_GET_CLASS (context)->read_async (context,
+                                                    formats,
+                                                    io_priority,
+                                                    cancellable,
+                                                    callback,
+                                                    user_data);
+
+  gdk_content_formats_unref (formats);
+}
+
+GInputStream *
+gdk_drop_read_finish (GdkDragContext *context,
+                      const char    **out_mime_type,
+                      GAsyncResult   *result,
+                      GError        **error)
+{
+  g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  if (g_async_result_is_tagged (result, gdk_drag_context_read_local_async))
+    {
+      return gdk_drag_context_read_local_finish (context, out_mime_type, result, error);
+    }
+  else
+    {
+      return GDK_DRAG_CONTEXT_GET_CLASS (context)->read_finish (context, out_mime_type, result, error);
+    }
+}
+
 /**
  * gdk_drag_context_get_drag_window:
  * @context: a #GdkDragContext
diff --git a/gdk/gdkdnd.h b/gdk/gdkdnd.h
index 85f8fa0..70c69e1 100644
--- a/gdk/gdkdnd.h
+++ b/gdk/gdkdnd.h
@@ -121,6 +121,19 @@ void             gdk_drop_finish        (GdkDragContext   *context,
 GDK_AVAILABLE_IN_ALL
 GdkAtom          gdk_drag_get_selection (GdkDragContext   *context);
 
+GDK_AVAILABLE_IN_3_94
+void                    gdk_drop_read_async             (GdkDragContext        *context,
+                                                         const char           **mime_types,
+                                                         int                    io_priority,
+                                                         GCancellable          *cancellable,
+                                                         GAsyncReadyCallback    callback,
+                                                         gpointer               user_data);
+GDK_AVAILABLE_IN_3_94
+GInputStream *          gdk_drop_read_finish            (GdkDragContext        *context,
+                                                         const char           **out_mime_type,
+                                                         GAsyncResult          *result,
+                                                         GError               **error);
+
 /* Source side */
 
 GDK_AVAILABLE_IN_ALL
diff --git a/gdk/gdkdndprivate.h b/gdk/gdkdndprivate.h
index 78ae19b..e44e49b 100644
--- a/gdk/gdkdndprivate.h
+++ b/gdk/gdkdndprivate.h
@@ -87,6 +87,16 @@ struct _GdkDragContextClass {
   void        (*drop_finish)   (GdkDragContext  *context,
                                 gboolean         success,
                                 guint32          time_);
+  void                  (* read_async)                          (GdkDragContext         *context,
+                                                                 GdkContentFormats      *formats,
+                                                                 int                     io_priority,
+                                                                 GCancellable           *cancellable,
+                                                                 GAsyncReadyCallback     callback,
+                                                                 gpointer                user_data);
+  GInputStream *        (* read_finish)                         (GdkDragContext         *context,
+                                                                 const char            **out_mime_type,
+                                                                 GAsyncResult           *result,
+                                                                 GError                **error);
   gboolean    (*drop_status)   (GdkDragContext  *context);
   GdkWindow*  (*get_drag_window) (GdkDragContext *context);
   void        (*set_hotspot)   (GdkDragContext  *context,
diff --git a/gdk/wayland/gdkdnd-wayland.c b/gdk/wayland/gdkdnd-wayland.c
index a7281b8..b64f487 100644
--- a/gdk/wayland/gdkdnd-wayland.c
+++ b/gdk/wayland/gdkdnd-wayland.c
@@ -24,10 +24,14 @@
 #include "gdkprivate-wayland.h"
 #include "gdkcontentformats.h"
 #include "gdkdisplay-wayland.h"
+#include "gdkintl.h"
 #include "gdkseat-wayland.h"
 
 #include "gdkdeviceprivate.h"
 
+#include <glib-unix.h>
+#include <gio/gunixinputstream.h>
+#include <gio/gunixoutputstream.h>
 #include <string.h>
 
 #define GDK_TYPE_WAYLAND_DRAG_CONTEXT              (gdk_wayland_drag_context_get_type ())
@@ -324,6 +328,80 @@ gdk_wayland_drag_context_drop_finish (GdkDragContext *context,
   gdk_wayland_selection_set_offer (display, selection, NULL);
 }
 
+static void
+gdk_wayland_drag_context_read_async (GdkDragContext      *context,
+                                     GdkContentFormats   *formats,
+                                     int                  io_priority,
+                                     GCancellable        *cancellable,
+                                     GAsyncReadyCallback  callback,
+                                     gpointer             user_data)
+{
+  GdkDisplay *display;
+  GdkContentFormats *dnd_formats;
+  GInputStream *stream;
+  struct wl_data_offer *offer;
+  const char *mime_type;
+  int pipe_fd[2];
+  GError *error = NULL;
+  GTask *task;
+
+  display = gdk_drag_context_get_display (context),
+  task = g_task_new (context, cancellable, callback, user_data);
+  g_task_set_priority (task, io_priority);
+  g_task_set_source_tag (task, gdk_wayland_drag_context_read_async);
+
+  GDK_NOTE (DND, char *s = gdk_content_formats_to_string (formats);
+                 g_printerr ("%p: read for %s\n", context, s);
+                 g_free (s); );
+  dnd_formats = gdk_wayland_selection_get_targets (display,
+                                                   gdk_drag_get_selection (context));                      
+  mime_type = gdk_content_formats_match_mime_type (formats, dnd_formats);
+  if (mime_type == NULL)
+    {
+      g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                               _("No compatible transfer format found"));
+      return;
+    }
+  /* offer formats should be empty if we have no offer */
+  offer = gdk_wayland_selection_get_offer (display,
+                                           gdk_drag_get_selection (context));
+  g_assert (offer);
+
+  g_task_set_task_data (task, (gpointer) mime_type, NULL);
+
+  if (!g_unix_open_pipe (pipe_fd, FD_CLOEXEC, &error))
+    {
+      g_task_return_error (task, error);
+      return;
+    }
+
+  wl_data_offer_accept (offer,
+                        _gdk_wayland_display_get_serial (GDK_WAYLAND_DISPLAY (display)),
+                        mime_type);
+  wl_data_offer_receive (offer, mime_type, pipe_fd[1]);
+  stream = g_unix_input_stream_new (pipe_fd[0], TRUE);
+  close (pipe_fd[1]);
+  g_task_return_pointer (task, stream, g_object_unref);
+}
+
+static GInputStream *
+gdk_wayland_drag_context_read_finish (GdkDragContext  *context,
+                                      const char     **out_mime_type,
+                                      GAsyncResult    *result,
+                                      GError         **error)
+{
+  GTask *task;
+
+  g_return_val_if_fail (g_task_is_valid (result, G_OBJECT (context)), NULL);
+  task = G_TASK (result);
+  g_return_val_if_fail (g_task_get_source_tag (task) == gdk_wayland_drag_context_read_async, NULL);
+
+  if (out_mime_type)
+    *out_mime_type = g_task_get_task_data (task);
+
+  return g_task_propagate_pointer (task, error);
+}
+
 static gboolean
 gdk_wayland_drag_context_drop_status (GdkDragContext *context)
 {
@@ -471,6 +549,9 @@ gdk_wayland_drag_context_class_init (GdkWaylandDragContextClass *klass)
   context_class->drag_drop = gdk_wayland_drag_context_drag_drop;
   context_class->drop_reply = gdk_wayland_drag_context_drop_reply;
   context_class->drop_finish = gdk_wayland_drag_context_drop_finish;
+  context_class->drop_finish = gdk_wayland_drag_context_drop_finish;
+  context_class->read_async = gdk_wayland_drag_context_read_async;
+  context_class->read_finish = gdk_wayland_drag_context_read_finish;
   context_class->drop_status = gdk_wayland_drag_context_drop_status;
   context_class->get_selection = gdk_wayland_drag_context_get_selection;
   context_class->get_drag_window = gdk_wayland_drag_context_get_drag_window;
diff --git a/gdk/x11/gdkclipboard-x11.c b/gdk/x11/gdkclipboard-x11.c
index f6d7b8c..817792e 100644
--- a/gdk/x11/gdkclipboard-x11.c
+++ b/gdk/x11/gdkclipboard-x11.c
@@ -287,7 +287,7 @@ static const struct {
   { "SAVE_TARGETS",  NULL,                       NULL,              "NULL",          32, handle_save_targets 
}
 };
 
-static GSList *
+GSList *
 gdk_x11_clipboard_formats_to_targets (GdkContentFormats *formats)
 {
   GSList *targets;
diff --git a/gdk/x11/gdkclipboard-x11.h b/gdk/x11/gdkclipboard-x11.h
index a4ed9d4..0c0322d 100644
--- a/gdk/x11/gdkclipboard-x11.h
+++ b/gdk/x11/gdkclipboard-x11.h
@@ -36,6 +36,7 @@ GType                   gdk_x11_clipboard_get_type              (void) G_GNUC_CO
 GdkClipboard *          gdk_x11_clipboard_new                   (GdkDisplay             *display,
                                                                  const gchar            *selection);
 
+GSList *                gdk_x11_clipboard_formats_to_targets    (GdkContentFormats      *formats);
 
 G_END_DECLS
 
diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c
index 85a98c5..9b626e2 100644
--- a/gdk/x11/gdkdnd-x11.c
+++ b/gdk/x11/gdkdnd-x11.c
@@ -25,16 +25,19 @@
 #include "config.h"
 
 #include "gdkx11dnd.h"
-#include "gdkdndprivate.h"
-#include "gdkdeviceprivate.h"
 
-#include "gdkinternals.h"
 #include "gdkasync.h"
-#include "gdkcontentformatsprivate.h"
+#include "gdkclipboardprivate.h"
+#include "gdkclipboard-x11.h"
+#include "gdkdeviceprivate.h"
+#include "gdkdisplay-x11.h"
+#include "gdkdndprivate.h"
+#include "gdkinternals.h"
+#include "gdkintl.h"
 #include "gdkproperty.h"
 #include "gdkprivate-x11.h"
 #include "gdkscreen-x11.h"
-#include "gdkdisplay-x11.h"
+#include "gdkselectioninputstream-x11.h"
 
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
@@ -243,6 +246,135 @@ static void        gdk_x11_drag_context_drop_performed (GdkDragContext *context,
                                                         guint32         time);
 
 static void
+gdk_x11_drag_context_read_got_stream (GObject      *source,
+                                      GAsyncResult *res,
+                                      gpointer      data)
+{
+  GTask *task = data;
+  GError *error = NULL;
+  GInputStream *stream;
+  const char *type;
+  int format;
+  
+  stream = gdk_x11_selection_input_stream_new_finish (res, &type, &format, &error);
+  if (stream == NULL)
+    {
+      GSList *targets, *next;
+      
+      targets = g_task_get_task_data (task);
+      next = targets->next;
+      if (next)
+        {
+          GdkDragContext *context = GDK_DRAG_CONTEXT (g_task_get_source_object (task));
+
+          GDK_NOTE (DND, g_printerr ("reading %s failed, trying %s next\n",
+                                     (char *) targets->data, (char *) next->data));
+          targets->next = NULL;
+          g_task_set_task_data (task, next, (GDestroyNotify) g_slist_free);
+          gdk_x11_selection_input_stream_new_async (gdk_drag_context_get_display (context),
+                                                    gdk_drag_get_selection (context),
+                                                    next->data,
+                                                    CurrentTime,
+                                                    g_task_get_priority (task),
+                                                    g_task_get_cancellable (task),
+                                                    gdk_x11_drag_context_read_got_stream,
+                                                    task);
+          g_error_free (error);
+          return;
+        }
+
+      g_task_return_error (task, error);
+    }
+  else
+    {
+      const char *mime_type = ((GSList *) g_task_get_task_data (task))->data;
+#if 0
+      gsize i;
+
+      for (i = 0; i < G_N_ELEMENTS (special_targets); i++)
+        {
+          if (g_str_equal (mime_type, special_targets[i].x_target))
+            {
+              g_assert (special_targets[i].mime_type != NULL);
+
+              GDK_NOTE(CLIPBOARD, g_printerr ("%s: reading with converter from %s to %s\n",
+                                              cb->selection, mime_type, special_targets[i].mime_type));
+              mime_type = g_intern_string (special_targets[i].mime_type);
+              g_task_set_task_data (task, g_slist_prepend (NULL, (gpointer) mime_type), (GDestroyNotify) 
g_slist_free);
+              stream = special_targets[i].convert (cb, stream, type, format);
+              break;
+            }
+        }
+#endif
+
+      GDK_NOTE(DND, g_printerr ("reading DND as %s now\n",
+                                mime_type));
+      g_task_return_pointer (task, stream, g_object_unref);
+    }
+
+  g_object_unref (task);
+}
+
+static void
+gdk_x11_drag_context_read_async (GdkDragContext      *context,
+                                 GdkContentFormats   *formats,
+                                 int                  io_priority,
+                                 GCancellable        *cancellable,
+                                 GAsyncReadyCallback  callback,
+                                 gpointer             user_data)
+{
+  GSList *targets;
+  GTask *task;
+
+  task = g_task_new (context, cancellable, callback, user_data);
+  g_task_set_priority (task, io_priority);
+  g_task_set_source_tag (task, gdk_x11_drag_context_read_async);
+
+  targets = gdk_x11_clipboard_formats_to_targets (formats);
+  g_task_set_task_data (task, targets, (GDestroyNotify) g_slist_free);
+  if (targets == NULL)
+    {
+      g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                               _("No compatible transfer format found"));
+      return;
+    }
+
+  GDK_NOTE(DND, g_printerr ("new read for %s (%u other options)\n",
+                            (char *) targets->data, g_slist_length (targets->next)));
+  gdk_x11_selection_input_stream_new_async (gdk_drag_context_get_display (context),
+                                            gdk_drag_get_selection (context),
+                                            targets->data,
+                                            CurrentTime,
+                                            io_priority,
+                                            cancellable,
+                                            gdk_x11_drag_context_read_got_stream,
+                                            task);
+}
+
+static GInputStream *
+gdk_x11_drag_context_read_finish (GdkDragContext  *context,
+                                  const char     **out_mime_type,
+                                  GAsyncResult    *result,
+                                  GError         **error)
+{
+  GTask *task;
+
+  g_return_val_if_fail (g_task_is_valid (result, G_OBJECT (context)), NULL);
+  task = G_TASK (result);
+  g_return_val_if_fail (g_task_get_source_tag (task) == gdk_x11_drag_context_read_async, NULL);
+
+  if (out_mime_type)
+    {
+      GSList *targets;
+
+      targets = g_task_get_task_data (task);
+      *out_mime_type = targets ? targets->data : NULL;
+    }
+
+  return g_task_propagate_pointer (task, error);
+}
+
+static void
 gdk_x11_drag_context_class_init (GdkX11DragContextClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -258,6 +390,8 @@ gdk_x11_drag_context_class_init (GdkX11DragContextClass *klass)
   context_class->drop_reply = gdk_x11_drag_context_drop_reply;
   context_class->drop_finish = gdk_x11_drag_context_drop_finish;
   context_class->drop_status = gdk_x11_drag_context_drop_status;
+  context_class->read_async = gdk_x11_drag_context_read_async;
+  context_class->read_finish = gdk_x11_drag_context_read_finish;
   context_class->get_selection = gdk_x11_drag_context_get_selection;
   context_class->get_drag_window = gdk_x11_drag_context_get_drag_window;
   context_class->set_hotspot = gdk_x11_drag_context_set_hotspot;
diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c
index 1526a3f..fd28212 100644
--- a/gtk/gtkdnd.c
+++ b/gtk/gtkdnd.c
@@ -326,6 +326,115 @@ gtk_drag_get_event_actions (const GdkEvent *event,
  * Destination side *
  ********************/
 
+typedef struct {
+  GdkDragContext *context;
+  GtkWidget *widget;
+  const char *mime_type;
+  guint time;
+} GtkDragGetData;
+
+static void
+gtk_drag_get_data_finish (GtkDragGetData *data,
+                          guchar         *bytes,
+                          gsize           size)
+{
+  GtkDragDestSite *site;
+  GtkSelectionData sdata;
+
+  site = g_object_get_data (G_OBJECT (data->widget), "gtk-drag-dest");
+
+  sdata.selection = gdk_drag_get_selection (data->context);
+  sdata.target = data->mime_type;
+  sdata.type = data->mime_type;
+  sdata.format = 8;
+  sdata.length = size;
+  sdata.data = bytes;
+  sdata.display = gtk_widget_get_display (data->widget);
+  
+  if (site && site->target_list)
+    {
+      if (gdk_content_formats_contain_mime_type (site->target_list, data->mime_type))
+        {
+          if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
+              size >= 0)
+            g_signal_emit_by_name (data->widget,
+                                   "drag-data-received",
+                                   data->context,
+                                   &sdata,
+                                   data->time);
+        }
+    }
+  else
+    {
+      g_signal_emit_by_name (data->widget,
+                             "drag-data-received",
+                             data->context,
+                             &sdata,
+                             data->time);
+    }
+  
+  if (site && site->flags & GTK_DEST_DEFAULT_DROP)
+    {
+
+      gtk_drag_finish (data->context, 
+                       size > 0,
+                       (gdk_drag_context_get_selected_action (data->context) == GDK_ACTION_MOVE),
+                       data->time);
+    }
+  
+  g_object_unref (data->widget);
+  g_slice_free (GtkDragGetData, data);
+}
+
+static void
+gtk_drag_get_data_got_data (GObject      *source,
+                            GAsyncResult *result,
+                            gpointer      data)
+{
+  gssize written;
+
+  written = g_output_stream_splice_finish (G_OUTPUT_STREAM (source), result, NULL);
+  if (written < 0)
+    {
+      gtk_drag_get_data_finish (data, NULL, 0);
+    }
+  else
+    {
+      gtk_drag_get_data_finish (data,
+                                g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (source)),
+                                g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (source)));
+    }
+}
+
+static void
+gtk_drag_get_data_got_stream (GObject      *source,
+                              GAsyncResult *result,
+                              gpointer      user_data)
+{
+  GtkDragGetData *data = user_data;
+  GInputStream *input_stream;
+  GOutputStream *output_stream;
+
+  input_stream = gdk_drop_read_finish (GDK_DRAG_CONTEXT (source), &data->mime_type, result, NULL);
+  if (input_stream == NULL)
+    {
+      gtk_drag_get_data_finish (data, NULL, 0);
+      return;
+    }
+
+  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,
+                                data);
+  g_object_unref (output_stream);
+  g_object_unref (input_stream);
+
+}
+
 /**
  * gtk_drag_get_data: (method)
  * @widget: the widget that will receive the
@@ -351,25 +460,23 @@ gtk_drag_get_data (GtkWidget      *widget,
                    GdkAtom         target,
                    guint32         time_)
 {
-  GtkWidget *selection_widget;
+  GtkDragGetData *data;
 
   g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
 
-  selection_widget = gtk_drag_get_ipc_widget (widget);
-
-  g_object_ref (context);
-  g_object_ref (widget);
-
-  g_signal_connect (selection_widget, "selection-received",
-                    G_CALLBACK (gtk_drag_selection_received), widget);
-
-  g_object_set_data (G_OBJECT (selection_widget), I_("drag-context"), context);
-
-  gtk_selection_convert (selection_widget,
-                         gdk_drag_get_selection (context),
-                         target,
-                         time_);
+  data = g_slice_new0 (GtkDragGetData);
+  data->widget = g_object_ref (widget);
+  data->context = context;
+  data->mime_type = target;
+  data->time = time_;
+
+  gdk_drop_read_async (context,
+                       (const gchar *[2]) { target, NULL },
+                       G_PRIORITY_DEFAULT,
+                       NULL,
+                       gtk_drag_get_data_got_stream,
+                       data);
 }
 
 /**


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