[glib/wip/oholy/gappinfo-async: 2/4] gappinfo: Add launch_uris_async() and launch_uris_finish() vfuncs
- From: Ondrej Holy <oholy src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/oholy/gappinfo-async: 2/4] gappinfo: Add launch_uris_async() and launch_uris_finish() vfuncs
- Date: Wed, 23 Jan 2019 14:28:04 +0000 (UTC)
commit 29772c7993f55d887aad83cf9ba29015977e9d71
Author: Ondrej Holy <oholy redhat com>
Date: Tue Jan 22 15:39:15 2019 +0100
gappinfo: Add launch_uris_async() and launch_uris_finish() vfuncs
The g_app_info_launch_uris_async() and g_app_info_launch_uris_finish()
functions are crucial to fix g_app_info_launch_default_for_uri_async()
to be really asynchronous.
https://gitlab.gnome.org/GNOME/glib/issues/1347
https://gitlab.gnome.org/GNOME/glib/issues/1249
gio/gappinfo.c | 55 ++++++++++++++++++
gio/gappinfo.h | 22 ++++++++
gio/gdesktopappinfo.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 222 insertions(+), 5 deletions(-)
---
diff --git a/gio/gappinfo.c b/gio/gappinfo.c
index 47cd73366..784999811 100644
--- a/gio/gappinfo.c
+++ b/gio/gappinfo.c
@@ -662,6 +662,61 @@ g_app_info_launch_uris (GAppInfo *appinfo,
return (* iface->launch_uris) (appinfo, uris, launch_context, error);
}
+/**
+ * g_app_info_launch_uris_async:
+ * @appinfo: a #GAppInfo
+ * @uris: (nullable) (element-type utf8): a #GList containing URIs to launch.
+ * @context: (nullable): a #GAppLaunchContext or %NULL
+ * @cancellable: (nullable): a #GCancellable
+ * @callback: (nullable): a #GAsyncReadyCallback to call when the request is done
+ * @user_data: (nullable): data to pass to @callback
+ *
+ * Async version of g_app_info_launch_uris().
+ *
+ * Since: 2.60
+ **/
+void
+g_app_info_launch_uris_async (GAppInfo *appinfo,
+ GList *uris,
+ GAppLaunchContext *context,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GAppInfoIface *iface;
+
+ g_return_if_fail (G_IS_APP_INFO (appinfo));
+
+ iface = G_APP_INFO_GET_IFACE (appinfo);
+
+ return (* iface->launch_uris_async) (appinfo, uris, context, cancellable, callback, user_data);
+}
+
+/**
+ * g_app_info_launch_uris_finish:
+ * @appinfo: a #GAppInfo
+ * @result: a #GAsyncResult
+ * @error: (nullable): a #GError
+ *
+ * Finishes g_app_info_launch_uris_async() operation.
+ *
+ * Returns: %TRUE on successful launch, %FALSE otherwise.
+ *
+ * Since: 2.60
+ */
+gboolean
+g_app_info_launch_uris_finish (GAppInfo *appinfo,
+ GAsyncResult *result,
+ GError **error)
+{
+ GAppInfoIface *iface;
+
+ g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
+
+ iface = G_APP_INFO_GET_IFACE (appinfo);
+
+ return (* iface->launch_uris_finish) (appinfo, result, error);
+}
/**
* g_app_info_should_show:
diff --git a/gio/gappinfo.h b/gio/gappinfo.h
index 4889be923..0678d968c 100644
--- a/gio/gappinfo.h
+++ b/gio/gappinfo.h
@@ -107,6 +107,16 @@ struct _GAppInfoIface
GList *uris,
GAppLaunchContext *context,
GError **error);
+ void (* launch_uris_async) (GAppInfo *appinfo,
+ GList *uris,
+ GAppLaunchContext *context,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (* launch_uris_finish) (GAppInfo *appinfo,
+ GAsyncResult *result,
+ GError **error);
+
gboolean (* should_show) (GAppInfo *appinfo);
/* For changing associations */
@@ -173,6 +183,18 @@ gboolean g_app_info_launch_uris (GAppInfo *appin
GList *uris,
GAppLaunchContext *context,
GError **error);
+GLIB_AVAILABLE_IN_2_60
+void g_app_info_launch_uris_async (GAppInfo *appinfo,
+ GList *uris,
+ GAppLaunchContext *context,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GLIB_AVAILABLE_IN_2_60
+gboolean g_app_info_launch_uris_finish (GAppInfo *appinfo,
+ GAsyncResult *result,
+ GError **error);
+
GLIB_AVAILABLE_IN_ALL
gboolean g_app_info_should_show (GAppInfo *appinfo);
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index 9ebfce4f0..17f0895ce 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -2870,7 +2870,10 @@ static void
launch_uris_with_dbus (GDesktopAppInfo *info,
GDBusConnection *session_bus,
GList *uris,
- GAppLaunchContext *launch_context)
+ GAppLaunchContext *launch_context,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GVariantBuilder builder;
gchar *object_path;
@@ -2896,7 +2899,8 @@ launch_uris_with_dbus (GDesktopAppInfo *info,
object_path = object_path_from_appid (info->app_id);
g_dbus_connection_call (session_bus, info->app_id, object_path, "org.freedesktop.Application",
uris ? "Open" : "Activate", g_variant_builder_end (&builder),
- NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+ NULL, G_DBUS_CALL_FLAGS_NONE, -1,
+ cancellable, callback, user_data);
g_free (object_path);
}
@@ -2904,7 +2908,10 @@ static gboolean
g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo *info,
GDBusConnection *session_bus,
GList *uris,
- GAppLaunchContext *launch_context)
+ GAppLaunchContext *launch_context,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GList *ruris = uris;
char *app_id = NULL;
@@ -2921,7 +2928,8 @@ g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo *info,
}
#endif
- launch_uris_with_dbus (info, session_bus, ruris, launch_context);
+ launch_uris_with_dbus (info, session_bus, uris, launch_context,
+ cancellable, callback, user_data);
if (ruris != uris)
g_list_free_full (ruris, g_free);
@@ -2952,7 +2960,8 @@ g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
if (session_bus && info->app_id)
- g_desktop_app_info_launch_uris_with_dbus (info, session_bus, uris, launch_context);
+ g_desktop_app_info_launch_uris_with_dbus (info, session_bus, uris, launch_context,
+ NULL, NULL, NULL);
else
success = g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec, uris, launch_context,
spawn_flags, user_setup, user_setup_data,
@@ -2986,6 +2995,135 @@ g_desktop_app_info_launch_uris (GAppInfo *appinfo,
error);
}
+typedef struct
+{
+ GAppInfo *appinfo;
+ GList *uris;
+ GAppLaunchContext *context;
+} LaunchUrisData;
+
+static void
+launch_uris_data_free (LaunchUrisData *data)
+{
+ g_clear_object (&data->context);
+ g_list_free_full (data->uris, g_free);
+ g_free (data);
+}
+
+static void
+launch_uris_with_dbus_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ GError *error = NULL;
+
+ g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
+ if (error != NULL)
+ {
+ g_dbus_error_strip_remote_error (error);
+ g_task_return_error (task, error);
+ }
+ else
+ g_task_return_boolean (task, TRUE);
+
+ g_object_unref (task);
+}
+
+static void
+launch_uris_flush_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+
+ g_dbus_connection_flush_finish (G_DBUS_CONNECTION (object), result, NULL);
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+launch_uris_bus_get_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ GDesktopAppInfo *info = G_DESKTOP_APP_INFO (g_task_get_source_object (task));
+ LaunchUrisData *data = g_task_get_task_data (task);
+ GDBusConnection *session_bus;
+ GError *error = NULL;
+
+ session_bus = g_bus_get_finish (result, NULL);
+
+ if (session_bus && info->app_id)
+ {
+ /* FIXME: The g_document_portal_add_documents() function, which is called
+ * from the g_desktop_app_info_launch_uris_with_dbus() function, still
+ * uses blocking calls.
+ */
+ g_desktop_app_info_launch_uris_with_dbus (info, session_bus,
+ data->uris, data->context,
+ g_task_get_cancellable (task),
+ launch_uris_with_dbus_cb, task);
+ }
+ else
+ {
+ /* FIXME: The D-Bus message from the notify_desktop_launch() function
+ * can be still lost even if flush is called later. See:
+ * https://gitlab.freedesktop.org/dbus/dbus/issues/72
+ */
+ g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec,
+ data->uris, data->context,
+ _SPAWN_FLAGS_DEFAULT, NULL,
+ NULL, NULL, NULL, -1, -1, -1,
+ &error);
+ if (error != NULL)
+ {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ }
+ else
+ g_dbus_connection_flush (session_bus,
+ g_task_get_cancellable (task),
+ launch_uris_flush_cb,
+ task);
+ }
+
+ g_clear_object (&session_bus);
+}
+
+static void
+g_desktop_app_info_launch_uris_async (GAppInfo *appinfo,
+ GList *uris,
+ GAppLaunchContext *context,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ LaunchUrisData *data;
+
+ task = g_task_new (appinfo, cancellable, callback, user_data);
+ g_task_set_source_tag (task, g_desktop_app_info_launch_uris_async);
+
+ data = g_new0 (LaunchUrisData, 1);
+ data->uris = g_list_copy_deep (uris, (GCopyFunc) g_strdup, NULL);
+ data->context = (context != NULL) ? g_object_ref (context) : NULL;
+ g_task_set_task_data (task, data, (GDestroyNotify) launch_uris_data_free);
+
+ g_bus_get (G_BUS_TYPE_SESSION, cancellable, launch_uris_bus_get_cb, task);
+}
+
+static gboolean
+g_desktop_app_info_launch_uris_finish (GAppInfo *appinfo,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, appinfo), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
static gboolean
g_desktop_app_info_supports_uris (GAppInfo *appinfo)
{
@@ -3876,6 +4014,8 @@ g_desktop_app_info_iface_init (GAppInfoIface *iface)
iface->supports_uris = g_desktop_app_info_supports_uris;
iface->supports_files = g_desktop_app_info_supports_files;
iface->launch_uris = g_desktop_app_info_launch_uris;
+ iface->launch_uris_async = g_desktop_app_info_launch_uris_async;
+ iface->launch_uris_finish = g_desktop_app_info_launch_uris_finish;
iface->should_show = g_desktop_app_info_should_show;
iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]