tokio_dbus_runtime/name_owner.rs
1use tokio_dbus::org_freedesktop_dbus;
2
3use crate::{Result, SignalMessage};
4
5/// The `org.freedesktop.DBus.NameOwnerChanged` signal, which the bus emits
6/// when the ownership of a well known name changes.
7///
8/// Register interest with [`Connection::watch_name`], then decode incoming
9/// signals with [`decode()`].
10///
11/// [`Connection::watch_name`]: crate::Connection::watch_name
12/// [`decode()`]: Self::decode
13#[derive(Debug, Clone, PartialEq, Eq)]
14#[non_exhaustive]
15pub struct NameOwnerChanged {
16 /// The name whose ownership changed.
17 pub name: String,
18 /// The unique name of the previous owner, or `None` when the name was not
19 /// owned before.
20 pub old_owner: Option<String>,
21 /// The unique name of the new owner, or `None` when the name went away.
22 pub new_owner: Option<String>,
23}
24
25impl NameOwnerChanged {
26 /// The member name of this signal.
27 pub const MEMBER: &'static str = "NameOwnerChanged";
28
29 /// Decode a `NameOwnerChanged` signal.
30 ///
31 /// Returns `None` when the message is some other signal, so this can be
32 /// applied to everything which arrives without inspecting the message
33 /// first. The empty owner strings the bus uses for "no owner" are decoded
34 /// into `None`.
35 ///
36 /// # Examples
37 ///
38 /// ```no_run
39 /// use tokio_dbus_runtime::{Connection, Incoming, NameOwnerChanged};
40 ///
41 /// # #[tokio::main] async fn main() -> tokio_dbus_runtime::Result<()> {
42 /// let mut c = Connection::session_bus().await?;
43 /// c.watch_name("org.kde.StatusNotifierWatcher").await?;
44 ///
45 /// loop {
46 /// if let Incoming::Signal(message) = c.next().await? {
47 /// if let Some(changed) = NameOwnerChanged::decode(&message)? {
48 /// if changed.new_owner.is_some() {
49 /// // The watcher is back, register with it again.
50 /// }
51 /// }
52 /// }
53 /// }
54 /// # }
55 /// ```
56 pub fn decode(message: &SignalMessage) -> Result<Option<Self>> {
57 if message.interface() != Some(org_freedesktop_dbus::INTERFACE)
58 || message.member() != Self::MEMBER
59 || message.sender() != Some(org_freedesktop_dbus::DESTINATION)
60 {
61 return Ok(None);
62 }
63
64 let mut body = message.body();
65 let name = body.read::<str>()?.to_owned();
66 let old_owner = body.read::<str>()?;
67 let new_owner = body.read::<str>()?;
68
69 Ok(Some(Self {
70 name,
71 old_owner: (!old_owner.is_empty()).then(|| old_owner.to_owned()),
72 new_owner: (!new_owner.is_empty()).then(|| new_owner.to_owned()),
73 }))
74 }
75
76 /// The match rule which selects this signal for `name`, as passed to
77 /// [`Connection::add_match`].
78 ///
79 /// [`Connection::add_match`]: crate::Connection::add_match
80 ///
81 /// # Examples
82 ///
83 /// ```
84 /// use tokio_dbus_runtime::NameOwnerChanged;
85 ///
86 /// assert_eq!(
87 /// NameOwnerChanged::rule("org.kde.StatusNotifierWatcher"),
88 /// "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='org.kde.StatusNotifierWatcher'",
89 /// );
90 /// ```
91 pub fn rule(name: &str) -> String {
92 format!(
93 "type='signal',sender='{bus}',interface='{bus}',member='{member}',arg0='{name}'",
94 bus = org_freedesktop_dbus::DESTINATION,
95 member = Self::MEMBER,
96 )
97 }
98}