[glib] Add async variant of g_app_info_launch_default_for_uri



commit c1e8f705dd3043e6d001d49db00fe6ea12959613
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Jul 16 11:45:44 2016 -0400

    Add async variant of g_app_info_launch_default_for_uri
    
    This is useful in the portalized case, when the portal may
    present an app chooser dialog to the user.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=768752

 docs/reference/gio/gio-sections.txt |    2 +
 gio/gappinfo.c                      |  256 ++++++++++++++++++++++++++++-------
 gio/gappinfo.h                      |   11 ++
 3 files changed, 219 insertions(+), 50 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 6207717..85fd2b9 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1427,6 +1427,8 @@ g_app_info_get_default_for_uri_scheme
 g_app_info_get_fallback_for_type
 g_app_info_get_recommended_for_type
 g_app_info_launch_default_for_uri
+g_app_info_launch_default_for_uri_async
+g_app_info_launch_default_for_uri_finish
 g_app_launch_context_setenv
 g_app_launch_context_unsetenv
 g_app_launch_context_get_environment
diff --git a/gio/gappinfo.c b/gio/gappinfo.c
index d9ae46e..398528e 100644
--- a/gio/gappinfo.c
+++ b/gio/gappinfo.c
@@ -36,7 +36,6 @@
 #endif
 
 
-
 /**
  * SECTION:gappinfo
  * @short_description: Application information and launch contexts
@@ -678,20 +677,95 @@ g_app_info_should_show (GAppInfo *appinfo)
 }
 
 #ifdef G_OS_UNIX
-static gboolean
-launch_default_with_portal (const char         *uri,
-                            GAppLaunchContext  *context,
-                            GError            **error)
+static void
+response_received (GDBusConnection *connection,
+                   const char      *sender_name,
+                   const char      *object_path,
+                   const char      *interface_name,
+                   const char      *signal_name,
+                   GVariant        *parameters,
+                   gpointer         user_data)
+{
+  GTask *task = user_data;
+  guint32 response;
+  guint signal_id;
+
+  signal_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (task), "signal-id"));
+  g_dbus_connection_signal_unsubscribe (connection, signal_id);
+
+  g_variant_get (parameters, "(u@a{sv})", &response, NULL);
+
+  if (response == 0)
+    g_task_return_boolean (task, TRUE);
+  else if (response == 1)
+    g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Launch cancelled");
+  else
+    g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Launch failed");
+
+  g_object_unref (task);
+}
+
+static void
+open_uri_done (GObject      *source,
+               GAsyncResult *result,
+               gpointer      user_data)
+{
+  GDBusConnection *connection = G_DBUS_CONNECTION (source);
+  GTask *task = user_data;
+  GVariant *res;
+  GError *error = NULL;
+  const char *path;
+  guint signal_id;
+
+  res = g_dbus_connection_call_finish (connection, result, &error);
+
+  if (res == NULL)
+    {
+      g_task_return_error (task, error);
+      g_object_unref (task);
+      return;
+    }
+
+  g_variant_get (res, "(&o)", &path);
+
+  signal_id =
+      g_dbus_connection_signal_subscribe (connection,
+                                          "org.freedesktop.portal.Desktop",
+                                          "org.freedesktop.portal.Request",
+                                          "Response",
+                                          path,
+                                          NULL,
+                                          G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
+                                          response_received,
+                                          task, NULL);
+
+  g_object_set_data (G_OBJECT (task), "signal-id", GINT_TO_POINTER (signal_id));
+
+  g_variant_unref (res);
+}
+
+static void
+launch_default_with_portal_async (const char          *uri,
+                                  GAppLaunchContext   *context,
+                                  GCancellable        *cancellable,
+                                  GAsyncReadyCallback  callback,
+                                  gpointer             user_data)
 {
   GDBusConnection *session_bus;
   GVariantBuilder opt_builder;
   const char *parent_window = NULL;
   GFile *file;
   char *real_uri;
+  GTask *task;
+  GAsyncReadyCallback dbus_callback;
+  GError *error = NULL;
 
-  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
+  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
   if (session_bus == NULL)
-    return FALSE;
+    {
+      g_task_report_error (context, callback, user_data, NULL, error);
+      return;
+    }
 
   if (context && context->priv->envp)
     parent_window = g_environ_getenv (context->priv->envp, "PARENT_WINDOW_ID");
@@ -702,16 +776,13 @@ launch_default_with_portal (const char         *uri,
 
   if (g_file_is_native (file))
     {
-      GError *local_error = NULL;
-
-      real_uri = g_document_portal_add_document (file, &local_error);
+      real_uri = g_document_portal_add_document (file, &error);
       g_object_unref (file);
 
       if (real_uri == NULL)
         {
-          g_warning ("Can't register with document portal: %s", local_error->message);
-          g_propagate_error (error, local_error);
-          return FALSE;
+          g_task_report_error (context, callback, user_data, NULL, error);
+          return;
         }
     }
   else
@@ -720,6 +791,17 @@ launch_default_with_portal (const char         *uri,
       real_uri = g_strdup (uri);
     }
 
+  if (callback)
+    {
+      task = g_task_new (context, cancellable, callback, user_data);
+      dbus_callback = open_uri_done;
+    }
+  else
+    {
+      task = NULL;
+      dbus_callback = NULL;
+    }
+
   g_dbus_connection_call (session_bus,
                           "org.freedesktop.portal.Desktop",
                           "/org/freedesktop/portal/desktop",
@@ -732,46 +814,35 @@ launch_default_with_portal (const char         *uri,
                           NULL,
                           G_DBUS_CALL_FLAGS_NONE,
                           G_MAXINT,
-                          NULL,
-                          NULL,
-                          NULL);
+                          cancellable,
+                          dbus_callback,
+                          task);
 
-  g_dbus_connection_flush (session_bus, NULL, NULL, NULL);
+  g_dbus_connection_flush (session_bus, cancellable, NULL, NULL);
   g_object_unref (session_bus);
   g_free (real_uri);
+}
 
+static gboolean
+launch_default_with_portal (const char         *uri,
+                            GAppLaunchContext  *context,
+                            GError            **error)
+{
+  launch_default_with_portal_async (uri, context, NULL, NULL, NULL);
   return TRUE;
 }
 #endif
 
-/**
- * g_app_info_launch_default_for_uri:
- * @uri: the uri to show
- * @launch_context: (allow-none): an optional #GAppLaunchContext.
- * @error: a #GError.
- *
- * Utility function that launches the default application
- * registered to handle the specified uri. Synchronous I/O
- * is done on the uri to detect the type of the file if
- * required.
- * 
- * Returns: %TRUE on success, %FALSE on error.
- **/
-gboolean
-g_app_info_launch_default_for_uri (const char         *uri,
-                                  GAppLaunchContext  *launch_context,
-                                  GError            **error)
+static gboolean
+launch_default_for_uri (const char         *uri,
+                        GAppLaunchContext  *context,
+                        GError            **error)
 {
   char *uri_scheme;
   GAppInfo *app_info = NULL;
   GList l;
   gboolean res;
 
-#ifdef G_OS_UNIX
-  if (glib_should_use_portal ())
-    return launch_default_with_portal (uri, launch_context, error);
-#endif
-
   /* g_file_query_default_handler() calls
    * g_app_info_get_default_for_uri_scheme() too, but we have to do it
    * here anyway in case GFile can't parse @uri correctly.
@@ -788,27 +859,112 @@ g_app_info_launch_default_for_uri (const char         *uri,
       file = g_file_new_for_uri (uri);
       app_info = g_file_query_default_handler (file, NULL, error);
       g_object_unref (file);
-      if (app_info == NULL)
-       return FALSE;
-
-      /* We still use the original @uri rather than calling
-       * g_file_get_uri(), because GFile might have modified the URI
-       * in ways we don't want (eg, removing the fragment identifier
-       * from a file: URI).
-       */
     }
 
+  if (app_info == NULL)
+    return FALSE;
+
   l.data = (char *)uri;
   l.next = l.prev = NULL;
-  res = g_app_info_launch_uris (app_info, &l,
-                               launch_context, error);
+  res = g_app_info_launch_uris (app_info, &l, context, error);
 
   g_object_unref (app_info);
-  
+
   return res;
 }
 
 /**
+ * g_app_info_launch_default_for_uri:
+ * @uri: the uri to show
+ * @launch_context: (allow-none): an optional #GAppLaunchContext
+ * @error: (nullable): return location for an error, or %NULL
+ *
+ * Utility function that launches the default application
+ * registered to handle the specified uri. Synchronous I/O
+ * is done on the uri to detect the type of the file if
+ * required.
+ * 
+ * Returns: %TRUE on success, %FALSE on error.
+ **/
+gboolean
+g_app_info_launch_default_for_uri (const char         *uri,
+                                  GAppLaunchContext  *launch_context,
+                                  GError            **error)
+{
+#ifdef G_OS_UNIX
+  if (glib_should_use_portal ())
+    return launch_default_with_portal (uri, launch_context, error);
+  else
+#endif
+    return launch_default_for_uri (uri, launch_context, error);
+}
+
+/**
+ * g_app_info_launch_default_for_uri_async:
+ * @uri: the uri to show
+ * @context: (allow-none): an optional #GAppLaunchContext
+ * cancellable: (allow-none): a #GCancellable
+ * @callback: (allow-none): a #GASyncReadyCallback to call when the request is done
+ * @user_data: (allow-none): data to pass to @callback
+ *
+ * Async version of g_app_info_launch_default_for_uri().
+ *
+ * This version is useful if you are interested in receiving
+ * error information in the case where the application is
+ * sandboxed and the portal may present an application chooser
+ * dialog to the user.
+ *
+ * Since: 2.50
+ */
+void
+g_app_info_launch_default_for_uri_async (const char          *uri,
+                                         GAppLaunchContext   *context,
+                                         GCancellable        *cancellable,
+                                         GAsyncReadyCallback  callback,
+                                         gpointer             user_data)
+{
+  gboolean res;
+  GError *error = NULL;
+  GTask *task;
+
+#ifdef G_OS_UNIX
+  if (glib_should_use_portal ())
+    {
+      launch_default_with_portal_async (uri, context, cancellable, callback, user_data);
+      return;
+    }
+#endif
+
+  res = launch_default_for_uri (uri, context, &error);
+
+  task = g_task_new (context, cancellable, callback, user_data);
+  if (!res)
+    g_task_return_error (task, error);
+  else
+    g_task_return_boolean (task, TRUE);
+
+  g_object_unref (task);
+}
+
+/**
+ * g_app_info_launch_default_for_uri_finish:
+ * @result: a #GAsyncResult
+ * @error: (nullable): return location for an error, or %NULL
+ *
+ * Finishes an asynchronous launch-default-for-uri operation.
+ *
+ * Returns: %TRUE if the launch was successful, %FALSE if @error is set
+ *
+ * Since: 2.50
+ */
+gboolean
+g_app_info_launch_default_for_uri_finish (GAsyncResult  *result,
+                                          GError       **error)
+{
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+/**
  * g_app_info_can_delete:
  * @appinfo: a #GAppInfo
  *
diff --git a/gio/gappinfo.h b/gio/gappinfo.h
index 5bf3cf6..8b417a7 100644
--- a/gio/gappinfo.h
+++ b/gio/gappinfo.h
@@ -230,6 +230,17 @@ gboolean  g_app_info_launch_default_for_uri      (const char              *uri,
                                                   GAppLaunchContext       *launch_context,
                                                   GError                 **error);
 
+GLIB_AVAILABLE_IN_2_50
+void      g_app_info_launch_default_for_uri_async  (const char           *uri,
+                                                    GAppLaunchContext    *launch_context,
+                                                    GCancellable         *cancellable,
+                                                    GAsyncReadyCallback   callback,
+                                                    gpointer              user_data);
+GLIB_AVAILABLE_IN_2_50
+gboolean  g_app_info_launch_default_for_uri_finish (GAsyncResult         *result,
+                                                    GError              **error);
+
+
 /**
  * GAppLaunchContext:
  *


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