How can I get the position of my application's dock icon using the Accessibility API?
Found it! Using this forum post as reference, I was able to shape the given sample code to what I needed:
- (NSArray *)subelementsFromElement:(AXUIElementRef)element forAttribute:(NSString *)attribute
{
NSArray *subElements = nil;
CFIndex count = 0;
AXError result;
result = AXUIElementGetAttributeValueCount(element, (CFStringRef)attribute, &count);
if (result != kAXErrorSuccess) return nil;
result = AXUIElementCopyAttributeValues(element, (CFStringRef)attribute, 0, count, (CFArrayRef *)&subElements);
if (result != kAXErrorSuccess) return nil;
return [subElements autorelease];
}
- (AXUIElementRef)appDockIconByName:(NSString *)appName
{
AXUIElementRef appElement = NULL;
appElement = AXUIElementCreateApplication([[[NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"] lastObject] processIdentifier]);
if (appElement != NULL)
{
AXUIElementRef firstChild = (__bridge AXUIElementRef)[[self subelementsFromElement:appElement forAttribute:@"AXChildren"] objectAtIndex:0];
NSArray *children = [self subelementsFromElement:firstChild forAttribute:@"AXChildren"];
NSEnumerator *e = [children objectEnumerator];
AXUIElementRef axElement;
while (axElement = (__bridge AXUIElementRef)[e nextObject])
{
CFTypeRef value;
id titleValue;
AXError result = AXUIElementCopyAttributeValue(axElement, kAXTitleAttribute, &value);
if (result == kAXErrorSuccess)
{
if (AXValueGetType(value) != kAXValueIllegalType)
titleValue = [NSValue valueWithPointer:value];
else
titleValue = (__bridge id)value; // assume toll-free bridging
if ([titleValue isEqual:appName]) {
return axElement;
}
}
}
}
return nil;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
AXUIElementRef dockIcon = [self appDockIconByName:@"MYAPPNAME"];
if (dockIcon) {
CFTypeRef value;
CGPoint iconPosition;
AXError result = AXUIElementCopyAttributeValue(dockIcon, kAXPositionAttribute, &value);
if (result == kAXErrorSuccess)
{
if (AXValueGetValue(value, kAXValueCGPointType, &iconPosition)) {
NSLog(@"position: (%f, %f)", iconPosition.x, iconPosition.y);
}
}
}
}
As for Mac OS El Capitan, looks like you aren't supposed to get the position of the icon using Accessibility API. The matter is that the icon isn't located in accessibility objects hierarchy of the app—it can be found in the hierarchy of the system Dock application. A sandboxed app isn't supposed to access the accessibility objects of other apps.
The code in approved answer doesn't yield any warnings of the sandboxd
daemon in the console, looks like it doesn't violate any rules. It creates the top-level accessibility object with the function AXUIElementCreateApplication
. The documentation states, that it:
Creates and returns the top-level accessibility object for the
application with the specified process ID.
Unfortunately, this top-level object is not the ancestor of the Dock icon. I've tried to run the code, and it calculates the position of the first app's main menu item (which has the same title as the app itself). The comparison takes place in this line:
if ([titleValue isEqual:appName]) {
So the output was always the same for my app:
position: (45.000000, 0.000000)
An attempt to access the other app's accessibility object yielded a warning in console. I guess another way to calculate the position of the icon has to be found.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With