392 lines
7.2 KiB
Bash
Executable File
392 lines
7.2 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
## INIT ##
|
|
# get script base directory
|
|
SCRIPT_PATH=$(readlink -f "${BASH_SOURCE[0]}")
|
|
SCRIPT_DIR=$(dirname -- "$SCRIPT_PATH")
|
|
|
|
# store arguments globally
|
|
ARG_LIST=("$@")
|
|
|
|
# get version number
|
|
VERSION=$(cat ${SCRIPT_DIR}/VERSION | xargs)
|
|
|
|
# location of workplace config file
|
|
CONFIG_PATH="${HOME}/.config/workplace.ini"
|
|
|
|
# load libraries
|
|
source "${SCRIPT_DIR}/lib/color"
|
|
source "${SCRIPT_DIR}/lib/log"
|
|
source "${SCRIPT_DIR}/lib/toolcheck"
|
|
source "${SCRIPT_DIR}/lib/ini"
|
|
source "${SCRIPT_DIR}/lib/snore"
|
|
|
|
|
|
|
|
#
|
|
# Explain usage of script.
|
|
#
|
|
workplace_help(){
|
|
echo "WorkPlace v${VERSION}"
|
|
echo
|
|
echo "Usage: $0 <command>"
|
|
echo
|
|
echo "Commands:"
|
|
echo " set <name> - Set workplace"
|
|
echo " update - Automatically determine current workplace setup"
|
|
echo " updatedaemon - Run as daemon and call update when setup changes are detected"
|
|
echo
|
|
echo " help - Display this help message and exit"
|
|
echo " version - Display version information and exit"
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# Display version information.
|
|
#
|
|
workplace_version(){
|
|
echo "WorkPlace v${VERSION}"
|
|
echo "(c) 2024 DrMaxNix"
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# Run command `set`.
|
|
#
|
|
workplace_set(){
|
|
## FIND CONFIG SECTION ##
|
|
# make sure param is present
|
|
if [[ ! ${1:-""} ]]; then
|
|
log_error "Missing workplace name; See '$0 help' for usage information"
|
|
fi
|
|
|
|
# try to find section
|
|
workplace_section=""
|
|
for n in $(workplace_available_name_list); do
|
|
if [[ "$n" == "$1" ]]; then
|
|
workplace_name="$n"
|
|
fi
|
|
done
|
|
if [[ ! ${workplace_name:-""} ]]; then
|
|
log_error "Invalid workplace name '$1'; Check config file"
|
|
fi
|
|
|
|
|
|
## RUN COMMANDS ##
|
|
local -n workplace_section="ini__${workplace_name}"
|
|
local -n workplace_section_key_list="ini__${workplace_name}__key_list"
|
|
for k in ${workplace_section_key_list[*]}; do
|
|
# `set` command
|
|
if [[ "$k" =~ ^set\. ]]; then
|
|
command=$(echo "$k" | grep -oPe '(?<=^set.).*')
|
|
param="${workplace_section[$k]}"
|
|
workplace_setcommand_run "$command" "$param"
|
|
continue; fi
|
|
|
|
# `run` command
|
|
if [[ "$k" =~ ^run\. ]]; then
|
|
param="${workplace_section[$k]}"
|
|
workplace_runcommand_run "$param"
|
|
continue; fi
|
|
|
|
# `trigger` command
|
|
if [[ "$k" =~ ^trigger\. ]]; then
|
|
# ignore
|
|
continue; fi
|
|
|
|
# unknown command type
|
|
log_warn "Unknown command type for '$k'"
|
|
done
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# Run command `update`.
|
|
#
|
|
workplace_update(){
|
|
## DETECT SETUP ##
|
|
# connected usb devices
|
|
usb_id_list=$(workplace_usb_id_list)
|
|
|
|
|
|
## FILTER ##
|
|
workplace_list_prio_0=""
|
|
workplace_list_prio_1=""
|
|
for n in $(workplace_available_name_list); do
|
|
local -n workplace_section="ini__$n"
|
|
|
|
# default
|
|
trigger_default="${workplace_section[trigger.default]:-""}"
|
|
if [[ "$trigger_default" == "true" ]]; then
|
|
workplace_list_prio_0="${workplace_list_prio_0} $n"
|
|
fi
|
|
|
|
# usb-id
|
|
trigger_usbid="${workplace_section[trigger.usb-id]:-""}"
|
|
if [[ "$trigger_usbid" ]]; then
|
|
for i in $usb_id_list; do
|
|
if [[ "$i" == "$trigger_usbid" ]]; then
|
|
workplace_list_prio_1="${workplace_list_prio_1} $n"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
done
|
|
workplace_list_prio_0="$(echo $workplace_list_prio_0 | xargs)"
|
|
workplace_list_prio_1="$(echo $workplace_list_prio_1 | xargs)"
|
|
|
|
|
|
## SELECT BEST ONE ##
|
|
workplace=""
|
|
|
|
# by prio
|
|
if [[ "$workplace_list_prio_1" ]]; then
|
|
workplace="$workplace_list_prio_1"
|
|
elif [[ "$workplace_list_prio_0" ]]; then
|
|
workplace="$workplace_list_prio_0"
|
|
fi
|
|
|
|
# make sure we have found one
|
|
if [[ ! "$workplace" ]]; then
|
|
log_warn "No matching workplace trigger found"
|
|
return
|
|
fi
|
|
|
|
|
|
## SET NEW WORKPLACE ##
|
|
log_info "Switching to workplace '$workplace'"
|
|
workplace_set "$workplace"
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# Run command `updatedaemon`.
|
|
#
|
|
workplace_updatedaemon(){
|
|
## INIT ##
|
|
# prepare forking
|
|
trap "kill -s SIGTERM -- -$$" EXIT
|
|
|
|
# update once
|
|
kill -s SIGUSR1 $$
|
|
|
|
|
|
## LISTEN FOR SCREEN RESOLUTION CHANGE ##
|
|
xeventbind resolution /usr/bin/echo |
|
|
while read -r; do
|
|
kill -s SIGUSR1 $$
|
|
done &
|
|
|
|
|
|
## LISTEN FOR LOGIN ##
|
|
gdbus monitor -y -d org.freedesktop.login1 |
|
|
grep --line-buffered "LockedHint" |
|
|
while read -r; do
|
|
kill -s SIGUSR1 $$
|
|
done &
|
|
|
|
|
|
## KEEP RUNNING ##
|
|
while true; do
|
|
workplace_handle_change
|
|
snore 0.5
|
|
done
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# HELPER: (Re-)load config.
|
|
#
|
|
workplace_config_load(){
|
|
# clear used variables
|
|
unset ini
|
|
for v in $(compgen -A variable | grep -Pe '^ini__'); do
|
|
unset $v
|
|
done
|
|
|
|
# parse ini file
|
|
ini_parse "$CONFIG_PATH"
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# HELPER: Get defined workplace names.
|
|
#
|
|
workplace_available_name_list(){
|
|
for v in ${ini[*]}; do
|
|
# ignore root section
|
|
[[ "$v" == "_root" ]] && continue
|
|
|
|
# include this section's name
|
|
echo $v
|
|
done
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# HELPER: Run a `set` command.
|
|
#
|
|
workplace_setcommand_run(){
|
|
case ${1:-""} in
|
|
## CORE ##
|
|
# volume
|
|
"volume")
|
|
if [[ "$2" -le 0 ]]; then
|
|
amixer set 'Master',0 "$2%" off > /dev/null || true
|
|
else
|
|
amixer set 'Master',0 "$2%" on > /dev/null || true
|
|
fi
|
|
;;
|
|
|
|
# powerprofile
|
|
"powerprofile")
|
|
powerprofilesctl set "$2" || true
|
|
;;
|
|
|
|
# text scaling factor
|
|
"text-scaling-factor")
|
|
dconf write /org/gnome/desktop/interface/text-scaling-factor "$2" || true
|
|
;;
|
|
|
|
|
|
## DASH-TO-DOCK EXTENSION ##
|
|
# dock position (includes fix for buggy window size)
|
|
"dash-to-dock.position")
|
|
if [[ "$2" == "LEFT" ]]; then
|
|
dconf write /org/gnome/shell/extensions/dash-to-dock/dock-position "'BOTTOM'" || true
|
|
else
|
|
dconf write /org/gnome/shell/extensions/dash-to-dock/dock-position "'LEFT'" || true
|
|
fi
|
|
snore 0.3
|
|
dconf write /org/gnome/shell/extensions/dash-to-dock/dock-position "'$2'" || true
|
|
;;
|
|
|
|
|
|
## PAM EXTENSION ##
|
|
# fprintd module
|
|
"pam.fprintd")
|
|
if [[ "$2" == "true" || "$2" == "1" ]]; then
|
|
sudo --non-interactive pam-auth-update --enable fprintd
|
|
else
|
|
sudo --non-interactive pam-auth-update --disable fprintd
|
|
fi
|
|
;;
|
|
|
|
|
|
## ERROR HANDLING ##
|
|
*)
|
|
log_error "Invalid setcommand '$1'"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# HELPER: Run a `run` command.
|
|
#
|
|
workplace_runcommand_run(){
|
|
bash_exit=0
|
|
bash -c "$1" 1>&2 || bash_exit=$?
|
|
if [[ "$bash_exit" -gt 0 ]]; then
|
|
log_warn "Run command failed: '$1'"
|
|
fi
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# HELPER: Get list of connected usb device ids.
|
|
#
|
|
workplace_usb_id_list(){
|
|
lsusb_id_regex='^Bus [0-9]+ Device [0-9]+: ID ([0-9a-f]{4}:[0-9a-f]{4}) .*$'
|
|
lsusb_out=$"$(lsusb)"
|
|
while IFS= read -r line; do
|
|
if [[ "$line" =~ $lsusb_id_regex ]]; then
|
|
echo $line | sed -E "s/$lsusb_id_regex/\1/g"
|
|
fi
|
|
done <<< "$lsusb_out"
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# HELPER: Handle detected setup change.
|
|
#
|
|
trap "workplace_change_flag=1" SIGUSR1
|
|
workplace_handle_change(){
|
|
## CHECK FLAG ##
|
|
# ignore if not set
|
|
if [[ ! ${workplace_change_flag:-""} -gt 0 ]]; then
|
|
return
|
|
fi
|
|
|
|
# unset flag
|
|
workplace_change_flag=0
|
|
|
|
|
|
## DO UPDATE ##
|
|
# reload config
|
|
workplace_config_load
|
|
|
|
# run update function
|
|
workplace_update
|
|
|
|
# sleep to prevent spamming
|
|
snore 1
|
|
}
|
|
|
|
|
|
|
|
## MAIN ##
|
|
case ${1:-""} in
|
|
set)
|
|
workplace_toolcheck
|
|
workplace_config_load
|
|
workplace_set "$2"
|
|
exit 0
|
|
;;
|
|
|
|
update)
|
|
workplace_toolcheck
|
|
workplace_config_load
|
|
workplace_update
|
|
exit 0
|
|
;;
|
|
|
|
updatedaemon)
|
|
workplace_toolcheck
|
|
workplace_updatedaemon
|
|
exit 0
|
|
;;
|
|
|
|
help)
|
|
workplace_help
|
|
exit 0
|
|
;;
|
|
|
|
version)
|
|
workplace_version
|
|
exit 0
|
|
;;
|
|
|
|
"")
|
|
log_error "No command given; See '$0 help' for usage information"
|
|
exit 1
|
|
;;
|
|
|
|
*)
|
|
log_error "Invalid command '$1'; See '$0 help' for usage information"
|
|
exit 1
|
|
;;
|
|
esac
|