Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --idle-timeout-when-locked for idle timeout when session is locked #3546

Merged
merged 5 commits into from
Oct 17, 2024

Conversation

hbatagelo
Copy link
Contributor

@hbatagelo hbatagelo commented Aug 12, 2024

Fixes #3306.

This PR adds a new configuration option, --idle-timeout-when-locked, that allows the compositor to apply a separate idle timeout when the session is locked. The default value is 0, meaning the display will stay on indefinitely when the session is locked.

Examples showing its interaction with the existing --idle-timeout option:

  • --idle-timeout=60 --idle-timeout-when-locked=10: The display turns off after 60s of idle time when the session is unlocked, and after 10s of idle time when the session is locked.
  • --idle-timeout=0 --idle-timeout-when-locked=10: The display never turns off when idle, but it turns off after 10s of idle time when the session is locked.
  • --idle-timeout=60 --idle-timeout-when-locked=0: The display turns off after 60s of idle time but never when the session is locked.
  • --idle-timeout=0 --idle-timeout-on-lock=0: This is the default behavior. The display never turns off, wether the session is locked or unlocked.

Implementation details:

BasicIdleHandler now registers a session lock listener via the SessionLockListener class, which takes on_lock and on_unlock callbacks to track the state of the session lock. When the idle handlers (the dimmer and the power setter) are registered, they will use the timeout value from --idle-timeout-when-locked when the session is locked, and from --idle-timeout when the session is not locked.

@hbatagelo hbatagelo requested a review from a team as a code owner August 12, 2024 19:28
Copy link
Collaborator

@Saviq Saviq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be a little more flexible. Particularly, we want to give time for any lockscreen to render, so that on resume it's already there.

Not sure if we need it to be configurable, maybe just hardcoding a second-long delay would be appropriate…?

@AlanGriffiths @mattkae thoughts?

@@ -215,6 +267,16 @@ void msh::BasicIdleHandler::set_display_off_timeout(std::optional<time::Duration
display_config_controller, mir_power_mode_off, multiplexer);
observers.push_back(power_setter);
idle_hub->register_interest(power_setter, off_timeout);
if (off_timeout == time::Duration{} && previous_off_timeout)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is "just me", but I find that off_timeout == time::Duration{0} better expresses a comparison to zero. (I know comparing to "default constructed" has the same meaning to the compiler but it takes more thought to read)

@AlanGriffiths
Copy link
Contributor

AlanGriffiths commented Aug 13, 2024

I think this needs to be a little more flexible. Particularly, we want to give time for any lockscreen to render, so that on resume it's already there.

Not sure if we need it to be configurable, maybe just hardcoding a second-long delay would be appropriate…?

@AlanGriffiths @mattkae thoughts?

I don't think turning the screen off will actually prevent the lockscreen rendering. Is this actually down to our "smooth boot" changes? I.e. showing the preexisting display buffer until we have something to composite. If so, we could also avoid flashing the old content by just blanking the display before poweroff.

@RAOF
Copy link
Contributor

RAOF commented Aug 13, 2024

I think this needs to be a little more flexible. Particularly, we want to give time for any lockscreen to render, so that on resume it's already there.
Not sure if we need it to be configurable, maybe just hardcoding a second-long delay would be appropriate…?
@AlanGriffiths @mattkae thoughts?

I don't think turning the screen off will actually prevent the lockscreen rendering.

I agree. I think it might be a little bit less jarring if we let the lockscreen render¹ between locking and turning the display off, though? For reference, GNOME lets the lockscreen animate in before turning the display off.

¹: Probably just a 5sec delay; while we could, I don't think we need to actually check that the lockscreen has submitted buffers for each output.

@mattkae
Copy link
Contributor

mattkae commented Aug 13, 2024

I am 👍 for a timer that will idle the screen X seconds after a lock. That way, the lock client has some time to respond before the screen goes dim.

I also think that the X seconds here should be configurable by the compositor implementer. Different authors may want this behavior to happen on a different timing (or not at all)

@RAOF
Copy link
Contributor

RAOF commented Aug 22, 2024

When talking with Harlen yesterday talking about the appropriate behaviour here, we had something of an idea:
We don't particularly want to change the screen blanking time when locking the session¹. What we want is for the screen to turn off shortly after the session is locked. The suggestion is that, when the SessionLockObserver notifies us of a session lock we arm a 5-second Alarm that will turn off the display, and register a 0-timeout idle handler with the IdleHub whose active() handler will cancel that Alarm.

This might be worth supporting directly in IdleHub, as a one-shot run_if_inactive_for(timeout, std::function<> functor) that fires functor if there is no activity event before timeout.

¹: In the degenerate case where we want the screen to turn off immediately on session lock, we very much don't want the screen off timer to continue to fire immediately, because that will ensure the screen turns off even while the user is trying to unlock their session!

@hbatagelo hbatagelo changed the title Goes idle just after the session is locked Add --idle-timeout-on-lock for idle timeout when session is locked Sep 23, 2024
@hbatagelo hbatagelo changed the title Add --idle-timeout-on-lock for idle timeout when session is locked Add --idle-timeout-on-lock for idle timeout when session is locked Sep 23, 2024
@hbatagelo hbatagelo changed the title Add --idle-timeout-on-lock for idle timeout when session is locked Add --idle-timeout-on-lock for idle timeout when session is locked Sep 23, 2024
@hbatagelo
Copy link
Contributor Author

I've updated the title and top comment to reflect the latest changes.

While the new behavior aligns with Chris's description, I kept the logic in BasicIdleHandler. Directly using IdleHub could achieve the same results but would require changing its interface. Also, keeping the logic in BasicIdleHandler makes it easier to reuse the existing dimmer and power-setter observers for both --idle-timeout and --idle-timeout-on-lock: the display will dim if either timeout exceeds 20s (a pre-existing hardcoded value).

Copy link
Contributor

@AlanGriffiths AlanGriffiths left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some quick things to fix. I'll look at the functionality tomorrow

Comment on lines 1 to 2
MIR_PLATFORM_2.18 {
MIR_PLATFORM_2.19 {
global:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we're breaking the mirplatform ABI: idle_timeout_on_lock_opt should be in a new 2.19 stanza

/// set_display_off_timeout while the session is locked and remains idle. If Mir becomes active after the session
/// is locked, this timeout is disabled. If the session is already locked when this function is called, the new
/// timeout will only take effect after the next session lock.
virtual void set_display_off_timeout_on_lock(std::optional<time::Duration> timeout) = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Aside] This is breaking the mirserver ABI. We need to bump accordingly (either now or before 2.19)

Don't worry about it here - there's other stuff breaking things in the pipeline

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I didn't notice it before because the symbols checking tool doesn't detect changes in the vtable.
If it's just a matter of bumping MIR_VERSION_MINOR and MIRSERVER_ABI, we can do it now. Is it enough to follow the how-to?

Comment on lines 206 to 210
explicit SessionLockListener(std::function<void()> const& on_lock) : on_lock_{on_lock} {};

private:
void on_lock() override { on_lock_(); };
void on_unlock() override {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
explicit SessionLockListener(std::function<void()> const& on_lock) : on_lock_{on_lock} {};
private:
void on_lock() override { on_lock_(); };
void on_unlock() override {};
explicit SessionLockListener(std::function<void()> const& on_lock) : on_lock_{on_lock} {}
private:
void on_lock() override { on_lock_(); }
void on_unlock() override {}

@AlanGriffiths
Copy link
Contributor

  • --idle-timeout=60 --idle-timeout-on-lock=10: The display turns off after 60s of idle time, but when the session is locked it turns off after 10s of being idle. If Mir becomes active before 10s, the idle timeout reverts to 60s even if the session stays locked.

Have I misunderstood this?

In a VT:

  1. snap refresh miriway --channel-edge/mir-pr3546
  2. /snap/miriway/current/example-configs/alan_g.bash
  3. miriway --idle-timeout-on-lock=10
  4. Use for a bit and then lock the screen with Ctrl-Alt-L

Expect: after 10s the screen dims and turns off
Actual: the screen remains active

In case it matters...

$ grep idle ~/.config/miriway-shell.config
idle-timeout=600

@hbatagelo
Copy link
Contributor Author

I suspect that, by the time you release the modifier keys, you activate the session and restore the 600s timeout. We'll probably need something a bit more elaborate than the 0-timeout idle handler to prevent this immediate reactivation. I'll work on that.

@hbatagelo
Copy link
Contributor Author

I changed the 0-timeout idle handler to a 200ms timeout. This should serve as a grace period to prevent immediate reactivation when the session is locked using a keyboard shortcut.

@AlanGriffiths
Copy link
Contributor

I changed the 0-timeout idle handler to a 200ms timeout. This should serve as a grace period to prevent immediate reactivation when the session is locked using a keyboard shortcut.

This is better but doesn't work very well. It too easy to "linger" on a shift key when locking the screen.

Also consider the case when the screen is woken by activity but not unlocked.

In both cases, it would be better to recognize that the screen is still locked and just reset the timeout to idle-timeout-on-lock

@hbatagelo
Copy link
Contributor Author

In both cases, it would be better to recognize that the screen is still locked and just reset the timeout to idle-timeout-on-lock

Agreed. That appears to be the easiest solution as well, since it doesn't require restoring to a timeout that changes the behavior. The other option would be to ignore key releases after the session is locked, but that would be more involved.

@AlanGriffiths
Copy link
Contributor

Agreed

In which case, maybe s/idle-timeout-on-lock/idle-timeout-when-locked/g

@AlanGriffiths
Copy link
Contributor

@hbatagelo ping!

@hbatagelo hbatagelo force-pushed the MIRENG-454/idle-timeout-on-lock branch from 705f236 to 004fcd3 Compare October 17, 2024 12:31
@hbatagelo hbatagelo changed the title Add --idle-timeout-on-lock for idle timeout when session is locked Add --idle-timeout-when-locked for idle timeout when session is locked Oct 17, 2024
Copy link
Contributor

@AlanGriffiths AlanGriffiths left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a pre-existing nit about validating on use, not on input, but it is protected by validating on input first

Comment on lines 273 to 275
{
fatal_error("BasicIdleHandler given invalid timeout %d, should be >0", off_timeout.count());
fatal_error("BasicIdleHandler given invalid timeout %d, should be >0", off_timeout->count());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the wrong time to be validating input and erroring. (That should be on startup when the input is parsed)

@hbatagelo hbatagelo added this pull request to the merge queue Oct 17, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Oct 17, 2024
@hbatagelo hbatagelo added this pull request to the merge queue Oct 17, 2024
Merged via the queue into main with commit f66bcae Oct 17, 2024
30 of 38 checks passed
@hbatagelo hbatagelo deleted the MIRENG-454/idle-timeout-on-lock branch October 17, 2024 18:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Mir should idle-timeout soon after receiving a lock
5 participants