From b96f7db6651f69b2b106371ac8b2874971d10060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 13 Mar 2021 21:15:56 +0200 Subject: [PATCH 1/2] glib: Provide interface subclassing infrastructure to get the parent interface struct Fixes https://github.com/gtk-rs/gtk-rs/issues/328 Fixes https://github.com/gtk-rs/gtk-rs/issues/329 --- glib-macros/src/object_subclass_attribute.rs | 1 + glib/src/subclass/object.rs | 1 + glib/src/subclass/types.rs | 54 ++++++++++++++++++-- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/glib-macros/src/object_subclass_attribute.rs b/glib-macros/src/object_subclass_attribute.rs index fc9c920f0124..b2d00cf81d4c 100644 --- a/glib-macros/src/object_subclass_attribute.rs +++ b/glib-macros/src/object_subclass_attribute.rs @@ -95,6 +95,7 @@ pub fn impl_object_subclass(input: &syn::ItemImpl) -> TokenStream { static mut DATA: #crate_ident::subclass::TypeData = #crate_ident::subclass::TypeData { type_: #crate_ident::Type::INVALID, parent_class: std::ptr::null_mut(), + parent_ifaces: None, class_data: None, private_offset: 0, private_imp_offset: 0, diff --git a/glib/src/subclass/object.rs b/glib/src/subclass/object.rs index 34ac39107be5..087d6ef99982 100644 --- a/glib/src/subclass/object.rs +++ b/glib/src/subclass/object.rs @@ -402,6 +402,7 @@ mod test { } } + #[derive(Clone, Copy)] #[repr(C)] pub struct DummyInterface { parent: gobject_ffi::GTypeInterface, diff --git a/glib/src/subclass/types.rs b/glib/src/subclass/types.rs index c88230784a1f..383071e89de0 100644 --- a/glib/src/subclass/types.rs +++ b/glib/src/subclass/types.rs @@ -129,7 +129,10 @@ pub unsafe trait IsSubclassable: crate::object::IsClass { } /// Trait for implementable interfaces. -pub unsafe trait IsImplementable: crate::object::IsInterface { +pub unsafe trait IsImplementable: crate::object::IsInterface +where + ::GlibClassType: Copy, +{ /// Override the virtual methods of this interface for the given subclass and do other /// interface initialization. /// @@ -145,8 +148,24 @@ pub unsafe trait IsImplementable: crate::object::IsInterface unsafe extern "C" fn interface_init>( iface: ffi::gpointer, _iface_data: ffi::gpointer, -) { +) where + ::GlibClassType: Copy, +{ let iface = &mut *(iface as *mut crate::Interface); + + let mut data = T::type_data(); + if data.as_ref().parent_ifaces.is_none() { + data.as_mut().parent_ifaces = Some(HashMap::new()); + } + { + let copy = Box::new(*iface.as_ref()); + data.as_mut() + .parent_ifaces + .as_mut() + .unwrap() + .insert(A::static_type(), Box::into_raw(copy) as ffi::gpointer); + } + A::interface_init(iface); } @@ -167,7 +186,10 @@ impl InterfaceList for () { fn instance_init(_instance: &mut InitializingObject) {} } -impl> InterfaceList for (A,) { +impl> InterfaceList for (A,) +where + ::GlibClassType: Copy, +{ fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> { vec![( A::static_type().to_glib(), @@ -205,7 +227,10 @@ macro_rules! interface_list_trait( // and then implements the trait on (A, B, C). macro_rules! interface_list_trait_impl( ($($name:ident),+) => ( - impl),+> InterfaceList for ( $($name),+ ) { + impl),+> InterfaceList for ( $($name),+ ) + where + $(<$name as ObjectType>::GlibClassType: Copy),+ + { fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> { let mut types = Vec::new(); interface_list_trait_inner_iface_infos!(types, $($name)+) @@ -287,6 +312,8 @@ pub struct TypeData { #[doc(hidden)] pub parent_class: ffi::gpointer, #[doc(hidden)] + pub parent_ifaces: Option>, + #[doc(hidden)] pub class_data: Option>>, #[doc(hidden)] pub private_offset: isize, @@ -308,9 +335,28 @@ impl TypeData { /// This is used for chaining up to the parent class' implementation /// of virtual methods. pub fn get_parent_class(&self) -> ffi::gpointer { + debug_assert!(!self.parent_class.is_null()); self.parent_class } + /// Returns a pointer to the native parent interface struct for interface `type_`. + /// + /// This is used for chaining up to the parent interface's implementation + /// of virtual methods. + /// + /// # Panics + /// + /// This function panics if the type to which the `TypeData` belongs does not implement the + /// given interface or was not registered yet. + pub fn get_parent_interface(&self) -> ffi::gpointer { + match self.parent_ifaces { + None => unreachable!("No parent interfaces"), + Some(ref parent_ifaces) => *parent_ifaces + .get(&I::static_type()) + .expect("Parent interface not found"), + } + } + /// Returns a pointer to the class implementation specific data. /// /// This is used for class implementations to store additional data. From e3b221744333e79b82ed128595676c4104502b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 13 Mar 2021 21:16:35 +0200 Subject: [PATCH 2/2] gio: Add support for chaining up to parent interface implementations --- gio/src/subclass/action_group.rs | 454 ++++++++++++++++++++++--------- gio/src/subclass/action_map.rs | 57 ++++ gio/src/subclass/list_model.rs | 52 ++++ gio/src/subclass/mod.rs | 8 +- gio/src/subclass/seekable.rs | 127 +++++++++ 5 files changed, 565 insertions(+), 133 deletions(-) diff --git a/gio/src/subclass/action_group.rs b/gio/src/subclass/action_group.rs index 3a1f1ac3c4c7..9caa96536a01 100644 --- a/gio/src/subclass/action_group.rs +++ b/gio/src/subclass/action_group.rs @@ -5,18 +5,162 @@ use glib::subclass::prelude::*; use glib::translate::*; use glib::{Cast, GString, ObjectExt, Quark, Variant, VariantType}; use once_cell::sync::Lazy; +use std::mem; use std::ptr; pub trait ActionGroupImpl: ObjectImpl { fn action_added(&self, action_group: &Self::Type, action_name: &str) { + self.parent_action_added(action_group, action_name); + } + + fn action_enabled_changed(&self, action_group: &Self::Type, action_name: &str, enabled: bool) { + self.parent_action_enabled_changed(action_group, action_name, enabled); + } + + fn action_removed(&self, action_group: &Self::Type, action_name: &str) { + self.parent_action_removed(action_group, action_name); + } + + fn action_state_changed(&self, action_group: &Self::Type, action_name: &str, state: &Variant) { + self.parent_action_state_changed(action_group, action_name, state); + } + + fn activate_action( + &self, + action_group: &Self::Type, + action_name: &str, + parameter: Option<&Variant>, + ) { + self.parent_activate_action(action_group, action_name, parameter); + } + + fn change_action_state(&self, action_group: &Self::Type, action_name: &str, value: &Variant) { + self.parent_change_action_state(action_group, action_name, value) + } + + fn get_action_enabled(&self, action_group: &Self::Type, action_name: &str) -> bool { + self.parent_get_action_enabled(action_group, action_name) + } + + fn get_action_parameter_type( + &self, + action_group: &Self::Type, + action_name: &str, + ) -> Option { + self.parent_get_action_parameter_type(action_group, action_name) + } + + fn get_action_state(&self, action_group: &Self::Type, action_name: &str) -> Option { + self.parent_get_action_state(action_group, action_name) + } + + fn get_action_state_hint( + &self, + action_group: &Self::Type, + action_name: &str, + ) -> Option { + self.parent_get_action_state_hint(action_group, action_name) + } + + fn get_action_state_type( + &self, + action_group: &Self::Type, + action_name: &str, + ) -> Option { + self.parent_get_action_state_type(action_group, action_name) + } + + fn has_action(&self, action_group: &Self::Type, action_name: &str) -> bool { + self.parent_has_action(action_group, action_name) + } + + fn list_actions(&self, action_group: &Self::Type) -> Vec; + fn query_action( + &self, + action_group: &Self::Type, + action_name: &str, + ) -> Option<( + bool, + Option, + Option, + Option, + Option, + )>; +} + +pub trait ActionGroupImplExt: ObjectSubclass { + fn parent_action_added(&self, action_group: &Self::Type, action_name: &str); + fn parent_action_enabled_changed( + &self, + action_group: &Self::Type, + action_name: &str, + enabled: bool, + ); + fn parent_action_removed(&self, action_group: &Self::Type, action_name: &str); + fn parent_action_state_changed( + &self, + action_group: &Self::Type, + action_name: &str, + state: &Variant, + ); + fn parent_activate_action( + &self, + action_group: &Self::Type, + action_name: &str, + parameter: Option<&Variant>, + ); + fn parent_change_action_state( + &self, + action_group: &Self::Type, + action_name: &str, + value: &Variant, + ); + fn parent_get_action_enabled(&self, action_group: &Self::Type, action_name: &str) -> bool; + fn parent_get_action_parameter_type( + &self, + action_group: &Self::Type, + action_name: &str, + ) -> Option; + fn parent_get_action_state( + &self, + action_group: &Self::Type, + action_name: &str, + ) -> Option; + fn parent_get_action_state_hint( + &self, + action_group: &Self::Type, + action_name: &str, + ) -> Option; + fn parent_get_action_state_type( + &self, + action_group: &Self::Type, + action_name: &str, + ) -> Option; + fn parent_has_action(&self, action_group: &Self::Type, action_name: &str) -> bool; + + fn parent_list_actions(&self, action_group: &Self::Type) -> Vec; + fn parent_query_action( + &self, + action_group: &Self::Type, + action_name: &str, + ) -> Option<( + bool, + Option, + Option, + Option, + Option, + )>; +} + +impl ActionGroupImplExt for T { + fn parent_action_added(&self, action_group: &Self::Type, action_name: &str) { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; - if let Some(f) = (*iface).action_added.as_ref() { - f( + if let Some(func) = (*parent_iface).action_added { + func( action_group .unsafe_cast_ref::() .to_glib_none() @@ -24,20 +168,22 @@ pub trait ActionGroupImpl: ObjectImpl { action_name.to_glib_none().0, ); } - - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); } } - fn action_enabled_changed(&self, action_group: &Self::Type, action_name: &str, enabled: bool) { + fn parent_action_enabled_changed( + &self, + action_group: &Self::Type, + action_name: &str, + enabled: bool, + ) { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; - if let Some(f) = (*iface).action_enabled_changed.as_ref() { - f( + if let Some(func) = (*parent_iface).action_enabled_changed { + func( action_group .unsafe_cast_ref::() .to_glib_none() @@ -46,19 +192,17 @@ pub trait ActionGroupImpl: ObjectImpl { enabled.to_glib(), ); } - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); } } - fn action_removed(&self, action_group: &Self::Type, action_name: &str) { + fn parent_action_removed(&self, action_group: &Self::Type, action_name: &str) { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; - if let Some(f) = (*iface).action_removed.as_ref() { - f( + if let Some(func) = (*parent_iface).action_removed { + func( action_group .unsafe_cast_ref::() .to_glib_none() @@ -66,20 +210,22 @@ pub trait ActionGroupImpl: ObjectImpl { action_name.to_glib_none().0, ); } - - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); } } - fn action_state_changed(&self, action_group: &Self::Type, action_name: &str, state: &Variant) { + fn parent_action_state_changed( + &self, + action_group: &Self::Type, + action_name: &str, + state: &Variant, + ) { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; - if let Some(f) = (*iface).action_state_changed.as_ref() { - f( + if let Some(func) = (*parent_iface).action_state_changed { + func( action_group .unsafe_cast_ref::() .to_glib_none() @@ -88,26 +234,24 @@ pub trait ActionGroupImpl: ObjectImpl { state.to_glib_none().0, ); } - - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); } } - fn activate_action( + fn parent_activate_action( &self, action_group: &Self::Type, action_name: &str, parameter: Option<&Variant>, ) { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); - - let f = (*iface).activate_action.as_ref().unwrap(); - - f( + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; + + let func = (*parent_iface) + .activate_action + .expect("no parent \"activate_action\" implementation"); + func( action_group .unsafe_cast_ref::() .to_glib_none() @@ -115,21 +259,24 @@ pub trait ActionGroupImpl: ObjectImpl { action_name.to_glib_none().0, parameter.to_glib_none().0, ); - - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); } } - fn change_action_state(&self, action_group: &Self::Type, action_name: &str, value: &Variant) { + fn parent_change_action_state( + &self, + action_group: &Self::Type, + action_name: &str, + value: &Variant, + ) { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); - - let f = (*iface).change_action_state.as_ref().unwrap(); - - f( + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; + + let func = (*parent_iface) + .change_action_state + .expect("no parent \"change_action_state\" implementation"); + func( action_group .unsafe_cast_ref::() .to_glib_none() @@ -137,157 +284,165 @@ pub trait ActionGroupImpl: ObjectImpl { action_name.to_glib_none().0, value.to_glib_none().0, ); - - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); } } - fn get_action_enabled(&self, action_group: &Self::Type, action_name: &str) -> bool { + fn parent_get_action_enabled(&self, action_group: &Self::Type, action_name: &str) -> bool { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); - - let f = (*iface).get_action_enabled.as_ref().unwrap(); - - let ret = f( + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; + + let func = (*parent_iface) + .get_action_enabled + .expect("no parent \"get_action_enabled\" implementation"); + let ret = func( action_group .unsafe_cast_ref::() .to_glib_none() .0, action_name.to_glib_none().0, ); - - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); from_glib(ret) } } - fn get_action_parameter_type( + fn parent_get_action_parameter_type( &self, action_group: &Self::Type, action_name: &str, ) -> Option { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); - - let f = (*iface).get_action_parameter_type.as_ref().unwrap(); - - let ret = f( + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; + + let func = (*parent_iface) + .get_action_parameter_type + .expect("no parent \"get_action_parameter_type\" implementation"); + let ret = func( action_group .unsafe_cast_ref::() .to_glib_none() .0, action_name.to_glib_none().0, ); - - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); - from_glib_full(ret) + from_glib_none(ret) } } - fn get_action_state(&self, action_group: &Self::Type, action_name: &str) -> Option { + fn parent_get_action_state( + &self, + action_group: &Self::Type, + action_name: &str, + ) -> Option { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); - - let f = (*iface).get_action_state.as_ref().unwrap(); - - let ret = f( + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; + + let func = (*parent_iface) + .get_action_state + .expect("no parent \"get_action_state\" implementation"); + let ret = func( action_group .unsafe_cast_ref::() .to_glib_none() .0, action_name.to_glib_none().0, ); - - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); - from_glib_full(ret) + from_glib_none(ret) } } - fn get_action_state_hint( + fn parent_get_action_state_hint( &self, action_group: &Self::Type, action_name: &str, ) -> Option { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); - - let f = (*iface).get_action_state_hint.as_ref().unwrap(); - - let ret = f( + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; + + let func = (*parent_iface) + .get_action_state_hint + .expect("no parent \"get_action_state_hint\" implementation"); + let ret = func( action_group .unsafe_cast_ref::() .to_glib_none() .0, action_name.to_glib_none().0, ); - - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); - from_glib_full(ret) + from_glib_none(ret) } } - fn get_action_state_type( + fn parent_get_action_state_type( &self, action_group: &Self::Type, action_name: &str, ) -> Option { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); - - let f = (*iface).get_action_state_type.as_ref().unwrap(); - - let ret = f( + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; + + let func = (*parent_iface) + .get_action_state_type + .expect("no parent \"get_action_state_type\" implementation"); + let ret = func( action_group .unsafe_cast_ref::() .to_glib_none() .0, action_name.to_glib_none().0, ); - - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); - from_glib_full(ret) + from_glib_none(ret) } } - fn has_action(&self, action_group: &Self::Type, action_name: &str) -> bool { + fn parent_has_action(&self, action_group: &Self::Type, action_name: &str) -> bool { unsafe { - let type_ = ffi::g_action_group_get_type(); - let iface = glib::gobject_ffi::g_type_default_interface_ref(type_) - as *mut ffi::GActionGroupInterface; - assert!(!iface.is_null()); - - let f = (*iface).has_action.as_ref().unwrap(); - - let ret = f( + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; + + let func = (*parent_iface) + .has_action + .expect("no parent \"has_action\" implementation"); + let ret = func( action_group .unsafe_cast_ref::() .to_glib_none() .0, action_name.to_glib_none().0, ); - - glib::gobject_ffi::g_type_default_interface_unref(iface as glib::ffi::gpointer); from_glib(ret) } } - fn list_actions(&self, action_group: &Self::Type) -> Vec; - fn query_action( + fn parent_list_actions(&self, action_group: &Self::Type) -> Vec { + unsafe { + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; + + let func = (*parent_iface) + .list_actions + .expect("no parent \"list_actions\" implementation"); + let ret = func( + action_group + .unsafe_cast_ref::() + .to_glib_none() + .0, + ); + FromGlibPtrContainer::from_glib_none(ret) + } + } + + fn parent_query_action( &self, action_group: &Self::Type, action_name: &str, @@ -297,7 +452,48 @@ pub trait ActionGroupImpl: ObjectImpl { Option, Option, Option, - )>; + )> { + unsafe { + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionGroupInterface; + + let func = (*parent_iface) + .query_action + .expect("no parent \"query_action\" implementation"); + + let mut enabled = mem::MaybeUninit::uninit(); + let mut parameter_type = ptr::null(); + let mut state_type = ptr::null(); + let mut state_hint = ptr::null_mut(); + let mut state = ptr::null_mut(); + + let ret: bool = from_glib(func( + action_group + .unsafe_cast_ref::() + .to_glib_none() + .0, + action_name.to_glib_none().0, + enabled.as_mut_ptr(), + &mut parameter_type, + &mut state_type, + &mut state_hint, + &mut state, + )); + + if !ret { + None + } else { + Some(( + from_glib(enabled.assume_init()), + from_glib_none(parameter_type), + from_glib_none(state_type), + from_glib_none(state_hint), + from_glib_none(state), + )) + } + } + } } unsafe impl IsImplementable for ActionGroup { diff --git a/gio/src/subclass/action_map.rs b/gio/src/subclass/action_map.rs index 6a4b1c2b1759..70169e3be1a4 100644 --- a/gio/src/subclass/action_map.rs +++ b/gio/src/subclass/action_map.rs @@ -13,6 +13,63 @@ pub trait ActionMapImpl: ObjectImpl { fn remove_action(&self, action_map: &Self::Type, action_name: &str); } +pub trait ActionMapImplExt: ObjectSubclass { + fn parent_lookup_action(&self, action_map: &Self::Type, action_name: &str) -> Option; + fn parent_add_action(&self, action_map: &Self::Type, action: &Action); + fn parent_remove_action(&self, action_map: &Self::Type, action_name: &str); +} + +impl ActionMapImplExt for T { + fn parent_lookup_action(&self, action_map: &Self::Type, name: &str) -> Option { + unsafe { + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionMapInterface; + + let func = (*parent_iface) + .lookup_action + .expect("no parent \"lookup_action\" implementation"); + let ret = func( + action_map.unsafe_cast_ref::().to_glib_none().0, + name.to_glib_none().0, + ); + from_glib_none(ret) + } + } + + fn parent_add_action(&self, action_map: &Self::Type, action: &Action) { + unsafe { + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionMapInterface; + + let func = (*parent_iface) + .add_action + .expect("no parent \"add_action\" implementation"); + func( + action_map.unsafe_cast_ref::().to_glib_none().0, + action.to_glib_none().0, + ); + } + } + + fn parent_remove_action(&self, action_map: &Self::Type, action_name: &str) { + unsafe { + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GActionMapInterface; + + let func = (*parent_iface) + .remove_action + .expect("no parent \"remove_action\" implementation"); + func( + action_map.unsafe_cast_ref::().to_glib_none().0, + action_name.to_glib_none().0, + ); + } + } +} + unsafe impl IsImplementable for ActionMap where ::Type: IsA, diff --git a/gio/src/subclass/list_model.rs b/gio/src/subclass/list_model.rs index b403f5c08b9c..72880ec2afee 100644 --- a/gio/src/subclass/list_model.rs +++ b/gio/src/subclass/list_model.rs @@ -12,6 +12,58 @@ pub trait ListModelImpl: ObjectImpl { fn get_item(&self, list_model: &Self::Type, position: u32) -> Option; } +pub trait ListModelImplExt: ObjectSubclass { + fn parent_get_item_type(&self, list_model: &Self::Type) -> glib::Type; + fn parent_get_n_items(&self, list_model: &Self::Type) -> u32; + fn parent_get_item(&self, list_model: &Self::Type, position: u32) -> Option; +} + +impl ListModelImplExt for T { + fn parent_get_item_type(&self, list_model: &Self::Type) -> glib::Type { + unsafe { + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GListModelInterface; + + let func = (*parent_iface) + .get_item_type + .expect("no parent \"get_item_type\" implementation"); + let ret = func(list_model.unsafe_cast_ref::().to_glib_none().0); + from_glib(ret) + } + } + + fn parent_get_n_items(&self, list_model: &Self::Type) -> u32 { + unsafe { + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GListModelInterface; + + let func = (*parent_iface) + .get_n_items + .expect("no parent \"get_n_items\" implementation"); + func(list_model.unsafe_cast_ref::().to_glib_none().0) + } + } + + fn parent_get_item(&self, list_model: &Self::Type, position: u32) -> Option { + unsafe { + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().get_parent_interface::() + as *const ffi::GListModelInterface; + + let func = (*parent_iface) + .get_item + .expect("no parent \"get_item\" implementation"); + let ret = func( + list_model.unsafe_cast_ref::().to_glib_none().0, + position, + ); + from_glib_full(ret) + } + } +} + unsafe impl IsImplementable for ListModel where ::Type: IsA, diff --git a/gio/src/subclass/mod.rs b/gio/src/subclass/mod.rs index fcd4d478b7fd..e11c019b8a55 100644 --- a/gio/src/subclass/mod.rs +++ b/gio/src/subclass/mod.rs @@ -16,13 +16,13 @@ pub mod prelude { #[doc(hidden)] pub use glib::subclass::prelude::*; - pub use super::action_group::ActionGroupImpl; - pub use super::action_map::ActionMapImpl; + pub use super::action_group::{ActionGroupImpl, ActionGroupImplExt}; + pub use super::action_map::{ActionMapImpl, ActionMapImplExt}; pub use super::application::{ApplicationImpl, ApplicationImplExt}; pub use super::input_stream::{InputStreamImpl, InputStreamImplExt}; pub use super::io_stream::{IOStreamImpl, IOStreamImplExt}; #[cfg(any(feature = "v2_44", feature = "dox"))] - pub use super::list_model::ListModelImpl; + pub use super::list_model::{ListModelImpl, ListModelImplExt}; pub use super::output_stream::{OutputStreamImpl, OutputStreamImplExt}; - pub use super::seekable::SeekableImpl; + pub use super::seekable::{SeekableImpl, SeekableImplExt}; } diff --git a/gio/src/subclass/seekable.rs b/gio/src/subclass/seekable.rs index 2defbf4260c8..0110eb5e6ddc 100644 --- a/gio/src/subclass/seekable.rs +++ b/gio/src/subclass/seekable.rs @@ -8,6 +8,7 @@ use glib::SeekType; use glib::subclass::prelude::*; use std::mem; +use std::ptr; use crate::Cancellable; use crate::Seekable; @@ -31,6 +32,132 @@ pub trait SeekableImpl: ObjectImpl + Send { ) -> Result<(), Error>; } +pub trait SeekableImplExt: ObjectSubclass { + fn parent_tell(&self, seekable: &Self::Type) -> i64; + fn parent_can_seek(&self, seekable: &Self::Type) -> bool; + fn parent_seek( + &self, + seekable: &Self::Type, + offset: i64, + type_: SeekType, + cancellable: Option<&Cancellable>, + ) -> Result<(), Error>; + fn parent_can_truncate(&self, seekable: &Self::Type) -> bool; + fn parent_truncate( + &self, + seekable: &Self::Type, + offset: i64, + cancellable: Option<&Cancellable>, + ) -> Result<(), Error>; +} + +impl SeekableImplExt for T { + fn parent_tell(&self, seekable: &Self::Type) -> i64 { + unsafe { + let type_data = Self::type_data(); + let parent_iface = + type_data.as_ref().get_parent_interface::() as *const ffi::GSeekableIface; + + let func = (*parent_iface) + .tell + .expect("no parent \"tell\" implementation"); + func(seekable.unsafe_cast_ref::().to_glib_none().0) + } + } + + fn parent_can_seek(&self, seekable: &Self::Type) -> bool { + unsafe { + let type_data = Self::type_data(); + let parent_iface = + type_data.as_ref().get_parent_interface::() as *const ffi::GSeekableIface; + + let func = (*parent_iface) + .can_seek + .expect("no parent \"can_seek\" implementation"); + let ret = func(seekable.unsafe_cast_ref::().to_glib_none().0); + from_glib(ret) + } + } + + fn parent_seek( + &self, + seekable: &Self::Type, + offset: i64, + type_: SeekType, + cancellable: Option<&Cancellable>, + ) -> Result<(), Error> { + unsafe { + let type_data = Self::type_data(); + let parent_iface = + type_data.as_ref().get_parent_interface::() as *const ffi::GSeekableIface; + + let func = (*parent_iface) + .seek + .expect("no parent \"seek\" implementation"); + + let mut err = ptr::null_mut(); + func( + seekable.unsafe_cast_ref::().to_glib_none().0, + offset, + type_.to_glib(), + cancellable.to_glib_none().0, + &mut err, + ); + + if err.is_null() { + Ok(()) + } else { + Err(from_glib_full(err)) + } + } + } + + fn parent_can_truncate(&self, seekable: &Self::Type) -> bool { + unsafe { + let type_data = Self::type_data(); + let parent_iface = + type_data.as_ref().get_parent_interface::() as *const ffi::GSeekableIface; + + let func = (*parent_iface) + .can_truncate + .expect("no parent \"can_truncate\" implementation"); + let ret = func(seekable.unsafe_cast_ref::().to_glib_none().0); + from_glib(ret) + } + } + + fn parent_truncate( + &self, + seekable: &Self::Type, + offset: i64, + cancellable: Option<&Cancellable>, + ) -> Result<(), Error> { + unsafe { + let type_data = Self::type_data(); + let parent_iface = + type_data.as_ref().get_parent_interface::() as *const ffi::GSeekableIface; + + let func = (*parent_iface) + .truncate_fn + .expect("no parent \"truncate\" implementation"); + + let mut err = ptr::null_mut(); + func( + seekable.unsafe_cast_ref::().to_glib_none().0, + offset, + cancellable.to_glib_none().0, + &mut err, + ); + + if err.is_null() { + Ok(()) + } else { + Err(from_glib_full(err)) + } + } + } +} + unsafe impl IsImplementable for Seekable { fn interface_init(iface: &mut glib::Interface) { let iface = iface.as_mut();