Files
dotfiles/bin/linux-toggle-app

174 lines
4.0 KiB
Bash
Executable File

#! /usr/bin/env bash
if [ -n "$DEBUG" ]; then set -x; fi
show-help() {
echo "usage: $(basename "$0") [<options>]"
echo
echo "Toggle visibility of a window belonging to a specific process:"
echo " - If not running the <executable> will be launched."
echo " - If process is running <window-name> (or first window found) will be"
echo " activated and focused."
echo " - If process is running and <window-name> is in focus, minimize it."
echo
echo "Options:"
echo " -p (Required) process name given to pgrep to narrow list of"
echo " possible target windows."
echo " -f Search full process name instead of just the first word."
echo " -e Executable name or path used to launch process when it is not"
echo " running. If not specified, will attempt to use process name"
echo " instead."
echo " -c Command used to launch process when it is not running. Can used"
echo " instead of -e if the launch command is more complex than a"
echo " single executable."
echo " -w Title/name of window which belongs to process to focus on."
echo " Allows regular expression matching. If not specified, the first"
echo " window found belonging to process will be used."
echo " -b Bring window to current desktop if it is on another one."
echo " -a Assign window to all desktops/workspaces after activating it."
echo " -h Display this help message."
echo
echo "Requirements:"
echo " - xdotool"
echo " - wmctrl"
}
error() {
echo -e "ERROR: $*" 1>&2
}
error-help() {
error "$@"
show-help 1>&2
}
OPT_PROC=""
OPT_FULL=""
OPT_BIN=""
OPT_CMD=""
OPT_WIN=""
OPT_BRING=""
OPT_ALL=""
parse-arguments() {
while getopts ":p:e:c:w:fbah" opt; do
case ${opt} in
p)
OPT_PROC="$OPTARG"
;;
f)
OPT_FULL="1"
;;
e)
OPT_BIN="$OPTARG"
;;
c)
OPT_CMD="$OPTARG"
;;
w)
OPT_WIN="$OPTARG"
;;
b)
OPT_BRING="1"
;;
a)
OPT_ALL="1"
;;
h)
show-help
exit 0
;;
\?)
error-help "Invalid option: -${OPTARG}\n" 1>&2
exit 1
;;
esac
done
shift $((OPTIND - 1))
if [ -z "$OPT_PROC" ]; then
error-help "-p option is required."
exit 1
fi
if [ -z "$OPT_BIN" ]; then
OPT_BIN="$OPT_PROC"
fi
if [ -z "$OPT_CMD" ] && ! command -v "$OPT_BIN" &> /dev/null; then
error "\"${OPT_BIN}\" does not seem to be a valid executable."
exit 2
fi
}
main() {
local target
local pid
local win_id
local focused_id
parse-arguments "$@"
mapfile -t target < <(find-window)
pid="${target[0]}"
win_id="${target[1]}"
if [ -z "$pid" ]; then
if [ -n "$OPT_CMD" ]; then
echo "$OPT_PROC not running, launching with: \"$OPT_CMD\""
exec $OPT_CMD
else
echo "$OPT_PROC not running, launching with: \"$OPT_BIN\""
exec "$OPT_BIN"
fi
else
echo "$OPT_PROC instance found"
focused_id="$(xdotool getactivewindow)"
if [ "$win_id" == "$focused_id" ]; then
echo "Target window is in focus, minimizing"
xdotool windowminimize "$win_id"
else
if [ -n "$OPT_BRING" ]; then
echo "Bring window to current desktop and activate"
wmctrl -i -R "$win_id"
if [ -n "$OPT_ALL" ]; then
echo "Assign window to all desktops"
xdotool set_desktop_for_window "$win_id" -1
fi
else
echo "Activating window triggering desktop switch as needed"
xdotool windowactivate "$win_id"
fi
fi
fi
}
find-window() {
local pid
local win_id
local opts
local pgrep_opts
pgrep_opts=()
opts=(--all --onlyvisible)
if [ -n "$OPT_WIN" ]; then
opts+=(--name "$OPT_WIN")
fi
if [ -n "$OPT_FULL" ]; then
pgrep_opts+=(-f)
fi
for pid in $(pgrep "${pgrep_opts[@]}" "$OPT_PROC"); do
win_id="$(xdotool search --pid "$pid" "${opts[@]}")"
if [ -n "$win_id" ]; then
echo -e "$pid\n$win_id"
break
fi
done
}
main "$@"