diff --git a/bin/compton-trans b/bin/compton-trans index f813433..6beeabf 100755 --- a/bin/compton-trans +++ b/bin/compton-trans @@ -7,6 +7,7 @@ # # Usage: +# $ compton-trans [options] [+|-]opacity # By window id # $ compton-trans -w "$WINDOWID" 75 # By name @@ -18,117 +19,190 @@ # $ compton-trans -s 75 # Increment current window 5% # $ compton-trans -c +5 +# Delete current window's opacity +# $ compton-trans -c --delete +# Reset all windows +# $ compton-trans --reset # "command" is a shell built-in, faster than "which" if test -z "$(command -v xprop)" -o -z "$(command -v xwininfo)"; then - echo "Please install x11-utils/xorg-xprop/xorg-xwininfo." >& 2 + echo 'Please install x11-utils/xorg-xprop/xorg-xwininfo.' >& 2 exit 1 fi +# Variables +active= +wprefix= window= opacity= cur= -i= +action= +treeout= +wid= +topmost= +lineno= +option= +v= -# Read options -while getopts "scn:w:o:" option; do - case "$option" in - s) wprefix=''; window='' ;; - c) - active=$(xprop -root -notype "_NET_ACTIVE_WINDOW" \ - | sed 's/^.*\(0x\S*\).*$/\1/') - wprefix='-id '; window="$active" - ;; - n) wprefix='-name '; window="$OPTARG" ;; - w) wprefix='-id '; window="$OPTARG" ;; - o) opacity="$OPTARG" ;; - \?) exit 1;; - esac +# Workaround: replace '-5' with '~5' so as not to confuse getopts. +for v in "$@"; do + shift && set -- "$@" "$(echo "$v" | sed 's/^-\([0-9]\+%\?\)$/~\1/')" done -# Read positional arguments -shift $(($OPTIND - 1)) -[ -n "$1" ] && opacity="$1" +# This takes into account the fact that getopts stops on +# any argument it doesn't recongize or errors on. This +# allows for things like `compton-trans -5` as well +# as `compton-trans -c +5 -s` (contrived example). +while test $# -gt 0; do + # Reset option index + OPTIND=1 + + # Read options + while getopts 'scrdgn:w:o:-:' option "$@"; do + if test "$option" = '-'; then + case "$OPTARG" in + select | current | reset | delete | get) + v='' + ;; + name | window | opacity) + eval v=\$$OPTIND + OPTIND=$((OPTIND + 1)) + ;; + name=* | window=* | opacity=*) + v=$(echo "$OPTARG" | sed 's/^[^=]\+=//') + ;; + *) + echo "$0: illegal option $OPTARG" >& 2 + exit 1 + ;; + esac + option=$(echo "$OPTARG" | cut -c 1) + OPTARG=$v + fi + case "$option" in + s) wprefix=''; window='' ;; + c) + active=$(xprop -root -notype _NET_ACTIVE_WINDOW \ + | sed 's/^.*\(0x\S*\).*$/\1/') + wprefix='-id'; window=$active + ;; + r) action='reset' ;; + d) action='delete' ;; + g) action='get' ;; + n) wprefix='-name'; window=$OPTARG ;; + w) wprefix='-id'; window=$OPTARG ;; + o) opacity=$OPTARG ;; + \?) exit 1 ;; + esac + done + + # Read positional arguments + shift $((OPTIND - 1)) + test -n "$1" && opacity=$1 && shift +done + +# clean up opacity. xargs == a poor man's trim. +opacity=$(echo "$opacity" | xargs | sed 's/%//g' | sed 's/^~\([0-9]\+\)$/-\1/') # Validate opacity value -if [ -z "$opacity" ]; then - echo "No opacity specified." +if test -z "$action" && ! echo "$opacity" | grep -q '^[+-]\?[0-9]\+$'; then + echo "Invalid opacity specified: $opacity." exit 1 fi -opacity="$(echo "$opacity" \ - | sed -rn 's/^[[:space:]]*([+-]?[[:digit:]]+)[[:space:]]*$/\1/p')" - -if [ -z "$opacity" ]; then - echo "Invalid opacity value." - exit 1 +# Reset opacity for all windows +if test x"$action" = x'reset'; then + xwininfo -root -tree \ + | sed -n 's/^ \(0x[[:xdigit:]]*\).*/\1/p' \ + | while IFS=$'\n' read wid; do + xprop -id "$wid" -remove _NET_WM_WINDOW_OPACITY + done + exit 0 fi # Get ID of the target window -if [ -z "$wprefix" ]; then +if test -z "$wprefix"; then treeout=$(xwininfo -children -frame) else - treeout=$(xwininfo -children $wprefix"$window") + test "$wprefix" = '-id' \ + && ! echo "$window" | grep -q '^\(0x\)\?[0-9a-fA-F]\+$' \ + && echo 'Bad window ID.' && exit 1 + treeout=$(xwininfo -children $wprefix "$window") fi wid=$(echo "$treeout" | sed -n 's/^xwininfo:.*: \(0x[[:xdigit:]]*\).*$/\1/p') -if [ -z "$wid" ]; then - echo "Failed to find window." +if test -z "$wid"; then + echo 'Failed to find window.' exit 1 fi # Make sure it's not root window -if echo "$treeout" | fgrep "Parent window id: 0x0" > /dev/null; then - echo "Cannot set opacity on root window." +if echo "$treeout" | fgrep -q 'Parent window id: 0x0'; then + echo 'Cannot set opacity on root window.' exit 1 fi # If it's already the topmost window -if echo "$treeout" | grep "Parent window id: 0x[[:xdigit:]]* (the root window)" > /dev/null; then - topmost="$wid" +if echo "$treeout" | grep -q 'Parent window id: 0x[[:xdigit:]]* (the root window)'; then + topmost=$wid else # Get the whole window tree - treeout="$(xwininfo -root -tree)" + treeout=$(xwininfo -root -tree) - if [ -z "$treeout" ]; then - echo "Failed to get root window tree." + if test -z "$treeout"; then + echo 'Failed to get root window tree.' exit 1 fi # Find the line number of the target window in the window tree - lineno="$(echo -n "$treeout" | grep -nw "$wid" | head -n1 | cut -d ':' -f 1)" + lineno=$(echo -n "$treeout" | grep -nw "$wid" | head -n1 | cut -d ':' -f 1) - if [ -z "$lineno" ]; then - echo "Failed to find window in window tree." + if test -z "$lineno"; then + echo 'Failed to find window in window tree.' exit 1 fi # Find the highest ancestor of the target window below - topmost=$(echo -n "$treeout" | head -n $(($lineno + 1)) | sed -n 's/^ \(0x[[:xdigit:]]*\).*/\1/p' | tail -n1) + topmost=$(echo -n "$treeout" \ + | head -n $((lineno + 1)) \ + | sed -n 's/^ \(0x[[:xdigit:]]*\).*/\1/p' \ + | tail -n 1) fi -if [ -z "$topmost" ]; then - echo "Failed to find the highest parent window below root of the" \ - "selected window." +if test -z "$topmost"; then + echo 'Failed to find the highest parent window below root of the' \ + 'selected window.' exit 1 fi -# Calculate the desired opacity -if echo "$opacity" | grep '^[+-]' > /dev/null; then - sign=$(echo "$opacity" | cut -b1) - cur=$(xprop -id "$topmost" -notype "_NET_WM_WINDOW_OPACITY" \ - | sed 's/^.*\b\([0-9]\+\).*$\|^.*$/\1/') - [ -z "$cur" ] && cur=0xffffffff - cur=$((cur * 100 / 0xffffffff)) - opacity="$(echo "$opacity" | sed 's/^[+-]//')" - opacity=$(($cur $sign $opacity)) +# Remove the opacity property. +if test x"$action" = x'delete'; then + xprop -id "$topmost" -remove _NET_WM_WINDOW_OPACITY + exit 0 fi -[ $opacity -lt 0 ] && opacity=0 -[ $opacity -gt 100 ] && opacity=100 +# Get current opacity. +cur=$(xprop -id "$topmost" -notype _NET_WM_WINDOW_OPACITY \ + | sed 's/^.*\b\([0-9]\+\).*$\|^.*$/\1/') +test -z "$cur" && cur=0xffffffff +cur=$((cur * 100 / 0xffffffff)) + +# Output current opacity. +if test x"$action" = x'get'; then + echo "$cur" + exit 0 +fi + +# Calculate the desired opacity +if echo "$opacity" | grep -q '^[+-]'; then + opacity=$((cur + opacity)) +fi + +test $opacity -lt 0 && opacity=0 +test $opacity -gt 100 && opacity=100 # Set opacity -opacity=$(($opacity * 0xffffffff / 100)) +opacity=$((opacity * 0xffffffff / 100)) xprop -id "$topmost" -f _NET_WM_WINDOW_OPACITY 32c \ -set _NET_WM_WINDOW_OPACITY "$opacity"