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