From 1dfc367ba2b238365d4cb6913e62bdc60a35a5d4 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Thu, 21 Mar 2019 21:22:25 +0000 Subject: [PATCH] Update Plymouth when updating pending firmware Some updates take some time to deploy, so we need to update the UI to avoid the user thinking it's just hung. --- src/fu-offline.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/src/fu-offline.c b/src/fu-offline.c index 21b1352cc..088970005 100644 --- a/src/fu-offline.c +++ b/src/fu-offline.c @@ -16,6 +16,81 @@ #include "fu-plugin-private.h" #include "fu-util-common.h" +struct FuUtilPrivate { + gchar *splash_cmd; + GTimer *splash_timer; +}; + +static gboolean +fu_offline_set_splash_progress (FuUtilPrivate *priv, guint percentage, GError **error) +{ + g_autofree gchar *msg = NULL; + g_autofree gchar *str = NULL; + g_autoptr(GSubprocess) subprocess = NULL; + + /* call into plymouth if installed */ + if (priv->splash_cmd == NULL) + return TRUE; + + /* TRANSLATORS: this is the message we send plymouth to advise + * of the new percentage completion when installing firmware */ + msg = g_strdup_printf ("%s - %u%%", _("Installing Firmware"), percentage); + str = g_strdup_printf ("%u", percentage); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_NONE, error, + priv->splash_cmd, "update", + "--status", msg, + "--progress", str, NULL); + if (subprocess == NULL) + return FALSE; + return g_subprocess_wait (subprocess, NULL, error); +} + +static gboolean +fu_offline_set_splash_mode (FuUtilPrivate *priv, const gchar *mode, GError **error) +{ + g_autofree gchar *mode_str = NULL; + g_autoptr(GSubprocess) subprocess = NULL; + + /* call into plymouth if installed */ + if (priv->splash_cmd == NULL) + return TRUE; + mode_str = g_strdup_printf ("--%s", mode); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_NONE, error, + priv->splash_cmd, + "change-mode", mode_str, NULL); + if (subprocess == NULL) + return FALSE; + return g_subprocess_wait (subprocess, NULL, error); +} + +static void +fu_offline_client_notify_cb (GObject *object, GParamSpec *pspec, gpointer user_data) +{ + FuUtilPrivate *priv = (FuUtilPrivate *) user_data; + FwupdClient *client = FWUPD_CLIENT (object); + + /* rate limit to 1 second */ + if (g_timer_elapsed (priv->splash_timer, NULL) < 1.f || + fwupd_client_get_percentage (client) < 5) + return; + fu_offline_set_splash_progress (priv, fwupd_client_get_percentage (client), NULL); + g_timer_reset (priv->splash_timer); +} + +static void +fu_util_private_free (FuUtilPrivate *priv) +{ + if (priv->splash_timer != NULL) + g_timer_destroy (priv->splash_timer); + g_free (priv->splash_cmd); + g_free (priv); +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuUtilPrivate, fu_util_private_free) +#pragma clang diagnostic pop + int main (int argc, char *argv[]) { @@ -26,6 +101,7 @@ main (int argc, char *argv[]) g_autoptr(FwupdClient) client = NULL; g_autoptr(GError) error = NULL; g_autoptr(GPtrArray) results = NULL; + g_autoptr(FuUtilPrivate) priv = g_new0 (FuUtilPrivate, 1); setlocale (LC_ALL, ""); @@ -50,6 +126,10 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } + /* find plymouth, but not an error if not found */ + priv->splash_cmd = g_find_program_in_path ("plymouth"); + priv->splash_timer = g_timer_new (); + /* ensure D-Bus errors are registered */ fwupd_error_quark (); @@ -65,6 +145,8 @@ main (int argc, char *argv[]) /* connect to the daemon */ client = fwupd_client_new (); + g_signal_connect (client, "notify::percentage", + G_CALLBACK (fu_offline_client_notify_cb), priv); if (!fwupd_client_connect (client, NULL, &error)) { /* TRANSLATORS: we could not talk to the fwupd daemon */ g_printerr ("%s: %s\n", _("Failed to connect to daemon"), @@ -72,6 +154,14 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } + /* set up splash */ + if (!fu_offline_set_splash_mode (priv, "updates", &error)) { + /* TRANSLATORS: we could not talk to plymouth */ + g_printerr ("%s: %s\n", _("Failed to set splash mode"), + error->message); + return EXIT_FAILURE; + } + /* apply each update */ for (guint i = 0; i < results->len; i++) { FwupdDevice *dev = g_ptr_array_index (results, i); @@ -131,6 +221,7 @@ main (int argc, char *argv[]) } /* reboot */ + fu_offline_set_splash_mode (priv, "reboot", NULL); if (!fu_util_update_reboot (&error)) { /* TRANSLATORS: we could not reboot for some reason */ g_printerr ("%s: %s\n", _("Failed to reboot"), error->message);