Skip to content

Instantly share code, notes, and snippets.

@mpontus
Created November 15, 2020 04:20
Show Gist options
  • Save mpontus/b55878689731194964ff27999273680f to your computer and use it in GitHub Desktop.
Save mpontus/b55878689731194964ff27999273680f to your computer and use it in GitHub Desktop.
Launch an application or bring existing window to the front
#!/bin/bash
#
# Sources I found useful:
# - Messing around with WM and windows: https://askubuntu.com/a/127329
# - Command-line arguments: https://stackoverflow.com/a/29754866
#
# I also needed to run a .desktop file. So you just gonna try to
# `locate .desktop | grep -i whatever`, then link whatever you've got
# to either `{/usr{,/local},~/.local}/share/applications/`. Then you
# can run `gtk-launch emacs.desktop`, whatever.. you can omit
# ".desktop" if you'd like.
function usage {
echo "Usage: $0 [-R] [-W <wmclass>] [-c <command>] [--] [<name>]"
echo "-R switch to workspace with found window"
echo "-W search window by classname"
echo "-c command to run to spawn new instance"
echo;
echo "Unless -c is specified, name will be used to run the program no "
echo "windows are found. If -W is not specified, then window title will be "
echo "used for search instead. Use -R to move to the window's workspace, "
echo "instead of bringing it up. ";
exit 1
}
# # saner programming env: these switches turn some bugs into errors
# set -o errexit -o pipefail -o noclobber -o nounset
# Actually a small nuisance here, but I'm keeping it as a snippet
set -o pipefail -o noclobber -o nounset
# -allow a command to fail with !’s side effect on errexit
# -use return value from ${PIPESTATUS[0]}, because ! hosed $?
! getopt --test || usage
if [[ ${PIPESTATUS[0]} -ne 4 ]]; then
echo 'I’m sorry, `getopt --test` failed in this environment.'
exit 1
fi
# -regarding ! and PIPESTATUS see above
# -temporarily store output to be able to check for errors
# -activate quoting/enhanced mode (e.g. by writing out “--options”)
# -pass arguments only via -- "$@" to separate them correctly
! PARSED=$(getopt --options=c:W:R --name "$0" -- "$@")
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
# e.g. return value is 1
# then getopt has complained about wrong arguments to stdout
exit 2
fi
# read getopt’s output this way to handle the quoting right:
eval set -- "$PARSED"
name= wmcls= cmd= move= win=
# now enjoy the options in order and nicely split until we see --
while true; do
case "$1" in
-c)
cmd="$2"
shift 2
;;
-R)
move=y
shift
;;
-W)
wmcls="$2"
shift 2
;;
--)
shift
break
;;
*)
echo "Programming error"
exit 3
;;
esac
done
# handle non-option arguments
if [[ $# -ne 1 && -z "$wmcls" ]]; then
echo "$0: Window title is required"
exit 4
fi
name="$@"
if [ -z "$cmd" ]; then
cmd="$@"
fi
if [[ -n "$wmcls" ]]; then
win=$(xdotool search --onlyvisible --limit 1 --class "$wmcls")
if [[ -z "$win" ]]; then
win=$(xdotool search --limit 1 --classname "$wmcls")
fi
elif [[ -n "$name" ]]; then
win=$(xdotool search --onlyvisible --limit 1 --name "$name")
if [[ -z "$win" ]]; then
win=$(xdotool search --limit 1 --name "$name")
fi
fi
# Window class you can find uing `xprop WM_CLASS`
if [ -z "$win" ]; then
# we could not find the window
eval "$cmd" &
elif [[ "$win" == "$(xdotool getactivewindow)" ]]; then
# toggle active window
xdotool windowminimize "$win"
elif [ -z "$move" ]; then
# switch to the window
wmctrl -i -R "$win"
else
# bring the window up
wmctrl -i -R "$win"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment