[gtk/matthiasc/css-change-tracking-4: 1/20] Tweak the file transfer portal _again_



commit 69fb3648b2e20935b7839f874fb0b52dee32448b
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Jan 17 22:31:51 2020 -0500

    Tweak the file transfer portal _again_
    
    This is a neverending story. I was seeing problems in tests where
    the nested mainloop was picking up unrelated timeouts.
    
    Break down and make this async. This changes the ordering in which
    the (de)serializers are registered. If this is causing issues, we
    can introduce priorities or something else.

 gdk/filetransferportal.c        | 388 +++++++++++++++++++++++++---------------
 gdk/filetransferportalprivate.h |   3 +-
 gdk/gdkcontentdeserializer.c    | 106 +----------
 gdk/gdkcontentserializer.c      |  77 +-------
 4 files changed, 243 insertions(+), 331 deletions(-)
---
diff --git a/gdk/filetransferportal.c b/gdk/filetransferportal.c
index ba5f6d4ef0..541fd85a24 100644
--- a/gdk/filetransferportal.c
+++ b/gdk/filetransferportal.c
@@ -23,6 +23,10 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 
+#include "gdkcontentformats.h"
+#include "gdkcontentserializer.h"
+#include "gdkcontentdeserializer.h"
+
 #include <gio/gio.h>
 
 #ifdef G_OS_UNIX
@@ -42,145 +46,6 @@
 #include "filetransferportalprivate.h"
 
 static GDBusProxy *file_transfer_proxy = NULL;
-static gboolean done;
-static guint timeout_id;
-
-static void
-got_proxy (GObject *source,
-           GAsyncResult *result,
-           gpointer data)
-{
-  GError *error = NULL;
-
-  file_transfer_proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
-  if (!file_transfer_proxy)
-    {
-      g_message ("failed to get file transfer portal proxy: %s", error->message);
-      g_error_free (error);
-    }
-
-  if (timeout_id)
-    {
-      g_source_remove (timeout_id);
-      timeout_id = 0;
-    }
-
-  done = TRUE;
-  g_main_context_wakeup (NULL);
-}
-
-static void
-got_bus (GObject *source,
-         GAsyncResult *result,
-         gpointer data)
-{
-  GDBusConnection **bus = data;
-  GError *error = NULL;
-
-  *bus = g_bus_get_finish (result, &error);
-  if (!*bus)
-    {
-      g_message ("failed to get session bus connection: %s", error->message);
-      g_error_free (error);
-    }
-
-  if (timeout_id)
-    {
-      g_source_remove (timeout_id);
-      timeout_id = 0;
-    }
-
-  done = TRUE;
-  g_main_context_wakeup (NULL);
-}
-
-static gboolean
-give_up_on_proxy (gpointer data)
-{
-  GCancellable *cancellable = data;
-
-  g_cancellable_cancel (cancellable);
-
-  timeout_id = 0;
-
-  done = TRUE;
-  g_main_context_wakeup (NULL);
-
-  return G_SOURCE_REMOVE;
-}
-
-static GDBusProxy *
-ensure_file_transfer_portal (void)
-{
-  if (file_transfer_proxy == NULL)
-    {
-      GCancellable *cancellable;
-      GDBusConnection *bus = NULL;
-
-      cancellable = g_cancellable_new ();
- 
-      done = FALSE;
-      timeout_id = g_timeout_add (500, give_up_on_proxy, cancellable);
-      g_bus_get (G_BUS_TYPE_SESSION,
-                 cancellable,
-                 got_bus,
-                 &bus);
-
-      while (!done)
-        g_main_context_iteration (NULL, TRUE);
-
-      if (bus)
-        {
-          done = FALSE;
-          timeout_id = g_timeout_add (500, give_up_on_proxy, cancellable);
-          g_dbus_proxy_new (bus,
-                            G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
-                            | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
-                            | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
-                            NULL,
-                            "org.freedesktop.portal.Documents",
-                            "/org/freedesktop/portal/documents",
-                            "org.freedesktop.portal.FileTransfer",
-                            cancellable,
-                            got_proxy,
-                            NULL);
-
-          while (!done)
-            g_main_context_iteration (NULL, TRUE);
-
-          g_clear_object (&bus);
-        }
-
-      g_clear_object (&cancellable);
-    }
-
-  if (file_transfer_proxy)
-    {
-      char *owner = g_dbus_proxy_get_name_owner (file_transfer_proxy);
-
-      if (owner)
-        {
-          g_free (owner);
-          return file_transfer_proxy;
-        }
-    }
-
-  return NULL;
-}
-
-gboolean
-file_transfer_portal_available (void)
-{
-  gboolean available;
-
-  ensure_file_transfer_portal ();
-
-  available = file_transfer_proxy != NULL;
-
-  g_clear_object (&file_transfer_proxy);
-
-  return available;
-}
 
 typedef struct {
   GTask *task;
@@ -328,15 +193,12 @@ file_transfer_portal_register_files (const char          **files,
                                      gpointer              data)
 {
   GTask *task;
-  GDBusProxy *proxy;
   AddFileData *afd;
   GVariantBuilder options;
 
   task = g_task_new (NULL, NULL, callback, data);
 
-  proxy = ensure_file_transfer_portal ();
-
-  if (proxy == NULL)
+  if (file_transfer_proxy == NULL)
     {
       g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
                                "No portal found");
@@ -354,7 +216,7 @@ file_transfer_portal_register_files (const char          **files,
   g_variant_builder_add (&options, "{sv}", "writable", g_variant_new_boolean (writable));
   g_variant_builder_add (&options, "{sv}", "autostop", g_variant_new_boolean (TRUE));
 
-  g_dbus_proxy_call (proxy, "StartTransfer",
+  g_dbus_proxy_call (file_transfer_proxy, "StartTransfer",
                      g_variant_new ("(a{sv})", &options),
                      0, -1, NULL, start_session_done, afd);
 }
@@ -406,15 +268,12 @@ file_transfer_portal_retrieve_files (const char          *key,
                                      GAsyncReadyCallback  callback,
                                      gpointer             data)
 {
-  GDBusProxy *proxy;
   GTask *task;
   GVariantBuilder options;
 
   task = g_task_new (NULL, NULL, callback, data);
 
-  proxy = ensure_file_transfer_portal ();
-
-  if (proxy == NULL)
+  if (file_transfer_proxy == NULL)
     {
       g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
                                "No portal found");
@@ -423,7 +282,7 @@ file_transfer_portal_retrieve_files (const char          *key,
     }
 
   g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
-  g_dbus_proxy_call (proxy,
+  g_dbus_proxy_call (file_transfer_proxy,
                      "RetrieveFiles",
                      g_variant_new ("(sa{sv})", key, &options),
                      0, -1, NULL,
@@ -444,4 +303,235 @@ file_transfer_portal_retrieve_files_finish (GAsyncResult   *result,
   return FALSE;
 }
 
+
+/* serializer */
+
+static void
+file_serializer_finish (GObject      *source,
+                        GAsyncResult *result,
+                        gpointer      serializer)
+{
+  GOutputStream *stream = G_OUTPUT_STREAM (source);
+  GError *error = NULL;
+
+  if (!g_output_stream_write_all_finish (stream, result, NULL, &error))
+    gdk_content_serializer_return_error (serializer, error);
+  else
+    gdk_content_serializer_return_success (serializer);
+}
+
+static void
+portal_ready (GObject *object,
+              GAsyncResult *result,
+              gpointer serializer)
+{
+  GError *error = NULL;
+  char *key;
+
+  if (!file_transfer_portal_register_files_finish (result, &key, &error))
+    {
+      gdk_content_serializer_return_error (serializer, error);
+      return;
+    }
+
+  g_output_stream_write_all_async (gdk_content_serializer_get_output_stream (serializer),
+                                   key,
+                                   strlen (key) + 1,
+                                   gdk_content_serializer_get_priority (serializer),
+                                   gdk_content_serializer_get_cancellable (serializer),
+                                   file_serializer_finish,
+                                   serializer);
+  gdk_content_serializer_set_task_data (serializer, key, g_free);
+}
+
+static void
+portal_file_serializer (GdkContentSerializer *serializer)
+{
+  GFile *file;
+  const GValue *value;
+  GPtrArray *files;
+
+  files = g_ptr_array_new_with_free_func (g_free);
+
+  value = gdk_content_serializer_get_value (serializer);
+
+  if (G_VALUE_HOLDS (value, G_TYPE_FILE))
+    {
+      file = g_value_get_object (gdk_content_serializer_get_value (serializer));
+      if (file)
+        g_ptr_array_add (files, g_file_get_path (file));
+      g_ptr_array_add (files, NULL);
+    }
+  else if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
+    {
+      GSList *l;
+
+      for (l = g_value_get_boxed (value); l; l = l->next)
+        g_ptr_array_add (files, g_file_get_path (l->data));
+
+      g_ptr_array_add (files, NULL);
+    }
+
+  /* this call doesn't copy the strings, so keep the array around until the registration is done */
+  file_transfer_portal_register_files ((const char **)files->pdata, TRUE, portal_ready, serializer);
+  gdk_content_serializer_set_task_data (serializer, files, (GDestroyNotify)g_ptr_array_unref);
+}
+
+/* deserializer */
+
+static void
+portal_finish (GObject *object,
+               GAsyncResult *result,
+               gpointer deserializer)
+{
+  char **files = NULL;
+  GError *error = NULL;
+  GValue *value;
+
+  if (!file_transfer_portal_retrieve_files_finish (result, &files, &error))
+    {
+      gdk_content_deserializer_return_error (deserializer, error);
+      return;
+    }
+
+  value = gdk_content_deserializer_get_value (deserializer);
+  if (G_VALUE_HOLDS (value, G_TYPE_FILE))
+    {
+      if (files[0] != NULL)
+        g_value_take_object (value, g_file_new_for_path (files[0]));
+    }
+  else
+    {
+      GSList *l = NULL;
+      gsize i;
+
+      for (i = 0; files[i] != NULL; i++)
+        l = g_slist_prepend (l, g_file_new_for_path (files[i]));
+      g_value_take_boxed (value, g_slist_reverse (l));
+    }
+  g_strfreev (files);
+
+  gdk_content_deserializer_return_success (deserializer);
+}
+
+static void
+portal_file_deserializer_finish (GObject      *source,
+                                 GAsyncResult *result,
+                                 gpointer      deserializer)
+{
+  GOutputStream *stream = G_OUTPUT_STREAM (source);
+  GError *error = NULL;
+  gssize written;
+  char *key;
+
+  written = g_output_stream_splice_finish (stream, result, &error);
+  if (written < 0)
+    {
+      gdk_content_deserializer_return_error (deserializer, error);
+      return;
+    }
+
+  /* write terminating NULL */
+  if (!g_output_stream_write (stream, "", 1, NULL, &error))
+    {
+      gdk_content_deserializer_return_error (deserializer, error);
+      return;
+    }
+
+  key = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (stream));
+  if (key == NULL)
+    {
+      GError *gerror = g_error_new (G_IO_ERROR,
+                                    G_IO_ERROR_NOT_FOUND,
+                                    "Could not convert data from %s to %s",
+                                    gdk_content_deserializer_get_mime_type (deserializer),
+                                    g_type_name (gdk_content_deserializer_get_gtype (deserializer)));
+      gdk_content_deserializer_return_error (deserializer, gerror);
+      return;
+    }
+
+  file_transfer_portal_retrieve_files (key, portal_finish, deserializer);
+  gdk_content_deserializer_set_task_data (deserializer, key, g_free);
+}
+
+static void
+portal_file_deserializer (GdkContentDeserializer *deserializer)
+{
+  GOutputStream *output;
+
+  output = g_memory_output_stream_new_resizable ();
+
+  g_output_stream_splice_async (output,
+                                gdk_content_deserializer_get_input_stream (deserializer),
+                                G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+                                gdk_content_deserializer_get_priority (deserializer),
+                                gdk_content_deserializer_get_cancellable (deserializer),
+                                portal_file_deserializer_finish,
+                                deserializer);
+  g_object_unref (output);
+}
+
+static void
+got_proxy (GObject *source,
+           GAsyncResult *result,
+           gpointer data)
+{
+  GError *error = NULL;
+
+  file_transfer_proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
+  if (!file_transfer_proxy)
+    {
+      g_message ("Failed to get file transfer portal: %s", error->message);
+      g_clear_error (&error);
+      return;
+    }
+
+  gdk_content_register_serializer (G_TYPE_FILE,
+                                   "application/vnd.portal.files",
+                                   portal_file_serializer,
+                                   NULL,
+                                   NULL);
+
+  gdk_content_register_serializer (GDK_TYPE_FILE_LIST,
+                                   "application/vnd.portal.files",
+                                   portal_file_serializer,
+                                   NULL,
+                                   NULL);
+
+  gdk_content_register_deserializer ("application/vnd.portal.files",
+                                     GDK_TYPE_FILE_LIST,
+                                     portal_file_deserializer,
+                                     NULL,
+                                     NULL);
+
+  gdk_content_register_deserializer ("application/vnd.portal.files",
+                                     G_TYPE_FILE,
+                                     portal_file_deserializer,
+                                     NULL,
+                                     NULL);
+}
+
+void
+file_transfer_portal_register (void)
+{
+  static gboolean called;
+
+  if (!called)
+    {
+      called = TRUE;
+      g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
+                                G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
+                                | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
+                                | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+                                NULL,
+                                "org.freedesktop.portal.Documents",
+                                "/org/freedesktop/portal/documents",
+                                "org.freedesktop.portal.FileTransfer",
+                                NULL,
+                                got_proxy,
+                                NULL);
+    }
+}
+
+
 #endif /* G_OS_UNIX */
diff --git a/gdk/filetransferportalprivate.h b/gdk/filetransferportalprivate.h
index d23fdfbd75..37bc3009cf 100644
--- a/gdk/filetransferportalprivate.h
+++ b/gdk/filetransferportalprivate.h
@@ -19,7 +19,8 @@
 #define __FILE_TRANSFER_PROTOCOL_H__
 
 
-gboolean file_transfer_portal_available             (void);
+void     file_transfer_portal_register              (void);
+
 void     file_transfer_portal_register_files        (const char           **files,
                                                      gboolean               writable,
                                                      GAsyncReadyCallback    callback,
diff --git a/gdk/gdkcontentdeserializer.c b/gdk/gdkcontentdeserializer.c
index 0015520b3c..12594b1fd8 100644
--- a/gdk/gdkcontentdeserializer.c
+++ b/gdk/gdkcontentdeserializer.c
@@ -692,95 +692,6 @@ string_deserializer (GdkContentDeserializer *deserializer)
   g_object_unref (filter);
 }
 
-#ifdef G_OS_UNIX
-static void
-portal_finish (GObject *object,
-               GAsyncResult *result,
-               gpointer deserializer)
-{
-  char **files = NULL;
-  GError *error = NULL;
-  GValue *value;
-
-  if (!file_transfer_portal_retrieve_files_finish (result, &files, &error))
-    {
-      gdk_content_deserializer_return_error (deserializer, error);
-      return;
-    }
-
-  value = gdk_content_deserializer_get_value (deserializer);
-  if (G_VALUE_HOLDS (value, G_TYPE_FILE))
-    {
-      if (files[0] != NULL)
-        g_value_take_object (value, g_file_new_for_path (files[0]));
-    }
-  else
-    {
-      GSList *l = NULL;
-      gsize i;
-
-      for (i = 0; files[i] != NULL; i++)
-        l = g_slist_prepend (l, g_file_new_for_path (files[i]));
-      g_value_take_boxed (value, g_slist_reverse (l));
-    }
-  g_strfreev (files);
-
-  gdk_content_deserializer_return_success (deserializer);
-}
-
-static void
-portal_file_deserializer_finish (GObject      *source,
-                                 GAsyncResult *result,
-                                 gpointer      deserializer)
-{
-  GOutputStream *stream = G_OUTPUT_STREAM (source);
-  GError *error = NULL;
-  gssize written;
-  char *key;
-
-  written = g_output_stream_splice_finish (stream, result, &error);
-  if (written < 0)
-    {
-      gdk_content_deserializer_return_error (deserializer, error);
-      return;
-    }
-
-  /* write terminating NULL */
-  if (!g_output_stream_write (stream, "", 1, NULL, &error))
-    {
-      gdk_content_deserializer_return_error (deserializer, error);
-      return;
-    }
-
-  key = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (stream));
-  if (key == NULL)
-    {
-      deserialize_not_found (deserializer);
-      return;
-    }
-
-  file_transfer_portal_retrieve_files (key, portal_finish, deserializer);
-  gdk_content_deserializer_set_task_data (deserializer, key, g_free);
-}
-
-static void
-portal_file_deserializer (GdkContentDeserializer *deserializer)
-{
-  GOutputStream *output;
-
-  output = g_memory_output_stream_new_resizable ();
-
-  g_output_stream_splice_async (output,
-                                gdk_content_deserializer_get_input_stream (deserializer),
-                                G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
-                                gdk_content_deserializer_get_priority (deserializer),
-                                gdk_content_deserializer_get_cancellable (deserializer),
-                                portal_file_deserializer_finish,
-                                deserializer);
-  g_object_unref (output);
-}
-#endif /* G_OS_UNIX */
-
 static void
 file_uri_deserializer_finish (GObject      *source,
                               GAsyncResult *result,
@@ -965,13 +876,7 @@ init (void)
   g_slist_free (formats);
 
 #ifdef G_OS_UNIX
-  gboolean has_portal = file_transfer_portal_available ();
-  if (has_portal)
-    gdk_content_register_deserializer ("application/vnd.portal.files",
-                                       GDK_TYPE_FILE_LIST,
-                                       portal_file_deserializer,
-                                       NULL,
-                                       NULL);
+  file_transfer_portal_register ();
 #endif
 
   gdk_content_register_deserializer ("text/uri-list",
@@ -980,15 +885,6 @@ init (void)
                                      NULL,
                                      NULL);
 
-#ifdef G_OS_UNIX
-  if (has_portal)
-    gdk_content_register_deserializer ("application/vnd.portal.files",
-                                       G_TYPE_FILE,
-                                       portal_file_deserializer,
-                                       NULL,
-                                       NULL);
-#endif
-
   gdk_content_register_deserializer ("text/uri-list",
                                      G_TYPE_FILE,
                                      file_uri_deserializer,
diff --git a/gdk/gdkcontentserializer.c b/gdk/gdkcontentserializer.c
index 6caea1edef..63d1232167 100644
--- a/gdk/gdkcontentserializer.c
+++ b/gdk/gdkcontentserializer.c
@@ -703,65 +703,6 @@ file_serializer_finish (GObject      *source,
     gdk_content_serializer_return_success (serializer);
 }
 
-#ifdef G_OS_UNIX
-static void
-portal_ready (GObject *object,
-              GAsyncResult *result,
-              gpointer serializer)
-{
-  GError *error = NULL;
-  char *key;
-
-  if (!file_transfer_portal_register_files_finish (result, &key, &error))
-    {
-      gdk_content_serializer_return_error (serializer, error);
-      return;
-    }
-
-  g_output_stream_write_all_async (gdk_content_serializer_get_output_stream (serializer),
-                                   key,
-                                   strlen (key) + 1,
-                                   gdk_content_serializer_get_priority (serializer),
-                                   gdk_content_serializer_get_cancellable (serializer),
-                                   file_serializer_finish,
-                                   serializer);
-  gdk_content_serializer_set_task_data (serializer, key, g_free);
-}
-
-static void
-portal_file_serializer (GdkContentSerializer *serializer)
-{
-  GFile *file;
-  const GValue *value;
-  GPtrArray *files;
-
-  files = g_ptr_array_new_with_free_func (g_free);
-
-  value = gdk_content_serializer_get_value (serializer);
-
-  if (G_VALUE_HOLDS (value, G_TYPE_FILE))
-    {
-      file = g_value_get_object (gdk_content_serializer_get_value (serializer));
-      if (file)
-        g_ptr_array_add (files, g_file_get_path (file));
-      g_ptr_array_add (files, NULL);
-    }
-  else if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
-    {
-      GSList *l;
-
-      for (l = g_value_get_boxed (value); l; l = l->next)
-        g_ptr_array_add (files, g_file_get_path (l->data));
-
-      g_ptr_array_add (files, NULL);
-    }
-
-  /* this call doesn't copy the strings, so keep the array around until the registration is done */
-  file_transfer_portal_register_files ((const char **)files->pdata, TRUE, portal_ready, serializer);
-  gdk_content_serializer_set_task_data (serializer, files, (GDestroyNotify)g_ptr_array_unref);
-}
-#endif /* G_OS_UNIX */
-
 static void
 file_uri_serializer (GdkContentSerializer *serializer)
 {
@@ -967,14 +908,7 @@ init (void)
   g_slist_free (formats);
 
 #ifdef G_OS_UNIX
-  gboolean has_portal = file_transfer_portal_available ();
-
-  if (has_portal)
-    gdk_content_register_serializer (G_TYPE_FILE,
-                                     "application/vnd.portal.files",
-                                     portal_file_serializer,
-                                     NULL,
-                                     NULL);
+  file_transfer_portal_register ();
 #endif
 
   gdk_content_register_serializer (G_TYPE_FILE,
@@ -988,15 +922,6 @@ init (void)
                                    NULL,
                                    NULL);
 
-#ifdef G_OS_UNIX
-  if (has_portal)
-    gdk_content_register_serializer (GDK_TYPE_FILE_LIST,
-                                     "application/vnd.portal.files",
-                                     portal_file_serializer,
-                                     NULL,
-                                     NULL);
-#endif
-
   gdk_content_register_serializer (GDK_TYPE_FILE_LIST,
                                    "text/uri-list",
                                    file_uri_serializer,


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