From f328eee88c4e700a29625e87fd6fc997a138c66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 22 Nov 2024 19:23:59 +0100 Subject: [PATCH 1/3] loginDialog: Split out getBannerText() helper The new methods will make it easier to add alternative sources for the banner text. Part-of: --- js/gdm/loginDialog.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index 27baae83ad..c3c397c0d1 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -873,11 +873,18 @@ export const LoginDialog = GObject.registerClass({ this._authPrompt.cancelButton.visible = cancelVisible; } + _getBannerText() { + const enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY); + if (!enabled) + return null; + + return this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY); + } + _updateBanner() { - let enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY); - let text = this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY); + const text = this._getBannerText(); - if (enabled && text) { + if (text) { this._bannerLabel.set_text(text); this._bannerLabel.show(); } else { -- 2.48.1 From 5f92c12c727bd447d7e539b1e6c8f3ac6ddf715a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 22 Nov 2024 19:36:42 +0100 Subject: [PATCH 2/3] loginDialog: Update banner asynchronously We will soon allow reading the banner text from a file. Prepare for that by making the method asynchronous. Part-of: --- js/gdm/loginDialog.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index c3c397c0d1..125cf299fa 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -505,9 +505,9 @@ export const LoginDialog = GObject.registerClass({ this._settings = new Gio.Settings({schema_id: GdmUtil.LOGIN_SCREEN_SCHEMA}); this._settings.connect(`changed::${GdmUtil.BANNER_MESSAGE_KEY}`, - this._updateBanner.bind(this)); + () => this._updateBanner().catch(logError)); this._settings.connect(`changed::${GdmUtil.BANNER_MESSAGE_TEXT_KEY}`, - this._updateBanner.bind(this)); + () => this._updateBanner().catch(logError)); this._settings.connect(`changed::${GdmUtil.DISABLE_USER_LIST_KEY}`, this._updateDisableUserList.bind(this)); this._settings.connect(`changed::${GdmUtil.LOGO_KEY}`, @@ -576,7 +576,7 @@ export const LoginDialog = GObject.registerClass({ this._bannerLabel.clutter_text.line_wrap = true; this._bannerLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; bannerBox.add_child(this._bannerLabel); - this._updateBanner(); + this._updateBanner().catch(logError); this._sessionMenuButton = new SessionMenuButton(); this._sessionMenuButton.connect('session-activated', @@ -873,16 +873,19 @@ export const LoginDialog = GObject.registerClass({ this._authPrompt.cancelButton.visible = cancelVisible; } - _getBannerText() { + async _getBannerText() { const enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY); if (!enabled) return null; + // placeholder + await false; + return this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY); } - _updateBanner() { - const text = this._getBannerText(); + async _updateBanner() { + const text = await this._getBannerText(); if (text) { this._bannerLabel.set_text(text); -- 2.48.1 From a73a4f8455b1374b38724a532137a9b614a7fb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 22 Nov 2024 19:17:44 +0100 Subject: [PATCH 3/3] loginDialog: Support loading banner message from file Support the new `banner-message-path` and `banner-message-source` settings, which allows loading the banner message from a path instead of GSettings. This is mainly useful for `/etc/motd` and similar mechanisms, to show the same message for both graphical and non-graphical logins. Part-of: --- js/gdm/loginDialog.js | 53 +++++++++++++++++++++++++++++++++++++++++-- js/gdm/util.js | 2 ++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index 125cf299fa..fa91615026 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -46,6 +46,8 @@ const _SCROLL_ANIMATION_TIME = 500; const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; const _CONFLICTING_SESSION_DIALOG_TIMEOUT = 60; +Gio._promisify(Gio.File.prototype, 'load_contents_async'); + export const UserListItem = GObject.registerClass({ Signals: {'activate': {}}, }, class UserListItem extends St.Button { @@ -508,6 +510,16 @@ export const LoginDialog = GObject.registerClass({ () => this._updateBanner().catch(logError)); this._settings.connect(`changed::${GdmUtil.BANNER_MESSAGE_TEXT_KEY}`, () => this._updateBanner().catch(logError)); + this._settings.connect(`changed::${GdmUtil.BANNER_MESSAGE_SOURCE_KEY}`, + () => { + if (this._updateBannerMessageFile()) + this._updateBanner().catch(logError); + }); + this._settings.connect(`changed::${GdmUtil.BANNER_MESSAGE_PATH_KEY}`, + () => { + if (this._updateBannerMessageFile()) + this._updateBanner().catch(logError); + }); this._settings.connect(`changed::${GdmUtil.DISABLE_USER_LIST_KEY}`, this._updateDisableUserList.bind(this)); this._settings.connect(`changed::${GdmUtil.LOGO_KEY}`, @@ -576,6 +588,8 @@ export const LoginDialog = GObject.registerClass({ this._bannerLabel.clutter_text.line_wrap = true; this._bannerLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; bannerBox.add_child(this._bannerLabel); + + this._updateBannerMessageFile(); this._updateBanner().catch(logError); this._sessionMenuButton = new SessionMenuButton(); @@ -873,13 +887,48 @@ export const LoginDialog = GObject.registerClass({ this._authPrompt.cancelButton.visible = cancelVisible; } + _updateBannerMessageFile() { + const path = this._settings.get_string(GdmUtil.BANNER_MESSAGE_SOURCE_KEY) === 'file' + ? this._settings.get_string(GdmUtil.BANNER_MESSAGE_PATH_KEY) + : null; + const file = path + ? Gio.File.new_for_path(path) + : null; + + if (!file && !this._bannerMessageFile) + return false; + + if (file && this._bannerMessageFile && this._bannerMessageFile.equal(file)) + return false; + + this._bannerMessageMonitor?.disconnectObject(this); + this._bannerMessageMonitor = null; + + this._bannerMessageFile = file; + + if (file) { + this._bannerMessageMonitor = file.monitor_file(Gio.FileMonitorFlags.NONE, null); + this._bannerMessageMonitor.connectObject( + 'changed', () => this._updateBanner().catch(logError), this); + } + + return true; + } + async _getBannerText() { const enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY); if (!enabled) return null; - // placeholder - await false; + if (this._bannerMessageFile) { + try { + const [contents] = await this._bannerMessageFile.load_contents_async(null); + return new TextDecoder().decode(contents); + } catch (e) { + console.error(`Failed to read banner from ${this._bannerMessageFile.get_path()}: ${e.message}`); + return null; + } + } return this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY); } diff --git a/js/gdm/util.js b/js/gdm/util.js index 1e0154f36f..f6b797c321 100644 --- a/js/gdm/util.js +++ b/js/gdm/util.js @@ -33,7 +33,9 @@ export const PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication'; export const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication'; export const SMARTCARD_AUTHENTICATION_KEY = 'enable-smartcard-authentication'; export const BANNER_MESSAGE_KEY = 'banner-message-enable'; +export const BANNER_MESSAGE_SOURCE_KEY = 'banner-message-source'; export const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text'; +export const BANNER_MESSAGE_PATH_KEY = 'banner-message-path'; export const ALLOWED_FAILURES_KEY = 'allowed-failures'; export const LOGO_KEY = 'logo'; -- 2.48.1