[gnome-control-center/T20771: 34/44] info: add a way to check for manual updates
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center/T20771: 34/44] info: add a way to check for manual updates
- Date: Tue, 23 Jan 2018 21:09:26 +0000 (UTC)
commit 1ce373f07b9b7438ab18458d6fb9d54bf185c083
Author: Cosimo Cecchi <cosimo endlessm com>
Date: Fri Sep 26 18:08:59 2014 -0700
info: add a way to check for manual updates
Coordinate with the EosUpdater daemon to manually check for available
updates and possibly install them.
panels/info/Makefile.am | 13 +-
panels/info/cc-info-overview-panel.c | 338 +++++++++++++++++++++++++++++++++-
panels/info/eos-updater.xml | 39 ++++
panels/info/info-overview.ui | 56 +++++--
4 files changed, 431 insertions(+), 15 deletions(-)
---
diff --git a/panels/info/Makefile.am b/panels/info/Makefile.am
index 5c7e9d7..a8c7d47 100644
--- a/panels/info/Makefile.am
+++ b/panels/info/Makefile.am
@@ -15,7 +15,9 @@ noinst_LTLIBRARIES = libinfo.la
BUILT_SOURCES = \
cc-info-resources.c \
- cc-info-resources.h
+ cc-info-resources.h \
+ eos-updater-generated.c \
+ eos-updater-generated.h
libinfo_la_SOURCES = \
$(BUILT_SOURCES) \
@@ -49,6 +51,13 @@ cc-info-resources.c: info.gresource.xml $(resource_files)
cc-info-resources.h: info.gresource.xml $(resource_files)
$(AM_V_GEN) glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name
cc_info $<
+eos-updater-generated.c: eos-updater-generated.h
+eos-updater-generated.h: $(srcdir)/eos-updater.xml
+ gdbus-codegen $< \
+ --interface-prefix com.endlessm. \
+ --generate-c-code eos-updater-generated \
+ --c-namespace Eos
+
@INTLTOOL_DESKTOP_RULE@
desktopdir = $(datadir)/applications
@@ -67,6 +76,6 @@ update-from-gsd:
git commit -m "info: Update from gnome-settings-daemon" $(SPACEFILES)
CLEANFILES = $(desktop_in_files) $(desktop_DATA) $(BUILT_SOURCES)
-EXTRA_DIST = $(resource_files) info.gresource.xml info-cleanup-test.txt
+EXTRA_DIST = $(resource_files) info.gresource.xml info-cleanup-test.txt $(srcdir)/eos-updater.xml
-include $(top_srcdir)/git.mk
diff --git a/panels/info/cc-info-overview-panel.c b/panels/info/cc-info-overview-panel.c
index 2e77ab9..d86c8ba 100644
--- a/panels/info/cc-info-overview-panel.c
+++ b/panels/info/cc-info-overview-panel.c
@@ -23,6 +23,7 @@
#include "cc-info-panel.h"
#include "cc-info-resources.h"
+#include "eos-updater-generated.h"
#include "info-cleanup.h"
#include <glib.h>
@@ -47,6 +48,21 @@
#include "cc-info-overview-panel.h"
+typedef enum {
+ EOS_UPDATER_STATE_NONE = 0,
+ EOS_UPDATER_STATE_READY,
+ EOS_UPDATER_STATE_ERROR,
+ EOS_UPDATER_STATE_POLLING,
+ EOS_UPDATER_STATE_UPDATE_AVAILABLE,
+ EOS_UPDATER_STATE_FETCHING,
+ EOS_UPDATER_STATE_UPDATE_READY,
+ EOS_UPDATER_STATE_APPLYING_UPDATE,
+ EOS_UPDATER_STATE_UPDATE_APPLIED,
+ EOS_UPDATER_N_STATES,
+} EosUpdaterState;
+
+#define EOS_UPDATER_ERROR_LIVE_BOOT_STR "com.endlessm.Updater.Error.LiveBoot"
+#define EOS_UPDATER_ERROR_NON_OSTREE_STR "com.endlessm.Updater.Error.NotOstreeSystem"
typedef struct {
/* Will be one or 2 GPU name strings, or "Unknown" */
@@ -66,6 +82,10 @@ typedef struct
GtkWidget *graphics_label;
GtkWidget *virt_type_label;
+ GtkWidget *os_updates_box;
+ GtkWidget *os_updates_label;
+ GtkWidget *os_updates_spinner;
+
/* Virtualisation labels */
GtkWidget *label8;
GtkWidget *grid1;
@@ -82,6 +102,11 @@ typedef struct
guint64 total_bytes;
GraphicsData *graphics_data;
+
+ EosUpdater *updater_proxy;
+ GDBusProxy *session_proxy;
+ GCancellable *updater_cancellable;
+ gboolean updater_activated;
} CcInfoOverviewPanelPrivate;
struct _CcInfoOverviewPanel
@@ -92,7 +117,13 @@ struct _CcInfoOverviewPanel
CcInfoOverviewPanelPrivate *priv;
};
-static void get_primary_disc_info_start (CcInfoOverviewPanel *self);
+static void get_primary_disc_info_start (CcInfoOverviewPanel *self);
+static void sync_state_from_updater (CcInfoOverviewPanel *self,
+ gboolean is_initial_state);
+static void sync_initial_state_from_updater (CcInfoOverviewPanel *self);
+static gboolean updates_link_activated (GtkLabel *label,
+ gchar *uri,
+ CcInfoOverviewPanel *self);
typedef struct
{
@@ -108,6 +139,298 @@ typedef struct
G_DEFINE_TYPE_WITH_PRIVATE (CcInfoOverviewPanel, cc_info_overview_panel, CC_TYPE_PANEL)
static gboolean
+is_updater_state_spinning (EosUpdaterState state)
+{
+ switch (state)
+ {
+ case EOS_UPDATER_STATE_POLLING:
+ case EOS_UPDATER_STATE_FETCHING:
+ case EOS_UPDATER_STATE_APPLYING_UPDATE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static gboolean
+is_updater_state_interactive (CcInfoOverviewPanel *self,
+ EosUpdaterState state)
+{
+ CcInfoOverviewPanelPrivate *priv = cc_info_overview_panel_get_instance_private (self);
+ switch (state)
+ {
+ case EOS_UPDATER_STATE_READY:
+ case EOS_UPDATER_STATE_ERROR:
+ case EOS_UPDATER_STATE_UPDATE_AVAILABLE:
+ case EOS_UPDATER_STATE_UPDATE_READY:
+ return (!priv->updater_activated);
+ case EOS_UPDATER_STATE_UPDATE_APPLIED:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static const gchar *
+get_message_for_updater_state (CcInfoOverviewPanel *self,
+ EosUpdaterState state)
+{
+ CcInfoOverviewPanelPrivate *priv = cc_info_overview_panel_get_instance_private (self);
+ switch (state)
+ {
+ case EOS_UPDATER_STATE_NONE:
+ case EOS_UPDATER_STATE_READY:
+ if (priv->updater_activated)
+ return _("No updates available");
+ else
+ return _("Check for updates now");
+ case EOS_UPDATER_STATE_ERROR:
+ return _("Update failed");
+ case EOS_UPDATER_STATE_POLLING:
+ return _("Checking for updates…");
+ case EOS_UPDATER_STATE_UPDATE_AVAILABLE:
+ case EOS_UPDATER_STATE_UPDATE_READY:
+ return _("Install updates now");
+ case EOS_UPDATER_STATE_FETCHING:
+ case EOS_UPDATER_STATE_APPLYING_UPDATE:
+ return _("Installing updates…");
+ case EOS_UPDATER_STATE_UPDATE_APPLIED:
+ return _("Restart to complete update");
+ default:
+ return NULL;
+ }
+}
+
+static void
+updates_apply_completed (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EosUpdater *proxy = (EosUpdater *) object;
+ g_autoptr(GError) error = NULL;
+
+ eos_updater_call_apply_finish (proxy, res, &error);
+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ {
+ CcInfoOverviewPanel *self = user_data;
+ g_warning ("Failed to call Apply() on EOS updater: %s", error->message);
+ sync_state_from_updater (self, FALSE);
+ }
+}
+
+static void
+updates_fetch_completed (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EosUpdater *proxy = (EosUpdater *) object;
+ g_autoptr(GError) error = NULL;
+
+ eos_updater_call_fetch_finish (proxy, res, &error);
+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ {
+ CcInfoOverviewPanel *self = user_data;
+ g_warning ("Failed to call Fetch() on EOS updater: %s", error->message);
+ sync_state_from_updater (self, FALSE);
+ }
+}
+
+static void
+updates_poll_completed (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EosUpdater *proxy = (EosUpdater *) object;
+ g_autoptr(GError) error = NULL;
+
+ eos_updater_call_poll_finish (proxy, res, &error);
+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ {
+ CcInfoOverviewPanel *self = user_data;
+ g_warning ("Failed to call Poll() on EOS updater: %s", error->message);
+ sync_state_from_updater (self, FALSE);
+ }
+}
+
+static gboolean
+updates_link_activated (GtkLabel *label,
+ gchar *uri,
+ CcInfoOverviewPanel *self)
+{
+ CcInfoOverviewPanelPrivate *priv = cc_info_overview_panel_get_instance_private (self);
+ EosUpdaterState state;
+
+ state = eos_updater_get_state (priv->updater_proxy);
+ g_assert (is_updater_state_interactive (self, state));
+ priv->updater_activated = TRUE;
+
+ switch (state)
+ {
+ case EOS_UPDATER_STATE_ERROR:
+ case EOS_UPDATER_STATE_READY:
+ eos_updater_call_poll (priv->updater_proxy,
+ priv->updater_cancellable,
+ updates_poll_completed, self);
+ break;
+ case EOS_UPDATER_STATE_UPDATE_AVAILABLE:
+ eos_updater_call_fetch (priv->updater_proxy,
+ priv->updater_cancellable,
+ updates_fetch_completed, self);
+ break;
+ case EOS_UPDATER_STATE_UPDATE_READY:
+ eos_updater_call_apply (priv->updater_proxy,
+ priv->updater_cancellable,
+ updates_apply_completed, self);
+ break;
+ case EOS_UPDATER_STATE_UPDATE_APPLIED:
+ g_dbus_proxy_call (priv->session_proxy,
+ "Reboot",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, NULL, NULL);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ return TRUE;
+}
+
+static void
+updates_maybe_do_automatic_step (CcInfoOverviewPanel *self)
+{
+ CcInfoOverviewPanelPrivate *priv = cc_info_overview_panel_get_instance_private (self);
+ EosUpdaterState state;
+
+ if (!priv->updater_activated)
+ return;
+
+ state = eos_updater_get_state (priv->updater_proxy);
+ switch (state)
+ {
+ case EOS_UPDATER_STATE_UPDATE_AVAILABLE:
+ eos_updater_call_fetch (priv->updater_proxy,
+ priv->updater_cancellable,
+ updates_fetch_completed, self);
+ break;
+ case EOS_UPDATER_STATE_UPDATE_READY:
+ eos_updater_call_apply (priv->updater_proxy,
+ priv->updater_cancellable,
+ updates_apply_completed, self);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+sync_state_from_updater (CcInfoOverviewPanel *self,
+ gboolean is_initial_state)
+{
+ CcInfoOverviewPanelPrivate *priv = cc_info_overview_panel_get_instance_private (self);
+ EosUpdaterState state;
+ gboolean is_live_boot, is_non_ostree;
+ gboolean state_spinning, state_interactive;
+ const gchar *message, *error_name;
+ g_autofree gchar *markup = NULL;
+
+ state = eos_updater_get_state (priv->updater_proxy);
+ error_name = eos_updater_get_error_name (priv->updater_proxy);
+ is_live_boot = state == EOS_UPDATER_STATE_ERROR &&
+ g_strcmp0 (error_name, EOS_UPDATER_ERROR_LIVE_BOOT_STR) == 0;
+ is_non_ostree = state == EOS_UPDATER_STATE_ERROR &&
+ g_strcmp0 (error_name, EOS_UPDATER_ERROR_NON_OSTREE_STR) == 0;
+
+ /* Attempt to clear the error by pretending to be ready, which will
+ * trigger a poll
+ */
+ if (state == EOS_UPDATER_STATE_ERROR && is_initial_state)
+ state = EOS_UPDATER_STATE_READY;
+
+ state_spinning = is_updater_state_spinning (state);
+ state_interactive = is_updater_state_interactive (self, state);
+ message = get_message_for_updater_state (self, state);
+
+ gtk_widget_set_visible (priv->os_updates_spinner, state_spinning);
+ g_object_set (priv->os_updates_spinner, "active", state_spinning, NULL);
+
+ gtk_widget_set_visible (priv->os_updates_label, !is_live_boot && !is_non_ostree);
+ if (state_interactive)
+ markup = g_strdup_printf ("<a href='updates-link'>%s</a>", message);
+ else
+ markup = g_strdup (message);
+
+ gtk_label_set_markup (GTK_LABEL (priv->os_updates_label), markup);
+
+ updates_maybe_do_automatic_step (self);
+}
+
+static void
+updater_state_changed (EosUpdater *proxy,
+ GParamSpec *pspec,
+ CcInfoOverviewPanel *self)
+{
+ sync_state_from_updater (self, FALSE);
+}
+
+static void
+sync_initial_state_from_updater (CcInfoOverviewPanel *self)
+{
+ CcInfoOverviewPanelPrivate *priv = cc_info_overview_panel_get_instance_private (self);
+
+ priv->updater_cancellable = g_cancellable_new ();
+
+ sync_state_from_updater (self, TRUE);
+
+ g_signal_connect (priv->updater_proxy, "notify::state", G_CALLBACK (updater_state_changed), self);
+}
+
+static void
+info_overview_panel_setup_eos_updater (CcInfoOverviewPanel *self)
+{
+ CcInfoOverviewPanelPrivate *priv = cc_info_overview_panel_get_instance_private (self);
+ g_autoptr(GError) error = NULL;
+
+ priv->updater_proxy = eos_updater_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "com.endlessm.Updater",
+ "/com/endlessm/Updater",
+ NULL,
+ &error);
+
+ if (error)
+ {
+ g_critical ("Unable to get a proxy to the EOS updater: %s. Updates will not be available.",
+ error->message);
+ }
+
+ priv->session_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.gnome.SessionManager",
+ "/org/gnome/SessionManager",
+ "org.gnome.SessionManager",
+ NULL,
+ &error);
+
+ if (error)
+ {
+ g_critical ("Unable to get a proxy to gnome-session: %s. Updates will not be available.",
+ error->message);
+ }
+
+ if (!priv->updater_proxy || !priv->session_proxy)
+ {
+ gtk_widget_set_visible (priv->os_updates_box, FALSE);
+ }
+ else
+ {
+ g_signal_connect (priv->os_updates_label, "activate-link", G_CALLBACK (updates_link_activated), self);
+ sync_initial_state_from_updater (self);
+ }
+}
+
+static gboolean
on_attribution_label_link (GtkLabel *label,
gchar *uri,
CcInfoOverviewPanel *self)
@@ -930,6 +1253,15 @@ cc_info_overview_panel_finalize (GObject *object)
g_free (priv->gnome_date);
g_free (priv->gnome_distributor);
+ if (priv->updater_cancellable)
+ {
+ g_cancellable_cancel (priv->updater_cancellable);
+ g_clear_object (&priv->updater_cancellable);
+ }
+
+ g_clear_object (&priv->updater_proxy);
+ g_clear_object (&priv->session_proxy);
+
G_OBJECT_CLASS (cc_info_overview_panel_parent_class)->finalize (object);
}
@@ -951,6 +1283,9 @@ cc_info_overview_panel_class_init (CcInfoOverviewPanelClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, processor_label);
gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, os_name_label);
gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, os_type_label);
+ gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, os_updates_box);
+ gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, os_updates_label);
+ gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, os_updates_spinner);
gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, disk_label);
gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, graphics_label);
gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, virt_type_label);
@@ -971,6 +1306,7 @@ cc_info_overview_panel_init (CcInfoOverviewPanel *self)
info_overview_panel_setup_overview (self);
info_overview_panel_setup_virt (self);
+ info_overview_panel_setup_eos_updater (self);
}
GtkWidget *
diff --git a/panels/info/eos-updater.xml b/panels/info/eos-updater.xml
new file mode 100644
index 0000000..3fa9aae
--- /dev/null
+++ b/panels/info/eos-updater.xml
@@ -0,0 +1,39 @@
+<node>
+ <interface name="com.endlessm.Updater">
+ <method name="Poll" ></method>
+ <method name="Fetch"></method>
+ <method name="Apply"></method>
+
+ <property name="State" type="u" access="read"/>
+ <property name="UpdateID" type="s" access="read"/>
+ <property name="UpdateRefspec" type="s" access="read"/>
+ <property name="OriginalRefspec" type="s" access="read"/>
+ <property name="CurrentID" type="s" access="read"/>
+ <property name="UpdateLabel" type="s" access="read"/>
+ <property name="UpdateMessage" type="s" access="read"/>
+ <property name="DownloadSize" type="x" access="read"/>
+ <property name="DownloadedBytes" type="x" access="read"/>
+ <property name="UnpackedSize" type="x" access="read"/>
+ <property name="FullDownloadSize" type="x" access="read"/>
+ <property name="FullUnpackedSize" type="x" access="read"/>
+ <!-- An error code, in an unspecified error domain! See ErrorName. -->
+ <property name="ErrorCode" type="u" access="read"/>
+ <!-- a fully-qualified D-Bus error name, as might be returned from a D-Bus
+ method. "com.endlessm.Updater.Error.LiveBoot" when the system is a
+ read-only live USB, where updates are not supported.
+ -->
+ <property name="ErrorName" type="s" access="read"/>
+ <!-- a human-readable, albeit unlocalized, error message -->
+ <property name="ErrorMessage" type="s" access="read"/>
+
+ <signal name="StateChanged">
+ <arg type="u" name="state"/>
+ </signal>
+
+ <signal name="Progress">
+ <arg type="x" name="fetched"/>
+ <arg type="x" name="expected"/>
+ </signal>
+
+ </interface>
+</node>
diff --git a/panels/info/info-overview.ui b/panels/info/info-overview.ui
index 3b4eb3b..d05fd7b 100644
--- a/panels/info/info-overview.ui
+++ b/panels/info/info-overview.ui
@@ -301,20 +301,52 @@
</packing>
</child>
<child>
- <object class="GtkLabel" id="attribution_label">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="use_markup">True</property>
- <property name="xalign">0</property>
- <property name="margin_left">22</property>
- <property name="label" translatable="yes"><a href='attribution-link'>Endless Terms of
Use</a></property>
- <signal name="activate-link" handler="on_attribution_label_link" object="CcInfoOverviewPanel"
swapped="no" />
- <attributes>
- <attribute name="scale" value="0.83"/>
- </attributes>
- <style>
- <class name="dim-label"/>
- </style>
+ <property name="orientation">horizontal</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkLabel" id="attribution_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0.0</property>
+ <property name="margin_left">22</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes"><a href='attribution-link'>Endless Terms of
Use</a></property>
+ <signal name="activate-link" handler="on_attribution_label_link"
object="CcInfoOverviewPanel" swapped="no" />
+ <attributes>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="os_updates_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">horizontal</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkSpinner" id="os_updates_spinner">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="os_updates_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="use_markup">True</property>
+ <property name="label"></property>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
<packing>
<property name="expand">False</property>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]