Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

307 lines
7.8 KiB

#!/usr/bin/zsh
#
# Setup outputs with xrandr as a backend and dmenu as a frontend
#
# external commands: cat, cut, dmenu, grep, sed, xrandr
# Released under GPLv2
#
typeset XRANDR_TXT # readonly; stdout of running xrandr without any options
typeset -A OUTPUT_CONFIGURED # key=connected output name
typeset -a DISCONNECT_OUTPUTS
typeset OPT_MODE='auto'
typeset OPT_ROTATION='normal'
typeset -ir EXIT_CLEAN=7
typeset -ir ERR_BAD_ARGS=257
typeset -ir ERR_BAD_SELECTION=258
typeset -ir ERR_NO_OPTIONS=259
if ! command -v cat &>/dev/null; then
echo 'coreutils seem to be missing. You'\''re gonna have a bad time.' >&2
exit 255
elif ! command -v grep &>/dev/null; then
echo 'grep seems to be missing. You'\''re gonna have a bad time.' >&2
exit 255
elif ! command -v xrandr &>/dev/null; then
echo 'Ran xrandr-dmenu without xrandr? You'\''re gonna have a bad time.' >&2
exit 255
elif ! command -v dmenu &>/dev/null; then
echo 'Ran xrandr-dmenu without dmenu? You'\''re gonna have a bad time.' >&2
exit 255
elif ! xset q &>/dev/null; then
echo 'Woah there, cowboy! You need to run this from inside X!' >&2
exit 1
fi
XRANDR_TXT="$(xrandr)" || exit $?
function () {
typeset opt
typeset output
typeset help_msg="usage: xrandr-dmenu [options]
Setup X outputs position, mode, etc
Input 'exit' or press 'ESC' at any point to cancel.
Options:
-m Select mode for outputs
-M Use current mode for outputs
-r Select rotation for outputs
-R Use current rotation for outputs"
while getopts mMrRh opt; do
case "${opt}" in
('m') OPT_MODE='change' ;;
('M') OPT_MODE='no_change' ;;
('r') OPT_ROTATION='change' ;;
('R') OPT_ROTATION='no_change' ;;
('h')
echo "${help_msg}"
exit 0
;;
('?')
echo "${help_msg}"
exit 1
;;
esac
done
for output in $(grep ' connected' <<< "${XRANDR_TXT}" | cut -d ' ' -f 1); do
OUTPUT_CONFIGURED[${output}]='false'
done
for output ($(grep ' disconnected' <<< "${XRANDR_TXT}" | cut -d ' ' -f 1)) {
DISCONNECTED_OUTPUTS+=("${output}")
}
} "$@"
typeset -r XRANDR_TXT
typeset -r OPT_MODE
typeset -r OPT_ROTATION
typeset -r DISCONNECTED_OUTPUTS
function main() {
typeset prompt
typeset menu
typeset output
typeset mode
typeset rotation
typeset position
typeset xrandr_cmd
# set primary output
prompt='Select primary output:'
output="$(menu_select "${prompt}" ${(k)=OUTPUT_CONFIGURED})"
[ "$output" = "eDP1" ] && bail 1
position='--primary'
mode="$(select_mode ${output})" || bail $?
rotation="$(select_rotation ${output})" || bail $?
OUTPUT_CONFIGURED[${output}]='true'
xrandr_cmd="xrandr --output ${output} ${position} ${rotation} ${mode}"
# set additional outputs
prompt='Select next output:'
while ! all_outputs_configured; do
menu="$(list_unconfigured_outputs)"
output="$(menu_select ${prompt} ${=menu})" || bail $?
position="$(select_position ${output})" || bail $?
if [[ "${position}" != '--off' ]]; then
mode="$(select_mode ${output})" || bail $?
rotation="$(select_rotation ${output})" || bail $?
fi
OUTPUT_CONFIGURED[${output}]='true'
xrandr_cmd+=" --output ${output} ${position} ${rotation} ${mode}"
done
if [ "$(pidof x11vnc)" ]; then
killvnc="$(printf "no\nyes" | dmenu -p "Would you like to kill existing vnc display?")"
if [ "$killvnc" = "yes" ]; then
xrandr --output HDMI2 --off
killall -9 x11vnc
vnc="$(printf "no\nyes" | dmenu -p "Would you like to connect to your ipad?")"
fi
else
vnc="$(printf "no\nyes" | dmenu -p "Would you like to connect to your ipad?")"
fi
if [ "$vnc" = "yes" ]; then
$HOME/.local/bin/ipad_xrandr.sh
pidof x11vnc && notify-send -t 60000 -a " Network info" "$(echo -e "wlan0: $wlan\neth0: $eth\nRunning on port 5900")"
fi
# forcibly '--off' disconnected outputs
for output in ${DISCONNECTED_OUTPUTS}; do
xrandr_cmd+=" --output ${output} --off"
done
# do the deed
if ! ${=xrandr_cmd}; then
echo "Failed to execute xrandr command:\n${xrandr_cmd}"
bail 255
fi
}
################################################################################
# Uses dmenu to select the position of a given output relative to an already
# configured output. --same-as and --off are considered a position.
# Prints in the form of xrandr option (eg, '--right-of DP1') to stdout
# Global variables:
# ERR_BAD_ARG
# Arguments:
# $1=name of output to configure
# Returns:
# ERR_BAD_ARG for no $1
################################################################################
function select_position() {
[[ -z $1 ]] && return "${ERR_BAD_ARG}"
typeset output
typeset prompt
typeset -a menu
typeset anchor
typeset position
typeset selection
output="$1"
prompt="Select position of ${output}:"
for anchor in $(list_configured_outputs); do
for position in 'left of' 'right of' 'above' 'below' 'same as'; do
menu+=("${position} ${anchor}")
done
done
menu+=('off')
selection="$(menu_select "${prompt}" ${menu})" || return $?
case "${selection[(w)1]}" in
(left|right|same) echo "--${selection/ /-}" ;;
(above|below|mirror|off) echo "--${selection}" ;;
esac
}
################################################################################
# Uses dmenu to display the detected mode options for a given output and lets
# the user select a mode to use. Prints choice in xrandr option format
# (eg, '--mode 800x600' or '--auto') to stdout
# Global variables:
# XRANDR_TXT
# OPT_MODE
# ERR_BAD_ARGS
# Arguments:
# $1 - name of which output we are working with
# Returns:
# ERR_BAD_ARGS
################################################################################
function select_mode() {
[[ -z $1 ]] && return "${ERR_BAD_ARGS}"
typeset output
typeset prompt
typeset menu
typeset selection
output="$1"
prompt="Select mode for ${output}:"
if [[ "${OPT_MODE}" == 'auto' ]]; then
echo '--auto'
elif [[ "${OPT_MODE}" == 'no_change' ]]; then
echo ''
else
# TODO: make this not ugly. A better sed should negate the need for cut/grep
menu="$(echo \"${XRANDR_TXT}\" \
| sed -n '/^'${output}' /,/^[^ ]/ s/ * //p' \
| cut -d ' ' -f 1 \
| grep x \
| cat <(echo auto) -)"
selection="$(menu_select "${prompt}" ${=menu})" || return $?
if [[ 'auto' == "${selection}" ]]; then
echo '--auto'
else
echo "--mode ${selection}"
fi
fi
}
function select_rotation() {
[[ -z $1 ]] && return "${ERR_BAD_ARGS}"
typeset menu
typeset prompt
prompt="Select rotation of $1:"
menu=('normal' 'inverted' 'left' 'right')
if [[ "${OPT_ROTATION}" == 'normal' ]]; then
echo '--rotate normal'
elif [[ "${OPT_ROTATION}" == 'no_change' ]]; then
echo ''
else
echo -n "--rotate ${selection}"
menu_select "${prompt}" ${menu} || return $?
fi
}
function menu_select() {
[[ -z "$2" ]] && return ${ERR_BAD_ARGS}
typeset selection
typeset prompt
typeset -a menu
prompt="$1"
shift
menu=($*)
if [[ ${#menu} == 1 ]]; then
echo "${menu}"
else
while [[ -z "${menu[(r)${selection}]}" ]]; do
echo "${(F)menu}" | dmenu -p "${prompt}" | read selection
[[ "${(L)selection}" == 'exit' ]] || [[ -z "${selection}" ]] \
&& return ${EXIT_CLEAN}
done
echo "${selection}"
fi
}
function list_configured_outputs() {
typeset -a list
typeset output
for output in ${(k)OUTPUT_CONFIGURED}; do
${OUTPUT_CONFIGURED[$output]} && list+=("${output}")
done
echo "${(F)list}"
}
function list_unconfigured_outputs() {
typeset -a list
typeset output
for output in ${(k)OUTPUT_CONFIGURED}; do
${OUTPUT_CONFIGURED[$output]} || list+=("${output}")
done
echo "${(F)list}"
}
function all_outputs_configured() {
typeset config
for config in ${OUTPUT_CONFIGURED}; do
$config || return 257
done
return 0
}
function bail() {
[[ "$1" == ${EXIT_CLEAN} ]] && exit 0 || exit "$1"
}
main