1 parent
e2523f1d99
commit
894a69d41f
3 files changed
+53
-13
No files matched your search
@@ -14,11 +14,47 @@ class Applications {
|
||||
}
|
||||
|
||||
static func manuallyRefreshAllWindows() {
|
||||
removeZombieWindows()
|
||||
addMissingWindows()
|
||||
}
|
||||
|
||||
/// we may not receive a window-created event in some cases:
|
||||
/// * we can't subscribe to the app
|
||||
/// * we couldn't subscribe to the app before the window was created
|
||||
/// * weird cases like apps launching at startup with "restaure windows"
|
||||
/// this manually queries the system for windows, and keeps our list in-sync with the actual system
|
||||
static func addMissingWindows() {
|
||||
for app in list {
|
||||
app.manuallyUpdateWindows()
|
||||
}
|
||||
}
|
||||
|
||||
/// we may not receive a window-destroyed event in some cases:
|
||||
/// * Sequoia bug: https://github.com/lwouis/alt-tab-macos/issues/3589
|
||||
/// * Logic Pro bug: https://github.com/lwouis/alt-tab-macos/issues/4924
|
||||
/// this acts as a garbage-collector for windows, to keep our list in-sync with the actual system
|
||||
static func removeZombieWindows() {
|
||||
let wIds = Windows.list.compactMap { $0.cgWindowId }
|
||||
guard !wIds.isEmpty else { return }
|
||||
let values = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: wIds.count)
|
||||
for (i, id) in wIds.enumerated() {
|
||||
values[i] = UnsafeRawPointer(bitPattern: UInt(id))
|
||||
}
|
||||
let rawIds = CFArrayCreate(kCFAllocatorDefault, values, wIds.count, nil)
|
||||
let descriptions = (CGWindowListCreateDescriptionFromArray(rawIds) as? [[CFString: Any]])
|
||||
let existingWids = descriptions?.compactMap { $0[kCGWindowNumber] } as? [CGWindowID]
|
||||
guard let existingWids else { return }
|
||||
let believedAlive = Set(wIds)
|
||||
let confirmedAlive = Set(existingWids)
|
||||
let zombies = believedAlive.subtracting(confirmedAlive)
|
||||
for (index, window) in Windows.list.enumerated().reversed() {
|
||||
if let wid = window.cgWindowId, zombies.contains(wid) {
|
||||
Logger.error("----", window.title, window.application.bundleIdentifier)
|
||||
Windows.removeWindow(index, window.application.pid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func addRunningApplications(_ runningApps: [NSRunningApplication]) {
|
||||
runningApps.forEach {
|
||||
let bundleIdentifier = $0.bundleIdentifier
|
||||
|
||||
+16
-2
@@ -131,7 +131,21 @@ class Windows {
|
||||
}
|
||||
}
|
||||
|
||||
static func removeAndUpdateFocus(_ window: Window) {
|
||||
static func removeWindow(_ index: Int, _ pid: pid_t) {
|
||||
let window = Windows.list[index]
|
||||
removeAndUpdateFocus(window)
|
||||
if window.application.addWindowlessWindowIfNeeded() != nil {
|
||||
Applications.find(pid)?.focusedWindow = nil
|
||||
}
|
||||
if Windows.list.count > 0 {
|
||||
moveFocusedWindowIndexAfterWindowDestroyedInBackground(index)
|
||||
App.app.refreshOpenUi([], .refreshUiAfterExternalEvent)
|
||||
} else {
|
||||
App.app.hideUi()
|
||||
}
|
||||
}
|
||||
|
||||
private static func removeAndUpdateFocus(_ window: Window) {
|
||||
let removedWindowOldFocusOrder = window.lastFocusOrder
|
||||
list.removeAll {
|
||||
if $0.lastFocusOrder == removedWindowOldFocusOrder {
|
||||
@@ -245,7 +259,7 @@ class Windows {
|
||||
return targetIndex
|
||||
}
|
||||
|
||||
static func moveFocusedWindowIndexAfterWindowDestroyedInBackground(_ index: Int) {
|
||||
private static func moveFocusedWindowIndexAfterWindowDestroyedInBackground(_ index: Int) {
|
||||
if index < focusedWindowIndex {
|
||||
cycleFocusedWindowIndex(-1)
|
||||
}
|
||||
|
||||
@@ -150,17 +150,7 @@ class AccessibilityEvents {
|
||||
let wid = try element.cgWindowId()
|
||||
DispatchQueue.main.async {
|
||||
if let index = (Windows.list.firstIndex { $0.isEqualRobust(element, wid) }) {
|
||||
let window = Windows.list[index]
|
||||
Windows.removeAndUpdateFocus(window)
|
||||
if window.application.addWindowlessWindowIfNeeded() != nil {
|
||||
Applications.find(pid)?.focusedWindow = nil
|
||||
}
|
||||
if Windows.list.count > 0 {
|
||||
Windows.moveFocusedWindowIndexAfterWindowDestroyedInBackground(index)
|
||||
App.app.refreshOpenUi([], .refreshUiAfterExternalEvent)
|
||||
} else {
|
||||
App.app.hideUi()
|
||||
}
|
||||
Windows.removeWindow(index, pid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user