1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{prelude::*, signal::SignalHandlerId, translate::*};
4
5use crate::{ClockTime, Object, ObjectFlags};
6
7mod sealed {
8 pub trait Sealed {}
9 impl<T: super::IsA<super::Object>> Sealed for T {}
10}
11
12pub trait GstObjectExtManual: sealed::Sealed + 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 // It would be nice to display the actual signal name in the panic messages below,
32 // but that would require to copy `signal_name` so as to move it into the closure
33 // which seems too much for the messages of development errors
34 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
83 fn g_value_array(
84 &self,
85 property_name: &str,
86 timestamp: ClockTime,
87 interval: ClockTime,
88 values: &mut [glib::Value],
89 ) -> Result<(), glib::error::BoolError> {
90 let n_values = values.len() as u32;
91 unsafe {
92 glib::result_from_gboolean!(
93 ffi::gst_object_get_g_value_array(
94 self.as_ref().to_glib_none().0,
95 property_name.to_glib_none().0,
96 timestamp.into_glib(),
97 interval.into_glib(),
98 n_values,
99 values.as_mut_ptr() as *mut glib::gobject_ffi::GValue,
100 ),
101 "Failed to get value array"
102 )
103 }
104 }
105
106 #[inline]
107 fn object_lock(&self) -> crate::utils::ObjectLockGuard<Self> {
108 crate::utils::ObjectLockGuard::acquire(self)
109 }
110}
111
112impl<O: IsA<Object>> GstObjectExtManual for O {}
113
114#[cfg(test)]
115mod tests {
116 use std::sync::{Arc, Mutex};
117
118 use super::*;
119 use crate::prelude::*;
120
121 #[test]
122 fn test_deep_notify() {
123 crate::init().unwrap();
124
125 let bin = crate::Bin::new();
126 let identity = crate::ElementFactory::make("identity")
127 .name("id")
128 .build()
129 .unwrap();
130 bin.add(&identity).unwrap();
131
132 let notify = Arc::new(Mutex::new(None));
133 let notify_clone = notify.clone();
134 bin.connect_deep_notify(None, move |_, id, prop| {
135 *notify_clone.lock().unwrap() = Some((id.clone(), prop.name()));
136 });
137
138 identity.set_property("silent", false);
139 assert_eq!(
140 *notify.lock().unwrap(),
141 Some((identity.upcast::<crate::Object>(), "silent"))
142 );
143 }
144}
145