Skip to main content

gio/
dbus.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::num::NonZeroU32;
4
5use glib::translate::*;
6
7use crate::{BusNameOwnerFlags, BusNameWatcherFlags, BusType, DBusConnection, ffi};
8
9#[derive(Debug, Eq, PartialEq)]
10pub struct OwnerId(NonZeroU32);
11#[derive(Debug, Eq, PartialEq)]
12pub struct WatcherId(NonZeroU32);
13
14fn own_closure<F>(f: F) -> glib::Closure
15where
16    F: Fn(DBusConnection, &str) + 'static,
17{
18    glib::Closure::new_local(move |args| {
19        let conn = args[0].get::<DBusConnection>().unwrap();
20        let name = args[1].get::<&str>().unwrap();
21        f(conn, name);
22        None
23    })
24}
25
26fn appeared_closure<F>(f: F) -> glib::Closure
27where
28    F: Fn(DBusConnection, &str, &str) + 'static,
29{
30    glib::Closure::new_local(move |args| {
31        let conn = args[0].get::<DBusConnection>().unwrap();
32        let name = args[1].get::<&str>().unwrap();
33        let name_owner = args[2].get::<&str>().unwrap();
34        f(conn, name, name_owner);
35        None
36    })
37}
38
39fn vanished_closure<F>(f: F) -> glib::Closure
40where
41    F: Fn(DBusConnection, &str) + 'static,
42{
43    glib::Closure::new_local(move |args| {
44        let conn = args[0].get::<DBusConnection>().unwrap();
45        let name = args[1].get::<&str>().unwrap();
46        f(conn, name);
47        None
48    })
49}
50
51/// Like `bus_own_name()` but takes a [`DBusConnection`][crate::DBusConnection] instead
52/// of a [`BusType`][crate::BusType].
53/// ## `connection`
54/// a bus connection
55/// ## `name`
56/// the well-known name to own
57/// ## `flags`
58/// a set of flags with ownership options
59/// ## `name_acquired_handler`
60/// handler to invoke when
61///   @name is acquired, or `NULL` to ignore
62/// ## `name_lost_handler`
63/// handler to invoke when @name
64///   is lost, or `NULL` to ignore
65///
66/// # Returns
67///
68/// an identifier (never 0) that can be used with
69///   `bus_unown_name()` to stop owning the name
70#[doc(alias = "g_bus_own_name_on_connection_with_closures")]
71pub fn bus_own_name_on_connection<NameAcquired, NameLost>(
72    connection: &DBusConnection,
73    name: &str,
74    flags: BusNameOwnerFlags,
75    name_acquired: NameAcquired,
76    name_lost: NameLost,
77) -> OwnerId
78where
79    NameAcquired: Fn(DBusConnection, &str) + 'static,
80    NameLost: Fn(DBusConnection, &str) + 'static,
81{
82    unsafe {
83        let id = ffi::g_bus_own_name_on_connection_with_closures(
84            connection.to_glib_none().0,
85            name.to_glib_none().0,
86            flags.into_glib(),
87            own_closure(name_acquired).to_glib_none().0,
88            own_closure(name_lost).to_glib_none().0,
89        );
90        OwnerId(NonZeroU32::new_unchecked(id))
91    }
92}
93
94///  only the first call
95/// will work.
96///
97/// Another guarantee is that invocations of @name_acquired_handler
98/// and @name_lost_handler are guaranteed to alternate; that
99/// is, if @name_acquired_handler is invoked then you are
100/// guaranteed that the next time one of the handlers is invoked, it
101/// will be @name_lost_handler. The reverse is also true.
102///
103/// If you plan on exporting objects (using, for example,
104/// [`DBusConnection::register_object()`][crate::DBusConnection::register_object()]), note that it is generally too late
105/// to export the objects in @name_acquired_handler. Instead, you can do this
106/// in @bus_acquired_handler since you are guaranteed that this will run
107/// before @name is requested from the bus.
108///
109/// This behavior makes it very simple to write applications that want
110/// to [own names](dbus-name-owning.html#d-bus-name-owning) and export objects.
111/// Simply register objects to be exported in @bus_acquired_handler and
112/// unregister the objects (if any) in @name_lost_handler.
113/// ## `bus_type`
114/// the type of bus to own a name on
115/// ## `name`
116/// the well-known name to own
117/// ## `flags`
118/// a set of flags with ownership options
119/// ## `bus_acquired_handler`
120/// handler to invoke when
121///   connected to the bus of type @bus_type, or `NULL` to ignore
122/// ## `name_acquired_handler`
123/// handler to invoke when
124///   @name is acquired, or `NULL` to ignore
125/// ## `name_lost_handler`
126/// handler to invoke when @name
127///   is lost, or `NULL` to ignore
128///
129/// # Returns
130///
131/// an identifier (never 0) that can be used with
132///   `bus_unown_name()` to stop owning the name
133#[doc(alias = "g_bus_own_name_with_closures")]
134pub fn bus_own_name<BusAcquired, NameAcquired, NameLost>(
135    bus_type: BusType,
136    name: &str,
137    flags: BusNameOwnerFlags,
138    bus_acquired: BusAcquired,
139    name_acquired: NameAcquired,
140    name_lost: NameLost,
141) -> OwnerId
142where
143    BusAcquired: Fn(DBusConnection, &str) + 'static,
144    NameAcquired: Fn(DBusConnection, &str) + 'static,
145    NameLost: Fn(Option<DBusConnection>, &str) + 'static,
146{
147    unsafe {
148        let id = ffi::g_bus_own_name_with_closures(
149            bus_type.into_glib(),
150            name.to_glib_none().0,
151            flags.into_glib(),
152            own_closure(bus_acquired).to_glib_none().0,
153            own_closure(name_acquired).to_glib_none().0,
154            glib::Closure::new_local(move |args| {
155                let conn = args[0].get::<Option<DBusConnection>>().unwrap();
156                let name = args[1].get::<&str>().unwrap();
157                name_lost(conn, name);
158                None
159            })
160            .to_glib_none()
161            .0,
162        );
163        OwnerId(NonZeroU32::new_unchecked(id))
164    }
165}
166
167#[doc(alias = "g_bus_unown_name")]
168pub fn bus_unown_name(owner_id: OwnerId) {
169    unsafe {
170        ffi::g_bus_unown_name(owner_id.0.into());
171    }
172}
173
174/// Like g_bus_watch_name() but takes a #GDBusConnection instead of a
175/// #GBusType.
176/// ## `connection`
177/// A #GDBusConnection.
178/// ## `name`
179/// The name (well-known or unique) to watch.
180/// ## `flags`
181/// Flags from the #GBusNameWatcherFlags enumeration.
182/// ## `name_appeared_handler`
183/// Handler to invoke when
184///   @name is known to exist or [`None`].
185/// ## `name_vanished_handler`
186/// Handler to invoke when
187///   @name is known to not exist or [`None`].
188///
189/// # Returns
190///
191/// An identifier (never 0) that can be used with
192/// g_bus_unwatch_name() to stop watching the name.
193#[doc(alias = "g_bus_watch_name_on_connection_with_closures")]
194pub fn bus_watch_name_on_connection<NameAppeared, NameVanished>(
195    connection: &DBusConnection,
196    name: &str,
197    flags: BusNameWatcherFlags,
198    name_appeared: NameAppeared,
199    name_vanished: NameVanished,
200) -> WatcherId
201where
202    NameAppeared: Fn(DBusConnection, &str, &str) + 'static,
203    NameVanished: Fn(DBusConnection, &str) + 'static,
204{
205    unsafe {
206        let id = ffi::g_bus_watch_name_on_connection_with_closures(
207            connection.to_glib_none().0,
208            name.to_glib_none().0,
209            flags.into_glib(),
210            appeared_closure(name_appeared).to_glib_none().0,
211            vanished_closure(name_vanished).to_glib_none().0,
212        );
213        WatcherId(NonZeroU32::new_unchecked(id))
214    }
215}
216
217/// Starts watching @name on the bus specified by @bus_type and calls
218/// @name_appeared_handler and @name_vanished_handler when the name is
219/// known to have an owner respectively known to lose its
220/// owner. Callbacks will be invoked in the thread-default main context
221/// (see [`glib::MainContext::push_thread_default()`][crate::glib::MainContext::push_thread_default()])
222/// of the thread you are calling this function from.
223///
224/// You are guaranteed that one of the handlers will be invoked after
225/// calling this function. When you are done watching the name, just
226/// call g_bus_unwatch_name() with the watcher id this function
227/// returns.
228///
229/// If the name vanishes or appears (for example the application owning
230/// the name could restart), the handlers are also invoked. If the
231/// #GDBusConnection that is used for watching the name disconnects, then
232/// @name_vanished_handler is invoked since it is no longer
233/// possible to access the name.
234///
235/// Another guarantee is that invocations of @name_appeared_handler
236/// and @name_vanished_handler are guaranteed to alternate; that
237/// is, if @name_appeared_handler is invoked then you are
238/// guaranteed that the next time one of the handlers is invoked, it
239/// will be @name_vanished_handler. The reverse is also true.
240///
241/// This behavior makes it very simple to write applications that want
242/// to take action when a certain [name exists](dbus-name-watching.html#d-bus-name-watching).
243/// Basically, the application should create object proxies in
244/// @name_appeared_handler and destroy them again (if any) in
245/// @name_vanished_handler.
246/// ## `bus_type`
247/// The type of bus to watch a name on.
248/// ## `name`
249/// The name (well-known or unique) to watch.
250/// ## `flags`
251/// Flags from the #GBusNameWatcherFlags enumeration.
252/// ## `name_appeared_handler`
253/// Handler to invoke when
254///   @name is known to exist or [`None`].
255/// ## `name_vanished_handler`
256/// Handler to invoke when
257///   @name is known to not exist or [`None`].
258///
259/// # Returns
260///
261/// An identifier (never 0) that can be used with
262/// g_bus_unwatch_name() to stop watching the name.
263#[doc(alias = "g_bus_watch_name_with_closures")]
264pub fn bus_watch_name<NameAppeared, NameVanished>(
265    bus_type: BusType,
266    name: &str,
267    flags: BusNameWatcherFlags,
268    name_appeared: NameAppeared,
269    name_vanished: NameVanished,
270) -> WatcherId
271where
272    NameAppeared: Fn(DBusConnection, &str, &str) + 'static,
273    NameVanished: Fn(DBusConnection, &str) + 'static,
274{
275    unsafe {
276        let id = ffi::g_bus_watch_name_with_closures(
277            bus_type.into_glib(),
278            name.to_glib_none().0,
279            flags.into_glib(),
280            appeared_closure(name_appeared).to_glib_none().0,
281            vanished_closure(name_vanished).to_glib_none().0,
282        );
283        WatcherId(NonZeroU32::new_unchecked(id))
284    }
285}
286
287#[doc(alias = "g_bus_unwatch_name")]
288pub fn bus_unwatch_name(watcher_id: WatcherId) {
289    unsafe {
290        ffi::g_bus_unwatch_name(watcher_id.0.into());
291    }
292}