#! /usr/bin/env bash if [ -n "$DEBUG" ]; then set -x; fi show-help() { echo "usage: $(basename "$0") []" echo echo "Toggle visibility of a window belonging to a specific process:" echo " - If not running the will be launched." echo " - If process is running (or first window found) will be" echo " activated and focused." echo " - If process is running and 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 "$@"