gnome-initial-setup/live-user-mode.patch
Michael Catanzaro 6b8dd31e0c Update live-user-mode.patch again
Hopefully fix gnome-initial-setup failing to create user account or log
into the user session.

Also, remove stray patches that I included by mistake.
2024-01-22 14:18:16 -06:00

2871 lines
106 KiB
Diff

From 575edeab57c891a7053279c676e82bebe53222d3 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 15 Aug 2023 10:53:41 -0400
Subject: [PATCH 01/16] 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 beb96ecd..32b3fe46 100644
--- a/gnome-initial-setup/meson.build
+++ b/gnome-initial-setup/meson.build
@@ -51,7 +51,7 @@ dependencies = [
dependency ('gsettings-desktop-schemas', version: '>= 3.37.1'),
dependency ('fontconfig'),
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 5d30fcd1..00e24d7b 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
--
2.43.0
From 60a2db34bd50d561e716a63dd526ee7ff4810a29 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Sat, 9 Sep 2023 17:07:46 -0400
Subject: [PATCH 02/16] 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);
}
--
2.43.0
From 1478cce3663bfa276066c073be3bbb65bc4b1785 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 8 Sep 2023 11:02:39 -0400
Subject: [PATCH 03/16] 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);
}
--
2.43.0
From e8d5b6a4c1ee9bfb3f8ed7dbe5f25053fae7a1ae Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 24 Aug 2023 21:19:40 -0400
Subject: [PATCH 04/16] 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);
--
2.43.0
From 7b83c89d8b2fe2f9de5f7f364a7af5f2f4fcc605 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Sun, 13 Aug 2023 09:09:56 -0400
Subject: [PATCH 05/16] 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 | 126 +++++++++++++---------
3 files changed, 92 insertions(+), 59 deletions(-)
diff --git a/gnome-initial-setup/gis-driver.c b/gnome-initial-setup/gis-driver.c
index 0b3f542f..4325b631 100644
--- a/gnome-initial-setup/gis-driver.c
+++ b/gnome-initial-setup/gis-driver.c
@@ -30,8 +30,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
@@ -39,12 +37,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;
}
@@ -645,7 +644,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 adb04075..a079c705 100644
--- a/gnome-initial-setup/gnome-initial-setup.c
+++ b/gnome-initial-setup/gnome-initial-setup.c
@@ -55,26 +55,26 @@ 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 (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 (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 },
};
@@ -105,26 +105,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:
@@ -132,28 +121,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
@@ -196,7 +225,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);
@@ -215,13 +245,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;
--
2.43.0
From 68391446ee06083a06899cdadb09ca90b4b40af3 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 30 Aug 2023 15:08:23 -0400
Subject: [PATCH 06/16] 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);
--
2.43.0
From f1e4b58ced27b028e13dd9bb29794419dc08fb72 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Sun, 13 Aug 2023 09:39:07 -0400
Subject: [PATCH 07/16] 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 | 24 +-
.../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, 700 insertions(+), 17 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 4325b631..6a4727cc 100644
--- a/gnome-initial-setup/gis-driver.c
+++ b/gnome-initial-setup/gis-driver.c
@@ -40,6 +40,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 }
};
@@ -786,7 +788,7 @@ gis_driver_startup (GApplication *app)
G_APPLICATION_CLASS (gis_driver_parent_class)->startup (app);
- 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 a079c705..02ca2808 100644
--- a/gnome-initial-setup/gnome-initial-setup.c
+++ b/gnome-initial-setup/gnome-initial-setup.c
@@ -40,13 +40,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;
@@ -64,17 +67,19 @@ 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 (account, 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),
#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 },
};
@@ -118,8 +123,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:
@@ -275,6 +280,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;
}
@@ -308,6 +315,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 }
};
@@ -326,6 +335,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);
@@ -344,7 +356,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 <http://www.gnu.org/licenses/>.
+ */
+
+/* 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 <glib/gstdio.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gio/gdesktopappinfo.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <act/act-user-manager.h>
+
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GisInstallPage" parent="GisPage">
+ <child>
+ <object class="AdwStatusPage" id="status_page">
+ <property name="icon-name">document-save-symbolic</property>
+ <property name="title" translatable="yes">Try or Install?</property>
+ <property name="description" translatable="yes">You can try a temporary version of ${NAME} without making changes to the computer. If you decide to install later, just launch the installer from the Activities view.
+
+ Alternatively, choose install to launch the installer.</property>
+
+ <child>
+ <object class="GtkButton" id="start_button">
+ <property name="use_underline">True</property>
+ <property name="halign">center</property>
+ <style>
+ <class name="suggested-action"/>
+ <class name="pill"/>
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkBox" id="button_box">
+ <property name="orientation">horizontal</property>
+ <property name="homogeneous">True</property>
+ <property name="spacing">24</property>
+ <property name="halign">center</property>
+ <child>
+ <object class="GtkButton" id="try_button">
+ <property name="label" translatable="yes">Try ${NAME}</property>
+ <style>
+ <class name="pill"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="install_button">
+ <property name="label" translatable="yes">Install to Disk…</property>
+ <style>
+ <class name="suggested-action"/>
+ <class name="pill"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/initial-setup">
+ <file preprocess="xml-stripblanks" alias="gis-install-page.ui">gis-install-page.ui</file>
+ <file alias="gis-install-page.css">gis-install-page.css</file>
+ </gresource>
+</gresources>
+
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 8d327f69..ff8406ba 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);
--
2.43.0
From 3f15601af333aeddb8e4458e69f81023a8184a8f Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 16 Aug 2023 10:47:13 -0400
Subject: [PATCH 08/16] 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 6a4727cc..78265527 100644
--- a/gnome-initial-setup/gis-driver.c
+++ b/gnome-initial-setup/gis-driver.c
@@ -101,6 +101,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)
@@ -131,6 +133,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 02ca2808..4e2aa5af 100644
--- a/gnome-initial-setup/gnome-initial-setup.c
+++ b/gnome-initial-setup/gnome-initial-setup.c
@@ -48,6 +48,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;
@@ -119,6 +121,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:
@@ -187,6 +190,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);
}
@@ -396,6 +419,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)
{
@@ -407,6 +470,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 00e24d7b..95fe8e51 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)
--
2.43.0
From 935b2cca6dd7e3ce31e2540d90e5864190885d81 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Sun, 13 Aug 2023 16:33:49 -0400
Subject: [PATCH 09/16] 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)
--
2.43.0
From 03073bd42bf01f5d051f299860be40afd1844447 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 22 Aug 2023 13:51:40 -0400
Subject: [PATCH 10/16] 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 4e2aa5af..2de3ecab 100644
--- a/gnome-initial-setup/gnome-initial-setup.c
+++ b/gnome-initial-setup/gnome-initial-setup.c
@@ -196,6 +196,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);
@@ -208,6 +210,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);
--
2.43.0
From baaa29d56bbb91f3ad15f90e3db98eea446b9adb Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Wed, 17 Jan 2024 12:29:54 -0600
Subject: [PATCH 11/16] Fix criticals in set_localed_input()
If the default input sources do not match the current input sources,
these won't be set in set_input_settings() and we shouldn't try to use
them.
Fixes: (gnome-initial-setup:41149): GLib-CRITICAL **: 10:09:25.599: g_strjoinv: assertion 'str_array != NULL' failed
---
gnome-initial-setup/pages/keyboard/gis-keyboard-page.c | 4 ++--
1 file changed, 2 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 7801667c..3b59a0bf 100644
--- a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c
+++ b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c
@@ -253,12 +253,12 @@ set_localed_input (GisKeyboardPage *self)
g_autofree char *variants = NULL;
g_autofree char *options = NULL;
- if (!priv->localed)
+ if (!priv->localed || !priv->system_layouts || !priv->system_variants)
return;
layouts = g_strjoinv (",", priv->system_layouts);
variants = g_strjoinv (",", priv->system_variants);
- options = g_strjoinv (",", priv->system_options);
+ options = priv->system_options ? g_strjoinv (",", priv->system_options) : g_strdup ("");
g_dbus_proxy_call (priv->localed,
"SetX11Keyboard",
--
2.43.0
From b46a3d7e6df08030680c2e7aaa6408c28315e75f Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Fri, 19 Jan 2024 15:49:15 -0600
Subject: [PATCH 12/16] assistant: assert next page exists when switching to
next page
If there is no next page, then we should crash nicely on this assert
rather than not so nicely.
---
gnome-initial-setup/gis-assistant.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/gnome-initial-setup/gis-assistant.c b/gnome-initial-setup/gis-assistant.c
index 8a7fc52b..c1af2943 100644
--- a/gnome-initial-setup/gis-assistant.c
+++ b/gnome-initial-setup/gis-assistant.c
@@ -111,7 +111,9 @@ find_next_page (GisAssistant *self,
static void
switch_to_next_page (GisAssistant *assistant)
{
- switch_to (assistant, find_next_page (assistant, assistant->current_page));
+ GisPage *next = find_next_page (assistant, assistant->current_page);
+ g_assert (next != NULL);
+ switch_to (assistant, next);
}
static void
--
2.43.0
From deecf58106544ac8603575cb80e79ddfa1b822ba Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Fri, 19 Jan 2024 15:50:33 -0600
Subject: [PATCH 13/16] summary: don't crash if there is no user account to
create
---
gnome-initial-setup/pages/summary/gis-summary-page.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/gnome-initial-setup/pages/summary/gis-summary-page.c b/gnome-initial-setup/pages/summary/gis-summary-page.c
index 8a526b64..8c005640 100644
--- a/gnome-initial-setup/pages/summary/gis-summary-page.c
+++ b/gnome-initial-setup/pages/summary/gis-summary-page.c
@@ -151,6 +151,11 @@ log_user_in (GisSummaryPage *page)
return;
}
+ if (!priv->user_account) {
+ g_info ("No new user account (was the account page skipped?); not initiating login");
+ return;
+ }
+
g_signal_connect (user_verifier, "info",
G_CALLBACK (on_info), page);
g_signal_connect (user_verifier, "problem",
--
2.43.0
From b3e54dbaa09e944e537050c7393cd69e44488384 Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Fri, 19 Jan 2024 15:52:03 -0600
Subject: [PATCH 14/16] Don't show warnings when failing to connect to gdm
This is an expected condition. We need to log it since it might be
needed when debugging, but a warning is overkill.
---
gnome-initial-setup/gis-driver.c | 3 ++-
gnome-initial-setup/pages/install/gis-install-page.c | 2 +-
gnome-initial-setup/pages/summary/gis-summary-page.c | 2 +-
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/gnome-initial-setup/gis-driver.c b/gnome-initial-setup/gis-driver.c
index 78265527..653ba56b 100644
--- a/gnome-initial-setup/gis-driver.c
+++ b/gnome-initial-setup/gis-driver.c
@@ -777,7 +777,8 @@ connect_to_gdm (GisDriver *driver)
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);
+ /* Not a warning because this is expected if running in a user session */
+ g_message ("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);
diff --git a/gnome-initial-setup/pages/install/gis-install-page.c b/gnome-initial-setup/pages/install/gis-install-page.c
index 36ed7539..850c8241 100644
--- a/gnome-initial-setup/pages/install/gis-install-page.c
+++ b/gnome-initial-setup/pages/install/gis-install-page.c
@@ -131,7 +131,7 @@ log_user_in (GisInstallPage *page)
if (!gis_driver_get_gdm_objects (GIS_PAGE (page)->driver,
&greeter, &user_verifier)) {
- g_warning ("No GDM connection; not initiating login");
+ g_info ("No GDM connection; not initiating login");
return;
}
diff --git a/gnome-initial-setup/pages/summary/gis-summary-page.c b/gnome-initial-setup/pages/summary/gis-summary-page.c
index 8c005640..1352cb41 100644
--- a/gnome-initial-setup/pages/summary/gis-summary-page.c
+++ b/gnome-initial-setup/pages/summary/gis-summary-page.c
@@ -147,7 +147,7 @@ log_user_in (GisSummaryPage *page)
if (!gis_driver_get_gdm_objects (GIS_PAGE (page)->driver,
&greeter, &user_verifier)) {
- g_warning ("No GDM connection; not initiating login");
+ g_info ("No GDM connection; not initiating login");
return;
}
--
2.43.0
From fa8caf710c38c41fc17f6dacc1c964a849e4c6e1 Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Fri, 19 Jan 2024 15:58:09 -0600
Subject: [PATCH 15/16] Never skip the summary page if available
This avoids a crash when finishing the welcome page if there are no
other pages available.
---
gnome-initial-setup/gnome-initial-setup.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c
index 2de3ecab..54bca86f 100644
--- a/gnome-initial-setup/gnome-initial-setup.c
+++ b/gnome-initial-setup/gnome-initial-setup.c
@@ -99,6 +99,16 @@ should_skip_page (const gchar *page_id,
if (strcmp (page_id, "welcome") == 0)
return !should_skip_page ("language", skip_pages);
+ /* We have to make sure the welcome page is not the last page because it
+ * unconditionally attempts to load the next page. So, always show the
+ * summary page.
+ *
+ * This doesn't work in existing user mode, but that's OK because we don't
+ * skip arbitrary previously-visited pages when in existing user mode.
+ */
+ if (strcmp (page_id, "summary") == 0)
+ return FALSE;
+
/* check through our skip pages list for pages we don't want */
if (skip_pages) {
while (skip_pages[i]) {
--
2.43.0
From b4e51c75dce43fb8095909278122c96a32b7a62d Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Mon, 22 Jan 2024 14:07:15 -0600
Subject: [PATCH 16/16] Fix failure to log into user account
Currently gis_driver_get_user_permissions() is guaranteed to fail
because we call it after gis_driver_save_data(), which creates the user
account. We need to call it later at the right point.
Also, let's own the user_password that we store on the summary and
install page. Even if it's not expected to change, it doesn't seem very
safe to rely on the GisDriver not deleting it.
---
.../pages/install/gis-install-page.c | 41 ++++++++++++++----
.../pages/summary/gis-summary-page.c | 42 ++++++++++++-------
2 files changed, 59 insertions(+), 24 deletions(-)
diff --git a/gnome-initial-setup/pages/install/gis-install-page.c b/gnome-initial-setup/pages/install/gis-install-page.c
index 850c8241..be4d6968 100644
--- a/gnome-initial-setup/pages/install/gis-install-page.c
+++ b/gnome-initial-setup/pages/install/gis-install-page.c
@@ -43,9 +43,7 @@ struct _GisInstallPagePrivate {
GtkWidget *install_button;
AdwStatusPage *status_page;
GDesktopAppInfo *installer;
-
- ActUser *user_account;
- const gchar *user_password;
+ char *user_password;
};
typedef struct _GisInstallPagePrivate GisInstallPagePrivate;
@@ -128,6 +126,24 @@ log_user_in (GisInstallPage *page)
g_autoptr(GError) error = NULL;
GdmGreeter *greeter = NULL;
GdmUserVerifier *user_verifier = NULL;
+ ActUser *user_account = NULL;
+ const char *user_password = NULL;
+
+ gis_driver_get_user_permissions (GIS_PAGE (page)->driver,
+ &user_account,
+ &user_password);
+ if (user_account == NULL) {
+ g_info ("No new user account (was the account page skipped?); not initiating login");
+ return;
+ }
+ g_assert (priv->user_password == NULL);
+ priv->user_password = g_strdup (user_password);
+
+ if (!gis_driver_get_gdm_objects (GIS_PAGE (page)->driver,
+ &greeter, &user_verifier)) {
+ g_info ("No GDM connection; not initiating login");
+ return;
+ }
if (!gis_driver_get_gdm_objects (GIS_PAGE (page)->driver,
&greeter, &user_verifier)) {
@@ -149,7 +165,7 @@ log_user_in (GisInstallPage *page)
gdm_user_verifier_call_begin_verification_for_user_sync (user_verifier,
SERVICE_NAME,
- act_user_get_user_name (priv->user_account),
+ act_user_get_user_name (user_account),
NULL, &error);
if (error != NULL)
@@ -259,11 +275,6 @@ 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);
}
@@ -341,6 +352,17 @@ gis_install_page_constructed (GObject *object)
gtk_widget_set_visible (GTK_WIDGET (page), TRUE);
}
+static void
+gis_install_page_finalize (GObject *object)
+{
+ GisInstallPage *page = GIS_INSTALL_PAGE (object);
+ GisInstallPagePrivate *priv = gis_install_page_get_instance_private (page);
+
+ g_clear_pointer (&priv->user_password, g_free);
+
+ G_OBJECT_CLASS (gis_install_page_parent_class)->finalize (object);
+}
+
static void
gis_install_page_locale_changed (GisPage *page)
{
@@ -365,6 +387,7 @@ gis_install_page_class_init (GisInstallPageClass *klass)
page_class->locale_changed = gis_install_page_locale_changed;
page_class->shown = gis_install_page_shown;
object_class->constructed = gis_install_page_constructed;
+ object_class->finalize = gis_install_page_finalize;
}
static void
diff --git a/gnome-initial-setup/pages/summary/gis-summary-page.c b/gnome-initial-setup/pages/summary/gis-summary-page.c
index 1352cb41..1fc14556 100644
--- a/gnome-initial-setup/pages/summary/gis-summary-page.c
+++ b/gnome-initial-setup/pages/summary/gis-summary-page.c
@@ -40,9 +40,7 @@
struct _GisSummaryPagePrivate {
GtkWidget *start_button;
AdwStatusPage *status_page;
-
- ActUser *user_account;
- const gchar *user_password;
+ char *user_password;
};
typedef struct _GisSummaryPagePrivate GisSummaryPagePrivate;
@@ -144,15 +142,22 @@ log_user_in (GisSummaryPage *page)
g_autoptr(GError) error = NULL;
GdmGreeter *greeter = NULL;
GdmUserVerifier *user_verifier = NULL;
+ ActUser *user_account = NULL;
+ const char *user_password = NULL;
- if (!gis_driver_get_gdm_objects (GIS_PAGE (page)->driver,
- &greeter, &user_verifier)) {
- g_info ("No GDM connection; not initiating login");
+ gis_driver_get_user_permissions (GIS_PAGE (page)->driver,
+ &user_account,
+ &user_password);
+ if (user_account == NULL) {
+ g_info ("No new user account (was the account page skipped?); not initiating login");
return;
}
+ g_assert (priv->user_password == NULL);
+ priv->user_password = g_strdup (user_password);
- if (!priv->user_account) {
- g_info ("No new user account (was the account page skipped?); not initiating login");
+ if (!gis_driver_get_gdm_objects (GIS_PAGE (page)->driver,
+ &greeter, &user_verifier)) {
+ g_info ("No GDM connection; not initiating login");
return;
}
@@ -171,11 +176,11 @@ log_user_in (GisSummaryPage *page)
/* We are in NEW_USER mode and we want to make it possible for third
* parties to find out which user ID we created.
*/
- add_uid_file (act_user_get_uid (priv->user_account));
+ add_uid_file (act_user_get_uid (user_account));
gdm_user_verifier_call_begin_verification_for_user_sync (user_verifier,
SERVICE_NAME,
- act_user_get_user_name (priv->user_account),
+ act_user_get_user_name (user_account),
NULL, &error);
if (error != NULL)
@@ -214,11 +219,6 @@ gis_summary_page_shown (GisPage *page)
{
GisSummaryPage *summary = GIS_SUMMARY_PAGE (page);
GisSummaryPagePrivate *priv = gis_summary_page_get_instance_private (summary);
- 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->start_button);
}
@@ -264,6 +264,17 @@ gis_summary_page_constructed (GObject *object)
gtk_widget_set_visible (GTK_WIDGET (page), TRUE);
}
+static void
+gis_summary_page_finalize (GObject *object)
+{
+ GisSummaryPage *page = GIS_SUMMARY_PAGE (object);
+ GisSummaryPagePrivate *priv = gis_summary_page_get_instance_private (page);
+
+ g_clear_pointer (&priv->user_password, g_free);
+
+ G_OBJECT_CLASS (gis_summary_page_parent_class)->finalize (object);
+}
+
static void
gis_summary_page_locale_changed (GisPage *page)
{
@@ -286,6 +297,7 @@ gis_summary_page_class_init (GisSummaryPageClass *klass)
page_class->locale_changed = gis_summary_page_locale_changed;
page_class->shown = gis_summary_page_shown;
object_class->constructed = gis_summary_page_constructed;
+ object_class->finalize = gis_summary_page_finalize;
}
static void
--
2.43.0