gio/
dbus_object_manager_client.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::{
4    BusType, Cancellable, DBusConnection, DBusObjectManagerClient, DBusObjectManagerClientFlags,
5    DBusObjectProxy, DBusProxy, GioFuture, ffi,
6};
7use glib::object::{Cast as _, IsA};
8use glib::signal::connect_raw;
9use glib::translate::{
10    Borrowed, FromGlibPtrBorrow as _, IntoGlib as _, ToGlibPtr as _, from_glib_borrow,
11    from_glib_full,
12};
13use glib::{SignalHandlerId, StrVRef};
14use std::future::Future;
15use std::pin::Pin;
16
17type DBusProxyTypeFn = Box<
18    dyn Fn(&DBusObjectManagerClient, &str, Option<&str>) -> glib::types::Type
19        + Send
20        + Sync
21        + 'static,
22>;
23
24impl DBusObjectManagerClient {
25    #[doc(alias = "g_dbus_object_manager_client_new_sync")]
26    pub fn new_sync(
27        connection: &DBusConnection,
28        flags: DBusObjectManagerClientFlags,
29        name: Option<&str>,
30        object_path: &str,
31        cancellable: Option<&impl IsA<Cancellable>>,
32    ) -> Result<DBusObjectManagerClient, glib::Error> {
33        Self::new_sync_impl(connection, flags, name, object_path, None, cancellable)
34    }
35
36    #[doc(alias = "g_dbus_object_manager_client_new_sync")]
37    pub fn new_sync_with_fn<
38        F: Fn(&DBusObjectManagerClient, &str, Option<&str>) -> glib::types::Type
39            + Send
40            + Sync
41            + 'static,
42    >(
43        connection: &DBusConnection,
44        flags: DBusObjectManagerClientFlags,
45        name: Option<&str>,
46        object_path: &str,
47        get_proxy_type_func: F,
48        cancellable: Option<&impl IsA<Cancellable>>,
49    ) -> Result<DBusObjectManagerClient, glib::Error> {
50        Self::new_sync_impl(
51            connection,
52            flags,
53            name,
54            object_path,
55            Some(Box::new(get_proxy_type_func)),
56            cancellable,
57        )
58    }
59
60    #[doc(alias = "g_dbus_object_manager_client_new_for_bus_sync")]
61    pub fn for_bus_sync(
62        bus_type: BusType,
63        flags: DBusObjectManagerClientFlags,
64        name: &str,
65        object_path: &str,
66        cancellable: Option<&impl IsA<Cancellable>>,
67    ) -> Result<DBusObjectManagerClient, glib::Error> {
68        Self::for_bus_sync_impl(bus_type, flags, name, object_path, None, cancellable)
69    }
70
71    #[doc(alias = "g_dbus_object_manager_client_new_for_bus_sync")]
72    pub fn for_bus_sync_with_fn<
73        F: Fn(&DBusObjectManagerClient, &str, Option<&str>) -> glib::types::Type
74            + Send
75            + Sync
76            + 'static,
77    >(
78        bus_type: BusType,
79        flags: DBusObjectManagerClientFlags,
80        name: &str,
81        object_path: &str,
82        get_proxy_type_func: F,
83        cancellable: Option<&impl IsA<Cancellable>>,
84    ) -> Result<DBusObjectManagerClient, glib::Error> {
85        Self::for_bus_sync_impl(
86            bus_type,
87            flags,
88            name,
89            object_path,
90            Some(Box::new(get_proxy_type_func)),
91            cancellable,
92        )
93    }
94
95    /// Asynchronously creates a new #GDBusObjectManagerClient object.
96    ///
97    /// This is an asynchronous failable constructor. When the result is
98    /// ready, @callback will be invoked in the thread-default main context
99    /// (see [`glib::MainContext::push_thread_default()`][crate::glib::MainContext::push_thread_default()])
100    /// of the thread you are calling this method from. You can then call
101    /// g_dbus_object_manager_client_new_finish() to get the result. See
102    /// g_dbus_object_manager_client_new_sync() for the synchronous version.
103    /// ## `connection`
104    /// A #GDBusConnection.
105    /// ## `flags`
106    /// Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
107    /// ## `name`
108    /// The owner of the control object (unique or well-known name).
109    /// ## `object_path`
110    /// The object path of the control object.
111    /// ## `get_proxy_type_func`
112    /// A #GDBusProxyTypeFunc function or [`None`] to always construct #GDBusProxy proxies.
113    /// ## `get_proxy_type_user_data`
114    /// User data to pass to @get_proxy_type_func.
115    /// ## `get_proxy_type_destroy_notify`
116    /// Free function for @get_proxy_type_user_data or [`None`].
117    /// ## `cancellable`
118    /// A #GCancellable or [`None`]
119    /// ## `callback`
120    /// A #GAsyncReadyCallback to call when the request is satisfied.
121    #[allow(clippy::new_ret_no_self)]
122    #[doc(alias = "g_dbus_object_manager_client_new")]
123    pub fn new<P: FnOnce(Result<DBusObjectManagerClient, glib::Error>) + Send + Sync + 'static>(
124        connection: &DBusConnection,
125        flags: DBusObjectManagerClientFlags,
126        name: &str,
127        object_path: &str,
128        cancellable: Option<&impl IsA<Cancellable>>,
129        callback: P,
130    ) {
131        Self::new_impl(
132            connection,
133            flags,
134            name,
135            object_path,
136            None,
137            cancellable,
138            callback,
139        )
140    }
141
142    #[allow(clippy::new_ret_no_self)]
143    #[doc(alias = "g_dbus_object_manager_client_new")]
144    pub fn new_with_fn<
145        P: FnOnce(Result<DBusObjectManagerClient, glib::Error>) + Send + Sync + 'static,
146        F: Fn(&DBusObjectManagerClient, &str, Option<&str>) -> glib::types::Type
147            + Send
148            + Sync
149            + 'static,
150    >(
151        connection: &DBusConnection,
152        flags: DBusObjectManagerClientFlags,
153        name: &str,
154        object_path: &str,
155        get_proxy_type_func: F,
156        cancellable: Option<&impl IsA<Cancellable>>,
157        callback: P,
158    ) {
159        Self::new_impl(
160            connection,
161            flags,
162            name,
163            object_path,
164            Some(Box::new(get_proxy_type_func)),
165            cancellable,
166            callback,
167        )
168    }
169
170    #[allow(clippy::new_ret_no_self)]
171    fn new_impl<P: FnOnce(Result<DBusObjectManagerClient, glib::Error>) + Send + Sync + 'static>(
172        connection: &DBusConnection,
173        flags: DBusObjectManagerClientFlags,
174        name: &str,
175        object_path: &str,
176        get_proxy_type_func: Option<DBusProxyTypeFn>,
177        cancellable: Option<&impl IsA<Cancellable>>,
178        callback: P,
179    ) {
180        let main_context = glib::MainContext::ref_thread_default();
181        let is_main_context_owner = main_context.is_owner();
182        let has_acquired_main_context = (!is_main_context_owner)
183            .then(|| main_context.acquire().ok())
184            .flatten();
185        assert!(
186            is_main_context_owner || has_acquired_main_context.is_some(),
187            "Async operations only allowed if the thread is owning the MainContext"
188        );
189
190        unsafe extern "C" fn get_proxy_type_func_func(
191            manager: *mut ffi::GDBusObjectManagerClient,
192            object_path: *const std::ffi::c_char,
193            interface_name: *const std::ffi::c_char,
194            data: glib::ffi::gpointer,
195        ) -> glib::ffi::GType {
196            unsafe {
197                let manager = from_glib_borrow(manager);
198                let object_path: Borrowed<glib::GString> = from_glib_borrow(object_path);
199                let interface_name: Borrowed<Option<glib::GString>> =
200                    from_glib_borrow(interface_name);
201                let callback = &*(data as *mut Option<DBusProxyTypeFn>);
202                if let Some(ref callback) = *callback {
203                    callback(
204                        &manager,
205                        object_path.as_str(),
206                        (*interface_name).as_ref().map(|s| s.as_str()),
207                    )
208                } else {
209                    panic!("cannot get closure...")
210                }
211                .into_glib()
212            }
213        }
214
215        unsafe extern "C" fn get_proxy_type_destroy_notify_func(data: glib::ffi::gpointer) {
216            unsafe {
217                let _callback = Box::from_raw(data as *mut Option<DBusProxyTypeFn>);
218            }
219        }
220
221        unsafe extern "C" fn new_trampoline<
222            P: FnOnce(Result<DBusObjectManagerClient, glib::Error>) + Send + Sync + 'static,
223        >(
224            _source_object: *mut glib::gobject_ffi::GObject,
225            res: *mut crate::ffi::GAsyncResult,
226            user_data: glib::ffi::gpointer,
227        ) {
228            unsafe {
229                let mut error = std::ptr::null_mut();
230                let ret = ffi::g_dbus_object_manager_client_new_finish(res, &mut error);
231                let result = if error.is_null() {
232                    Ok(from_glib_full(ret))
233                } else {
234                    Err(from_glib_full(error))
235                };
236                let callback: Box<glib::thread_guard::ThreadGuard<P>> =
237                    Box::from_raw(user_data as *mut _);
238                let callback: P = callback.into_inner();
239                callback(result);
240            }
241        }
242
243        let get_proxy_type_user_data = Box::new(get_proxy_type_func);
244        let get_proxy_type_func = if get_proxy_type_user_data.is_some() {
245            Some(get_proxy_type_func_func as _)
246        } else {
247            None
248        };
249        let get_proxy_type_destroy_notify = if get_proxy_type_user_data.is_some() {
250            Some(get_proxy_type_destroy_notify_func as _)
251        } else {
252            None
253        };
254
255        let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
256            Box::new(glib::thread_guard::ThreadGuard::new(callback));
257        let callback = new_trampoline::<P>;
258
259        unsafe {
260            ffi::g_dbus_object_manager_client_new(
261                connection.to_glib_none().0,
262                flags.into_glib(),
263                name.to_glib_none().0,
264                object_path.to_glib_none().0,
265                get_proxy_type_func,
266                Box::into_raw(get_proxy_type_user_data) as *mut _,
267                get_proxy_type_destroy_notify,
268                cancellable.map(|p| p.as_ref()).to_glib_none().0,
269                Some(callback),
270                Box::into_raw(user_data) as *mut _,
271            );
272        }
273    }
274
275    pub fn new_future(
276        connection: &DBusConnection,
277        flags: DBusObjectManagerClientFlags,
278        name: &str,
279        object_path: &str,
280    ) -> Pin<Box<dyn Future<Output = Result<DBusObjectManagerClient, glib::Error>> + 'static>> {
281        Self::new_future_impl(connection, flags, name, object_path, None)
282    }
283
284    pub fn new_future_with_fn<
285        F: Fn(&DBusObjectManagerClient, &str, Option<&str>) -> glib::types::Type
286            + Send
287            + Sync
288            + 'static,
289    >(
290        connection: &DBusConnection,
291        flags: DBusObjectManagerClientFlags,
292        name: &str,
293        object_path: &str,
294        get_proxy_type_func: F,
295    ) -> Pin<Box<dyn Future<Output = Result<DBusObjectManagerClient, glib::Error>> + 'static>> {
296        Self::new_future_impl(
297            connection,
298            flags,
299            name,
300            object_path,
301            Some(Box::new(get_proxy_type_func)),
302        )
303    }
304
305    fn new_future_impl(
306        connection: &DBusConnection,
307        flags: DBusObjectManagerClientFlags,
308        name: &str,
309        object_path: &str,
310        get_proxy_type_func: Option<DBusProxyTypeFn>,
311    ) -> Pin<Box<dyn Future<Output = Result<DBusObjectManagerClient, glib::Error>> + 'static>> {
312        let connection = connection.clone();
313        let name = String::from(name);
314        let object_path = String::from(object_path);
315        Box::pin(GioFuture::new(&(), move |_obj, cancellable, send| {
316            Self::new_impl(
317                &connection,
318                flags,
319                &name,
320                &object_path,
321                get_proxy_type_func,
322                Some(cancellable),
323                move |res| {
324                    send.resolve(res);
325                },
326            );
327        }))
328    }
329
330    /// Like g_dbus_object_manager_client_new() but takes a #GBusType instead of a
331    /// #GDBusConnection.
332    ///
333    /// This is an asynchronous failable constructor. When the result is
334    /// ready, @callback will be invoked in the thread-default main context
335    /// (see [`glib::MainContext::push_thread_default()`][crate::glib::MainContext::push_thread_default()])
336    /// of the thread you are calling this method from. You can
337    /// then call g_dbus_object_manager_client_new_for_bus_finish() to get the result. See
338    /// g_dbus_object_manager_client_new_for_bus_sync() for the synchronous version.
339    /// ## `bus_type`
340    /// A #GBusType.
341    /// ## `flags`
342    /// Zero or more flags from the #GDBusObjectManagerClientFlags enumeration.
343    /// ## `name`
344    /// The owner of the control object (unique or well-known name).
345    /// ## `object_path`
346    /// The object path of the control object.
347    /// ## `get_proxy_type_func`
348    /// A #GDBusProxyTypeFunc function or [`None`] to always construct #GDBusProxy proxies.
349    /// ## `get_proxy_type_user_data`
350    /// User data to pass to @get_proxy_type_func.
351    /// ## `get_proxy_type_destroy_notify`
352    /// Free function for @get_proxy_type_user_data or [`None`].
353    /// ## `cancellable`
354    /// A #GCancellable or [`None`]
355    /// ## `callback`
356    /// A #GAsyncReadyCallback to call when the request is satisfied.
357    #[doc(alias = "g_dbus_object_manager_client_new_for_bus")]
358    #[allow(clippy::new_ret_no_self)]
359    pub fn new_for_bus<
360        P: FnOnce(Result<DBusObjectManagerClient, glib::Error>) + Send + Sync + 'static,
361    >(
362        bus_type: BusType,
363        flags: DBusObjectManagerClientFlags,
364        name: &str,
365        object_path: &str,
366        cancellable: Option<&impl IsA<Cancellable>>,
367        callback: P,
368    ) {
369        Self::new_for_bus_impl(
370            bus_type,
371            flags,
372            name,
373            object_path,
374            None,
375            cancellable,
376            callback,
377        );
378    }
379
380    #[doc(alias = "g_dbus_object_manager_client_new_for_bus")]
381    #[allow(clippy::new_ret_no_self)]
382    pub fn new_for_bus_with_fn<
383        P: FnOnce(Result<DBusObjectManagerClient, glib::Error>) + Send + Sync + 'static,
384        F: Fn(&DBusObjectManagerClient, &str, Option<&str>) -> glib::types::Type
385            + Send
386            + Sync
387            + 'static,
388    >(
389        bus_type: BusType,
390        flags: DBusObjectManagerClientFlags,
391        name: &str,
392        object_path: &str,
393        get_proxy_type_func: F,
394        cancellable: Option<&impl IsA<Cancellable>>,
395        callback: P,
396    ) {
397        Self::new_for_bus_impl(
398            bus_type,
399            flags,
400            name,
401            object_path,
402            Some(Box::new(get_proxy_type_func)),
403            cancellable,
404            callback,
405        );
406    }
407
408    #[allow(clippy::new_ret_no_self)]
409    fn new_for_bus_impl<
410        P: FnOnce(Result<DBusObjectManagerClient, glib::Error>) + Send + Sync + 'static,
411    >(
412        bus_type: BusType,
413        flags: DBusObjectManagerClientFlags,
414        name: &str,
415        object_path: &str,
416        get_proxy_type_func: Option<DBusProxyTypeFn>,
417        cancellable: Option<&impl IsA<Cancellable>>,
418        callback: P,
419    ) {
420        let main_context = glib::MainContext::ref_thread_default();
421        let is_main_context_owner = main_context.is_owner();
422        let has_acquired_main_context = (!is_main_context_owner)
423            .then(|| main_context.acquire().ok())
424            .flatten();
425        assert!(
426            is_main_context_owner || has_acquired_main_context.is_some(),
427            "Async operations only allowed if the thread is owning the MainContext"
428        );
429
430        unsafe extern "C" fn get_proxy_type_func_func(
431            manager: *mut ffi::GDBusObjectManagerClient,
432            object_path: *const std::ffi::c_char,
433            interface_name: *const std::ffi::c_char,
434            data: glib::ffi::gpointer,
435        ) -> glib::ffi::GType {
436            unsafe {
437                let manager = from_glib_borrow(manager);
438                let object_path: Borrowed<glib::GString> = from_glib_borrow(object_path);
439                let interface_name: Borrowed<Option<glib::GString>> =
440                    from_glib_borrow(interface_name);
441                let callback = &*(data as *mut Option<DBusProxyTypeFn>);
442                if let Some(ref callback) = *callback {
443                    callback(
444                        &manager,
445                        object_path.as_str(),
446                        (*interface_name).as_ref().map(|s| s.as_str()),
447                    )
448                } else {
449                    panic!("cannot get closure...")
450                }
451                .into_glib()
452            }
453        }
454
455        unsafe extern "C" fn get_proxy_type_destroy_notify_func(data: glib::ffi::gpointer) {
456            unsafe {
457                let _callback = Box::from_raw(data as *mut Option<DBusProxyTypeFn>);
458            }
459        }
460
461        unsafe extern "C" fn new_for_bus_trampoline<
462            P: FnOnce(Result<DBusObjectManagerClient, glib::Error>) + Send + Sync + 'static,
463        >(
464            _source_object: *mut glib::gobject_ffi::GObject,
465            res: *mut crate::ffi::GAsyncResult,
466            user_data: glib::ffi::gpointer,
467        ) {
468            unsafe {
469                let mut error = std::ptr::null_mut();
470                let ret = ffi::g_dbus_object_manager_client_new_finish(res, &mut error);
471                let result = if error.is_null() {
472                    Ok(from_glib_full(ret))
473                } else {
474                    Err(from_glib_full(error))
475                };
476                let callback: Box<glib::thread_guard::ThreadGuard<P>> =
477                    Box::from_raw(user_data as *mut _);
478                let callback: P = callback.into_inner();
479                callback(result);
480            }
481        }
482
483        let get_proxy_type_user_data = Box::new(get_proxy_type_func);
484        let get_proxy_type_func = if get_proxy_type_user_data.is_some() {
485            Some(get_proxy_type_func_func as _)
486        } else {
487            None
488        };
489        let get_proxy_type_destroy_notify = if get_proxy_type_user_data.is_some() {
490            Some(get_proxy_type_destroy_notify_func as _)
491        } else {
492            None
493        };
494
495        let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
496            Box::new(glib::thread_guard::ThreadGuard::new(callback));
497        let callback = new_for_bus_trampoline::<P>;
498
499        unsafe {
500            ffi::g_dbus_object_manager_client_new_for_bus(
501                bus_type.into_glib(),
502                flags.into_glib(),
503                name.to_glib_none().0,
504                object_path.to_glib_none().0,
505                get_proxy_type_func,
506                Box::into_raw(get_proxy_type_user_data) as *mut _,
507                get_proxy_type_destroy_notify,
508                cancellable.map(|p| p.as_ref()).to_glib_none().0,
509                Some(callback),
510                Box::into_raw(user_data) as *mut _,
511            );
512        }
513    }
514
515    pub fn new_for_bus_future(
516        bus_type: BusType,
517        flags: DBusObjectManagerClientFlags,
518        name: &str,
519        object_path: &str,
520    ) -> Pin<Box<dyn Future<Output = Result<DBusObjectManagerClient, glib::Error>> + 'static>> {
521        Self::new_for_bus_future_impl(bus_type, flags, name, object_path, None)
522    }
523
524    pub fn new_for_bus_future_with_fn<
525        F: Fn(&DBusObjectManagerClient, &str, Option<&str>) -> glib::types::Type
526            + Send
527            + Sync
528            + 'static,
529    >(
530        bus_type: BusType,
531        flags: DBusObjectManagerClientFlags,
532        name: &str,
533        object_path: &str,
534        get_proxy_type_func: F,
535    ) -> Pin<Box<dyn Future<Output = Result<DBusObjectManagerClient, glib::Error>> + 'static>> {
536        Self::new_for_bus_future_impl(
537            bus_type,
538            flags,
539            name,
540            object_path,
541            Some(Box::new(get_proxy_type_func)),
542        )
543    }
544
545    fn new_for_bus_future_impl(
546        bus_type: BusType,
547        flags: DBusObjectManagerClientFlags,
548        name: &str,
549        object_path: &str,
550        get_proxy_type_func: Option<DBusProxyTypeFn>,
551    ) -> Pin<Box<dyn Future<Output = Result<DBusObjectManagerClient, glib::Error>> + 'static>> {
552        let name = String::from(name);
553        let object_path = String::from(object_path);
554        Box::pin(GioFuture::new(&(), move |_obj, cancellable, send| {
555            Self::new_for_bus_impl(
556                bus_type,
557                flags,
558                &name,
559                &object_path,
560                get_proxy_type_func,
561                Some(cancellable),
562                move |res| {
563                    send.resolve(res);
564                },
565            );
566        }))
567    }
568}
569
570pub trait DBusObjectManagerClientExtManual: IsA<DBusObjectManagerClient> + 'static {
571    #[doc(alias = "interface-proxy-properties-changed")]
572    fn connect_interface_proxy_properties_changed<
573        F: Fn(&Self, &DBusObjectProxy, &DBusProxy, &glib::Variant, &StrVRef) + Send + Sync + 'static,
574    >(
575        &self,
576        f: F,
577    ) -> SignalHandlerId {
578        unsafe extern "C" fn interface_proxy_properties_changed_trampoline<
579            P: IsA<DBusObjectManagerClient>,
580            F: Fn(&P, &DBusObjectProxy, &DBusProxy, &glib::Variant, &StrVRef) + Send + Sync + 'static,
581        >(
582            this: *mut ffi::GDBusObjectManagerClient,
583            object_proxy: *mut ffi::GDBusObjectProxy,
584            interface_proxy: *mut ffi::GDBusProxy,
585            changed_properties: *mut glib::ffi::GVariant,
586            invalidated_properties: *const *const std::ffi::c_char,
587            f: glib::ffi::gpointer,
588        ) {
589            unsafe {
590                let f: &F = &*(f as *const F);
591                f(
592                    DBusObjectManagerClient::from_glib_borrow(this).unsafe_cast_ref(),
593                    &from_glib_borrow(object_proxy),
594                    &from_glib_borrow(interface_proxy),
595                    &from_glib_borrow(changed_properties),
596                    StrVRef::from_glib_borrow(invalidated_properties),
597                )
598            }
599        }
600        unsafe {
601            let f: Box<F> = Box::new(f);
602            connect_raw(
603                self.as_ptr() as *mut _,
604                c"interface-proxy-properties-changed".as_ptr() as *const _,
605                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
606                    interface_proxy_properties_changed_trampoline::<Self, F> as *const (),
607                )),
608                Box::into_raw(f),
609            )
610        }
611    }
612}
613
614impl<O: IsA<DBusObjectManagerClient>> DBusObjectManagerClientExtManual for O {}