From a7112122b3f1c68ab96e644e4c62715f02d5af69 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Sun, 13 Aug 2023 09:39:07 -0400 Subject: [PATCH 06/10] gnome-initial-setup: Add live user mode This commit adds a new "live user" mode meant to be run in live image environments. It asks questions the user should answer before the installer is started, and provides a way for the user to initiate the installer or just jump into the live session instead. --- data/20-gnome-initial-setup.rules.in | 3 +- gnome-initial-setup/gis-driver.c | 4 +- gnome-initial-setup/gis-driver.h | 4 +- gnome-initial-setup/gis-util.c | 70 ++++ gnome-initial-setup/gis-util.h | 2 + gnome-initial-setup/gnome-initial-setup.c | 26 +- .../pages/account/gis-account-pages.c | 21 + .../pages/install/gis-install-page.c | 384 ++++++++++++++++++ .../pages/install/gis-install-page.h | 52 +++ .../pages/install/gis-install-page.ui | 49 +++ .../pages/install/install.gresource.xml | 7 + gnome-initial-setup/pages/install/meson.build | 9 + .../pages/keyboard/gis-keyboard-page.c | 4 +- .../pages/language/gis-language-page.c | 5 +- gnome-initial-setup/pages/meson.build | 1 + .../pages/password/gis-password-page.c | 6 + 16 files changed, 632 insertions(+), 15 deletions(-) create mode 100644 gnome-initial-setup/pages/install/gis-install-page.c create mode 100644 gnome-initial-setup/pages/install/gis-install-page.h create mode 100644 gnome-initial-setup/pages/install/gis-install-page.ui create mode 100644 gnome-initial-setup/pages/install/install.gresource.xml create mode 100644 gnome-initial-setup/pages/install/meson.build diff --git a/data/20-gnome-initial-setup.rules.in b/data/20-gnome-initial-setup.rules.in index 02fd21d0..881efde9 100644 --- a/data/20-gnome-initial-setup.rules.in +++ b/data/20-gnome-initial-setup.rules.in @@ -1,29 +1,30 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // // DO NOT EDIT THIS FILE, it will be overwritten on update. // // Allow the gnome-initial-setup user to do certain actions without // being interrupted by password dialogs polkit.addRule(function(action, subject) { if (subject.user !== 'gnome-initial-setup') return undefined; var actionMatches = (action.id.indexOf('org.freedesktop.hostname1.') === 0 || action.id.indexOf('org.freedesktop.NetworkManager.') === 0 || action.id.indexOf('org.freedesktop.locale1.') === 0 || action.id.indexOf('org.freedesktop.accounts.') === 0 || action.id.indexOf('org.freedesktop.timedate1.') === 0 || action.id.indexOf('org.freedesktop.realmd.') === 0 || action.id.indexOf('com.endlessm.ParentalControls.') === 0 || - action.id.indexOf('org.fedoraproject.thirdparty.') === 0); + action.id.indexOf('org.fedoraproject.thirdparty.') === 0 || + action.id.indexOf('org.freedesktop.login1.reboot') === 0); if (actionMatches) { if (subject.local) return 'yes'; else return 'auth_admin'; } return undefined; }); diff --git a/gnome-initial-setup/gis-driver.c b/gnome-initial-setup/gis-driver.c index 98fe2ca6..41cd6e38 100644 --- a/gnome-initial-setup/gis-driver.c +++ b/gnome-initial-setup/gis-driver.c @@ -19,60 +19,62 @@ * Jasper St. Pierre */ #include "config.h" #include "gnome-initial-setup.h" #include #include #include #ifdef HAVE_WEBKITGTK_6_0 #include #else #include #endif #include "cc-common-language.h" #include "gis-assistant.h" /* Statically include this for now. Maybe later * we'll generate this from glib-mkenums. */ GType gis_driver_mode_get_type (void) { static GType enum_type_id = 0; if (G_UNLIKELY (!enum_type_id)) { static const GFlagsValue values[] = { { GIS_DRIVER_MODE_NEW_USER, "GIS_DRIVER_MODE_NEW_USER", "new_user" }, { GIS_DRIVER_MODE_EXISTING_USER, "GIS_DRIVER_MODE_EXISTING_USER", "existing_user" }, + { GIS_DRIVER_MODE_LIVE_USER, "GIS_DRIVER_MODE_LIVE_USER", "live_user" }, + { GIS_DRIVER_MODE_SYSTEM, "GIS_DRIVER_MODE_SYSTEM", "system" }, { GIS_DRIVER_MODE_ALL, "GIS_DRIVER_MODE_ALL", "all" }, { 0, NULL, NULL } }; enum_type_id = g_flags_register_static("GisDriverMode", values); } return enum_type_id; } enum { REBUILD_PAGES, LOCALE_CHANGED, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; typedef enum { PROP_MODE = 1, PROP_USERNAME, PROP_SMALL_SCREEN, PROP_PARENTAL_CONTROLS_ENABLED, PROP_FULL_NAME, PROP_AVATAR, } GisDriverProperty; static GParamSpec *obj_props[PROP_AVATAR + 1]; struct _GisDriver { AdwApplication parent_instance; @@ -767,61 +769,61 @@ static void connect_to_gdm (GisDriver *driver) { g_autoptr(GError) error = NULL; driver->client = gdm_client_new (); driver->greeter = gdm_client_get_greeter_sync (driver->client, NULL, &error); if (error == NULL) driver->user_verifier = gdm_client_get_user_verifier_sync (driver->client, NULL, &error); if (error != NULL) { g_warning ("Failed to open connection to GDM: %s", error->message); g_clear_object (&driver->user_verifier); g_clear_object (&driver->greeter); g_clear_object (&driver->client); } } static void gis_driver_startup (GApplication *app) { GisDriver *driver = GIS_DRIVER (app); WebKitWebContext *context = webkit_web_context_get_default (); G_APPLICATION_CLASS (gis_driver_parent_class)->startup (app); #if !WEBKIT_CHECK_VERSION(2, 39, 5) webkit_web_context_set_sandbox_enabled (context, TRUE); #endif - if (driver->mode == GIS_DRIVER_MODE_NEW_USER) + if (driver->mode & GIS_DRIVER_MODE_SYSTEM) connect_to_gdm (driver); driver->main_window = g_object_new (GTK_TYPE_APPLICATION_WINDOW, "application", app, "icon-name", "preferences-system", "deletable", FALSE, "title", _("Initial Setup"), NULL); g_signal_connect (driver->main_window, "realize", G_CALLBACK (window_realize_cb), (gpointer)app); driver->assistant = g_object_new (GIS_TYPE_ASSISTANT, NULL); gtk_window_set_child (GTK_WINDOW (driver->main_window), GTK_WIDGET (driver->assistant)); gis_driver_set_user_language (driver, setlocale (LC_MESSAGES, NULL), FALSE); prepare_main_window (driver); rebuild_pages (driver); } static void gis_driver_init (GisDriver *driver) { load_vendor_conf_file (driver); } diff --git a/gnome-initial-setup/gis-driver.h b/gnome-initial-setup/gis-driver.h index b57db2e2..aedb9a73 100644 --- a/gnome-initial-setup/gis-driver.h +++ b/gnome-initial-setup/gis-driver.h @@ -17,61 +17,63 @@ * * Written by: * Jasper St. Pierre */ #ifndef __GIS_DRIVER_H__ #define __GIS_DRIVER_H__ #include "gis-assistant.h" #include "gis-page.h" #include #include #include G_BEGIN_DECLS #define GIS_TYPE_DRIVER (gis_driver_get_type ()) #define GIS_TYPE_DRIVER_MODE (gis_driver_mode_get_type ()) G_DECLARE_FINAL_TYPE (GisDriver, gis_driver, GIS, DRIVER, AdwApplication) typedef enum { UM_LOCAL, UM_ENTERPRISE, NUM_MODES, } UmAccountMode; typedef enum { GIS_DRIVER_MODE_NEW_USER = 1 << 0, GIS_DRIVER_MODE_EXISTING_USER = 1 << 1, - GIS_DRIVER_MODE_ALL = (GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), + GIS_DRIVER_MODE_LIVE_USER = 1 << 2, + GIS_DRIVER_MODE_SYSTEM = (GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_LIVE_USER), + GIS_DRIVER_MODE_ALL = (GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER | GIS_DRIVER_MODE_LIVE_USER), } GisDriverMode; GType gis_driver_mode_get_type (void); GisAssistant *gis_driver_get_assistant (GisDriver *driver); void gis_driver_set_user_permissions (GisDriver *driver, ActUser *user, const gchar *password); void gis_driver_get_user_permissions (GisDriver *driver, ActUser **user, const gchar **password); void gis_driver_set_parent_permissions (GisDriver *driver, ActUser *parent, const gchar *password); void gis_driver_get_parent_permissions (GisDriver *driver, ActUser **parent, const gchar **password); void gis_driver_set_account_mode (GisDriver *driver, UmAccountMode mode); UmAccountMode gis_driver_get_account_mode (GisDriver *driver); void gis_driver_set_parental_controls_enabled (GisDriver *driver, gboolean parental_controls_enabled); diff --git a/gnome-initial-setup/gis-util.c b/gnome-initial-setup/gis-util.c index ac153fc1..315661b6 100644 --- a/gnome-initial-setup/gis-util.c +++ b/gnome-initial-setup/gis-util.c @@ -4,30 +4,100 @@ * 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 . */ #include "config.h" #include #include "gis-util.h" void gis_add_style_from_resource (const char *resource_path) { g_autoptr(GtkCssProvider) provider = gtk_css_provider_new (); gtk_css_provider_load_from_resource (provider, resource_path); gtk_style_context_add_provider_for_display (gdk_display_get_default (), GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); } + +gboolean +gis_kernel_command_line_has_argument (const char *arguments[]) +{ + GError *error = NULL; + g_autofree char *contents = NULL; + g_autoptr (GString) pattern = NULL; + gboolean has_argument = FALSE; + size_t i; + + if (!g_file_get_contents ("/proc/cmdline", &contents, NULL, &error)) { + g_error_free (error); + return FALSE; + } + + /* Build up the pattern by iterating through the alternatives, + * escaping all dots so they don't match any character but period, + * and adding word boundary specifiers around the arguments so + * substrings don't get matched. + * + * Also, add a | between each alternative. + */ + pattern = g_string_new (NULL); + for (i = 0; arguments[i] != NULL; i++) { + g_autofree char *escaped_argument = g_regex_escape_string (arguments[i], -1); + + if (i > 0) { + g_string_append (pattern, "|"); + } + + g_string_append (pattern, "\\b"); + + g_string_append (pattern, escaped_argument); + + g_string_append (pattern, "\\b"); + } + + has_argument = g_regex_match_simple (pattern->str, contents, 0, 0); + + return has_argument; +} + +void +gis_substitute_word_in_text (char **text, + const char *old_word, + const char *new_word) +{ + g_autoptr (GError) error = NULL; + g_autofree char *pattern = g_strdup_printf ("\\b%s\\b", old_word); + g_autoptr (GRegex) regex = g_regex_new (pattern, 0, 0, &error); + g_autofree char *replacement_text = NULL; + + if (text == NULL || *text == NULL) { + return; + } + + if (error != NULL) { + g_debug ("Error creating regex to match %s: %s\n", old_word, error->message); + } + + replacement_text = g_regex_replace (regex, *text, -1, 0, new_word, 0, &error); + + if (error != NULL) { + g_debug ("Error replacing %s with %s in %s: %s\n", old_word, new_word, *text, error->message); + return; + } + + g_free (*text); + *text = g_steal_pointer (&replacement_text); +} diff --git a/gnome-initial-setup/gis-util.h b/gnome-initial-setup/gis-util.h index 5041bddd..10dcd70c 100644 --- a/gnome-initial-setup/gis-util.h +++ b/gnome-initial-setup/gis-util.h @@ -1,19 +1,21 @@ /* * Copyright 2023 Endless OS Foundation LLC * * 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 . */ #pragma once void gis_add_style_from_resource (const char *path); +gboolean gis_kernel_command_line_has_argument (const char *arguments[]); +void gis_substitute_word_in_text (char **text, const char *old_word, const char *new_word); diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c index 3635f293..0e155cd3 100644 --- a/gnome-initial-setup/gnome-initial-setup.c +++ b/gnome-initial-setup/gnome-initial-setup.c @@ -14,144 +14,149 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * Written by: * Jasper St. Pierre */ #include "config.h" #include "gnome-initial-setup.h" #include #include #include #include #include #include "pages/welcome/gis-welcome-page.h" #include "pages/language/gis-language-page.h" #include "pages/keyboard/gis-keyboard-page.h" #include "pages/network/gis-network-page.h" #include "pages/timezone/gis-timezone-page.h" #include "pages/privacy/gis-privacy-page.h" #include "pages/software/gis-software-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" #include "pages/password/gis-password-page.h" #include "pages/summary/gis-summary-page.h" +#include "pages/install/gis-install-page.h" #define VENDOR_PAGES_GROUP "pages" #define VENDOR_SKIP_KEY "skip" #define VENDOR_NEW_USER_ONLY_KEY "new_user_only" #define VENDOR_EXISTING_USER_ONLY_KEY "existing_user_only" +#define VENDOR_LIVE_USER_ONLY_KEY "live_user_only" #define STATE_FILE GIS_WORKING_DIR "/state" static gboolean force_existing_user_mode; +static gboolean force_live_user_mode; static GPtrArray *skipped_pages; typedef GisPage *(*PreparePage) (GisDriver *driver); typedef struct { const gchar *page_id; PreparePage prepare_page_func; GisDriverMode modes; } PageData; #define PAGE(name, modes) { #name, gis_prepare_ ## name ## _page, modes } static PageData page_table[] = { PAGE (welcome, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), PAGE (language, GIS_DRIVER_MODE_ALL), PAGE (keyboard, GIS_DRIVER_MODE_ALL), - PAGE (network, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), + PAGE (network, GIS_DRIVER_MODE_ALL), PAGE (privacy, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), - PAGE (timezone, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), + PAGE (timezone, GIS_DRIVER_MODE_ALL), PAGE (software, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), PAGE (goa, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), - PAGE (account, GIS_DRIVER_MODE_NEW_USER), - PAGE (password, GIS_DRIVER_MODE_NEW_USER), + /* In live user mode, the account page isn't displayed, it just quietly creates the live user */ + PAGE (account, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_LIVE_USER), + PAGE (password, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_LIVE_USER), #ifdef HAVE_PARENTAL_CONTROLS PAGE (parental_controls, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), PAGE (parent_password, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), #endif PAGE (summary, GIS_DRIVER_MODE_NEW_USER), + PAGE (install, GIS_DRIVER_MODE_LIVE_USER), { NULL }, }; #undef PAGE static gboolean should_skip_page (const gchar *page_id, gchar **skip_pages) { guint i = 0; /* special case welcome. We only want to show it if language * is skipped */ if (strcmp (page_id, "welcome") == 0) return !should_skip_page ("language", skip_pages); /* check through our skip pages list for pages we don't want */ if (skip_pages) { while (skip_pages[i]) { if (g_strcmp0 (skip_pages[i], page_id) == 0) return TRUE; i++; } } return FALSE; } static gchar ** pages_to_skip_from_file (GisDriver *driver) { GisDriverMode driver_mode; GisDriverMode other_modes; g_autoptr(GStrvBuilder) builder = g_strv_builder_new(); g_auto (GStrv) skip_pages = NULL; g_autofree char *mode_group = NULL; g_autoptr (GFlagsClass) driver_mode_flags_class = NULL; const GFlagsValue *driver_mode_flags = NULL; g_autoptr (GError) error = NULL; /* This code will read the keyfile containing vendor customization options and * look for options under the "pages" group, and supports the following keys: * - skip (optional): list of pages to be skipped always - * - new_user_only (optional): list of pages to be skipped in existing user mode - * - existing_user_only (optional): list of pages to be skipped in new user mode + * - new_user_only (optional): list of pages to be skipped for modes other than new_user + * - existing_user_only (optional): list of pages to be skipped for modes other than existing_user * * In addition it will look for options under the "{mode} pages" group where {mode} is the * current driver mode for the following keys: * - skip (optional): list of pages to be skipped for the current mode * * This is how this file might look on a vendor image: * * [pages] * skip=timezone * * [new_user pages] * skip=language;keyboard * * Older files might look like so: * * [pages] * skip=timezone * existing_user_only=language;keyboard */ skip_pages = gis_driver_conf_get_string_list (driver, VENDOR_PAGES_GROUP, VENDOR_SKIP_KEY, NULL); if (skip_pages != NULL) { g_strv_builder_addv (builder, (const char **) skip_pages); g_clear_pointer (&skip_pages, g_strfreev); } driver_mode_flags_class = g_type_class_ref (GIS_TYPE_DRIVER_MODE); @@ -273,130 +278,137 @@ rebuild_pages_cb (GisDriver *driver) driver_mode = gis_driver_get_mode (driver); skip_pages = pages_to_skip_from_file (driver); for (; page_data->page_id != NULL; ++page_data) { skipped = FALSE; if (((page_data->modes & driver_mode) == 0) || (should_skip_page (page_data->page_id, skip_pages))) skipped = TRUE; page = page_data->prepare_page_func (driver); if (!page) continue; if (skipped) { gis_page_skip (page); g_ptr_array_add (skipped_pages, page); } else { gis_driver_add_page (driver, page); } } g_strfreev (skip_pages); } static GisDriverMode get_mode (void) { if (force_existing_user_mode) return GIS_DRIVER_MODE_EXISTING_USER; + else if (force_live_user_mode) + return GIS_DRIVER_MODE_LIVE_USER; else return GIS_DRIVER_MODE_NEW_USER; } static gboolean initial_setup_disabled_by_anaconda (void) { const gchar *file_name = SYSCONFDIR "/sysconfig/anaconda"; g_autoptr(GError) error = NULL; g_autoptr(GKeyFile) key_file = g_key_file_new (); if (!g_key_file_load_from_file (key_file, file_name, G_KEY_FILE_NONE, &error)) { if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) && !g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)) { g_warning ("Could not read %s: %s", file_name, error->message); } return FALSE; } return g_key_file_get_boolean (key_file, "General", "post_install_tools_disabled", NULL); } int main (int argc, char *argv[]) { GisDriver *driver; int status; GOptionContext *context; GisDriverMode mode; GOptionEntry entries[] = { { "existing-user", 0, 0, G_OPTION_ARG_NONE, &force_existing_user_mode, _("Force existing user mode"), NULL }, + { "live-user", 0, 0, G_OPTION_ARG_NONE, &force_live_user_mode, + _("Force live user mode"), NULL }, { NULL } }; g_unsetenv ("GIO_USE_VFS"); /* By default, libadwaita reads settings from the Settings portal, which causes * the portal to be started, which causes gnome-keyring to be started. This * interferes with our attempt below to manually start gnome-keyring and set * the login keyring password to a well-known value, which we overwrite with * the user's password once they choose one. */ g_setenv ("ADW_DISABLE_PORTAL", "1", TRUE); context = g_option_context_new (_("— GNOME initial setup")); g_option_context_add_main_entries (context, entries, NULL); g_option_context_parse (context, &argc, &argv, NULL); + if (gis_kernel_command_line_has_argument ((const char *[]) { "rd.live.image", "endless.live_boot", NULL })) + force_live_user_mode = TRUE; + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); g_message ("Starting gnome-initial-setup"); if (gis_get_mock_mode ()) g_message ("Mock mode: changes will not be saved to disk"); else g_message ("Production mode: changes will be saved to disk"); skipped_pages = g_ptr_array_new_with_free_func (destroy_page); mode = get_mode (); /* When we are running as the gnome-initial-setup user we * dont have a normal user session and need to initialize * the keyring manually so that we can pass the credentials * along to the new user in the handoff. */ - if (mode == GIS_DRIVER_MODE_NEW_USER && !gis_get_mock_mode ()) + if ((mode & GIS_DRIVER_MODE_SYSTEM) && !gis_get_mock_mode ()) gis_ensure_login_keyring (); driver = gis_driver_new (mode); adw_style_manager_set_color_scheme (adw_style_manager_get_default (), ADW_COLOR_SCHEME_PREFER_LIGHT); /* On first login, GNOME Shell offers to run a tour. If we also run Initial * Setup, the two immovable, centred windows will sit atop one another. * Until we have the ability to run Initial Setup in the "kiosk" mode, like * it does in new-user mode, disable Initial Setup for existing users. * * https://gitlab.gnome.org/GNOME/gnome-initial-setup/-/issues/120#note_1019004 * https://gitlab.gnome.org/GNOME/gnome-initial-setup/-/issues/12 */ if (mode == GIS_DRIVER_MODE_EXISTING_USER) { g_message ("Skipping gnome-initial-setup for existing user"); gis_ensure_stamp_files (driver); exit (EXIT_SUCCESS); } /* We only do this in existing-user mode, because if gdm launches us * in new-user mode and we just exit, gdm's special g-i-s session * never terminates. */ if (initial_setup_disabled_by_anaconda () && mode == GIS_DRIVER_MODE_EXISTING_USER) { gis_ensure_stamp_files (driver); exit (EXIT_SUCCESS); } g_signal_connect (driver, "rebuild-pages", G_CALLBACK (rebuild_pages_cb), NULL); diff --git a/gnome-initial-setup/pages/account/gis-account-pages.c b/gnome-initial-setup/pages/account/gis-account-pages.c index d9cc8d9f..8b0d8e99 100644 --- a/gnome-initial-setup/pages/account/gis-account-pages.c +++ b/gnome-initial-setup/pages/account/gis-account-pages.c @@ -1,32 +1,53 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2013 Red Hat * * 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 . * * Written by: * Jasper St. Pierre */ #include "config.h" #include "gis-account-pages.h" #include "gis-account-page.h" GisPage * gis_prepare_account_page (GisDriver *driver) { + GisDriverMode driver_mode; + + driver_mode = gis_driver_get_mode (driver); + + if (driver_mode == GIS_DRIVER_MODE_LIVE_USER && !gis_kernel_command_line_has_argument ((const char *[]) { "rd.live.overlay", NULL })) { + ActUserManager *act_client = act_user_manager_get_default (); + const char *username = "liveuser"; + g_autoptr(ActUser) user = NULL; + g_autoptr(GError) error = NULL; + + user = act_user_manager_create_user (act_client, username, username, ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR, &error); + + if (user != NULL) { + act_user_set_password_mode (user, ACT_USER_PASSWORD_MODE_NONE); + gis_driver_set_username (driver, username); + gis_driver_set_account_mode (driver, UM_LOCAL); + gis_driver_set_user_permissions (driver, user, NULL); + } + return NULL; + } + return g_object_new (GIS_TYPE_ACCOUNT_PAGE, "driver", driver, NULL); } diff --git a/gnome-initial-setup/pages/install/gis-install-page.c b/gnome-initial-setup/pages/install/gis-install-page.c new file mode 100644 index 00000000..70e3f9ec --- /dev/null +++ b/gnome-initial-setup/pages/install/gis-install-page.c @@ -0,0 +1,384 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2023 Red Hat + * + * 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 . + */ + +/* Install page {{{1 */ + +#define PAGE_ID "install" + +#include "config.h" +#include "cc-common-language.h" +#include "gis-install-page.h" +#include "gis-pkexec.h" + +#include +#include +#include +#include +#include +#include + +#include + +#define SERVICE_NAME "gdm-password" +#define VENDOR_INSTALLER_GROUP "install" +#define VENDOR_APPLICATION_KEY "application" + +struct _GisInstallPagePrivate { + GtkWidget *try_button; + GtkWidget *install_button; + AdwStatusPage *status_page; + GDesktopAppInfo *installer; + + ActUser *user_account; + const gchar *user_password; +}; +typedef struct _GisInstallPagePrivate GisInstallPagePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GisInstallPage, gis_install_page, GIS_TYPE_PAGE); + +static void +request_info_query (GisInstallPage *page, + GdmUserVerifier *user_verifier, + const char *question, + gboolean is_secret) +{ + /* TODO: pop up modal dialog */ + g_debug ("user verifier asks%s question: %s", + is_secret ? " secret" : "", + question); +} + +static void +on_info (GdmUserVerifier *user_verifier, + const char *service_name, + const char *info, + GisInstallPage *page) +{ + g_debug ("PAM module info: %s", info); +} + +static void +on_problem (GdmUserVerifier *user_verifier, + const char *service_name, + const char *problem, + GisInstallPage *page) +{ + g_warning ("PAM module error: %s", problem); +} + +static void +on_info_query (GdmUserVerifier *user_verifier, + const char *service_name, + const char *question, + GisInstallPage *page) +{ + request_info_query (page, user_verifier, question, FALSE); +} + +static void +on_secret_info_query (GdmUserVerifier *user_verifier, + const char *service_name, + const char *question, + GisInstallPage *page) +{ + GisInstallPagePrivate *priv = gis_install_page_get_instance_private (page); + gboolean should_send_password = priv->user_password != NULL; + + g_debug ("PAM module secret info query: %s", question); + if (should_send_password) { + g_debug ("sending password\n"); + gdm_user_verifier_call_answer_query (user_verifier, + service_name, + priv->user_password, + NULL, NULL, NULL); + priv->user_password = NULL; + } else { + request_info_query (page, user_verifier, question, TRUE); + } +} + +static void +on_session_opened (GdmGreeter *greeter, + const char *service_name, + GisInstallPage *page) +{ + gdm_greeter_call_start_session_when_ready_sync (greeter, service_name, + TRUE, NULL, NULL); +} + +static void +log_user_in (GisInstallPage *page) +{ + GisInstallPagePrivate *priv = gis_install_page_get_instance_private (page); + g_autoptr(GError) error = NULL; + GdmGreeter *greeter = NULL; + GdmUserVerifier *user_verifier = NULL; + + if (!gis_driver_get_gdm_objects (GIS_PAGE (page)->driver, + &greeter, &user_verifier)) { + g_warning ("No GDM connection; not initiating login"); + return; + } + + g_signal_connect (user_verifier, "info", + G_CALLBACK (on_info), page); + g_signal_connect (user_verifier, "problem", + G_CALLBACK (on_problem), page); + g_signal_connect (user_verifier, "info-query", + G_CALLBACK (on_info_query), page); + g_signal_connect (user_verifier, "secret-info-query", + G_CALLBACK (on_secret_info_query), page); + + g_signal_connect (greeter, "session-opened", + G_CALLBACK (on_session_opened), page); + + gdm_user_verifier_call_begin_verification_for_user_sync (user_verifier, + SERVICE_NAME, + act_user_get_user_name (priv->user_account), + NULL, &error); + + if (error != NULL) + g_warning ("Could not begin verification: %s", error->message); +} + +static void +on_try_button_clicked (GtkButton *button, + GisInstallPage *page) +{ + gis_ensure_stamp_files (GIS_PAGE (page)->driver); + + gis_driver_hide_window (GIS_PAGE (page)->driver); + log_user_in (page); +} + +static void +on_installer_exited (GPid pid, + int exit_status, + gpointer user_data) +{ + g_autoptr (GError) error = NULL; + g_autoptr(GSubprocessLauncher) launcher = NULL; + g_autoptr(GSubprocess) subprocess = NULL; + gboolean started_to_reboot; + + launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_SEARCH_PATH_FROM_ENVP); + + g_subprocess_launcher_unsetenv (launcher, "SHELL"); + + subprocess = g_subprocess_launcher_spawn (launcher, &error, "systemctl", "reboot", NULL); + + if (subprocess == NULL) { + g_warning ("Failed to initiate reboot: %s\n", error->message); + return; + } + + started_to_reboot = g_subprocess_wait (subprocess, NULL, &error); + + if (!started_to_reboot) { + g_warning ("Failed to reboot: %s\n", error->message); + return; + } +} + +static void +on_installer_started (GDesktopAppInfo *appinfo, + GPid pid, + gpointer user_data) +{ + g_child_watch_add (pid, on_installer_exited, user_data); +} + +static void +run_installer (GisInstallPage *page) +{ + g_autoptr (GError) error = NULL; + GisInstallPagePrivate *priv = gis_install_page_get_instance_private (page); + gboolean installer_launched; + g_autoptr (GAppLaunchContext) launch_context = NULL; + g_autofree char *language = NULL; + + gis_ensure_stamp_files (GIS_PAGE (page)->driver); + + launch_context = g_app_launch_context_new (); + + g_app_launch_context_unsetenv (launch_context, "SHELL"); + + language = cc_common_language_get_current_language (); + + if (language != NULL) + g_app_launch_context_setenv (launch_context, "LANG", language); + + installer_launched = g_desktop_app_info_launch_uris_as_manager (priv->installer, + NULL, + launch_context, + G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_CHILD_INHERITS_STDERR | G_SPAWN_CHILD_INHERITS_STDOUT | G_SPAWN_SEARCH_PATH, + NULL, + NULL, + on_installer_started, + page, + &error); + + if (!installer_launched) + g_warning ("Could not launch installer: %s", error->message); +} + +static void +on_install_button_clicked (GtkButton *button, + GisInstallPage *page) +{ + gis_driver_hide_window (GIS_PAGE (page)->driver); + run_installer (page); +} + +static void +gis_install_page_shown (GisPage *page) +{ + GisInstallPage *install = GIS_INSTALL_PAGE (page); + GisInstallPagePrivate *priv = gis_install_page_get_instance_private (install); + g_autoptr(GError) local_error = NULL; + + if (!gis_driver_save_data (GIS_PAGE (page)->driver, &local_error)) + g_warning ("Error saving data: %s", local_error->message); + + gis_driver_get_user_permissions (GIS_PAGE (page)->driver, + &priv->user_account, + &priv->user_password); + + gtk_widget_grab_focus (priv->install_button); +} + +static void +update_distro_name (GisInstallPage *page) +{ + GisInstallPagePrivate *priv = gis_install_page_get_instance_private (page); + g_autofree char *name = g_get_os_info (G_OS_INFO_KEY_NAME); + g_autofree char *text = NULL; + + if (!name) + name = g_strdup ("GNOME"); + + text = g_strdup (adw_status_page_get_description (priv->status_page)); + gis_substitute_word_in_text (&text, "GNOME", name); + adw_status_page_set_description (priv->status_page, text); + g_clear_pointer (&text, g_free); +} + +static void +update_distro_logo (GisInstallPage *page) +{ + GisInstallPagePrivate *priv = gis_install_page_get_instance_private (page); + g_autoptr (GtkIconTheme) icon_theme = NULL; + g_autofree char *logo_name = g_get_os_info ("LOGO"); + g_autoptr(GtkIconPaintable) icon_paintable = NULL; + g_autoptr(GPtrArray) array = NULL; + g_autoptr(GIcon) icon = NULL; + + if (logo_name == NULL) + logo_name = g_strdup ("gnome-logo"); + + array = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (array, (gpointer) g_strdup_printf ("%s-text", logo_name)); + g_ptr_array_add (array, (gpointer) g_strdup_printf ("%s", logo_name)); + + icon = g_themed_icon_new_from_names ((char **) array->pdata, array->len); + icon_theme = g_object_ref (gtk_icon_theme_get_for_display (gdk_display_get_default ())); + icon_paintable = gtk_icon_theme_lookup_by_gicon (icon_theme, icon, + 192, + gtk_widget_get_scale_factor (GTK_WIDGET (priv->status_page)), + gtk_widget_get_direction (GTK_WIDGET (priv->status_page)), + 0); + + adw_status_page_set_paintable (priv->status_page, GDK_PAINTABLE (icon_paintable)); +} + +static gboolean +find_installer (GisInstallPage *page) +{ + GisInstallPagePrivate *priv = gis_install_page_get_instance_private (page); + g_autofree char *desktop_file = NULL; + + desktop_file = gis_driver_conf_get_string (GIS_PAGE (page)->driver, + VENDOR_INSTALLER_GROUP, + VENDOR_APPLICATION_KEY); + + if (!desktop_file) + return FALSE; + + priv->installer = g_desktop_app_info_new (desktop_file); + + return priv->installer != NULL; +} + +static void +gis_install_page_constructed (GObject *object) +{ + GisInstallPage *page = GIS_INSTALL_PAGE (object); + GisInstallPagePrivate *priv = gis_install_page_get_instance_private (page); + + G_OBJECT_CLASS (gis_install_page_parent_class)->constructed (object); + + if (!find_installer (page)) + gtk_widget_set_sensitive (priv->install_button, FALSE); + + update_distro_name (page); + update_distro_logo (page); + g_signal_connect (priv->try_button, "clicked", G_CALLBACK (on_try_button_clicked), page); + g_signal_connect (priv->install_button, "clicked", G_CALLBACK (on_install_button_clicked), page); + + gis_page_set_complete (GIS_PAGE (page), TRUE); + + gtk_widget_set_visible (GTK_WIDGET (page), TRUE); +} + +static void +gis_install_page_locale_changed (GisPage *page) +{ + gis_page_set_title (page, _("Install or Try?")); +} + +static void +gis_install_page_class_init (GisInstallPageClass *klass) +{ + GisPageClass *page_class = GIS_PAGE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), "/org/gnome/initial-setup/gis-install-page.ui"); + + gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisInstallPage, try_button); + gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisInstallPage, install_button); + gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisInstallPage, status_page); + + page_class->page_id = PAGE_ID; + page_class->locale_changed = gis_install_page_locale_changed; + page_class->shown = gis_install_page_shown; + object_class->constructed = gis_install_page_constructed; +} + +static void +gis_install_page_init (GisInstallPage *page) +{ + gtk_widget_init_template (GTK_WIDGET (page)); +} + +GisPage * +gis_prepare_install_page (GisDriver *driver) +{ + return g_object_new (GIS_TYPE_INSTALL_PAGE, + "driver", driver, + NULL); +} diff --git a/gnome-initial-setup/pages/install/gis-install-page.h b/gnome-initial-setup/pages/install/gis-install-page.h new file mode 100644 index 00000000..292427d8 --- /dev/null +++ b/gnome-initial-setup/pages/install/gis-install-page.h @@ -0,0 +1,52 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2023 Red Hat + * + * 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 . + */ + +#ifndef __GIS_INSTALL_PAGE_H__ +#define __GIS_INSTALL_PAGE_H__ + +#include "gnome-initial-setup.h" + +G_BEGIN_DECLS + +#define GIS_TYPE_INSTALL_PAGE (gis_install_page_get_type ()) +#define GIS_INSTALL_PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIS_TYPE_INSTALL_PAGE, GisInstallPage)) +#define GIS_INSTALL_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIS_TYPE_INSTALL_PAGE, GisInstallPageClass)) +#define GIS_IS_INSTALL_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIS_TYPE_INSTALL_PAGE)) +#define GIS_IS_INSTALL_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIS_TYPE_INSTALL_PAGE)) +#define GIS_INSTALL_PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIS_TYPE_INSTALL_PAGE, GisInstallPageClass)) + +typedef struct _GisInstallPage GisInstallPage; +typedef struct _GisInstallPageClass GisInstallPageClass; + +struct _GisInstallPage +{ + GisPage parent; +}; + +struct _GisInstallPageClass +{ + GisPageClass parent_class; +}; + +GType gis_install_page_get_type (void); + +GisPage *gis_prepare_install_page (GisDriver *driver); + +G_END_DECLS + +#endif /* __GIS_INSTALL_PAGE_H__ */ diff --git a/gnome-initial-setup/pages/install/gis-install-page.ui b/gnome-initial-setup/pages/install/gis-install-page.ui new file mode 100644 index 00000000..08cfbd6e --- /dev/null +++ b/gnome-initial-setup/pages/install/gis-install-page.ui @@ -0,0 +1,49 @@ + + + + diff --git a/gnome-initial-setup/pages/install/install.gresource.xml b/gnome-initial-setup/pages/install/install.gresource.xml new file mode 100644 index 00000000..f1802db5 --- /dev/null +++ b/gnome-initial-setup/pages/install/install.gresource.xml @@ -0,0 +1,7 @@ + + + + gis-install-page.ui + + + diff --git a/gnome-initial-setup/pages/install/meson.build b/gnome-initial-setup/pages/install/meson.build new file mode 100644 index 00000000..e5084e5e --- /dev/null +++ b/gnome-initial-setup/pages/install/meson.build @@ -0,0 +1,9 @@ +sources += gnome.compile_resources( + 'install-resources', + files('install.gresource.xml'), + c_name: 'install' +) +sources += files( + 'gis-install-page.c', + 'gis-install-page.h' +) diff --git a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c index 2583c447..cb4f68d8 100644 --- a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c +++ b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c @@ -189,61 +189,61 @@ change_locale_permission_acquired (GObject *source, { GisKeyboardPage *page = GIS_KEYBOARD_PAGE (data); GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (page); GError *error = NULL; gboolean allowed; allowed = g_permission_acquire_finish (priv->permission, res, &error); if (error) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning ("Failed to acquire permission: %s", error->message); g_error_free (error); return; } if (allowed) set_localed_input (GIS_KEYBOARD_PAGE (data)); } static void update_input (GisKeyboardPage *self) { GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); const gchar *type; const gchar *id; type = cc_input_chooser_get_input_type (CC_INPUT_CHOOSER (priv->input_chooser)); id = cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)); set_input_settings (self, type, id); - if (gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER) { + if (gis_driver_get_mode (GIS_PAGE (self)->driver) & GIS_DRIVER_MODE_SYSTEM) { if (g_permission_get_allowed (priv->permission)) { set_localed_input (self); } else if (g_permission_get_can_acquire (priv->permission)) { g_permission_acquire_async (priv->permission, NULL, change_locale_permission_acquired, self); } } } static gboolean gis_keyboard_page_apply (GisPage *page, GCancellable *cancellable) { update_input (GIS_KEYBOARD_PAGE (page)); return FALSE; } static void add_default_input_sources (GisKeyboardPage *self) { GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); GVariantBuilder builder; gboolean defaults_have_latin = FALSE; size_t i; g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)")); for (i = 0; priv->default_input_source_ids[i] != NULL; i++) { @@ -365,61 +365,61 @@ static void gis_keyboard_page_constructed (GObject *object) { GisKeyboardPage *self = GIS_KEYBOARD_PAGE (object); GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); G_OBJECT_CLASS (gis_keyboard_page_parent_class)->constructed (object); g_signal_connect (priv->input_chooser, "confirm", G_CALLBACK (input_confirmed), self); g_signal_connect (priv->input_chooser, "changed", G_CALLBACK (input_changed), self); priv->input_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR); g_settings_delay (priv->input_settings); priv->cancellable = g_cancellable_new (); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, NULL, "org.freedesktop.locale1", "/org/freedesktop/locale1", "org.freedesktop.locale1", priv->cancellable, (GAsyncReadyCallback) localed_proxy_ready, self); gnome_get_default_input_sources (priv->cancellable, on_got_default_sources, self); /* If we're in new user mode then we're manipulating system settings */ - if (gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER) + if (gis_driver_get_mode (GIS_PAGE (self)->driver) & GIS_DRIVER_MODE_SYSTEM) priv->permission = polkit_permission_new_sync ("org.freedesktop.locale1.set-keyboard", NULL, NULL, NULL); update_page_complete (self); gtk_widget_set_visible (GTK_WIDGET (self), TRUE); } static void gis_keyboard_page_locale_changed (GisPage *page) { gis_page_set_title (GIS_PAGE (page), _("Typing")); } static void gis_keyboard_page_class_init (GisKeyboardPageClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GisPageClass * page_class = GIS_PAGE_CLASS (klass); gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), "/org/gnome/initial-setup/gis-keyboard-page.ui"); gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisKeyboardPage, input_chooser); page_class->page_id = PAGE_ID; page_class->apply = gis_keyboard_page_apply; page_class->skip = gis_keyboard_page_skip; page_class->locale_changed = gis_keyboard_page_locale_changed; object_class->constructed = gis_keyboard_page_constructed; object_class->finalize = gis_keyboard_page_finalize; } diff --git a/gnome-initial-setup/pages/language/gis-language-page.c b/gnome-initial-setup/pages/language/gis-language-page.c index 87b9f2d8..f7931c46 100644 --- a/gnome-initial-setup/pages/language/gis-language-page.c +++ b/gnome-initial-setup/pages/language/gis-language-page.c @@ -99,61 +99,61 @@ change_locale_permission_acquired (GObject *source, } static void user_loaded (GObject *object, GParamSpec *pspec, gpointer user_data) { gchar *new_locale_id = user_data; act_user_set_language (ACT_USER (object), new_locale_id); g_free (new_locale_id); } static void language_changed (CcLanguageChooser *chooser, GParamSpec *pspec, GisLanguagePage *page) { GisLanguagePagePrivate *priv = gis_language_page_get_instance_private (page); GisDriver *driver; GSettings *region_settings; ActUser *user; priv->new_locale_id = cc_language_chooser_get_language (chooser); driver = GIS_PAGE (page)->driver; gis_driver_set_user_language (driver, priv->new_locale_id, TRUE); gtk_widget_set_default_direction (gtk_get_locale_direction ()); - if (gis_driver_get_mode (driver) == GIS_DRIVER_MODE_NEW_USER) { + if (gis_driver_get_mode (driver) & GIS_DRIVER_MODE_SYSTEM) { if (g_permission_get_allowed (priv->permission)) { set_localed_locale (page); } else if (g_permission_get_can_acquire (priv->permission)) { g_permission_acquire_async (priv->permission, NULL, change_locale_permission_acquired, page); } } /* Ensure we won't override the selected language for format strings */ region_settings = g_settings_new (GNOME_SYSTEM_LOCALE_DIR); g_settings_reset (region_settings, REGION_KEY); g_object_unref (region_settings); user = act_user_manager_get_user (act_user_manager_get_default (), g_get_user_name ()); if (act_user_is_loaded (user)) act_user_set_language (user, priv->new_locale_id); else g_signal_connect (user, "notify::is-loaded", G_CALLBACK (user_loaded), g_strdup (priv->new_locale_id)); gis_welcome_widget_show_locale (GIS_WELCOME_WIDGET (priv->welcome_widget), priv->new_locale_id); } @@ -207,62 +207,61 @@ update_distro_logo (GisLanguagePage *page) break; } } } static void language_confirmed (CcLanguageChooser *chooser, GisLanguagePage *page) { gis_assistant_next_page (gis_driver_get_assistant (GIS_PAGE (page)->driver)); } static void gis_language_page_constructed (GObject *object) { GisLanguagePage *page = GIS_LANGUAGE_PAGE (object); GisLanguagePagePrivate *priv = gis_language_page_get_instance_private (page); GDBusConnection *bus; g_type_ensure (CC_TYPE_LANGUAGE_CHOOSER); G_OBJECT_CLASS (gis_language_page_parent_class)->constructed (object); update_distro_logo (page); g_signal_connect (priv->language_chooser, "notify::language", G_CALLBACK (language_changed), page); g_signal_connect (priv->language_chooser, "confirm", G_CALLBACK (language_confirmed), page); - /* If we're in new user mode then we're manipulating system settings */ - if (gis_driver_get_mode (GIS_PAGE (page)->driver) == GIS_DRIVER_MODE_NEW_USER) + if (gis_driver_get_mode (GIS_PAGE (page)->driver) & GIS_DRIVER_MODE_SYSTEM) { priv->permission = polkit_permission_new_sync ("org.freedesktop.locale1.set-locale", NULL, NULL, NULL); bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); g_dbus_proxy_new (bus, G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, NULL, "org.freedesktop.locale1", "/org/freedesktop/locale1", "org.freedesktop.locale1", priv->cancellable, (GAsyncReadyCallback) localed_proxy_ready, object); g_object_unref (bus); } gis_page_set_complete (GIS_PAGE (page), TRUE); gtk_widget_set_visible (GTK_WIDGET (page), TRUE); } static void gis_language_page_locale_changed (GisPage *page) { gis_page_set_title (GIS_PAGE (page), _("Welcome")); } static void gis_language_page_dispose (GObject *object) { GisLanguagePage *page = GIS_LANGUAGE_PAGE (object); diff --git a/gnome-initial-setup/pages/meson.build b/gnome-initial-setup/pages/meson.build index 32305018..5ac4a80d 100644 --- a/gnome-initial-setup/pages/meson.build +++ b/gnome-initial-setup/pages/meson.build @@ -1,21 +1,22 @@ pages = [ 'account', + 'install', 'language', 'keyboard', 'network', 'timezone', 'privacy', 'goa', 'password', 'software', 'summary', 'welcome', ] if libmalcontent_dep.found() and libmalcontent_ui_dep.found() pages += 'parental-controls' endif foreach page: pages subdir (page) endforeach diff --git a/gnome-initial-setup/pages/password/gis-password-page.c b/gnome-initial-setup/pages/password/gis-password-page.c index 6c12ca38..3d648c48 100644 --- a/gnome-initial-setup/pages/password/gis-password-page.c +++ b/gnome-initial-setup/pages/password/gis-password-page.c @@ -464,47 +464,53 @@ gis_password_page_class_init (GisPasswordPageClass *klass) * * If %FALSE (the default), this page will collect a password for the main * user account. If %TRUE, it will collect a password for controlling access * to parental controls — this will affect where the password is stored, and * the appearance of the page. * * Since: 3.36 */ obj_props[PROP_PARENT_MODE] = g_param_spec_boolean ("parent-mode", "Parent Mode", "Whether to collect a password for the main user account or a parent account.", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (object_class, G_N_ELEMENTS (obj_props), obj_props); gis_add_style_from_resource ("/org/gnome/initial-setup/gis-password-page.css"); } static void gis_password_page_init (GisPasswordPage *page) { g_type_ensure (GIS_TYPE_PAGE_HEADER); gtk_widget_init_template (GTK_WIDGET (page)); } GisPage * gis_prepare_password_page (GisDriver *driver) { + GisDriverMode driver_mode; + + driver_mode = gis_driver_get_mode (driver); + if (driver_mode == GIS_DRIVER_MODE_LIVE_USER && !gis_kernel_command_line_has_argument ((const char *[]) { "rd.live.overlay", NULL })) + return NULL; + return g_object_new (GIS_TYPE_PASSWORD_PAGE, "driver", driver, NULL); } GisPage * gis_prepare_parent_password_page (GisDriver *driver) { /* Skip prompting for the parent password if parental controls aren’t enabled. */ if (!gis_driver_get_parental_controls_enabled (driver)) return NULL; return g_object_new (GIS_TYPE_PASSWORD_PAGE, "driver", driver, "parent-mode", TRUE, NULL); } -- 2.41.0.rc2