perf: debounce screen/space events to minimize work
This commit is contained in:
1 parent
ff66a0664d
commit
e2b47790a9
2 files changed
+50
-18
No files matched your search
@@ -1,19 +1,52 @@
|
||||
import Cocoa
|
||||
|
||||
class ScreensEvents {
|
||||
static let debouncerScreenAndSpace = Debouncer(.main)
|
||||
|
||||
static func observe() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleEvent), name: NSApplication.didChangeScreenParametersNotification, object: nil)
|
||||
}
|
||||
|
||||
@objc private static func handleEvent(_ notification: Notification) {
|
||||
Logger.debug { notification.name.rawValue }
|
||||
Spaces.refresh()
|
||||
// a screen added or removed, or screen resolution change can mess up layout; we reset components
|
||||
App.app.resetPreferencesDependentComponents()
|
||||
// a screen added or removed can shuffle windows around Spaces; we refresh them
|
||||
App.app.refreshOpenUi(Windows.list, .refreshUiAfterExternalEvent)
|
||||
Logger.info { "screens:\(NSScreen.screens.map { ($0.uuid() ?? "nil" as CFString, $0.frame) })" }
|
||||
Logger.info { "spaces:\(Spaces.screenSpacesMap)" }
|
||||
Logger.info { "current space:\(Spaces.currentSpaceIndex) (id:\(Spaces.currentSpaceId))" }
|
||||
// screen notifications often arrive in groups (e.g. 2 in a row in a short time)
|
||||
// we debounce to minimize work
|
||||
debouncerScreenAndSpace.debounce(.screenEvent) {
|
||||
Logger.debug { notification.name.rawValue }
|
||||
Spaces.refresh()
|
||||
// a screen added or removed, or screen resolution change can mess up layout; we reset components
|
||||
App.app.resetPreferencesDependentComponents()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class Debouncer {
|
||||
private let queue: DispatchQueue
|
||||
private var workItem: DispatchWorkItem?
|
||||
private var contextsBlocks = [DebounceContext: () -> Void]()
|
||||
|
||||
init(_ queue: DispatchQueue) {
|
||||
self.queue = queue
|
||||
}
|
||||
|
||||
func debounce(_ context: DebounceContext, _ block: @escaping () -> Void) {
|
||||
contextsBlocks[context] = block
|
||||
workItem?.cancel()
|
||||
let item = DispatchWorkItem(block: {
|
||||
for block in self.contextsBlocks.values {
|
||||
block()
|
||||
}
|
||||
// ScreensEvents: a screen added or removed can shuffle windows around Spaces; we refresh them
|
||||
// SpacesEvents: if UI was kept open during Space transition, the Spaces may be obsolete; we refresh them
|
||||
App.app.refreshOpenUi(Windows.list, .refreshUiAfterExternalEvent)
|
||||
Logger.info { "screens:\(NSScreen.screens.map { ($0.uuid() ?? "nil" as CFString, $0.frame) })" }
|
||||
Logger.info { "currentSpace:\(Spaces.currentSpaceIndex) (id:\(Spaces.currentSpaceId)) spaces:\(Spaces.screenSpacesMap)" }
|
||||
})
|
||||
workItem = item
|
||||
queue.asyncAfter(deadline: .now() + humanPerceptionDelay, execute: item)
|
||||
}
|
||||
}
|
||||
|
||||
enum DebounceContext {
|
||||
case spaceEvent
|
||||
case screenEvent
|
||||
}
|
||||
@@ -6,14 +6,13 @@ class SpacesEvents {
|
||||
}
|
||||
|
||||
@objc private static func handleEvent(_ notification: Notification) {
|
||||
Logger.debug { notification.name.rawValue }
|
||||
// if UI was kept open during Space transition, the Spaces may be obsolete; we refresh them
|
||||
App.app.refreshOpenUi(Windows.list, .refreshUiAfterExternalEvent)
|
||||
Logger.info { "current space:\(Spaces.currentSpaceIndex) (id:\(Spaces.currentSpaceId))" }
|
||||
// Workaround for Safari full-screen videos
|
||||
// when full-screening a video, Safari spawns a second full-screen window called "Safari"
|
||||
// this window doesn't emit resize/move events. It doesn't pass isActualWindow on creation. It's added on focusedWindowChanged
|
||||
// for such cases, we refresh isFullscreen on Space change
|
||||
Windows.updateIsFullscreenOnCurrentSpace()
|
||||
ScreensEvents.debouncerScreenAndSpace.debounce(.spaceEvent) {
|
||||
Logger.debug { notification.name.rawValue }
|
||||
// Workaround for Safari full-screen videos
|
||||
// when full-screening a video, Safari spawns a second full-screen window called "Safari"
|
||||
// this window doesn't emit resize/move events. It doesn't pass isActualWindow on creation. It's added on focusedWindowChanged
|
||||
// for such cases, we refresh isFullscreen on Space change
|
||||
Windows.updateIsFullscreenOnCurrentSpace()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user