[gnome-software/gnome-3-16] Show installation progress when installing applications



commit 0e57cd7937b099b74a991c19759c4aece8690a03
Author: Richard Hughes <richard hughsie com>
Date:   Mon Jun 8 12:03:33 2015 +0100

    Show installation progress when installing applications

 src/gs-app-row.c                   |   29 +++++++++++++++++++++++
 src/gs-app.c                       |   44 ++++++++++++++++++++++++++++++++++++
 src/gs-app.h                       |    3 ++
 src/gs-page.c                      |   20 ++++++++++++++++
 src/gs-plugin-loader.c             |   29 +++++++++++++++++++++++
 src/gs-plugin-loader.h             |    3 ++
 src/gs-plugin.c                    |   36 +++++++++++++++++++++++++++++
 src/gs-plugin.h                    |    9 +++++++
 src/plugins/gs-plugin-packagekit.c |   44 +++++++++++++++++++++--------------
 9 files changed, 199 insertions(+), 18 deletions(-)
---
diff --git a/src/gs-app-row.c b/src/gs-app-row.c
index 8f74027..c024da4 100644
--- a/src/gs-app-row.c
+++ b/src/gs-app-row.c
@@ -44,6 +44,7 @@ struct _GsAppRowPrivate
        GtkWidget       *description_label;
        GtkWidget       *button_box;
        GtkWidget       *button;
+       GtkCssProvider  *button_css_provider;
        GtkWidget       *spinner;
        GtkWidget       *label;
        GtkWidget       *checkbox;
@@ -111,6 +112,20 @@ gs_app_row_get_description (GsAppRow *app_row)
 }
 
 /**
+ * gs_app_row_get_button_css:
+ **/
+static gchar *
+gs_app_row_get_button_css (gint percentage)
+{
+       if (percentage == 0)
+               return g_strdup ("* { background: @theme_bg_color; }");
+       else if (percentage == 100)
+               return g_strdup ("* { background: @theme_selected_bg_color; }");
+       else
+               return g_strdup_printf ("* { background: linear-gradient(to right, @theme_selected_bg_color 
%d%%, @theme_bg_color %d%%); }", percentage, percentage + 1);
+}
+
+/**
  * gs_app_row_refresh:
  **/
 void
@@ -119,10 +134,17 @@ gs_app_row_refresh (GsAppRow *app_row)
        GsAppRowPrivate *priv = app_row->priv;
        GtkStyleContext *context;
        GString *str = NULL;
+       _cleanup_free_ gchar *button_css = NULL;
 
        if (app_row->priv->app == NULL)
                return;
 
+       /* do a fill bar for the current progress */
+       if (gs_app_get_progress (priv->app) > 0) {
+               button_css = gs_app_row_get_button_css (gs_app_get_progress (priv->app));
+               gtk_css_provider_load_from_data (priv->button_css_provider, button_css, -1, NULL);
+       }
+
        /* join the lines*/
        str = gs_app_row_get_description (app_row);
        gs_string_replace (str, "\n", " ");
@@ -350,6 +372,9 @@ gs_app_row_set_app (GsAppRow *app_row, GsApp *app)
        g_signal_connect_object (app_row->priv->app, "notify::rating",
                                 G_CALLBACK (gs_app_row_notify_props_changed_cb),
                                 app_row, 0);
+       g_signal_connect_object (app_row->priv->app, "notify::progress",
+                                G_CALLBACK (gs_app_row_notify_props_changed_cb),
+                                app_row, 0);
        gs_app_row_refresh (app_row);
 }
 
@@ -474,6 +499,10 @@ gs_app_row_init (GsAppRow *app_row)
        gtk_widget_init_template (GTK_WIDGET (app_row));
 
        priv->colorful = TRUE;
+       priv->button_css_provider = gtk_css_provider_new ();
+       gtk_style_context_add_provider (gtk_widget_get_style_context (priv->button),
+                                       GTK_STYLE_PROVIDER (priv->button_css_provider),
+                                       GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 
        g_signal_connect (priv->button, "clicked",
                          G_CALLBACK (button_clicked), app_row);
diff --git a/src/gs-app.c b/src/gs-app.c
index 39c9eee..c61e493 100644
--- a/src/gs-app.c
+++ b/src/gs-app.c
@@ -87,6 +87,7 @@ struct GsAppPrivate
        GsAppKind                kind;
        AsIdKind                 id_kind;
        AsAppState               state;
+       guint                    progress;
        GHashTable              *metadata;
        GdkPixbuf               *pixbuf;
        GdkPixbuf               *featured_pixbuf;
@@ -110,6 +111,7 @@ enum {
        PROP_RATING,
        PROP_KIND,
        PROP_STATE,
+       PROP_PROGRESS,
        PROP_INSTALL_DATE,
        PROP_LAST
 };
@@ -180,6 +182,8 @@ gs_app_to_string (GsApp *app)
        }
        g_string_append_printf (str, "\tstate:\t%s\n",
                                as_app_state_to_string (priv->state));
+       if (priv->progress > 0)
+               g_string_append_printf (str, "\tprogress:\t%i%%\n", priv->progress);
        if (priv->id != NULL)
                g_string_append_printf (str, "\tid:\t%s\n", priv->id);
        if ((priv->kudos & GS_APP_KUDO_MY_LANGUAGE) > 0)
@@ -377,6 +381,16 @@ gs_app_get_state (GsApp *app)
 }
 
 /**
+ * gs_app_get_progress:
+ */
+guint
+gs_app_get_progress (GsApp *app)
+{
+       g_return_val_if_fail (GS_IS_APP (app), 0);
+       return app->priv->progress;
+}
+
+/**
  * gs_app_set_state_internal:
  */
 static gboolean
@@ -477,6 +491,22 @@ gs_app_set_state_internal (GsApp *app, AsAppState state)
 }
 
 /**
+ * gs_app_set_progress:
+ *
+ * This sets the progress completion of the application.
+ */
+void
+gs_app_set_progress (GsApp *app, guint percentage)
+{
+       GsAppPrivate *priv = app->priv;
+       g_return_if_fail (GS_IS_APP (app));
+       if (priv->progress == percentage)
+               return;
+       priv->progress = percentage;
+       gs_app_queue_notify (app, "progress");
+}
+
+/**
  * gs_app_set_state:
  *
  * This sets the state of the application. The following state diagram explains
@@ -2009,6 +2039,9 @@ gs_app_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *
        case PROP_STATE:
                g_value_set_uint (value, priv->state);
                break;
+       case PROP_PROGRESS:
+               g_value_set_uint (value, priv->progress);
+               break;
        case PROP_INSTALL_DATE:
                g_value_set_uint64 (value, priv->install_date);
                break;
@@ -2025,6 +2058,7 @@ static void
 gs_app_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
 {
        GsApp *app = GS_APP (object);
+       GsAppPrivate *priv = app->priv;
 
        switch (prop_id) {
        case PROP_ID:
@@ -2057,6 +2091,9 @@ gs_app_set_property (GObject *object, guint prop_id, const GValue *value, GParam
        case PROP_STATE:
                gs_app_set_state_internal (app, g_value_get_uint (value));
                break;
+       case PROP_PROGRESS:
+               priv->progress = g_value_get_uint (value);
+               break;
        case PROP_INSTALL_DATE:
                gs_app_set_install_date (app, g_value_get_uint64 (value));
                break;
@@ -2144,6 +2181,13 @@ gs_app_class_init (GsAppClass *klass)
                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
        g_object_class_install_property (object_class, PROP_STATE, pspec);
 
+       /**
+        * GsApp:progress:
+        */
+       pspec = g_param_spec_uint ("progress", NULL, NULL, 0, 100, 0,
+                                  G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+       g_object_class_install_property (object_class, PROP_PROGRESS, pspec);
+
        pspec = g_param_spec_uint64 ("install-date", NULL, NULL,
                                     0, G_MAXUINT64, 0,
                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
diff --git a/src/gs-app.h b/src/gs-app.h
index d0941b4..12d6bce 100644
--- a/src/gs-app.h
+++ b/src/gs-app.h
@@ -130,6 +130,9 @@ void                 gs_app_set_id_kind             (GsApp          *app,
 AsAppState      gs_app_get_state               (GsApp          *app);
 void            gs_app_set_state               (GsApp          *app,
                                                 AsAppState      state);
+guint           gs_app_get_progress            (GsApp          *app);
+void            gs_app_set_progress            (GsApp          *app,
+                                                guint           percentage);
 const gchar    *gs_app_get_name                (GsApp          *app);
 void            gs_app_set_name                (GsApp          *app,
                                                 GsAppQuality    quality,
diff --git a/src/gs-page.c b/src/gs-page.c
index 0a1917f..8f2529a 100644
--- a/src/gs-page.c
+++ b/src/gs-page.c
@@ -43,6 +43,7 @@ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GsPage, gs_page, GTK_TYPE_BIN)
 typedef struct {
        GsApp           *app;
        GsPage          *page;
+       guint            progress_id;
 } InstallRemoveData;
 
 static void
@@ -67,6 +68,9 @@ gs_page_app_installed_cb (GObject *source,
        gboolean ret;
        _cleanup_error_free_ GError *error = NULL;
 
+       /* no longer update this application */
+       g_signal_handler_disconnect (plugin_loader, data->progress_id);
+
        ret = gs_plugin_loader_app_action_finish (plugin_loader,
                                                  res,
                                                  &error);
@@ -121,6 +125,18 @@ gs_page_app_removed_cb (GObject *source,
        install_remove_data_free (data);
 }
 
+static void
+gs_page_app_progress_changed_cb (GsPluginLoader *loader,
+                                GsApp *app,
+                                guint percentage,
+                                InstallRemoveData *data)
+{
+       /* some plugins can't map the progress to a specific package */
+       if (app == NULL)
+               app = data->app;
+       gs_app_set_progress (app, percentage);
+}
+
 void
 gs_page_install_app (GsPage *page, GsApp *app)
 {
@@ -138,6 +154,10 @@ gs_page_install_app (GsPage *page, GsApp *app)
        data = g_slice_new0 (InstallRemoveData);
        data->app = g_object_ref (app);
        data->page = g_object_ref (page);
+       data->progress_id =
+               g_signal_connect (priv->plugin_loader, "progress-changed",
+                                 G_CALLBACK (gs_page_app_progress_changed_cb),
+                                 data);
        gs_plugin_loader_app_action_async (priv->plugin_loader,
                                           app,
                                           GS_PLUGIN_LOADER_ACTION_INSTALL,
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 191dd53..8d7bbd2 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -59,6 +59,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (GsPluginLoader, gs_plugin_loader, G_TYPE_OBJECT)
 
 enum {
        SIGNAL_STATUS_CHANGED,
+       SIGNAL_PROGRESS_CHANGED,
        SIGNAL_PENDING_APPS_CHANGED,
        SIGNAL_UPDATES_CHANGED,
        SIGNAL_LAST
@@ -2878,6 +2879,26 @@ gs_plugin_loader_status_update_cb (GsPlugin *plugin,
 }
 
 /**
+ * gs_plugin_loader_progress_update_cb:
+ */
+static void
+gs_plugin_loader_progress_update_cb (GsPlugin *plugin,
+                                    GsApp *app,
+                                    guint percentage,
+                                    gpointer user_data)
+{
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (user_data);
+
+       /* new, or an app, so emit */
+       g_debug ("emitting %i%%(%s)",
+                percentage,
+                app != NULL ? gs_app_get_id (app) : "<general>");
+       g_signal_emit (plugin_loader,
+                      signals[SIGNAL_PROGRESS_CHANGED],
+                      0, app, percentage);
+}
+
+/**
  * gs_plugin_loader_updates_changed_delay_cb:
  */
 static gboolean
@@ -2968,6 +2989,8 @@ gs_plugin_loader_open_plugin (GsPluginLoader *plugin_loader,
        plugin->name = g_strdup (plugin_name ());
        plugin->status_update_fn = gs_plugin_loader_status_update_cb;
        plugin->status_update_user_data = plugin_loader;
+       plugin->progress_update_fn = gs_plugin_loader_progress_update_cb;
+       plugin->progress_update_user_data = plugin_loader;
        plugin->updates_changed_fn = gs_plugin_loader_updates_changed_cb;
        plugin->updates_changed_user_data = plugin_loader;
        plugin->profile = g_object_ref (plugin_loader->priv->profile);
@@ -3207,6 +3230,12 @@ gs_plugin_loader_class_init (GsPluginLoaderClass *klass)
                              G_STRUCT_OFFSET (GsPluginLoaderClass, status_changed),
                              NULL, NULL, g_cclosure_marshal_generic,
                              G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
+       signals [SIGNAL_PROGRESS_CHANGED] =
+               g_signal_new ("progress-changed",
+                             G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (GsPluginLoaderClass, progress_changed),
+                             NULL, NULL, g_cclosure_marshal_generic,
+                             G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
        signals [SIGNAL_PENDING_APPS_CHANGED] =
                g_signal_new ("pending-apps-changed",
                              G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
index 1146e81..e7bc8c5 100644
--- a/src/gs-plugin-loader.h
+++ b/src/gs-plugin-loader.h
@@ -52,6 +52,9 @@ typedef struct
        void                    (*status_changed)       (GsPluginLoader *plugin_loader,
                                                         GsApp          *app,
                                                         GsPluginStatus  status);
+       void                    (*progress_changed)     (GsPluginLoader *plugin_loader,
+                                                        GsApp          *app,
+                                                        guint           percentage);
        void                    (*pending_apps_changed) (GsPluginLoader *plugin_loader);
        void                    (*updates_changed)      (GsPluginLoader *plugin_loader);
 } GsPluginLoaderClass;
diff --git a/src/gs-plugin.c b/src/gs-plugin.c
index 2448657..5155401 100644
--- a/src/gs-plugin.c
+++ b/src/gs-plugin.c
@@ -232,6 +232,7 @@ typedef struct {
        GsPlugin        *plugin;
        GsApp           *app;
        GsPluginStatus   status;
+       guint            percentage;
 } GsPluginStatusHelper;
 
 /**
@@ -270,6 +271,41 @@ gs_plugin_status_update (GsPlugin *plugin, GsApp *app, GsPluginStatus status)
 }
 
 /**
+ * gs_plugin_progress_update_cb:
+ **/
+static gboolean
+gs_plugin_progress_update_cb (gpointer user_data)
+{
+       GsPluginStatusHelper *helper = (GsPluginStatusHelper *) user_data;
+
+       /* call back into the loader */
+       helper->plugin->progress_update_fn (helper->plugin,
+                                           helper->app,
+                                           helper->percentage,
+                                           helper->plugin->progress_update_user_data);
+       if (helper->app != NULL)
+               g_object_unref (helper->app);
+       g_slice_free (GsPluginStatusHelper, helper);
+       return FALSE;
+}
+
+/**
+ * gs_plugin_progress_update:
+ **/
+void
+gs_plugin_progress_update (GsPlugin *plugin, GsApp *app, guint percentage)
+{
+       GsPluginStatusHelper *helper;
+
+       helper = g_slice_new0 (GsPluginStatusHelper);
+       helper->plugin = plugin;
+       helper->percentage = percentage;
+       if (app != NULL)
+               helper->app = g_object_ref (app);
+       g_idle_add (gs_plugin_progress_update_cb, helper);
+}
+
+/**
  * gs_plugin_updates_changed_cb:
  **/
 static gboolean
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index 64ef6ef..657920a 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -52,6 +52,10 @@ typedef void (*GsPluginStatusUpdate) (GsPlugin       *plugin,
                                         GsApp          *app,
                                         GsPluginStatus  status,
                                         gpointer        user_data);
+typedef void (*GsPluginProgressUpdate) (GsPlugin       *plugin,
+                                        GsApp          *app,
+                                        guint           percentage,
+                                        gpointer        user_data);
 typedef void (*GsPluginUpdatesChanged) (GsPlugin       *plugin,
                                         gpointer        user_data);
 
@@ -70,6 +74,8 @@ struct GsPlugin {
        gint                     scale;
        GsPluginStatusUpdate     status_update_fn;
        gpointer                 status_update_user_data;
+       GsPluginProgressUpdate   progress_update_fn;
+       gpointer                 progress_update_user_data;
        GsPluginUpdatesChanged   updates_changed_fn;
        gpointer                 updates_changed_user_data;
        GsProfile               *profile;
@@ -175,6 +181,9 @@ void                 gs_plugin_list_randomize               (GList          **list);
 void            gs_plugin_status_update                (GsPlugin       *plugin,
                                                         GsApp          *app,
                                                         GsPluginStatus  status);
+void            gs_plugin_progress_update              (GsPlugin       *plugin,
+                                                        GsApp          *app,
+                                                        guint           percentage);
 void            gs_plugin_updates_changed              (GsPlugin       *plugin);
 const gchar    *gs_plugin_status_to_string             (GsPluginStatus  status);
 gboolean        gs_plugin_add_search                   (GsPlugin       *plugin,
diff --git a/src/plugins/gs-plugin-packagekit.c b/src/plugins/gs-plugin-packagekit.c
index fe21ba3..d3cc649 100644
--- a/src/plugins/gs-plugin-packagekit.c
+++ b/src/plugins/gs-plugin-packagekit.c
@@ -74,28 +74,36 @@ gs_plugin_packagekit_progress_cb (PkProgress *progress,
                                  PkProgressType type,
                                  gpointer user_data)
 {
-       GsPluginStatus plugin_status;
-       PkStatusEnum status;
        GsPlugin *plugin = GS_PLUGIN (user_data);
 
-       if (type != PK_PROGRESS_TYPE_STATUS)
-               return;
-       g_object_get (progress,
-                     "status", &status,
-                     NULL);
-
-       /* profile */
-       if (status == PK_STATUS_ENUM_SETUP) {
-               gs_profile_start (plugin->profile,
-                                 "packagekit-refine::transaction");
-       } else if (status == PK_STATUS_ENUM_FINISHED) {
-               gs_profile_stop (plugin->profile,
-                                "packagekit-refine::transaction");
-       }
+       if (type == PK_PROGRESS_TYPE_STATUS) {
+               GsPluginStatus plugin_status;
+               PkStatusEnum status;
+               g_object_get (progress,
+                             "status", &status,
+                             NULL);
+
+               /* profile */
+               if (status == PK_STATUS_ENUM_SETUP) {
+                       gs_profile_start (plugin->profile,
+                                         "packagekit-refine::transaction");
+               } else if (status == PK_STATUS_ENUM_FINISHED) {
+                       gs_profile_stop (plugin->profile,
+                                        "packagekit-refine::transaction");
+               }
 
-       plugin_status = packagekit_status_enum_to_plugin_status (status);
-       if (plugin_status != GS_PLUGIN_STATUS_UNKNOWN)
-               gs_plugin_status_update (plugin, NULL, plugin_status);
+               plugin_status = packagekit_status_enum_to_plugin_status (status);
+               if (plugin_status != GS_PLUGIN_STATUS_UNKNOWN)
+                       gs_plugin_status_update (plugin, NULL, plugin_status);
+
+       } else if (type == PK_PROGRESS_TYPE_PERCENTAGE) {
+               gint percentage;
+               g_object_get (progress,
+                             "percentage", &percentage,
+                             NULL);
+               if (percentage > 0 && percentage <= 100)
+                       gs_plugin_progress_update (plugin, NULL, percentage);
+       }
 }
 
 /**


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