Created
July 16, 2026 07:45
-
-
Save bjoern-r/3512a1c53936e82ce73f36b20db99965 to your computer and use it in GitHub Desktop.
script to fetch the current screen layout from sway and convert to kanshi profile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # | |
| # sway-to-kanshi.sh | |
| # | |
| # Fetches the current monitor arrangement from the running sway instance | |
| # (via `swaymsg -t get_outputs`) and prints it in kanshi config format. | |
| # | |
| # kanshi profile syntax reference: | |
| # https://github.com/emersion/kanshi (man 5 kanshi) | |
| # | |
| # profile [<name>] { | |
| # output <criteria> [enable|disable] [mode <width>x<height>[@<rate>Hz]] \ | |
| # [position <x>,<y>] [scale <factor>] [transform <transform>] \ | |
| # [adaptive_sync on|off] | |
| # ... | |
| # } | |
| # | |
| # Usage: | |
| # ./sway-to-kanshi.sh # print profile to stdout | |
| # ./sway-to-kanshi.sh -n docked # name the profile "docked" | |
| # ./sway-to-kanshi.sh -o ~/.config/kanshi/config # write/append to a file | |
| # ./sway-to-kanshi.sh --by-name # match outputs by name instead of make/model/serial | |
| set -euo pipefail | |
| PROFILE_NAME="" | |
| OUTFILE="" | |
| MATCH="identifier" # identifier = "make model serial"; name = output name (e.g. DP-1) | |
| usage() { | |
| cat >&2 <<EOF | |
| Usage: ${0##*/} [-n NAME] [-o FILE] [--by-name] | |
| -n, --name NAME Set the kanshi profile name (default: unnamed). | |
| -o, --output FILE Append the generated profile to FILE (default: stdout). | |
| --by-name Match outputs by connector name (DP-1, HDMI-A-1, ...) | |
| instead of the more portable "make model serial". | |
| -h, --help Show this help. | |
| EOF | |
| exit "${1:-0}" | |
| } | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| -n|--name) PROFILE_NAME="$2"; shift 2 ;; | |
| -o|--output) OUTFILE="$2"; shift 2 ;; | |
| --by-name) MATCH="name"; shift ;; | |
| -h|--help) usage 0 ;; | |
| *) echo "Unknown argument: $1" >&2; usage 1 ;; | |
| esac | |
| done | |
| command -v swaymsg >/dev/null || { echo "swaymsg not found" >&2; exit 1; } | |
| command -v jq >/dev/null || { echo "jq not found" >&2; exit 1; } | |
| if [[ -z "${SWAYSOCK:-}" && -z "${WAYLAND_DISPLAY:-}" ]]; then | |
| echo "Warning: no SWAYSOCK/WAYLAND_DISPLAY set; is sway running in this session?" >&2 | |
| fi | |
| outputs_json="$(swaymsg -t get_outputs)" | |
| # Build the kanshi profile. jq emits one 'output ...' line per connected output. | |
| profile_body="$( | |
| jq -r --arg match "$MATCH" ' | |
| # kanshi transform names differ slightly from sway; sway uses the same set, | |
| # so pass through. sway "normal"/"90"/"180"/"270"/"flipped*" are valid in kanshi. | |
| def crit: | |
| if $match == "name" then .name | |
| else ((.make // "Unknown") + " " + (.model // "Unknown") + " " + (.serial // "Unknown")) | |
| end; | |
| .[] | | |
| if (.active | not) then | |
| "\toutput \"" + crit + "\" disable" | |
| else | |
| "\toutput \"" + crit + "\"" | |
| + " enable" | |
| + " mode " + (.current_mode.width|tostring) + "x" + (.current_mode.height|tostring) | |
| + "@" + ((.current_mode.refresh/1000)|(.*1000|round/1000)|tostring) + "Hz" | |
| + " position " + (.rect.x|tostring) + "," + (.rect.y|tostring) | |
| + " scale " + (.scale|tostring) | |
| + (if (.transform // "normal") != "normal" then " transform " + .transform else "" end) | |
| + (if (.adaptive_sync_status // "disabled") == "enabled" then " adaptive_sync on" else "" end) | |
| end | |
| ' <<<"$outputs_json" | |
| )" | |
| if [[ -n "$PROFILE_NAME" ]]; then | |
| profile="profile $PROFILE_NAME {"$'\n'"$profile_body"$'\n'"}" | |
| else | |
| profile="profile {"$'\n'"$profile_body"$'\n'"}" | |
| fi | |
| if [[ -n "$OUTFILE" ]]; then | |
| mkdir -p "$(dirname "$OUTFILE")" | |
| { [[ -s "$OUTFILE" ]] && printf '\n'; printf '%s\n' "$profile"; } >>"$OUTFILE" | |
| echo "Wrote profile to $OUTFILE" >&2 | |
| else | |
| printf '%s\n' "$profile" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment