use std::{any::Any, collections::BTreeMap, marker, mem, ptr};
use super::{interface::ObjectInterface, SignalId};
use crate::{
ffi, gobject_ffi,
object::{IsClass, IsInterface, ObjectSubclassIs, ParentClassIs},
prelude::*,
translate::*,
Closure, InterfaceInfo, Object, Type, TypeFlags, TypeInfo, Value,
};
#[derive(Debug, PartialEq, Eq)]
pub struct InitializingType<T>(pub(crate) Type, pub(crate) marker::PhantomData<*const T>);
impl<T> IntoGlib for InitializingType<T> {
type GlibType = ffi::GType;
#[inline]
fn into_glib(self) -> ffi::GType {
self.0.into_glib()
}
}
struct PrivateStruct<T: ObjectSubclass> {
imp: T,
instance_data: Option<BTreeMap<Type, Box<dyn Any + Send + Sync>>>,
}
pub unsafe trait InstanceStruct: Sized + 'static {
type Type: ObjectSubclass;
#[inline]
fn instance_init(&mut self) {
unsafe {
let obj = from_glib_borrow::<_, Object>(self as *mut _ as *mut gobject_ffi::GObject);
let obj = Borrowed::new(obj.into_inner().unsafe_cast());
let mut obj = InitializingObject(obj);
<<Self::Type as ObjectSubclass>::ParentType as IsSubclassable<Self::Type>>::instance_init(
&mut obj,
);
}
}
}
pub unsafe trait InstanceStructExt: InstanceStruct {
#[doc(alias = "get_impl")]
fn imp(&self) -> &Self::Type;
#[doc(alias = "get_class")]
fn class(&self) -> &<Self::Type as ObjectSubclass>::Class;
}
#[inline]
fn offset_ptr_by_bytes<T, U>(ptr: *const T, offset: isize) -> *const U {
let ptr = ptr as usize;
let ptr = if offset < 0 {
ptr - (-offset) as usize
} else {
ptr + offset as usize
};
debug_assert_eq!(ptr & (mem::align_of::<U>() - 1), 0);
ptr as *const U
}
#[inline]
fn offset_ptr_by_bytes_mut<T, U>(ptr: *mut T, offset: isize) -> *mut U {
let ptr = ptr as usize;
let ptr = if offset < 0 {
ptr - (-offset) as usize
} else {
ptr + offset as usize
};
debug_assert_eq!(ptr & (mem::align_of::<U>() - 1), 0);
ptr as *mut U
}
unsafe impl<T: InstanceStruct> InstanceStructExt for T {
#[inline]
fn imp(&self) -> &Self::Type {
unsafe {
let data = Self::Type::type_data();
let private_offset = data.as_ref().impl_offset();
let imp = offset_ptr_by_bytes::<T, Self::Type>(self, private_offset);
&*imp
}
}
#[inline]
fn class(&self) -> &<Self::Type as ObjectSubclass>::Class {
unsafe { &**(self as *const _ as *const *const <Self::Type as ObjectSubclass>::Class) }
}
}
pub trait ObjectSubclassIsExt: ObjectSubclassIs {
fn imp(&self) -> &Self::Subclass;
}
impl<T: ObjectSubclassIs<Subclass = S>, S: ObjectSubclass<Type = Self>> ObjectSubclassIsExt for T {
#[inline]
fn imp(&self) -> &T::Subclass {
T::Subclass::from_obj(self)
}
}
pub unsafe trait ClassStruct: Sized + 'static {
type Type: ObjectSubclass;
#[inline]
fn class_init(&mut self) {
unsafe {
let base = &mut *(self as *mut _
as *mut crate::Class<<Self::Type as ObjectSubclass>::ParentType>);
<<Self::Type as ObjectSubclass>::ParentType as IsSubclassable<Self::Type>>::class_init(
base,
);
}
}
}
pub unsafe trait IsSubclassable<T: ObjectSubclass>: IsSubclassableDefault<T> {
#[inline]
fn class_init(class: &mut crate::Class<Self>) {
Self::default_class_init(class);
}
#[inline]
fn instance_init(instance: &mut InitializingObject<T>) {
Self::default_instance_init(instance);
}
}
#[doc(hidden)]
pub trait IsSubclassableDefault<T: ObjectSubclass>: IsClass {
fn default_class_init(class: &mut crate::Class<Self>);
fn default_instance_init(instance: &mut InitializingObject<T>);
}
impl<T: ObjectSubclass, U: IsSubclassable<T> + ParentClassIs> IsSubclassableDefault<T> for U
where
U::Parent: IsSubclassable<T>,
{
#[inline]
fn default_class_init(class: &mut crate::Class<Self>) {
U::Parent::class_init(class);
}
#[inline]
fn default_instance_init(instance: &mut InitializingObject<T>) {
U::Parent::instance_init(instance);
}
}
impl<T: ObjectSubclass> IsSubclassableDefault<T> for Object {
#[inline]
fn default_class_init(_class: &mut crate::Class<Self>) {}
#[inline]
fn default_instance_init(_instance: &mut InitializingObject<T>) {}
}
pub trait IsSubclassableExt: IsClass + ParentClassIs {
fn parent_class_init<T: ObjectSubclass>(class: &mut crate::Class<Self>)
where
Self::Parent: IsSubclassable<T>;
fn parent_instance_init<T: ObjectSubclass>(instance: &mut InitializingObject<T>)
where
Self::Parent: IsSubclassable<T>;
}
impl<U: IsClass + ParentClassIs> IsSubclassableExt for U {
#[inline]
fn parent_class_init<T: ObjectSubclass>(class: &mut crate::Class<Self>)
where
U::Parent: IsSubclassable<T>,
{
Self::Parent::class_init(class);
}
#[inline]
fn parent_instance_init<T: ObjectSubclass>(instance: &mut InitializingObject<T>)
where
U::Parent: IsSubclassable<T>,
{
Self::Parent::instance_init(instance);
}
}
pub unsafe trait InterfaceStruct: Sized + 'static
where
Self: Copy,
{
type Type: ObjectInterface;
#[inline]
fn interface_init(&mut self) {}
}
pub unsafe trait IsImplementable<T: ObjectSubclass>: IsInterface {
fn interface_init(_iface: &mut crate::Interface<Self>) {}
fn instance_init(_instance: &mut InitializingObject<T>) {}
}
unsafe extern "C" fn interface_init<T: ObjectSubclass, A: IsImplementable<T>>(
iface: ffi::gpointer,
_iface_data: ffi::gpointer,
) where
<A as ObjectType>::GlibClassType: Copy,
{
let iface = &mut *(iface as *mut crate::Interface<A>);
let mut data = T::type_data();
if data.as_ref().parent_ifaces.is_none() {
data.as_mut().parent_ifaces = Some(BTreeMap::default());
}
{
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);
}
pub trait InterfaceList<T: ObjectSubclass> {
fn iface_infos() -> Vec<(Type, InterfaceInfo)>;
fn instance_init(_instance: &mut InitializingObject<T>);
}
impl<T: ObjectSubclass> InterfaceList<T> for () {
fn iface_infos() -> Vec<(Type, InterfaceInfo)> {
vec![]
}
#[inline]
fn instance_init(_instance: &mut InitializingObject<T>) {}
}
impl<T: ObjectSubclass, A: IsImplementable<T>> InterfaceList<T> for (A,)
where
<A as ObjectType>::GlibClassType: Copy,
{
fn iface_infos() -> Vec<(Type, InterfaceInfo)> {
vec![(
A::static_type(),
InterfaceInfo(gobject_ffi::GInterfaceInfo {
interface_init: Some(interface_init::<T, A>),
..InterfaceInfo::default().0
}),
)]
}
#[inline]
fn instance_init(instance: &mut InitializingObject<T>) {
A::instance_init(instance);
}
}
macro_rules! interface_list_trait(
($name1:ident, $name2: ident, $($name:ident),*) => (
interface_list_trait!(__impl $name1, $name2; $($name),*);
);
(__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => (
interface_list_trait_impl!($($name),+);
interface_list_trait!(__impl $($name),+ , $name1; $($name2),*);
);
(__impl $($name:ident),+; $name1:ident) => (
interface_list_trait_impl!($($name),+);
interface_list_trait_impl!($($name),+, $name1);
);
);
macro_rules! interface_list_trait_impl(
($($name:ident),+) => (
impl<T: ObjectSubclass, $($name: IsImplementable<T>),+> InterfaceList<T> for ( $($name),+ )
where
$(<$name as ObjectType>::GlibClassType: Copy),+
{
fn iface_infos() -> Vec<(Type, InterfaceInfo)> {
vec![
$(
(
$name::static_type(),
InterfaceInfo(gobject_ffi::GInterfaceInfo {
interface_init: Some(interface_init::<T, $name>),
interface_finalize: None,
interface_data: ptr::null_mut(),
}),
)
),+
]
}
#[inline]
fn instance_init(instance: &mut InitializingObject<T>) {
$(
$name::instance_init(instance);
)+
}
}
);
);
interface_list_trait!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
pub struct TypeData {
type_: Type,
parent_class: ffi::gpointer,
parent_ifaces: Option<BTreeMap<Type, ffi::gpointer>>,
class_data: Option<BTreeMap<Type, Box<dyn Any + Send + Sync>>>,
private_offset: isize,
private_imp_offset: isize,
}
unsafe impl Send for TypeData {}
unsafe impl Sync for TypeData {}
impl TypeData {
pub const fn new() -> Self {
Self {
type_: Type::INVALID,
parent_class: ::std::ptr::null_mut(),
parent_ifaces: None,
class_data: None,
private_offset: 0,
private_imp_offset: 0,
}
}
#[inline]
#[doc(alias = "get_type")]
pub fn type_(&self) -> Type {
self.type_
}
#[doc(alias = "get_parent_class")]
#[inline]
pub fn parent_class(&self) -> ffi::gpointer {
debug_assert!(!self.parent_class.is_null());
self.parent_class
}
#[doc(alias = "get_parent_interface")]
pub fn parent_interface<I: crate::object::IsInterface>(&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"),
}
}
#[doc(alias = "get_class_data")]
pub fn class_data<T: Any + Send + Sync + 'static>(&self, type_: Type) -> Option<&T> {
match self.class_data {
None => None,
Some(ref data) => data.get(&type_).and_then(|ptr| ptr.downcast_ref()),
}
}
#[doc(alias = "get_class_data_mut")]
pub unsafe fn class_data_mut<T: Any + Send + Sync + 'static>(
&mut self,
type_: Type,
) -> Option<&mut T> {
match self.class_data {
None => None,
Some(ref mut data) => data.get_mut(&type_).and_then(|v| v.downcast_mut()),
}
}
pub unsafe fn set_class_data<T: Any + Send + Sync + 'static>(&mut self, type_: Type, data: T) {
if self.class_data.is_none() {
self.class_data = Some(BTreeMap::default());
}
if let Some(ref mut class_data) = self.class_data {
assert!(
class_data.get(&type_).is_none(),
"The class_data already contains a key for {type_}",
);
class_data.insert(type_, Box::new(data));
}
}
#[doc(alias = "get_impl_offset")]
#[inline]
pub fn impl_offset(&self) -> isize {
self.private_offset + self.private_imp_offset
}
}
impl Default for TypeData {
fn default() -> Self {
Self::new()
}
}
pub unsafe trait ObjectSubclassType {
fn type_data() -> ptr::NonNull<TypeData>;
#[doc(alias = "get_type")]
fn type_() -> Type;
}
pub trait ObjectSubclass: ObjectSubclassType + Sized + 'static {
const NAME: &'static str;
const ABSTRACT: bool = false;
const ALLOW_NAME_CONFLICT: bool = false;
type Type: ObjectType
+ ObjectSubclassIs<Subclass = Self>
+ FromGlibPtrFull<*mut <Self::Type as ObjectType>::GlibType>
+ FromGlibPtrBorrow<*mut <Self::Type as ObjectType>::GlibType>
+ FromGlibPtrNone<*mut <Self::Type as ObjectType>::GlibType>;
type ParentType: IsSubclassable<Self>
+ FromGlibPtrFull<*mut <Self::ParentType as ObjectType>::GlibType>
+ FromGlibPtrBorrow<*mut <Self::ParentType as ObjectType>::GlibType>
+ FromGlibPtrNone<*mut <Self::ParentType as ObjectType>::GlibType>;
type Interfaces: InterfaceList<Self>;
type Instance: InstanceStruct<Type = Self>;
type Class: ClassStruct<Type = Self>;
#[inline]
fn type_init(_type_: &mut InitializingType<Self>) {}
#[inline]
fn class_init(_klass: &mut Self::Class) {}
fn new() -> Self {
unimplemented!();
}
#[inline]
fn with_class(_klass: &Self::Class) -> Self {
Self::new()
}
#[inline]
fn instance_init(_obj: &InitializingObject<Self>) {}
}
pub trait ObjectSubclassExt: ObjectSubclass {
#[doc(alias = "get_instance")]
fn obj(&self) -> crate::BorrowedObject<'_, Self::Type>;
fn from_obj(obj: &Self::Type) -> &Self;
fn ref_counted(&self) -> super::ObjectImplRef<Self>;
#[doc(alias = "get_instance_data")]
fn instance_data<U: Any + Send + Sync + 'static>(&self, type_: Type) -> Option<&U>;
}
impl<T: ObjectSubclass> ObjectSubclassExt for T {
#[inline]
fn obj(&self) -> crate::BorrowedObject<'_, Self::Type> {
unsafe {
let data = Self::type_data();
let type_ = data.as_ref().type_();
debug_assert!(type_.is_valid());
let offset = -data.as_ref().impl_offset();
let ptr =
offset_ptr_by_bytes::<Self, <Self::Type as ObjectType>::GlibType>(self, offset);
debug_assert_ne!((*(ptr as *const gobject_ffi::GObject)).ref_count, 0);
crate::BorrowedObject::new(mut_override(ptr))
}
}
#[inline]
fn from_obj(obj: &Self::Type) -> &Self {
unsafe {
let ptr = obj.as_ptr() as *const Self::Instance;
(*ptr).imp()
}
}
#[inline]
fn ref_counted(&self) -> super::ObjectImplRef<Self> {
super::ObjectImplRef::new(self)
}
#[inline]
fn instance_data<U: Any + Send + Sync + 'static>(&self, type_: Type) -> Option<&U> {
unsafe {
let type_data = Self::type_data();
let self_type_ = type_data.as_ref().type_();
debug_assert!(self_type_.is_valid());
let offset = -type_data.as_ref().private_imp_offset;
let ptr = offset_ptr_by_bytes::<Self, PrivateStruct<Self>>(self, offset);
let priv_ = &*ptr;
match priv_.instance_data {
None => None,
Some(ref data) => data.get(&type_).and_then(|ptr| ptr.downcast_ref()),
}
}
}
}
pub trait FromObject {
type FromObjectType;
fn from_object(obj: &Self::FromObjectType) -> &Self;
}
pub struct InitializingObject<T: ObjectSubclass>(Borrowed<T::Type>);
impl<T: ObjectSubclass> InitializingObject<T> {
#[inline]
pub unsafe fn as_ref(&self) -> &T::Type {
&self.0
}
#[inline]
pub fn as_ptr(&self) -> *mut T::Type {
self.0.as_ptr() as *const T::Type as *mut T::Type
}
pub fn set_instance_data<U: Any + Send + Sync + 'static>(&mut self, type_: Type, data: U) {
unsafe {
let type_data = T::type_data();
let self_type_ = type_data.as_ref().type_();
debug_assert!(self_type_.is_valid());
let offset = type_data.as_ref().private_offset;
let ptr = offset_ptr_by_bytes_mut::<
<<T as ObjectSubclass>::Type as ObjectType>::GlibType,
PrivateStruct<T>,
>(self.0.as_ptr(), offset);
let priv_ = &mut *ptr;
if priv_.instance_data.is_none() {
priv_.instance_data = Some(BTreeMap::default());
}
if let Some(ref mut instance_data) = priv_.instance_data {
assert!(
instance_data.get(&type_).is_none(),
"The class_data already contains a key for {type_}",
);
instance_data.insert(type_, Box::new(data));
}
}
}
}
unsafe extern "C" fn class_init<T: ObjectSubclass>(
klass: ffi::gpointer,
_klass_data: ffi::gpointer,
) {
let mut data = T::type_data();
let mut private_offset = data.as_ref().private_offset as i32;
gobject_ffi::g_type_class_adjust_private_offset(klass, &mut private_offset);
data.as_mut().private_offset = private_offset as isize;
{
let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass);
gobject_klass.finalize = Some(finalize::<T>);
}
{
let klass = &mut *(klass as *mut T::Class);
let parent_class = gobject_ffi::g_type_class_peek_parent(klass as *mut _ as ffi::gpointer)
as *mut <T::ParentType as ObjectType>::GlibClassType;
debug_assert!(!parent_class.is_null());
data.as_mut().parent_class = parent_class as ffi::gpointer;
klass.class_init();
T::class_init(klass);
}
}
unsafe extern "C" fn instance_init<T: ObjectSubclass>(
obj: *mut gobject_ffi::GTypeInstance,
klass: ffi::gpointer,
) {
let mut data = T::type_data();
let private_offset = data.as_mut().private_offset;
let priv_ptr = offset_ptr_by_bytes_mut::<gobject_ffi::GTypeInstance, PrivateStruct<T>>(
obj,
private_offset,
);
assert!(
priv_ptr as usize & (mem::align_of::<PrivateStruct<T>>() - 1) == 0,
"Private instance data has higher alignment requirements ({}) than \
the allocation from GLib. If alignment of more than {} bytes \
is required, store the corresponding data separately on the heap.",
mem::align_of::<PrivateStruct<T>>(),
2 * mem::size_of::<usize>(),
);
let klass = &*(klass as *const T::Class);
let imp = T::with_class(klass);
ptr::write(
priv_ptr,
PrivateStruct {
imp,
instance_data: None,
},
);
T::Instance::instance_init(&mut *(obj as *mut _));
let obj = from_glib_borrow::<_, Object>(obj.cast());
let obj = Borrowed::new(obj.into_inner().unsafe_cast());
let mut obj = InitializingObject(obj);
T::Interfaces::instance_init(&mut obj);
T::instance_init(&obj);
}
unsafe extern "C" fn finalize<T: ObjectSubclass>(obj: *mut gobject_ffi::GObject) {
let mut data = T::type_data();
let private_offset = data.as_mut().private_offset;
let priv_ptr =
offset_ptr_by_bytes_mut::<gobject_ffi::GObject, PrivateStruct<T>>(obj, private_offset);
ptr::drop_in_place(ptr::addr_of_mut!((*priv_ptr).imp));
ptr::drop_in_place(ptr::addr_of_mut!((*priv_ptr).instance_data));
let parent_class = &*(data.as_ref().parent_class() as *const gobject_ffi::GObjectClass);
if let Some(ref func) = parent_class.finalize {
func(obj);
}
}
pub fn register_type<T: ObjectSubclass>() -> Type {
assert!(
mem::align_of::<T>() <= 2 * mem::size_of::<usize>(),
"Alignment {} of type not supported, bigger than {}",
mem::align_of::<T>(),
2 * mem::size_of::<usize>(),
);
unsafe {
use std::ffi::CString;
let type_name = if T::ALLOW_NAME_CONFLICT {
let mut i = 0;
loop {
let type_name = CString::new(if i == 0 {
T::NAME.to_string()
} else {
format!("{}-{}", T::NAME, i)
})
.unwrap();
if gobject_ffi::g_type_from_name(type_name.as_ptr()) == gobject_ffi::G_TYPE_INVALID
{
break type_name;
}
i += 1;
}
} else {
let type_name = CString::new(T::NAME).unwrap();
assert_eq!(
gobject_ffi::g_type_from_name(type_name.as_ptr()),
gobject_ffi::G_TYPE_INVALID,
"Type {} has already been registered",
type_name.to_str().unwrap()
);
type_name
};
let type_ = Type::from_glib(gobject_ffi::g_type_register_static_simple(
<T::ParentType as StaticType>::static_type().into_glib(),
type_name.as_ptr(),
mem::size_of::<T::Class>() as u32,
Some(class_init::<T>),
mem::size_of::<T::Instance>() as u32,
Some(instance_init::<T>),
if T::ABSTRACT {
gobject_ffi::G_TYPE_FLAG_ABSTRACT
} else {
0
},
));
assert!(type_.is_valid());
let mut data = T::type_data();
data.as_mut().type_ = type_;
let private_offset = gobject_ffi::g_type_add_instance_private(
type_.into_glib(),
mem::size_of::<PrivateStruct<T>>(),
);
data.as_mut().private_offset = private_offset as isize;
data.as_mut().private_imp_offset = {
let priv_ = mem::MaybeUninit::<PrivateStruct<T>>::uninit();
let ptr = priv_.as_ptr();
let imp_ptr = ptr::addr_of!((*ptr).imp);
(imp_ptr as isize) - (ptr as isize)
};
let iface_types = T::Interfaces::iface_infos();
for (iface_type, iface_info) in iface_types {
gobject_ffi::g_type_add_interface_static(
type_.into_glib(),
iface_type.into_glib(),
iface_info.as_ptr(),
);
}
T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData));
type_
}
}
pub fn register_dynamic_type<P: DynamicObjectRegisterExt, T: ObjectSubclass>(
type_plugin: &P,
) -> Type {
assert!(
mem::align_of::<T>() <= 2 * mem::size_of::<usize>(),
"Alignment {} of type not supported, bigger than {}",
mem::align_of::<T>(),
2 * mem::size_of::<usize>(),
);
unsafe {
use std::ffi::CString;
let type_name = CString::new(T::NAME).unwrap();
let already_registered =
gobject_ffi::g_type_from_name(type_name.as_ptr()) != gobject_ffi::G_TYPE_INVALID;
let type_info = TypeInfo(gobject_ffi::GTypeInfo {
class_size: mem::size_of::<T::Class>() as u16,
class_init: Some(class_init::<T>),
instance_size: mem::size_of::<T::Instance>() as u16,
instance_init: Some(instance_init::<T>),
..TypeInfo::default().0
});
let type_ = type_plugin.register_dynamic_type(
<T::ParentType as StaticType>::static_type(),
type_name.to_str().unwrap(),
&type_info,
if T::ABSTRACT {
TypeFlags::ABSTRACT
} else {
TypeFlags::NONE
},
);
assert!(type_.is_valid());
let mut data = T::type_data();
data.as_mut().type_ = type_;
let private_offset = mem::size_of::<PrivateStruct<T>>();
data.as_mut().private_offset = private_offset as isize;
data.as_mut().private_imp_offset = {
let priv_ = mem::MaybeUninit::<PrivateStruct<T>>::uninit();
let ptr = priv_.as_ptr();
let imp_ptr = ptr::addr_of!((*ptr).imp);
(imp_ptr as isize) - (ptr as isize)
};
let plugin_ptr = type_plugin.as_ref().to_glib_none().0;
let iface_types = T::Interfaces::iface_infos();
for (iface_type, iface_info) in iface_types {
match gobject_ffi::g_type_get_plugin(iface_type.into_glib()) {
iface_plugin if iface_plugin != plugin_ptr => {
if !already_registered {
gobject_ffi::g_type_add_interface_static(
type_.into_glib(),
iface_type.into_glib(),
iface_info.as_ptr(),
);
}
}
_ => type_plugin.add_dynamic_interface(type_, iface_type, &iface_info),
}
}
T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData));
type_
}
}
pub(crate) unsafe fn signal_override_class_handler<F>(
name: &str,
type_: ffi::GType,
class_handler: F,
) where
F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
{
let (signal_id, _) = SignalId::parse_name(name, from_glib(type_), false)
.unwrap_or_else(|| panic!("Signal '{name}' not found"));
let query = signal_id.query();
let return_type = query.return_type();
let class_handler = Closure::new(move |values| {
let instance = gobject_ffi::g_value_get_object(values[0].to_glib_none().0);
let res = class_handler(
&super::SignalClassHandlerToken(
instance as *mut _,
return_type.into(),
values.as_ptr(),
),
values,
);
if return_type == Type::UNIT {
if let Some(ref v) = res {
panic!(
"Signal has no return value but class handler returned a value of type {}",
v.type_()
);
}
} else {
match res {
None => {
panic!("Signal has a return value but class handler returned none");
}
Some(ref v) => {
assert!(
v.type_().is_a(return_type.into()),
"Signal has a return type of {} but class handler returned {}",
Type::from(return_type),
v.type_()
);
}
}
}
res
});
gobject_ffi::g_signal_override_class_closure(
signal_id.into_glib(),
type_,
class_handler.to_glib_none().0,
);
}
pub(crate) unsafe fn signal_chain_from_overridden(
instance: *mut gobject_ffi::GTypeInstance,
token: &super::SignalClassHandlerToken,
values: &[Value],
) -> Option<Value> {
assert_eq!(instance, token.0);
assert_eq!(
values.as_ptr(),
token.2,
"Arguments must be forwarded without changes when chaining up"
);
let mut result = Value::from_type_unchecked(token.1);
gobject_ffi::g_signal_chain_from_overridden(
values.as_ptr() as *mut Value as *mut gobject_ffi::GValue,
result.to_glib_none_mut().0,
);
Some(result).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT)
}