Carbon Accessibility API - Getting windows information across spaces
I have the following (minor) problem that I want to solve programmatically. Whenever I unplug my secondary monitor from my laptop, every windows get moved to be visible in the now smaller resolution. When I plug my external monitor back in, I need to manually replace the windows to their correct position. I have to do that every morning (sigh).
Now I decided to write a simple command-line program that could save the position of every open windows and reposition them when I want to restore their positions.
I have managed to do something that works just fine by using the Accessi开发者_JAVA技巧bility API, which allows me to control windows that aren't part of my process space. I have a problem though: the program can only see the windows that are in my current space (I'm talking about the OSX Spaces feature here).
In other words, when I run my program to save the windows positions, it will only be able to save the positions of the windows in the space I'm currently in.
Some more details about my program:
- It loops through all the processes running and get their PIDs.
- It creates application elements from these PIDs (
AXUIElementCreateApplication
) - It gets the windows associated with this application, and then their positions
When getting the windows elements from the application element, the AXUIElementCopyAttributeValues
only returns me the windows of the current space.
Now, is there a way to control any windows (across different spaces)? If not, I wouldn't mind programmatically changing spaces to get every windows, but that doesn't seem possible.
Any help would be appreciated!
I'm not aware of a documented way to switch spaces.
You probably want CGSPrivate.h - CGSSetWorkspace
et al. Just keep in mind those functions are SPI and can break without warning even in a 10.6.x release.
If you want to avoid using private APIs you can take advantage of the fact Mission Control has keyboard shortcuts for moving to various spaces, and you can programmatically send the key codes to activate them. I wrote a blog post about it (http://ianyh.com/blog/2013/06/05/accessibility/) for a tiling window manager I've been working on called Amethyst, which has some example code you can check out in -[AMWindow moveToSpace:]
.
The short version is moving to a space looks something like using the default ctrl + arrow key
to move to adjacent spaces:
CGEventRef keyboardDownEvent = CGEventCreateKeyboardEvent(NULL, kVK_RightArrow, true);
CGEventRef keyboardUpEvent = CGEventCreateKeyboardEvent(NULL, kVK_RightArrow, false);
CGEventSetFlags(keyboardDownEvent, kCGEventFlagMaskControl);
CGEventSetFlags(keyboardUpEvent, 0);
CGEventPost(kCGHIDEventTap, keyboardDownEvent);
CGEventPost(kCGHIDEventTap, keyboardUpEvent);
CFRelease(keyboardEvent);
CFRelease(keyboardEventUp);
You could combine this with NSWorkspaceActiveSpaceDidChangeNotification
to traverse all spaces and gather window data.
Also, as a potentially interesting note the accessibility APIs can actually give you windows across all spaces at the same time, but it will only give you windows in spaces that you have traversed to since the process utilizing the APIs launched. I have no idea why this is the case, but it does seem to be.
精彩评论