[gnome-software] Add a simple plugin loader
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Add a simple plugin loader
- Date: Thu, 7 Mar 2013 16:06:39 +0000 (UTC)
commit add578e1fb284dc2bb6c8d5f98dd84995de5f5f4
Author: Richard Hughes <richard hughsie com>
Date: Thu Mar 7 09:50:33 2013 +0000
Add a simple plugin loader
This will be used to implement different backends for each distro.
configure.ac | 2 +-
src/Makefile.am | 5 +
src/gs-main.c | 15 +-
src/gs-plugin-loader.c | 665 ++++++++++++++++++++++++++++++++++++++++++++++++
src/gs-plugin-loader.h | 88 +++++++
src/gs-plugin.h | 106 ++++++++
src/gs-self-test.c | 21 ++
7 files changed, 900 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index e155b5e..3f6d7e1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -72,7 +72,7 @@ GLIB_GSETTINGS
dnl ---------------------------------------------------------------------------
dnl - Check library dependencies
dnl ---------------------------------------------------------------------------
-PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.31.10 gobject-2.0 gthread-2.0 gio-2.0 >= 2.25.9)
+PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.31.10 gobject-2.0 gthread-2.0 gio-2.0 >= 2.25.9 gmodule-2.0)
PKG_CHECK_MODULES(GTK, gtk+-3.0 >= 3.5.6)
PKG_CHECK_MODULES(PACKAGEKIT, packagekit-glib2 >= 0.7.5)
diff --git a/src/Makefile.am b/src/Makefile.am
index b63f0d1..a63afb7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,6 +4,7 @@ INCLUDES = \
$(PACKAGEKIT_CFLAGS) \
-DG_LOG_DOMAIN=\"Gs\" \
-DI_KNOW_THE_PACKAGEKIT_GLIB2_API_IS_SUBJECT_TO_CHANGE \
+ -DLIBDIR=\"$(libdir)\" \
-DBINDIR=\"$(bindir)\" \
-DDATADIR=\"$(datadir)\" \
-DVERSION="\"$(VERSION)\"" \
@@ -29,6 +30,9 @@ gnome_software_SOURCES = \
gs-app.h \
gs-app-widget.c \
gs-app-widget.h \
+ gs-plugin.h \
+ gs-plugin-loader.c \
+ gs-plugin-loader.h \
ch-markdown.c \
ch-markdown.h \
egg-list-box.c \
@@ -64,6 +68,7 @@ check_PROGRAMS = \
gs_self_test_SOURCES = \
gs-app.c \
+ gs-plugin-loader.c \
gs-self-test.c
gs_self_test_LDADD = \
diff --git a/src/gs-main.c b/src/gs-main.c
index 431a784..38527d5 100644
--- a/src/gs-main.c
+++ b/src/gs-main.c
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2012 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2012-2013 Richard Hughes <richard hughsie com>
*
* Licensed under the GNU General Public License Version 2
*
@@ -29,6 +29,7 @@
#include "egg-list-box.h"
#include "gs-app-widget.h"
#include "gs-resources.h"
+#include "gs-plugin-loader.h"
#define GS_MAIN_ICON_SIZE 64
@@ -61,6 +62,7 @@ typedef struct {
GtkCssProvider *provider;
gboolean ignore_primary_buttons;
gchar **blacklisted_remove;
+ GsPluginLoader *plugin_loader;
} GsMainPrivate;
static void gs_main_set_overview_mode_ui (GsMainPrivate *priv, GsMainMode mode);
@@ -1609,10 +1611,21 @@ main (int argc, char **argv)
g_strv_length (priv->blacklisted_remove));
g_bytes_unref (data);
+ /* load the plugins */
+ priv->plugin_loader = gs_plugin_loader_new ();
+ gs_plugin_loader_set_location (priv->plugin_loader, NULL);
+ ret = gs_plugin_loader_setup (priv->plugin_loader, &error);
+ if (!ret) {
+ g_warning ("Failed to setup plugins: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
/* wait */
status = g_application_run (G_APPLICATION (priv->application), argc, argv);
out:
if (priv != NULL) {
+ g_object_unref (priv->plugin_loader);
g_object_unref (priv->task);
g_object_unref (priv->desktop);
g_object_unref (priv->cancellable);
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
new file mode 100644
index 0000000..1fe3bcd
--- /dev/null
+++ b/src/gs-plugin-loader.c
@@ -0,0 +1,665 @@
+/* -*- 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.
+ */
+
+#include "config.h"
+
+#include "gs-plugin-loader.h"
+#include "gs-plugin.h"
+
+static void gs_plugin_loader_finalize (GObject *object);
+
+#define GS_PLUGIN_LOADER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_PLUGIN_LOADER,
GsPluginLoaderPrivate))
+
+struct GsPluginLoaderPrivate
+{
+ GPtrArray *plugins;
+ gchar *location;
+};
+
+G_DEFINE_TYPE (GsPluginLoader, gs_plugin_loader, G_TYPE_OBJECT)
+
+/**
+ * gs_plugin_loader_error_quark:
+ * Return value: Our personal error quark.
+ **/
+GQuark
+gs_plugin_loader_error_quark (void)
+{
+ static GQuark quark = 0;
+ if (!quark)
+ quark = g_quark_from_static_string ("gs_plugin_loader_error");
+ return quark;
+}
+
+/**
+ * gs_plugin_loader_run_refine:
+ **/
+static gboolean
+gs_plugin_loader_run_refine (GsPluginLoader *plugin_loader,
+ GList *list,
+ GError **error)
+{
+ gboolean ret = TRUE;
+ GsPlugin *plugin;
+ const gchar *function_name = "gs_plugin_refine";
+ GsPluginRefineFunc plugin_func = NULL;
+ guint i;
+
+ /* run each plugin */
+ for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
+ plugin = g_ptr_array_index (plugin_loader->priv->plugins, i);
+ if (!plugin->enabled)
+ continue;
+ ret = g_module_symbol (plugin->module,
+ function_name,
+ (gpointer *) &plugin_func);
+ if (!ret)
+ continue;
+ g_debug ("run %s on %s", function_name,
+ g_module_name (plugin->module));
+ ret = plugin_func (plugin, list, error);
+ if (!ret)
+ goto out;
+ }
+out:
+ return ret;
+}
+
+/**
+ * gs_plugin_loader_run_results:
+ **/
+static GList *
+gs_plugin_loader_run_results (GsPluginLoader *plugin_loader,
+ const gchar *function_name,
+ GError **error)
+{
+ gboolean ret;
+ GList *list = NULL;
+ GsPlugin *plugin;
+ GsPluginResultsFunc plugin_func = NULL;
+ guint i;
+
+ /* run each plugin */
+ for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
+ plugin = g_ptr_array_index (plugin_loader->priv->plugins, i);
+ if (!plugin->enabled)
+ continue;
+ ret = g_module_symbol (plugin->module,
+ function_name,
+ (gpointer *) &plugin_func);
+ if (!ret)
+ continue;
+ g_debug ("run %s on %s", function_name,
+ g_module_name (plugin->module));
+ ret = plugin_func (plugin, &list, error);
+ if (!ret)
+ goto out;
+ }
+
+ /* run refine() on each one */
+ ret = gs_plugin_loader_run_refine (plugin_loader, list, error);
+ if (!ret)
+ goto out;
+
+ /* success */
+out:
+ return list;
+}
+
+/**
+ * gs_plugin_loader_remove_packages:
+ **/
+static GList *
+gs_plugin_loader_remove_packages (GList *list)
+{
+ GList *l;
+ GsApp *app;
+
+ for (l = list; l != NULL;) {
+ app = GS_APP (l->data);
+ if (gs_app_get_kind (app) != GS_APP_KIND_PACKAGE) {
+ l = l->next;
+ continue;
+ }
+ g_debug ("removing package %s", gs_app_get_id (app));
+ g_object_unref (app);
+ l = list = g_list_delete_link (list, l);
+ }
+ return list;
+}
+
+/**
+ * gs_plugin_loader_get_updates:
+ **/
+GList *
+gs_plugin_loader_get_updates (GsPluginLoader *plugin_loader, GError **error)
+{
+ GList *list;
+ GList *l;
+ GsApp *app;
+ GsApp *app_tmp;
+ 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",
+ error);
+ if (list == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_LOADER_ERROR,
+ GS_PLUGIN_LOADER_ERROR_FAILED,
+ "no updates to show");
+ goto out;
+ }
+
+ /* coalesce all packages down into one os-update */
+ for (l = 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;
+ break;
+ }
+ }
+
+ /* smush them all together */
+ 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) {
+ app_tmp = GS_APP (l->data);
+ if (gs_app_get_kind (app_tmp) != GS_APP_KIND_PACKAGE)
+ continue;
+ g_string_append_printf (str_id, "%s,",
+ gs_app_get_id (app_tmp));
+ g_string_append_printf (str_summary, "%s\n",
+ gs_app_get_summary (app_tmp));
+ }
+ g_string_truncate (str_id, str_id->len - 1);
+ g_string_truncate (str_summary, str_summary->len - 1);
+
+ /* create new meta object */
+ app = gs_app_new (str_id->str);
+ 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);
+
+ /* remove any packages that are not proper applications or
+ * OS updates */
+ list = gs_plugin_loader_remove_packages (list);
+ }
+
+out:
+ if (str_id != NULL)
+ g_string_free (str_id, TRUE);
+ if (str_summary != NULL)
+ g_string_free (str_summary, TRUE);
+ return list;
+}
+
+/**
+ * gs_plugin_loader_get_installed:
+ **/
+GList *
+gs_plugin_loader_get_installed (GsPluginLoader *plugin_loader, GError **error)
+{
+ GList *list;
+ list = gs_plugin_loader_run_results (plugin_loader,
+ "gs_plugin_add_installed",
+ error);
+ list = gs_plugin_loader_remove_packages (list);
+ if (list == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_LOADER_ERROR,
+ GS_PLUGIN_LOADER_ERROR_FAILED,
+ "no installed packages to show");
+ goto out;
+ }
+out:
+ return list;
+}
+
+/**
+ * gs_plugin_loader_get_popular:
+ **/
+GList *
+gs_plugin_loader_get_popular (GsPluginLoader *plugin_loader, GError **error)
+{
+ GList *list;
+ list = gs_plugin_loader_run_results (plugin_loader,
+ "gs_plugin_add_popular",
+ error);
+ list = gs_plugin_loader_remove_packages (list);
+ if (list == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_LOADER_ERROR,
+ GS_PLUGIN_LOADER_ERROR_FAILED,
+ "no popular apps to show");
+ goto out;
+ }
+out:
+ return list;
+}
+
+/**
+ * gs_plugin_loader_search:
+ **/
+GList *
+gs_plugin_loader_search (GsPluginLoader *plugin_loader, const gchar *value, GError **error)
+{
+ const gchar *function_name = "gs_plugin_add_search";
+ gboolean ret;
+ GList *list = NULL;
+ GsPlugin *plugin;
+ GsPluginSearchFunc plugin_func = NULL;
+ guint i;
+
+ /* run each plugin */
+ for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
+ plugin = g_ptr_array_index (plugin_loader->priv->plugins, i);
+ if (!plugin->enabled)
+ continue;
+ ret = g_module_symbol (plugin->module,
+ function_name,
+ (gpointer *) &plugin_func);
+ if (!ret)
+ continue;
+ g_debug ("run %s on %s", function_name,
+ g_module_name (plugin->module));
+ ret = plugin_func (plugin, value, &list, error);
+ if (!ret)
+ goto out;
+ }
+
+ /* run refine() on each one */
+ ret = gs_plugin_loader_run_refine (plugin_loader, list, error);
+ if (!ret)
+ goto out;
+
+ /* success */
+ list = gs_plugin_loader_remove_packages (list);
+ if (list == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_LOADER_ERROR,
+ GS_PLUGIN_LOADER_ERROR_FAILED,
+ "no search results to show");
+ goto out;
+ }
+out:
+ return list;
+}
+
+
+/**
+ * gs_plugin_loader_run_action:
+ **/
+static gboolean
+gs_plugin_loader_run_action (GsPluginLoader *plugin_loader,
+ GsApp *app,
+ const gchar *function_name,
+ GError **error)
+{
+ gboolean exists;
+ gboolean ret = FALSE;
+ GError *error_local = NULL;
+ GsPluginActionFunc plugin_func = NULL;
+ GsPlugin *plugin;
+ guint i;
+
+ /* run each plugin */
+ for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
+ plugin = g_ptr_array_index (plugin_loader->priv->plugins, i);
+ if (!plugin->enabled)
+ continue;
+ exists = g_module_symbol (plugin->module,
+ function_name,
+ (gpointer *) &plugin_func);
+ if (!exists)
+ continue;
+ g_debug ("run %s on %s", function_name,
+ g_module_name (plugin->module));
+ ret = plugin_func (plugin, app, &error_local);
+ if (!ret) {
+ if (g_error_matches (error_local,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED)) {
+ g_debug ("not supported for plugin %s",
+ plugin->name);
+ g_clear_error (&error_local);
+ } else {
+ g_propagate_error (error, error_local);
+ goto out;
+ }
+ }
+ }
+
+ /* nothing ran */
+ if (!ret) {
+ g_set_error (error,
+ GS_PLUGIN_LOADER_ERROR,
+ GS_PLUGIN_LOADER_ERROR_FAILED,
+ "no plugin could handle %s",
+ function_name);
+ }
+out:
+ return ret;
+}
+
+/**
+ * gs_plugin_loader_app_update:
+ **/
+gboolean
+gs_plugin_loader_app_update (GsPluginLoader *plugin_loader, GsApp *app, GError **error)
+{
+ return gs_plugin_loader_run_action (plugin_loader,
+ app,
+ "gs_plugin_app_update",
+ error);
+}
+
+/**
+ * gs_plugin_loader_app_install:
+ **/
+gboolean
+gs_plugin_loader_app_install (GsPluginLoader *plugin_loader, GsApp *app, GError **error)
+{
+ return gs_plugin_loader_run_action (plugin_loader,
+ app,
+ "gs_plugin_app_install",
+ error);
+}
+
+/**
+ * gs_plugin_loader_app_remove:
+ **/
+gboolean
+gs_plugin_loader_app_remove (GsPluginLoader *plugin_loader, GsApp *app, GError **error)
+{
+ return gs_plugin_loader_run_action (plugin_loader,
+ app,
+ "gs_plugin_app_remove",
+ error);
+}
+
+/**
+ * gs_plugin_loader_run:
+ **/
+static void
+gs_plugin_loader_run (GsPluginLoader *plugin_loader, const gchar *function_name)
+{
+ gboolean ret;
+ GsPluginFunc plugin_func = NULL;
+ GsPlugin *plugin;
+ guint i;
+
+ /* run each plugin */
+ for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
+ plugin = g_ptr_array_index (plugin_loader->priv->plugins, i);
+ ret = g_module_symbol (plugin->module,
+ function_name,
+ (gpointer *) &plugin_func);
+ if (!ret)
+ continue;
+ g_debug ("run %s on %s", function_name,
+ g_module_name (plugin->module));
+ plugin_func (plugin);
+ }
+}
+
+/**
+ * gs_plugin_loader_set_enabled:
+ */
+gboolean
+gs_plugin_loader_set_enabled (GsPluginLoader *plugin_loader,
+ const gchar *plugin_name,
+ gboolean enabled)
+{
+ gboolean ret = FALSE;
+ GsPlugin *plugin;
+ guint i;
+
+ for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
+ plugin = g_ptr_array_index (plugin_loader->priv->plugins, i);
+ if (g_strcmp0 (plugin->name, plugin_name) == 0) {
+ plugin->enabled = enabled;
+ ret = TRUE;
+ break;
+ }
+ }
+ return ret;
+}
+
+/**
+ * gs_plugin_loader_open_plugin:
+ */
+static GsPlugin *
+gs_plugin_loader_open_plugin (GsPluginLoader *plugin_loader,
+ const gchar *filename)
+{
+ gboolean ret;
+ GModule *module;
+ GsPluginGetNameFunc plugin_name = NULL;
+ GsPluginGetPriorityFunc plugin_prio = NULL;
+ GsPlugin *plugin = NULL;
+
+ module = g_module_open (filename, 0);
+ if (module == NULL) {
+ g_warning ("failed to open plugin %s: %s",
+ filename, g_module_error ());
+ goto out;
+ }
+
+ /* get description */
+ ret = g_module_symbol (module,
+ "gs_plugin_get_name",
+ (gpointer *) &plugin_name);
+ if (!ret) {
+ g_warning ("Plugin %s requires name", filename);
+ g_module_close (module);
+ goto out;
+ }
+
+ /* get priority */
+ ret = g_module_symbol (module,
+ "gs_plugin_get_priority",
+ (gpointer *) &plugin_prio);
+ if (!ret) {
+ g_warning ("Plugin %s requires priority", filename);
+ g_module_close (module);
+ goto out;
+ }
+
+ /* print what we know */
+ plugin = g_new0 (GsPlugin, 1);
+ plugin->enabled = FALSE;
+ plugin->module = module;
+ plugin->pixbuf_size = 64;
+ plugin->priority = plugin_prio (plugin);
+ plugin->name = g_strdup (plugin_name ());
+ g_debug ("opened plugin %s: %s", filename, plugin->name);
+
+ /* add to array */
+ g_ptr_array_add (plugin_loader->priv->plugins, plugin);
+out:
+ return plugin;
+}
+
+/**
+ * gs_plugin_loader_set_location:
+ */
+void
+gs_plugin_loader_set_location (GsPluginLoader *plugin_loader, const gchar *location)
+{
+ g_free (plugin_loader->priv->location);
+
+ /* something non-default specified */
+ if (location != NULL) {
+ plugin_loader->priv->location = g_strdup (location);
+ return;
+ }
+
+ /* use the default, but this requires a 'make install' */
+ plugin_loader->priv->location = g_build_filename (LIBDIR, "gs-plugins", NULL);
+}
+
+/**
+ * gs_plugin_loader_plugin_sort_fn:
+ */
+static gint
+gs_plugin_loader_plugin_sort_fn (gconstpointer a, gconstpointer b)
+{
+ GsPlugin **pa = (GsPlugin **) a;
+ GsPlugin **pb = (GsPlugin **) b;
+ return (*pa)->priority < (*pb)->priority;
+}
+
+/**
+ * gs_plugin_loader_setup:
+ */
+gboolean
+gs_plugin_loader_setup (GsPluginLoader *plugin_loader, GError **error)
+{
+ const gchar *filename_tmp;
+ gboolean ret = TRUE;
+ gchar *filename_plugin;
+ GDir *dir;
+ GsPlugin *plugin;
+ guint i;
+
+ g_return_val_if_fail (plugin_loader->priv->location != NULL, FALSE);
+
+ /* search in the plugin directory for plugins */
+ dir = g_dir_open (plugin_loader->priv->location, 0, error);
+ if (dir == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+
+ /* try to open each plugin */
+ g_debug ("searching for plugins in %s", plugin_loader->priv->location);
+ do {
+ filename_tmp = g_dir_read_name (dir);
+ if (filename_tmp == NULL)
+ break;
+ if (!g_str_has_suffix (filename_tmp, ".so"))
+ continue;
+ filename_plugin = g_build_filename (plugin_loader->priv->location,
+ filename_tmp,
+ NULL);
+ gs_plugin_loader_open_plugin (plugin_loader, filename_plugin);
+ g_free (filename_plugin);
+ } while (TRUE);
+
+ /* sort by priority */
+ g_ptr_array_sort (plugin_loader->priv->plugins,
+ gs_plugin_loader_plugin_sort_fn);
+
+ /* print what the priorities are */
+ for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
+ plugin = g_ptr_array_index (plugin_loader->priv->plugins, i);
+ g_debug ("%.1f\t->\t%s [%s]",
+ plugin->priority,
+ plugin->name,
+ plugin->enabled ? "enabled" : "disabled");
+ }
+
+ /* run the plugins */
+ gs_plugin_loader_run (plugin_loader, "gs_plugin_initialize");
+out:
+ if (dir != NULL)
+ g_dir_close (dir);
+ return ret;
+}
+
+/**
+ * gs_plugin_loader_plugin_free:
+ **/
+static void
+gs_plugin_loader_plugin_free (GsPlugin *plugin)
+{
+ g_free (plugin->priv);
+ g_free (plugin->name);
+ g_module_close (plugin->module);
+ g_free (plugin);
+}
+
+/**
+ * gs_plugin_loader_class_init:
+ * @klass: The GsPluginLoaderClass
+ **/
+static void
+gs_plugin_loader_class_init (GsPluginLoaderClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gs_plugin_loader_finalize;
+
+ g_type_class_add_private (klass, sizeof (GsPluginLoaderPrivate));
+}
+
+/**
+ * gs_plugin_loader_init:
+ **/
+static void
+gs_plugin_loader_init (GsPluginLoader *plugin_loader)
+{
+ plugin_loader->priv = GS_PLUGIN_LOADER_GET_PRIVATE (plugin_loader);
+ plugin_loader->priv->plugins = g_ptr_array_new_with_free_func ((GDestroyNotify)
gs_plugin_loader_plugin_free);
+}
+
+/**
+ * gs_plugin_loader_finalize:
+ * @object: The object to finalize
+ **/
+static void
+gs_plugin_loader_finalize (GObject *object)
+{
+ GsPluginLoader *plugin_loader;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GS_IS_PLUGIN_LOADER (object));
+
+ plugin_loader = GS_PLUGIN_LOADER (object);
+
+ g_return_if_fail (plugin_loader->priv != NULL);
+
+ /* run the plugins */
+ gs_plugin_loader_run (plugin_loader, "gs_plugin_destroy");
+
+ g_ptr_array_unref (plugin_loader->priv->plugins);
+ g_free (plugin_loader->priv->location);
+
+ G_OBJECT_CLASS (gs_plugin_loader_parent_class)->finalize (object);
+}
+
+/**
+ * gs_plugin_loader_new:
+ *
+ * Return value: a new GsPluginLoader object.
+ **/
+GsPluginLoader *
+gs_plugin_loader_new (void)
+{
+ GsPluginLoader *plugin_loader;
+ plugin_loader = g_object_new (GS_TYPE_PLUGIN_LOADER, NULL);
+ return GS_PLUGIN_LOADER (plugin_loader);
+}
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
new file mode 100644
index 0000000..0e52bf2
--- /dev/null
+++ b/src/gs-plugin-loader.h
@@ -0,0 +1,88 @@
+/* -*- 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_H
+#define __GS_PLUGIN_LOADER_H
+
+#include <glib-object.h>
+
+#include "gs-app.h"
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_PLUGIN_LOADER (gs_plugin_loader_get_type ())
+#define GS_PLUGIN_LOADER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_PLUGIN_LOADER,
GsPluginLoader))
+#define GS_PLUGIN_LOADER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GS_TYPE_PLUGIN_LOADER,
GsPluginLoaderClass))
+#define GS_IS_PLUGIN_LOADER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_PLUGIN_LOADER))
+#define GS_IS_PLUGIN_LOADER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GS_TYPE_PLUGIN_LOADER))
+#define GS_PLUGIN_LOADER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GS_TYPE_PLUGIN_LOADER,
GsPluginLoaderClass))
+#define GS_PLUGIN_LOADER_ERROR (gs_plugin_loader_error_quark ())
+
+typedef struct GsPluginLoaderPrivate GsPluginLoaderPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GsPluginLoaderPrivate *priv;
+} GsPluginLoader;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GsPluginLoaderClass;
+
+typedef enum
+{
+ GS_PLUGIN_LOADER_ERROR_FAILED,
+ GS_PLUGIN_LOADER_ERROR_LAST
+} GsPluginLoaderError;
+
+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,
+ GError **error);
+GList *gs_plugin_loader_get_updates (GsPluginLoader *plugin_loader,
+ GError **error);
+GList *gs_plugin_loader_get_popular (GsPluginLoader *plugin_loader,
+ GError **error);
+GList *gs_plugin_loader_search (GsPluginLoader *plugin_loader,
+ const gchar *value,
+ GError **error);
+gboolean gs_plugin_loader_setup (GsPluginLoader *plugin_loader,
+ GError **error);
+gboolean gs_plugin_loader_set_enabled (GsPluginLoader *plugin_loader,
+ const gchar *plugin_name,
+ gboolean enabled);
+void gs_plugin_loader_set_location (GsPluginLoader *plugin_loader,
+ const gchar *location);
+gboolean gs_plugin_loader_app_install (GsPluginLoader *plugin_loader,
+ GsApp *app,
+ GError **error);
+gboolean gs_plugin_loader_app_update (GsPluginLoader *plugin_loader,
+ GsApp *app,
+ GError **error);
+gboolean gs_plugin_loader_app_remove (GsPluginLoader *plugin_loader,
+ GsApp *app,
+ GError **error);
+
+#endif /* __GS_PLUGIN_LOADER_H */
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
new file mode 100644
index 0000000..d98f964
--- /dev/null
+++ b/src/gs-plugin.h
@@ -0,0 +1,106 @@
+/* -*- 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.
+ */
+
+#ifndef __GS_PLUGIN_H
+#define __GS_PLUGIN_H
+
+#include <glib-object.h>
+#include <gmodule.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+#include "gs-app.h"
+
+G_BEGIN_DECLS
+
+typedef struct GsPluginPrivate GsPluginPrivate;
+
+typedef struct {
+ GModule *module;
+ gdouble priority; /* largest number gets run first */
+ gboolean enabled;
+ gchar *name;
+ GsPluginPrivate *priv;
+ GCancellable *cancellable;
+ guint pixbuf_size;
+} GsPlugin;
+
+typedef enum {
+ GS_PLUGIN_ERROR_FAILED,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ GS_PLUGIN_ERROR_LAST
+} GsPluginError;
+
+/* helpers */
+#define gs_plugin_add_app(l,a) (*l=g_list_prepend(*l,a))
+#define GS_PLUGIN_ERROR 1
+#define GS_PLUGIN_GET_PRIVATE(x) g_new0 (x,1)
+
+typedef const gchar *(*GsPluginGetNameFunc) (void);
+typedef gdouble (*GsPluginGetPriorityFunc) (GsPlugin *plugin);
+typedef void (*GsPluginFunc) (GsPlugin *plugin);
+typedef gboolean (*GsPluginSearchFunc) (GsPlugin *plugin,
+ const gchar *value,
+ GList **list,
+ GError **error);
+typedef gboolean (*GsPluginResultsFunc) (GsPlugin *plugin,
+ GList **list,
+ GError **error);
+typedef gboolean (*GsPluginActionFunc) (GsPlugin *plugin,
+ GsApp *app,
+ GError **error);
+typedef gboolean (*GsPluginRefineFunc) (GsPlugin *plugin,
+ GList *list,
+ GError **error);
+
+const gchar *gs_plugin_get_name (void);
+void gs_plugin_initialize (GsPlugin *plugin);
+void gs_plugin_destroy (GsPlugin *plugin);
+gboolean gs_plugin_add_search (GsPlugin *plugin,
+ const gchar *value,
+ GList *list,
+ GError **error);
+gdouble gs_plugin_get_priority (GsPlugin *plugin);
+gboolean gs_plugin_add_installed (GsPlugin *plugin,
+ GList **list,
+ GError **error);
+gboolean gs_plugin_add_updates (GsPlugin *plugin,
+ GList **list,
+ GError **error);
+gboolean gs_plugin_add_popular (GsPlugin *plugin,
+ GList **list,
+ GError **error);
+gboolean gs_plugin_refine (GsPlugin *plugin,
+ GList *list,
+ GError **error);
+gboolean gs_plugin_app_install (GsPlugin *plugin,
+ GsApp *app,
+ GError **error);
+gboolean gs_plugin_app_update (GsPlugin *plugin,
+ GsApp *app,
+ GError **error);
+gboolean gs_plugin_app_remove (GsPlugin *plugin,
+ GsApp *app,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __GS_PLUGIN_H */
diff --git a/src/gs-self-test.c b/src/gs-self-test.c
index e43873b..e984b1d 100644
--- a/src/gs-self-test.c
+++ b/src/gs-self-test.c
@@ -26,6 +26,7 @@
#include <gtk/gtk.h>
#include "gs-app.h"
+#include "gs-plugin-loader.h"
static void
gs_app_func (void)
@@ -40,6 +41,25 @@ gs_app_func (void)
g_object_unref (app);
}
+static void
+gs_plugin_loader_func (void)
+{
+ gboolean ret;
+ GError *error = NULL;
+ GsPluginLoader *loader;
+
+ loader = gs_plugin_loader_new ();
+ g_assert (GS_IS_PLUGIN_LOADER (loader));
+
+ /* load the plugins */
+ gs_plugin_loader_set_location (loader, "./plugins/.libs");
+ ret = gs_plugin_loader_setup (loader, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ g_object_unref (loader);
+}
+
int
main (int argc, char **argv)
{
@@ -52,6 +72,7 @@ main (int argc, char **argv)
/* tests go here */
g_test_add_func ("/gnome-software/app", gs_app_func);
+ g_test_add_func ("/gnome-software/plugin-loader", gs_plugin_loader_func);
return g_test_run ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]