| 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 | |