mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-12-23 02:26:35 +00:00
Move gobject-subclass to its own repository
This commit is contained in:
parent
80793cd766
commit
6803cb5fac
15 changed files with 13 additions and 927 deletions
|
@ -1,7 +1,6 @@
|
|||
[workspace]
|
||||
|
||||
members = [
|
||||
"gobject-subclass",
|
||||
"gst-plugin",
|
||||
"gst-plugin-simple",
|
||||
"gst-plugin-file",
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
[package]
|
||||
name = "gobject-subclass"
|
||||
version = "0.1.0"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
repository = "https://github.com/sdroege/gst-plugin-rs/tree/master/gobject-subclass"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
|
||||
[lib]
|
||||
name = "gobject_subclass"
|
||||
path = "src/lib.rs"
|
|
@ -1,79 +0,0 @@
|
|||
// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
//
|
||||
// Heavily inspired by the mopa trait
|
||||
|
||||
use std::any::{Any, TypeId};
|
||||
|
||||
pub trait AnyImpl: Any {
|
||||
fn get_type_id(&self) -> TypeId;
|
||||
}
|
||||
|
||||
impl<T: Any> AnyImpl for T {
|
||||
fn get_type_id(&self) -> TypeId {
|
||||
TypeId::of::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
// warning: constraints is defined as a repetition to minimize code duplication.
|
||||
// multiple items will generate invalide code.
|
||||
#[macro_export]
|
||||
macro_rules! any_impl {
|
||||
|
||||
($bound:ident, $trait:ident $(, $constraint:ident)*) => {
|
||||
impl<T: $bound> $trait<T>
|
||||
$(
|
||||
where T::InstanceStructType: $constraint
|
||||
)*
|
||||
{
|
||||
#[inline]
|
||||
pub fn downcast_ref<U: $trait<T>>(&self) -> Option<&U> {
|
||||
if self.is::<U>() {
|
||||
unsafe { Some(self.downcast_ref_unchecked()) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn downcast_ref_unchecked<U: $trait<T>>(&self) -> &U {
|
||||
&*(self as *const Self as *const U)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is<U: $trait<T>>(&self) -> bool {
|
||||
use std::any::TypeId;
|
||||
TypeId::of::<U>() == $crate::anyimpl::AnyImpl::get_type_id(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($trait:ident) => {
|
||||
impl $trait {
|
||||
#[inline]
|
||||
pub fn downcast_ref<U: $trait>(&self) -> Option<&U> {
|
||||
if self.is::<U>() {
|
||||
unsafe { Some(self.downcast_ref_unchecked()) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn downcast_ref_unchecked<U: $trait>(&self) -> &U {
|
||||
&*(self as *const Self as *const U)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is<U: $trait>(&self) -> bool {
|
||||
use std::any::TypeId;
|
||||
TypeId::of::<U>() == $crate::anyimpl::AnyImpl::get_type_id(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::ptr;
|
||||
|
||||
use glib_ffi;
|
||||
use gobject_ffi;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! callback_guard {
|
||||
() => {
|
||||
let _guard = $crate::glib::CallbackGuard::new();
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! floating_reference_guard {
|
||||
($obj:ident) => {
|
||||
let _guard = $crate::guard::FloatingReferenceGuard::new($obj as *mut _);
|
||||
};
|
||||
}
|
||||
|
||||
pub struct FloatingReferenceGuard(ptr::NonNull<gobject_ffi::GObject>);
|
||||
|
||||
impl FloatingReferenceGuard {
|
||||
pub unsafe fn new(obj: *mut gobject_ffi::GObject) -> Option<FloatingReferenceGuard> {
|
||||
assert!(!obj.is_null());
|
||||
if gobject_ffi::g_object_is_floating(obj) != glib_ffi::GFALSE {
|
||||
gobject_ffi::g_object_ref_sink(obj);
|
||||
Some(FloatingReferenceGuard(ptr::NonNull::new_unchecked(obj)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FloatingReferenceGuard {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gobject_ffi::g_object_force_floating(self.0.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern crate glib_sys as glib_ffi;
|
||||
extern crate gobject_sys as gobject_ffi;
|
||||
|
||||
extern crate libc;
|
||||
|
||||
pub extern crate glib;
|
||||
|
||||
#[macro_use]
|
||||
pub mod anyimpl;
|
||||
|
||||
#[macro_use]
|
||||
pub mod guard;
|
||||
|
||||
pub mod properties;
|
||||
#[macro_use]
|
||||
pub mod object;
|
|
@ -1,530 +0,0 @@
|
|||
// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::any::TypeId;
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::CString;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use glib_ffi;
|
||||
use gobject_ffi;
|
||||
|
||||
use glib;
|
||||
use glib::translate::*;
|
||||
|
||||
pub use properties::*;
|
||||
|
||||
pub trait ObjectImpl<T: ObjectType>: 'static {
|
||||
fn set_property(&self, _obj: &glib::Object, _id: u32, _value: &glib::Value) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_property(&self, _obj: &glib::Object, _id: u32) -> Result<glib::Value, ()> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn notify(&self, obj: &glib::Object, name: &str) {
|
||||
unsafe {
|
||||
gobject_ffi::g_object_notify(obj.to_glib_none().0, name.to_glib_none().0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// warning: constraints is defined as a repetition to minimize code duplication.
|
||||
// multiple items will generate invalide code.
|
||||
#[macro_export]
|
||||
macro_rules! box_object_impl(
|
||||
($name:ident $(, $constraint:ident)*) => {
|
||||
impl<T: ObjectType> ObjectImpl<T> for Box<$name<T>>
|
||||
$(
|
||||
where T::InstanceStructType: $constraint
|
||||
)*
|
||||
{
|
||||
fn set_property(&self, obj: &glib::Object, id: u32, value: &glib::Value) {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.set_property(obj, id, value);
|
||||
}
|
||||
|
||||
fn get_property(&self, obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.get_property(obj, id)
|
||||
}
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
pub trait ImplTypeStatic<T: ObjectType>: Send + Sync + 'static {
|
||||
fn get_name(&self) -> &str;
|
||||
fn new(&self, &T) -> T::ImplType;
|
||||
fn class_init(&self, &mut ClassStruct<T>);
|
||||
fn type_init(&self, _: &TypeInitToken, _type_: glib::Type) {}
|
||||
}
|
||||
|
||||
pub struct ClassInitToken(());
|
||||
pub struct TypeInitToken(());
|
||||
|
||||
pub trait ObjectType: FromGlibPtrBorrow<*mut <Self as ObjectType>::InstanceStructType>
|
||||
where
|
||||
Self: Sized + 'static,
|
||||
Self::InstanceStructType: Instance<Self>,
|
||||
{
|
||||
const NAME: &'static str;
|
||||
type InstanceStructType: Instance<Self> + 'static;
|
||||
type GlibType;
|
||||
type GlibClassType;
|
||||
type ImplType: ObjectImpl<Self>;
|
||||
|
||||
fn glib_type() -> glib::Type;
|
||||
|
||||
fn class_init(token: &ClassInitToken, klass: &mut ClassStruct<Self>);
|
||||
|
||||
fn set_property(_obj: &Self, _id: u32, _value: &glib::Value) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_property(_obj: &Self, _id: u32) -> Result<glib::Value, ()> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
unsafe fn get_instance(&self) -> *mut Self::InstanceStructType;
|
||||
|
||||
fn get_impl(&self) -> &Self::ImplType {
|
||||
unsafe { (*self.get_instance()).get_impl() }
|
||||
}
|
||||
|
||||
unsafe fn get_class(&self) -> *const ClassStruct<Self> {
|
||||
(*self.get_instance()).get_class()
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! object_type_fns(
|
||||
() => {
|
||||
unsafe fn get_instance(&self) -> *mut Self::InstanceStructType {
|
||||
self.to_glib_none().0
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
pub trait Instance<T: ObjectType> {
|
||||
fn parent(&self) -> &T::GlibType;
|
||||
|
||||
fn get_impl(&self) -> &T::ImplType;
|
||||
|
||||
unsafe fn set_impl(&mut self, imp: ptr::NonNull<T::ImplType>);
|
||||
|
||||
unsafe fn get_class(&self) -> *const ClassStruct<T>;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct InstanceStruct<T: ObjectType> {
|
||||
_parent: T::GlibType,
|
||||
_imp: ptr::NonNull<T::ImplType>,
|
||||
}
|
||||
|
||||
impl<T: ObjectType> Instance<T> for InstanceStruct<T> {
|
||||
fn parent(&self) -> &T::GlibType {
|
||||
&self._parent
|
||||
}
|
||||
|
||||
fn get_impl(&self) -> &T::ImplType {
|
||||
unsafe { self._imp.as_ref() }
|
||||
}
|
||||
|
||||
unsafe fn set_impl(&mut self, imp: ptr::NonNull<T::ImplType>) {
|
||||
self._imp = imp;
|
||||
}
|
||||
|
||||
unsafe fn get_class(&self) -> *const ClassStruct<T> {
|
||||
*(self as *const _ as *const *const ClassStruct<T>)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ClassStruct<T: ObjectType> {
|
||||
pub parent: T::GlibClassType,
|
||||
pub imp_static: ptr::NonNull<Box<ImplTypeStatic<T>>>,
|
||||
pub parent_class: ptr::NonNull<T::GlibClassType>,
|
||||
pub interfaces_static: *const Vec<(glib_ffi::GType, glib_ffi::gpointer)>,
|
||||
}
|
||||
|
||||
impl<T: ObjectType> ClassStruct<T> {
|
||||
pub fn get_parent_class(&self) -> *const T::GlibClassType {
|
||||
self.parent_class.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ObjectType> ClassStruct<T> {
|
||||
pub fn get_interface_static(&self, type_: glib_ffi::GType) -> glib_ffi::gpointer {
|
||||
unsafe {
|
||||
if self.interfaces_static.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
for &(t, p) in &(*self.interfaces_static) {
|
||||
if t == type_ {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe trait ObjectClass {
|
||||
fn install_properties(&mut self, properties: &[Property]) {
|
||||
if properties.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut pspecs = Vec::with_capacity(properties.len());
|
||||
|
||||
pspecs.push(ptr::null_mut());
|
||||
|
||||
for property in properties {
|
||||
pspecs.push(property.into());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
gobject_ffi::g_object_class_install_properties(
|
||||
self as *mut _ as *mut gobject_ffi::GObjectClass,
|
||||
pspecs.len() as u32,
|
||||
pspecs.as_mut_ptr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_signal(&mut self, name: &str, arg_types: &[glib::Type], ret_type: glib::Type) {
|
||||
let arg_types = arg_types.iter().map(|t| t.to_glib()).collect::<Vec<_>>();
|
||||
unsafe {
|
||||
gobject_ffi::g_signal_newv(
|
||||
name.to_glib_none().0,
|
||||
*(self as *mut _ as *mut glib_ffi::GType),
|
||||
gobject_ffi::G_SIGNAL_RUN_LAST,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ret_type.to_glib(),
|
||||
arg_types.len() as u32,
|
||||
arg_types.as_ptr() as *mut _,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_signal_with_accumulator<F>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
arg_types: &[glib::Type],
|
||||
ret_type: glib::Type,
|
||||
accumulator: F,
|
||||
) where
|
||||
F: Fn(&mut glib::Value, &glib::Value) -> bool + Send + Sync + 'static,
|
||||
{
|
||||
let arg_types = arg_types.iter().map(|t| t.to_glib()).collect::<Vec<_>>();
|
||||
|
||||
let accumulator: Box<
|
||||
Box<Fn(&mut glib::Value, &glib::Value) -> bool + Send + Sync + 'static>,
|
||||
> = Box::new(Box::new(accumulator));
|
||||
|
||||
unsafe extern "C" fn accumulator_trampoline(
|
||||
_ihint: *mut gobject_ffi::GSignalInvocationHint,
|
||||
return_accu: *mut gobject_ffi::GValue,
|
||||
handler_return: *const gobject_ffi::GValue,
|
||||
data: glib_ffi::gpointer,
|
||||
) -> glib_ffi::gboolean {
|
||||
callback_guard!();
|
||||
let accumulator: &&(Fn(&mut glib::Value, &glib::Value) -> bool
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static) = mem::transmute(data);
|
||||
accumulator(
|
||||
&mut *(return_accu as *mut glib::Value),
|
||||
&*(handler_return as *const glib::Value),
|
||||
).to_glib()
|
||||
}
|
||||
|
||||
unsafe {
|
||||
gobject_ffi::g_signal_newv(
|
||||
name.to_glib_none().0,
|
||||
*(self as *mut _ as *mut glib_ffi::GType),
|
||||
gobject_ffi::G_SIGNAL_RUN_LAST,
|
||||
ptr::null_mut(),
|
||||
Some(accumulator_trampoline),
|
||||
Box::into_raw(accumulator) as glib_ffi::gpointer,
|
||||
None,
|
||||
ret_type.to_glib(),
|
||||
arg_types.len() as u32,
|
||||
arg_types.as_ptr() as *mut _,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_action_signal<F>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
arg_types: &[glib::Type],
|
||||
ret_type: glib::Type,
|
||||
handler: F,
|
||||
) where
|
||||
F: Fn(&[glib::Value]) -> Option<glib::Value> + Send + Sync + 'static,
|
||||
{
|
||||
let arg_types = arg_types.iter().map(|t| t.to_glib()).collect::<Vec<_>>();
|
||||
let handler = glib::Closure::new(handler);
|
||||
unsafe {
|
||||
gobject_ffi::g_signal_newv(
|
||||
name.to_glib_none().0,
|
||||
*(self as *mut _ as *mut glib_ffi::GType),
|
||||
gobject_ffi::G_SIGNAL_RUN_LAST | gobject_ffi::G_SIGNAL_ACTION,
|
||||
handler.to_glib_none().0,
|
||||
None,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
ret_type.to_glib(),
|
||||
arg_types.len() as u32,
|
||||
arg_types.as_ptr() as *mut _,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ObjectType> ObjectClass for ClassStruct<T> {}
|
||||
|
||||
unsafe extern "C" fn class_init<T: ObjectType>(
|
||||
klass: glib_ffi::gpointer,
|
||||
_klass_data: glib_ffi::gpointer,
|
||||
) {
|
||||
callback_guard!();
|
||||
{
|
||||
let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass);
|
||||
|
||||
gobject_klass.finalize = Some(finalize::<T>);
|
||||
gobject_klass.set_property = Some(set_property::<T>);
|
||||
gobject_klass.get_property = Some(get_property::<T>);
|
||||
}
|
||||
|
||||
{
|
||||
let klass = &mut *(klass as *mut ClassStruct<T>);
|
||||
let parent_class = gobject_ffi::g_type_class_peek_parent(
|
||||
klass as *mut _ as glib_ffi::gpointer,
|
||||
) as *mut T::GlibClassType;
|
||||
assert!(!parent_class.is_null());
|
||||
klass.parent_class = ptr::NonNull::new_unchecked(parent_class);
|
||||
T::class_init(&ClassInitToken(()), klass);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn finalize<T: ObjectType>(obj: *mut gobject_ffi::GObject) {
|
||||
callback_guard!();
|
||||
let instance = &mut *(obj as *mut T::InstanceStructType);
|
||||
|
||||
drop(Box::from_raw(instance.get_impl() as *const _ as *mut T::ImplType));
|
||||
instance.set_impl(ptr::NonNull::dangling());
|
||||
|
||||
let klass = *(obj as *const glib_ffi::gpointer);
|
||||
let parent_klass = gobject_ffi::g_type_class_peek_parent(klass);
|
||||
let parent_klass =
|
||||
&*(gobject_ffi::g_type_class_peek_parent(parent_klass) as *const gobject_ffi::GObjectClass);
|
||||
parent_klass.finalize.map(|f| f(obj));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn get_property<T: ObjectType>(
|
||||
obj: *mut gobject_ffi::GObject,
|
||||
id: u32,
|
||||
value: *mut gobject_ffi::GValue,
|
||||
_pspec: *mut gobject_ffi::GParamSpec,
|
||||
) {
|
||||
callback_guard!();
|
||||
floating_reference_guard!(obj);
|
||||
match T::get_property(&from_glib_borrow(obj as *mut T::InstanceStructType), id - 1) {
|
||||
Ok(v) => {
|
||||
gobject_ffi::g_value_unset(value);
|
||||
ptr::write(value, ptr::read(v.to_glib_none().0));
|
||||
mem::forget(v);
|
||||
}
|
||||
Err(()) => eprintln!("Failed to get property"),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn set_property<T: ObjectType>(
|
||||
obj: *mut gobject_ffi::GObject,
|
||||
id: u32,
|
||||
value: *mut gobject_ffi::GValue,
|
||||
_pspec: *mut gobject_ffi::GParamSpec,
|
||||
) {
|
||||
callback_guard!();
|
||||
floating_reference_guard!(obj);
|
||||
T::set_property(
|
||||
&from_glib_borrow(obj as *mut T::InstanceStructType),
|
||||
id - 1,
|
||||
&*(value as *mut glib::Value),
|
||||
);
|
||||
}
|
||||
|
||||
static mut TYPES: *mut Mutex<BTreeMap<TypeId, glib::Type>> = 0 as *mut _;
|
||||
|
||||
pub unsafe fn get_type<T: ObjectType>() -> glib_ffi::GType {
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
|
||||
static ONCE: Once = ONCE_INIT;
|
||||
|
||||
ONCE.call_once(|| {
|
||||
TYPES = Box::into_raw(Box::new(Mutex::new(BTreeMap::new())));
|
||||
});
|
||||
|
||||
let mut types = (*TYPES).lock().unwrap();
|
||||
types
|
||||
.entry(TypeId::of::<T>())
|
||||
.or_insert_with(|| {
|
||||
let type_info = gobject_ffi::GTypeInfo {
|
||||
class_size: mem::size_of::<ClassStruct<T>>() as u16,
|
||||
base_init: None,
|
||||
base_finalize: None,
|
||||
class_init: Some(class_init::<T>),
|
||||
class_finalize: None,
|
||||
class_data: ptr::null_mut(),
|
||||
instance_size: mem::size_of::<T::InstanceStructType>() as u16,
|
||||
n_preallocs: 0,
|
||||
instance_init: None,
|
||||
value_table: ptr::null(),
|
||||
};
|
||||
|
||||
let type_name = {
|
||||
let mut idx = 0;
|
||||
|
||||
loop {
|
||||
let type_name = CString::new(format!("{}-{}", T::NAME, idx)).unwrap();
|
||||
if gobject_ffi::g_type_from_name(type_name.as_ptr())
|
||||
== gobject_ffi::G_TYPE_INVALID
|
||||
{
|
||||
break type_name;
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
};
|
||||
|
||||
from_glib(gobject_ffi::g_type_register_static(
|
||||
T::glib_type().to_glib(),
|
||||
type_name.as_ptr(),
|
||||
&type_info,
|
||||
gobject_ffi::G_TYPE_FLAG_ABSTRACT,
|
||||
))
|
||||
})
|
||||
.to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn sub_class_init<T: ObjectType>(
|
||||
klass: glib_ffi::gpointer,
|
||||
klass_data: glib_ffi::gpointer,
|
||||
) {
|
||||
callback_guard!();
|
||||
{
|
||||
let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass);
|
||||
|
||||
gobject_klass.set_property = Some(sub_set_property::<T>);
|
||||
gobject_klass.get_property = Some(sub_get_property::<T>);
|
||||
}
|
||||
{
|
||||
assert!(!klass_data.is_null());
|
||||
let klass = &mut *(klass as *mut ClassStruct<T>);
|
||||
let imp_static = klass_data as *mut Box<ImplTypeStatic<T>>;
|
||||
klass.imp_static = ptr::NonNull::new_unchecked(imp_static);
|
||||
klass.interfaces_static = Box::into_raw(Box::new(Vec::new()));
|
||||
|
||||
(*imp_static).class_init(klass);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn sub_get_property<T: ObjectType>(
|
||||
obj: *mut gobject_ffi::GObject,
|
||||
id: u32,
|
||||
value: *mut gobject_ffi::GValue,
|
||||
_pspec: *mut gobject_ffi::GParamSpec,
|
||||
) {
|
||||
callback_guard!();
|
||||
floating_reference_guard!(obj);
|
||||
let instance = &*(obj as *mut T::InstanceStructType);
|
||||
let imp = instance.get_impl();
|
||||
|
||||
match imp.get_property(&from_glib_borrow(obj), id - 1) {
|
||||
Ok(v) => {
|
||||
gobject_ffi::g_value_unset(value);
|
||||
ptr::write(value, ptr::read(v.to_glib_none().0));
|
||||
mem::forget(v);
|
||||
}
|
||||
Err(()) => eprintln!("Failed to get property"),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn sub_set_property<T: ObjectType>(
|
||||
obj: *mut gobject_ffi::GObject,
|
||||
id: u32,
|
||||
value: *mut gobject_ffi::GValue,
|
||||
_pspec: *mut gobject_ffi::GParamSpec,
|
||||
) {
|
||||
callback_guard!();
|
||||
floating_reference_guard!(obj);
|
||||
let instance = &*(obj as *mut T::InstanceStructType);
|
||||
let imp = instance.get_impl();
|
||||
imp.set_property(
|
||||
&from_glib_borrow(obj),
|
||||
id - 1,
|
||||
&*(value as *mut glib::Value),
|
||||
);
|
||||
}
|
||||
|
||||
unsafe extern "C" fn sub_init<T: ObjectType>(
|
||||
obj: *mut gobject_ffi::GTypeInstance,
|
||||
_klass: glib_ffi::gpointer,
|
||||
) {
|
||||
callback_guard!();
|
||||
floating_reference_guard!(obj);
|
||||
let instance = &mut *(obj as *mut T::InstanceStructType);
|
||||
let klass = &**(obj as *const *const ClassStruct<T>);
|
||||
let rs_instance: T = from_glib_borrow(obj as *mut T::InstanceStructType);
|
||||
|
||||
let imp = klass.imp_static.as_ref().new(&rs_instance);
|
||||
instance.set_impl(ptr::NonNull::new_unchecked(Box::into_raw(Box::new(imp))));
|
||||
}
|
||||
|
||||
pub fn register_type<T: ObjectType, I: ImplTypeStatic<T>>(imp: I) -> glib::Type {
|
||||
unsafe {
|
||||
let parent_type = get_type::<T>();
|
||||
let type_name = format!("{}-{}", T::NAME, imp.get_name());
|
||||
|
||||
let imp: Box<ImplTypeStatic<T>> = Box::new(imp);
|
||||
let imp_ptr = Box::into_raw(Box::new(imp));
|
||||
|
||||
let type_info = gobject_ffi::GTypeInfo {
|
||||
class_size: mem::size_of::<ClassStruct<T>>() as u16,
|
||||
base_init: None,
|
||||
base_finalize: None,
|
||||
class_init: Some(sub_class_init::<T>),
|
||||
class_finalize: None,
|
||||
class_data: imp_ptr as glib_ffi::gpointer,
|
||||
instance_size: mem::size_of::<T::InstanceStructType>() as u16,
|
||||
n_preallocs: 0,
|
||||
instance_init: Some(sub_init::<T>),
|
||||
value_table: ptr::null(),
|
||||
};
|
||||
|
||||
let type_ = from_glib(gobject_ffi::g_type_register_static(
|
||||
parent_type,
|
||||
type_name.to_glib_none().0,
|
||||
&type_info,
|
||||
0,
|
||||
));
|
||||
|
||||
(*imp_ptr).type_init(&TypeInitToken(()), type_);
|
||||
|
||||
type_
|
||||
}
|
||||
}
|
|
@ -1,216 +0,0 @@
|
|||
// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use gobject_ffi;
|
||||
|
||||
use glib;
|
||||
use glib::translate::*;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum PropertyMutability {
|
||||
Readable,
|
||||
Writable,
|
||||
ReadWrite,
|
||||
}
|
||||
|
||||
impl Into<gobject_ffi::GParamFlags> for PropertyMutability {
|
||||
fn into(self) -> gobject_ffi::GParamFlags {
|
||||
use self::PropertyMutability::*;
|
||||
|
||||
match self {
|
||||
Readable => gobject_ffi::G_PARAM_READABLE,
|
||||
Writable => gobject_ffi::G_PARAM_WRITABLE,
|
||||
ReadWrite => gobject_ffi::G_PARAM_READWRITE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Property<'a> {
|
||||
Boolean(&'a str, &'a str, &'a str, bool, PropertyMutability),
|
||||
Int(
|
||||
&'a str,
|
||||
&'a str,
|
||||
&'a str,
|
||||
(i32, i32),
|
||||
i32,
|
||||
PropertyMutability,
|
||||
),
|
||||
Int64(
|
||||
&'a str,
|
||||
&'a str,
|
||||
&'a str,
|
||||
(i64, i64),
|
||||
i64,
|
||||
PropertyMutability,
|
||||
),
|
||||
UInt(
|
||||
&'a str,
|
||||
&'a str,
|
||||
&'a str,
|
||||
(u32, u32),
|
||||
u32,
|
||||
PropertyMutability,
|
||||
),
|
||||
UInt64(
|
||||
&'a str,
|
||||
&'a str,
|
||||
&'a str,
|
||||
(u64, u64),
|
||||
u64,
|
||||
PropertyMutability,
|
||||
),
|
||||
Float(
|
||||
&'a str,
|
||||
&'a str,
|
||||
&'a str,
|
||||
(f32, f32),
|
||||
f32,
|
||||
PropertyMutability,
|
||||
),
|
||||
Double(
|
||||
&'a str,
|
||||
&'a str,
|
||||
&'a str,
|
||||
(f64, f64),
|
||||
f64,
|
||||
PropertyMutability,
|
||||
),
|
||||
String(
|
||||
&'a str,
|
||||
&'a str,
|
||||
&'a str,
|
||||
Option<&'a str>,
|
||||
PropertyMutability,
|
||||
),
|
||||
Boxed(
|
||||
&'a str,
|
||||
&'a str,
|
||||
&'a str,
|
||||
fn() -> glib::Type,
|
||||
PropertyMutability,
|
||||
),
|
||||
Object(
|
||||
&'a str,
|
||||
&'a str,
|
||||
&'a str,
|
||||
fn() -> glib::Type,
|
||||
PropertyMutability,
|
||||
),
|
||||
}
|
||||
|
||||
impl<'a> Into<*mut gobject_ffi::GParamSpec> for &'a Property<'a> {
|
||||
fn into(self) -> *mut gobject_ffi::GParamSpec {
|
||||
unsafe {
|
||||
match *self {
|
||||
Property::Boolean(name, nick, description, default, mutability) => {
|
||||
gobject_ffi::g_param_spec_boolean(
|
||||
name.to_glib_none().0,
|
||||
nick.to_glib_none().0,
|
||||
description.to_glib_none().0,
|
||||
default.to_glib(),
|
||||
mutability.into(),
|
||||
)
|
||||
}
|
||||
Property::Int(name, nick, description, (min, max), default, mutability) => {
|
||||
gobject_ffi::g_param_spec_int(
|
||||
name.to_glib_none().0,
|
||||
nick.to_glib_none().0,
|
||||
description.to_glib_none().0,
|
||||
min,
|
||||
max,
|
||||
default,
|
||||
mutability.into(),
|
||||
)
|
||||
}
|
||||
Property::Int64(name, nick, description, (min, max), default, mutability) => {
|
||||
gobject_ffi::g_param_spec_int64(
|
||||
name.to_glib_none().0,
|
||||
nick.to_glib_none().0,
|
||||
description.to_glib_none().0,
|
||||
min,
|
||||
max,
|
||||
default,
|
||||
mutability.into(),
|
||||
)
|
||||
}
|
||||
Property::UInt(name, nick, description, (min, max), default, mutability) => {
|
||||
gobject_ffi::g_param_spec_uint(
|
||||
name.to_glib_none().0,
|
||||
nick.to_glib_none().0,
|
||||
description.to_glib_none().0,
|
||||
min,
|
||||
max,
|
||||
default,
|
||||
mutability.into(),
|
||||
)
|
||||
}
|
||||
Property::UInt64(name, nick, description, (min, max), default, mutability) => {
|
||||
gobject_ffi::g_param_spec_uint64(
|
||||
name.to_glib_none().0,
|
||||
nick.to_glib_none().0,
|
||||
description.to_glib_none().0,
|
||||
min,
|
||||
max,
|
||||
default,
|
||||
mutability.into(),
|
||||
)
|
||||
}
|
||||
Property::Float(name, nick, description, (min, max), default, mutability) => {
|
||||
gobject_ffi::g_param_spec_float(
|
||||
name.to_glib_none().0,
|
||||
nick.to_glib_none().0,
|
||||
description.to_glib_none().0,
|
||||
min,
|
||||
max,
|
||||
default,
|
||||
mutability.into(),
|
||||
)
|
||||
}
|
||||
Property::Double(name, nick, description, (min, max), default, mutability) => {
|
||||
gobject_ffi::g_param_spec_double(
|
||||
name.to_glib_none().0,
|
||||
nick.to_glib_none().0,
|
||||
description.to_glib_none().0,
|
||||
min,
|
||||
max,
|
||||
default,
|
||||
mutability.into(),
|
||||
)
|
||||
}
|
||||
Property::String(name, nick, description, default, mutability) => {
|
||||
gobject_ffi::g_param_spec_string(
|
||||
name.to_glib_none().0,
|
||||
nick.to_glib_none().0,
|
||||
description.to_glib_none().0,
|
||||
default.to_glib_none().0,
|
||||
mutability.into(),
|
||||
)
|
||||
}
|
||||
Property::Boxed(name, nick, description, get_type, mutability) => {
|
||||
gobject_ffi::g_param_spec_boxed(
|
||||
name.to_glib_none().0,
|
||||
nick.to_glib_none().0,
|
||||
description.to_glib_none().0,
|
||||
get_type().to_glib(),
|
||||
mutability.into(),
|
||||
)
|
||||
}
|
||||
Property::Object(name, nick, description, get_type, mutability) => {
|
||||
gobject_ffi::g_param_spec_object(
|
||||
name.to_glib_none().0,
|
||||
nick.to_glib_none().0,
|
||||
description.to_glib_none().0,
|
||||
get_type().to_glib(),
|
||||
mutability.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "gst-plugin-audiofx"
|
||||
version = "0.1.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
repository = "https://github.com/sdroege/gst-plugin-rs"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
gobject-subclass = { path="../gobject-subclass" }
|
||||
gobject-subclass = { git = "https://github.com/sdroege/gobject-subclass" }
|
||||
gst-plugin = { path="../gst-plugin" }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { git = "https://github.com/sdroege/gstreamer-rs" }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gst-plugin-file"
|
||||
version = "0.1.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
repository = "https://github.com/sdroege/gst-plugin-rs"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gst-plugin-flv"
|
||||
version = "0.1.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
repository = "https://github.com/sdroege/gst-plugin-rs"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gst-plugin-http"
|
||||
version = "0.1.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
repository = "https://github.com/sdroege/gst-plugin-rs"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gst-plugin-simple"
|
||||
version = "0.1.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
repository = "https://github.com/sdroege/gst-plugin-rs"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
@ -8,7 +8,7 @@ license = "MIT/Apache-2.0"
|
|||
[dependencies]
|
||||
url = "1.1"
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gobject-subclass = { path="../gobject-subclass" }
|
||||
gobject-subclass = { git = "https://github.com/sdroege/gobject-subclass" }
|
||||
gst-plugin = { path="../gst-plugin" }
|
||||
gstreamer = { git = "https://github.com/sdroege/gstreamer-rs" }
|
||||
gstreamer-base = { git = "https://github.com/sdroege/gstreamer-rs" }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gst-plugin-togglerecord"
|
||||
version = "0.1.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
license = "LGPL-2.1+"
|
||||
|
||||
|
@ -8,7 +8,7 @@ license = "LGPL-2.1+"
|
|||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { git = "https://github.com/sdroege/gstreamer-rs" }
|
||||
gstreamer-video = { git = "https://github.com/sdroege/gstreamer-rs" }
|
||||
gobject-subclass = { path="../gobject-subclass" }
|
||||
gobject-subclass = { git = "https://github.com/sdroege/gobject-subclass" }
|
||||
gst-plugin = { path = "../gst-plugin" }
|
||||
gtk = { git = "https://github.com/gtk-rs/gtk", features = ["v3_6"], optional = true }
|
||||
gio = { git = "https://github.com/gtk-rs/gio", optional = true }
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "gst-plugin-tutorial"
|
||||
version = "0.1.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
repository = "https://github.com/sdroege/gst-plugin-rs"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
gobject-subclass = { path="../gobject-subclass" }
|
||||
gobject-subclass = { git = "https://github.com/sdroege/gobject-subclass" }
|
||||
gst-plugin = { path="../gst-plugin" }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { git = "https://github.com/sdroege/gstreamer-rs" }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gst-plugin"
|
||||
version = "0.1.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["multimedia"]
|
||||
description = "Infrastructure for writing GStreamer plugins in Rust"
|
||||
|
@ -15,7 +15,7 @@ keywords = ["gstreamer", "multimedia", "audio", "video", "gnome"]
|
|||
libc = "0.2"
|
||||
lazy_static = "1.0"
|
||||
byteorder = "1.0"
|
||||
gobject-subclass = { path="../gobject-subclass" }
|
||||
gobject-subclass = { git = "https://github.com/sdroege/gobject-subclass" }
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://github.com/sdroege/gstreamer-sys" }
|
||||
|
|
Loading…
Reference in a new issue