Skip to content

Instantly share code, notes, and snippets.

@oleasteo
Created October 18, 2025 18:01
Show Gist options
  • Select an option

  • Save oleasteo/d15acd9512432f75f77bbdec9472fdf9 to your computer and use it in GitHub Desktop.

Select an option

Save oleasteo/d15acd9512432f75f77bbdec9472fdf9 to your computer and use it in GitHub Desktop.
hyprland monitor configuration script
#!/bin/bash
# Usage: hypr-monitor [... OPTIONS DISPLAYNAME]
#
# The first available display will be the primary one (0x0 coordinates).
# Options always apply to the next display name
#
# All
#
# Options:
# --left Align the display to the left.
# --mirror [DISPLAYNAME] Mirror the given display.
#
# Examples:
# hypr-monitor laptop # [!laptop]
# hypr-monitor primary --left primary vertical # [laptop] [!primary] [vertical]
# hypr-monitor laptop --mirror laptop primary # [laptop = primary]
###
### Setup: Modify for your monitor names & configurations
###
# list all monitors that can safely be addressed statically
monitors_known=(eDP-1 DP-3 HDMI-A-1)
declare -A name_alias
declare -A res
declare -A position
declare -A scale
declare -A transform
# define aliases of known monitor configurations
name_alias[other]=' '
name_alias[laptop]=eDP-1
name_alias[primary]=DP-3
name_alias[vertical]=HDMI-A-1
# Configuration: laptop
#res[laptop]=2240x1400@90
res[laptop]=highres
scale[laptop]=1.25
# Configuration: vertical
transform[vertical]=transform,3
position[vertical]=auto-center-right
# additional commands to run before display changes
pre_exec() {
killall waybar 2>/dev/null
}
# additional commands to run after display changes
post_exec() {
hyprctl dispatch exec waybar >/dev/null
pidof hyprpaper >/dev/null || hyprctl dispatch exec hyprpaper >/dev/null
}
###
### Actual code; you should not need to modify anything below this line.
###
resolve_name() {
echo "${name_alias[$1]:-$1}"
}
list_enabled_known_monitors() {
_patterns=()
for m in "${monitors_known[@]}"; do _patterns+=(-e "$m"); done
hyprctl monitors -j | jq -r '.[].name' | grep -Fx "${_patterns[@]}"
}
# dispatch time in case we've been called by hyprland keybinds, etc.
sleep 0.1
pre_exec
monitors_enabled=($(list_enabled_known_monitors))
primary_name=
primary_line=
commands=()
_first=true
while [ $# -gt 0 ]; do
_position=
_res=
_scale=
_transform=
while [ "${1:0:2}" = "--" ]; do
opt="$1"; shift
case "$opt" in
--left) _position=auto-left;;
--mirror) _transform=mirror,"$(resolve_name "$1")"; shift;;
esac
done
name="$1"; shift
cmdline="keyword monitor $(resolve_name "$name")"
_position=${_position:-${position[$name]:-auto-right}}
[ $_first = true -a "$(resolve_name "$name")" != " " ] && _position=0x0
_res=${_res:-${res[$name]:-preferred}}
_scale=${_scale:-${scale[$name]:-auto}}
_transform=${_transform:-${transform[$name]}}
cmdline+=",$_res,$_position,$_scale"
[ -n "$_transform" ] && cmdline+=",$_transform"
if [ $_first = true ]; then
primary_name="$(resolve_name "$name")"
primary_line="$cmdline"
else
commands+=("$cmdline")
fi
_first=false
done
# ensure the primary display is enabled, before doing anything else;
# hyprland crashes if a batch command disables all previously enabled
# monitors, even if the same batch would enable another monitor :/
echo "$ $primary_line"
hyprctl $primary_line
sleep 0.15
# disable (batch) all known monitors as we require them to be explicitly named in args
# also, hyprland doesn't reset display order if they're previously enabled
#concatline="; $primary_line"
#echo "$+ ${concatline:2}"
concatline=
monitors_enabled+=(" ")
for monitor in "${monitors_enabled[@]}"; do
if [ "$monitor" != "$primary_name" ]; then
concatline+="; keyword monitor $monitor,disable"
echo "$+ keyword monitor $monitor,disable"
fi
done
hyprctl --batch "${concatline:2}" >/dev/null && echo batch: ok
sleep 0.15
# since we set the first (primary) monitor explicitly at 0x0, up to two monitors can
# safely be batched w/o hyprland messing up the display order
if [ ${#commands[@]} -le 1 ]; then
concatline=
for line in "${commands[@]}"; do
concatline+="; $line"
echo "$+ $line"
done
hyprctl --batch "${concatline:2}" >/dev/null && echo batch: ok
sleep 0.15
else
for line in "${commands[@]}"; do
echo "$ $line"
hyprctl $line
sleep 0.15
done
fi
sleep 0.1
post_exec
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment