Window Managers like i3, Awesome, Xmonad, Sway etc etc are great. But it does feel like reinventing the wheel sometimes with basic features that come included with full desktop environments.
As life starts to show hints that it might finally be returning to relative normal soon and we all brush up on our social skills and personal hygiene. I find myself thinking that it might be useful to have my screen auto-lock after a set period whilst I’m out and about.
There are already a couple of options for this, such as Xscreensaver but I don’t want a bloated screensaver, I just want to trigger a custom lock screen I’ve already built in AwesomeWM.
I figured I may as well document how I did it, so here we go.
First thing to do is to ascertain how long the user has been idle. Fortunately this is relatively easy with Xprintidle, so let’s use that:
#!/bin/bash
IDLE_TIME="$(xprintidle)"
MAX_IDLE="180000" # 3 minutes
echo "Idle time is: $IDLE_TIME"
[ "$IDLE_TIME" -gt "$MAX_IDLE" ] && $(echo "lock_screen_show()" | awesome-client) || exit 0
This nice simple script I’ve called idle-check
checks whether the idle time (in ms) is greater than the timeout. If it is, it calls the lock_screen_show
function I have defined in my Awesome config.
Good start, but the big problem with this is that when I’m watching a video for example, I don’t want the script to trigger. We’ll solve that in the next step.
Let’s create another script to check if a fullscreen application is running. We can do this using a combination of xwininfo
and xdotool
.
#!/bin/bash
root_geo="$(xwininfo -root | grep geometry)"
[ "$(xwininfo -id $(xdotool getactivewindow) | grep geometry)" = "$root_geo" ] && echo "1" || echo "0"
This script gets the resolution of the screen (root_geo
) and uses xdotool
to get the currently active window before comparing the geometry of said window to the max resolution. If they match, we know the currently active application is in fullscreen mode.
We can simply return 1 to represent fullscreen and 0 otherwise.
Now that we have this set up, we can add it to the check in our initial script:
#!/bin/bash
IDLE_TIME="$(xprintidle)"
MAX_IDLE="180000" # 3 minutes
echo "Idle time is: $IDLE_TIME"
+ echo "Fullscreen status is: $(is_fullscreen)"
- [ "$IDLE_TIME" -gt "$MAX_IDLE" ] && $(echo "lock_screen_show()" | awesome-client) || exit 0
+ [ "$IDLE_TIME" -gt "$MAX_IDLE" ] && [ "$(is_fullscreen)" -eq "0" ] && $(echo "lock_screen_show()" | awesome-client) || exit 0
Here, is_fullscreen
is the name of our other script.
Almost there. We now have a script which, when run will check the idle time and, if greater than the specified timeout (and no fullscreen app is running) it will call the lock function.
The only thing left to do is run this script on an interval to constantly poll the status. To do this with cron just append * * * * * /path/to/your/script
using crontab-e
. However I’m going to be using Systemd timers, which I’ll detail in the next step.
Create a service file in ~/.config/systemd/user
called something like idle-check.service
with the following:
[Unit]
Description=Check if user has been idle for more than 3 minutes and lock the screen
After=multi-user.target
[Service]
Environment=DISPLAY=:0
ExecStart=/path/to/your/idle-check/script
[Install]
WantedBy=basic.target
Then, create a timer to activate this service at the same location (e.g. idle-check.timer
);
[Unit]
Description=Run idle check every minute
[Timer]
OnBootSec=2min
OnCalendar=*-*-* *:*:00
Unit=idle-check.service
[Install]
WantedBy=basic.target
Enable it with systemd --user enable idle-check.timer
and you’re good to go!