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::{ffi, BusNameOwnerFlags, BusNameWatcherFlags, BusType, DBusConnection};
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 g_bus_own_name() but takes a #GDBusConnection instead of a
52/// #GBusType.
53/// ## `connection`
54/// a #GDBusConnection
55/// ## `name`
56/// the well-known name to own
57/// ## `flags`
58/// a set of flags from the #GBusNameOwnerFlags enumeration
59/// ## `name_acquired_handler`
60/// handler to invoke when
61///   @name is acquired or [`None`]
62/// ## `name_lost_handler`
63/// handler to invoke when @name
64///   is lost or [`None`]
65///
66/// # Returns
67///
68/// an identifier (never 0) that can be used with
69///     g_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/// Starts acquiring @name on the bus specified by @bus_type and calls
95/// @name_acquired_handler and @name_lost_handler when the name is
96/// acquired respectively lost. Callbacks will be invoked in the thread-default
97/// main context (see [`glib::MainContext::push_thread_default()`][crate::glib::MainContext::push_thread_default()])
98/// of the thread you are calling this function from.
99///
100/// You are guaranteed that one of the @name_acquired_handler and @name_lost_handler
101/// callbacks will be invoked after calling this function - there are three
102/// possible cases:
103///
104/// - @name_lost_handler with a [`None`] connection (if a connection to the bus
105///   can't be made).
106///
107/// - @bus_acquired_handler then @name_lost_handler (if the name can't be
108///   obtained)
109///
110/// - @bus_acquired_handler then @name_acquired_handler (if the name was
111///   obtained).
112///
113/// When you are done owning the name, just call g_bus_unown_name()
114/// with the owner id this function returns.
115///
116/// If the name is acquired or lost (for example another application
117/// could acquire the name if you allow replacement or the application
118/// currently owning the name exits), the handlers are also invoked.
119/// If the #GDBusConnection that is used for attempting to own the name
120/// closes, then @name_lost_handler is invoked since it is no longer
121/// possible for other processes to access the process.
122///
123/// You cannot use g_bus_own_name() several times for the same name (unless
124/// interleaved with calls to g_bus_unown_name()) - only the first call
125/// will work.
126///
127/// Another guarantee is that invocations of @name_acquired_handler
128/// and @name_lost_handler are guaranteed to alternate; that
129/// is, if @name_acquired_handler is invoked then you are
130/// guaranteed that the next time one of the handlers is invoked, it
131/// will be @name_lost_handler. The reverse is also true.
132///
133/// If you plan on exporting objects (using e.g.
134/// g_dbus_connection_register_object()), note that it is generally too late
135/// to export the objects in @name_acquired_handler. Instead, you can do this
136/// in @bus_acquired_handler since you are guaranteed that this will run
137/// before @name is requested from the bus.
138///
139/// This behavior makes it very simple to write applications that wants
140/// to [own names](dbus-name-owning.html#d-bus-name-owning) and export objects.
141/// Simply register objects to be exported in @bus_acquired_handler and
142/// unregister the objects (if any) in @name_lost_handler.
143/// ## `bus_type`
144/// the type of bus to own a name on
145/// ## `name`
146/// the well-known name to own
147/// ## `flags`
148/// a set of flags from the #GBusNameOwnerFlags enumeration
149/// ## `bus_acquired_handler`
150/// handler to invoke when
151///   connected to the bus of type @bus_type or [`None`]
152/// ## `name_acquired_handler`
153/// handler to invoke when
154///   @name is acquired or [`None`]
155/// ## `name_lost_handler`
156/// handler to invoke when @name
157///   is lost or [`None`]
158///
159/// # Returns
160///
161/// an identifier (never 0) that can be used with
162///     g_bus_unown_name() to stop owning the name.
163#[doc(alias = "g_bus_own_name_with_closures")]
164pub fn bus_own_name<BusAcquired, NameAcquired, NameLost>(
165    bus_type: BusType,
166    name: &str,
167    flags: BusNameOwnerFlags,
168    bus_acquired: BusAcquired,
169    name_acquired: NameAcquired,
170    name_lost: NameLost,
171) -> OwnerId
172where
173    BusAcquired: Fn(DBusConnection, &str) + 'static,
174    NameAcquired: Fn(DBusConnection, &str) + 'static,
175    NameLost: Fn(Option<DBusConnection>, &str) + 'static,
176{
177    unsafe {
178        let id = ffi::g_bus_own_name_with_closures(
179            bus_type.into_glib(),
180            name.to_glib_none().0,
181            flags.into_glib(),
182            own_closure(bus_acquired).to_glib_none().0,
183            own_closure(name_acquired).to_glib_none().0,
184            glib::Closure::new_local(move |args| {
185                let conn = args[0].get::<Option<DBusConnection>>().unwrap();
186                let name = args[1].get::<&str>().unwrap();
187                name_lost(conn, name);
188                None
189            })
190            .to_glib_none()
191            .0,
192        );
193        OwnerId(NonZeroU32::new_unchecked(id))
194    }
195}
196
197#[doc(alias = "g_bus_unown_name")]
198pub fn bus_unown_name(owner_id: OwnerId) {
199    unsafe {
200        ffi::g_bus_unown_name(owner_id.0.into());
201    }
202}
203
204/// Like g_bus_watch_name() but takes a #GDBusConnection instead of a
205/// #GBusType.
206/// ## `connection`
207/// A #GDBusConnection.
208/// ## `name`
209/// The name (well-known or unique) to watch.
210/// ## `flags`
211/// Flags from the #GBusNameWatcherFlags enumeration.
212/// ## `name_appeared_handler`
213/// Handler to invoke when
214///   @name is known to exist or [`None`].
215/// ## `name_vanished_handler`
216/// Handler to invoke when
217///   @name is known to not exist or [`None`].
218///
219/// # Returns
220///
221/// An identifier (never 0) that can be used with
222/// g_bus_unwatch_name() to stop watching the name.
223#[doc(alias = "g_bus_watch_name_on_connection_with_closures")]
224pub fn bus_watch_name_on_connection<NameAppeared, NameVanished>(
225    connection: &DBusConnection,
226    name: &str,
227    flags: BusNameWatcherFlags,
228    name_appeared: NameAppeared,
229    name_vanished: NameVanished,
230) -> WatcherId
231where
232    NameAppeared: Fn(DBusConnection, &str, &str) + 'static,
233    NameVanished: Fn(DBusConnection, &str) + 'static,
234{
235    unsafe {
236        let id = ffi::g_bus_watch_name_on_connection_with_closures(
237            connection.to_glib_none().0,
238            name.to_glib_none().0,
239            flags.into_glib(),
240            appeared_closure(name_appeared).to_glib_none().0,
241            vanished_closure(name_vanished).to_glib_none().0,
242        );
243        WatcherId(NonZeroU32::new_unchecked(id))
244    }
245}
246
247/// Starts watching @name on the bus specified by @bus_type and calls
248/// @name_appeared_handler and @name_vanished_handler when the name is
249/// known to have an owner respectively known to lose its
250/// owner. Callbacks will be invoked in the thread-default main context
251/// (see [`glib::MainContext::push_thread_default()`][crate::glib::MainContext::push_thread_default()])
252/// of the thread you are calling this function from.
253///
254/// You are guaranteed that one of the handlers will be invoked after
255/// calling this function. When you are done watching the name, just
256/// call g_bus_unwatch_name() with the watcher id this function
257/// returns.
258///
259/// If the name vanishes or appears (for example the application owning
260/// the name could restart), the handlers are also invoked. If the
261/// #GDBusConnection that is used for watching the name disconnects, then
262/// @name_vanished_handler is invoked since it is no longer
263/// possible to access the name.
264///
265/// Another guarantee is that invocations of @name_appeared_handler
266/// and @name_vanished_handler are guaranteed to alternate; that
267/// is, if @name_appeared_handler is invoked then you are
268/// guaranteed that the next time one of the handlers is invoked, it
269/// will be @name_vanished_handler. The reverse is also true.
270///
271/// This behavior makes it very simple to write applications that want
272/// to take action when a certain [name exists](dbus-name-watching.html#d-bus-name-watching).
273/// Basically, the application should create object proxies in
274/// @name_appeared_handler and destroy them again (if any) in
275/// @name_vanished_handler.
276/// ## `bus_type`
277/// The type of bus to watch a name on.
278/// ## `name`
279/// The name (well-known or unique) to watch.
280/// ## `flags`
281/// Flags from the #GBusNameWatcherFlags enumeration.
282/// ## `name_appeared_handler`
283/// Handler to invoke when
284///   @name is known to exist or [`None`].
285/// ## `name_vanished_handler`
286/// Handler to invoke when
287///   @name is known to not exist or [`None`].
288///
289/// # Returns
290///
291/// An identifier (never 0) that can be used with
292/// g_bus_unwatch_name() to stop watching the name.
293#[doc(alias = "g_bus_watch_name_with_closures")]
294pub fn bus_watch_name<NameAppeared, NameVanished>(
295    bus_type: BusType,
296    name: &str,
297    flags: BusNameWatcherFlags,
298    name_appeared: NameAppeared,
299    name_vanished: NameVanished,
300) -> WatcherId
301where
302    NameAppeared: Fn(DBusConnection, &str, &str) + 'static,
303    NameVanished: Fn(DBusConnection, &str) + 'static,
304{
305    unsafe {
306        let id = ffi::g_bus_watch_name_with_closures(
307            bus_type.into_glib(),
308            name.to_glib_none().0,
309            flags.into_glib(),
310            appeared_closure(name_appeared).to_glib_none().0,
311            vanished_closure(name_vanished).to_glib_none().0,
312        );
313        WatcherId(NonZeroU32::new_unchecked(id))
314    }
315}
316
317#[doc(alias = "g_bus_unwatch_name")]
318pub fn bus_unwatch_name(watcher_id: WatcherId) {
319    unsafe {
320        ffi::g_bus_unwatch_name(watcher_id.0.into());
321    }
322}