[gnome-remote-desktop] clipboard: Split up SelectionTransfer handling



commit 8e855503eb6eae84d71498c896fe6ebb78c91100
Author: Pascal Nowack <Pascal Nowack gmx de>
Date:   Thu Oct 28 10:37:55 2021 +0200

    clipboard: Split up SelectionTransfer handling
    
    Currently, when gnome-remote-desktop handles a SelectionTransfer-
    signal, the mime type content is requested synchronously from the
    respective backend.
    Since this process is done synchronously, the main thread is blocked
    and cannot handle any other events, such as input events.
    With additional network latency, this becomes worse.
    
    To allow the backend implementations to transform to an asynchronous
    implementation, split up the SelectionTransfer handling.
    The signal will now just emit the request on the backend and the
    backend will, when it has the response ready submit the response
    itself.
    
    Both the RDP and VNC backend will currently still function as before,
    as the handling is just split up.
    Since the VNC backend does not support delayed rendering of clipboard
    data, no further changes will happen for the VNC backend.
    The RDP backend, on the other hand, will be reworked in the next commit
    to handle mime type content requests asynchronously.

 src/grd-clipboard-rdp.c | 32 +++++++++++-----
 src/grd-clipboard-vnc.c | 13 ++++---
 src/grd-clipboard.c     | 45 +++++++++++++++--------
 src/grd-clipboard.h     | 19 ++++++----
 src/grd-session.c       | 97 ++++++++++++++++++++++++++++---------------------
 src/grd-session.h       |  7 +++-
 6 files changed, 133 insertions(+), 80 deletions(-)
---
diff --git a/src/grd-clipboard-rdp.c b/src/grd-clipboard-rdp.c
index f4091a7..ec8df70 100644
--- a/src/grd-clipboard-rdp.c
+++ b/src/grd-clipboard-rdp.c
@@ -819,10 +819,10 @@ convert_client_content_for_server (GrdClipboardRdp *clipboard_rdp,
   return dst_data;
 }
 
-static uint8_t *
+static void
 grd_clipboard_rdp_request_client_content_for_mime_type (GrdClipboard     *clipboard,
                                                         GrdMimeTypeTable *mime_type_table,
-                                                        uint32_t         *size)
+                                                        unsigned int      serial)
 {
   GrdClipboardRdp *clipboard_rdp = GRD_CLIPBOARD_RDP (clipboard);
   GrdRdpFuseClipboard *rdp_fuse_clipboard = clipboard_rdp->rdp_fuse_clipboard;
@@ -833,9 +833,12 @@ grd_clipboard_rdp_request_client_content_for_mime_type (GrdClipboard     *clipbo
   uint32_t src_size, dst_size;
   uint32_t clip_data_id = 0;
 
-  *size = 0;
   if (mime_type == GRD_MIME_TYPE_NONE)
-    return NULL;
+    {
+      grd_clipboard_submit_client_content_for_mime_type (clipboard, serial,
+                                                         NULL, 0);
+      return;
+    }
 
   if (g_hash_table_contains (clipboard_rdp->format_data_cache,
                              GUINT_TO_POINTER (mime_type)))
@@ -844,13 +847,19 @@ grd_clipboard_rdp_request_client_content_for_mime_type (GrdClipboard     *clipbo
 
       format_data = g_hash_table_lookup (clipboard_rdp->format_data_cache,
                                          GUINT_TO_POINTER (mime_type));
-      *size = format_data->size;
 
-      return g_memdup2 (format_data->data, format_data->size);
+      grd_clipboard_submit_client_content_for_mime_type (clipboard, serial,
+                                                         format_data->data,
+                                                         format_data->size);
+      return;
     }
 
   if (WaitForSingleObject (completed_format_list_event, 0) == WAIT_TIMEOUT)
-    return NULL;
+    {
+      grd_clipboard_submit_client_content_for_mime_type (clipboard, serial,
+                                                         NULL, 0);
+      return;
+    }
 
   if (clipboard_rdp->cliprdr_context->canLockClipData &&
       (mime_type == GRD_MIME_TYPE_TEXT_URILIST ||
@@ -866,7 +875,9 @@ grd_clipboard_rdp_request_client_content_for_mime_type (GrdClipboard     *clipbo
            mime_type == GRD_MIME_TYPE_XS_GNOME_COPIED_FILES))
         grd_rdp_fuse_clipboard_clip_data_id_free (rdp_fuse_clipboard, clip_data_id);
 
-      return NULL;
+      grd_clipboard_submit_client_content_for_mime_type (clipboard, serial,
+                                                         NULL, 0);
+      return;
     }
 
   dst_data = NULL;
@@ -899,7 +910,7 @@ grd_clipboard_rdp_request_client_content_for_mime_type (GrdClipboard     *clipbo
     {
       FormatData *format_data = g_malloc0 (sizeof (FormatData));
 
-      format_data->size = *size = dst_size;
+      format_data->size = dst_size;
       format_data->data = dst_data;
 
       g_hash_table_insert (clipboard_rdp->format_data_cache,
@@ -909,7 +920,8 @@ grd_clipboard_rdp_request_client_content_for_mime_type (GrdClipboard     *clipbo
 
   g_free (src_data);
 
-  return g_memdup2 (dst_data, dst_size);
+  grd_clipboard_submit_client_content_for_mime_type (clipboard, serial,
+                                                     dst_data, dst_size);
 }
 
 static void
diff --git a/src/grd-clipboard-vnc.c b/src/grd-clipboard-vnc.c
index d0a8df4..ca6daba 100644
--- a/src/grd-clipboard-vnc.c
+++ b/src/grd-clipboard-vnc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Pascal Nowack
+ * Copyright (C) 2020-2021 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
@@ -79,16 +79,17 @@ grd_clipboard_vnc_update_client_mime_type_list (GrdClipboard *clipboard,
   g_list_free (mime_type_list);
 }
 
-static uint8_t *
+static void
 grd_clipboard_vnc_request_client_content_for_mime_type (GrdClipboard     *clipboard,
                                                         GrdMimeTypeTable *mime_type_table,
-                                                        uint32_t         *size)
+                                                        unsigned int      serial)
 {
   GrdClipboardVnc *clipboard_vnc = GRD_CLIPBOARD_VNC (clipboard);
+  uint32_t size;
 
-  *size = strlen (clipboard_vnc->clipboard_utf8_string);
-
-  return g_memdup2 (clipboard_vnc->clipboard_utf8_string, *size);
+  size = strlen (clipboard_vnc->clipboard_utf8_string);
+  grd_clipboard_submit_client_content_for_mime_type (
+    clipboard, serial, (uint8_t *) clipboard_vnc->clipboard_utf8_string, size);
 }
 
 static void
diff --git a/src/grd-clipboard.c b/src/grd-clipboard.c
index 1b1e40e..81b9155 100644
--- a/src/grd-clipboard.c
+++ b/src/grd-clipboard.c
@@ -396,36 +396,51 @@ grd_clipboard_update_client_mime_type_list (GrdClipboard *clipboard,
   g_debug ("Clipboard[SelectionOwnerChanged]: Update complete");
 }
 
-uint8_t *
+void
+grd_clipboard_submit_client_content_for_mime_type (GrdClipboard  *clipboard,
+                                                   unsigned int   serial,
+                                                   const uint8_t *data,
+                                                   uint32_t       size)
+{
+  GrdClipboardPrivate *priv = grd_clipboard_get_instance_private (clipboard);
+
+  g_assert (priv->enabled);
+
+  if (data && size)
+    g_debug ("Clipboard[SelectionTransfer]: Request for serial %u was successful", serial);
+  else
+    g_debug ("Clipboard[SelectionTransfer]: Request for serial %u failed", serial);
+
+  grd_session_selection_write (priv->session, serial, data, size);
+}
+
+void
 grd_clipboard_request_client_content_for_mime_type (GrdClipboard *clipboard,
                                                     GrdMimeType   mime_type,
-                                                    uint32_t     *size)
+                                                    unsigned int  serial)
 {
   GrdClipboardClass *klass = GRD_CLIPBOARD_GET_CLASS (clipboard);
   GrdClipboardPrivate *priv = grd_clipboard_get_instance_private (clipboard);
   GrdMimeTypeTable *mime_type_table = NULL;
-  uint8_t *mime_type_content = NULL;
 
-  *size = 0;
+  g_assert (priv->enabled);
 
-  if (!klass->request_client_content_for_mime_type)
-    return NULL;
+  g_return_if_fail (klass->request_client_content_for_mime_type);
 
   g_debug ("Clipboard[SelectionTransfer]: Requesting data from clients clipboard"
-           " (mime type: %s)", grd_mime_type_to_string (mime_type));
+           " (mime type: %s, serial: %u)",
+           grd_mime_type_to_string (mime_type), serial);
   mime_type_table = g_hash_table_lookup (priv->client_mime_type_tables,
                                          GUINT_TO_POINTER (mime_type));
-  if (mime_type_table)
+  if (!mime_type_table)
     {
-      mime_type_content = klass->request_client_content_for_mime_type (
-                            clipboard, mime_type_table, size);
+      grd_clipboard_submit_client_content_for_mime_type (clipboard, serial,
+                                                         NULL, 0);
+      return;
     }
-  if (mime_type_content)
-    g_debug ("Clipboard[SelectionTransfer]: Request successful");
-  else
-    g_debug ("Clipboard[SelectionTransfer]: Request failed");
 
-  return mime_type_content;
+  klass->request_client_content_for_mime_type (clipboard, mime_type_table,
+                                               serial);
 }
 
 static void
diff --git a/src/grd-clipboard.h b/src/grd-clipboard.h
index 93249d0..81bfe1b 100644
--- a/src/grd-clipboard.h
+++ b/src/grd-clipboard.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Pascal Nowack
+ * Copyright (C) 2020-2021 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
@@ -35,9 +35,9 @@ struct _GrdClipboardClass
 
   void (*update_client_mime_type_list) (GrdClipboard *clipboard,
                                         GList        *mime_type_list);
-  uint8_t *(*request_client_content_for_mime_type) (GrdClipboard     *clipboard,
-                                                    GrdMimeTypeTable *mime_type_table,
-                                                    uint32_t         *size);
+  void (*request_client_content_for_mime_type) (GrdClipboard     *clipboard,
+                                                GrdMimeTypeTable *mime_type_table,
+                                                unsigned int      serial);
   void (*submit_requested_server_content) (GrdClipboard *clipboard,
                                            uint8_t      *data,
                                            uint32_t      size);
@@ -59,8 +59,13 @@ void grd_clipboard_disable_clipboard (GrdClipboard *clipboard);
 void grd_clipboard_update_client_mime_type_list (GrdClipboard *clipboard,
                                                  GList        *mime_type_list);
 
-uint8_t *grd_clipboard_request_client_content_for_mime_type (GrdClipboard *clipboard,
-                                                             GrdMimeType   mime_type,
-                                                             uint32_t     *size);
+void grd_clipboard_submit_client_content_for_mime_type (GrdClipboard  *clipboard,
+                                                        unsigned int   serial,
+                                                        const uint8_t *data,
+                                                        uint32_t       size);
+
+void grd_clipboard_request_client_content_for_mime_type (GrdClipboard *clipboard,
+                                                         GrdMimeType   mime_type,
+                                                         unsigned int  serial);
 
 #endif /* GRD_CLIPBOARD_H */
diff --git a/src/grd-session.c b/src/grd-session.c
index 0bcc9bf..39d7410 100644
--- a/src/grd-session.c
+++ b/src/grd-session.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2015 Red Hat Inc.
- * Copyright (C) 2020 Pascal Nowack
+ * Copyright (C) 2020-2021 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
@@ -325,6 +325,59 @@ acquire_fd_from_list (GUnixFDList  *fd_list,
   return fd;
 }
 
+void
+grd_session_selection_write (GrdSession    *session,
+                             unsigned int   serial,
+                             const uint8_t *data,
+                             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;
+
+  if (!data || !size)
+    {
+      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 for serial %u: %s",
+                 serial, 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 for serial %u: %s",
+                 serial, error->message);
+      return;
+    }
+
+  if (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);
+      return;
+    }
+
+  grd_dbus_remote_desktop_session_call_selection_write_done (
+    priv->remote_desktop_session, serial, TRUE, NULL, NULL, NULL);
+
+  close (fd);
+}
+
 int
 grd_session_selection_read (GrdSession  *session,
                             GrdMimeType  mime_type)
@@ -617,13 +670,6 @@ on_remote_desktop_session_selection_transfer (GrdDBusRemoteDesktopSession *sessi
                                               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;
 
   if (!priv->clipboard)
@@ -637,39 +683,8 @@ on_remote_desktop_session_selection_transfer (GrdDBusRemoteDesktopSession *sessi
       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);
+  grd_clipboard_request_client_content_for_mime_type (priv->clipboard,
+                                                      mime_type, serial);
 }
 
 static void
diff --git a/src/grd-session.h b/src/grd-session.h
index cc0d136..cca7d9e 100644
--- a/src/grd-session.h
+++ b/src/grd-session.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2015 Red Hat Inc.
- * Copyright (C) 2020 Pascal Nowack
+ * Copyright (C) 2020-2021 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
@@ -110,6 +110,11 @@ void grd_session_disable_clipboard (GrdSession *session);
 void grd_session_set_selection (GrdSession *session,
                                 GList      *mime_type_tables);
 
+void grd_session_selection_write (GrdSession    *session,
+                                  unsigned int   serial,
+                                  const uint8_t *data,
+                                  uint32_t       size);
+
 int grd_session_selection_read (GrdSession  *session,
                                 GrdMimeType  mime_type);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]