#!/usr/bin/env bash # Quick display control for Hyprland # Profiles: # laptop -> keep eDP-2, disable all externals # dual -> eDP-2 + primary external # triple -> eDP-2 + both externals # Toggles: # toggle-externals -> if any external enabled => laptop; else => triple (or dual if only one preset) # dpms-toggle-focused -> blank/unblank the currently focused monitor (does NOT change layout) set -euo pipefail PRIMARY="eDP-2" # --- exact enable lines (copy from hyprland.conf) --- EXT1='desc:Samsung Electric Company S24F350 H4ZR302705, highres@highrr, auto-right, 1' EXT2='desc:Samsung Electric Company S24F350 H4ZK111233, highres@highrr, auto-right, 1, transform, 1' # Optional fallback by connector (harmless if not present) EXT_FALLBACK='HDMI-A-1, highres@highrr, auto-right, 1' # Which external is the "main" one you prefer for Dual: DUAL_MAIN="$EXT1" notify() { if command -v notify-send >/dev/null 2>&1; then notify-send -a "Hyprland" "$1" "${2:-}" else [ -n "${2:-}" ] && printf '%s: %s\n' "$1" "$2" >&2 || printf '%s\n' "$1" >&2 fi } hypr() { local out if ! out="$(hyprctl "$@" 2>&1)"; then notify "hyprctl failed" "$out" exit 1 fi } jqok(){ command -v jq >/dev/null; } monjson(){ hyprctl -j monitors 2>/dev/null || true; } any_external_enabled() { if jqok; then monjson | jq -e --arg P "$PRIMARY" '.[] | select(.name!=$P and (.disabled!=true))' >/dev/null else hyprctl monitors | awk -v P="$PRIMARY" '/^Monitor /{gsub(/^Monitor[ \t]+/, "", $0); split($0,a," "); if (a[1]!=P){print; exit 0}}' | grep -q . fi } disable_all_externals() { if jqok; then mapfile -t names < <(monjson | jq -r --arg P "$PRIMARY" '.[] | select(.name!=$P) | .name') else mapfile -t names < <(hyprctl monitors | awk -v P="$PRIMARY" '/^Monitor /{gsub(/^Monitor[ \t]+/, "", $0); split($0,a," "); if (a[1]!=P) print a[1]}') fi for n in "${names[@]:-}"; do hypr keyword monitor "$n, disable" done } enable_line() { local line="$1" [ -n "$line" ] && hypr keyword monitor "$line" } profile_laptop() { disable_all_externals notify "Profile: Laptop-only" "$PRIMARY active, externals disabled" } profile_dual() { # Ensure only one external is on disable_all_externals enable_line "$DUAL_MAIN" notify "Profile: Dual" "Enabled main external with preferred transform" } profile_triple() { # Ensure both externals are on (and only those two) disable_all_externals enable_line "$EXT1" enable_line "$EXT2" # You can drop EXT_FALLBACK if you don't actually need it: # enable_line "$EXT_FALLBACK" notify "Profile: Triple" "Enabled both externals" } toggle_externals() { if any_external_enabled; then profile_laptop else # Prefer triple if we have two presets, else dual if [ -n "$EXT1" ] && [ -n "$EXT2" ]; then profile_triple else profile_dual fi fi } dpms_toggle_focused() { # Blank/unblank the currently focused output, layout unchanged local name if jqok; then name="$(monjson | jq -r '.[] | select(.focused==true) | .name // empty')" else name="$(hyprctl monitors | awk '$1=="Monitor"{gsub(/^Monitor[ \t]+/,""); split($0,a," "); name=a[1]} /focused: yes/{print name; exit}')" fi [ -z "$name" ] && { notify "No focused monitor" ""; exit 2; } hypr dispatch dpms toggle "$name" notify "DPMS toggle" "$name" } case "${1:-}" in laptop) profile_laptop ;; dual) profile_dual ;; triple) profile_triple ;; toggle-externals) toggle_externals ;; dpms-toggle-focused) dpms_toggle_focused ;; *) cat <