From 29d0c022b1557cef6b93efbc76734b816b92f62e Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Fri, 30 Oct 2026 20:36:17 +0100 Subject: monitors: draw a scale being typed at 1 The page binds the canvas to size(), and an empty or partial scale gave Infinity or NaN and broke the fit. Apply is still held back until the scale is a positive number. Also marks the per-axis snap as a ceiling and checks a rotated scaled monitor and a two-monitor file. Co-Authored-By: Claude Opus 5.5 --- desktop/modules/monitors/Mon.js | 9 +++++++-- desktop/modules/monitors/test_mon.js | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'desktop') diff --git a/desktop/modules/monitors/Mon.js b/desktop/modules/monitors/Mon.js index 9b5e158..865e155 100644 --- a/desktop/modules/monitors/Mon.js +++ b/desktop/modules/monitors/Mon.js @@ -52,12 +52,14 @@ function draft(m) { position: m.x + "x" + m.y, x: m.x, y: m.y }; } -// Logical size: an odd transform is a quarter turn, scale divides. +// Logical size: an odd transform is a quarter turn, scale divides. A scale +// being typed ("", "1.") draws at 1 until it is a positive number. function size(mode, scale, transform) { const p = /^(\d+)x(\d+)/.exec(mode); + const k = +scale > 0 ? +scale : 1; let w = +p[1], h = +p[2]; if (transform % 2) { const t = w; w = h; h = t; } - return { w: w / +scale, h: h / +scale }; + return { w: w / k, h: h / k }; } // The layout position: exact XxY, or where Hyprland last put an auto one. @@ -90,6 +92,9 @@ function nearest(v, cands, t) { // r ({x, y, w, h}, logical) moved so an edge within t lies on an edge of one // of others: beside it, or aligned with it. Each axis on its own, rounded. +// ponytail: an axis snaps to a monitor however far off it is on the other +// axis, and overlaps are not refused; right for two monitors, check both +// axes together if a third is added. function snap(r, others, t) { const xs = [], ys = []; for (const o of others) { diff --git a/desktop/modules/monitors/test_mon.js b/desktop/modules/monitors/test_mon.js index 6b12ee7..5d28ce4 100644 --- a/desktop/modules/monitors/test_mon.js +++ b/desktop/modules/monitors/test_mon.js @@ -40,6 +40,9 @@ assert.deepStrictEqual([d.mode, d.scale, d.transform, d.vrr, d.position, d.x, d. // Logical size: an odd transform swaps, scale divides. assert.deepStrictEqual(M.size("1920x1080@100.00", "1", 1), { w: 1080, h: 1920 }); assert.deepStrictEqual(M.size("2560x1440@60.00", "1.25", 0), { w: 2048, h: 1152 }); +assert.deepStrictEqual(M.size("2560x1440@60.00", "2", 7), { w: 720, h: 1280 }); +// A scale mid-typing draws at 1 rather than Infinity or NaN. +assert.deepStrictEqual(M.size("1920x1080@60.00", "", 0), { w: 1920, h: 1080 }); // Exact positions parse, auto ones fall back to where Hyprland put it. assert.deepStrictEqual(M.xy({ position: "-1080x-960", x: 0, y: 0 }), { x: -1080, y: -960 }); @@ -55,6 +58,9 @@ assert.ok(M.lua(Object.assign({}, d, { vrr: true })).endsWith("transform = 1, vr const f = M.file([d]); assert.ok(f.startsWith("-- Monitors, written by the keystone settings window")); assert.ok(f.includes("-- DP-3: ASUS VG279Q3A\n" + M.lua(d) + "\n")); +// Two monitors, in order, a blank line before each. +const two = M.file([d, Object.assign({}, d, { name: "DP-1" })]); +assert.ok(two.indexOf("-- DP-3") < two.indexOf("-- DP-1") && two.includes(M.lua(d) + "\n\n-- DP-1")); // Snapping: DP-1 is 2560x1080 at 0,-540. A 1080x1920 monitor dropped with // its right edge 30px short of DP-1's left edge snaps flush; 200px short -- cgit v1.2.3