Created
October 18, 2025 18:01
-
-
Save oleasteo/d15acd9512432f75f77bbdec9472fdf9 to your computer and use it in GitHub Desktop.
hyprland monitor configuration script
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
| #!/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