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}