Snap monitor scaling up to the nearest clean scale Hyprland accepts

Hyprland only takes scales where the mode divides into whole logical
pixels (in 1/120 steps), so picking 3x on a 1280x800 QEMU display threw
a red error overlay and silently kept the old scale. Round the request
up to the nearest clean divisor instead, so 3x becomes 3.2x.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
David Heinemeier Hansson
2026-07-20 21:52:32 -07:00
co-authored by Claude Fable 5
parent 503388b4d6
commit 0526ebefcc
2 changed files with 33 additions and 3 deletions
+19 -2
View File
@@ -52,15 +52,32 @@ audit_scale_change() {
"$grandparent_cmd" >>"$SCALE_LOG"
}
# Hyprland only accepts scales where the mode divides into whole logical
# pixels (in 1/120 steps), so clean scales are divisors of gcd(w*120, h*120).
# Round the requested scale up to the nearest one, so 3x on a 1280x800 QEMU
# display becomes 3.2x instead of a red error overlay.
clean_scale() {
awk -v scale="$1" -v width="$2" -v height="$3" '
function gcd(a, b, t) { while (b) { t = a % b; a = b; b = t } return a }
BEGIN {
g = gcd(width * 120, height * 120)
k = int(scale * 120 + 0.5)
if (k > g) k = g
while (g % k != 0) k++
printf "%g\n", k / 120
}'
}
set_scale() {
local new_scale="$1"
local requested="${2:-$new_scale}"
local requested_scale="$1"
local requested="${2:-$requested_scale}"
local monitor_info="$(hyprctl monitors -j | jq -e -c '.[] | select(.focused == true)')"
local active_monitor="$(echo "$monitor_info" | jq -r '.name')"
local current_scale="$(echo "$monitor_info" | jq -r '.scale')"
local width="$(echo "$monitor_info" | jq -r '.width')"
local height="$(echo "$monitor_info" | jq -r '.height')"
local refresh_rate="$(echo "$monitor_info" | jq -r '.refreshRate')"
local new_scale="$(clean_scale "$requested_scale" "$width" "$height")"
local monitor_lua="$HOME/.config/hypr/monitors.lua"
hyprctl eval "hl.monitor({ output = \"$active_monitor\", mode = \"${width}x${height}@${refresh_rate}\", position = \"auto\", scale = $new_scale })" >/dev/null