Skip to main content

xa11y_core/
provider.rs

1use crate::element::ElementData;
2use crate::error::{Error, Result};
3use crate::event_provider::Subscription;
4use crate::selector::{matches_simple, Combinator, Selector, SelectorGroup, SelectorSegment};
5use crate::shell::ShellSurfaceKind;
6
7/// Platform backend trait for accessibility tree access.
8///
9/// Providers implement lazy, on-demand tree navigation. Elements are identified
10/// by their [`ElementData`] (which contains a provider-specific `handle` for
11/// looking up the underlying platform object).
12///
13/// # Action model
14///
15/// Common actions are first-class methods with proper typed signatures.
16/// Platform-specific or custom actions use [`perform_action`](Self::perform_action)
17/// as an escape hatch — it takes a `snake_case` action name string.
18///
19/// Providers should check platform permissions in their constructor (`new()`)
20/// and return [`Error::PermissionDenied`](crate::Error::PermissionDenied) if
21/// required permissions are not granted.
22pub trait Provider: Send + Sync {
23    // ── Tree navigation ─────────────────────────────────────────────
24
25    /// Get direct children of an element.
26    ///
27    /// If `element` is `None`, returns top-level application elements.
28    fn get_children(&self, element: Option<&ElementData>) -> Result<Vec<ElementData>>;
29
30    /// List an application's windows. Backends whose native window list is
31    /// wider than their accessibility tree roots can override this.
32    fn app_windows(&self, app: &ElementData) -> Result<Vec<ElementData>> {
33        self.get_children(Some(app))
34    }
35
36    /// Get the parent of an element.
37    ///
38    /// Returns `None` for top-level (application) elements.
39    fn get_parent(&self, element: &ElementData) -> Result<Option<ElementData>>;
40
41    /// Enumerate top-level applications visible to this provider.
42    ///
43    /// Backends return one `ElementData` per application, always with
44    /// `role=Application` as the **enumeration** contract. The direct-attach
45    /// path ([`app_by_pid`](Self::app_by_pid)) is the one exception: macOS
46    /// deliberately preserves `Role::Unknown` for a process that exposes no
47    /// AX application (Window Server), so that `windows()` fails honestly
48    /// instead of pretending the process has no windows. Windows synthesizes
49    /// one Application node per
50    /// process (UIA exposes applications as their top-level windows; the
51    /// provider groups them by pid — and calls the process's first window the
52    /// node's representative — see `xa11y-windows`). AT-SPI can return several
53    /// native registrations sharing a pid; the core collapses those into one
54    /// public `App` and uses [`app_roots`](Self::app_roots) for process-wide
55    /// traversal. The application's top-level
56    /// windows are its `app_windows` results, filtered to `Window|Dialog`.
57    /// This is the dedicated discovery primitive: it replaces the previous
58    /// `find_elements(None, application_selector, .., depth=0)` idiom and
59    /// lets each backend batch the platform-specific enumeration (CGWindowList
60    /// on macOS, the AT-SPI registry on Linux, UIA's desktop root on Windows)
61    /// in one place.
62    ///
63    /// Required: every `Provider` implements this explicitly. There's no
64    /// default impl — discovery and subtree search have different cost
65    /// profiles, and silently routing app discovery through `get_children`
66    /// would hide the difference from implementors.
67    fn list_apps(&self) -> Result<Vec<ElementData>>;
68
69    /// Whether [`list_apps`](Self::list_apps) can expose more than one
70    /// `Application` entry for a single process id.
71    ///
72    /// Only the AT-SPI backend can (a per-process entry plus per-event-loop
73    /// pieces such as a tray or a tooltip context); macOS and Windows
74    /// guarantee one entry per pid. When `false`, [`App::windows_with`]
75    /// skips the same-pid merge — and the full `list_apps` re-enumeration it
76    /// requires — because the calling entry's descendants already cover the
77    /// process, so no cross-entry merge can add anything.
78    ///
79    /// Defaults to `false`. A provider that overrides this with `true` must
80    /// answer `get_children` per same-pid entry and give each entry (and its
81    /// windows) a stable identity durable across `list_apps` calls, since
82    /// the merge deduplicates by that identity.
83    fn splits_app_across_entries(&self) -> bool {
84        false
85    }
86
87    /// Return every native application root that belongs to the same process
88    /// as `app`.
89    ///
90    /// Most accessibility APIs expose exactly one root per process, so the
91    /// default is the supplied root. AT-SPI providers override this because a
92    /// process may register several independent roots.
93    fn app_roots(&self, app: &ElementData) -> Result<Vec<ElementData>> {
94        Ok(vec![app.clone()])
95    }
96
97    /// Find the application owning process `pid` — one attempt, no polling.
98    ///
99    /// This is the single-shot discovery primitive behind `App::by_pid`; the
100    /// core's lookup loop owns the retry/timeout policy. Returns
101    /// [`Error::SelectorNotMatched`] when no accessible application for `pid`
102    /// exists *yet* — the signal the poll loop retries on — and any other
103    /// error when the lookup itself failed (permissions, platform API
104    /// failure), which short-circuits the poll.
105    ///
106    /// The default implementation filters [`list_apps`](Self::list_apps) by
107    /// `pid`, and its not-matched error carries enumeration diagnostics (how
108    /// many apps were visible and how many had no resolvable pid) so a
109    /// timeout on an opaque CI runner says *why* the app was invisible.
110    /// Backends override this where the platform supports reaching a process
111    /// directly (`AXUIElementCreateApplication` on macOS, a UIA `ProcessId`
112    /// property search on Windows): direct attach is immune to enumeration
113    /// blind spots such as top-level windows that are still unnamed while the
114    /// app starts up.
115    fn app_by_pid(&self, pid: u32) -> Result<ElementData> {
116        let apps = self.list_apps()?;
117        let total = apps.len();
118        let unresolved = apps.iter().filter(|a| a.pid.is_none()).count();
119        if let Some(data) = apps.into_iter().find(|a| a.pid == Some(pid)) {
120            return Ok(data);
121        }
122        // The enumeration counts are structured diagnosis fields (tenet 6),
123        // not prose baked into the selector — bindings expose them as
124        // attributes, and `App::by_pid_with` merges in the full candidate
125        // list at its terminal failure site. Cheap to build (two counters),
126        // so attaching it per poll tick is fine.
127        Err(
128            Error::selector_not_matched(format!("application[pid={pid}]")).diagnose(
129                crate::error::Diagnosis {
130                    last_observed: Some(format!(
131                        "enumerated {total} running apps, {unresolved} without a resolvable pid"
132                    )),
133                    ..Default::default()
134                },
135            ),
136        )
137    }
138
139    /// Identify the application that currently holds the system foreground /
140    /// input focus — one attempt, no polling.
141    ///
142    /// Each backend uses its platform's canonical foreground mechanism: the
143    /// system-wide `AXUIElement`'s focused-application attribute (macOS),
144    /// `GetForegroundWindow` + `ElementFromHandle` (Windows), and the focused
145    /// element's `Application` ancestor in the AT-SPI registry (Linux). The
146    /// returned `ElementData` has the same shape [`list_apps`](Self::list_apps)
147    /// produces for that app — in particular its `pid` lines up — so the core
148    /// can tag the foreground entry within an enumeration by pid.
149    ///
150    /// Returns [`Error::SelectorNotMatched`] when no application currently
151    /// holds focus (e.g. focus rests on the desktop / shell, or the screen is
152    /// locked). That is a legitimate state, not a failure: the core treats it
153    /// as "nothing is foreground" — every listed app stays untagged — rather
154    /// than surfacing an error. Any other error (permission, platform API
155    /// failure) is a real failure and propagates.
156    ///
157    /// Required: every `Provider` implements this explicitly. Like
158    /// [`list_apps`](Self::list_apps) there is no default impl — there is no
159    /// portable way to derive the foreground app, so a silent no-op default
160    /// would hide an unimplemented backend (tenet 1).
161    fn focused_app(&self) -> Result<ElementData>;
162
163    /// Enumerate OS shell surfaces — taskbars, panels, docks, menu bars,
164    /// status items, the desktop, and any transient shell flyout currently
165    /// open. One entry per surface, each a real platform element usable as a
166    /// search root.
167    ///
168    /// The listing is live: transient surfaces
169    /// ([`ShellSurfaceKind::Flyout`]) appear only while they are on screen,
170    /// and enumerating NEVER opens, closes, or presses anything. Required —
171    /// no default impl, for the same reason [`list_apps`](Self::list_apps)
172    /// has none: enumeration is platform-specific, and a silent empty default
173    /// would hide an unimplemented backend (tenet 1).
174    ///
175    /// The kind is part of the primitive's contract, so it travels in the
176    /// signature where the compiler sees it rather than being smuggled
177    /// through `raw`. Backends return the platform root untouched;
178    /// `ShellSurface::list_with` additionally stamps `raw["shell_kind"]` on
179    /// the surface root, in one place, so a consumer holding only an
180    /// [`Element`](crate::Element) can read the kind back. That stamp is a
181    /// readback, not a selector: it is on the root alone, a rooted locator
182    /// only emits descendants of its root, and `TreeNode` carries no `raw`.
183    fn list_shell_surfaces(&self) -> Result<Vec<(ShellSurfaceKind, ElementData)>>;
184
185    /// Search for elements matching a selector.
186    ///
187    /// The selector is already parsed by the core — providers match against it
188    /// during traversal and can prune subtrees that can't match.
189    ///
190    /// `root` is the subtree root to search under (always present; use
191    /// [`list_apps`](Self::list_apps) to discover application roots first).
192    /// If `limit` is `Some(n)`, stops after finding `n` matches.
193    /// If `max_depth` is `Some(d)`, does not descend deeper than `d` levels.
194    ///
195    /// This is a thin convenience wrapper that re-uses
196    /// [`find_elements_group`](Self::find_elements_group) with a single-clause
197    /// group. Backends do **not** override this method — they override
198    /// `find_elements_group`, and the single-clause case runs through the
199    /// same native code path as multi-clause queries.
200    fn find_elements(
201        &self,
202        root: &ElementData,
203        selector: &Selector,
204        limit: Option<usize>,
205        max_depth: Option<u32>,
206    ) -> Result<Vec<ElementData>> {
207        let group = SelectorGroup {
208            clauses: vec![selector.clone()],
209        };
210        self.find_elements_group(root, &group, limit, max_depth)
211    }
212
213    /// Search for elements matching any clause of a comma-separated selector
214    /// group, scoped to `root`'s subtree.
215    ///
216    /// This is the **primary search primitive** each backend should override.
217    /// A native implementation performs ONE platform-level subtree query/walk
218    /// (e.g. `FindAllBuildCache(TreeScope_Subtree)` on Windows, one DFS over
219    /// AT-SPI children on Linux, one AX walk on macOS) and evaluates every
220    /// clause inline against each visited element. This avoids the
221    /// per-clause-walk perf cliff and also keeps the cross-clause dedup
222    /// correct: because everything happens inside one call, each platform
223    /// node is visited once and platform identity is stable.
224    ///
225    /// `root` is non-optional: app discovery now goes through
226    /// [`list_apps`](Self::list_apps) and any rootless multi-app search is
227    /// performed by the caller (e.g. `Locator`) by enumerating apps and
228    /// invoking this method per app.
229    ///
230    /// The default implementation traverses via [`get_children`](Self::get_children)
231    /// and uses tree-path identity for cross-clause merging. It's the
232    /// fallback for backends that haven't shipped a native override yet —
233    /// the same path the test/mock provider exercises.
234    fn find_elements_group(
235        &self,
236        root: &ElementData,
237        group: &SelectorGroup,
238        limit: Option<usize>,
239        max_depth: Option<u32>,
240    ) -> Result<Vec<ElementData>> {
241        crate::selector::find_elements_in_tree_group(
242            |el| self.get_children(el),
243            Some(root),
244            group,
245            limit,
246            max_depth,
247        )
248    }
249
250    /// Narrow candidates through remaining selector segments (Child/Descendant
251    /// combinators), deduplicate, apply final :nth and limit.
252    fn narrow_multi_segment(
253        &self,
254        mut candidates: Vec<ElementData>,
255        segments: &[SelectorSegment],
256        max_depth: u32,
257        limit: Option<usize>,
258    ) -> Result<Vec<ElementData>> {
259        for segment in segments {
260            let mut next_candidates = Vec::new();
261            for candidate in &candidates {
262                match segment.combinator {
263                    Combinator::Child => {
264                        let children = self.get_children(Some(candidate))?;
265                        for child in children {
266                            if matches_simple(&child, &segment.simple) {
267                                next_candidates.push(child);
268                            }
269                        }
270                    }
271                    Combinator::Descendant => {
272                        let sub_selector = Selector {
273                            segments: vec![SelectorSegment {
274                                combinator: Combinator::Root,
275                                simple: segment.simple.clone(),
276                            }],
277                        };
278                        let mut sub_results =
279                            self.find_elements(candidate, &sub_selector, None, Some(max_depth))?;
280                        next_candidates.append(&mut sub_results);
281                    }
282                    Combinator::Root => unreachable!(),
283                }
284            }
285            let mut seen = std::collections::HashSet::new();
286            next_candidates.retain(|e| seen.insert(e.handle));
287            candidates = next_candidates;
288        }
289
290        // Apply :nth on last segment
291        if let Some(nth) = segments.last().and_then(|s| s.simple.nth) {
292            if nth <= candidates.len() {
293                candidates = vec![candidates.remove(nth - 1)];
294            } else {
295                candidates.clear();
296            }
297        }
298
299        if let Some(limit) = limit {
300            candidates.truncate(limit);
301        }
302
303        Ok(candidates)
304    }
305
306    // ── Common actions ──────────────────────────────────────────────
307
308    /// Click / tap / invoke the element.
309    fn press(&self, element: &ElementData) -> Result<()>;
310
311    /// Set keyboard focus to the element.
312    fn focus(&self, element: &ElementData) -> Result<()>;
313
314    /// Remove keyboard focus from the element.
315    fn blur(&self, element: &ElementData) -> Result<()>;
316
317    /// Toggle a checkbox or switch.
318    fn toggle(&self, element: &ElementData) -> Result<()>;
319
320    /// Select an item in a list, tab group, or menu.
321    fn select(&self, element: &ElementData) -> Result<()>;
322
323    /// Expand a collapsible element (combo box, tree item, disclosure).
324    fn expand(&self, element: &ElementData) -> Result<()>;
325
326    /// Collapse an expanded element.
327    fn collapse(&self, element: &ElementData) -> Result<()>;
328
329    /// Show the element's context menu or dropdown.
330    fn show_menu(&self, element: &ElementData) -> Result<()>;
331
332    /// Increment a slider or spinner by one step.
333    fn increment(&self, element: &ElementData) -> Result<()>;
334
335    /// Decrement a slider or spinner by one step.
336    fn decrement(&self, element: &ElementData) -> Result<()>;
337
338    /// Scroll the element into the visible area.
339    fn scroll_into_view(&self, element: &ElementData) -> Result<()>;
340
341    // ── Typed operations ────────────────────────────────────────────
342
343    /// Set the text value of the element.
344    fn set_value(&self, element: &ElementData, value: &str) -> Result<()>;
345
346    /// Set the numeric value of the element (slider, spinner).
347    fn set_numeric_value(&self, element: &ElementData, value: f64) -> Result<()>;
348
349    /// Insert text at the current cursor position.
350    fn type_text(&self, element: &ElementData, text: &str) -> Result<()>;
351
352    /// Select a text range (0-based character offsets).
353    fn set_text_selection(&self, element: &ElementData, start: u32, end: u32) -> Result<()>;
354
355    // ── Generic action escape hatch ─────────────────────────────────
356
357    /// Perform an action by `snake_case` name.
358    ///
359    /// This is the escape hatch for platform-specific actions not covered by
360    /// the first-class methods above. The provider converts the name to the
361    /// platform's convention (e.g. `"custom_thing"` → `"AXCustomThing"` on
362    /// macOS) and invokes it.
363    ///
364    /// Well-known action names (`"press"`, `"focus"`, etc.) should also work
365    /// here — providers should delegate to the corresponding method.
366    fn perform_action(&self, element: &ElementData, action: &str) -> Result<()>;
367
368    // ── Window management ──────────────────────────────────────────
369
370    /// `App::windows` filters `app_windows` to `Role::Window | Role::Dialog`.
371    /// By default `app_windows` returns the Application node's children.
372    /// Windows overrides it because native dialogs can be UIA descendants
373    /// of another window; listing them does not make them separate roots
374    /// for an app-wide tree walk.
375    ///
376    /// Linux refines the contract: an app may register several AT-SPI
377    /// Application entries (per-process instance plus per-event-loop pieces
378    /// such as a tray or the GTK IM context), so `App::windows_with` starts
379    /// from this entry's filtered children, then merges the filtered children
380    /// of every same-pid Application entry and deduplicates by stable id (see
381    /// `same_window_identity`). The result is process-complete rather than a
382    /// strict direct-children filter, and merged windows are not this node's
383    /// children, so no single z-order spans them. Providers that split an app
384    /// across entries must answer `app_windows` per entry; the merge is
385    /// core's job.
386    ///
387    /// The filter lives in `App::windows_with`; backends only override
388    /// `app_windows` when native window listing differs from tree navigation.
389    ///
390    /// Activate the window: bring it to the foreground and give it focus.
391    ///
392    /// Window verbs may use the platform accessibility API or a native
393    /// window-manager protocol. A native provider must establish a durable
394    /// association from this accessibility element to exactly one native
395    /// window before it mutates state; process lifetime, destroyed/reused
396    /// identifiers, and same-process ambiguity are errors rather than guesses.
397    /// Titles are never sufficient identity by themselves.
398    ///
399    /// Unless a backend documents a stronger postcondition, success means the
400    /// semantic platform request was accepted for delivery. Window managers
401    /// commonly apply it asynchronously; consumers can re-read the element's
402    /// tri-state window flags or bounds to observe completion. Unsupported
403    /// capabilities and refused requests must remain distinct errors, and a
404    /// backend must never substitute simulated input.
405    ///
406    /// Required: every `Provider` implements this explicitly. There is no
407    /// portable default — each platform's activation mechanism is unique
408    /// (AXRaise on macOS, `SetForegroundWindow` on Windows, GrabFocus on
409    /// Linux), and a silent no-op default would hide an unimplemented
410    /// backend (tenet 1).
411    fn activate(&self, element: &ElementData) -> Result<()>;
412
413    /// Minimize the window.
414    fn minimize(&self, element: &ElementData) -> Result<()>;
415
416    /// Maximize the window.
417    ///
418    /// Distinct from [`Self::enter_fullscreen`]: maximizing leaves the window
419    /// in its platform's maximized state (the macOS zoom equivalent, Windows
420    /// `WindowVisualState_Maximized`) while fullscreen is the native
421    /// fullscreen state. A platform without the operation fails surfaceably
422    /// rather than substituting the other.
423    fn maximize(&self, element: &ElementData) -> Result<()>;
424
425    /// Put the window in native fullscreen.
426    ///
427    /// Distinct from [`Self::maximize`]: fullscreen is the platform's native
428    /// fullscreen state (macOS `AXFullScreen`), not a maximized window.
429    /// [`Self::restore`] clears it. A platform without an accessibility API
430    /// for fullscreen fails surfaceably.
431    fn enter_fullscreen(&self, element: &ElementData) -> Result<()>;
432
433    /// Restore the window to its normal state (from minimized/maximized/fullscreen).
434    fn restore(&self, element: &ElementData) -> Result<()>;
435
436    /// Close the window.
437    fn close(&self, element: &ElementData) -> Result<()>;
438
439    /// Move the window in the coordinates of [`ElementData::bounds`]
440    /// (physical pixels on Windows, logical points elsewhere).
441    fn move_to(&self, element: &ElementData, x: i32, y: i32) -> Result<()>;
442
443    /// Resize the window in the units of [`ElementData::bounds`].
444    fn resize_to(&self, element: &ElementData, width: u32, height: u32) -> Result<()>;
445
446    // ── Events ──────────────────────────────────────────────────────
447
448    /// Subscribe to all accessibility events for an application.
449    ///
450    /// The element should be an application-level element (role=Application).
451    /// The provider extracts the PID from `element.pid`.
452    ///
453    /// Returns a [`Subscription`] that receives events until dropped.
454    fn subscribe(&self, element: &ElementData) -> Result<Subscription>;
455}
456
457// Blanket impl so shared references to a provider act as providers themselves.
458// Used by the umbrella crate's singleton (a `&'static dyn Provider` wrapped in
459// `Arc<_>`) and by any caller that wants to share a provider via `&T`. The
460// orphan rules keep this collision-free for downstream crates because `xa11y-core`
461// owns the `Provider` trait.
462impl<T: Provider + ?Sized> Provider for &T {
463    fn get_children(&self, element: Option<&ElementData>) -> Result<Vec<ElementData>> {
464        (**self).get_children(element)
465    }
466    fn app_windows(&self, app: &ElementData) -> Result<Vec<ElementData>> {
467        (**self).app_windows(app)
468    }
469    fn get_parent(&self, element: &ElementData) -> Result<Option<ElementData>> {
470        (**self).get_parent(element)
471    }
472    fn list_apps(&self) -> Result<Vec<ElementData>> {
473        (**self).list_apps()
474    }
475    // Delegated explicitly (despite having a default impl) so a concrete
476    // provider's override isn't bypassed when it's used through a shared
477    // reference — the default body on `&T` would re-route and silently
478    // answer `false` for a Linux provider passed by reference.
479    fn splits_app_across_entries(&self) -> bool {
480        (**self).splits_app_across_entries()
481    }
482    fn app_roots(&self, app: &ElementData) -> Result<Vec<ElementData>> {
483        (**self).app_roots(app)
484    }
485    // Delegated explicitly (despite having a default impl) so a concrete
486    // provider's PID-direct override isn't bypassed when it's used through a
487    // shared reference — the default body on `&T` would re-route through
488    // `list_apps` and silently lose the override.
489    fn app_by_pid(&self, pid: u32) -> Result<ElementData> {
490        (**self).app_by_pid(pid)
491    }
492    fn focused_app(&self) -> Result<ElementData> {
493        (**self).focused_app()
494    }
495    fn list_shell_surfaces(&self) -> Result<Vec<(ShellSurfaceKind, ElementData)>> {
496        (**self).list_shell_surfaces()
497    }
498    fn find_elements(
499        &self,
500        root: &ElementData,
501        selector: &Selector,
502        limit: Option<usize>,
503        max_depth: Option<u32>,
504    ) -> Result<Vec<ElementData>> {
505        (**self).find_elements(root, selector, limit, max_depth)
506    }
507    fn find_elements_group(
508        &self,
509        root: &ElementData,
510        group: &SelectorGroup,
511        limit: Option<usize>,
512        max_depth: Option<u32>,
513    ) -> Result<Vec<ElementData>> {
514        (**self).find_elements_group(root, group, limit, max_depth)
515    }
516    fn narrow_multi_segment(
517        &self,
518        candidates: Vec<ElementData>,
519        segments: &[SelectorSegment],
520        max_depth: u32,
521        limit: Option<usize>,
522    ) -> Result<Vec<ElementData>> {
523        (**self).narrow_multi_segment(candidates, segments, max_depth, limit)
524    }
525    fn press(&self, element: &ElementData) -> Result<()> {
526        (**self).press(element)
527    }
528    fn focus(&self, element: &ElementData) -> Result<()> {
529        (**self).focus(element)
530    }
531    fn blur(&self, element: &ElementData) -> Result<()> {
532        (**self).blur(element)
533    }
534    fn toggle(&self, element: &ElementData) -> Result<()> {
535        (**self).toggle(element)
536    }
537    fn select(&self, element: &ElementData) -> Result<()> {
538        (**self).select(element)
539    }
540    fn expand(&self, element: &ElementData) -> Result<()> {
541        (**self).expand(element)
542    }
543    fn collapse(&self, element: &ElementData) -> Result<()> {
544        (**self).collapse(element)
545    }
546    fn show_menu(&self, element: &ElementData) -> Result<()> {
547        (**self).show_menu(element)
548    }
549    fn increment(&self, element: &ElementData) -> Result<()> {
550        (**self).increment(element)
551    }
552    fn decrement(&self, element: &ElementData) -> Result<()> {
553        (**self).decrement(element)
554    }
555    fn scroll_into_view(&self, element: &ElementData) -> Result<()> {
556        (**self).scroll_into_view(element)
557    }
558    fn set_value(&self, element: &ElementData, value: &str) -> Result<()> {
559        (**self).set_value(element, value)
560    }
561    fn set_numeric_value(&self, element: &ElementData, value: f64) -> Result<()> {
562        (**self).set_numeric_value(element, value)
563    }
564    fn type_text(&self, element: &ElementData, text: &str) -> Result<()> {
565        (**self).type_text(element, text)
566    }
567    fn set_text_selection(&self, element: &ElementData, start: u32, end: u32) -> Result<()> {
568        (**self).set_text_selection(element, start, end)
569    }
570    fn perform_action(&self, element: &ElementData, action: &str) -> Result<()> {
571        (**self).perform_action(element, action)
572    }
573    fn activate(&self, element: &ElementData) -> Result<()> {
574        (**self).activate(element)
575    }
576    fn minimize(&self, element: &ElementData) -> Result<()> {
577        (**self).minimize(element)
578    }
579    fn maximize(&self, element: &ElementData) -> Result<()> {
580        (**self).maximize(element)
581    }
582    fn enter_fullscreen(&self, element: &ElementData) -> Result<()> {
583        (**self).enter_fullscreen(element)
584    }
585    fn restore(&self, element: &ElementData) -> Result<()> {
586        (**self).restore(element)
587    }
588    fn close(&self, element: &ElementData) -> Result<()> {
589        (**self).close(element)
590    }
591    fn move_to(&self, element: &ElementData, x: i32, y: i32) -> Result<()> {
592        (**self).move_to(element, x, y)
593    }
594    fn resize_to(&self, element: &ElementData, width: u32, height: u32) -> Result<()> {
595        (**self).resize_to(element, width, height)
596    }
597    fn subscribe(&self, element: &ElementData) -> Result<Subscription> {
598        (**self).subscribe(element)
599    }
600}