[gtk+] wayland: Implement reading the clipboard
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] wayland: Implement reading the clipboard
- Date: Sun, 3 Dec 2017 04:56:06 +0000 (UTC)
commit 82002eabfed16b2a47d715ab0c7b3883f35c7ab7
Author: Benjamin Otte <otte redhat com>
Date: Sun Dec 3 02:48:17 2017 +0100
wayland: Implement reading the clipboard
We now keep track of what's in the clipboard and allow people to read
its contents.
gdk/wayland/gdkclipboard-wayland.c | 139 ++++++++++++++++++++++++++++++++++-
gdk/wayland/gdkclipboard-wayland.h | 4 +
gdk/wayland/gdkdevice-wayland.c | 38 ++--------
gdk/wayland/gdkprivate-wayland.h | 2 +
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 cddc37b..51d5ed2 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 cf8bd7e..5e5eba8 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 908d9bd..ca2ea3e 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 0a21c89..2f99104 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 846972a..f2d76fc 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,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]