123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- #!/bin/bash
- #------------------------------------------------------------------------------
- # Modifies the volume according to the passed argument and uses the ratpoison
- # window manager to draw a volume volume bar. By default increases volume when
- # called.
- #
- # Dependencies:
- # - amixer and/or pulsemixer (used to fetch and set audio value)
- # - ratpoison
- #
- # Notes:
- # - So that ratpoison can output unicode while we use unicode sequences, we
- # need to assign potential unicode characters using printf -v
- # - When the script is executed multiple times in a row (say, when the user is
- # quickly changing the volume), ratpoison would not properly restore the
- # bar gravity to what it was. To avoid this, we prefer to exit early if a
- # specific lockfile (/tmp/ratvol.lock) exists.
- # - Reasoning for disabling set -u:
- # Seting a variable declared as an integer (declare -i) to a string,
- # causes it to have value 0. This script (ab)uses this behaviour for
- # error handling, since it saves us the use of two regexes calls to
- # validate user input for the barsize and step arguments. Since set -u
- # conflicts with this behaviour (it raises variable unbound error on string
- # assigments to integer variables), I have disabled it.
- #------------------------------------------------------------------------------
- set -e -o pipefail
- # Desc:
- # Stop script execution and output a foramtted error message.
- # Args:
- # $@: string
- # contents of the error message
- die() {
- local err_msg="ratvol: ${@}"
- ratpoison -c "echo ${err_msg}" # Also print error message in ratpoison
- printf '%s\n' "${err_msg}"
- printf "Try ratvol -h for more information\n"
- exit 1;
- }
- usage() {
- cat <<-USAGE_END
- Usage: ratvol [OPTIONS] [+]
- Modifies the master volume, by default decreasing it, and draws a volume
- bar using ratpoison.
- -c, --character [character] Character used to fill volume bar, it must be only one
- -g, --gravity [gravity] Where the volume bar should be drawn Valid positions are:
- nw, w, sw, n, c, s, ne, e, se
- -s, --step [step] How much the volume the volume step should be
- -p, --percentage Show the percentage level
- -t, --msgtime Duration that the volume bar will stay on screen
- -h, --help Prints this message
- USAGE_END
- exit ${1}
- }
- # Desc:
- # Draws a volume bar using ratpoison.
- # Args:
- # $1: int volume
- # The percentage of the current volume level
- # $2: enum(nw|w|sw|n|c|s|ne|e|se) gravity
- # Where should ratpoison draw the bar (the gravity)
- # $3: bool show_percentage
- # Whether or not to show the percentage value in the bar
- # $4: char fill_char
- # The character used to fill the volume bar
- # $5: int barsize
- # The size of the volume bar
- # $6: int max_vol
- # The maximum volume that audio backend allows
- # $7: int msgtime
- # The amount of time the volume bar stays on the screen
- # $8: int icon
- # The icon, if any, that should appear in the beginning of the bar
- drawbar() {
- local -r volume=${1} gravity=${2} show_percentage=${3}
- local -r fill_char=${4} barsize=${5} max_vol=${6} msgtime=${7}
- local -r old_gravity=$(ratpoison -c 'set bargravity')
- local -r old_msgtime=$(ratpoison -c 'set msgwait')
- local -r filled=$((barsize * volume / max_vol))
-
- # Format volbar according to icon
- local volbar
- # Escape the '%' so printf can output it
- [[ ${8} == '%' ]] && local -r icon="%${8}"
- if [[ -z ${icon} ]] ; then
- # Empty if there is no icon
- local volbar=""
- else
- # Use printf to handle unicode
- printf -v volbar "${icon} "
- fi
- for ((i=0 ; i < barsize; i++)) ; do
- # Draw the percentage
- if ${show_percentage} && ((i == barsize / 2 - 2 )); then
- volbar+="[${volume}%]"
- fi
- # Draw the filled part of the volume bar
- if ((i < filled)) ; then
- volbar+=${fill_char}
- continue
- fi
- # Fill the remainder with empty space
- volbar+=' '
- done
- # Prepare ratpoison for drawing
- ratpoison -c "set bargravity ${gravity}"
- ratpoison -c "set msgwait ${msgtime}"
-
- # Draw the bar
- ratpoison -c "echo ${volbar}"
-
- # Restore changed settings
- ratpoison -c "set bargravity ${old_gravity}"
- ratpoison -c "set msgwait ${old_msgtime}"
- }
- main() {
- # Handles race issues when various calls are made in quick sucession
- local -r lockfile='/tmp/ratvol.lock'
- [[ -e ${lockfile} ]] && exit
- trap "rm ${lockfile}" EXIT
- touch ${lockfile}
- local -r volregex='[[:digit:]]*(?=%)'
- local -r block_char='\u2588'
- local -i barsize=34
- local -i step=5
- local -i max_vol=100
- printf -v icon '\u266a'
- printf -v character "${block_char}"
- msgtime=1
- show_percentage=false
- gravity='nw'
- op='-'
- short_opts='hpg:s:S:t:i:c:'
- long_opts='help,show-percentage,no-icon,gravity:,step:,barsize:,msgtime:,character:'
- parsed=$(getopt --options ${short_opts} --longoptions ${long_opts} -n 'compiled' -- "${@}")
- [[ $? != 0 ]] && die 'Try ratvol -h for more information'
- eval set -- "${parsed}"
- while true; do
- case "${1}" in
- -g|--gravity)
- gravity="${2}"
- shift 2
- ;;
- -p|--percentage)
- show_percentage=true
- shift
- ;;
- -s|--step)
- step="${2}"
- shift 2
- ;;
- -i|--icon)
- icon="${2}"
- shift 2
- ;;
- -t|--msgtime)
- msgtime="${2}"
- shift 2
- ;;
- -t|--step)
- step="${2}"
- shift 2
- ;;
- -S|--barsize)
- barsize="${2}"
- shift 2
- ;;
- -c|--character)
- printf -v character "${2}"
- shift 2
- ;;
- --)
- shift
- break
- ;;
- -h|--help) usage 0 ;;
- *)
- echo 'Internal error.' >&2
- exit 1
- ;;
- esac
- done
- # Input validation
- [[ ${gravity} != @(nw|w|sw|n|c|s|ne|e|se) ]] && die "Bad value for gravity: ${gravity}"
- ((${#character} != 1)) && die "Character must have a length of 1: ${character}"
- ((${step} <= 0)) && die "Step can't be less than 0: ${step}"
- ((${barsize} <= 0)) && die "Barsize can't be less than 0: ${barsize}"
- ((${msgtime} <= 0)) && die "Msgtime can't be less than 0: ${msgtime}"
- # Handle invalid volume operation and extra invalid arguments
- if ((${#} >= 1)) ; then
- ((${#} > 1)) && die "Unrecognized arguments: ${@}"
- if [[ ${1} == '+' ]] ; then
- op='+'
- elif [[ ${1} == '-' ]] ; then
- : # nop
- else
- die "Unrecognized argument: ${1}"
- fi
- fi
- # Check if pulsemixer exists
- if [[ -n $(type -P pulsemixer) ]] ; then
- volume="$(pulsemixer --change-volume ${op}5 --get-volume)"
- # pulsemixer gives two audio levels, we only need one, so we cut the second
- volume=${volume% *}
- max_vol=150
- else
- volume="$(amixer set Master ${step}%${op} | grep -Po ${volregex})"
- fi
- drawbar\
- ${volume} ${gravity} ${show_percentage}\
- ${character} ${barsize} ${max_vol}\
- ${msgtime} ${icon}
- }
- main $@
|