Add window edge snapping resistance#150
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis PR implements window snapping for move and resize operations. WindowManager.getVisibleWindowRects(excluding:) collects on-screen window rectangles. MouseTracker adds snapRects, snapDistance, and last-applied state, populates snapRects when tracking starts, and clears them on reset. Move handling replaces the computed origin with a snapped origin based on nearest X/Y edge deltas within snapDistance. Resize handling clamps dimensions to >=1, computes snapped origin/size using active edges (quadrant-driven fallback), and applies WindowManager.resize only when snapped values differ from the last applied ones. Sequence Diagram(s)sequenceDiagram
participant MouseTracker
participant WindowManager
participant CGWindowList
MouseTracker->>WindowManager: getVisibleWindowRects(excluding: currentAXWindow?)
WindowManager->>CGWindowList: CGWindowListCopyWindowInfo(query on-screen windows)
CGWindowList-->>WindowManager: window info list
WindowManager-->>MouseTracker: [CGRect] visible window rects
MouseTracker->>MouseTracker: compute target origin/size (move or resize)
MouseTracker->>MouseTracker: compute snapped origin/size using snapRects & snapDistance
MouseTracker->>WindowManager: move/resize window to snapped origin/size
WindowManager-->>MouseTracker: confirmation (implicit)
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Swift` Shift/src/Manager/WindowManager.swift:
- Around line 23-41: getVisibleWindowRects currently iterates apps'
kAXWindowsAttribute (AXUIElement) causing inclusion of minimized/off‑space
windows and synchronous AX round‑trips during prepareTracking; replace the AX
round‑trip with reading kCGWindowBounds from each CGWindowListCopyWindowInfo
entry (which was already filtered with .optionOnScreenOnly) similar to
getTopWindowAtCursorUsingCGWindowList, building rects directly from
kCGWindowBounds to avoid AX queries and eliminate invisible/off‑space windows;
if you must keep AX, add checks for kAXMinimizedAttribute and intersect each
rect with NSScreen.screens frames to exclude off‑space windows and minimize AX
calls during prepareTracking.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2d621e4c-f2ca-4cd6-902e-b12f1e329169
📒 Files selected for processing (2)
Swift Shift/src/Manager/MouseTracker.swiftSwift Shift/src/Manager/WindowManager.swift
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Swift` Shift/src/Manager/WindowManager.swift:
- Line 37: The exclusion check in WindowManager.swift incorrectly filters any
window that fully contains the dragged window by using
rect.intersection(excludedRect).equalTo(excludedRect); change the logic so it
only excludes the exact same window by comparing the rects for exact equality
(use rect.equalTo(excludedRect) when unwrapping excludedRect) instead of using
intersection(); update the conditional around excludedRect and rect to return
nil only when the two rects are exactly equal.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c7df5245-bde2-4e96-bcb5-0efe581bfea8
📒 Files selected for processing (1)
Swift Shift/src/Manager/WindowManager.swift
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
Swift Shift/src/Manager/WindowManager.swift (1)
37-37: 🏗️ Heavy liftConsider using a more robust method to identify and exclude the dragged window.
The
excludedRectis computed from the AX API (getPosition/getSize) whilerectcomes fromkCGWindowBoundsinCGWindowListCopyWindowInfo. Comparing them with exact floating-point equality viaequalTois fragile and may fail if the two APIs produce slightly different values due to precision differences or timing. While no issues are currently reported, this could cause the dragged window to appear in snap targets under edge cases.Prefer using the window's
CGWindowIDfor comparison: extract it frominfo[kCGWindowNumber as String] as? CGWindowIDand derive a matching ID from the AX element via_AXUIElementGetWindow. Alternatively, add a small epsilon tolerance to the rect comparison if window IDs are unavailable.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Swift` Shift/src/Manager/WindowManager.swift at line 37, The current exact rect comparison (rect.equalTo(excludedRect)) is fragile; instead use the window's CGWindowID for robust exclusion: extract the CGWindowID from the CGWindowList info via info[kCGWindowNumber as String] as? CGWindowID and obtain the AX element's window ID via _AXUIElementGetWindow, then compare IDs to skip the dragged window (fallback: if IDs unavailable, use rect comparison with a small epsilon/tolerance). Update the logic around excludedRect/rect in WindowManager.swift to prefer ID comparison, falling back to tolerant rect comparison.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Swift` Shift/src/Manager/WindowManager.swift:
- Line 36: The current check uses NSRunningApplication(processIdentifier:
pid)?.bundleIdentifier and only filters when a bundleId exists, thereby
including windows with nil bundle identifiers; change this to explicitly exclude
nil bundle identifiers by making the conditional require a non-nil bundleId
(e.g., replace the optional binding with a guard/if-let that returns nil when
bundleId is nil) or, if inclusion is desired, add a PreferencesManager flag
(e.g., PreferencesManager.includeAppsWithoutBundleId) and use that flag
alongside NSRunningApplication(processIdentifier: pid)?.bundleIdentifier and
PreferencesManager.isAppIgnored(bundleId) to decide whether to return nil;
update the logic around NSRunningApplication(processIdentifier:
pid)?.bundleIdentifier and PreferencesManager.isAppIgnored to reflect the chosen
behavior.
---
Nitpick comments:
In `@Swift` Shift/src/Manager/WindowManager.swift:
- Line 37: The current exact rect comparison (rect.equalTo(excludedRect)) is
fragile; instead use the window's CGWindowID for robust exclusion: extract the
CGWindowID from the CGWindowList info via info[kCGWindowNumber as String] as?
CGWindowID and obtain the AX element's window ID via _AXUIElementGetWindow, then
compare IDs to skip the dragged window (fallback: if IDs unavailable, use rect
comparison with a small epsilon/tolerance). Update the logic around
excludedRect/rect in WindowManager.swift to prefer ID comparison, falling back
to tolerant rect comparison.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b57ab647-45d1-4769-aa66-9f963f653d68
📒 Files selected for processing (1)
Swift Shift/src/Manager/WindowManager.swift
Summary
CleanShot.2026-05-13.at.18.50.29.yafw.balanced.mp4
Fixes #44
Test plan
xcodebuild -project "Swift Shift.xcodeproj" -scheme "Swift Shift" -configuration Debug buildSummary by CodeRabbit
New Features
Bug Fixes / Improvements