[gnome-software] Allow plugins to emit status changed events



commit 7685ba52a8a18902470b5bdc0325252c0309379d
Author: Richard Hughes <richard hughsie com>
Date:   Thu Mar 7 22:01:33 2013 +0000

    Allow plugins to emit status changed events

 src/gs-main.c                      |   47 +++++++++++++++++++++++++++
 src/gs-plugin-loader.c             |   61 ++++++++++++++++++++++++++++++++++++
 src/gs-plugin-loader.h             |    4 ++
 src/gs-plugin.h                    |   22 +++++++++++--
 src/gs-self-test.c                 |   15 +++++++++
 src/plugins/gs-plugin-dummy.c      |    6 +++
 src/plugins/gs-plugin-packagekit.c |    6 +++
 7 files changed, 158 insertions(+), 3 deletions(-)
---
diff --git a/src/gs-main.c b/src/gs-main.c
index 573acf2..22550b3 100644
--- a/src/gs-main.c
+++ b/src/gs-main.c
@@ -233,6 +233,49 @@ gs_main_progress_cb (PkProgress *progress,
        }
 }
 
+/**
+ * gs_main_progress_cb:
+ **/
+static void
+gs_main_plugin_loader_status_changed_cb (GsPluginLoader *plugin_loader,
+                                        GsApp *app,
+                                        GsPluginStatus status,
+                                        GsMainPrivate  *priv)
+{
+       GtkWidget *widget;
+       const gchar *status_text = NULL;
+
+       /* translate */
+       if (status == GS_PLUGIN_STATUS_WAITING) {
+               /* TRANSLATORS: we're waiting for something to happen */
+               status_text = _("Waiting...");
+       }
+
+       /* update the label */
+       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "label_waiting"));
+       if (status_text != NULL) {
+               gtk_label_set_markup (GTK_LABEL (widget), status_text);
+               gtk_widget_show (widget);
+       } else {
+               gtk_widget_hide (widget);
+       }
+
+       /* show the waiting panel if the delay is significant */
+       if (status == GS_PLUGIN_STATUS_FINISHED) {
+               gs_main_set_overview_mode_ui (priv, priv->mode);
+               if (priv->waiting_tab_id > 0) {
+                       g_source_remove (priv->waiting_tab_id);
+                       priv->waiting_tab_id = 0;
+               }
+       } else {
+               if (priv->waiting_tab_id == 0) {
+                       priv->waiting_tab_id = g_timeout_add (50,
+                                                             gs_main_show_waiting_tab_cb,
+                                                             priv);
+               }
+       }
+}
+
 typedef struct {
        GsAppWidget     *app_widget;
        GsMainPrivate   *priv;
@@ -1292,6 +1335,10 @@ gs_main_startup_cb (GApplication *application, GsMainPrivate *priv)
        g_signal_connect (GTK_EDITABLE (widget), "changed",
                          G_CALLBACK (gs_main_filter_text_changed_cb), priv);
 
+       /* show the status on a different page */
+       g_signal_connect (priv->plugin_loader, "status-changed",
+                         G_CALLBACK (gs_main_plugin_loader_status_changed_cb), priv);
+
        /* show main UI */
        gtk_widget_show (main_window);
        gs_main_set_overview_mode (priv, GS_MAIN_MODE_INSTALLED);
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 46b1d52..de0ba40 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -32,10 +32,18 @@ struct GsPluginLoaderPrivate
 {
        GPtrArray               *plugins;
        gchar                   *location;
+       GsPluginStatus           status_last;
 };
 
 G_DEFINE_TYPE (GsPluginLoader, gs_plugin_loader, G_TYPE_OBJECT)
 
+enum {
+       SIGNAL_STATUS_CHANGED,
+       SIGNAL_LAST
+};
+
+static guint signals [SIGNAL_LAST] = { 0 };
+
 /**
  * gs_plugin_loader_error_quark:
  * Return value: Our personal error quark.
@@ -79,6 +87,7 @@ gs_plugin_loader_run_refine (GsPluginLoader *plugin_loader,
                ret = plugin_func (plugin, list, error);
                if (!ret)
                        goto out;
+               gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
                g_debug ("%s(%s) took %.0fms",
                         plugin->name,
                         function_name,
@@ -118,6 +127,7 @@ gs_plugin_loader_run_results (GsPluginLoader *plugin_loader,
                ret = plugin_func (plugin, &list, error);
                if (!ret)
                        goto out;
+               gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
                g_debug ("%s(%s) took %.0fms",
                         plugin->name,
                         function_name,
@@ -316,6 +326,7 @@ gs_plugin_loader_search (GsPluginLoader *plugin_loader, const gchar *value, GErr
                ret = plugin_func (plugin, value, &list, error);
                if (!ret)
                        goto out;
+               gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
                g_debug ("%s(%s) took %.0fms",
                         plugin->name,
                         function_name,
@@ -383,6 +394,7 @@ gs_plugin_loader_run_action (GsPluginLoader *plugin_loader,
                                goto out;
                        }
                }
+               gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
                g_debug ("%s(%s) took %.0fms",
                         plugin->name,
                         function_name,
@@ -456,6 +468,7 @@ gs_plugin_loader_run (GsPluginLoader *plugin_loader, const gchar *function_name)
                                       (gpointer *) &plugin_func);
                if (!ret)
                        continue;
+               gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
                g_debug ("run %s on %s", function_name,
                         g_module_name (plugin->module));
                plugin_func (plugin);
@@ -486,6 +499,44 @@ gs_plugin_loader_set_enabled (GsPluginLoader *plugin_loader,
 }
 
 /**
+ * gs_plugin_loader_status_to_string:
+ */
+static const gchar *
+gs_plugin_loader_status_to_string (GsPluginStatus status)
+{
+       if (status == GS_PLUGIN_STATUS_WAITING)
+               return "waiting";
+       if (status == GS_PLUGIN_STATUS_FINISHED)
+               return "finished";
+       return "unknown";
+}
+
+/**
+ * gs_plugin_loader_status_update_cb:
+ */
+static void
+gs_plugin_loader_status_update_cb (GsPlugin *plugin,
+                                  GsApp *app,
+                                  GsPluginStatus status,
+                                  gpointer user_data)
+{
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (user_data);
+
+       /* same as last time */
+       if (app == NULL && status == plugin_loader->priv->status_last)
+               return;
+
+       /* new, or an app, so emit */
+       g_debug ("emitting %s(%s)",
+                gs_plugin_loader_status_to_string (status),
+                app != NULL ? gs_app_get_id (app) : "<general>");
+       plugin_loader->priv->status_last = status;
+       g_signal_emit (plugin_loader,
+                      signals[SIGNAL_STATUS_CHANGED],
+                      0, app, status);
+}
+
+/**
  * gs_plugin_loader_open_plugin:
  */
 static GsPlugin *
@@ -533,6 +584,8 @@ gs_plugin_loader_open_plugin (GsPluginLoader *plugin_loader,
        plugin->priority = plugin_prio (plugin);
        plugin->name = g_strdup (plugin_name ());
        plugin->timer = g_timer_new ();
+       plugin->status_update_fn = gs_plugin_loader_status_update_cb;
+       plugin->status_update_user_data = plugin_loader;
        g_debug ("opened plugin %s: %s", filename, plugin->name);
 
        /* add to array */
@@ -652,6 +705,13 @@ gs_plugin_loader_class_init (GsPluginLoaderClass *klass)
 
        object_class->finalize = gs_plugin_loader_finalize;
 
+       signals [SIGNAL_STATUS_CHANGED] =
+               g_signal_new ("status-changed",
+                             G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (GsPluginLoaderClass, status_changed),
+                             NULL, NULL, g_cclosure_marshal_generic,
+                             G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
+
        g_type_class_add_private (klass, sizeof (GsPluginLoaderPrivate));
 }
 
@@ -663,6 +723,7 @@ 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);
+       plugin_loader->priv->status_last = GS_PLUGIN_STATUS_LAST;
 }
 
 /**
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
index 0e52bf2..c0d7d74 100644
--- a/src/gs-plugin-loader.h
+++ b/src/gs-plugin-loader.h
@@ -25,6 +25,7 @@
 #include <glib-object.h>
 
 #include "gs-app.h"
+#include "gs-plugin.h"
 
 G_BEGIN_DECLS
 
@@ -47,6 +48,9 @@ typedef struct
 typedef struct
 {
        GObjectClass             parent_class;
+       void                    (*status_changed)       (GsPluginLoader *plugin_loader,
+                                                        GsApp          *app,
+                                                        GsPluginStatus  status);
 } GsPluginLoaderClass;
 
 typedef enum
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index d2d1e5a..edbcc6e 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -31,9 +31,22 @@
 
 G_BEGIN_DECLS
 
-typedef struct GsPluginPrivate GsPluginPrivate;
+typedef struct GsPluginPrivate GsPluginPrivate;
+typedef struct GsPlugin        GsPlugin;
 
-typedef struct {
+typedef enum {
+       GS_PLUGIN_STATUS_UNKNOWN,
+       GS_PLUGIN_STATUS_WAITING,
+       GS_PLUGIN_STATUS_FINISHED,
+       GS_PLUGIN_STATUS_LAST
+} GsPluginStatus;
+
+typedef void (*GsPluginStatusUpdate)   (GsPlugin       *plugin,
+                                        GsApp          *app,
+                                        GsPluginStatus  status,
+                                        gpointer        user_data);
+
+struct GsPlugin {
        GModule                 *module;
        gdouble                  priority;      /* largest number gets run first */
        gboolean                 enabled;
@@ -42,7 +55,9 @@ typedef struct {
        GCancellable            *cancellable;
        guint                    pixbuf_size;
        GTimer                  *timer;
-} GsPlugin;
+       GsPluginStatusUpdate     status_update_fn;
+       gpointer                 status_update_user_data;
+};
 
 typedef enum {
        GS_PLUGIN_ERROR_FAILED,
@@ -52,6 +67,7 @@ typedef enum {
 
 /* helpers */
 #define        gs_plugin_add_app(l,a)                          (*l=g_list_prepend(*l,a))
+#define        gs_plugin_status_update(p,a,s)                  
(p->status_update_fn(p,a,s,p->status_update_user_data))
 #define        GS_PLUGIN_ERROR                                 1
 #define        GS_PLUGIN_GET_PRIVATE(x)                        g_new0 (x,1)
 
diff --git a/src/gs-self-test.c b/src/gs-self-test.c
index 5c68215..96958b0 100644
--- a/src/gs-self-test.c
+++ b/src/gs-self-test.c
@@ -41,6 +41,17 @@ gs_app_func (void)
        g_object_unref (app);
 }
 
+static guint _status_changed_cnt = 0;
+
+static void
+gs_plugin_loader_status_changed_cb (GsPluginLoader *plugin_loader,
+                                   GsApp *app,
+                                   GsPluginStatus status,
+                                   gpointer user_data)
+{
+       _status_changed_cnt++;
+}
+
 static void
 gs_plugin_loader_func (void)
 {
@@ -53,6 +64,8 @@ gs_plugin_loader_func (void)
 
        loader = gs_plugin_loader_new ();
        g_assert (GS_IS_PLUGIN_LOADER (loader));
+       g_signal_connect (loader, "status-changed",
+                         G_CALLBACK (gs_plugin_loader_status_changed_cb), NULL);
 
        /* load the plugins */
        gs_plugin_loader_set_location (loader, "./plugins/.libs");
@@ -91,9 +104,11 @@ gs_plugin_loader_func (void)
        g_list_free_full (list, (GDestroyNotify) g_object_unref);
 
        /* get updates */
+       g_assert_cmpint (_status_changed_cnt, ==, 0);
        list = gs_plugin_loader_get_updates (loader, &error);
        g_assert_no_error (error);
        g_assert (list != NULL);
+       g_assert_cmpint (_status_changed_cnt, ==, 1);
        g_assert_cmpint (g_list_length (list), ==, 2);
        app = g_list_nth_data (list, 0);
        g_assert_cmpstr (gs_app_get_id (app), ==, 
"os-update:gnome-boxes-libs;0.0.1;i386;updates-testing,libvirt-glib-devel;0.0.1;noarch;fedora");
diff --git a/src/plugins/gs-plugin-dummy.c b/src/plugins/gs-plugin-dummy.c
index 2f3436a..fea821b 100644
--- a/src/plugins/gs-plugin-dummy.c
+++ b/src/plugins/gs-plugin-dummy.c
@@ -82,6 +82,12 @@ gs_plugin_add_updates (GsPlugin *plugin, GList **list, GError **error)
 {
        GsApp *app;
 
+       /* update UI as this might take some time */
+       gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_WAITING);
+
+       /* spin */
+       g_usleep (2 * G_USEC_PER_SEC);
+
        /* add a normal application */
        app = gs_app_new ("gnome-boxes");
        gs_app_set_name (app, "Boxes");
diff --git a/src/plugins/gs-plugin-packagekit.c b/src/plugins/gs-plugin-packagekit.c
index b5f8068..70369a0 100644
--- a/src/plugins/gs-plugin-packagekit.c
+++ b/src/plugins/gs-plugin-packagekit.c
@@ -141,6 +141,9 @@ gs_plugin_add_installed (GsPlugin *plugin, GList **list, GError **error)
        PkBitfield filter;
        PkResults *results;
 
+       /* update UI as this might take some time */
+       gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_WAITING);
+
        /* do sync call */
        filter = pk_bitfield_from_enums (PK_FILTER_ENUM_INSTALLED,
                                         PK_FILTER_ENUM_NEWEST,
@@ -175,6 +178,9 @@ gs_plugin_add_updates (GsPlugin *plugin, GList **list, GError **error)
        PkBitfield filter;
        PkResults *results;
 
+       /* update UI as this might take some time */
+       gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_WAITING);
+
        /* do sync call */
        filter = pk_bitfield_from_enums (PK_FILTER_ENUM_ARCH, -1);
        results = pk_client_get_updates (PK_CLIENT(plugin->priv->task),


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