diff --git a/glib-macros/tests/object_subclass_dynamic.rs b/glib-macros/tests/object_subclass_dynamic.rs index 80890d0d275c..31ad917d215c 100644 --- a/glib-macros/tests/object_subclass_dynamic.rs +++ b/glib-macros/tests/object_subclass_dynamic.rs @@ -11,13 +11,21 @@ mod static_ { // impl for an object interface to register as a static type. #[derive(Clone, Copy)] #[repr(C)] - pub struct MyStaticInterface { + pub struct MyStaticInterfaceClass { parent: glib::gobject_ffi::GTypeInterface, } + unsafe impl InterfaceStruct for MyStaticInterfaceClass { + type Type = MyStaticInterface; + } + + pub enum MyStaticInterface {} + #[glib::object_interface] - unsafe impl ObjectInterface for MyStaticInterface { + impl ObjectInterface for MyStaticInterface { const NAME: &'static str = "MyStaticInterface"; + + type Interface = MyStaticInterfaceClass; } pub trait MyStaticInterfaceImpl: ObjectImpl + ObjectSubclass {} @@ -69,15 +77,22 @@ mod module { // impl for a object interface to register as a dynamic type and that extends `MyStaticInterface`. #[derive(Clone, Copy)] #[repr(C)] - pub struct MyModuleInterface { + pub struct MyModuleInterfaceClass { parent: glib::gobject_ffi::GTypeInterface, } + unsafe impl InterfaceStruct for MyModuleInterfaceClass { + type Type = MyModuleInterface; + } + + pub enum MyModuleInterface {} + #[glib::object_interface] #[object_interface_dynamic] - unsafe impl ObjectInterface for MyModuleInterface { + impl ObjectInterface for MyModuleInterface { const NAME: &'static str = "MyModuleInterface"; type Prerequisites = (MyStaticInterface,); + type Interface = MyModuleInterfaceClass; } pub trait MyModuleInterfaceImpl: ObjectImpl + ObjectSubclass {} @@ -106,15 +121,22 @@ mod module { // impl for an object interface to lazy register as a dynamic type and that extends `MyStaticInterface`. #[derive(Clone, Copy)] #[repr(C)] - pub struct MyModuleInterfaceLazy { + pub struct MyModuleInterfaceLazyClass { parent: glib::gobject_ffi::GTypeInterface, } + unsafe impl InterfaceStruct for MyModuleInterfaceLazyClass { + type Type = MyModuleInterfaceLazy; + } + + pub enum MyModuleInterfaceLazy {} + #[glib::object_interface] #[object_interface_dynamic(lazy_registration = true)] - unsafe impl ObjectInterface for MyModuleInterfaceLazy { + impl ObjectInterface for MyModuleInterfaceLazy { const NAME: &'static str = "MyModuleInterfaceLazy"; type Prerequisites = (MyStaticInterface,); + type Interface = MyModuleInterfaceLazyClass; } pub trait MyModuleInterfaceLazyImpl: ObjectImpl + ObjectSubclass {} @@ -295,15 +317,22 @@ pub mod plugin { // impl for a object interface to register as a dynamic type and that extends `MyStaticInterface`. #[derive(Clone, Copy)] #[repr(C)] - pub struct MyPluginInterface { + pub struct MyPluginInterfaceClass { parent: glib::gobject_ffi::GTypeInterface, } + unsafe impl InterfaceStruct for MyPluginInterfaceClass { + type Type = MyPluginInterface; + } + + pub enum MyPluginInterface {} + #[glib::object_interface] #[object_interface_dynamic(plugin_type = super::MyPlugin)] - unsafe impl ObjectInterface for MyPluginInterface { + impl ObjectInterface for MyPluginInterface { const NAME: &'static str = "MyPluginInterface"; type Prerequisites = (MyStaticInterface,); + type Interface = MyPluginInterfaceClass; } pub trait MyPluginInterfaceImpl: ObjectImpl + ObjectSubclass {} @@ -332,15 +361,22 @@ pub mod plugin { // impl for an object interface to lazy register as a dynamic type and that extends `MyStaticInterface`. #[derive(Clone, Copy)] #[repr(C)] - pub struct MyPluginInterfaceLazy { + pub struct MyPluginInterfaceLazyClass { parent: glib::gobject_ffi::GTypeInterface, } + unsafe impl InterfaceStruct for MyPluginInterfaceLazyClass { + type Type = MyPluginInterfaceLazy; + } + + pub enum MyPluginInterfaceLazy {} + #[glib::object_interface] #[object_interface_dynamic(plugin_type = super::MyPlugin, lazy_registration = true)] - unsafe impl ObjectInterface for MyPluginInterfaceLazy { + impl ObjectInterface for MyPluginInterfaceLazy { const NAME: &'static str = "MyPluginInterfaceLazy"; type Prerequisites = (MyStaticInterface,); + type Interface = MyPluginInterfaceLazyClass; } pub trait MyPluginInterfaceLazyImpl: ObjectImpl + ObjectSubclass {} diff --git a/glib/src/object.rs b/glib/src/object.rs index 7925796f2e75..6782905f94d7 100644 --- a/glib/src/object.rs +++ b/glib/src/object.rs @@ -1317,6 +1317,15 @@ macro_rules! glib_object_wrapper { ); }; + (@object_interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $iface:ty, + @type_ $get_type_expr:expr, @requires [$($requires:tt)*]) => { + $crate::glib_object_wrapper!( + @interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $iface, std::os::raw::c_void, + @ffi_class <$iface as $crate::subclass::interface::ObjectInterface>::Interface, + @type_ $get_type_expr, @requires [$($requires)*] + ); + }; + (@interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty, @type_ $get_type_expr:expr, @requires [$($requires:tt)*]) => { $crate::glib_object_wrapper!( diff --git a/glib/src/subclass/interface.rs b/glib/src/subclass/interface.rs index 5fdafe934c6d..85197dbb65f7 100644 --- a/glib/src/subclass/interface.rs +++ b/glib/src/subclass/interface.rs @@ -2,7 +2,7 @@ use std::{marker, mem}; -use super::{InitializingType, Signal}; +use super::{types::InterfaceStruct, InitializingType, Signal}; use crate::{prelude::*, translate::*, Object, ParamSpec, Type, TypeFlags, TypeInfo}; // rustdoc-stripper-ignore-next @@ -69,17 +69,15 @@ pub unsafe trait ObjectInterfaceType { /// The central trait for defining a `GObject` interface. /// -/// Links together the type name, and the interface struct for type registration and allows hooking -/// into various steps of the type registration and initialization. -/// -/// This must only be implemented on `#[repr(C)]` structs and have `gobject_ffi::GTypeInterface` as -/// the first field. +/// Links together the type name, the empty instance and class structs for type +/// registration and allows hooking into various steps of the type registration +/// and initialization. /// /// See [`register_interface`] for registering an implementation of this trait /// with the type system. /// /// [`register_interface`]: fn.register_interface.html -pub unsafe trait ObjectInterface: ObjectInterfaceType + Sized + 'static { +pub trait ObjectInterface: ObjectInterfaceType + Sized + 'static { /// `GObject` type name. /// /// This must be unique in the whole process. @@ -91,6 +89,10 @@ pub unsafe trait ObjectInterface: ObjectInterfaceType + Sized + 'static { /// in case of interfaces. type Prerequisites: PrerequisiteList; + // rustdoc-stripper-ignore-next + /// The C class struct. + type Interface: InterfaceStruct; + /// Additional type initialization. /// /// This is called right after the type was registered and allows @@ -107,7 +109,7 @@ pub unsafe trait ObjectInterface: ObjectInterfaceType + Sized + 'static { /// and for setting default implementations of interface functions. /// /// Optional - fn interface_init(&mut self) {} + fn interface_init(_klass: &mut Self::Interface) {} /// Properties installed for this interface. /// @@ -155,12 +157,12 @@ unsafe extern "C" fn interface_init( klass: ffi::gpointer, _klass_data: ffi::gpointer, ) { - let iface = &mut *(klass as *mut T); + let iface = &mut *(klass as *mut T::Interface); let pspecs = ::properties(); for pspec in pspecs { gobject_ffi::g_object_interface_install_property( - iface as *mut T as *mut _, + iface as *mut T::Interface as *mut _, pspec.to_glib_none().0, ); } @@ -171,10 +173,10 @@ unsafe extern "C" fn interface_init( signal.register(type_); } - iface.interface_init(); + T::interface_init(iface); } -/// Register a `glib::Type` ID for `T`. +/// Register a `glib::Type` ID for `T::Class`. /// /// This must be called only once and will panic on a second call. /// @@ -195,7 +197,7 @@ pub fn register_interface() -> Type { let type_ = gobject_ffi::g_type_register_static_simple( Type::INTERFACE.into_glib(), type_name.as_ptr(), - mem::size_of::() as u32, + mem::size_of::() as u32, Some(interface_init::), 0, None, @@ -216,7 +218,7 @@ pub fn register_interface() -> Type { } } -/// Registers a `glib::Type` ID for `T` as a dynamic type. +/// Registers a `glib::Type` ID for `T::Class` as a dynamic type. /// /// An object interface must be explicitly registered as a dynamic type when /// the system loads the implementation by calling [`TypePluginImpl::use_`] or @@ -243,7 +245,7 @@ pub fn register_dynamic_interface() as u16, + class_size: mem::size_of::() as u16, class_init: Some(interface_init::), ..TypeInfo::default().0 }); diff --git a/glib/src/subclass/mod.rs b/glib/src/subclass/mod.rs index ddaf96e59818..2ac82b03ee0f 100644 --- a/glib/src/subclass/mod.rs +++ b/glib/src/subclass/mod.rs @@ -450,9 +450,9 @@ pub mod prelude { type_module::{TypeModuleImpl, TypeModuleImplExt}, type_plugin::{TypePluginImpl, TypePluginImplExt, TypePluginRegisterImpl}, types::{ - ClassStruct, InstanceStruct, InstanceStructExt, IsImplementable, IsSubclassable, - IsSubclassableExt, ObjectSubclass, ObjectSubclassExt, ObjectSubclassIsExt, - ObjectSubclassType, + ClassStruct, InstanceStruct, InstanceStructExt, InterfaceStruct, IsImplementable, + IsSubclassable, IsSubclassableExt, ObjectSubclass, ObjectSubclassExt, + ObjectSubclassIsExt, ObjectSubclassType, }, }; } diff --git a/glib/src/subclass/object.rs b/glib/src/subclass/object.rs index e840e13d8e36..24713dbcae7c 100644 --- a/glib/src/subclass/object.rs +++ b/glib/src/subclass/object.rs @@ -460,9 +460,16 @@ mod test { parent: gobject_ffi::GTypeInterface, } + unsafe impl InterfaceStruct for DummyInterface { + type Type = Dummy; + } + + pub enum Dummy {} + #[glib::object_interface] - unsafe impl ObjectInterface for DummyInterface { + impl ObjectInterface for Dummy { const NAME: &'static str = "Dummy"; + type Interface = DummyInterface; } } @@ -475,7 +482,7 @@ mod test { } wrapper! { - pub struct Dummy(ObjectInterface); + pub struct Dummy(ObjectInterface); } unsafe impl IsImplementable for Dummy {} diff --git a/glib/src/subclass/types.rs b/glib/src/subclass/types.rs index 1e4e8a5b1479..d4547986ce45 100644 --- a/glib/src/subclass/types.rs +++ b/glib/src/subclass/types.rs @@ -5,7 +5,7 @@ use std::{any::Any, collections::BTreeMap, marker, mem, ptr}; -use super::SignalId; +use super::{interface::ObjectInterface, SignalId}; use crate::{ object::{IsClass, IsInterface, ObjectSubclassIs, ParentClassIs}, prelude::*, @@ -280,11 +280,29 @@ impl IsSubclassableExt for U { } // rustdoc-stripper-ignore-next -/// Trait for implementable interfaces. -pub unsafe trait IsImplementable: IsInterface +/// Trait implemented by structs that implement a `GTypeInterface` C class struct. +/// +/// This must only be implemented on `#[repr(C)]` structs and have an interface +/// that inherits from `gobject_ffi::GTypeInterface` as the first field. +pub unsafe trait InterfaceStruct: Sized + 'static where - ::GlibClassType: Copy, + Self: Copy, { + // rustdoc-stripper-ignore-next + /// Corresponding object interface type for this class struct. + type Type: ObjectInterface; + + // rustdoc-stripper-ignore-next + /// Set up default implementations for interface vfuncs. + /// + /// This is automatically called during type initialization. + #[inline] + fn interface_init(&mut self) {} +} + +// rustdoc-stripper-ignore-next +/// Trait for implementable interfaces. +pub unsafe trait IsImplementable: IsInterface { // rustdoc-stripper-ignore-next /// Override the virtual methods of this interface for the given subclass and do other /// interface initialization. @@ -631,7 +649,7 @@ pub trait ObjectSubclass: ObjectSubclassType + Sized + 'static { // rustdoc-stripper-ignore-next /// The C class struct. /// - /// See [`basic::ClassStruct`] for an basic instance struct that should be + /// See [`basic::ClassStruct`] for an basic class struct that should be /// used in most cases. /// /// [`basic::ClassStruct`]: ../basic/struct.ClassStruct.html diff --git a/glib/src/wrapper.rs b/glib/src/wrapper.rs index 1ad0610cf28c..a45b41fa123e 100644 --- a/glib/src/wrapper.rs +++ b/glib/src/wrapper.rs @@ -436,8 +436,7 @@ macro_rules! wrapper { $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectInterface<$iface_name:ty>) $(@requires $($requires:path),+)?; ) => { $crate::glib_object_wrapper!( - @interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, std::os::raw::c_void, - @ffi_class $iface_name, + @object_interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $iface_name, @type_ $crate::translate::IntoGlib::into_glib(<$iface_name as $crate::subclass::interface::ObjectInterfaceType>::type_()), @requires [$( $($requires),+ )?] );