summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdk/broadway/gdkdnd-broadway.c13
-rw-r--r--gdk/broadway/gdkprivate-broadway.h12
-rw-r--r--gdk/gdkdnd.c173
-rw-r--r--gdk/gdkdnd.h2
-rw-r--r--gdk/gdkdndprivate.h11
-rw-r--r--gdk/gdkwindow.c23
-rw-r--r--gdk/gdkwindowimpl.h2
-rw-r--r--gdk/wayland/gdkdnd-wayland.c14
-rw-r--r--gdk/wayland/gdkprivate-wayland.h2
-rw-r--r--gdk/wayland/gdkselection-wayland.c120
-rw-r--r--gdk/x11/gdkdnd-x11.c14
-rw-r--r--gdk/x11/gdkprivate-x11.h12
-rw-r--r--gtk/gtkdnd.c156
13 files changed, 422 insertions, 132 deletions
diff --git a/gdk/broadway/gdkdnd-broadway.c b/gdk/broadway/gdkdnd-broadway.c
index c670d8d3d9..3747ca1e88 100644
--- a/gdk/broadway/gdkdnd-broadway.c
+++ b/gdk/broadway/gdkdnd-broadway.c
@@ -84,12 +84,12 @@ gdk_broadway_drag_context_finalize (GObject *object)
/* Drag Contexts */
GdkDragContext *
-_gdk_broadway_window_drag_begin (GdkWindow *window,
- GdkDevice *device,
- GdkContentFormats *formats,
- GdkDragAction actions,
- gint dx,
- gint dy)
+_gdk_broadway_window_drag_begin (GdkWindow *window,
+ GdkDevice *device,
+ GdkContentProvider *content,
+ GdkDragAction actions,
+ gint dx,
+ gint dy)
{
GdkDragContext *new_context;
@@ -98,6 +98,7 @@ _gdk_broadway_window_drag_begin (GdkWindow *window,
new_context = g_object_new (GDK_TYPE_BROADWAY_DRAG_CONTEXT,
"display", gdk_window_get_display (window),
+ "content", content,
NULL);
return new_context;
diff --git a/gdk/broadway/gdkprivate-broadway.h b/gdk/broadway/gdkprivate-broadway.h
index bc40ea9c32..39523a9079 100644
--- a/gdk/broadway/gdkprivate-broadway.h
+++ b/gdk/broadway/gdkprivate-broadway.h
@@ -47,12 +47,12 @@ void gdk_broadway_window_set_nodes (GdkWindow *window,
GPtrArray *node_textures);
void _gdk_broadway_window_register_dnd (GdkWindow *window);
-GdkDragContext * _gdk_broadway_window_drag_begin (GdkWindow *window,
- GdkDevice *device,
- GdkContentFormats *formats,
- GdkDragAction actions,
- gint dx,
- gint dy);
+GdkDragContext * _gdk_broadway_window_drag_begin (GdkWindow *window,
+ GdkDevice *device,
+ GdkContentProvider *content,
+ GdkDragAction actions,
+ gint dx,
+ gint dy);
void _gdk_broadway_window_translate (GdkWindow *window,
cairo_region_t *area,
gint dx,
diff --git a/gdk/gdkdnd.c b/gdk/gdkdnd.c
index 956be1a196..2344b7ee65 100644
--- a/gdk/gdkdnd.c
+++ b/gdk/gdkdnd.c
@@ -29,6 +29,8 @@
#include "gdkwindow.h"
#include "gdkintl.h"
#include "gdkcontentformats.h"
+#include "gdkcontentprovider.h"
+#include "gdkcontentserializer.h"
#include "gdkcursor.h"
#include "gdkenumtypes.h"
#include "gdkeventsprivate.h"
@@ -48,7 +50,9 @@ static struct {
enum {
PROP_0,
+ PROP_CONTENT,
PROP_DISPLAY,
+ PROP_FORMATS,
N_PROPERTIES
};
@@ -261,6 +265,12 @@ gdk_drag_context_set_property (GObject *gobject,
switch (prop_id)
{
+ case PROP_CONTENT:
+ context->content = g_value_dup_object (value);
+ if (context->content)
+ context->formats = gdk_content_provider_ref_formats (context->content);
+ break;
+
case PROP_DISPLAY:
context->display = g_value_get_object (value);
g_assert (context->display != NULL);
@@ -282,10 +292,18 @@ gdk_drag_context_get_property (GObject *gobject,
switch (prop_id)
{
+ case PROP_CONTENT:
+ g_value_set_object (value, context->content);
+ break;
+
case PROP_DISPLAY:
g_value_set_object (value, context->display);
break;
+ case PROP_FORMATS:
+ g_value_set_boxed (value, context->formats);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@@ -298,6 +316,8 @@ gdk_drag_context_finalize (GObject *object)
GdkDragContext *context = GDK_DRAG_CONTEXT (object);
contexts = g_list_remove (contexts, context);
+
+ g_clear_object (&context->content);
g_clear_pointer (&context->formats, gdk_content_formats_unref);
if (context->source_window)
@@ -353,6 +373,24 @@ gdk_drag_context_class_init (GdkDragContextClass *klass)
object_class->finalize = gdk_drag_context_finalize;
/**
+ * GdkDragContext:content:
+ *
+ * The #GdkContentProvider or %NULL if the context is not a source-side
+ * context.
+ *
+ * Since: 3.94
+ */
+ properties[PROP_CONTENT] =
+ g_param_spec_object ("content",
+ "Content",
+ "The content being dragged",
+ GDK_TYPE_CONTENT_PROVIDER,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
* GdkDragContext:display:
*
* The #GdkDisplay that the drag context belongs to.
@@ -370,6 +408,22 @@ gdk_drag_context_class_init (GdkDragContextClass *klass)
G_PARAM_EXPLICIT_NOTIFY);
/**
+ * GdkDragContext:formats:
+ *
+ * The possible formats that the context can provide its data in.
+ *
+ * Since: 3.94
+ */
+ properties[PROP_FORMATS] =
+ g_param_spec_boxed ("formats",
+ "Formats",
+ "The possible formats for data",
+ GDK_TYPE_CONTENT_FORMATS,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
* GdkDragContext::cancel:
* @context: The object on which the signal is emitted
* @reason: The reason the context was cancelled
@@ -655,6 +709,125 @@ gdk_drag_get_selection (GdkDragContext *context)
return GDK_DRAG_CONTEXT_GET_CLASS (context)->get_selection (context);
}
+static void
+gdk_drag_context_write_done (GObject *content,
+ GAsyncResult *result,
+ gpointer task)
+{
+ GError *error = NULL;
+
+ if (gdk_content_provider_write_mime_type_finish (GDK_CONTENT_PROVIDER (content), result, &error))
+ g_task_return_boolean (task, TRUE);
+ else
+ g_task_return_error (task, error);
+
+ g_object_unref (task);
+}
+
+static void
+gdk_drag_context_write_serialize_done (GObject *content,
+ GAsyncResult *result,
+ gpointer task)
+{
+ GError *error = NULL;
+
+ if (gdk_content_serialize_finish (result, &error))
+ g_task_return_boolean (task, TRUE);
+ else
+ g_task_return_error (task, error);
+
+ g_object_unref (task);
+}
+
+void
+gdk_drag_context_write_async (GdkDragContext *context,
+ const char *mime_type,
+ GOutputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GdkContentFormats *formats, *mime_formats;
+ GTask *task;
+ GType gtype;
+
+ g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+ g_return_if_fail (context->content);
+ g_return_if_fail (mime_type != NULL);
+ g_return_if_fail (mime_type == g_intern_string (mime_type));
+ g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ g_return_if_fail (callback != NULL);
+
+ 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_write_async);
+
+ formats = gdk_content_provider_ref_formats (context->content);
+ if (gdk_content_formats_contain_mime_type (formats, mime_type))
+ {
+ gdk_content_provider_write_mime_type_async (context->content,
+ mime_type,
+ stream,
+ io_priority,
+ cancellable,
+ gdk_drag_context_write_done,
+ task);
+ gdk_content_formats_unref (formats);
+ return;
+ }
+
+ mime_formats = gdk_content_formats_new ((const gchar *[2]) { mime_type, NULL }, 1);
+ mime_formats = gdk_content_formats_union_serialize_gtypes (mime_formats);
+ gtype = gdk_content_formats_match_gtype (formats, mime_formats);
+ if (gtype != G_TYPE_INVALID)
+ {
+ GValue value = G_VALUE_INIT;
+ GError *error = NULL;
+
+ g_assert (gtype != G_TYPE_INVALID);
+
+ g_value_init (&value, gtype);
+ if (gdk_content_provider_get_value (context->content, &value, &error))
+ {
+ gdk_content_serialize_async (stream,
+ mime_type,
+ &value,
+ io_priority,
+ cancellable,
+ gdk_drag_context_write_serialize_done,
+ g_object_ref (task));
+ }
+ else
+ {
+ g_task_return_error (task, error);
+ }
+
+ g_value_unset (&value);
+ }
+ else
+ {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("No compatible formats to transfer clipboard contents."));
+ }
+
+ gdk_content_formats_unref (mime_formats);
+ gdk_content_formats_unref (formats);
+ g_object_unref (task);
+}
+
+gboolean
+gdk_drag_context_write_finish (GdkDragContext *context,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, context), FALSE);
+ g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gdk_drag_context_write_async, FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
void
gdk_drop_read_async (GdkDragContext *context,
const char **mime_types,
diff --git a/gdk/gdkdnd.h b/gdk/gdkdnd.h
index 4a3926e589..8f75a7d1d2 100644
--- a/gdk/gdkdnd.h
+++ b/gdk/gdkdnd.h
@@ -136,7 +136,7 @@ GInputStream * gdk_drop_read_finish (GdkDragContext *
GDK_AVAILABLE_IN_ALL
GdkDragContext * gdk_drag_begin (GdkWindow *window,
GdkDevice *device,
- GdkContentFormats *formats,
+ GdkContentProvider *content,
GdkDragAction actions,
gint dx,
gint dy);
diff --git a/gdk/gdkdndprivate.h b/gdk/gdkdndprivate.h
index 5cb477acb6..127b514265 100644
--- a/gdk/gdkdndprivate.h
+++ b/gdk/gdkdndprivate.h
@@ -134,6 +134,7 @@ struct _GdkDragContext {
GdkWindow *dest_window;
GdkWindow *drag_window;
+ GdkContentProvider *content;
GdkContentFormats *formats;
GdkDragAction actions;
GdkDragAction suggested_action;
@@ -177,6 +178,16 @@ void gdk_drag_find_window (GdkDragContext *context,
GdkWindow **dest_window,
GdkDragProtocol *protocol);
+void gdk_drag_context_write_async (GdkDragContext *context,
+ const char *mime_type,
+ GOutputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean gdk_drag_context_write_finish (GdkDragContext *context,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index c504bc889b..a9a15c7eec 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -6927,7 +6927,7 @@ gdk_window_register_dnd (GdkWindow *window)
* gdk_drag_begin:
* @window: the source window for this drag
* @device: the device that controls this drag
- * @formats: (transfer none): the offered formats
+ * @content: (transfer none): the offered content
* @actions: the actions supported by this drag
* @dx: the x offset to @device's position where the drag nominally started
* @dy: the y offset to @device's position where the drag nominally started
@@ -6940,14 +6940,19 @@ gdk_window_register_dnd (GdkWindow *window)
* %NULL on error.
*/
GdkDragContext *
-gdk_drag_begin (GdkWindow *window,
- GdkDevice *device,
- GdkContentFormats *formats,
- GdkDragAction actions,
- gint dx,
- gint dy)
-{
- return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->drag_begin (window, device, formats, actions, dx, dy);
+gdk_drag_begin (GdkWindow *window,
+ GdkDevice *device,
+ GdkContentProvider *content,
+ GdkDragAction actions,
+ gint dx,
+ gint dy)
+{
+ g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (gdk_window_get_display (window) == gdk_device_get_display (device), NULL);
+ g_return_val_if_fail (GDK_IS_CONTENT_PROVIDER (content), NULL);
+
+ return GDK_WINDOW_IMPL_GET_CLASS (window->impl)->drag_begin (window, device, content, actions, dx, dy);
}
/**
diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h
index f1abe35307..4383b84538 100644
--- a/gdk/gdkwindowimpl.h
+++ b/gdk/gdkwindowimpl.h
@@ -219,7 +219,7 @@ struct _GdkWindowImplClass
void (* register_dnd) (GdkWindow *window);
GdkDragContext * (*drag_begin) (GdkWindow *window,
GdkDevice *device,
- GdkContentFormats *formats,
+ GdkContentProvider*content,
GdkDragAction actions,
gint dx,
gint dy);
diff --git a/gdk/wayland/gdkdnd-wayland.c b/gdk/wayland/gdkdnd-wayland.c
index 208b71e20d..ac849741a9 100644
--- a/gdk/wayland/gdkdnd-wayland.c
+++ b/gdk/wayland/gdkdnd-wayland.c
@@ -548,12 +548,12 @@ create_dnd_window (GdkDisplay *display)
}
GdkDragContext *
-_gdk_wayland_window_drag_begin (GdkWindow *window,
- GdkDevice *device,
- GdkContentFormats *formats,
- GdkDragAction actions,
- gint dx,
- gint dy)
+_gdk_wayland_window_drag_begin (GdkWindow *window,
+ GdkDevice *device,
+ GdkContentProvider *content,
+ GdkDragAction actions,
+ gint dx,
+ gint dy)
{
GdkWaylandDragContext *context_wayland;
GdkDragContext *context;
@@ -566,11 +566,11 @@ _gdk_wayland_window_drag_begin (GdkWindow *window,
context_wayland = g_object_new (GDK_TYPE_WAYLAND_DRAG_CONTEXT,
"display", display_wayland,
+ "content", content,
NULL);
context = GDK_DRAG_CONTEXT (context_wayland);
context->source_window = g_object_ref (window);
context->is_source = TRUE;
- context->formats = gdk_content_formats_ref (formats);
gdk_drag_context_set_device (context, device);
diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h
index 6b6e356a11..a6ee0c0cdb 100644
--- a/gdk/wayland/gdkprivate-wayland.h
+++ b/gdk/wayland/gdkprivate-wayland.h
@@ -93,7 +93,7 @@ void gdk_wayland_window_sync (GdkWindow *window);
void _gdk_wayland_window_register_dnd (GdkWindow *window);
GdkDragContext *_gdk_wayland_window_drag_begin (GdkWindow *window,
GdkDevice *device,
- GdkContentFormats *formats,
+ GdkContentProvider *content,
GdkDragAction actions,
gint dx,
gint dy);
diff --git a/gdk/wayland/gdkselection-wayland.c b/gdk/wayland/gdkselection-wayland.c
index 4634033ab4..6d1904822a 100644
--- a/gdk/wayland/gdkselection-wayland.c
+++ b/gdk/wayland/gdkselection-wayland.c
@@ -753,63 +753,6 @@ gdk_wayland_selection_lookup_requestor_buffer (GdkWindow *requestor)
return NULL;
}
-static gboolean
-gdk_wayland_selection_source_handles_target (GdkWaylandSelection *wayland_selection,
- GdkAtom target)
-{
- GdkAtom atom;
- guint i;
-
- if (target == NULL)
- return FALSE;
-
- for (i = 0; i < wayland_selection->source_targets->len; i++)
- {
- atom = g_array_index (wayland_selection->source_targets, GdkAtom, i);
-
- if (atom == target)
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-gdk_wayland_selection_request_target (GdkWaylandSelection *wayland_selection,
- GdkWindow *window,
- GdkAtom selection,
- GdkAtom target,
- gint fd)
-{
- if (wayland_selection->stored_selection.fd == fd &&
- wayland_selection->requested_target == target)
- return FALSE;
-
- /* If we didn't issue gdk_wayland_selection_check_write() yet
- * on a previous fd, it will still linger here. Just close it,
- * as we can't have more than one fd on the fly.
- */
- if (wayland_selection->stored_selection.fd >= 0)
- close (wayland_selection->stored_selection.fd);
-
- wayland_selection->stored_selection.fd = fd;
- wayland_selection->requested_target = target;
-
- if (window &&
- gdk_wayland_selection_source_handles_target (wayland_selection, target))
- {
- gdk_wayland_selection_emit_request (window, selection, target);
- return TRUE;
- }
- else
- {
- close (fd);
- wayland_selection->stored_selection.fd = -1;
- }
-
- return FALSE;
-}
-
static void
data_source_target (void *data,
struct wl_data_source *source,
@@ -821,44 +764,47 @@ data_source_target (void *data,
}
static void
-data_source_send (void *data,
- struct wl_data_source *source,
- const char *mime_type,
- int32_t fd)
+gdk_wayland_drag_context_write_done (GObject *context,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GdkWaylandSelection *wayland_selection = data;
- GdkWindow *window;
- GdkAtom selection;
-
- GDK_NOTE (EVENTS,
- g_message ("data source send, source = %p, mime_type = %s, fd = %d",
- source, mime_type, fd));
+ GError *error = NULL;
- if (!mime_type)
+ if (!gdk_drag_context_write_finish (GDK_DRAG_CONTEXT (context), result, &error))
{
- close (fd);
- return;
+ GDK_NOTE(DND, g_printerr ("%p: failed to write stream: %s\n", context, error->message));
+ g_error_free (error);
}
+}
- if (source == wayland_selection->dnd_source)
- {
- window = wayland_selection->dnd_owner;
- selection = atoms[ATOM_DND];
- }
- else
- {
- close (fd);
- return;
- }
+static void
+data_source_send (void *data,
+ struct wl_data_source *source,
+ const char *mime_type,
+ int32_t fd)
+{
+ GdkDragContext *context;
+ GOutputStream *stream;
- if (!window)
+ context = gdk_wayland_drag_context_lookup_by_data_source (source);
+ if (!context)
return;
- if (!gdk_wayland_selection_request_target (wayland_selection, window,
- selection,
- gdk_atom_intern (mime_type, FALSE),
- fd))
- gdk_wayland_selection_check_write (wayland_selection);
+ GDK_NOTE (DND, g_printerr ("%p: data source send request for %s on fd %d\n",
+ source, mime_type, fd));
+
+ //mime_type = gdk_intern_mime_type (mime_type);
+ mime_type = g_intern_string (mime_type);
+ stream = g_unix_output_stream_new (fd, TRUE);
+
+ gdk_drag_context_write_async (context,
+ mime_type,
+ stream,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ gdk_wayland_drag_context_write_done,
+ context);
+ g_object_unref (stream);
}
static void
diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c
index 3443fb2a28..c36c10bf41 100644
--- a/gdk/x11/gdkdnd-x11.c
+++ b/gdk/x11/gdkdnd-x11.c
@@ -2857,25 +2857,25 @@ drag_context_ungrab (GdkDragContext *context)
}
GdkDragContext *
-_gdk_x11_window_drag_begin (GdkWindow *window,
- GdkDevice *device,
- GdkContentFormats *formats,
- GdkDragAction actions,
- gint dx,
- gint dy)
+_gdk_x11_window_drag_begin (GdkWindow *window,
+ GdkDevice *device,
+ GdkContentProvider *content,
+ GdkDragAction actions,
+ gint dx,
+ gint dy)
{
GdkDragContext *context;
int x_root, y_root;
context = (GdkDragContext *) g_object_new (GDK_TYPE_X11_DRAG_CONTEXT,
"display", gdk_window_get_display (window),
+ "content", content,
NULL);
context->is_source = TRUE;
context->source_window = window;
g_object_ref (window);
- context->formats = gdk_content_formats_ref (formats);
precache_target_list (context);
gdk_drag_context_set_device (context, device);
diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h
index 8d0919763e..6ebd0e8eb1 100644
--- a/gdk/x11/gdkprivate-x11.h
+++ b/gdk/x11/gdkprivate-x11.h
@@ -282,12 +282,12 @@ void _gdk_x11_cursor_display_finalize (GdkDisplay *display);
void _gdk_x11_window_register_dnd (GdkWindow *window);
-GdkDragContext * _gdk_x11_window_drag_begin (GdkWindow *window,
- GdkDevice *device,
- GdkContentFormats *formats,
- GdkDragAction actions,
- gint x_root,
- gint y_root);
+GdkDragContext * _gdk_x11_window_drag_begin (GdkWindow *window,
+ GdkDevice *device,
+ GdkContentProvider *content,
+ GdkDragAction actions,
+ gint dx,
+ gint dy);
GdkGrabStatus _gdk_x11_convert_grab_status (gint status);
diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c
index 085a7a9774..dd2a0034e0 100644
--- a/gtk/gtkdnd.c
+++ b/gtk/gtkdnd.c
@@ -960,6 +960,150 @@ gtk_drag_dest_drop (GtkWidget *widget,
* Source side *
***************/
+#define GTK_TYPE_DRAG_CONTENT (gtk_drag_content_get_type ())
+#define GTK_DRAG_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_DRAG_CONTENT, GtkDragContent))
+#define GTK_IS_DRAG_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_DRAG_CONTENT))
+#define GTK_DRAG_CONTENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_DRAG_CONTENT, GtkDragContentClass))
+#define GTK_IS_DRAG_CONTENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_DRAG_CONTENT))
+#define GTK_DRAG_CONTENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_DRAG_CONTENT, GtkDragContentClass))
+
+typedef struct _GtkDragContent GtkDragContent;
+typedef struct _GtkDragContentClass GtkDragContentClass;
+
+struct _GtkDragContent
+{
+ GdkContentProvider parent;
+
+ GtkWidget *widget;
+ GdkDragContext *context;
+ GdkContentFormats *formats;
+ guint32 time;
+};
+
+struct _GtkDragContentClass
+{
+ GdkContentProviderClass parent_class;
+};
+
+GType gtk_drag_content_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE (GtkDragContent, gtk_drag_content, GDK_TYPE_CONTENT_PROVIDER)
+
+static GdkContentFormats *
+gtk_drag_content_ref_formats (GdkContentProvider *provider)
+{
+ GtkDragContent *content = GTK_DRAG_CONTENT (provider);
+
+ return gdk_content_formats_ref (content->formats);
+}
+
+static void
+gtk_drag_content_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
+gtk_drag_content_write_mime_type_async (GdkContentProvider *provider,
+ const char *mime_type,
+ GOutputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GtkDragContent *content = GTK_DRAG_CONTENT (provider);
+ GtkSelectionData sdata = { 0, };
+ GTask *task;
+
+ task = g_task_new (content, cancellable, callback, user_data);
+ g_task_set_priority (task, io_priority);
+ g_task_set_source_tag (task, gtk_drag_content_write_mime_type_async);
+
+ sdata.selection = gdk_drag_get_selection (content->context);
+ sdata.target = gdk_atom_intern (mime_type, FALSE);
+ sdata.length = -1;
+ sdata.display = gtk_widget_get_display (content->widget);
+
+ g_signal_emit_by_name (content->widget, "drag-data-get",
+ content->context,
+ &sdata,
+ content->time);
+
+ if (sdata.length == -1)
+ {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Cannot provide contents as ā€œ%sā€"), mime_type);
+ g_object_unref (task);
+ return;
+ }
+ g_task_set_task_data (task, sdata.data, g_free);
+
+ g_output_stream_write_all_async (stream,
+ sdata.data,
+ sdata.length,
+ io_priority,
+ cancellable,
+ gtk_drag_content_write_mime_type_done,
+ task);
+}
+
+static gboolean
+gtk_drag_content_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)) == gtk_drag_content_write_mime_type_async, FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+gtk_drag_content_finalize (GObject *object)
+{
+ GtkDragContent *content = GTK_DRAG_CONTENT (object);
+
+ g_clear_object (&content->widget);
+ g_clear_pointer (&content->formats, (GDestroyNotify) gdk_content_formats_unref);
+
+ G_OBJECT_CLASS (gtk_drag_content_parent_class)->finalize (object);
+}
+
+static void
+gtk_drag_content_class_init (GtkDragContentClass *class)
+{
+ GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class);
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = gtk_drag_content_finalize;
+
+ provider_class->ref_formats = gtk_drag_content_ref_formats;
+ provider_class->write_mime_type_async = gtk_drag_content_write_mime_type_async;
+ provider_class->write_mime_type_finish = gtk_drag_content_write_mime_type_finish;
+}
+
+static void
+gtk_drag_content_init (GtkDragContent *content)
+{
+}
+
/* Like gtk_drag_begin(), but also takes a GtkIconHelper
* so that we can set the icon from the source site information
*/
@@ -979,6 +1123,7 @@ gtk_drag_begin_internal (GtkWidget *widget,
GdkWindow *ipc_window;
int dx, dy;
GdkAtom selection;
+ GtkDragContent *content;
guint32 time;
ipc_widget = gtk_drag_get_ipc_widget (widget);
@@ -1001,13 +1146,22 @@ gtk_drag_begin_internal (GtkWidget *widget,
dx -= x;
dy -= y;
- context = gdk_drag_begin (ipc_window, device, target_list, actions, dx, dy);
+ content = g_object_new (GTK_TYPE_DRAG_CONTENT, NULL);
+ content->widget = g_object_ref (widget);
+ content->formats = gdk_content_formats_ref (target_list);
+ content->time = time;
+
+ context = gdk_drag_begin (ipc_window, device, GDK_CONTENT_PROVIDER (content), actions, dx, dy);
if (context == NULL)
{
gtk_drag_release_ipc_widget (ipc_widget);
+ g_object_unref (content);
return NULL;
}
+ content->context = context;
+ g_object_unref (content);
+
info = gtk_drag_get_source_info (context, TRUE);
info->ipc_widget = ipc_widget;