atspi_common/events/
object.rs

1//! All events which can be received by the `org.a11y.atspi.Object` interface.
2
3#![deny(missing_docs)]
4
5#[cfg(feature = "zbus")]
6use crate::events::MessageConversion;
7#[cfg(feature = "zbus")]
8use crate::object_ref::ObjectRef;
9#[cfg(feature = "zbus")]
10use crate::EventProperties;
11use crate::{
12	error::AtspiError,
13	events::{
14		DBusInterface, DBusMatchRule, DBusMember, EventBody, EventBodyOwned, RegistryEventString,
15	},
16	object_ref::ObjectRefOwned,
17	State,
18};
19use std::hash::Hash;
20#[cfg(feature = "zbus")]
21use zbus::message::{Body as DbusBody, Header};
22use zvariant::{OwnedValue, Value};
23
24const ACCESSIBLE_NAME_PROPERTY_NAME: &str = "accessible-name";
25const ACCESSIBLE_DESCRIPTION_PROPERTY_NAME: &str = "accessible-description";
26const ACCESSIBLE_HELP_TEXT_PROPERTY_NAME: &str = "accessible-help-text";
27const ACCESSIBLE_PARENT_PROPERTY_NAME: &str = "accessible-parent";
28const ACCESSIBLE_ROLE_PROPERTY_NAME: &str = "accessible-role";
29const ACCESSIBLE_TABLE_CAPTION_PROPERTY_NAME: &str = "accessible-table-caption";
30const ACCESSIBLE_TABLE_COLUMN_DESCRIPTION_PROPERTY_NAME: &str =
31	"accessible-table-column-description";
32const ACCESSIBLE_TABLE_COLUMN_HEADER_PROPERTY_NAME: &str = "accessible-table-column-header";
33const ACCESSIBLE_TABLE_ROW_DESCRIPTION_PROPERTY_NAME: &str = "accessible-table-row-description";
34const ACCESSIBLE_TABLE_ROW_HEADER_PROPERTY_NAME: &str = "accessible-table-row-header";
35const ACCESSIBLE_TABLE_SUMMARY_PROPERTY_NAME: &str = "accessible-table-summary";
36
37/// An event representing a property change on UI item `item` with new value `value`.
38#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
39pub struct PropertyChangeEvent {
40	/// The [`crate::ObjectRef`] which the event applies to.
41	pub item: ObjectRefOwned,
42	/// The name of the property.
43	// TODO: this is not necessary since the string is encoded in the `Property` type.
44	pub property: String,
45	/// The value of the property.
46	pub value: Property,
47}
48
49impl_event_type_properties_for_event!(PropertyChangeEvent);
50
51impl Hash for PropertyChangeEvent {
52	fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
53		self.item.hash(state);
54		self.property.hash(state);
55	}
56}
57
58// Do not derive Eq if not all fields implement Eq
59impl Eq for PropertyChangeEvent {}
60
61// TODO: Looks like a false positive Clippy lint
62// Derive me.
63#[allow(clippy::derivable_impls)]
64impl Default for PropertyChangeEvent {
65	fn default() -> Self {
66		Self {
67			item: ObjectRefOwned::default(),
68			property: String::default(),
69			value: Property::default(),
70		}
71	}
72}
73
74/// Any accessibility related property on an [`crate::ObjectRef`].
75/// This is used only in the [`PropertyChangeEvent`]; this event gets triggered if a role or accessible
76/// description of an item changes.
77#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
78#[non_exhaustive]
79pub enum Property {
80	/// Name of the element; this can either be the text of a simple UI element like a [`crate::Role::Button`], but it could also be alternative text via [`aria-label`](https://www.w3.org/TR/wai-aria/#aria-label).
81	Name(String),
82	/// The extended description of an item (usually via [`aria-describedby`](https://www.w3.org/TR/wai-aria/#aria-describedby)).
83	Description(String),
84	/// The [ARIA role](https://www.w3.org/TR/wai-aria/#roles) of a given item.
85	Role(crate::Role),
86	/// Parent of the item in a hierarchical tree.
87	Parent(ObjectRefOwned),
88	/// A description of the table as a whole: in HTML this is achieved via the
89	/// `<table><caption>VALUE_HERE</caption>...</table>` pattern
90	TableCaption(String),
91	/// Similar to [`Self::TableColumnHeader`] except it's the attached description instead of the
92	/// data in the header.
93	TableColumnDescription(String),
94	/// A column header: in HTML this is accomplished with the use of `<th>` in an aligned column with a given `<td>` cell element
95	TableColumnHeader(String),
96	/// Similar to [`Self::TableRowHeader`] except it's the attached description instead of the
97	/// data in the header.
98	TableRowDescription(String),
99	/// Row header: in HTML this is accomplished with the use of `<th scope="row">` at the beginning of a `<tr>`
100	TableRowHeader(String),
101	/// The table summary is a shorter description of the table. In HTML this would be accomplished
102	/// with the [figure/figcaption pattern](https://www.w3.org/WAI/tutorials/tables/caption-summary/#using-the-figure-element-to-mark-up-a-table-summary)
103	TableSummary(String),
104	/// The attached help text of the item.
105	HelpText(String),
106	/// Any other attribute not explicitly laid out above.
107	Other((String, OwnedValue)),
108}
109
110impl Clone for Property {
111	fn clone(&self) -> Self {
112		match self {
113			Property::Name(name) => Self::Name(name.clone()),
114			Property::Description(description) => Self::Description(description.clone()),
115			Property::Role(role) => Self::Role(*role),
116			Property::Parent(parent) => Self::Parent(parent.clone()),
117			Property::TableCaption(table_caption) => Self::TableCaption(table_caption.clone()),
118			Property::TableColumnDescription(table_column_description) => {
119				Self::TableColumnDescription(table_column_description.clone())
120			}
121			Property::TableColumnHeader(table_column_header) => {
122				Self::TableColumnHeader(table_column_header.clone())
123			}
124			Property::TableRowDescription(table_row_description) => {
125				Self::TableRowDescription(table_row_description.clone())
126			}
127			Property::TableRowHeader(table_row_header) => {
128				Self::TableRowHeader(table_row_header.clone())
129			}
130			Property::TableSummary(table_summary) => Self::TableSummary(table_summary.clone()),
131      Property::HelpText(help_text) => Self::HelpText(help_text.clone()),
132			Property::Other((property, value)) => Self::Other((
133				property.clone(),
134				value
135					.try_clone()
136					.expect("Could not clone 'value'.  Since properties are not known to carry files, we do not expect to exceed open file limit."),
137			)),
138		}
139	}
140}
141
142impl Default for Property {
143	fn default() -> Self {
144		Self::Other((String::default(), u64::default().into()))
145	}
146}
147
148impl TryFrom<EventBody<'_>> for Property {
149	type Error = AtspiError;
150
151	fn try_from(mut body: EventBody<'_>) -> Result<Self, Self::Error> {
152		let property = body.kind();
153
154		match property {
155			ACCESSIBLE_NAME_PROPERTY_NAME => Ok(Self::Name(
156				body.take_any_data()
157					.try_into()
158					.map_err(|_| AtspiError::ParseError(ACCESSIBLE_NAME_PROPERTY_NAME))?,
159			)),
160			ACCESSIBLE_DESCRIPTION_PROPERTY_NAME => Ok(Self::Description(
161				body.take_any_data()
162					.try_into()
163					.map_err(|_| AtspiError::ParseError(ACCESSIBLE_DESCRIPTION_PROPERTY_NAME))?,
164			)),
165			ACCESSIBLE_ROLE_PROPERTY_NAME => Ok(Self::Role({
166				let role_int: u32 = body
167					.any_data()
168					.try_into()
169					.map_err(|_| AtspiError::ParseError(ACCESSIBLE_ROLE_PROPERTY_NAME))?;
170				let role: crate::Role = crate::Role::try_from(role_int)
171					.map_err(|_| AtspiError::ParseError("accessible-role"))?;
172				role
173			})),
174			ACCESSIBLE_PARENT_PROPERTY_NAME => Ok(Self::Parent(
175				body.take_any_data()
176					.try_into()
177					.map_err(|_| AtspiError::ParseError(ACCESSIBLE_PARENT_PROPERTY_NAME))?,
178			)),
179			ACCESSIBLE_TABLE_CAPTION_PROPERTY_NAME => Ok(Self::TableCaption(
180				body.take_any_data()
181					.try_into()
182					.map_err(|_| AtspiError::ParseError(ACCESSIBLE_TABLE_CAPTION_PROPERTY_NAME))?,
183			)),
184			ACCESSIBLE_TABLE_COLUMN_DESCRIPTION_PROPERTY_NAME => {
185				Ok(Self::TableColumnDescription(body.take_any_data().try_into().map_err(|_| {
186					AtspiError::ParseError(ACCESSIBLE_TABLE_COLUMN_DESCRIPTION_PROPERTY_NAME)
187				})?))
188			}
189			ACCESSIBLE_TABLE_COLUMN_HEADER_PROPERTY_NAME => {
190				Ok(Self::TableColumnHeader(body.take_any_data().try_into().map_err(|_| {
191					AtspiError::ParseError(ACCESSIBLE_TABLE_COLUMN_HEADER_PROPERTY_NAME)
192				})?))
193			}
194			ACCESSIBLE_TABLE_ROW_DESCRIPTION_PROPERTY_NAME => {
195				Ok(Self::TableRowDescription(body.take_any_data().try_into().map_err(|_| {
196					AtspiError::ParseError(ACCESSIBLE_TABLE_ROW_DESCRIPTION_PROPERTY_NAME)
197				})?))
198			}
199			ACCESSIBLE_TABLE_ROW_HEADER_PROPERTY_NAME => {
200				Ok(Self::TableRowHeader(body.take_any_data().try_into().map_err(|_| {
201					AtspiError::ParseError(ACCESSIBLE_TABLE_ROW_HEADER_PROPERTY_NAME)
202				})?))
203			}
204			ACCESSIBLE_TABLE_SUMMARY_PROPERTY_NAME => Ok(Self::TableSummary(
205				body.take_any_data()
206					.try_into()
207					.map_err(|_| AtspiError::ParseError(ACCESSIBLE_TABLE_SUMMARY_PROPERTY_NAME))?,
208			)),
209			ACCESSIBLE_HELP_TEXT_PROPERTY_NAME => Ok(Self::HelpText(
210				body.take_any_data()
211					.try_into()
212					.map_err(|_| AtspiError::ParseError(ACCESSIBLE_HELP_TEXT_PROPERTY_NAME))?,
213			)),
214			_ => Ok(Self::Other((property.to_string(), body.take_any_data()))),
215		}
216	}
217}
218
219impl From<Property> for OwnedValue {
220	fn from(property: Property) -> Self {
221		let value = match property {
222			Property::Name(name) => Value::from(name),
223			Property::Description(description) => Value::from(description),
224			Property::Role(role) => Value::from(role as u32),
225			Property::Parent(parent) => Value::from(parent),
226			Property::TableCaption(table_caption) => Value::from(table_caption),
227			Property::TableColumnDescription(table_column_description) => {
228				Value::from(table_column_description)
229			}
230			Property::TableColumnHeader(table_column_header) => Value::from(table_column_header),
231			Property::TableRowDescription(table_row_description) => {
232				Value::from(table_row_description)
233			}
234			Property::TableRowHeader(table_row_header) => Value::from(table_row_header),
235			Property::TableSummary(table_summary) => Value::from(table_summary),
236			Property::HelpText(help_text) => Value::from(help_text),
237			Property::Other((_, value)) => value.into(),
238		};
239		value.try_into().expect("Should succeed as there are no borrowed file descriptors involved that could, potentially, exceed the open file limit when converted to OwnedValue")
240	}
241}
242
243#[cfg(test)]
244mod test_property {
245	use crate::events::object::{Property, PropertyChangeEvent};
246	use crate::events::{EventBody, EventBodyOwned};
247	use crate::{ObjectRef, Role};
248
249	static TEST_OBJECT_REF: &ObjectRef =
250		&ObjectRef::from_static_str_unchecked(":0.0", "/org/a11y/atspi/test/path");
251
252	macro_rules! property_subtype_test {
253		($name:ident, $key:expr, $prop:path, $val:expr) => {
254			#[test]
255			fn $name() {
256				let prop = $prop($val);
257				let prop_ev = PropertyChangeEvent {
258					item: TEST_OBJECT_REF.clone().into(),
259					property: $key.to_string(),
260					value: prop.clone(),
261				};
262				let ev_body: EventBodyOwned = prop_ev.try_into().expect("Valid event body!");
263				let ev: EventBody<'_> = ev_body.into();
264				let prop2: Property = ev.try_into().expect("Valid Property value");
265				assert_eq!(prop, prop2);
266			}
267		};
268	}
269	property_subtype_test!(
270		test_prop_type_desc,
271		"accessible-description",
272		Property::Description,
273		"Accessible description text here!".to_string()
274	);
275	property_subtype_test!(
276		test_prop_type_name,
277		"accessible-name",
278		Property::Name,
279		"Accessible name here!".to_string()
280	);
281	property_subtype_test!(test_prop_type_role, "accessible-role", Property::Role, Role::Invalid);
282	property_subtype_test!(
283		test_prop_type_parent,
284		"accessible-parent",
285		Property::Parent,
286		ObjectRef::from_static_str_unchecked(":420.69", "/fake/a11y/addr").into()
287	);
288	property_subtype_test!(
289		test_prop_type_table_caption,
290		"accessible-table-caption",
291		Property::TableCaption,
292		"Accessible table description here".to_string()
293	);
294	property_subtype_test!(
295		test_prop_type_table_cd,
296		"accessible-table-column-description",
297		Property::TableColumnDescription,
298		"Accessible table column description here!".to_string()
299	);
300	property_subtype_test!(
301		test_prop_type_table_ch,
302		"accessible-table-column-header",
303		Property::TableColumnHeader,
304		"Accessible table column header here!".to_string()
305	);
306	property_subtype_test!(
307		test_prop_type_table_rd,
308		"accessible-table-row-description",
309		Property::TableRowDescription,
310		"Accessible table row description here!".to_string()
311	);
312	property_subtype_test!(
313		test_prop_type_table_rh,
314		"accessible-table-row-header",
315		Property::TableRowHeader,
316		"Accessible table row header here!".to_string()
317	);
318	property_subtype_test!(
319		test_prop_help_text,
320		"accessible-help-text",
321		Property::HelpText,
322		"Accessible help text here!".to_string()
323	);
324}
325
326/// An event triggered when the visual bounds for an item have changed.
327/// This usually happens either:
328///
329/// 1. due to a re-draw on a window whose size has changed and dynamically adjusted said item's visual size, or
330/// 2. content within the bounds of said item has changed to change its size.
331#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
332pub struct BoundsChangedEvent {
333	/// The [`crate::ObjectRef`] which the event applies to.
334	pub item: ObjectRefOwned,
335}
336
337impl_event_type_properties_for_event!(BoundsChangedEvent);
338
339/// A link has been selected.
340#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
341pub struct LinkSelectedEvent {
342	/// The [`crate::ObjectRef`] which the event applies to.
343	pub item: ObjectRefOwned,
344}
345
346impl_event_type_properties_for_event!(LinkSelectedEvent);
347
348/// A state of an object has been modified.
349/// A [`State`] can be added or removed from any [`crate::ObjectRef`].
350#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
351pub struct StateChangedEvent {
352	/// The [`crate::ObjectRef`] which the event applies to.
353	pub item: ObjectRefOwned,
354	/// The state to be enabled/disabled.
355	pub state: State,
356	/// Whether the state was enabled or disabled.
357	#[serde(with = "i32_bool_conversion")]
358	pub enabled: bool,
359}
360
361impl_event_type_properties_for_event!(StateChangedEvent);
362
363mod i32_bool_conversion {
364	use serde::{Deserialize, Deserializer, Serializer};
365	/// Convert an integer flag to a boolean.
366	/// returns true if value is more than 0, otherwise false
367	pub fn deserialize<'de, D>(de: D) -> Result<bool, D::Error>
368	where
369		D: Deserializer<'de>,
370	{
371		let int: i32 = Deserialize::deserialize(de)?;
372		Ok(int > 0)
373	}
374
375	/// Convert a boolean flag to an integer.
376	/// returns 0 if false and 1 if true
377	// TODO: Will the world REALLY fall apart if we were not to use a reference here?
378	// In other words, see if &bool can be replaced with bool.
379	#[allow(clippy::trivially_copy_pass_by_ref)]
380	pub fn serialize<S>(b: &bool, ser: S) -> Result<S::Ok, S::Error>
381	where
382		S: Serializer,
383	{
384		let val: i32 = (*b).into();
385		ser.serialize_i32(val)
386	}
387}
388
389/// A child of `item` has been added or removed.
390#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
391pub struct ChildrenChangedEvent {
392	/// The [`crate::ObjectRef`] which the event applies to.
393	pub item: ObjectRefOwned,
394	/// The [`crate::Operation`] being performed.
395	pub operation: crate::Operation,
396	/// Index to remove from/add to.
397	pub index_in_parent: i32,
398	/// A reference to the new child.
399	pub child: ObjectRefOwned,
400}
401
402impl_event_type_properties_for_event!(ChildrenChangedEvent);
403
404/// A change in whether a particular item is visible or invisible (but still present).
405#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
406pub struct VisibleDataChangedEvent {
407	/// The [`crate::ObjectRef`] which the event applies to.
408	pub item: ObjectRefOwned,
409}
410
411impl_event_type_properties_for_event!(VisibleDataChangedEvent);
412
413/// The selection of this item has changed.
414/// For example: when a selection from a series of checkboxes is changed, this will change the state of the child, _and_ cause a [`SelectionChangedEvent`] on the parent.
415#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
416pub struct SelectionChangedEvent {
417	/// The [`crate::ObjectRef`] which the event applies to.
418	pub item: ObjectRefOwned,
419}
420
421impl_event_type_properties_for_event!(SelectionChangedEvent);
422
423/// An event sent when the method of selecting items in a list/set of options changes.
424/// Also see: <https://docs.gtk.org/gtk4//method.GridView.set_model.html>
425#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
426pub struct ModelChangedEvent {
427	/// The [`crate::ObjectRef`] which the event applies to.
428	pub item: ObjectRefOwned,
429}
430
431impl_event_type_properties_for_event!(ModelChangedEvent);
432
433/// An event fired when the focus has moved within a tree.
434/// The parent: `item` and descendant (may not be a direct child): `descebdant` are both referenced for convenience.
435#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
436pub struct ActiveDescendantChangedEvent {
437	/// The [`crate::ObjectRef`] which the event applies to.
438	pub item: ObjectRefOwned,
439	/// The descendant which is now the active one.
440	pub descendant: ObjectRefOwned,
441}
442
443impl_event_type_properties_for_event!(ActiveDescendantChangedEvent);
444
445/// An announcement with a defined text string and an [ARIA politeness level](https://www.w3.org/TR/2009/WD-wai-aria-20091215/states_and_properties#aria-live).
446#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
447pub struct AnnouncementEvent {
448	/// The [`crate::ObjectRef`] which the event applies to.
449	pub item: ObjectRefOwned,
450	/// Text of the announcement.
451	pub text: String,
452	/// Politeness level.
453	pub live: crate::Politeness,
454}
455
456impl_event_type_properties_for_event!(AnnouncementEvent);
457
458/// Signal that some attribute of an object (usually styling) has changed.
459/// This event does not encode _what_ has changed about the attributes, merely that they have
460/// changed.
461///
462/// To query the updated information, use `atspi_proxies::AccessibleProxy`'s `get_attribute` method.
463#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
464pub struct AttributesChangedEvent {
465	/// The [`crate::ObjectRef`] which the event applies to.
466	pub item: ObjectRefOwned,
467}
468
469impl_event_type_properties_for_event!(AttributesChangedEvent);
470
471/// A row has been added to a table.
472#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
473pub struct RowInsertedEvent {
474	/// The table which has had a row inserted.
475	pub item: ObjectRefOwned,
476}
477
478impl_event_type_properties_for_event!(RowInsertedEvent);
479
480/// A row has been moved within a table.
481#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
482pub struct RowReorderedEvent {
483	/// The table which has had a row re-ordered.
484	pub item: ObjectRefOwned,
485}
486
487impl_event_type_properties_for_event!(RowReorderedEvent);
488
489/// A row has been deleted from a table.
490#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
491pub struct RowDeletedEvent {
492	/// The table which has had a row removed.
493	pub item: ObjectRefOwned,
494}
495
496impl_event_type_properties_for_event!(RowDeletedEvent);
497
498/// A column has been added to a table.
499#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
500pub struct ColumnInsertedEvent {
501	/// The table which has had a column inserted.
502	pub item: ObjectRefOwned,
503}
504
505impl_event_type_properties_for_event!(ColumnInsertedEvent);
506
507/// A column has been re-ordered within a table.
508#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
509pub struct ColumnReorderedEvent {
510	/// The table which has had a column re-ordered.
511	pub item: ObjectRefOwned,
512}
513
514impl_event_type_properties_for_event!(ColumnReorderedEvent);
515
516/// A column has been removed from a table.
517#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
518pub struct ColumnDeletedEvent {
519	/// The table which has had a column removed.
520	pub item: ObjectRefOwned,
521}
522
523impl_event_type_properties_for_event!(ColumnDeletedEvent);
524
525/// The bounds of a piece of text have changed.
526/// This event does _not_ specify what the new bounds are; it is only to notify an AT that the bounds have changed.
527/// To query information about the new state of the selection, use `atspi_proxies::TextProxy`'s `get_bounded_ranges` function.
528#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
529pub struct TextBoundsChangedEvent {
530	/// The [`crate::ObjectRef`] which the event applies to.
531	pub item: ObjectRefOwned,
532}
533
534impl_event_type_properties_for_event!(TextBoundsChangedEvent);
535
536/// The user's selection of a piece of text has changed.
537/// This event does _not_ specify what the new selection is, nor its indecies; it is only to notify an AT that the selection has changed.
538/// To query information about the new state of the selection, use `atspi_proxies::TextProxy`'s methods.
539#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
540pub struct TextSelectionChangedEvent {
541	/// The [`crate::ObjectRef`] which the event applies to.
542	pub item: ObjectRefOwned,
543}
544
545impl_event_type_properties_for_event!(TextSelectionChangedEvent);
546
547/// Text has changed within the UI element `item`.
548#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
549pub struct TextChangedEvent {
550	/// The [`crate::ObjectRef`] which the event applies to.
551	pub item: ObjectRefOwned,
552	/// The [`crate::Operation`] being performed.
553	pub operation: crate::Operation,
554	/// starting index of the insertion/deletion
555	///
556	/// NOTE: This gives the Unicode index (not the byte index). I.e., it groups unicode sequences
557	/// into one character.
558	/// Always use the appropriate insertion methods to deal with this, i.e., do not use
559	/// [`String::insert_str`].
560	pub start_pos: i32,
561	/// length of the insertion/deletion
562	///
563	/// NOTE: This gives the unicode length (not the byte length).
564	pub length: i32,
565	/// the text being inserted/deleted
566	pub text: String,
567}
568
569impl_event_type_properties_for_event!(TextChangedEvent);
570
571/// Signal that some attributes about the text (usually styling) have changed.
572/// This event does not encode _what_ has changed about the attributes, merely that they have
573/// changed.
574#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
575pub struct TextAttributesChangedEvent {
576	/// The [`crate::ObjectRef`] which the event applies to.
577	pub item: ObjectRefOwned,
578}
579
580impl_event_type_properties_for_event!(TextAttributesChangedEvent);
581
582/// The caret of the user also known as a cursor (not to be confused with mouse pointer) has changed position.
583#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, Eq, Hash, Default)]
584pub struct TextCaretMovedEvent {
585	/// The object on which the caret has been moved on.
586	pub item: ObjectRefOwned,
587	/// New position of the caret.
588	/// NOTE: this provide the Unicode index (not the byte index) and therefore when referencing
589	/// locations in a string, you should be using the [`std::str::Chars`] iterator, and not use
590	/// anything like [`str::get`] (as this uses the byte index).
591	///
592	/// See also: [`TextChangedEvent`].
593	pub position: i32,
594}
595
596impl_event_type_properties_for_event!(TextCaretMovedEvent);
597
598impl_member_interface_registry_string_and_match_rule_for_event!(
599	PropertyChangeEvent,
600	"PropertyChange",
601	"org.a11y.atspi.Event.Object",
602	"object:property-change",
603	"type='signal',interface='org.a11y.atspi.Event.Object',member='PropertyChange'"
604);
605
606#[cfg(feature = "zbus")]
607impl MessageConversion<'_> for PropertyChangeEvent {
608	type Body<'b> = EventBody<'b>;
609
610	fn from_message_unchecked_parts(item: ObjectRef, body: DbusBody) -> Result<Self, AtspiError> {
611		let mut body = body.deserialize_unchecked::<Self::Body<'_>>()?;
612		let property: String = body.take_kind();
613		let value: Property = body.try_into()?;
614		Ok(Self { item: item.into(), property, value })
615	}
616
617	fn from_message_unchecked(msg: &zbus::Message, header: &Header) -> Result<Self, AtspiError> {
618		let item = header.try_into()?;
619		let body = msg.body();
620		Self::from_message_unchecked_parts(item, body)
621	}
622
623	fn body(&self) -> Self::Body<'_> {
624		let copy = self.clone();
625		EventBodyOwned::from(copy).into()
626	}
627}
628
629impl_member_interface_registry_string_and_match_rule_for_event!(
630	BoundsChangedEvent,
631	"BoundsChanged",
632	"org.a11y.atspi.Event.Object",
633	"object:bounds-changed",
634	"type='signal',interface='org.a11y.atspi.Event.Object',member='BoundsChanged'"
635);
636
637impl_member_interface_registry_string_and_match_rule_for_event!(
638	LinkSelectedEvent,
639	"LinkSelected",
640	"org.a11y.atspi.Event.Object",
641	"object:link-selected",
642	"type='signal',interface='org.a11y.atspi.Event.Object',member='LinkSelected'"
643);
644
645impl_member_interface_registry_string_and_match_rule_for_event!(
646	StateChangedEvent,
647	"StateChanged",
648	"org.a11y.atspi.Event.Object",
649	"object:state-changed",
650	"type='signal',interface='org.a11y.atspi.Event.Object',member='StateChanged'"
651);
652
653#[cfg(feature = "zbus")]
654impl MessageConversion<'_> for StateChangedEvent {
655	type Body<'a> = EventBody<'a>;
656
657	fn from_message_unchecked_parts(item: ObjectRef, body: DbusBody) -> Result<Self, AtspiError> {
658		let body: Self::Body<'_> = body.deserialize_unchecked()?;
659		Ok(Self { item: item.into(), state: body.kind().into(), enabled: body.detail1() > 0 })
660	}
661
662	fn from_message_unchecked(msg: &zbus::Message, header: &Header) -> Result<Self, AtspiError> {
663		let item = header.try_into()?;
664		let body = msg.body();
665		Self::from_message_unchecked_parts(item, body)
666	}
667
668	fn body(&self) -> Self::Body<'_> {
669		let copy = self.clone();
670		copy.into()
671	}
672}
673
674impl_member_interface_registry_string_and_match_rule_for_event!(
675	ChildrenChangedEvent,
676	"ChildrenChanged",
677	"org.a11y.atspi.Event.Object",
678	"object:children-changed",
679	"type='signal',interface='org.a11y.atspi.Event.Object',member='ChildrenChanged'"
680);
681
682#[cfg(feature = "zbus")]
683impl MessageConversion<'_> for ChildrenChangedEvent {
684	type Body<'a> = EventBody<'a>;
685
686	fn from_message_unchecked_parts(item: ObjectRef, body: DbusBody) -> Result<Self, AtspiError> {
687		let mut body = body.deserialize_unchecked::<Self::Body<'_>>()?;
688		Ok(Self {
689			item: item.into(),
690			operation: body.kind().parse()?,
691			index_in_parent: body.detail1(),
692			child: body.take_any_data().try_into()?,
693		})
694	}
695
696	fn from_message_unchecked(msg: &zbus::Message, header: &Header) -> Result<Self, AtspiError> {
697		let item = header.try_into()?;
698		let body = msg.body();
699		Self::from_message_unchecked_parts(item, body)
700	}
701
702	fn body(&self) -> Self::Body<'_> {
703		EventBodyOwned::from(self.clone()).into()
704	}
705}
706
707impl_member_interface_registry_string_and_match_rule_for_event!(
708	VisibleDataChangedEvent,
709	"VisibleDataChanged",
710	"org.a11y.atspi.Event.Object",
711	"object:visible-data-changed",
712	"type='signal',interface='org.a11y.atspi.Event.Object',member='VisibleDataChanged'"
713);
714
715impl_member_interface_registry_string_and_match_rule_for_event!(
716	SelectionChangedEvent,
717	"SelectionChanged",
718	"org.a11y.atspi.Event.Object",
719	"object:selection-changed",
720	"type='signal',interface='org.a11y.atspi.Event.Object',member='SelectionChanged'"
721);
722
723impl_member_interface_registry_string_and_match_rule_for_event!(
724	ModelChangedEvent,
725	"ModelChanged",
726	"org.a11y.atspi.Event.Object",
727	"object:model-changed",
728	"type='signal',interface='org.a11y.atspi.Event.Object',member='ModelChanged'"
729);
730
731impl_member_interface_registry_string_and_match_rule_for_event!(
732	ActiveDescendantChangedEvent,
733	"ActiveDescendantChanged",
734	"org.a11y.atspi.Event.Object",
735	"object:active-descendant-changed",
736	"type='signal',interface='org.a11y.atspi.Event.Object',member='ActiveDescendantChanged'"
737);
738
739#[cfg(feature = "zbus")]
740impl MessageConversion<'_> for ActiveDescendantChangedEvent {
741	type Body<'a> = EventBody<'a>;
742
743	fn from_message_unchecked_parts(item: ObjectRef, body: DbusBody) -> Result<Self, AtspiError> {
744		let mut body = body.deserialize_unchecked::<Self::Body<'_>>()?;
745		Ok(Self { item: item.into(), descendant: body.take_any_data().try_into()? })
746	}
747
748	fn from_message_unchecked(msg: &zbus::Message, header: &Header) -> Result<Self, AtspiError> {
749		let item = header.try_into()?;
750		let body = msg.body();
751		Self::from_message_unchecked_parts(item, body)
752	}
753
754	fn body(&self) -> Self::Body<'_> {
755		EventBodyOwned::from(self.clone()).into()
756	}
757}
758
759impl_member_interface_registry_string_and_match_rule_for_event!(
760	AnnouncementEvent,
761	"Announcement",
762	"org.a11y.atspi.Event.Object",
763	"object:announcement",
764	"type='signal',interface='org.a11y.atspi.Event.Object',member='Announcement'"
765);
766
767#[cfg(feature = "zbus")]
768impl MessageConversion<'_> for AnnouncementEvent {
769	type Body<'a> = EventBody<'a>;
770
771	fn from_message_unchecked_parts(item: ObjectRef, body: DbusBody) -> Result<Self, AtspiError> {
772		let mut body = body.deserialize_unchecked::<Self::Body<'_>>()?;
773		Ok(Self {
774			item: item.into(),
775			text: body
776				.take_any_data()
777				.try_into()
778				.map_err(|_| AtspiError::Conversion("text"))?,
779			live: body.detail1().try_into()?,
780		})
781	}
782
783	fn from_message_unchecked(msg: &zbus::Message, header: &Header) -> Result<Self, AtspiError> {
784		let item = header.try_into()?;
785		let body = msg.body();
786		Self::from_message_unchecked_parts(item, body)
787	}
788
789	fn body(&self) -> Self::Body<'_> {
790		EventBodyOwned::from(self.clone()).into()
791	}
792}
793
794impl_member_interface_registry_string_and_match_rule_for_event!(
795	AttributesChangedEvent,
796	"AttributesChanged",
797	"org.a11y.atspi.Event.Object",
798	"object:attributes-changed",
799	"type='signal',interface='org.a11y.atspi.Event.Object',member='AttributesChanged'"
800);
801
802impl_member_interface_registry_string_and_match_rule_for_event!(
803	RowInsertedEvent,
804	"RowInserted",
805	"org.a11y.atspi.Event.Object",
806	"object:row-inserted",
807	"type='signal',interface='org.a11y.atspi.Event.Object',member='RowInserted'"
808);
809
810impl_member_interface_registry_string_and_match_rule_for_event!(
811	RowReorderedEvent,
812	"RowReordered",
813	"org.a11y.atspi.Event.Object",
814	"object:row-reordered",
815	"type='signal',interface='org.a11y.atspi.Event.Object',member='RowReordered'"
816);
817
818impl_member_interface_registry_string_and_match_rule_for_event!(
819	RowDeletedEvent,
820	"RowDeleted",
821	"org.a11y.atspi.Event.Object",
822	"object:row-deleted",
823	"type='signal',interface='org.a11y.atspi.Event.Object',member='RowDeleted'"
824);
825
826impl_member_interface_registry_string_and_match_rule_for_event!(
827	ColumnInsertedEvent,
828	"ColumnInserted",
829	"org.a11y.atspi.Event.Object",
830	"object:column-inserted",
831	"type='signal',interface='org.a11y.atspi.Event.Object',member='ColumnInserted'"
832);
833
834impl_member_interface_registry_string_and_match_rule_for_event!(
835	ColumnReorderedEvent,
836	"ColumnReordered",
837	"org.a11y.atspi.Event.Object",
838	"object:column-reordered",
839	"type='signal',interface='org.a11y.atspi.Event.Object',member='ColumnReordered'"
840);
841
842impl_member_interface_registry_string_and_match_rule_for_event!(
843	ColumnDeletedEvent,
844	"ColumnDeleted",
845	"org.a11y.atspi.Event.Object",
846	"object:column-deleted",
847	"type='signal',interface='org.a11y.atspi.Event.Object',member='ColumnDeleted'"
848);
849
850impl_member_interface_registry_string_and_match_rule_for_event!(
851	TextBoundsChangedEvent,
852	"TextBoundsChanged",
853	"org.a11y.atspi.Event.Object",
854	"object:text-bounds-changed",
855	"type='signal',interface='org.a11y.atspi.Event.Object',member='TextBoundsChanged'"
856);
857
858impl_member_interface_registry_string_and_match_rule_for_event!(
859	TextSelectionChangedEvent,
860	"TextSelectionChanged",
861	"org.a11y.atspi.Event.Object",
862	"object:text-selection-changed",
863	"type='signal',interface='org.a11y.atspi.Event.Object',member='TextSelectionChanged'"
864);
865
866impl_member_interface_registry_string_and_match_rule_for_event!(
867	TextChangedEvent,
868	"TextChanged",
869	"org.a11y.atspi.Event.Object",
870	"object:text-changed",
871	"type='signal',interface='org.a11y.atspi.Event.Object',member='TextChanged'"
872);
873
874#[cfg(feature = "zbus")]
875impl MessageConversion<'_> for TextChangedEvent {
876	type Body<'a> = EventBody<'a>;
877
878	fn from_message_unchecked_parts(item: ObjectRef, body: DbusBody) -> Result<Self, AtspiError> {
879		let mut body = body.deserialize_unchecked::<Self::Body<'_>>()?;
880		Ok(Self {
881			item: item.into(),
882			operation: body.kind().parse()?,
883			start_pos: body.detail1(),
884			length: body.detail2(),
885			text: body.take_any_data().try_into()?,
886		})
887	}
888
889	fn from_message_unchecked(msg: &zbus::Message, header: &Header) -> Result<Self, AtspiError> {
890		let item = header.try_into()?;
891		let body = msg.body();
892		Self::from_message_unchecked_parts(item, body)
893	}
894
895	fn body(&self) -> Self::Body<'_> {
896		EventBodyOwned::from(self.clone()).into()
897	}
898}
899
900impl_member_interface_registry_string_and_match_rule_for_event!(
901	TextAttributesChangedEvent,
902	"TextAttributesChanged",
903	"org.a11y.atspi.Event.Object",
904	"object:text-attributes-changed",
905	"type='signal',interface='org.a11y.atspi.Event.Object',member='TextAttributesChanged'"
906);
907
908impl_member_interface_registry_string_and_match_rule_for_event!(
909	TextCaretMovedEvent,
910	"TextCaretMoved",
911	"org.a11y.atspi.Event.Object",
912	"object:text-caret-moved",
913	"type='signal',interface='org.a11y.atspi.Event.Object',member='TextCaretMoved'"
914);
915
916#[cfg(feature = "zbus")]
917impl MessageConversion<'_> for TextCaretMovedEvent {
918	type Body<'a> = EventBody<'a>;
919
920	fn from_message_unchecked_parts(item: ObjectRef, body: DbusBody) -> Result<Self, AtspiError> {
921		let body = body.deserialize_unchecked::<Self::Body<'_>>()?;
922		Ok(Self { item: item.into(), position: body.detail1() })
923	}
924
925	fn from_message_unchecked(msg: &zbus::Message, header: &Header) -> Result<Self, AtspiError> {
926		let item = header.try_into()?;
927		let body = msg.body();
928		Self::from_message_unchecked_parts(item, body)
929	}
930
931	fn body(&self) -> Self::Body<'_> {
932		EventBodyOwned::from(self.clone()).into()
933	}
934}
935
936event_test_cases!(PropertyChangeEvent);
937impl_to_dbus_message!(PropertyChangeEvent);
938impl_from_dbus_message!(PropertyChangeEvent);
939impl_event_properties!(PropertyChangeEvent);
940
941impl From<PropertyChangeEvent> for EventBodyOwned {
942	fn from(event: PropertyChangeEvent) -> Self {
943		EventBodyOwned { kind: event.property, any_data: event.value.into(), ..Default::default() }
944	}
945}
946
947impl From<&PropertyChangeEvent> for EventBodyOwned {
948	fn from(event: &PropertyChangeEvent) -> Self {
949		EventBodyOwned {
950			kind: event.property.clone(),
951			any_data: event.value.clone().into(),
952			..Default::default()
953		}
954	}
955}
956
957impl From<PropertyChangeEvent> for EventBody<'_> {
958	fn from(event: PropertyChangeEvent) -> Self {
959		EventBodyOwned::from(event).into()
960	}
961}
962
963event_test_cases!(BoundsChangedEvent);
964impl_to_dbus_message!(BoundsChangedEvent);
965impl_from_dbus_message!(BoundsChangedEvent);
966impl_event_properties!(BoundsChangedEvent);
967impl_from_object_ref!(BoundsChangedEvent);
968
969event_test_cases!(LinkSelectedEvent);
970impl_to_dbus_message!(LinkSelectedEvent);
971impl_from_dbus_message!(LinkSelectedEvent);
972impl_event_properties!(LinkSelectedEvent);
973impl_from_object_ref!(LinkSelectedEvent);
974
975event_test_cases!(StateChangedEvent);
976impl_to_dbus_message!(StateChangedEvent);
977impl_from_dbus_message!(StateChangedEvent);
978impl_event_properties!(StateChangedEvent);
979
980impl From<StateChangedEvent> for EventBodyOwned {
981	fn from(event: StateChangedEvent) -> Self {
982		EventBodyOwned {
983			kind: event.state.to_string(),
984			detail1: event.enabled.into(),
985			..Default::default()
986		}
987	}
988}
989
990impl From<&StateChangedEvent> for EventBodyOwned {
991	fn from(event: &StateChangedEvent) -> Self {
992		EventBodyOwned {
993			kind: event.state.to_string(),
994			detail1: event.enabled.into(),
995			..Default::default()
996		}
997	}
998}
999
1000impl From<StateChangedEvent> for EventBody<'_> {
1001	fn from(event: StateChangedEvent) -> Self {
1002		EventBodyOwned::from(event).into()
1003	}
1004}
1005
1006event_test_cases!(ChildrenChangedEvent);
1007impl_to_dbus_message!(ChildrenChangedEvent);
1008impl_from_dbus_message!(ChildrenChangedEvent);
1009impl_event_properties!(ChildrenChangedEvent);
1010
1011impl From<ChildrenChangedEvent> for EventBodyOwned {
1012	fn from(event: ChildrenChangedEvent) -> Self {
1013		EventBodyOwned {
1014			kind: event.operation.to_string(),
1015			detail1: event.index_in_parent,
1016
1017			// `OwnedValue` is constructed from the `crate::ObjectRef`
1018			// Only way to fail is to convert a `Fd` into an `OwnedValue`.
1019			// Therefore, this is safe.
1020			any_data: Value::from(event.child)
1021				.try_into()
1022				.expect("Failed to convert child to OwnedValue"),
1023			..Default::default()
1024		}
1025	}
1026}
1027
1028impl From<&ChildrenChangedEvent> for EventBodyOwned {
1029	fn from(event: &ChildrenChangedEvent) -> Self {
1030		EventBodyOwned {
1031			kind: event.operation.to_string(),
1032			detail1: event.index_in_parent,
1033			detail2: i32::default(),
1034			// `OwnedValue` is constructed from the `crate::ObjectRef`
1035			// Only path to fail is to convert a `Fd` into an `OwnedValue`.
1036			// Therefore, this is safe.
1037			any_data: Value::from(event.child.clone())
1038				.try_into()
1039				.expect("ObjectRef should convert to OwnedValue without error"),
1040			properties: super::event_body::Properties,
1041		}
1042	}
1043}
1044
1045impl From<ChildrenChangedEvent> for EventBody<'_> {
1046	fn from(event: ChildrenChangedEvent) -> Self {
1047		EventBodyOwned::from(event).into()
1048	}
1049}
1050
1051event_test_cases!(VisibleDataChangedEvent);
1052impl_to_dbus_message!(VisibleDataChangedEvent);
1053impl_from_dbus_message!(VisibleDataChangedEvent);
1054impl_event_properties!(VisibleDataChangedEvent);
1055impl_from_object_ref!(VisibleDataChangedEvent);
1056
1057event_test_cases!(SelectionChangedEvent);
1058impl_to_dbus_message!(SelectionChangedEvent);
1059impl_from_dbus_message!(SelectionChangedEvent);
1060impl_event_properties!(SelectionChangedEvent);
1061impl_from_object_ref!(SelectionChangedEvent);
1062
1063event_test_cases!(ModelChangedEvent);
1064impl_to_dbus_message!(ModelChangedEvent);
1065impl_from_dbus_message!(ModelChangedEvent);
1066impl_event_properties!(ModelChangedEvent);
1067impl_from_object_ref!(ModelChangedEvent);
1068
1069event_test_cases!(ActiveDescendantChangedEvent);
1070impl_to_dbus_message!(ActiveDescendantChangedEvent);
1071impl_from_dbus_message!(ActiveDescendantChangedEvent);
1072impl_event_properties!(ActiveDescendantChangedEvent);
1073impl From<ActiveDescendantChangedEvent> for EventBodyOwned {
1074	fn from(event: ActiveDescendantChangedEvent) -> Self {
1075		EventBodyOwned {
1076			// `OwnedValue` is constructed from the `crate::ObjectRef`
1077			// Only way to fail is to convert a Fd into an `OwnedValue`.
1078			// Therefore, this is safe.
1079			any_data: Value::from(event.descendant)
1080				.try_to_owned()
1081				.expect("Failed to convert descendant to OwnedValue"),
1082			..Default::default()
1083		}
1084	}
1085}
1086
1087event_test_cases!(AnnouncementEvent);
1088impl_to_dbus_message!(AnnouncementEvent);
1089impl_from_dbus_message!(AnnouncementEvent);
1090impl_event_properties!(AnnouncementEvent);
1091impl From<AnnouncementEvent> for EventBodyOwned {
1092	fn from(event: AnnouncementEvent) -> Self {
1093		EventBodyOwned {
1094			detail1: event.live as i32,
1095			// `OwnedValue` is constructed from `String`
1096			// Therefore, this is safe.
1097			any_data: Value::from(event.text)
1098				.try_to_owned()
1099				.expect("Failed to convert text to OwnedValue"),
1100			..Default::default()
1101		}
1102	}
1103}
1104
1105event_test_cases!(AttributesChangedEvent);
1106impl_to_dbus_message!(AttributesChangedEvent);
1107impl_from_dbus_message!(AttributesChangedEvent);
1108impl_event_properties!(AttributesChangedEvent);
1109impl_from_object_ref!(AttributesChangedEvent);
1110
1111event_test_cases!(RowInsertedEvent);
1112impl_to_dbus_message!(RowInsertedEvent);
1113impl_from_dbus_message!(RowInsertedEvent);
1114impl_event_properties!(RowInsertedEvent);
1115impl_from_object_ref!(RowInsertedEvent);
1116
1117event_test_cases!(RowReorderedEvent);
1118impl_to_dbus_message!(RowReorderedEvent);
1119impl_from_dbus_message!(RowReorderedEvent);
1120impl_event_properties!(RowReorderedEvent);
1121impl_from_object_ref!(RowReorderedEvent);
1122
1123event_test_cases!(RowDeletedEvent);
1124impl_to_dbus_message!(RowDeletedEvent);
1125impl_from_dbus_message!(RowDeletedEvent);
1126impl_event_properties!(RowDeletedEvent);
1127impl_from_object_ref!(RowDeletedEvent);
1128
1129event_test_cases!(ColumnInsertedEvent);
1130impl_to_dbus_message!(ColumnInsertedEvent);
1131impl_from_dbus_message!(ColumnInsertedEvent);
1132impl_event_properties!(ColumnInsertedEvent);
1133impl_from_object_ref!(ColumnInsertedEvent);
1134
1135event_test_cases!(ColumnReorderedEvent);
1136impl_to_dbus_message!(ColumnReorderedEvent);
1137impl_from_dbus_message!(ColumnReorderedEvent);
1138impl_event_properties!(ColumnReorderedEvent);
1139impl_from_object_ref!(ColumnReorderedEvent);
1140
1141event_test_cases!(ColumnDeletedEvent);
1142impl_to_dbus_message!(ColumnDeletedEvent);
1143impl_from_dbus_message!(ColumnDeletedEvent);
1144impl_event_properties!(ColumnDeletedEvent);
1145impl_from_object_ref!(ColumnDeletedEvent);
1146
1147event_test_cases!(TextBoundsChangedEvent);
1148impl_to_dbus_message!(TextBoundsChangedEvent);
1149impl_from_dbus_message!(TextBoundsChangedEvent);
1150impl_event_properties!(TextBoundsChangedEvent);
1151impl_from_object_ref!(TextBoundsChangedEvent);
1152
1153event_test_cases!(TextSelectionChangedEvent);
1154impl_to_dbus_message!(TextSelectionChangedEvent);
1155impl_from_dbus_message!(TextSelectionChangedEvent);
1156impl_event_properties!(TextSelectionChangedEvent);
1157impl_from_object_ref!(TextSelectionChangedEvent);
1158
1159event_test_cases!(TextChangedEvent);
1160
1161assert_impl_all!(TextChangedEvent:Clone,std::fmt::Debug,serde::Serialize,serde::Deserialize<'static>,Default,PartialEq,Eq,std::hash::Hash,crate::EventProperties,crate::EventTypeProperties);
1162#[cfg(feature = "zbus")]
1163assert_impl_all!(zbus::Message:TryFrom<TextChangedEvent>);
1164
1165impl_to_dbus_message!(TextChangedEvent);
1166impl_from_dbus_message!(TextChangedEvent);
1167impl_event_properties!(TextChangedEvent);
1168impl From<TextChangedEvent> for EventBodyOwned {
1169	fn from(event: TextChangedEvent) -> Self {
1170		EventBodyOwned {
1171			kind: event.operation.to_string(),
1172			detail1: event.start_pos,
1173			detail2: event.length,
1174			// `OwnedValue` is constructed from a `String`
1175			// Therefore, this is safe.
1176			any_data: Value::from(event.text)
1177				.try_to_owned()
1178				.expect("Failed to convert child to OwnedValue"),
1179			..Default::default()
1180		}
1181	}
1182}
1183
1184event_test_cases!(TextAttributesChangedEvent);
1185impl_to_dbus_message!(TextAttributesChangedEvent);
1186impl_from_dbus_message!(TextAttributesChangedEvent);
1187impl_event_properties!(TextAttributesChangedEvent);
1188impl_from_object_ref!(TextAttributesChangedEvent);
1189
1190event_test_cases!(TextCaretMovedEvent);
1191impl_to_dbus_message!(TextCaretMovedEvent);
1192impl_from_dbus_message!(TextCaretMovedEvent);
1193impl_event_properties!(TextCaretMovedEvent);
1194impl From<TextCaretMovedEvent> for EventBodyOwned {
1195	fn from(event: TextCaretMovedEvent) -> Self {
1196		EventBodyOwned { detail1: event.position, ..Default::default() }
1197	}
1198}
1199
1200impl_msg_conversion_ext_for_target_type!(PropertyChangeEvent);
1201impl_msg_conversion_ext_for_target_type!(BoundsChangedEvent);
1202impl_msg_conversion_ext_for_target_type!(LinkSelectedEvent);
1203impl_msg_conversion_ext_for_target_type!(StateChangedEvent);
1204impl_msg_conversion_ext_for_target_type!(ChildrenChangedEvent);
1205impl_msg_conversion_ext_for_target_type!(VisibleDataChangedEvent);
1206impl_msg_conversion_ext_for_target_type!(SelectionChangedEvent);
1207impl_msg_conversion_ext_for_target_type!(ModelChangedEvent);
1208impl_msg_conversion_ext_for_target_type!(ActiveDescendantChangedEvent);
1209impl_msg_conversion_ext_for_target_type!(AnnouncementEvent);
1210impl_msg_conversion_ext_for_target_type!(AttributesChangedEvent);
1211impl_msg_conversion_ext_for_target_type!(RowInsertedEvent);
1212impl_msg_conversion_ext_for_target_type!(RowReorderedEvent);
1213impl_msg_conversion_ext_for_target_type!(RowDeletedEvent);
1214impl_msg_conversion_ext_for_target_type!(ColumnInsertedEvent);
1215impl_msg_conversion_ext_for_target_type!(ColumnReorderedEvent);
1216impl_msg_conversion_ext_for_target_type!(ColumnDeletedEvent);
1217impl_msg_conversion_ext_for_target_type!(TextBoundsChangedEvent);
1218impl_msg_conversion_ext_for_target_type!(TextSelectionChangedEvent);
1219impl_msg_conversion_ext_for_target_type!(TextChangedEvent);
1220impl_msg_conversion_ext_for_target_type!(TextAttributesChangedEvent);
1221impl_msg_conversion_ext_for_target_type!(TextCaretMovedEvent);
1222
1223impl_msg_conversion_for_types_built_from_object_ref!(BoundsChangedEvent);
1224impl_msg_conversion_for_types_built_from_object_ref!(LinkSelectedEvent);
1225impl_msg_conversion_for_types_built_from_object_ref!(VisibleDataChangedEvent);
1226impl_msg_conversion_for_types_built_from_object_ref!(SelectionChangedEvent);
1227impl_msg_conversion_for_types_built_from_object_ref!(ModelChangedEvent);
1228impl_msg_conversion_for_types_built_from_object_ref!(AttributesChangedEvent);
1229impl_msg_conversion_for_types_built_from_object_ref!(RowInsertedEvent);
1230impl_msg_conversion_for_types_built_from_object_ref!(RowReorderedEvent);
1231impl_msg_conversion_for_types_built_from_object_ref!(RowDeletedEvent);
1232impl_msg_conversion_for_types_built_from_object_ref!(ColumnInsertedEvent);
1233impl_msg_conversion_for_types_built_from_object_ref!(ColumnReorderedEvent);
1234impl_msg_conversion_for_types_built_from_object_ref!(ColumnDeletedEvent);
1235impl_msg_conversion_for_types_built_from_object_ref!(TextBoundsChangedEvent);
1236impl_msg_conversion_for_types_built_from_object_ref!(TextSelectionChangedEvent);
1237impl_msg_conversion_for_types_built_from_object_ref!(TextAttributesChangedEvent);