1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 //! Module that contains all types needed for creating a direct subclass of `GObject`
4 //! or implementing virtual methods of it.
5 
6 use super::prelude::*;
7 use super::Signal;
8 use crate::translate::*;
9 use crate::{Cast, Object, ObjectType, ParamSpec, Value};
10 use std::mem;
11 use std::ptr;
12 
13 /// Trait for implementors of `glib::Object` subclasses.
14 ///
15 /// This allows overriding the virtual methods of `glib::Object`.
16 pub trait ObjectImpl: ObjectSubclass + ObjectImplExt {
17     /// Properties installed for this type.
properties() -> &'static [ParamSpec]18     fn properties() -> &'static [ParamSpec] {
19         &[]
20     }
21 
22     /// Signals installed for this type.
signals() -> &'static [Signal]23     fn signals() -> &'static [Signal] {
24         &[]
25     }
26 
27     /// Property setter.
28     ///
29     /// This is called whenever the property of this specific subclass with the
30     /// given index is set. The new value is passed as `glib::Value`.
set_property(&self, _obj: &Self::Type, _id: usize, _value: &Value, _pspec: &ParamSpec)31     fn set_property(&self, _obj: &Self::Type, _id: usize, _value: &Value, _pspec: &ParamSpec) {
32         unimplemented!()
33     }
34 
35     /// Property getter.
36     ///
37     /// This is called whenever the property value of the specific subclass with the
38     /// given index should be returned.
39     #[doc(alias = "get_property")]
property(&self, _obj: &Self::Type, _id: usize, _pspec: &ParamSpec) -> Value40     fn property(&self, _obj: &Self::Type, _id: usize, _pspec: &ParamSpec) -> Value {
41         unimplemented!()
42     }
43 
44     /// Constructed.
45     ///
46     /// This is called once construction of the instance is finished.
47     ///
48     /// Should chain up to the parent class' implementation.
constructed(&self, obj: &Self::Type)49     fn constructed(&self, obj: &Self::Type) {
50         self.parent_constructed(obj);
51     }
52 
53     /// Disposes of the object.
54     ///
55     /// When `dispose()` ends, the object should not hold any reference to any other member object.
56     /// The object is also expected to be able to answer client method invocations (with possibly an
57     /// error code but no memory violation) until it is dropped. `dispose()` can be executed more
58     /// than once.
dispose(&self, _obj: &Self::Type)59     fn dispose(&self, _obj: &Self::Type) {}
60 }
61 
62 #[doc(alias = "get_property")]
property<T: ObjectImpl>( obj: *mut gobject_ffi::GObject, id: u32, value: *mut gobject_ffi::GValue, pspec: *mut gobject_ffi::GParamSpec, )63 unsafe extern "C" fn property<T: ObjectImpl>(
64     obj: *mut gobject_ffi::GObject,
65     id: u32,
66     value: *mut gobject_ffi::GValue,
67     pspec: *mut gobject_ffi::GParamSpec,
68 ) {
69     let instance = &*(obj as *mut T::Instance);
70     let imp = instance.impl_();
71 
72     let v = imp.property(
73         from_glib_borrow::<_, Object>(obj).unsafe_cast_ref(),
74         id as usize,
75         &from_glib_borrow(pspec),
76     );
77 
78     // We first unset the value we get passed in, in case it contained
79     // any previous data. Then we directly overwrite it with our new
80     // value, and pass ownership of the contained data to the C GValue
81     // by forgetting it on the Rust side.
82     //
83     // Without this, by using the GValue API, we would have to create
84     // a copy of the value when setting it on the destination just to
85     // immediately free the original value afterwards.
86     gobject_ffi::g_value_unset(value);
87     let v = mem::ManuallyDrop::new(v);
88     ptr::write(value, ptr::read(v.to_glib_none().0));
89 }
90 
set_property<T: ObjectImpl>( obj: *mut gobject_ffi::GObject, id: u32, value: *mut gobject_ffi::GValue, pspec: *mut gobject_ffi::GParamSpec, )91 unsafe extern "C" fn set_property<T: ObjectImpl>(
92     obj: *mut gobject_ffi::GObject,
93     id: u32,
94     value: *mut gobject_ffi::GValue,
95     pspec: *mut gobject_ffi::GParamSpec,
96 ) {
97     let instance = &*(obj as *mut T::Instance);
98     let imp = instance.impl_();
99     imp.set_property(
100         from_glib_borrow::<_, Object>(obj).unsafe_cast_ref(),
101         id as usize,
102         &*(value as *mut Value),
103         &from_glib_borrow(pspec),
104     );
105 }
106 
constructed<T: ObjectImpl>(obj: *mut gobject_ffi::GObject)107 unsafe extern "C" fn constructed<T: ObjectImpl>(obj: *mut gobject_ffi::GObject) {
108     let instance = &*(obj as *mut T::Instance);
109     let imp = instance.impl_();
110 
111     imp.constructed(from_glib_borrow::<_, Object>(obj).unsafe_cast_ref());
112 }
113 
dispose<T: ObjectImpl>(obj: *mut gobject_ffi::GObject)114 unsafe extern "C" fn dispose<T: ObjectImpl>(obj: *mut gobject_ffi::GObject) {
115     let instance = &*(obj as *mut T::Instance);
116     let imp = instance.impl_();
117 
118     imp.dispose(from_glib_borrow::<_, Object>(obj).unsafe_cast_ref());
119 
120     // Chain up to the parent's dispose.
121     let data = T::type_data();
122     let parent_class = data.as_ref().parent_class() as *mut gobject_ffi::GObjectClass;
123     if let Some(ref func) = (*parent_class).dispose {
124         func(obj);
125     }
126 }
127 
128 /// Extension trait for `glib::Object`'s class struct.
129 ///
130 /// This contains various class methods and allows subclasses to override signal class handlers.
131 pub unsafe trait ObjectClassSubclassExt: Sized + 'static {
override_signal_class_handler<F>(&mut self, name: &str, class_handler: F) where F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,132     fn override_signal_class_handler<F>(&mut self, name: &str, class_handler: F)
133     where
134         F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
135     {
136         unsafe {
137             super::types::signal_override_class_handler(
138                 name,
139                 *(self as *mut _ as *mut ffi::GType),
140                 class_handler,
141             );
142         }
143     }
144 }
145 
146 unsafe impl ObjectClassSubclassExt for crate::Class<Object> {}
147 
148 unsafe impl<T: ObjectImpl> IsSubclassable<T> for Object {
class_init(class: &mut crate::Class<Self>)149     fn class_init(class: &mut crate::Class<Self>) {
150         let klass = class.as_mut();
151         klass.set_property = Some(set_property::<T>);
152         klass.get_property = Some(property::<T>);
153         klass.constructed = Some(constructed::<T>);
154         klass.dispose = Some(dispose::<T>);
155 
156         let pspecs = <T as ObjectImpl>::properties();
157         if !pspecs.is_empty() {
158             unsafe {
159                 let mut pspecs_ptrs = Vec::with_capacity(pspecs.len() + 1);
160 
161                 pspecs_ptrs.push(ptr::null_mut());
162 
163                 for pspec in pspecs {
164                     pspecs_ptrs.push(pspec.to_glib_none().0);
165                 }
166 
167                 gobject_ffi::g_object_class_install_properties(
168                     klass,
169                     pspecs_ptrs.len() as u32,
170                     pspecs_ptrs.as_mut_ptr(),
171                 );
172             }
173         }
174 
175         let type_ = T::type_();
176         let signals = <T as ObjectImpl>::signals();
177         for signal in signals {
178             signal.register(type_);
179         }
180     }
181 
instance_init(_instance: &mut super::InitializingObject<T>)182     fn instance_init(_instance: &mut super::InitializingObject<T>) {}
183 }
184 
185 pub trait ObjectImplExt: ObjectSubclass {
186     /// Chain up to the parent class' implementation of `glib::Object::constructed()`.
parent_constructed(&self, obj: &Self::Type)187     fn parent_constructed(&self, obj: &Self::Type);
188 
189     /// Chain up to parent class signal handler.
signal_chain_from_overridden( &self, token: &super::SignalClassHandlerToken, values: &[Value], ) -> Option<Value>190     fn signal_chain_from_overridden(
191         &self,
192         token: &super::SignalClassHandlerToken,
193         values: &[Value],
194     ) -> Option<Value>;
195 }
196 
197 impl<T: ObjectImpl> ObjectImplExt for T {
parent_constructed(&self, obj: &Self::Type)198     fn parent_constructed(&self, obj: &Self::Type) {
199         unsafe {
200             let data = T::type_data();
201             let parent_class = data.as_ref().parent_class() as *mut gobject_ffi::GObjectClass;
202 
203             if let Some(ref func) = (*parent_class).constructed {
204                 func(obj.unsafe_cast_ref::<Object>().to_glib_none().0);
205             }
206         }
207     }
208 
signal_chain_from_overridden( &self, token: &super::SignalClassHandlerToken, values: &[Value], ) -> Option<Value>209     fn signal_chain_from_overridden(
210         &self,
211         token: &super::SignalClassHandlerToken,
212         values: &[Value],
213     ) -> Option<Value> {
214         unsafe {
215             super::types::signal_chain_from_overridden(
216                 self.instance().as_ptr() as *mut _,
217                 token,
218                 values,
219             )
220         }
221     }
222 }
223 
224 #[cfg(test)]
225 mod test {
226     use super::super::super::object::ObjectExt;
227     use super::super::super::value::{ToValue, Value};
228     use super::*;
229     // We rename the current crate as glib, since the macros in glib-macros
230     // generate the glib namespace through the crate_ident_new utility,
231     // and that returns `glib` (and not `crate`) when called inside the glib crate
232     use crate as glib;
233     use crate::StaticType;
234 
235     use std::cell::RefCell;
236 
237     mod imp {
238         use super::*;
239 
240         // A dummy `Object` to test setting an `Object` property and returning an `Object` in signals
241         #[derive(Default)]
242         pub struct ChildObject;
243 
244         #[glib::object_subclass]
245         impl ObjectSubclass for ChildObject {
246             const NAME: &'static str = "ChildObject";
247             type Type = super::ChildObject;
248             type ParentType = Object;
249         }
250 
251         impl ObjectImpl for ChildObject {}
252 
253         #[derive(Default)]
254         pub struct SimpleObject {
255             name: RefCell<Option<String>>,
256             construct_name: RefCell<Option<String>>,
257             constructed: RefCell<bool>,
258         }
259 
260         #[glib::object_subclass]
261         impl ObjectSubclass for SimpleObject {
262             const NAME: &'static str = "SimpleObject";
263             type Type = super::SimpleObject;
264             type ParentType = Object;
265             type Interfaces = (super::Dummy,);
266         }
267 
268         impl ObjectImpl for SimpleObject {
properties() -> &'static [ParamSpec]269             fn properties() -> &'static [ParamSpec] {
270                 use once_cell::sync::Lazy;
271                 static PROPERTIES: Lazy<Vec<ParamSpec>> = Lazy::new(|| {
272                     vec![
273                         crate::ParamSpec::new_string(
274                             "name",
275                             "Name",
276                             "Name of this object",
277                             None,
278                             crate::ParamFlags::READWRITE,
279                         ),
280                         crate::ParamSpec::new_string(
281                             "construct-name",
282                             "Construct Name",
283                             "Construct Name of this object",
284                             None,
285                             crate::ParamFlags::READWRITE | crate::ParamFlags::CONSTRUCT_ONLY,
286                         ),
287                         crate::ParamSpec::new_boolean(
288                             "constructed",
289                             "Constructed",
290                             "True if the constructed() virtual method was called",
291                             false,
292                             crate::ParamFlags::READABLE,
293                         ),
294                         crate::ParamSpec::new_object(
295                             "child",
296                             "Child",
297                             "Child object",
298                             super::ChildObject::static_type(),
299                             crate::ParamFlags::READWRITE,
300                         ),
301                     ]
302                 });
303 
304                 PROPERTIES.as_ref()
305             }
306 
signals() -> &'static [super::Signal]307             fn signals() -> &'static [super::Signal] {
308                 use once_cell::sync::Lazy;
309                 static SIGNALS: Lazy<Vec<super::Signal>> = Lazy::new(|| {
310                     vec![
311                         super::Signal::builder(
312                             "name-changed",
313                             &[String::static_type().into()],
314                             crate::Type::UNIT.into(),
315                         )
316                         .build(),
317                         super::Signal::builder(
318                             "change-name",
319                             &[String::static_type().into()],
320                             String::static_type().into(),
321                         )
322                         .action()
323                         .class_handler(|_, args| {
324                             let obj = args[0]
325                                 .get::<super::SimpleObject>()
326                                 .expect("Failed to get Object from args[0]");
327                             let new_name = args[1]
328                                 .get::<String>()
329                                 .expect("Failed to get Object from args[1]");
330                             let imp = SimpleObject::from_instance(&obj);
331 
332                             let old_name = imp.name.borrow_mut().take();
333                             *imp.name.borrow_mut() = Some(new_name);
334 
335                             obj.emit_by_name("name-changed", &[&*imp.name.borrow()])
336                                 .expect("Failed to borrow name");
337 
338                             Some(old_name.to_value())
339                         })
340                         .build(),
341                         super::Signal::builder("create-string", &[], String::static_type().into())
342                             .build(),
343                         super::Signal::builder(
344                             "create-child-object",
345                             &[],
346                             ChildObject::type_().into(),
347                         )
348                         .build(),
349                     ]
350                 });
351 
352                 SIGNALS.as_ref()
353             }
354 
set_property( &self, obj: &Self::Type, _id: usize, value: &Value, pspec: &crate::ParamSpec, )355             fn set_property(
356                 &self,
357                 obj: &Self::Type,
358                 _id: usize,
359                 value: &Value,
360                 pspec: &crate::ParamSpec,
361             ) {
362                 match pspec.name() {
363                     "name" => {
364                         let name = value
365                             .get()
366                             .expect("type conformity checked by 'Object::set_property'");
367                         self.name.replace(name);
368                         obj.emit_by_name("name-changed", &[&*self.name.borrow()])
369                             .expect("Failed to borrow name");
370                     }
371                     "construct-name" => {
372                         let name = value
373                             .get()
374                             .expect("type conformity checked by 'Object::set_property'");
375                         self.construct_name.replace(name);
376                     }
377                     "child" => {
378                         // not stored, only used to test `set_property` with `Objects`
379                     }
380                     _ => unimplemented!(),
381                 }
382             }
383 
property(&self, _obj: &Self::Type, _id: usize, pspec: &crate::ParamSpec) -> Value384             fn property(&self, _obj: &Self::Type, _id: usize, pspec: &crate::ParamSpec) -> Value {
385                 match pspec.name() {
386                     "name" => self.name.borrow().to_value(),
387                     "construct-name" => self.construct_name.borrow().to_value(),
388                     "constructed" => self.constructed.borrow().to_value(),
389                     _ => unimplemented!(),
390                 }
391             }
392 
constructed(&self, obj: &Self::Type)393             fn constructed(&self, obj: &Self::Type) {
394                 self.parent_constructed(obj);
395 
396                 assert_eq!(obj, &self.instance());
397                 assert_eq!(self as *const _, Self::from_instance(obj) as *const _);
398 
399                 *self.constructed.borrow_mut() = true;
400             }
401         }
402 
403         #[derive(Clone, Copy)]
404         #[repr(C)]
405         pub struct DummyInterface {
406             parent: gobject_ffi::GTypeInterface,
407         }
408 
409         #[glib::object_interface]
410         unsafe impl ObjectInterface for DummyInterface {
411             const NAME: &'static str = "Dummy";
412         }
413     }
414 
415     wrapper! {
416         pub struct ChildObject(ObjectSubclass<imp::ChildObject>);
417     }
418 
419     wrapper! {
420         pub struct SimpleObject(ObjectSubclass<imp::SimpleObject>);
421     }
422 
423     wrapper! {
424         pub struct Dummy(ObjectInterface<imp::DummyInterface>);
425     }
426 
427     unsafe impl<T: ObjectSubclass> IsImplementable<T> for Dummy {
interface_init(_iface: &mut crate::Interface<Dummy>)428         fn interface_init(_iface: &mut crate::Interface<Dummy>) {}
instance_init(_instance: &mut super::super::InitializingObject<T>)429         fn instance_init(_instance: &mut super::super::InitializingObject<T>) {}
430     }
431 
432     #[test]
test_create()433     fn test_create() {
434         let type_ = SimpleObject::static_type();
435         let obj = Object::with_type(type_, &[]).expect("Object::new failed");
436 
437         assert!(obj.type_().is_a(Dummy::static_type()));
438 
439         assert!(obj
440             .property("constructed")
441             .expect("Failed to get 'constructed' property")
442             .get::<bool>()
443             .expect("Failed to get bool from 'constructed' property"),);
444 
445         let weak = obj.downgrade();
446         drop(obj);
447         assert!(weak.upgrade().is_none());
448     }
449 
450     #[test]
test_create_child_object()451     fn test_create_child_object() {
452         let obj: ChildObject = Object::new(&[]).expect("Object::new failed");
453 
454         let imp = imp::ChildObject::from_instance(&obj);
455         assert_eq!(obj, imp.instance());
456     }
457 
458     #[test]
test_set_properties()459     fn test_set_properties() {
460         let obj = Object::with_type(
461             SimpleObject::static_type(),
462             &[("construct-name", &"meh"), ("name", &"initial")],
463         )
464         .expect("Object::new failed");
465 
466         assert_eq!(
467             obj.property("construct-name")
468                 .expect("Failed to get 'construct-name' property")
469                 .get::<&str>()
470                 .expect("Failed to get str from 'construct-name' property"),
471             "meh"
472         );
473         assert_eq!(
474             obj.set_property("construct-name", &"test")
475                 .err()
476                 .expect("Failed to set 'construct-name' property")
477                 .to_string(),
478             "property 'construct-name' of type 'SimpleObject' is not writable",
479         );
480         assert_eq!(
481             obj.property("construct-name")
482                 .expect("Failed to get 'construct-name' property")
483                 .get::<&str>()
484                 .expect("Failed to get str from 'construct-name' property"),
485             "meh"
486         );
487 
488         assert_eq!(
489             obj.property("name")
490                 .expect("Failed to get 'name' property")
491                 .get::<&str>()
492                 .expect("Failed to get str from 'name' property"),
493             "initial"
494         );
495         assert!(obj.set_property("name", &"test").is_ok());
496         assert_eq!(
497             obj.property("name")
498                 .expect("Failed to get 'name' property")
499                 .get::<&str>()
500                 .expect("Failed to get str from 'name' property"),
501             "test"
502         );
503 
504         assert_eq!(
505             obj.set_property("test", &true)
506                 .err()
507                 .expect("set_property failed")
508                 .to_string(),
509             "property 'test' of type 'SimpleObject' not found",
510         );
511 
512         assert_eq!(
513             obj.set_property("constructed", &false)
514                 .err()
515                 .expect("Failed to set 'constructed' property")
516                 .to_string(),
517             "property 'constructed' of type 'SimpleObject' is not writable",
518         );
519 
520         assert_eq!(
521             obj.set_property("name", &false)
522                 .err()
523                 .expect("Failed to set 'name' property")
524                 .to_string(),
525             "property 'name' of type 'SimpleObject' can't be set from the given type (expected: 'gchararray', got: 'gboolean')",
526         );
527 
528         let other_obj =
529             Object::with_type(SimpleObject::static_type(), &[]).expect("Object::new failed");
530         assert_eq!(
531             obj.set_property("child", &other_obj)
532                 .err()
533                 .expect("Failed to set 'child' property")
534                 .to_string(),
535             "property 'child' of type 'SimpleObject' can't be set from the given object type (expected: 'ChildObject', got: 'SimpleObject')",
536         );
537 
538         let child = Object::with_type(ChildObject::static_type(), &[]).expect("Object::new failed");
539         assert!(obj.set_property("child", &child).is_ok());
540     }
541 
542     #[test]
test_signals()543     fn test_signals() {
544         use std::sync::atomic::{AtomicBool, Ordering};
545         use std::sync::Arc;
546 
547         let type_ = SimpleObject::static_type();
548         let obj = Object::with_type(type_, &[("name", &"old-name")]).expect("Object::new failed");
549 
550         let name_changed_triggered = Arc::new(AtomicBool::new(false));
551         let name_changed_clone = name_changed_triggered.clone();
552         obj.connect("name-changed", false, move |args| {
553             let _obj = args[0].get::<Object>().expect("Failed to get args[0]");
554             let name = args[1].get::<&str>().expect("Failed to get args[1]");
555 
556             assert_eq!(name, "new-name");
557             name_changed_clone.store(true, Ordering::Relaxed);
558 
559             None
560         })
561         .expect("Failed to connect on 'name-changed'");
562 
563         assert_eq!(
564             obj.property("name")
565                 .expect("Failed to get 'name' property")
566                 .get::<&str>()
567                 .expect("Failed to get str from 'name' property"),
568             "old-name"
569         );
570         assert!(!name_changed_triggered.load(Ordering::Relaxed));
571 
572         assert_eq!(
573             obj.emit_by_name("change-name", &[&"new-name"])
574                 .expect("Failed to emit")
575                 .expect("Failed to get value from emit")
576                 .get::<&str>()
577                 .expect("Failed to get str from emit"),
578             "old-name"
579         );
580         assert!(name_changed_triggered.load(Ordering::Relaxed));
581     }
582 
583     #[test]
test_signal_return_expected_type()584     fn test_signal_return_expected_type() {
585         let obj = Object::with_type(SimpleObject::static_type(), &[]).expect("Object::new failed");
586 
587         obj.connect("create-string", false, move |_args| {
588             Some("return value".to_value())
589         })
590         .expect("Failed to connect on 'create-string'");
591 
592         let signal_id = imp::SimpleObject::signals()[2].signal_id();
593 
594         let value = obj
595             .emit(signal_id, &[])
596             .expect("Failed to emit")
597             .expect("Failed to get value from emit");
598         assert_eq!(value.get::<&str>(), Ok("return value"));
599     }
600 
601     #[test]
test_callback_validity()602     fn test_callback_validity() {
603         use std::sync::atomic::{AtomicBool, Ordering};
604         use std::sync::Arc;
605 
606         let type_ = SimpleObject::static_type();
607         let obj = Object::with_type(type_, &[("name", &"old-name")]).expect("Object::new failed");
608 
609         let name_changed_triggered = Arc::new(AtomicBool::new(false));
610         let name_changed_clone = name_changed_triggered.clone();
611 
612         obj.connect_notify(Some("name"), move |_, _| {
613             name_changed_clone.store(true, Ordering::Relaxed);
614         });
615         obj.notify("name");
616         assert!(name_changed_triggered.load(Ordering::Relaxed));
617     }
618 
619     // Note: can't test type mismatch in signals since panics accross FFI boundaries
620     // are UB. See https://github.com/gtk-rs/glib/issues/518
621 
622     #[test]
test_signal_return_expected_object_type()623     fn test_signal_return_expected_object_type() {
624         let obj = Object::with_type(SimpleObject::static_type(), &[]).expect("Object::new failed");
625 
626         obj.connect("create-child-object", false, move |_args| {
627             Some(
628                 Object::with_type(ChildObject::static_type(), &[])
629                     .expect("Object::new failed")
630                     .to_value(),
631             )
632         })
633         .expect("Failed to connect on 'create-child-object'");
634 
635         let value = obj
636             .emit_by_name("create-child-object", &[])
637             .expect("Failed to emit")
638             .expect("Failed to get value from emit");
639         assert!(value.type_().is_a(ChildObject::static_type()));
640     }
641 }
642