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::{types::InterfaceStruct, InitializingType, Signal}; |
6 | use crate::{ |
7 | ffi, gobject_ffi, prelude::*, translate::*, Object, ParamSpec, Type, TypeFlags, TypeInfo, |
8 | }; |
9 | |
10 | // rustdoc-stripper-ignore-next |
11 | /// Trait for a type list of prerequisite object types. |
12 | pub trait PrerequisiteList { |
13 | // rustdoc-stripper-ignore-next |
14 | /// Returns the list of types for this list. |
15 | fn types() -> Vec<Type>; |
16 | } |
17 | |
18 | impl PrerequisiteList for () { |
19 | fn types() -> Vec<Type> { |
20 | vec![] |
21 | } |
22 | } |
23 | |
24 | impl<T: ObjectType> PrerequisiteList for (T,) { |
25 | fn types() -> Vec<Type> { |
26 | vec![T::static_type()] |
27 | } |
28 | } |
29 | |
30 | // Generates all the PrerequisiteList impls for prerequisite_lists of arbitrary sizes based on a list of type |
31 | // parameters like A B C. It would generate the impl then for (A, B) and (A, B, C). |
32 | macro_rules! prerequisite_list_trait( |
33 | ($name1:ident, $name2: ident, $($name:ident),*) => ( |
34 | prerequisite_list_trait!(__impl $name1, $name2; $($name),*); |
35 | ); |
36 | (__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => ( |
37 | prerequisite_list_trait_impl!($($name),+); |
38 | prerequisite_list_trait!(__impl $($name),+ , $name1; $($name2),*); |
39 | ); |
40 | (__impl $($name:ident),+; $name1:ident) => ( |
41 | prerequisite_list_trait_impl!($($name),+); |
42 | prerequisite_list_trait_impl!($($name),+, $name1); |
43 | ); |
44 | ); |
45 | |
46 | // Generates the impl block for PrerequisiteList on prerequisite_lists or arbitrary sizes based on its |
47 | // arguments. Takes a list of type parameters as parameters, e.g. A B C |
48 | // and then implements the trait on (A, B, C). |
49 | macro_rules! prerequisite_list_trait_impl( |
50 | ($($name:ident),+) => ( |
51 | impl<$($name: ObjectType),+> PrerequisiteList for ( $($name),+ ) { |
52 | fn types() -> Vec<Type> { |
53 | vec![$($name::static_type()),+] |
54 | } |
55 | } |
56 | ); |
57 | ); |
58 | |
59 | prerequisite_list_trait!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S); |
60 | |
61 | /// Type methods required for an [`ObjectInterface`] implementation. |
62 | /// |
63 | /// This is usually generated by the [`#[object_interface]`](crate::object_interface) attribute macro. |
64 | pub unsafe trait ObjectInterfaceType { |
65 | /// Returns the `glib::Type` ID of the interface. |
66 | /// |
67 | /// This will register the type with the type system on the first call. |
68 | #[doc (alias = "get_type" )] |
69 | fn type_() -> Type; |
70 | } |
71 | |
72 | /// The central trait for defining a `GObject` interface. |
73 | /// |
74 | /// Links together the type name, the empty instance and class structs for type |
75 | /// registration and allows hooking into various steps of the type registration |
76 | /// and initialization. |
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 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 | // rustdoc-stripper-ignore-next |
89 | /// Allow name conflicts for this class. |
90 | /// |
91 | /// By default, trying to register a type with a name that was registered before will panic. If |
92 | /// this is set to `true` then a new name will be selected by appending a counter. |
93 | /// |
94 | /// This is useful for defining new types in Rust library crates that might be linked multiple |
95 | /// times in the same process. |
96 | /// |
97 | /// A consequence of setting this to `true` is that it's not guaranteed that |
98 | /// `glib::Type::from_name(Self::NAME).unwrap() == Self::type_()`. |
99 | /// |
100 | /// Note that this is not allowed for dynamic types. If a dynamic type is registered and a type |
101 | /// with that name exists already, it is assumed that they're the same. |
102 | /// |
103 | /// Optional. |
104 | const ALLOW_NAME_CONFLICT: bool = false; |
105 | |
106 | /// Prerequisites for this interface. |
107 | /// |
108 | /// Any implementer of the interface must be a subclass of the prerequisites or implement them |
109 | /// in case of interfaces. |
110 | type Prerequisites: PrerequisiteList; |
111 | |
112 | // rustdoc-stripper-ignore-next |
113 | /// The C instance struct. This is usually either `std::ffi::c_void` or a newtype wrapper |
114 | /// around it. |
115 | /// |
116 | /// Optional |
117 | type Instance; |
118 | |
119 | // rustdoc-stripper-ignore-next |
120 | /// The C class struct. |
121 | type Interface: InterfaceStruct<Type = Self>; |
122 | |
123 | /// Additional type initialization. |
124 | /// |
125 | /// This is called right after the type was registered and allows |
126 | /// interfaces to do additional type-specific initialization. |
127 | /// |
128 | /// Optional |
129 | fn type_init(_type_: &mut InitializingType<Self>) {} |
130 | |
131 | /// Interface initialization. |
132 | /// |
133 | /// This is called after `type_init` and before the first implementor |
134 | /// of the interface is created. Interfaces can use this to do interface- |
135 | /// specific initialization, e.g. for installing signals on the interface, |
136 | /// and for setting default implementations of interface functions. |
137 | /// |
138 | /// Optional |
139 | fn interface_init(_klass: &mut Self::Interface) {} |
140 | |
141 | /// Properties installed for this interface. |
142 | /// |
143 | /// All implementors of the interface must provide these properties. |
144 | fn properties() -> &'static [ParamSpec] { |
145 | &[] |
146 | } |
147 | |
148 | /// Signals installed for this interface. |
149 | fn signals() -> &'static [Signal] { |
150 | &[] |
151 | } |
152 | } |
153 | |
154 | pub trait ObjectInterfaceExt: ObjectInterface { |
155 | /// Get interface from an instance. |
156 | /// |
157 | /// This will panic if `obj` does not implement the interface. |
158 | #[inline ] |
159 | #[deprecated = "Use from_obj() instead" ] |
160 | fn from_instance<T: IsA<Object>>(obj: &T) -> &Self { |
161 | Self::from_obj(obj) |
162 | } |
163 | |
164 | /// Get interface from an instance. |
165 | /// |
166 | /// This will panic if `obj` does not implement the interface. |
167 | #[inline ] |
168 | fn from_obj<T: IsA<Object>>(obj: &T) -> &Self { |
169 | assert!(obj.as_ref().type_().is_a(Self::type_())); |
170 | |
171 | unsafe { |
172 | let klass = (*(obj.as_ptr() as *const gobject_ffi::GTypeInstance)).g_class; |
173 | let interface = |
174 | gobject_ffi::g_type_interface_peek(klass as *mut _, Self::type_().into_glib()); |
175 | debug_assert!(!interface.is_null()); |
176 | &*(interface as *const Self) |
177 | } |
178 | } |
179 | } |
180 | |
181 | impl<T: ObjectInterface> ObjectInterfaceExt for T {} |
182 | |
183 | unsafe extern "C" fn interface_init<T: ObjectInterface>( |
184 | klass: ffi::gpointer, |
185 | _klass_data: ffi::gpointer, |
186 | ) { |
187 | let iface: &mut ::Interface = &mut *(klass as *mut T::Interface); |
188 | |
189 | let pspecs: &'static [ParamSpec] = <T as ObjectInterface>::properties(); |
190 | for pspec: &'static ParamSpec in pspecs { |
191 | gobject_ffi::g_object_interface_install_property( |
192 | iface as *mut T::Interface as *mut _, |
193 | pspec.to_glib_none().0, |
194 | ); |
195 | } |
196 | |
197 | let type_: Type = T::type_(); |
198 | let signals: &'static [Signal] = <T as ObjectInterface>::signals(); |
199 | for signal: &'static Signal in signals { |
200 | signal.register(type_); |
201 | } |
202 | |
203 | T::interface_init(_klass:iface); |
204 | } |
205 | |
206 | /// Register a `glib::Type` ID for `T::Class`. |
207 | /// |
208 | /// This must be called only once and will panic on a second call. |
209 | /// |
210 | /// The [`object_interface!`] macro will create a `type_()` function around this, which will |
211 | /// ensure that it's only ever called once. |
212 | /// |
213 | /// [`object_interface!`]: ../../macro.object_interface.html |
214 | pub fn register_interface<T: ObjectInterface>() -> Type { |
215 | assert_eq!(mem::size_of::<T>(), 0); |
216 | |
217 | unsafe { |
218 | use std::ffi::CString; |
219 | |
220 | let type_name = if T::ALLOW_NAME_CONFLICT { |
221 | let mut i = 0; |
222 | loop { |
223 | let type_name = CString::new(if i == 0 { |
224 | T::NAME.to_string() |
225 | } else { |
226 | format!(" {}- {}" , T::NAME, i) |
227 | }) |
228 | .unwrap(); |
229 | if gobject_ffi::g_type_from_name(type_name.as_ptr()) == gobject_ffi::G_TYPE_INVALID |
230 | { |
231 | break type_name; |
232 | } |
233 | i += 1; |
234 | } |
235 | } else { |
236 | let type_name = CString::new(T::NAME).unwrap(); |
237 | assert_eq!( |
238 | gobject_ffi::g_type_from_name(type_name.as_ptr()), |
239 | gobject_ffi::G_TYPE_INVALID, |
240 | "Type {} has already been registered" , |
241 | type_name.to_str().unwrap() |
242 | ); |
243 | |
244 | type_name |
245 | }; |
246 | |
247 | let type_ = gobject_ffi::g_type_register_static_simple( |
248 | Type::INTERFACE.into_glib(), |
249 | type_name.as_ptr(), |
250 | mem::size_of::<T::Interface>() as u32, |
251 | Some(interface_init::<T>), |
252 | 0, |
253 | None, |
254 | 0, |
255 | ); |
256 | |
257 | let prerequisites = T::Prerequisites::types(); |
258 | for prerequisite in prerequisites { |
259 | gobject_ffi::g_type_interface_add_prerequisite(type_, prerequisite.into_glib()); |
260 | } |
261 | |
262 | let type_ = Type::from_glib(type_); |
263 | assert!(type_.is_valid()); |
264 | |
265 | T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData)); |
266 | |
267 | type_ |
268 | } |
269 | } |
270 | |
271 | /// Registers a `glib::Type` ID for `T::Class` as a dynamic type. |
272 | /// |
273 | /// An object interface must be explicitly registered as a dynamic type when |
274 | /// the system loads the implementation by calling [`TypePluginImpl::use_`] or |
275 | /// more specifically [`TypeModuleImpl::load`]. Therefore, unlike for object |
276 | /// interfaces registered as static types, object interfaces registered as |
277 | /// dynamic types can be registered several times. |
278 | /// |
279 | /// The [`object_interface_dynamic!`] macro helper attribute will create |
280 | /// `register_interface()` and `on_implementation_load()` functions around this, |
281 | /// which will ensure that the function is called when necessary. |
282 | /// |
283 | /// [`object_interface_dynamic!`]: ../../../glib_macros/attr.object_interface.html |
284 | /// [`TypePluginImpl::use_`]: ../type_plugin/trait.TypePluginImpl.html#method.use_ |
285 | /// [`TypeModuleImpl::load`]: ../type_module/trait.TypeModuleImpl.html#method.load |
286 | pub fn register_dynamic_interface<P: DynamicObjectRegisterExt, T: ObjectInterface>( |
287 | type_plugin: &P, |
288 | ) -> Type { |
289 | assert_eq!(mem::size_of::<T>(), 0); |
290 | |
291 | unsafe { |
292 | use std::ffi::CString; |
293 | |
294 | let type_name = CString::new(T::NAME).unwrap(); |
295 | |
296 | let already_registered = |
297 | gobject_ffi::g_type_from_name(type_name.as_ptr()) != gobject_ffi::G_TYPE_INVALID; |
298 | |
299 | let type_info = TypeInfo(gobject_ffi::GTypeInfo { |
300 | class_size: mem::size_of::<T::Interface>() as u16, |
301 | class_init: Some(interface_init::<T>), |
302 | ..TypeInfo::default().0 |
303 | }); |
304 | |
305 | // registers the interface within the `type_plugin` |
306 | let type_ = type_plugin.register_dynamic_type( |
307 | Type::INTERFACE, |
308 | type_name.to_str().unwrap(), |
309 | &type_info, |
310 | TypeFlags::ABSTRACT, |
311 | ); |
312 | |
313 | let prerequisites = T::Prerequisites::types(); |
314 | for prerequisite in prerequisites { |
315 | // adding prerequisite interface can be done only once |
316 | if !already_registered { |
317 | gobject_ffi::g_type_interface_add_prerequisite( |
318 | type_.into_glib(), |
319 | prerequisite.into_glib(), |
320 | ); |
321 | } |
322 | } |
323 | |
324 | assert!(type_.is_valid()); |
325 | |
326 | T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData)); |
327 | |
328 | type_ |
329 | } |
330 | } |
331 | |