summaryrefslogtreecommitdiff
path: root/scripts/lib
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib')
-rw-r--r--scripts/lib/lib_common.sh134
-rw-r--r--scripts/lib/lib_handle.sh140
2 files changed, 274 insertions, 0 deletions
diff --git a/scripts/lib/lib_common.sh b/scripts/lib/lib_common.sh
new file mode 100644
index 0000000..58ee5ba
--- /dev/null
+++ b/scripts/lib/lib_common.sh
@@ -0,0 +1,134 @@
+#!/bin/sh
+
+progname=$(basename "${0}")
+
+# @FUNCTION: err
+# @USAGE: [-x] <message> ...
+# @DESCRIPTION:
+# Print given messages to stderr line by line and exit with status 1.
+#
+# If "-x" is specified, suppress the program prefix (`program: `)
+# from the output. Otherwise, the first line is prefixed with "program: ".
+#
+# This function is intended for fatal errors; it always exits the script.
+# @EXAMPLE:
+# err "Invalid usage" "Try '${progname} -h' for help."
+err() {
+ if [ "${1}" != "-x" ]; then
+ printf "%s: " "${progname}"
+ else
+ shift
+ fi
+
+ for line in "${@}"; do
+ echo "${line}" >&2
+ done
+ exit 1
+}
+
+# @FUNCTION: invalid_use
+# USAGE: [-h]
+# @DESCRIPTION:
+# Output a usage error message. If `-h` is not specified output:
+# "<program>: Invalid usage "
+# "Try 'program -h' for help."
+# else output only:
+# "Try 'program -h' for help."
+
+invalid_use() {
+ [ "${1}" = "-h" ] && err -x "Try '${progname} -h' for help."
+ err "Invalid usage" "Try '${progname} -h' for help."
+}
+
+# @FUNCTION: check_program
+# USAGE: <command> [error-msg]
+# @DESCRIPTION:
+# Check if command exists on the system.
+# If not, print an error message to stderr and exit with status 1.
+# The default error message is "`command` must be installed"
+# but can optionally be overwritten.
+#
+# @EXAMPLE:
+# Check if pulseaudio is installed.
+#
+# check_program "pactl" "pulseaudio must be installed"
+
+check_program() {
+ command -v "${1}" > /dev/null 2>&1 && return 0
+ [ -n "${2}" ] && err "${2}"
+ err "${1} must be installed"
+}
+
+# @FUNCTION: get_random_filename
+# @USAGE: get_random_filename [parentdir] <extension>
+# @DESCRIPTION:
+# Write a random file path to stdout, under parentdir, (if provided else under /tmp) with the extension.
+#
+# @EXAMPLE:
+# Get a filepath in the `/var` directory with the extension `.png`
+#
+# get_random_filename .png /var
+
+get_random_filename() {
+ [ "${#}" -eq 2 ] && parentdir="${2}" || parentdir="/tmp"
+
+ extension="${1}"
+
+ echo "${parentdir}/$(date '+%b%d::%H%M%S')${extension}"
+}
+
+# @FUNCTION: run
+# @USAGE: [--reload-status] [--reload-compositor] [--success-notify <msg>] [--failure-notify <msg>] <command> [success-msg] [failure-msg]
+# @DESCRIPTION:
+# Safely execute a simple shell command, print optional success/failure messages,
+# and optionally reload the status bar or restart the compositor.
+#
+# Success messages are printed to stdout; failure messages are printed to stderr.
+# Optional desktop notifications can be sent using --success-notify and --failure-notify.
+# Command output is not suppressed.
+#
+# Options:
+# --reload-status Reload the status bar (via `slreload`).
+# --reload-compositor Restart the compositor (kills and restarts `picom`).
+# --success-notify <msg> Send a desktop notification on success.
+# --failure-notify <msg> Send a desktop notification on failure.
+#
+# Restrictions:
+# - Does NOT use `eval`; only simple commands and arguments are supported.
+# - Shell operators like `&&`, `||`, `|`, `>`, `>>`, etc. will NOT work.
+# - This design prevents unintended execution and makes the function safe in scripts.
+#
+# Return value:
+# Exits with 0 if the command succeeds, 1 otherwise.
+#
+# @EXAMPLES:
+# # Run xwallpaper and print the image path on success
+# run "xwallpaper --zoom ${image}" "${image}"
+#
+# # Restart compositor and show a success message
+# run --reload-compositor "xwallpaper --zoom ${image}" "Wallpaper updated" "Wallpaper failed"
+#
+# # With notification hooks
+# run --success-notify "Wallpaper set" \
+# --failure-notify "Wallpaper failed" \
+# "xwallpaper --zoom ${image}" "Wallpaper updated" "Wallpaper failed"
+
+run() {
+ no_exit=0
+ reload_status=0
+ reload_compositor=0
+
+ [ "${1}" = "--no-exit" ] && no_exit=1 && shift
+ [ "${1}" = "--reload-status" ] && reload_status=1 && shift
+ [ "${1}" = "--reload-compositor" ] && reload_compositor=1 && shift
+
+ trap '
+ [ "${reload_status}" -eq 1 ] && status_handle reload
+ [ "${reload_compositor}" -eq 1 ] && compositor_handle start
+ ' EXIT
+
+ [ "${reload_compositor}" -eq 1 ] && compositor_handle stop
+
+ eval "${@}"
+ [ "${no_exit}" -eq 1 ] || exit "${?}"
+}
diff --git a/scripts/lib/lib_handle.sh b/scripts/lib/lib_handle.sh
new file mode 100644
index 0000000..d4524d9
--- /dev/null
+++ b/scripts/lib/lib_handle.sh
@@ -0,0 +1,140 @@
+#!/bin/sh
+. "lib_common.sh"
+
+volume_handle() {
+ case "${1}" in
+ "up") pactl set-sink-volume @DEFAULT_SINK@ +"${2}"% ;;
+ "down") pactl set-sink-volume @DEFAULT_SINK@ -"${2}"% ;;
+ "set") pactl set-sink-volume @DEFAULT_SINK@ "${2}"% ;;
+ "toggle") pactl set-sink-mute @DEFAULT_SINK@ toggle;;
+ "get-current")
+ pactl get-sink-volume @DEFAULT_SINK@ |
+ sed -n 's/.* \([0-9][0-9]*%\).*/\1/p'
+ ;;
+ "check_program")
+ check_program "pactl" "pulseaudio must be installed" ;;
+
+ esac
+}
+
+brightness_handle() {
+ case "${1}" in
+ "up") brightnessctl set +"${2}"% ;;
+ "down") brightnessctl set "${2}"-% ;;
+ "set") brightnessctl set "${2}"% ;;
+ "get-current")
+ printf '%s\n' \
+ $(( ($(brightnessctl g) * 100) / $(brightnessctl m) ))
+ ;;
+ "check_program") check_program "brightnessctl"
+ esac
+}
+
+screenshot_handle() {
+ case "${1}" in
+ "fullscreen") flags="-z" ;;
+ "select") flags="-zs" ;;
+ "focused-window") flags="-zu" ;;
+ "check_program")
+ check_program "scrot"
+ return
+ ;;
+ esac
+ shift
+ scrot "${flags}" "${1}"
+}
+
+wallpaper_handle() {
+ case "${1}" in
+ "clear") xwallpaper --clear ;;
+ "set") xwallpaper --zoom "${2}" ;;
+ "check_program") check_program "xwallpaper" ;;
+ esac
+
+}
+
+screenlock_handle() {
+ if [ "${#}" -eq 0 ]; then
+ slock
+ else
+ slock -f "${1}"
+ fi
+}
+
+input_device_handle() {
+ case "$1" in
+ "enable") xinput enable "${2}";;
+ "disable") xinput disable "${2}";;
+ "list") xinput list ;;
+ "get-id")
+ dev=$(xinput list --name-only | grep -i -m1 "${1}" ) || return 1
+ printf "${dev#∼ }"
+ ;;
+ "is_enabled")
+ xinput list-props "${2}" | grep -q "Device Enabled.*1$"
+ return $?
+ ;;
+ "check_program") check_program "xclip" ;;
+ esac
+}
+
+clipboard_handle() {
+ case "${1}" in
+ "text") xclip -selection clipboard ;;
+ "file") xclip -selection clipboard -t "${2}" -i "${3}" ;;
+ "get-clipboard") xclip -o -selection clipboard ;;
+ esac
+}
+
+image_handle() {
+ case "${1}" in
+ "blur") mogrify -blur 0x8 "${2}" ;;
+ "check_program")
+ check_program "mogrify" "imagemagick must be installed"
+ ;;
+ esac
+}
+
+file_handle() {
+ file=$2
+ case $1 in
+ get-mime_type)
+ m=$(file --mime-type -b "$file" 2>/dev/null) && { echo "$m"; return; }
+ m=$(file -I "$file" 2>/dev/null) && { m=${m#*: }; m=${m%%;*}; echo "$m"; return; }
+ m=$(file -i "$file" 2>/dev/null) && { m=${m#*: }; m=${m%%;*}; echo "$m"; return; }
+ return 1
+ ;;
+ esac
+}
+
+notify_handle() {
+ case "${1}" in
+ "reload") xsetroot -name "fsignal:1" ;;
+ "send")
+ echo "${2}" > /tmp/noti.fifo
+ shift 2
+ printf "%s\n" "$*" > /tmp/noti.txt
+ xsetroot -name "fsignal:1"
+ ;;
+ esac
+}
+
+compositor_handle() {
+ case "${1}" in
+ "start") pgrep -x picom >/dev/null || picom -b & ;;
+ "stop") pgrep -x picom >/dev/null && pkill -x picom ;;
+ esac
+}
+
+status_handle() {
+ [ "${1}" = "reload" ] && slreload
+}
+
+menu_handle() {
+ case "${1}" in
+ "default") flags="" ;;
+ "center") flags="-bw 1 -c -g 1 -l 25" ;;
+ esac
+ shift
+ dmenu ${flags}
+}