diff pui-backend.c @ 10:adba37525ee5

Notify about required session or system restarts Follow all PackageKit transactions and indicate when a session or system restart is required. Generate enum types with glib-mkenums.
author Guido Berhoerster <guido+pui@berhoerster.name>
date Fri, 06 Jul 2018 14:12:46 +0200
parents 2477a6151087
children 9905d4ae351c
line wrap: on
line diff
--- a/pui-backend.c	Wed Jul 04 17:08:47 2018 +0200
+++ b/pui-backend.c	Fri Jul 06 14:12:46 2018 +0200
@@ -34,6 +34,7 @@
 #include "pui-common.h"
 #include "pui-backend.h"
 #include "pui-get-updates.h"
+#include "pui-types.h"
 
 #define	LOW_BATTERY_THRESHOLD	10.0
 
@@ -41,6 +42,8 @@
 	GObject		parent_instance;
 	PkControl	*pk_control;
 	GCancellable	*cancellable;
+	PkClient	*pk_client;
+	PkTransactionList *transaction_list;
 	UpClient	*up_client;
 	UpDevice	*up_device;
 	gchar		*proxy_http;
@@ -58,6 +61,7 @@
 	gboolean	use_mobile_connection;
 	guint		important_updates;
 	guint		normal_updates;
+	PuiRestart	restart_type;
 };
 
 static void	pui_backend_async_initable_iface_init(gpointer, gpointer);
@@ -76,6 +80,7 @@
     PROP_0,
     PROP_IMPORTANT_UPDATES,
     PROP_NORMAL_UPDATES,
+    PROP_RESTART_TYPE,
     PROP_REFRESH_INTERVAL,
     PROP_USE_MOBILE_CONNECTION,
     PROP_LAST
@@ -276,6 +281,9 @@
 	case PROP_NORMAL_UPDATES:
 		g_value_set_uint(value, self->normal_updates);
 		break;
+	case PROP_RESTART_TYPE:
+		g_value_set_enum(value, self->restart_type);
+		break;
 	case PROP_REFRESH_INTERVAL:
 		g_value_set_uint(value, self->refresh_interval);
 		break;
@@ -298,6 +306,14 @@
 		self->periodic_check_id = 0;
 	}
 
+	if (self->transaction_list != NULL) {
+		g_clear_object(&self->transaction_list);
+	}
+
+	if (self->pk_client != NULL) {
+		g_clear_object(&self->pk_client);
+	}
+
 	if (self->cancellable != NULL) {
 		g_cancellable_cancel(self->cancellable);
 		g_clear_object(&self->cancellable);
@@ -353,6 +369,11 @@
 	    "Number of available normal updates", 0, G_MAXUINT, 0,
 	    G_PARAM_READABLE);
 
+	properties[PROP_RESTART_TYPE] =
+	    g_param_spec_enum("restart-type", "Type of restart required",
+	    "The Type of restart required", PUI_TYPE_RESTART, PUI_RESTART_NONE,
+	    G_PARAM_READABLE);
+
 	properties[PROP_REFRESH_INTERVAL] =
 	    g_param_spec_uint("refresh-interval", "Refresh interval",
 	    "Interval in seconds for refreshing the package cache", 0,
@@ -382,6 +403,8 @@
 {
 	self->pk_control = pk_control_new();
 
+	self->pk_client = pk_client_new();
+
 	self->inhibited = TRUE;
 
 	self->up_client = up_client_new();
@@ -470,6 +493,8 @@
 {
 	PuiBackend	*self = user_data;
 
+	g_debug("number of updates changed");
+
 	/*
 	 * schedule a check after a short delay so that a rapid succession of
 	 * signals is coalesced
@@ -489,11 +514,85 @@
 {
 	PuiBackend	*self = user_data;
 
+	/*
+	 * do not restart package-update-indicator if a session or system
+	 * restart is required since that iformation would be lost across the
+	 * restart, rather keep running and risk errors when interacting with
+	 * a newer version of the PackageKit daemon
+	 */
+	if (self->restart_type > PUI_RESTART_NONE) {
+		return;
+	}
+
 	g_debug("emitting signal restart-required");
 	g_signal_emit(self, signals[RESTART_REQUIRED], 0);
 }
 
 static void
+on_transaction_adopt_finish(GObject *source_object, GAsyncResult *result,
+    gpointer user_data)
+{
+	PuiBackend	*self = user_data;
+	PkClient	*pk_client = PK_CLIENT(source_object);
+	PkResults	*results;
+	GError		*error = NULL;
+	PkRestartEnum	restart;
+
+	results = pk_client_generic_finish(pk_client, result, &error);
+	if (results == NULL) {
+		g_warning("failed to get transaction results: %s",
+		    error->message);
+		g_error_free(error);
+		goto out;
+	}
+
+	/* check if transaction requires a restart */
+	restart = pk_results_get_require_restart_worst(results);
+	switch (restart) {
+	case PK_RESTART_ENUM_SESSION:		/* FALLTHROUGH */
+	case PK_RESTART_ENUM_SECURITY_SESSION:
+		if (self->restart_type < PUI_RESTART_SESSION) {
+			self->restart_type = PUI_RESTART_SESSION;
+			g_object_notify_by_pspec(G_OBJECT(self),
+			    properties[PROP_RESTART_TYPE]);
+			g_signal_emit(self, signals[STATE_CHANGED], 0);
+		}
+		break;
+	case PK_RESTART_ENUM_SYSTEM:		/* FALLTHROUGH */
+	case PK_RESTART_ENUM_SECURITY_SYSTEM:
+		if (self->restart_type < PUI_RESTART_SYSTEM) {
+			self->restart_type = PUI_RESTART_SYSTEM;
+			g_object_notify_by_pspec(G_OBJECT(self),
+			    properties[PROP_RESTART_TYPE]);
+			g_signal_emit(self, signals[STATE_CHANGED], 0);
+		}
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	g_debug("transaction finished, required restart: %s",
+	    pk_restart_enum_to_string(restart));
+
+out:
+	if (results != NULL) {
+		g_object_unref(results);
+	}
+}
+
+static void
+on_transaction_list_added(PkTransactionList *transaction_list,
+    const gchar *transaction_id, gpointer user_data)
+{
+	PuiBackend	*self = user_data;
+
+	/* adopt transaction in order to monitor it for restart requirements */
+	pk_client_adopt_async(self->pk_client, transaction_id, NULL, NULL,
+	    NULL, on_transaction_adopt_finish, user_data);
+}
+
+static void
 pui_backend_init_async(GAsyncInitable *initable, int io_priority,
     GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
 {
@@ -546,6 +645,10 @@
 	/* get notifications when an application restart is required */
 	g_signal_connect(self->pk_control, "restart-schedule",
 	    G_CALLBACK(on_restart_schedule), self);
+	/* get notifications when a transactions are added */
+	self->transaction_list = pk_transaction_list_new();
+	g_signal_connect(self->transaction_list, "added",
+	    G_CALLBACK(on_transaction_list_added), self);
 
 	check_inhibit(self);