dotfiles/.local/bin/i3hwlock

110 lines
2.7 KiB
Bash
Executable File

#!/bin/bash
# i3hwlock
#
# Allows locking i3 by the presence of a file. This file is intended to be
# created using udev rules so that you can trigger the lock when you remove
# a device such as a YubiKey. Example rule below.
#
# /etc/udev/rules.d/99-i3hwlock-yubikey.rules:
# ACTION=="add", SUBSYSTEM=="input", ENV{ID_VENDOR_ID}=="1050", RUN+="/usr/bin/rm /tmp/i3hwlock.trigger"
# ACTION=="remove", SUBSYSTEM=="input", ENV{ID_VENDOR_ID}=="1050", RUN+="/usr/bin/touch /tmp/i3hwlock.trigger"
LOCK_TIMEOUT=3 # How many seconds to wait before locking.
DMENU_FILE="/tmp/i3hwlock"
TRIGGER_FILE="$DMENU_FILE.trigger"
ABORT_FILE="$DMENU_FILE.abort"
CONTINUE_FILE="$DMENU_FILE.continue"
LOCKING_FILE="$DMENU_FILE.locking"
function check_prerequisites() {
[ -e "$ABORT_FILE" ] && rm "$ABORT_FILE"
if ! which inotifywait >/dev/null; then
echo "ERROR: inotifywait not found." 1>&2
return 1
fi
}
function dmenu_selection() {
selection="$(xargs -n 1 <<<"Continue Abort" | dmenu -i -p "The screen is about to lock")"
[ -z "$selection" ] && return
file="$DMENU_FILE.${selection,,}"
echo "INFO: Touching $file"
touch "$file"
}
function abort_lock() {
[ -e "$ABORT_FILE" ] && rm "$ABORT_FILE"
if ! [ -f "$LOCKING_FILE" ]; then
echo "WARN: Abort initiated without file '$LOCKING_FILE'." 1>&2
return 0
fi
echo "INFO: Aborting lock."
killall dmenu
notify-send "Lock aborted." &
[ -e $LOCKING_FILE ] && rm "$LOCKING_FILE"
}
function lock() {
[ -e "$CONTINUE_FILE" ] && rm "$CONTINUE_FILE"
if ! [ -f "$LOCKING_FILE" ]; then
echo "WARN: Won't lock as file '$LOCKING_FILE' is missing." 1>&2
return 0
fi
echo "INFO: Locking now."
killall dmenu
i3exit lock 2>/dev/null || i3lock --color=29414f --nofork
[ -e $LOCKING_FILE ] && rm "$LOCKING_FILE"
}
function delayed_lock() {
echo "INFO: Delayed lock initiated."
touch "$DMENU_FILE.locking"
for i in $(seq $LOCK_TIMEOUT); do
notify-send "Locking in $((LOCK_TIMEOUT - i + 1))" -t 1000 &
sleep 1
if [ -e "$ABORT_FILE" ]; then
abort_lock
return 0
elif [ -e "$CONTINUE_FILE" ]; then
break
fi
done
! [ -e $LOCKING_FILE ] && return 0
lock
}
function listen() {
while read -r directory action file; do
if [[ "$file" == "${TRIGGER_FILE##*/}" ]]; then
if [[ "$action" == "CLOSE_WRITE,CLOSE" ]] && ! [ -e "$LOCKING_FILE" ]; then
$0 dmenu-selection &
$0 delayed-lock &
elif [[ "$action" == "DELETE" ]]; then
abort_lock
fi
fi
done < <(inotifywait -m "${TRIGGER_FILE%/*}")
}
check_prerequisites || exit 1
if [ -z "$1" ]; then
listen || exit 2
elif [[ "$1" == delayed-lock ]]; then
delayed_lock || exit 3
elif [[ "$1" == dmenu-selection ]]; then
dmenu_selection || exit 4
else
echo "ERROR: Unrecognized action: '$1'." 1>&2
exit 127
fi