From e1677b87555c5d81a203d814fc002207f22deea9 Mon Sep 17 00:00:00 2001 From: Kai Azim Date: Sun, 25 Jan 2026 21:23:18 -0700 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20Extracted=20window=20snapping?= =?UTF-8?q?=20fixes=20from=20PR=20#1015?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Loop/Core/WindowDragManager.swift | 75 +++++++++++++------------------ 1 file changed, 32 insertions(+), 43 deletions(-) diff --git a/Loop/Core/WindowDragManager.swift b/Loop/Core/WindowDragManager.swift index 55914315..26ffb742 100644 --- a/Loop/Core/WindowDragManager.swift +++ b/Loop/Core/WindowDragManager.swift @@ -9,6 +9,7 @@ import Defaults import Scribe import SwiftUI +@MainActor final class WindowDragManager { static let shared = WindowDragManager() private init() {} @@ -42,7 +43,6 @@ final class WindowDragManager { !Defaults[.stashManagerStashedWindows].isEmpty } - @MainActor func addObservers() { accessibilityCheckerTask = Task(priority: .background) { [weak self] in for await status in AccessibilityManager.shared.stream(initial: true) { @@ -90,7 +90,7 @@ final class WindowDragManager { return } - Task { @MainActor in + Task { guard let initialMousePosition else { initialMousePosition = currentMousePosition return @@ -110,9 +110,6 @@ final class WindowDragManager { } if let window = draggingWindow, let initialFrame = initialWindowFrame, hasWindowResized(window.frame, initialFrame) { - StashManager.shared.onWindowDragged(window.cgWindowID) - WindowRecords.eraseRecords(for: window) - if hasWindowMoved(window.frame, initialFrame) { if Defaults[.restoreWindowFrameOnDrag] { restoreInitialWindowSize(window) @@ -131,28 +128,33 @@ final class WindowDragManager { processSnapAction() } } + + StashManager.shared.onWindowDragged(window.cgWindowID) + WindowRecords.eraseRecords(for: window) } } } private func leftMouseUp(_: CGEvent) { - Task { @MainActor in + guard Defaults[.windowSnapping] else { + return + } + + Task { + previewController.close() + if let window = draggingWindow, + let screen = NSScreen.screenWithMouse, let initialFrame = initialWindowFrame, hasWindowMoved(window.frame, initialFrame) { - if Defaults[.windowSnapping] { - attemptWindowSnap(window) - } + WindowEngine.resize(window, to: .init(direction), on: screen) } - previewController.close() draggingWindow = nil - resetDragState() } } - @MainActor private func setCurrentDraggingWindow() { guard determineDraggedWindowTask == nil else { return @@ -163,9 +165,8 @@ final class WindowDragManager { determineDraggedWindowTask = nil } - guard - let draggingWindow = try? WindowUtility.windowAtPosition(currentMousePosition), - !draggingWindow.isAppExcluded + guard let draggingWindow = try? WindowUtility.windowAtPosition(currentMousePosition), + !draggingWindow.isAppExcluded else { didFailToResolveDraggedWindow = true return @@ -263,41 +264,29 @@ final class WindowDragManager { await AccentColorController.shared.refresh() } - direction = WindowDirection.getSnapDirection( + let newDirection = WindowDirection.getSnapDirection( mouseLocation: currentMousePosition, - currentDirection: direction, + currentDirection: oldDirection, screenFrame: screenFrame, ignoredFrame: ignoredFrame ) - Log.info("Window snapping direction changed: \(direction.debugDescription)", category: .windowDragManager) - - previewController.open(screen: screen, window: draggingWindow, startingAction: nil) - previewController.setAction(to: WindowAction(direction)) - } else { + // Only update if direction actually changed + if newDirection != oldDirection { + direction = newDirection + + Log.info("Window snapping direction changed: \(newDirection.debugDescription)", category: .windowDragManager) + + previewController.open(screen: screen, window: draggingWindow, startingAction: nil) + previewController.setAction(to: WindowAction(newDirection)) + + if newDirection != .noAction, Defaults[.hapticFeedback] { + NSHapticFeedbackManager.defaultPerformer.perform(.alignment, performanceTime: .now) + } + } + } else if !(oldDirection == .noAction || oldDirection == .noSelection) { direction = .noAction previewController.close() } - - if direction != oldDirection { - if Defaults[.hapticFeedback] { - NSHapticFeedbackManager.defaultPerformer.perform( - NSHapticFeedbackManager.FeedbackPattern.alignment, - performanceTime: NSHapticFeedbackManager.PerformanceTime.now - ) - } - } - } - - private func attemptWindowSnap(_ window: Window) { - guard let screen = NSScreen.screenWithMouse else { - return - } - - let snapDirection = direction - DispatchQueue.main.async { - WindowEngine.resize(window, to: .init(snapDirection), on: screen) - self.direction = .noAction - } } } From 14be82be9819d4f2061ba271ed8fec071772446e Mon Sep 17 00:00:00 2001 From: Kai Azim Date: Sun, 25 Jan 2026 21:24:28 -0700 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=8E=A8=20Format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Loop/Core/WindowDragManager.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Loop/Core/WindowDragManager.swift b/Loop/Core/WindowDragManager.swift index 26ffb742..37b7e676 100644 --- a/Loop/Core/WindowDragManager.swift +++ b/Loop/Core/WindowDragManager.swift @@ -128,7 +128,7 @@ final class WindowDragManager { processSnapAction() } } - + StashManager.shared.onWindowDragged(window.cgWindowID) WindowRecords.eraseRecords(for: window) } @@ -276,10 +276,10 @@ final class WindowDragManager { direction = newDirection Log.info("Window snapping direction changed: \(newDirection.debugDescription)", category: .windowDragManager) - + previewController.open(screen: screen, window: draggingWindow, startingAction: nil) previewController.setAction(to: WindowAction(newDirection)) - + if newDirection != .noAction, Defaults[.hapticFeedback] { NSHapticFeedbackManager.defaultPerformer.perform(.alignment, performanceTime: .now) } From 6363bccca557cc4485b0588df7e49f32b8474b2e Mon Sep 17 00:00:00 2001 From: Kai Azim Date: Sun, 25 Jan 2026 21:35:42 -0700 Subject: [PATCH 3/3] =?UTF-8?q?=E2=9C=A8=20Extract=20WindowUtility=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Window/WindowUtility.swift | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Loop/Window Management/Window/WindowUtility.swift b/Loop/Window Management/Window/WindowUtility.swift index 6e9ea0e1..623d37d3 100644 --- a/Loop/Window Management/Window/WindowUtility.swift +++ b/Loop/Window Management/Window/WindowUtility.swift @@ -10,31 +10,28 @@ import Defaults import Scribe /// This enum is in charge of fetching windows in the user's workspace, which will be used by Loop. +@Loggable(style: .static) enum WindowUtility { /// Get the target window, depending on the user's preferences. This could be the frontmost window, or the window under the cursor. /// - Returns: The target window static func userDefinedTargetWindow() -> Window? { var result: Window? - do { - Log.info("Getting window at cursor...", category: .windowUtility) + log.info("Getting window at cursor...") - if Defaults[.resizeWindowUnderCursor], - let mouseLocation = CGEvent.mouseLocation, - let window = try windowAtPosition(mouseLocation) { - result = window - } - } catch { - Log.warn("Failed to get window at cursor: \(error.localizedDescription)", category: .windowUtility) + if Defaults[.resizeWindowUnderCursor], + let mouseLocation = CGEvent.mouseLocation, + let window = windowAtPosition(mouseLocation) { + result = window } if result == nil { do { - Log.info("Getting frontmost window...", category: .windowUtility) + log.info("Getting frontmost window...") result = try frontmostWindow() } catch { - Log.warn("Failed to get frontmost window: \(error.localizedDescription)", category: .windowUtility) + log.warn("Failed to get frontmost window: \(error.localizedDescription)") } } @@ -53,11 +50,15 @@ enum WindowUtility { /// Get the Window at a given position. /// - Parameter position: The position to check for /// - Returns: The window at the given position, if any - static func windowAtPosition(_ position: CGPoint) throws -> Window? { - // If we can find the window at a point using the Accessibility API, return it - if let element = try AXUIElement.systemWide.getElementAtPosition(position), - let windowElement: AXUIElement = try element.getValue(.window) { - return try Window(element: windowElement) + static func windowAtPosition(_ position: CGPoint) -> Window? { + do { + // If we can find the window at a point using the Accessibility API, return it + if let element = try AXUIElement.systemWide.getElementAtPosition(position), + let windowElement: AXUIElement = try element.getValue(.window) { + return try Window(element: windowElement) + } + } catch { + log.warn("Failed to determine element at position: \(error.localizedDescription)") } // If the previous method didn't work, loop through all windows on-screen and return the first one that contains the desired point