Class AccessibleTree
Immutable, and read from any thread with no lock. That is the whole shape of this design and it is what the three platforms decide between them: one of them calls a provider from several of its own threads at once while the user-interface thread sleeps, and another never calls at all but wants the entire tree in a single message. A snapshot answers both, and the staleness argument is short — a snapshot goes stale only while the user-interface thread is running, and the user-interface thread publishes before it goes back to sleep.
The node at index 0 is the root. Every other node is reachable from it through the
link indices on AccessibleNode, in tree order, which is paint order, which is the order
the Tab key walks: reading order is defined to be that order and never a sort by geometry, which
would be right in a left-to-right interface and backwards in a right-to-left one.
The window stamp on this type is the half a reader needs and cannot ask for. A window's screen origin and its scale are user-interface-thread-confined, so a reader on a platform thread that tried to ask would throw; they are captured here, once, by the thread that may.
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final AccessibleTreeThe tree of a window that has nothing to say: no nodes, no stamp, no identifiers. -
Method Summary
Modifier and TypeMethodDescriptionlongThe node the keyboard cursor is on inside the focused node: the first node publishedAccessible.State.ACTIVEstrictly belowfocused()in reading order, whichever containers lie between them.children(AccessibleNode node) The children of a node, in order, walked along the sibling links.longWhere the user is, for a platform that puts its focus on the item rather than on the widget: the active descendant when there is one, and the focused node otherwise.@Nullable AccessibleNodefind(long id) longfirstActiveBelow(int index) The first node publishedAccessible.State.ACTIVEstrictly below a node, in reading order: whatactiveDescendant()is resolved from, exposed so that the walk of a window whose focused node opened a popup can read the popup's cursor off the popup's own tree, and so that a bridge can ask the same of any subtree.longfocused()longbooleanholds(long id) Whether an identifier was minted for this window's scene, which is the question a bridge holding several windows' trees asks beforefind(long): a relation may name a node in another window — a native popup's root names the field that opened it — and the number alone says which tree to look in.intindexInParent(AccessibleNode node) Where a node sits among its siblings.intindexOf(long id) locale()floatnode(int index) intrestamp(int newScreenX, int newScreenY, float newFactor, boolean positioning) The same tree with a new window stamp and every node untouched.@Nullable AccessibleNoderoot()floatlongsceneTag()floatintscreenX()intscreenY()boolean
-
Field Details
-
EMPTY
The tree of a window that has nothing to say: no nodes, no stamp, no identifiers.
-
-
Method Details
-
restamp
The same tree with a new window stamp and every node untouched.A window drag changes every screen rectangle this tree publishes and changes nothing in it: the boxes are scene-local, and a move does not touch one of them. So a move re-stamps and walks nothing, which is the difference between a drag costing four numbers and a drag costing a whole tree walk per callback the compositor sends.
- Parameters:
newScreenX- the window's content origin in native screen coordinatesnewScreenY- the same, verticallynewFactor- the multiplier from logical points to native screen coordinatespositioning- whether the platform lets this window know where it is at all- Returns:
- a tree with the new stamp, or this one when nothing in the stamp moved
-
sceneTag
public long sceneTag()- Returns:
- the tag every identifier minted for this window carries above its serial, which is
what makes an identifier process-wide;
0for the empty tree
-
holds
public boolean holds(long id) Whether an identifier was minted for this window's scene, which is the question a bridge holding several windows' trees asks beforefind(long): a relation may name a node in another window — a native popup's root names the field that opened it — and the number alone says which tree to look in. Answered from the identifier's high bits and nothing else, so it costs no lookup and no registry; it does not say whether the node is in this snapshot, whichfind(long)does.- Parameters:
id- a node identifier- Returns:
- whether it belongs to this window's scene
-
nodeCount
public int nodeCount()- Returns:
- how many nodes this tree holds;
0for a window with nothing to say
-
node
- Parameters:
index- the node's index, as carried by the link accessors onAccessibleNode- Returns:
- the node at that index
- Throws:
IndexOutOfBoundsException- if the index is not one of this tree's
-
root
- Returns:
- the root node, or
nullwhen this tree is empty
-
indexOf
public int indexOf(long id) - Parameters:
id- the identifier to look for- Returns:
- the index of the node carrying it, or
AccessibleNode.NONE. Linear in the node count: a bridge that resolves identifiers on every platform call keeps a map of its own rather than asking this repeatedly.
-
find
- Parameters:
id- the identifier to look for- Returns:
- the node carrying it, or
null
-
children
The children of a node, in order, walked along the sibling links. Resolved through the node's identifier rather than its links directly, so a node held from an earlier snapshot answers with its children in this one, or with none when it is gone.- Parameters:
node- a node of this tree or of an earlier one- Returns:
- its children in this tree, first to last; empty when it has none or is not here
-
indexInParent
Where a node sits among its siblings.- Parameters:
node- a node of this tree or of an earlier one- Returns:
- its position under its parent, from zero;
-1for the root, which has no siblings, and for a node that is not in this tree
-
focused
public long focused()- Returns:
- the identifier of the node holding the keyboard focus, or
0when nothing in this window does
-
activeDescendant
public long activeDescendant()The node the keyboard cursor is on inside the focused node: the first node publishedAccessible.State.ACTIVEstrictly belowfocused()in reading order, whichever containers lie between them. Never the window node's ownACTIVE, and never resolved through aSelectionFacet: a container that is not the focused node, or below it, has no cursor to publish. When the focused node's own subtree holds noACTIVEnode and it opened a popup that is a window of its own, the cursor is read across theAccessible.Relation.CONTROLLER_FORrelation into that window's tree, so the identifier here may belong to another window —holds(long)says which.- Returns:
- the identifier of the active descendant, or
0when the focused node has none or nothing is focused
-
effectiveFocus
public long effectiveFocus()Where the user is, for a platform that puts its focus on the item rather than on the widget: the active descendant when there is one, and the focused node otherwise.- Returns:
- the identifier of the node a reader should be standing on, or
0when nothing in this window holds the focus
-
firstActiveBelow
public long firstActiveBelow(int index) The first node publishedAccessible.State.ACTIVEstrictly below a node, in reading order: whatactiveDescendant()is resolved from, exposed so that the walk of a window whose focused node opened a popup can read the popup's cursor off the popup's own tree, and so that a bridge can ask the same of any subtree. Allocates nothing.- Parameters:
index- the index of the node whose subtree is searched; its own bit is never counted- Returns:
- the identifier of the first active node below it, or
0when there is none - Throws:
IndexOutOfBoundsException- if the index is not one of this tree's
-
screenX
public int screenX()- Returns:
- the window's content origin in native screen coordinates, captured on the
user-interface thread at publish time. A placeholder when
supportsAbsolutePositioning()is false.
-
screenY
public int screenY()- Returns:
- the same, vertically
-
logicalToScreenFactor
public float logicalToScreenFactor()- Returns:
- the multiplier from this scene's logical points to native screen coordinates: one on a platform that measures in points, the monitor scale on one that measures in pixels. It already folds in an application's content-scale override, so one multiplier gives all three platforms the answer each of them wants.
-
supportsAbsolutePositioning
public boolean supportsAbsolutePositioning()- Returns:
- whether this window can know where it is on the screen at all. Where it cannot, the origin above is a placeholder and a bridge reports window-relative extents truthfully rather than dressing zeros up as a position.
-
sceneWidth
public float sceneWidth()- Returns:
- the scene's width in logical points at publish time
-
sceneHeight
public float sceneHeight()- Returns:
- the scene's height in logical points at publish time. This is the content view's height, and it is what a bridge flips against on the one platform whose accessibility coordinates run from the bottom.
-
locale
- Returns:
- the scene's own language, which a node inherits when it declares none
-
generation
public long generation()- Returns:
- a counter that moves on every publish and every re-stamp of this window. Meaningless except compared with itself: it is what lets a bridge holding a derived form of a tree — a pre-marshalled message, a cached element list — know that the form is still current without comparing anything.
-