Created
November 26, 2023 22:13
-
-
Save mensinda/94d0b05604bbb50f9b5bd4a5f1b48bfb to your computer and use it in GitHub Desktop.
wlroots lock screen manager
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
SELF="$(readlink -f "$0")" | |
### _____ _____ _ _ ______ _____ _____ | |
### / __ \ _ | \ | || ___|_ _| __ \ | |
### | / \/ | | | \| || |_ | | | | \/ | |
### | | | | | | . ` || _| | | | | __ | |
### | \__/\ \_/ / |\ || | _| |_| |_\ \ | |
### \____/\___/\_| \_/\_| \___/ \____/ | |
### | |
SIMULATION_MODE=0 | |
# The FIFO / named pipe used for IPC between the lockmgr and swayidle | |
FIFO="/tmp/wlroots_lockmgr" | |
# Common swaylock arguments. | |
LOCK_ARGS="--show-failed-attempts --hide-keyboard-layout --indicator-caps-lock" | |
# Set **ONE** of the following variables to set the background image / color of the lock screen: | |
# | |
# LOCK_COLOR="#000000" | |
# LOCK_IMG="/path/to/your/lock/wallpaper" | |
# LOCK_IMG_DIR="/path/to/a/dir/from/which/to/pick/a/random/wallpaper" | |
# | |
# Black screen by default | |
LOCK_COLOR="#000000" | |
# swayidle configuration with some changes: | |
# - the timeout can now be relative to the last timeout | |
# - the command is now comma (`,`) seperated list of commands to execute. Commands in this | |
# context are not shell commands, but functions inside this script. All command functions | |
# have a `cmd_` prefix. | |
# | |
# New functions can be added by implementing new `cmd_<command name>` functions. | |
SWAYIDLE_COMMANDS=( | |
"timeout 60 mgr_reset,notify" | |
"timeout +5 lock resume grace_unlock" | |
"timeout +3 grace_end" | |
"timeout +30 dpms_off resume dpms_on" | |
"before-sleep lock" | |
"lock lock" | |
"unlock unlock" | |
) | |
### _____ ________ ______ ___ ___ _ _______ _____ | |
### / __ \ _ | \/ || \/ | / _ \ | \ | | _ \/ ___| | |
### | / \/ | | | . . || . . |/ /_\ \| \| | | | |\ `--. | |
### | | | | | | |\/| || |\/| || _ || . ` | | | | `--. \ | |
### | \__/\ \_/ / | | || | | || | | || |\ | |/ / /\__/ / | |
### \____/\___/\_| |_/\_| |_/\_| |_/\_| \_/___/ \____/ | |
### | |
# This will store the swayidle PID in the future | |
CHILD_PID=-1 | |
ALLOW_GRACE_UNLOCK=0 | |
cmd_mgr_reset() { | |
msg1 "Starting lock chain" | |
ALLOW_GRACE_UNLOCK=1 | |
} | |
cmd_notify() { | |
msg2 "Notifying the user" | |
notify-send "Sleepy..." "I am about to lock your screen because of inactivity. Please do something if you don't want that to happen!" | |
} | |
cmd_lock() { | |
if pidof swaylock > /dev/null; then | |
msg2 "Screen is already locked --> Doing nothing" | |
return 0 | |
fi | |
msg2 "Locking the screen" | |
extra_args="" | |
[ -n "$LOCK_COLOR" ] && extra_args="-c '$LOCK_COLOR'" | |
[ -n "$LOCK_IMG" ] && extra_args="-i '$LOCK_IMG'" | |
[ -n "$LOCK_IMG_DIR" ] && extra_args="-i '$LOCK_IMG_DIR/$(ls "$LOCK_IMG_DIR" | sort -R | tail -n 1)'" | |
# `--daemonize` should always be passed unless you feel like | |
# messing around with the IPC logic if this script :) | |
if (( SIMULATION_MODE == 1 )); then | |
msg3 "swaylock --daemonize $LOCK_ARGS $extra_args" | |
else | |
swaylock --daemonize $LOCK_ARGS $extra_args | |
fi | |
} | |
# Workaround helper for https://github.com/swaywm/swayidle/issues/54 | |
_disable_grace_delayed() { | |
sleep 2 | |
$SELF grace_end | |
} | |
cmd_manual_lock() { | |
msg1 "Manually lock triggered" | |
sleep .5 | |
msg2 "Setting swayidle status to idle" | |
if ps -p $CHILD_PID &> /dev/null; then | |
kill -SIGUSR1 $CHILD_PID | |
fi | |
_disable_grace_delayed & | |
} | |
cmd_grace_unlock() { | |
if (( ALLOW_GRACE_UNLOCK == 1 )); then | |
msg2 "Unlocking because activity within the grace period" | |
if pidof swaylock > /dev/null; then | |
killall -SIGUSR1 swaylock | |
fi | |
else | |
msg2 "The grace period has passed --> No automatic unlock" | |
fi | |
} | |
cmd_grace_end() { | |
msg2 "The grace period ends now!" | |
ALLOW_GRACE_UNLOCK=0 | |
} | |
cmd_dpms_off() { | |
msg2 "DPMS off" | |
if (( SIMULATION_MODE == 1 )); then | |
return 0 | |
fi | |
case ${XDG_CURRENT_DESKTOP:-sway} in | |
Hyprland|hyprland) | |
hyprctl dispatch dpms off | |
;; | |
sway|Sway) | |
swaymsg "output * dpms off" | |
;; | |
*) | |
error "DPMS control for $XDG_CURRENT_DESKTOP is not yet supported!" | |
;; | |
esac | |
} | |
cmd_dpms_on() { | |
msg2 "DPMS on" | |
if (( SIMULATION_MODE == 1 )); then | |
return 0 | |
fi | |
case ${XDG_CURRENT_DESKTOP:-sway} in | |
Hyprland|hyprland) | |
hyprctl dispatch dpms on | |
;; | |
sway|Sway) | |
swaymsg "output * dpms on" | |
;; | |
*) | |
error "DPMS control for $XDG_CURRENT_DESKTOP is not yet supported!" | |
;; | |
esac | |
} | |
# Could be used to manually terminate the lockmgr | |
cmd_exit() { | |
msg1 "Exit requested --> terminating" | |
exit 0 | |
} | |
### _ _____ _____ | |
### | | | _ | __ \ | |
### | | | | | | | \/ | |
### | | | | | | | __ | |
### | |___\ \_/ / |_\ \ | |
### \_____/\___/ \____/ | |
### | |
msg1() { | |
echo -e "\x1b[1;35m[\x1b[0m$(date '+%F %T')\x1b[1;35m]\x1b[0m \x1b[1;32m=>\x1b[0m $*" | |
} | |
msg2() { | |
echo -e "\x1b[1;35m[\x1b[0m$(date '+%F %T')\x1b[1;35m]\x1b[0m \x1b[1;34m - \x1b[0m $*" | |
} | |
msg3() { | |
echo -e "\x1b[1;35m[\x1b[0m$(date '+%F %T')\x1b[1;35m]\x1b[0m \x1b[1;36m -- \x1b[0m $*" | |
} | |
warn() { | |
echo -e "\x1b[1;35m[\x1b[0m$(date '+%F %T')\x1b[1;35m]\x1b[0m \x1b[1;33mWARN:\x1b[0m $*" | |
} | |
error() { | |
echo -e "\x1b[1;35m[\x1b[0m$(date '+%F %T')\x1b[1;35m]\x1b[0m \x1b[1;31mERROR:\x1b[0m $*" | |
} | |
### ___ ___ ___ _____ _ _ | |
### | \/ | / _ \|_ _| \ | | | |
### | . . |/ /_\ \ | | | \| | | |
### | |\/| || _ | | | | . ` | | |
### | | | || | | |_| |_| |\ | | |
### \_| |_/\_| |_/\___/\_| \_/ | |
### | |
cleanup() { | |
msg1 "Begin cleanup" | |
if [ -e $FIFO ]; then | |
msg2 "Deleting named pipe $FIFO" | |
rm -f $FIFO | |
fi | |
if ps -p $CHILD_PID &> /dev/null; then | |
msg2 "Terminating swayidle child process $CHILD_PID" | |
kill -SIGTERM $CHILD_PID | |
fi | |
msg2 "Cleanup DONE" | |
} | |
add_time() { | |
t=$1 | |
[[ ${t:0:1} == '+' || ${t:0:1} == '-' ]] && (( t = $last_time ${t:0:1} ${t:1} )) | |
last_time=$t | |
swayidle_cmd+=($t) | |
} | |
dispatch_main() { | |
if [ ! -p $FIFO ]; then | |
warn "FIFO $FIFO does not exist. The manager does not seem to be running. Doing nothing." | |
exit 1 | |
fi | |
echo $1 > $FIFO | |
} | |
manager_main() { | |
if [ -e $FIFO ]; then | |
cat <<EOF | |
FIFO $FIFO already exists. | |
Only one instance of $0 may run at a time. However, | |
the existence of $FIFO indicates that another | |
instance is already running. | |
Please manually delete $FIFO, if you are sure that | |
the other instance of $0 has exited / crashed. | |
EOF | |
exit 1 | |
fi | |
msg1 "Startup" | |
# Set the cleanup exit hook | |
trap cleanup EXIT | |
# Prepare FIFO | |
msg2 "Creating named pipe $FIFO" | |
mkfifo $FIFO | |
# Building swayidle command | |
msg2 "Building swayidle command:" | |
swayidle_cmd=(swayidle -w) | |
last_time=0 | |
for i in "${SWAYIDLE_COMMANDS[@]}"; do | |
c=($i) | |
swayidle_cmd+=(${c[0]}) | |
case "${c[0]}" in | |
timeout) | |
add_time ${c[1]} | |
swayidle_cmd+=("$SELF '${c[2]}'") | |
if [[ "${c[3]}" == 'resume' ]]; then | |
swayidle_cmd+=(resume) | |
swayidle_cmd+=("$SELF '${c[4]}'") | |
fi | |
;; | |
before-sleep|after-resume|lock|unlock) | |
swayidle_cmd+=("$SELF '${c[1]}'") | |
;; | |
idlehint) | |
add_time ${c[1]} | |
;; | |
*) | |
error "Unknown command '${c[0]}'" | |
exit 1 | |
;; | |
esac | |
done | |
# Start swayidle | |
"${swayidle_cmd[@]}" & | |
CHILD_PID=$! | |
msg2 "Started swayidle: PID=$CHILD_PID" | |
# Main loop | |
msg2 "Starting main loop" | |
while true; do | |
# Read from the FIFO with a timeout | |
read -st 1 cmd <> $FIFO || cmd='' | |
# Check if the FIFO was deleted | |
if [ ! -p $FIFO ]; then | |
warn "FIFO $FIFO was deleted. --> Exiting" | |
exit 1 | |
fi | |
# Empty command / timeout? | |
[ -z "$cmd" ] && continue | |
# Commands may be chained via `,` | |
for i in ${cmd//,/ }; do | |
# Exec command if known | |
if [[ "$(LC_ALL=C type -t "cmd_$i")" == 'function' ]]; then | |
cmd_$i | |
else | |
warn "Unknown command '$i' --> ignoring" | |
fi | |
done | |
done | |
} | |
if [ -n "$1" ]; then | |
dispatch_main "$1" | |
else | |
manager_main | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment