[gnome-initial-setup/wip/pwithnall/misc-fixes: 45/70] page-util: adopt logic to launch eos-installer




commit a723bb1b05440b3f0ad6dbd407b8a79a5379e5e5
Author: Will Thompson <will willthompson co uk>
Date:   Fri Mar 2 20:08:17 2018 +0000

    page-util: adopt logic to launch eos-installer
    
    Previously, on reformatter-only images, the language page would advance
    to the live-chooser page, which would immediately hide the FBE and
    launch eos-installer. When that process exited, the live-chooser page
    would re-show the FBE and move to the language page.
    
    As well as being awkward, if animations are enabled (as they are on most
    non-VM systems) then the transition back to the language page is not
    instantaneous, so you see a flash of the live-chooser page when
    eos-installer exits.
    
    To solve this, move the hide-launch-wait-reshow logic to gis-page-util,
    and launch eos-installer directly from the language page when the user
    clicks Next. To avoid actually advancing to the next page, we (ab)use
    the ->apply() vfunc, which is intended to be used by pages like the
    keyboard page which need to asynchronously change system settings when
    you hit Next, delaying the transition to the next page, and blocking it
    in the event that the operation fails. In this case, the asynchronous
    operation is to launch eos-installer, wait for it to terminate, and
    always report that ->apply() failed.
    
    (Ported from setlocale() to nl_langinfo() in the 3.34 rebase by
    Philip C.)
    
    (Rebase 3.38: Fix minor rebase conflicts.)
    
    https://phabricator.endlessm.com/T14616

 gnome-initial-setup/gis-page-util.c                | 103 ++++++++++++++++++++-
 gnome-initial-setup/gis-page-util.h                |  11 ++-
 .../pages/language/gis-language-page.c             |  50 ++++++----
 .../pages/live-chooser/gis-live-chooser-page.c     |  82 +---------------
 4 files changed, 144 insertions(+), 102 deletions(-)
---
diff --git a/gnome-initial-setup/gis-page-util.c b/gnome-initial-setup/gis-page-util.c
index 2246b056..7fd65fa4 100644
--- a/gnome-initial-setup/gis-page-util.c
+++ b/gnome-initial-setup/gis-page-util.c
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
  *
- * Copyright (C) 2017 Endless Mobile, Inc.
+ * Copyright © 2017–2018 Endless Mobile, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -13,14 +13,15 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * Written by:
  *     Mario Sanchez Prada <mario endlessm com>
+ *     Will Thompson <wjt endlessm com>
  */
 
+#define _GNU_SOURCE 1  /* for NL_LOCALE_NAME */
+
 #include "config.h"
 
 #include "gis-page-util.h"
@@ -30,6 +31,8 @@
 #include <glib.h>
 #include <glib/gstdio.h>
 #include <gtk/gtk.h>
+#include <langinfo.h>
+#include <locale.h>
 #include <polkit/polkit.h>
 #include <sys/types.h>
 #include <sys/xattr.h>
@@ -349,3 +352,95 @@ gis_page_util_show_factory_dialog (GisPage *page)
   g_signal_connect (factory_dialog, "delete-event",
                     G_CALLBACK (gtk_widget_hide_on_delete), NULL);
 }
+
+static gboolean
+run_dialog_cb (gpointer user_data)
+{
+  GtkDialog *dialog = GTK_DIALOG (user_data);
+  gtk_dialog_run (dialog);
+  return G_SOURCE_REMOVE;
+}
+
+static void
+on_reformatter_exited (GTask  *task,
+                       GError *error)
+{
+  GisPage *page = GIS_PAGE (g_task_get_source_object (task));
+
+  gis_driver_show_window (page->driver);
+
+  if (error == NULL)
+    {
+      g_task_return_boolean (task, TRUE);
+      return;
+    }
+
+  GtkWindow *toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (page)));
+  GtkWidget *message_dialog;
+
+  g_critical ("Error running the reformatter: %s", error->message);
+
+  message_dialog = gtk_message_dialog_new (toplevel,
+                                           GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                           GTK_MESSAGE_ERROR,
+                                           GTK_BUTTONS_CLOSE,
+                                           /* Translators: this is shown when launching the
+                                            * reformatter (an external program) fails. The
+                                            * placeholder is an error message describing what went
+                                            * wrong.
+                                            */
+                                           _("Error running the reformatter: %s"), error->message);
+  g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, run_dialog_cb,
+                   message_dialog, (GDestroyNotify) gtk_widget_destroy);
+
+  g_task_return_error (task, g_steal_pointer (&error));
+}
+
+static void
+reformatter_exited_cb (GObject      *source,
+                       GAsyncResult *result,
+                       gpointer      user_data)
+{
+  g_autoptr(GTask) task = G_TASK (user_data);
+  g_autoptr(GError) error = NULL;
+
+  g_subprocess_wait_check_finish (G_SUBPROCESS (source), result, &error);
+  on_reformatter_exited (task, g_steal_pointer (&error));
+}
+
+/**
+ * gis_page_util_run_reformatter:
+ *
+ * Launches the reformatter, and arranges for the assistant to be hidden for
+ * the duration of its runtime. @callback will be called when the reformatter
+ * exits.
+ *
+ * There is no corresponding _finish() function because (at present) neither
+ * caller actually cares about the result.
+ */
+void
+gis_page_util_run_reformatter (GisPage            *page,
+                               GAsyncReadyCallback callback,
+                               gpointer            user_data)
+{
+  g_autoptr(GTask) task = g_task_new (page, NULL, callback, user_data);
+  g_autoptr(GSubprocessLauncher) launcher = NULL;
+  g_autoptr(GSubprocess) subprocess = NULL;
+  const gchar *locale = nl_langinfo (NL_LOCALE_NAME (LC_MESSAGES));
+  const gchar *command = "/usr/lib/eos-installer/gnome-image-installer";
+  g_autoptr(GError) error = NULL;
+
+  launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
+  g_subprocess_launcher_setenv (launcher, "LANG", locale, TRUE);
+  subprocess = g_subprocess_launcher_spawn (launcher, &error, command, NULL);
+
+  if (error)
+    {
+      on_reformatter_exited (task, g_steal_pointer (&error));
+      return;
+    }
+
+  gis_driver_hide_window (page->driver);
+  g_subprocess_wait_check_async (subprocess, NULL, reformatter_exited_cb,
+                                 g_steal_pointer (&task));
+}
diff --git a/gnome-initial-setup/gis-page-util.h b/gnome-initial-setup/gis-page-util.h
index 48b28b18..35da6d9e 100644
--- a/gnome-initial-setup/gis-page-util.h
+++ b/gnome-initial-setup/gis-page-util.h
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
  *
- * Copyright (C) 2017 Endless Mobile, Inc.
+ * Copyright © 2017–2018 Endless Mobile, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -13,12 +13,11 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * Written by:
  *     Mario Sanchez Prada <mario endlessm com>
+ *     Will Thompson <wjt endlessm com>
  */
 
 #ifndef __GIS_PAGE_UTIL_H__
@@ -32,6 +31,10 @@ G_BEGIN_DECLS
 
 void gis_page_util_show_factory_dialog (GisPage *page);
 
+void gis_page_util_run_reformatter (GisPage            *page,
+                                    GAsyncReadyCallback callback,
+                                    gpointer            user_data);
+
 gchar *gis_page_util_get_image_version (const gchar *path,
                                         GError     **error);
 
diff --git a/gnome-initial-setup/pages/language/gis-language-page.c 
b/gnome-initial-setup/pages/language/gis-language-page.c
index 676572b7..e5c50301 100644
--- a/gnome-initial-setup/pages/language/gis-language-page.c
+++ b/gnome-initial-setup/pages/language/gis-language-page.c
@@ -365,6 +365,34 @@ gis_language_page_locale_changed (GisPage *page)
   gis_page_set_title (GIS_PAGE (page), _("Welcome"));
 }
 
+static void
+reformatter_exited_cb (GObject      *source,
+                       GAsyncResult *result,
+                       gpointer      user_data)
+{
+  GisPage *page = GIS_PAGE (source);
+  /* We claim that the apply operation was unsuccessful so that the assistant
+   * doesn't advance to the next page.
+   */
+  gboolean valid = FALSE;
+
+  gis_page_apply_complete (page, valid);
+}
+
+static gboolean
+gis_language_page_apply (GisPage      *page,
+                         GCancellable *cancellable)
+{
+  if (!gis_driver_is_reformatter (page->driver))
+    return FALSE;
+
+  /* We abuse the "apply" hook to not actually advance to the next page when
+   * launching the reformatter.
+   */
+  gis_page_util_run_reformatter (page, reformatter_exited_cb, NULL);
+  return TRUE;
+}
+
 /* See https://github.com/endlessm/eos-installer/blob/master/UNATTENDED.md for
  * full documentation on the reformatter's unattended mode.
  */
@@ -424,19 +452,12 @@ check_reformatter_key_file (const gchar *path,
   return TRUE;
 }
 
-static gboolean
-assistant_next_idle_cb (gpointer user_data)
-{
-  gis_assistant_next_page (GIS_ASSISTANT (user_data));
-  return G_SOURCE_REMOVE;
-}
-
 static void
 gis_language_page_shown (GisPage *page)
 {
   GisLanguagePage *self = GIS_LANGUAGE_PAGE (page);
   GisLanguagePagePrivate *priv = gis_language_page_get_instance_private (self);
-  gboolean skip_ahead = FALSE;
+  gboolean launch_immediately = FALSE;
   g_autofree gchar *locale = NULL;
 
   /* For now, only support unattended mode on eosinstaller images. */
@@ -452,7 +473,7 @@ gis_language_page_shown (GisPage *page)
   priv->checked_unattended_config = TRUE;
 
   if (check_reformatter_key_file (UNATTENDED_INI_PATH, &locale))
-    skip_ahead = TRUE;
+    launch_immediately = TRUE;
   else
     check_reformatter_key_file (INSTALL_INI_PATH, &locale);
 
@@ -460,14 +481,8 @@ gis_language_page_shown (GisPage *page)
     cc_language_chooser_set_language (CC_LANGUAGE_CHOOSER (priv->language_chooser),
                                       locale);
 
-  if (skip_ahead)
-    {
-      gis_driver_hide_window (page->driver);
-      g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
-                       assistant_next_idle_cb,
-                       g_object_ref (gis_driver_get_assistant (page->driver)),
-                       g_object_unref);
-    }
+  if (launch_immediately)
+    gis_page_util_run_reformatter (page, NULL, NULL);
 }
 
 static void
@@ -499,6 +514,7 @@ gis_language_page_class_init (GisLanguagePageClass *klass)
   page_class->page_id = PAGE_ID;
   page_class->locale_changed = gis_language_page_locale_changed;
   page_class->get_accel_group = gis_language_page_get_accel_group;
+  page_class->apply = gis_language_page_apply;
   page_class->shown = gis_language_page_shown;
   object_class->constructed = gis_language_page_constructed;
   object_class->dispose = gis_language_page_dispose;
diff --git a/gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.c 
b/gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.c
index 8a5a1693..49aa6662 100644
--- a/gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.c
+++ b/gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.c
@@ -32,6 +32,7 @@
 #include <langinfo.h>
 #include <locale.h>
 
+#include "gis-page-util.h"
 #include "pages/language/cc-language-chooser.h"
 
 #define LIVE_ACCOUNT_AVATAR "/usr/share/pixmaps/faces/sunflower.jpg"
@@ -125,68 +126,9 @@ try_button_clicked (GisLiveChooserPage *page)
 }
 
 static void
-on_reformatter_exited (GisLiveChooserPage *page,
-                       const GError       *error)
+reformat_button_clicked (GisLiveChooserPage *page)
 {
-  GisDriver *driver = GIS_PAGE (page)->driver;
-
-  gis_driver_show_window (driver);
-
-  if (gis_driver_is_reformatter (driver))
-    gis_assistant_previous_page (gis_driver_get_assistant (driver));
-
-  if (error != NULL)
-    {
-      GtkWindow *toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (page)));
-      GtkWidget *message_dialog;
-
-      g_critical ("Error running the reformatter: %s", error->message);
-
-      message_dialog = gtk_message_dialog_new (toplevel,
-                                               GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-                                               GTK_MESSAGE_ERROR,
-                                               GTK_BUTTONS_CLOSE,
-                                               _("Error running the reformatter: %s"), error->message);
-
-      gtk_dialog_run (GTK_DIALOG (message_dialog));
-      gtk_widget_destroy (message_dialog);
-    }
-}
-
-static void
-reformatter_exited_cb (GObject      *source,
-                       GAsyncResult *result,
-                       gpointer      user_data)
-{
-  GisLiveChooserPage *page = GIS_LIVE_CHOOSER_PAGE (user_data);
-  g_autoptr(GError) error = NULL;
-
-  g_subprocess_wait_check_finish (G_SUBPROCESS (source), result, &error);
-  on_reformatter_exited (page, error);
-}
-
-static void
-gis_live_chooser_page_launch_reformatter (GisLiveChooserPage *page)
-{
-  g_autoptr(GSubprocessLauncher) launcher = NULL;
-  g_autoptr(GSubprocess) subprocess = NULL;
-  const gchar *locale = nl_langinfo (NL_LOCALE_NAME (LC_MESSAGES));
-  const gchar *command = "/usr/lib/eos-installer/gnome-image-installer";
-  g_autoptr(GError) error = NULL;
-
-  launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
-  g_subprocess_launcher_setenv (launcher, "LANG", locale, TRUE);
-  subprocess = g_subprocess_launcher_spawn (launcher, &error, command, NULL);
-  if (error)
-    {
-      on_reformatter_exited (page, error);
-    }
-  else
-    {
-      gis_driver_hide_window (GIS_PAGE (page)->driver);
-      g_subprocess_wait_check_async (subprocess, NULL,
-                                     reformatter_exited_cb, page);
-    }
+  gis_page_util_run_reformatter (GIS_PAGE (page), NULL, NULL);
 }
 
 static void
@@ -209,7 +151,7 @@ gis_live_chooser_page_constructed (GObject *object)
 
   g_signal_connect_swapped (priv->reformat_button,
                             "clicked",
-                            G_CALLBACK (gis_live_chooser_page_launch_reformatter),
+                            G_CALLBACK (reformat_button_clicked),
                             page);
 
   g_object_bind_property (driver, "live-dvd", priv->try_label, "visible", G_BINDING_SYNC_CREATE | 
G_BINDING_INVERT_BOOLEAN);
@@ -236,15 +178,6 @@ gis_live_chooser_page_locale_changed (GisPage *page)
   gis_page_set_title (page, _("Try or Reformat"));
 }
 
-static void
-gis_live_chooser_page_shown (GisPage *page)
-{
-  GisLiveChooserPage *self = GIS_LIVE_CHOOSER_PAGE (page);
-
-  if (gis_driver_is_reformatter (page->driver))
-    gis_live_chooser_page_launch_reformatter (self);
-}
-
 static void
 gis_live_chooser_page_class_init (GisLiveChooserPageClass *klass)
 {
@@ -254,7 +187,6 @@ gis_live_chooser_page_class_init (GisLiveChooserPageClass *klass)
   page_class->page_id = "live-chooser";
   page_class->locale_changed = gis_live_chooser_page_locale_changed;
   page_class->save_data = gis_live_chooser_page_save_data;
-  page_class->shown = gis_live_chooser_page_shown;
 
   gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), 
"/org/gnome/initial-setup/gis-live-chooser-page.ui");
 
@@ -280,11 +212,7 @@ gis_live_chooser_page_init (GisLiveChooserPage *page)
 GisPage *
 gis_prepare_live_chooser_page (GisDriver *driver)
 {
-  /* Only include this page when running on live media or as a standalone
-   * reformatter.
-   */
-  if (!gis_driver_is_live_session (driver) &&
-      !gis_driver_is_reformatter (driver))
+  if (!gis_driver_is_live_session (driver))
     return NULL;
 
   return g_object_new (GIS_TYPE_LIVE_CHOOSER_PAGE,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]