diff options
-rw-r--r-- | gdk/wayland/gdkclipboard-wayland.c | 139 | ||||
-rw-r--r-- | gdk/wayland/gdkclipboard-wayland.h | 4 | ||||
-rw-r--r-- | gdk/wayland/gdkdevice-wayland.c | 38 | ||||
-rw-r--r-- | gdk/wayland/gdkprivate-wayland.h | 2 | ||||
-rw-r--r-- | gdk/wayland/gdkselection-wayland.c | 19 |
5 files changed, 168 insertions, 34 deletions
diff --git a/gdk/wayland/gdkclipboard-wayland.c b/gdk/wayland/gdkclipboard-wayland.c index cddc37b74c..51d5ed2f67 100644 --- a/gdk/wayland/gdkclipboard-wayland.c +++ b/gdk/wayland/gdkclipboard-wayland.c @@ -20,12 +20,21 @@ #include "gdkclipboardprivate.h" #include "gdkclipboard-wayland.h" +#include "gdkcontentformats.h" +#include "gdkintl.h" +#include "gdk-private.h" + +#include <glib-unix.h> +#include <gio/gunixinputstream.h> typedef struct _GdkWaylandClipboardClass GdkWaylandClipboardClass; struct _GdkWaylandClipboard { GdkClipboard parent; + + struct wl_data_offer *offer; + GdkContentFormats *offer_formats; }; struct _GdkWaylandClipboardClass @@ -36,28 +45,130 @@ struct _GdkWaylandClipboardClass G_DEFINE_TYPE (GdkWaylandClipboard, gdk_wayland_clipboard, GDK_TYPE_CLIPBOARD) static void +gdk_wayland_clipboard_discard_offer (GdkWaylandClipboard *cb) +{ + g_clear_pointer (&cb->offer_formats, gdk_content_formats_unref); + g_clear_pointer (&cb->offer, (GDestroyNotify) wl_data_offer_destroy); +} + +static void gdk_wayland_clipboard_finalize (GObject *object) { - //GdkWaylandClipboard *cb = GDK_WAYLAND_CLIPBOARD (object); + GdkWaylandClipboard *cb = GDK_WAYLAND_CLIPBOARD (object); + gdk_wayland_clipboard_discard_offer (cb); + G_OBJECT_CLASS (gdk_wayland_clipboard_parent_class)->finalize (object); } +static gboolean +gdk_wayland_clipboard_claim (GdkClipboard *clipboard, + GdkContentFormats *formats, + gboolean local, + GdkContentProvider *content) +{ + GdkWaylandClipboard *cb = GDK_WAYLAND_CLIPBOARD (clipboard); + + if (local) + { + /* not handled yet */ + cb->offer = NULL; + } + + return GDK_CLIPBOARD_CLASS (gdk_wayland_clipboard_parent_class)->claim (clipboard, formats, local, content); +} + +static void +gdk_wayland_clipboard_read_async (GdkClipboard *clipboard, + GdkContentFormats *formats, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GdkWaylandClipboard *cb = GDK_WAYLAND_CLIPBOARD (clipboard); + GInputStream *stream; + const char *mime_type; + int pipe_fd[2]; + GError *error = NULL; + GTask *task; + + task = g_task_new (clipboard, cancellable, callback, user_data); + g_task_set_priority (task, io_priority); + g_task_set_source_tag (task, gdk_wayland_clipboard_read_async); + + GDK_NOTE (CLIPBOARD, char *s = gdk_content_formats_to_string (formats); + g_printerr ("%p: read for %s\n", cb, s); + g_free (s); ); + mime_type = gdk_content_formats_match_mime_type (formats, cb->offer_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 */ + g_assert (cb->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_receive (cb->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_clipboard_read_finish (GdkClipboard *clipboard, + const char **out_mime_type, + GAsyncResult *result, + GError **error) +{ + GInputStream *stream; + GTask *task; + + g_return_val_if_fail (g_task_is_valid (result, G_OBJECT (clipboard)), NULL); + task = G_TASK (result); + g_return_val_if_fail (g_task_get_source_tag (task) == gdk_wayland_clipboard_read_async, NULL); + + stream = g_task_propagate_pointer (task, error); + + if (stream) + { + if (out_mime_type) + *out_mime_type = g_task_get_task_data (task); + g_object_ref (stream); + } + else + { + if (out_mime_type) + *out_mime_type = NULL; + } + + return stream; +} + static void gdk_wayland_clipboard_class_init (GdkWaylandClipboardClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); - //GdkClipboardClass *clipboard_class = GDK_CLIPBOARD_CLASS (class); + GdkClipboardClass *clipboard_class = GDK_CLIPBOARD_CLASS (class); object_class->finalize = gdk_wayland_clipboard_finalize; -#if 0 clipboard_class->claim = gdk_wayland_clipboard_claim; +#if 0 clipboard_class->store_async = gdk_wayland_clipboard_store_async; clipboard_class->store_finish = gdk_wayland_clipboard_store_finish; +#endif clipboard_class->read_async = gdk_wayland_clipboard_read_async; clipboard_class->read_finish = gdk_wayland_clipboard_read_finish; -#endif } static void @@ -76,3 +187,23 @@ gdk_wayland_clipboard_new (GdkDisplay *display) return GDK_CLIPBOARD (cb); } + +void +gdk_wayland_clipboard_claim_remote (GdkWaylandClipboard *cb, + struct wl_data_offer *offer, + GdkContentFormats *formats) +{ + g_return_if_fail (GDK_IS_WAYLAND_CLIPBOARD (cb)); + + gdk_wayland_clipboard_discard_offer (cb); + + GDK_NOTE (CLIPBOARD, char *s = gdk_content_formats_to_string (formats); + g_printerr ("%p: remote clipboard claim for %s\n", cb, s); + g_free (s); ); + cb->offer_formats = formats; + cb->offer = offer; + + gdk_clipboard_claim_remote (GDK_CLIPBOARD (cb), + cb->offer_formats); +} + diff --git a/gdk/wayland/gdkclipboard-wayland.h b/gdk/wayland/gdkclipboard-wayland.h index cf8bd7efe2..5e5eba8a65 100644 --- a/gdk/wayland/gdkclipboard-wayland.h +++ b/gdk/wayland/gdkclipboard-wayland.h @@ -20,6 +20,7 @@ #include "gdk/gdkclipboard.h" +#include <wayland-client.h> G_BEGIN_DECLS @@ -33,6 +34,9 @@ GType gdk_wayland_clipboard_get_type (void) G_GNU GdkClipboard * gdk_wayland_clipboard_new (GdkDisplay *display); +void gdk_wayland_clipboard_claim_remote (GdkWaylandClipboard *cb, + struct wl_data_offer *offer, + GdkContentFormats *formats); G_END_DECLS diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index 908d9bdfdb..ca2ea3e6a9 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -216,7 +216,6 @@ struct _GdkWaylandSeat GdkModifierType key_modifiers; GdkWindow *keyboard_focus; - GdkAtom pending_selection; GdkWindow *grab_window; uint32_t grab_time; gboolean have_server_repeat; @@ -1191,26 +1190,16 @@ data_device_selection (void *data, struct wl_data_offer *offer) { GdkWaylandSeat *seat = data; - GdkAtom selection; - - GDK_NOTE (EVENTS, - g_message ("data device selection, data device %p, data offer %p", - wl_data_device, offer)); + GdkContentFormats *formats; - selection = gdk_atom_intern_static_string ("CLIPBOARD"); - gdk_wayland_selection_set_offer (seat->display, selection, offer); - -#if 0 - /* If we already have keyboard focus, the selection was targeted at the - * focused surface. If we don't we will receive keyboard focus directly after - * this, so lets wait and find out what window will get the focus before - * emitting the owner-changed event. - */ - if (seat->keyboard_focus) - emit_selection_owner_change (seat->keyboard_focus, selection); + if (offer) + formats = gdk_wayland_selection_steal_offer (seat->display, offer); else - seat->pending_selection = selection; -#endif + formats = gdk_content_formats_new (NULL, 0); + + gdk_wayland_clipboard_claim_remote (GDK_WAYLAND_CLIPBOARD (seat->clipboard), + offer, + formats); } static const struct wl_data_device_listener data_device_listener = { @@ -1860,15 +1849,6 @@ keyboard_handle_enter (void *data, seat, seat->keyboard_focus)); _gdk_wayland_display_deliver_event (seat->display, event); - - /* - if (seat->pending_selection != NULL) - { - emit_selection_owner_change (seat->keyboard_focus, - seat->pending_selection); - seat->pending_selection = NULL; - } - */ } static void stop_key_repeat (GdkWaylandSeat *seat); @@ -4811,8 +4791,6 @@ _gdk_wayland_display_create_seat (GdkWaylandDisplay *display_wayland, seat->foreign_dnd_window = create_foreign_dnd_window (display); seat->wl_seat = wl_seat; - seat->pending_selection = NULL; - wl_seat_add_listener (seat->wl_seat, &seat_listener, seat); wl_seat_set_user_data (seat->wl_seat, seat); diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h index 0a21c89ed4..2f991047de 100644 --- a/gdk/wayland/gdkprivate-wayland.h +++ b/gdk/wayland/gdkprivate-wayland.h @@ -227,10 +227,12 @@ GdkWaylandSelection * gdk_wayland_display_get_selection (GdkDisplay *display); GdkWaylandSelection * gdk_wayland_selection_new (void); void gdk_wayland_selection_free (GdkWaylandSelection *selection); + void gdk_wayland_selection_ensure_offer (GdkDisplay *display, struct wl_data_offer *wl_offer); void gdk_wayland_selection_ensure_primary_offer (GdkDisplay *display, struct gtk_primary_selection_offer *wp_offer); +GdkContentFormats *gdk_wayland_selection_steal_offer (GdkDisplay *display, gpointer wl_offer); void gdk_wayland_selection_set_offer (GdkDisplay *display, GdkAtom selection, diff --git a/gdk/wayland/gdkselection-wayland.c b/gdk/wayland/gdkselection-wayland.c index 846972a18e..f2d76fc3c6 100644 --- a/gdk/wayland/gdkselection-wayland.c +++ b/gdk/wayland/gdkselection-wayland.c @@ -537,6 +537,25 @@ gdk_wayland_selection_ensure_primary_offer (GdkDisplay * } } +GdkContentFormats * +gdk_wayland_selection_steal_offer (GdkDisplay *display, + gpointer wl_offer) +{ + GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display); + GdkContentFormats *formats; + DataOfferData *info; + + info = g_hash_table_lookup (selection->offers, wl_offer); + if (info == NULL) + return NULL; + + g_hash_table_steal (selection->offers, wl_offer); + formats = info->targets; + g_slice_free (DataOfferData, info); + + return formats; +} + void gdk_wayland_selection_set_offer (GdkDisplay *display, GdkAtom selection_atom, |