[gnome-software] Run the plugin loader methods in a new thread for each request



commit 7a76bbe622c1abacaa97bca328efe338e6c1126a
Author: Richard Hughes <richard hughsie com>
Date:   Mon Mar 11 12:03:47 2013 +0000

    Run the plugin loader methods in a new thread for each request

 src/Makefile.am             |    3 +
 src/gs-main.c               |   75 +++++++--
 src/gs-plugin-loader-sync.c |  139 +++++++++++++++
 src/gs-plugin-loader-sync.h |   43 +++++
 src/gs-plugin-loader.c      |  389 +++++++++++++++++++++++++++++++++++++------
 src/gs-plugin-loader.h      |   18 ++-
 src/gs-self-test.c          |    1 +
 7 files changed, 594 insertions(+), 74 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index b9e190d..d99017f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,6 +36,8 @@ gnome_software_SOURCES =                              \
        gs-plugin.h                                     \
        gs-plugin-loader.c                              \
        gs-plugin-loader.h                              \
+       gs-plugin-loader-sync.c                         \
+       gs-plugin-loader-sync.h                         \
        ch-markdown.c                                   \
        ch-markdown.h                                   \
        egg-list-box.c                                  \
@@ -72,6 +74,7 @@ check_PROGRAMS =                                              \
 gs_self_test_SOURCES =                                         \
        gs-app.c                                                \
        gs-plugin-loader.c                                      \
+       gs-plugin-loader-sync.c                                 \
        gs-self-test.c
 
 gs_self_test_LDADD =                                           \
diff --git a/src/gs-main.c b/src/gs-main.c
index 2008954..6b3cfff 100644
--- a/src/gs-main.c
+++ b/src/gs-main.c
@@ -836,24 +836,24 @@ out:
 }
 
 /**
- * gs_main_get_installed_packages:
+ * gs_main_get_installed_cb:
  **/
 static void
-gs_main_get_installed_packages (GsMainPrivate *priv)
+gs_main_get_installed_cb (GObject *source_object,
+                         GAsyncResult *res,
+                         gpointer user_data)
 {
-       GtkWidget *widget;
        GError *error = NULL;
        GList *l;
        GList *list;
        GsApp *app;
+       GsMainPrivate *priv = (GsMainPrivate *) user_data;
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
+       GtkWidget *widget;
 
-       /* remove old entries */
-       _gtk_container_remove_all (GTK_CONTAINER (priv->list_box_installed));
-
-       /* get popular apps */
-       list = gs_plugin_loader_get_installed (priv->plugin_loader,
-                                              priv->cancellable,
-                                              &error);
+       list = gs_plugin_loader_get_installed_finish (plugin_loader,
+                                                     res,
+                                                     &error);
        if (list == NULL) {
                g_warning ("failed to get installed apps: %s", error->message);
                g_error_free (error);
@@ -881,6 +881,22 @@ out:
 }
 
 /**
+ * gs_main_get_installed:
+ **/
+static void
+gs_main_get_installed (GsMainPrivate *priv)
+{
+       /* remove old entries */
+       _gtk_container_remove_all (GTK_CONTAINER (priv->list_box_installed));
+
+       /* get popular apps */
+       gs_plugin_loader_get_installed_async (priv->plugin_loader,
+                                             priv->cancellable,
+                                             gs_main_get_installed_cb,
+                                             priv);
+}
+
+/**
  * gs_main_get_updates:
  **/
 static void
@@ -897,33 +913,39 @@ gs_main_get_updates (GsMainPrivate *priv)
                                     (GAsyncReadyCallback) gs_main_get_updates_cb, priv);
 }
 
+
 /**
- * gs_main_get_popular:
+ * gs_main_get_popular_cb:
  **/
 static void
-gs_main_get_popular (GsMainPrivate *priv)
+gs_main_get_popular_cb (GObject *source_object,
+                       GAsyncResult *res,
+                       gpointer user_data)
 {
        GError *error = NULL;
        GList *l;
        GList *list;
        GsApp *app;
+       GsMainPrivate *priv = (GsMainPrivate *) user_data;
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
        GtkListStore *liststore;
        GtkTreeIter iter;
 
        /* get popular apps */
-       list = gs_plugin_loader_get_popular (priv->plugin_loader,
-                                            priv->cancellable,
-                                            &error);
+       list = gs_plugin_loader_get_popular_finish (plugin_loader,
+                                                   res,
+                                                   &error);
        if (list == NULL) {
                g_warning ("failed to get popular apps: %s", error->message);
                g_error_free (error);
                goto out;
        }
+
        liststore = GTK_LIST_STORE (gtk_builder_get_object (priv->builder, "liststore_popular"));
        gtk_list_store_clear (liststore);
        for (l = list; l != NULL; l = l->next) {
                app = GS_APP (l->data);
-               g_debug ("adding favourite %s", gs_app_get_id (app));
+               g_debug ("adding popular %s", gs_app_get_id (app));
                gtk_list_store_append (liststore, &iter);
                gtk_list_store_set (liststore,
                                    &iter,
@@ -937,6 +959,25 @@ out:
 }
 
 /**
+ * gs_main_get_popular:
+ **/
+static void
+gs_main_get_popular (GsMainPrivate *priv)
+{
+       GtkListStore *liststore;
+
+       /* remove old entries */
+       liststore = GTK_LIST_STORE (gtk_builder_get_object (priv->builder, "liststore_popular"));
+       gtk_list_store_clear (liststore);
+
+       /* get popular apps */
+       gs_plugin_loader_get_popular_async (priv->plugin_loader,
+                                           priv->cancellable,
+                                           gs_main_get_popular_cb,
+                                           priv);
+}
+
+/**
  * gs_main_set_overview_mode_ui:
  **/
 static void
@@ -1029,7 +1070,7 @@ gs_main_set_overview_mode (GsMainPrivate *priv, GsMainMode mode)
                gs_main_get_popular (priv);
                break;
        case GS_MAIN_MODE_INSTALLED:
-               gs_main_get_installed_packages (priv);
+               gs_main_get_installed (priv);
                break;
        case GS_MAIN_MODE_UPDATES:
                gs_main_get_updates (priv);
diff --git a/src/gs-plugin-loader-sync.c b/src/gs-plugin-loader-sync.c
new file mode 100644
index 0000000..301682d
--- /dev/null
+++ b/src/gs-plugin-loader-sync.c
@@ -0,0 +1,139 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2012-2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include "gs-plugin-loader-sync.h"
+
+/* tiny helper to help us do the async operation */
+typedef struct {
+       GError          **error;
+       GList           *list;
+       GMainLoop       *loop;
+} GsPluginLoaderHelper;
+
+static void
+gs_plugin_loader_get_installed_finish_sync (GsPluginLoader *plugin_loader,
+                                           GAsyncResult *res,
+                                           GsPluginLoaderHelper *helper)
+{
+       helper->list = gs_plugin_loader_get_installed_finish (plugin_loader,
+                                                             res,
+                                                             helper->error);
+       g_main_loop_quit (helper->loop);
+}
+
+/**
+ * gs_plugin_loader_get_installed:
+ **/
+GList *
+gs_plugin_loader_get_installed (GsPluginLoader *plugin_loader,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       GsPluginLoaderHelper helper;
+
+       /* create temp object */
+       helper.loop = g_main_loop_new (NULL, FALSE);
+       helper.error = error;
+
+       /* run async method */
+       gs_plugin_loader_get_installed_async (plugin_loader,
+                                             cancellable,
+                                             (GAsyncReadyCallback) 
gs_plugin_loader_get_installed_finish_sync,
+                                             &helper);
+       g_main_loop_run (helper.loop);
+       g_main_loop_unref (helper.loop);
+
+       return helper.list;
+}
+
+static void
+gs_plugin_loader_get_updates_finish_sync (GsPluginLoader *plugin_loader,
+                                         GAsyncResult *res,
+                                         GsPluginLoaderHelper *helper)
+{
+       helper->list = gs_plugin_loader_get_updates_finish (plugin_loader,
+                                                           res,
+                                                           helper->error);
+       g_main_loop_quit (helper->loop);
+}
+
+/**
+ * gs_plugin_loader_get_updates:
+ **/
+GList *
+gs_plugin_loader_get_updates (GsPluginLoader *plugin_loader,
+                             GCancellable *cancellable,
+                             GError **error)
+{
+       GsPluginLoaderHelper helper;
+
+       /* create temp object */
+       helper.loop = g_main_loop_new (NULL, FALSE);
+       helper.error = error;
+
+       /* run async method */
+       gs_plugin_loader_get_updates_async (plugin_loader,
+                                           cancellable,
+                                           (GAsyncReadyCallback) gs_plugin_loader_get_updates_finish_sync,
+                                           &helper);
+       g_main_loop_run (helper.loop);
+       g_main_loop_unref (helper.loop);
+
+       return helper.list;
+}
+
+static void
+gs_plugin_loader_get_popular_finish_sync (GsPluginLoader *plugin_loader,
+                                         GAsyncResult *res,
+                                         GsPluginLoaderHelper *helper)
+{
+       helper->list = gs_plugin_loader_get_popular_finish (plugin_loader,
+                                                           res,
+                                                           helper->error);
+       g_main_loop_quit (helper->loop);
+}
+
+/**
+ * gs_plugin_loader_get_popular:
+ **/
+GList *
+gs_plugin_loader_get_popular (GsPluginLoader *plugin_loader,
+                             GCancellable *cancellable,
+                             GError **error)
+{
+       GsPluginLoaderHelper helper;
+
+       /* create temp object */
+       helper.loop = g_main_loop_new (NULL, FALSE);
+       helper.error = error;
+
+       /* run async method */
+       gs_plugin_loader_get_popular_async (plugin_loader,
+                                           cancellable,
+                                           (GAsyncReadyCallback) gs_plugin_loader_get_popular_finish_sync,
+                                           &helper);
+       g_main_loop_run (helper.loop);
+       g_main_loop_unref (helper.loop);
+
+       return helper.list;
+}
diff --git a/src/gs-plugin-loader-sync.h b/src/gs-plugin-loader-sync.h
new file mode 100644
index 0000000..ef43254
--- /dev/null
+++ b/src/gs-plugin-loader-sync.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007-2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GS_PLUGIN_LOADER_SYNC_H
+#define __GS_PLUGIN_LOADER_SYNC_H
+
+#include <glib-object.h>
+
+#include "gs-plugin-loader.h"
+
+G_BEGIN_DECLS
+
+GList          *gs_plugin_loader_get_installed         (GsPluginLoader *plugin_loader,
+                                                        GCancellable   *cancellable,
+                                                        GError         **error);
+GList          *gs_plugin_loader_get_updates           (GsPluginLoader *plugin_loader,
+                                                        GCancellable   *cancellable,
+                                                        GError         **error);
+GList          *gs_plugin_loader_get_popular           (GsPluginLoader *plugin_loader,
+                                                        GCancellable   *cancellable,
+                                                        GError         **error);
+
+G_END_DECLS
+
+#endif /* __GS_PLUGIN_LOADER_SYNC_H */
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index d1c3f4b..75c9f58 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -94,6 +94,9 @@ gs_plugin_loader_run_refine (GsPluginLoader *plugin_loader,
                         function_name,
                         g_timer_elapsed (plugin->timer, NULL) * 1000);
        }
+
+       /* success */
+       ret = TRUE;
 out:
        return ret;
 }
@@ -113,6 +116,11 @@ gs_plugin_loader_run_results (GsPluginLoader *plugin_loader,
        GsPluginResultsFunc plugin_func = NULL;
        guint i;
 
+       g_return_val_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader), NULL);
+       g_return_val_if_fail (function_name != NULL, NULL);
+       g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+       g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+
        /* run each plugin */
        for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
                plugin = g_ptr_array_index (plugin_loader->priv->plugins, i);
@@ -131,9 +139,12 @@ gs_plugin_loader_run_results (GsPluginLoader *plugin_loader,
                g_debug ("run %s on %s", function_name,
                         g_module_name (plugin->module));
                g_timer_start (plugin->timer);
+
+               g_assert (error == NULL || *error == NULL);
                ret = plugin_func (plugin, &list, cancellable, error);
                if (!ret)
                        goto out;
+
                gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
                g_debug ("%s(%s) took %.0fms",
                         plugin->name,
@@ -197,36 +208,77 @@ gs_plugin_loader_remove_invalid (GList *list)
        return list;
 }
 
+/******************************************************************************/
+
+/* async state */
+typedef struct {
+       gboolean                         ret;
+       GCancellable                    *cancellable;
+       GList                           *list;
+       GSimpleAsyncResult              *res;
+       GsPluginLoader                  *plugin_loader;
+} GsPluginLoaderAsyncState;
+
+/******************************************************************************/
+
 /**
- * gs_plugin_loader_get_updates:
+ * cd_plugin_loader_get_all_state_finish:
  **/
-GList *
-gs_plugin_loader_get_updates (GsPluginLoader *plugin_loader,
-                             GCancellable *cancellable,
-                             GError **error)
+static void
+cd_plugin_loader_get_all_state_finish (GsPluginLoaderAsyncState *state,
+                                      const GError *error)
 {
-       GList *list;
+       if (state->ret) {
+               g_simple_async_result_set_op_res_gpointer (state->res,
+                                                          g_list_copy (state->list),
+                                                          (GDestroyNotify) g_list_free);
+       } else {
+               g_simple_async_result_set_from_error (state->res, error);
+       }
+
+       /* deallocate */
+       if (state->cancellable != NULL)
+               g_object_unref (state->cancellable);
+
+       g_list_free (state->list);
+       g_object_unref (state->res);
+       g_object_unref (state->plugin_loader);
+       g_slice_free (GsPluginLoaderAsyncState, state);
+}
+
+/******************************************************************************/
+
+/**
+ * cd_plugin_loader_get_updates_thread_cb:
+ **/
+static void
+cd_plugin_loader_get_updates_thread_cb (GSimpleAsyncResult *res,
+                                       GObject *object,
+                                       GCancellable *cancellable)
+{
+       gboolean has_os_update = FALSE;
+       GError *error = NULL;
        GList *l;
        GsApp *app;
        GsApp *app_tmp;
+       GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) g_object_get_data (G_OBJECT 
(cancellable), "state");
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
        GString *str_id = NULL;
        GString *str_summary = NULL;
-       gboolean has_os_update = FALSE;
 
-       list = gs_plugin_loader_run_results (plugin_loader,
-                                            "gs_plugin_add_updates",
-                                            cancellable,
-                                            error);
-       if (list == NULL) {
-               g_set_error (error,
-                            GS_PLUGIN_LOADER_ERROR,
-                            GS_PLUGIN_LOADER_ERROR_FAILED,
-                            "no updates to show");
+       /* do things that would block */
+       state->list = gs_plugin_loader_run_results (plugin_loader,
+                                                   "gs_plugin_add_updates",
+                                                   cancellable,
+                                                   &error);
+       if (state->list == NULL) {
+               cd_plugin_loader_get_all_state_finish (state, error);
+               g_error_free (error);
                goto out;
        }
 
        /* coalesce all packages down into one os-update */
-       for (l = list; l != NULL; l = l->next) {
+       for (l = state->list; l != NULL; l = l->next) {
                app_tmp = GS_APP (l->data);
                if (gs_app_get_kind (app_tmp) == GS_APP_KIND_PACKAGE) {
                        has_os_update = TRUE;
@@ -238,7 +290,7 @@ gs_plugin_loader_get_updates (GsPluginLoader *plugin_loader,
        if (has_os_update) {
                str_summary = g_string_new ("This updates the system:\n");
                str_id = g_string_new ("os-update:");
-               for (l = list; l != NULL; l = l->next) {
+               for (l = state->list; l != NULL; l = l->next) {
                        app_tmp = GS_APP (l->data);
                        if (gs_app_get_kind (app_tmp) != GS_APP_KIND_PACKAGE)
                                continue;
@@ -255,72 +307,294 @@ gs_plugin_loader_get_updates (GsPluginLoader *plugin_loader,
                gs_app_set_kind (app, GS_APP_KIND_OS_UPDATE);
                gs_app_set_name (app, "OS Update");
                gs_app_set_summary (app, str_summary->str);
-               gs_plugin_add_app (&list, app);
+               gs_plugin_add_app (&state->list, app);
 
                /* remove any packages that are not proper applications or
                 * OS updates */
-               list = gs_plugin_loader_remove_invalid (list);
+               state->list = gs_plugin_loader_remove_invalid (state->list);
+               if (state->list == NULL) {
+                       g_set_error_literal (&error,
+                                            GS_PLUGIN_LOADER_ERROR,
+                                            GS_PLUGIN_LOADER_ERROR_FAILED,
+                                            "no updates to show after invalid");
+                       cd_plugin_loader_get_all_state_finish (state, error);
+                       g_error_free (error);
+                       goto out;
+               }
        }
 
+       /* success */
+       state->ret = TRUE;
+       cd_plugin_loader_get_all_state_finish (state, NULL);
 out:
        if (str_id != NULL)
                g_string_free (str_id, TRUE);
        if (str_summary != NULL)
                g_string_free (str_summary, TRUE);
-       return list;
+       return;
+}
+
+/**
+ * gs_plugin_loader_get_updates_async:
+ **/
+void
+gs_plugin_loader_get_updates_async (GsPluginLoader *plugin_loader,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
+{
+       GCancellable *tmp;
+       GsPluginLoaderAsyncState *state;
+
+       g_return_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader));
+       g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+       /* save state */
+       state = g_slice_new0 (GsPluginLoaderAsyncState);
+       state->res = g_simple_async_result_new (G_OBJECT (plugin_loader),
+                                               callback,
+                                               user_data,
+                                               gs_plugin_loader_get_updates_async);
+       state->plugin_loader = g_object_ref (plugin_loader);
+       if (cancellable != NULL)
+               state->cancellable = g_object_ref (cancellable);
+
+       /* run in a thread */
+       tmp = g_cancellable_new ();
+       g_object_set_data (G_OBJECT (tmp), "state", state);
+       g_simple_async_result_run_in_thread (G_SIMPLE_ASYNC_RESULT (state->res),
+                                            cd_plugin_loader_get_updates_thread_cb,
+                                            0,
+                                            (GCancellable *) tmp);
+       g_object_unref (tmp);
 }
 
 /**
- * gs_plugin_loader_get_installed:
+ * gs_plugin_loader_get_updates_finish:
  **/
 GList *
-gs_plugin_loader_get_installed (GsPluginLoader *plugin_loader,
-                               GCancellable *cancellable,
-                               GError **error)
-{
-       GList *list;
-       list = gs_plugin_loader_run_results (plugin_loader,
-                                            "gs_plugin_add_installed",
-                                            cancellable,
-                                            error);
-       list = gs_plugin_loader_remove_invalid (list);
-       if (list == NULL) {
-               g_set_error (error,
-                            GS_PLUGIN_LOADER_ERROR,
-                            GS_PLUGIN_LOADER_ERROR_FAILED,
-                            "no installed packages to show");
+gs_plugin_loader_get_updates_finish (GsPluginLoader *plugin_loader,
+                                      GAsyncResult *res,
+                                      GError **error)
+{
+       GSimpleAsyncResult *simple;
+
+       g_return_val_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader), NULL);
+       g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), NULL);
+       g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+       /* failed */
+       simple = G_SIMPLE_ASYNC_RESULT (res);
+       if (g_simple_async_result_propagate_error (simple, error))
+               return NULL;
+
+       /* grab detail */
+       return g_list_copy (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+/******************************************************************************/
+
+/**
+ * cd_plugin_loader_get_installed_thread_cb:
+ **/
+static void
+cd_plugin_loader_get_installed_thread_cb (GSimpleAsyncResult *res,
+                                         GObject *object,
+                                         GCancellable *cancellable)
+{
+       GError *error = NULL;
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
+       GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) g_object_get_data (G_OBJECT 
(cancellable), "state");
+
+       /* do things that would block */
+       state->list = gs_plugin_loader_run_results (plugin_loader,
+                                                   "gs_plugin_add_installed",
+                                                   cancellable,
+                                                   &error);
+       if (state->list == NULL) {
+               cd_plugin_loader_get_all_state_finish (state, error);
+               g_error_free (error);
                goto out;
        }
+       state->list = gs_plugin_loader_remove_invalid (state->list);
+       if (state->list == NULL) {
+               g_set_error_literal (&error,
+                                    GS_PLUGIN_LOADER_ERROR,
+                                    GS_PLUGIN_LOADER_ERROR_FAILED,
+                                    "no installed applications to show after invalid");
+               cd_plugin_loader_get_all_state_finish (state, error);
+               g_error_free (error);
+               goto out;
+       }
+
+       /* success */
+       state->ret = TRUE;
+       cd_plugin_loader_get_all_state_finish (state, NULL);
 out:
-       return list;
+       return;
+}
+
+/**
+ * gs_plugin_loader_get_installed_async:
+ **/
+void
+gs_plugin_loader_get_installed_async (GsPluginLoader *plugin_loader,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
+{
+       GCancellable *tmp;
+       GsPluginLoaderAsyncState *state;
+
+       g_return_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader));
+       g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+       /* save state */
+       state = g_slice_new0 (GsPluginLoaderAsyncState);
+       state->res = g_simple_async_result_new (G_OBJECT (plugin_loader),
+                                               callback,
+                                               user_data,
+                                               gs_plugin_loader_get_installed_async);
+       state->plugin_loader = g_object_ref (plugin_loader);
+       if (cancellable != NULL)
+               state->cancellable = g_object_ref (cancellable);
+
+       /* run in a thread */
+       tmp = g_cancellable_new ();
+       g_object_set_data (G_OBJECT (tmp), "state", state);
+       g_simple_async_result_run_in_thread (G_SIMPLE_ASYNC_RESULT (state->res),
+                                            cd_plugin_loader_get_installed_thread_cb,
+                                            0,
+                                            (GCancellable *) tmp);
+       g_object_unref (tmp);
 }
 
 /**
- * gs_plugin_loader_get_popular:
+ * gs_plugin_loader_get_installed_finish:
  **/
 GList *
-gs_plugin_loader_get_popular (GsPluginLoader *plugin_loader,
-                             GCancellable *cancellable,
-                             GError **error)
+gs_plugin_loader_get_installed_finish (GsPluginLoader *plugin_loader,
+                                      GAsyncResult *res,
+                                      GError **error)
 {
-       GList *list;
-       list = gs_plugin_loader_run_results (plugin_loader,
-                                            "gs_plugin_add_popular",
-                                            cancellable,
-                                            error);
-       list = gs_plugin_loader_remove_invalid (list);
-       if (list == NULL) {
-               g_set_error (error,
-                            GS_PLUGIN_LOADER_ERROR,
-                            GS_PLUGIN_LOADER_ERROR_FAILED,
-                            "no popular apps to show");
+       GSimpleAsyncResult *simple;
+
+       g_return_val_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader), NULL);
+       g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), NULL);
+       g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+       /* failed */
+       simple = G_SIMPLE_ASYNC_RESULT (res);
+       if (g_simple_async_result_propagate_error (simple, error))
+               return NULL;
+
+       /* grab detail */
+       return g_list_copy (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+/******************************************************************************/
+
+/**
+ * cd_plugin_loader_get_popular_thread_cb:
+ **/
+static void
+cd_plugin_loader_get_popular_thread_cb (GSimpleAsyncResult *res,
+                                         GObject *object,
+                                         GCancellable *cancellable)
+{
+       GError *error = NULL;
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
+       GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) g_object_get_data (G_OBJECT 
(cancellable), "state");
+
+       /* do things that would block */
+       state->list = gs_plugin_loader_run_results (plugin_loader,
+                                                   "gs_plugin_add_popular",
+                                                   cancellable,
+                                                   &error);
+       if (state->list == NULL) {
+               cd_plugin_loader_get_all_state_finish (state, error);
+               g_error_free (error);
+               goto out;
+       }
+       state->list = gs_plugin_loader_remove_invalid (state->list);
+       if (state->list == NULL) {
+               g_set_error_literal (&error,
+                                    GS_PLUGIN_LOADER_ERROR,
+                                    GS_PLUGIN_LOADER_ERROR_FAILED,
+                                    "no popular apps to show");
+               cd_plugin_loader_get_all_state_finish (state, error);
+               g_error_free (error);
                goto out;
        }
+
+       /* success */
+       state->ret = TRUE;
+       cd_plugin_loader_get_all_state_finish (state, NULL);
 out:
-       return list;
+       return;
+}
+
+/**
+ * gs_plugin_loader_get_popular_async:
+ **/
+void
+gs_plugin_loader_get_popular_async (GsPluginLoader *plugin_loader,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
+{
+       GCancellable *tmp;
+       GsPluginLoaderAsyncState *state;
+
+       g_return_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader));
+       g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+       /* save state */
+       state = g_slice_new0 (GsPluginLoaderAsyncState);
+       state->res = g_simple_async_result_new (G_OBJECT (plugin_loader),
+                                               callback,
+                                               user_data,
+                                               gs_plugin_loader_get_popular_async);
+       state->plugin_loader = g_object_ref (plugin_loader);
+       if (cancellable != NULL)
+               state->cancellable = g_object_ref (cancellable);
+
+       /* run in a thread */
+       tmp = g_cancellable_new ();
+       g_object_set_data (G_OBJECT (tmp), "state", state);
+       g_simple_async_result_run_in_thread (G_SIMPLE_ASYNC_RESULT (state->res),
+                                            cd_plugin_loader_get_popular_thread_cb,
+                                            0,
+                                            (GCancellable *) tmp);
+       g_object_unref (tmp);
 }
 
 /**
+ * gs_plugin_loader_get_popular_finish:
+ **/
+GList *
+gs_plugin_loader_get_popular_finish (GsPluginLoader *plugin_loader,
+                                    GAsyncResult *res,
+                                    GError **error)
+{
+       GSimpleAsyncResult *simple;
+
+       g_return_val_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader), NULL);
+       g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), NULL);
+       g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+       /* failed */
+       simple = G_SIMPLE_ASYNC_RESULT (res);
+       if (g_simple_async_result_propagate_error (simple, error))
+               return NULL;
+
+       /* grab detail */
+       return g_list_copy (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+/******************************************************************************/
+
+/**
  * gs_plugin_loader_search:
  **/
 GList *
@@ -402,6 +676,7 @@ gs_plugin_loader_run_action (GsPluginLoader *plugin_loader,
 {
        gboolean exists;
        gboolean ret = FALSE;
+       gboolean anything_ran = FALSE;
        GError *error_local = NULL;
        GsPluginActionFunc plugin_func = NULL;
        GsPlugin *plugin;
@@ -443,16 +718,22 @@ gs_plugin_loader_run_action (GsPluginLoader *plugin_loader,
                         plugin->name,
                         function_name,
                         g_timer_elapsed (plugin->timer, NULL) * 1000);
+               anything_ran = TRUE;
        }
 
        /* nothing ran */
-       if (!ret) {
+       if (!anything_ran) {
+               ret = FALSE;
                g_set_error (error,
                             GS_PLUGIN_LOADER_ERROR,
                             GS_PLUGIN_LOADER_ERROR_FAILED,
                             "no plugin could handle %s",
                             function_name);
+               goto out;
        }
+
+       /* success */
+       ret = TRUE;
 out:
        return ret;
 }
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
index 076f950..43b6a5c 100644
--- a/src/gs-plugin-loader.h
+++ b/src/gs-plugin-loader.h
@@ -63,14 +63,26 @@ GQuark               gs_plugin_loader_error_quark           (void);
 GType           gs_plugin_loader_get_type              (void);
 
 GsPluginLoader *gs_plugin_loader_new                   (void);
-GList          *gs_plugin_loader_get_installed         (GsPluginLoader *plugin_loader,
+void            gs_plugin_loader_get_installed_async   (GsPluginLoader *plugin_loader,
                                                         GCancellable   *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer        user_data);
+GList          *gs_plugin_loader_get_installed_finish  (GsPluginLoader *plugin_loader,
+                                                        GAsyncResult   *res,
                                                         GError         **error);
-GList          *gs_plugin_loader_get_updates           (GsPluginLoader *plugin_loader,
+void            gs_plugin_loader_get_updates_async     (GsPluginLoader *plugin_loader,
                                                         GCancellable   *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer        user_data);
+GList          *gs_plugin_loader_get_updates_finish    (GsPluginLoader *plugin_loader,
+                                                        GAsyncResult   *res,
                                                         GError         **error);
-GList          *gs_plugin_loader_get_popular           (GsPluginLoader *plugin_loader,
+void            gs_plugin_loader_get_popular_async     (GsPluginLoader *plugin_loader,
                                                         GCancellable   *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer        user_data);
+GList          *gs_plugin_loader_get_popular_finish    (GsPluginLoader *plugin_loader,
+                                                        GAsyncResult   *res,
                                                         GError         **error);
 GList          *gs_plugin_loader_search                (GsPluginLoader *plugin_loader,
                                                         const gchar    *value,
diff --git a/src/gs-self-test.c b/src/gs-self-test.c
index 40e412f..eb1d420 100644
--- a/src/gs-self-test.c
+++ b/src/gs-self-test.c
@@ -27,6 +27,7 @@
 
 #include "gs-app.h"
 #include "gs-plugin-loader.h"
+#include "gs-plugin-loader-sync.h"
 
 static void
 gs_app_func (void)


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