Skip to content

Fit a new snap into the space beside a recently snapped window - #1903

Open
kiteretsu903 wants to merge 4 commits into
rxhanson:mainfrom
kiteretsu903:fix/review-fit-remaining-space
Open

kiteretsu903 wants to merge 4 commits into
rxhanson:mainfrom
kiteretsu903:fix/review-fit-remaining-space

Conversation

@kiteretsu903

@kiteretsu903 kiteretsu903 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Adds the off-by-default “Fit remaining space” option under Adjacent Windows. If a window has just been snapped to one side, the next complementary half-screen snap can use its actual edge instead of assuming a 50/50 split. Only the incoming window is resized; the existing neighbor stays in place.

Behavior and boundaries

  • Works for left/right and top/bottom half-screen pairs, respecting configured gaps and outer padding.

  • Uses a verified snap from the preceding 10 seconds; a displayed drag preview keeps that verified anchor until release, with geometry and identity rechecked. The neighbor must still belong to the same process instance, be visible, and remain at its recorded geometry. This does not infer a layout from any old window occupying one side of the screen.

  • Explicit fractions and repeated-command size cycling keep their requested geometry. If there is no valid recent complementary snap, normal placement applies.

  • Partial occlusion still allows the neighbor to participate. Complete coverage, including coverage by several visible windows together, does not. The incoming window is excluded from that occlusion check.

  • The remaining size is requested even if the application reports a larger minimum. An application may enforce a larger minimum and overlap its neighbor; Fit does not shrink or move that neighbor to compensate. A region with no positive extent is rejected.

  • Responsive grid-rounded and maximum-size results can settle smaller than requested and keep the configured edge alignment. Response evidence survives probes of the other axis. Bounded probes distinguish minimum/maximum constraints; one fixed axis can settle after the other axis responds, while wholly ignored resizing still fails.

  • Drag snaps preserve the pre-drag restore frame. Interrupted placements preserve restore history and retire stale action cycling.

Implementation

SnappedWindowFit resolves the target; a short-lived session owns the recent anchor. A shared serial placement coordinator verifies writes and handles cancellation without depending on animation interpolation. Helper and divider changes reuse placement utilities through their own feature-specific paths. Elements without an AX window ID retain the ordinary mover fallback using the resolved bookkeeping ID.

Rebuilt on current main without #1902. Placement uses reported AX constraints and verification from the current attempt; it does not read, learn, or persist window size limits. The proposed preview-only tracking feature is outside this change.

Validation

The current branch passed a signed Debug build and all 602 XCTest tests. Regression coverage includes rounded-down resizing, mixed minimum/grid constraints, an axis already at its maximum, fixed-axis settlement, wholly ignored resizing, and preview expiry. Native acceptance on macOS 27.2 / Apple silicon covers both axes and animation modes, both connected displays, disabled behavior and explicit fractions, gaps, anchor invalidation/occlusion, changing minima, drag restore history, and interruption by a subsequent shortcut. The 13-method native suite also checks the missing-AX-ID fallback and hidden-neighbor rejection. Its non-animated history test models a late write with a fixture frame change between cancellation and the next command. The occlusion fixture waits for WindowServer to confirm stacking order before executing the snap. The installed Rectangle binary and saved preferences are restored and verified after each run.

These are automated native acceptance results; they do not claim Intel or older-macOS execution. The demo below predates the standalone rebase.

An earlier physical-input acceptance run used global macOS mouse events to drag the incoming window to the complementary screen edge. It filled the remaining 576 points beside an 864-point anchor, with matching AX/WindowServer geometry and the anchor unchanged. The test used deterministic temporary snap settings; the installed binary, saved preferences, and pointer position were restored afterward.

This replaces the corresponding part of #1887.

Demo

06-fit-remaining-space.mp4

Window animation is disabled. Recorded with the combined build and only this feature and its required visual options enabled.

Settings

Fit a new snap into the space beside a recently snapped window settings

@kiteretsu903
kiteretsu903 force-pushed the fix/review-fit-remaining-space branch from 7a59f42 to 95bbdbd Compare October 14, 2026 01:38
@kiteretsu903
kiteretsu903 marked this pull request as ready for review October 14, 2026 02:27
@rxhanson

Copy link
Copy Markdown
Owner

There's a flaw in my design of WindowManager, where it becomes a place that needs to be modified in most changes to Rectangle functionality. Ideally, this change wouldn't have to modify the WindowManager, but would leverage a hook instead (which also goes for ShortcutManager). I'm debating whether this work should be done prior to merging this change. The different architecture would look a little more like a pipeline with hooks at each of the different stages of before/after calculations, adjusting calculations, and before/after applying the window placement. On this note, placeBesideSnappedWindow should be moved outside of WindowManager, and I think it would make more sense to have things like this live in files that hook into the pipeline as opposed to being directly inserted as part of it. I realize that these PRs have been in limbo for a while, but want to make sure that it's easy to build something stable. I'll give it a little more thought and post back when I decide on a direction.

@kiteretsu903

Copy link
Copy Markdown
Contributor Author

There's a flaw in my design of WindowManager, where it becomes a place that needs to be modified in most changes to Rectangle functionality. Ideally, this change wouldn't have to modify the WindowManager, but would leverage a hook instead (which also goes for ShortcutManager). I'm debating whether this work should be done prior to merging this change. The different architecture would look a little more like a pipeline with hooks at each of the different stages of before/after calculations, adjusting calculations, and before/after applying the window placement. On this note, placeBesideSnappedWindow should be moved outside of WindowManager, and I think it would make more sense to have things like this live in files that hook into the pipeline as opposed to being directly inserted as part of it. I realize that these PRs have been in limbo for a while, but want to make sure that it's easy to build something stable. I'll give it a little more thought and post back when I decide on a direction.

That makes sense to me. Let me know how I could help with the refactoring!

@rxhanson

Copy link
Copy Markdown
Owner

Thanks for your understanding! I'm getting ready to wrap up some other app work and will rearchitect the WindowManager soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants