From db93ef6e2dc43f2be22ed548da806eb0d38f6fcf Mon Sep 17 00:00:00 2001 From: Tyler Hebenstreit Date: Wed, 1 Jul 2026 19:24:07 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9E=20Don't=20let=20no-op=20actions=20?= =?UTF-8?q?clobber=20the=20cached=20base=20frame=20(grow-from-zero)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `recomputeTargetFrame` unconditionally cached the frame returned by `WindowFrameResolver.getFrame`, including the zero-size centered sentinel that no-frame actions (.noAction/.noSelection/.cycle/.minimize/.hide, and window-focus actions) return. In a preview-only chord (e.g. trigger + a "do nothing" action, then an arrow), `lastAppliedFrame` is still nil, so the subsequent grow/shrink/move reads that sentinel from `cachedTargetFrame.raw` as its base and resizes from a zero-size box at screen center instead of the window's real frame. Skip caching for no-op/no-frame actions, preserving the real base frame — matching pre-refactor (1.4.2) behavior. --- .../Window Manipulation/ResizeContext.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Loop/Window Management/Window Manipulation/ResizeContext.swift b/Loop/Window Management/Window Manipulation/ResizeContext.swift index 237db048..ad5753ea 100644 --- a/Loop/Window Management/Window Manipulation/ResizeContext.swift +++ b/Loop/Window Management/Window Manipulation/ResizeContext.swift @@ -131,6 +131,18 @@ final class ResizeContext { } private func recomputeTargetFrame() { + // No-op / no-frame actions (.noAction, .noSelection, .cycle, .minimize, .hide) and + // window-focus actions return a zero-size sentinel from `getFrame`. Caching that + // sentinel would clobber `cachedTargetFrame.raw`, which grow/shrink/move actions use + // as their base frame while nothing has been applied yet (preview-only chords) — + // making a subsequent grow resize from a zero-size box at screen center instead of + // the window's real frame. Preserve the previously-cached real frame for these. + let noFrameActions: [WindowDirection] = [.noAction, .noSelection, .cycle, .minimize, .hide] + guard !noFrameActions.contains(action.direction), !action.direction.willFocusWindow else { + needsRecompute = false + return + } + let result = WindowFrameResolver.getFrame(resizeContext: self) let normalized = CGRect(