swayidle
swayidle copied to clipboard
SIGUSR1 gets queued up when idle inhibitor is active
This one's a bit peculiar. When an idle inhibitor is active (I use Waybar's idle_inhibitor module for this, which uses the associated Wayland protocol) sending a SIGUSR1 to swayidle does nothing (this is correct, since the system can't be considered idle). However, the second you turn off the idle inhibitor swayidle believes the system is idle, and thus locks.
I think this is confusing and unexpected, especially since idle inhibition can be active for long periods of time after which your system might surprise lock on you if you forgot you triggered swayidle some way (for example through a lockcmd shortcut in sway).
I would expect that while the idle inhibitor is active, swayidle would discard requests to enter idle state, instead of seemingly delaying processing them.
~ ❯❯❯ /usr/bin/swayidle -w -d \
timeout 300 'swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png' \
timeout 600 'swaymsg "output * dpms off"' \
resume 'swaymsg "output * dpms on"' \
lock 'swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png' \
before-sleep 'swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png'
Got timeout
Register idle timeout at 300000 ms
Setup idle
Command: swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png
Got timeout
Register idle timeout at 600000 ms
Setup idle
Command: swaymsg "output * dpms off"
Setup resume
Command: swaymsg "output * dpms on"
Got lock
Command: swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png
Setup lock hook: swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png
Got before-sleep
Command: swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png
Setup sleep lock: swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png
Got sleep lock: 11
Register with timeout: 600000
Register with timeout: 300000
---> Sent SIGUSR1
Got SIGUSR1
Register with timeout: 0
Register with timeout: 0
idle state
Cmd exec swaymsg "output * dpms off"
Spawned process swaymsg "output * dpms off"
idle state
Cmd exec swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png
Spawned process swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png
active state
Register with timeout: 600000
Cmd exec swaymsg "output * dpms on"
Spawned process swaymsg "output * dpms on"
active state
Register with timeout: 300000
---> Activate Idle inhibitor
---> Sent SIGUSR1
Got SIGUSR1
Register with timeout: 0
Register with timeout: 0
---> Deactivate idle inhibitor
idle state
Cmd exec swaymsg "output * dpms off"
Spawned process swaymsg "output * dpms off"
idle state
Cmd exec swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png
Spawned process swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png
active state
Register with timeout: 600000
Cmd exec swaymsg "output * dpms on"
Spawned process swaymsg "output * dpms on"
active state
Register with timeout: 300000
If I send multiple SIGUSR1's while the idle inhibitor is active you get this instead:
Got SIGUSR1
Register with timeout: 0
Register with timeout: 0
Got SIGUSR1
Register with timeout: 0
Register with timeout: 0
Got SIGUSR1
Register with timeout: 0
Register with timeout: 0
Got SIGUSR1
Register with timeout: 0
Register with timeout: 0
---> Deactivate idle inhibitor
idle state
Cmd exec swaymsg "output * dpms off"
Spawned process swaymsg "output * dpms off"
idle state
Cmd exec swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png
Spawned process swaylock -f -c 000000 -i /home/daenney/Pictures/Rainbow_Dash_Wallpaper.png
active state
Register with timeout: 600000
Cmd exec swaymsg "output * dpms on"
Spawned process swaymsg "output * dpms on"
active state
Register with timeout: 300000
Offending code seems to be in this function. Perhaps someone with a better understanding of C can help out?
https://github.com/swaywm/swayidle/blob/master/main.c#L852
the current behaviour seems to make no sense, but I'm curious as to the thinking behind this @daenney :
When an idle inhibitor is active (I use Waybar's idle_inhibitor module for this, which uses the associated Wayland protocol) sending a SIGUSR1 to swayidle does nothing (this is correct, since the system can't be considered idle).
personally: I want SIGUSR1 to lock the screen regardless of any inhibitors (as it's coming from me pressing my "lock screen now" hotkey)
the current behaviour SIGUSR1 seems completely broken (I suspect it predates the idle inhibitors entirely)
as a note this happens because the trigger of the timeouts is done by the compositor
swayidle asks it to register a timeout 0ms in the future, and when idle is inhibited the compositor doesn't do anything until the inhibition disappears
personally: I want SIGUSR1 to lock the screen regardless of any inhibitors (as it's coming from me pressing my "lock screen now" hotkey)
Yeah, I agree with that, it would make sense for that to always work.
It's unclear to me why USR1 shouldn't be handled by just running the timeout commands directly, i.e., why does it go through the compositor and the idle notifications at all?
OK, I can identify one issue. If we do handle_idled(cmd, NULL)
instead of register_timeout(cmd, 0)
, then the resume commands never run. This is logical because if we use register_timeout
we rely on the compositor to tell us when the system "wakes up". On the other hand, if we just run the idle commands directly with handle_idled
, the resume commands will be enabled, but never actually run. This is tricky, because from sway's perspective, the system may not actually be "idle", i.e., there may have been inhibitors that sway-idle bypassed. Regardless, this means the system will also never leave idle, so we can't use that event.