#!/usr/bin/env bash # Generate ~/.config/sway/config.d/05-outputs.conf from the monitors sway sees right now. # Laptop panel first (left), the rest follow to the right. Run inside a sway session. # Usage: outputs-setup.sh [--auto] (--auto: no questions, guess scales) set -euo pipefail AUTO=0; [ "${1:-}" = "--auto" ] && AUTO=1 OUT=${XDG_CONFIG_HOME:-$HOME/.config}/sway/config.d/05-outputs.conf command -v swaymsg >/dev/null && [ -n "${SWAYSOCK:-}" ] || { echo "Run this inside a sway session." >&2; exit 1; } command -v python3 >/dev/null || { echo "python3 is required." >&2; exit 1; } mapfile -t ROWS < <(swaymsg -t get_outputs -r | python3 -c ' import json,sys outs=[o for o in json.load(sys.stdin) if o.get("active") or o.get("power", True)] # internal panels (eDP/LVDS/DSI) first, then the others by name outs.sort(key=lambda o:(0 if o["name"].startswith(("eDP","LVDS","DSI")) else 1, o["name"])) for o in outs: m=o.get("current_mode") or {} print(o["name"], m.get("width",0), m.get("height",0), o.get("make","?").replace(" ","_"), o.get("model","?").replace(" ","_")) ') [ "${#ROWS[@]}" -gt 0 ] || { echo "No outputs found." >&2; exit 1; } guess_scale() { # name width height case $1 in eDP*|LVDS*|DSI*) if [ "$2" -ge 3000 ]; then echo 2 elif [ "$2" -ge 2400 ]; then echo 1.5 elif [ "$2" -ge 1900 ] && [ "$3" -ge 1200 ]; then echo 1.25 else echo 1; fi ;; *) echo 1 ;; esac } x=0; body="" for row in "${ROWS[@]}"; do read -r name w h make model <<<"$row" scale=$(guess_scale "$name" "$w" "$h") if [ "$AUTO" = 0 ]; then read -r -p "$name ($make $model, ${w}x${h}) scale [$scale]: " ans || ans="" [ -n "$ans" ] && scale=$ans fi body+="output $name position $x 0 scale $scale"$'\n' x=$(python3 -c "print(int($x + $w / $scale))") done mkdir -p "$(dirname "$OUT")" [ -e "$OUT" ] && cp -a "$OUT" "$OUT.bak" { echo "# Monitor layout, generated by outputs-setup.sh (edit freely; re-run to regenerate)" printf '%s' "$body" } > "$OUT" echo "Wrote $OUT:"; cat "$OUT" swaymsg reload >/dev/null && echo "sway reloaded."