use super::{InitializingType, Property};
use glib_sys;
use gobject_sys;
use std::borrow::Borrow;
use std::marker;
use std::mem;
use translate::*;
use {IsA, Object, ObjectExt, SignalFlags, StaticType, Type, Value};
impl<T: ObjectInterface> InitializingType<T> {
pub fn add_prerequisite<I: StaticType>(&mut self) {
unsafe {
gobject_sys::g_type_interface_add_prerequisite(
self.0.to_glib(),
I::static_type().to_glib(),
)
}
}
}
#[macro_export]
macro_rules! glib_object_interface {
() => {
fn get_type() -> $crate::Type {
static ONCE: ::std::sync::Once = ::std::sync::Once::new();
static mut TYPE: $crate::Type = $crate::Type::Invalid;
ONCE.call_once(|| {
let type_ = $crate::subclass::register_interface::<Self>();
unsafe {
TYPE = type_;
}
});
unsafe {
assert_ne!(TYPE, $crate::Type::Invalid);
TYPE
}
}
};
}
pub trait ObjectInterface: Sized + 'static {
const NAME: &'static str;
fn get_type() -> Type;
fn type_init(_type_: &mut InitializingType<Self>) {}
fn interface_init(&mut self) {}
}
pub trait ObjectInterfaceExt: ObjectInterface {
fn from_instance<T: IsA<Object>>(obj: &T) -> &Self {
assert!(obj.as_ref().get_type().is_a(&Self::get_type()));
unsafe {
let klass = (*(obj.as_ptr() as *const gobject_sys::GTypeInstance)).g_class;
let interface =
gobject_sys::g_type_interface_peek(klass as *mut _, Self::get_type().to_glib());
assert!(!interface.is_null());
&*(interface as *const Self)
}
}
fn install_properties<'a, T: Borrow<Property<'a>>>(&mut self, properties: &[T]) {
if properties.is_empty() {
return;
}
for property in properties {
let property = property.borrow();
let pspec = (property.1)(property.0);
unsafe {
gobject_sys::g_object_interface_install_property(
self as *mut Self as *mut _,
pspec.to_glib_none().0,
);
}
}
}
fn add_signal(&mut self, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type) {
unsafe {
super::types::add_signal(
*(self as *mut _ as *mut glib_sys::GType),
name,
flags,
arg_types,
ret_type,
);
}
}
fn add_signal_with_class_handler<F>(
&mut self,
name: &str,
flags: SignalFlags,
arg_types: &[Type],
ret_type: Type,
class_handler: F,
) where
F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
{
unsafe {
super::types::add_signal_with_class_handler(
*(self as *mut _ as *mut glib_sys::GType),
name,
flags,
arg_types,
ret_type,
class_handler,
);
}
}
fn add_signal_with_accumulator<F>(
&mut self,
name: &str,
flags: SignalFlags,
arg_types: &[Type],
ret_type: Type,
accumulator: F,
) where
F: Fn(&super::SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,
{
unsafe {
super::types::add_signal_with_accumulator(
*(self as *mut _ as *mut glib_sys::GType),
name,
flags,
arg_types,
ret_type,
accumulator,
);
}
}
fn add_signal_with_class_handler_and_accumulator<F, G>(
&mut self,
name: &str,
flags: SignalFlags,
arg_types: &[Type],
ret_type: Type,
class_handler: F,
accumulator: G,
) where
F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
G: Fn(&super::SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,
{
unsafe {
super::types::add_signal_with_class_handler_and_accumulator(
*(self as *mut _ as *mut glib_sys::GType),
name,
flags,
arg_types,
ret_type,
class_handler,
accumulator,
);
}
}
}
impl<T: ObjectInterface> ObjectInterfaceExt for T {}
unsafe extern "C" fn interface_init<T: ObjectInterface>(
klass: glib_sys::gpointer,
_klass_data: glib_sys::gpointer,
) {
let iface = &mut *(klass as *mut T);
iface.interface_init();
}
pub fn register_interface<T: ObjectInterface>() -> Type {
unsafe {
use std::ffi::CString;
let type_name = CString::new(T::NAME).unwrap();
assert_eq!(
gobject_sys::g_type_from_name(type_name.as_ptr()),
gobject_sys::G_TYPE_INVALID
);
let type_ = from_glib(gobject_sys::g_type_register_static_simple(
Type::BaseInterface.to_glib(),
type_name.as_ptr(),
mem::size_of::<T>() as u32,
Some(interface_init::<T>),
0,
None,
0,
));
T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData));
type_
}
}