#!/bin/sh # Generate kanshi's dock profile from kernel EDID. # # Neither identity kanshi can see is trustworthy here: Hyprland reports each # monitor's serial on the other monitor's output, and connector names get # renumbered when the dock brings displays back in a different order. The # kernel reads EDID over each connector's own DDC channel and is correct, so # connector names are resolved from serials fresh on every display change. USER_NAME=connorjohnstone CONF=/home/$USER_NAME/.config/kanshi/generated SCALE=1.5 # Serials in the physical left-to-right order they sit on the desk. ORDER="PB4HB16301805 PB4HB16301801" exec 9>/run/monitor-layout.lock flock -w 60 9 || exit 0 [ -n "$LAYOUT_DELAY" ] && sleep "$LAYOUT_DELAY" connector_for_serial() { for c in /sys/class/drm/card*-*; do [ -r "$c/status" ] || continue [ "$(cat "$c/status")" = connected ] || continue if edid-decode <"$c/edid" 2>/dev/null | grep -qF "'$1'"; then echo "$c" return 0 fi done return 1 } # Same directory as $CONF so the final rename is atomic: kanshi reloads on # SIGHUP and must never observe a half-written config. tmp=$(mktemp "$CONF.XXXXXX") || exit 1 trap 'rm -f "$tmp"' EXIT INT TERM body="" x=0 for serial in $ORDER; do path=$(connector_for_serial "$serial") || continue name=$(basename "$path" | sed 's/^card[0-9]*-//') mode=$(head -1 "$path/modes" 2>/dev/null) [ -n "$mode" ] || continue width=$(awk -v m="${mode%%x*}" -v s="$SCALE" 'BEGIN{printf "%d", m / s}') body="$body output $name enable position $x,0 scale $SCALE " x=$((x + width)) done if [ -n "$body" ]; then printf 'profile generated_dock {\n%s output eDP-1 disable\n}\n' "$body" >"$tmp" else : >"$tmp" fi chown "$USER_NAME:$USER_NAME" "$tmp" chmod 0644 "$tmp" mv -f "$tmp" "$CONF" pkill -HUP -u "$USER_NAME" kanshi