forked from AuroraMiddleware/gtk
wayland: Implement reading the clipboard
We now keep track of what's in the clipboard and allow people to read its contents.
This commit is contained in:
parent
00192266a1
commit
82002eabfe
@ -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
|
||||
@ -35,29 +44,131 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
GdkContentFormats *formats;
|
||||
|
||||
GDK_NOTE (EVENTS,
|
||||
g_message ("data device selection, data device %p, data offer %p",
|
||||
wl_data_device, offer));
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user