gfx/accessibility_mac.h
The macOS end of accessibility: handing our component tree to NSAccessibility.
#include <sonore/gfx/accessibility_mac.h>- 5types
- 41other declarations
- Guides: The native editor
On this page
Design notes
Written, compiled, never run
Said first, as window_cocoa.h says it: as of 2026-10-14 no machine in this project has executed a line of this file. It has been COMPILED, on Windows, against the Objective-C runtime shim in tests/au_shim (tests/ mac_syntax_mac_input.cpp), which proves every name exists and every call has the right shape -- and not that VoiceOver hears anything. The Windows bridge (uia_win32.h) is verified by being the screen reader; this one is verified by nobody until a Mac developer runs tests/mac_input_selftest.cpp, which asks AppKit -- through the same attribute API the accessibility server uses -- what this file exposes, and prints it.
The shape
Same as UIA's, on the same platform-neutral model (accessibility.h):
the editor's NSView -- an AXGroup named after the editor, whose
accessibilityChildren are the top-level elements
(window_cocoa.h registers those view methods)
one element each -- an NSAccessibilityElement SUBCLASS, created at
runtime with objc_allocateClassPair like the
view itself, one instance per accessible
component
The roles, subroles and how each reads its value come from accessibleRoleMapping -- the same table UIA reads -- so a combo box cannot be one thing to NVDA and another to VoiceOver by accident.
Why elements are KEPT, where UIA makes them per call
A UIA client identifies an element by its runtime id, so the Windows bridge can hand out a new COM object on every navigation. VoiceOver identifies an element by the OBJECT: it compares pointers to see whether the focus moved, and a notification is about the object it is posted for. So each element lives as long as its component does -- matched across rebuilds by detail::matchAccessibleNodes -- and is told it is destroyed (NSAccessibilityUIElementDestroyedNotification) when the component goes.
Threads
None to worry about, unlike UIA: AppKit services accessibility requests on the main thread, which is the thread the editor runs on. Every read comes from a snapshot retaken on the editor's clock, and every ACTION retakes it first, so the component pointer it acts on was found in the live tree a moment ago rather than remembered from a frame that may have closed a panel.
Types 5
NSPoint, NSSize and NSRect, laid out as CoreGraphics lays them out.
No comment on this one in the header yet; the source says the rest.
No comment on this one in the header yet; the source says the rest.
The two AppKit functions the bridge calls, which are C functions rather than messages and so are resolved with dlsym -- the same rule window_cocoa.h follows for CoreGraphics, so no project has to name a framework.
The bridge: the snapshot, the elements, and the announcements.
Owned by NativeWindowCocoa, created with its view and detached before the view goes. Detaching leaves every element answering as an empty element, which is the right answer for one VoiceOver still holds after the editor closed.
Functions 41
- fn
template <typename Ret, typename... Args> inline Ret send(id target, SEL selector, Args... args)objc_msgSend through a correctly typed pointer -- see cocoa::msg in window_cocoa.h, which this duplicates so the bridge needs nothing from the window peer that includes it.gfx::nsax::send · accessibility_mac.h:90 - fn
template <typename Ret, typename... Args> inline Ret sendRect(id target, SEL selector, Args... args)A message answering a struct larger than 16 bytes (an NSRect): through objc_msgSend_stret on x86_64, plain objc_msgSend on arm64.gfx::nsax::sendRect · accessibility_mac.h:98 - fn
inline id cls(const char* name)gfx::nsax::cls · accessibility_mac.h:107 - fn
inline SEL sel(const char* name)gfx::nsax::sel · accessibility_mac.h:108 - fn
inline id string(const std::string& utf8)gfx::nsax::string · accessibility_mac.h:122 - fn
inline std::string utf8Of(id value)An NSString's UTF-8, or empty for nil or anything that is not one.gfx::nsax::utf8Of · accessibility_mac.h:127 - fn
inline id number(double value)gfx::nsax::number · accessibility_mac.h:134 - fn
inline id array(const std::vector<id>& items)gfx::nsax::array · accessibility_mac.h:136 - fn
inline const AppKitAccessibilityApi& appKit()gfx::nsax::appKit · accessibility_mac.h:153 - fn
inline void post(id element, const char* notification)Post one of AppKit's notifications ("AXValueChanged" and the rest are the values of the NSAccessibility*Notification constants).gfx::nsax::post · accessibility_mac.h:169 - fn
inline bool viewOnScreen(id view, Rect* out)Where a view's bounds are on the screen, in Cocoa's y-up desktop space.gfx::nsax::viewOnScreen · accessibility_mac.h:181More
convertRect:toView:nil takes the flipped view into its window (which undoes the flip), and convertRectToScreen: places the window. False with no window -- a view not yet in one is nowhere a reader could point at.
- fn
inline MacAccessibilityRoot* rootOf(id element)gfx::nsax::rootOf · accessibility_mac.h:496 - fn
inline const AccessibleNode* nodeOfElement(id self)gfx::nsax::nodeOfElement · accessibility_mac.h:502 - fn
inline id axRole(id self, SEL)gfx::nsax::axRole · accessibility_mac.h:507 - fn
inline id axSubrole(id self, SEL)gfx::nsax::axSubrole · accessibility_mac.h:512 - fn
inline id axRoleDescription(id self, SEL)gfx::nsax::axRoleDescription · accessibility_mac.h:518 - fn
inline id axLabel(id self, SEL)The name as a DESCRIPTION -- unless the role reads it as its title or as its value, where saying it twice is what a reader would then do.gfx::nsax::axLabel · accessibility_mac.h:529 - fn
inline id axTitle(id self, SEL)gfx::nsax::axTitle · accessibility_mac.h:537 - fn
inline id axValue(id self, SEL)Typed as the role reads it: a number for a slider (with the text as its description), 0 or 1 for a toggle, the text for a field or a choice.gfx::nsax::axValue · accessibility_mac.h:545 - fn
inline id axValueDescription(id self, SEL)gfx::nsax::axValueDescription · accessibility_mac.h:564 - fn
inline id axMinValue(id self, SEL)gfx::nsax::axMinValue · accessibility_mac.h:572 - fn
inline id axMaxValue(id self, SEL)gfx::nsax::axMaxValue · accessibility_mac.h:577 - fn
inline id axHelp(id self, SEL)gfx::nsax::axHelp · accessibility_mac.h:582 - fn
inline void axSetValue(id self, SEL, id value)gfx::nsax::axSetValue · accessibility_mac.h:587 - fn
inline AxRect axFrame(id self, SEL)gfx::nsax::axFrame · accessibility_mac.h:591 - fn
inline id axParent(id self, SEL)gfx::nsax::axParent · accessibility_mac.h:596 - fn
inline id axChildren(id self, SEL)gfx::nsax::axChildren · accessibility_mac.h:601 - fn
inline id axWindow(id self, SEL)gfx::nsax::axWindow · accessibility_mac.h:606 - fn
inline BOOL axIsElement(id self, SEL)gfx::nsax::axIsElement · accessibility_mac.h:611 - fn
inline BOOL axIsEnabled(id self, SEL)gfx::nsax::axIsEnabled · accessibility_mac.h:613 - fn
inline BOOL axIsFocused(id self, SEL)gfx::nsax::axIsFocused · accessibility_mac.h:618 - fn
inline void axSetFocused(id self, SEL, BOOL focused)gfx::nsax::axSetFocused · accessibility_mac.h:623 - fn
inline BOOL axIsSelected(id self, SEL)gfx::nsax::axIsSelected · accessibility_mac.h:628 - fn
inline id axHitTest(id self, SEL, AxPoint point)gfx::nsax::axHitTest · accessibility_mac.h:633 - fn
inline BOOL axPerform(id self, AccessibleAction action)gfx::nsax::axPerform · accessibility_mac.h:640 - fn
inline BOOL axPress(id self, SEL)gfx::nsax::axPress · accessibility_mac.h:644 - fn
inline BOOL axIncrement(id self, SEL)gfx::nsax::axIncrement · accessibility_mac.h:645 - fn
inline BOOL axDecrement(id self, SEL)gfx::nsax::axDecrement · accessibility_mac.h:646 - fn
inline BOOL axShowMenu(id self, SEL)gfx::nsax::axShowMenu · accessibility_mac.h:647 - fn
inline BOOL axSelectorAllowed(id self, SEL, SEL asked)isAccessibilitySelectorAllowed: -- which of the methods above apply to THIS element now. AppKit builds the action list and the settable attributes from the implemented methods filtered through this, so a label offers no press and a read-only field no settable value, from the one class all elements share.gfx::nsax::axSelectorAllowed · accessibility_mac.h:656 - fn
inline Class elementClass()The element class, registered once per binary.gfx::nsax::elementClass · accessibility_mac.h:680More
A subclass of NSAccessibilityElement (10.10), which already implements the protocol's plumbing -- the attribute API a reader's server calls, built from the methods below -- and needs from us what the element IS. Named after an address in this binary, for the reason window_cocoa.h names its view class so: two plugins built from this SDK share one Objective-C runtime.