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