Skip to main content

Locator

Struct Locator 

Source
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

Source

pub fn xpath(&self) -> &str

The XPath expression this locator resolves with.

Source

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”).

Source

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.

Source

pub fn nth(&self, n: usize) -> Locator

Return a locator pinned to the n-th (0-indexed) match of this one.

Source

pub fn first(&self) -> Locator

Shorthand for nth(0).

Source

pub fn last(&self) -> Locator

Locator for the last match of this selector.

Source

pub fn parent(&self) -> Locator

Locator for the parent of the matched element(s).

Source

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.

Source

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).

Source

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.

Source

pub async fn name(&self) -> Result<Option<String>>

Accessible name of the matched element, or None when the element has no accessible name set.

Source

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.

Source

pub async fn attribute(&self, key: &str) -> Result<Option<String>>

Read a single toolkit attribute by key.

Source

pub async fn attributes(&self) -> Result<HashMap<String, String>>

All toolkit attributes as a map.

Source

pub async fn is_showing(&self) -> Result<bool>

Whether the matched element currently has the AT-SPI State::Showing state.

Source

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.”

Source

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.

Source

pub async fn wait_for_checked(&self) -> Result<()>

Poll until the element has the AT-SPI State::Checked state.

Source

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.

Source

pub async fn wait_for_focused(&self) -> Result<()>

Poll until the element has the AT-SPI State::Focused state.

Source

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.

Source

pub async fn wait_for_expanded(&self) -> Result<()>

Poll until the element has the AT-SPI State::Expanded state.

Source

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.

Source

pub async fn wait_for_editable(&self) -> Result<()>

Poll until the element has the AT-SPI State::Editable state.

Source

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.

Source

pub async fn wait_for_selected(&self) -> Result<()>

Poll until the element has the AT-SPI State::Selected state.

Source

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.

Source

pub async fn wait_for_pressed(&self) -> Result<()>

Poll until the element has the AT-SPI State::Pressed state.

Source

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.

Source

pub async fn wait_for_modal(&self) -> Result<()>

Poll until the element has the AT-SPI State::Modal state.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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::Atspi so 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 GTK4 Entry / Text situation): fall back to a pointer click at the widget’s centre, the same way a user would focus it. Needs bounds() from the snapshot; off-screen widgets without layout return an Error::Atspi directing the caller to fill_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.

Source

pub async fn fill_with_opts(&self, text: &str, mode: FillMode) -> Result<()>

Same as fill but lets the caller pick the select-all strategy. See FillMode for the tradeoffs between strategies.

Source

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.

Source

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 (GTK4 DropDown can 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::ElementStale if the container went away between resolution and the D-Bus call.
  • Auto-wait timeout if the container never becomes actionable.
Source

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.

Source

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::Atspi when no scrollable ancestor exists (the element isn’t inside a ScrollPane / Viewport — nothing to scroll).
  • Error::Atspi when 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.
Source

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.

Source

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.

Source

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.

Source

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.

Source

pub async fn wait_for<T, F, Fut>(&self, pred: F) -> Result<T>
where F: Fn(Vec<ElementInfo>) -> Fut, Fut: Future<Output = Result<Option<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.

Source

pub async fn wait_until<F>(&self, pred: F) -> Result<Vec<ElementInfo>>
where F: Fn(&[ElementInfo]) -> bool,

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.

Source

pub async fn wait_until_async<F, Fut>( &self, pred: F, ) -> Result<Vec<ElementInfo>>
where F: Fn(Vec<ElementInfo>) -> Fut, Fut: Future<Output = bool>,

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.

Source

pub async fn wait_for_visible(&self) -> Result<()>

Poll until the element exists and has the Showing state.

Source

pub async fn wait_for_hidden(&self) -> Result<()>

Poll until the element either doesn’t exist or doesn’t have the Showing state. The inverse of wait_for_visible.

Source

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).

Source

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.

Source

pub async fn wait_for_text<F>(&self, pred: F) -> Result<String>
where F: Fn(&str) -> bool,

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§

Source§

impl Clone for Locator

Source§

fn clone(&self) -> Locator

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more