1// Copyright 2024 The AccessKit Authors. All rights reserved.
2// Licensed under the Apache License, Version 2.0 (found in
3// the LICENSE-APACHE file) or the MIT license (found in
4// the LICENSE-MIT file), at your option.
5
6//! API that corresponds more closely to the libatspi client API,
7//! intended to be used by bindings to languages with less rich
8//! type systems.
9
10use crate::{
11 Adapter, Event as EventEnum, NodeIdOrRoot, ObjectEvent, PlatformNode, PlatformRoot, Property,
12 WindowEvent,
13};
14
15pub use crate::{CoordType, Error, Layer, Rect, Result, Role, StateSet};
16
17#[derive(Clone, Hash, PartialEq)]
18pub enum Accessible {
19 Node(PlatformNode),
20 Root(PlatformRoot),
21}
22
23impl Accessible {
24 pub fn role(&self) -> Result<Role> {
25 match self {
26 Self::Node(node) => node.role(),
27 Self::Root(_) => Ok(Role::Application),
28 }
29 }
30
31 pub fn localized_role_name(&self) -> Result<String> {
32 match self {
33 Self::Node(node) => node.localized_role_name(),
34 Self::Root(_) => Ok("".into()),
35 }
36 }
37
38 pub fn name(&self) -> Result<String> {
39 match self {
40 Self::Node(node) => node.name(),
41 Self::Root(root) => root.name(),
42 }
43 }
44
45 pub fn description(&self) -> Result<String> {
46 match self {
47 Self::Node(node) => node.description(),
48 Self::Root(_) => Ok("".into()),
49 }
50 }
51
52 pub fn state(&self) -> StateSet {
53 match self {
54 Self::Node(node) => node.state(),
55 Self::Root(_) => StateSet::empty(),
56 }
57 }
58
59 pub fn parent(&self) -> Result<Option<Self>> {
60 match self {
61 Self::Node(node) => match node.parent()? {
62 NodeIdOrRoot::Node(id) => Ok(Some(Self::Node(node.relative(id)))),
63 NodeIdOrRoot::Root => node.root().map(|root| Some(Self::Root(root))),
64 },
65 Self::Root(_) => Ok(None),
66 }
67 }
68
69 pub fn index_in_parent(&self) -> Result<i32> {
70 match self {
71 Self::Node(node) => node.index_in_parent(),
72 Self::Root(_) => Ok(-1),
73 }
74 }
75
76 pub fn child_count(&self) -> Result<i32> {
77 match self {
78 Self::Node(node) => node.child_count(),
79 Self::Root(root) => root.child_count(),
80 }
81 }
82
83 pub fn child_at_index(&self, index: usize) -> Result<Option<Self>> {
84 match self {
85 Self::Node(node) => node
86 .child_at_index(index)
87 .map(|id| id.map(|id| Self::Node(node.relative(id)))),
88 Self::Root(root) => root
89 .child_at_index(index)
90 .map(|child| child.map(Self::Node)),
91 }
92 }
93
94 pub fn map_children<T, I>(&self, f: impl Fn(Self) -> I) -> Result<T>
95 where
96 T: FromIterator<I>,
97 {
98 match self {
99 Self::Node(node) => node.map_children(|id| f(Self::Node(node.relative(id)))),
100 Self::Root(root) => root.map_children(|node| f(Self::Node(node))),
101 }
102 }
103
104 pub fn application(&self) -> Result<Self> {
105 match self {
106 Self::Node(node) => node.root().map(Self::Root),
107 Self::Root(root) => Ok(Self::Root(root.clone())),
108 }
109 }
110
111 pub fn toolkit_name(&self) -> Result<String> {
112 match self {
113 Self::Node(node) => node.toolkit_name(),
114 Self::Root(root) => root.toolkit_name(),
115 }
116 }
117
118 pub fn toolkit_version(&self) -> Result<String> {
119 match self {
120 Self::Node(node) => node.toolkit_version(),
121 Self::Root(root) => root.toolkit_version(),
122 }
123 }
124
125 pub fn supports_action(&self) -> Result<bool> {
126 match self {
127 Self::Node(node) => node.supports_action(),
128 Self::Root(_) => Ok(false),
129 }
130 }
131
132 pub fn n_actions(&self) -> Result<i32> {
133 match self {
134 Self::Node(node) => node.n_actions(),
135 Self::Root(_) => Err(Error::UnsupportedInterface),
136 }
137 }
138
139 pub fn action_name(&self, index: i32) -> Result<String> {
140 match self {
141 Self::Node(node) => node.action_name(index),
142 Self::Root(_) => Err(Error::UnsupportedInterface),
143 }
144 }
145
146 pub fn do_action(&self, index: i32) -> Result<bool> {
147 match self {
148 Self::Node(node) => node.do_action(index),
149 Self::Root(_) => Err(Error::UnsupportedInterface),
150 }
151 }
152
153 pub fn supports_component(&self) -> Result<bool> {
154 match self {
155 Self::Node(node) => node.supports_component(),
156 Self::Root(_) => Ok(false),
157 }
158 }
159
160 pub fn contains(&self, x: i32, y: i32, coord_type: CoordType) -> Result<bool> {
161 match self {
162 Self::Node(node) => node.contains(x, y, coord_type),
163 Self::Root(_) => Err(Error::UnsupportedInterface),
164 }
165 }
166
167 pub fn accessible_at_point(
168 &self,
169 x: i32,
170 y: i32,
171 coord_type: CoordType,
172 ) -> Result<Option<Self>> {
173 match self {
174 Self::Node(node) => node
175 .accessible_at_point(x, y, coord_type)
176 .map(|id| id.map(|id| Self::Node(node.relative(id)))),
177 Self::Root(_) => Err(Error::UnsupportedInterface),
178 }
179 }
180
181 pub fn extents(&self, coord_type: CoordType) -> Result<Rect> {
182 match self {
183 Self::Node(node) => node.extents(coord_type),
184 Self::Root(_) => Err(Error::UnsupportedInterface),
185 }
186 }
187
188 pub fn layer(&self) -> Result<Layer> {
189 match self {
190 Self::Node(node) => node.layer(),
191 Self::Root(_) => Err(Error::UnsupportedInterface),
192 }
193 }
194
195 pub fn grab_focus(&self) -> Result<bool> {
196 match self {
197 Self::Node(node) => node.grab_focus(),
198 Self::Root(_) => Err(Error::UnsupportedInterface),
199 }
200 }
201
202 pub fn scroll_to_point(&self, coord_type: CoordType, x: i32, y: i32) -> Result<bool> {
203 match self {
204 Self::Node(node) => node.scroll_to_point(coord_type, x, y),
205 Self::Root(_) => Err(Error::UnsupportedInterface),
206 }
207 }
208
209 pub fn supports_value(&self) -> Result<bool> {
210 match self {
211 Self::Node(node) => node.supports_value(),
212 Self::Root(_) => Ok(false),
213 }
214 }
215
216 pub fn minimum_value(&self) -> Result<f64> {
217 match self {
218 Self::Node(node) => node.minimum_value(),
219 Self::Root(_) => Err(Error::UnsupportedInterface),
220 }
221 }
222
223 pub fn maximum_value(&self) -> Result<f64> {
224 match self {
225 Self::Node(node) => node.maximum_value(),
226 Self::Root(_) => Err(Error::UnsupportedInterface),
227 }
228 }
229
230 pub fn minimum_increment(&self) -> Result<f64> {
231 match self {
232 Self::Node(node) => node.minimum_increment(),
233 Self::Root(_) => Err(Error::UnsupportedInterface),
234 }
235 }
236
237 pub fn current_value(&self) -> Result<f64> {
238 match self {
239 Self::Node(node) => node.current_value(),
240 Self::Root(_) => Err(Error::UnsupportedInterface),
241 }
242 }
243
244 pub fn set_current_value(&self, value: f64) -> Result<()> {
245 match self {
246 Self::Node(node) => node.set_current_value(value),
247 Self::Root(_) => Err(Error::UnsupportedInterface),
248 }
249 }
250}
251
252#[derive(PartialEq)]
253pub enum EventData {
254 U32(u32),
255 F64(f64),
256 String(String),
257 Rect(Rect),
258 Accessible(Accessible),
259}
260
261#[derive(PartialEq)]
262pub struct Event {
263 pub kind: String,
264 pub source: Accessible,
265 pub detail1: i32,
266 pub detail2: i32,
267 pub data: Option<EventData>,
268}
269
270impl Event {
271 pub fn new(adapter: &Adapter, event: EventEnum) -> Self {
272 match event {
273 EventEnum::Object { target, event } => {
274 let source = match target {
275 NodeIdOrRoot::Node(target) => Accessible::Node(adapter.platform_node(target)),
276 NodeIdOrRoot::Root => Accessible::Root(adapter.platform_root()),
277 };
278 match event {
279 ObjectEvent::ActiveDescendantChanged(child) => {
280 let child = Accessible::Node(adapter.platform_node(child));
281 Self {
282 kind: "object:active-descendant-changed".into(),
283 source,
284 detail1: 0,
285 detail2: 0,
286 data: Some(EventData::Accessible(child)),
287 }
288 }
289 ObjectEvent::Announcement(message, politeness) => Self {
290 kind: "object:announcement".into(),
291 source,
292 detail1: politeness as i32,
293 detail2: 0,
294 data: Some(EventData::String(message)),
295 },
296 ObjectEvent::BoundsChanged(bounds) => Self {
297 kind: "object:bounds-changed".into(),
298 source,
299 detail1: 0,
300 detail2: 0,
301 data: Some(EventData::Rect(bounds)),
302 },
303 ObjectEvent::ChildAdded(index, child) => {
304 let child = Accessible::Node(adapter.platform_node(child));
305 Self {
306 kind: "object:children-changed:add".into(),
307 source,
308 detail1: index as i32,
309 detail2: 0,
310 data: Some(EventData::Accessible(child)),
311 }
312 }
313 ObjectEvent::ChildRemoved(child) => {
314 let child = Accessible::Node(adapter.platform_node(child));
315 Self {
316 kind: "object:children-changed:remove".into(),
317 source,
318 detail1: -1,
319 detail2: 0,
320 data: Some(EventData::Accessible(child)),
321 }
322 }
323 ObjectEvent::PropertyChanged(property) => Self {
324 kind: match property {
325 Property::Name(_) => "object:property-change:accessible-name",
326 Property::Description(_) => {
327 "object:property-change:accessible-description"
328 }
329 Property::Parent(_) => "object:property-change:accessible-parent",
330 Property::Role(_) => "object:property-change:accessible-role",
331 Property::Value(_) => "object:property-change:accessible-value",
332 }
333 .into(),
334 source,
335 detail1: 0,
336 detail2: 0,
337 data: Some(match property {
338 Property::Name(value) => EventData::String(value),
339 Property::Description(value) => EventData::String(value),
340 Property::Parent(parent) => {
341 let parent = match parent {
342 NodeIdOrRoot::Node(parent) => {
343 Accessible::Node(adapter.platform_node(parent))
344 }
345 NodeIdOrRoot::Root => Accessible::Root(adapter.platform_root()),
346 };
347 EventData::Accessible(parent)
348 }
349 Property::Role(value) => EventData::U32(value as u32),
350 Property::Value(value) => EventData::F64(value),
351 }),
352 },
353 ObjectEvent::StateChanged(state, value) => Self {
354 kind: format!("object:state-changed:{}", String::from(state)),
355 source,
356 detail1: value as i32,
357 detail2: 0,
358 data: None,
359 },
360 }
361 }
362 EventEnum::Window {
363 target,
364 name,
365 event,
366 } => {
367 let kind = match event {
368 WindowEvent::Activated => "window:activate",
369 WindowEvent::Deactivated => "window:deactivate",
370 };
371 let source = Accessible::Node(adapter.platform_node(target));
372 Self {
373 kind: kind.into(),
374 source,
375 detail1: 0,
376 detail2: 0,
377 data: Some(EventData::String(name)),
378 }
379 }
380 }
381 }
382}
383