diff --git a/gnome-shell.spec b/gnome-shell.spec index 7aea317..8920e46 100644 --- a/gnome-shell.spec +++ b/gnome-shell.spec @@ -39,6 +39,8 @@ Patch20: 0001-systemActions-Optionally-allow-restart-shutdown-on-l.patch Patch21: 0001-authPrompt-Connect-disable-show-password-key-with-pa.patch Patch22: 0001-gdm-util-Early-initialize-all-internal-properties.patch Patch23: 0001-main-Register-session-with-GDM-on-startup.patch +# Passwordless GDM patch series +Patch24: pre-changes-for-passwordless-gdm-backport.patch # Misc. Patch30: 0001-panel-add-an-icon-to-the-ActivitiesButton.patch diff --git a/pre-changes-for-passwordless-gdm-backport.patch b/pre-changes-for-passwordless-gdm-backport.patch new file mode 100644 index 0000000..3a9b58e --- /dev/null +++ b/pre-changes-for-passwordless-gdm-backport.patch @@ -0,0 +1,348 @@ +From 38531053c836ca7ae91e5f20785a67e690422d01 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 25 Aug 2025 14:25:49 +0200 +Subject: [PATCH 1/6] gdm/authPrompt: Unset the entry reference on destruction + +We use the internal entry as the reference to the text entry that is +currently in use, but during destruction we do not unset it, thus the +garbage collector may requires further cycles to actually release it. + +Simplify its job here, improves 572d011894c9b490b8a17ad7db6adec335fbb017 + +Part-of: +--- + js/gdm/authPrompt.js | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js +index 2b65eee8b9..e4950e56ce 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -133,6 +133,7 @@ var AuthPrompt = GObject.registerClass({ + + this._userVerifier.destroy(); + this._userVerifier = null; ++ this._entry = null; + } + + vfunc_key_press_event(keyPressEvent) { +-- +2.52.0 + + +From 34ff1bdba494f66282cba3c8a955b48b041371cc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 25 Aug 2025 14:29:55 +0200 +Subject: [PATCH 2/6] gdm/authPrompt: Clear the inactive entry too + +In multi-factor authentication cases we may end up clearing the current +entry, but we are potentially leaving a previously filled inactive entry +as it is. + +Avoid this, and clear all the entries we have when clearing the prompt. + +Part-of: +--- + js/gdm/authPrompt.js | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js +index e4950e56ce..2d306d16b5 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -489,6 +489,7 @@ var AuthPrompt = GObject.registerClass({ + + clear() { + this._entry.text = ''; ++ this._inactiveEntry.text = ''; + this.stopSpinning(); + this._authList.clear(); + this._authList.hide(); +-- +2.52.0 + + +From 576c74f85fe316ef541a347bd51134ceb091658a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Aug 2025 16:40:07 +0200 +Subject: [PATCH 3/6] gdm/authPrompt: Factorize the entry update code + +Cleanup the code a bit to make future updates smaller + +Part-of: +--- + js/gdm/authPrompt.js | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js +index 2d306d16b5..ed42409b12 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -305,13 +305,22 @@ var AuthPrompt = GObject.registerClass({ + } + + _updateEntry(secret) { ++ let newEntry, inactiveEntry; ++ + if (secret && this._entry !== this._passwordEntry) { +- this._mainBox.replace_child(this._entry, this._passwordEntry); +- this._entry = this._passwordEntry; ++ newEntry = this._passwordEntry; ++ inactiveEntry = this._textEntry; + } else if (!secret && this._entry !== this._textEntry) { +- this._mainBox.replace_child(this._entry, this._textEntry); +- this._entry = this._textEntry; ++ newEntry = this._textEntry; ++ inactiveEntry = this._passwordEntry; ++ } ++ ++ if (newEntry) { ++ this._mainBox.replace_child(this._entry, newEntry); ++ this._entry = newEntry; ++ this._inactiveEntry = inactiveEntry; + } ++ + this._capsLockWarningLabel.visible = secret; + } + +-- +2.52.0 + + +From 2b9dd08c26da92ed0b2e86356fb26a1b69d02f66 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 25 Aug 2025 14:35:57 +0200 +Subject: [PATCH 4/6] gdm/authPrompt: Preserve the text when switching entry + visibility + +The text visibility of an auth prompt entry may change dynamically at +runtime, in particular when unlocking the screen with the blank screen +or with the screen shield visible this is happening: + - The user starts typing the PAM credential (may be secret or not) + - Under the hood the PAM conversation starts and actually asks user + for input + - The entry text is not cleared because we use what the user has typed + so far as the preemptive secret. + - The entry is adjusted to follow the requested PAM text visibility + settings. + -> This may lead to switching the actual text entry widget in use + +Now, if the first entry that PAM requires is "ECHO ON", like it may +happen in the case in which a visible value is requested, we end up +"clearing" what the user as typed instead of preserving the value as +pre-filled value. + +Causing the user typing something wrong instead. + +To prevent this we need to restore both the text, the cursor position +and the selection bounds (in case the use pressed some key [binding]) +leading to a position or selection change. + +Part-of: +--- + js/gdm/authPrompt.js | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js +index ed42409b12..e4084ad22d 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -319,6 +319,9 @@ var AuthPrompt = GObject.registerClass({ + this._mainBox.replace_child(this._entry, newEntry); + this._entry = newEntry; + this._inactiveEntry = inactiveEntry; ++ ++ const {text, cursorPosition, selectionBound} = inactiveEntry.clutterText; ++ this._entry.clutterText.set({text, cursorPosition, selectionBound}); + } + + this._capsLockWarningLabel.visible = secret; +-- +2.52.0 + + +From 1670d0e80215cd3c934dc1de79997753b9eafdf8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Aug 2025 15:08:23 +0200 +Subject: [PATCH 5/6] gdm/authPrompt: Fix key focus handling on choice list + +When a choice list widget is prompted in GDM we call updateSensitivity() +but this does not act on the currently visible authentication widget but +rather on the text entry all the times. + +And this causes that when a choice list is shown we always set the key +focus to the (hidden) text entry. + +This implies that when the list is finally shown, moving the arrow keys +leads makes the entry context menu to be shown instead of being able to +navigate through the entries. + +So, make updateSensitivity use the currently visible authorization +widget instead and use it to control the sensitivity of the choice list + +Part-of: +--- + js/gdm/authPrompt.js | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js +index e4084ad22d..f9205d41dd 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -524,13 +524,13 @@ var AuthPrompt = GObject.registerClass({ + this._authList.set({ + opacity: 0, + visible: true, +- reactive: false, + }); ++ this.updateSensitivity(false); + this._authList.ease({ + opacity: 255, + duration: MESSAGE_FADE_OUT_ANIMATION_TIME, + transition: Clutter.AnimationMode.EASE_OUT_QUAD, +- onComplete: () => (this._authList.reactive = true), ++ onComplete: () => this.updateSensitivity(true), + }); + } + +@@ -606,18 +606,25 @@ var AuthPrompt = GObject.registerClass({ + } + + updateSensitivity(sensitive) { +- if (this._entry.reactive === sensitive) ++ let authWidget; ++ ++ if (this._authList.visible) ++ authWidget = this._authList; ++ else ++ authWidget = this._entry; ++ ++ if (authWidget.reactive === sensitive) + return; + +- this._entry.reactive = sensitive; ++ authWidget.reactive = sensitive; + + if (sensitive) { +- this._entry.grab_key_focus(); ++ authWidget.grab_key_focus(); + } else { + this.grab_key_focus(); + +- if (this._entry === this._passwordEntry) +- this._entry.password_visible = false; ++ if (authWidget === this._passwordEntry) ++ authWidget.password_visible = false; + } + } + +-- +2.52.0 + + +From c82bbfa5eeb3e3e6455f9d168b0463183d8eaf0a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Tue, 8 Jul 2025 17:42:56 +0200 +Subject: [PATCH 6/6] loginDialog: Move session/a11y buttons into a box + +The intermediate container allows the theme to control the distance +from the edge and spacing between buttons, which is more accessible +to the designers than computing the values from code. + +Part-of: +--- + .../widgets/_login-dialog.scss | 5 ++++ + js/gdm/loginDialog.js | 27 +++++++++++-------- + 2 files changed, 21 insertions(+), 11 deletions(-) + +diff --git a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss +index f68d5de996..307a751628 100644 +--- a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss ++++ b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss +@@ -89,6 +89,11 @@ + } + } + ++.login-dialog-bottom-button-group { ++ padding: 32px; ++ spacing: 16px; ++} ++ + .login-dialog-logo-bin { padding: 24px 0px; } + .login-dialog-banner { color: darken($osd_fg_color,10%); } + .login-dialog-button-box { width: 23em; spacing: 5px; } +diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js +index fbced3e4ab..a218e59d78 100644 +--- a/js/gdm/loginDialog.js ++++ b/js/gdm/loginDialog.js +@@ -559,6 +559,11 @@ var LoginDialog = GObject.registerClass({ + bannerBox.add_child(this._bannerLabel); + this._updateBanner(); + ++ this._bottomButtonGroup = new St.BoxLayout({ ++ style_class: 'login-dialog-bottom-button-group', ++ }); ++ this.add_child(this._bottomButtonGroup); ++ + this._sessionMenuButton = new SessionMenuButton(); + this._sessionMenuButton.connect('session-activated', + (list, sessionId) => { +@@ -566,7 +571,7 @@ var LoginDialog = GObject.registerClass({ + }); + this._sessionMenuButton.opacity = 0; + this._sessionMenuButton.show(); +- this.add_child(this._sessionMenuButton); ++ this._bottomButtonGroup.add_child(this._sessionMenuButton); + + this._logoBin = new St.Widget({ style_class: 'login-dialog-logo-bin', + x_align: Clutter.ActorAlign.CENTER, +@@ -625,17 +630,17 @@ var LoginDialog = GObject.registerClass({ + return actorBox; + } + +- _getSessionMenuButtonAllocation(dialogBox) { ++ _getBottomButtonGroupAllocation(dialogBox) { + let actorBox = new Clutter.ActorBox(); + +- let [, , natWidth, natHeight] = this._sessionMenuButton.get_preferred_size(); ++ const [, , natWidth, natHeight] = this._bottomButtonGroup.get_preferred_size(); + + if (this.get_text_direction() === Clutter.TextDirection.RTL) +- actorBox.x1 = dialogBox.x1 + natWidth; ++ actorBox.x1 = dialogBox.x1; + else +- actorBox.x1 = dialogBox.x2 - (natWidth * 2); ++ actorBox.x1 = dialogBox.x2 - natWidth; + +- actorBox.y1 = dialogBox.y2 - (natHeight * 2); ++ actorBox.y1 = dialogBox.y2 - natHeight; + actorBox.x2 = actorBox.x1 + natWidth; + actorBox.y2 = actorBox.y1 + natHeight; + +@@ -698,9 +703,9 @@ var LoginDialog = GObject.registerClass({ + logoHeight = logoAllocation.y2 - logoAllocation.y1; + } + +- let sessionMenuButtonAllocation = null; +- if (this._sessionMenuButton.visible) +- sessionMenuButtonAllocation = this._getSessionMenuButtonAllocation(dialogBox); ++ let bottomButtonGroupAllocation = null; ++ if (this._bottomButtonGroup.visible) ++ bottomButtonGroupAllocation = this._getBottomButtonGroupAllocation(dialogBox); + + // Then figure out if we're overly constrained and need to + // try a different layout, or if we have what extra space we +@@ -801,8 +806,8 @@ var LoginDialog = GObject.registerClass({ + if (logoAllocation) + this._logoBin.allocate(logoAllocation); + +- if (sessionMenuButtonAllocation) +- this._sessionMenuButton.allocate(sessionMenuButtonAllocation); ++ if (bottomButtonGroupAllocation) ++ this._bottomButtonGroup.allocate(bottomButtonGroupAllocation); + } + + _ensureUserListLoaded() { +-- +2.52.0 +