pub struct Locator { /* private fields */ }Expand description
A lazy, re-resolving handle to one or more AT-SPI elements.
See the module-level documentation for the resolution model.
Implementations§
Source§impl Locator
impl Locator
Sourcepub fn with_timeout(&self, timeout: Duration) -> Locator
pub fn with_timeout(&self, timeout: Duration) -> Locator
Return a new locator with a per-call timeout override for auto-wait
and wait_for_* methods. Duration::ZERO means “try once, don’t
wait,” useful for negative assertions (“this element should NOT
exist right now”).
Sourcepub fn locate(&self, sub: &str) -> Locator
pub fn locate(&self, sub: &str) -> Locator
Scope a sub-expression to the nodes matched by this locator.
If sub is absolute (starts with /), it replaces the current
selector entirely. Otherwise it’s evaluated as descendants of the
current matches: (self)//sub.
Sourcepub fn nth(&self, n: usize) -> Locator
pub fn nth(&self, n: usize) -> Locator
Return a locator pinned to the n-th (0-indexed) match of this one.
Sourcepub async fn count(&self) -> Result<usize>
pub async fn count(&self) -> Result<usize>
Number of elements matched by this selector. Does not auto-wait — returns the current count, which may be zero.
Sourcepub async fn all(&self) -> Result<Vec<Locator>>
pub async fn all(&self) -> Result<Vec<Locator>>
Enumerate each match as a locator pinned by ordinal.
Each returned locator still re-resolves (so ordinal pins are
evaluated on each use, not frozen to the AT-SPI identity observed at
all() time).
Sourcepub async fn inspect_all(&self) -> Result<Vec<ElementInfo>>
pub async fn inspect_all(&self) -> Result<Vec<ElementInfo>>
Take one AT-SPI snapshot and return full metadata for every match.
More efficient than calling all() and then metadata methods on each
returned locator, which would re-snapshot per match.
Sourcepub async fn name(&self) -> Result<Option<String>>
pub async fn name(&self) -> Result<Option<String>>
Accessible name of the matched element, or None when the element
has no accessible name set.
Sourcepub async fn role(&self) -> Result<String>
pub async fn role(&self) -> Result<String>
Raw AT-SPI role name (e.g. "push button", "menu item").
Falls back to the PascalCase XML element tag only when the snapshot
lacks a role attribute — which shouldn’t happen for live snapshots,
but can in hand-crafted test XML.
Sourcepub async fn attribute(&self, key: &str) -> Result<Option<String>>
pub async fn attribute(&self, key: &str) -> Result<Option<String>>
Read a single toolkit attribute by key.
Sourcepub async fn attributes(&self) -> Result<HashMap<String, String>>
pub async fn attributes(&self) -> Result<HashMap<String, String>>
All toolkit attributes as a map.
Sourcepub async fn is_showing(&self) -> Result<bool>
pub async fn is_showing(&self) -> Result<bool>
Whether the matched element currently has the AT-SPI State::Showing
state.
Sourcepub async fn is_enabled(&self) -> Result<bool>
pub async fn is_enabled(&self) -> Result<bool>
Whether the matched element is currently interactable.
Returns true when the element has either the AT-SPI State::Enabled
state or the State::Sensitive state — GTK reports the latter,
Qt/others the former. Both mean “user can interact with this widget
right now.”
Sourcepub async fn is_checked(&self) -> Result<bool>
pub async fn is_checked(&self) -> Result<bool>
Whether the matched element currently has the AT-SPI State::Checked
state. Use for checkboxes, toggle buttons, and checkable menu items.
Sourcepub async fn wait_for_checked(&self) -> Result<()>
pub async fn wait_for_checked(&self) -> Result<()>
Poll until the element has the AT-SPI State::Checked state.
Sourcepub async fn is_focused(&self) -> Result<bool>
pub async fn is_focused(&self) -> Result<bool>
Whether the matched element currently has the AT-SPI State::Focused
state — i.e. it holds keyboard focus right now.
Sourcepub async fn wait_for_focused(&self) -> Result<()>
pub async fn wait_for_focused(&self) -> Result<()>
Poll until the element has the AT-SPI State::Focused state.
Sourcepub async fn is_expanded(&self) -> Result<bool>
pub async fn is_expanded(&self) -> Result<bool>
Whether the matched element currently has the AT-SPI State::Expanded
state. Use for tree rows, expanders, and disclosure triangles.
An element that is collapsible but not currently expanded has
State::Expandable (and possibly State::Collapsed) but not
State::Expanded.
Sourcepub async fn wait_for_expanded(&self) -> Result<()>
pub async fn wait_for_expanded(&self) -> Result<()>
Poll until the element has the AT-SPI State::Expanded state.
Sourcepub async fn is_editable(&self) -> Result<bool>
pub async fn is_editable(&self) -> Result<bool>
Whether the matched element currently has the AT-SPI State::Editable
state — i.e. the user can type into it.
Sourcepub async fn wait_for_editable(&self) -> Result<()>
pub async fn wait_for_editable(&self) -> Result<()>
Poll until the element has the AT-SPI State::Editable state.
Sourcepub async fn is_selected(&self) -> Result<bool>
pub async fn is_selected(&self) -> Result<bool>
Whether the matched element currently has the AT-SPI State::Selected
state. Use for list and table rows, selectable menu items, and tabs.
Sourcepub async fn wait_for_selected(&self) -> Result<()>
pub async fn wait_for_selected(&self) -> Result<()>
Poll until the element has the AT-SPI State::Selected state.
Sourcepub async fn is_pressed(&self) -> Result<bool>
pub async fn is_pressed(&self) -> Result<bool>
Whether the matched element currently has the AT-SPI State::Pressed
state — i.e. a toggle button is in its pressed position.
Sourcepub async fn wait_for_pressed(&self) -> Result<()>
pub async fn wait_for_pressed(&self) -> Result<()>
Poll until the element has the AT-SPI State::Pressed state.
Sourcepub async fn is_modal(&self) -> Result<bool>
pub async fn is_modal(&self) -> Result<bool>
Whether the matched element currently has the AT-SPI State::Modal
state — i.e. a dialog that blocks interaction with its parent window.
Sourcepub async fn wait_for_modal(&self) -> Result<()>
pub async fn wait_for_modal(&self) -> Result<()>
Poll until the element has the AT-SPI State::Modal state.
Sourcepub async fn bounds(&self) -> Result<Rect>
pub async fn bounds(&self) -> Result<Rect>
Screen-relative bounding rectangle (x, y, width, height) in logical pixels, as captured at snapshot time from the AT-SPI Component interface.
Returns Error::Atspi if the element doesn’t implement Component
or hasn’t been laid out yet (get_extents returned a zero-area
rect). Callers that want to tolerate missing bounds should use
Locator::inspect_all and read ElementInfo::bounds directly.
Sourcepub async fn text(&self) -> Result<String>
pub async fn text(&self) -> Result<String>
Text contents of the matched element via the AT-SPI Text interface. Unlike other metadata, text isn’t captured in the snapshot — each call makes a live read through the Text proxy after auto-waiting for the element to exist.
Sourcepub async fn click(&self) -> Result<()>
pub async fn click(&self) -> Result<()>
Invoke the primary action (index 0) on the matched element.
Auto-waits for the element to be resolvable, showing, and enabled within the effective timeout. Requires exactly one match.
Sourcepub async fn set_text(&self, text: &str) -> Result<()>
pub async fn set_text(&self, text: &str) -> Result<()>
Replace the contents of an editable text element via the AT-SPI
EditableText::SetTextContents interface. Fast (one D-Bus round
trip) but requires the target to implement EditableText — some
toolkits (notably GTK4 TextView and widgets with custom entry
buffers) don’t. For those, use fill instead.
Auto-waits for the element to be resolvable, showing, and enabled.
Sourcepub async fn fill(&self, text: &str) -> Result<()>
pub async fn fill(&self, text: &str) -> Result<()>
Replace the contents of a text widget by simulating keyboard input:
focus the element, clear existing content per mode, then type.
Slower than set_text but works on any widget
that accepts keyboard input — including GtkTextView and other
targets that don’t implement the AT-SPI EditableText interface.
Use set_text when the target exposes EditableText; use fill
as the compatibility fallback.
§Focus handling
fill tries AT-SPI Component::grab_focus first. Three cases:
- Granted: focus took, fill proceeds normally.
- Rejected (the bridge said the widget can’t take focus
right now): surfaced as
Error::Atspiso callers see the real problem rather than typing into the wrong widget. - NotSupported (the widget’s a11y bridge doesn’t expose
Component::grab_focus— the documented GTK4Entry/Textsituation): fall back to a pointer click at the widget’s centre, the same way a user would focus it. Needsbounds()from the snapshot; off-screen widgets without layout return anError::Atspidirecting the caller tofill_assume_focused.
Stale-element and transport errors always propagate. Skip the
focus step entirely with fill_assume_focused
when the widget is already focused through another path —
useful for off-screen widgets or to avoid the extra pointer
click round-trip.
Fills with FillMode::default(). Use
fill_with_opts when the default select-all
strategy doesn’t work on the target widget — see FillMode for
the tradeoffs.
Sourcepub async fn fill_assume_focused(
&self,
text: &str,
mode: FillMode,
) -> Result<()>
pub async fn fill_assume_focused( &self, text: &str, mode: FillMode, ) -> Result<()>
Like fill_with_opts but skips the
AT-SPI focus call entirely.
Use this when the caller has already focused the widget through
some other path (a prior pointer click, Tab navigation, the
app’s own grab_focus on startup) — typical for GTK4 text
widgets that don’t expose the Component interface, where the
fill_with_opts focus call would error with NotSupported.
Keystrokes route to whatever currently has keyboard focus, so
the caller is responsible for ensuring that’s the intended
target before calling. If something else has focus, this method
will silently type into it.
Sourcepub async fn select_option(&self, by: SelectBy<'_>) -> Result<()>
pub async fn select_option(&self, by: SelectBy<'_>) -> Result<()>
Pick an option in a combobox, dropdown, or other AT-SPI Selection
container — the equivalent of Playwright’s selectOption.
Resolves to one container element (auto-waits for showing +
enabled), then calls Selection::select_child(index) on it.
Much faster and less flaky than clicking the widget open,
locating the item in the popup, and clicking it — no popup
positioning to race against.
§Modes
SelectBy::Index— no tree walk; the index is passed through directly. Use when tests don’t care about the visible label or when the popup’s options don’t appear in the accessibility tree until it’s opened (GTK4DropDowncan behave this way in headless compositors).SelectBy::Label— takes a fresh snapshot, enumerates the container’s direct a11y children in document order, and picks the one whose accessible name matches. Exactly one match is required; zero →Error::Atspi, more than one →Error::AmbiguousSelector.
§Errors
Error::Atspi("select_child(..) returned false ...")when the target doesn’t implement the Selection interface or the index is out of range for its selection model.Error::ElementStaleif the container went away between resolution and the D-Bus call.- Auto-wait timeout if the container never becomes actionable.
Sourcepub async fn focus(&self) -> Result<()>
pub async fn focus(&self) -> Result<()>
Give keyboard focus to the matched element.
Auto-waits for the element to be resolvable, showing, and focusable
— the last is a weaker check than “actionable” because some widgets
accept focus without accepting activation (read-only text boxes,
scroll regions, etc.). Uses AT-SPI’s Component::grab_focus under
the hood.
§Toolkit caveats
This relies on the target widget implementing the AT-SPI Component
interface. Some toolkits (notably GTK4 in its current form) don’t
expose Component on all widgets — you may see
Error::Atspi("NotSupported") from grab_focus even when the
widget is visibly focusable on screen. When that happens the
fallback is to drive focus via keyboard navigation (Tab /
Shift+Tab) or synthesize a pointer click.
Sourcepub async fn scroll_into_view(&self) -> Result<()>
pub async fn scroll_into_view(&self) -> Result<()>
Bring the matched element into its scrollable ancestor’s viewport.
Tries AT-SPI Component::scroll_to(ScrollType::Anywhere) first — a
single round-trip that lets the toolkit do the right thing for the
specific widget (virtualized list, scroll pane, etc.). If the
widget doesn’t honor that call, falls back to moving the pointer
over the nearest scrollable ancestor and sending discrete
mouse-wheel events until the target’s bounds lie fully inside the
ancestor’s bounds.
Returns cleanly when the element is already in view (no-op).
§Errors
Error::Atspiwhen no scrollable ancestor exists (the element isn’t inside aScrollPane/Viewport— nothing to scroll).Error::Atspiwhen the fallback loop exhausts its retry budget (the wheel events didn’t bring the element into view; likely a toolkit that ignores synthesized axis events).- Auto-wait timeout if the element never resolves.
Sourcepub async fn hover(&self) -> Result<()>
pub async fn hover(&self) -> Result<()>
Move the pointer to the centre of the matched element without clicking. Useful for revealing hover states like tooltips and slide-out menus.
Auto-waits for the element to be resolvable, showing, and enabled.
Does not call scroll_into_view —
invoke it explicitly if the element may be off-screen.
Sourcepub async fn double_click(&self) -> Result<()>
pub async fn double_click(&self) -> Result<()>
Double-click the matched element at its centre with the primary mouse button.
Differs from calling click twice: click routes
through the AT-SPI Action interface and never synthesizes
pointer events, so toolkits don’t see a double-click — they see
two independent activations. This method synthesizes real pointer
events at the element’s centre, with the two clicks spaced inside
the system double-click window (see [DOUBLE_CLICK_GAP]).
Auto-waits for the element to be resolvable, showing, and enabled.
Sourcepub async fn right_click(&self) -> Result<()>
pub async fn right_click(&self) -> Result<()>
Right-click the matched element at its centre, typically opening the widget’s context menu.
Auto-waits for the element to be resolvable, showing, and enabled.
Sourcepub async fn drag_to(&self, target: &Locator) -> Result<()>
pub async fn drag_to(&self, target: &Locator) -> Result<()>
Drag from the centre of this element to the centre of target
with the primary mouse button held down.
The gesture moves in small linear steps (see
[DRAG_INTERMEDIATE_STEPS]) so toolkits that only start their DnD
machinery after a few pixels of movement — GTK4 in particular —
reliably pick it up.
Auto-waits for both endpoints to be resolvable, showing, and enabled before any button is pressed. If any pointer motion fails mid-drag, the button is released before the error propagates so subsequent calls don’t inherit a stuck button.
Sourcepub async fn wait_for<T, F, Fut>(&self, pred: F) -> Result<T>
pub async fn wait_for<T, F, Fut>(&self, pred: F) -> Result<T>
The most general wait primitive. Polls with exponential backoff
until pred returns Ok(Some(T)), a non-retriable error, or the
effective timeout elapses. The predicate receives the full
multi-match node-set and can map it to any output type.
Ok(None) means “not yet, keep polling.” Err(e) where e is
retriable (ElementStale) is swallowed and retried. All other
errors propagate immediately. On timeout, returns the last
retriable error if there was one, otherwise Error::Timeout.
Most callers should reach for wait_until or
wait_until_async first — this is the
escape hatch for cases that need a non-bool output, e.g.
wait_for_text which returns the matched
String.
Sourcepub async fn wait_until<F>(&self, pred: F) -> Result<Vec<ElementInfo>>
pub async fn wait_until<F>(&self, pred: F) -> Result<Vec<ElementInfo>>
Poll until a sync predicate over the current multi-match node-set
returns true. Returns the matching set (same as
inspect_all would observe) on success.
The predicate sees all matches, so it can express:
- “exactly one match satisfying X”:
|h| h.len() == 1 && cond(&h[0]) - “element is gone or not showing” (the shape of
wait_for_hidden):|h| h.is_empty() || !showing(&h[0]) - “count reaches N”:
|h| h.len() == n
For predicates that need I/O of their own (another locator, a live
text read, the filesystem), use
wait_until_async.
Sourcepub async fn wait_until_async<F, Fut>(
&self,
pred: F,
) -> Result<Vec<ElementInfo>>
pub async fn wait_until_async<F, Fut>( &self, pred: F, ) -> Result<Vec<ElementInfo>>
Async counterpart to wait_until. Identical
semantics, except the predicate can .await — useful when the
decision depends on a second locator’s state, a live text read, a
bounds query, or any other I/O that isn’t already captured in the
snapshot ElementInfo.
Sourcepub async fn wait_for_visible(&self) -> Result<()>
pub async fn wait_for_visible(&self) -> Result<()>
Poll until the element exists and has the Showing state.
Poll until the element either doesn’t exist or doesn’t have the
Showing state. The inverse of wait_for_visible.
Sourcepub async fn wait_for_enabled(&self) -> Result<()>
pub async fn wait_for_enabled(&self) -> Result<()>
Poll until the element exists and is interactable (has either the
Enabled or Sensitive state — see Locator::is_enabled for why
both are treated as equivalent).
Sourcepub async fn wait_for_count(&self, n: usize) -> Result<()>
pub async fn wait_for_count(&self, n: usize) -> Result<()>
Poll until the selector matches exactly n elements. Useful for
lists that populate asynchronously after a user action.
Sourcepub async fn wait_for_text<F>(&self, pred: F) -> Result<String>
pub async fn wait_for_text<F>(&self, pred: F) -> Result<String>
Poll until the element’s text contents satisfy pred. Returns the
matching text on success so the caller can inspect it further.
Unlike the snapshot-backed waits, text isn’t captured in the tree
snapshot — this does a live read through the AT-SPI Text proxy per
tick, which is why it uses wait_for directly
(the predicate maps to String, not bool).
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Locator
impl !RefUnwindSafe for Locator
impl Send for Locator
impl Sync for Locator
impl Unpin for Locator
impl UnsafeUnpin for Locator
impl !UnwindSafe for Locator
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more