1use std::ptr;
4#[cfg(feature = "v1_28")]
5use std::{future::Future, pin::Pin};
6
7use glib::{prelude::*, signal::SignalHandlerId, translate::*};
8
9use crate::{ClockTime, Object, ObjectFlags, ffi};
10
11pub trait GstObjectExtManual: IsA<Object> + 'static {
12 #[doc(alias = "deep-notify")]
13 fn connect_deep_notify<
14 F: Fn(&Self, &crate::Object, &glib::ParamSpec) + Send + Sync + 'static,
15 >(
16 &self,
17 name: Option<&str>,
18 f: F,
19 ) -> SignalHandlerId {
20 let signal_name = if let Some(name) = name {
21 format!("deep-notify::{name}")
22 } else {
23 "deep-notify".into()
24 };
25
26 let obj: Borrowed<glib::Object> =
27 unsafe { from_glib_borrow(self.as_ptr() as *mut glib::gobject_ffi::GObject) };
28
29 obj.connect(signal_name.as_str(), false, move |values| {
30 let obj: Self = unsafe {
34 values[0]
35 .get::<crate::Object>()
36 .unwrap_or_else(|err| panic!("Object signal \"deep-notify\": values[0]: {err}"))
37 .unsafe_cast()
38 };
39 let prop_obj: crate::Object = values[1]
40 .get()
41 .unwrap_or_else(|err| panic!("Object signal \"deep-notify\": values[1]: {err}"));
42
43 let pspec = unsafe {
44 let pspec = glib::gobject_ffi::g_value_get_param(values[2].to_glib_none().0);
45 from_glib_none(pspec)
46 };
47
48 f(&obj, &prop_obj, &pspec);
49
50 None
51 })
52 }
53
54 fn set_object_flags(&self, flags: ObjectFlags) {
55 unsafe {
56 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
57 let _guard = self.as_ref().object_lock();
58 (*ptr).flags |= flags.into_glib();
59 }
60 }
61
62 fn unset_object_flags(&self, flags: ObjectFlags) {
63 unsafe {
64 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
65 let _guard = self.as_ref().object_lock();
66 (*ptr).flags &= !flags.into_glib();
67 }
68 }
69
70 #[doc(alias = "get_object_flags")]
71 fn object_flags(&self) -> ObjectFlags {
72 unsafe {
73 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
74 let _guard = self.as_ref().object_lock();
75 from_glib((*ptr).flags)
76 }
77 }
78
79 #[doc(alias = "get_g_value_array")]
80 #[doc(alias = "gst_object_get_g_value_array")]
81 fn g_value_array(
82 &self,
83 property_name: &str,
84 timestamp: ClockTime,
85 interval: ClockTime,
86 values: &mut [glib::Value],
87 ) -> Result<(), glib::error::BoolError> {
88 let n_values = values.len() as u32;
89 unsafe {
90 glib::result_from_gboolean!(
91 ffi::gst_object_get_g_value_array(
92 self.as_ref().to_glib_none().0,
93 property_name.to_glib_none().0,
94 timestamp.into_glib(),
95 interval.into_glib(),
96 n_values,
97 values.as_mut_ptr() as *mut glib::gobject_ffi::GValue,
98 ),
99 "Failed to get value array"
100 )
101 }
102 }
103
104 #[inline]
105 fn object_lock(&self) -> crate::utils::ObjectLockGuard<'_, Self> {
106 crate::utils::ObjectLockGuard::acquire(self)
107 }
108
109 #[cfg(feature = "v1_28")]
110 #[doc(alias = "gst_object_call_async")]
111 fn call_async<F>(&self, func: F)
112 where
113 F: FnOnce(&Self) + Send + 'static,
114 {
115 let user_data: Box<F> = Box::new(func);
116
117 unsafe extern "C" fn trampoline<O: IsA<Object>, F: FnOnce(&O) + Send + 'static>(
118 object: *mut ffi::GstObject,
119 user_data: glib::ffi::gpointer,
120 ) {
121 unsafe {
122 let callback: Box<F> = Box::from_raw(user_data as *mut _);
123 callback(Object::from_glib_borrow(object).unsafe_cast_ref());
124 }
125 }
126
127 unsafe {
128 ffi::gst_object_call_async(
129 self.as_ref().to_glib_none().0,
130 Some(trampoline::<Self, F>),
131 Box::into_raw(user_data) as *mut _,
132 );
133 }
134 }
135
136 #[cfg(feature = "v1_28")]
137 fn call_async_future<F, T>(&self, func: F) -> Pin<Box<dyn Future<Output = T> + Send + 'static>>
138 where
139 F: FnOnce(&Self) -> T + Send + 'static,
140 T: Send + 'static,
141 {
142 use futures_channel::oneshot;
143
144 let (sender, receiver) = oneshot::channel();
145
146 self.call_async(move |object| {
147 let _ = sender.send(func(object));
148 });
149
150 Box::pin(async move { receiver.await.expect("sender dropped") })
151 }
152
153 #[doc(alias = "gst_object_set_parent")]
162 #[doc(alias = "parent")]
163 unsafe fn set_parent(&self, parent: &impl IsA<Object>) -> Result<Self, glib::error::BoolError> {
164 unsafe {
165 glib::result_from_gboolean!(
166 ffi::gst_object_set_parent(
167 self.as_ref().to_glib_none().0,
168 parent.as_ref().to_glib_none().0
169 ),
170 "Failed to set parent object"
171 )
172 .map(|_| {
173 Object::from_glib_full(self.as_ref().as_ptr()).unsafe_cast()
175 })
176 }
177 }
178
179 #[doc(alias = "gst_object_set_parent")]
183 #[doc(alias = "parent")]
184 unsafe fn unset_parent(&self, parent: &impl IsA<Object>) -> Result<(), glib::error::BoolError> {
185 unsafe {
186 let _lock = self.object_lock();
187
188 if (*self.as_ref().as_ptr()).parent != parent.as_ref().as_ptr() {
189 return Err(glib::bool_error!("Failed to unset parent object"));
190 }
191
192 (*self.as_ref().as_ptr()).parent = ptr::null_mut();
193
194 Ok(())
195 }
196 }
197}
198
199impl<O: IsA<Object>> GstObjectExtManual for O {}
200
201#[cfg(test)]
202mod tests {
203 use std::sync::{Arc, Mutex};
204
205 use super::*;
206 use crate::prelude::*;
207
208 #[test]
209 fn test_deep_notify() {
210 crate::init().unwrap();
211
212 let bin = crate::Bin::new();
213 let identity = crate::ElementFactory::make("identity")
214 .name("id")
215 .build()
216 .unwrap();
217 bin.add(&identity).unwrap();
218
219 let notify = Arc::new(Mutex::new(None));
220 let notify_clone = notify.clone();
221 bin.connect_deep_notify(None, move |_, id, prop| {
222 *notify_clone.lock().unwrap() = Some((id.clone(), prop.name()));
223 });
224
225 identity.set_property("silent", false);
226 assert_eq!(
227 *notify.lock().unwrap(),
228 Some((identity.upcast::<crate::Object>(), "silent"))
229 );
230 }
231
232 mod test_object {
233 use super::*;
234
235 use glib::subclass::prelude::*;
236
237 pub mod imp {
238 use std::collections::BTreeSet;
239
240 use super::*;
241
242 use crate::subclass::prelude::*;
243
244 #[derive(Default)]
245 pub struct TestObject {
246 pub(super) children: Mutex<BTreeSet<Object>>,
247 }
248
249 #[glib::object_subclass]
250 impl ObjectSubclass for TestObject {
251 const NAME: &'static str = "TestObject";
252 type Type = super::TestObject;
253 type ParentType = crate::Object;
254 }
255
256 impl ObjectImpl for TestObject {
257 fn dispose(&self) {
258 unsafe {
261 let mut children = self.children.lock().unwrap();
262 for child in children.iter() {
263 child.unset_parent(&*self.obj()).unwrap();
264 }
265 children.clear();
266 }
267 }
268 }
269
270 impl GstObjectImpl for TestObject {}
271 }
272
273 glib::wrapper! {
274 pub struct TestObject(ObjectSubclass<imp::TestObject>) @extends crate::Object;
275 }
276
277 impl TestObject {
278 pub fn new() -> Self {
279 glib::Object::builder().build()
280 }
281
282 pub fn add(&self, child: &impl IsA<Object>) -> bool {
283 if child.as_ref() == self.upcast_ref::<Object>() {
284 return false;
285 }
286
287 let mut children = self.imp().children.lock().unwrap();
288
289 if children.iter().any(|other| other.name() == child.name()) {
290 return false;
291 }
292
293 unsafe {
296 if let Ok(child) = child.as_ref().set_parent(self) {
297 let inserted = children.insert(child);
298 assert!(inserted);
299 true
300 } else {
301 false
302 }
303 }
304 }
305
306 pub fn remove(&self, child: &impl IsA<Object>) -> bool {
307 let mut children = self.imp().children.lock().unwrap();
308
309 unsafe {
312 if child.unset_parent(self).is_ok() {
313 let found = children.remove(child.as_ref());
314 assert!(found);
315 true
316 } else {
317 false
318 }
319 }
320 }
321 }
322 }
323
324 #[test]
325 fn test_set_unset_parent() {
326 crate::init().unwrap();
327
328 let p1 = test_object::TestObject::new();
329 let p2 = test_object::TestObject::new();
330
331 let c1 = test_object::TestObject::new();
332 let c2 = test_object::TestObject::new();
333
334 assert!(p1.add(&c1));
335 assert!(p1.parent().is_none());
336 assert_eq!(c1.parent().as_ref(), Some(p1.upcast_ref()));
337 assert_eq!(p1.ref_count(), 1);
338 assert_eq!(c1.ref_count(), 2);
339
340 assert!(p2.add(&c2));
341 assert!(p2.parent().is_none());
342 assert_eq!(c2.parent().as_ref(), Some(p2.upcast_ref()));
343 assert_eq!(p2.ref_count(), 1);
344 assert_eq!(c2.ref_count(), 2);
345
346 assert!(!p2.add(&c1));
347 assert_eq!(c1.parent().as_ref(), Some(p1.upcast_ref()));
348
349 assert!(p2.remove(&c2));
350 assert_eq!(c2.parent().as_ref(), None::<&Object>);
351 assert_eq!(p2.ref_count(), 1);
352 assert_eq!(c2.ref_count(), 1);
353
354 assert!(p1.add(&c2));
355 assert_eq!(c2.parent().as_ref(), Some(p1.upcast_ref()));
356 assert_eq!(p1.ref_count(), 1);
357 assert_eq!(c2.ref_count(), 2);
358
359 assert!(p1.remove(&c2));
360 assert_eq!(c1.parent().as_ref(), Some(p1.upcast_ref()));
361 assert_eq!(c2.parent().as_ref(), None::<&Object>);
362
363 assert_eq!(p1.ref_count(), 1);
364 assert_eq!(p2.ref_count(), 1);
365 assert_eq!(c1.ref_count(), 2);
366 assert_eq!(c2.ref_count(), 1);
367 }
368}