1 // Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com> 2 // 3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 6 // option. This file may not be copied, modified, or distributed 7 // except according to those terms. 8 9 use glib; 10 use glib::object::{Cast, ObjectExt}; 11 use glib::signal::SignalHandlerId; 12 use glib::translate::*; 13 use glib::IsA; 14 15 use gobject_sys; 16 17 use ObjectFlags; 18 19 pub trait GstObjectExtManual: 'static { connect_deep_notify<F: Fn(&Self, &::Object, &glib::ParamSpec) + Send + Sync + 'static>( &self, name: Option<&str>, f: F, ) -> SignalHandlerId20 fn connect_deep_notify<F: Fn(&Self, &::Object, &glib::ParamSpec) + Send + Sync + 'static>( 21 &self, 22 name: Option<&str>, 23 f: F, 24 ) -> SignalHandlerId; 25 set_object_flags(&self, flags: ObjectFlags)26 fn set_object_flags(&self, flags: ObjectFlags); 27 unset_object_flags(&self, flags: ObjectFlags)28 fn unset_object_flags(&self, flags: ObjectFlags); 29 get_object_flags(&self) -> ObjectFlags30 fn get_object_flags(&self) -> ObjectFlags; 31 } 32 33 impl<O: IsA<::Object>> GstObjectExtManual for O { connect_deep_notify<F: Fn(&Self, &::Object, &glib::ParamSpec) + Send + Sync + 'static>( &self, name: Option<&str>, f: F, ) -> SignalHandlerId34 fn connect_deep_notify<F: Fn(&Self, &::Object, &glib::ParamSpec) + Send + Sync + 'static>( 35 &self, 36 name: Option<&str>, 37 f: F, 38 ) -> SignalHandlerId { 39 let signal_name = if let Some(name) = name { 40 format!("deep-notify::{}", name) 41 } else { 42 "deep-notify".into() 43 }; 44 45 let obj: glib::Object = 46 unsafe { from_glib_borrow(self.as_ptr() as *mut gobject_sys::GObject) }; 47 48 obj.connect(signal_name.as_str(), false, move |values| { 49 // It would be nice to display the actual signal name in the panic messages below, 50 // but that would require to copy `signal_name` so as to move it into the closure 51 // which seems too much for the messages of development errors 52 let obj: O = unsafe { 53 values[0] 54 .get::<::Object>() 55 .unwrap_or_else(|err| { 56 panic!("Object signal \"deep-notify\": values[0]: {}", err) 57 }) 58 .expect("Object signal \"deep-notify\": values[0] not defined") 59 .unsafe_cast() 60 }; 61 let prop_obj: ::Object = values[1] 62 .get() 63 .unwrap_or_else(|err| panic!("Object signal \"deep-notify\": values[1]: {}", err)) 64 .expect("Object signal \"deep-notify\": values[1] not defined"); 65 66 let pspec = unsafe { 67 let pspec = gobject_sys::g_value_get_param(values[2].to_glib_none().0); 68 from_glib_none(pspec) 69 }; 70 71 f(&obj, &prop_obj, &pspec); 72 73 None 74 }) 75 .unwrap() 76 } 77 set_object_flags(&self, flags: ObjectFlags)78 fn set_object_flags(&self, flags: ObjectFlags) { 79 unsafe { 80 let ptr: *mut gst_sys::GstObject = self.as_ptr() as *mut _; 81 let _guard = ::utils::MutexGuard::lock(&(*ptr).lock); 82 (*ptr).flags |= flags.to_glib(); 83 } 84 } 85 unset_object_flags(&self, flags: ObjectFlags)86 fn unset_object_flags(&self, flags: ObjectFlags) { 87 unsafe { 88 let ptr: *mut gst_sys::GstObject = self.as_ptr() as *mut _; 89 let _guard = ::utils::MutexGuard::lock(&(*ptr).lock); 90 (*ptr).flags &= !flags.to_glib(); 91 } 92 } 93 get_object_flags(&self) -> ObjectFlags94 fn get_object_flags(&self) -> ObjectFlags { 95 unsafe { 96 let ptr: *mut gst_sys::GstObject = self.as_ptr() as *mut _; 97 let _guard = ::utils::MutexGuard::lock(&(*ptr).lock); 98 from_glib((*ptr).flags) 99 } 100 } 101 } 102 103 #[cfg(test)] 104 mod tests { 105 use super::*; 106 use prelude::*; 107 use std::sync::{Arc, Mutex}; 108 109 #[test] test_deep_notify()110 fn test_deep_notify() { 111 ::init().unwrap(); 112 113 let bin = ::Bin::new(None); 114 let identity = ::ElementFactory::make("identity", Some("id")).unwrap(); 115 bin.add(&identity).unwrap(); 116 117 let notify = Arc::new(Mutex::new(None)); 118 let notify_clone = notify.clone(); 119 bin.connect_deep_notify(None, move |_, id, prop| { 120 *notify_clone.lock().unwrap() = Some((id.clone(), prop.get_name())); 121 }); 122 123 identity.set_property("silent", &false).unwrap(); 124 assert_eq!( 125 *notify.lock().unwrap(), 126 Some((identity.upcast::<::Object>(), String::from("silent"))) 127 ); 128 } 129 } 130