[gnome-software/1276-software-became-unresponsive-while-updating-flatpaks: 26/26] gs-plugin-loader: Convert app_create()/get_system_app() into async methods
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/1276-software-became-unresponsive-while-updating-flatpaks: 26/26] gs-plugin-loader: Convert app_create()/get_system_app() into async methods
- Date: Tue, 27 Jul 2021 16:32:01 +0000 (UTC)
commit 30b835e2a78bef438f1b572617bbf4d4552d3138
Author: Milan Crha <mcrha redhat com>
Date: Tue Jul 20 21:04:59 2021 +0200
gs-plugin-loader: Convert app_create()/get_system_app() into async methods
These call refine, which can mean I/O calls on the calling thread,
which is, in some situations, the main/GUI thread, thus it could
block the application in certain cases. Doing the calls in a dedicated
thread helps to avoid application freeze.
Closes https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1276
lib/gs-plugin-loader-sync.c | 72 +++++++++++++++++
lib/gs-plugin-loader-sync.h | 7 ++
lib/gs-plugin-loader.c | 174 ++++++++++++++++++++++++++++++++---------
lib/gs-plugin-loader.h | 18 ++++-
plugins/core/gs-self-test.c | 13 ++-
plugins/flatpak/gs-self-test.c | 11 ++-
src/gs-application.c | 76 +++++++++++++++---
src/gs-search-page.c | 21 ++++-
src/gs-update-monitor.c | 48 ++++++------
src/gs-updates-page.c | 119 ++++++++++++++++++----------
10 files changed, 437 insertions(+), 122 deletions(-)
---
diff --git a/lib/gs-plugin-loader-sync.c b/lib/gs-plugin-loader-sync.c
index bf83fe224..f7b0d0f50 100644
--- a/lib/gs-plugin-loader-sync.c
+++ b/lib/gs-plugin-loader-sync.c
@@ -178,3 +178,75 @@ gs_plugin_loader_job_process_app (GsPluginLoader *plugin_loader,
return app;
}
+
+GsApp *
+gs_plugin_loader_app_create (GsPluginLoader *plugin_loader,
+ const gchar *unique_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginLoaderHelper helper;
+ GsApp *app;
+
+ /* create temp object */
+ helper.res = NULL;
+ helper.context = g_main_context_new ();
+ helper.loop = g_main_loop_new (helper.context, FALSE);
+
+ g_main_context_push_thread_default (helper.context);
+
+ /* run async method */
+ gs_plugin_loader_app_create_async (plugin_loader,
+ unique_id,
+ cancellable,
+ _helper_finish_sync,
+ &helper);
+ g_main_loop_run (helper.loop);
+ app = gs_plugin_loader_app_create_finish (plugin_loader,
+ helper.res,
+ error);
+
+ g_main_context_pop_thread_default (helper.context);
+
+ g_main_loop_unref (helper.loop);
+ g_main_context_unref (helper.context);
+ if (helper.res != NULL)
+ g_object_unref (helper.res);
+
+ return app;
+}
+
+GsApp *
+gs_plugin_loader_get_system_app (GsPluginLoader *plugin_loader,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginLoaderHelper helper;
+ GsApp *app;
+
+ /* create temp object */
+ helper.res = NULL;
+ helper.context = g_main_context_new ();
+ helper.loop = g_main_loop_new (helper.context, FALSE);
+
+ g_main_context_push_thread_default (helper.context);
+
+ /* run async method */
+ gs_plugin_loader_get_system_app_async (plugin_loader,
+ cancellable,
+ _helper_finish_sync,
+ &helper);
+ g_main_loop_run (helper.loop);
+ app = gs_plugin_loader_get_system_app_finish (plugin_loader,
+ helper.res,
+ error);
+
+ g_main_context_pop_thread_default (helper.context);
+
+ g_main_loop_unref (helper.loop);
+ g_main_context_unref (helper.context);
+ if (helper.res != NULL)
+ g_object_unref (helper.res);
+
+ return app;
+}
diff --git a/lib/gs-plugin-loader-sync.h b/lib/gs-plugin-loader-sync.h
index b428ba9f1..493effd0e 100644
--- a/lib/gs-plugin-loader-sync.h
+++ b/lib/gs-plugin-loader-sync.h
@@ -30,5 +30,12 @@ GPtrArray *gs_plugin_loader_job_get_categories (GsPluginLoader *plugin_loader,
GsPluginJob *plugin_job,
GCancellable *cancellable,
GError **error);
+GsApp *gs_plugin_loader_app_create (GsPluginLoader *plugin_loader,
+ const gchar *unique_id,
+ GCancellable *cancellable,
+ GError **error);
+GsApp *gs_plugin_loader_get_system_app (GsPluginLoader *plugin_loader,
+ GCancellable *cancellable,
+ GError **error);
G_END_DECLS
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 474aad154..54d27a53a 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -2318,24 +2318,19 @@ gs_plugin_loader_plugin_sort_fn (gconstpointer a, gconstpointer b)
}
static void
-gs_plugin_loader_plugin_dir_changed_cb (GFileMonitor *monitor,
- GFile *file,
- GFile *other_file,
- GFileMonitorEvent event_type,
- GsPluginLoader *plugin_loader)
+gs_plugin_loader_software_app_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
g_autoptr(GsApp) app = NULL;
g_autoptr(GsPluginEvent) event = gs_plugin_event_new ();
g_autoptr(GError) error = NULL;
- /* already triggered */
- if (plugin_loader->plugin_dir_dirty)
- return;
+ app = gs_plugin_loader_app_create_finish (plugin_loader, result, NULL);
/* add app */
gs_plugin_event_set_action (event, GS_PLUGIN_ACTION_SETUP);
- app = gs_plugin_loader_app_create (plugin_loader,
- "system/*/*/org.gnome.Software.desktop/*");
if (app != NULL)
gs_plugin_event_set_app (event, app);
@@ -2346,6 +2341,22 @@ gs_plugin_loader_plugin_dir_changed_cb (GFileMonitor *monitor,
"A restart is required");
gs_plugin_event_set_error (event, error);
gs_plugin_loader_add_event (plugin_loader, event);
+}
+
+static void
+gs_plugin_loader_plugin_dir_changed_cb (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ GsPluginLoader *plugin_loader)
+{
+ /* already triggered */
+ if (plugin_loader->plugin_dir_dirty)
+ return;
+
+ gs_plugin_loader_app_create_async (plugin_loader, "system/*/*/org.gnome.Software.desktop/*",
+ NULL, gs_plugin_loader_software_app_created_cb, NULL);
+
plugin_loader->plugin_dir_dirty = TRUE;
}
@@ -3932,25 +3943,21 @@ gs_plugin_loader_get_plugin_supported (GsPluginLoader *plugin_loader,
return FALSE;
}
-/**
- * gs_plugin_loader_app_create:
- * @plugin_loader: a #GsPluginLoader
- * @unique_id: a unique_id
- *
- * Returns an application from the global cache, creating if required.
- *
- * Returns: (transfer full): a #GsApp
- **/
-GsApp *
-gs_plugin_loader_app_create (GsPluginLoader *plugin_loader, const gchar *unique_id)
+static void
+gs_plugin_loader_job_app_create_thread_cb (GTask *task,
+ gpointer object,
+ gpointer task_data,
+ GCancellable *cancellable)
{
- g_autoptr(GError) error = NULL;
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (g_task_get_source_object (task));
+ const gchar *unique_id = task_data;
+ GError *error = NULL;
g_autoptr(GsApp) app = NULL;
g_autoptr(GsAppList) list = gs_app_list_new ();
g_autoptr(GsPluginJob) plugin_job = NULL;
g_autoptr(GsPluginLoaderHelper) helper = NULL;
- /* use the plugin loader to convert a wildcard app*/
+ /* use the plugin loader to convert a wildcard app */
app = gs_app_new (NULL);
gs_app_add_quirk (app, GS_APP_QUIRK_IS_WILDCARD);
gs_app_set_from_unique_id (app, unique_id, AS_COMPONENT_KIND_UNKNOWN);
@@ -3958,15 +3965,18 @@ gs_plugin_loader_app_create (GsPluginLoader *plugin_loader, const gchar *unique_
plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REFINE, NULL);
helper = gs_plugin_loader_helper_new (plugin_loader, plugin_job);
if (!gs_plugin_loader_run_refine (helper, list, NULL, &error)) {
- g_warning ("%s", error->message);
- return NULL;
+ g_prefix_error (&error, "Failed to refine '%s': ", unique_id);
+ g_task_return_error (task, error);
+ return;
}
/* return the matching GsApp */
for (guint i = 0; i < gs_app_list_length (list); i++) {
GsApp *app_tmp = gs_app_list_index (list, i);
- if (g_strcmp0 (unique_id, gs_app_get_unique_id (app_tmp)) == 0)
- return g_object_ref (app_tmp);
+ if (g_strcmp0 (unique_id, gs_app_get_unique_id (app_tmp)) == 0) {
+ g_task_return_pointer (task, g_object_ref (app_tmp), g_object_unref);
+ return;
+ }
}
/* return the first returned app that's not a wildcard */
@@ -3975,27 +3985,121 @@ gs_plugin_loader_app_create (GsPluginLoader *plugin_loader, const gchar *unique_
if (!gs_app_has_quirk (app_tmp, GS_APP_QUIRK_IS_WILDCARD)) {
g_debug ("returning imperfect match: %s != %s",
unique_id, gs_app_get_unique_id (app_tmp));
- return g_object_ref (app_tmp);
+ g_task_return_pointer (task, g_object_ref (app_tmp), g_object_unref);
+ return;
}
}
/* does not exist */
- g_warning ("failed to create an app for %s", unique_id);
- return NULL;
+ g_task_return_new_error (task,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "Failed to create an app for '%s'", unique_id);
+}
+
+/**
+ * gs_plugin_loader_app_create_async:
+ * @plugin_loader: a #GsPluginLoader
+ * @unique_id: a unique_id
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: function to call when complete
+ * @user_data: user data to pass to @callback
+ *
+ * Create a #GsApp identified by @unique_id asynchronously.
+ * Finish the call with gs_plugin_loader_app_create_finish().
+ *
+ * Since: 41
+ **/
+void
+gs_plugin_loader_app_create_async (GsPluginLoader *plugin_loader,
+ const gchar *unique_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GsPluginJob) plugin_job = NULL;
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader));
+ g_return_if_fail (unique_id != NULL);
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ /* run in a thread */
+ task = g_task_new (plugin_loader, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gs_plugin_loader_app_create_async);
+ g_task_set_task_data (task, g_strdup (unique_id), g_free);
+ g_task_run_in_thread (task, gs_plugin_loader_job_app_create_thread_cb);
+}
+
+/**
+ * gs_plugin_loader_app_create_finish:
+ * @plugin_loader: a #GsPluginLoader
+ * @res: a #GAsyncResult
+ * @error: A #GError, or %NULL
+ *
+ * Finishes call to gs_plugin_loader_app_create_async().
+ *
+ * Returns: (transfer full): a #GsApp, or %NULL on error.
+ *
+ * Since: 41
+ **/
+GsApp *
+gs_plugin_loader_app_create_finish (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GError **error)
+{
+ GsApp *app;
+
+ g_return_val_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader), NULL);
+ g_return_val_if_fail (G_IS_TASK (res), NULL);
+ g_return_val_if_fail (g_task_is_valid (res, plugin_loader), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ app = g_task_propagate_pointer (G_TASK (res), error);
+ gs_utils_error_convert_gio (error);
+ return app;
+}
+
+/**
+ * gs_plugin_loader_get_system_app_async:
+ * @plugin_loader: a #GsPluginLoader
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: function to call when complete
+ * @user_data: user data to pass to @callback
+ *
+ * Get the application that represents the currently installed OS
+ * asynchronously. Finish the call with gs_plugin_loader_get_system_app_finish().
+ *
+ * Since: 41
+ **/
+void
+gs_plugin_loader_get_system_app_async (GsPluginLoader *plugin_loader,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ gs_plugin_loader_app_create_async (plugin_loader, "*/*/*/system/*", cancellable, callback, user_data);
}
/**
- * gs_plugin_loader_get_system_app:
+ * gs_plugin_loader_get_system_app_finish:
* @plugin_loader: a #GsPluginLoader
+ * @res: a #GAsyncResult
+ * @error: A #GError, or %NULL
+ *
+ * Finishes call to gs_plugin_loader_get_system_app_async().
*
- * Returns the application that represents the currently installed OS.
+ * Returns: (transfer full): a #GsApp, which represents
+ * the currently installed OS, or %NULL on error.
*
- * Returns: (transfer full): a #GsApp
+ * Since: 41
**/
GsApp *
-gs_plugin_loader_get_system_app (GsPluginLoader *plugin_loader)
+gs_plugin_loader_get_system_app_finish (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GError **error)
{
- return gs_plugin_loader_app_create (plugin_loader, "*/*/*/system/*");
+ return gs_plugin_loader_app_create_finish (plugin_loader, res, error);
}
/**
diff --git a/lib/gs-plugin-loader.h b/lib/gs-plugin-loader.h
index 960795598..71fd35af8 100644
--- a/lib/gs-plugin-loader.h
+++ b/lib/gs-plugin-loader.h
@@ -70,9 +70,21 @@ GPtrArray *gs_plugin_loader_get_events (GsPluginLoader *plugin_loader);
GsPluginEvent *gs_plugin_loader_get_event_default (GsPluginLoader *plugin_loader);
void gs_plugin_loader_remove_events (GsPluginLoader *plugin_loader);
-GsApp *gs_plugin_loader_app_create (GsPluginLoader *plugin_loader,
- const gchar *unique_id);
-GsApp *gs_plugin_loader_get_system_app (GsPluginLoader *plugin_loader);
+void gs_plugin_loader_app_create_async (GsPluginLoader *plugin_loader,
+ const gchar *unique_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GsApp *gs_plugin_loader_app_create_finish (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GError **error);
+void gs_plugin_loader_get_system_app_async (GsPluginLoader *plugin_loader,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GsApp *gs_plugin_loader_get_system_app_finish (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GError **error);
SoupSession *gs_plugin_loader_get_soup_session (GsPluginLoader *plugin_loader);
GsOdrsProvider *gs_plugin_loader_get_odrs_provider (GsPluginLoader *plugin_loader);
diff --git a/plugins/core/gs-self-test.c b/plugins/core/gs-self-test.c
index 53be465a9..dac3925d7 100644
--- a/plugins/core/gs-self-test.c
+++ b/plugins/core/gs-self-test.c
@@ -29,7 +29,9 @@ gs_plugins_core_search_repo_name_func (GsPluginLoader *plugin_loader)
gs_plugin_loader_setup_again (plugin_loader);
/* force this app to be installed */
- app_tmp = gs_plugin_loader_app_create (plugin_loader, "*/*/yellow/arachne.desktop/*");
+ app_tmp = gs_plugin_loader_app_create (plugin_loader, "*/*/yellow/arachne.desktop/*", NULL, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (app_tmp);
gs_app_set_state (app_tmp, GS_APP_STATE_INSTALLED);
/* get search result based on addon keyword */
@@ -63,7 +65,9 @@ gs_plugins_core_os_release_func (GsPluginLoader *plugin_loader)
gs_plugin_loader_setup_again (plugin_loader);
/* refine system application */
- app = gs_plugin_loader_get_system_app (plugin_loader);
+ app = gs_plugin_loader_get_system_app (plugin_loader, NULL, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (app);
plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REFINE,
"app", app,
"refine-flags", GS_PLUGIN_REFINE_FLAGS_REQUIRE_URL |
@@ -89,8 +93,9 @@ gs_plugins_core_os_release_func (GsPluginLoader *plugin_loader)
g_assert_cmpstr (gs_app_get_summary (app), ==, "Fedora Workstation");
/* check we can get this by the old name too */
- app3 = gs_plugin_loader_get_system_app (plugin_loader);
- g_assert (app3 != NULL);
+ app3 = gs_plugin_loader_get_system_app (plugin_loader, NULL, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (app3);
g_assert (app3 == app);
}
diff --git a/plugins/flatpak/gs-self-test.c b/plugins/flatpak/gs-self-test.c
index e17eaf385..a19ed4b6c 100644
--- a/plugins/flatpak/gs-self-test.c
+++ b/plugins/flatpak/gs-self-test.c
@@ -1696,8 +1696,12 @@ gs_plugins_flatpak_runtime_extension_func (GsPluginLoader *plugin_loader)
/* check if the extension was installed */
extension = gs_plugin_loader_app_create (plugin_loader,
- "user/flatpak/*/org.test.Chiron.Extension/master");
+ "user/flatpak/*/org.test.Chiron.Extension/master",
+ NULL, &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
g_assert_nonnull (extension);
+
g_assert_cmpint (gs_app_get_state (extension), ==, GS_APP_STATE_INSTALLED);
/* switch to the new repo (to get the update) */
@@ -1782,7 +1786,10 @@ gs_plugins_flatpak_runtime_extension_func (GsPluginLoader *plugin_loader)
/* The install refreshes GsApp-s cache, thus re-get the extension */
g_clear_object (&extension);
extension = gs_plugin_loader_app_create (plugin_loader,
- "user/flatpak/*/org.test.Chiron.Extension/master");
+ "user/flatpak/*/org.test.Chiron.Extension/master",
+ NULL, &error);
+ gs_test_flush_main_context ();
+ g_assert_no_error (error);
g_assert_nonnull (extension);
/* check the extension's state after the update */
diff --git a/src/gs-application.c b/src/gs-application.c
index 2ddfaadfc..40356f905 100644
--- a/src/gs-application.c
+++ b/src/gs-application.c
@@ -573,6 +573,28 @@ _search_launchable_details_cb (GObject *source, GAsyncResult *res, gpointer user
gs_shell_show_app (app->shell, a);
}
+static void
+gs_application_app_to_show_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GsApplication *gs_app = user_data;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GError) error = NULL;
+
+ app = gs_plugin_loader_app_create_finish (GS_PLUGIN_LOADER (source_object), result, &error);
+ if (app == NULL) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+ !g_error_matches (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_CANCELLED))
+ g_warning ("Failed to create application: %s", error->message);
+ } else {
+ g_return_if_fail (GS_IS_APPLICATION (gs_app));
+
+ gs_shell_reset_state (gs_app->shell);
+ gs_shell_show_app (gs_app->shell, app);
+ }
+}
+
static void
details_activated (GSimpleAction *action,
GVariant *parameter,
@@ -594,9 +616,8 @@ details_activated (GSimpleAction *action,
g_autoptr(GsPluginJob) plugin_job = NULL;
data_id = gs_utils_unique_id_compat_convert (id);
if (data_id != NULL) {
- g_autoptr(GsApp) a = gs_plugin_loader_app_create (app->plugin_loader, data_id);
- gs_shell_reset_state (app->shell);
- gs_shell_show_app (app->shell, a);
+ gs_plugin_loader_app_create_async (app->plugin_loader, data_id, app->cancellable,
+ gs_application_app_to_show_created_cb, app);
return;
}
@@ -656,6 +677,41 @@ details_url_activated (GSimpleAction *action,
gs_shell_show_app (app->shell, a);
}
+typedef struct {
+ GWeakRef gs_app_weakref;
+ gchar *data_id;
+ GsShellInteraction interaction;
+} InstallActivatedHelper;
+
+static void
+gs_application_app_to_install_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ InstallActivatedHelper *helper = user_data;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GError) error = NULL;
+
+ app = gs_plugin_loader_app_create_finish (GS_PLUGIN_LOADER (source_object), result, &error);
+ if (app == NULL) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+ !g_error_matches (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_CANCELLED))
+ g_warning ("Failed to create application '%s': %s", helper->data_id, error->message);
+ } else {
+ g_autoptr(GsApplication) gs_app = NULL;
+
+ gs_app = g_weak_ref_get (&helper->gs_app_weakref);
+ if (gs_app != NULL) {
+ gs_shell_reset_state (gs_app->shell);
+ gs_shell_install (gs_app->shell, app, helper->interaction);
+ }
+ }
+
+ g_weak_ref_clear (&helper->gs_app_weakref);
+ g_free (helper->data_id);
+ g_slice_free (InstallActivatedHelper, helper);
+}
+
static void
install_activated (GSimpleAction *action,
GVariant *parameter,
@@ -664,6 +720,7 @@ install_activated (GSimpleAction *action,
GsApplication *app = GS_APPLICATION (data);
const gchar *id;
GsShellInteraction interaction;
+ InstallActivatedHelper *helper;
g_autoptr (GsApp) a = NULL;
g_autofree gchar *data_id = NULL;
@@ -677,14 +734,13 @@ install_activated (GSimpleAction *action,
if (interaction == GS_SHELL_INTERACTION_FULL)
gs_application_present_window (app, NULL);
- a = gs_plugin_loader_app_create (app->plugin_loader, data_id);
- if (a == NULL) {
- g_warning ("Could not create app from data-id: %s", data_id);
- return;
- }
+ helper = g_slice_new0 (InstallActivatedHelper);
+ g_weak_ref_init (&helper->gs_app_weakref, app);
+ helper->data_id = g_strdup (data_id);
+ helper->interaction = interaction;
- gs_shell_reset_state (app->shell);
- gs_shell_install (app->shell, a, interaction);
+ gs_plugin_loader_app_create_async (app->plugin_loader, data_id, app->cancellable,
+ gs_application_app_to_install_created_cb, helper);
}
static GFile *
diff --git a/src/gs-search-page.c b/src/gs-search-page.c
index abaa358a1..6b89edb50 100644
--- a/src/gs-search-page.c
+++ b/src/gs-search-page.c
@@ -81,6 +81,23 @@ gs_search_page_waiting_cancel (GsSearchPage *self)
self->waiting_id = 0;
}
+static void
+gs_search_page_app_to_show_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GsSearchPage *self = user_data;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GError) error = NULL;
+
+ app = gs_plugin_loader_app_create_finish (GS_PLUGIN_LOADER (source_object), result, &error);
+ if (app != NULL) {
+ g_return_if_fail (GS_IS_SEARCH_PAGE (self));
+
+ gs_shell_show_app (self->shell, app);
+ }
+}
+
static void
gs_search_page_get_search_cb (GObject *source_object,
GAsyncResult *res,
@@ -167,8 +184,8 @@ gs_search_page_get_search_cb (GObject *source_object,
if (self->appid_to_show != NULL) {
g_autoptr (GsApp) a = NULL;
if (as_utils_data_id_valid (self->appid_to_show)) {
- a = gs_plugin_loader_app_create (self->plugin_loader,
- self->appid_to_show);
+ gs_plugin_loader_app_create_async (self->plugin_loader, self->appid_to_show,
self->cancellable,
+ gs_search_page_app_to_show_created_cb, self);
} else {
a = gs_app_new (self->appid_to_show);
}
diff --git a/src/gs-update-monitor.c b/src/gs-update-monitor.c
index dd09b76d5..0f18eef0c 100644
--- a/src/gs-update-monitor.c
+++ b/src/gs-update-monitor.c
@@ -60,17 +60,28 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(DownloadUpdatesData, download_updates_data_free);
typedef struct {
GsUpdateMonitor *monitor;
GsApp *app;
-} LanguagePackData;
+} WithAppData;
+
+static WithAppData *
+with_app_data_new (GsUpdateMonitor *monitor,
+ GsApp *app)
+{
+ WithAppData *data;
+ data = g_slice_new0 (WithAppData);
+ data->monitor = g_object_ref (monitor);
+ data->app = g_object_ref (app);
+ return data;
+}
static void
-language_pack_data_free (LanguagePackData *data)
+with_app_data_free (WithAppData *data)
{
g_clear_object (&data->monitor);
g_clear_object (&data->app);
- g_slice_free (LanguagePackData, data);
+ g_slice_free (WithAppData, data);
}
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(LanguagePackData, language_pack_data_free);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(WithAppData, with_app_data_free);
static gboolean
reenable_offline_update_notification (gpointer data)
@@ -612,13 +623,14 @@ static void
get_system_finished_cb (GObject *object, GAsyncResult *res, gpointer data)
{
GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
- GsUpdateMonitor *monitor = GS_UPDATE_MONITOR (data);
+ GsUpdateMonitor *monitor = data;
g_autoptr(GError) error = NULL;
g_autoptr(GNotification) n = NULL;
g_autoptr(GsApp) app = NULL;
/* get result */
- if (!gs_plugin_loader_job_action_finish (plugin_loader, res, &error)) {
+ app = gs_plugin_loader_get_system_app_finish (plugin_loader, res, &error);
+ if (app == NULL) {
if (!g_error_matches (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_CANCELLED))
g_warning ("failed to get system: %s", error->message);
return;
@@ -632,7 +644,6 @@ get_system_finished_cb (GObject *object, GAsyncResult *res, gpointer data)
return;
/* is not EOL */
- app = gs_plugin_loader_get_system_app (plugin_loader);
if (gs_app_get_state (app) != GS_APP_STATE_UNAVAILABLE)
return;
@@ -766,17 +777,10 @@ static void
get_system (GsUpdateMonitor *monitor)
{
g_autoptr(GsApp) app = NULL;
- g_autoptr(GsPluginJob) plugin_job = NULL;
g_debug ("Getting system");
- app = gs_plugin_loader_get_system_app (monitor->plugin_loader);
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REFINE,
- "app", app,
- NULL);
- gs_plugin_loader_job_process_async (monitor->plugin_loader, plugin_job,
- monitor->cancellable,
- get_system_finished_cb,
- monitor);
+ gs_plugin_loader_get_system_app_async (monitor->plugin_loader, monitor->cancellable,
+ get_system_finished_cb, monitor);
}
static void
@@ -816,7 +820,7 @@ static void
install_language_pack_cb (GObject *object, GAsyncResult *res, gpointer data)
{
g_autoptr(GError) error = NULL;
- g_autoptr(LanguagePackData) language_pack_data = data;
+ g_autoptr(WithAppData) with_app_data = data;
if (!gs_plugin_loader_job_action_finish (GS_PLUGIN_LOADER (object), res, &error)) {
if (!g_error_matches (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_CANCELLED))
@@ -824,7 +828,7 @@ install_language_pack_cb (GObject *object, GAsyncResult *res, gpointer data)
return;
} else {
g_debug ("language pack for %s installed",
- gs_app_get_name (language_pack_data->app));
+ gs_app_get_name (with_app_data->app));
}
}
@@ -852,12 +856,10 @@ get_language_pack_cb (GObject *object, GAsyncResult *res, gpointer data)
/* there should be one langpack for a given locale */
app = g_object_ref (gs_app_list_index (app_list, 0));
if (!gs_app_is_installed (app)) {
- g_autoptr(LanguagePackData) language_pack_data = NULL;
+ WithAppData *with_app_data;
g_autoptr(GsPluginJob) plugin_job = NULL;
- language_pack_data = g_slice_new0 (LanguagePackData);
- language_pack_data->monitor = g_object_ref (monitor);
- language_pack_data->app = g_object_ref (app);
+ with_app_data = with_app_data_new (monitor, app);
plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_INSTALL,
"app", app,
@@ -866,7 +868,7 @@ get_language_pack_cb (GObject *object, GAsyncResult *res, gpointer data)
plugin_job,
monitor->cancellable,
install_language_pack_cb,
- g_steal_pointer (&language_pack_data));
+ with_app_data);
}
}
diff --git a/src/gs-updates-page.c b/src/gs-updates-page.c
index a95ec461b..7219048ff 100644
--- a/src/gs-updates-page.c
+++ b/src/gs-updates-page.c
@@ -515,31 +515,52 @@ gs_updates_page_get_upgrades_cb (GObject *source_object,
gs_updates_page_decrement_refresh_count (self);
}
+typedef struct {
+ GsApp *app; /* (owned) */
+ GsUpdatesPage *self; /* (owned) */
+} GsPageHelper;
+
+static GsPageHelper *
+gs_page_helper_new (GsUpdatesPage *self,
+ GsApp *app)
+{
+ GsPageHelper *helper;
+ helper = g_slice_new0 (GsPageHelper);
+ helper->self = g_object_ref (self);
+ helper->app = g_object_ref (app);
+ return helper;
+}
+
static void
-gs_updates_page_get_system_finished_cb (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
+gs_page_helper_free (GsPageHelper *helper)
+{
+ g_clear_object (&helper->app);
+ g_clear_object (&helper->self);
+ g_slice_free (GsPageHelper, helper);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GsPageHelper, gs_page_helper_free);
+
+static void
+gs_updates_page_refine_system_finished_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
{
GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
- GsUpdatesPage *self = GS_UPDATES_PAGE (user_data);
+ g_autoptr(GsPageHelper) helper = user_data;
+ GsUpdatesPage *self = helper->self;
+ GsApp *app = helper->app;
g_autoptr(GError) error = NULL;
- g_autoptr(GsApp) app = NULL;
g_autoptr(GString) str = g_string_new (NULL);
/* get result */
if (!gs_plugin_loader_job_action_finish (plugin_loader, res, &error)) {
if (!g_error_matches (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_CANCELLED))
- g_warning ("failed to get system: %s", error->message);
+ g_warning ("Failed to refine system: %s", error->message);
return;
}
/* show or hide the end of life notification */
- app = gs_plugin_loader_get_system_app (plugin_loader);
- if (app == NULL) {
- g_warning ("failed to get system app");
- gtk_widget_set_visible (self->box_end_of_life, FALSE);
- return;
- }
if (gs_app_get_state (app) != GS_APP_STATE_UNAVAILABLE) {
gtk_widget_set_visible (self->box_end_of_life, FALSE);
return;
@@ -570,6 +591,45 @@ gs_updates_page_get_system_finished_cb (GObject *source_object,
}
+static void
+gs_updates_page_get_system_finished_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ guint64 refine_flags;
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
+ GsUpdatesPage *self = user_data;
+ GsPageHelper *helper;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GsPluginJob) plugin_job = NULL;
+ g_autoptr(GError) error = NULL;
+
+ app = gs_plugin_loader_get_system_app_finish (plugin_loader, res, &error);
+ if (app == NULL) {
+ if (!g_error_matches (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_CANCELLED))
+ g_warning ("Failed to get system: %s", error->message);
+ return;
+ }
+
+ g_return_if_fail (GS_IS_UPDATES_PAGE (self));
+
+ refine_flags = GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_UPDATE_DETAILS |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION;
+
+ helper = gs_page_helper_new (self, app);
+ plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REFINE,
+ "interactive", TRUE,
+ "app", app,
+ "refine-flags", refine_flags,
+ NULL);
+ gs_plugin_loader_job_process_async (self->plugin_loader, plugin_job,
+ self->cancellable,
+ gs_updates_page_refine_system_finished_cb,
+ helper);
+}
+
static void
gs_updates_page_load (GsUpdatesPage *self)
{
@@ -601,17 +661,8 @@ gs_updates_page_load (GsUpdatesPage *self)
self);
/* get the system state */
- g_object_unref (plugin_job);
- app = gs_plugin_loader_get_system_app (self->plugin_loader);
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REFINE,
- "interactive", TRUE,
- "app", app,
- "refine-flags", refine_flags,
- NULL);
- gs_plugin_loader_job_process_async (self->plugin_loader, plugin_job,
- self->cancellable,
- gs_updates_page_get_system_finished_cb,
- self);
+ gs_plugin_loader_get_system_app_async (self->plugin_loader, self->cancellable,
+ gs_updates_page_get_system_finished_cb, self);
/* don't refresh every each time */
if ((self->result_flags & GS_UPDATES_PAGE_FLAG_HAS_UPGRADES) == 0) {
@@ -865,29 +916,13 @@ gs_updates_page_pending_apps_changed_cb (GsPluginLoader *plugin_loader,
gs_updates_page_invalidate (self);
}
-typedef struct {
- GsApp *app;
- GsUpdatesPage *self;
-} GsPageHelper;
-
-static void
-gs_page_helper_free (GsPageHelper *helper)
-{
- if (helper->app != NULL)
- g_object_unref (helper->app);
- if (helper->self != NULL)
- g_object_unref (helper->self);
- g_slice_free (GsPageHelper, helper);
-}
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GsPageHelper, gs_page_helper_free);
-
static void
upgrade_download_finished_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
+ g_autoptr(GsPageHelper) helper = user_data;
g_autoptr(GError) error = NULL;
if (!gs_plugin_loader_job_action_finish (plugin_loader, res, &error)) {
@@ -911,9 +946,7 @@ gs_updates_page_upgrade_download_cb (GsUpgradeBanner *upgrade_banner,
return;
}
- helper = g_slice_new0 (GsPageHelper);
- helper->app = g_object_ref (app);
- helper->self = g_object_ref (self);
+ helper = gs_page_helper_new (self, app);
if (self->cancellable_upgrade_download != NULL)
g_object_unref (self->cancellable_upgrade_download);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]