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