glib/subclass/
interface.rs

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::{types::InterfaceStruct, InitializingType, Signal};
6use 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.
12pub trait PrerequisiteList {
13    // rustdoc-stripper-ignore-next
14    /// Returns the list of types for this list.
15    fn types() -> Vec<Type>;
16}
17
18impl PrerequisiteList for () {
19    fn types() -> Vec<Type> {
20        vec![]
21    }
22}
23
24impl<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).
32macro_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).
49macro_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
59prerequisite_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.
64pub 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
82pub 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
154pub 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
181impl<T: ObjectInterface> ObjectInterfaceExt for T {}
182
183unsafe extern "C" fn interface_init<T: ObjectInterface>(
184    klass: ffi::gpointer,
185    _klass_data: ffi::gpointer,
186) {
187    let iface = &mut *(klass as *mut T::Interface);
188
189    let pspecs = <T as ObjectInterface>::properties();
190    for pspec 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_ = T::type_();
198    let signals = <T as ObjectInterface>::signals();
199    for signal in signals {
200        signal.register(type_);
201    }
202
203    T::interface_init(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
214pub 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
286pub 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}