AlmaLinux changes: Use AlmaLinux icon as activities button
Use unbranded illustrations Fix Firefox desktop filename in favorites
This commit is contained in:
commit
fce3901f94
File diff suppressed because it is too large
Load Diff
@ -40,7 +40,6 @@ Patch: disable-unlock-entry-until-question.patch
|
||||
Patch: 0001-main-Register-session-with-GDM-on-startup.patch
|
||||
Patch: 0001-loginManager-Update-RegisterSession.patch
|
||||
# Passwordless work
|
||||
Patch: pre-changes-for-passwordless-gdm-backport.patch
|
||||
Patch: 0001-Support-for-web-login-and-unified-auth-mechanism.patch
|
||||
Patch: post-changes-for-passwordless-gdm-backport.patch
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
From 45dd4808e26dabd03c25c126e97b22a20b4bcfa5 Mon Sep 17 00:00:00 2001
|
||||
From bc94cdc84421125da2dcc5fc3d627a475bd565cc Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 12:07:45 +0200
|
||||
Subject: [PATCH 1/5] Use Object.keys(this._sections) instead of
|
||||
Subject: [PATCH 01/12] Use Object.keys(this._sections) instead of
|
||||
this._sections.keys()
|
||||
|
||||
---
|
||||
@ -25,10 +25,10 @@ index 5aaa45fd3..e2c516585 100644
|
||||
2.55.0
|
||||
|
||||
|
||||
From 2f4e4d9bff76e6b4db951890b82282cc7a01921a Mon Sep 17 00:00:00 2001
|
||||
From e1e99c9b443a60cf176d21b8538fc7f1ebd8ed65 Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 12:52:09 +0200
|
||||
Subject: [PATCH 2/5] Don't use _once timeout variants
|
||||
Subject: [PATCH 02/12] Don't use _once timeout variants
|
||||
|
||||
---
|
||||
js/gdm/authServices.js | 7 +++++--
|
||||
@ -98,16 +98,15 @@ index cf6a4e1fb..0271d98f2 100644
|
||||
2.55.0
|
||||
|
||||
|
||||
From 398fd1ad475e2092977cb210e12d3403bc0fdbaa Mon Sep 17 00:00:00 2001
|
||||
From 9927abed68a443ee9f00ddcc5e4c48187a3c70da Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Tue, 9 Jun 2026 09:57:09 +0200
|
||||
Subject: [PATCH 3/5] gdm: Use alternative to Promise.withResolvers()
|
||||
Subject: [PATCH 03/12] gdm: Use alternative to Promise.withResolvers()
|
||||
|
||||
It doesn't exist in this version
|
||||
---
|
||||
js/gdm/authServices.js | 6 +++++-
|
||||
js/gdm/userVerifier.js | 6 +++++-
|
||||
2 files changed, 10 insertions(+), 2 deletions(-)
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/gdm/authServices.js b/js/gdm/authServices.js
|
||||
index e13d4106e..e5cf21c96 100644
|
||||
@ -126,31 +125,14 @@ index e13d4106e..e5cf21c96 100644
|
||||
const task = Gio.Task.new(this, cancellable, () => {
|
||||
try {
|
||||
const res = task.propagate_boolean();
|
||||
diff --git a/js/gdm/userVerifier.js b/js/gdm/userVerifier.js
|
||||
index 02decbf86..27777c6f1 100644
|
||||
--- a/js/gdm/userVerifier.js
|
||||
+++ b/js/gdm/userVerifier.js
|
||||
@@ -223,7 +223,11 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
return;
|
||||
|
||||
const message = this.currentMessage;
|
||||
- const {promise, resolve} = Promise.withResolvers();
|
||||
+ let resolve, reject;
|
||||
+ const promise = new Promise((res, rej) => {
|
||||
+ resolve = res;
|
||||
+ reject = rej;
|
||||
+ });
|
||||
this._showMessageResolver = resolve;
|
||||
|
||||
this.emit('show-message', {
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
||||
From dda52fc6a0e12af8dc3b6eca5f853923c311d837 Mon Sep 17 00:00:00 2001
|
||||
From 8b06c49cb2e31b26cbf155bae0795fb7c0d7d6f6 Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Thu, 6 Aug 2026 23:58:46 +0200
|
||||
Subject: [PATCH 4/5] gdm: Use old ButtonMask enum
|
||||
Subject: [PATCH 04/12] gdm: Use old ButtonMask enum
|
||||
|
||||
In this version it still used as ONE, TWO and THREE
|
||||
---
|
||||
@ -187,7 +169,7 @@ index e2c516585..ca9a0b9d1 100644
|
||||
this.bind_property('reactive',
|
||||
this, 'can-focus',
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index 007c1538c..7e69525f9 100644
|
||||
index 4c1697f08..31addc47f 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -291,7 +291,7 @@ export const AuthPrompt = GObject.registerClass({
|
||||
@ -215,10 +197,11 @@ index 3b6496296..34c371b8d 100644
|
||||
--
|
||||
2.55.0
|
||||
|
||||
From 5e3b6d53a6e34e27e6c38d517fe51cfe52b2b96e Mon Sep 17 00:00:00 2001
|
||||
|
||||
From 4373ce16c8653c523fcca8879915254aa76d21d0 Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Fri, 7 Aug 2026 11:42:37 +0200
|
||||
Subject: [PATCH 5/5] style: Fix color styles to adapt when on light-mode
|
||||
Subject: [PATCH 05/12] style: Fix color styles to adapt when on light-mode
|
||||
(classic-mode)
|
||||
|
||||
---
|
||||
@ -276,3 +259,866 @@ index da04425bd..98ecf7b0f 100644
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
||||
From 3745870fd893ae84cde12f4a84e4bd9b2ea65762 Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Wed, 12 Aug 2026 12:37:41 +0200
|
||||
Subject: [PATCH 06/12] gdm: Restore util.js and misc/smartcardManager.js as
|
||||
compat shims
|
||||
|
||||
Several symbols moved out of util.js into userVerifier.js and
|
||||
settings.js, and smartcardManager.js moved from misc/ to gdm/.
|
||||
Extensions importing from the old locations would break.
|
||||
|
||||
Re-export the moved symbols from util.js, and add back
|
||||
misc/smartcardManager.js as a thin re-export of the new gdm/
|
||||
location, to keep the old import paths and names working.
|
||||
---
|
||||
js/gdm/util.js | 21 +++++++++++++++++++++
|
||||
js/js-resources.gresource.xml | 1 +
|
||||
js/misc/smartcardManager.js | 3 +++
|
||||
3 files changed, 25 insertions(+)
|
||||
create mode 100644 js/misc/smartcardManager.js
|
||||
|
||||
diff --git a/js/gdm/util.js b/js/gdm/util.js
|
||||
index 10f9131d9..d9a7e2239 100644
|
||||
--- a/js/gdm/util.js
|
||||
+++ b/js/gdm/util.js
|
||||
@@ -3,6 +3,27 @@ import Clutter from 'gi://Clutter';
|
||||
import * as Batch from './batch.js';
|
||||
import * as Main from '../ui/main.js';
|
||||
|
||||
+// Re-exported for backward compatibility: these symbols used to live in
|
||||
+// this file before being split into userVerifier.js and settings.js.
|
||||
+export {MessageType, ShellUserVerifier} from './userVerifier.js';
|
||||
+export {
|
||||
+ LOGIN_SCREEN_SCHEMA,
|
||||
+ PASSWORD_AUTHENTICATION_KEY,
|
||||
+ FINGERPRINT_AUTHENTICATION_KEY,
|
||||
+ SMARTCARD_AUTHENTICATION_KEY,
|
||||
+ BANNER_MESSAGE_KEY,
|
||||
+ BANNER_MESSAGE_SOURCE_KEY,
|
||||
+ BANNER_MESSAGE_TEXT_KEY,
|
||||
+ BANNER_MESSAGE_PATH_KEY,
|
||||
+ ALLOWED_FAILURES_KEY,
|
||||
+ LOGO_KEY,
|
||||
+ DISABLE_USER_LIST_KEY,
|
||||
+} from './settings.js';
|
||||
+
|
||||
+export const PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||
+export const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||
+export const SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
|
||||
+
|
||||
export const CLONE_FADE_ANIMATION_TIME = 250;
|
||||
|
||||
/**
|
||||
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
|
||||
index daff41d6a..a1c0e6e3c 100644
|
||||
--- a/js/js-resources.gresource.xml
|
||||
+++ b/js/js-resources.gresource.xml
|
||||
@@ -50,6 +50,7 @@
|
||||
<file>misc/permissionStore.js</file>
|
||||
<file>misc/signals.js</file>
|
||||
<file>misc/signalTracker.js</file>
|
||||
+ <file>misc/smartcardManager.js</file>
|
||||
<file>misc/systemActions.js</file>
|
||||
<file>misc/timeLimitsManager.js</file>
|
||||
<file>misc/util.js</file>
|
||||
diff --git a/js/misc/smartcardManager.js b/js/misc/smartcardManager.js
|
||||
new file mode 100644
|
||||
index 000000000..df62ec048
|
||||
--- /dev/null
|
||||
+++ b/js/misc/smartcardManager.js
|
||||
@@ -0,0 +1,3 @@
|
||||
+// Re-exported for backward compatibility: this module used to live here
|
||||
+// before being moved to gdm/smartcardManager.js.
|
||||
+export {getSmartcardManager} from '../gdm/smartcardManager.js';
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
||||
From bd1327dfb48dc9533d6e9055e6a42f0c1c1024bf Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Wed, 12 Aug 2026 12:37:50 +0200
|
||||
Subject: [PATCH 07/12] authPrompt: Restore BeginRequestType as alias for
|
||||
ResetType
|
||||
|
||||
ResetType was renamed from BeginRequestType. Keep the old name
|
||||
exported as an alias so extensions referencing
|
||||
AuthPrompt.BeginRequestType keep working.
|
||||
---
|
||||
js/gdm/authPrompt.js | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index 31addc47f..4f7ceb86c 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -44,6 +44,9 @@ export const ResetType = {
|
||||
REUSE_USERNAME: 2,
|
||||
};
|
||||
|
||||
+// Kept for backward compatibility: ResetType used to be named BeginRequestType.
|
||||
+export const BeginRequestType = ResetType;
|
||||
+
|
||||
export const AuthPrompt = GObject.registerClass({
|
||||
Signals: {
|
||||
'cancelled': {},
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
||||
From e5d4b76c4de043cb26f88065e623028970a5e1af Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Wed, 12 Aug 2026 12:38:25 +0200
|
||||
Subject: [PATCH 08/12] Revert "gdm/authServices: Use per-request callbacks to
|
||||
handle services queries"
|
||||
|
||||
This reverts commit 929f864f1135a4225c09857ae3655d16de6c9251.
|
||||
|
||||
The per-request callback pattern removed ShellUserVerifier.answerQuery()
|
||||
and selectChoice() as public methods, breaking extensions that call them
|
||||
directly (e.g. ShellUserVerifier subclasses used by external IdP
|
||||
integrations). Restore the original answerQuery()/selectChoice() API so
|
||||
those extensions keep working, at the cost of the per-request context
|
||||
safety the callback pattern added.
|
||||
---
|
||||
js/gdm/authPrompt.js | 82 ++++++++--------------------
|
||||
js/gdm/authServices.js | 14 ++++-
|
||||
js/gdm/authServicesLegacy.js | 29 ++++------
|
||||
js/gdm/authServicesSSSDSwitchable.js | 55 +++++++------------
|
||||
js/gdm/userVerifier.js | 16 +++++-
|
||||
5 files changed, 79 insertions(+), 117 deletions(-)
|
||||
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index 4f7ceb86c..bbf6c4e4e 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -194,7 +194,20 @@ export const AuthPrompt = GObject.registerClass({
|
||||
|
||||
this._authList = new AuthList.AuthList();
|
||||
this._authList.hide();
|
||||
- this._authListActivateId = 0;
|
||||
+ this._authList.connect('activate', (list, key) => {
|
||||
+ this._authList.reactive = false;
|
||||
+ this._authList.ease({
|
||||
+ opacity: 0,
|
||||
+ duration: MESSAGE_FADE_OUT_ANIMATION_TIME * 0.5,
|
||||
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
+ onComplete: () => {
|
||||
+ this._authListTitle.child.text = '';
|
||||
+ this._authList.clear();
|
||||
+ this._authList.hide();
|
||||
+ this._userVerifier.selectChoice(this._queryingService, key);
|
||||
+ },
|
||||
+ });
|
||||
+ });
|
||||
this.add_child(this._authList);
|
||||
|
||||
this._authListTitle = new St.Bin({
|
||||
@@ -300,7 +313,6 @@ export const AuthPrompt = GObject.registerClass({
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
});
|
||||
- this._authButton.connect('clicked', () => this._completePendingCallback());
|
||||
this._mainBox.add_child(this._authButton);
|
||||
|
||||
this._webLoginDialog = new WebLogin.WebLoginDialog();
|
||||
@@ -372,7 +384,7 @@ export const AuthPrompt = GObject.registerClass({
|
||||
this.startSpinning({animate: true});
|
||||
|
||||
if (this._queryingService) {
|
||||
- this._completePendingCallback(this._entry.text);
|
||||
+ this._userVerifier.answerQuery(this._queryingService, this._entry.text);
|
||||
} else {
|
||||
this._preemptiveAnswer = this._entry.text;
|
||||
|
||||
@@ -410,37 +422,17 @@ export const AuthPrompt = GObject.registerClass({
|
||||
this._capsLockWarningLabel.visible = secret;
|
||||
}
|
||||
|
||||
- _setPendingCallback(callback) {
|
||||
- if (this._pendingCallback)
|
||||
- throw new Error('A pending request is already active');
|
||||
- this._pendingCallback = callback;
|
||||
- }
|
||||
-
|
||||
- _completePendingCallback(...args) {
|
||||
- if (!this._pendingCallback)
|
||||
- throw new Error('No pending request to complete');
|
||||
-
|
||||
- const callback = this._pendingCallback;
|
||||
- this._pendingCallback = null;
|
||||
-
|
||||
- this._userVerifier.handlePendingMessages()
|
||||
- .then(() => callback(...args))
|
||||
- .catch(logErrorUnlessCancelled);
|
||||
- }
|
||||
-
|
||||
- _onAskQuestion({serviceName, question, secret, answerHandler}) {
|
||||
+ _onAskQuestion({serviceName, question, secret}) {
|
||||
if (this._queryingService)
|
||||
this.clear();
|
||||
|
||||
this._queryingService = serviceName;
|
||||
this.promptStep++;
|
||||
|
||||
- this._setPendingCallback(answerHandler);
|
||||
-
|
||||
const preemptiveAnswer = this._preemptiveAnswer;
|
||||
this._clearPreemptiveState();
|
||||
if (preemptiveAnswer) {
|
||||
- this._completePendingCallback(preemptiveAnswer);
|
||||
+ this._userVerifier.answerQuery(this._queryingService, preemptiveAnswer);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -457,7 +449,7 @@ export const AuthPrompt = GObject.registerClass({
|
||||
this.emit('prompted');
|
||||
}
|
||||
|
||||
- _onShowChoiceList({serviceName, promptMessage, choiceList, choiceHandler}) {
|
||||
+ _onShowChoiceList({serviceName, promptMessage, choiceList}) {
|
||||
if (this._queryingService)
|
||||
this.clear();
|
||||
|
||||
@@ -466,9 +458,6 @@ export const AuthPrompt = GObject.registerClass({
|
||||
|
||||
this._clearPreemptiveState();
|
||||
|
||||
- this._connectAuthListActivate();
|
||||
- this._setPendingCallback(choiceHandler);
|
||||
-
|
||||
this.setChoiceList(promptMessage, choiceList);
|
||||
this.updateSensitivity({sensitive: true});
|
||||
this.emit('prompted');
|
||||
@@ -512,7 +501,10 @@ export const AuthPrompt = GObject.registerClass({
|
||||
|
||||
this._clearPreemptiveState();
|
||||
|
||||
- this._setPendingCallback(callback);
|
||||
+ const authButtonClickedId = this._authButton.connect('clicked', () => {
|
||||
+ this._authButton.disconnect(authButtonClickedId);
|
||||
+ callback();
|
||||
+ });
|
||||
|
||||
this._authButton.set_label(label);
|
||||
|
||||
@@ -687,10 +679,8 @@ export const AuthPrompt = GObject.registerClass({
|
||||
this._authListTitle.child.text = '';
|
||||
this._authList.clear();
|
||||
this._authList.hide();
|
||||
- this._disconnectAuthListActivate();
|
||||
this._authButton.hide();
|
||||
this._closeWebLoginDialog();
|
||||
- this._pendingCallback = null;
|
||||
|
||||
[this._mainBox, this._webLoginDialog].forEach(widget => {
|
||||
widget.opacity = 255;
|
||||
@@ -714,34 +704,6 @@ export const AuthPrompt = GObject.registerClass({
|
||||
this.updateSensitivity({sensitive: true});
|
||||
}
|
||||
|
||||
- _connectAuthListActivate() {
|
||||
- if (this._authListActivateId)
|
||||
- return;
|
||||
-
|
||||
- this._authListActivateId =
|
||||
- this._authList.connect('activate', (list, key) => {
|
||||
- this._authList.reactive = false;
|
||||
- this._authList.ease({
|
||||
- opacity: 0,
|
||||
- duration: MESSAGE_FADE_OUT_ANIMATION_TIME * 0.5,
|
||||
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
- onComplete: () => {
|
||||
- this._authListTitle.child.text = '';
|
||||
- this._authList.clear();
|
||||
- this._authList.hide();
|
||||
- this._completePendingCallback(key);
|
||||
- },
|
||||
- });
|
||||
- });
|
||||
- }
|
||||
-
|
||||
- _disconnectAuthListActivate() {
|
||||
- if (this._authListActivateId) {
|
||||
- this._authList.disconnect(this._authListActivateId);
|
||||
- this._authListActivateId = 0;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
_fadeInElement(element) {
|
||||
if (element.visible)
|
||||
return;
|
||||
diff --git a/js/gdm/authServices.js b/js/gdm/authServices.js
|
||||
index e5cf21c96..e5c60e1d7 100644
|
||||
--- a/js/gdm/authServices.js
|
||||
+++ b/js/gdm/authServices.js
|
||||
@@ -81,7 +81,6 @@ export class AuthServices extends GObject.Object {
|
||||
* @param {string} serviceName
|
||||
* @param {string} question
|
||||
* @param {boolean} [secret]
|
||||
- * @param {Function} answerHandler
|
||||
*/
|
||||
'ask-question': {param_types: [GObject.TYPE_JSOBJECT]},
|
||||
/**
|
||||
@@ -93,7 +92,6 @@ export class AuthServices extends GObject.Object {
|
||||
* @param {string} serviceName
|
||||
* @param {string} promptMessage
|
||||
* @param {object} [choiceList] - keys map to {title: string}
|
||||
- * @param {Function} [choiceHandler]
|
||||
*/
|
||||
'show-choice-list': {param_types: [GObject.TYPE_JSOBJECT]},
|
||||
/**
|
||||
@@ -167,6 +165,14 @@ export class AuthServices extends GObject.Object {
|
||||
return this._handleGetSupportedRoles();
|
||||
}
|
||||
|
||||
+ selectChoice(serviceName, key) {
|
||||
+ this._handleSelectChoice(serviceName, key);
|
||||
+ }
|
||||
+
|
||||
+ answerQuery(serviceName, answer) {
|
||||
+ this._handleAnswerQuery(serviceName, answer);
|
||||
+ }
|
||||
+
|
||||
async beginVerification(userName, userVerifierProxies) {
|
||||
this._cancellable?.cancel();
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
@@ -483,6 +489,10 @@ export class AuthServices extends GObject.Object {
|
||||
return this.constructor.SupportedRoles;
|
||||
}
|
||||
|
||||
+ _handleSelectChoice() {}
|
||||
+
|
||||
+ _handleAnswerQuery() {}
|
||||
+
|
||||
_handleBeginVerification() {}
|
||||
|
||||
_handleSelectMechanism() {
|
||||
diff --git a/js/gdm/authServicesLegacy.js b/js/gdm/authServicesLegacy.js
|
||||
index 0e5c525de..f257b55fc 100644
|
||||
--- a/js/gdm/authServicesLegacy.js
|
||||
+++ b/js/gdm/authServicesLegacy.js
|
||||
@@ -77,6 +77,14 @@ export class AuthServicesLegacy extends AuthServices {
|
||||
this._fingerprintReadyTimeoutId = 0;
|
||||
}
|
||||
|
||||
+ _handleSelectChoice(serviceName, key) {
|
||||
+ if (serviceName !== this._selectedMechanism?.serviceName)
|
||||
+ return;
|
||||
+
|
||||
+ this._userVerifierChoiceList.call_select_choice(
|
||||
+ serviceName, key, this._cancellable).catch(logErrorUnlessCancelled);
|
||||
+ }
|
||||
+
|
||||
_handleAnswerQuery(serviceName, answer) {
|
||||
if (serviceName !== this._selectedMechanism?.serviceName)
|
||||
return;
|
||||
@@ -246,11 +254,7 @@ export class AuthServicesLegacy extends AuthServices {
|
||||
if (serviceName !== this._selectedMechanism?.serviceName)
|
||||
return;
|
||||
|
||||
- this.emit('ask-question', {
|
||||
- serviceName,
|
||||
- question,
|
||||
- answerHandler: answer => this._handleAnswerQuery(serviceName, answer),
|
||||
- });
|
||||
+ this.emit('ask-question', {serviceName, question});
|
||||
}
|
||||
|
||||
_handleOnSecretInfoQuery(serviceName, secretQuestion) {
|
||||
@@ -262,7 +266,7 @@ export class AuthServicesLegacy extends AuthServices {
|
||||
token = this._credentialManagers[serviceName].token;
|
||||
|
||||
if (token) {
|
||||
- this._handleAnswerQuery(serviceName, token);
|
||||
+ this.answerQuery(serviceName, token);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -270,7 +274,6 @@ export class AuthServicesLegacy extends AuthServices {
|
||||
serviceName,
|
||||
question: secretQuestion,
|
||||
secret: true,
|
||||
- answerHandler: answer => this._handleAnswerQuery(serviceName, answer),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -346,17 +349,7 @@ export class AuthServicesLegacy extends AuthServices {
|
||||
for (const [key, value] of Object.entries(list.deepUnpack()))
|
||||
choiceList[key] = {title: value};
|
||||
|
||||
- this.emit('show-choice-list', {
|
||||
- serviceName,
|
||||
- promptMessage,
|
||||
- choiceList,
|
||||
- choiceHandler: key => {
|
||||
- if (serviceName !== this._selectedMechanism?.serviceName)
|
||||
- return;
|
||||
- this._userVerifierChoiceList.call_select_choice(
|
||||
- serviceName, key, this._cancellable).catch(logErrorUnlessCancelled);
|
||||
- },
|
||||
- });
|
||||
+ this.emit('show-choice-list', {serviceName, promptMessage, choiceList});
|
||||
}
|
||||
|
||||
_handleGetCredentialManagerServices() {
|
||||
diff --git a/js/gdm/authServicesSSSDSwitchable.js b/js/gdm/authServicesSSSDSwitchable.js
|
||||
index 0271d98f2..3a81b99c2 100644
|
||||
--- a/js/gdm/authServicesSSSDSwitchable.js
|
||||
+++ b/js/gdm/authServicesSSSDSwitchable.js
|
||||
@@ -74,6 +74,23 @@ export class AuthServicesSSSDSwitchable extends AuthServices {
|
||||
}
|
||||
}
|
||||
|
||||
+ _handleSelectChoice(serviceName, key) {
|
||||
+ if (serviceName !== this._selectedMechanism?.serviceName)
|
||||
+ return;
|
||||
+
|
||||
+ if (this._selectedMechanism.role === Role.SMARTCARD) {
|
||||
+ const certificates = this._selectedMechanism.certificates;
|
||||
+ const cert = certificates.find(c => c.keyId === key);
|
||||
+ this._selectedSmartcard = cert;
|
||||
+ this._promptStatus = PromptStatus.PIN_PROMPT;
|
||||
+ this.emit('ask-question', {
|
||||
+ serviceName,
|
||||
+ question: cert.pinPrompt,
|
||||
+ secret: true,
|
||||
+ });
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
_handleAnswerQuery(serviceName, answer) {
|
||||
if (serviceName !== this._selectedMechanism?.serviceName)
|
||||
return;
|
||||
@@ -349,7 +366,6 @@ export class AuthServicesSSSDSwitchable extends AuthServices {
|
||||
serviceName,
|
||||
question: secretQuestion,
|
||||
secret: true,
|
||||
- answerHandler: answer => this._handleAnswerQuery(serviceName, answer),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -437,12 +453,7 @@ export class AuthServicesSSSDSwitchable extends AuthServices {
|
||||
const {serviceName, prompt} = this._selectedMechanism;
|
||||
|
||||
this._promptStatus = PromptStatus.PASSWORD_PROMPT;
|
||||
- this.emit('ask-question', {
|
||||
- serviceName,
|
||||
- question: prompt,
|
||||
- secret: true,
|
||||
- answerHandler: answer => this._handleAnswerQuery(serviceName, answer),
|
||||
- });
|
||||
+ this.emit('ask-question', {serviceName, question: prompt, secret: true});
|
||||
}
|
||||
|
||||
_startSmartcardLogin() {
|
||||
@@ -455,7 +466,6 @@ export class AuthServicesSSSDSwitchable extends AuthServices {
|
||||
serviceName,
|
||||
question: certificates[0].pinPrompt,
|
||||
secret: true,
|
||||
- answerHandler: answer => this._handleAnswerQuery(serviceName, answer),
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -469,27 +479,7 @@ export class AuthServicesSSSDSwitchable extends AuthServices {
|
||||
: _('Select Identity');
|
||||
|
||||
this._promptStatus = PromptStatus.CERT_LIST_PROMPT;
|
||||
- this.emit('show-choice-list', {
|
||||
- serviceName,
|
||||
- promptMessage,
|
||||
- choiceList,
|
||||
- choiceHandler: key => {
|
||||
- if (serviceName !== this._selectedMechanism?.serviceName)
|
||||
- return;
|
||||
-
|
||||
- if (this._selectedMechanism.role === Role.SMARTCARD) {
|
||||
- const cert = this._selectedMechanism.certificates.find(c => c.keyId === key);
|
||||
- this._selectedSmartcard = cert;
|
||||
- this._promptStatus = PromptStatus.PIN_PROMPT;
|
||||
- this.emit('ask-question', {
|
||||
- serviceName,
|
||||
- question: cert.pinPrompt,
|
||||
- secret: true,
|
||||
- answerHandler: answer => this._handleAnswerQuery(serviceName, answer),
|
||||
- });
|
||||
- }
|
||||
- },
|
||||
- });
|
||||
+ this.emit('show-choice-list', {serviceName, promptMessage, choiceList});
|
||||
}
|
||||
|
||||
_parseCertInstruction(certInstruction) {
|
||||
@@ -524,12 +514,7 @@ export class AuthServicesSSSDSwitchable extends AuthServices {
|
||||
}
|
||||
|
||||
this._promptStatus = PromptStatus.PIN_PROMPT;
|
||||
- this.emit('ask-question', {
|
||||
- serviceName,
|
||||
- question: pinPrompt,
|
||||
- secret: true,
|
||||
- answerHandler: answer => this._handleAnswerQuery(serviceName, answer),
|
||||
- });
|
||||
+ this.emit('ask-question', {serviceName, question: pinPrompt, secret: true});
|
||||
|
||||
if (pinAttempts <= 3 && pinAttempts > 0) {
|
||||
const message = _('You have %d attempts left. If the passkey gets locked, you may not able to access your account.').format(pinAttempts);
|
||||
diff --git a/js/gdm/userVerifier.js b/js/gdm/userVerifier.js
|
||||
index 6c63a313d..116c4ae1d 100644
|
||||
--- a/js/gdm/userVerifier.js
|
||||
+++ b/js/gdm/userVerifier.js
|
||||
@@ -180,6 +180,18 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
this._settings = null;
|
||||
}
|
||||
|
||||
+ selectChoice(serviceName, key) {
|
||||
+ this._authServices.forEach(s => s.selectChoice(serviceName, key));
|
||||
+ }
|
||||
+
|
||||
+ async answerQuery(serviceName, answer) {
|
||||
+ // Wait for pending messages to be displayed before answering to
|
||||
+ // ensure no messages get lost
|
||||
+ await this._handlePendingMessages().catch(logErrorUnlessCancelled);
|
||||
+
|
||||
+ this._authServices.forEach(s => s.answerQuery(serviceName, answer));
|
||||
+ }
|
||||
+
|
||||
addCredentialManager(serviceName, credentialManager) {
|
||||
this._authServices.forEach(s => s.addCredentialManager(serviceName, credentialManager));
|
||||
}
|
||||
@@ -464,14 +476,14 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
|
||||
async _waitPendingMessages({task}) {
|
||||
try {
|
||||
- await this.handlePendingMessages();
|
||||
+ await this._handlePendingMessages();
|
||||
task.return_boolean(true);
|
||||
} catch (e) {
|
||||
task.return_error(e);
|
||||
}
|
||||
}
|
||||
|
||||
- handlePendingMessages() {
|
||||
+ _handlePendingMessages() {
|
||||
if (!this.hasPendingMessages)
|
||||
return Promise.resolve();
|
||||
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
||||
From 3aae4d78f1432281589ff688d799c582bf80156b Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Wed, 12 Aug 2026 12:40:53 +0200
|
||||
Subject: [PATCH 09/12] gdm: Restore positional signal signatures on
|
||||
ShellUserVerifier
|
||||
|
||||
Signals on ShellUserVerifier ('ask-question', 'show-message',
|
||||
'show-choice-list', 'verification-failed', 'reset') were changed to
|
||||
pass a single object argument instead of the original positional
|
||||
arguments, breaking extensions that connect to them with the old
|
||||
handler signatures (e.g. (verifier, serviceName, question, secret)).
|
||||
|
||||
Restore the original positional argument order. Where the object
|
||||
carried genuinely new information (like the show-message wiggle
|
||||
resolver), append it as a trailing positional argument, which old
|
||||
handlers simply ignore.
|
||||
---
|
||||
js/gdm/authPrompt.js | 12 ++++++++----
|
||||
js/gdm/userVerifier.js | 20 +++++++++++---------
|
||||
2 files changed, 19 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index bbf6c4e4e..97129ca00 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -98,13 +98,17 @@ export const AuthPrompt = GObject.registerClass({
|
||||
this._userVerifier = this._createUserVerifier(this._gdmClient, {reauthenticationOnly});
|
||||
|
||||
this._userVerifier.connectObject(
|
||||
- 'ask-question', (_, args) => this._onAskQuestion(args),
|
||||
- 'show-message', (_, args) => this._onShowMessage(args),
|
||||
- 'show-choice-list', (_, args) => this._onShowChoiceList(args),
|
||||
+ 'ask-question', (_, serviceName, question, secret) =>
|
||||
+ this._onAskQuestion({serviceName, question, secret}),
|
||||
+ 'show-message', (_, serviceName, message, type, shouldWiggle) =>
|
||||
+ this._onShowMessage({message, type, shouldWiggle}),
|
||||
+ 'show-choice-list', (_, serviceName, promptMessage, choiceList) =>
|
||||
+ this._onShowChoiceList({serviceName, promptMessage, choiceList}),
|
||||
'show-button', (_, args) => this._onShowButton(args),
|
||||
'mechanisms-changed', (_, args) => this.emit('mechanisms-changed', args),
|
||||
'web-login', (_, args) => this._onWebLogin(args),
|
||||
- 'verification-failed', (_, args) => this._onVerificationFailed(args),
|
||||
+ 'verification-failed', (_, serviceName, canRetry) =>
|
||||
+ this._onVerificationFailed({serviceName, canRetry}),
|
||||
'verification-complete', () => this._onVerificationComplete(),
|
||||
'reset', (_, args) => this._onReset(args),
|
||||
this);
|
||||
diff --git a/js/gdm/userVerifier.js b/js/gdm/userVerifier.js
|
||||
index 116c4ae1d..e5d3a1835 100644
|
||||
--- a/js/gdm/userVerifier.js
|
||||
+++ b/js/gdm/userVerifier.js
|
||||
@@ -242,11 +242,11 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
const message = this.currentMessage;
|
||||
|
||||
delete this._currentMessageExtraInterval;
|
||||
- this.emit('show-message', {
|
||||
- message: message.text,
|
||||
- type: message.type,
|
||||
- shouldWiggle: message.wiggle,
|
||||
- });
|
||||
+ this.emit('show-message',
|
||||
+ message.serviceName,
|
||||
+ message.text,
|
||||
+ message.type,
|
||||
+ message.wiggle);
|
||||
|
||||
this._messageQueueTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
||||
message.interval + (this._currentMessageExtraInterval | 0), () => {
|
||||
@@ -299,7 +299,7 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
this._messageQueueTimeoutId = 0;
|
||||
}
|
||||
|
||||
- this.emit('show-message', {type: MessageType.NONE});
|
||||
+ this.emit('show-message', null, null, MessageType.NONE);
|
||||
}
|
||||
|
||||
_reportInitError(initError) {
|
||||
@@ -404,7 +404,8 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
_connectAuthServices() {
|
||||
this._authServices.forEach(authServices => {
|
||||
authServices.connectObject(
|
||||
- 'ask-question', (_, args) => this.emit('ask-question', args),
|
||||
+ 'ask-question', (_, args) =>
|
||||
+ this.emit('ask-question', args.serviceName, args.question, args.secret ?? false),
|
||||
'queue-message', (_, args) => this._queueMessage(args),
|
||||
'queue-priority-message', (_, args) => this._queuePriorityMessage(args),
|
||||
'wait-pending-messages', (_, args) => this._waitPendingMessages(args),
|
||||
@@ -412,7 +413,8 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
'verification-failed', (_, args) => this._verificationFailed(args),
|
||||
'verification-complete', () => this.emit('verification-complete'),
|
||||
'reset', (_, args) => this.emit('reset', args),
|
||||
- 'show-choice-list', (_, args) => this.emit('show-choice-list', args),
|
||||
+ 'show-choice-list', (_, args) =>
|
||||
+ this.emit('show-choice-list', args.serviceName, args.promptMessage, args.choiceList),
|
||||
'show-button', (_, args) => this.emit('show-button', args),
|
||||
'mechanisms-changed', () => this._onMechanismsChanged(),
|
||||
'web-login', (_, args) => this.emit('web-login', args),
|
||||
@@ -422,7 +424,7 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
|
||||
_verificationFailed({serviceName, canRetry}) {
|
||||
this._filterServiceMessages({serviceName, messageType: MessageType.ERROR});
|
||||
- this.emit('verification-failed', {serviceName, canRetry});
|
||||
+ this.emit('verification-failed', serviceName, canRetry);
|
||||
}
|
||||
|
||||
get selectedMechanism() {
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
||||
From 9c61a84b465df3bd0c83bbc6e3be5db811b5d04e Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Wed, 12 Aug 2026 12:42:29 +0200
|
||||
Subject: [PATCH 10/12] gdm: Add backward-compatible property and method shims
|
||||
|
||||
Several ShellUserVerifier properties and methods were dropped when
|
||||
the class gained support for multiple concurrently-active AuthServices
|
||||
(reauthenticating, smartcardDetected, serviceIsForeground(),
|
||||
foregroundServiceDeterminesUsername(), serviceIsDefault(),
|
||||
serviceIsFingerprint(), finishMessageQueue()), and AuthPrompt's
|
||||
addCharacter() was renamed to startPreemptiveInput().
|
||||
|
||||
Restore reauthenticating as a real, tracked property, and add the
|
||||
rest back as deprecated shims (documented with why they can no longer
|
||||
be meaningfully implemented) so extensions calling them don't crash
|
||||
with a TypeError.
|
||||
---
|
||||
js/gdm/authPrompt.js | 8 ++++++
|
||||
js/gdm/userVerifier.js | 61 ++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 69 insertions(+)
|
||||
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index 97129ca00..d062cdc4b 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -923,6 +923,14 @@ export const AuthPrompt = GObject.registerClass({
|
||||
this._entry.clutter_text.insert_unichar(unichar);
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * @deprecated Renamed to startPreemptiveInput(), kept for backward
|
||||
+ * compatibility.
|
||||
+ */
|
||||
+ addCharacter(unichar) {
|
||||
+ this.startPreemptiveInput(unichar);
|
||||
+ }
|
||||
+
|
||||
_clearPreemptiveState() {
|
||||
this._preemptiveInput = false;
|
||||
this._preemptiveAnswer = null;
|
||||
diff --git a/js/gdm/userVerifier.js b/js/gdm/userVerifier.js
|
||||
index e5d3a1835..2e863cb8b 100644
|
||||
--- a/js/gdm/userVerifier.js
|
||||
+++ b/js/gdm/userVerifier.js
|
||||
@@ -65,6 +65,9 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
this._messageQueue = [];
|
||||
this._messageQueueTimeoutId = 0;
|
||||
|
||||
+ // Kept for backward compatibility, see begin()/_getUserVerifierProxies().
|
||||
+ this.reauthenticating = false;
|
||||
+
|
||||
this._settings = new Gio.Settings({schema_id: LOGIN_SCREEN_SCHEMA});
|
||||
this._settings.connect('changed', () => this._onSettingsChanged());
|
||||
this._updateAuthServices();
|
||||
@@ -82,9 +85,21 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
return this._messageQueue ? this._messageQueue[0] : null;
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * @deprecated Kept for backward compatibility, always returns false.
|
||||
+ * Smartcard detection is now internal to AuthServicesLegacy and no
|
||||
+ * longer surfaced as a top-level property; the 'smartcard-status-changed'
|
||||
+ * signal has also been removed. Use the 'mechanisms-changed' signal and
|
||||
+ * check a mechanism's role instead.
|
||||
+ */
|
||||
+ get smartcardDetected() {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
async begin(userName, hold) {
|
||||
this._cancellable?.cancel();
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
+ this.reauthenticating = false;
|
||||
|
||||
try {
|
||||
const proxies = await this._getUserVerifierProxies(userName, this._cancellable);
|
||||
@@ -114,6 +129,51 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
return this._authServices.some(s => s.needsUsername());
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * @deprecated Kept for backward compatibility. Replaced by needsUsername(),
|
||||
+ * of which this is the logical inverse: the "foreground service" concept
|
||||
+ * no longer exists now that multiple AuthServices can be active at once,
|
||||
+ * each exposing its own selectable mechanisms.
|
||||
+ */
|
||||
+ foregroundServiceDeterminesUsername() {
|
||||
+ return !this.needsUsername();
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * @deprecated Kept for backward compatibility, always returns false.
|
||||
+ * There is no single "foreground service" anymore: each AuthServices
|
||||
+ * instance tracks its own selected mechanism (see selectedMechanism).
|
||||
+ */
|
||||
+ serviceIsForeground(_serviceName) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * @deprecated Kept for backward compatibility, always returns false.
|
||||
+ * Service roles are now assigned dynamically across AuthServices
|
||||
+ * instances (see _redistributeRoles()) rather than through a single
|
||||
+ * fixed default service.
|
||||
+ */
|
||||
+ serviceIsDefault(_serviceName) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * @deprecated Kept for backward compatibility, always returns false.
|
||||
+ * Fingerprint handling is now internal to AuthServicesLegacy; use the
|
||||
+ * 'mechanisms-changed' signal and check a mechanism's role instead.
|
||||
+ */
|
||||
+ serviceIsFingerprint(_serviceName) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * @deprecated Renamed to the private _finishMessageQueue().
|
||||
+ */
|
||||
+ finishMessageQueue() {
|
||||
+ this._finishMessageQueue();
|
||||
+ }
|
||||
+
|
||||
setDriverService(serviceName) {
|
||||
if (this._driverService === serviceName)
|
||||
return;
|
||||
@@ -322,6 +382,7 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
try {
|
||||
proxies.userVerifier = await this._client.open_reauthentication_channel(
|
||||
userName, cancellable);
|
||||
+ this.reauthenticating = true;
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
throw e;
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
||||
From 173fd8c7d0ace6b253df40d7db1260d0b202b17e Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Wed, 12 Aug 2026 13:08:48 +0200
|
||||
Subject: [PATCH 11/12] authPrompt: updateSensitivity() signature
|
||||
|
||||
updateSensitivity() started requiring a {sensitive} options object
|
||||
instead of accepting a plain boolean. Restore its call signature.
|
||||
|
||||
This also fixes _onUserStoppedTypePreemptiveAnswer(), which was
|
||||
already calling updateSensitivity(false) with a bare boolean and
|
||||
silently getting undefined out of the {sensitive} destructuring.
|
||||
---
|
||||
js/gdm/authPrompt.js | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index d062cdc4b..8d4de6bde 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -783,7 +783,11 @@ export const AuthPrompt = GObject.registerClass({
|
||||
wiggle(this._message, wiggleParameters);
|
||||
}
|
||||
|
||||
- updateSensitivity({sensitive}) {
|
||||
+ updateSensitivity(params) {
|
||||
+ // Kept for backward compatibility: this used to take a plain
|
||||
+ // boolean instead of a {sensitive} options object.
|
||||
+ const {sensitive} = typeof params === 'boolean' ? {sensitive: params} : params;
|
||||
+
|
||||
if (sensitive && this._preemptiveAnswer)
|
||||
return;
|
||||
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
||||
From f3ee5bfd61b258f90fcfda784bac7e99194a89a5 Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Wed, 12 Aug 2026 17:08:36 +0200
|
||||
Subject: [PATCH 12/12] gdm/userVerifier: needsUsername should use every
|
||||
|
||||
When every authServices needUsername then return true, otherwise return
|
||||
false.
|
||||
---
|
||||
js/gdm/userVerifier.js | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/gdm/userVerifier.js b/js/gdm/userVerifier.js
|
||||
index 2e863cb8b..e0a85c693 100644
|
||||
--- a/js/gdm/userVerifier.js
|
||||
+++ b/js/gdm/userVerifier.js
|
||||
@@ -126,7 +126,7 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
}
|
||||
|
||||
needsUsername() {
|
||||
- return this._authServices.some(s => s.needsUsername());
|
||||
+ return this._authServices.every(s => s.needsUsername());
|
||||
}
|
||||
|
||||
/**
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
||||
@ -1,217 +0,0 @@
|
||||
|
||||
From 1c91eaa7fb93536a1e3e2695d856721d403171f6 Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Tue, 5 May 2026 17:26:27 +0200
|
||||
Subject: [PATCH 1/3] animationUtils: Skip no-op wiggle to avoid cancelling
|
||||
pending transitions
|
||||
|
||||
When wiggle() is called with duration 0, the async easeAsync calls
|
||||
yield between microtasks, leaving pending operations that remove
|
||||
transitions on the same property. This becomes a problem when two
|
||||
setMessage() calls happen in the same call stack (e.g. via
|
||||
_queuePriorityMessage): the first fires a no-op wiggle(dur:0) and
|
||||
the second starts the real wiggle(dur:65). When microtasks drain,
|
||||
the first wiggle's pending easeAsync calls overwrite the second
|
||||
wiggle's active transition, effectively cancelling the real animation.
|
||||
|
||||
Return early when duration is 0, since the animation is a no-op anyway.
|
||||
|
||||
Fixes: fdadbb7a5a2 ("animationUtils: Use easeAsync() for wiggle")
|
||||
Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/work_items/9207
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/4209>
|
||||
---
|
||||
js/misc/animationUtils.js | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/js/misc/animationUtils.js b/js/misc/animationUtils.js
|
||||
index cf6889609..9d065cf78 100644
|
||||
--- a/js/misc/animationUtils.js
|
||||
+++ b/js/misc/animationUtils.js
|
||||
@@ -84,7 +84,7 @@ export function ensureActorVisibleInScrollView(scrollView, actor) {
|
||||
* @param {number} params.wiggleCount - the number of times to wiggle the actor
|
||||
*/
|
||||
export function wiggle(actor, params) {
|
||||
- if (!St.Settings.get().enable_animations)
|
||||
+ if (!St.Settings.get().enable_animations || params?.duration === 0)
|
||||
return;
|
||||
|
||||
params = Params.parse(params, {
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
||||
From b5a37cbdd89eeed44966455ba22b0f10a3f25091 Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Tue, 5 May 2026 21:32:06 +0200
|
||||
Subject: [PATCH 2/3] authPrompt: Call wiggle directly in _onShowMessage
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/4209>
|
||||
---
|
||||
js/gdm/authPrompt.js | 13 +++++--------
|
||||
1 file changed, 5 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index 3b4a2f798..f05856416 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -394,21 +394,20 @@ export const AuthPrompt = GObject.registerClass({
|
||||
}
|
||||
|
||||
_onShowMessage(_userVerifier, serviceName, message, type) {
|
||||
- let wiggleParameters = {duration: 0};
|
||||
+ this.setMessage(message, type);
|
||||
+ this.emit('prompted');
|
||||
|
||||
if (type === GdmUtil.MessageType.ERROR &&
|
||||
this._userVerifier.serviceIsFingerprint(serviceName)) {
|
||||
// TODO: Use Await for wiggle to be over before unfreezing the user verifier queue
|
||||
- wiggleParameters = {
|
||||
+ const wiggleParameters = {
|
||||
duration: 65,
|
||||
wiggleCount: 3,
|
||||
};
|
||||
this._userVerifier.increaseCurrentMessageTimeout(
|
||||
wiggleParameters.duration * (wiggleParameters.wiggleCount + 2));
|
||||
+ wiggle(this._message, wiggleParameters);
|
||||
}
|
||||
-
|
||||
- this.setMessage(message, type, wiggleParameters);
|
||||
- this.emit('prompted');
|
||||
}
|
||||
|
||||
_onVerificationFailed(userVerifier, serviceName, canRetry) {
|
||||
@@ -587,7 +586,7 @@ export const AuthPrompt = GObject.registerClass({
|
||||
});
|
||||
}
|
||||
|
||||
- setMessage(message, type, wiggleParameters = {duration: 0}) {
|
||||
+ setMessage(message, type) {
|
||||
if (type === GdmUtil.MessageType.ERROR)
|
||||
this._message.add_style_class_name('login-dialog-message-warning');
|
||||
else
|
||||
@@ -607,8 +606,6 @@ export const AuthPrompt = GObject.registerClass({
|
||||
} else {
|
||||
this._message.opacity = 0;
|
||||
}
|
||||
-
|
||||
- wiggle(this._message, wiggleParameters);
|
||||
}
|
||||
|
||||
updateSensitivity(sensitive) {
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
||||
From 1e3f937a6ccfc8ea79c80d78df121102cffbdeff Mon Sep 17 00:00:00 2001
|
||||
From: Joan Torres Lopez <joantolo@redhat.com>
|
||||
Date: Tue, 5 May 2026 17:28:18 +0200
|
||||
Subject: [PATCH 3/3] authPrompt: Await wiggle via show-message promise
|
||||
resolver
|
||||
|
||||
Pass promise resolver through the show-message signal so the
|
||||
message queue waits for the wiggle animation to finish before scheduling
|
||||
the next message timeout. This replaces the previous approach of manually
|
||||
increasing the timeout duration to account for the wiggle.
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/4209>
|
||||
---
|
||||
js/gdm/authPrompt.js | 21 +++++++++------------
|
||||
js/gdm/util.js | 27 +++++++++++++++++----------
|
||||
2 files changed, 26 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
||||
index f05856416..b1e8202bd 100644
|
||||
--- a/js/gdm/authPrompt.js
|
||||
+++ b/js/gdm/authPrompt.js
|
||||
@@ -393,21 +393,18 @@ export const AuthPrompt = GObject.registerClass({
|
||||
this.reset();
|
||||
}
|
||||
|
||||
- _onShowMessage(_userVerifier, serviceName, message, type) {
|
||||
+ _onShowMessage(_userVerifier, serviceName, message, type, showMessageResolver) {
|
||||
this.setMessage(message, type);
|
||||
this.emit('prompted');
|
||||
|
||||
- if (type === GdmUtil.MessageType.ERROR &&
|
||||
- this._userVerifier.serviceIsFingerprint(serviceName)) {
|
||||
- // TODO: Use Await for wiggle to be over before unfreezing the user verifier queue
|
||||
- const wiggleParameters = {
|
||||
- duration: 65,
|
||||
- wiggleCount: 3,
|
||||
- };
|
||||
- this._userVerifier.increaseCurrentMessageTimeout(
|
||||
- wiggleParameters.duration * (wiggleParameters.wiggleCount + 2));
|
||||
- wiggle(this._message, wiggleParameters);
|
||||
- }
|
||||
+ const shouldWiggle = type === GdmUtil.MessageType.ERROR &&
|
||||
+ this._userVerifier.serviceIsFingerprint(serviceName);
|
||||
+
|
||||
+ const wigglePromise = shouldWiggle
|
||||
+ ? wiggle(this._message, {duration: 65, wiggleCount: 3})
|
||||
+ : Promise.resolve();
|
||||
+
|
||||
+ showMessageResolver?.(wigglePromise);
|
||||
}
|
||||
|
||||
_onVerificationFailed(userVerifier, serviceName, canRetry) {
|
||||
diff --git a/js/gdm/util.js b/js/gdm/util.js
|
||||
index 4b0f763f0..e529f84fa 100644
|
||||
--- a/js/gdm/util.js
|
||||
+++ b/js/gdm/util.js
|
||||
@@ -262,11 +262,6 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
this.emit('no-more-messages');
|
||||
}
|
||||
|
||||
- increaseCurrentMessageTimeout(interval) {
|
||||
- if (!this._messageQueueTimeoutId && interval > 0)
|
||||
- this._currentMessageExtraInterval = interval;
|
||||
- }
|
||||
-
|
||||
_serviceHasPendingMessages(serviceName) {
|
||||
return this._messageQueue.some(m => m.serviceName === serviceName);
|
||||
}
|
||||
@@ -279,17 +274,23 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
this._queuePriorityMessage(serviceName, null, messageType);
|
||||
}
|
||||
|
||||
- _queueMessageTimeout() {
|
||||
- if (this._messageQueueTimeoutId !== 0)
|
||||
+ async _queueMessageTimeout() {
|
||||
+ if (this._messageQueueTimeoutId !== 0 || this._showMessageResolver)
|
||||
return;
|
||||
|
||||
const message = this.currentMessage;
|
||||
+ const {promise, resolve} = Promise.withResolvers();
|
||||
+ this._showMessageResolver = resolve;
|
||||
|
||||
- delete this._currentMessageExtraInterval;
|
||||
- this.emit('show-message', message.serviceName, message.text, message.type);
|
||||
+ this.emit('show-message', message.serviceName, message.text, message.type, this._showMessageResolver);
|
||||
+
|
||||
+ await promise.catch(logError);
|
||||
+ if (!this._showMessageResolver)
|
||||
+ return;
|
||||
+ this._showMessageResolver = null;
|
||||
|
||||
this._messageQueueTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
||||
- message.interval + (this._currentMessageExtraInterval | 0), () => {
|
||||
+ message.interval, () => {
|
||||
this._messageQueueTimeoutId = 0;
|
||||
|
||||
if (this._messageQueue.length > 1) {
|
||||
@@ -332,6 +333,12 @@ export class ShellUserVerifier extends Signals.EventEmitter {
|
||||
GLib.source_remove(this._messageQueueTimeoutId);
|
||||
this._messageQueueTimeoutId = 0;
|
||||
}
|
||||
+
|
||||
+ if (this._showMessageResolver) {
|
||||
+ this._showMessageResolver();
|
||||
+ this._showMessageResolver = null;
|
||||
+ }
|
||||
+
|
||||
this.emit('show-message', null, null, MessageType.NONE);
|
||||
}
|
||||
|
||||
--
|
||||
2.55.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user