[gnome-software] Show installation progress when installing applications
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Show installation progress when installing applications
- Date: Mon, 8 Jun 2015 11:03:55 +0000 (UTC)
commit da59a0c147a3abe58f323a1f8436c863827ec226
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 | 46 +++++++++++++++++++++---------------
9 files changed, 200 insertions(+), 19 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 8dd41a5..c5d57a8 100644
--- a/src/gs-app.c
+++ b/src/gs-app.c
@@ -85,6 +85,7 @@ struct GsAppPrivate
GsAppKind kind;
AsIdKind id_kind;
AsAppState state;
+ guint progress;
GHashTable *metadata;
GdkPixbuf *pixbuf;
GdkPixbuf *featured_pixbuf;
@@ -108,6 +109,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 (app)->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 (app);
+ 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
@@ -2030,6 +2060,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;
@@ -2046,6 +2079,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 (app);
switch (prop_id) {
case PROP_ID:
@@ -2078,6 +2112,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;
@@ -2226,6 +2263,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 56761bb..927e818 100644
--- a/src/gs-app.h
+++ b/src/gs-app.h
@@ -129,6 +129,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 06eab22..6ae6b83 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -57,6 +57,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
@@ -2739,6 +2740,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
@@ -2829,6 +2850,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);
@@ -3123,6 +3146,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 de24cda..3744e49 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 97dfe56..c0bba4d 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;
@@ -173,6 +179,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 e0f0e95..95da83f 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]