From f72a5d65e0e762a16c33f91e180b2edbd46e95eb Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Tue, 22 Jan 2019 15:37:44 +0100 Subject: [PATCH] gfile: Add g_file_query_default_handler_async() This is needed as a first step to fix the g_app_info_launch_default_for_uri_async() function to be really asynchronous. It still uses the g_app_info_get_default_for_uri_scheme() and g_app_info_get_default_for_type() functions, which may use synchronous calls to local MIME DB. https://gitlab.gnome.org/GNOME/glib/issues/1347 https://gitlab.gnome.org/GNOME/glib/issues/1249 --- docs/reference/gio/gio-sections.txt | 2 + gio/gfile.c | 123 ++++++++++++++++++++++++++++ gio/gfile.h | 11 +++ 3 files changed, 136 insertions(+) diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index e61001f68..f792c5104 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -125,6 +125,8 @@ g_file_query_filesystem_info g_file_query_filesystem_info_async g_file_query_filesystem_info_finish g_file_query_default_handler +g_file_query_default_handler_async +g_file_query_default_handler_finish g_file_measure_disk_usage g_file_measure_disk_usage_async g_file_measure_disk_usage_finish diff --git a/gio/gfile.c b/gio/gfile.c index e6b468b55..c7926478c 100644 --- a/gio/gfile.c +++ b/gio/gfile.c @@ -6885,6 +6885,129 @@ g_file_query_default_handler (GFile *file, return NULL; } +static void +query_default_handler_query_info_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GFile *file = G_FILE (object); + GTask *task = G_TASK (user_data); + GError *error = NULL; + GFileInfo *info; + const char *content_type; + GAppInfo *appinfo = NULL; + + info = g_file_query_info_finish (file, result, &error); + if (info == NULL) + { + g_task_return_error (task, g_steal_pointer (&error)); + g_object_unref (task); + return; + } + + content_type = g_file_info_get_content_type (info); + if (content_type) + { + char *path; + + /* Don't use is_native(), as we want to support fuse paths if available */ + path = g_file_get_path (file); + + /* FIXME: The following still uses blocking calls. */ + appinfo = g_app_info_get_default_for_type (content_type, + path == NULL); + g_free (path); + } + + g_object_unref (info); + + if (appinfo != NULL) + g_task_return_pointer (task, g_steal_pointer (&appinfo), g_object_unref); + else + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + _("No application is registered as handling this file")); + g_object_unref (task); +} + +/** + * g_file_query_default_handler_async: + * @file: a #GFile to open + * @cancellable: optional #GCancellable object, %NULL to ignore + * @callback: (nullable): a #GAsyncReadyCallback to call when the request is done + * @user_data: (nullable): data to pass to @callback + * + * Async version of g_file_query_default_handler(). + * + * Since: 2.60 + */ +void +g_file_query_default_handler_async (GFile *file, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + char *uri_scheme; + + task = g_task_new (file, cancellable, callback, user_data); + g_task_set_source_tag (task, g_file_query_default_handler_async); + + uri_scheme = g_file_get_uri_scheme (file); + if (uri_scheme && uri_scheme[0] != '\0') + { + GAppInfo *appinfo; + + /* FIXME: The following still uses blocking calls. */ + appinfo = g_app_info_get_default_for_uri_scheme (uri_scheme); + g_free (uri_scheme); + + if (appinfo != NULL) + { + g_task_return_pointer (task, g_steal_pointer (&appinfo), g_object_unref); + g_object_unref (task); + return; + } + } + else + g_free (uri_scheme); + + g_file_query_info_async (file, + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + 0, + io_priority, + cancellable, + query_default_handler_query_info_cb, + g_steal_pointer (&task)); +} + +/** + * g_file_query_default_handler_finish: + * @file: a #GFile to open + * @result: a #GAsyncResult + * @error: (nullable): a #GError + * + * Finishes g_file_query_default_handler_async() operation. + * + * Returns: (transfer full): a #GAppInfo if the handle was found, + * %NULL if there were errors. + * When you are done with it, release it with g_object_unref() + * + * Since: 2.60 + */ +GAppInfo * +g_file_query_default_handler_finish (GFile *file, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (G_IS_FILE (file), NULL); + g_return_val_if_fail (g_task_is_valid (result, file), NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} + #define GET_CONTENT_BLOCK_SIZE 8192 /** diff --git a/gio/gfile.h b/gio/gfile.h index 4aff644c3..6e25b0de0 100644 --- a/gio/gfile.h +++ b/gio/gfile.h @@ -1183,6 +1183,17 @@ GLIB_AVAILABLE_IN_ALL GAppInfo *g_file_query_default_handler (GFile *file, GCancellable *cancellable, GError **error); +GLIB_AVAILABLE_IN_2_60 +void g_file_query_default_handler_async (GFile *file, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GLIB_AVAILABLE_IN_2_60 +GAppInfo *g_file_query_default_handler_finish (GFile *file, + GAsyncResult *result, + GError **error); + GLIB_AVAILABLE_IN_ALL gboolean g_file_load_contents (GFile *file, GCancellable *cancellable,