1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use super::{InitializingType, Signal};
4 use crate::translate::*;
5 use crate::{IsA, Object, ObjectExt, ParamSpec, Type};
6 use std::marker;
7 use std::mem;
8 
9 /// Trait for a type list of prerequisite object types.
10 pub trait PrerequisiteList {
11     /// Returns the list of types for this list.
types() -> Vec<ffi::GType>12     fn types() -> Vec<ffi::GType>;
13 }
14 
15 impl PrerequisiteList for () {
types() -> Vec<ffi::GType>16     fn types() -> Vec<ffi::GType> {
17         vec![]
18     }
19 }
20 
21 impl<T: crate::ObjectType> PrerequisiteList for (T,) {
types() -> Vec<ffi::GType>22     fn types() -> Vec<ffi::GType> {
23         vec![T::static_type().into_glib()]
24     }
25 }
26 
27 // Generates all the PrerequisiteList impls for prerequisite_lists of arbitrary sizes based on a list of type
28 // parameters like A B C. It would generate the impl then for (A, B) and (A, B, C).
29 macro_rules! prerequisite_list_trait(
30     ($name1:ident, $name2: ident, $($name:ident),*) => (
31         prerequisite_list_trait!(__impl $name1, $name2; $($name),*);
32     );
33     (__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => (
34         prerequisite_list_trait_impl!($($name),+);
35         prerequisite_list_trait!(__impl $($name),+ , $name1; $($name2),*);
36     );
37     (__impl $($name:ident),+; $name1:ident) => (
38         prerequisite_list_trait_impl!($($name),+);
39         prerequisite_list_trait_impl!($($name),+, $name1);
40     );
41 );
42 
43 // Generates the impl block for PrerequisiteList on prerequisite_lists or arbitrary sizes based on its
44 // arguments. Takes a list of type parameters as parameters, e.g. A B C
45 // and then implements the trait on (A, B, C).
46 macro_rules! prerequisite_list_trait_impl(
47     ($($name:ident),+) => (
48         impl<$($name: crate::ObjectType),+> PrerequisiteList for ( $($name),+ ) {
49             fn types() -> Vec<ffi::GType> {
50                 vec![$($name::static_type().into_glib()),+]
51             }
52         }
53     );
54 );
55 
56 prerequisite_list_trait!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
57 
58 /// Type methods required for an [`ObjectInterface`] implementation.
59 ///
60 /// This is usually generated by the [`#[object_interface]`](crate::object_interface) attribute macro.
61 pub unsafe trait ObjectInterfaceType {
62     /// Returns the `glib::Type` ID of the interface.
63     ///
64     /// This will register the type with the type system on the first call.
65     #[doc(alias = "get_type")]
type_() -> Type66     fn type_() -> Type;
67 }
68 
69 /// The central trait for defining a `GObject` interface.
70 ///
71 /// Links together the type name, and the interface struct for type registration and allows hooking
72 /// into various steps of the type registration and initialization.
73 ///
74 /// This must only be implemented on `#[repr(C)]` structs and have `gobject_ffi::GTypeInterface` as
75 /// the first field.
76 ///
77 /// See [`register_interface`] for registering an implementation of this trait
78 /// with the type system.
79 ///
80 /// [`register_interface`]: fn.register_interface.html
81 pub unsafe trait ObjectInterface: ObjectInterfaceType + Sized + 'static {
82     /// `GObject` type name.
83     ///
84     /// This must be unique in the whole process.
85     const NAME: &'static str;
86 
87     /// Prerequisites for this interface.
88     ///
89     /// Any implementer of the interface must be a subclass of the prerequisites or implement them
90     /// in case of interfaces.
91     type Prerequisites: PrerequisiteList;
92 
93     /// Additional type initialization.
94     ///
95     /// This is called right after the type was registered and allows
96     /// interfaces to do additional type-specific initialization.
97     ///
98     /// Optional
type_init(_type_: &mut InitializingType<Self>)99     fn type_init(_type_: &mut InitializingType<Self>) {}
100 
101     /// Interface initialization.
102     ///
103     /// This is called after `type_init` and before the first implementor
104     /// of the interface is created. Interfaces can use this to do interface-
105     /// specific initialization, e.g. for installing signals on the interface,
106     /// and for setting default implementations of interface functions.
107     ///
108     /// Optional
interface_init(&mut self)109     fn interface_init(&mut self) {}
110 
111     /// Properties installed for this interface.
112     ///
113     /// All implementors of the interface must provide these properties.
properties() -> &'static [ParamSpec]114     fn properties() -> &'static [ParamSpec] {
115         &[]
116     }
117 
118     /// Signals installed for this interface.
signals() -> &'static [Signal]119     fn signals() -> &'static [Signal] {
120         &[]
121     }
122 }
123 
124 pub trait ObjectInterfaceExt: ObjectInterface {
125     /// Get interface from an instance.
126     ///
127     /// This will panic if `obj` does not implement the interface.
from_instance<T: IsA<Object>>(obj: &T) -> &Self128     fn from_instance<T: IsA<Object>>(obj: &T) -> &Self {
129         assert!(obj.as_ref().type_().is_a(Self::type_()));
130 
131         unsafe {
132             let klass = (*(obj.as_ptr() as *const gobject_ffi::GTypeInstance)).g_class;
133             let interface =
134                 gobject_ffi::g_type_interface_peek(klass as *mut _, Self::type_().into_glib());
135             assert!(!interface.is_null());
136             &*(interface as *const Self)
137         }
138     }
139 }
140 
141 impl<T: ObjectInterface> ObjectInterfaceExt for T {}
142 
interface_init<T: ObjectInterface>( klass: ffi::gpointer, _klass_data: ffi::gpointer, )143 unsafe extern "C" fn interface_init<T: ObjectInterface>(
144     klass: ffi::gpointer,
145     _klass_data: ffi::gpointer,
146 ) {
147     let iface = &mut *(klass as *mut T);
148 
149     let pspecs = <T as ObjectInterface>::properties();
150     for pspec in pspecs {
151         gobject_ffi::g_object_interface_install_property(
152             iface as *mut T as *mut _,
153             pspec.to_glib_none().0,
154         );
155     }
156 
157     let type_ = T::type_();
158     let signals = <T as ObjectInterface>::signals();
159     for signal in signals {
160         signal.register(type_);
161     }
162 
163     iface.interface_init();
164 }
165 
166 /// Register a `glib::Type` ID for `T`.
167 ///
168 /// This must be called only once and will panic on a second call.
169 ///
170 /// The [`object_interface!`] macro will create a `type_()` function around this, which will
171 /// ensure that it's only ever called once.
172 ///
173 /// [`object_interface!`]: ../../macro.object_interface.html
register_interface<T: ObjectInterface>() -> Type174 pub fn register_interface<T: ObjectInterface>() -> Type {
175     unsafe {
176         use std::ffi::CString;
177 
178         let type_name = CString::new(T::NAME).unwrap();
179         assert_eq!(
180             gobject_ffi::g_type_from_name(type_name.as_ptr()),
181             gobject_ffi::G_TYPE_INVALID
182         );
183 
184         let type_ = gobject_ffi::g_type_register_static_simple(
185             Type::INTERFACE.into_glib(),
186             type_name.as_ptr(),
187             mem::size_of::<T>() as u32,
188             Some(interface_init::<T>),
189             0,
190             None,
191             0,
192         );
193 
194         let prerequisites = T::Prerequisites::types();
195         for prerequisite in prerequisites {
196             gobject_ffi::g_type_interface_add_prerequisite(type_, prerequisite);
197         }
198 
199         let type_ = from_glib(type_);
200 
201         T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData));
202 
203         type_
204     }
205 }
206