From 92ab3700f20ad3d290890fcb5c6c1a533f212ca8 Mon Sep 17 00:00:00 2001 From: Christoph Anton Mitterer Date: Fri, 19 Sep 2025 19:16:25 +0200 Subject: [PATCH 1/6] allow the Cancel button to be the default button Signed-off-by: Christoph Anton Mitterer --- js/ui/endSessionDialog.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/ui/endSessionDialog.js b/js/ui/endSessionDialog.js index 2fa71ae6c9..42f4930867 100644 --- a/js/ui/endSessionDialog.js +++ b/js/ui/endSessionDialog.js @@ -103,12 +103,13 @@ class EndSessionDialog extends ModalDialog.ModalDialog { } } - _addCancel() { + _addCancel(buttonIsDefault=false) { this.addButton({ label: _("Cancel"), action: () => { this._dialogProxy.CancelRemote(); }, + default: buttonIsDefault, key: Clutter.KEY_Escape }); } From 2f0a5589260fa76e9079a5c7448943da2dfa9480 Mon Sep 17 00:00:00 2001 From: Christoph Anton Mitterer Date: Fri, 19 Sep 2025 19:19:09 +0200 Subject: [PATCH 2/6] let `_addCancel()` return the button object and action Signed-off-by: Christoph Anton Mitterer --- js/ui/endSessionDialog.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/js/ui/endSessionDialog.js b/js/ui/endSessionDialog.js index 42f4930867..00d77be482 100644 --- a/js/ui/endSessionDialog.js +++ b/js/ui/endSessionDialog.js @@ -104,14 +104,17 @@ class EndSessionDialog extends ModalDialog.ModalDialog { } _addCancel(buttonIsDefault=false) { - this.addButton({ + let buttonAction = () => { + this._dialogProxy.CancelRemote(); + }; + let button = this.addButton({ label: _("Cancel"), - action: () => { - this._dialogProxy.CancelRemote(); - }, + action: buttonAction, default: buttonIsDefault, key: Clutter.KEY_Escape }); + + return [button, buttonAction]; } _getCapabilities(result, error) { From 756598b12d2baba9416e8a209962ce0d8fc553eb Mon Sep 17 00:00:00 2001 From: Christoph Anton Mitterer Date: Fri, 19 Sep 2025 19:33:44 +0200 Subject: [PATCH 3/6] store each button object and action This merely stores each of the button objects as well as their actions in a separate variable for later use. The assignment of `this._defaultAction` is also refactored. Signed-off-by: Christoph Anton Mitterer --- js/ui/endSessionDialog.js | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/js/ui/endSessionDialog.js b/js/ui/endSessionDialog.js index 00d77be482..b8b17607db 100644 --- a/js/ui/endSessionDialog.js +++ b/js/ui/endSessionDialog.js @@ -128,7 +128,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog { var [canSwitchUser, canStop, canRestart, canHybridSleep, canSuspend, canHibernate, canLogout] = result[0]; var content = null; - let button; + let button, buttonAction; switch(this._mode) { case DialogMode.LOGOUT: @@ -154,41 +154,45 @@ class EndSessionDialog extends ModalDialog.ModalDialog { break; case DialogMode.SHUTDOWN: - this._addCancel(); + [button, buttonAction] = this._addCancel(); if (canSuspend) { - this.addButton({ + buttonAction = () => { + this._dialogProxy.SuspendRemote(); + this.close(); + }; + button = this.addButton({ label: _("Suspend"), - action: () => { - this._dialogProxy.SuspendRemote(); - this.close(); - }, + action: buttonAction }); } if (canHibernate) { - this.addButton({ + buttonAction = this._dialogProxy.HibernateRemote.bind(this._dialogProxy); + button = this.addButton({ label: _("Hibernate"), - action: this._dialogProxy.HibernateRemote.bind(this._dialogProxy) + action: buttonAction }); } if (canRestart) { - this.addButton({ + buttonAction = this._dialogProxy.RestartRemote.bind(this._dialogProxy); + button = this.addButton({ label: _("Restart"), - action: this._dialogProxy.RestartRemote.bind(this._dialogProxy), + action: buttonAction }); } if (canStop) { - this._defaultAction = this._dialogProxy.ShutdownRemote.bind(this._dialogProxy); + buttonAction = this._dialogProxy.ShutdownRemote.bind(this._dialogProxy); button = this.addButton({ label: _("Shut Down"), - action: this._defaultAction, + action: buttonAction, destructive_action: true, default: true, }); button.grab_key_focus(); + this._defaultAction = buttonAction; } this._messageDialogContent.title = _("Shut Down"); From 04c30f0343dc2a311143daac2e53b8f332ac6515 Mon Sep 17 00:00:00 2001 From: Christoph Anton Mitterer Date: Fri, 19 Sep 2025 19:40:46 +0200 Subject: [PATCH 4/6] determine the shutdown dialog default action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reads the string array from GSesttings. While keeping the order, it filters out any values which are either completely unknown or whose action is not available (as determined by the `can*`- variables; the `cancel`-action is always available). Duplicate values don’t matter and are thus left as is. If the resulting array is empty, subscribing its first element will yield `undefined`, which is just as desired and causes no default action to be set at all. Signed-off-by: Christoph Anton Mitterer --- js/ui/endSessionDialog.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/js/ui/endSessionDialog.js b/js/ui/endSessionDialog.js index b8b17607db..7fa45123d5 100644 --- a/js/ui/endSessionDialog.js +++ b/js/ui/endSessionDialog.js @@ -60,6 +60,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog { this._inhibited = false; this._settings = new Gio.Settings({ schema_id: 'org.cinnamon.SessionManager' }); this._currentTime = this._settings.get_int('quit-time-delay'); + this._shutdownDefaultActions = this._settings.get_strv("shutdown-dialog-default-actions"); this._progressTimerId = 0; this._defaultAction = null; @@ -154,6 +155,15 @@ class EndSessionDialog extends ModalDialog.ModalDialog { break; case DialogMode.SHUTDOWN: + const allowedShutdownDefaultActions = { + "cancel": true, + "shutdown": canStop, + "restart": canRestart, + "suspend": canSuspend, + "hibernate": canHibernate + }; + let shutdownDefaultAction = this._shutdownDefaultActions.filter(a => allowedShutdownDefaultActions[a])[0]; + [button, buttonAction] = this._addCancel(); if (canSuspend) { From 251a5def28cc8488b8d1b2e78d53884ec8d3da66 Mon Sep 17 00:00:00 2001 From: Christoph Anton Mitterer Date: Fri, 19 Sep 2025 19:52:35 +0200 Subject: [PATCH 5/6] make the determined button the default one Signed-off-by: Christoph Anton Mitterer --- js/ui/endSessionDialog.js | 42 +++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/js/ui/endSessionDialog.js b/js/ui/endSessionDialog.js index 7fa45123d5..d58edc97cf 100644 --- a/js/ui/endSessionDialog.js +++ b/js/ui/endSessionDialog.js @@ -129,7 +129,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog { var [canSwitchUser, canStop, canRestart, canHybridSleep, canSuspend, canHibernate, canLogout] = result[0]; var content = null; - let button, buttonAction; + let button, buttonAction, buttonIsDefault; switch(this._mode) { case DialogMode.LOGOUT: @@ -164,45 +164,71 @@ class EndSessionDialog extends ModalDialog.ModalDialog { }; let shutdownDefaultAction = this._shutdownDefaultActions.filter(a => allowedShutdownDefaultActions[a])[0]; - [button, buttonAction] = this._addCancel(); + buttonIsDefault = (shutdownDefaultAction == "cancel"); + [button, buttonAction] = this._addCancel(buttonIsDefault); + if (buttonIsDefault) { + button.grab_key_focus(); + this._defaultAction = buttonAction; + } if (canSuspend) { + buttonIsDefault = (shutdownDefaultAction == "suspend"); buttonAction = () => { this._dialogProxy.SuspendRemote(); this.close(); }; button = this.addButton({ label: _("Suspend"), - action: buttonAction + action: buttonAction, + default: buttonIsDefault }); + if (buttonIsDefault) { + button.grab_key_focus(); + this._defaultAction = buttonAction; + } } if (canHibernate) { + buttonIsDefault = (shutdownDefaultAction == "hibernate"); buttonAction = this._dialogProxy.HibernateRemote.bind(this._dialogProxy); button = this.addButton({ label: _("Hibernate"), - action: buttonAction + action: buttonAction, + default: buttonIsDefault }); + if (buttonIsDefault) { + button.grab_key_focus(); + this._defaultAction = buttonAction; + } } if (canRestart) { + buttonIsDefault = (shutdownDefaultAction == "restart"); buttonAction = this._dialogProxy.RestartRemote.bind(this._dialogProxy); button = this.addButton({ label: _("Restart"), - action: buttonAction + action: buttonAction, + default: buttonIsDefault }); + if (buttonIsDefault) { + button.grab_key_focus(); + this._defaultAction = buttonAction; + } } if (canStop) { + buttonIsDefault = (shutdownDefaultAction == "shutdown"); buttonAction = this._dialogProxy.ShutdownRemote.bind(this._dialogProxy); button = this.addButton({ label: _("Shut Down"), action: buttonAction, destructive_action: true, - default: true, + default: buttonIsDefault }); - button.grab_key_focus(); - this._defaultAction = buttonAction; + if (buttonIsDefault) { + button.grab_key_focus(); + this._defaultAction = buttonAction; + } } this._messageDialogContent.title = _("Shut Down"); From b3f845665a2d21372fccdfe3b0b392ca7220099c Mon Sep 17 00:00:00 2001 From: Christoph Anton Mitterer Date: Fri, 19 Sep 2025 20:24:37 +0200 Subject: [PATCH 6/6] also consider restarting a destructive action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just as with shutdown, restart would loose any data where the application hasn’t installed an inhibitor or somehow else make a backup on spurious termination. Actually, one could even argue that suspend and hibernate are destructive as well (consider for example while downloading some data or burning an optical medium). Signed-off-by: Christoph Anton Mitterer --- js/ui/endSessionDialog.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/ui/endSessionDialog.js b/js/ui/endSessionDialog.js index d58edc97cf..f563db94d3 100644 --- a/js/ui/endSessionDialog.js +++ b/js/ui/endSessionDialog.js @@ -208,6 +208,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog { button = this.addButton({ label: _("Restart"), action: buttonAction, + destructive_action: true, default: buttonIsDefault }); if (buttonIsDefault) {