diff options
-rw-r--r-- | gdk/broadway/gdkdnd-broadway.c | 13 | ||||
-rw-r--r-- | gdk/broadway/gdkprivate-broadway.h | 12 | ||||
-rw-r--r-- | gdk/gdkdnd.c | 173 | ||||
-rw-r--r-- | gdk/gdkdnd.h | 2 | ||||
-rw-r--r-- | gdk/gdkdndprivate.h | 11 | ||||
-rw-r--r-- | gdk/gdkwindow.c | 23 | ||||
-rw-r--r-- | gdk/gdkwindowimpl.h | 2 | ||||
-rw-r--r-- | gdk/wayland/gdkdnd-wayland.c | 14 | ||||
-rw-r--r-- | gdk/wayland/gdkprivate-wayland.h | 2 | ||||
-rw-r--r-- | gdk/wayland/gdkselection-wayland.c | 120 | ||||
-rw-r--r-- | gdk/x11/gdkdnd-x11.c | 14 | ||||
-rw-r--r-- | gdk/x11/gdkprivate-x11.h | 12 | ||||
-rw-r--r-- | gtk/gtkdnd.c | 156 |
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; |