Skip to content

Instantly share code, notes, and snippets.

@NeoTheFox
Last active June 23, 2026 13:10
Show Gist options
  • Select an option

  • Save NeoTheFox/cf0ee713a7c108931c8df6d58b9487fc to your computer and use it in GitHub Desktop.

Select an option

Save NeoTheFox/cf0ee713a7c108931c8df6d58b9487fc to your computer and use it in GitHub Desktop.
hdr auto-toggle script for Sway
#!/usr/bin/env bash
# hdr-toggle — enable HDR on a sway output for the duration of a command
#
# Turns HDR on for an HDR-capable output, runs the wrapped command, then
# restores the output's previous HDR state
set -euo pipefail
usage() {
cat <<'EOF'
Usage: hdr-toggle [--] <command> [args...]
Enable HDR on a sway output, run <command>, then restore the prior HDR state
once it exits.
Output selection (in order of precedence):
1. HDR_OUTPUT — output name; must be HDR-capable.
2. WAYLANDDRV_PRIMARY_MONITOR — Wine's primary monitor; used if HDR-capable,
otherwise ignored with a warning.
3. The first HDR-capable output.
HDR_OUTPUT=DP-2 hdr-toggle <command> [args...]
List output names with: swaymsg -t get_outputs -r | jq -r '.[].name'
Environment:
HDR_OUTPUT Force the target output by name (overrides everything below).
HDR_DELAY Seconds to wait after enabling HDR before running the command,
for monitors slow to switch (e.g. HDR_DELAY=2). Accepts decimals.
Options:
-h, --help Show this help and exit.
Examples:
hdr-toggle gamescope -- mygame
HDR_OUTPUT=DP-1 hdr-toggle steam -applaunch 123456
HDR_DELAY=2 hdr-toggle mygame
EOF
}
case "${1-}" in
-h | --help)
usage
exit 0
;;
"")
usage >&2
exit 1
;;
--)
shift
;;
esac
if [[ $# -eq 0 ]]; then
echo "hdr-toggle: no command given" >&2
usage >&2
exit 1
fi
command -v swaymsg >/dev/null 2>&1 || {
echo "hdr-toggle: swaymsg not found (is sway installed?)" >&2
exit 1
}
command -v jq >/dev/null 2>&1 || {
echo "hdr-toggle: jq not found" >&2
exit 1
}
if [[ -n "${HDR_DELAY-}" ]] && ! [[ "$HDR_DELAY" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
echo "hdr-toggle: HDR_DELAY must be a non-negative number of seconds" >&2
exit 1
fi
outputs=$(swaymsg -t get_outputs -r 2>/dev/null) || {
echo "hdr-toggle: cannot reach sway IPC (is sway running? is SWAYSOCK set?)" >&2
exit 1
}
# Returns an output's .features.hdr value ("true"/"false"), or "" if not found.
output_hdr_cap() {
jq -r --arg o "$1" '.[] | select(.name==$o) | .features.hdr' <<<"$outputs"
}
# Select the target output by precedence:
# 1. HDR_OUTPUT — explicit; hard error if missing/not capable.
# 2. WAYLANDDRV_PRIMARY_MONITOR — hint; warn and fall back if missing/not capable.
# 3. first HDR-capable output.
OUTPUT=""
if [[ -n "${HDR_OUTPUT-}" ]]; then
cap=$(output_hdr_cap "$HDR_OUTPUT")
if [[ -z "$cap" ]]; then
echo "hdr-toggle: output '$HDR_OUTPUT' not found" >&2
exit 1
fi
if [[ "$cap" != "true" ]]; then
echo "hdr-toggle: output '$HDR_OUTPUT' is not HDR-capable" >&2
exit 1
fi
OUTPUT="$HDR_OUTPUT"
elif [[ -n "${WAYLANDDRV_PRIMARY_MONITOR-}" ]]; then
cap=$(output_hdr_cap "$WAYLANDDRV_PRIMARY_MONITOR")
if [[ "$cap" == "true" ]]; then
OUTPUT="$WAYLANDDRV_PRIMARY_MONITOR"
elif [[ -z "$cap" ]]; then
echo "hdr-toggle: WAYLANDDRV_PRIMARY_MONITOR='$WAYLANDDRV_PRIMARY_MONITOR' not found; using first HDR-capable output" >&2
else
echo "hdr-toggle: WAYLANDDRV_PRIMARY_MONITOR='$WAYLANDDRV_PRIMARY_MONITOR' is not HDR-capable; using first HDR-capable output" >&2
fi
fi
if [[ -z "$OUTPUT" ]]; then
OUTPUT=$(jq -r '[.[] | select(.features.hdr==true)][0].name // empty' <<<"$outputs")
if [[ -z "$OUTPUT" ]]; then
echo "hdr-toggle: no HDR-capable output found" >&2
exit 1
fi
fi
PRIOR=$(jq -r --arg o "$OUTPUT" '.[] | select(.name==$o) | .hdr' <<<"$outputs")
restored=0
# shellcheck disable=SC2329 # invoked indirectly via trap
restore_hdr() {
[[ $restored -eq 1 ]] && return
restored=1
if [[ "$PRIOR" == "true" ]]; then
swaymsg output "$OUTPUT" hdr on >/dev/null
else
swaymsg output "$OUTPUT" hdr off >/dev/null
fi
}
trap restore_hdr EXIT INT TERM
# Enable HDR (no-op if it was already on).
if [[ "$PRIOR" != "true" ]]; then
swaymsg output "$OUTPUT" hdr on >/dev/null
# Give a slow monitor time to switch modes before launching the command.
[[ -n "${HDR_DELAY-}" ]] && sleep "$HDR_DELAY"
fi
# Run the wrapped command, preserving its exit code. The trap restores HDR.
set +e
"$@"
rc=$?
set -e
exit "$rc"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment