[gnome-initial-setup/wip/pwithnall/misc-fixes: 25/70] live-chooser: add the Live Chooser page
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-initial-setup/wip/pwithnall/misc-fixes: 25/70] live-chooser: add the Live Chooser page
- Date: Fri, 11 Sep 2020 13:29:12 +0000 (UTC)
commit fad4d499fd86defa3576de86cc153eac71021b9e
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Wed Jul 24 16:40:27 2019 -0700
live-chooser: add the Live Chooser page
When booting from live media, present the user with a choice between
entering a temporary session, or launching the reformatter.
Adds a script named eos-transient-setup to do some of the tasks that
will be used for live mode as well as for store demo mode later in the
downstream series of patches.
(Rebase 3.38: Fix declaration of save_data() function, and use new
gis_page_set_has_forward() API. Drop `--mode demo` support from
`eos-transient-setup`.)
Reference to related tickets:
https://phabricator.endlessm.com/T12547
https://phabricator.endlessm.com/T12548
https://phabricator.endlessm.com/T13578
https://phabricator.endlessm.com/T13654
https://phabricator.endlessm.com/T13950
https://phabricator.endlessm.com/T14616
https://phabricator.endlessm.com/T15370
https://phabricator.endlessm.com/T15438
https://phabricator.endlessm.com/T15834
https://phabricator.endlessm.com/T15938
https://phabricator.endlessm.com/T16130
https://phabricator.endlessm.com/T17082
https://phabricator.endlessm.com/T17622
https://phabricator.endlessm.com/T18063
https://phabricator.endlessm.com/T18708
https://phabricator.endlessm.com/T20103
https://phabricator.endlessm.com/T20990
https://phabricator.endlessm.com/T23552
data/eos-transient-setup.service.in | 13 +
data/meson.build | 12 +
gnome-initial-setup/eos-transient-setup | 286 +++++++++++++++++++++
gnome-initial-setup/gnome-initial-setup.c | 2 +
gnome-initial-setup/meson.build | 5 +
.../pages/live-chooser/gis-live-chooser-page.c | 265 +++++++++++++++++++
.../pages/live-chooser/gis-live-chooser-page.h | 58 +++++
.../pages/live-chooser/gis-live-chooser-page.ui | 195 ++++++++++++++
.../pages/live-chooser/install-endless.png | Bin 0 -> 3293 bytes
.../pages/live-chooser/live-chooser.css | 4 +
.../pages/live-chooser/live-chooser.gresource.xml | 9 +
gnome-initial-setup/pages/live-chooser/meson.build | 9 +
.../pages/live-chooser/try-endless.png | Bin 0 -> 3105 bytes
gnome-initial-setup/pages/meson.build | 1 +
meson_options.txt | 5 +
po/POTFILES.in | 2 +
16 files changed, 866 insertions(+)
---
diff --git a/data/eos-transient-setup.service.in b/data/eos-transient-setup.service.in
new file mode 100644
index 00000000..b3e40867
--- /dev/null
+++ b/data/eos-transient-setup.service.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=Adjust desktop settings for live boot
+After=eos-live-boot-overlayfs-setup.service
+Before=display-manager.service
+ConditionKernelCommandLine=endless.live_boot
+
+[Service]
+Type=oneshot
+ExecStart=@LIBEXECDIR@/eos-transient-setup --mode live
+RemainAfterExit=yes
+
+[Install]
+WantedBy=graphical.target
diff --git a/data/meson.build b/data/meson.build
index aa4f7983..8f73b8b3 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -90,7 +90,19 @@ configure_file(
configuration: desktop_conf,
)
+systemd_system_unit_dir = get_option('systemd-system-unit-dir')
systemd_dep = dependency ('systemd')
+if systemd_system_unit_dir == ''
+ systemd_system_unit_dir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir')
+endif
+
+configure_file(
+ input: 'eos-transient-setup.service.in',
+ output: 'eos-transient-setup.service',
+ install: true,
+ install_dir: systemd_system_unit_dir,
+ configuration: desktop_conf
+)
install_data(
'product_serial.conf',
diff --git a/gnome-initial-setup/eos-transient-setup b/gnome-initial-setup/eos-transient-setup
new file mode 100755
index 00000000..002dc586
--- /dev/null
+++ b/gnome-initial-setup/eos-transient-setup
@@ -0,0 +1,286 @@
+#!/usr/bin/env python3
+# eos-transient-setup – configures the system for transient sessions
+# Copyright (C) 2016-2018 Endless Mobile, Ltd.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# 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.
+
+import argparse
+import enum
+import glob
+import json
+import logging
+import os
+import subprocess
+import sys
+import tempfile
+
+import gi
+gi.require_version('OSTree', '1.0')
+from gi.repository import GLib, Gio, OSTree # noqa: E402
+
+log = logging.getLogger(sys.argv[0])
+
+ICON_GRID_DIR = '/var/lib/eos-image-defaults/icon-grid'
+
+DESKTOP_GRID_ID = 'desktop'
+
+EOS_INSTALLER = 'com.endlessm.Installer.desktop'
+EOS_INSTALLER_PATH = os.path.join('/usr/share/applications', EOS_INSTALLER)
+LOCAL_APPS_DIR = '/usr/local/share/applications'
+LOCAL_DESKTOP_PATH = os.path.join(LOCAL_APPS_DIR, EOS_INSTALLER)
+
+GOOGLE_CHROME = 'google-chrome.desktop'
+CHROMIUM_BROWSER = 'chromium-browser.desktop'
+
+LIVE_SETTINGS_DB = '/var/lib/eos-image-defaults/settings.live'
+USER_PROFILE_PATH = '/usr/local/share/dconf/profile/user'
+USER_PROFILE = '''user-db:user
+file-db:/var/lib/eos-image-defaults/settings.live
+file-db:/var/lib/eos-image-defaults/settings
+file-db:/usr/share/eos-default-settings/settings
+'''
+
+SHELL_SCHEMA = 'org.gnome.shell'
+FAVORITE_APPS_KEY = 'favorite-apps'
+
+GS_SCHEMA = 'org.gnome.software'
+ALLOW_UPDATES = 'allow-updates'
+
+GSD_POWER_SCHEMA = "org.gnome.settings-daemon.plugins.power"
+GSD_SLEEP_INACTIVE_AC_TYPE = "sleep-inactive-ac-type"
+GSD_SLEEP_INACTIVE_AC_TIMEOUT = "sleep-inactive-ac-timeout"
+GSD_SLEEP_INACTIVE_BATTERY_TYPE = "sleep-inactive-battery-type"
+GSD_SLEEP_INACTIVE_BATTERY_TIMEOUT = "sleep-inactive-battery-timeout"
+
+ONE_MINUTE = 60
+
+
+# The other mode here (demo mode) was removed with the rebase to 3.38. The
+# --mode argument has been kept around to maintain CLI API compatibility.
+class Mode(enum.Enum):
+ live = 1
+
+
+class AdjustGSettings(object):
+ def __init__(self):
+ self.keyfile = GLib.KeyFile()
+
+ def update(self, schema, key, variant):
+ """Stages 'variant' as the new value for 'key' in 'schema'."""
+ value = variant.print_(False)
+ log.info('Updating %s: %s to %s', schema, key, value)
+ self.keyfile.set_string(schema.replace('.', '/'), key, value)
+
+ def prepare(self, mode):
+ """Stage all settings to be overridden."""
+ self.update_favorite_apps(mode)
+ self.disallow_app_center_updates()
+
+ def write_dconf_compile(self):
+ """Write dconf database with overridden settings.
+
+ We also adjust the 'user' profile to use it.
+ """
+ with tempfile.TemporaryDirectory(suffix='.d') as d:
+ keyfile_path = os.path.join(d, '00-live')
+ log.info('writing keyfile to %s', keyfile_path)
+ self.keyfile.save_to_file(keyfile_path)
+
+ os.makedirs(os.path.dirname(LIVE_SETTINGS_DB), exist_ok=True)
+
+ args = ['dconf', 'compile', LIVE_SETTINGS_DB, d]
+ log.info('$ %s', ' '.join(args))
+ subprocess.check_call(args)
+
+ log.info('Installing new DConf profile to %s', USER_PROFILE_PATH)
+ os.makedirs(os.path.dirname(USER_PROFILE_PATH), exist_ok=True)
+ with open(USER_PROFILE_PATH, 'w') as f:
+ f.write(USER_PROFILE)
+
+ def write_stdout(self):
+ """Write keyfile with overridden settings to stdout, for debugging."""
+ data, length = self.keyfile.to_data()
+ print(data)
+
+ def adjust_power_settings(self):
+ """Configure session to log out after a short period of inactivity."""
+ for key in (GSD_SLEEP_INACTIVE_AC_TYPE,
+ GSD_SLEEP_INACTIVE_BATTERY_TYPE):
+ self.update(GSD_POWER_SCHEMA, key,
+ GLib.Variant('s', 'logout'))
+
+ for key in (GSD_SLEEP_INACTIVE_AC_TIMEOUT,
+ GSD_SLEEP_INACTIVE_BATTERY_TIMEOUT):
+ self.update(GSD_POWER_SCHEMA, key,
+ GLib.Variant('i', ONE_MINUTE))
+
+ def update_favorite_apps(self, mode):
+ """Adjust default favourite apps, which are shown on the taskbar."""
+ settings = Gio.Settings(schema=SHELL_SCHEMA)
+ favorite_apps = settings.get_strv(FAVORITE_APPS_KEY)
+ changed = False
+
+ if mode == Mode.live:
+ # Prepend installer icon
+ if EOS_INSTALLER not in favorite_apps:
+ favorite_apps.insert(0, EOS_INSTALLER)
+ changed = True
+
+ # Replace Chrome (downloaded on demand) with Chromium (pre-installed).
+ # This effectively undoes a step taken in the image builder,
+ # pre-seeding /var/eos-image-defaults/settings with the opposite
+ # change.
+ if replace_chrome_with_chromium(favorite_apps):
+ changed = True
+
+ if changed:
+ self.update(SHELL_SCHEMA, FAVORITE_APPS_KEY,
+ GLib.Variant('as', favorite_apps))
+
+ def disallow_app_center_updates(self):
+ """Forbid installing app updates."""
+ self.update(GS_SCHEMA, ALLOW_UPDATES, GLib.Variant('b', False))
+
+
+def install_installer_desktop_file():
+ """Make eos-installer visible in user sessions.
+
+ eos-installer is shipped in all images, but its desktop file contains
+ NoDisplay=true. Make a copy with this setting removed so it can be added to
+ the desktop and taskbar and found via search.
+ """
+ log.info('Copying %s to %s with NoDisplay removed',
+ EOS_INSTALLER_PATH, LOCAL_DESKTOP_PATH)
+ os.makedirs(LOCAL_APPS_DIR, exist_ok=True)
+
+ kf = GLib.KeyFile()
+ kf.load_from_file(EOS_INSTALLER_PATH,
+ GLib.KeyFileFlags.KEEP_COMMENTS |
+ GLib.KeyFileFlags.KEEP_TRANSLATIONS)
+ kf.remove_key('Desktop Entry', 'NoDisplay')
+ kf.save_to_file(LOCAL_DESKTOP_PATH)
+
+
+def disable_chrome_auto_download():
+ """Prevent Chrome auto-downloader from running."""
+ cmd = os.path.join('/usr/share/eos-google-chrome-helper',
+ 'eos-google-chrome-system-helper.py')
+ log.info('$ %s', cmd)
+ subprocess.check_call([cmd])
+
+
+def replace_chrome_with_chromium(apps):
+ """Replace Chrome with Chromium in a list of .desktop file names."""
+ if GOOGLE_CHROME in apps:
+ apps[apps.index(GOOGLE_CHROME)] = CHROMIUM_BROWSER
+ return True
+ else:
+ return False
+
+
+def remove_chrome_from_icon_grids():
+ """Replace Chrome with Chromium in icon grids, if needed."""
+ pattern = os.path.join(ICON_GRID_DIR, 'icon-grid-*.json')
+ for path in glob.glob(pattern):
+ log.info("Checking %s", path)
+ try:
+ with open(path, 'r') as f:
+ grid = json.load(fp=f)
+
+ if replace_chrome_with_chromium(grid[DESKTOP_GRID_ID]):
+ log.info("Updating %s", path)
+
+ with open(path, 'w') as f:
+ json.dump(grid, fp=f)
+ except Exception:
+ log.exception("while processing %s", path)
+
+
+def prepend_installer_to_icon_grid():
+ """Prepend installer to icon grid."""
+ pattern = os.path.join(ICON_GRID_DIR, 'icon-grid-prepend-*.json')
+ c_path = os.path.join(ICON_GRID_DIR, 'icon-grid-prepend-C.json')
+ paths = glob.glob(pattern)
+ if c_path not in paths:
+ paths.append(c_path)
+
+ for path in paths:
+ try:
+ try:
+ with open(path, 'r') as f:
+ log.info("reading existing file %s", path)
+ grid = json.load(fp=f)
+ except FileNotFoundError:
+ grid = {}
+
+ desktop = grid.setdefault(DESKTOP_GRID_ID, [])
+ if EOS_INSTALLER not in desktop:
+ desktop.insert(0, EOS_INSTALLER)
+
+ log.info("Writing %s: %s", path, json.dumps(obj=grid))
+ with open(path, 'w') as f:
+ json.dump(obj=grid, fp=f)
+ except Exception:
+ log.exception("while processing %s", path)
+
+
+def reduce_ostree_min_free_space():
+ '''Don't require any free space on disk when installing apps. On live
+ systems, free space is at most half of physical RAM, and running out is not
+ a big deal.'''
+ repo = OSTree.Repo.new_default()
+ repo.open()
+ config = repo.copy_config()
+ # -size alone takes precedence but set both for clarity.
+ config.set_string('core', 'min-free-space-size', '0MB')
+ config.set_integer('core', 'min-free-space-percent', 0)
+ repo.write_config(config)
+
+
+def main():
+ """Configures system settings for live sessions."""
+ p = argparse.ArgumentParser(description=main.__doc__)
+ p.add_argument('--mode', choices=[m.name for m in Mode], required=True,
+ default='live',
+ help='Whether to adjust settings for live mode')
+ p.add_argument('--dry-run', action='store_true',
+ help='Just print the DConf keyfile to stdout')
+ a = p.parse_args()
+ mode = Mode[a.mode]
+
+ logging.basicConfig(
+ level=logging.INFO,
+ format='%(name)s:%(lineno)-3s %(funcName)20s %(levelname)7s: '
+ '%(message)s')
+
+ setup = AdjustGSettings()
+ setup.prepare(mode=mode)
+
+ if a.dry_run:
+ setup.write_stdout()
+ else:
+ setup.write_dconf_compile()
+
+ disable_chrome_auto_download()
+ remove_chrome_from_icon_grids()
+ reduce_ostree_min_free_space()
+
+ if mode == Mode.live:
+ install_installer_desktop_file()
+ prepend_installer_to_icon_grid()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c
index 5414f5ee..3b22076c 100644
--- a/gnome-initial-setup/gnome-initial-setup.c
+++ b/gnome-initial-setup/gnome-initial-setup.c
@@ -41,6 +41,7 @@
#include "pages/network/gis-network-page.h"
#include "pages/timezone/gis-timezone-page.h"
#include "pages/privacy/gis-privacy-page.h"
+#include "pages/live-chooser/gis-live-chooser-page.h"
#include "pages/goa/gis-goa-page.h"
#include "pages/account/gis-account-pages.h"
#include "pages/parental-controls/gis-parental-controls-page.h"
@@ -70,6 +71,7 @@ typedef struct {
static PageData page_table[] = {
PAGE (welcome, FALSE),
PAGE (language, FALSE),
+ PAGE (live_chooser, TRUE),
PAGE (keyboard, FALSE),
PAGE (display, TRUE),
PAGE (endless_eula, TRUE),
diff --git a/gnome-initial-setup/meson.build b/gnome-initial-setup/meson.build
index 427d61ff..8d31a936 100644
--- a/gnome-initial-setup/meson.build
+++ b/gnome-initial-setup/meson.build
@@ -64,6 +64,11 @@ dependencies = [
libmalcontent_ui_dep,
]
+install_data(
+ 'eos-transient-setup',
+ install_dir: libexec_dir
+)
+
executable(
'gnome-initial-setup',
sources,
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
new file mode 100644
index 00000000..240d4b99
--- /dev/null
+++ b/gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.c
@@ -0,0 +1,265 @@
+/* gis-live-chooser-page.c
+ *
+ * Copyright (C) 2016 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 as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ * Georges Basile Stavracas Neto <georges stavracas gmail com>
+ */
+
+#define _GNU_SOURCE 1 /* for NL_LOCALE_NAME */
+
+#include "gis-live-chooser-page.h"
+#include "live-chooser-resources.h"
+
+#include <act/act-user-manager.h>
+#include <gio/gio.h>
+#include <glib/gi18n.h>
+#include <polkit/polkit.h>
+
+#include <langinfo.h>
+#include <locale.h>
+
+#include "pages/language/cc-language-chooser.h"
+
+#define LIVE_ACCOUNT_AVATAR "/usr/share/pixmaps/faces/sunflower.jpg"
+#define LIVE_ACCOUNT_USERNAME "live"
+#define LIVE_ACCOUNT_FULLNAME "Endless OS"
+
+struct _GisLiveChooserPagePrivate
+{
+ GtkWidget *try_label;
+ GtkWidget *reformat_label;
+ GtkWidget *try_button;
+ GtkWidget *reformat_button;
+
+ ActUserManager *act_client;
+};
+
+typedef struct _GisLiveChooserPagePrivate GisLiveChooserPagePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GisLiveChooserPage, gis_live_chooser_page, GIS_TYPE_PAGE);
+
+static gboolean
+gis_live_chooser_page_save_data (GisPage *page,
+ GError **error)
+{
+ GisLiveChooserPage *self = GIS_LIVE_CHOOSER_PAGE (page);
+ GisLiveChooserPagePrivate *priv = gis_live_chooser_page_get_instance_private (self);
+ g_autoptr(ActUser) user = NULL;
+ const gchar *language;
+
+ user = act_user_manager_create_user (priv->act_client,
+ LIVE_ACCOUNT_USERNAME,
+ LIVE_ACCOUNT_FULLNAME,
+ ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR,
+ error);
+ if (user == NULL)
+ {
+ g_prefix_error (error, "Failed to create live user: ");
+ return FALSE;
+ }
+
+ act_user_set_password_mode (user, ACT_USER_PASSWORD_MODE_NONE);
+ act_user_set_automatic_login (user, FALSE);
+ act_user_set_icon_file (user, LIVE_ACCOUNT_AVATAR);
+
+ language = gis_driver_get_user_language (page->driver);
+
+ if (language)
+ act_user_set_language (user, language);
+
+ gis_driver_set_user_permissions (page->driver, user, NULL);
+
+ gis_update_login_keyring_password ("");
+
+ return TRUE;
+}
+
+static void
+load_css_overrides (GisLiveChooserPage *page)
+{
+ GtkCssProvider *provider;
+ GError *error;
+
+ error = NULL;
+ provider = gtk_css_provider_new ();
+ gtk_css_provider_load_from_resource (provider, "/org/gnome/initial-setup/live-chooser.css");
+
+ if (error != NULL)
+ {
+ g_warning ("Unable to load CSS overrides for the live-chooser page: %s", error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ gtk_style_context_add_provider_for_screen (gtk_widget_get_screen (GTK_WIDGET (page)),
+ GTK_STYLE_PROVIDER (provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ }
+
+ g_object_unref (provider);
+}
+
+static void
+try_button_clicked (GisLiveChooserPage *page)
+{
+ GisAssistant *assistant = gis_driver_get_assistant (GIS_PAGE (page)->driver);
+
+ gis_assistant_next_page (assistant);
+}
+
+static void
+on_reformatter_exited (GisLiveChooserPage *page,
+ const GError *error)
+{
+ GisDriver *driver = GIS_PAGE (page)->driver;
+
+ gis_driver_show_window (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
+reformat_button_clicked (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);
+ }
+}
+
+static void
+gis_live_chooser_page_constructed (GObject *object)
+{
+ GisLiveChooserPage *page = GIS_LIVE_CHOOSER_PAGE (object);
+ GisLiveChooserPagePrivate *priv = gis_live_chooser_page_get_instance_private (page);
+
+ G_OBJECT_CLASS (gis_live_chooser_page_parent_class)->constructed (object);
+
+ gis_page_set_has_forward (GIS_PAGE (page), FALSE);
+
+ priv->act_client = act_user_manager_get_default ();
+
+ g_signal_connect_swapped (priv->try_button,
+ "clicked",
+ G_CALLBACK (try_button_clicked),
+ page);
+
+ g_signal_connect_swapped (priv->reformat_button,
+ "clicked",
+ G_CALLBACK (reformat_button_clicked),
+ page);
+
+
+ load_css_overrides (page);
+
+ gtk_widget_show (GTK_WIDGET (page));
+}
+
+static void
+gis_live_chooser_page_locale_changed (GisPage *page)
+{
+ GisLiveChooserPagePrivate *priv = gis_live_chooser_page_get_instance_private (GIS_LIVE_CHOOSER_PAGE
(page));
+
+ gtk_label_set_label (GTK_LABEL (priv->try_label), _("Try Endless OS by running it from the USB Stick."));
+ gtk_label_set_label (GTK_LABEL (priv->reformat_label), _("Reformat this computer with Endless OS."));
+ gtk_button_set_label (GTK_BUTTON (priv->try_button), _("Try It"));
+ gtk_button_set_label (GTK_BUTTON (priv->reformat_button), _("Reformat"));
+
+ gis_page_set_title (page, _("Try or Reformat"));
+}
+
+static void
+gis_live_chooser_page_class_init (GisLiveChooserPageClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GisPageClass *page_class = GIS_PAGE_CLASS (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;
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass),
"/org/gnome/initial-setup/gis-live-chooser-page.ui");
+
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisLiveChooserPage, try_label);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisLiveChooserPage,
reformat_label);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisLiveChooserPage, try_button);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisLiveChooserPage,
reformat_button);
+
+ object_class->constructed = gis_live_chooser_page_constructed;
+}
+
+static void
+gis_live_chooser_page_init (GisLiveChooserPage *page)
+{
+ g_resources_register (live_chooser_get_resource ());
+
+ gtk_widget_init_template (GTK_WIDGET (page));
+}
+
+GisPage *
+gis_prepare_live_chooser_page (GisDriver *driver)
+{
+ /* Only show this page when running on a live boot session */
+ if (!gis_driver_is_live_session (driver))
+ return NULL;
+
+ return g_object_new (GIS_TYPE_LIVE_CHOOSER_PAGE,
+ "driver", driver,
+ NULL);
+}
diff --git a/gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.h
b/gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.h
new file mode 100644
index 00000000..b386264f
--- /dev/null
+++ b/gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.h
@@ -0,0 +1,58 @@
+/* gis-live-chooser-page.h
+ *
+ * Copyright (C) 2016 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 as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ * Georges Basile Stavracas Neto <georges stavracas gmail com>
+ */
+
+#ifndef GIS_LIVE_CHOOSER_PAGE_H
+#define GIS_LIVE_CHOOSER_PAGE_H
+
+#include "gnome-initial-setup.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GIS_TYPE_LIVE_CHOOSER_PAGE (gis_live_chooser_page_get_type())
+#define GIS_LIVE_CHOOSER_PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GIS_TYPE_LIVE_CHOOSER_PAGE, GisLiveChooserPage))
+#define GIS_LIVE_CHOOSER_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
GIS_TYPE_LIVE_CHOOSER_PAGE, GisLiveChooserPageClass))
+#define GIS_IS_LIVE_CHOOSER_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
GIS_TYPE_LIVE_CHOOSER_PAGE))
+#define GIS_IS_LIVE_CHOOSER_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
GIS_TYPE_LIVE_CHOOSER_PAGE))
+#define GIS_LIVE_CHOOSER_PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GIS_TYPE_LIVE_CHOOSER_PAGE, GisLiveChooserPageClass))
+
+typedef struct _GisLiveChooserPage GisLiveChooserPage;
+typedef struct _GisLiveChooserPageClass GisLiveChooserPageClass;
+
+struct _GisLiveChooserPage
+{
+ GisPage parent;
+};
+
+struct _GisLiveChooserPageClass
+{
+ GisPageClass parent_class;
+};
+
+GType gis_live_chooser_page_get_type (void);
+
+GisPage *gis_prepare_live_chooser_page (GisDriver *driver);
+
+G_END_DECLS
+
+#endif /* GIS_LIVE_CHOOSER_PAGE_H */
+
diff --git a/gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.ui
b/gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.ui
new file mode 100644
index 00000000..e429166e
--- /dev/null
+++ b/gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.ui
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <template class="GisLiveChooserPage" parent="GisPage">
+ <child>
+ <object class="GtkBox" id="main_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="margin_start">24</property>
+ <property name="margin_end">24</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">24</property>
+ <child type="center">
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="spacing">24</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border_width">18</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">24</property>
+ <child>
+ <object class="GtkLabel" id="try_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Try Endless OS by running it from the USB
Stick.</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <property name="yalign">0</property>
+ <property name="max_width_chars">30</property>
+ <attributes>
+ <attribute name="scale" value="1.4"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="try_icon">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="resource">/org/gnome/initial-setup/try-endless.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="try_button">
+ <property name="label" translatable="yes">Try It</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <style>
+ <class name="rounded-frame"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="border_width">18</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">24</property>
+ <child>
+ <object class="GtkLabel" id="reformat_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Reformat this computer with Endless
OS.</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <property name="yalign">0</property>
+ <property name="max_width_chars">30</property>
+ <attributes>
+ <attribute name="scale" value="1.4"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="reformat_icon">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="resource">/org/gnome/initial-setup/install-endless.png</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="reformat_button">
+ <property name="label" translatable="yes">Reformat</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <style>
+ <class name="rounded-frame"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+ <object class="GtkSizeGroup">
+ <property name="mode">vertical</property>
+ <widgets>
+ <widget name="reformat_label"/>
+ <widget name="try_label"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup">
+ <property name="mode">vertical</property>
+ <widgets>
+ <widget name="reformat_icon"/>
+ <widget name="try_icon"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/gnome-initial-setup/pages/live-chooser/install-endless.png
b/gnome-initial-setup/pages/live-chooser/install-endless.png
new file mode 100644
index 00000000..74307a28
Binary files /dev/null and b/gnome-initial-setup/pages/live-chooser/install-endless.png differ
diff --git a/gnome-initial-setup/pages/live-chooser/live-chooser.css
b/gnome-initial-setup/pages/live-chooser/live-chooser.css
new file mode 100644
index 00000000..b2bc76e1
--- /dev/null
+++ b/gnome-initial-setup/pages/live-chooser/live-chooser.css
@@ -0,0 +1,4 @@
+frame.rounded-frame {
+ border: solid 1px @borders;
+ border-radius: 4px;
+}
diff --git a/gnome-initial-setup/pages/live-chooser/live-chooser.gresource.xml
b/gnome-initial-setup/pages/live-chooser/live-chooser.gresource.xml
new file mode 100644
index 00000000..9e309981
--- /dev/null
+++ b/gnome-initial-setup/pages/live-chooser/live-chooser.gresource.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/initial-setup">
+ <file alias="live-chooser.css">live-chooser.css</file>
+ <file preprocess="xml-stripblanks" alias="gis-live-chooser-page.ui">gis-live-chooser-page.ui</file>
+ <file>install-endless.png</file>
+ <file>try-endless.png</file>
+ </gresource>
+</gresources>
diff --git a/gnome-initial-setup/pages/live-chooser/meson.build
b/gnome-initial-setup/pages/live-chooser/meson.build
new file mode 100644
index 00000000..08900a77
--- /dev/null
+++ b/gnome-initial-setup/pages/live-chooser/meson.build
@@ -0,0 +1,9 @@
+sources += gnome.compile_resources(
+ 'live-chooser-resources',
+ files('live-chooser.gresource.xml'),
+ c_name: 'live_chooser'
+)
+
+sources += files(
+ 'gis-live-chooser-page.c',
+)
diff --git a/gnome-initial-setup/pages/live-chooser/try-endless.png
b/gnome-initial-setup/pages/live-chooser/try-endless.png
new file mode 100644
index 00000000..eb55491f
Binary files /dev/null and b/gnome-initial-setup/pages/live-chooser/try-endless.png differ
diff --git a/gnome-initial-setup/pages/meson.build b/gnome-initial-setup/pages/meson.build
index 6c14d5f6..0898d2ac 100644
--- a/gnome-initial-setup/pages/meson.build
+++ b/gnome-initial-setup/pages/meson.build
@@ -2,6 +2,7 @@ pages = [
'account',
'display',
'language',
+ 'live-chooser',
'keyboard',
'endless-eula',
'network',
diff --git a/meson_options.txt b/meson_options.txt
index be386b59..7a71d278 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -21,6 +21,11 @@ option('systemd',
description: 'Enable systemd integration'
)
+option('systemd-system-unit-dir',
+ description: 'the directory to install systemd system units',
+ type: 'string'
+)
+
option('parental_controls',
type: 'feature',
value: 'auto',
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b40ed056..65ee030a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -30,6 +30,8 @@ gnome-initial-setup/pages/language/cc-language-chooser.c
gnome-initial-setup/pages/language/gis-language-page.c
gnome-initial-setup/pages/language/gis-language-page.ui
gnome-initial-setup/pages/language/gis-welcome-widget.c
+gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.c
+gnome-initial-setup/pages/live-chooser/gis-live-chooser-page.ui
gnome-initial-setup/pages/network/gis-network-page.c
gnome-initial-setup/pages/network/gis-network-page.ui
gnome-initial-setup/pages/parental-controls/gis-parental-controls-page.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]