diff --git a/0001-gnome-initial-setup-Bump-GLib-required-version-to-2..patch b/0001-gnome-initial-setup-Bump-GLib-required-version-to-2..patch deleted file mode 100644 index e711d2d..0000000 --- a/0001-gnome-initial-setup-Bump-GLib-required-version-to-2..patch +++ /dev/null @@ -1,150 +0,0 @@ -From 555b00faf5c25f6903ff9f247a60b0a488bfee14 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 15 Aug 2023 10:53:41 -0400 -Subject: [PATCH 1/9] gnome-initial-setup: Bump GLib required version to 2.76 - -This gives us GStrvBuilder, g_ptr_array_sort_values, etc ---- - gnome-initial-setup/meson.build | 2 +- - meson.build | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/gnome-initial-setup/meson.build b/gnome-initial-setup/meson.build -index a6a014d1..64fa834a 100644 ---- a/gnome-initial-setup/meson.build -+++ b/gnome-initial-setup/meson.build -@@ -25,61 +25,61 @@ sources += [ - 'gis-driver.h', - 'gis-keyring.h' - ] - - geocode_glib_2_dep = dependency( - 'geocode-glib-2.0', - fallback: ['geocode-glib', 'geocode_glib_dep'], - default_options: [ - 'enable-gtk-doc=false', - 'enable-installed-tests=false', - 'enable-introspection=false', - 'soup2=false', - ], - ) - - gweather_dep = dependency('gweather4') - - subdir('pages') - - dependencies = [ - dependency ('libnm', version: '>= 1.2'), - dependency ('libnma-gtk4', version: '>= 1.0'), - dependency ('polkit-gobject-1', version: '>= 0.103'), - dependency ('accountsservice'), - geocode_glib_2_dep, - dependency ('gnome-desktop-4'), - dependency ('gsettings-desktop-schemas', version: '>= 3.37.1'), - dependency ('fontconfig'), - dependency ('goa-1.0'), - dependency ('gtk4', version: '>= 4.6'), -- dependency ('glib-2.0', version: '>= 2.63.1'), -+ dependency ('glib-2.0', version: '>= 2.76.0'), - dependency ('gio-unix-2.0', version: '>= 2.53.0'), - dependency ('gdm', version: '>= 3.8.3'), - gweather_dep, - dependency ('libgeoclue-2.0', version: '>= 2.3.1'), - cc.find_library('m', required: false), - dependency ('pango', version: '>= 1.32.5'), - dependency ('json-glib-1.0'), - dependency ('krb5'), - dependency ('libsecret-1', version: '>= 0.18.8'), - dependency ('pwquality'), - dependency ('rest-1.0'), - ibus_dep, - libmalcontent_dep, - libmalcontent_ui_dep, - libadwaita_dep, - webkitgtk_dep - ] - - executable( - 'gnome-initial-setup', - sources, - include_directories: config_h_dir, - dependencies: dependencies, - install: true, - install_dir: get_option('libexecdir') - ) - - executable( - 'gnome-initial-setup-copy-worker', - ['gnome-initial-setup-copy-worker.c'], -diff --git a/meson.build b/meson.build -index a1057988..7dd876e3 100644 ---- a/meson.build -+++ b/meson.build -@@ -3,62 +3,62 @@ project('gnome-initial-setup', - version: '45.beta', - license: 'GPL-2.0-or-later', - meson_version: '>= 0.53.0', - ) - - cc = meson.get_compiler('c') - gnome = import('gnome') - i18n = import('i18n') - - prefix = get_option('prefix') - po_dir = join_paths(meson.current_source_dir(), 'po') - bin_dir = join_paths(prefix, get_option('bindir')) - data_dir = join_paths(prefix, get_option('datadir')) - locale_dir = join_paths(prefix, get_option('localedir')) - libexec_dir = join_paths(prefix, get_option('libexecdir')) - sysconf_dir = join_paths(prefix, get_option('sysconfdir')) - pkgdata_dir = join_paths(data_dir, meson.project_name()) - pkgsysconf_dir = join_paths(sysconf_dir, meson.project_name()) - - conf = configuration_data() - conf.set_quoted('GETTEXT_PACKAGE', meson.project_name()) - conf.set_quoted('GNOMELOCALEDIR', locale_dir) - conf.set_quoted('PKGDATADIR', pkgdata_dir) - conf.set_quoted('DATADIR', data_dir) - conf.set_quoted('PKGSYSCONFDIR', pkgsysconf_dir) - conf.set_quoted('SYSCONFDIR', sysconf_dir) - conf.set_quoted('LIBEXECDIR', libexec_dir) - conf.set('SECRET_API_SUBJECT_TO_CHANGE', true) - conf.set_quoted('G_LOG_DOMAIN', 'InitialSetup') - conf.set('G_LOG_USE_STRUCTURED', true) --conf.set('GLIB_VERSION_MIN_REQUIRED', 'GLIB_VERSION_2_64') --conf.set('GLIB_VERSION_MAX_ALLOWED', 'GLIB_VERSION_2_64') -+conf.set('GLIB_VERSION_MIN_REQUIRED', 'GLIB_VERSION_2_76') -+conf.set('GLIB_VERSION_MAX_ALLOWED', 'GLIB_VERSION_2_76') - - enable_systemd = get_option('systemd') - if enable_systemd - systemd_dep = dependency('systemd', version: '>= 242', required: false) - assert(systemd_dep.found(), 'Systemd support explicitly required, but systemd not found') - - systemd_userunitdir = systemd_dep.get_variable(pkgconfig: 'systemduserunitdir', - pkgconfig_define: ['prefix', prefix]) - systemd_sysusersdir = systemd_dep.get_variable(pkgconfig: 'sysusersdir', - pkgconfig_define: ['prefix', prefix]) - endif - - vendor_conf_file = get_option('vendor-conf-file') - if vendor_conf_file != '' - conf.set_quoted('VENDOR_CONF_FILE', vendor_conf_file) - endif - - # Needed for the 'keyboard' page - ibus_dep = dependency ('ibus-1.0', - version: '>= 1.4.99', - required: get_option('ibus')) - have_ibus = ibus_dep.found() - conf.set('HAVE_IBUS', have_ibus) - - # Check for libadwaita before malcontent-ui, otherwise Meson may search and - # find an older version of libadwaita in the host system, cache it, and fail - # to fallback to a submodule. - libadwaita_dep = dependency( - 'libadwaita-1', - version: '>= 1.2.alpha', --- -2.41.0 - diff --git a/0002-keyboard-Don-t-require-localed-for-existing-user-mod.patch b/0002-keyboard-Don-t-require-localed-for-existing-user-mod.patch deleted file mode 100644 index 25d444d..0000000 --- a/0002-keyboard-Don-t-require-localed-for-existing-user-mod.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 1a15a39b5cc4cfa14f3b953c19b03901c923cbc1 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sat, 9 Sep 2023 17:07:46 -0400 -Subject: [PATCH 2/9] keyboard: Don't require localed for existing user mode - -If we're in existing user mode, the user may not have -permission to set the system keymap. - -This commit makes sure that lack of permission doesn't -prevent the keyboard page from completing. ---- - gnome-initial-setup/pages/keyboard/gis-keyboard-page.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c -index fa41230f..da384495 100644 ---- a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c -+++ b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c -@@ -388,62 +388,67 @@ preselect_input_source (GisKeyboardPage *self) - * - If we got nothing from gnome-desktop and there's no system-wide - * keyboard layout set, we don't preselect anything. - * - * See: - * - https://bugzilla.gnome.org/show_bug.cgi?id=776189 - * - https://gitlab.gnome.org/GNOME/gnome-initial-setup/-/issues/104 - */ - language = cc_common_language_get_current_language (); - - desktop_got_something = gnome_get_input_source_from_locale (language, &type, &id); - desktop_got_input_method = (desktop_got_something && g_strcmp0 (type, "xkb") != 0); - - if (desktop_got_something && (desktop_got_input_method || !priv->system_sources)) { - cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), - id, type); - } else if (priv->system_sources) { - cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), - (const gchar *) priv->system_sources->data, - "xkb"); - } - - g_free (language); - } - - static void - update_page_complete (GisKeyboardPage *self) - { - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); - gboolean complete; - -- complete = (priv->localed != NULL && -- cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)) != NULL); -+ if (gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER) { -+ complete = (priv->localed != NULL && -+ cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)) != NULL); -+ } else { -+ complete = cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)) != NULL; -+ } -+ - gis_page_set_complete (GIS_PAGE (self), complete); - } - - static void - localed_proxy_ready (GObject *source, - GAsyncResult *res, - gpointer data) - { - GisKeyboardPage *self = data; - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); - GDBusProxy *proxy; - GError *error = NULL; - - proxy = g_dbus_proxy_new_finish (res, &error); - - if (!proxy) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("Failed to contact localed: %s", error->message); - g_error_free (error); - return; - } - - priv->localed = proxy; - - preselect_input_source (self); - update_page_complete (self); - } - - static void - input_confirmed (CcInputChooser *chooser, --- -2.41.0 - diff --git a/0003-language-Don-t-proceed-until-localed-has-set-locale.patch b/0003-language-Don-t-proceed-until-localed-has-set-locale.patch deleted file mode 100644 index 6dc2f53..0000000 --- a/0003-language-Don-t-proceed-until-localed-has-set-locale.patch +++ /dev/null @@ -1,295 +0,0 @@ -From ec880bd018b4ff243baba1d44ac24ff3558b13b5 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 8 Sep 2023 11:02:39 -0400 -Subject: [PATCH 3/9] language: Don't proceed until localed has set locale - -In sysmte modes, the keyboard page requires reading the locale from -localed, so we need to make sure the setting has been applied before -proceeding to the keyboard page from the language page. - -This commit changes the Next button to desensitize if a set locale -operation is pending. ---- - .../pages/language/gis-language-page.c | 31 +++++++++++++++++-- - 1 file changed, 28 insertions(+), 3 deletions(-) - -diff --git a/gnome-initial-setup/pages/language/gis-language-page.c b/gnome-initial-setup/pages/language/gis-language-page.c -index 87b9f2d8..26a01257 100644 ---- a/gnome-initial-setup/pages/language/gis-language-page.c -+++ b/gnome-initial-setup/pages/language/gis-language-page.c -@@ -29,181 +29,204 @@ - #define GNOME_SYSTEM_LOCALE_DIR "org.gnome.system.locale" - #define REGION_KEY "region" - - #include "config.h" - #include "language-resources.h" - #include "gis-welcome-widget.h" - #include "cc-language-chooser.h" - #include "gis-language-page.h" - - #include - #include - #include - #include - - struct _GisLanguagePagePrivate - { - GtkWidget *logo; - GtkWidget *welcome_widget; - GtkWidget *language_chooser; - - GDBusProxy *localed; - GPermission *permission; - const gchar *new_locale_id; - - GCancellable *cancellable; - }; - typedef struct _GisLanguagePagePrivate GisLanguagePagePrivate; - - G_DEFINE_TYPE_WITH_PRIVATE (GisLanguagePage, gis_language_page, GIS_TYPE_PAGE); - -+static void -+on_locale_set (GDBusProxy *proxy, -+ GAsyncResult *result, -+ GisLanguagePage *self) -+{ -+ g_autoptr(GError) error = NULL; -+ g_autoptr(GVariant) call_result = NULL; -+ -+ call_result = g_dbus_proxy_call_finish (proxy, result, &error); -+ -+ if (error != NULL) { -+ g_warning ("Could not set system locale: %s", error->message); -+ } -+ -+ gis_page_set_complete (GIS_PAGE (self), TRUE); -+} -+ - static void - set_localed_locale (GisLanguagePage *self) - { - GisLanguagePagePrivate *priv = gis_language_page_get_instance_private (self); - GVariantBuilder *b; - gchar *s; - - b = g_variant_builder_new (G_VARIANT_TYPE ("as")); - s = g_strconcat ("LANG=", priv->new_locale_id, NULL); - g_variant_builder_add (b, "s", s); - g_free (s); - - g_dbus_proxy_call (priv->localed, - "SetLocale", - g_variant_new ("(asb)", b, TRUE), - G_DBUS_CALL_FLAGS_NONE, -- -1, NULL, NULL, NULL); -+ -1, priv->cancellable, -+ (GAsyncReadyCallback) on_locale_set, -+ self); - g_variant_builder_unref (b); - } - - static void - change_locale_permission_acquired (GObject *source, - GAsyncResult *res, - gpointer data) - { - GisLanguagePage *page = GIS_LANGUAGE_PAGE (data); - GisLanguagePagePrivate *priv = gis_language_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_locale (page); - } - - 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) { -+ -+ gis_page_set_complete (GIS_PAGE (page), FALSE); -+ - 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); - } - - static void - localed_proxy_ready (GObject *source, - GAsyncResult *res, - gpointer data) - { - GisLanguagePage *self = data; - GisLanguagePagePrivate *priv = gis_language_page_get_instance_private (self); - GDBusProxy *proxy; - GError *error = NULL; - - proxy = g_dbus_proxy_new_finish (res, &error); - - if (!proxy) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("Failed to contact localed: %s", error->message); - g_error_free (error); - return; - } - - priv->localed = proxy; -+ gis_page_set_complete (GIS_PAGE (self), TRUE); - } - - static void - update_distro_logo (GisLanguagePage *page) - { - GisLanguagePagePrivate *priv = gis_language_page_get_instance_private (page); - g_autofree char *id = g_get_os_info (G_OS_INFO_KEY_ID); - gsize i; - - static const struct { - const char *id; - const char *logo; - } id_to_logo[] = { - { "debian", "emblem-debian" }, - { "fedora", "fedora-logo-icon" }, - { "ubuntu", "ubuntu-logo-icon" }, - { "openSUSE Tumbleweed", "opensuse-logo-icon" }, - { "openSUSE Leap", "opensuse-logo-icon" }, - { "SLED", "suse-logo-icon" }, - { "SLES", "suse-logo-icon" }, - }; - - for (i = 0; i < G_N_ELEMENTS (id_to_logo); i++) - { - if (g_strcmp0 (id, id_to_logo[i].id) == 0) - { - g_object_set (priv->logo, "icon-name", id_to_logo[i].logo, NULL); - break; - } - } -@@ -224,62 +247,64 @@ gis_language_page_constructed (GObject *object) - 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) - { - 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); -+ else -+ { -+ 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); - GisLanguagePagePrivate *priv = gis_language_page_get_instance_private (page); - - g_clear_object (&priv->permission); - g_clear_object (&priv->localed); - g_clear_object (&priv->cancellable); - - G_OBJECT_CLASS (gis_language_page_parent_class)->dispose (object); - } - - static void - gis_language_page_class_init (GisLanguagePageClass *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-language-page.ui"); - --- -2.41.0 - diff --git a/0004-keyboard-Get-default-input-sources-from-gnome-deskto.patch b/0004-keyboard-Get-default-input-sources-from-gnome-deskto.patch deleted file mode 100644 index ab48af7..0000000 --- a/0004-keyboard-Get-default-input-sources-from-gnome-deskto.patch +++ /dev/null @@ -1,776 +0,0 @@ -From f34f6580a33b4e5e4073ea1ddf10e7a9b4aa751e Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 24 Aug 2023 21:19:40 -0400 -Subject: [PATCH 4/9] keyboard: Get default input sources from gnome-desktop - -Right now, we figure out the default input sources ourselves, -based on the current locale and layout information coming from -localed. - -This logic needs to be duplicated in several components, so its -now provided by gnome-desktop. - -This commit changes it over to use gnome-desktop APIs. - -The same time if leverages a gnome-desktop API to fix a bug -where cyrillic layouts were getting added without a latin -counterpart. ---- - .../pages/keyboard/gis-keyboard-page.c | 475 +++++++++--------- - 1 file changed, 239 insertions(+), 236 deletions(-) - -diff --git a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c -index da384495..f2bfe164 100644 ---- a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c -+++ b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c -@@ -17,508 +17,511 @@ - * Author: Sergey Udaltsov - * Michael Wood - * - * Based on gnome-control-center cc-region-panel.c - */ - - #define PAGE_ID "keyboard" - - #include "config.h" - - #include - #include - #include - #include - #include - - #define GNOME_DESKTOP_USE_UNSTABLE_API - #include - - #include "gis-keyboard-page.h" - #include "keyboard-resources.h" - #include "cc-input-chooser.h" - - #include "cc-common-language.h" - - #include "gis-page-header.h" - - #define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources" - #define KEY_CURRENT_INPUT_SOURCE "current" - #define KEY_INPUT_SOURCES "sources" -+#define KEY_MRU_SOURCES "mru-sources" -+#define KEY_INPUT_OPTIONS "xkb-options" - - struct _GisKeyboardPagePrivate { - GtkWidget *input_chooser; - - GDBusProxy *localed; - GCancellable *cancellable; - GPermission *permission; - GSettings *input_settings; -- -- GSList *system_sources; -+ char **default_input_source_ids; -+ char **default_input_source_types; -+ char **default_options; -+ char **system_layouts; -+ char **system_variants; -+ char **system_options; -+ -+ gboolean should_skip; - }; - typedef struct _GisKeyboardPagePrivate GisKeyboardPagePrivate; - - G_DEFINE_TYPE_WITH_PRIVATE (GisKeyboardPage, gis_keyboard_page, GIS_TYPE_PAGE); - - static void - gis_keyboard_page_finalize (GObject *object) - { - GisKeyboardPage *self = GIS_KEYBOARD_PAGE (object); - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); - - if (priv->cancellable) - g_cancellable_cancel (priv->cancellable); - g_clear_object (&priv->cancellable); - - g_clear_object (&priv->permission); - g_clear_object (&priv->localed); - g_clear_object (&priv->input_settings); -- -- g_slist_free_full (priv->system_sources, g_free); -+ g_clear_pointer (&priv->default_input_source_ids, g_strfreev); -+ g_clear_pointer (&priv->default_input_source_types, g_strfreev); -+ g_clear_pointer (&priv->default_options, g_strfreev); -+ g_clear_pointer (&priv->system_layouts, g_strfreev); -+ g_clear_pointer (&priv->system_variants, g_strfreev); -+ g_clear_pointer (&priv->system_options, g_strfreev); - - G_OBJECT_CLASS (gis_keyboard_page_parent_class)->finalize (object); - } - - static void --set_input_settings (GisKeyboardPage *self) -+add_defaults_to_variant_builder (GisKeyboardPage *self, -+ const char *already_added_type, -+ const char *already_added_id, -+ GVariantBuilder *input_source_builder, -+ char **default_layout) -+ - { - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); -- const gchar *type; -- const gchar *id; -- GVariantBuilder builder; -- GSList *l; -- gboolean is_xkb_source = FALSE; -+ size_t i; - -- 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)); -+ for (i = 0; priv->default_input_source_ids && priv->default_input_source_ids[i] != NULL; i++) { -+ if (g_strcmp0 (already_added_id, priv->default_input_source_ids[i]) == 0 && g_strcmp0 (already_added_type, priv->default_input_source_types[i]) == 0) { -+ continue; -+ } - -- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)")); -+ g_variant_builder_add (input_source_builder, "(ss)", priv->default_input_source_types[i], priv->default_input_source_ids[i]); - -- if (g_str_equal (type, "xkb")) { -- g_variant_builder_add (&builder, "(ss)", type, id); -- is_xkb_source = TRUE; -+ if (*default_layout != NULL) { -+ if (!gnome_input_source_is_non_latin (priv->default_input_source_types[i], priv->default_input_source_ids[i])) { -+ *default_layout = g_strdup (priv->default_input_source_ids[i]); -+ } -+ } - } -+} - -- for (l = priv->system_sources; l; l = l->next) { -- const gchar *sid = l->data; - -- if (g_str_equal (id, sid) && g_str_equal (type, "xkb")) -- continue; -+static void -+add_input_source_to_arrays (GisKeyboardPage *self, -+ const char *type, -+ const char *id, -+ GPtrArray *layouts_array, -+ GPtrArray *variants_array) -+{ -+ g_auto(GStrv) layout_and_variant = NULL; -+ const char *layout, *variant; -+ -+ if (!g_str_equal (type, "xkb")) { -+ return; -+ } -+ -+ layout_and_variant = g_strsplit (id, "+", -1); -+ -+ layout = layout_and_variant[0]; -+ variant = layout_and_variant[1]?: ""; -+ -+ if (g_ptr_array_find_with_equal_func (layouts_array, layout, g_str_equal, NULL) && -+ g_ptr_array_find_with_equal_func (variants_array, variant, g_str_equal, NULL)) { -+ return; -+ } -+ -+ g_ptr_array_add (layouts_array, g_strdup (layout)); -+ g_ptr_array_add (variants_array, g_strdup (variant)); -+} -+ -+static void -+add_defaults_to_arrays (GisKeyboardPage *self, -+ GPtrArray *layouts_array, -+ GPtrArray *variants_array) -+{ -+ GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); -+ size_t i; -+ -+ for (i = 0; priv->default_input_source_ids && priv->default_input_source_ids[i] != NULL; i++) { -+ add_input_source_to_arrays (self, priv->default_input_source_types[i], priv->default_input_source_ids[i], layouts_array, variants_array); -+ } -+} -+ -+static void -+set_input_settings (GisKeyboardPage *self, -+ const char *type, -+ const char *id) -+{ -+ GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); -+ g_autofree char *layout = NULL; -+ g_autofree char *variant = NULL; -+ g_autoptr(GVariant) default_input_sources = NULL; -+ g_autoptr(GVariant) input_sources = NULL; -+ g_autoptr(GPtrArray) layouts_array = NULL; -+ g_autoptr(GPtrArray) variants_array = NULL; -+ GVariantBuilder input_source_builder; -+ GVariantBuilder input_options_builder; -+ g_autoptr(GVariant) input_options = NULL; -+ gboolean is_system_mode; -+ size_t i; -+ g_autofree char *default_input_source_id = NULL; -+ -+ default_input_sources = g_settings_get_default_value (priv->input_settings, KEY_INPUT_SOURCES); -+ input_sources = g_settings_get_value (priv->input_settings, KEY_INPUT_SOURCES); -+ -+ if (!g_variant_equal (default_input_sources, input_sources)) -+ return; -+ -+ g_clear_pointer (&input_sources, g_variant_unref); -+ -+ g_variant_builder_init (&input_options_builder, G_VARIANT_TYPE ("as")); -+ -+ is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER; -+ -+ layouts_array = g_ptr_array_new (); -+ variants_array = g_ptr_array_new (); -+ -+ /* Notice the added latin layout (if relevant) gets put first for gsettings -+ * (input_source_builder and last for localed (layouts_array/variants_array) -+ * This ensures we get a cyrillic layout on ttys, but a latin layout by default -+ * in the UI. -+ */ -+ g_variant_builder_init (&input_source_builder, G_VARIANT_TYPE ("a(ss)")); -+ if (type != NULL && id != NULL) { -+ add_input_source_to_arrays (self, type, id, layouts_array, variants_array); -+ -+ if (gnome_input_source_is_non_latin (type, id)) { -+ default_input_source_id = g_strdup ("us"); -+ add_input_source_to_arrays (self, "xkb", default_input_source_id, layouts_array, variants_array); -+ g_variant_builder_add (&input_source_builder, "(ss)", "xkb", default_input_source_id); -+ } else { -+ default_input_source_id = g_strdup (id); -+ } - -- g_variant_builder_add (&builder, "(ss)", "xkb", sid); -+ g_variant_builder_add (&input_source_builder, "(ss)", type, id); - } - -- if (!is_xkb_source) -- g_variant_builder_add (&builder, "(ss)", type, id); -+ if (default_input_source_id == NULL || !is_system_mode) { -+ add_defaults_to_variant_builder (self, type, id, &input_source_builder, &default_input_source_id); -+ } -+ input_sources = g_variant_builder_end (&input_source_builder); -+ -+ for (i = 0; priv->default_options[i] != NULL; i++) { -+ g_variant_builder_add (&input_options_builder, "s", priv->default_options[i]); -+ } -+ input_options = g_variant_builder_end (&input_options_builder); -+ -+ add_defaults_to_arrays (self, layouts_array, variants_array); -+ g_ptr_array_add (layouts_array, NULL); -+ g_ptr_array_add (variants_array, NULL); -+ -+ priv->system_layouts = (char **) g_ptr_array_steal (layouts_array, NULL); -+ priv->system_variants = (char **) g_ptr_array_steal (variants_array, NULL); - -- g_settings_set_value (priv->input_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder)); -- g_settings_set_uint (priv->input_settings, KEY_CURRENT_INPUT_SOURCE, 0); -+ g_variant_get (input_options, "^as", &priv->system_options); -+ -+ g_settings_set_value (priv->input_settings, KEY_INPUT_SOURCES, g_steal_pointer (&input_sources)); -+ g_settings_set_value (priv->input_settings, KEY_INPUT_OPTIONS, g_steal_pointer (&input_options)); -+ -+ if (default_input_source_id != NULL) { -+ GVariantBuilder mru_input_source_builder; -+ -+ g_variant_builder_init (&mru_input_source_builder, G_VARIANT_TYPE ("a(ss)")); -+ g_variant_builder_add (&mru_input_source_builder, "(ss)", type, default_input_source_id); -+ g_settings_set_value (priv->input_settings, KEY_MRU_SOURCES, g_variant_builder_end (&mru_input_source_builder)); -+ } - -- g_settings_apply (priv->input_settings); -+ g_settings_apply (priv->input_settings); - } - - static void - set_localed_input (GisKeyboardPage *self) - { - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); -- const gchar *layout, *variant; -- GString *layouts; -- GString *variants; -- GSList *l; -+ g_autofree char *layouts = NULL; -+ g_autofree char *variants = NULL; -+ g_autofree char *options = NULL; - - if (!priv->localed) - return; - -- cc_input_chooser_get_layout (CC_INPUT_CHOOSER (priv->input_chooser), &layout, &variant); -- if (layout == NULL) -- layout = ""; -- if (variant == NULL) -- variant = ""; -- -- layouts = g_string_new (layout); -- variants = g_string_new (variant); -- --#define LAYOUT(a) (a[0]) --#define VARIANT(a) (a[1] ? a[1] : "") -- for (l = priv->system_sources; l; l = l->next) { -- const gchar *sid = l->data; -- gchar **lv = g_strsplit (sid, "+", -1); -- -- if (!g_str_equal (LAYOUT (lv), layout) || -- !g_str_equal (VARIANT (lv), variant)) { -- if (layouts->str[0]) { -- g_string_append_c (layouts, ','); -- g_string_append_c (variants, ','); -- } -- g_string_append (layouts, LAYOUT (lv)); -- g_string_append (variants, VARIANT (lv)); -- } -- g_strfreev (lv); -- } --#undef LAYOUT --#undef VARIANT -+ layouts = g_strjoinv (",", priv->system_layouts); -+ variants = g_strjoinv (",", priv->system_variants); -+ options = g_strjoinv (",", priv->system_options); - - g_dbus_proxy_call (priv->localed, - "SetX11Keyboard", -- g_variant_new ("(ssssbb)", layouts->str, "", variants->str, "", TRUE, TRUE), -+ g_variant_new ("(ssssbb)", layouts, "", variants, options, TRUE, TRUE), - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, NULL, NULL); -- g_string_free (layouts, TRUE); -- g_string_free (variants, TRUE); - } - - static void - change_locale_permission_acquired (GObject *source, - GAsyncResult *res, - gpointer data) - { - 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; - -- set_input_settings (self); -+ 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 (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 GSList * --get_localed_input (GDBusProxy *proxy) --{ -- GVariant *v; -- const gchar *s; -- gchar *id; -- guint i, n; -- gchar **layouts = NULL; -- gchar **variants = NULL; -- GSList *sources = NULL; -- -- v = g_dbus_proxy_get_cached_property (proxy, "X11Layout"); -- if (v) { -- s = g_variant_get_string (v, NULL); -- layouts = g_strsplit (s, ",", -1); -- g_variant_unref (v); -- } -- -- v = g_dbus_proxy_get_cached_property (proxy, "X11Variant"); -- if (v) { -- s = g_variant_get_string (v, NULL); -- if (s && *s) -- variants = g_strsplit (s, ",", -1); -- g_variant_unref (v); -- } -- -- if (variants && variants[0]) -- n = MIN (g_strv_length (layouts), g_strv_length (variants)); -- else if (layouts && layouts[0]) -- n = g_strv_length (layouts); -- else -- n = 0; -- -- for (i = 0; i < n && layouts[i][0]; i++) { -- if (variants && variants[i] && variants[i][0]) -- id = g_strdup_printf ("%s+%s", layouts[i], variants[i]); -- else -- id = g_strdup (layouts[i]); -- sources = g_slist_prepend (sources, id); -- } -- -- g_strfreev (variants); -- g_strfreev (layouts); -- -- return sources; --} -- - static void --add_default_keyboard_layout (GDBusProxy *proxy, -- GVariantBuilder *builder) -+add_default_input_sources (GisKeyboardPage *self) - { -- GSList *sources = get_localed_input (proxy); -- sources = g_slist_reverse (sources); -- -- for (; sources; sources = sources->next) -- g_variant_builder_add (builder, "(ss)", "xkb", -- (const gchar *) sources->data); -- -- g_slist_free_full (sources, g_free); --} -- --static void --add_default_input_sources (GisKeyboardPage *self, -- GDBusProxy *proxy) --{ -- const gchar *type; -- const gchar *id; -- gchar *language; -- GVariantBuilder builder; -- GSettings *input_settings; -- -- input_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR); -- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)")); -- -- add_default_keyboard_layout (proxy, &builder); -- -- /* add other input sources */ -- language = cc_common_language_get_current_language (); -- if (gnome_get_input_source_from_locale (language, &type, &id)) { -- if (!g_str_equal (type, "xkb")) -- g_variant_builder_add (&builder, "(ss)", type, id); -- } -- g_free (language); -- -- g_settings_delay (input_settings); -- g_settings_set_value (input_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder)); -- g_settings_set_uint (input_settings, KEY_CURRENT_INPUT_SOURCE, 0); -- g_settings_apply (input_settings); -- -- g_object_unref (input_settings); --} -- --static void --skip_proxy_ready (GObject *source, -- GAsyncResult *res, -- gpointer data) --{ -- GisKeyboardPage *self = data; -- GDBusProxy *proxy; -- GError *error = NULL; -- -- proxy = g_dbus_proxy_new_finish (res, &error); -- -- if (!proxy) { -- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) -- g_warning ("Failed to contact localed: %s", error->message); -- g_error_free (error); -- return; -- } -- -- add_default_input_sources (self, proxy); -- -- g_object_unref (proxy); -+ set_input_settings (self, NULL, NULL); - } - - static void - gis_keyboard_page_skip (GisPage *page) - { - GisKeyboardPage *self = GIS_KEYBOARD_PAGE (page); - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); - -- 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) skip_proxy_ready, -- self); -+ priv->should_skip = TRUE; -+ -+ if (priv->default_input_source_ids != NULL) -+ add_default_input_sources (self); - } - - static void - preselect_input_source (GisKeyboardPage *self) - { -- const gchar *type; -- const gchar *id; -- gchar *language; -- gboolean desktop_got_something; -- gboolean desktop_got_input_method; -+ const char *language = NULL; - - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); -- GSList *sources = get_localed_input (priv->localed); -- -- /* These will be added silently after the user selection when -- * writing out the settings. */ -- g_slist_free_full (priv->system_sources, g_free); -- priv->system_sources = g_slist_reverse (sources); -- -- /* We have two potential sources of information as to which -- * source to pre-select here: the keyboard layout that is -- * configured system-wide (read from priv->system_sources), -- * and a gnome-desktop function that lets us look up a default -- * input source for a given language. -- * -- * An important limitation here is that there is no system-wide -- * configuration for input methods, so if the best choice for the -- * language is an input method, we will only find it from the -- * gnome-desktop lookup. But if both sources give us keyboard layouts, -- * we want to prefer the one that's configured system-wide over the one -- * from gnome-desktop. -- * -- * So we first do the gnome-desktop lookup, and keep track of what we -- * got. -- * -- * - If we got an input method, we preselect that, and we're done. -- * - If we got a keyboard layout, and there's no system-wide keyboard -- * layout set, we preselect the layout we got from gnome-desktop. -- * - If we didn't get an input method from gnome-desktop and there -- * is a system-wide keyboard layout set, we preselect that. -- * - If we got nothing from gnome-desktop and there's no system-wide -- * keyboard layout set, we don't preselect anything. -- * -- * See: -- * - https://bugzilla.gnome.org/show_bug.cgi?id=776189 -- * - https://gitlab.gnome.org/GNOME/gnome-initial-setup/-/issues/104 -- */ -- language = cc_common_language_get_current_language (); - -- desktop_got_something = gnome_get_input_source_from_locale (language, &type, &id); -- desktop_got_input_method = (desktop_got_something && g_strcmp0 (type, "xkb") != 0); -+ language = cc_common_language_get_current_language (); - -- if (desktop_got_something && (desktop_got_input_method || !priv->system_sources)) { -- cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), -- id, type); -- } else if (priv->system_sources) { -- cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), -- (const gchar *) priv->system_sources->data, -- "xkb"); -+ /* We deduce the initial input source from language if we're in a system mode -+ * (where preexisting system configuration may be stale) or if the language -+ * requires an input method (because there is no way for system configuration -+ * to denote the need for an input method) -+ * -+ * If it's a non-system mode we can trust the system configuration is probably -+ * a better bet than a heuristic based on locale. -+ */ -+ if (language != NULL) { -+ gboolean got_input_source; -+ const char *id, *type; -+ -+ got_input_source = gnome_get_input_source_from_locale (language, &type, &id); -+ -+ if (got_input_source) { -+ gboolean is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER; -+ if (is_system_mode || g_str_equal (type, "ibus")) { -+ cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), -+ id, -+ type); -+ return; -+ } -+ } - } - -- g_free (language); -+ cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), -+ priv->default_input_source_ids[0], -+ priv->default_input_source_types[0]); - } - - static void - update_page_complete (GisKeyboardPage *self) - { - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); - gboolean complete; - - if (gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER) { - complete = (priv->localed != NULL && - cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)) != NULL); - } else { - complete = cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)) != NULL; - } - - gis_page_set_complete (GIS_PAGE (self), complete); - } - - static void - localed_proxy_ready (GObject *source, - GAsyncResult *res, - gpointer data) - { - GisKeyboardPage *self = data; - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); - GDBusProxy *proxy; - GError *error = NULL; - - proxy = g_dbus_proxy_new_finish (res, &error); - - if (!proxy) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("Failed to contact localed: %s", error->message); - g_error_free (error); - return; - } - - priv->localed = proxy; -- -- preselect_input_source (self); -- update_page_complete (self); -+ update_page_complete (self); - } - - static void - input_confirmed (CcInputChooser *chooser, - GisKeyboardPage *self) - { - gis_assistant_next_page (gis_driver_get_assistant (GIS_PAGE (self)->driver)); - } - - static void - input_changed (CcInputChooser *chooser, - GisKeyboardPage *self) - { - update_page_complete (self); - } - -+static void -+on_got_default_sources (GObject *source, -+ GAsyncResult *res, -+ gpointer data) -+{ -+ GisKeyboardPage *self = data; -+ GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); -+ g_autoptr (GError) error = NULL; -+ gboolean success = FALSE; -+ g_auto (GStrv) ids = NULL; -+ g_auto (GStrv) types = NULL; -+ g_auto (GStrv) options = NULL; -+ -+ success = gnome_get_default_input_sources_finish (res, &ids, &types, &options, &error); -+ -+ if (!success) { -+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) -+ g_warning ("Failed to fetch default input sources: %s", error->message); -+ return; -+ } -+ -+ priv->default_input_source_ids = g_steal_pointer (&ids); -+ priv->default_input_source_types = g_steal_pointer (&types); -+ priv->default_options = g_steal_pointer (&options); -+ -+ if (priv->should_skip) { -+ add_default_input_sources (self); -+ return; -+ } -+ -+ preselect_input_source (self); -+ update_page_complete (self); -+} -+ - 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) - 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; --- -2.41.0 - diff --git a/0005-driver-Specify-mode-via-flags-instead-of-boolean.patch b/0005-driver-Specify-mode-via-flags-instead-of-boolean.patch deleted file mode 100644 index 01cdf46..0000000 --- a/0005-driver-Specify-mode-via-flags-instead-of-boolean.patch +++ /dev/null @@ -1,633 +0,0 @@ -From 07f191dbc961b793fe9761f577d94f5f10502380 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 13 Aug 2023 09:09:56 -0400 -Subject: [PATCH 5/9] driver: Specify mode via flags instead of boolean - -At the moment we just have system mode and new user mode, -but we're actually going to want other modes (such as -live user mode) as well. - -Currently the code distinguishes between its two available -modes using a boolean `is_new_user`. That isn't extensible beyond -two modes, so this commit changes it use bit flags instead. ---- - gnome-initial-setup/gis-driver.c | 17 ++- - gnome-initial-setup/gis-driver.h | 8 +- - gnome-initial-setup/gnome-initial-setup.c | 128 +++++++++++++--------- - 3 files changed, 93 insertions(+), 60 deletions(-) - -diff --git a/gnome-initial-setup/gis-driver.c b/gnome-initial-setup/gis-driver.c -index 98b4fc3e..d3013063 100644 ---- a/gnome-initial-setup/gis-driver.c -+++ b/gnome-initial-setup/gis-driver.c -@@ -9,75 +9,74 @@ - * - * 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 "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" - --#define GIS_TYPE_DRIVER_MODE (gis_driver_mode_get_type ()) -- - /* 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 GEnumValue values[] = { -+ 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_ALL, "GIS_DRIVER_MODE_ALL", "all" }, - { 0, NULL, NULL } - }; -- enum_type_id = g_enum_register_static("GisDriverMode", values); -+ 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; - - GtkWindow *main_window; - GisAssistant *assistant; - - GdmClient *client; -@@ -624,61 +623,61 @@ gis_driver_get_property (GObject *object, - break; - case PROP_SMALL_SCREEN: - g_value_set_boolean (value, driver->small_screen); - break; - case PROP_PARENTAL_CONTROLS_ENABLED: - g_value_set_boolean (value, driver->parental_controls_enabled); - break; - case PROP_FULL_NAME: - g_value_set_string (value, driver->full_name); - break; - case PROP_AVATAR: - g_value_set_object (value, driver->avatar); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - } - - static void - gis_driver_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) - { - GisDriver *driver = GIS_DRIVER (object); - - switch ((GisDriverProperty) prop_id) - { - case PROP_MODE: -- driver->mode = g_value_get_enum (value); -+ driver->mode = g_value_get_flags (value); - break; - case PROP_USERNAME: - g_free (driver->username); - driver->username = g_value_dup_string (value); - break; - case PROP_PARENTAL_CONTROLS_ENABLED: - gis_driver_set_parental_controls_enabled (driver, g_value_get_boolean (value)); - break; - case PROP_FULL_NAME: - gis_driver_set_full_name (driver, g_value_get_string (value)); - break; - case PROP_AVATAR: - gis_driver_set_avatar (driver, g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - } - - static void - gis_driver_activate (GApplication *app) - { - GisDriver *driver = GIS_DRIVER (app); - - G_APPLICATION_CLASS (gis_driver_parent_class)->activate (app); - - gtk_window_present (GTK_WINDOW (driver->main_window)); - } - -@@ -826,64 +825,64 @@ gis_driver_init (GisDriver *driver) - static void - gis_driver_class_init (GisDriverClass *klass) - { - GApplicationClass *application_class = G_APPLICATION_CLASS (klass); - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->get_property = gis_driver_get_property; - gobject_class->set_property = gis_driver_set_property; - gobject_class->dispose = gis_driver_dispose; - gobject_class->finalize = gis_driver_finalize; - application_class->startup = gis_driver_startup; - application_class->activate = gis_driver_activate; - - signals[REBUILD_PAGES] = - g_signal_new ("rebuild-pages", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - signals[LOCALE_CHANGED] = - g_signal_new ("locale-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - obj_props[PROP_MODE] = -- g_param_spec_enum ("mode", "", "", -- GIS_TYPE_DRIVER_MODE, -- GIS_DRIVER_MODE_EXISTING_USER, -- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); -+ g_param_spec_flags ("mode", "", "", -+ GIS_TYPE_DRIVER_MODE, -+ GIS_DRIVER_MODE_EXISTING_USER, -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_props[PROP_USERNAME] = - g_param_spec_string ("username", "", "", - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - obj_props[PROP_SMALL_SCREEN] = - g_param_spec_boolean ("small-screen", "", "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - /** - * GisDriver:parental-controls-enabled: - * - * Whether parental controls are enabled for the main user. If this is %TRUE, - * two user accounts will be created when this page is saved: one for the main - * user (a child) which will be a standard account; and one for the parent - * which will be an administrative account. - * - * Since: 3.36 - */ - obj_props[PROP_PARENTAL_CONTROLS_ENABLED] = - g_param_spec_boolean ("parental-controls-enabled", - "Parental Controls Enabled", - "Whether parental controls are enabled for the main user.", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - - /** - * GisDriver:full-name: (nullable) -diff --git a/gnome-initial-setup/gis-driver.h b/gnome-initial-setup/gis-driver.h -index 9b935e24..b57db2e2 100644 ---- a/gnome-initial-setup/gis-driver.h -+++ b/gnome-initial-setup/gis-driver.h -@@ -4,74 +4,78 @@ - * - * 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 - */ - - #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, -- GIS_DRIVER_MODE_EXISTING_USER, -+ 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), - } 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); - - gboolean gis_driver_get_parental_controls_enabled (GisDriver *driver); - - void gis_driver_set_user_language (GisDriver *driver, - const gchar *lang_id, -diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c -index 113ded36..59955779 100644 ---- a/gnome-initial-setup/gnome-initial-setup.c -+++ b/gnome-initial-setup/gnome-initial-setup.c -@@ -29,228 +29,258 @@ - #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" - - #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" - - static gboolean force_existing_user_mode; - - static GPtrArray *skipped_pages; - - typedef GisPage *(*PreparePage) (GisDriver *driver); - - typedef struct { - const gchar *page_id; - PreparePage prepare_page_func; -- gboolean new_user_only; -+ GisDriverMode modes; - } PageData; - --#define PAGE(name, new_user_only) { #name, gis_prepare_ ## name ## _page, new_user_only } -+#define PAGE(name, modes) { #name, gis_prepare_ ## name ## _page, modes } - - static PageData page_table[] = { -- PAGE (welcome, FALSE), -- PAGE (language, FALSE), -- PAGE (keyboard, FALSE), -- PAGE (network, FALSE), -- PAGE (privacy, FALSE), -- PAGE (timezone, TRUE), -- PAGE (software, TRUE), -- PAGE (goa, FALSE), -- PAGE (account, TRUE), -- PAGE (password, TRUE), -+ 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 (privacy, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), -+ PAGE (timezone, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), -+ 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), - #ifdef HAVE_PARENTAL_CONTROLS -- PAGE (parental_controls, TRUE), -- PAGE (parent_password, TRUE), -+ 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, FALSE), -+ PAGE (summary, GIS_DRIVER_MODE_NEW_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 ** --strv_append (gchar **a, -- gchar **b) -+pages_to_skip_from_file (GisDriver *driver) - { -- guint n = g_strv_length (a); -- guint m = g_strv_length (b); -- -- a = g_renew (gchar *, a, n + m + 1); -- for (guint i = 0; i < m; i++) -- a[n + i] = g_strdup (b[i]); -- a[n + m] = NULL; -- -- return a; --} -- --static gchar ** --pages_to_skip_from_file (GisDriver *driver, -- gboolean is_new_user) --{ -- GStrv skip_pages = NULL; -- GStrv additional_skip_pages = NULL; -+ 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; - - /* 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 - * -+ * 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); -- additional_skip_pages = -- gis_driver_conf_get_string_list (driver, VENDOR_PAGES_GROUP, -- is_new_user ? VENDOR_EXISTING_USER_ONLY_KEY : VENDOR_NEW_USER_ONLY_KEY, -- NULL); -- -- if (!skip_pages && additional_skip_pages) { -- skip_pages = additional_skip_pages; -- } else if (skip_pages && additional_skip_pages) { -- skip_pages = strv_append (skip_pages, additional_skip_pages); -- g_strfreev (additional_skip_pages); -+ 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); -+ -+ driver_mode = gis_driver_get_mode (driver); -+ driver_mode_flags = g_flags_get_first_value (driver_mode_flags_class, driver_mode); -+ -+ mode_group = g_strdup_printf ("%s pages", driver_mode_flags->value_nick); -+ skip_pages = gis_driver_conf_get_string_list (driver, mode_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); -+ } -+ -+ other_modes = GIS_DRIVER_MODE_ALL & ~driver_mode; -+ while (other_modes) { -+ const GFlagsValue *other_mode_flags = g_flags_get_first_value (driver_mode_flags_class, other_modes); -+ -+ if (other_mode_flags != NULL) { -+ g_autofree char *vendor_key = g_strdup_printf ("%s_only", other_mode_flags->value_nick); -+ -+ skip_pages = gis_driver_conf_get_string_list (driver, VENDOR_PAGES_GROUP, -+ vendor_key, NULL); -+ -+ if (skip_pages != NULL) -+ { -+ g_strv_builder_addv (builder, (const char **) skip_pages); -+ g_clear_pointer (&skip_pages, g_strfreev); -+ } -+ -+ other_modes &= ~other_mode_flags->value; -+ } - } - -- return skip_pages; -+ return g_strv_builder_end (builder); - } - - static void - destroy_pages_after (GisAssistant *assistant, - GisPage *page) - { - GList *pages, *l, *next; - - pages = gis_assistant_get_all_pages (assistant); - - for (l = pages; l != NULL; l = l->next) - if (l->data == page) - break; - - l = l->next; - for (; l != NULL; l = next) { - next = l->next; - gis_assistant_remove_page (assistant, l->data); - } - } - - static void - destroy_page (gpointer data) - { - GtkWidget *assistant; - GisPage *page; - - page = data; - assistant = gtk_widget_get_ancestor (GTK_WIDGET (page), GIS_TYPE_ASSISTANT); - - if (assistant) - gis_assistant_remove_page (GIS_ASSISTANT (assistant), page); - } - - static void - rebuild_pages_cb (GisDriver *driver) - { - PageData *page_data; - GisPage *page; - GisAssistant *assistant; - GisPage *current_page; - gchar **skip_pages; -- gboolean is_new_user, skipped; -+ GisDriverMode driver_mode; -+ gboolean skipped; - - assistant = gis_driver_get_assistant (driver); - current_page = gis_assistant_get_current_page (assistant); - page_data = page_table; - - g_ptr_array_free (skipped_pages, TRUE); - skipped_pages = g_ptr_array_new_with_free_func (destroy_page); - - if (current_page != NULL) { - destroy_pages_after (assistant, current_page); - - for (page_data = page_table; page_data->page_id != NULL; ++page_data) - if (g_str_equal (page_data->page_id, GIS_PAGE_GET_CLASS (current_page)->page_id)) - break; - - ++page_data; - } - -- is_new_user = (gis_driver_get_mode (driver) == GIS_DRIVER_MODE_NEW_USER); -- skip_pages = pages_to_skip_from_file (driver, is_new_user); -+ 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->new_user_only && !is_new_user) || -+ 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 - return GIS_DRIVER_MODE_NEW_USER; - } - - static gboolean - initial_setup_disabled_by_anaconda (void) - { --- -2.41.0 - diff --git a/0006-gnome-initial-setup-Add-live-user-mode.patch b/0006-gnome-initial-setup-Add-live-user-mode.patch deleted file mode 100644 index 588e58b..0000000 --- a/0006-gnome-initial-setup-Add-live-user-mode.patch +++ /dev/null @@ -1,1783 +0,0 @@ -From 026a99057ae42b6aee41e8be486c56c63bbaeb43 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 13 Aug 2023 09:39:07 -0400 -Subject: [PATCH 6/9] 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 | 10 +- - .../pages/language/gis-language-page.c | 5 +- - gnome-initial-setup/pages/meson.build | 1 + - .../pages/password/gis-password-page.c | 6 + - 16 files changed, 635 insertions(+), 18 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 d3013063..b18a3808 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; - -@@ -764,61 +766,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 59955779..bc7a4ee9 100644 ---- a/gnome-initial-setup/gnome-initial-setup.c -+++ b/gnome-initial-setup/gnome-initial-setup.c -@@ -14,141 +14,146 @@ - * - * 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" - - 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; - - /* 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); - -@@ -250,130 +255,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 f2bfe164..7801667c 100644 ---- a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c -+++ b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c -@@ -160,61 +160,61 @@ add_defaults_to_arrays (GisKeyboardPage *self, - - static void - set_input_settings (GisKeyboardPage *self, - const char *type, - const char *id) - { - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); - g_autofree char *layout = NULL; - g_autofree char *variant = NULL; - g_autoptr(GVariant) default_input_sources = NULL; - g_autoptr(GVariant) input_sources = NULL; - g_autoptr(GPtrArray) layouts_array = NULL; - g_autoptr(GPtrArray) variants_array = NULL; - GVariantBuilder input_source_builder; - GVariantBuilder input_options_builder; - g_autoptr(GVariant) input_options = NULL; - gboolean is_system_mode; - size_t i; - g_autofree char *default_input_source_id = NULL; - - default_input_sources = g_settings_get_default_value (priv->input_settings, KEY_INPUT_SOURCES); - input_sources = g_settings_get_value (priv->input_settings, KEY_INPUT_SOURCES); - - if (!g_variant_equal (default_input_sources, input_sources)) - return; - - g_clear_pointer (&input_sources, g_variant_unref); - - g_variant_builder_init (&input_options_builder, G_VARIANT_TYPE ("as")); - -- is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER; -+ is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) & GIS_DRIVER_MODE_SYSTEM; - - layouts_array = g_ptr_array_new (); - variants_array = g_ptr_array_new (); - - /* Notice the added latin layout (if relevant) gets put first for gsettings - * (input_source_builder and last for localed (layouts_array/variants_array) - * This ensures we get a cyrillic layout on ttys, but a latin layout by default - * in the UI. - */ - g_variant_builder_init (&input_source_builder, G_VARIANT_TYPE ("a(ss)")); - if (type != NULL && id != NULL) { - add_input_source_to_arrays (self, type, id, layouts_array, variants_array); - - if (gnome_input_source_is_non_latin (type, id)) { - default_input_source_id = g_strdup ("us"); - add_input_source_to_arrays (self, "xkb", default_input_source_id, layouts_array, variants_array); - g_variant_builder_add (&input_source_builder, "(ss)", "xkb", default_input_source_id); - } else { - default_input_source_id = g_strdup (id); - } - - g_variant_builder_add (&input_source_builder, "(ss)", type, id); - } - - if (default_input_source_id == NULL || !is_system_mode) { - add_defaults_to_variant_builder (self, type, id, &input_source_builder, &default_input_source_id); - } - input_sources = g_variant_builder_end (&input_source_builder); - - for (i = 0; priv->default_options[i] != NULL; i++) { -@@ -274,61 +274,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) - { - set_input_settings (self, NULL, NULL); - } - - static void - gis_keyboard_page_skip (GisPage *page) - { - GisKeyboardPage *self = GIS_KEYBOARD_PAGE (page); - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); -@@ -336,82 +336,82 @@ gis_keyboard_page_skip (GisPage *page) - priv->should_skip = TRUE; - - if (priv->default_input_source_ids != NULL) - add_default_input_sources (self); - } - - static void - preselect_input_source (GisKeyboardPage *self) - { - const char *language = NULL; - - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); - - language = cc_common_language_get_current_language (); - - /* We deduce the initial input source from language if we're in a system mode - * (where preexisting system configuration may be stale) or if the language - * requires an input method (because there is no way for system configuration - * to denote the need for an input method) - * - * If it's a non-system mode we can trust the system configuration is probably - * a better bet than a heuristic based on locale. - */ - if (language != NULL) { - gboolean got_input_source; - const char *id, *type; - - got_input_source = gnome_get_input_source_from_locale (language, &type, &id); - - if (got_input_source) { -- gboolean is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER; -+ gboolean is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) & GIS_DRIVER_MODE_SYSTEM; - if (is_system_mode || g_str_equal (type, "ibus")) { - cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), - id, - type); - return; - } - } - } - - cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), - priv->default_input_source_ids[0], - priv->default_input_source_types[0]); - } - - static void - update_page_complete (GisKeyboardPage *self) - { - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); - gboolean complete; - -- 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) { - complete = (priv->localed != NULL && - cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)) != NULL); - } else { - complete = cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)) != NULL; - } - - gis_page_set_complete (GIS_PAGE (self), complete); - } - - static void - localed_proxy_ready (GObject *source, - GAsyncResult *res, - gpointer data) - { - GisKeyboardPage *self = data; - GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); - GDBusProxy *proxy; - GError *error = NULL; - - proxy = g_dbus_proxy_new_finish (res, &error); - - if (!proxy) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("Failed to contact localed: %s", error->message); - g_error_free (error); - return; - } - - priv->localed = proxy; - update_page_complete (self); -@@ -469,61 +469,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 26a01257..17117fa1 100644 ---- a/gnome-initial-setup/pages/language/gis-language-page.c -+++ b/gnome-initial-setup/pages/language/gis-language-page.c -@@ -118,61 +118,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) { - - gis_page_set_complete (GIS_PAGE (page), FALSE); - - 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), -@@ -230,62 +230,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); - } - else - { - 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) -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 - diff --git a/0007-initial-setup-Don-t-show-duplicated-pages-between-mo.patch b/0007-initial-setup-Don-t-show-duplicated-pages-between-mo.patch deleted file mode 100644 index f7e7173..0000000 --- a/0007-initial-setup-Don-t-show-duplicated-pages-between-mo.patch +++ /dev/null @@ -1,539 +0,0 @@ -From 53f42c970a1233c84dcc80667a096eb428f27592 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 16 Aug 2023 10:47:13 -0400 -Subject: [PATCH 7/9] initial-setup: Don't show duplicated pages between modes - -It's possible a user just got asked questions in live mode -before install that they'll then get asked again on first -boot when the initial user is created. - -This commit tracks that information so it doesn't get reasked. ---- - data/meson.build | 6 +++ - gnome-initial-setup/gis-driver.c | 3 ++ - gnome-initial-setup/gnome-initial-setup.c | 65 +++++++++++++++++++++++ - meson.build | 4 ++ - 4 files changed, 78 insertions(+) - -diff --git a/data/meson.build b/data/meson.build -index 6a4ef7df..0bfccf56 100644 ---- a/data/meson.build -+++ b/data/meson.build -@@ -103,30 +103,36 @@ if enable_systemd - install_data('gnome-initial-setup.conf', install_dir: systemd_sysusersdir) - endif - - - rules_dir = join_paths(data_dir, 'polkit-1', 'rules.d') - configure_file( - input: '20-gnome-initial-setup.rules.in', - output: '20-gnome-initial-setup.rules', - install: true, - install_dir: rules_dir, - configuration: data_conf, - ) - - session_dir = join_paths(data_dir, 'gnome-session', 'sessions') - configure_file( - input: '@0@.session.in'.format(meson.project_name()), - output: '@BASENAME@', - configuration: { - 'this_component': meson.project_name(), - 'gnome_session_required_components': ';'.join([ - gis_shell_component, - meson.project_name(), - ] + - gis_gnome_session_required_components), - }, - install_dir: session_dir, - ) - - mode_dir = join_paths(data_dir, 'gnome-shell', 'modes') - install_data('initial-setup.json', install_dir: mode_dir) -+ -+install_subdir( -+ 'gnome-initial-setup', -+ install_dir : working_dir, -+ strip_directory : true -+) -diff --git a/gnome-initial-setup/gis-driver.c b/gnome-initial-setup/gis-driver.c -index b18a3808..41cd6e38 100644 ---- a/gnome-initial-setup/gis-driver.c -+++ b/gnome-initial-setup/gis-driver.c -@@ -80,90 +80,93 @@ struct _GisDriver { - - GtkWindow *main_window; - GisAssistant *assistant; - - GdmClient *client; - GdmGreeter *greeter; - GdmUserVerifier *user_verifier; - - ActUser *user_account; - gchar *user_password; - - ActUser *parent_account; /* (owned) (nullable) */ - gchar *parent_password; /* (owned) (nullable) */ - - gboolean parental_controls_enabled; - - gchar *lang_id; - gchar *username; - gchar *full_name; /* (owned) (nullable) */ - - GdkPaintable *avatar; /* (owned) (nullable) */ - - GisDriverMode mode; - UmAccountMode account_mode; - gboolean small_screen; - - locale_t locale; - - const gchar *vendor_conf_file_path; - GKeyFile *vendor_conf_file; -+ -+ GKeyFile *state_file; - }; - - G_DEFINE_TYPE (GisDriver, gis_driver, ADW_TYPE_APPLICATION) - - static void - gis_driver_dispose (GObject *object) - { - GisDriver *driver = GIS_DRIVER (object); - - g_clear_object (&driver->user_verifier); - g_clear_object (&driver->greeter); - g_clear_object (&driver->client); - - G_OBJECT_CLASS (gis_driver_parent_class)->dispose (object); - } - - static void - gis_driver_finalize (GObject *object) - { - GisDriver *driver = GIS_DRIVER (object); - - g_free (driver->lang_id); - g_free (driver->username); - g_free (driver->full_name); - g_free (driver->user_password); - - g_clear_object (&driver->avatar); - - g_clear_object (&driver->user_account); - g_clear_pointer (&driver->vendor_conf_file, g_key_file_free); -+ g_clear_pointer (&driver->state_file, g_key_file_free); - - g_clear_object (&driver->parent_account); - g_free (driver->parent_password); - - if (driver->locale != (locale_t) 0) - { - uselocale (LC_GLOBAL_LOCALE); - freelocale (driver->locale); - } - - G_OBJECT_CLASS (gis_driver_parent_class)->finalize (object); - } - - static void - assistant_page_changed (GtkScrolledWindow *sw) - { - gtk_adjustment_set_value (gtk_scrolled_window_get_vadjustment (sw), 0); - } - - static void - prepare_main_window (GisDriver *driver) - { - GtkWidget *child, *sw; - - child = gtk_window_get_child (GTK_WINDOW (driver->main_window)); - g_object_ref (child); - gtk_window_set_child (GTK_WINDOW (driver->main_window), NULL); - sw = gtk_scrolled_window_new (); - gtk_window_set_child (GTK_WINDOW (driver->main_window), sw); - gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child); -diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c -index bc7a4ee9..2bd2d375 100644 ---- a/gnome-initial-setup/gnome-initial-setup.c -+++ b/gnome-initial-setup/gnome-initial-setup.c -@@ -22,60 +22,62 @@ - #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_ALL), - PAGE (privacy, 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), - /* 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), -@@ -94,60 +96,61 @@ should_skip_page (const gchar *page_id, - 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 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) - { -@@ -162,60 +165,80 @@ pages_to_skip_from_file (GisDriver *driver) - - mode_group = g_strdup_printf ("%s pages", driver_mode_flags->value_nick); - skip_pages = gis_driver_conf_get_string_list (driver, mode_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); - } - - other_modes = GIS_DRIVER_MODE_ALL & ~driver_mode; - while (other_modes) { - const GFlagsValue *other_mode_flags = g_flags_get_first_value (driver_mode_flags_class, other_modes); - - if (other_mode_flags != NULL) { - g_autofree char *vendor_key = g_strdup_printf ("%s_only", other_mode_flags->value_nick); - - skip_pages = gis_driver_conf_get_string_list (driver, VENDOR_PAGES_GROUP, - vendor_key, NULL); - - if (skip_pages != NULL) - { - g_strv_builder_addv (builder, (const char **) skip_pages); - g_clear_pointer (&skip_pages, g_strfreev); - } - - other_modes &= ~other_mode_flags->value; - } - } - -+ /* Also, if this is a system mode, we check if the user already answered questions earlier in -+ * a different system mode, and skip those pages too. -+ */ -+ if (driver_mode & GIS_DRIVER_MODE_NEW_USER) { -+ g_autoptr(GKeyFile) state = NULL; -+ gboolean state_loaded; -+ -+ state = g_key_file_new (); -+ state_loaded = g_key_file_load_from_file (state, STATE_FILE, G_KEY_FILE_NONE, &error); -+ -+ if (state_loaded) { -+ skip_pages = g_key_file_get_string_list (state, VENDOR_PAGES_GROUP, VENDOR_SKIP_KEY, NULL, NULL); -+ -+ if (skip_pages != NULL) { -+ g_strv_builder_addv (builder, (const char **) skip_pages); -+ g_clear_pointer (&skip_pages, g_strfreev); -+ } -+ } -+ } -+ - return g_strv_builder_end (builder); - } - - static void - destroy_pages_after (GisAssistant *assistant, - GisPage *page) - { - GList *pages, *l, *next; - - pages = gis_assistant_get_all_pages (assistant); - - for (l = pages; l != NULL; l = l->next) - if (l->data == page) - break; - - l = l->next; - for (; l != NULL; l = next) { - next = l->next; - gis_assistant_remove_page (assistant, l->data); - } - } - - static void - destroy_page (gpointer data) - { - GtkWidget *assistant; - GisPage *page; - - page = data; - assistant = gtk_widget_get_ancestor (GTK_WIDGET (page), GIS_TYPE_ASSISTANT); -@@ -371,59 +394,101 @@ main (int argc, char *argv[]) - * 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); - status = g_application_run (G_APPLICATION (driver), argc, argv); - - g_ptr_array_free (skipped_pages, TRUE); - - g_object_unref (driver); - g_option_context_free (context); - return status; - } - -+static void -+write_state (GisDriver *driver) -+{ -+ g_autoptr(GKeyFile) state = NULL; -+ g_autoptr(GError) error = NULL; -+ g_autoptr(GStrvBuilder) builder = NULL; -+ g_auto(GStrv) visited_pages = NULL; -+ GisAssistant *assistant; -+ GList *pages, *node; -+ -+ assistant = gis_driver_get_assistant (driver); -+ -+ if (assistant == NULL) -+ return; -+ -+ state = g_key_file_new (); -+ -+ builder = g_strv_builder_new (); -+ -+ pages = gis_assistant_get_all_pages (assistant); -+ for (node = pages; node != NULL; node = node->next) { -+ GisPage *page = node->data; -+ g_strv_builder_add (builder, GIS_PAGE_GET_CLASS (page)->page_id); -+ } -+ -+ visited_pages = g_strv_builder_end (builder); -+ -+ g_key_file_set_string_list (state, -+ VENDOR_PAGES_GROUP, -+ VENDOR_SKIP_KEY, -+ (const char * const *) -+ visited_pages, -+ g_strv_length (visited_pages)); -+ -+ if (!g_key_file_save_to_file (state, STATE_FILE, &error)) { -+ g_warning ("Unable to save state to %s: %s", STATE_FILE, error->message); -+ return; -+ } -+} -+ - void - gis_ensure_stamp_files (GisDriver *driver) - { - g_autofree gchar *done_file = NULL; - g_autoptr(GError) error = NULL; - - done_file = g_build_filename (g_get_user_config_dir (), "gnome-initial-setup-done", NULL); - if (!g_file_set_contents (done_file, "yes", -1, &error)) { - g_warning ("Unable to create %s: %s", done_file, error->message); - g_clear_error (&error); - } -+ -+ write_state (driver); - } - - /** - * gis_get_mock_mode: - * - * Gets whether gnome-initial-setup has been built for development, and hence - * shouldn’t permanently change any system configuration. - * - * By default, mock mode is enabled when running in a build environment. This - * heuristic may be changed in future. - * - * Returns: %TRUE if in mock mode, %FALSE otherwise - */ - gboolean - gis_get_mock_mode (void) - { - return (g_getenv ("UNDER_JHBUILD") != NULL); - } -diff --git a/meson.build b/meson.build -index 7dd876e3..7058e6cf 100644 ---- a/meson.build -+++ b/meson.build -@@ -1,59 +1,63 @@ - project('gnome-initial-setup', - ['c'], - version: '45.beta', - license: 'GPL-2.0-or-later', - meson_version: '>= 0.53.0', - ) - - cc = meson.get_compiler('c') - gnome = import('gnome') - i18n = import('i18n') - - prefix = get_option('prefix') - po_dir = join_paths(meson.current_source_dir(), 'po') - bin_dir = join_paths(prefix, get_option('bindir')) - data_dir = join_paths(prefix, get_option('datadir')) - locale_dir = join_paths(prefix, get_option('localedir')) -+localstate_dir = join_paths(prefix, get_option('localstatedir')) - libexec_dir = join_paths(prefix, get_option('libexecdir')) - sysconf_dir = join_paths(prefix, get_option('sysconfdir')) - pkgdata_dir = join_paths(data_dir, meson.project_name()) - pkgsysconf_dir = join_paths(sysconf_dir, meson.project_name()) -+working_dir = join_paths(localstate_dir, 'lib', 'gnome-initial-setup') - - conf = configuration_data() - conf.set_quoted('GETTEXT_PACKAGE', meson.project_name()) - conf.set_quoted('GNOMELOCALEDIR', locale_dir) - conf.set_quoted('PKGDATADIR', pkgdata_dir) - conf.set_quoted('DATADIR', data_dir) -+conf.set_quoted('LOCALSTATEDIR', localstate_dir) - conf.set_quoted('PKGSYSCONFDIR', pkgsysconf_dir) - conf.set_quoted('SYSCONFDIR', sysconf_dir) - conf.set_quoted('LIBEXECDIR', libexec_dir) -+conf.set_quoted('GIS_WORKING_DIR', working_dir) - conf.set('SECRET_API_SUBJECT_TO_CHANGE', true) - conf.set_quoted('G_LOG_DOMAIN', 'InitialSetup') - conf.set('G_LOG_USE_STRUCTURED', true) - conf.set('GLIB_VERSION_MIN_REQUIRED', 'GLIB_VERSION_2_76') - conf.set('GLIB_VERSION_MAX_ALLOWED', 'GLIB_VERSION_2_76') - - enable_systemd = get_option('systemd') - if enable_systemd - systemd_dep = dependency('systemd', version: '>= 242', required: false) - assert(systemd_dep.found(), 'Systemd support explicitly required, but systemd not found') - - systemd_userunitdir = systemd_dep.get_variable(pkgconfig: 'systemduserunitdir', - pkgconfig_define: ['prefix', prefix]) - systemd_sysusersdir = systemd_dep.get_variable(pkgconfig: 'sysusersdir', - pkgconfig_define: ['prefix', prefix]) - endif - - vendor_conf_file = get_option('vendor-conf-file') - if vendor_conf_file != '' - conf.set_quoted('VENDOR_CONF_FILE', vendor_conf_file) - endif - - # Needed for the 'keyboard' page - ibus_dep = dependency ('ibus-1.0', - version: '>= 1.4.99', - required: get_option('ibus')) - have_ibus = ibus_dep.found() - conf.set('HAVE_IBUS', have_ibus) - - # Check for libadwaita before malcontent-ui, otherwise Meson may search and --- -2.41.0 - diff --git a/0008-polkit-Add-fedora-specfic-rules.patch b/0008-polkit-Add-fedora-specfic-rules.patch deleted file mode 100644 index 89d15c4..0000000 --- a/0008-polkit-Add-fedora-specfic-rules.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 2706720a58dba752ca0dbc65d7f1425df7db3bda Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Sun, 13 Aug 2023 16:33:49 -0400 -Subject: [PATCH 8/9] polkit: Add fedora specfic rules - -We should probably add some way to check vendor.conf for the policy -updates instead of a hardcoded list. ---- - data/20-gnome-initial-setup.rules.in | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/data/20-gnome-initial-setup.rules.in b/data/20-gnome-initial-setup.rules.in -index 881efde9..f5b7d981 100644 ---- a/data/20-gnome-initial-setup.rules.in -+++ b/data/20-gnome-initial-setup.rules.in -@@ -1,30 +1,31 @@ - // -*- 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.freedesktop.login1.reboot') === 0); -+ action.id.indexOf('org.freedesktop.login1.reboot') === 0 || -+ action.id.indexOf('org.fedoraproject.pkexec.liveinst') === 0); - - if (actionMatches) { - if (subject.local) - return 'yes'; - else - return 'auth_admin'; - } - - return undefined; - }); --- -2.41.0 - diff --git a/0009-gnome-initial-setup-Read-etc-sysconfig-anaconda.patch b/0009-gnome-initial-setup-Read-etc-sysconfig-anaconda.patch deleted file mode 100644 index c7a33d1..0000000 --- a/0009-gnome-initial-setup-Read-etc-sysconfig-anaconda.patch +++ /dev/null @@ -1,117 +0,0 @@ -From d42637a6f59981bac75a55eaee8fd1fc3b251e02 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 22 Aug 2023 13:51:40 -0400 -Subject: [PATCH 9/9] gnome-initial-setup: Read /etc/sysconfig/anaconda - -Just as /var/lib/gnome-initial-setup/state may show pages the user has -already answered, on Fedora, /etc/sysconfig/anaconda shows pages the user has -already answered via Anaconda. - -This commit skips those from the --new-user mode as well. ---- - gnome-initial-setup/gnome-initial-setup.c | 23 +++++++++++++++++++++++ - 1 file changed, 23 insertions(+) - -diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c -index 2bd2d375..474dfc58 100644 ---- a/gnome-initial-setup/gnome-initial-setup.c -+++ b/gnome-initial-setup/gnome-initial-setup.c -@@ -171,72 +171,95 @@ pages_to_skip_from_file (GisDriver *driver) - g_strv_builder_addv (builder, (const char **) skip_pages); - g_clear_pointer (&skip_pages, g_strfreev); - } - - other_modes = GIS_DRIVER_MODE_ALL & ~driver_mode; - while (other_modes) { - const GFlagsValue *other_mode_flags = g_flags_get_first_value (driver_mode_flags_class, other_modes); - - if (other_mode_flags != NULL) { - g_autofree char *vendor_key = g_strdup_printf ("%s_only", other_mode_flags->value_nick); - - skip_pages = gis_driver_conf_get_string_list (driver, VENDOR_PAGES_GROUP, - vendor_key, NULL); - - if (skip_pages != NULL) - { - g_strv_builder_addv (builder, (const char **) skip_pages); - g_clear_pointer (&skip_pages, g_strfreev); - } - - other_modes &= ~other_mode_flags->value; - } - } - - /* Also, if this is a system mode, we check if the user already answered questions earlier in - * a different system mode, and skip those pages too. - */ - if (driver_mode & GIS_DRIVER_MODE_NEW_USER) { - g_autoptr(GKeyFile) state = NULL; - gboolean state_loaded; -+ g_autoptr(GKeyFile) anaconda = NULL; -+ gboolean anaconda_loaded; - - state = g_key_file_new (); - state_loaded = g_key_file_load_from_file (state, STATE_FILE, G_KEY_FILE_NONE, &error); - - if (state_loaded) { - skip_pages = g_key_file_get_string_list (state, VENDOR_PAGES_GROUP, VENDOR_SKIP_KEY, NULL, NULL); - - if (skip_pages != NULL) { - g_strv_builder_addv (builder, (const char **) skip_pages); - g_clear_pointer (&skip_pages, g_strfreev); - } - } -+ -+ anaconda = g_key_file_new (); -+ anaconda_loaded = g_key_file_load_from_file (anaconda, "/etc/sysconfig/anaconda", G_KEY_FILE_NONE, NULL); -+ -+ if (anaconda_loaded) { -+ struct { -+ const char *spoke_name; -+ const char *page_name; -+ } spoke_page_map[] = { -+ { "WelcomeLanguageSpoke", "language" }, -+ { "DatetimeSpoke", "timezone" }, -+ { "KeyboardSpoke", "keyboard" }, -+ { NULL, NULL } -+ }; -+ size_t i; -+ -+ for (i = 0; spoke_page_map[i].spoke_name != NULL; i++) { -+ if (g_key_file_get_boolean (anaconda, spoke_page_map[i].spoke_name, "visited", NULL)) -+ g_strv_builder_add (builder, spoke_page_map[i].page_name); -+ } -+ } - } - - return g_strv_builder_end (builder); - } - - static void - destroy_pages_after (GisAssistant *assistant, - GisPage *page) - { - GList *pages, *l, *next; - - pages = gis_assistant_get_all_pages (assistant); - - for (l = pages; l != NULL; l = l->next) - if (l->data == page) - break; - - l = l->next; - for (; l != NULL; l = next) { - next = l->next; - gis_assistant_remove_page (assistant, l->data); - } - } - - static void - destroy_page (gpointer data) - { - GtkWidget *assistant; - GisPage *page; - --- -2.41.0 - diff --git a/gnome-initial-setup.spec b/gnome-initial-setup.spec index f2c043f..c5b8064 100644 --- a/gnome-initial-setup.spec +++ b/gnome-initial-setup.spec @@ -17,16 +17,8 @@ URL: https://wiki.gnome.org/Design/OS/InitialSetup Source0: https://download.gnome.org/sources/%{name}/45/%{name}-%{tarball_version}.tar.xz Source1: vendor.conf -Patch: 0001-gnome-initial-setup-Bump-GLib-required-version-to-2..patch -Patch: 0002-keyboard-Don-t-require-localed-for-existing-user-mod.patch -Patch: 0003-language-Don-t-proceed-until-localed-has-set-locale.patch -Patch: 0004-keyboard-Get-default-input-sources-from-gnome-deskto.patch -Patch: 0005-driver-Specify-mode-via-flags-instead-of-boolean.patch -Patch: 0006-gnome-initial-setup-Add-live-user-mode.patch -Patch: 0007-initial-setup-Don-t-show-duplicated-pages-between-mo.patch -Patch: 0008-polkit-Add-fedora-specfic-rules.patch -Patch: 0009-gnome-initial-setup-Read-etc-sysconfig-anaconda.patch - +# https://gitlab.gnome.org/GNOME/gnome-initial-setup/-/merge_requests/200 +Patch: live-user-mode.patch BuildRequires: desktop-file-utils BuildRequires: gcc diff --git a/live-user-mode.patch b/live-user-mode.patch new file mode 100644 index 0000000..e08ceb6 --- /dev/null +++ b/live-user-mode.patch @@ -0,0 +1,2480 @@ +From e51d40084fe304ba78404354e9aed00396954bdd Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 15 Aug 2023 10:53:41 -0400 +Subject: [PATCH 01/10] gnome-initial-setup: Bump GLib required version to 2.76 + +This gives us GStrvBuilder, g_ptr_array_sort_values, etc +--- + gnome-initial-setup/meson.build | 2 +- + meson.build | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/gnome-initial-setup/meson.build b/gnome-initial-setup/meson.build +index a6a014d1..64fa834a 100644 +--- a/gnome-initial-setup/meson.build ++++ b/gnome-initial-setup/meson.build +@@ -52,7 +52,7 @@ dependencies = [ + dependency ('fontconfig'), + dependency ('goa-1.0'), + dependency ('gtk4', version: '>= 4.6'), +- dependency ('glib-2.0', version: '>= 2.63.1'), ++ dependency ('glib-2.0', version: '>= 2.76.0'), + dependency ('gio-unix-2.0', version: '>= 2.53.0'), + dependency ('gdm', version: '>= 3.8.3'), + gweather_dep, +diff --git a/meson.build b/meson.build +index 2e40a2e2..fba4d96a 100644 +--- a/meson.build ++++ b/meson.build +@@ -30,8 +30,8 @@ conf.set_quoted('LIBEXECDIR', libexec_dir) + conf.set('SECRET_API_SUBJECT_TO_CHANGE', true) + conf.set_quoted('G_LOG_DOMAIN', 'InitialSetup') + conf.set('G_LOG_USE_STRUCTURED', true) +-conf.set('GLIB_VERSION_MIN_REQUIRED', 'GLIB_VERSION_2_64') +-conf.set('GLIB_VERSION_MAX_ALLOWED', 'GLIB_VERSION_2_64') ++conf.set('GLIB_VERSION_MIN_REQUIRED', 'GLIB_VERSION_2_76') ++conf.set('GLIB_VERSION_MAX_ALLOWED', 'GLIB_VERSION_2_76') + + enable_systemd = get_option('systemd') + if enable_systemd +-- +GitLab + + +From b729f698befddefb9618aa8399ade5306486dd9f Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sat, 9 Sep 2023 17:07:46 -0400 +Subject: [PATCH 02/10] keyboard: Don't require localed for existing user mode + +If we're in existing user mode, the user may not have +permission to set the system keymap. + +This commit makes sure that lack of permission doesn't +prevent the keyboard page from completing. +--- + gnome-initial-setup/pages/keyboard/gis-keyboard-page.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c +index fa41230f..da384495 100644 +--- a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c ++++ b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c +@@ -415,8 +415,13 @@ update_page_complete (GisKeyboardPage *self) + GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); + gboolean complete; + +- complete = (priv->localed != NULL && +- cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)) != NULL); ++ if (gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER) { ++ complete = (priv->localed != NULL && ++ cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)) != NULL); ++ } else { ++ complete = cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)) != NULL; ++ } ++ + gis_page_set_complete (GIS_PAGE (self), complete); + } + +-- +GitLab + + +From 2f5bf8a8203c0b12937c8be0fb536dd8f28f2fca Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Fri, 8 Sep 2023 11:02:39 -0400 +Subject: [PATCH 03/10] language: Don't proceed until localed has set locale + +In sysmte modes, the keyboard page requires reading the locale from +localed, so we need to make sure the setting has been applied before +proceeding to the keyboard page from the language page. + +This commit changes the Next button to desensitize if a set locale +operation is pending. +--- + .../pages/language/gis-language-page.c | 31 +++++++++++++++++-- + 1 file changed, 28 insertions(+), 3 deletions(-) + +diff --git a/gnome-initial-setup/pages/language/gis-language-page.c b/gnome-initial-setup/pages/language/gis-language-page.c +index 87b9f2d8..26a01257 100644 +--- a/gnome-initial-setup/pages/language/gis-language-page.c ++++ b/gnome-initial-setup/pages/language/gis-language-page.c +@@ -56,6 +56,23 @@ typedef struct _GisLanguagePagePrivate GisLanguagePagePrivate; + + G_DEFINE_TYPE_WITH_PRIVATE (GisLanguagePage, gis_language_page, GIS_TYPE_PAGE); + ++static void ++on_locale_set (GDBusProxy *proxy, ++ GAsyncResult *result, ++ GisLanguagePage *self) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(GVariant) call_result = NULL; ++ ++ call_result = g_dbus_proxy_call_finish (proxy, result, &error); ++ ++ if (error != NULL) { ++ g_warning ("Could not set system locale: %s", error->message); ++ } ++ ++ gis_page_set_complete (GIS_PAGE (self), TRUE); ++} ++ + static void + set_localed_locale (GisLanguagePage *self) + { +@@ -72,7 +89,9 @@ set_localed_locale (GisLanguagePage *self) + "SetLocale", + g_variant_new ("(asb)", b, TRUE), + G_DBUS_CALL_FLAGS_NONE, +- -1, NULL, NULL, NULL); ++ -1, priv->cancellable, ++ (GAsyncReadyCallback) on_locale_set, ++ self); + g_variant_builder_unref (b); + } + +@@ -127,6 +146,9 @@ language_changed (CcLanguageChooser *chooser, + gtk_widget_set_default_direction (gtk_get_locale_direction ()); + + if (gis_driver_get_mode (driver) == GIS_DRIVER_MODE_NEW_USER) { ++ ++ gis_page_set_complete (GIS_PAGE (page), FALSE); ++ + if (g_permission_get_allowed (priv->permission)) { + set_localed_locale (page); + } +@@ -177,6 +199,7 @@ localed_proxy_ready (GObject *source, + } + + priv->localed = proxy; ++ gis_page_set_complete (GIS_PAGE (self), TRUE); + } + + static void +@@ -251,8 +274,10 @@ gis_language_page_constructed (GObject *object) + object); + g_object_unref (bus); + } +- +- gis_page_set_complete (GIS_PAGE (page), TRUE); ++ else ++ { ++ gis_page_set_complete (GIS_PAGE (page), TRUE); ++ } + gtk_widget_set_visible (GTK_WIDGET (page), TRUE); + } + +-- +GitLab + + +From 4ac881f55d46bc45e09a831aa5ab9ae2ba173477 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 24 Aug 2023 21:19:40 -0400 +Subject: [PATCH 04/10] keyboard: Get default input sources from gnome-desktop + +Right now, we figure out the default input sources ourselves, +based on the current locale and layout information coming from +localed. + +This logic needs to be duplicated in several components, so its +now provided by gnome-desktop. + +This commit changes it over to use gnome-desktop APIs. + +The same time if leverages a gnome-desktop API to fix a bug +where cyrillic layouts were getting added without a latin +counterpart. +--- + .../pages/keyboard/gis-keyboard-page.c | 475 +++++++++--------- + 1 file changed, 239 insertions(+), 236 deletions(-) + +diff --git a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c +index da384495..f2bfe164 100644 +--- a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c ++++ b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c +@@ -44,6 +44,8 @@ + #define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources" + #define KEY_CURRENT_INPUT_SOURCE "current" + #define KEY_INPUT_SOURCES "sources" ++#define KEY_MRU_SOURCES "mru-sources" ++#define KEY_INPUT_OPTIONS "xkb-options" + + struct _GisKeyboardPagePrivate { + GtkWidget *input_chooser; +@@ -52,8 +54,14 @@ struct _GisKeyboardPagePrivate { + GCancellable *cancellable; + GPermission *permission; + GSettings *input_settings; +- +- GSList *system_sources; ++ char **default_input_source_ids; ++ char **default_input_source_types; ++ char **default_options; ++ char **system_layouts; ++ char **system_variants; ++ char **system_options; ++ ++ gboolean should_skip; + }; + typedef struct _GisKeyboardPagePrivate GisKeyboardPagePrivate; + +@@ -72,98 +80,191 @@ gis_keyboard_page_finalize (GObject *object) + g_clear_object (&priv->permission); + g_clear_object (&priv->localed); + g_clear_object (&priv->input_settings); +- +- g_slist_free_full (priv->system_sources, g_free); ++ g_clear_pointer (&priv->default_input_source_ids, g_strfreev); ++ g_clear_pointer (&priv->default_input_source_types, g_strfreev); ++ g_clear_pointer (&priv->default_options, g_strfreev); ++ g_clear_pointer (&priv->system_layouts, g_strfreev); ++ g_clear_pointer (&priv->system_variants, g_strfreev); ++ g_clear_pointer (&priv->system_options, g_strfreev); + + G_OBJECT_CLASS (gis_keyboard_page_parent_class)->finalize (object); + } + + static void +-set_input_settings (GisKeyboardPage *self) ++add_defaults_to_variant_builder (GisKeyboardPage *self, ++ const char *already_added_type, ++ const char *already_added_id, ++ GVariantBuilder *input_source_builder, ++ char **default_layout) ++ + { + GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); +- const gchar *type; +- const gchar *id; +- GVariantBuilder builder; +- GSList *l; +- gboolean is_xkb_source = FALSE; ++ size_t i; + +- 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)); ++ for (i = 0; priv->default_input_source_ids && priv->default_input_source_ids[i] != NULL; i++) { ++ if (g_strcmp0 (already_added_id, priv->default_input_source_ids[i]) == 0 && g_strcmp0 (already_added_type, priv->default_input_source_types[i]) == 0) { ++ continue; ++ } + +- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)")); ++ g_variant_builder_add (input_source_builder, "(ss)", priv->default_input_source_types[i], priv->default_input_source_ids[i]); + +- if (g_str_equal (type, "xkb")) { +- g_variant_builder_add (&builder, "(ss)", type, id); +- is_xkb_source = TRUE; ++ if (*default_layout != NULL) { ++ if (!gnome_input_source_is_non_latin (priv->default_input_source_types[i], priv->default_input_source_ids[i])) { ++ *default_layout = g_strdup (priv->default_input_source_ids[i]); ++ } ++ } + } ++} + +- for (l = priv->system_sources; l; l = l->next) { +- const gchar *sid = l->data; + +- if (g_str_equal (id, sid) && g_str_equal (type, "xkb")) +- continue; ++static void ++add_input_source_to_arrays (GisKeyboardPage *self, ++ const char *type, ++ const char *id, ++ GPtrArray *layouts_array, ++ GPtrArray *variants_array) ++{ ++ g_auto(GStrv) layout_and_variant = NULL; ++ const char *layout, *variant; ++ ++ if (!g_str_equal (type, "xkb")) { ++ return; ++ } ++ ++ layout_and_variant = g_strsplit (id, "+", -1); ++ ++ layout = layout_and_variant[0]; ++ variant = layout_and_variant[1]?: ""; ++ ++ if (g_ptr_array_find_with_equal_func (layouts_array, layout, g_str_equal, NULL) && ++ g_ptr_array_find_with_equal_func (variants_array, variant, g_str_equal, NULL)) { ++ return; ++ } ++ ++ g_ptr_array_add (layouts_array, g_strdup (layout)); ++ g_ptr_array_add (variants_array, g_strdup (variant)); ++} ++ ++static void ++add_defaults_to_arrays (GisKeyboardPage *self, ++ GPtrArray *layouts_array, ++ GPtrArray *variants_array) ++{ ++ GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); ++ size_t i; ++ ++ for (i = 0; priv->default_input_source_ids && priv->default_input_source_ids[i] != NULL; i++) { ++ add_input_source_to_arrays (self, priv->default_input_source_types[i], priv->default_input_source_ids[i], layouts_array, variants_array); ++ } ++} ++ ++static void ++set_input_settings (GisKeyboardPage *self, ++ const char *type, ++ const char *id) ++{ ++ GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); ++ g_autofree char *layout = NULL; ++ g_autofree char *variant = NULL; ++ g_autoptr(GVariant) default_input_sources = NULL; ++ g_autoptr(GVariant) input_sources = NULL; ++ g_autoptr(GPtrArray) layouts_array = NULL; ++ g_autoptr(GPtrArray) variants_array = NULL; ++ GVariantBuilder input_source_builder; ++ GVariantBuilder input_options_builder; ++ g_autoptr(GVariant) input_options = NULL; ++ gboolean is_system_mode; ++ size_t i; ++ g_autofree char *default_input_source_id = NULL; ++ ++ default_input_sources = g_settings_get_default_value (priv->input_settings, KEY_INPUT_SOURCES); ++ input_sources = g_settings_get_value (priv->input_settings, KEY_INPUT_SOURCES); ++ ++ if (!g_variant_equal (default_input_sources, input_sources)) ++ return; ++ ++ g_clear_pointer (&input_sources, g_variant_unref); ++ ++ g_variant_builder_init (&input_options_builder, G_VARIANT_TYPE ("as")); ++ ++ is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER; ++ ++ layouts_array = g_ptr_array_new (); ++ variants_array = g_ptr_array_new (); ++ ++ /* Notice the added latin layout (if relevant) gets put first for gsettings ++ * (input_source_builder and last for localed (layouts_array/variants_array) ++ * This ensures we get a cyrillic layout on ttys, but a latin layout by default ++ * in the UI. ++ */ ++ g_variant_builder_init (&input_source_builder, G_VARIANT_TYPE ("a(ss)")); ++ if (type != NULL && id != NULL) { ++ add_input_source_to_arrays (self, type, id, layouts_array, variants_array); ++ ++ if (gnome_input_source_is_non_latin (type, id)) { ++ default_input_source_id = g_strdup ("us"); ++ add_input_source_to_arrays (self, "xkb", default_input_source_id, layouts_array, variants_array); ++ g_variant_builder_add (&input_source_builder, "(ss)", "xkb", default_input_source_id); ++ } else { ++ default_input_source_id = g_strdup (id); ++ } + +- g_variant_builder_add (&builder, "(ss)", "xkb", sid); ++ g_variant_builder_add (&input_source_builder, "(ss)", type, id); + } + +- if (!is_xkb_source) +- g_variant_builder_add (&builder, "(ss)", type, id); ++ if (default_input_source_id == NULL || !is_system_mode) { ++ add_defaults_to_variant_builder (self, type, id, &input_source_builder, &default_input_source_id); ++ } ++ input_sources = g_variant_builder_end (&input_source_builder); ++ ++ for (i = 0; priv->default_options[i] != NULL; i++) { ++ g_variant_builder_add (&input_options_builder, "s", priv->default_options[i]); ++ } ++ input_options = g_variant_builder_end (&input_options_builder); ++ ++ add_defaults_to_arrays (self, layouts_array, variants_array); ++ g_ptr_array_add (layouts_array, NULL); ++ g_ptr_array_add (variants_array, NULL); ++ ++ priv->system_layouts = (char **) g_ptr_array_steal (layouts_array, NULL); ++ priv->system_variants = (char **) g_ptr_array_steal (variants_array, NULL); + +- g_settings_set_value (priv->input_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder)); +- g_settings_set_uint (priv->input_settings, KEY_CURRENT_INPUT_SOURCE, 0); ++ g_variant_get (input_options, "^as", &priv->system_options); ++ ++ g_settings_set_value (priv->input_settings, KEY_INPUT_SOURCES, g_steal_pointer (&input_sources)); ++ g_settings_set_value (priv->input_settings, KEY_INPUT_OPTIONS, g_steal_pointer (&input_options)); ++ ++ if (default_input_source_id != NULL) { ++ GVariantBuilder mru_input_source_builder; ++ ++ g_variant_builder_init (&mru_input_source_builder, G_VARIANT_TYPE ("a(ss)")); ++ g_variant_builder_add (&mru_input_source_builder, "(ss)", type, default_input_source_id); ++ g_settings_set_value (priv->input_settings, KEY_MRU_SOURCES, g_variant_builder_end (&mru_input_source_builder)); ++ } + +- g_settings_apply (priv->input_settings); ++ g_settings_apply (priv->input_settings); + } + + static void + set_localed_input (GisKeyboardPage *self) + { + GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); +- const gchar *layout, *variant; +- GString *layouts; +- GString *variants; +- GSList *l; ++ g_autofree char *layouts = NULL; ++ g_autofree char *variants = NULL; ++ g_autofree char *options = NULL; + + if (!priv->localed) + return; + +- cc_input_chooser_get_layout (CC_INPUT_CHOOSER (priv->input_chooser), &layout, &variant); +- if (layout == NULL) +- layout = ""; +- if (variant == NULL) +- variant = ""; +- +- layouts = g_string_new (layout); +- variants = g_string_new (variant); +- +-#define LAYOUT(a) (a[0]) +-#define VARIANT(a) (a[1] ? a[1] : "") +- for (l = priv->system_sources; l; l = l->next) { +- const gchar *sid = l->data; +- gchar **lv = g_strsplit (sid, "+", -1); +- +- if (!g_str_equal (LAYOUT (lv), layout) || +- !g_str_equal (VARIANT (lv), variant)) { +- if (layouts->str[0]) { +- g_string_append_c (layouts, ','); +- g_string_append_c (variants, ','); +- } +- g_string_append (layouts, LAYOUT (lv)); +- g_string_append (variants, VARIANT (lv)); +- } +- g_strfreev (lv); +- } +-#undef LAYOUT +-#undef VARIANT ++ layouts = g_strjoinv (",", priv->system_layouts); ++ variants = g_strjoinv (",", priv->system_variants); ++ options = g_strjoinv (",", priv->system_options); + + g_dbus_proxy_call (priv->localed, + "SetX11Keyboard", +- g_variant_new ("(ssssbb)", layouts->str, "", variants->str, "", TRUE, TRUE), ++ g_variant_new ("(ssssbb)", layouts, "", variants, options, TRUE, TRUE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, NULL, NULL); +- g_string_free (layouts, TRUE); +- g_string_free (variants, TRUE); + } + + static void +@@ -192,8 +293,13 @@ static void + update_input (GisKeyboardPage *self) + { + GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); ++ const gchar *type; ++ const gchar *id; + +- set_input_settings (self); ++ 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 (g_permission_get_allowed (priv->permission)) { +@@ -215,119 +321,10 @@ gis_keyboard_page_apply (GisPage *page, + return FALSE; + } + +-static GSList * +-get_localed_input (GDBusProxy *proxy) +-{ +- GVariant *v; +- const gchar *s; +- gchar *id; +- guint i, n; +- gchar **layouts = NULL; +- gchar **variants = NULL; +- GSList *sources = NULL; +- +- v = g_dbus_proxy_get_cached_property (proxy, "X11Layout"); +- if (v) { +- s = g_variant_get_string (v, NULL); +- layouts = g_strsplit (s, ",", -1); +- g_variant_unref (v); +- } +- +- v = g_dbus_proxy_get_cached_property (proxy, "X11Variant"); +- if (v) { +- s = g_variant_get_string (v, NULL); +- if (s && *s) +- variants = g_strsplit (s, ",", -1); +- g_variant_unref (v); +- } +- +- if (variants && variants[0]) +- n = MIN (g_strv_length (layouts), g_strv_length (variants)); +- else if (layouts && layouts[0]) +- n = g_strv_length (layouts); +- else +- n = 0; +- +- for (i = 0; i < n && layouts[i][0]; i++) { +- if (variants && variants[i] && variants[i][0]) +- id = g_strdup_printf ("%s+%s", layouts[i], variants[i]); +- else +- id = g_strdup (layouts[i]); +- sources = g_slist_prepend (sources, id); +- } +- +- g_strfreev (variants); +- g_strfreev (layouts); +- +- return sources; +-} +- + static void +-add_default_keyboard_layout (GDBusProxy *proxy, +- GVariantBuilder *builder) ++add_default_input_sources (GisKeyboardPage *self) + { +- GSList *sources = get_localed_input (proxy); +- sources = g_slist_reverse (sources); +- +- for (; sources; sources = sources->next) +- g_variant_builder_add (builder, "(ss)", "xkb", +- (const gchar *) sources->data); +- +- g_slist_free_full (sources, g_free); +-} +- +-static void +-add_default_input_sources (GisKeyboardPage *self, +- GDBusProxy *proxy) +-{ +- const gchar *type; +- const gchar *id; +- gchar *language; +- GVariantBuilder builder; +- GSettings *input_settings; +- +- input_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR); +- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)")); +- +- add_default_keyboard_layout (proxy, &builder); +- +- /* add other input sources */ +- language = cc_common_language_get_current_language (); +- if (gnome_get_input_source_from_locale (language, &type, &id)) { +- if (!g_str_equal (type, "xkb")) +- g_variant_builder_add (&builder, "(ss)", type, id); +- } +- g_free (language); +- +- g_settings_delay (input_settings); +- g_settings_set_value (input_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder)); +- g_settings_set_uint (input_settings, KEY_CURRENT_INPUT_SOURCE, 0); +- g_settings_apply (input_settings); +- +- g_object_unref (input_settings); +-} +- +-static void +-skip_proxy_ready (GObject *source, +- GAsyncResult *res, +- gpointer data) +-{ +- GisKeyboardPage *self = data; +- GDBusProxy *proxy; +- GError *error = NULL; +- +- proxy = g_dbus_proxy_new_finish (res, &error); +- +- if (!proxy) { +- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) +- g_warning ("Failed to contact localed: %s", error->message); +- g_error_free (error); +- return; +- } +- +- add_default_input_sources (self, proxy); +- +- g_object_unref (proxy); ++ set_input_settings (self, NULL, NULL); + } + + static void +@@ -336,77 +333,49 @@ gis_keyboard_page_skip (GisPage *page) + GisKeyboardPage *self = GIS_KEYBOARD_PAGE (page); + GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); + +- 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) skip_proxy_ready, +- self); ++ priv->should_skip = TRUE; ++ ++ if (priv->default_input_source_ids != NULL) ++ add_default_input_sources (self); + } + + static void + preselect_input_source (GisKeyboardPage *self) + { +- const gchar *type; +- const gchar *id; +- gchar *language; +- gboolean desktop_got_something; +- gboolean desktop_got_input_method; ++ const char *language = NULL; + + GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); +- GSList *sources = get_localed_input (priv->localed); +- +- /* These will be added silently after the user selection when +- * writing out the settings. */ +- g_slist_free_full (priv->system_sources, g_free); +- priv->system_sources = g_slist_reverse (sources); +- +- /* We have two potential sources of information as to which +- * source to pre-select here: the keyboard layout that is +- * configured system-wide (read from priv->system_sources), +- * and a gnome-desktop function that lets us look up a default +- * input source for a given language. +- * +- * An important limitation here is that there is no system-wide +- * configuration for input methods, so if the best choice for the +- * language is an input method, we will only find it from the +- * gnome-desktop lookup. But if both sources give us keyboard layouts, +- * we want to prefer the one that's configured system-wide over the one +- * from gnome-desktop. +- * +- * So we first do the gnome-desktop lookup, and keep track of what we +- * got. +- * +- * - If we got an input method, we preselect that, and we're done. +- * - If we got a keyboard layout, and there's no system-wide keyboard +- * layout set, we preselect the layout we got from gnome-desktop. +- * - If we didn't get an input method from gnome-desktop and there +- * is a system-wide keyboard layout set, we preselect that. +- * - If we got nothing from gnome-desktop and there's no system-wide +- * keyboard layout set, we don't preselect anything. +- * +- * See: +- * - https://bugzilla.gnome.org/show_bug.cgi?id=776189 +- * - https://gitlab.gnome.org/GNOME/gnome-initial-setup/-/issues/104 +- */ +- language = cc_common_language_get_current_language (); + +- desktop_got_something = gnome_get_input_source_from_locale (language, &type, &id); +- desktop_got_input_method = (desktop_got_something && g_strcmp0 (type, "xkb") != 0); ++ language = cc_common_language_get_current_language (); + +- if (desktop_got_something && (desktop_got_input_method || !priv->system_sources)) { +- cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), +- id, type); +- } else if (priv->system_sources) { +- cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), +- (const gchar *) priv->system_sources->data, +- "xkb"); ++ /* We deduce the initial input source from language if we're in a system mode ++ * (where preexisting system configuration may be stale) or if the language ++ * requires an input method (because there is no way for system configuration ++ * to denote the need for an input method) ++ * ++ * If it's a non-system mode we can trust the system configuration is probably ++ * a better bet than a heuristic based on locale. ++ */ ++ if (language != NULL) { ++ gboolean got_input_source; ++ const char *id, *type; ++ ++ got_input_source = gnome_get_input_source_from_locale (language, &type, &id); ++ ++ if (got_input_source) { ++ gboolean is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER; ++ if (is_system_mode || g_str_equal (type, "ibus")) { ++ cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), ++ id, ++ type); ++ return; ++ } ++ } + } + +- g_free (language); ++ cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), ++ priv->default_input_source_ids[0], ++ priv->default_input_source_types[0]); + } + + static void +@@ -445,9 +414,7 @@ localed_proxy_ready (GObject *source, + } + + priv->localed = proxy; +- +- preselect_input_source (self); +- update_page_complete (self); ++ update_page_complete (self); + } + + static void +@@ -464,6 +431,40 @@ input_changed (CcInputChooser *chooser, + update_page_complete (self); + } + ++static void ++on_got_default_sources (GObject *source, ++ GAsyncResult *res, ++ gpointer data) ++{ ++ GisKeyboardPage *self = data; ++ GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); ++ g_autoptr (GError) error = NULL; ++ gboolean success = FALSE; ++ g_auto (GStrv) ids = NULL; ++ g_auto (GStrv) types = NULL; ++ g_auto (GStrv) options = NULL; ++ ++ success = gnome_get_default_input_sources_finish (res, &ids, &types, &options, &error); ++ ++ if (!success) { ++ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) ++ g_warning ("Failed to fetch default input sources: %s", error->message); ++ return; ++ } ++ ++ priv->default_input_source_ids = g_steal_pointer (&ids); ++ priv->default_input_source_types = g_steal_pointer (&types); ++ priv->default_options = g_steal_pointer (&options); ++ ++ if (priv->should_skip) { ++ add_default_input_sources (self); ++ return; ++ } ++ ++ preselect_input_source (self); ++ update_page_complete (self); ++} ++ + static void + gis_keyboard_page_constructed (GObject *object) + { +@@ -492,6 +493,8 @@ gis_keyboard_page_constructed (GObject *object) + (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) + priv->permission = polkit_permission_new_sync ("org.freedesktop.locale1.set-keyboard", NULL, NULL, NULL); +-- +GitLab + + +From b67c0d9a551891e88b969981d8cfcaa36eb8fed2 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 13 Aug 2023 09:09:56 -0400 +Subject: [PATCH 05/10] driver: Specify mode via flags instead of boolean + +At the moment we just have system mode and new user mode, +but we're actually going to want other modes (such as +live user mode) as well. + +Currently the code distinguishes between its two available +modes using a boolean `is_new_user`. That isn't extensible beyond +two modes, so this commit changes it use bit flags instead. +--- + gnome-initial-setup/gis-driver.c | 17 ++- + gnome-initial-setup/gis-driver.h | 8 +- + gnome-initial-setup/gnome-initial-setup.c | 128 +++++++++++++--------- + 3 files changed, 93 insertions(+), 60 deletions(-) + +diff --git a/gnome-initial-setup/gis-driver.c b/gnome-initial-setup/gis-driver.c +index 98b4fc3e..d3013063 100644 +--- a/gnome-initial-setup/gis-driver.c ++++ b/gnome-initial-setup/gis-driver.c +@@ -36,8 +36,6 @@ + #include "cc-common-language.h" + #include "gis-assistant.h" + +-#define GIS_TYPE_DRIVER_MODE (gis_driver_mode_get_type ()) +- + /* Statically include this for now. Maybe later + * we'll generate this from glib-mkenums. */ + GType +@@ -45,12 +43,13 @@ gis_driver_mode_get_type (void) { + static GType enum_type_id = 0; + if (G_UNLIKELY (!enum_type_id)) + { +- static const GEnumValue values[] = { ++ 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_ALL, "GIS_DRIVER_MODE_ALL", "all" }, + { 0, NULL, NULL } + }; +- enum_type_id = g_enum_register_static("GisDriverMode", values); ++ enum_type_id = g_flags_register_static("GisDriverMode", values); + } + return enum_type_id; + } +@@ -651,7 +650,7 @@ gis_driver_set_property (GObject *object, + switch ((GisDriverProperty) prop_id) + { + case PROP_MODE: +- driver->mode = g_value_get_enum (value); ++ driver->mode = g_value_get_flags (value); + break; + case PROP_USERNAME: + g_free (driver->username); +@@ -853,10 +852,10 @@ gis_driver_class_init (GisDriverClass *klass) + G_TYPE_NONE, 0); + + obj_props[PROP_MODE] = +- g_param_spec_enum ("mode", "", "", +- GIS_TYPE_DRIVER_MODE, +- GIS_DRIVER_MODE_EXISTING_USER, +- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); ++ g_param_spec_flags ("mode", "", "", ++ GIS_TYPE_DRIVER_MODE, ++ GIS_DRIVER_MODE_EXISTING_USER, ++ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + + obj_props[PROP_USERNAME] = + g_param_spec_string ("username", "", "", +diff --git a/gnome-initial-setup/gis-driver.h b/gnome-initial-setup/gis-driver.h +index 9b935e24..b57db2e2 100644 +--- a/gnome-initial-setup/gis-driver.h ++++ b/gnome-initial-setup/gis-driver.h +@@ -31,6 +31,7 @@ + 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) + +@@ -41,10 +42,13 @@ typedef enum { + } UmAccountMode; + + typedef enum { +- GIS_DRIVER_MODE_NEW_USER, +- GIS_DRIVER_MODE_EXISTING_USER, ++ 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), + } GisDriverMode; + ++GType gis_driver_mode_get_type (void); ++ + GisAssistant *gis_driver_get_assistant (GisDriver *driver); + + void gis_driver_set_user_permissions (GisDriver *driver, +diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c +index 113ded36..59955779 100644 +--- a/gnome-initial-setup/gnome-initial-setup.c ++++ b/gnome-initial-setup/gnome-initial-setup.c +@@ -56,27 +56,27 @@ typedef GisPage *(*PreparePage) (GisDriver *driver); + typedef struct { + const gchar *page_id; + PreparePage prepare_page_func; +- gboolean new_user_only; ++ GisDriverMode modes; + } PageData; + +-#define PAGE(name, new_user_only) { #name, gis_prepare_ ## name ## _page, new_user_only } ++#define PAGE(name, modes) { #name, gis_prepare_ ## name ## _page, modes } + + static PageData page_table[] = { +- PAGE (welcome, FALSE), +- PAGE (language, FALSE), +- PAGE (keyboard, FALSE), +- PAGE (network, FALSE), +- PAGE (privacy, FALSE), +- PAGE (timezone, TRUE), +- PAGE (software, TRUE), +- PAGE (goa, FALSE), +- PAGE (account, TRUE), +- PAGE (password, TRUE), ++ 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 (privacy, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), ++ PAGE (timezone, GIS_DRIVER_MODE_NEW_USER | GIS_DRIVER_MODE_EXISTING_USER), ++ 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), + #ifdef HAVE_PARENTAL_CONTROLS +- PAGE (parental_controls, TRUE), +- PAGE (parent_password, TRUE), ++ 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, FALSE), ++ PAGE (summary, GIS_DRIVER_MODE_NEW_USER), + { NULL }, + }; + +@@ -107,26 +107,15 @@ should_skip_page (const gchar *page_id, + } + + static gchar ** +-strv_append (gchar **a, +- gchar **b) ++pages_to_skip_from_file (GisDriver *driver) + { +- guint n = g_strv_length (a); +- guint m = g_strv_length (b); +- +- a = g_renew (gchar *, a, n + m + 1); +- for (guint i = 0; i < m; i++) +- a[n + i] = g_strdup (b[i]); +- a[n + m] = NULL; +- +- return a; +-} +- +-static gchar ** +-pages_to_skip_from_file (GisDriver *driver, +- gboolean is_new_user) +-{ +- GStrv skip_pages = NULL; +- GStrv additional_skip_pages = NULL; ++ 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; + + /* This code will read the keyfile containing vendor customization options and + * look for options under the "pages" group, and supports the following keys: +@@ -134,28 +123,68 @@ pages_to_skip_from_file (GisDriver *driver, + * - 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 + * ++ * 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); +- additional_skip_pages = +- gis_driver_conf_get_string_list (driver, VENDOR_PAGES_GROUP, +- is_new_user ? VENDOR_EXISTING_USER_ONLY_KEY : VENDOR_NEW_USER_ONLY_KEY, +- NULL); +- +- if (!skip_pages && additional_skip_pages) { +- skip_pages = additional_skip_pages; +- } else if (skip_pages && additional_skip_pages) { +- skip_pages = strv_append (skip_pages, additional_skip_pages); +- g_strfreev (additional_skip_pages); ++ 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); ++ ++ driver_mode = gis_driver_get_mode (driver); ++ driver_mode_flags = g_flags_get_first_value (driver_mode_flags_class, driver_mode); ++ ++ mode_group = g_strdup_printf ("%s pages", driver_mode_flags->value_nick); ++ skip_pages = gis_driver_conf_get_string_list (driver, mode_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); ++ } ++ ++ other_modes = GIS_DRIVER_MODE_ALL & ~driver_mode; ++ while (other_modes) { ++ const GFlagsValue *other_mode_flags = g_flags_get_first_value (driver_mode_flags_class, other_modes); ++ ++ if (other_mode_flags != NULL) { ++ g_autofree char *vendor_key = g_strdup_printf ("%s_only", other_mode_flags->value_nick); ++ ++ skip_pages = gis_driver_conf_get_string_list (driver, VENDOR_PAGES_GROUP, ++ vendor_key, NULL); ++ ++ if (skip_pages != NULL) ++ { ++ g_strv_builder_addv (builder, (const char **) skip_pages); ++ g_clear_pointer (&skip_pages, g_strfreev); ++ } ++ ++ other_modes &= ~other_mode_flags->value; ++ } + } + +- return skip_pages; ++ return g_strv_builder_end (builder); + } + + static void +@@ -198,7 +227,8 @@ rebuild_pages_cb (GisDriver *driver) + GisAssistant *assistant; + GisPage *current_page; + gchar **skip_pages; +- gboolean is_new_user, skipped; ++ GisDriverMode driver_mode; ++ gboolean skipped; + + assistant = gis_driver_get_assistant (driver); + current_page = gis_assistant_get_current_page (assistant); +@@ -217,13 +247,13 @@ rebuild_pages_cb (GisDriver *driver) + ++page_data; + } + +- is_new_user = (gis_driver_get_mode (driver) == GIS_DRIVER_MODE_NEW_USER); +- skip_pages = pages_to_skip_from_file (driver, is_new_user); ++ 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->new_user_only && !is_new_user) || ++ if (((page_data->modes & driver_mode) == 0) || + (should_skip_page (page_data->page_id, skip_pages))) + skipped = TRUE; + +-- +GitLab + + +From 5d02f9f885d370e587f5620d03820cce4118d340 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Wed, 30 Aug 2023 15:08:23 -0400 +Subject: [PATCH 06/10] assistant: Show Back button on summary page + +commit f60b4622350468f7ef17f79d9bc6679bf8cce7b9 changed the +assistant to no longer show the back and forward buttons on the +last page. + +Hiding the forward button makes sense: there's no more pages go +to. + +Hiding the back button doesn't really make sense: there are a +bunch of pages the user could potentially want to revisit. + +This commit shows the back button on the last page (either +the summary page or the install page). +--- + gnome-initial-setup/gis-assistant.c | 14 +++++++++----- + .../pages/summary/gis-summary-page.c | 16 +++++++++------- + 2 files changed, 18 insertions(+), 12 deletions(-) + +diff --git a/gnome-initial-setup/gis-assistant.c b/gnome-initial-setup/gis-assistant.c +index a3122b71..8a7fc52b 100644 +--- a/gnome-initial-setup/gis-assistant.c ++++ b/gnome-initial-setup/gis-assistant.c +@@ -59,6 +59,8 @@ struct _GisAssistant + + GList *pages; + GisPage *current_page; ++ ++ gboolean data_saved; + }; + + G_DEFINE_TYPE (GisAssistant, gis_assistant, GTK_TYPE_BOX) +@@ -182,6 +184,7 @@ update_navigation_buttons (GisAssistant *assistant) + { + GisPage *page = assistant->current_page; + GList *l; ++ gboolean is_first_page; + gboolean is_last_page; + + if (page == NULL) +@@ -189,11 +192,13 @@ update_navigation_buttons (GisAssistant *assistant) + + l = g_list_find (assistant->pages, page); + ++ is_first_page = (l->prev == NULL); + is_last_page = (l->next == NULL); + ++ gtk_widget_set_visible (assistant->back, !is_first_page && !assistant->data_saved); ++ + if (is_last_page) + { +- gtk_widget_set_visible (assistant->back, FALSE); + gtk_widget_set_visible (assistant->forward, FALSE); + gtk_widget_set_visible (assistant->skip, FALSE); + gtk_widget_set_visible (assistant->cancel, FALSE); +@@ -201,12 +206,8 @@ update_navigation_buttons (GisAssistant *assistant) + } + else + { +- gboolean is_first_page; + GtkWidget *next_widget; + +- is_first_page = (l->prev == NULL); +- gtk_widget_set_visible (assistant->back, !is_first_page); +- + if (gis_page_get_needs_accept (page)) + next_widget = assistant->accept; + else +@@ -418,6 +419,9 @@ gis_assistant_save_data (GisAssistant *assistant, + { + GList *l; + ++ assistant->data_saved = TRUE; ++ gtk_widget_set_visible (assistant->back, FALSE); ++ + for (l = assistant->pages; l != NULL; l = l->next) + { + if (!gis_page_save_data (l->data, error)) +diff --git a/gnome-initial-setup/pages/summary/gis-summary-page.c b/gnome-initial-setup/pages/summary/gis-summary-page.c +index 0aee2dad..8a526b64 100644 +--- a/gnome-initial-setup/pages/summary/gis-summary-page.c ++++ b/gnome-initial-setup/pages/summary/gis-summary-page.c +@@ -180,6 +180,15 @@ log_user_in (GisSummaryPage *page) + static void + done_cb (GtkButton *button, GisSummaryPage *page) + { ++ g_autoptr (GError) error = NULL; ++ ++ if (!gis_driver_save_data (GIS_PAGE (page)->driver, &error)) ++ { ++ /* FIXME: This should probably be shown to the user and some options ++ * provided to them. */ ++ g_warning ("Error saving data: %s", error->message); ++ } ++ + gis_ensure_stamp_files (GIS_PAGE (page)->driver); + + switch (gis_driver_get_mode (GIS_PAGE (page)->driver)) +@@ -202,13 +211,6 @@ gis_summary_page_shown (GisPage *page) + GisSummaryPagePrivate *priv = gis_summary_page_get_instance_private (summary); + g_autoptr(GError) local_error = NULL; + +- if (!gis_driver_save_data (GIS_PAGE (page)->driver, &local_error)) +- { +- /* FIXME: This should probably be shown to the user and some options +- * provided to them. */ +- g_warning ("Error saving data: %s", local_error->message); +- } +- + gis_driver_get_user_permissions (GIS_PAGE (page)->driver, + &priv->user_account, + &priv->user_password); +-- +GitLab + + +From af751585cd5d124e7de19ab9e1b08d4cd925c6c3 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 13 Aug 2023 09:39:07 -0400 +Subject: [PATCH 07/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 | 122 ++++++ + gnome-initial-setup/gis-util.h | 4 + + gnome-initial-setup/gnome-initial-setup.c | 26 +- + .../pages/account/gis-account-pages.c | 21 + + .../pages/install/gis-install-page.c | 382 ++++++++++++++++++ + .../pages/install/gis-install-page.css | 11 + + .../pages/install/gis-install-page.h | 52 +++ + .../pages/install/gis-install-page.ui | 51 +++ + .../pages/install/install.gresource.xml | 8 + + gnome-initial-setup/pages/install/meson.build | 9 + + .../pages/keyboard/gis-keyboard-page.c | 10 +- + .../pages/language/gis-language-page.c | 5 +- + gnome-initial-setup/pages/meson.build | 1 + + .../pages/password/gis-password-page.c | 6 + + 17 files changed, 701 insertions(+), 18 deletions(-) + create mode 100644 gnome-initial-setup/pages/install/gis-install-page.c + create mode 100644 gnome-initial-setup/pages/install/gis-install-page.css + 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 +@@ -16,7 +16,8 @@ polkit.addRule(function(action, subject) { + 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) +diff --git a/gnome-initial-setup/gis-driver.c b/gnome-initial-setup/gis-driver.c +index d3013063..b18a3808 100644 +--- a/gnome-initial-setup/gis-driver.c ++++ b/gnome-initial-setup/gis-driver.c +@@ -46,6 +46,8 @@ gis_driver_mode_get_type (void) { + 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 } + }; +@@ -791,7 +793,7 @@ gis_driver_startup (GApplication *app) + 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, +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 +@@ -44,7 +44,9 @@ typedef enum { + 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); +diff --git a/gnome-initial-setup/gis-util.c b/gnome-initial-setup/gis-util.c +index ac153fc1..424c26d7 100644 +--- a/gnome-initial-setup/gis-util.c ++++ b/gnome-initial-setup/gis-util.c +@@ -31,3 +31,125 @@ gis_add_style_from_resource (const char *resource_path) + 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; ++} ++ ++static gboolean ++is_valid_shell_identifier_character (char c, ++ gboolean first) ++{ ++ return (!first && g_ascii_isdigit (c)) || ++ c == '_' || ++ g_ascii_isalpha (c); ++} ++ ++void ++gis_substitute_variables_in_text (char **text, ++ GisVariableLookupFunc lookup_func, ++ gpointer user_data) ++{ ++ GString *s = g_string_new (""); ++ const char *p, *start; ++ char c; ++ ++ p = *text; ++ while (*p) { ++ c = *p; ++ if (c == '\\') { ++ p++; ++ c = *p; ++ if (c != '\0') { ++ p++; ++ switch (c) { ++ case '\\': ++ g_string_append_c (s, '\\'); ++ break; ++ case '$': ++ g_string_append_c (s, '$'); ++ break; ++ default: ++ g_string_append_c (s, '\\'); ++ g_string_append_c (s, c); ++ break; ++ } ++ } ++ } else if (c == '$') { ++ gboolean brackets = FALSE; ++ p++; ++ if (*p == '{') { ++ brackets = TRUE; ++ p++; ++ } ++ start = p; ++ while (*p != '\0' && ++ is_valid_shell_identifier_character (*p, p == start)) { ++ p++; ++ } ++ if (p == start || (brackets && *p != '}')) { ++ g_string_append_c (s, '$'); ++ if (brackets) ++ g_string_append_c (s, '{'); ++ g_string_append_len (s, start, p - start); ++ } else { ++ g_autofree char *variable = NULL; ++ g_autofree char *value = NULL; ++ ++ variable = g_strndup (start, p - start); ++ ++ if (brackets && *p == '}') ++ p++; ++ ++ if (lookup_func) ++ value = lookup_func (variable, user_data); ++ if (value) { ++ g_string_append (s, value); ++ } ++ } ++ } else { ++ p++; ++ g_string_append_c (s, c); ++ } ++ } ++ g_free (*text); ++ *text = g_string_free (s, FALSE); ++} ++ +diff --git a/gnome-initial-setup/gis-util.h b/gnome-initial-setup/gis-util.h +index 5041bddd..80d4f9a0 100644 +--- a/gnome-initial-setup/gis-util.h ++++ b/gnome-initial-setup/gis-util.h +@@ -17,3 +17,7 @@ + #pragma once + + void gis_add_style_from_resource (const char *path); ++gboolean gis_kernel_command_line_has_argument (const char *arguments[]); ++ ++typedef char * (* GisVariableLookupFunc) (const char *key, gpointer user_data); ++void gis_substitute_variables_in_text (char **text, GisVariableLookupFunc lookup_func, gpointer user_data); +diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c +index 59955779..bc7a4ee9 100644 +--- a/gnome-initial-setup/gnome-initial-setup.c ++++ b/gnome-initial-setup/gnome-initial-setup.c +@@ -41,13 +41,16 @@ + #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" + + static gboolean force_existing_user_mode; ++static gboolean force_live_user_mode; + + static GPtrArray *skipped_pages; + +@@ -65,18 +68,20 @@ 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 }, + }; + +@@ -120,8 +125,8 @@ pages_to_skip_from_file (GisDriver *driver) + /* 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: +@@ -277,6 +282,8 @@ 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; + } +@@ -310,6 +317,8 @@ main (int argc, char *argv[]) + 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 } + }; + +@@ -328,6 +337,9 @@ main (int argc, char *argv[]) + + 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); +@@ -346,7 +358,7 @@ main (int argc, char *argv[]) + * 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); +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 +@@ -26,6 +26,27 @@ + 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..36ed7539 +--- /dev/null ++++ b/gnome-initial-setup/pages/install/gis-install-page.c +@@ -0,0 +1,382 @@ ++/* -*- 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) ++{ ++ ++ g_autoptr (GError) error = NULL; ++ ++ if (!gis_driver_save_data (GIS_PAGE (page)->driver, &error)) ++ g_warning ("Error saving data: %s", error->message); ++ ++ 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; ++ ++ if (!gis_driver_save_data (GIS_PAGE (page)->driver, &error)) ++ g_warning ("Error saving data: %s", error->message); ++ ++ 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; ++ ++ 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 *text = NULL; ++ ++ text = g_strdup (adw_status_page_get_description (priv->status_page)); ++ gis_substitute_variables_in_text (&text, (GisVariableLookupFunc) g_get_os_info, NULL); ++ adw_status_page_set_description (priv->status_page, text); ++ g_clear_pointer (&text, g_free); ++ ++ text = g_strdup (gtk_button_get_label (GTK_BUTTON (priv->try_button))); ++ gis_substitute_variables_in_text (&text, (GisVariableLookupFunc) g_get_os_info, NULL); ++ gtk_button_set_label (GTK_BUTTON (priv->try_button), text); ++ g_clear_pointer (&text, g_free); ++} ++ ++ ++static void ++apply_stylesheet (GisInstallPage *page) ++{ ++ GisInstallPagePrivate *priv = gis_install_page_get_instance_private (page); ++ g_autoptr (GtkCssProvider) css_provider = gtk_css_provider_new(); ++ ++ gtk_widget_add_css_class (GTK_WIDGET (priv->status_page), "override-icon-size"); ++ gtk_widget_add_css_class (GTK_WIDGET (priv->status_page), "override-button-line-height"); ++ ++ gtk_css_provider_load_from_resource (css_provider, "/org/gnome/initial-setup/gis-install-page.css"); ++ ++ gtk_style_context_add_provider_for_display (gtk_widget_get_display (GTK_WIDGET (priv->status_page)), ++ GTK_STYLE_PROVIDER (css_provider), ++ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); ++} ++ ++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); ++ ++ apply_stylesheet (page); ++ update_distro_name (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) ++{ ++ g_autofree char *title = g_strdup (_("Install ${PRETTY_NAME}")); ++ gis_substitute_variables_in_text (&title, (GisVariableLookupFunc) g_get_os_info, NULL); ++ gis_page_set_title (page, title); ++} ++ ++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.css b/gnome-initial-setup/pages/install/gis-install-page.css +new file mode 100644 +index 00000000..f3583b33 +--- /dev/null ++++ b/gnome-initial-setup/pages/install/gis-install-page.css +@@ -0,0 +1,11 @@ ++.override-icon-size image { ++ -gtk-icon-size: 70px; ++} ++ ++.override-button-line-height button { ++ line-height: 1.75; ++} ++ ++.description { ++ line-height: 1.25; ++} +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..c9ed5c88 +--- /dev/null ++++ b/gnome-initial-setup/pages/install/gis-install-page.ui +@@ -0,0 +1,51 @@ ++ ++ ++ ++ +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..15391108 +--- /dev/null ++++ b/gnome-initial-setup/pages/install/install.gresource.xml +@@ -0,0 +1,8 @@ ++ ++ ++ ++ gis-install-page.ui ++ gis-install-page.css ++ ++ ++ +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 f2bfe164..7801667c 100644 +--- a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c ++++ b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c +@@ -187,7 +187,7 @@ set_input_settings (GisKeyboardPage *self, + + g_variant_builder_init (&input_options_builder, G_VARIANT_TYPE ("as")); + +- is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER; ++ is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) & GIS_DRIVER_MODE_SYSTEM; + + layouts_array = g_ptr_array_new (); + variants_array = g_ptr_array_new (); +@@ -301,7 +301,7 @@ update_input (GisKeyboardPage *self) + + 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)) { +@@ -363,7 +363,7 @@ preselect_input_source (GisKeyboardPage *self) + got_input_source = gnome_get_input_source_from_locale (language, &type, &id); + + if (got_input_source) { +- gboolean is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER; ++ gboolean is_system_mode = gis_driver_get_mode (GIS_PAGE (self)->driver) & GIS_DRIVER_MODE_SYSTEM; + if (is_system_mode || g_str_equal (type, "ibus")) { + cc_input_chooser_set_input (CC_INPUT_CHOOSER (priv->input_chooser), + id, +@@ -384,7 +384,7 @@ update_page_complete (GisKeyboardPage *self) + GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self); + gboolean complete; + +- 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) { + complete = (priv->localed != NULL && + cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)) != NULL); + } else { +@@ -496,7 +496,7 @@ gis_keyboard_page_constructed (GObject *object) + 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); +diff --git a/gnome-initial-setup/pages/language/gis-language-page.c b/gnome-initial-setup/pages/language/gis-language-page.c +index 26a01257..17117fa1 100644 +--- a/gnome-initial-setup/pages/language/gis-language-page.c ++++ b/gnome-initial-setup/pages/language/gis-language-page.c +@@ -145,7 +145,7 @@ language_changed (CcLanguageChooser *chooser, + 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) { + + gis_page_set_complete (GIS_PAGE (page), FALSE); + +@@ -257,8 +257,7 @@ gis_language_page_constructed (GObject *object) + 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); + +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,5 +1,6 @@ + pages = [ + 'account', ++ 'install', + 'language', + 'keyboard', + 'network', +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 +@@ -491,6 +491,12 @@ gis_password_page_init (GisPasswordPage *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); +-- +GitLab + + +From 8c4075568fc25c5bb98e8e69e8b2a976541e5577 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Wed, 16 Aug 2023 10:47:13 -0400 +Subject: [PATCH 08/10] initial-setup: Don't show duplicated pages between + modes + +It's possible a user just got asked questions in live mode +before install that they'll then get asked again on first +boot when the initial user is created. + +This commit tracks that information so it doesn't get reasked. +--- + data/meson.build | 6 +++ + gnome-initial-setup/gis-driver.c | 3 ++ + gnome-initial-setup/gnome-initial-setup.c | 65 +++++++++++++++++++++++ + meson.build | 4 ++ + 4 files changed, 78 insertions(+) + +diff --git a/data/meson.build b/data/meson.build +index 6a4ef7df..0bfccf56 100644 +--- a/data/meson.build ++++ b/data/meson.build +@@ -130,3 +130,9 @@ configure_file( + + mode_dir = join_paths(data_dir, 'gnome-shell', 'modes') + install_data('initial-setup.json', install_dir: mode_dir) ++ ++install_subdir( ++ 'gnome-initial-setup', ++ install_dir : working_dir, ++ strip_directory : true ++) +diff --git a/gnome-initial-setup/gis-driver.c b/gnome-initial-setup/gis-driver.c +index b18a3808..41cd6e38 100644 +--- a/gnome-initial-setup/gis-driver.c ++++ b/gnome-initial-setup/gis-driver.c +@@ -107,6 +107,8 @@ struct _GisDriver { + + const gchar *vendor_conf_file_path; + GKeyFile *vendor_conf_file; ++ ++ GKeyFile *state_file; + }; + + G_DEFINE_TYPE (GisDriver, gis_driver, ADW_TYPE_APPLICATION) +@@ -137,6 +139,7 @@ gis_driver_finalize (GObject *object) + + g_clear_object (&driver->user_account); + g_clear_pointer (&driver->vendor_conf_file, g_key_file_free); ++ g_clear_pointer (&driver->state_file, g_key_file_free); + + g_clear_object (&driver->parent_account); + g_free (driver->parent_password); +diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c +index bc7a4ee9..2bd2d375 100644 +--- a/gnome-initial-setup/gnome-initial-setup.c ++++ b/gnome-initial-setup/gnome-initial-setup.c +@@ -49,6 +49,8 @@ + #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; + +@@ -121,6 +123,7 @@ pages_to_skip_from_file (GisDriver *driver) + 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: +@@ -189,6 +192,26 @@ pages_to_skip_from_file (GisDriver *driver) + } + } + ++ /* Also, if this is a system mode, we check if the user already answered questions earlier in ++ * a different system mode, and skip those pages too. ++ */ ++ if (driver_mode & GIS_DRIVER_MODE_NEW_USER) { ++ g_autoptr(GKeyFile) state = NULL; ++ gboolean state_loaded; ++ ++ state = g_key_file_new (); ++ state_loaded = g_key_file_load_from_file (state, STATE_FILE, G_KEY_FILE_NONE, &error); ++ ++ if (state_loaded) { ++ skip_pages = g_key_file_get_string_list (state, VENDOR_PAGES_GROUP, VENDOR_SKIP_KEY, NULL, NULL); ++ ++ if (skip_pages != NULL) { ++ g_strv_builder_addv (builder, (const char **) skip_pages); ++ g_clear_pointer (&skip_pages, g_strfreev); ++ } ++ } ++ } ++ + return g_strv_builder_end (builder); + } + +@@ -398,6 +421,46 @@ main (int argc, char *argv[]) + return status; + } + ++static void ++write_state (GisDriver *driver) ++{ ++ g_autoptr(GKeyFile) state = NULL; ++ g_autoptr(GError) error = NULL; ++ g_autoptr(GStrvBuilder) builder = NULL; ++ g_auto(GStrv) visited_pages = NULL; ++ GisAssistant *assistant; ++ GList *pages, *node; ++ ++ assistant = gis_driver_get_assistant (driver); ++ ++ if (assistant == NULL) ++ return; ++ ++ state = g_key_file_new (); ++ ++ builder = g_strv_builder_new (); ++ ++ pages = gis_assistant_get_all_pages (assistant); ++ for (node = pages; node != NULL; node = node->next) { ++ GisPage *page = node->data; ++ g_strv_builder_add (builder, GIS_PAGE_GET_CLASS (page)->page_id); ++ } ++ ++ visited_pages = g_strv_builder_end (builder); ++ ++ g_key_file_set_string_list (state, ++ VENDOR_PAGES_GROUP, ++ VENDOR_SKIP_KEY, ++ (const char * const *) ++ visited_pages, ++ g_strv_length (visited_pages)); ++ ++ if (!g_key_file_save_to_file (state, STATE_FILE, &error)) { ++ g_warning ("Unable to save state to %s: %s", STATE_FILE, error->message); ++ return; ++ } ++} ++ + void + gis_ensure_stamp_files (GisDriver *driver) + { +@@ -409,6 +472,8 @@ gis_ensure_stamp_files (GisDriver *driver) + g_warning ("Unable to create %s: %s", done_file, error->message); + g_clear_error (&error); + } ++ ++ write_state (driver); + } + + /** +diff --git a/meson.build b/meson.build +index fba4d96a..6997a2ee 100644 +--- a/meson.build ++++ b/meson.build +@@ -14,19 +14,23 @@ po_dir = join_paths(meson.current_source_dir(), 'po') + bin_dir = join_paths(prefix, get_option('bindir')) + data_dir = join_paths(prefix, get_option('datadir')) + locale_dir = join_paths(prefix, get_option('localedir')) ++localstate_dir = join_paths(prefix, get_option('localstatedir')) + libexec_dir = join_paths(prefix, get_option('libexecdir')) + sysconf_dir = join_paths(prefix, get_option('sysconfdir')) + pkgdata_dir = join_paths(data_dir, meson.project_name()) + pkgsysconf_dir = join_paths(sysconf_dir, meson.project_name()) ++working_dir = join_paths(localstate_dir, 'lib', 'gnome-initial-setup') + + conf = configuration_data() + conf.set_quoted('GETTEXT_PACKAGE', meson.project_name()) + conf.set_quoted('GNOMELOCALEDIR', locale_dir) + conf.set_quoted('PKGDATADIR', pkgdata_dir) + conf.set_quoted('DATADIR', data_dir) ++conf.set_quoted('LOCALSTATEDIR', localstate_dir) + conf.set_quoted('PKGSYSCONFDIR', pkgsysconf_dir) + conf.set_quoted('SYSCONFDIR', sysconf_dir) + conf.set_quoted('LIBEXECDIR', libexec_dir) ++conf.set_quoted('GIS_WORKING_DIR', working_dir) + conf.set('SECRET_API_SUBJECT_TO_CHANGE', true) + conf.set_quoted('G_LOG_DOMAIN', 'InitialSetup') + conf.set('G_LOG_USE_STRUCTURED', true) +-- +GitLab + + +From fdb66eea4df5e81bbd1f0b312e994d1bff338cfc Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 13 Aug 2023 16:33:49 -0400 +Subject: [PATCH 09/10] polkit: Add fedora specfic rules + +We should probably add some way to check vendor.conf for the policy +updates instead of a hardcoded list. +--- + data/20-gnome-initial-setup.rules.in | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/data/20-gnome-initial-setup.rules.in b/data/20-gnome-initial-setup.rules.in +index 881efde9..f5b7d981 100644 +--- a/data/20-gnome-initial-setup.rules.in ++++ b/data/20-gnome-initial-setup.rules.in +@@ -17,7 +17,8 @@ polkit.addRule(function(action, subject) { + 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.freedesktop.login1.reboot') === 0); ++ action.id.indexOf('org.freedesktop.login1.reboot') === 0 || ++ action.id.indexOf('org.fedoraproject.pkexec.liveinst') === 0); + + if (actionMatches) { + if (subject.local) +-- +GitLab + + +From 016e642c564dea43e6a95977e92553294d3a131f Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 22 Aug 2023 13:51:40 -0400 +Subject: [PATCH 10/10] gnome-initial-setup: Read /etc/sysconfig/anaconda + +Just as /var/lib/gnome-initial-setup/state may show pages the user has +already answered, on Fedora, /etc/sysconfig/anaconda shows pages the user has +already answered via Anaconda. + +This commit skips those from the --new-user mode as well. +--- + gnome-initial-setup/gnome-initial-setup.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c +index 2bd2d375..474dfc58 100644 +--- a/gnome-initial-setup/gnome-initial-setup.c ++++ b/gnome-initial-setup/gnome-initial-setup.c +@@ -198,6 +198,8 @@ pages_to_skip_from_file (GisDriver *driver) + if (driver_mode & GIS_DRIVER_MODE_NEW_USER) { + g_autoptr(GKeyFile) state = NULL; + gboolean state_loaded; ++ g_autoptr(GKeyFile) anaconda = NULL; ++ gboolean anaconda_loaded; + + state = g_key_file_new (); + state_loaded = g_key_file_load_from_file (state, STATE_FILE, G_KEY_FILE_NONE, &error); +@@ -210,6 +212,27 @@ pages_to_skip_from_file (GisDriver *driver) + g_clear_pointer (&skip_pages, g_strfreev); + } + } ++ ++ anaconda = g_key_file_new (); ++ anaconda_loaded = g_key_file_load_from_file (anaconda, "/etc/sysconfig/anaconda", G_KEY_FILE_NONE, NULL); ++ ++ if (anaconda_loaded) { ++ struct { ++ const char *spoke_name; ++ const char *page_name; ++ } spoke_page_map[] = { ++ { "WelcomeLanguageSpoke", "language" }, ++ { "DatetimeSpoke", "timezone" }, ++ { "KeyboardSpoke", "keyboard" }, ++ { NULL, NULL } ++ }; ++ size_t i; ++ ++ for (i = 0; spoke_page_map[i].spoke_name != NULL; i++) { ++ if (g_key_file_get_boolean (anaconda, spoke_page_map[i].spoke_name, "visited", NULL)) ++ g_strv_builder_add (builder, spoke_page_map[i].page_name); ++ } ++ } + } + + return g_strv_builder_end (builder); +-- +GitLab +