From 8ae406087c58b6230b1b988b4a5b48dfc6f00f75 Mon Sep 17 00:00:00 2001 From: Joshua Van Deren Date: Sun, 9 Aug 2026 00:10:38 -0600 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=90=9E=20Avoid=20cursor=20stutter=20w?= =?UTF-8?q?hen=20suppressing=20Mission=20Control?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrite top-edge drag events in an active tap instead of warping the cursor each frame, which caused the stutter reported in #609. Co-authored-by: Cursor --- Loop/Core/WindowDragManager.swift | 65 ++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/Loop/Core/WindowDragManager.swift b/Loop/Core/WindowDragManager.swift index 29564f9f..b7200e87 100644 --- a/Loop/Core/WindowDragManager.swift +++ b/Loop/Core/WindowDragManager.swift @@ -6,6 +6,7 @@ // import Defaults +import os import Scribe import SwiftUI @@ -23,12 +24,18 @@ final class WindowDragManager { private let previewController = PreviewController() - private var leftMouseDraggedMonitor: PassiveEventMonitor? + private var leftMouseDraggedMonitor: ActiveEventMonitor? private var leftMouseUpMonitor: PassiveEventMonitor? private var determineDraggedWindowTask: Task<(), Never>? private var accessibilityCheckerTask: Task<(), Never>? + /// Mirrored onto the event-tap thread so top-edge drag events can be rewritten without warping the cursor. + private let shouldSuppressMissionControlMirror = OSAllocatedUnfairLock(initialState: false) + nonisolated private var shouldSuppressMissionControlAtomic: Bool { + shouldSuppressMissionControlMirror.withLock { $0 } + } + private var currentMousePosition: CGPoint { NSEvent.mouseLocation.flipY(screen: NSScreen.screens[0]) } @@ -67,11 +74,21 @@ final class WindowDragManager { private func setupListeners() { removeListeners() - let leftMouseDraggedMonitor = PassiveEventMonitor( + let leftMouseDraggedMonitor = ActiveEventMonitor( "snapping_left_mouse_dragged_monitor", - events: [.leftMouseDragged], - callback: leftMouseDragged - ) + events: [.leftMouseDragged] + ) { [weak self] event -> Unmanaged? in + guard let self else { + return Unmanaged.passUnretained(event) + } + + if shouldSuppressMissionControlAtomic { + Self.nudgeEventOffTopEdge(event) + } + + leftMouseDragged(event: event) + return Unmanaged.passUnretained(event) + } let leftMouseUpMonitor = PassiveEventMonitor( "snapping_left_mouse_up_monitor", @@ -94,6 +111,29 @@ final class WindowDragManager { leftMouseDraggedMonitor = nil } + /// Rewrites a top-edge drag so macOS never sees a sustained Mission Control trigger zone hit. + /// Prefer this over `CGWarpMouseCursorPosition`, which fights the cursor every event and causes stutter. + private nonisolated static func nudgeEventOffTopEdge(_ event: CGEvent) { + let location = event.location + + let screenBounds = NSScreen.screens + .map(\.displayBounds) + .first { bounds in + location.x >= bounds.minX && + location.x <= bounds.maxX && + location.y >= bounds.minY && + location.y <= bounds.maxY + } ?? NSScreen.main?.displayBounds + + guard let bounds = screenBounds, location.y <= bounds.minY else { + return + } + + var adjusted = location + adjusted.y = bounds.minY + 1 + event.location = adjusted + } + private func leftMouseDragged(event _: CGEvent) { guard shouldMonitorDragActions else { return @@ -114,15 +154,6 @@ final class WindowDragManager { } if Defaults[.windowSnapping] { - // Only warp cursor away from top edge if top snap area is enabled - if Defaults[.suppressMissionControlOnTopDrag], - let frame = NSScreen.main?.displayBounds, - let mouseLocation = CGEvent.mouseLocation, - mouseLocation.y == frame.minY { - let newOrigin = CGPoint(x: mouseLocation.x, y: frame.minY + 1) - CGWarpMouseCursorPosition(newOrigin) - } - processSnapAction() } } @@ -183,6 +214,11 @@ final class WindowDragManager { await context.refreshResolvedState() self.resizeContext = context + // Arm top-edge event rewriting early so Mission Control never sees a sustained hit. + shouldSuppressMissionControlMirror.withLock { + $0 = Defaults[.windowSnapping] && Defaults[.suppressMissionControlOnTopDrag] + } + log.info("Determined window being dragged: \(window.description)") } } @@ -193,6 +229,7 @@ final class WindowDragManager { initialWindowFrame = nil determineDraggedWindowTask?.cancel() determineDraggedWindowTask = nil + shouldSuppressMissionControlMirror.withLock { $0 = false } } private func hasWindowMoved(_ windowFrame: CGRect, _ initialFrame: CGRect) -> Bool { From 98dda0d5ca68391879ecb142b966a6147927dd20 Mon Sep 17 00:00:00 2001 From: Joshua Van Deren Date: Sun, 9 Aug 2026 00:12:36 -0600 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8E=A8=20Clarify=20Mission=20Control?= =?UTF-8?q?=20suppress=20drag=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- Loop/Core/WindowDragManager.swift | 32 +++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/Loop/Core/WindowDragManager.swift b/Loop/Core/WindowDragManager.swift index b7200e87..103c302e 100644 --- a/Loop/Core/WindowDragManager.swift +++ b/Loop/Core/WindowDragManager.swift @@ -24,16 +24,21 @@ final class WindowDragManager { private let previewController = PreviewController() + /// Active (not listen-only) so we can rewrite top-edge drag events before macOS handles them. + /// See `nudgeEventOffTopEdge(_:)` — this replaces cursor warping, which caused stutter (#609). private var leftMouseDraggedMonitor: ActiveEventMonitor? private var leftMouseUpMonitor: PassiveEventMonitor? private var determineDraggedWindowTask: Task<(), Never>? private var accessibilityCheckerTask: Task<(), Never>? - /// Mirrored onto the event-tap thread so top-edge drag events can be rewritten without warping the cursor. - private let shouldSuppressMissionControlMirror = OSAllocatedUnfairLock(initialState: false) - nonisolated private var shouldSuppressMissionControlAtomic: Bool { - shouldSuppressMissionControlMirror.withLock { $0 } + /// Whether the current window drag should keep Mission Control from opening. + /// + /// The drag callback runs on the event-tap thread, while window resolution happens on the + /// main actor, so this flag is shared through a lock (same pattern as `LoopManager`). + private let shouldSuppressMissionControlOnDrag = OSAllocatedUnfairLock(initialState: false) + nonisolated private var isSuppressingMissionControl: Bool { + shouldSuppressMissionControlOnDrag.withLock { $0 } } private var currentMousePosition: CGPoint { @@ -82,7 +87,9 @@ final class WindowDragManager { return Unmanaged.passUnretained(event) } - if shouldSuppressMissionControlAtomic { + // If suppress is enabled for this drag, shift the event 1px off the top edge + // before it reaches the system (prevents Mission Control without warping the cursor). + if isSuppressingMissionControl { Self.nudgeEventOffTopEdge(event) } @@ -111,11 +118,15 @@ final class WindowDragManager { leftMouseDraggedMonitor = nil } - /// Rewrites a top-edge drag so macOS never sees a sustained Mission Control trigger zone hit. - /// Prefer this over `CGWarpMouseCursorPosition`, which fights the cursor every event and causes stutter. + /// Keeps Mission Control from opening during a top-edge window snap. + /// + /// macOS opens Mission Control when a window drag stays on the top screen edge. + /// We rewrite that event so its reported Y is 1px below the edge. Mutating the event + /// is smoother than `CGWarpMouseCursorPosition`, which fights the real cursor every frame. private nonisolated static func nudgeEventOffTopEdge(_ event: CGEvent) { let location = event.location + // CGEvent locations use display coordinates (`NSScreen.displayBounds`), not AppKit frames. let screenBounds = NSScreen.screens .map(\.displayBounds) .first { bounds in @@ -125,6 +136,7 @@ final class WindowDragManager { location.y <= bounds.maxY } ?? NSScreen.main?.displayBounds + // Top edge in these coordinates is `minY` (origin is top-left of the main display). guard let bounds = screenBounds, location.y <= bounds.minY else { return } @@ -214,8 +226,8 @@ final class WindowDragManager { await context.refreshResolvedState() self.resizeContext = context - // Arm top-edge event rewriting early so Mission Control never sees a sustained hit. - shouldSuppressMissionControlMirror.withLock { + // Enable Mission Control suppression for the rest of this drag when the setting allows it. + shouldSuppressMissionControlOnDrag.withLock { $0 = Defaults[.windowSnapping] && Defaults[.suppressMissionControlOnTopDrag] } @@ -229,7 +241,7 @@ final class WindowDragManager { initialWindowFrame = nil determineDraggedWindowTask?.cancel() determineDraggedWindowTask = nil - shouldSuppressMissionControlMirror.withLock { $0 = false } + shouldSuppressMissionControlOnDrag.withLock { $0 = false } } private func hasWindowMoved(_ windowFrame: CGRect, _ initialFrame: CGRect) -> Bool {