fix: avoid showing closed windows (closes #3589)

closes #4924
This commit is contained in:
lwouis committed 2025-12-20 01:14:30 +01:00
1 parent e2523f1d99
commit 894a69d41f
3 files changed
+53 -13

No files matched your search

+36
View File
@@ -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
View File
@@ -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)
}
+1 -11
View File
@@ -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)
}
}
}