From 2c782ad01824166cab603076a7bbddbc514788ce Mon Sep 17 00:00:00 2001 From: Mihai Moldovan Date: Thu, 31 Aug 2023 11:58:21 +0200 Subject: settings: add shutdown-dialog-timeout integer option. Defaulting to 60, this sets the amount in seconds until the focused button is triggered in the shutdown dialog. --- data/org.ArcticaProject.arctica-greeter.gschema.xml | 4 ++++ src/settings.vala | 1 + 2 files changed, 5 insertions(+) diff --git a/data/org.ArcticaProject.arctica-greeter.gschema.xml b/data/org.ArcticaProject.arctica-greeter.gschema.xml index 28002cc..52633c5 100644 --- a/data/org.ArcticaProject.arctica-greeter.gschema.xml +++ b/data/org.ArcticaProject.arctica-greeter.gschema.xml @@ -211,5 +211,9 @@ false Whether to hide Wayland sessions. + + 60 + Time in seconds until the shutdown dialog forcefully selects the default action. Set to 0 to disable. + diff --git a/src/settings.vala b/src/settings.vala index 7e49894..16b5a82 100644 --- a/src/settings.vala +++ b/src/settings.vala @@ -73,6 +73,7 @@ public class AGSettings : Object public const string KEY_MENUBAR_ALPHA = "menubar-alpha"; public const string KEY_HIDE_X11_SESSIONS = "hide-x11-sessions"; public const string KEY_HIDE_WAYLAND_SESSIONS = "hide-wayland-sessions"; + public const string KEY_SHUTDOWN_DIALOG_TIMEOUT = "shutdown-dialog-timeout"; public static bool get_boolean (string key) { -- cgit v1.2.3 From 9b8185c782e28baff506dca6c04d494005e56afd Mon Sep 17 00:00:00 2001 From: Mihai Moldovan Date: Thu, 31 Aug 2023 11:59:58 +0200 Subject: src/shutdown-dialog.vala: remove focus_{next,prev}. They are not GTK overrides and the only consumers have been removed, so get rid of them. They only confused me. --- src/shutdown-dialog.vala | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/shutdown-dialog.vala b/src/shutdown-dialog.vala index 9c5be6e..672b776 100644 --- a/src/shutdown-dialog.vala +++ b/src/shutdown-dialog.vala @@ -361,18 +361,6 @@ public class ShutdownDialog : Gtk.Fixed set_size_request (monitor.width, monitor.height); } - public void focus_next () - { - Gtk.Window pWindow = (Gtk.Window) get_toplevel (); - pWindow.move_focus (Gtk.DirectionType.TAB_FORWARD); - } - - public void focus_prev () - { - Gtk.Window pWindow = (Gtk.Window) get_toplevel (); - pWindow.move_focus (Gtk.DirectionType.TAB_BACKWARD); - } - public void cancel () { Gtk.Window pWindow = (Gtk.Window) get_toplevel (); -- cgit v1.2.3 From 91d8d20e430551a6c53b53f403596fea1860c0f6 Mon Sep 17 00:00:00 2001 From: Mihai Moldovan Date: Thu, 31 Aug 2023 12:02:58 +0200 Subject: src/shutdown-dialog.vala: implement timer function triggering focused button. Once the shutdown dialog is created/realized/shown, a new message will show up at the bottom of the dialog signifying that the default action will be triggered automatically in a configurable amount of seconds. This message will be updated once per second, counting down. Once the countdown reaches zero, the currently focused button (if any) is automatically clicked. The message will keep showing for another 10 seconds, just in case the user removed the focus and no button is actually focused. Multiple actions will cancel the timer: - Pressing escape. - Selecting a different button via (Shift +) Tab or the left or right arrow keys. - Clicking within the dialog (but not on any button). - Closing the dialog. Fixes: https://github.com/ArcticaProject/arctica-greeter/issues/39 --- src/shutdown-dialog.vala | 108 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) diff --git a/src/shutdown-dialog.vala b/src/shutdown-dialog.vala index 672b776..6bac067 100644 --- a/src/shutdown-dialog.vala +++ b/src/shutdown-dialog.vala @@ -47,6 +47,7 @@ public class ShutdownDialog : Gtk.Fixed private const int CLOSE_OFFSET = 3; private const int BUTTON_TEXT_SPACE = 9; private const int BLUR_RADIUS = 8; + private const uint DEFAULT_ACTION_SUPPLEMENTAL_TIME = 10; private Monitor monitor; private weak Background background; @@ -55,10 +56,14 @@ public class ShutdownDialog : Gtk.Fixed private Gtk.Box vbox; private DialogButton close_button; private Gtk.Box button_box; + private Gtk.Label default_action_label; private Gtk.EventBox monitor_events; private Gtk.EventBox vbox_events; private AnimateTimer animation; + private uint default_action_timeout; + private uint default_action_time_remaining; + private uint default_action_time_supplemental; private bool closing = false; public static string font = AGSettings.get_string (AGSettings.KEY_FONT_NAME); @@ -81,6 +86,11 @@ public class ShutdownDialog : Gtk.Fixed close (); return true; }); + monitor_events.events |= Gdk.EventMask.KEY_PRESS_MASK; + monitor_events.key_press_event.connect (() => { + stop_default_action_timeout (); + return false; + }); add (monitor_events); vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 10); @@ -97,7 +107,15 @@ public class ShutdownDialog : Gtk.Fixed vbox_events.visible = true; vbox_events.set_visible_window (false); vbox_events.events |= Gdk.EventMask.BUTTON_PRESS_MASK; - vbox_events.button_press_event.connect (() => { return true; }); + vbox_events.button_press_event.connect (() => { + stop_default_action_timeout (); + return true; + }); + vbox_events.events |= Gdk.EventMask.KEY_PRESS_MASK; + vbox_events.key_press_event.connect (() => { + stop_default_action_timeout (); + return false; + }); vbox_events.add (vbox); monitor_events.add (vbox_events); @@ -249,6 +267,12 @@ public class ShutdownDialog : Gtk.Fixed show.connect(() => { button.grab_focus (); }); } + default_action_label = new Gtk.Label (null); + default_action_label.set_line_wrap (true); + default_action_label.set_alignment (0.0f, 0.5f); + default_action_label.visible = false; + vbox.pack_start (default_action_label, false, false, 0); + close_button = new DialogButton (Path.build_filename (Config.PKGDATADIR, "dialog_close.png"), Path.build_filename (Config.PKGDATADIR, "dialog_close_highlight.png"), Path.build_filename (Config.PKGDATADIR, "dialog_close_press.png")); close_button.can_focus = false; close_button.clicked.connect (() => { close (); }); @@ -258,10 +282,89 @@ public class ShutdownDialog : Gtk.Fixed animation = new AnimateTimer ((x) => { return x; }, AnimateTimer.INSTANT); animation.animate.connect (() => { queue_draw (); }); show.connect (() => { animation.reset(); }); + show.connect (() => { default_action_timeout_init (); }); + } + + private bool update_default_action_label () + { + if (0 == default_action_time_remaining) + { + if (DEFAULT_ACTION_SUPPLEMENTAL_TIME == default_action_time_supplemental) + { + /* Fun begins here, actually trigger option. */ + var text = _("Selecting default action now."); + default_action_label.set_markup ("%s".printf (font_family, font_size_base+1, AGSettings.get_string (AGSettings.KEY_TOGGLEBOX_FONT_FGCOLOR), text)); + + /* + * Note that, if no button is focused, this will do + * nothing. + */ + Gtk.Window pWindow = (Gtk.Window) get_toplevel (); + var focused = pWindow.get_focus (); + if ((null != focused) && (focused is DialogButton)) + { + (focused as DialogButton).clicked (); + } + + --default_action_time_supplemental; + + return true; + } + else if (0 == default_action_time_supplemental) + { + stop_default_action_timeout (); + + return false; + } + else + { + --default_action_time_supplemental; + + return true; + } + } + else + { + var text = ngettext ("Selecting default action in one second …", "Selecting default action in %u seconds …", default_action_time_remaining).printf (default_action_time_remaining); + default_action_label.set_markup ("%s".printf (font_family, font_size_base+1, AGSettings.get_string (AGSettings.KEY_TOGGLEBOX_FONT_FGCOLOR), text)); + + --default_action_time_remaining; + + return true; + } + } + + private void stop_default_action_timeout () + { + if (0 != default_action_timeout) + { + GLib.Source.remove (default_action_timeout); + } + default_action_timeout = 0; + default_action_time_remaining = AGSettings.get_integer (AGSettings.KEY_SHUTDOWN_DIALOG_TIMEOUT); + default_action_time_supplemental = DEFAULT_ACTION_SUPPLEMENTAL_TIME; + + default_action_label.hide (); + } + + private void default_action_timeout_init () + { + /* Timer for forcefully selecting default option. */ + default_action_time_remaining = AGSettings.get_integer (AGSettings.KEY_SHUTDOWN_DIALOG_TIMEOUT); + default_action_time_supplemental = DEFAULT_ACTION_SUPPLEMENTAL_TIME; + + /* Zero means disabled, not instantaneous, honor that. */ + if (default_action_time_remaining > 0) + { + default_action_timeout = GLib.Timeout.add_seconds (1, update_default_action_label); + default_action_label.visible = true; + } } public void close () { + stop_default_action_timeout (); + var start_value = 1.0f - animation.progress; animation = new AnimateTimer ((x) => { return start_value + x; }, AnimateTimer.INSTANT); animation.animate.connect ((p) => @@ -366,6 +469,9 @@ public class ShutdownDialog : Gtk.Fixed Gtk.Window pWindow = (Gtk.Window) get_toplevel (); var widget = pWindow.get_focus (); + /* No matter what, stop the default action timer. */ + stop_default_action_timeout (); + if (widget is DialogButton) { pWindow = (Gtk.Window) get_toplevel (); -- cgit v1.2.3