Himanshu P
Himanshu P

Reputation: 9945

Separating real and dummy windows returned by CGWindowListCopyWindowInfo

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

Answers (2)

AD Progress
AD Progress

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

Ted Wrigley
Ted Wrigley

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:

  • Only one dictionary entry has that window number (it's a simple widow, which may be on or off screen)
  • Several dictionaries have that window id, and only one of them in the group has the key 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.
  • Several dictionaries have that window id, and none have the key 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

Related Questions