Reputation: 9945
I am creating a window switcher for macOS.
I am using CGWindowListCopyWindowInfo
to get the list of open windows.
let windows = CGWindowListCopyWindowInfo([.excludeDesktopElements], kCGNullWindowID)
I am not using the optionOnScreenOnly
option along with CGWindowListCopyWindowInfo
because that excludes off-space windows.
However, this leads to certain dummy windows also getting included in the list of windows. For example, there is a window present for each open tab on Xcode. There is also an additional invisible window for VLC player apart from the actual window. These windows aren't present if I use optionOnScreenOnly
.
Is there a way to separate these dummy windows from actual windows?
I have explored the kCGWindowLayer
and kCGWindowStoreType
keys in the dictionaries returned by CGWindowListCopyWindowInfo
but couldn't tell the windows apart.
Edit:
I am open to both Swift and Objective-C solutions, as well as private API calls.
Edit 2:
I know this is possible to do because the app Witch handles these cases correctly.
Upvotes: 7
Views: 602
Reputation: 5126
How about using a different approach, by checking what apps are running and visible using the following:
let runningApps = NSWorkspace.shared.runningApplications.filter{ $0.activationPolicy == .regular }
If you print(runningApps)
you will get a list of apps currently ran in your workspace.
Hope this helps.
Upvotes: 2
Reputation: 3194
I'm not sure if this captures all the cases you're interested in, but if we take the array of dictionaries returned by CGWindowListCopyWindowInfo()
and group the entries by kCGWindowNumber
(the window ID), it looks like we'll end up with one of three cases:
kCGWindowIsOnscreen
set to 1: the others either lack the key or have it set to 0. This means we have a window with several tabs, and the entry with kCGWindowIsOnscreen
set is the visible tab.kCGWindowIsOnscreen
set to 1 (it is missing or set to 0 in all cases). This means we have a window with several tabs that is currently off-screen.I'm assuming you're probably already filtering out anything that isn't in layer 0 (kCGWindowLayer = 0
). It seems that most of the things that we visually perceive as a 'window' are in layer 0 (status menu items seem to be in layers with single or low double digits; widgets seem to be up around layer 100...).
I don't see any simple, direct way to get at this, but you should be able to build this logic into something workable.
Upvotes: 2