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}