Question

I'm using NSWorkspace's NSWorkspaceDidActivateApplicationNotification to detect when the active application changes. I get NSRunningApplication from the userInfo key of the notification.

I need to get a notification when the active document changes. I can get the active document by using the accessibility framework's NSAccessibilityDocumentAttribute key through AXUIElementCopyAttributeValue().

I need a more accurate way of detecting when the document changes other than polling. Some applications use multiple windows, while others use a single window with multiple tabs. With tabbed applications the window returns the currently viewed document.

I don't have to use the accessibility framework. AppleScript (scripting bridge) seems to also be able to get a window's document, but the accessibility framework seems to work with more applications.

I only care about the active document, of the active window, of the active application. What currently has focus on the system.

I've been testing with applications like Sublime Text 2, and Xcode. Sublime returns the currently selected tab, where Xcode returns the active project.

Was it helpful?

Solution

I was actually trying to achieve exactly the same thing and I think I've found a solution for it.

What I did was using CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);

That will give you a list of all the active windows, including windows that you probably don't care about.

I only care about windows that have kCGWindowLayer = 0; so I filtered the windows that are on layer 0.

Here's how I did it:

    CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
NSMutableArray *data = [(__bridge NSArray *) windowList mutableCopy];

NSMutableArray *filteredData = [[NSMutableArray alloc] initWithCapacity:10];

for (NSMutableDictionary *theDict in data) {
    id layer = [theDict objectForKey:(id)kCGWindowLayer];

    if ([layer intValue] == 0) {
        [filteredData addObject:theDict];
    }
}

NSLog(@"window: %@", filteredData);

This might be the most elegant solution, so if anyone else has a better idea, please share. Also you should have a look at Apple's demo app Son of Grab.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top