gio/subclass/
dbus_proxy.rs1#![deny(unsafe_op_in_unsafe_fn)]
4
5use glib::{prelude::*, subclass::prelude::*, translate::*};
6
7use crate::{
8 DBusProxy, ffi,
9 subclass::prelude::{AsyncInitableImpl, DBusInterfaceImpl, InitableImpl},
10};
11
12pub trait DBusProxyImpl:
13 ObjectImpl
14 + AsyncInitableImpl
15 + DBusInterfaceImpl
16 + InitableImpl
17 + ObjectSubclass<Type: IsA<DBusProxy>>
18{
19 fn g_properties_changed(
21 &self,
22 changed_properties: &glib::Variant,
23 invalidated_properties: &glib::StrVRef,
24 ) {
25 self.parent_g_properties_changed(changed_properties, invalidated_properties);
26 }
27
28 fn g_signal(
30 &self,
31 sender_name: Option<&glib::GStr>,
32 signal_name: &glib::GStr,
33 parameters: &glib::Variant,
34 ) {
35 self.parent_g_signal(sender_name, signal_name, parameters);
36 }
37}
38
39pub trait DBusProxyImplExt: DBusProxyImpl {
40 fn parent_g_properties_changed(
41 &self,
42 changed_properties: &glib::Variant,
43 invalidated_properties: &glib::StrVRef,
44 ) {
45 unsafe {
46 let data = Self::type_data();
47 let parent_class = data.as_ref().parent_class() as *const ffi::GDBusProxyClass;
48
49 if let Some(f) = (*parent_class).g_properties_changed {
50 f(
51 self.obj().unsafe_cast_ref::<DBusProxy>().to_glib_none().0,
52 changed_properties.to_glib_none().0,
53 invalidated_properties.to_glib_none().0,
54 );
55 }
56 }
57 }
58
59 fn parent_g_signal(
60 &self,
61 sender_name: Option<&glib::GStr>,
62 signal_name: &glib::GStr,
63 parameters: &glib::Variant,
64 ) {
65 unsafe {
66 let data = Self::type_data();
67 let parent_class = data.as_ref().parent_class() as *const ffi::GDBusProxyClass;
68
69 if let Some(f) = (*parent_class).g_signal {
70 f(
71 self.obj().unsafe_cast_ref::<DBusProxy>().to_glib_none().0,
72 sender_name.to_glib_none().0,
73 signal_name.to_glib_none().0,
74 parameters.to_glib_none().0,
75 );
76 }
77 }
78 }
79}
80
81impl<T: DBusProxyImpl> DBusProxyImplExt for T {}
82
83unsafe impl<T: DBusProxyImpl> IsSubclassable<T> for DBusProxy {
84 fn class_init(class: &mut glib::Class<Self>) {
85 Self::parent_class_init::<T>(class);
86 let class = class.as_mut();
87 class.g_properties_changed = Some(g_properties_changed::<T>);
88 class.g_signal = Some(g_signal::<T>);
89 }
90}
91
92unsafe extern "C" fn g_properties_changed<T: DBusProxyImpl>(
93 proxy: *mut ffi::GDBusProxy,
94 changed_properties: *mut glib::ffi::GVariant,
95 invalidated_properties: *const *const libc::c_char,
96) {
97 let instance = unsafe { &*(proxy as *mut T::Instance) };
98 let imp = instance.imp();
99
100 let changed_properties = unsafe { from_glib_borrow(changed_properties) };
101 let invalidated_properties = unsafe { glib::StrVRef::from_glib_borrow(invalidated_properties) };
102 imp.g_properties_changed(&changed_properties, invalidated_properties);
103}
104
105unsafe extern "C" fn g_signal<T: DBusProxyImpl>(
106 proxy: *mut ffi::GDBusProxy,
107 sender_name: *const libc::c_char,
108 signal_name: *const libc::c_char,
109 parameters: *mut glib::ffi::GVariant,
110) {
111 let instance = unsafe { &*(proxy as *mut T::Instance) };
112 let imp = instance.imp();
113
114 let sender_name = unsafe { Option::<&glib::GStr>::from_glib_none(sender_name) };
115 let signal_name = unsafe { from_glib_none(signal_name) };
116 let parameters = unsafe { from_glib_borrow(parameters) };
117 imp.g_signal(sender_name, signal_name, ¶meters);
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 use std::cell::RefCell;
125
126 use crate::{
127 AsyncInitable, Cancellable, DBusConnection, DBusConnectionFlags, DBusInterface, Initable,
128 MemoryInputStream, MemoryOutputStream, SimpleIOStream,
129 };
130
131 mod imp {
132 use super::*;
133
134 #[derive(Default)]
135 pub struct CustomDBusProxyImpl {
136 pub(super) g_properties_changed_called: RefCell<bool>,
137 pub(super) g_signal_called: RefCell<bool>,
138 }
139
140 #[glib::object_subclass]
141 impl ObjectSubclass for CustomDBusProxyImpl {
142 const NAME: &'static str = "CustomDBusProxyImpl";
143 type Type = super::CustomDBusProxyImpl;
144 type ParentType = DBusProxy;
145 type Interfaces = (DBusInterface, Initable, AsyncInitable);
146 }
147
148 impl ObjectImpl for CustomDBusProxyImpl {}
149
150 impl InitableImpl for CustomDBusProxyImpl {}
151 impl AsyncInitableImpl for CustomDBusProxyImpl {}
152 impl DBusInterfaceImpl for CustomDBusProxyImpl {}
153
154 impl DBusProxyImpl for CustomDBusProxyImpl {
155 fn g_signal(
156 &self,
157 sender_name: Option<&glib::GStr>,
158 signal_name: &glib::GStr,
159 parameters: &glib::Variant,
160 ) {
161 *self.g_signal_called.borrow_mut() = true;
162 self.parent_g_signal(sender_name, signal_name, parameters);
163 }
164
165 fn g_properties_changed(
166 &self,
167 changed_properties: &glib::Variant,
168 invalidated_properties: &glib::StrVRef,
169 ) {
170 *self.g_properties_changed_called.borrow_mut() = true;
171 self.parent_g_properties_changed(changed_properties, invalidated_properties);
172 }
173 }
174 }
175
176 glib::wrapper! {
177 pub struct CustomDBusProxyImpl(ObjectSubclass<imp::CustomDBusProxyImpl>)
178 @extends DBusProxy,
179 @implements DBusInterface, Initable, AsyncInitable;
180 }
181
182 #[test]
183 fn g_signal_is_called() {
184 let proxy = create_custom_proxy_impl();
185 let sender_name = "org.example.Sender";
186 let signal_name = "example";
187 let parameters = glib::Variant::array_from_iter::<glib::Variant>([]);
188 proxy
189 .upcast_ref::<DBusProxy>()
190 .emit_by_name::<()>("g-signal", &[&sender_name, &signal_name, ¶meters]);
191 assert!(*proxy.imp().g_signal_called.borrow());
192 }
193
194 #[test]
195 fn g_properties_changed_is_called() {
196 let proxy = create_custom_proxy_impl();
197 let changed_properties = glib::Variant::array_from_iter::<String>([]);
198 let invalidated_properties = glib::StrV::new();
199 proxy.upcast_ref::<DBusProxy>().emit_by_name::<()>(
200 "g-properties-changed",
201 &[&changed_properties, &invalidated_properties],
202 );
203 assert!(*proxy.imp().g_properties_changed_called.borrow());
204 }
205
206 fn create_custom_proxy_impl() -> CustomDBusProxyImpl {
207 let connection = create_no_op_dbus_connection();
210 Initable::builder()
211 .property("g-connection", connection)
212 .property("g-object-path", "/org/example/test")
213 .property("g-interface-name", "org.example.Test")
214 .build(Option::<&Cancellable>::None)
215 .expect("failed to create CustomDBusProxyImpl")
216 }
217
218 fn create_no_op_dbus_connection() -> DBusConnection {
219 let input = MemoryInputStream::new();
220 let output = MemoryOutputStream::new_resizable();
221 let stream = SimpleIOStream::new(&input, &output);
222 DBusConnection::new_sync(
223 &stream,
224 None,
225 DBusConnectionFlags::NONE,
226 None,
227 Option::<&Cancellable>::None,
228 )
229 .expect("failed to create DBusConnection")
230 }
231}