Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mac / Cocoa - Getting a list of windows using Accessibility API

I want to use the Accessibility API to get a list of all windows for a given application (external).

The goal is to check if a certain window is open. First I check that the application is running (using [NSWorkspace runningApplications] and checking each one), and then I want to check the title bar text of each window that is open for that application.

PS

So I can create an element for the app using the PID:

AXUIElementRef app = AXUIElementCreateApplication(pid);

but what do I do with it? Am I even going in the right direction? Can't beleive it's so hard to find examples on this.

like image 351
Ben Packard Avatar asked Jan 21 '10 07:01

Ben Packard


3 Answers

I don't know a way to get window ID and PID from the Accessibility API.
The NSWindow method Laurent mentioned only provides Window IDs but not the PID of the window owning application.
I would use the CGWindowList methods that are available since 10.5.
To get a list of window IDs and the PID of the owner you can try the following:

CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
for (NSMutableDictionary* entry in (NSArray*)windowList) 
{
    NSString* ownerName = [entry objectForKey:(id)kCGWindowOwnerName];
    NSInteger ownerPID = [[entry objectForKey:(id)kCGWindowOwnerPID] integerValue];
    NSLog(@"%@:%d", ownerName, ownerPID);
}
CFRelease(windowList);  

You can control if you want all windows (including offscreen, ...) with the option paramter.
Also the entry objects contain a lot more information. Documentation link

like image 198
Thomas Zoechling Avatar answered Nov 05 '22 09:11

Thomas Zoechling


This works for me in Swift 5.1:

let windowList: CFArray? = CGWindowListCopyWindowInfo(.optionOnScreenOnly, kCGNullWindowID)

for entry in windowList! as Array {

    let ownerName: String = entry.object(forKey: kCGWindowName) as? String ?? "N/A"
    let ownerPID: Int = entry.object(forKey: kCGWindowOwnerPID) as? Int ?? 0
    print("ownerName: \(ownerName), ownerPID:\(ownerPID)")
}
like image 24
blakeness Avatar answered Nov 05 '22 09:11

blakeness


Use AXUIElementCopyAttributeValues to copy the value for kAXWindowsAttribute, which should be an array of AXUIElement objects representing the application's windows.

As you can guess from its function name, it follows the copy rule.

like image 37
Peter Hosey Avatar answered Nov 05 '22 09:11

Peter Hosey