[gnome-remote-desktop] session: Add APIs and callbacks for clipboard handling
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-remote-desktop] session: Add APIs and callbacks for clipboard handling
- Date: Fri, 5 Feb 2021 17:07:07 +0000 (UTC)
commit 45d56c8a4a70a9f21a3ca2449176a876344eb2b4
Author: Pascal Nowack <Pascal Nowack gmx de>
Date: Tue Sep 22 13:45:40 2020 +0200
session: Add APIs and callbacks for clipboard handling
Add APIs to enable or disable a clipboard.
Also add APIs to submit mime type lists, requested content for a mime
type and to read the content for a mime type from mutter.
Additionally, handle SelectionOwnerChanged- and SelectionTransfer-
signals with the previously implemented clipboard APIs in
grd-clipboard.
src/grd-session.c | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/grd-session.h | 15 +++
2 files changed, 319 insertions(+)
---
diff --git a/src/grd-session.c b/src/grd-session.c
index bbaee00..2c54c30 100644
--- a/src/grd-session.c
+++ b/src/grd-session.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Red Hat Inc.
+ * Copyright (C) 2020 Pascal Nowack
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -24,8 +25,12 @@
#include "grd-session.h"
+#include <gio/gunixfdlist.h>
#include <glib-object.h>
+#include <glib-unix.h>
+#include <sys/mman.h>
+#include "grd-clipboard.h"
#include "grd-dbus-remote-desktop.h"
#include "grd-context.h"
#include "grd-private.h"
@@ -63,6 +68,8 @@ typedef struct _GrdSessionPrivate
GrdStream *stream;
+ GrdClipboard *clipboard;
+
GCancellable *cancellable;
gboolean started;
@@ -174,6 +181,194 @@ grd_session_notify_pointer_motion_absolute (GrdSession *session,
priv->remote_desktop_session, stream_path, x, y, NULL, NULL, NULL);
}
+static GVariant *
+serialize_mime_type_tables (GList *mime_type_tables)
+{
+ GVariantBuilder builder;
+ GList *l;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
+ for (l = mime_type_tables; l; l = l->next)
+ {
+ GrdMimeTypeTable *mime_type_table = l->data;
+ GrdMimeType mime_type;
+ const char *mime_type_string;
+
+ mime_type = mime_type_table->mime_type;
+ mime_type_string = grd_mime_type_to_string (mime_type);
+ g_variant_builder_add (&builder, "s", mime_type_string);
+ }
+
+ return g_variant_builder_end (&builder);
+}
+
+static GVariant *
+serialize_clipboard_options (GList *mime_type_tables)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+ if (mime_type_tables)
+ {
+ g_variant_builder_add (&builder, "{sv}", "mime-types",
+ serialize_mime_type_tables (mime_type_tables));
+ }
+
+ return g_variant_builder_end (&builder);
+}
+
+gboolean
+grd_session_enable_clipboard (GrdSession *session,
+ GrdClipboard *clipboard,
+ GList *mime_type_tables)
+{
+ GrdSessionPrivate *priv = grd_session_get_instance_private (session);
+ GVariant *options_variant;
+ g_autoptr (GError) error = NULL;
+
+ if (!priv->remote_desktop_session)
+ return FALSE;
+
+ priv->clipboard = clipboard;
+
+ options_variant = serialize_clipboard_options (mime_type_tables);
+ if (!grd_dbus_remote_desktop_session_call_enable_clipboard_sync (
+ priv->remote_desktop_session, options_variant, NULL, &error))
+ {
+ g_warning ("Failed to enable clipboard: %s", error->message);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+grd_session_disable_clipboard (GrdSession *session)
+{
+ GrdSessionPrivate *priv = grd_session_get_instance_private (session);
+
+ if (!priv->remote_desktop_session)
+ return;
+
+ grd_dbus_remote_desktop_session_call_disable_clipboard (
+ priv->remote_desktop_session, NULL, NULL, NULL);
+}
+
+void
+grd_session_set_selection (GrdSession *session,
+ GList *mime_type_tables)
+{
+ GrdSessionPrivate *priv = grd_session_get_instance_private (session);
+ GVariant *options_variant;
+ g_autoptr (GError) error = NULL;
+
+ options_variant = serialize_clipboard_options (mime_type_tables);
+
+ if (!grd_dbus_remote_desktop_session_call_set_selection_sync (
+ priv->remote_desktop_session, options_variant, NULL, &error))
+ g_warning ("Failed to set selection: %s", error->message);
+}
+
+static int
+acquire_fd_from_list (GUnixFDList *fd_list,
+ int fd_idx,
+ GError **error)
+{
+ int fd;
+ int fd_flags;
+
+ fd = g_unix_fd_list_get (fd_list, fd_idx, error);
+ if (fd == -1)
+ {
+ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
+ "fcntl: %s", g_strerror (errno));
+ return -1;
+ }
+
+ fd_flags = fcntl (fd, F_GETFD);
+ if (fd_flags == -1)
+ {
+ close (fd);
+ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
+ "fcntl: %s", g_strerror (errno));
+ return -1;
+ }
+
+ if (fcntl (fd, F_SETFD, fd_flags | FD_CLOEXEC) == -1)
+ {
+ close (fd);
+ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
+ "fcntl: %s", g_strerror (errno));
+ return -1;
+ }
+
+ return fd;
+}
+
+uint8_t *
+grd_session_selection_read (GrdSession *session,
+ GrdMimeType mime_type,
+ uint32_t *size)
+{
+ GrdSessionPrivate *priv = grd_session_get_instance_private (session);
+ g_autoptr (GError) error = NULL;
+ g_autoptr (GVariant) fd_variant = NULL;
+ g_autoptr (GUnixFDList) fd_list = NULL;
+ int fd_idx;
+ int fd;
+ const char *mime_type_string;
+ GArray *data;
+
+ mime_type_string = grd_mime_type_to_string (mime_type);
+ if (!grd_dbus_remote_desktop_session_call_selection_read_sync (
+ priv->remote_desktop_session, mime_type_string, NULL, &fd_variant,
+ &fd_list, NULL, &error))
+ {
+ g_warning ("Failed to read selection: %s", error->message);
+ return NULL;
+ }
+
+ g_variant_get (fd_variant, "h", &fd_idx);
+ fd = acquire_fd_from_list (fd_list, fd_idx, &error);
+ if (fd == -1)
+ {
+ g_warning ("Failed to acquire file descriptor: %s", error->message);
+ return NULL;
+ }
+
+ data = g_array_new (FALSE, TRUE, sizeof (uint8_t));
+ while (TRUE)
+ {
+ int len;
+ uint8_t buffer[1024];
+
+ len = read (fd, buffer, G_N_ELEMENTS (buffer));
+ if (len < 0)
+ {
+ if (errno == EAGAIN)
+ continue;
+
+ g_warning ("read() failed: %s", g_strerror (errno));
+ break;
+ }
+ else if (len == 0)
+ {
+ break;
+ }
+ else
+ {
+ g_array_append_vals (data, buffer, len);
+ }
+ }
+
+ if (data->len >= 0)
+ *size = data->len;
+
+ close (fd);
+
+ return (uint8_t *) g_array_free (data, FALSE);
+}
+
static void
on_stream_ready (GrdStream *stream,
GrdSession *session)
@@ -380,6 +575,109 @@ on_remote_desktop_session_closed (GrdDBusRemoteDesktopSession *session_proxy,
grd_session_stop (session);
}
+static void
+on_remote_desktop_session_selection_owner_changed (GrdDBusRemoteDesktopSession *session_proxy,
+ GVariant *options_variant,
+ GrdSession *session)
+{
+ GrdSessionPrivate *priv = grd_session_get_instance_private (session);
+ GVariant *is_owner_variant, *mime_types_variant;
+ GVariantIter iter;
+ const char *mime_string;
+ GrdMimeType mime_type;
+ GList *mime_type_list = NULL;
+
+ is_owner_variant = g_variant_lookup_value (options_variant, "session-is-owner",
+ G_VARIANT_TYPE ("b"));
+ if (is_owner_variant && g_variant_get_boolean (is_owner_variant))
+ return;
+
+ mime_types_variant = g_variant_lookup_value (options_variant, "mime-types",
+ G_VARIANT_TYPE ("(as)"));
+ if (!mime_types_variant)
+ return;
+
+ g_variant_iter_init (&iter, g_variant_get_child_value (mime_types_variant, 0));
+ while (g_variant_iter_loop (&iter, "s", &mime_string))
+ {
+ mime_type = grd_mime_type_from_string (mime_string);
+ if (mime_type != GRD_MIME_TYPE_NONE)
+ {
+ mime_type_list = g_list_append (mime_type_list,
+ GUINT_TO_POINTER (mime_type));
+ g_debug ("Clipboard[SelectionOwnerChanged]: Server advertises mime "
+ "type %s", mime_string);
+ }
+ else
+ {
+ g_debug ("Clipboard[SelectionOwnerChanged]: Server advertised unknown "
+ "mime type: %s", mime_string);
+ }
+ }
+
+ if (mime_type_list)
+ grd_clipboard_update_client_mime_type_list (priv->clipboard, mime_type_list);
+}
+
+static void
+on_remote_desktop_session_selection_transfer (GrdDBusRemoteDesktopSession *session_proxy,
+ char *mime_type_string,
+ unsigned int serial,
+ GrdSession *session)
+{
+ GrdSessionPrivate *priv = grd_session_get_instance_private (session);
+ uint8_t *data;
+ uint32_t size;
+ g_autoptr (GError) error = NULL;
+ g_autoptr (GVariant) fd_variant = NULL;
+ g_autoptr (GUnixFDList) fd_list = NULL;
+ int fd_idx;
+ int fd;
+ GrdMimeType mime_type;
+
+ mime_type = grd_mime_type_from_string (mime_type_string);
+ if (mime_type == GRD_MIME_TYPE_NONE)
+ {
+ grd_dbus_remote_desktop_session_call_selection_write_done (
+ priv->remote_desktop_session, serial, FALSE, NULL, NULL, NULL);
+ return;
+ }
+
+ if (!grd_dbus_remote_desktop_session_call_selection_write_sync (
+ priv->remote_desktop_session, serial, NULL, &fd_variant, &fd_list,
+ NULL, &error))
+ {
+ g_warning ("Failed to write selection: %s", error->message);
+ return;
+ }
+
+ g_variant_get (fd_variant, "h", &fd_idx);
+ fd = acquire_fd_from_list (fd_list, fd_idx, &error);
+ if (fd == -1)
+ {
+ g_warning ("Failed to acquire file descriptor: %s", error->message);
+ return;
+ }
+
+ data = grd_clipboard_request_client_content_for_mime_type (priv->clipboard,
+ mime_type, &size);
+ if (!size || write (fd, data, size) < 0)
+ {
+ grd_dbus_remote_desktop_session_call_selection_write_done (
+ priv->remote_desktop_session, serial, FALSE, NULL, NULL, NULL);
+
+ close (fd);
+ g_free (data);
+ return;
+ }
+
+ grd_dbus_remote_desktop_session_call_selection_write_done (
+ priv->remote_desktop_session, serial, TRUE, NULL, NULL, NULL);
+
+ close (fd);
+ g_free (data);
+}
+
static void
on_remote_desktop_session_proxy_acquired (GObject *object,
GAsyncResult *result,
@@ -410,6 +708,12 @@ on_remote_desktop_session_proxy_acquired (GObject *object,
g_signal_connect (session_proxy, "closed",
G_CALLBACK (on_remote_desktop_session_closed),
session);
+ g_signal_connect (session_proxy, "selection-owner-changed",
+ G_CALLBACK (on_remote_desktop_session_selection_owner_changed),
+ session);
+ g_signal_connect (session_proxy, "selection-transfer",
+ G_CALLBACK (on_remote_desktop_session_selection_transfer),
+ session);
priv->remote_desktop_session = session_proxy;
diff --git a/src/grd-session.h b/src/grd-session.h
index 2dc6f48..937c068 100644
--- a/src/grd-session.h
+++ b/src/grd-session.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Red Hat Inc.
+ * Copyright (C) 2020 Pascal Nowack
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -26,6 +27,7 @@
#include <glib-object.h>
#include <stdint.h>
+#include "grd-mime-type.h"
#include "grd-types.h"
#define GRD_TYPE_SESSION (grd_session_get_type ())
@@ -89,6 +91,19 @@ void grd_session_notify_pointer_motion_absolute (GrdSession *session,
double x,
double y);
+gboolean grd_session_enable_clipboard (GrdSession *session,
+ GrdClipboard *clipboard,
+ GList *mime_type_tables);
+
+void grd_session_disable_clipboard (GrdSession *session);
+
+void grd_session_set_selection (GrdSession *session,
+ GList *mime_type_tables);
+
+uint8_t *grd_session_selection_read (GrdSession *session,
+ GrdMimeType mime_type,
+ uint32_t *size);
+
void grd_session_start (GrdSession *session);
void grd_session_stop (GrdSession *session);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]