[gnome-software] Run the plugin loader methods in a new thread for each request
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Run the plugin loader methods in a new thread for each request
- Date: Mon, 11 Mar 2013 20:11:01 +0000 (UTC)
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]