diff --git a/docs/reference/gio/gio-sections-common.txt b/docs/reference/gio/gio-sections-common.txt index 5f45a66f4..be4311701 100644 --- a/docs/reference/gio/gio-sections-common.txt +++ b/docs/reference/gio/gio-sections-common.txt @@ -1442,6 +1442,8 @@ g_app_info_get_supported_types g_app_info_get_all g_app_info_get_all_for_type g_app_info_get_default_for_type +g_app_info_get_default_for_type_async +g_app_info_get_default_for_type_finish g_app_info_get_default_for_uri_scheme g_app_info_get_fallback_for_type g_app_info_get_recommended_for_type diff --git a/gio/gappinfo.c b/gio/gappinfo.c index 8f64974c2..cced4d022 100644 --- a/gio/gappinfo.c +++ b/gio/gappinfo.c @@ -778,6 +778,106 @@ g_app_info_should_show (GAppInfo *appinfo) return (* iface->should_show) (appinfo); } +typedef struct { + char *content_type; + gboolean must_support_uris; +} DefaultForTypeData; + +static void +default_for_type_data_free (DefaultForTypeData *data) +{ + g_free (data->content_type); + g_free (data); +} + +static void +get_default_for_type_thread (GTask *task, + gpointer object, + gpointer task_data, + GCancellable *cancellable) +{ + DefaultForTypeData *data = task_data; + GAppInfo *info; + + info = g_app_info_get_default_for_type (data->content_type, + data->must_support_uris); + + if (!info) + { + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + _("Failed to find default application for " + "content type ā€˜%sā€™"), data->content_type); + return; + } + + g_task_return_pointer (task, g_steal_pointer (&info), g_object_unref); +} + +/** + * g_app_info_get_default_for_type_async: + * @content_type: the content type to find a #GAppInfo for + * @must_support_uris: if %TRUE, the #GAppInfo is expected to + * support URIs + * @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 + * + * Asynchronously gets the default #GAppInfo for a given content type. + * + * Since: 2.74 + */ +void +g_app_info_get_default_for_type_async (const char *content_type, + gboolean must_support_uris, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + DefaultForTypeData *data; + + g_return_if_fail (content_type != NULL && *content_type != '\0'); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + data = g_new0 (DefaultForTypeData, 1); + data->content_type = g_strdup (content_type); + data->must_support_uris = must_support_uris; + + task = g_task_new (NULL, cancellable, callback, user_data); + g_task_set_source_tag (task, g_app_info_get_default_for_type_async); + g_task_set_task_data (task, data, (GDestroyNotify) default_for_type_data_free); + g_task_set_check_cancellable (task, TRUE); + g_task_run_in_thread (task, get_default_for_type_thread); + g_object_unref (task); +} + +/** + * g_app_info_get_default_for_type_finish: + * @result: a #GAsyncResult + * @error: (nullable): a #GError + * + * Finishes a default #GAppInfo lookup started by + * g_app_info_get_default_for_type_async(). + * + * If no #GAppInfo is found, then @error will be set to %G_IO_ERROR_NOT_FOUND. + * + * Returns: (transfer full): #GAppInfo for given @content_type or + * %NULL on error. + * + * Since: 2.74 + */ +GAppInfo * +g_app_info_get_default_for_type_finish (GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == + g_app_info_get_default_for_type_async, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} + /** * g_app_info_launch_default_for_uri: * @uri: the uri to show diff --git a/gio/gappinfo.h b/gio/gappinfo.h index 8a49ab42c..722e8b36d 100644 --- a/gio/gappinfo.h +++ b/gio/gappinfo.h @@ -246,6 +246,15 @@ void g_app_info_reset_type_associations (const char *content_type); GLIB_AVAILABLE_IN_ALL GAppInfo *g_app_info_get_default_for_type (const char *content_type, gboolean must_support_uris); +GLIB_AVAILABLE_IN_2_74 +void g_app_info_get_default_for_type_async (const char *content_type, + gboolean must_support_uris, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GLIB_AVAILABLE_IN_2_74 +GAppInfo *g_app_info_get_default_for_type_finish (GAsyncResult *result, + GError **error); GLIB_AVAILABLE_IN_ALL GAppInfo *g_app_info_get_default_for_uri_scheme (const char *uri_scheme); diff --git a/gio/tests/desktop-app-info.c b/gio/tests/desktop-app-info.c index 65815fe70..75bf6c557 100644 --- a/gio/tests/desktop-app-info.c +++ b/gio/tests/desktop-app-info.c @@ -154,6 +154,119 @@ test_default (void) g_object_unref (info3); } +typedef struct +{ + GAppInfo *expected_info; + GMainLoop *loop; +} DefaultForTypeData; + +static void +on_default_for_type_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GAppInfo *info; + GError *error = NULL; + DefaultForTypeData *data = user_data; + + g_assert_null (object); + + info = g_app_info_get_default_for_type_finish (result, &error); + + if (data->expected_info) + { + g_assert_nonnull (info); + g_assert_no_error (error); + g_assert_true (g_app_info_equal (info, data->expected_info)); + } + else + { + g_assert_null (info); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + } + + g_main_loop_quit (data->loop); + g_clear_object (&info); + g_clear_error (&error); +} + +static void +test_default_async (void) +{ + DefaultForTypeData data; + GAppInfo *info1, *info2, *info3; + GList *list; + GError *error = NULL; + + data.loop = g_main_loop_new (NULL, TRUE); + + info1 = create_app_info ("Blah1"); + info2 = create_app_info ("Blah2"); + info3 = create_app_info ("Blah3"); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, + "*assertion*content_type*failed*"); + g_app_info_get_default_for_type_async (NULL, FALSE, NULL, NULL, NULL); + g_test_assert_expected_messages (); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, + "*assertion*content_type*failed*"); + g_app_info_get_default_for_type_async ("", FALSE, NULL, NULL, NULL); + g_test_assert_expected_messages (); + + g_app_info_set_as_default_for_type (info1, "application/x-test", &error); + g_assert_no_error (error); + + g_app_info_set_as_default_for_type (info2, "application/x-test", &error); + g_assert_no_error (error); + + data.expected_info = info2; + g_app_info_get_default_for_type_async ("application/x-test", FALSE, + NULL, on_default_for_type_cb, &data); + g_main_loop_run (data.loop); + + /* now try adding something, but not setting as default */ + g_app_info_add_supports_type (info3, "application/x-test", &error); + g_assert_no_error (error); + + /* check that info2 is still default */ + data.expected_info = info2; + g_app_info_get_default_for_type_async ("application/x-test", FALSE, + NULL, on_default_for_type_cb, &data); + g_main_loop_run (data.loop); + + /* now remove info1 again */ + g_app_info_remove_supports_type (info1, "application/x-test", &error); + g_assert_no_error (error); + + /* and make sure info2 is still default */ + data.expected_info = info2; + g_app_info_get_default_for_type_async ("application/x-test", FALSE, + NULL, on_default_for_type_cb, &data); + g_main_loop_run (data.loop); + + /* now clean it all up */ + g_app_info_reset_type_associations ("application/x-test"); + + data.expected_info = NULL; + g_app_info_get_default_for_type_async ("application/x-test", FALSE, + NULL, on_default_for_type_cb, &data); + g_main_loop_run (data.loop); + + list = g_app_info_get_all_for_type ("application/x-test"); + g_assert_null (list); + + g_app_info_delete (info1); + g_app_info_delete (info2); + g_app_info_delete (info3); + + g_object_unref (info1); + g_object_unref (info2); + g_object_unref (info3); + + g_main_loop_unref (data.loop); +} + static void test_fallback (void) { @@ -824,6 +937,7 @@ main (int argc, g_test_add_func ("/desktop-app-info/delete", test_delete); g_test_add_func ("/desktop-app-info/default", test_default); + g_test_add_func ("/desktop-app-info/default-async", test_default_async); g_test_add_func ("/desktop-app-info/fallback", test_fallback); g_test_add_func ("/desktop-app-info/lastused", test_last_used); g_test_add_func ("/desktop-app-info/extra-getters", test_extra_getters);