[gnome-software] Allow plugins to say that installation can/cannot be cancelled
- From: Iain Lane <iainl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Allow plugins to say that installation can/cannot be cancelled
- Date: Wed, 16 Aug 2017 15:40:23 +0000 (UTC)
commit 82bd6c445727af4e1fd83dad16dadafbd71bed9d
Author: Iain Lane <iain orangesquash org uk>
Date: Tue Aug 8 14:58:56 2017 +0100
Allow plugins to say that installation can/cannot be cancelled
For example - it's not safe to cancel a distro package installation
after it has gone past a certain point, or else you'll end up with a
broken system.
Also implement this for the PackageKit plugin by propagating the
allow-cancel property up.
https://bugzilla.gnome.org/show_bug.cgi?id=785515
lib/gs-app.c | 57 +++++++++++++++++++++++++++++
lib/gs-app.h | 3 ++
plugins/packagekit/gs-plugin-packagekit.c | 10 +++++
src/gs-app-row.c | 6 +++-
src/gs-details-page.c | 37 ++++++++++++++++++-
5 files changed, 111 insertions(+), 2 deletions(-)
---
diff --git a/lib/gs-app.c b/lib/gs-app.c
index d63654a..5ae25fa 100644
--- a/lib/gs-app.c
+++ b/lib/gs-app.c
@@ -107,6 +107,7 @@ typedef struct
AsAppScope scope;
AsBundleKind bundle_kind;
guint progress;
+ gboolean allow_cancel;
GHashTable *metadata;
GPtrArray *addons; /* of GsApp */
GHashTable *addons_hash; /* of "id" */
@@ -136,6 +137,7 @@ enum {
PROP_KIND,
PROP_STATE,
PROP_PROGRESS,
+ PROP_CAN_CANCEL_INSTALLATION,
PROP_INSTALL_DATE,
PROP_QUIRK,
PROP_LAST
@@ -792,6 +794,24 @@ gs_app_get_progress (GsApp *app)
}
/**
+ * gs_app_get_allow_cancel:
+ * @app: a #GsApp
+ *
+ * Gets whether the app's installation or upgrade can be cancelled.
+ *
+ * Returns: TRUE if cancellation is possible, FALSE otherwise.
+ *
+ * Since: 3.26
+ **/
+gboolean
+gs_app_get_allow_cancel (GsApp *app)
+{
+ GsAppPrivate *priv = gs_app_get_instance_private (app);
+ g_return_val_if_fail (GS_IS_APP (app), FALSE);
+ return priv->allow_cancel;
+}
+
+/**
* gs_app_set_state_recover:
* @app: a #GsApp
*
@@ -995,6 +1015,29 @@ gs_app_set_progress (GsApp *app, guint percentage)
}
/**
+ * gs_app_set_allow_cancel:
+ * @app: a #GsApp
+ * @boolean: if the installation or upgrade can be cancelled or not
+ *
+ * This sets a flag indicating whether the operation can be cancelled or not.
+ * This is used by the UI to set the "Cancel" button insensitive as
+ * appropriate.
+ *
+ * Since: 3.26
+ **/
+void
+gs_app_set_allow_cancel (GsApp *app, gboolean allow_cancel)
+{
+ GsAppPrivate *priv = gs_app_get_instance_private (app);
+ g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->mutex);
+ g_return_if_fail (GS_IS_APP (app));
+ if (priv->allow_cancel == allow_cancel)
+ return;
+ priv->allow_cancel = allow_cancel;
+ gs_app_queue_notify (app, "allow-cancel");
+}
+
+/**
* gs_app_set_state:
* @app: a #GsApp
* @state: a #AsAppState, e.g. AS_APP_STATE_UPDATABLE_LIVE
@@ -3727,6 +3770,9 @@ gs_app_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *
case PROP_PROGRESS:
g_value_set_uint (value, priv->progress);
break;
+ case PROP_CAN_CANCEL_INSTALLATION:
+ g_value_set_boolean (value, priv->allow_cancel);
+ break;
case PROP_INSTALL_DATE:
g_value_set_uint64 (value, priv->install_date);
break;
@@ -3779,6 +3825,9 @@ gs_app_set_property (GObject *object, guint prop_id, const GValue *value, GParam
case PROP_PROGRESS:
priv->progress = g_value_get_uint (value);
break;
+ case PROP_CAN_CANCEL_INSTALLATION:
+ priv->allow_cancel = g_value_get_boolean (value);
+ break;
case PROP_INSTALL_DATE:
gs_app_set_install_date (app, g_value_get_uint64 (value));
break;
@@ -3945,6 +3994,13 @@ gs_app_class_init (GsAppClass *klass)
g_object_class_install_property (object_class, PROP_PROGRESS, pspec);
/**
+ * GsApp:allow-cancel:
+ */
+ pspec = g_param_spec_boolean ("allow-cancel", NULL, NULL, TRUE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+ g_object_class_install_property (object_class, PROP_CAN_CANCEL_INSTALLATION, pspec);
+
+ /**
* GsApp:install-date:
*/
pspec = g_param_spec_uint64 ("install-date", NULL, NULL,
@@ -3993,6 +4049,7 @@ gs_app_init (GsApp *app)
g_str_equal,
g_free,
g_free);
+ priv->allow_cancel = TRUE;
g_mutex_init (&priv->mutex);
}
diff --git a/lib/gs-app.h b/lib/gs-app.h
index a217be0..508d6a2 100644
--- a/lib/gs-app.h
+++ b/lib/gs-app.h
@@ -135,6 +135,9 @@ void gs_app_set_state_recover (GsApp *app);
guint gs_app_get_progress (GsApp *app);
void gs_app_set_progress (GsApp *app,
guint percentage);
+gboolean gs_app_get_allow_cancel (GsApp *app);
+void gs_app_set_allow_cancel (GsApp *app,
+ gboolean can_cancel);
const gchar *gs_app_get_unique_id (GsApp *app);
const gchar *gs_app_get_branch (GsApp *app);
void gs_app_set_branch (GsApp *app,
diff --git a/plugins/packagekit/gs-plugin-packagekit.c b/plugins/packagekit/gs-plugin-packagekit.c
index f91112a..d1e655d 100644
--- a/plugins/packagekit/gs-plugin-packagekit.c
+++ b/plugins/packagekit/gs-plugin-packagekit.c
@@ -94,6 +94,12 @@ gs_plugin_packagekit_progress_cb (PkProgress *progress,
if (data->app != NULL && percentage >= 0 && percentage <= 100)
gs_app_set_progress (data->app, (guint) percentage);
}
+
+ /* Only go from TRUE to FALSE - it doesn't make sense for a package
+ * install to become uncancellable later on */
+ if (gs_app_get_allow_cancel (data->app))
+ gs_app_set_allow_cancel (data->app,
+ pk_progress_get_allow_cancel (progress));
}
static gboolean
@@ -312,6 +318,10 @@ gs_plugin_app_install (GsPlugin *plugin,
/* state is known */
gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+ /* if we remove the app again later, we should be able to
+ * cancel the installation if we'd never installed it */
+ gs_app_set_allow_cancel (app, TRUE);
+
/* no longer valid */
gs_app_clear_source_ids (app);
return TRUE;
diff --git a/src/gs-app-row.c b/src/gs-app-row.c
index 8fa5808..85e8dc0 100644
--- a/src/gs-app-row.c
+++ b/src/gs-app-row.c
@@ -276,7 +276,8 @@ gs_app_row_refresh_button (GsAppRow *app_row, gboolean missing_search_result)
gtk_widget_set_sensitive (priv->button, FALSE);
break;
default:
- gtk_widget_set_sensitive (priv->button, TRUE);
+ gtk_widget_set_sensitive (priv->button,
+ gs_app_get_allow_cancel (priv->app));
break;
}
}
@@ -570,6 +571,9 @@ gs_app_row_set_app (GsAppRow *app_row, GsApp *app)
g_signal_connect_object (priv->app, "notify::progress",
G_CALLBACK (gs_app_row_notify_props_changed_cb),
app_row, 0);
+ g_signal_connect_object (priv->app, "notify::allow-cancel",
+ G_CALLBACK (gs_app_row_notify_props_changed_cb),
+ app_row, 0);
gs_app_row_refresh (app_row);
}
diff --git a/src/gs-details-page.c b/src/gs-details-page.c
index 76a04cb..25a26e5 100644
--- a/src/gs-details-page.c
+++ b/src/gs-details-page.c
@@ -412,8 +412,14 @@ gs_details_page_refresh_progress (GsDetailsPage *self)
switch (state) {
case AS_APP_STATE_INSTALLING:
gtk_widget_set_visible (self->button_cancel, TRUE);
+ /* If the app is installing, the user can only cancel it if
+ * 1) They haven't already, and
+ * 2) the plugin hasn't said that they can't, for example if a
+ * package manager has already gone 'too far'
+ */
gtk_widget_set_sensitive (self->button_cancel,
- !g_cancellable_is_cancelled (self->cancellable));
+ !g_cancellable_is_cancelled (self->cancellable) &&
+ gs_app_get_allow_cancel (self->app));
break;
default:
gtk_widget_set_visible (self->button_cancel, FALSE);
@@ -499,6 +505,25 @@ gs_details_page_progress_changed_cb (GsApp *app,
}
static gboolean
+gs_details_page_allow_cancel_changed_idle (gpointer user_data)
+{
+ GsDetailsPage *self = GS_DETAILS_PAGE (user_data);
+ gtk_widget_set_sensitive (self->button_cancel,
+ gs_app_get_allow_cancel (self->app));
+ g_object_unref (self);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+gs_details_page_allow_cancel_changed_cb (GsApp *app,
+ GParamSpec *pspec,
+ GsDetailsPage *self)
+{
+ g_idle_add (gs_details_page_allow_cancel_changed_idle,
+ g_object_ref (self));
+}
+
+static gboolean
gs_details_page_switch_to_idle (gpointer user_data)
{
GsDetailsPage *self = GS_DETAILS_PAGE (user_data);
@@ -1492,6 +1517,8 @@ set_app (GsDetailsPage *self, GsApp *app)
if (self->app != NULL) {
g_signal_handlers_disconnect_by_func (self->app, gs_details_page_notify_state_changed_cb,
self);
g_signal_handlers_disconnect_by_func (self->app, gs_details_page_progress_changed_cb, self);
+ g_signal_handlers_disconnect_by_func (self->app, gs_details_page_allow_cancel_changed_cb,
+ self);
}
/* save app */
@@ -1514,6 +1541,9 @@ set_app (GsDetailsPage *self, GsApp *app)
g_signal_connect_object (self->app, "notify::progress",
G_CALLBACK (gs_details_page_progress_changed_cb),
self, 0);
+ g_signal_connect_object (self->app, "notify::allow-cancel",
+ G_CALLBACK (gs_details_page_allow_cancel_changed_cb),
+ self, 0);
/* print what we've got */
tmp = gs_app_to_string (self->app);
@@ -1699,6 +1729,8 @@ gs_details_page_set_app (GsDetailsPage *self, GsApp *app)
g_signal_handlers_disconnect_by_func (self->settings,
settings_changed_cb,
self);
+ g_signal_handlers_disconnect_by_func (self->app, gs_details_page_allow_cancel_changed_cb,
+ self);
}
/* save app */
g_set_object (&self->app, app);
@@ -1718,6 +1750,9 @@ gs_details_page_set_app (GsDetailsPage *self, GsApp *app)
g_signal_connect_object (self->app, "notify::progress",
G_CALLBACK (gs_details_page_progress_changed_cb),
self, 0);
+ g_signal_connect_object (self->app, "notify::allow-cancel",
+ G_CALLBACK (gs_details_page_allow_cancel_changed_cb),
+ self, 0);
gs_details_page_load (self);
/* change widgets */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]