Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking issue for Spaces API #26

Open
tmandry opened this issue Nov 9, 2018 · 2 comments
Open

Tracking issue for Spaces API #26

tmandry opened this issue Nov 9, 2018 · 2 comments

Comments

@tmandry
Copy link
Owner

tmandry commented Nov 9, 2018

macOS doesn't expose much of the functionality of Spaces via public APIs, so Swindler's API surface will be pretty restricted. However, it should be good enough to support the basic functionality fo most window managers.

Those who want more can venture into private APIs on their own (they always break and I don't want to maintain that.)

Basically, we want to:

  • detect when the space changes
  • detect when we come back to a space that we've seen before
  • detect when we come to a new space that we haven't seen before
  • track which space each window is on

The first three goals (and part of the fourth) can be accomplished by subscribing to activeSpaceDidChangeNotification on NSWorkspace, then asking all our AXApplications for a list of windows. Only windows on the current space are returned. Finally, we can apply a heuristic, comparing lists of windows on each space to the list of windows on a current space.

Since we're using a heuristic, no space will have its own "identity" other than that of the windows which are on it. In particular, empty spaces are indistinguishable from each other, so we cull them when they are no longer active.

@tmandry
Copy link
Owner Author

tmandry commented Nov 9, 2018

The fourth goal, keeping track of which space each window is on, is a bit more subtle. The user can trigger Mission Control and drag windows to other spaces. As far as I can tell, there is no direct way to observe a window moving to another space. Nor is there a notification for Mission Control being activated.

So far, the best signal I've found is to watch com.apple.dock for the uiElementDestroyed notification. When Mission Control is triggered, an AXGroup element is created (with some nested groups for the window and desktop buttons). There's no way to observe this with the AX API, other than polling. However, when Mission Control is deactivated, that AXGroup gets destroyed, triggering the uiElementDestroyed notification. (At that point we won't be able to see what the element was, of course.)

When we see this notification occur, we can check to see if any windows from the current space have moved.

There's also a trick using Quartz event tap that can be used to detect when Mission Control is activated, but that won't help us much.

This tracking is going to be best-effort; we can only reliably track when windows move away from the current space when Mission Control is deactivated. We can also notice when a window we thought was on a space is no longer there when we switch to it. Hopefully, these are the only cases we really care about.

Also, let's not forget that there may be one space per screen.

Keeping that in mind.. we can support something like the following API:

Window
- isOnCurrentSpace: bool

Space
- knownWindows: [Window]

Screen
- activeSpace: Space

Events
- ActiveSpaceChanged(new: Space, old: Space)
- NewSpaceDetected(space)
- EmptySpaceCulled(space)
- WindowMovedFromCurrentSpace(window)
- WindowMovedToCurrentSpace(window)

I'm not including Window.space, for instance, because it just won't be useful beyond determining whether the window is on a current space.

@tmandry
Copy link
Owner Author

tmandry commented Nov 9, 2018

There is also a way to track the order of spaces, but tying that to the information we already have is not trivial. See this gist for more.

Using the defaults database to get this information probably falls in the category of undocumented APIs.

The window IDs there are probably CGWindowIds. See this comment for some links on getting window ids for AXWindows.

The main blocker for this, however, is that the window list can go stale. When a user changes the order of spaces we know we can rely on the information, because it all gets updated. However, it can already be stale the first time we read the window lists. Thus we won't know the order of the spaces until the first time they change!

I suspect that every space has an invisible window that is dedicated to it, owned by the Dock or something similar. If we can find these windows in the list and on the current space, it might be possible to determine the index of the current space. I have no idea if this will work, and if it does, whether it will continue to work in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant