#!/bin/sh # POSIX-compliant xrandr screen scaling shell script # Requires: xrandr, fzf, awk, sed, printf, cut, grep err() { printf "%s\n" "$*" >&2 exit 1 } for cmd in xrandr fzf awk sed grep cut printf; do command -v "$cmd" >/dev/null 2>&1 || err "required command not found: $cmd" done TMPDIR=${TMPDIR:-/tmp} tmp_out="$TMPDIR/xrandr_outputs_$" tmp_scales="$TMPDIR/xrandr_scales_$" xrandr --query >"$tmp_out" || err "xrandr failed" awk ' / connected/ { out=$1 if (match($0, /[0-9]+x[0-9]+\+[0-9]+\+[0-9]+/)) { res=substr($0, RSTART, RLENGTH) sub(/\+.*/,"",res) print out "\t" res } else { found=0 # scan following indented lines for "*" indicating current mode while (getline > 0) { if ($0 ~ /^[ \t]/) { if ($0 ~ /\*/) { split($1,a,"+") print out "\t" a[1] found=1 break } } else { break } } if (!found) print out "\tunknown" } } ' "$tmp_out" >"${tmp_out}.list" [ -s "${tmp_out}.list" ] || { rm -f "$tmp_out" "${tmp_out}.list" err "no connected outputs found." } chosen_line=$(awk -F'\t' '{printf "%s\t%s\n",$1,$2}' "${tmp_out}.list" | fzf --prompt="select output: " --with-nth=1,2 --tiebreak=index --exact) || { rm -f "$tmp_out" "${tmp_out}.list" exit 1 } out=$(printf '%s' "$chosen_line" | cut -f1) cur_res=$(printf '%s' "$chosen_line" | cut -f2) cat >"$tmp_scales" <<'EOF' 4k to 1080p 3840x2160 1920x1080 4k to 1440p 3840x2160 2560x1440 4k to 1600p 3840x2160 2560x1600 4k to 720p 3840x2160 1280x720 4k to 768p 3840x2160 1366x768 1440p to 720p 2560x1440 1280x720 1440p to 768p 2560x1440 1366x768 1440p to 900p 2560x1440 1600x900 1440p to 1080p 2560x1440 1920x1080 2560x1600 to 1080p 2560x1600 1920x1080 1080p to 800x600 1920x1080 800x600 1080p to 1024x768 1920x1080 1024x768 1080p to 720p 1920x1080 1280x720 1080p to 768p 1920x1080 1366x768 1080p to 900p 1920x1080 1600x900 1080p to 1440p 1920x1080 2560x1440 1080p to 4k 1920x1080 3840x2160 1600x900 to 1080p 1600x900 1920x1080 1600x900 to 720p 1600x900 1280x720 720p to 1080p 1280x720 1920x1080 720p to 4k 1280x720 3840x2160 720p to 1366x768 1280x720 1366x768 1024x768 to 1080p 1024x768 1920x1080 3440x1440 to 1080p 3440x1440 1920x1080 3440x1440 to 1440p 3440x1440 2560x1440 3440x1440 to 2560x1080 3440x1440 2560x1080 3440x1440 to 1600p 3440x1440 2560x1600 3440x1440 to 720p 3440x1440 1280x720 3440x1440 to 1366x768 3440x1440 1366x768 3840x1600 to 1080p 3840x1600 1920x1080 3840x1600 to 1440p 3840x1600 2560x1440 3840x1600 to 2560x1080 3840x1600 2560x1080 2560x1080 to 1080p 2560x1080 1920x1080 2560x1080 to 1440p 2560x1080 2560x1440 2560x1080 to 1366x768 2560x1080 1366x768 3200x1800 to 1080p 3200x1800 1920x1080 3200x1800 to 1440p 3200x1800 2560x1440 1366x768 to 720p 1366x768 1280x720 1366x768 to 1024x768 1366x768 1024x768 1366x768 to 1080p 1366x768 1920x1080 1366x768 to 720p 1366x768 1280x720 1280x800 to 1080p 1280x800 1920x1080 1280x800 to 1366x768 1280x800 1366x768 1280x800 to 1440p 1280x800 2560x1440 1280x720 to 1080p 1280x720 1920x1080 1152x864 to 1024x768 1152x864 1024x768 800x600 to 1024x768 800x600 1024x768 800x600 to 1080p 800x600 1920x1080 800x480 to 720p 800x480 1280x720 640x480 to 1080p 640x480 1920x1080 1600x1200 to 1080p 1600x1200 1920x1080 1600x1200 to 1280x1024 1600x1200 1280x1024 1280x1024 to 1080p 1280x1024 1920x1080 1280x1024 to 1366x768 1280x1024 1366x768 1024x768 to 1280x800 1024x768 1280x800 1024x768 to 1080p 1024x768 1920x1080 1152x864 to 1024x768 1152x864 1024x768 1400x1050 to 1080p 1400x1050 1920x1080 1400x1050 to 1440p 1400x1050 2560x1440 3840x2160 to 1600x900 3840x2160 1600x900 3840x2160 to 1366x768 3840x2160 1366x768 3840x2160 to 1280x800 3840x2160 1280x800 3840x2160 to 1024x768 3840x2160 1024x768 3200x1800 to 1600x900 3200x1800 1600x900 1360x768 to 720p 1360x768 1280x720 1360x768 to 1080p 1360x768 1920x1080 1920x1200 to 1080p 1920x1200 1920x1080 reset scaling - - EOF chosen_scale=$(grep -v '^#' "$tmp_scales" | awk -F'\t' '{printf "%s\t%s\t%s\n",$1,$2,$3}' | fzf --prompt="select scaling option: " --with-nth=1,2,3 --tiebreak=index --preview='echo {}') || { rm -f "$tmp_out" "${tmp_out}.list" "$tmp_scales" exit 1 } label=$(printf '%s' "$chosen_scale" | cut -f1) src=$(printf '%s' "$chosen_scale" | cut -f2) tgt=$(printf '%s' "$chosen_scale" | cut -f3) if [ "$label" = "reset scaling" ]; then scale_for_xrandr="1x1" else scale=$(awk -F'[x\t ]' -v s="$src" -v t="$tgt" ' BEGIN{ split(s,ss,"x"); split(t,tt,"x"); if (ss[1]==0 || ss[2]==0) { print "1.000000,1.000000"; exit } sx = tt[1]/ss[1]; sy = tt[2]/ss[2]; printf("%.6f,%.6f", sx, sy); }') scale_for_xrandr=$(printf '%s' "$scale" | sed 's/,/x/') fi printf 'applying: output=%s current=%s option=%s scale=%s\n' "$out" "$cur_res" "$label" "$scale_for_xrandr" xrandr --output "$out" --scale "$scale_for_xrandr" --filter bilinear rm -f "$tmp_out" "${tmp_out}.list" "$tmp_scales"