✨ initial codebase
This commit is contained in:
parent
ccfc21a116
commit
94478aba82
36
lib/color
Normal file
36
lib/color
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
## EMPTY DEFAULTS ##
|
||||||
|
color_bold=""
|
||||||
|
color_underline=""
|
||||||
|
color_standout=""
|
||||||
|
color_normal=""
|
||||||
|
color_black=""
|
||||||
|
color_red=""
|
||||||
|
color_green=""
|
||||||
|
color_yellow=""
|
||||||
|
color_blue=""
|
||||||
|
color_magenta=""
|
||||||
|
color_cyan=""
|
||||||
|
color_white=""
|
||||||
|
|
||||||
|
|
||||||
|
## ONLY IF PRINTING TO A TERMINAL ##
|
||||||
|
if test -t 1; then
|
||||||
|
# check count of supported colors
|
||||||
|
color_count=$(tput colors)
|
||||||
|
if [[ ! -z "$color_count" && "$color_count" -ge 8 ]]; then
|
||||||
|
color_bold="$(tput bold)"
|
||||||
|
color_underline="$(tput smul)"
|
||||||
|
color_standout="$(tput smso)"
|
||||||
|
color_normal="$(tput sgr0)"
|
||||||
|
color_black="$(tput setaf 0)"
|
||||||
|
color_red="$(tput setaf 1)"
|
||||||
|
color_green="$(tput setaf 2)"
|
||||||
|
color_yellow="$(tput setaf 3)"
|
||||||
|
color_blue="$(tput setaf 4)"
|
||||||
|
color_magenta="$(tput setaf 5)"
|
||||||
|
color_cyan="$(tput setaf 6)"
|
||||||
|
color_white="$(tput setaf 7)"
|
||||||
|
fi
|
||||||
|
fi
|
34
lib/ini
Normal file
34
lib/ini
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ini_parse(){
|
||||||
|
local filename="$1"
|
||||||
|
|
||||||
|
sections="$(gawk '{ if ($1 ~ /^\[/) section=tolower(gensub(/\[(.+)\]/,"\\1",1,$1)); configuration[section]=1 } END {for (key in configuration) { print key} }' $filename)"
|
||||||
|
for section in $sections; do
|
||||||
|
array_name="ini_${section}"
|
||||||
|
declare -g -A ${array_name}
|
||||||
|
done
|
||||||
|
|
||||||
|
eval $(gawk -F= '{
|
||||||
|
if($1 ~ /^\[/)
|
||||||
|
section=tolower(gensub(/\[(.+)\]/,"\\1",1,$1))
|
||||||
|
else if($1 !~ /^$/ && $1 !~ /^;/){
|
||||||
|
gsub(/^[ \t]+|[ \t]+$/, "", $1);
|
||||||
|
gsub(/[\[\]]/, "", $1);
|
||||||
|
gsub(/^[ \t]+|[ \t]+$/, "", $2);
|
||||||
|
if(configuration[section][$1] == "")
|
||||||
|
configuration[section][$1]=$2
|
||||||
|
else
|
||||||
|
configuration[section][$1]=configuration[section][$1]" "$2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END {
|
||||||
|
for(section in configuration)
|
||||||
|
for(key in configuration[section]){
|
||||||
|
section_name = section
|
||||||
|
gsub("-", "_", section_name)
|
||||||
|
print "ini_" section_name "[\""key"\"]=\""configuration[section][key]"\";"
|
||||||
|
}
|
||||||
|
}' ${filename}
|
||||||
|
)
|
||||||
|
}
|
40
lib/log
Normal file
40
lib/log
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Log a line with debug level.
|
||||||
|
#
|
||||||
|
log_debug(){
|
||||||
|
echo -ne "${color_green}[DEBUG]${color_normal} " 1>&2
|
||||||
|
echo "$1" 1>&2
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Log a line with info level.
|
||||||
|
#
|
||||||
|
log_info(){
|
||||||
|
echo -ne "${color_blue}[INFO ]${color_normal} " 1>&2
|
||||||
|
echo "$1" 1>&2
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Log a line with warning level.
|
||||||
|
#
|
||||||
|
log_warn(){
|
||||||
|
echo -ne "${color_yellow}[WARN ]${color_normal} " 1>&2
|
||||||
|
echo "$1" 1>&2
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Log a line with error level and exit.
|
||||||
|
#
|
||||||
|
log_error(){
|
||||||
|
echo -ne "${color_red}[ERROR]${color_normal} " 1>&2
|
||||||
|
echo "$1" 1>&2
|
||||||
|
exit 1
|
||||||
|
}
|
23
lib/toolcheck
Normal file
23
lib/toolcheck
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Make sure all required tools are installed.
|
||||||
|
#
|
||||||
|
workplace_toolcheck(){
|
||||||
|
## BINARIES IN PATH ##
|
||||||
|
bin_tool_list=("grep xeventbind")
|
||||||
|
for b in $bin_tool_list; do
|
||||||
|
if [[ ! -f $(which "$b") ]]; then
|
||||||
|
log_error "Missing tool '$b'"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
## DPKG PACKAGES ##
|
||||||
|
dpkg_tool_list=("gawk sed findutils procps usbutils libglib2.0-bin")
|
||||||
|
for d in $dpkg_tool_list; do
|
||||||
|
if ! dpkg -s $d 2>&1 | grep -q "Status: install ok installed"; then
|
||||||
|
log_error "Missing tool '$d'"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
351
workplace
Executable file
351
workplace
Executable file
@ -0,0 +1,351 @@
|
|||||||
|
#!/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"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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 commands `laptop` and `dock`.
|
||||||
|
#
|
||||||
|
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 SET COMMANDS ##
|
||||||
|
local -n workplace_section_name="ini_$workplace_name"
|
||||||
|
for k in "${!workplace_section_name[@]}"; do
|
||||||
|
# make sure this is a `set` command
|
||||||
|
if [[ ! "$k" =~ ^set\. ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# extract command and parameter
|
||||||
|
command=$(echo "$k" | grep -oPe '(?<=^set.).*')
|
||||||
|
param="${workplace_section_name[$k]}"
|
||||||
|
|
||||||
|
# run command
|
||||||
|
workplace_setcommand_run "$command" "$param"
|
||||||
|
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_name="ini_$n"
|
||||||
|
|
||||||
|
# default
|
||||||
|
trigger_default="${workplace_section_name[trigger.default]:-""}"
|
||||||
|
if [[ "$trigger_default" == "true" ]]; then
|
||||||
|
workplace_list_prio_0="${workplace_list_prio_0} $n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# usb-id
|
||||||
|
trigger_usbid="${workplace_section_name[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
|
||||||
|
sleep 0.5s
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# HELPER: (Re-)load config.
|
||||||
|
#
|
||||||
|
workplace_config_load(){
|
||||||
|
# clear used variables
|
||||||
|
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 $(compgen -A variable | grep -oPe '(?<=^ini_).*'); do
|
||||||
|
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
|
||||||
|
sleep 0.1s
|
||||||
|
dconf write /org/gnome/shell/extensions/dash-to-dock/dock-position "'$2'" || true
|
||||||
|
;;
|
||||||
|
|
||||||
|
|
||||||
|
## ERROR HANDLING ##
|
||||||
|
*)
|
||||||
|
log_error "Invalid setcommand '$1'"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
sleep 1s
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 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
|
5
workplace.desktop
Normal file
5
workplace.desktop
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Name=WorkPlace Update Daemon
|
||||||
|
Type=Application
|
||||||
|
Exec=~/.local/bin/workplace updatedaemon
|
||||||
|
Terminal=false
|
17
workplace.template.ini
Normal file
17
workplace.template.ini
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[laptop]
|
||||||
|
trigger.default = true
|
||||||
|
|
||||||
|
set.dash-to-dock.position = BOTTOM
|
||||||
|
set.text-scaling-factor = 1.3700000000000001
|
||||||
|
set.powerprofile = power-saver
|
||||||
|
set.volume = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[dock]
|
||||||
|
trigger.usb-id = 1234:5678
|
||||||
|
|
||||||
|
set.dash-to-dock.position = LEFT
|
||||||
|
set.text-scaling-factor = 1.0
|
||||||
|
set.powerprofile = balanced
|
||||||
|
set.volume = 90
|
Loading…
Reference in New Issue
Block a user