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}