1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{marker, mem};
4
5use super::{InitializingType, Signal};
6use crate::{prelude::*, translate::*, Object, ParamSpec, Type};
7
8// rustdoc-stripper-ignore-next
9/// Trait for a type list of prerequisite object types.
10pub trait PrerequisiteList {
11 // rustdoc-stripper-ignore-next
12 /// Returns the list of types for this list.
13 fn types() -> Vec<ffi::GType>;
14}
15
16impl PrerequisiteList for () {
17 fn types() -> Vec<ffi::GType> {
18 vec![]
19 }
20}
21
22impl<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).
30macro_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).
47macro_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
57prerequisite_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.
62pub 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
82pub 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
125pub 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
152impl<T: ObjectInterface> ObjectInterfaceExt for T {}
153
154unsafe 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
185pub 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