[gnome-remote-desktop] clipboard: Split up SelectionRead requests



commit 60e1d251559187637178915dcd857ce090c0a233
Author: Pascal Nowack <Pascal Nowack gmx de>
Date:   Sun Apr 25 17:38:27 2021 +0200

    clipboard: Split up SelectionRead requests
    
    In order to be able to handle SelectionRead requests in an async way,
    request_server_content_for_mime_type() needs to be adjusted to not to
    directly return the data.
    The function now becomes a void function, meaning no data returns to
    the calling function.
    To return the fetched data to the clipboard implementation, use a newly
    introduced vfunc.
    
    Functionality wise, nothing changes in this commit, since the backends
    still get their data in the same way, except that the calling function
    is not the same any more, as the part, that processes the returned
    data, is now a separate function.

 src/grd-clipboard-rdp.c | 323 +++++++++++++++++++++++++++---------------------
 src/grd-clipboard-vnc.c |  67 +++++-----
 src/grd-clipboard.c     |  19 +--
 src/grd-clipboard.h     |   8 +-
 4 files changed, 233 insertions(+), 184 deletions(-)
---
diff --git a/src/grd-clipboard-rdp.c b/src/grd-clipboard-rdp.c
index 73d4a62..e00a38a 100644
--- a/src/grd-clipboard-rdp.c
+++ b/src/grd-clipboard-rdp.c
@@ -99,7 +99,9 @@ struct _GrdClipboardRdp
   char *fuse_mount_path;
   GrdRdpFuseClipboard *rdp_fuse_clipboard;
   GHashTable *format_data_cache;
+
   GrdMimeType which_unicode_format;
+  ServerFormatDataRequestContext *format_data_request_context;
 
   HANDLE format_data_received_event;
   CLIPRDR_FORMAT_DATA_RESPONSE *format_data_response;
@@ -909,6 +911,159 @@ grd_clipboard_rdp_request_client_content_for_mime_type (GrdClipboard     *clipbo
   return g_memdup2 (dst_data, dst_size);
 }
 
+static void
+#ifdef HAVE_FREERDP_2_3
+serialize_file_list (FILEDESCRIPTORW  *files,
+                     uint32_t          n_files,
+                     uint8_t         **dst_data,
+                     uint32_t         *dst_size)
+{
+  FILEDESCRIPTORW *file;
+#else
+serialize_file_list (FILEDESCRIPTOR  *files,
+                     uint32_t         n_files,
+                     uint8_t        **dst_data,
+                     uint32_t        *dst_size)
+{
+  FILEDESCRIPTOR *file;
+#endif /* HAVE_FREERDP_2_3 */
+  wStream* s = NULL;
+  uint64_t last_write_time;
+  uint32_t i, j;
+
+  if (!files || !dst_data || !dst_size)
+    return;
+
+  if (!(s = Stream_New (NULL, 4 + n_files * CLIPRDR_FILEDESCRIPTOR_SIZE)))
+    return;
+
+  Stream_Write_UINT32 (s, n_files);                    /* cItems */
+  for (i = 0; i < n_files; ++i)
+    {
+      file = &files[i];
+
+      Stream_Write_UINT32 (s, file->dwFlags);          /* flags */
+      Stream_Zero (s, 32);                             /* reserved1 */
+      Stream_Write_UINT32 (s, file->dwFileAttributes); /* fileAttributes */
+      Stream_Zero (s, 16);                             /* reserved2 */
+
+      last_write_time = file->ftLastWriteTime.dwHighDateTime;
+      last_write_time <<= 32;
+      last_write_time += file->ftLastWriteTime.dwLowDateTime;
+
+      Stream_Write_UINT64 (s, last_write_time);        /* lastWriteTime */
+      Stream_Write_UINT32 (s, file->nFileSizeHigh);    /* fileSizeHigh */
+      Stream_Write_UINT32 (s, file->nFileSizeLow);     /* fileSizeLow */
+
+      for (j = 0; j < 260; j++)                        /* cFileName */
+        Stream_Write_UINT16 (s, file->cFileName[j]);
+    }
+
+  Stream_SealLength (s);
+  Stream_GetLength (s, *dst_size);
+  Stream_GetBuffer (s, *dst_data);
+
+  Stream_Free (s, FALSE);
+}
+
+static void
+grd_clipboard_rdp_submit_requested_server_content (GrdClipboard *clipboard,
+                                                   uint8_t      *src_data,
+                                                   uint32_t      src_size)
+{
+  GrdClipboardRdp *clipboard_rdp = GRD_CLIPBOARD_RDP (clipboard);
+  CliprdrServerContext *cliprdr_context = clipboard_rdp->cliprdr_context;
+  ServerFormatDataRequestContext *request_context;
+  CLIPRDR_FORMAT_DATA_RESPONSE format_data_response = {0};
+  GrdMimeType mime_type;
+  uint32_t src_format_id;
+  uint32_t dst_format_id;
+  uint8_t *dst_data = NULL;
+  uint32_t dst_size = 0;
+  BOOL success;
+
+  request_context = g_steal_pointer (&clipboard_rdp->format_data_request_context);
+  mime_type = request_context->mime_type;
+  src_format_id = request_context->src_format_id;
+  dst_format_id = request_context->dst_format_id;
+
+  if (src_data)
+    {
+      if (request_context->needs_conversion)
+        {
+          if (request_context->needs_null_terminator)
+            {
+              char *pnull_terminator;
+
+              src_data = g_realloc (src_data, src_size + 1);
+              pnull_terminator = (char *) src_data + src_size;
+              *pnull_terminator = '\0';
+              ++src_size;
+            }
+
+          success = ClipboardSetData (clipboard_rdp->system,
+                                      src_format_id, src_data, src_size);
+          if (success)
+            {
+              dst_data = ClipboardGetData (clipboard_rdp->system,
+                                           dst_format_id, &dst_size);
+
+              if (dst_data && mime_type == GRD_MIME_TYPE_TEXT_URILIST)
+                {
+                  uint64_t serial = clipboard_rdp->serial;
+                  ClipDataEntry *entry;
+#ifdef HAVE_FREERDP_2_3
+                  FILEDESCRIPTORW *files;
+                  uint32_t n_files;
+
+                  files = (FILEDESCRIPTORW *) dst_data;
+                  n_files = dst_size / sizeof (FILEDESCRIPTORW);
+#else
+                  FILEDESCRIPTOR *files;
+                  uint32_t n_files;
+
+                  files = (FILEDESCRIPTOR *) dst_data;
+                  n_files = dst_size / sizeof (FILEDESCRIPTOR);
+#endif /* HAVE_FREERDP_2_3 */
+
+                  dst_data = NULL;
+                  dst_size = 0;
+                  serialize_file_list (files, n_files, &dst_data, &dst_size);
+
+                  g_free (files);
+
+                  clipboard_rdp->has_file_list = TRUE;
+                  if (g_hash_table_lookup_extended (clipboard_rdp->serial_entry_table,
+                                                    GUINT_TO_POINTER (serial),
+                                                    NULL, (gpointer *) &entry))
+                    entry->has_file_list = TRUE;
+                }
+            }
+          if (!success || !dst_data)
+            g_warning ("[RDP.CLIPRDR] Converting clipboard content failed");
+        }
+      else
+        {
+          dst_data = g_steal_pointer (&src_data);
+          dst_size = src_size;
+        }
+    }
+
+  format_data_response.msgType = CB_FORMAT_DATA_RESPONSE;
+  format_data_response.msgFlags = dst_data ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
+  format_data_response.dataLen = dst_size;
+  format_data_response.requestedFormatData = dst_data;
+
+  cliprdr_context->ServerFormatDataResponse (cliprdr_context,
+                                             &format_data_response);
+
+  g_free (src_data);
+  g_free (dst_data);
+  g_free (request_context);
+
+  SetEvent (clipboard_rdp->completed_format_data_request_event);
+}
+
 /**
  * FreeRDP already updated our capabilites after the client told us
  * about its capabilities, there is nothing to do here
@@ -1427,165 +1582,47 @@ cliprdr_client_unlock_clipboard_data (CliprdrServerContext                *clipr
   return CHANNEL_RC_OK;
 }
 
-static void
-#ifdef HAVE_FREERDP_2_3
-serialize_file_list (FILEDESCRIPTORW  *files,
-                     uint32_t          n_files,
-                     uint8_t         **dst_data,
-                     uint32_t         *dst_size)
-{
-  FILEDESCRIPTORW *file;
-#else
-serialize_file_list (FILEDESCRIPTOR *files,
-                     uint32_t         n_files,
-                     uint8_t        **dst_data,
-                     uint32_t        *dst_size)
-{
-  FILEDESCRIPTOR *file;
-#endif /* HAVE_FREERDP_2_3 */
-  wStream* s = NULL;
-  uint64_t last_write_time;
-  uint32_t i, j;
-
-  if (!files || !dst_data || !dst_size)
-    return;
-
-  if (!(s = Stream_New (NULL, 4 + n_files * CLIPRDR_FILEDESCRIPTOR_SIZE)))
-    return;
-
-  Stream_Write_UINT32 (s, n_files);                    /* cItems */
-  for (i = 0; i < n_files; ++i)
-    {
-      file = &files[i];
-
-      Stream_Write_UINT32 (s, file->dwFlags);          /* flags */
-      Stream_Zero (s, 32);                             /* reserved1 */
-      Stream_Write_UINT32 (s, file->dwFileAttributes); /* fileAttributes */
-      Stream_Zero (s, 16);                             /* reserved2 */
-
-      last_write_time = file->ftLastWriteTime.dwHighDateTime;
-      last_write_time <<= 32;
-      last_write_time += file->ftLastWriteTime.dwLowDateTime;
-
-      Stream_Write_UINT64 (s, last_write_time);        /* lastWriteTime */
-      Stream_Write_UINT32 (s, file->nFileSizeHigh);    /* fileSizeHigh */
-      Stream_Write_UINT32 (s, file->nFileSizeLow);     /* fileSizeLow */
-
-      for (j = 0; j < 260; j++)                        /* cFileName */
-        Stream_Write_UINT16 (s, file->cFileName[j]);
-    }
-
-  Stream_SealLength (s);
-  Stream_GetLength (s, *dst_size);
-  Stream_GetBuffer (s, *dst_data);
-
-  Stream_Free (s, FALSE);
-}
-
 static gboolean
 request_server_format_data (gpointer user_data)
 {
-  ServerFormatDataRequestContext *request_context = user_data;
-  GrdClipboardRdp *clipboard_rdp = request_context->clipboard_rdp;
+  GrdClipboardRdp *clipboard_rdp = user_data;
   GrdClipboard *clipboard = GRD_CLIPBOARD (clipboard_rdp);
   CliprdrServerContext *cliprdr_context = clipboard_rdp->cliprdr_context;
-  CLIPRDR_FORMAT_DATA_RESPONSE format_data_response = {0};
-  GrdMimeType mime_type = request_context->mime_type;
-  uint32_t src_format_id = request_context->src_format_id;
-  uint32_t dst_format_id = request_context->dst_format_id;
-  uint8_t *src_data, *dst_data;
-  uint32_t src_size, dst_size;
-  BOOL success;
+  ServerFormatDataRequestContext *request_context;
+  GrdMimeType mime_type;
 
-  dst_data = src_data = NULL;
-  dst_size = src_size = 0;
+  request_context = clipboard_rdp->format_data_request_context;
+  mime_type = request_context->mime_type;
 
-  if (g_hash_table_contains (clipboard_rdp->allowed_server_formats,
-                             GUINT_TO_POINTER (mime_type)))
+  if (!g_hash_table_contains (clipboard_rdp->allowed_server_formats,
+                              GUINT_TO_POINTER (mime_type)))
     {
-      src_data = grd_clipboard_request_server_content_for_mime_type (clipboard,
-                                                                     mime_type,
-                                                                     &src_size);
-    }
-  if (src_data)
-    {
-      if (request_context->needs_conversion)
-        {
-          if (request_context->needs_null_terminator)
-            {
-              char *pnull_terminator;
-
-              src_data = g_realloc (src_data, src_size + 1);
-              pnull_terminator = (char *) src_data + src_size;
-              *pnull_terminator = '\0';
-              ++src_size;
-            }
-
-          success = ClipboardSetData (clipboard_rdp->system,
-                                      src_format_id, src_data, src_size);
-          if (success)
-            {
-              dst_data = ClipboardGetData (clipboard_rdp->system,
-                                           dst_format_id, &dst_size);
+      CLIPRDR_FORMAT_DATA_RESPONSE format_data_response = {0};
 
-              if (dst_data && mime_type == GRD_MIME_TYPE_TEXT_URILIST)
-                {
-                  uint64_t serial = clipboard_rdp->serial;
-                  ClipDataEntry *entry;
-#ifdef HAVE_FREERDP_2_3
-                  FILEDESCRIPTORW *files;
-                  uint32_t n_files;
-
-                  files = (FILEDESCRIPTORW *) dst_data;
-                  n_files = dst_size / sizeof (FILEDESCRIPTORW);
-#else
-                  FILEDESCRIPTOR *files;
-                  uint32_t n_files;
+      format_data_response.msgType = CB_FORMAT_DATA_RESPONSE;
+      format_data_response.msgFlags = CB_RESPONSE_FAIL;
 
-                  files = (FILEDESCRIPTOR *) dst_data;
-                  n_files = dst_size / sizeof (FILEDESCRIPTOR);
-#endif /* HAVE_FREERDP_2_3 */
+      cliprdr_context->ServerFormatDataResponse (cliprdr_context,
+                                                 &format_data_response);
 
-                  dst_data = NULL;
-                  dst_size = 0;
-                  serialize_file_list (files, n_files, &dst_data, &dst_size);
+      g_clear_pointer (&clipboard_rdp->format_data_request_context, g_free);
 
-                  g_free (files);
+      WaitForSingleObject (clipboard_rdp->format_data_request_received_event,
+                           INFINITE);
+      clipboard_rdp->server_format_data_request_id = 0;
+      ResetEvent (clipboard_rdp->format_data_request_received_event);
+      SetEvent (clipboard_rdp->completed_format_data_request_event);
 
-                  clipboard_rdp->has_file_list = TRUE;
-                  if (g_hash_table_lookup_extended (clipboard_rdp->serial_entry_table,
-                                                    GUINT_TO_POINTER (serial),
-                                                    NULL, (gpointer *) &entry))
-                    entry->has_file_list = TRUE;
-                }
-            }
-          if (!success || !dst_data)
-            g_warning ("[RDP.CLIPRDR] Converting clipboard content failed");
-        }
-      else
-        {
-          dst_data = g_steal_pointer (&src_data);
-          dst_size = src_size;
-        }
+      return G_SOURCE_REMOVE;
     }
 
-  format_data_response.msgType = CB_FORMAT_DATA_RESPONSE;
-  format_data_response.msgFlags = dst_data ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
-  format_data_response.dataLen = dst_size;
-  format_data_response.requestedFormatData = dst_data;
-
-  cliprdr_context->ServerFormatDataResponse (cliprdr_context,
-                                             &format_data_response);
-
-  g_free (src_data);
-  g_free (dst_data);
-  g_free (request_context);
+  grd_clipboard_request_server_content_for_mime_type_async (clipboard,
+                                                            mime_type);
 
   WaitForSingleObject (clipboard_rdp->format_data_request_received_event,
                        INFINITE);
   clipboard_rdp->server_format_data_request_id = 0;
   ResetEvent (clipboard_rdp->format_data_request_received_event);
-  SetEvent (clipboard_rdp->completed_format_data_request_event);
 
   return G_SOURCE_REMOVE;
 }
@@ -1686,8 +1723,11 @@ cliprdr_client_format_data_request (CliprdrServerContext              *cliprdr_c
       request_context->needs_null_terminator = needs_null_terminator;
       request_context->needs_conversion = needs_conversion;
 
+      g_assert (!clipboard_rdp->format_data_request_context);
+      clipboard_rdp->format_data_request_context = request_context;
+
       clipboard_rdp->server_format_data_request_id =
-        g_idle_add (request_server_format_data, request_context);
+        g_idle_add (request_server_format_data, clipboard_rdp);
       SetEvent (clipboard_rdp->format_data_request_received_event);
 
       return CHANNEL_RC_OK;
@@ -2028,6 +2068,7 @@ grd_clipboard_rdp_dispose (GObject *object)
   if (clipboard_rdp->clipboard_retrieval_id)
     g_clear_pointer (&clipboard_rdp->clipboard_retrieval_context.entry, g_free);
 
+  g_clear_pointer (&clipboard_rdp->format_data_request_context, g_free);
   g_clear_pointer (&clipboard_rdp->queued_server_formats, g_list_free);
   g_clear_pointer (&clipboard_rdp->pending_server_formats, g_list_free);
   g_hash_table_foreach_remove (clipboard_rdp->format_data_cache,
@@ -2155,4 +2196,6 @@ grd_clipboard_rdp_class_init (GrdClipboardRdpClass *klass)
     grd_clipboard_rdp_update_client_mime_type_list;
   clipboard_class->request_client_content_for_mime_type =
     grd_clipboard_rdp_request_client_content_for_mime_type;
+  clipboard_class->submit_requested_server_content =
+    grd_clipboard_rdp_submit_requested_server_content;
 }
diff --git a/src/grd-clipboard-vnc.c b/src/grd-clipboard-vnc.c
index 9e1ce04..d0a8df4 100644
--- a/src/grd-clipboard-vnc.c
+++ b/src/grd-clipboard-vnc.c
@@ -34,38 +34,6 @@ struct _GrdClipboardVnc
 
 G_DEFINE_TYPE (GrdClipboardVnc, grd_clipboard_vnc, GRD_TYPE_CLIPBOARD);
 
-static void
-update_vnc_clipboard (GrdClipboardVnc *clipboard_vnc,
-                      GrdMimeType      text_mime_type)
-{
-  GrdClipboard *clipboard = GRD_CLIPBOARD (clipboard_vnc);
-  g_autoptr (GError) error = NULL;
-  uint8_t *src_data;
-  uint32_t src_size;
-  char *dst_data;
-
-  src_data = grd_clipboard_request_server_content_for_mime_type (clipboard,
-                                                                 text_mime_type,
-                                                                 &src_size);
-  if (!src_data)
-    return;
-
-  dst_data = g_convert ((char *) src_data, src_size,
-                        "iso8859-1", "utf-8",
-                        NULL, NULL, &error);
-  if (!dst_data)
-    {
-      g_warning ("[VNC.Clipboard] Failed to convert clipboard content: %s",
-                 error->message);
-      return;
-    }
-
-  grd_session_vnc_set_client_clipboard_text (clipboard_vnc->session_vnc,
-                                             dst_data, strlen (dst_data));
-
-  g_free (dst_data);
-}
-
 static void
 grd_clipboard_vnc_update_client_mime_type_list (GrdClipboard *clipboard,
                                                 GList        *mime_type_list)
@@ -104,7 +72,8 @@ grd_clipboard_vnc_update_client_mime_type_list (GrdClipboard *clipboard,
     {
       g_clear_pointer (&clipboard_vnc->clipboard_utf8_string, g_free);
 
-      update_vnc_clipboard (clipboard_vnc, mime_type);
+      grd_clipboard_request_server_content_for_mime_type_async (clipboard,
+                                                                mime_type);
     }
 
   g_list_free (mime_type_list);
@@ -122,6 +91,36 @@ grd_clipboard_vnc_request_client_content_for_mime_type (GrdClipboard     *clipbo
   return g_memdup2 (clipboard_vnc->clipboard_utf8_string, *size);
 }
 
+static void
+grd_clipboard_vnc_submit_requested_server_content (GrdClipboard *clipboard,
+                                                   uint8_t      *src_data,
+                                                   uint32_t      src_size)
+{
+  GrdClipboardVnc *clipboard_vnc = GRD_CLIPBOARD_VNC (clipboard);
+  g_autoptr (GError) error = NULL;
+  char *dst_data;
+
+  if (!src_data)
+    return;
+
+  dst_data = g_convert ((char *) src_data, src_size,
+                        "iso8859-1", "utf-8",
+                        NULL, NULL, &error);
+  if (!dst_data)
+    {
+      g_warning ("[VNC.Clipboard] Failed to convert clipboard content: %s",
+                 error->message);
+      g_free (src_data);
+      return;
+    }
+
+  grd_session_vnc_set_client_clipboard_text (clipboard_vnc->session_vnc,
+                                             dst_data, strlen (dst_data));
+
+  g_free (src_data);
+  g_free (dst_data);
+}
+
 void
 grd_clipboard_vnc_maybe_enable_clipboard (GrdClipboardVnc *clipboard_vnc)
 {
@@ -203,4 +202,6 @@ grd_clipboard_vnc_class_init (GrdClipboardVncClass *klass)
     grd_clipboard_vnc_update_client_mime_type_list;
   clipboard_class->request_client_content_for_mime_type =
     grd_clipboard_vnc_request_client_content_for_mime_type;
+  clipboard_class->submit_requested_server_content =
+    grd_clipboard_vnc_submit_requested_server_content;
 }
diff --git a/src/grd-clipboard.c b/src/grd-clipboard.c
index 0fc8ca6..cbc4702 100644
--- a/src/grd-clipboard.c
+++ b/src/grd-clipboard.c
@@ -75,27 +75,30 @@ grd_clipboard_update_server_mime_type_list (GrdClipboard *clipboard,
   g_list_free (mime_type_tables);
 }
 
-uint8_t *
-grd_clipboard_request_server_content_for_mime_type (GrdClipboard *clipboard,
-                                                    GrdMimeType   mime_type,
-                                                    uint32_t     *size)
+void
+grd_clipboard_request_server_content_for_mime_type_async (GrdClipboard *clipboard,
+                                                          GrdMimeType   mime_type)
 {
+  GrdClipboardClass *klass = GRD_CLIPBOARD_GET_CLASS (clipboard);
   GrdClipboardPrivate *priv = grd_clipboard_get_instance_private (clipboard);
   uint8_t *data;
+  uint32_t size;
+
+  if (!klass->submit_requested_server_content)
+    return;
 
-  *size = 0;
   if (!priv->enabled)
-    return NULL;
+    return;
 
   g_debug ("Clipboard[SelectionRead]: Requesting data from servers clipboard"
            " (mime type: %s)", grd_mime_type_to_string (mime_type));
-  data = grd_session_selection_read (priv->session, mime_type, size);
+  data = grd_session_selection_read (priv->session, mime_type, &size);
   if (data)
     g_debug ("Clipboard[SelectionRead]: Request successful");
   else
     g_debug ("Clipboard[SelectionRead]: Request failed");
 
-  return data;
+  klass->submit_requested_server_content (clipboard, data, size);
 }
 
 void
diff --git a/src/grd-clipboard.h b/src/grd-clipboard.h
index 2e38d24..93249d0 100644
--- a/src/grd-clipboard.h
+++ b/src/grd-clipboard.h
@@ -38,14 +38,16 @@ struct _GrdClipboardClass
   uint8_t *(*request_client_content_for_mime_type) (GrdClipboard     *clipboard,
                                                     GrdMimeTypeTable *mime_type_table,
                                                     uint32_t         *size);
+  void (*submit_requested_server_content) (GrdClipboard *clipboard,
+                                           uint8_t      *data,
+                                           uint32_t      size);
 };
 
 void grd_clipboard_update_server_mime_type_list (GrdClipboard *clipboard,
                                                  GList        *mime_type_tables);
 
-uint8_t *grd_clipboard_request_server_content_for_mime_type (GrdClipboard *clipboard,
-                                                             GrdMimeType   mime_type,
-                                                             uint32_t     *size);
+void grd_clipboard_request_server_content_for_mime_type_async (GrdClipboard *clipboard,
+                                                               GrdMimeType   mime_type);
 
 void grd_clipboard_initialize (GrdClipboard *clipboard,
                                GrdSession   *session);


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