fix: some apps have messy launch behavior
See discussion: https://github.com/lwouis/alt-tab-macos/issues/117#issuecomment-583868046
This commit is contained in:
1 parent
6c440a7926
commit
7eb216d43c
2 files changed
+17
-13
No files matched your search
@@ -49,13 +49,15 @@ extension AXUIElement {
|
||||
return attribute(kAXSubroleAttribute, String.self)
|
||||
}
|
||||
|
||||
func subscribeWithRetry(_ axObserver: AXObserver, _ notification: String, _ pointer: UnsafeMutableRawPointer?) {
|
||||
func subscribeWithRetry(_ axObserver: AXObserver, _ notification: String, _ pointer: UnsafeMutableRawPointer?, _ callback: (() -> Void)? = nil, _ previousResult: AXError? = nil) {
|
||||
let result = AXObserverAddNotification(axObserver, self, notification as CFString, pointer)
|
||||
if result != .success && result != .notificationUnsupported && result != .notificationAlreadyRegistered {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10), execute: {
|
||||
self.subscribeWithRetry(axObserver, notification, pointer)
|
||||
})
|
||||
if result == .success || result == .notificationUnsupported || result == .notificationAlreadyRegistered {
|
||||
callback?()
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10), execute: {
|
||||
self.subscribeWithRetry(axObserver, notification, pointer, callback, result)
|
||||
})
|
||||
}
|
||||
|
||||
private func attribute<T>(_ key: String, _ type: T.Type) -> T? {
|
||||
|
||||
@@ -4,6 +4,7 @@ class Application: NSObject {
|
||||
var runningApplication: NSRunningApplication
|
||||
var axUiElement: AXUIElement?
|
||||
var axObserver: AXObserver?
|
||||
var isReallyFinishedLaunching = false
|
||||
|
||||
init(_ runningApplication: NSRunningApplication) {
|
||||
self.runningApplication = runningApplication
|
||||
@@ -22,13 +23,7 @@ class Application: NSObject {
|
||||
private func addAndObserveWindows() {
|
||||
axUiElement = AXUIElementCreateApplication(runningApplication.processIdentifier)
|
||||
AXObserverCreate(runningApplication.processIdentifier, axObserverCallback, &axObserver)
|
||||
observeAllWindows()
|
||||
}
|
||||
|
||||
private func observeAllWindows() {
|
||||
let windows = getActualWindows()
|
||||
debugPrint("Adding app: " + (runningApplication.bundleIdentifier ?? "nil"), windows.map { $0.title() })
|
||||
addWindows(windows)
|
||||
debugPrint("Adding app: " + (runningApplication.bundleIdentifier ?? "nil"))
|
||||
observeEvents()
|
||||
}
|
||||
|
||||
@@ -65,7 +60,14 @@ class Application: NSObject {
|
||||
kAXApplicationHiddenNotification,
|
||||
kAXApplicationShownNotification,
|
||||
] {
|
||||
axUiElement!.subscribeWithRetry(axObserver, notification, selfPointer)
|
||||
axUiElement!.subscribeWithRetry(axObserver, notification, selfPointer, {
|
||||
// some apps have `isFinishedLaunching == true` but are actually not finished, and will return .cannotComplete
|
||||
// we consider them ready when the first subscription succeeds, and list their windows again at that point
|
||||
if !self.isReallyFinishedLaunching {
|
||||
self.isReallyFinishedLaunching = true
|
||||
self.observeNewWindows()
|
||||
}
|
||||
})
|
||||
}
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), AXObserverGetRunLoopSource(axObserver), .defaultMode)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user