115 lines
3.4 KiB
Bash
Executable File
115 lines
3.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# monitor setup script using xrandr and fzf to manage multiple monitors and/or
|
|
# set resolutions and refresh rates.
|
|
|
|
command -v xrandr &>/dev/null || exit 1
|
|
command -v fzf &>/dev/null || exit 1
|
|
|
|
fzf_args=( --cycle --select-1 --exit-0 --header )
|
|
|
|
xrandr_q="$(xrandr -q)"
|
|
|
|
# Get outputs currently in use as regex matching either one (e.g. `HDMI-0|DP-0`)
|
|
in_use="$( <<<"$xrandr_q" \
|
|
tac | # Reverse for non-greedy matches
|
|
sed -En '/\*/,/ connected/p' | # lines from selected config to it's name
|
|
grep -Po '^.*(?= connected)' | # only the name
|
|
tr '\n' '|' # format into regex
|
|
)"
|
|
in_use="${in_use%|}" # remove trailing `|`
|
|
|
|
# Get all outputs in a table in the form `<name> <res> [*]`
|
|
formatted="$(<<<"$xrandr_q" \
|
|
grep -wA1 connected | # output line and highest res
|
|
awk '{ print $1 }' | # only name and resolution
|
|
grep -ve -- | # remove grep's match separator
|
|
paste - - | # join name and res
|
|
sed -E "s/($in_use).*/&\t*/" | # append `*` to all in-use
|
|
column -t # tabularize
|
|
)"
|
|
|
|
# Select all outputs to-use
|
|
selected=( $(<<<"$formatted" \
|
|
fzf -m "${fzf_args[@]}" "Select outputs" | # select
|
|
cut -d' ' -f1 # only output name
|
|
) )
|
|
# Abort if nothing was selected
|
|
(( ${#selected[@]} )) || exit 1
|
|
|
|
# Regex to match either one of the selected outputs
|
|
selected_regex="$(<<<"${selected[@]}" tr ' ' '|')"
|
|
|
|
# Gather non-selected outputs
|
|
non_selected=( $(<<<"$xrandr_q" \
|
|
grep connected | # list lines with output ({,dis}connected)
|
|
grep -Ev "$selected_regex" | # filter out selected ones
|
|
cut -d' ' -f1 # only output name
|
|
) )
|
|
|
|
# Choose primary
|
|
primary="$(<<<"$formatted" \
|
|
grep -E "$selected_regex" | # use formatted for more information
|
|
fzf "${fzf_args[@]}" "Select primary" |
|
|
cut -d' ' -f1 # name only
|
|
)"
|
|
[[ $primary ]] || exit 1
|
|
|
|
# Build the `xrandr` command
|
|
xrandr_cmd=(xrandr)
|
|
|
|
# Keep track of width to place the outputs side-by-side
|
|
width=0
|
|
|
|
for out in "${selected[@]}"; do
|
|
xrandr_cmd+=(--output "$out" --rotate normal)
|
|
[[ $out != $primary ]] || xrandr_cmd+=(--primary)
|
|
|
|
all_res="$(<<<"$xrandr_q" sed -En "
|
|
# all resolution lines for selected output (+ junk lines first and last)
|
|
/$out/,/^[^ ]/ {
|
|
# on lines that contain a resolution
|
|
/^ / {
|
|
# only print the resolution
|
|
s/^ *([^ ]*).*/\1/p
|
|
}
|
|
}"
|
|
)"
|
|
res="$(<<<"$all_res" fzf "${fzf_args[@]}" "Select resolution for $out")"
|
|
[[ $res ]] || exit 1
|
|
|
|
xrandr_cmd+=(--mode "$res")
|
|
|
|
rates="$(<<<"$xrandr_q" sed -En "
|
|
# all resolution lines for selected output
|
|
/$out/,/^[^ ]/ {
|
|
# on line with the selected resolution
|
|
/^ *$res/ {
|
|
# remove resolution and whitespace
|
|
s/^ *$res *//
|
|
# fix formatting when preferred mode is not the current one
|
|
s/ \+/+/
|
|
# put each rate on a new line
|
|
s/ +/\n/g
|
|
|
|
p
|
|
}
|
|
}"
|
|
)"
|
|
rate="$(<<<"$rates" fzf "${fzf_args[@]}" "Select refresh rate for $out")"
|
|
[[ $rate ]] || exit 1
|
|
rate="${rate%%[*+]*}" # remove current and preferred mode indicator
|
|
xrandr_cmd+=(--rate "$rate")
|
|
|
|
xrandr_cmd+=(--pos "${width}x0")
|
|
: "$((width+=${res%%x*}))"
|
|
done
|
|
|
|
for out in "${non_selected[@]}"; do
|
|
xrandr_cmd+=(--output "$out" --off)
|
|
done
|
|
|
|
# Print for debugging purposes and finally execute it
|
|
printf "%s\n" "${xrandr_cmd[*]}"
|
|
"${xrandr_cmd[@]}"
|