diff --git a/alt-tab-macos/logic/WindowManager.swift b/alt-tab-macos/logic/WindowManager.swift index b57b25dd..af8bed43 100644 --- a/alt-tab-macos/logic/WindowManager.swift +++ b/alt-tab-macos/logic/WindowManager.swift @@ -1,6 +1,8 @@ import Cocoa import Foundation +let minimumWindowSize: CGFloat = 200 + class OpenWindow { var target: AXUIElement? var ownerPid: pid_t? @@ -46,10 +48,10 @@ func computeDownscaledSize(_ image: NSImage) -> (Int, Int) { func axWindows(_ cgOwnerPid: pid_t) -> [AXUIElement] { if let windows = AXUIElementCopyAttributeValue(AXUIElementCreateApplication(cgOwnerPid), kAXWindowsAttribute, [AXUIElement].self) { return windows.filter { - let hasTitle = !(AXUIElementCopyAttributeValue($0, kAXTitleAttribute, String.self) ?? "").isEmpty // workaround: some apps like chrome use a window to implement the search popover - let isReasonablyTall = AXValueGetValue($0, kAXSizeAttribute, NSSize(), AXValueType.cgSize)!.height > 200 - return hasTitle && isReasonablyTall + let windowBounds = AXValueGetValue($0, kAXSizeAttribute, NSSize(), AXValueType.cgSize)! + let isReasonablyBig = windowBounds.width > minimumWindowSize && windowBounds.height > minimumWindowSize + return isReasonablyBig } } return [] @@ -58,9 +60,12 @@ func axWindows(_ cgOwnerPid: pid_t) -> [AXUIElement] { func cgWindows() -> [NSDictionary] { let windows = CGWindowListCopyWindowInfo([.excludeDesktopElements, .optionOnScreenOnly], kCGNullWindowID) as! [NSDictionary] return windows.filter { + // workaround: filtering this criteria seems to remove non-windows UI elements let isWindowNotMenubarOrOthers = $0[kCGWindowLayer] as? Int == 0 - let hasTitle = !(($0[kCGWindowName] as? String ?? "").isEmpty) - return isWindowNotMenubarOrOthers && hasTitle + let windowBounds = CGRect(dictionaryRepresentation: $0[kCGWindowBounds] as! NSDictionary)! + // workaround: some apps like chrome use a window to implement the search popover + let isReasonablyBig = windowBounds.width > minimumWindowSize && windowBounds.height > minimumWindowSize + return isWindowNotMenubarOrOthers && isReasonablyBig } } diff --git a/alt-tab-macos/ui/Application.swift b/alt-tab-macos/ui/Application.swift index cb984d4f..0b792a39 100644 --- a/alt-tab-macos/ui/Application.swift +++ b/alt-tab-macos/ui/Application.swift @@ -117,14 +117,16 @@ class Application: NSApplication, NSApplicationDelegate, NSWindowDelegate, NSCol var pidAndCurrentIndex: [pid_t: Int] = [:] for cgWindow in cgWindows() { let cgId = cgWindow[kCGWindowNumber] as! CGWindowID - let cgTitle = String(cgWindow[kCGWindowName] as! NSString) + let cgTitle = cgWindow[kCGWindowName] as? String ?? "" + let cgOwnerName = cgWindow[kCGWindowOwnerName] as? String ?? "" + let cellTitle = cgTitle.isEmpty ? cgOwnerName : cgTitle let cgOwnerPid = cgWindow[kCGWindowOwnerPID] as! pid_t let i = pidAndCurrentIndex.index(forKey: cgOwnerPid) pidAndCurrentIndex[cgOwnerPid] = (i == nil ? 0 : pidAndCurrentIndex[i!].value + 1) - let axWindow = axWindows(cgOwnerPid) + let axWindows_ = axWindows(cgOwnerPid) // windows may have changed between the CG and the AX calls - if axWindow.count > pidAndCurrentIndex[cgOwnerPid]! { - openWindows.append(OpenWindow(target: axWindow[pidAndCurrentIndex[cgOwnerPid]!], ownerPid: cgOwnerPid, cgId: cgId, cgTitle: cgTitle)) + if axWindows_.count > pidAndCurrentIndex[cgOwnerPid]! { + openWindows.append(OpenWindow(target: axWindows_[pidAndCurrentIndex[cgOwnerPid]!], ownerPid: cgOwnerPid, cgId: cgId, cgTitle: cellTitle)) } } }