Skip to content

fix: Return the view's window from accessibilityWindow on macOS - #801

Open
hotsyk wants to merge 1 commit into
AccessKit:mainfrom
hotsyk:fix/macos-window-for-nested-views
Open

hotsyk wants to merge 1 commit into
AccessKit:mainfrom
hotsyk:fix/macos-window-for-nested-views

Conversation

@hotsyk

@hotsyk hotsyk commented Sep 16, 2026

Copy link
Copy Markdown

Problem

On macOS, AccessKitNode answers accessibilityWindow and accessibilityTopLevelUIElement with the host view's accessibilityParent. That object is the window only when the host view is the window's content view.

Apps that host their AccessKit view inside other AppKit views get a different object. Examples are the document view of an NSScrollView, or a pane of an NSSplitView next to a native sidebar. AppKit then reports the nearest accessible ancestor, such as the scroll area or split group. Assistive technologies receive that ancestor as the node's window and top-level element. VoiceOver and the Accessibility Inspector then attribute nodes to the wrong element and can fail to associate them with their window.

We hit this in a GPUI-based editor whose render view is reparented into a split view with a native outline sidebar.

Change

  • Both selectors now return the live view's window(), upcast to AnyObject. They return nil when the view is detached or has been released.
  • The root node's accessibilityParent is unchanged, so the element hierarchy still runs through the real ancestor views.

Test

adapters/macos/tests/window_ownership.rs is a harness = false integration test. AppKit objects must be created on the main thread, which the default harness does not provide. The test checks both selectors on the root and on a child node in four states:

  1. The view is the window's content view.
  2. The view is nested in a scroll view's document view. Without this change the test fails here, returning the document view instead of the window.
  3. The view is detached from any window, which gives nil.
  4. The view is moved into a second window.

The test creates windows but never orders them front.

cargo test -p accesskit_macos --test window_ownership
cargo clippy -p accesskit_macos --all-targets
cargo fmt -p accesskit_macos -- --check

All pass locally on macOS 26.6 with Apple Silicon.

🤖 Generated with Claude Code

`accessibilityWindow` and `accessibilityTopLevelUIElement` returned the
host view's `accessibilityParent`. That is the window only when the view
is the window's content view. When the view is nested, for example as the
document view of an NSScrollView or inside an NSSplitView, AppKit reports
the nearest accessible ancestor instead, so assistive technologies were
given a non-window object as the node's window and top-level element.

Both selectors now return the live view's `window()`, or nil when the view
is detached or gone. The accessibility parent of the root node is
unchanged.

A `harness = false` integration test covers a content view, a view nested
in a scroll view, a detached view and a view moved to another window; it
fails on the nested case without this change.

Co-Authored-By: Claude Opus 5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant