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