atspi_common/events/
mod.rs

1pub mod cache;
2pub mod document;
3#[cfg(feature = "wrappers")]
4pub mod event_wrappers;
5
6pub use event_body::{EventBodyBorrowed, EventBodyOwned, EventBodyQtBorrowed, EventBodyQtOwned};
7#[cfg(feature = "wrappers")]
8pub use event_wrappers::{
9	CacheEvents, DocumentEvents, Event, FocusEvents, KeyboardEvents, MouseEvents, ObjectEvents,
10	TerminalEvents, WindowEvents,
11};
12pub mod event_body;
13pub mod focus;
14pub mod keyboard;
15pub mod mouse;
16pub mod object;
17pub mod terminal;
18pub mod traits;
19pub mod window;
20pub use traits::*;
21
22// Same as "(siiv(so))"
23// The only signature that is not found in XML descriptions
24pub(crate) const QSPI_EVENT_SIGNATURE: &Signature = &Signature::static_structure(&[
25	&Signature::Str,
26	&Signature::I32,
27	&Signature::I32,
28	&Signature::Variant,
29	&Signature::Structure(Fields::Static { fields: &[&Signature::Str, &Signature::ObjectPath] }),
30]);
31
32use serde::{Deserialize, Serialize};
33use zbus_lockstep_macros::validate;
34use zbus_names::{OwnedUniqueName, UniqueName};
35#[cfg(feature = "zbus")]
36use zvariant::OwnedObjectPath;
37use zvariant::{signature::Fields, ObjectPath, Signature, Type};
38
39#[cfg(feature = "zbus")]
40use crate::AtspiError;
41use crate::ObjectRef;
42
43impl HasInterfaceName for EventListenerEvents {
44	const DBUS_INTERFACE: &'static str = "org.a11y.atspi.Registry";
45}
46
47impl HasMatchRule for EventListenerEvents {
48	const MATCH_RULE_STRING: &'static str =
49		"type='signal',interface='org.a11y.atspi.Event.Registry'";
50}
51
52impl HasRegistryEventString for EventListenerEvents {
53	const REGISTRY_EVENT_STRING: &'static str = "Event";
54}
55
56#[cfg(feature = "zbus")]
57impl<T> MessageConversion for T
58where
59	ObjectRef: Into<T>,
60	// this bound is not actually used for anything, but I do not want to implement this trait for
61	// just any type that has an infallible conversion from an ObjectRef
62	T: BusProperties,
63{
64	type Body = EventBodyOwned;
65	fn from_message_unchecked_parts(obj_ref: ObjectRef, _: Self::Body) -> Result<Self, AtspiError> {
66		Ok(obj_ref.into())
67	}
68	fn from_message_unchecked(msg: &zbus::Message) -> Result<Self, AtspiError> {
69		let item: ObjectRef = msg.try_into()?;
70		Ok(item.into())
71	}
72	fn body(&self) -> Self::Body {
73		EventBodyOwned::default()
74	}
75}
76
77impl<T: BusProperties> HasMatchRule for T {
78	const MATCH_RULE_STRING: &'static str = <T as BusProperties>::MATCH_RULE_STRING;
79}
80impl<T: BusProperties> HasRegistryEventString for T {
81	const REGISTRY_EVENT_STRING: &'static str = <T as BusProperties>::REGISTRY_EVENT_STRING;
82}
83impl<T: BusProperties> HasInterfaceName for T {
84	const DBUS_INTERFACE: &'static str = <T as BusProperties>::DBUS_INTERFACE;
85}
86
87#[cfg(test)]
88mod accessible_deserialization_tests {
89	use crate::events::ObjectRef;
90	use zvariant::Value;
91
92	#[test]
93	fn try_into_value() {
94		let acc = ObjectRef::default();
95		let value_struct = Value::from(acc);
96		let Value::Structure(structure) = value_struct else {
97			panic!("Unable to destructure a structure out of the Value.");
98		};
99		let vals = structure.into_fields();
100		assert_eq!(vals.len(), 2);
101		let Value::Str(bus_name) = vals.first().unwrap() else {
102			panic!("Unable to destructure field value: {:?}", vals.first().unwrap());
103		};
104		assert_eq!(bus_name, ":0.0");
105		let Value::ObjectPath(path) = vals.last().unwrap() else {
106			panic!("Unable to destructure field value: {:?}", vals.get(1).unwrap());
107		};
108		assert_eq!(path.as_str(), "/org/a11y/atspi/accessible/null");
109	}
110	#[test]
111	fn try_from_value() {}
112}
113
114#[cfg(test)]
115mod accessible_tests {
116	use super::ObjectRef;
117
118	#[test]
119	fn test_accessible_default_doesnt_panic() {
120		let acc = ObjectRef::default();
121		assert_eq!(acc.name.as_str(), ":0.0");
122		assert_eq!(acc.path.as_str(), "/org/a11y/atspi/accessible/null");
123	}
124}
125#[cfg(feature = "zbus")]
126impl TryFrom<&zbus::Message> for ObjectRef {
127	type Error = AtspiError;
128	fn try_from(message: &zbus::Message) -> Result<Self, Self::Error> {
129		let header = message.header();
130		let path = header.path().expect("returned path is either `Some` or panics");
131		let owned_path: OwnedObjectPath = path.clone().into();
132
133		let sender: UniqueName<'_> = header.sender().expect("No sender in header").into();
134		let name: OwnedUniqueName = sender.to_owned().into();
135
136		Ok(ObjectRef { name, path: owned_path })
137	}
138}
139
140/// Signal type emitted by `EventListenerRegistered` and `EventListenerDeregistered` signals,
141/// which belong to the `Registry` interface, implemented by the registry-daemon.
142#[validate(signal: "EventListenerRegistered")]
143#[derive(Debug, Clone, Serialize, Deserialize, Type, PartialEq, Eq, Hash)]
144pub struct EventListeners {
145	pub bus_name: OwnedUniqueName,
146	pub path: String,
147}
148
149impl Default for EventListeners {
150	fn default() -> Self {
151		Self {
152			bus_name: UniqueName::try_from(":0.0").unwrap().into(),
153			path: "/org/a11y/atspi/accessible/null".to_string(),
154		}
155	}
156}
157
158#[cfg(test)]
159#[test]
160fn test_event_listener_default_no_panic() {
161	let el = EventListeners::default();
162	assert_eq!(el.bus_name.as_str(), ":0.0");
163	assert_eq!(el.path.as_str(), "/org/a11y/atspi/accessible/null");
164}
165
166/// Covers both `EventListener` events.
167#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
168#[allow(clippy::module_name_repetitions)]
169pub enum EventListenerEvents {
170	/// See: [`EventListenerRegisteredEvent`].
171	Registered(EventListenerRegisteredEvent),
172	/// See: [`EventListenerDeregisteredEvent`].
173	Deregistered(EventListenerDeregisteredEvent),
174}
175
176impl EventTypeProperties for EventListenerEvents {
177	fn member(&self) -> &'static str {
178		match self {
179			Self::Registered(inner) => inner.member(),
180			Self::Deregistered(inner) => inner.member(),
181		}
182	}
183	fn match_rule(&self) -> &'static str {
184		match self {
185			Self::Registered(inner) => inner.match_rule(),
186			Self::Deregistered(inner) => inner.match_rule(),
187		}
188	}
189	fn interface(&self) -> &'static str {
190		match self {
191			Self::Registered(inner) => inner.interface(),
192			Self::Deregistered(inner) => inner.interface(),
193		}
194	}
195	fn registry_string(&self) -> &'static str {
196		match self {
197			Self::Registered(inner) => inner.registry_string(),
198			Self::Deregistered(inner) => inner.registry_string(),
199		}
200	}
201}
202
203impl EventProperties for EventListenerEvents {
204	fn path(&self) -> ObjectPath<'_> {
205		match self {
206			Self::Registered(inner) => inner.path(),
207			Self::Deregistered(inner) => inner.path(),
208		}
209	}
210	fn sender(&self) -> UniqueName<'_> {
211		match self {
212			Self::Registered(inner) => inner.sender(),
213			Self::Deregistered(inner) => inner.sender(),
214		}
215	}
216}
217
218#[cfg(feature = "zbus")]
219impl EventWrapperMessageConversion for EventListenerEvents {
220	fn try_from_message_interface_checked(msg: &zbus::Message) -> Result<Self, AtspiError> {
221		let header = msg.header();
222		let member = header.member().ok_or(AtspiError::MissingMember)?;
223		match member.as_str() {
224			EventListenerRegisteredEvent::DBUS_MEMBER => Ok(EventListenerEvents::Registered(
225				EventListenerRegisteredEvent::from_message_unchecked(msg)?,
226			)),
227			EventListenerDeregisteredEvent::DBUS_MEMBER => Ok(EventListenerEvents::Deregistered(
228				EventListenerDeregisteredEvent::from_message_unchecked(msg)?,
229			)),
230			_ => Err(AtspiError::MemberMatch(format!(
231				"No member {} in {}",
232				member.as_str(),
233				Self::DBUS_INTERFACE
234			))),
235		}
236	}
237}
238
239#[cfg(feature = "zbus")]
240impl TryFrom<&zbus::Message> for EventListenerEvents {
241	type Error = AtspiError;
242	fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> {
243		Self::try_from_message(msg)
244	}
245}
246
247/// An event that is emitted by the registry daemon, to inform that an event has been deregistered
248/// to no longer listen for.
249#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default, Eq, Hash)]
250pub struct EventListenerDeregisteredEvent {
251	/// The [`ObjectRef`] the event applies to.
252	pub item: ObjectRef,
253	/// A list of events that have been deregistered via the registry interface.
254	/// See `atspi-connection`.
255	pub deregistered_event: EventListeners,
256}
257
258impl_from_user_facing_event_for_interface_event_enum!(
259	EventListenerDeregisteredEvent,
260	EventListenerEvents,
261	EventListenerEvents::Deregistered
262);
263impl_from_user_facing_type_for_event_enum!(EventListenerDeregisteredEvent, Event::Listener);
264impl_try_from_event_for_user_facing_type!(
265	EventListenerDeregisteredEvent,
266	EventListenerEvents::Deregistered,
267	Event::Listener
268);
269event_test_cases!(EventListenerDeregisteredEvent, Explicit);
270impl BusProperties for EventListenerDeregisteredEvent {
271	const REGISTRY_EVENT_STRING: &'static str = "Registry:EventListenerDeregistered";
272	const MATCH_RULE_STRING: &'static str =
273		"type='signal',interface='org.a11y.atspi.Registry',member='EventListenerDeregistered'";
274	const DBUS_MEMBER: &'static str = "EventListenerDeregistered";
275	const DBUS_INTERFACE: &'static str = "org.a11y.atspi.Registry";
276}
277
278#[cfg(feature = "zbus")]
279impl MessageConversion for EventListenerDeregisteredEvent {
280	type Body = EventListeners;
281
282	fn from_message_unchecked_parts(
283		item: ObjectRef,
284		deregistered_event: Self::Body,
285	) -> Result<Self, AtspiError> {
286		Ok(Self { item, deregistered_event })
287	}
288	fn from_message_unchecked(msg: &zbus::Message) -> Result<Self, AtspiError> {
289		let item = msg.try_into()?;
290		let body = msg.body().deserialize()?;
291		Self::from_message_unchecked_parts(item, body)
292	}
293	fn body(&self) -> Self::Body {
294		self.deregistered_event.clone()
295	}
296}
297impl_from_dbus_message!(EventListenerDeregisteredEvent, Explicit);
298impl_event_properties!(EventListenerDeregisteredEvent);
299impl_to_dbus_message!(EventListenerDeregisteredEvent);
300
301/// An event that is emitted by the regostry daemon to signal that an event has been registered to listen for.
302#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default, Eq, Hash)]
303pub struct EventListenerRegisteredEvent {
304	/// The [`ObjectRef`] the event applies to.
305	pub item: ObjectRef,
306	/// A list of events that have been registered via the registry interface.
307	/// See `atspi-connection`.
308	pub registered_event: EventListeners,
309}
310
311impl_from_user_facing_event_for_interface_event_enum!(
312	EventListenerRegisteredEvent,
313	EventListenerEvents,
314	EventListenerEvents::Registered
315);
316impl_from_user_facing_type_for_event_enum!(EventListenerRegisteredEvent, Event::Listener);
317impl_try_from_event_for_user_facing_type!(
318	EventListenerRegisteredEvent,
319	EventListenerEvents::Registered,
320	Event::Listener
321);
322event_test_cases!(EventListenerRegisteredEvent, Explicit);
323impl BusProperties for EventListenerRegisteredEvent {
324	const REGISTRY_EVENT_STRING: &'static str = "Registry:EventListenerRegistered";
325	const MATCH_RULE_STRING: &'static str =
326		"type='signal',interface='org.a11y.atspi.Registry',member='EventListenerRegistered'";
327	const DBUS_MEMBER: &'static str = "EventListenerRegistered";
328	const DBUS_INTERFACE: &'static str = "org.a11y.atspi.Registry";
329}
330
331#[cfg(feature = "zbus")]
332impl MessageConversion for EventListenerRegisteredEvent {
333	type Body = EventListeners;
334
335	fn from_message_unchecked_parts(
336		item: ObjectRef,
337		registered_event: Self::Body,
338	) -> Result<Self, AtspiError> {
339		Ok(Self { item, registered_event })
340	}
341	fn from_message_unchecked(msg: &zbus::Message) -> Result<Self, AtspiError> {
342		let item = msg.try_into()?;
343		let body = msg.body().deserialize()?;
344		Self::from_message_unchecked_parts(item, body)
345	}
346	fn body(&self) -> Self::Body {
347		self.registered_event.clone()
348	}
349}
350impl_from_dbus_message!(EventListenerRegisteredEvent, Explicit);
351impl_event_properties!(EventListenerRegisteredEvent);
352impl_to_dbus_message!(EventListenerRegisteredEvent);
353
354/// An event that is emitted when the registry daemon has started.
355#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default, Eq, Hash)]
356pub struct AvailableEvent {
357	/// The [`ObjectRef`] the event applies to.
358	pub item: ObjectRef,
359	pub socket: ObjectRef,
360}
361#[cfg(feature = "wrappers")]
362impl From<AvailableEvent> for Event {
363	fn from(ev: AvailableEvent) -> Event {
364		Event::Available(ev)
365	}
366}
367#[cfg(feature = "wrappers")]
368impl TryFrom<Event> for AvailableEvent {
369	type Error = AtspiError;
370	fn try_from(generic_event: Event) -> Result<AvailableEvent, Self::Error> {
371		if let Event::Available(specific_event) = generic_event {
372			Ok(specific_event)
373		} else {
374			Err(AtspiError::Conversion("Invalid type"))
375		}
376	}
377}
378event_test_cases!(AvailableEvent, Explicit);
379impl BusProperties for AvailableEvent {
380	const REGISTRY_EVENT_STRING: &'static str = "Socket:Available";
381	const MATCH_RULE_STRING: &'static str =
382		"type='signal',interface='org.a11y.atspi.Socket',member='Available'";
383	const DBUS_MEMBER: &'static str = "Available";
384	const DBUS_INTERFACE: &'static str = "org.a11y.atspi.Socket";
385}
386
387#[cfg(feature = "zbus")]
388impl MessageConversion for AvailableEvent {
389	type Body = ObjectRef;
390
391	fn from_message_unchecked_parts(
392		item: ObjectRef,
393		socket: Self::Body,
394	) -> Result<Self, AtspiError> {
395		Ok(Self { item, socket })
396	}
397	fn from_message_unchecked(msg: &zbus::Message) -> Result<Self, AtspiError> {
398		let item = msg.try_into()?;
399		let body = msg.body().deserialize()?;
400		Self::from_message_unchecked_parts(item, body)
401	}
402	fn body(&self) -> Self::Body {
403		self.socket.clone()
404	}
405}
406impl_from_dbus_message!(AvailableEvent, Explicit);
407impl_event_properties!(AvailableEvent);
408impl_to_dbus_message!(AvailableEvent);
409
410#[cfg(all(feature = "zbus", feature = "wrappers"))]
411impl TryFrom<&zbus::Message> for Event {
412	type Error = AtspiError;
413
414	fn try_from(msg: &zbus::Message) -> Result<Event, AtspiError> {
415		let header = msg.header();
416		let interface = header.interface().ok_or(AtspiError::MissingInterface)?;
417		let interface_str = interface.as_str();
418
419		match interface_str {
420			<AvailableEvent as HasInterfaceName>::DBUS_INTERFACE => {
421				Ok(AvailableEvent::try_from(msg)?.into())
422			}
423			<ObjectEvents as HasInterfaceName>::DBUS_INTERFACE => {
424				Ok(Event::Object(ObjectEvents::try_from_message_interface_checked(msg)?))
425			}
426			<DocumentEvents as HasInterfaceName>::DBUS_INTERFACE => {
427				Ok(Event::Document(DocumentEvents::try_from_message_interface_checked(msg)?))
428			}
429			<WindowEvents as HasInterfaceName>::DBUS_INTERFACE => {
430				Ok(Event::Window(WindowEvents::try_from_message_interface_checked(msg)?))
431			}
432			<TerminalEvents as HasInterfaceName>::DBUS_INTERFACE => {
433				Ok(Event::Terminal(TerminalEvents::try_from_message_interface_checked(msg)?))
434			}
435			<MouseEvents as HasInterfaceName>::DBUS_INTERFACE => {
436				Ok(Event::Mouse(MouseEvents::try_from_message_interface_checked(msg)?))
437			}
438			<FocusEvents as HasInterfaceName>::DBUS_INTERFACE => {
439				Ok(Event::Focus(FocusEvents::try_from_message_interface_checked(msg)?))
440			}
441			<KeyboardEvents as HasInterfaceName>::DBUS_INTERFACE => {
442				Ok(Event::Keyboard(KeyboardEvents::try_from_message_interface_checked(msg)?))
443			}
444			<CacheEvents as HasInterfaceName>::DBUS_INTERFACE => {
445				Ok(Event::Cache(CacheEvents::try_from_message_interface_checked(msg)?))
446			}
447			<EventListenerEvents as HasInterfaceName>::DBUS_INTERFACE => {
448				Ok(Event::Listener(EventListenerEvents::try_from_message_interface_checked(msg)?))
449			}
450			_ => Err(AtspiError::InterfaceMatch(format!(
451				"No events found with interface {interface_str}"
452			))),
453		}
454	}
455}
456
457impl<T: BusProperties> EventTypeProperties for T {
458	fn member(&self) -> &'static str {
459		<T>::DBUS_MEMBER
460	}
461	fn interface(&self) -> &'static str {
462		<T>::DBUS_INTERFACE
463	}
464	fn match_rule(&self) -> &'static str {
465		<T>::MATCH_RULE_STRING
466	}
467	fn registry_string(&self) -> &'static str {
468		<T>::REGISTRY_EVENT_STRING
469	}
470}
471
472assert_obj_safe!(EventTypeProperties);
473
474assert_obj_safe!(EventProperties);
475
476#[cfg(feature = "zbus")]
477impl<T> MessageConversionExt<crate::LegacyCacheItem> for T
478where
479	T: MessageConversion<Body = crate::LegacyCacheItem>,
480{
481	fn try_from_message(msg: &zbus::Message) -> Result<Self, AtspiError> {
482		<T as MessageConversionExt<crate::LegacyCacheItem>>::validate_interface(msg)?;
483		<T as MessageConversionExt<crate::LegacyCacheItem>>::validate_member(msg)?;
484		<T as MessageConversionExt<crate::LegacyCacheItem>>::validate_body(msg)?;
485		<T as MessageConversion>::from_message_unchecked(msg)
486	}
487}
488
489#[cfg(feature = "zbus")]
490impl<T> MessageConversionExt<EventListeners> for T
491where
492	T: MessageConversion<Body = EventListeners>,
493{
494	fn try_from_message(msg: &zbus::Message) -> Result<Self, AtspiError> {
495		<T as MessageConversionExt<EventListeners>>::validate_interface(msg)?;
496		<T as MessageConversionExt<EventListeners>>::validate_member(msg)?;
497		<T as MessageConversionExt<EventListeners>>::validate_body(msg)?;
498		<T as MessageConversion>::from_message_unchecked(msg)
499	}
500}
501
502#[cfg(feature = "zbus")]
503impl<T> MessageConversionExt<crate::CacheItem> for T
504where
505	T: MessageConversion<Body = crate::CacheItem>,
506{
507	fn try_from_message(msg: &zbus::Message) -> Result<Self, AtspiError> {
508		<T as MessageConversionExt<crate::CacheItem>>::validate_interface(msg)?;
509		<T as MessageConversionExt<crate::CacheItem>>::validate_member(msg)?;
510		<T as MessageConversionExt<crate::CacheItem>>::validate_body(msg)?;
511		<T as MessageConversion>::from_message_unchecked(msg)
512	}
513}
514
515#[cfg(feature = "zbus")]
516impl<T> MessageConversionExt<ObjectRef> for T
517where
518	T: MessageConversion<Body = ObjectRef>,
519{
520	fn try_from_message(msg: &zbus::Message) -> Result<Self, AtspiError> {
521		<T as MessageConversionExt<ObjectRef>>::validate_interface(msg)?;
522		<T as MessageConversionExt<ObjectRef>>::validate_member(msg)?;
523		<T as MessageConversionExt<ObjectRef>>::validate_body(msg)?;
524		<T as MessageConversion>::from_message_unchecked(msg)
525	}
526}
527
528#[cfg(feature = "zbus")]
529impl<T> MessageConversionExt<EventBodyOwned> for T
530where
531	T: MessageConversion<Body = EventBodyOwned>,
532{
533	fn try_from_message(msg: &zbus::Message) -> Result<Self, AtspiError> {
534		<T as MessageConversionExt<EventBodyOwned>>::validate_interface(msg)?;
535		<T as MessageConversionExt<EventBodyOwned>>::validate_member(msg)?;
536		let body = msg.body();
537		let body_sig = body.signature();
538		let data_body: EventBodyOwned = if body_sig == EventBodyOwned::SIGNATURE {
539			body.deserialize_unchecked()?
540		} else if body_sig == QSPI_EVENT_SIGNATURE {
541			let qtbody: EventBodyQtOwned = body.deserialize_unchecked()?;
542			qtbody.into()
543		} else {
544			return Err(AtspiError::SignatureMatch(format!(
545				"The message signature {} does not match the signal's body signature: {} or {}",
546				body_sig,
547				EventBodyOwned::SIGNATURE,
548				EventBodyQtOwned::SIGNATURE,
549			)));
550		};
551		let item = msg.try_into()?;
552		Self::from_message_unchecked_parts(item, data_body)
553	}
554}
555
556#[cfg(feature = "zbus")]
557impl<T: EventWrapperMessageConversion + HasInterfaceName> TryFromMessage for T {
558	fn try_from_message(msg: &zbus::Message) -> Result<T, AtspiError> {
559		let header = msg.header();
560		let interface = header.interface().ok_or(AtspiError::MissingInterface)?;
561		if interface != <T as HasInterfaceName>::DBUS_INTERFACE {
562			return Err(AtspiError::InterfaceMatch(format!(
563				"Interface {} does not match require interface for event: {}",
564				interface,
565				<T as HasInterfaceName>::DBUS_INTERFACE
566			)));
567		}
568		<T as EventWrapperMessageConversion>::try_from_message_interface_checked(msg)
569	}
570}