diff --git a/Sources/AppBundle/GlobalObserver.swift b/Sources/AppBundle/GlobalObserver.swift index 2c467464f..c11ec9c6b 100644 --- a/Sources/AppBundle/GlobalObserver.swift +++ b/Sources/AppBundle/GlobalObserver.swift @@ -11,7 +11,7 @@ class GlobalObserver { } let notifName = notification.name.rawValue MainActor.assumeIsolated { - refreshAndLayout(.globalObserver(notifName), screenIsDefinitelyUnlocked: false) + scheduleRefreshAndLayout(.globalObserver(notifName), screenIsDefinitelyUnlocked: false) } } @@ -67,7 +67,7 @@ class GlobalObserver { // Detect close button clicks for unfocused windows. Yes, kAXUIElementDestroyedNotification is that unreliable // And trigger new window detection that could be delayed due to mouseDown event default: - refreshAndLayout(.globalObserverLeftMouseUp, screenIsDefinitelyUnlocked: true) + scheduleRefreshAndLayout(.globalObserverLeftMouseUp, screenIsDefinitelyUnlocked: true) } } } diff --git a/Sources/AppBundle/layout/refresh.swift b/Sources/AppBundle/layout/refresh.swift index a431e0905..8ac243703 100644 --- a/Sources/AppBundle/layout/refresh.swift +++ b/Sources/AppBundle/layout/refresh.swift @@ -47,6 +47,25 @@ func refreshAndLayout(_ event: RefreshSessionEvent, screenIsDefinitelyUnlocked: refreshSession(event, screenIsDefinitelyUnlocked: screenIsDefinitelyUnlocked, startup: startup, body: {}) } +@MainActor private var havePendingRefresh = false +@MainActor private var pendingRefreshScreenIsDefinitelyUnlocked = false + +@MainActor +func scheduleRefreshAndLayout(_ event: RefreshSessionEvent, screenIsDefinitelyUnlocked: Bool = false) { + if havePendingRefresh { + if screenIsDefinitelyUnlocked { + pendingRefreshScreenIsDefinitelyUnlocked = true + } + return + } + havePendingRefresh = true + pendingRefreshScreenIsDefinitelyUnlocked = screenIsDefinitelyUnlocked + DispatchQueue.main.async { @MainActor in + havePendingRefresh = false + refreshSession(event, screenIsDefinitelyUnlocked: pendingRefreshScreenIsDefinitelyUnlocked, startup: false, body: {}) + } +} + @MainActor func refreshModel() { gc() @@ -81,7 +100,7 @@ func refreshObs(_ obs: AXObserver, ax: AXUIElement, notif: CFString, data: Unsaf check(Thread.isMainThread) let notif = notif as String MainActor.assumeIsolated { - refreshAndLayout(.ax(notif), screenIsDefinitelyUnlocked: false) + scheduleRefreshAndLayout(.ax(notif), screenIsDefinitelyUnlocked: false) } } diff --git a/Sources/AppBundle/mouse/moveWithMouse.swift b/Sources/AppBundle/mouse/moveWithMouse.swift index 2901eaa9d..3cfb043a6 100644 --- a/Sources/AppBundle/mouse/moveWithMouse.swift +++ b/Sources/AppBundle/mouse/moveWithMouse.swift @@ -9,7 +9,7 @@ func movedObs(_ obs: AXObserver, ax: AXUIElement, notif: CFString, data: UnsafeM if let windowId, let window = Window.get(byId: windowId), TrayMenuModel.shared.isEnabled { moveWithMouseIfTheCase(window) } - refreshAndLayout(.ax(notif), screenIsDefinitelyUnlocked: false) + scheduleRefreshAndLayout(.ax(notif), screenIsDefinitelyUnlocked: false) } } diff --git a/Sources/AppBundle/mouse/resizeWithMouse.swift b/Sources/AppBundle/mouse/resizeWithMouse.swift index 8baf55c3c..f67d9fb7a 100644 --- a/Sources/AppBundle/mouse/resizeWithMouse.swift +++ b/Sources/AppBundle/mouse/resizeWithMouse.swift @@ -9,7 +9,7 @@ func resizedObs(_ obs: AXObserver, ax: AXUIElement, notif: CFString, data: Unsaf if let windowId, let window = Window.get(byId: windowId), TrayMenuModel.shared.isEnabled { resizeWithMouseIfTheCase(window) } - refreshAndLayout(.ax(notif), screenIsDefinitelyUnlocked: false) + scheduleRefreshAndLayout(.ax(notif), screenIsDefinitelyUnlocked: false) } } @@ -21,7 +21,7 @@ func resetManipulatedWithMouseIfPossible() { for workspace in Workspace.all { workspace.resetResizeWeightBeforeResizeRecursive() } - refreshAndLayout(.resetManipulatedWithMouse, screenIsDefinitelyUnlocked: true) + scheduleRefreshAndLayout(.resetManipulatedWithMouse, screenIsDefinitelyUnlocked: true) } }