From 3a10d80b784307d2aa77e4915949f07c37f844ee Mon Sep 17 00:00:00 2001 From: Joan Torres Lopez Date: Thu, 30 Apr 2026 11:09:16 +0200 Subject: [PATCH] Add post-changes for passwordless GDM backport These are downstream changes to reshape the backport to fit the old gnome-shell version. Resolves: https://redhat.atlassian.net/browse/RHEL-169914 --- gnome-shell.spec | 3 + ...hanges-for-passwordless-gdm-backport.patch | 2866 +++++++++++++++++ 2 files changed, 2869 insertions(+) create mode 100644 post-changes-for-passwordless-gdm-backport.patch diff --git a/gnome-shell.spec b/gnome-shell.spec index 7e3d29f..057d4c9 100644 --- a/gnome-shell.spec +++ b/gnome-shell.spec @@ -42,6 +42,7 @@ Patch23: 0001-main-Register-session-with-GDM-on-startup.patch # Passwordless GDM patch series Patch24: pre-changes-for-passwordless-gdm-backport.patch Patch25: 0001-Support-for-web-login-and-unified-auth-mechanism.patch +Patch26: post-changes-for-passwordless-gdm-backport.patch # Misc. Patch30: 0001-panel-add-an-icon-to-the-ActivitiesButton.patch @@ -282,6 +283,8 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/evolution-calendar.de %{_datadir}/dbus-1/interfaces/org.gnome.ShellSearchProvider2.xml %{_datadir}/icons/hicolor/scalable/apps/org.gnome.Shell.Extensions.svg %{_datadir}/icons/hicolor/symbolic/apps/org.gnome.Shell.Extensions-symbolic.svg +%{_datadir}/icons/scalable/status/fingerprint-auth-symbolic.svg +%{_datadir}/icons/scalable/status/vcard-symbolic.svg %{_userunitdir}/org.gnome.Shell-disable-extensions.service %{_userunitdir}/org.gnome.Shell.target %{_userunitdir}/org.gnome.Shell@wayland.service diff --git a/post-changes-for-passwordless-gdm-backport.patch b/post-changes-for-passwordless-gdm-backport.patch new file mode 100644 index 0000000..d1b7103 --- /dev/null +++ b/post-changes-for-passwordless-gdm-backport.patch @@ -0,0 +1,2866 @@ +From 183d2cce2a34a0d6fca990c2264bae60cdfc5de4 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Wed, 25 Mar 2026 18:58:29 +0100 +Subject: [PATCH 01/30] gdm: Update styles from login-lock to login-dialog + +login-lock is used in newer versions, but in this version login-dialog +is used. +--- + data/theme/gnome-shell-sass/_widgets.scss | 1 + + .../widgets/_login-dialog.scss | 307 +++++++++++++++++- + .../gnome-shell-sass/widgets/_qr-code.scss | 4 +- + 3 files changed, 296 insertions(+), 16 deletions(-) + +diff --git a/data/theme/gnome-shell-sass/_widgets.scss b/data/theme/gnome-shell-sass/_widgets.scss +index a8d0aa9f4d..1651d9ca3b 100644 +--- a/data/theme/gnome-shell-sass/_widgets.scss ++++ b/data/theme/gnome-shell-sass/_widgets.scss +@@ -46,6 +46,7 @@ + @import 'widgets/tiled-previews'; + @import 'widgets/keyboard'; + @import 'widgets/looking-glass'; ++@import 'widgets/qr-code'; + // Lock / login screens + @import 'widgets/login-dialog'; + @import 'widgets/screen-shield'; +diff --git a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss +index 307a751628..f3aeed4bf3 100644 +--- a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss ++++ b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss +@@ -1,5 +1,7 @@ + /* Login Dialog */ + ++$_gdm_fg: $osd_fg_color; ++ + .login-dialog-banner-view { + padding-top: 24px; + max-width: 23em; +@@ -70,8 +72,10 @@ + } + } + ++ .next-button, + .cancel-button, + .switch-user-button, ++ .login-dialog-auth-menu-button, + .login-dialog-session-list-button { + padding: 0; + border-radius: 99px; +@@ -83,10 +87,40 @@ + StIcon { icon-size: $base_icon_size; } + } + ++ .next-button { ++ background-color: transparent !important; ++ } ++ ++ .switch-user-button { ++ min-width: 8.5em; ++ min-height: 2.5em; ++ @include fontsize($base_font_size - 1); ++ font-weight: bold; ++ } ++ + .caps-lock-warning-label, + .login-dialog-message-warning { + color: $osd_fg_color; + } ++ ++ .login-dialog-prompt-layout { ++ &.web-login-active { ++ width: 23em * 1.5; ++ } ++ } ++ ++ .login-dialog-prompt-entry-area { ++ margin: 0.5em $base_margin * 5; ++ } ++ ++ .login-dialog-prompt-entry { ++ border-radius: $base_border_radius * 1.5; ++ padding-right: 2.5em; // Make room for button-well inside entry ++ } ++ ++ .login-dialog-default-button-well { ++ margin-right: 0.4em; ++ } + } + + .login-dialog-bottom-button-group { +@@ -118,30 +152,185 @@ + padding-top: 1em; + } + +-.login-dialog-auth-list-view { -st-vfade-offset: 1em; } ++.login-dialog-auth-menu-button-popup { ++ padding: $base_padding * 3; ++ margin-right: $base_padding * 2; ++ ++ .login-dialog-auth-menu-item-section { ++ padding-top: $base_padding; ++ ++ &:first-child { ++ padding-top: 0; ++ } ++ ++ &-label { ++ @include fontsize($base_font_size - 1); ++ font-weight: bold; ++ color: $_gdm_fg; ++ } ++ } ++ ++ .login-dialog-auth-menu-item-icon { ++ color: $_gdm_fg; ++ icon-size: $base_icon_size; ++ margin-right: $base_margin * 2; ++ } ++ ++ .login-dialog-auth-menu-item-box { ++ spacing: $base_padding * .5; ++ ++ &-name { ++ color: $_gdm_fg; ++ @include fontsize($base_font_size); ++ font-weight: bold; ++ } ++ ++ &-description { ++ color: $_gdm_fg; ++ @include fontsize($base_font_size - 1); ++ } ++ } ++} ++ ++.login-dialog-auth-menu-button-indicator { ++ background-color: transparent !important; ++ border-width: 0; ++ margin-bottom: 32px; ++ margin-left: 32px; ++ ++ .login-dialog-auth-menu-button-indicator-icons { ++ spacing: $base_padding * 3; ++ ++ .login-dialog-auth-menu-button-indicator-icon { ++ icon-size: 2em; ++ } ++ } ++ ++ .login-dialog-auth-menu-button-indicator-description { ++ @include fontsize($base_font_size); ++ margin-left: $base_padding * 2; ++ min-width: 20em; ++ } ++} ++ ++.login-dialog-button-box { ++ height: 4em; ++} ++ ++.login-dialog-auth-list-view { ++ -st-vfade-offset: 1em; ++ max-height: 13em; ++} ++ + .login-dialog-auth-list { +- spacing: 6px; +- margin-left: 2em; ++ spacing: $base_padding * 1.5; ++ width: 23em; ++ margin-left: $base_margin * 5; + } + +-.login-dialog-auth-list-title { +- margin-left: 2em; ++.login-dialog { ++ .login-dialog-auth-list-title, ++ .login-dialog-auth-list-item { ++ border-radius: $base_border_radius * 1.5; ++ color: darken($_gdm_fg, 30%); ++ &:focus, &:selected { background-color: $selected_bg_color; color: $selected_fg_color; } ++ } ++ ++ .login-dialog-auth-list-title { ++ background-color: transparentize($_gdm_fg, .97) !important; ++ color: $_gdm_fg !important; ++ padding: $base_padding; ++ margin: 0.5em $base_margin * 5; ++ } ++ ++ .login-dialog-auth-list-item { ++ min-height: 3em; ++ padding: $base_padding * 1.5; ++ margin-bottom: $base_margin; ++ background-color: transparentize($_gdm_fg, .94); ++ } + } + +-.login-dialog-auth-list-item { +- border-radius: $base_border_radius + 4px; +- padding: 6px; +- color: darken($osd_fg_color,30%); +- &:focus, &:selected { background-color: $selected_bg_color; color: $selected_fg_color; } ++.unlock-dialog { ++ .login-dialog-auth-list-item { ++ border: none; ++ color: $osd_fg_color; ++ background-color: transparentize($osd_fg_color, 0.94); ++ &:hover, &:focus, &:selected { background-color: transparentize($osd_fg_color, 0.84); } ++ &:active { background-color: transparentize($osd_fg_color, 0.78); } ++ border-radius: $base_border_radius * 1.5; ++ min-height: 3em; ++ padding: $base_padding * 1.5; ++ margin-bottom: $base_margin; ++ } ++ ++ .login-dialog-auth-list-title { ++ background-color: transparent !important; ++ border: none; ++ color: $osd_fg_color !important; ++ padding: $base_padding; ++ } + } + +-.login-dialog-auth-list-label { ++.login-dialog-auth-list-title-label { + @include fontsize($base_font_size + 2); + font-weight: bold; +- padding-left: 15px; ++ padding: $base_padding; ++ text-align: center; ++} + +- &:ltr { padding-left: 14px; text-align: left; } +- &:rtl { padding-right: 14px; text-align: right; } ++.login-dialog-auth-list-item-title, ++.login-dialog-auth-list-item-subtitle { ++ @include fontsize($base_font_size); ++ text-align: center; ++ padding: $base_padding * 0.3 0; ++} ++ ++.login-dialog-auth-list-item-title { ++ color: $_gdm_fg; ++ font-weight: bold; ++} ++ ++.login-dialog-auth-list-item-subtitle { ++ color: darken($_gdm_fg, 20%); ++ font-weight: 500; ++} ++ ++.login-dialog-item-icon { ++ width: 1.3em; ++ height: 1.3em; ++ color: $_gdm_fg; ++ padding: $base_padding * 0.7 $base_padding; ++ border-radius: $base_border_radius; ++ ++ &:hover { ++ background-color: $system_bg_color; ++ } ++ ++ &-popup { ++ &.popup-menu { ++ min-width: 0; ++ } ++ ++ &-box { ++ padding: $base_padding 0; ++ } ++ ++ &-box &-labels { ++ spacing: $base_padding * 0.5; ++ font-weight: bold; ++ text-align: center; ++ ++ & > :first-child { ++ color: darken($fg_color, 30%); ++ font-weight: 500; ++ } ++ ++ & > :last-child { ++ color: $fg_color; ++ } ++ } ++ } + } + + .login-dialog-user-list-view { -st-vfade-offset: 1em; } +@@ -207,3 +396,93 @@ + @include fontsize($base_font_size + 1); + padding-top: 1em; + } ++ ++.web-login-spinner { ++ background-color: rgba(0, 0, 0, 0.5); ++ border: 5px rgba(0, 0, 0, 0.0); ++ border-radius: 50px; ++} ++ ++.web-login-title-label { ++ @include fontsize($base_font_size); ++ color: darken($_gdm_fg,30%); ++ text-align: center; ++} ++ ++.web-login-url-label { ++ @include fontsize($base_font_size); ++ font-family: monospace; ++ color: $_gdm_fg; ++ text-align: center; ++ ++ &.web-login-url-label-long { ++ @include fontsize($base_font_size - 2); ++ } ++} ++ ++.web-login-code-title-label { ++ @include fontsize($base_font_size); ++ color: $_gdm_fg; ++ text-align: center; ++} ++ ++.web-login-code-label { ++ @include fontsize($base_font_size); ++ color: $_gdm_fg; ++ font-weight: bold; ++ text-align: center; ++} ++ ++.web-login-prompt { ++ padding-top: $base_padding; ++ padding-bottom: $base_padding; ++ padding-left: $base_padding * 4.5; ++ padding-right: $base_padding * 4.5; ++ spacing: 1.75em; ++} ++ ++.web-login-button-label { ++ @include fontsize($base_font_size + 2); ++ color: $_gdm_fg; ++ min-width: 12em; ++ text-align: center; ++ font-weight: bold; ++ padding-bottom: 0.1em; ++} ++ ++.login-dialog, ++.unlock-dialog { ++ .web-login-intro-button, ++ .web-login-prompt-button { ++ border-radius: $base_border_radius * 4 !important; ++ padding: $base_padding * 1.5 $base_padding * 3; ++ background-color: transparentize($_gdm_fg, .94); ++ } ++ ++ .web-login-intro-button { ++ width: 10em; ++ } ++ ++ .web-login-prompt-button { ++ width: 7em; ++ margin: $base_margin * 6 $base_margin * 2; ++ } ++} ++ ++.login-dialog { ++ .web-login-intro-button, ++ .web-login-prompt-button { ++ &:hover, &:focus { ++ background-color: $selected_bg_color; ++ } ++ } ++} ++ ++.unlock-dialog { ++ .web-login-intro-button, ++ .web-login-prompt-button { ++ &:hover, &:focus { ++ background-color: transparentize($osd_fg_color, .84); ++ } ++ } ++} +diff --git a/data/theme/gnome-shell-sass/widgets/_qr-code.scss b/data/theme/gnome-shell-sass/widgets/_qr-code.scss +index da04425bd6..0d733453f2 100644 +--- a/data/theme/gnome-shell-sass/widgets/_qr-code.scss ++++ b/data/theme/gnome-shell-sass/widgets/_qr-code.scss +@@ -7,8 +7,8 @@ + background-color: $qrcode_bg_color; + border-color: $qrcode_bg_color; + } @else { +- background-color: $system_fg_color; +- border-color: $system_fg_color; ++ background-color: $osd_fg_color; ++ border-color: $osd_fg_color; + color: $system_bg_color; + } + } +-- +2.51.0 + + +From a6a9baab3e92e3adb9172227051e83c4d145e1df Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 26 Dec 2025 14:52:58 +0100 +Subject: [PATCH 02/30] gdm: Fix importing using the old gjs style + +--- + js/gdm/authMenuButton.js | 13 +++++-------- + js/gdm/authServices.js | 18 +++++++----------- + js/gdm/authServicesLegacy.js | 18 ++++++++---------- + js/gdm/authServicesSSSDSwitchable.js | 10 ++++------ + js/gdm/webLogin.js | 14 +++++++------- + js/misc/fingerprintManager.js | 10 ++++------ + js/misc/passkeyDeviceManager.js | 3 +-- + js/ui/qrCode.js | 10 +++------- + 8 files changed, 39 insertions(+), 57 deletions(-) + +diff --git a/js/gdm/authMenuButton.js b/js/gdm/authMenuButton.js +index 9b7cebf6d8..f7f458dec8 100644 +--- a/js/gdm/authMenuButton.js ++++ b/js/gdm/authMenuButton.js +@@ -1,4 +1,5 @@ + // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- ++/* exported AuthMenuButton, AuthMenuButtonIndicator */ + /* + * Copyright 2024 Red Hat, Inc + * +@@ -43,15 +44,11 @@ + * deactivates any other active item in the same section. + */ + +-import Atk from 'gi://Atk'; +-import Clutter from 'gi://Clutter'; +-import GObject from 'gi://GObject'; +-import Shell from 'gi://Shell'; +-import St from 'gi://St'; ++const { Atk, Clutter, GObject, Shell, St } = imports.gi; + +-import * as BoxPointer from '../ui/boxpointer.js'; +-import * as Main from '../ui/main.js'; +-import * as PopupMenu from '../ui/popupMenu.js'; ++const BoxPointer = imports.ui.boxpointer; ++const Main = imports.ui.main; ++const PopupMenu = imports.ui.popupMenu; + + const VISIBILITY_ANIMATION_TIME = 200; + +diff --git a/js/gdm/authServices.js b/js/gdm/authServices.js +index 0a94f493a2..0cafd2831c 100644 +--- a/js/gdm/authServices.js ++++ b/js/gdm/authServices.js +@@ -1,16 +1,12 @@ + // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +-import * as FingerprintManager from '../misc/fingerprintManager.js'; +-import * as Params from '../misc/params.js'; +-import {registerDestroyableType} from '../misc/signalTracker.js'; +-import * as PasskeyDeviceManager from '../misc/passkeyDeviceManager.js'; +-import * as SmartcardManager from '../misc/smartcardManager.js'; +-import {logErrorUnlessCancelled} from '../misc/errorUtils.js'; +-import * as Util from './util.js'; +-import Gdm from 'gi://Gdm'; +-import GLib from 'gi://GLib'; +-import Gio from 'gi://Gio'; +-import GObject from 'gi://GObject'; ++const { Gdm, Gio, GLib, GObject } = imports.gi; ++ ++const FingerprintManager = imports.misc.fingerprintManager; ++const Params = imports.misc.params; ++const PasskeyDeviceManager = imports.misc.passkeyDeviceManager; ++const SmartcardManager = imports.misc.smartcardManager; ++const Util = imports.gdm.util; + + Gio._promisify(Gdm.Client.prototype, 'open_reauthentication_channel'); + Gio._promisify(Gdm.Client.prototype, 'get_user_verifier'); +diff --git a/js/gdm/authServicesLegacy.js b/js/gdm/authServicesLegacy.js +index c1ff1242dc..dd134db4b9 100644 +--- a/js/gdm/authServicesLegacy.js ++++ b/js/gdm/authServicesLegacy.js +@@ -1,13 +1,11 @@ +-import GLib from 'gi://GLib'; +-import GObject from 'gi://GObject'; +- +-import * as Constants from './constants.js'; +-import {FingerprintReaderType} from '../misc/fingerprintManager.js'; +-import {logErrorUnlessCancelled} from '../misc/errorUtils.js'; +-import * as OVirt from './oVirt.js'; +-import * as Util from './util.js'; +-import * as Vmware from './vmware.js'; +-import {AuthServices} from './authServices.js'; ++const { GLib, GObject } = imports.gi; ++ ++const {AuthServices} = imports.gdm.authServices; ++const Constants = imports.gdm.constants; ++const {FingerprintReaderType} = imports.misc.fingerprintManager; ++const OVirt = imports.gdm.oVirt; ++const Util = imports.gdm.util; ++const Vmware = imports.gdm.vmware; + + const FINGERPRINT_ERROR_TIMEOUT_WAIT = 15; + const FINGERPRINT_READY_TIMEOUT_MS = 500; +diff --git a/js/gdm/authServicesSSSDSwitchable.js b/js/gdm/authServicesSSSDSwitchable.js +index de03dec1d7..4f74a2040d 100644 +--- a/js/gdm/authServicesSSSDSwitchable.js ++++ b/js/gdm/authServicesSSSDSwitchable.js +@@ -1,10 +1,8 @@ +-import GLib from 'gi://GLib'; +-import GObject from 'gi://GObject'; ++const { GLib, GObject } = imports.gi; + +-import * as Constants from './constants.js'; +-import {logErrorUnlessCancelled} from '../misc/errorUtils.js'; +-import * as Util from './util.js'; +-import {AuthServices} from './authServices.js'; ++const {AuthServices} = imports.gdm.authServices; ++const Constants = imports.gdm.constants; ++const Util = imports.gdm.util; + + const MechanismsStatus = { + WAITING: 0, +diff --git a/js/gdm/webLogin.js b/js/gdm/webLogin.js +index 8f2a0d8767..ef4f28b592 100644 +--- a/js/gdm/webLogin.js ++++ b/js/gdm/webLogin.js +@@ -3,13 +3,13 @@ + // A widget showing a URL for web login + /* exported WebLoginPrompt */ + +-import Clutter from 'gi://Clutter'; +-import GObject from 'gi://GObject'; +-import Pango from 'gi://Pango'; +-import St from 'gi://St'; +-import {Spinner} from '../ui/animation.js'; +-import * as Params from '../misc/params.js'; +-import {QrCode} from '../ui/qrCode.js'; ++const { Clutter, Gio, GnomeQR, GObject, Pango, St } = imports.gi; ++ ++const Params = imports.misc.params; ++const { Spinner } = imports.ui.animation; ++const { QrCode } = imports.ui.qrCode; ++ ++Gio._promisify(GnomeQR, 'generate_qr_code_async'); + + const QR_CODE_SIZE = 150; + const WEB_LOGIN_SPINNER_SIZE = 35; +diff --git a/js/misc/fingerprintManager.js b/js/misc/fingerprintManager.js +index 6ef2d68d3a..cdeb3579d1 100644 +--- a/js/misc/fingerprintManager.js ++++ b/js/misc/fingerprintManager.js +@@ -1,13 +1,11 @@ +-import Gio from 'gi://Gio'; +-import GLib from 'gi://GLib'; +-import GObject from 'gi://GObject'; ++const { Gio, GLib, GObject } = imports.gi; + +-import {loadInterfaceXML} from './fileUtils.js'; ++const FileUtils = imports.misc.fileUtils; + + const FprintManagerInfo = Gio.DBusInterfaceInfo.new_for_xml( +- loadInterfaceXML('net.reactivated.Fprint.Manager')); ++ FileUtils.loadInterfaceXML('net.reactivated.Fprint.Manager')); + const FprintDeviceInfo = Gio.DBusInterfaceInfo.new_for_xml( +- loadInterfaceXML('net.reactivated.Fprint.Device')); ++ FileUtils.loadInterfaceXML('net.reactivated.Fprint.Device')); + + export const FingerprintReaderType = { + NONE: 0, +diff --git a/js/misc/passkeyDeviceManager.js b/js/misc/passkeyDeviceManager.js +index 20799975aa..2aa81d2ce6 100644 +--- a/js/misc/passkeyDeviceManager.js ++++ b/js/misc/passkeyDeviceManager.js +@@ -1,5 +1,4 @@ +-import GObject from 'gi://GObject'; +-import GUdev from 'gi://GUdev'; ++const { GObject, GUdev } = imports.gi; + + let _passkeyDeviceManager = null; + +diff --git a/js/ui/qrCode.js b/js/ui/qrCode.js +index caf0999f34..d1fac46847 100644 +--- a/js/ui/qrCode.js ++++ b/js/ui/qrCode.js +@@ -1,10 +1,6 @@ +-import Clutter from 'gi://Clutter'; +-import Cogl from 'gi://Cogl'; +-import GObject from 'gi://GObject'; +-import Gio from 'gi://Gio'; +-import GnomeQR from 'gi://GnomeQR'; +-import St from 'gi://St'; +-import {logErrorUnlessCancelled} from '../misc/errorUtils.js'; ++/* exported QrCode */ ++ ++const { Clutter, Cogl, Gio, GnomeQR, GObject, St } = imports.gi; + + Gio._promisify(GnomeQR, 'generate_qr_code_async'); + +-- +2.51.0 + + +From 12ea582a78b26f37c9c7bdd12af35718cbbae961 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 26 Dec 2025 14:58:42 +0100 +Subject: [PATCH 03/30] gdm: Fix using the old gjs style for classes and + functions + +--- + js/gdm/authList.js | 45 +++++++++------------- + js/gdm/authMenuButton.js | 57 +++++++++++----------------- + js/gdm/authServices.js | 20 ++++------ + js/gdm/authServicesLegacy.js | 15 ++++---- + js/gdm/authServicesSSSDSwitchable.js | 15 ++++---- + js/gdm/constants.js | 22 ++++++----- + js/gdm/util.js | 9 +++-- + js/gdm/webLogin.js | 20 +++++----- + js/misc/fingerprintManager.js | 30 +++++++-------- + js/misc/passkeyDeviceManager.js | 23 +++++------ + js/ui/qrCode.js | 40 +++++++++---------- + 11 files changed, 131 insertions(+), 165 deletions(-) + +diff --git a/js/gdm/authList.js b/js/gdm/authList.js +index 3f1b2817f9..6eb34f6d97 100644 +--- a/js/gdm/authList.js ++++ b/js/gdm/authList.js +@@ -57,13 +57,10 @@ const ItemIconPopup = class extends PopupMenu.PopupMenu { + } + }; + ++const ItemIcon = GObject.registerClass( + class ItemIcon extends St.Button { +- static { +- GObject.registerClass(this); +- } +- +- constructor(iconName, iconTitle, iconSubtitle) { +- super({ ++ _init(iconName, iconTitle, iconSubtitle) { ++ super._init({ + style_class: 'login-dialog-item-icon', + iconName, + }); +@@ -71,21 +68,17 @@ class ItemIcon extends St.Button { + this._popup = new ItemIconPopup(this, iconTitle, iconSubtitle); + Main.uiGroup.add_child(this._popup.actor); + } +-} ++}); + +-class AuthListItem extends St.Button { +- static [GObject.signals] = { ++const AuthListItem = GObject.registerClass({ ++ Signals: { + 'activate': {}, +- }; +- +- static { +- GObject.registerClass(this); +- } +- +- constructor(key, content) { ++ }, ++}, class AuthListItem extends St.Button { ++ _init(key, content) { + const {title, subtitle, iconName, iconTitle, iconSubtitle} = content; + +- super({ ++ super._init({ + style_class: 'login-dialog-auth-list-item', + button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, + can_focus: true, +@@ -168,20 +161,16 @@ class AuthListItem extends St.Button { + this.remove_style_pseudo_class('selected'); + } + } +-} ++}); + +-export class AuthList extends St.BoxLayout { +- static [GObject.signals] = { ++var AuthList = GObject.registerClass({ ++ Signals: { + 'activate': {param_types: [GObject.TYPE_STRING]}, + 'item-added': {param_types: [AuthListItem.$gtype]}, +- }; +- +- static { +- GObject.registerClass(this); + } +- +- constructor() { +- super({ ++}, class AuthList extends St.BoxLayout { ++ _init() { ++ super._init({ + orientation: Clutter.Orientation.VERTICAL, + style_class: 'login-dialog-auth-list-layout', + y_align: Clutter.ActorAlign.CENTER, +@@ -278,4 +267,4 @@ export class AuthList extends St.BoxLayout { + this._box.destroy_all_children(); + this._items.clear(); + } +-} ++}); +diff --git a/js/gdm/authMenuButton.js b/js/gdm/authMenuButton.js +index f7f458dec8..e58c331b45 100644 +--- a/js/gdm/authMenuButton.js ++++ b/js/gdm/authMenuButton.js +@@ -71,13 +71,10 @@ class AuthMenuItemSection extends PopupMenu.PopupMenuSection { + } + } + ++const AuthMenuItem = GObject.registerClass( + class AuthMenuItem extends PopupMenu.PopupBaseMenuItem { +- static { +- GObject.registerClass(this); +- } +- +- constructor(item, params = {}) { +- super(params); ++ _init(item, params = {}) { ++ super._init(params); + + if (item.description && item.iconName) { + const icon = new St.Icon({ +@@ -117,42 +114,37 @@ class AuthMenuItem extends PopupMenu.PopupBaseMenuItem { + + this.setOrnament(PopupMenu.Ornament.HIDDEN); + } +-} ++}); + +-export class AuthMenuButton extends St.Button { +- static [GObject.properties] = { ++var AuthMenuButton = GObject.registerClass({ ++ Properties: { + 'title': GObject.ParamSpec.string( +- 'title', null, null, ++ 'title', 'title', 'title', + GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, + ''), + 'icon-name': GObject.ParamSpec.string( +- 'icon-name', null, null, ++ 'icon-name', 'icon-name', 'icon-name', + GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, + ''), + 'read-only': GObject.ParamSpec.boolean( +- 'read-only', null, null, ++ 'read-only', 'read-only', 'read-only', + GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, + false), + 'section-order': GObject.ParamSpec.jsobject( +- 'section-order', null, null, ++ 'section-order', 'section-order', 'section-order', + GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY), + 'animate-visibility': GObject.ParamSpec.boolean( +- 'animate-visibility', null, null, ++ 'animate-visibility', 'animate-visibility', 'animate-visibility', + GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, + false), +- }; +- +- static [GObject.signals] = { ++ }, ++ Signals: { + 'active-item-changed': {param_types: [GObject.TYPE_STRING]}, +- }; +- +- static { +- GObject.registerClass(this); +- } +- +- constructor(params) { ++ }, ++}, class AuthMenuButton extends St.Button { ++ _init(params) { + params.sectionOrder ??= []; +- super({ ++ super._init({ + ...params, + style_class: 'login-dialog-button login-dialog-auth-menu-button', + reactive: true, +@@ -452,16 +444,13 @@ export class AuthMenuButton extends St.Button { + closeMenu() { + this._menu.close(); + } +-} ++}); + +-export class AuthMenuButtonIndicator extends AuthMenuButton { +- static { +- GObject.registerClass(this); +- } +- +- constructor(params = {}) { ++var AuthMenuButtonIndicator = GObject.registerClass( ++class AuthMenuButtonIndicator extends AuthMenuButton { ++ _init(params = {}) { + params.readOnly ??= true; +- super(params); ++ super._init(params); + + this.add_style_class_name('login-dialog-auth-menu-button-indicator'); + } +@@ -526,4 +515,4 @@ export class AuthMenuButtonIndicator extends AuthMenuButton { + // Override to force visibility even when there's only one item + _updateVisibility() { + } +-} ++}); +diff --git a/js/gdm/authServices.js b/js/gdm/authServices.js +index 0cafd2831c..ce4f0729b3 100644 +--- a/js/gdm/authServices.js ++++ b/js/gdm/authServices.js +@@ -1,4 +1,5 @@ + // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- ++/* exported AuthServices */ + + const { Gdm, Gio, GLib, GObject } = imports.gi; + +@@ -16,8 +17,8 @@ Gio._promisify(Gdm.UserVerifierProxy.prototype, 'call_answer_query'); + Gio._promisify(Gdm.UserVerifierChoiceListProxy.prototype, 'call_select_choice'); + Gio._promisify(Gdm.UserVerifierCustomJSONProxy.prototype, 'call_reply'); + +-export class AuthServices extends GObject.Object { +- static [GObject.signals] = { ++var AuthServices = GObject.registerClass({ ++ Signals: { + 'destroy': {}, + 'queue-message': { + param_types: [GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_UINT], +@@ -51,13 +52,8 @@ export class AuthServices extends GObject.Object { + GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_JSOBJECT, + ], + }, +- }; +- +- static { +- GObject.registerClass(this); +- registerDestroyableType(this); +- } +- ++ }, ++}, class AuthServices extends GObject.Object { + static SupportedRoles = []; + static RoleToService = {}; + +@@ -65,8 +61,8 @@ export class AuthServices extends GObject.Object { + return roles.some(r => this.SupportedRoles.includes(r)); + } + +- constructor(params) { +- super(); ++ _init(params) { ++ super._init(); + params = Params.parse(params, { + client: null, + enabledRoles: [], +@@ -502,4 +498,4 @@ export class AuthServices extends GObject.Object { + throw new GObject.NotImplementedError( + `_handleCanStartService in ${this.constructor.name}`); + } +-} ++}); +diff --git a/js/gdm/authServicesLegacy.js b/js/gdm/authServicesLegacy.js +index dd134db4b9..8922546474 100644 +--- a/js/gdm/authServicesLegacy.js ++++ b/js/gdm/authServicesLegacy.js +@@ -1,3 +1,5 @@ ++/* exported AuthServicesLegacy */ ++ + const { GLib, GObject } = imports.gi; + + const {AuthServices} = imports.gdm.authServices; +@@ -28,7 +30,8 @@ const Mechanisms = [ + }, + ]; + +-export class AuthServicesLegacy extends AuthServices { ++var AuthServicesLegacy = GObject.registerClass({ ++}, class AuthServicesLegacy extends AuthServices { + static SupportedRoles = [ + Constants.PASSWORD_ROLE_NAME, + Constants.SMARTCARD_ROLE_NAME, +@@ -41,12 +44,8 @@ export class AuthServicesLegacy extends AuthServices { + [Constants.FINGERPRINT_ROLE_NAME]: Constants.FINGERPRINT_SERVICE_NAME, + }; + +- static { +- GObject.registerClass(this); +- } +- +- constructor(params) { +- super(params); ++ _init(params) { ++ super._init(params); + + this._updateEnabledMechanisms(); + +@@ -378,4 +377,4 @@ export class AuthServicesLegacy extends AuthServices { + }; + this.emit('reset', {softReset: true}); + } +-} ++}); +diff --git a/js/gdm/authServicesSSSDSwitchable.js b/js/gdm/authServicesSSSDSwitchable.js +index 4f74a2040d..4b4761d105 100644 +--- a/js/gdm/authServicesSSSDSwitchable.js ++++ b/js/gdm/authServicesSSSDSwitchable.js +@@ -1,3 +1,5 @@ ++/* exported AuthServicesSwitchable */ ++ + const { GLib, GObject } = imports.gi; + + const {AuthServices} = imports.gdm.authServices; +@@ -10,7 +12,8 @@ const MechanismsStatus = { + FOUND: 2, + }; + +-export class AuthServicesSSSDSwitchable extends AuthServices { ++var AuthServicesSSSDSwitchable = GObject.registerClass({ ++}, class AuthServicesSSSDSwitchable extends AuthServices { + static SupportedRoles = [ + Constants.PASSWORD_ROLE_NAME, + Constants.SMARTCARD_ROLE_NAME, +@@ -25,12 +28,8 @@ export class AuthServicesSSSDSwitchable extends AuthServices { + [Constants.WEB_LOGIN_ROLE_NAME]: Constants.SWITCHABLE_AUTH_SERVICE_NAME, + }; + +- static { +- GObject.registerClass(this); +- } +- +- constructor(params) { +- super(params); ++ _init(params) { ++ super._init(params); + + this._mechanismsStatus = MechanismsStatus.WAITING; + } +@@ -440,4 +439,4 @@ export class AuthServicesSSSDSwitchable extends AuthServices { + GLib.source_remove(this._webLoginTimeoutId); + this._webLoginTimeoutId = 0; + } +-} ++}); +diff --git a/js/gdm/constants.js b/js/gdm/constants.js +index 7c48599e64..cfbbe32426 100644 +--- a/js/gdm/constants.js ++++ b/js/gdm/constants.js +@@ -1,12 +1,16 @@ + // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- ++/* exported PASSWORD_ROLE_NAME, SMARTCARD_ROLE_NAME, FINGERPRINT_ROLE_NAME, ++ PASSKEY_ROLE_NAME, WEB_LOGIN_ROLE_NAME, PASSWORD_SERVICE_NAME, ++ SMARTCARD_SERVICE_NAME, FINGERPRINT_SERVICE_NAME, ++ SWITCHABLE_AUTH_SERVICE_NAME */ + +-export const PASSWORD_ROLE_NAME = 'password'; +-export const SMARTCARD_ROLE_NAME = 'smartcard'; +-export const FINGERPRINT_ROLE_NAME = 'fingerprint'; +-export const PASSKEY_ROLE_NAME = 'passkey'; +-export const WEB_LOGIN_ROLE_NAME = 'eidp'; ++var PASSWORD_ROLE_NAME = 'password'; ++var SMARTCARD_ROLE_NAME = 'smartcard'; ++var FINGERPRINT_ROLE_NAME = 'fingerprint'; ++var PASSKEY_ROLE_NAME = 'passkey'; ++var WEB_LOGIN_ROLE_NAME = 'eidp'; + +-export const PASSWORD_SERVICE_NAME = 'gdm-password'; +-export const SMARTCARD_SERVICE_NAME = 'gdm-smartcard'; +-export const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; +-export const SWITCHABLE_AUTH_SERVICE_NAME = 'gdm-switchable-auth'; ++var PASSWORD_SERVICE_NAME = 'gdm-password'; ++var SMARTCARD_SERVICE_NAME = 'gdm-smartcard'; ++var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; ++var SWITCHABLE_AUTH_SERVICE_NAME = 'gdm-switchable-auth'; +diff --git a/js/gdm/util.js b/js/gdm/util.js +index 743fce11b7..f1709edea3 100644 +--- a/js/gdm/util.js ++++ b/js/gdm/util.js +@@ -1,6 +1,7 @@ + // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + /* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY, +- DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor */ ++ DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor, ++ InitError, isSelectable, getIconName */ + + const { Clutter, Gio, GLib } = imports.gi; + const Signals = imports.signals; +@@ -125,7 +126,7 @@ function cloneAndFadeOutActor(actor) { + * a service via beginVerification fails. It wraps the underlying error + * and provides context about which service failed. + */ +-export class InitError extends Error { ++var InitError = class extends Error { + constructor(error, message, serviceName) { + super(message, {cause: error}); + this.serviceName = serviceName; +@@ -136,7 +137,7 @@ export class InitError extends Error { + * @param {object} mechanism + * @returns {boolean} + */ +-export function isSelectable(mechanism) { ++function isSelectable(mechanism) { + switch (mechanism.role) { + case Constants.PASSWORD_ROLE_NAME: + case Constants.SMARTCARD_ROLE_NAME: +@@ -154,7 +155,7 @@ export function isSelectable(mechanism) { + * @param {object} mechanism + * @returns {string} + */ +-export function getNonSelectableIconName(mechanism) { ++function getNonSelectableIconName(mechanism) { + // This is only used for non selectable mechanisms. + // Currently only fingerprint is non selectable + if (isSelectable(mechanism)) +diff --git a/js/gdm/webLogin.js b/js/gdm/webLogin.js +index ef4f28b592..9c858f7269 100644 +--- a/js/gdm/webLogin.js ++++ b/js/gdm/webLogin.js +@@ -1,7 +1,7 @@ + // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + // + // A widget showing a URL for web login +-/* exported WebLoginPrompt */ ++/* exported QrCode, WebLoginPrompt, WebLoginDialog, WebLoginIntro */ + + const { Clutter, Gio, GnomeQR, GObject, Pango, St } = imports.gi; + +@@ -15,9 +15,9 @@ const QR_CODE_SIZE = 150; + const WEB_LOGIN_SPINNER_SIZE = 35; + const URL_LABEL_LONG_THRESHOLD = 45; + +-export const WebLoginPrompt = GObject.registerClass( ++var WebLoginPrompt = GObject.registerClass( + class WebLoginPrompt extends St.BoxLayout { +- constructor(params) { ++ _init(params) { + const {qrSize: qrCodeSize, message, url, code} = Params.parse(params, { + qrSize: QR_CODE_SIZE, + message: null, +@@ -25,7 +25,7 @@ class WebLoginPrompt extends St.BoxLayout { + code: null, + }); + +- super({ ++ super._init({ + styleClass: 'web-login-prompt', + vertical: true, + y_align: Clutter.ActorAlign.CENTER, +@@ -124,13 +124,13 @@ class WebLoginPrompt extends St.BoxLayout { + } + }); + +-export const WebLoginDialog = GObject.registerClass({ ++var WebLoginDialog = GObject.registerClass({ + Signals: { + 'cancel': {}, + 'loading': {}, + }, + }, class WebLoginDialog extends St.Widget { +- constructor(params) { ++ _init(params) { + const {message, url, code, buttons} = Params.parse(params, { + message: null, + url: null, +@@ -138,7 +138,7 @@ export const WebLoginDialog = GObject.registerClass({ + buttons: [], + }); + +- super({ ++ super._init({ + layout_manager: new Clutter.BinLayout(), + x_expand: true, + y_expand: true, +@@ -279,9 +279,9 @@ export const WebLoginDialog = GObject.registerClass({ + } + }); + +-export var WebLoginIntro = GObject.registerClass( ++var WebLoginIntro = GObject.registerClass( + class WebLoginIntro extends St.Button { +- constructor(params) { ++ _init(params) { + const {message} = Params.parse(params, { + message: null, + }); +@@ -291,7 +291,7 @@ class WebLoginIntro extends St.Button { + style_class: 'web-login-button-label', + }); + +- super({ ++ super._init({ + style_class: 'web-login-intro-button', + accessible_name: message, + button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, +diff --git a/js/misc/fingerprintManager.js b/js/misc/fingerprintManager.js +index cdeb3579d1..151e787e0b 100644 +--- a/js/misc/fingerprintManager.js ++++ b/js/misc/fingerprintManager.js +@@ -1,4 +1,5 @@ + const { Gio, GLib, GObject } = imports.gi; ++/* exported FingerprintReaderType, FingerprintManager */ + + const FileUtils = imports.misc.fileUtils; + +@@ -7,7 +8,7 @@ const FprintManagerInfo = Gio.DBusInterfaceInfo.new_for_xml( + const FprintDeviceInfo = Gio.DBusInterfaceInfo.new_for_xml( + FileUtils.loadInterfaceXML('net.reactivated.Fprint.Device')); + +-export const FingerprintReaderType = { ++var FingerprintReaderType = { + NONE: 0, + PRESS: 1, + SWIPE: 2, +@@ -18,32 +19,27 @@ let _fingerprintManager = null; + /** + * @returns {FingerprintManager} + */ +-export function getFingerprintManager() { ++function getFingerprintManager() { + if (_fingerprintManager == null) + _fingerprintManager = new FingerprintManager(); + + return _fingerprintManager; + } + +-class FingerprintManager extends GObject.Object { +- static [GObject.properties] = { ++var FingerprintManager = GObject.registerClass({ ++ Properties: { + 'reader-type': GObject.ParamSpec.uint( +- 'reader-type', null, null, ++ 'reader-type', 'reader-type', 'reader-type', + GObject.ParamFlags.READWRITE, + FingerprintReaderType.NONE, FingerprintReaderType.SWIPE, + FingerprintReaderType.NONE), +- }; +- +- static [GObject.signals] = { ++ }, ++ Signals: { + 'reader-type-changed': {}, +- }; +- +- static { +- GObject.registerClass(this); +- } +- +- constructor() { +- super(); ++ }, ++}, class FingerprintManager extends GObject.Object { ++ _init() { ++ super._init(); + + this._fingerprintManagerProxy = new Gio.DBusProxy({ + g_connection: Gio.DBus.system, +@@ -133,4 +129,4 @@ class FingerprintManager extends GObject.Object { + + logError(e, 'Failed to interact with fprintd service'); + } +-} ++}); +diff --git a/js/misc/passkeyDeviceManager.js b/js/misc/passkeyDeviceManager.js +index 2aa81d2ce6..747ee93fc8 100644 +--- a/js/misc/passkeyDeviceManager.js ++++ b/js/misc/passkeyDeviceManager.js +@@ -1,30 +1,27 @@ + const { GObject, GUdev } = imports.gi; ++/* exported getPasskeyDeviceManager */ ++ + + let _passkeyDeviceManager = null; + + /** + * @returns {PasskeyDeviceManager} + */ +-export function getPasskeyDeviceManager() { ++function getPasskeyDeviceManager() { + if (_passkeyDeviceManager == null) + _passkeyDeviceManager = new PasskeyDeviceManager(); + + return _passkeyDeviceManager; + } + +-class PasskeyDeviceManager extends GObject.Object { +- static [GObject.signals] = { ++var PasskeyDeviceManager = GObject.registerClass({ ++ Signals: { + 'passkey-inserted': {param_types: [GObject.TYPE_JSOBJECT]}, + 'passkey-removed': {param_types: [GObject.TYPE_JSOBJECT]}, +- }; +- +- static { +- GObject.registerClass(this); +- } +- +- constructor() { +- super(); +- ++ }, ++}, class PasskeyDeviceManager extends GObject.Object { ++ _init() { ++ super._init(); + this._insertedPasskeys = new Map(); + this._udevClient = new GUdev.Client({subsystems: ['hidraw']}); + +@@ -65,4 +62,4 @@ class PasskeyDeviceManager extends GObject.Object { + this._insertedPasskeys.delete(sysfsPath); + this.emit('passkey-removed', device); + } +-} ++}); +diff --git a/js/ui/qrCode.js b/js/ui/qrCode.js +index d1fac46847..5920e45e5a 100644 +--- a/js/ui/qrCode.js ++++ b/js/ui/qrCode.js +@@ -7,43 +7,39 @@ Gio._promisify(GnomeQR, 'generate_qr_code_async'); + const QR_CODE_DEFAULT_SIZE = 150; + const QR_CODE_TRANSPARENT_COLOR = new GnomeQR.Color({alpha: 0}); + +-export class QrCode extends St.Bin { +- static [GObject.properties] = { ++var QrCode = GObject.registerClass({ ++ Properties: { + 'url': GObject.ParamSpec.string( +- 'url', null, null, ++ 'url', 'url', 'url', + GObject.ParamFlags.READWRITE, + null), +- }; +- +- static { +- GObject.registerClass(this); +- } +- +- constructor(params) { ++ }, ++}, class QrCode extends St.Bin { ++ _init(params) { + const qrSize = Math.max(params.width ?? 0, params.height ?? 0) || + QR_CODE_DEFAULT_SIZE; + +- super({ +- styleClass: 'qr-code', ++ super._init({ ++ style_class: 'qr-code', + width: qrSize, + height: qrSize, + ...params, + }); + + this.set_child(new Clutter.Actor({ +- xExpand: true, +- yExpand: true, +- xAlign: Clutter.ActorAlign.FILL, +- yAlign: Clutter.ActorAlign.FILL, +- minificationFilter: Clutter.ScalingFilter.NEAREST, +- magnificationFilter: Clutter.ScalingFilter.NEAREST, ++ x_expand: true, ++ y_expand: true, ++ x_align: Clutter.ActorAlign.FILL, ++ y_align: Clutter.ActorAlign.FILL, ++ minification_filter: Clutter.ScalingFilter.NEAREST, ++ magnification_filter: Clutter.ScalingFilter.NEAREST, + })); + + this._fgColor = null; + + this.connect('notify::url', () => + this._update().catch(logErrorUnlessCancelled)); +- }; ++ } + + vfunc_allocate(box) { + const width = box.get_width(); +@@ -69,7 +65,7 @@ export class QrCode extends St.Bin { + } + + async _update() { +- const fgColor = QrCode.#getGnomeQRColor(this._fgColor); ++ const fgColor = QrCode._getGnomeQRColor(this._fgColor); + + this._cancellable?.cancel(); + const cancellable = new Gio.Cancellable(); +@@ -100,7 +96,7 @@ export class QrCode extends St.Bin { + this.child.set_content(content); + } + +- static #getGnomeQRColor(color) { ++ static _getGnomeQRColor(color) { + if (!color) + return null; + +@@ -111,4 +107,4 @@ export class QrCode extends St.Bin { + alpha: color.alpha, + }); + } +-}; ++}); +-- +2.51.0 + + +From 8d635a7b5f8da824025ae9e206cd2cdf92bc83ff Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 26 Dec 2025 15:01:19 +0100 +Subject: [PATCH 04/30] gdm: Fix using logErrorUnless cancelled + +This function doesn't exist in this version. +--- + js/gdm/authServices.js | 3 ++- + js/gdm/authServicesLegacy.js | 12 +++++++++--- + js/gdm/authServicesSSSDSwitchable.js | 12 +++++++++--- + js/gdm/util.js | 5 ++++- + js/ui/qrCode.js | 13 ++++++++++--- + 5 files changed, 34 insertions(+), 11 deletions(-) + +diff --git a/js/gdm/authServices.js b/js/gdm/authServices.js +index ce4f0729b3..fea7ba0634 100644 +--- a/js/gdm/authServices.js ++++ b/js/gdm/authServices.js +@@ -373,7 +373,8 @@ var AuthServices = GObject.registerClass({ + await this._waitPendingMessages(); + this.emit('reset', {softReset: !doneTrying}); + } catch (e) { +- logErrorUnlessCancelled(e); ++ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) ++ logError(e); + } + } + +diff --git a/js/gdm/authServicesLegacy.js b/js/gdm/authServicesLegacy.js +index 8922546474..0fd0e10d81 100644 +--- a/js/gdm/authServicesLegacy.js ++++ b/js/gdm/authServicesLegacy.js +@@ -1,6 +1,6 @@ + /* exported AuthServicesLegacy */ + +-const { GLib, GObject } = imports.gi; ++const { Gio, GLib, GObject } = imports.gi; + + const {AuthServices} = imports.gdm.authServices; + const Constants = imports.gdm.constants; +@@ -61,7 +61,10 @@ var AuthServicesLegacy = GObject.registerClass({ + return; + + this._userVerifierChoiceList.call_select_choice( +- serviceName, key, this._cancellable).catch(logErrorUnlessCancelled); ++ serviceName, key, this._cancellable).catch(e => { ++ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) ++ logError(e); ++ }); + } + + _handleAnswerQuery(serviceName, answer) { +@@ -72,7 +75,10 @@ var AuthServicesLegacy = GObject.registerClass({ + this._smartcardInProgress = true; + + this._userVerifier.call_answer_query( +- serviceName, answer, this._cancellable).catch(logErrorUnlessCancelled); ++ serviceName, answer, this._cancellable).catch(e => { ++ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) ++ logError(e); ++ }); + } + + _handleBeginVerification() { +diff --git a/js/gdm/authServicesSSSDSwitchable.js b/js/gdm/authServicesSSSDSwitchable.js +index 4b4761d105..601f4cd295 100644 +--- a/js/gdm/authServicesSSSDSwitchable.js ++++ b/js/gdm/authServicesSSSDSwitchable.js +@@ -1,6 +1,6 @@ + /* exported AuthServicesSwitchable */ + +-const { GLib, GObject } = imports.gi; ++const { Gio, GLib, GObject } = imports.gi; + + const {AuthServices} = imports.gdm.authServices; + const Constants = imports.gdm.constants; +@@ -54,7 +54,10 @@ var AuthServicesSSSDSwitchable = GObject.registerClass({ + this._resettingPassword) { + this._userVerifier.call_answer_query(serviceName, + answer, +- this._cancellable).catch(logErrorUnlessCancelled); ++ this._cancellable).catch(e => { ++ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) ++ logError(e); ++ }); + return; + } + +@@ -316,7 +319,10 @@ var AuthServicesSSSDSwitchable = GObject.registerClass({ + const {serviceName} = this._selectedMechanism; + + this._userVerifierCustomJSON.call_reply( +- serviceName, JSON.stringify(response), this._cancellable).catch(logErrorUnlessCancelled); ++ serviceName, JSON.stringify(response), this._cancellable).catch(e => { ++ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) ++ logError(e); ++ }); + } + + _eventExpected() { +diff --git a/js/gdm/util.js b/js/gdm/util.js +index f1709edea3..17892c75e8 100644 +--- a/js/gdm/util.js ++++ b/js/gdm/util.js +@@ -282,7 +282,10 @@ var ShellUserVerifier = class { + async answerQuery(serviceName, answer) { + // Wait for pending messages to be displayed before answering to + // ensure no messages get lost +- await this._handlePendingMessages().catch(logErrorUnlessCancelled); ++ await this._handlePendingMessages().catch(e => { ++ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) ++ logError(e); ++ }); + + this._authServicesSSSDSwitchable?.answerQuery(serviceName, answer); + this._authServicesLegacy?.answerQuery(serviceName, answer); +diff --git a/js/ui/qrCode.js b/js/ui/qrCode.js +index 5920e45e5a..b53508c2dd 100644 +--- a/js/ui/qrCode.js ++++ b/js/ui/qrCode.js +@@ -37,8 +37,12 @@ var QrCode = GObject.registerClass({ + + this._fgColor = null; + +- this.connect('notify::url', () => +- this._update().catch(logErrorUnlessCancelled)); ++ this.connect('notify::url', () => { ++ this._update().catch(e => { ++ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) ++ logError(e); ++ }); ++ }); + } + + vfunc_allocate(box) { +@@ -60,7 +64,10 @@ var QrCode = GObject.registerClass({ + + if (!this._fgColor?.equal(fgColor)) { + this._fgColor = fgColor; +- this._update().catch(logErrorUnlessCancelled); ++ this._update().catch(e => { ++ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) ++ logError(e); ++ }); + } + } + +-- +2.51.0 + + +From 147ad05d7d926478da5d35ea14bcec81bf0795ee Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 12 Dec 2025 12:58:59 +0100 +Subject: [PATCH 05/30] gdm: Change connectObject to connect + +connectObject is a helper that isn't available in this older version. +--- + js/gdm/authPrompt.js | 24 +++--- + js/gdm/authServices.js | 138 +++++++++++++++++++++++++---------- + js/gdm/authServicesLegacy.js | 26 ++++++- + js/gdm/util.js | 61 +++++++++++----- + js/gdm/webLogin.js | 11 ++- + 5 files changed, 186 insertions(+), 74 deletions(-) + +diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js +index 8c5c8a1fab..6996dac18b 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -81,16 +81,16 @@ var AuthPrompt = GObject.registerClass({ + + this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly }); + +- this._userVerifier.connectObject( +- 'ask-question', this._onAskQuestion.bind(this), +- 'show-message', this._onShowMessage.bind(this), +- 'show-choice-list', this._onShowChoiceList.bind(this), +- 'mechanisms-changed', (_, ...args) => this.emit('mechanisms-changed', ...args), +- 'web-login', this._onWebLogin.bind(this), +- 'verification-failed', this._onVerificationFailed.bind(this), +- 'verification-complete', this._onVerificationComplete.bind(this), +- 'reset', this._onReset.bind(this), +- this); ++ this._userVerifierSignalIds = [ ++ this._userVerifier.connect('ask-question', this._onAskQuestion.bind(this)), ++ this._userVerifier.connect('show-message', this._onShowMessage.bind(this)), ++ this._userVerifier.connect('show-choice-list', this._onShowChoiceList.bind(this)), ++ this._userVerifier.connect('mechanisms-changed', (_, ...args) => this.emit('mechanisms-changed', ...args)), ++ this._userVerifier.connect('web-login', this._onWebLogin.bind(this)), ++ this._userVerifier.connect('verification-failed', this._onVerificationFailed.bind(this)), ++ this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this)), ++ this._userVerifier.connect('reset', this._onReset.bind(this)), ++ ]; + + this.connect('destroy', this._onDestroy.bind(this)); + +@@ -134,7 +134,9 @@ var AuthPrompt = GObject.registerClass({ + this._preemptiveAnswerWatchId = 0; + } + +- this._userVerifier.disconnectObject(this); ++ this._userVerifierSignalIds.forEach(id => ++ this._userVerifier.disconnect(id)); ++ this._userVerifierSignalIds = []; + this._userVerifier.destroy(); + this._userVerifier = null; + this._entry = null; +diff --git a/js/gdm/authServices.js b/js/gdm/authServices.js +index fea7ba0634..88462cf17e 100644 +--- a/js/gdm/authServices.js ++++ b/js/gdm/authServices.js +@@ -165,6 +165,8 @@ var AuthServices = GObject.registerClass({ + destroy() { + this.reset(); + this.clear(); ++ this._disconnectManagers(); ++ this._handleDestroy(); + this.emit('destroy'); + } + +@@ -202,10 +204,35 @@ var AuthServices = GObject.registerClass({ + } + + _disconnectUserVerifierSignals() { +- this._userVerifier?.get_connection().disconnectObject(this); +- this._userVerifier?.disconnectObject(this); +- this._userVerifierChoiceList?.disconnectObject(this); +- this._userVerifierCustomJSON?.disconnectObject(this); ++ this._userVerifierConnectionSignalIds?.forEach(id => ++ this._userVerifier?.get_connection().disconnect(id)); ++ this._userVerifierConnectionSignalIds = []; ++ ++ this._userVerifierSignalIds?.forEach(id => ++ this._userVerifier?.disconnect(id)); ++ this._userVerifierSignalIds = []; ++ ++ this._userVerifierChoiceListSignalIds?.forEach(id => ++ this._userVerifierChoiceList?.disconnect(id)); ++ this._userVerifierChoiceListSignalIds = []; ++ ++ this._userVerifierCustomJSONSignalIds?.forEach(id => ++ this._userVerifierCustomJSON?.disconnect(id)); ++ this._userVerifierCustomJSONSignalIds = []; ++ } ++ ++ _disconnectManagers() { ++ this._smartcardManagerSignalIds?.forEach(id => ++ this._smartcardManager?.disconnect(id)); ++ this._smartcardManagerSignalIds = []; ++ ++ this._passkeyDeviceManagerSignalIds?.forEach(id => ++ this._passkeyDeviceManager?.disconnect(id)); ++ this._passkeyDeviceManagerSignalIds = []; ++ ++ this._fingerprintManagerSignalIds?.forEach(id => ++ this._fingerprintManager?.disconnect(id)); ++ this._fingerprintManagerSignalIds = []; + } + + _updateEnabledMechanisms() { +@@ -218,18 +245,24 @@ var AuthServices = GObject.registerClass({ + + _connectSmartcardManager() { + this._smartcardManager = SmartcardManager.getSmartcardManager(); +- this._smartcardManager.connectObject( +- 'smartcard-inserted', () => this._handleSmartcardChanged(), +- 'smartcard-removed', () => this._handleSmartcardChanged(), +- this); ++ this._smartcardManagerSignalIds = []; ++ let id = this._smartcardManager.connect('smartcard-inserted', ++ () => this._handleSmartcardChanged()); ++ this._smartcardManagerSignalIds.push(id); ++ id = this._smartcardManager.connect('smartcard-removed', ++ () => this._handleSmartcardChanged()); ++ this._smartcardManagerSignalIds.push(id); + } + + _connectPasskeyDeviceManager() { + this._passkeyDeviceManager = PasskeyDeviceManager.getPasskeyDeviceManager(); +- this._passkeyDeviceManager.connectObject( +- 'passkey-inserted', () => this._handlePasskeyChanged(), +- 'passkey-removed', () => this._handlePasskeyChanged(), +- this); ++ this._passkeyDeviceManagerSignalIds = []; ++ let id = this._passkeyDeviceManager.connect('passkey-inserted', ++ () => this._handlePasskeyChanged()); ++ this._passkeyDeviceManagerSignalIds.push(id); ++ id = this._passkeyDeviceManager.connect('passkey-removed', ++ () => this._handlePasskeyChanged()); ++ this._passkeyDeviceManagerSignalIds.push(id); + } + + _connectFingerprintManager() { +@@ -237,10 +270,11 @@ var AuthServices = GObject.registerClass({ + if (!this._reauthOnly) + return; + +- this._fingerprintManager = FingerprintManager.getFingerprintManager(); +- this._fingerprintManager.connectObject( +- 'reader-type-changed', () => this._handleFingerprintChanged(), +- this); ++ this._fingerprintManager = new FingerprintManager.FingerprintManager(); ++ this._fingerprintManagerSignalIds = []; ++ let id = this._fingerprintManager.connect('reader-type-changed', ++ () => this._handleFingerprintChanged()); ++ this._fingerprintManagerSignalIds.push(id); + } + + _waitPendingMessages() { +@@ -276,29 +310,53 @@ var AuthServices = GObject.registerClass({ + } + + _connectUserVerifierSignals() { +- this._userVerifier.get_connection().connectObject( +- 'closed', () => this._clearUserVerifier(), +- this); +- +- this._userVerifier.connectObject( +- 'info', (_, ...args) => this._onInfo(...args), +- 'problem', (_, ...args) => this._onProblem(...args), +- 'info-query', (_, ...args) => this._onInfoQuery(...args), +- 'secret-info-query', (_, ...args) => this._onSecretInfoQuery(...args), +- 'conversation-started', (_, ...args) => this._onConversationStarted(...args), +- 'conversation-stopped', (_, ...args) => this._onConversationStopped(...args), +- 'service-unavailable', (_, ...args) => this._onServiceUnavailable(...args), +- 'reset', () => this.emit('reset', {}), +- 'verification-complete', (_, ...args) => this._onVerificationComplete(...args), +- this); +- +- this._userVerifierChoiceList?.connectObject( +- 'choice-query', (_, ...args) => this._onChoiceListQuery(...args), +- this); +- +- this._userVerifierCustomJSON?.connectObject( +- 'request', (_, ...args) => this._onCustomJSONRequest(...args), +- this); ++ this._userVerifierConnectionSignalIds = []; ++ let id = this._userVerifier.get_connection().connect('closed', ++ () => this._clearUserVerifier()); ++ this._userVerifierConnectionSignalIds.push(id); ++ ++ this._userVerifierSignalIds = []; ++ id = this._userVerifier.connect('info', ++ (_, ...args) => this._onInfo(...args)); ++ this._userVerifierSignalIds.push(id); ++ id = this._userVerifier.connect('problem', ++ (_, ...args) => this._onProblem(...args)); ++ this._userVerifierSignalIds.push(id); ++ id = this._userVerifier.connect('info-query', ++ (_, ...args) => this._onInfoQuery(...args)); ++ this._userVerifierSignalIds.push(id); ++ id = this._userVerifier.connect('secret-info-query', ++ (_, ...args) => this._onSecretInfoQuery(...args)); ++ this._userVerifierSignalIds.push(id); ++ id = this._userVerifier.connect('conversation-started', ++ (_, ...args) => this._onConversationStarted(...args)); ++ this._userVerifierSignalIds.push(id); ++ id = this._userVerifier.connect('conversation-stopped', ++ (_, ...args) => this._onConversationStopped(...args)); ++ this._userVerifierSignalIds.push(id); ++ id = this._userVerifier.connect('service-unavailable', ++ (_, ...args) => this._onServiceUnavailable(...args)); ++ this._userVerifierSignalIds.push(id); ++ id = this._userVerifier.connect('reset', ++ () => this.emit('reset', {})); ++ this._userVerifierSignalIds.push(id); ++ id = this._userVerifier.connect('verification-complete', ++ (_, ...args) => this._onVerificationComplete(...args)); ++ this._userVerifierSignalIds.push(id); ++ ++ this._userVerifierChoiceListSignalIds = []; ++ if (this._userVerifierChoiceList) { ++ id = this._userVerifierChoiceList.connect('choice-query', ++ (_, ...args) => this._onChoiceListQuery(...args)); ++ this._userVerifierChoiceListSignalIds.push(id); ++ } ++ ++ this._userVerifierCustomJSONSignalIds = []; ++ if (this._userVerifierCustomJSON) { ++ id = this._userVerifierCustomJSON.connect('request', ++ (_, ...args) => this._onCustomJSONRequest(...args)); ++ this._userVerifierCustomJSONSignalIds.push(id); ++ } + } + + _onInfo(serviceName, info) { +@@ -456,6 +514,8 @@ var AuthServices = GObject.registerClass({ + + _handleClear() {} + ++ _handleDestroy() {} ++ + _handleUpdateEnabledRoles() {} + + _handleUpdateEnabledMechanisms() { +diff --git a/js/gdm/authServicesLegacy.js b/js/gdm/authServicesLegacy.js +index 0fd0e10d81..5955aeadff 100644 +--- a/js/gdm/authServicesLegacy.js ++++ b/js/gdm/authServicesLegacy.js +@@ -50,6 +50,7 @@ var AuthServicesLegacy = GObject.registerClass({ + this._updateEnabledMechanisms(); + + this._credentialManagers = {}; ++ this._credentialManagerSignalIds = {}; + this.addCredentialManager(OVirt.SERVICE_NAME, OVirt.getOVirtCredentialsManager()); + this.addCredentialManager(Vmware.SERVICE_NAME, Vmware.getVmwareCredentialsManager()); + +@@ -104,6 +105,20 @@ var AuthServicesLegacy = GObject.registerClass({ + this._selectedMechanism = null; + } + ++ _handleDestroy() { ++ this._disconnectCredentialManagers(); ++ } ++ ++ _disconnectCredentialManagers() { ++ Object.keys(this._credentialManagerSignalIds).forEach(serviceName => { ++ const signalId = this._credentialManagerSignalIds[serviceName]; ++ const credentialManager = this._credentialManagers[serviceName]; ++ if (signalId) ++ credentialManager?.disconnect(signalId); ++ }); ++ this._credentialManagerSignalIds = {}; ++ } ++ + _handleClear() { + this._smartcardInProgress = false; + this._clearFingerprintReadyTimeout(); +@@ -359,9 +374,9 @@ var AuthServicesLegacy = GObject.registerClass({ + if (credentialManager.token) + this._onCredentialManagerAuthenticated(credentialManager); + +- credentialManager.connectObject( +- 'user-authenticated', () => this._onCredentialManagerAuthenticated(credentialManager), +- this); ++ const id = credentialManager.connect('user-authenticated', ++ () => this._onCredentialManagerAuthenticated(credentialManager)); ++ this._credentialManagerSignalIds[serviceName] = id; + } + + removeCredentialManager(serviceName) { +@@ -369,7 +384,10 @@ var AuthServicesLegacy = GObject.registerClass({ + if (!credentialManager) + return; + +- credentialManager.disconnectObject(this); ++ const signalId = this._credentialManagerSignalIds[serviceName]; ++ if (signalId) ++ credentialManager.disconnect(signalId); ++ delete this._credentialManagerSignalIds[serviceName]; + delete this._credentialManagers[serviceName]; + + if (this._selectedMechanism?.serviceName === serviceName) +diff --git a/js/gdm/util.js b/js/gdm/util.js +index 17892c75e8..85de597d33 100644 +--- a/js/gdm/util.js ++++ b/js/gdm/util.js +@@ -270,6 +270,8 @@ var ShellUserVerifier = class { + + this.cancel(); + ++ this._clearAuthServices(); ++ + this._settings.run_dispose(); + this._settings = null; + } +@@ -498,31 +500,54 @@ var ShellUserVerifier = class { + } + + _clearAuthServices() { ++ this._authServicesSSSDSwitchableSignalIds?.forEach(id => ++ this._authServicesSSSDSwitchable?.disconnect(id)); ++ this._authServicesSSSDSwitchableSignalIds = []; + this._authServicesSSSDSwitchable?.destroy(); + this._authServicesSSSDSwitchable = null; ++ ++ this._authServicesLegacySignalIds?.forEach(id => ++ this._authServicesLegacy?.disconnect(id)); ++ this._authServicesLegacySignalIds = []; + this._authServicesLegacy?.destroy(); + this._authServicesLegacy = null; + } + + _connectAuthServices() { +- [ +- this._authServicesSSSDSwitchable, +- this._authServicesLegacy, +- ].forEach(authServices => { +- authServices?.connectObject( +- 'ask-question', (_, ...args) => this.emit('ask-question', ...args), +- 'queue-message', (_, ...args) => this._queueMessage(...args), +- 'queue-priority-message', (_, ...args) => this._queuePriorityMessage(...args), +- 'wait-pending-messages', (_, ...args) => this._waitPendingMessages(...args), +- 'filter-messages', (_, ...args) => this._filterServiceMessages(...args), +- 'verification-failed', (_, ...args) => this._verificationFailed(...args), +- 'verification-complete', (_, ...args) => this.emit('verification-complete', ...args), +- 'reset', (_, ...args) => this.emit('reset', ...args), +- 'show-choice-list', (_, ...args) => this.emit('show-choice-list', ...args), +- 'mechanisms-changed', (_, ...args) => this._onMechanismsChanged(...args), +- 'web-login', (_, ...args) => this.emit('web-login', ...args), +- this); +- }); ++ const connectSignals = authServices => { ++ if (!authServices) ++ return []; ++ ++ return [ ++ authServices.connect('ask-question', ++ (_, ...args) => this.emit('ask-question', ...args)), ++ authServices.connect('queue-message', ++ (_, ...args) => this._queueMessage(...args)), ++ authServices.connect('queue-priority-message', ++ (_, ...args) => this._queuePriorityMessage(...args)), ++ authServices.connect('wait-pending-messages', ++ (_, ...args) => this._waitPendingMessages(...args)), ++ authServices.connect('filter-messages', ++ (_, ...args) => this._filterServiceMessages(...args)), ++ authServices.connect('verification-failed', ++ (_, ...args) => this._verificationFailed(...args)), ++ authServices.connect('verification-complete', ++ (_, ...args) => this.emit('verification-complete', ...args)), ++ authServices.connect('reset', ++ (_, ...args) => this.emit('reset', ...args)), ++ authServices.connect('show-choice-list', ++ (_, ...args) => this.emit('show-choice-list', ...args)), ++ authServices.connect('mechanisms-changed', ++ (_, ...args) => this._onMechanismsChanged(...args)), ++ authServices.connect('web-login', ++ (_, ...args) => this.emit('web-login', ...args)), ++ ]; ++ }; ++ ++ this._authServicesSSSDSwitchableSignalIds = ++ connectSignals(this._authServicesSSSDSwitchable); ++ this._authServicesLegacySignalIds = ++ connectSignals(this._authServicesLegacy); + } + + _verificationFailed(serviceName, canRetry) { +diff --git a/js/gdm/webLogin.js b/js/gdm/webLogin.js +index 9c858f7269..26da94b624 100644 +--- a/js/gdm/webLogin.js ++++ b/js/gdm/webLogin.js +@@ -182,7 +182,14 @@ var WebLoginDialog = GObject.registerClass({ + } + + _updateButtons(buttons) { ++ this._buttonBox.get_children().forEach(b => { ++ if (b._clickedSignalId) { ++ b.disconnect(b._clickedSignalId); ++ b._clickedSignalId = 0; ++ } ++ }); + this._buttonBox.destroy_all_children(); ++ + this._cancelButton = this._addButton({ + label: _('Cancel'), + action: () => this.emit('cancel'), +@@ -202,11 +209,11 @@ var WebLoginDialog = GObject.registerClass({ + }), + }); + +- button.connectObject('clicked', () => { ++ button._clickedSignalId = button.connect('clicked', () => { + if (b.needsLoading) + this._startLoading(); + b.action(); +- }, this); ++ }); + + button.default = b.default; + +-- +2.51.0 + + +From bcf392cbdac51d1bb1fb2e161c674bc4bd3286a6 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 26 Dec 2025 15:12:16 +0100 +Subject: [PATCH 06/30] gdm: Use promisify adding two params + +This is how it works in this old version +--- + js/gdm/authServices.js | 12 +++++------- + js/gdm/util.js | 7 ++++++- + js/gdm/webLogin.js | 2 +- + js/ui/qrCode.js | 2 +- + 4 files changed, 13 insertions(+), 10 deletions(-) + +diff --git a/js/gdm/authServices.js b/js/gdm/authServices.js +index 88462cf17e..3cb1985817 100644 +--- a/js/gdm/authServices.js ++++ b/js/gdm/authServices.js +@@ -9,13 +9,11 @@ const PasskeyDeviceManager = imports.misc.passkeyDeviceManager; + const SmartcardManager = imports.misc.smartcardManager; + const Util = imports.gdm.util; + +-Gio._promisify(Gdm.Client.prototype, 'open_reauthentication_channel'); +-Gio._promisify(Gdm.Client.prototype, 'get_user_verifier'); +-Gio._promisify(Gdm.UserVerifierProxy.prototype, 'call_begin_verification_for_user'); +-Gio._promisify(Gdm.UserVerifierProxy.prototype, 'call_begin_verification'); +-Gio._promisify(Gdm.UserVerifierProxy.prototype, 'call_answer_query'); +-Gio._promisify(Gdm.UserVerifierChoiceListProxy.prototype, 'call_select_choice'); +-Gio._promisify(Gdm.UserVerifierCustomJSONProxy.prototype, 'call_reply'); ++Gio._promisify(Gdm.UserVerifierProxy.prototype, 'call_begin_verification_for_user', 'call_begin_verification_for_user_finish'); ++Gio._promisify(Gdm.UserVerifierProxy.prototype, 'call_begin_verification', 'call_begin_verification_finish'); ++Gio._promisify(Gdm.UserVerifierProxy.prototype, 'call_answer_query', 'call_answer_query_finish'); ++Gio._promisify(Gdm.UserVerifierChoiceListProxy.prototype, 'call_select_choice', 'call_select_choice_finish'); ++Gio._promisify(Gdm.UserVerifierCustomJSONProxy.prototype, 'call_reply', 'call_reply_finish'); + + var AuthServices = GObject.registerClass({ + Signals: { +diff --git a/js/gdm/util.js b/js/gdm/util.js +index 85de597d33..4aeec5b02a 100644 +--- a/js/gdm/util.js ++++ b/js/gdm/util.js +@@ -3,7 +3,7 @@ + DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor, + InitError, isSelectable, getIconName */ + +-const { Clutter, Gio, GLib } = imports.gi; ++const { Clutter, Gdm, Gio, GLib } = imports.gi; + const Signals = imports.signals; + + const Batch = imports.gdm.batch; +@@ -13,6 +13,11 @@ const Params = imports.misc.params; + const { AuthServicesLegacy } = imports.gdm.authServicesLegacy; + const { AuthServicesSSSDSwitchable } = imports.gdm.authServicesSSSDSwitchable; + ++Gio._promisify(Gdm.Client.prototype, 'open_reauthentication_channel', 'open_reauthentication_channel_finish'); ++Gio._promisify(Gdm.Client.prototype, 'get_user_verifier', 'get_user_verifier_finish'); ++Gio._promisify(Gdm.UserVerifierProxy.prototype, 'call_begin_verification_for_user', 'call_begin_verification_for_user_finish'); ++Gio._promisify(Gdm.UserVerifierProxy.prototype, 'call_begin_verification', 'call_begin_verification_finish'); ++ + var FADE_ANIMATION_TIME = 160; + var CLONE_FADE_ANIMATION_TIME = 250; + +diff --git a/js/gdm/webLogin.js b/js/gdm/webLogin.js +index 26da94b624..f4972144fa 100644 +--- a/js/gdm/webLogin.js ++++ b/js/gdm/webLogin.js +@@ -9,7 +9,7 @@ const Params = imports.misc.params; + const { Spinner } = imports.ui.animation; + const { QrCode } = imports.ui.qrCode; + +-Gio._promisify(GnomeQR, 'generate_qr_code_async'); ++Gio._promisify(GnomeQR, 'generate_qr_code_async', 'generate_qr_code_finish'); + + const QR_CODE_SIZE = 150; + const WEB_LOGIN_SPINNER_SIZE = 35; +diff --git a/js/ui/qrCode.js b/js/ui/qrCode.js +index b53508c2dd..547ad7d153 100644 +--- a/js/ui/qrCode.js ++++ b/js/ui/qrCode.js +@@ -2,7 +2,7 @@ + + const { Clutter, Cogl, Gio, GnomeQR, GObject, St } = imports.gi; + +-Gio._promisify(GnomeQR, 'generate_qr_code_async'); ++Gio._promisify(GnomeQR, 'generate_qr_code_async', 'generate_qr_code_finish'); + + const QR_CODE_DEFAULT_SIZE = 150; + const QR_CODE_TRANSPARENT_COLOR = new GnomeQR.Color({alpha: 0}); +-- +2.51.0 + + +From 74a94cb0c34413d45ef2e1d599822c25c434e1b8 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 27 Mar 2026 13:52:50 +0100 +Subject: [PATCH 07/30] gdm: Use timeout_add_seconds instead of once + +_once type doesn't exist in this old glib version +--- + js/gdm/authServices.js | 7 +++++-- + js/gdm/authServicesSSSDSwitchable.js | 3 ++- + 2 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/js/gdm/authServices.js b/js/gdm/authServices.js +index 3cb1985817..003b4836a6 100644 +--- a/js/gdm/authServices.js ++++ b/js/gdm/authServices.js +@@ -277,8 +277,11 @@ var AuthServices = GObject.registerClass({ + + _waitPendingMessages() { + const cancellable = this._cancellable; +- const timeoutId = GLib.timeout_add_seconds_once(GLib.PRIORITY_DEFAULT, 10, +- () => cancellable.cancel()); ++ const timeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 10, ++ () => { ++ cancellable.cancel(); ++ return GLib.SOURCE_REMOVE; ++ }); + + const {promise, resolve, reject} = Promise.withResolvers(); + const task = Gio.Task.new(this, cancellable, () => { +diff --git a/js/gdm/authServicesSSSDSwitchable.js b/js/gdm/authServicesSSSDSwitchable.js +index 601f4cd295..48c1c020fb 100644 +--- a/js/gdm/authServicesSSSDSwitchable.js ++++ b/js/gdm/authServicesSSSDSwitchable.js +@@ -195,7 +195,7 @@ var AuthServicesSSSDSwitchable = GObject.registerClass({ + if (!timeout) + return; + +- this._webLoginTimeoutId = GLib.timeout_add_seconds_once(GLib.PRIORITY_DEFAULT, ++ this._webLoginTimeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, + timeout, () => { + if (this._selectedMechanism?.role !== Constants.WEB_LOGIN_ROLE_NAME) + webLoginMechanism.needsRefresh = true; +@@ -203,6 +203,7 @@ var AuthServicesSSSDSwitchable = GObject.registerClass({ + this.emit('reset', {softReset: true}); + + this._webLoginTimeoutId = 0; ++ return GLib.SOURCE_REMOVE; + }); + } + +-- +2.51.0 + + +From aff9353c2f80c15111f9b7f772b5fa45277251fd Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 27 Mar 2026 13:56:56 +0100 +Subject: [PATCH 08/30] gdm: fix Promise.withResolvers + +Use manual new Promise to extract them. +--- + js/gdm/authServices.js | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/js/gdm/authServices.js b/js/gdm/authServices.js +index 003b4836a6..00d19004f3 100644 +--- a/js/gdm/authServices.js ++++ b/js/gdm/authServices.js +@@ -283,7 +283,11 @@ var AuthServices = GObject.registerClass({ + return GLib.SOURCE_REMOVE; + }); + +- const {promise, resolve, reject} = Promise.withResolvers(); ++ let resolve, reject; ++ const promise = new Promise((_resolve, _reject) => { ++ resolve = _resolve; ++ reject = _reject; ++ }); + const task = Gio.Task.new(this, cancellable, () => { + try { + const res = task.propagate_boolean(); +-- +2.51.0 + + +From fdad9ac3e5bb6699d835d23a50033244fefc6907 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 12 Dec 2025 19:33:38 +0100 +Subject: [PATCH 09/30] data/theme: Add new icons to theme gresource + +They were in a different icons gresource that doesn't exist in 40 vesion +--- + data/gnome-shell-theme.gresource.xml | 2 ++ + data/icons/meson.build | 1 + + 2 files changed, 3 insertions(+) + +diff --git a/data/gnome-shell-theme.gresource.xml b/data/gnome-shell-theme.gresource.xml +index 7857f4407b..4f697f88df 100644 +--- a/data/gnome-shell-theme.gresource.xml ++++ b/data/gnome-shell-theme.gresource.xml +@@ -4,6 +4,8 @@ + calendar-today.svg + carousel-arrow-next-24-symbolic.svg + carousel-arrow-back-24-symbolic.svg ++ ../icons/scalable/status/fingerprint-auth-symbolic.svg ++ ../icons/scalable/status/vcard-symbolic.svg + checkbox-focused.svg + checkbox-off-focused.svg + checkbox-off.svg +diff --git a/data/icons/meson.build b/data/icons/meson.build +index eff6e4b530..44e2b164a3 100644 +--- a/data/icons/meson.build ++++ b/data/icons/meson.build +@@ -1 +1,2 @@ + install_subdir('hicolor', install_dir: icondir) ++install_subdir('scalable', install_dir: icondir) +-- +2.51.0 + + +From e0b648ce306e29ecb754711700d0b95aa4ed8769 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Mon, 15 Dec 2025 13:34:27 +0100 +Subject: [PATCH 10/30] gdm/authmenuButton: Use None ornament + +NOT_DOT doesn't exist. +--- + js/gdm/authMenuButton.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/gdm/authMenuButton.js b/js/gdm/authMenuButton.js +index e58c331b45..9a02b0cb05 100644 +--- a/js/gdm/authMenuButton.js ++++ b/js/gdm/authMenuButton.js +@@ -236,7 +236,7 @@ var AuthMenuButton = GObject.registerClass({ + + _updateOrnament() { + for (const menuItem of this._items.values()) +- menuItem.setOrnament(PopupMenu.Ornament.NO_DOT); ++ menuItem.setOrnament(PopupMenu.Ornament.NONE); + + for (const itemKey of this._activeItems) { + const menuItem = this._getMenuItem(JSON.parse(itemKey)); +-- +2.51.0 + + +From 6a246865fb5a2da8724aafea34995d5aab81c263 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 12 Dec 2025 20:33:15 +0100 +Subject: [PATCH 11/30] gdm/authMenuButton: Add proper style classes to button + +--- + js/gdm/authMenuButton.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/gdm/authMenuButton.js b/js/gdm/authMenuButton.js +index 9a02b0cb05..64dcf1a3f4 100644 +--- a/js/gdm/authMenuButton.js ++++ b/js/gdm/authMenuButton.js +@@ -146,7 +146,7 @@ var AuthMenuButton = GObject.registerClass({ + params.sectionOrder ??= []; + super._init({ + ...params, +- style_class: 'login-dialog-button login-dialog-auth-menu-button', ++ style_class: 'modal-dialog-button button login-dialog-auth-menu-button', + reactive: true, + track_hover: true, + can_focus: true, +-- +2.51.0 + + +From 11ad6201e3c032674d4e58f44d9fea9820fb4234 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 2 Jan 2026 14:48:42 +0100 +Subject: [PATCH 12/30] gdm/authMenuButton: Add style to indicator description + +This is needed to set its color in the lockscreen. +--- + data/theme/gnome-shell-sass/widgets/_login-dialog.scss | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss +index f3aeed4bf3..29c6803082 100644 +--- a/data/theme/gnome-shell-sass/widgets/_login-dialog.scss ++++ b/data/theme/gnome-shell-sass/widgets/_login-dialog.scss +@@ -123,6 +123,10 @@ $_gdm_fg: $osd_fg_color; + } + } + ++.login-dialog-auth-menu-button-indicator-description { ++ color: $osd_fg_color; ++} ++ + .login-dialog-bottom-button-group { + padding: 32px; + spacing: 16px; +-- +2.51.0 + + +From d7c9b074f8cb0bf2295daa3a518776cae023a039 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 27 Mar 2026 17:57:03 +0100 +Subject: [PATCH 13/30] gdm/authMenuButton: Add no-op () instead of null + +--- + js/gdm/authMenuButton.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/gdm/authMenuButton.js b/js/gdm/authMenuButton.js +index 64dcf1a3f4..a211ebe0d8 100644 +--- a/js/gdm/authMenuButton.js ++++ b/js/gdm/authMenuButton.js +@@ -475,7 +475,7 @@ class AuthMenuButtonIndicator extends AuthMenuButton { + this._descriptionLabel, 'visible', + GObject.BindingFlags.SYNC_CREATE, + (bind, source) => [true, !!source], +- null); ++ () => {}); + container.add_child(this._descriptionLabel); + + return container; +-- +2.51.0 + + +From 5fb0f23fda55d433a08db68920ed896cdf9e3d08 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Thu, 2 Apr 2026 19:38:34 +0200 +Subject: [PATCH 14/30] gdm/authMenuButton: Ensure visible of description is + properly binded to + +its text +--- + js/gdm/authMenuButton.js | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/js/gdm/authMenuButton.js b/js/gdm/authMenuButton.js +index a211ebe0d8..3dafd87630 100644 +--- a/js/gdm/authMenuButton.js ++++ b/js/gdm/authMenuButton.js +@@ -510,6 +510,7 @@ class AuthMenuButtonIndicator extends AuthMenuButton { + updateDescriptionLabel() { + const [item] = this._items.size === 1 ? this.getItems() : []; + this._descriptionLabel.text = item?.description ?? ''; ++ this._descriptionLabel.visible = !!this._descriptionLabel.text; + } + + // Override to force visibility even when there's only one item +-- +2.51.0 + + +From e9abaf90b24df1f98108ab48c5d00ec87a6d5c9e Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 27 Mar 2026 13:38:06 +0100 +Subject: [PATCH 15/30] Fix foreach in wrong type + +Map.keys() returns an iterator which doesn't have .forEach() in older +SpiderMonkey. Wrapped it with [...] to convert to an array first. +--- + js/gdm/authMenuButton.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/gdm/authMenuButton.js b/js/gdm/authMenuButton.js +index 3dafd87630..393dc5da4b 100644 +--- a/js/gdm/authMenuButton.js ++++ b/js/gdm/authMenuButton.js +@@ -307,7 +307,7 @@ var AuthMenuButton = GObject.registerClass({ + this._items.delete(itemKey); + }); + +- this._sections.keys().forEach(sectionName => { ++ [...this._sections.keys()].forEach(sectionName => { + const itemsInSection = this._findItems({sectionName}); + if (itemsInSection.length === 0) { + const section = this._sections.get(sectionName); +-- +2.51.0 + + +From 2e28cf05ef0033c42c6bb54839184701718bf48a Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 27 Mar 2026 12:56:24 +0100 +Subject: [PATCH 16/30] Change ??= by if statement + +This old js version doesn't support it. +--- + js/gdm/authMenuButton.js | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/js/gdm/authMenuButton.js b/js/gdm/authMenuButton.js +index 393dc5da4b..c5e864c686 100644 +--- a/js/gdm/authMenuButton.js ++++ b/js/gdm/authMenuButton.js +@@ -143,7 +143,8 @@ var AuthMenuButton = GObject.registerClass({ + }, + }, class AuthMenuButton extends St.Button { + _init(params) { +- params.sectionOrder ??= []; ++ if (params.sectionOrder === undefined || params.sectionOrder === null) ++ params.sectionOrder = []; + super._init({ + ...params, + style_class: 'modal-dialog-button button login-dialog-auth-menu-button', +@@ -449,7 +450,8 @@ var AuthMenuButton = GObject.registerClass({ + var AuthMenuButtonIndicator = GObject.registerClass( + class AuthMenuButtonIndicator extends AuthMenuButton { + _init(params = {}) { +- params.readOnly ??= true; ++ if (params.readOnly === undefined || params.readOnly === null) ++ params.readOnly = true; + super._init(params); + + this.add_style_class_name('login-dialog-auth-menu-button-indicator'); +-- +2.51.0 + + +From f55cd19afd2028dda3af2bb1490c13ca06caf759 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 12 Dec 2025 18:26:49 +0100 +Subject: [PATCH 17/30] gdm/util: Don't return a promise in + wait-pending-messages + +The callback of wait-pending-messages was returning a Promise. + +That was causing the error "Could not guess unspecified GValue type". +Avoid it embracing the callback with {} so the return isn't passed. +--- + js/gdm/util.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/gdm/util.js b/js/gdm/util.js +index 4aeec5b02a..629ba1b629 100644 +--- a/js/gdm/util.js ++++ b/js/gdm/util.js +@@ -531,7 +531,7 @@ var ShellUserVerifier = class { + authServices.connect('queue-priority-message', + (_, ...args) => this._queuePriorityMessage(...args)), + authServices.connect('wait-pending-messages', +- (_, ...args) => this._waitPendingMessages(...args)), ++ (_, ...args) => {this._waitPendingMessages(...args);}), + authServices.connect('filter-messages', + (_, ...args) => this._filterServiceMessages(...args)), + authServices.connect('verification-failed', +-- +2.51.0 + + +From 179858faf126b93d734452ebb522383b07bf0a1d Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 12 Dec 2025 16:26:57 +0100 +Subject: [PATCH 18/30] gdm/authPrompt: Fixes + +1. Don't set directly icon_name in StButton +2. Guard setting text on entries on clear +3. Use Const instead of GdmUtil to get standard service_names +4. Inputwell was an extra container, in old version directly store in + this. +5. On setChoiceList, don't hide _message. This keeps the same layout + avoiding height increase of mainBox +6. On vfunc_key_press_event, handle event more explicitly instead of + just calling event. +--- + js/gdm/authPrompt.js | 27 ++++++++++++++++++--------- + 1 file changed, 18 insertions(+), 9 deletions(-) + +diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js +index 6996dac18b..7f683b2ba0 100644 +--- a/js/gdm/authPrompt.js ++++ b/js/gdm/authPrompt.js +@@ -146,8 +146,17 @@ var AuthPrompt = GObject.registerClass({ + if (keyPressEvent.keyval == Clutter.KEY_Escape) + this.cancel(); + +- if (this._preemptiveInput && !this._pendingActivate) +- return this._entry.clutter_text.event(keyPressEvent, false); ++ if (this._preemptiveInput && !this._pendingActivate) { ++ const unichar = keyPressEvent.unicode_value; ++ if (keyPressEvent.keyval === Clutter.KEY_Return && ++ this._entry.clutter_text.text) { ++ this._pendingActivate = true; ++ } else if (GLib.unichar_isprint(unichar)) { ++ this._entry.clutter_text.insert_text(unichar, ++ this._entry.clutter_text.cursor_position); ++ } ++ return Clutter.EVENT_STOP; ++ } + + return super.vfunc_key_press_event(keyPressEvent); + } +@@ -200,7 +209,7 @@ var AuthPrompt = GObject.registerClass({ + }, + }); + }); +- this._inputWell.add_child(this._authList); ++ this.add_child(this._authList); + + // Use an insensitive button for the auth list title + // to get the same style as the auth list buttons +@@ -291,7 +300,7 @@ var AuthPrompt = GObject.registerClass({ + button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, + reactive: true, + can_focus: false, +- icon_name: 'go-next-symbolic', ++ child: new St.Icon({icon_name: 'go-next-symbolic'}), + }); + this._nextButton.connect('clicked', () => this._activateNext()); + this._nextButton.add_style_pseudo_class('default'); +@@ -322,7 +331,7 @@ var AuthPrompt = GObject.registerClass({ + } + }); + this._webLoginDialog.connect('loading', () => this.emit('loading', this._webLoginDialog.isLoading)); +- this._inputWell.add_child(this._webLoginDialog); ++ this.add_child(this._webLoginDialog); + } + + _updateShowPasswordIcon() { +@@ -638,8 +647,10 @@ var AuthPrompt = GObject.registerClass({ + }); + + if (!reuseEntryText) { +- this._entry.text = ''; +- this._inactiveEntry.text = ''; ++ if (this._entry) ++ this._entry.text = ''; ++ if (this._inactiveEntry) ++ this._inactiveEntry.text = ''; + } + + this._entryArea.hide(); +@@ -712,8 +723,6 @@ var AuthPrompt = GObject.registerClass({ + } + + this._entryArea.hide(); +- if (this._message.text === '') +- this._message.hide(); + this._fadeInElement(this._authList); + } + +-- +2.51.0 + + +From bf8ecd9f1dec3a58c9734ae0b6bfb5ab6f7e0e0d Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 12 Dec 2025 18:48:48 +0100 +Subject: [PATCH 19/30] gdm/authList: Use vertical instead of orientation + +orientation isn't a valid property for St.BoxLayout +--- + js/gdm/authList.js | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/js/gdm/authList.js b/js/gdm/authList.js +index 6eb34f6d97..b5072fe945 100644 +--- a/js/gdm/authList.js ++++ b/js/gdm/authList.js +@@ -32,7 +32,7 @@ const ItemIconPopup = class extends PopupMenu.PopupMenu { + this.actor.add_style_class_name('login-dialog-item-icon-popup'); + + const labels = new St.BoxLayout({ +- orientation: Clutter.Orientation.VERTICAL, ++ vertical: true, + style_class: 'login-dialog-item-icon-popup-labels', + }); + labels.add_child(new St.Label({text: title})); +@@ -95,7 +95,7 @@ const AuthListItem = GObject.registerClass({ + x_expand: true, + }); + this._labelBox = new St.BoxLayout({ +- orientation: Clutter.Orientation.VERTICAL, ++ vertical: true, + y_align: Clutter.ActorAlign.CENTER, + x_expand: true, + }); +@@ -171,7 +171,7 @@ var AuthList = GObject.registerClass({ + }, class AuthList extends St.BoxLayout { + _init() { + super._init({ +- orientation: Clutter.Orientation.VERTICAL, ++ vertical: true, + style_class: 'login-dialog-auth-list-layout', + y_align: Clutter.ActorAlign.CENTER, + x_expand: true, +-- +2.51.0 + + +From 2c10304549a203ea1e5fca2ad6e08e0ee5b0f701 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 27 Mar 2026 17:47:17 +0100 +Subject: [PATCH 20/30] gdm/authList: Use St.Icon instead of iconName as + property + +--- + js/gdm/authList.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/gdm/authList.js b/js/gdm/authList.js +index b5072fe945..0c8ef1f18d 100644 +--- a/js/gdm/authList.js ++++ b/js/gdm/authList.js +@@ -62,7 +62,7 @@ class ItemIcon extends St.Button { + _init(iconName, iconTitle, iconSubtitle) { + super._init({ + style_class: 'login-dialog-item-icon', +- iconName, ++ child: new St.Icon({icon_name: iconName}), + }); + + this._popup = new ItemIconPopup(this, iconTitle, iconSubtitle); +-- +2.51.0 + + +From 480c3f08428161c3f5ef2e85d7ddc7e9a0c42737 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 12 Dec 2025 19:02:04 +0100 +Subject: [PATCH 21/30] gdm/loginDialog: Use propper icon name for + authMenuButton + +--- + js/gdm/loginDialog.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js +index f59663401b..ab5b9c3d77 100644 +--- a/js/gdm/loginDialog.js ++++ b/js/gdm/loginDialog.js +@@ -445,7 +445,7 @@ var LoginDialog = GObject.registerClass({ + _createAuthMenuButton() { + this._authMenuButton = new AuthMenuButton.AuthMenuButton({ + title: _('Login Options'), +- iconName: 'cog-wheel-symbolic', ++ iconName: 'emblem-system-symbolic', + sectionOrder: [_PRIMARY_LOGIN_METHOD_SECTION_NAME, _SESSION_TYPE_SECTION_NAME], + }); + this._authMenuButton.updateSensitivity(false); +-- +2.51.0 + + +From 56de4883ea483307607d148e2880da220cf782c5 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Wed, 1 Apr 2026 13:05:30 +0200 +Subject: [PATCH 22/30] gdm/LoginDialog: Reduce min height of authprompt + +authprompt is smaller so min height has to be smaller +--- + js/gdm/loginDialog.js | 2 +- + js/ui/unlockDialog.js | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js +index ab5b9c3d77..cdf6f23e2d 100644 +--- a/js/gdm/loginDialog.js ++++ b/js/gdm/loginDialog.js +@@ -34,7 +34,7 @@ const UserWidget = imports.ui.userWidget; + + const _FADE_ANIMATION_TIME = 250; + const _SCROLL_ANIMATION_TIME = 500; +-const _FIXED_TOP_ACTOR_HEIGHT = 400; ++const _FIXED_TOP_ACTOR_HEIGHT = 300; + const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; + const _PRIMARY_LOGIN_METHOD_SECTION_NAME = _('Login Options'); + const _SESSION_TYPE_SECTION_NAME = _('Session Type'); +diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js +index 654959190e..477edbe8fd 100644 +--- a/js/ui/unlockDialog.js ++++ b/js/ui/unlockDialog.js +@@ -32,7 +32,7 @@ const BLUR_SIGMA = 60; + + const SUMMARY_ICON_SIZE = 32; + +-const FIXED_PROMPT_HEIGHT = 400; ++const FIXED_PROMPT_HEIGHT = 300; + + var NotificationsBox = GObject.registerClass({ + Signals: { 'wake-up-screen': {} }, +-- +2.51.0 + + +From 074089190aad31dc52f4da9748a2bda7cb04f239 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 12 Dec 2025 16:21:02 +0100 +Subject: [PATCH 23/30] gdm/webLogin: Some fixes for backport + +1. Use connect with notify::reactive because bind_property_full is not available +2. Use vertical property because orientation isn't available +3. Set '' as the default value for message +--- + js/gdm/webLogin.js | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/js/gdm/webLogin.js b/js/gdm/webLogin.js +index f4972144fa..d2e947f646 100644 +--- a/js/gdm/webLogin.js ++++ b/js/gdm/webLogin.js +@@ -144,14 +144,13 @@ var WebLoginDialog = GObject.registerClass({ + y_expand: true, + visible: false, + }); +- this.bind_property_full('reactive', +- this, 'opacity', +- GObject.BindingFlags.SYNC_CREATE, +- (_bind, source) => [true, source ? 255 : 128], +- null); ++ this.connect('notify::reactive', () => { ++ this.opacity = this.reactive ? 255 : 128; ++ }); ++ this.opacity = this.reactive ? 255 : 128; + + this._contentBox = new St.BoxLayout({ +- orientation: Clutter.Orientation.VERTICAL, ++ vertical: true, + x_expand: true, + y_expand: true, + }); +@@ -161,7 +160,7 @@ var WebLoginDialog = GObject.registerClass({ + this._contentBox.add_child(this._webLoginPrompt); + + this._buttonBox = new St.BoxLayout({ +- orientation: Clutter.Orientation.HORIZONTAL, ++ vertical: false, + x_align: Clutter.ActorAlign.CENTER, + x_expand: true, + }); +@@ -290,7 +289,7 @@ var WebLoginIntro = GObject.registerClass( + class WebLoginIntro extends St.Button { + _init(params) { + const {message} = Params.parse(params, { +- message: null, ++ message: '', + }); + + const label = new St.Label({ +-- +2.51.0 + + +From 908cce536d7933bb09138e4022af46813fe82092 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Mon, 15 Dec 2025 13:36:31 +0100 +Subject: [PATCH 24/30] gdm/webLogin: Vertically center align labels of buttons + +--- + js/gdm/webLogin.js | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/js/gdm/webLogin.js b/js/gdm/webLogin.js +index d2e947f646..062ad5f309 100644 +--- a/js/gdm/webLogin.js ++++ b/js/gdm/webLogin.js +@@ -205,6 +205,7 @@ var WebLoginDialog = GObject.registerClass({ + child: new St.Label({ + text: b.label, + style_class: 'web-login-button-label', ++ y_align: Clutter.ActorAlign.CENTER, + }), + }); + +@@ -295,6 +296,7 @@ class WebLoginIntro extends St.Button { + const label = new St.Label({ + text: message, + style_class: 'web-login-button-label', ++ y_align: Clutter.ActorAlign.CENTER, + }); + + super._init({ +@@ -304,6 +306,7 @@ class WebLoginIntro extends St.Button { + reactive: true, + can_focus: true, + child: label, ++ y_align: Clutter.ActorAlign.CENTER, + }); + } + +-- +2.51.0 + + +From 0e08e9a99057f24e3f8e57d66115d8368d00f2d0 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Mon, 15 Dec 2025 13:53:08 +0100 +Subject: [PATCH 25/30] gdm/webLogin: Set data to qr texture with the right + args + +This old version has a different signature for setting text data. +--- + js/ui/qrCode.js | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/js/ui/qrCode.js b/js/ui/qrCode.js +index 547ad7d153..adf6e40051 100644 +--- a/js/ui/qrCode.js ++++ b/js/ui/qrCode.js +@@ -87,14 +87,12 @@ var QrCode = GObject.registerClass({ + GnomeQR.EccLevel.LOW, + cancellable); + +- const coglContext = global.stage.context.get_backend().get_cogl_context(); + const bpp = Cogl.pixel_format_get_bytes_per_pixel(Cogl.PixelFormat.RGBA_8888, 0); + const rowStride = qrSize * bpp; + + const content = St.ImageContent.new_with_preferred_size(qrSize, qrSize); +- content.set_bytes( +- coglContext, +- pixelData, ++ content.set_data( ++ pixelData.get_data(), + Cogl.PixelFormat.RGBA_8888, + qrSize, + qrSize, +-- +2.51.0 + + +From 97ac6d29ff531f15dcadd907164ae5c4609bb016 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 26 Dec 2025 12:30:43 +0100 +Subject: [PATCH 26/30] gdm/webLogin: Make spinner size 16 + +In old versions spinner icon would be duplicated to fill the space +instead of scaled. +--- + js/gdm/webLogin.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/gdm/webLogin.js b/js/gdm/webLogin.js +index 062ad5f309..ac79816699 100644 +--- a/js/gdm/webLogin.js ++++ b/js/gdm/webLogin.js +@@ -12,7 +12,7 @@ const { QrCode } = imports.ui.qrCode; + Gio._promisify(GnomeQR, 'generate_qr_code_async', 'generate_qr_code_finish'); + + const QR_CODE_SIZE = 150; +-const WEB_LOGIN_SPINNER_SIZE = 35; ++const WEB_LOGIN_SPINNER_SIZE = 16; + const URL_LABEL_LONG_THRESHOLD = 45; + + var WebLoginPrompt = GObject.registerClass( +-- +2.51.0 + + +From 36e72660620d28929d250ee958df0eb0834a163d Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 26 Dec 2025 12:31:48 +0100 +Subject: [PATCH 27/30] gdm/unlockDialog: Use proper icon for gear + +In old versions the icon name is called 'emblem-system-symbolic' +--- + js/ui/unlockDialog.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js +index 477edbe8fd..85b512aa85 100644 +--- a/js/ui/unlockDialog.js ++++ b/js/ui/unlockDialog.js +@@ -646,7 +646,7 @@ var UnlockDialog = GObject.registerClass({ + // Login Options button + this._authMenuButton = new AuthMenuButton.AuthMenuButton({ + title: _('Login Options'), +- iconName: 'cog-wheel-symbolic', ++ iconName: 'emblem-system-symbolic', + }); + this._authMenuButton.connect('active-item-changed', () => { + const authMechanism = this._authMenuButton.getActiveItem(); +-- +2.51.0 + + +From 39d93c9d86f99e3ed46544d052ceae188e2adc25 Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 27 Mar 2026 17:53:33 +0100 +Subject: [PATCH 28/30] gdm/unlockDialog: Use vertical boolean instead + orientation + +--- + js/ui/unlockDialog.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js +index 85b512aa85..ab4141e2c3 100644 +--- a/js/ui/unlockDialog.js ++++ b/js/ui/unlockDialog.js +@@ -335,7 +335,7 @@ class UnlockDialogClock extends St.BoxLayout { + _init() { + super._init({ + style_class: 'unlock-dialog-clock', +- orientation: Clutter.Orientation.VERTICAL, ++ vertical: true, + y_align: Clutter.ActorAlign.CENTER, + }); + +-- +2.51.0 + + +From 0b4f7dcb4ec6821e38888898a8298a1e8a5e88bf Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Thu, 2 Apr 2026 18:55:31 +0200 +Subject: [PATCH 29/30] gdm/unlockDialog: Don't use timeout_add_once + +--- + js/gdm/authServicesLegacy.js | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/js/gdm/authServicesLegacy.js b/js/gdm/authServicesLegacy.js +index 5955aeadff..4c5a49effa 100644 +--- a/js/gdm/authServicesLegacy.js ++++ b/js/gdm/authServicesLegacy.js +@@ -136,12 +136,13 @@ var AuthServicesLegacy = GObject.registerClass({ + this._fingerprintReadyTimeoutId !== 0) + return; + +- this._fingerprintReadyTimeoutId = GLib.timeout_add_once( ++ this._fingerprintReadyTimeoutId = GLib.timeout_add( + GLib.PRIORITY_DEFAULT, + FINGERPRINT_READY_TIMEOUT_MS, + () => { + this._fingerprintReadyTimeoutId = 0; + this._setFingerprintReady(true); ++ return GLib.SOURCE_REMOVE; + }); + } + +-- +2.51.0 + + +From 17a21d8e27fddb369977c50e9e62de177222120b Mon Sep 17 00:00:00 2001 +From: Joan Torres Lopez +Date: Fri, 26 Dec 2025 12:34:11 +0100 +Subject: [PATCH 30/30] fingerprintManager: Update getDefaultService using + remote + +This is how async methods are called in this version. +--- + js/misc/fingerprintManager.js | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/js/misc/fingerprintManager.js b/js/misc/fingerprintManager.js +index 151e787e0b..4467e0bfa9 100644 +--- a/js/misc/fingerprintManager.js ++++ b/js/misc/fingerprintManager.js +@@ -64,23 +64,23 @@ var FingerprintManager = GObject.registerClass({ + } + + async checkReaderType(cancellable = null) { +- try { +- // Wrappers don't support null cancellable, so let's ignore it in case +- const args = cancellable ? [cancellable] : []; +- const [devicePath] = +- await this._fingerprintManagerProxy.GetDefaultDeviceAsync(...args); +- +- const fprintDeviceProxy = this._getFprintDeviceProxy(devicePath); +- await fprintDeviceProxy.init_async(GLib.PRIORITY_DEFAULT, cancellable ?? null); +- +- const fingerprintReaderKey = fprintDeviceProxy['scan-type'].toUpperCase(); +- const fingerprintReaderType = FingerprintReaderType[fingerprintReaderKey]; +- this._setFingerprintReaderType(fingerprintReaderType); +- } catch (e) { +- if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) ++ this._fingerprintManagerProxy.GetDefaultDeviceRemote((result, error) => { ++ if (error) { ++ this._handleFingerprintError(error); + return; +- this._handleFingerprintError(e); +- } ++ } ++ ++ try { ++ const [devicePath] = result; ++ const fprintDeviceProxy = this._getFprintDeviceProxy(devicePath); ++ fprintDeviceProxy.init(cancellable ?? null); ++ const fingerprintReaderKey = fprintDeviceProxy['scan-type'].toUpperCase(); ++ const fingerprintReaderType = FingerprintReaderType[fingerprintReaderKey]; ++ this._setFingerprintReaderType(fingerprintReaderType); ++ } catch (e) { ++ this._handleFingerprintError(e); ++ } ++ }); + } + + async _initFingerprintManagerProxy() { +-- +2.51.0 +