experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(display-watcher): use shared 50% stranded threshold instead of local 30%

display-watcher's Pass 1 used a 30% overlap threshold to decide whether
a window was accessible; window-placement's stranded rescue used 50%.
A window in the 30-49% band would skip Pass 1 (treated as accessible)
yet trip Pass 2's stranded rescue, doing the work twice with two
disagreeing definitions of off-screen.

Export maxOverlapFraction and isStranded from window-placement.ts (typed
against just the workArea field so DisplaySnapshot satisfies the
interface) and have display-watcher's isWindowAccessible delegate to
isStranded. Single source of truth for the threshold.

Tests: updated the local mirror in display-watcher.test.ts to match,
including a regression case that asserts a 30%-overlap window is now
correctly classified as inaccessible.

+62 -57
+32 -23
backend/electron/display-watcher.test.ts
··· 3 3 * 4 4 * These test the pure math functions extracted from display-watcher.ts: 5 5 * - findDisplayForPoint: determine which display contains a point 6 - * - isWindowAccessible: check if a window has >=30% area overlap with any display 6 + * - isWindowAccessible: check if a window has >=50% area overlap with any display 7 + * (matches `STRANDED_THRESHOLD` in window-placement.ts; production now 8 + * delegates to the shared isStranded helper) 7 9 * - findBestNewDisplay: find the nearest display by center-point proximity 8 10 * 9 11 * All functions are pure (no Electron dependencies) so they can run ··· 50 52 return null; 51 53 } 52 54 55 + // Mirrors the new shared logic: a window is accessible iff its overlap 56 + // with the best display's workArea is >= STRANDED_THRESHOLD (0.5). 57 + const STRANDED_THRESHOLD = 0.5; 58 + 53 59 function isWindowAccessible(displays: DisplaySnapshot[], bounds: Rectangle): boolean { 54 60 const windowArea = bounds.width * bounds.height; 55 61 ··· 66 72 67 73 if (overlapRight > overlapX && overlapBottom > overlapY) { 68 74 const overlapArea = (overlapRight - overlapX) * (overlapBottom - overlapY); 69 - if (overlapArea / windowArea >= 0.3) { 75 + if (overlapArea / windowArea >= STRANDED_THRESHOLD) { 70 76 return true; 71 77 } 72 78 } ··· 202 208 assert.strictEqual(isWindowAccessible(displays, { x: 100, y: 100, width: 0, height: 600 }), true); 203 209 }); 204 210 205 - it("window with exactly 30% overlap is accessible", () => { 206 - // Window 1000x1000 = 1,000,000 area 207 - // Need overlap of 300,000 (30%) 208 - // Place window so only 300px width overlaps with display1440 workArea 209 - // Window at x=-700, width=1000 -> overlaps from x=0 to x=300 (300px wide) 210 - // y=100, height=1000 -> overlaps from y=100 to y=1100 (1000px tall, within workArea 25-1440) 211 - // Overlap = 300 * 1000 = 300,000 = exactly 30% of 1,000,000 212 - assert.strictEqual(isWindowAccessible(displays, { x: -700, y: 100, width: 1000, height: 1000 }), true); 211 + it("window with exactly 50% overlap is accessible (boundary inclusive)", () => { 212 + // Window 1000x1000 = 1,000,000 area, threshold 500,000 (50%) 213 + // Window at x=-500, width=1000 -> overlaps from x=0 to x=500 (500px wide) 214 + // y=100, height=1000 -> overlaps 1000px tall (within workArea 25-1440) 215 + // Overlap = 500 * 1000 = 500,000 = exactly 50%; passes >= threshold. 216 + assert.strictEqual(isWindowAccessible(displays, { x: -500, y: 100, width: 1000, height: 1000 }), true); 213 217 }); 214 218 215 - it("window with less than 30% overlap is not accessible", () => { 216 - // Window 1000x1000 = 1,000,000 area 217 - // Place so only 299px width overlaps 218 - // x=-701, width=1000 -> overlaps from x=0 to x=299 (299px wide) 219 - // y=100, height=1000 -> overlaps 1000px tall 220 - // Overlap = 299 * 1000 = 299,000 < 30% of 1,000,000 221 - assert.strictEqual(isWindowAccessible(displays, { x: -701, y: 100, width: 1000, height: 1000 }), false); 219 + it("window with less than 50% overlap is not accessible", () => { 220 + // x=-501, width=1000 -> overlaps from x=0 to x=499 (499px wide) 221 + // Overlap = 499 * 1000 = 499,000 < 50% threshold 222 + assert.strictEqual(isWindowAccessible(displays, { x: -501, y: 100, width: 1000, height: 1000 }), false); 222 223 }); 223 224 224 225 it("window spanning two displays counts overlap per display", () => { 225 - // Window at the boundary between display1440 and display1080 226 - // If 30% is on either display, it's accessible 226 + // 320x600 window straddling the 2560 boundary: 160px on display1440, 227 + // 160px on display1080. Each display gets 96,000 / 192,000 = 50% 228 + // overlap; the per-display max is 50%, accessible. 227 229 assert.strictEqual(isWindowAccessible(displays, { x: 2400, y: 100, width: 320, height: 600 }), true); 228 230 }); 229 231 230 - it("large window mostly off-screen but >30% on display is accessible", () => { 231 - // 800x600 window with top-left at (-400, 100) 232 - // Overlaps display1440 from x=0 to x=400 (400px), y=100 to y=700 (600px) 233 - // Overlap = 400*600 = 240,000; window area = 480,000; ratio = 50% > 30% 232 + it("large window half off-screen with exactly 50% overlap is accessible", () => { 233 + // 800x600 at (-400, 100): overlaps display1440 from 0..400 (400px) by 234 + // 600px tall = 240,000 / 480,000 = exactly 50% — boundary inclusive. 234 235 assert.strictEqual(isWindowAccessible(displays, { x: -400, y: 100, width: 800, height: 600 }), true); 236 + }); 237 + 238 + it("window with only 30% overlap is no longer accessible (was true before threshold change)", () => { 239 + // x=-700, 1000x1000 window: only 300/1000px overlap = 30%, below the 240 + // 50% threshold. Previously isWindowAccessible used 0.3, which let 241 + // these windows skip Pass 1 yet trip Pass 2's stranded rescue. Now 242 + // both passes agree. 243 + assert.strictEqual(isWindowAccessible(displays, { x: -700, y: 100, width: 1000, height: 1000 }), false); 235 244 }); 236 245 237 246 it("window far off-screen with no overlap is not accessible", () => {
+19 -31
backend/electron/display-watcher.ts
··· 5 5 * and rescues genuinely orphaned windows that end up off-screen. 6 6 * 7 7 * macOS handles window migration natively when displays are added/removed. 8 - * This module only intervenes when a window has less than 30% area overlap 9 - * with any display workArea — meaning it's truly inaccessible to the user. 8 + * This module only intervenes when a window is "stranded" by the shared 9 + * `maxOverlapFraction` test in `window-placement.ts` — meaning it's truly 10 + * inaccessible to the user. 10 11 * 11 12 * Algorithm (single-pass safety net): 12 13 * - Snapshot display layout at startup and after each change 13 14 * - On display change: check every window's overlap with current displays 14 - * - If a window has <30% overlap with ANY display, it's orphaned: 15 - * find the nearest display and center the window on it 15 + * - If a window is stranded, find the nearest display and center the 16 + * window on it. Stranded threshold matches `STRANDED_THRESHOLD` 17 + * (50%) in window-placement.ts so both passes agree on what 18 + * "off-screen" means. 16 19 * - Window size is NEVER changed — only position is adjusted 17 20 * - If all windows are accessible (99% of cases), do nothing 18 21 */ ··· 20 23 import { BrowserWindow, screen, Display } from 'electron'; 21 24 import { getWindowInfo } from './main.js'; 22 25 import { WEB_CORE_ADDRESS } from './config.js'; 23 - import { computePlacement, type Placement } from './window-placement.js'; 26 + import { computePlacement, isStranded, type Placement } from './window-placement.js'; 24 27 25 28 const DEBUG = !!process.env.DEBUG; 26 29 ··· 78 81 79 82 /** 80 83 * Check if a window is still accessible on the current displays. 81 - * "Accessible" means the window has at least 30% area overlap with 82 - * any display's workArea, so the user can still interact with it. 83 - * Zero-size windows are always considered accessible (hidden/minimized). 84 + * 85 + * Delegates to the shared `isStranded` predicate in `window-placement.ts` 86 + * so this pass and `computePlacement`'s stranded rescue agree on what 87 + * counts as off-screen (50% overlap). Previously these used different 88 + * thresholds (30% here, 50% there), letting windows in the 30-49% band 89 + * fall through Pass 1's accessibility check and then trigger Pass 2's 90 + * stranded rescue — extra work and inconsistent semantics. 91 + * 92 + * Zero-size windows are always considered accessible (`isStranded` reports 93 + * full overlap for them). 84 94 */ 85 95 function isWindowAccessible(displays: DisplaySnapshot[], bounds: Electron.Rectangle): boolean { 86 - const windowArea = bounds.width * bounds.height; 87 - 88 - // Zero-size windows are always accessible (hidden, minimized, etc.) 89 - if (windowArea <= 0) return true; 90 - 91 - for (const d of displays) { 92 - const wa = d.workArea; 93 - 94 - // Calculate overlap rectangle 95 - const overlapX = Math.max(bounds.x, wa.x); 96 - const overlapY = Math.max(bounds.y, wa.y); 97 - const overlapRight = Math.min(bounds.x + bounds.width, wa.x + wa.width); 98 - const overlapBottom = Math.min(bounds.y + bounds.height, wa.y + wa.height); 99 - 100 - if (overlapRight > overlapX && overlapBottom > overlapY) { 101 - const overlapArea = (overlapRight - overlapX) * (overlapBottom - overlapY); 102 - if (overlapArea / windowArea >= 0.3) { 103 - return true; 104 - } 105 - } 106 - } 107 - 108 - return false; 96 + return !isStranded(displays, bounds); 109 97 } 110 98 111 99 /**
+11 -3
backend/electron/window-placement.ts
··· 131 131 * Return the fraction (0..1) of `bounds`' area that overlaps any display's 132 132 * workArea. Zero-size windows are reported as 1 (fully accessible) — they 133 133 * can't be stranded, they're hidden/minimized. 134 + * 135 + * Exported and typed against just the `workArea` field so both 136 + * `Electron.Display[]` and `display-watcher.ts`'s `DisplaySnapshot[]` 137 + * satisfy the parameter — keeps the threshold and overlap math in a 138 + * single place. 134 139 */ 135 - function maxOverlapFraction( 136 - displays: Electron.Display[], 140 + export function maxOverlapFraction( 141 + displays: ReadonlyArray<{ workArea: Electron.Rectangle }>, 137 142 bounds: Electron.Rectangle, 138 143 ): number { 139 144 const area = bounds.width * bounds.height; ··· 156 161 } 157 162 158 163 /** Window has < STRANDED_THRESHOLD area on any display → needs rescue. */ 159 - function isStranded(displays: Electron.Display[], bounds: Electron.Rectangle): boolean { 164 + export function isStranded( 165 + displays: ReadonlyArray<{ workArea: Electron.Rectangle }>, 166 + bounds: Electron.Rectangle, 167 + ): boolean { 160 168 if (displays.length === 0) return false; // can't rescue if there are no displays 161 169 return maxOverlapFraction(displays, bounds) < STRANDED_THRESHOLD; 162 170 }