Skip to main content

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}