Backport official GLib iterator safety fix for Linux desktop
This commit is contained in:
1 parent
43c43ebdc9
commit
8ef874c609
133 files changed
+55342
-2
No files matched your search
@@ -0,0 +1,715 @@
|
||||
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||
|
||||
use std::{fmt, num::NonZeroU32, ptr, sync::Mutex};
|
||||
|
||||
use crate::{
|
||||
prelude::*, translate::*, utils::is_canonical_pspec_name, Closure, IntoGStr, SignalFlags, Type,
|
||||
Value,
|
||||
};
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Builder for signals.
|
||||
#[allow(clippy::type_complexity)]
|
||||
#[must_use = "The builder must be built to be used"]
|
||||
pub struct SignalBuilder {
|
||||
name: String,
|
||||
flags: SignalFlags,
|
||||
param_types: Vec<SignalType>,
|
||||
return_type: SignalType,
|
||||
class_handler: Option<
|
||||
Box<dyn Fn(&SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static>,
|
||||
>,
|
||||
accumulator: Option<
|
||||
Box<dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static>,
|
||||
>,
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Signal metadata.
|
||||
pub struct Signal {
|
||||
name: String,
|
||||
flags: SignalFlags,
|
||||
param_types: Vec<SignalType>,
|
||||
return_type: SignalType,
|
||||
registration: Mutex<SignalRegistration>,
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Token passed to signal class handlers.
|
||||
pub struct SignalClassHandlerToken(
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Instance for which the signal is emitted.
|
||||
pub(super) *mut gobject_ffi::GTypeInstance,
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Return type.
|
||||
pub(super) Type,
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Arguments value array.
|
||||
pub(super) *const Value,
|
||||
);
|
||||
|
||||
impl fmt::Debug for SignalClassHandlerToken {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
f.debug_struct("SignalClassHandlerToken")
|
||||
.field("type", &unsafe {
|
||||
crate::Object::from_glib_borrow(self.0 as *mut gobject_ffi::GObject)
|
||||
})
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Signal invocation hint passed to signal accumulators.
|
||||
#[repr(transparent)]
|
||||
pub struct SignalInvocationHint(gobject_ffi::GSignalInvocationHint);
|
||||
|
||||
impl SignalInvocationHint {
|
||||
#[inline]
|
||||
pub fn detail(&self) -> Option<crate::Quark> {
|
||||
unsafe { try_from_glib(self.0.detail).ok() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn run_type(&self) -> SignalFlags {
|
||||
unsafe { from_glib(self.0.run_type) }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SignalInvocationHint {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
f.debug_struct("SignalInvocationHint")
|
||||
.field("detail", &self.detail())
|
||||
.field("run_type", &self.run_type())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// In-depth information of a specific signal
|
||||
pub struct SignalQuery(gobject_ffi::GSignalQuery);
|
||||
|
||||
unsafe impl Send for SignalQuery {}
|
||||
unsafe impl Sync for SignalQuery {}
|
||||
|
||||
impl SignalQuery {
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// The name of the signal.
|
||||
#[inline]
|
||||
pub fn signal_name<'a>(&self) -> &'a str {
|
||||
unsafe {
|
||||
let ptr = self.0.signal_name;
|
||||
std::ffi::CStr::from_ptr(ptr).to_str().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// The ID of the signal.
|
||||
#[inline]
|
||||
pub fn signal_id(&self) -> SignalId {
|
||||
unsafe { SignalId::from_glib(self.0.signal_id) }
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// The instance type this signal can be emitted for.
|
||||
#[inline]
|
||||
pub fn type_(&self) -> Type {
|
||||
unsafe { from_glib(self.0.itype) }
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// The signal flags.
|
||||
#[inline]
|
||||
pub fn flags(&self) -> SignalFlags {
|
||||
unsafe { from_glib(self.0.signal_flags) }
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// The return type for the user callback.
|
||||
#[inline]
|
||||
pub fn return_type(&self) -> SignalType {
|
||||
unsafe { from_glib(self.0.return_type) }
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// The number of parameters the user callback takes.
|
||||
#[inline]
|
||||
pub fn n_params(&self) -> u32 {
|
||||
self.0.n_params
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// The parameters for the user callback.
|
||||
#[inline]
|
||||
pub fn param_types(&self) -> &[SignalType] {
|
||||
if self.n_params() == 0 {
|
||||
return &[];
|
||||
}
|
||||
|
||||
unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
self.0.param_types as *const SignalType,
|
||||
self.0.n_params as usize,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SignalQuery {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
f.debug_struct("SignalQuery")
|
||||
.field("signal_name", &self.signal_name())
|
||||
.field("type", &self.type_())
|
||||
.field("flags", &self.flags())
|
||||
.field("return_type", &self.return_type())
|
||||
.field("param_types", &self.param_types())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Signal ID.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct SignalId(NonZeroU32);
|
||||
|
||||
impl SignalId {
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a new Signal Identifier.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller has to ensure it's a valid signal identifier.
|
||||
#[inline]
|
||||
pub unsafe fn new(id: NonZeroU32) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
|
||||
#[doc(alias = "g_signal_parse_name")]
|
||||
#[inline]
|
||||
pub fn parse_name(
|
||||
name: &str,
|
||||
type_: Type,
|
||||
force_detail: bool,
|
||||
) -> Option<(Self, Option<crate::Quark>)> {
|
||||
let mut signal_id = std::mem::MaybeUninit::uninit();
|
||||
let mut detail_quark = std::mem::MaybeUninit::uninit();
|
||||
unsafe {
|
||||
let found: bool = name.run_with_gstr(|name| {
|
||||
from_glib(gobject_ffi::g_signal_parse_name(
|
||||
name.as_ptr(),
|
||||
type_.into_glib(),
|
||||
signal_id.as_mut_ptr(),
|
||||
detail_quark.as_mut_ptr(),
|
||||
force_detail.into_glib(),
|
||||
))
|
||||
});
|
||||
|
||||
if found {
|
||||
Some((
|
||||
from_glib(signal_id.assume_init()),
|
||||
crate::Quark::try_from_glib(detail_quark.assume_init()).ok(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Find a SignalId by its `name`, and the `type` it connects to.
|
||||
#[doc(alias = "g_signal_lookup")]
|
||||
#[inline]
|
||||
pub fn lookup(name: &str, type_: Type) -> Option<Self> {
|
||||
unsafe {
|
||||
let signal_id = name.run_with_gstr(|name| {
|
||||
gobject_ffi::g_signal_lookup(name.as_ptr(), type_.into_glib())
|
||||
});
|
||||
if signal_id == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(Self::new(NonZeroU32::new_unchecked(signal_id)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Queries more in-depth information about the current signal.
|
||||
#[doc(alias = "g_signal_query")]
|
||||
#[inline]
|
||||
pub fn query(&self) -> SignalQuery {
|
||||
unsafe {
|
||||
let mut query_ptr = std::mem::MaybeUninit::uninit();
|
||||
gobject_ffi::g_signal_query(self.into_glib(), query_ptr.as_mut_ptr());
|
||||
let query = query_ptr.assume_init();
|
||||
debug_assert_ne!(query.signal_id, 0);
|
||||
SignalQuery(query)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Find the signal name.
|
||||
#[doc(alias = "g_signal_name")]
|
||||
#[inline]
|
||||
pub fn name<'a>(&self) -> &'a str {
|
||||
unsafe {
|
||||
let ptr = gobject_ffi::g_signal_name(self.into_glib());
|
||||
std::ffi::CStr::from_ptr(ptr).to_str().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl FromGlib<u32> for SignalId {
|
||||
#[inline]
|
||||
unsafe fn from_glib(signal_id: u32) -> Self {
|
||||
debug_assert_ne!(signal_id, 0);
|
||||
Self::new(NonZeroU32::new_unchecked(signal_id))
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl IntoGlib for SignalId {
|
||||
type GlibType = u32;
|
||||
|
||||
#[inline]
|
||||
fn into_glib(self) -> u32 {
|
||||
self.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct SignalType(ffi::GType);
|
||||
|
||||
impl SignalType {
|
||||
#[inline]
|
||||
pub fn with_static_scope(type_: Type) -> Self {
|
||||
Self(type_.into_glib() | gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn static_scope(&self) -> bool {
|
||||
(self.0 & gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT) != 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn type_(&self) -> Type {
|
||||
(*self).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Type> for SignalType {
|
||||
#[inline]
|
||||
fn from(type_: Type) -> Self {
|
||||
Self(type_.into_glib())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignalType> for Type {
|
||||
#[inline]
|
||||
fn from(type_: SignalType) -> Self {
|
||||
// Remove the extra-bit used for G_SIGNAL_TYPE_STATIC_SCOPE
|
||||
let type_ = type_.0 & (!gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT);
|
||||
unsafe { from_glib(type_) }
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Type> for SignalType {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Type) -> bool {
|
||||
let type_: Type = (*self).into();
|
||||
type_.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SignalType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let type_: Type = (*self).into();
|
||||
f.debug_struct("SignalType")
|
||||
.field("name", &type_.name())
|
||||
.field("static_scope", &self.static_scope())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SignalType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let type_: Type = (*self).into();
|
||||
f.debug_struct("SignalType")
|
||||
.field("name", &type_.name())
|
||||
.field("static_scope", &self.static_scope())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl FromGlib<ffi::GType> for SignalType {
|
||||
#[inline]
|
||||
unsafe fn from_glib(type_: ffi::GType) -> Self {
|
||||
Self(type_)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl IntoGlib for SignalType {
|
||||
type GlibType = ffi::GType;
|
||||
|
||||
#[inline]
|
||||
fn into_glib(self) -> ffi::GType {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
enum SignalRegistration {
|
||||
Unregistered {
|
||||
class_handler: Option<
|
||||
Box<
|
||||
dyn Fn(&SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
|
||||
>,
|
||||
>,
|
||||
accumulator: Option<
|
||||
Box<dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static>,
|
||||
>,
|
||||
},
|
||||
Registered {
|
||||
type_: Type,
|
||||
signal_id: SignalId,
|
||||
},
|
||||
}
|
||||
|
||||
impl SignalBuilder {
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// The signal's parameters.
|
||||
pub fn param_types(
|
||||
mut self,
|
||||
param_types: impl IntoIterator<Item = impl Into<SignalType>>,
|
||||
) -> Self {
|
||||
self.param_types = param_types
|
||||
.into_iter()
|
||||
.map(|t| t.into())
|
||||
.collect::<Vec<_>>();
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// The signal's returned value type.
|
||||
pub fn return_type<T: StaticType>(mut self) -> Self {
|
||||
self.return_type = T::static_type().into();
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// The signal's returned value type.
|
||||
pub fn return_type_from(mut self, type_: impl Into<SignalType>) -> Self {
|
||||
self.return_type = type_.into();
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Run the signal class handler in the first emission stage.
|
||||
pub fn run_first(mut self) -> Self {
|
||||
self.flags |= SignalFlags::RUN_FIRST;
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Run the signal class handler in the third emission stage.
|
||||
pub fn run_last(mut self) -> Self {
|
||||
self.flags |= SignalFlags::RUN_LAST;
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Run the signal class handler in the last emission stage.
|
||||
pub fn run_cleanup(mut self) -> Self {
|
||||
self.flags |= SignalFlags::RUN_CLEANUP;
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Signals being emitted for an object while currently being in emission for this very object
|
||||
/// will not be emitted recursively, but instead cause the first emission to be restarted.
|
||||
pub fn no_recurse(mut self) -> Self {
|
||||
self.flags |= SignalFlags::NO_RECURSE;
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// This signal supports "::detail" appendices to the signal name upon handler connections and
|
||||
/// emissions.
|
||||
pub fn detailed(mut self) -> Self {
|
||||
self.flags |= SignalFlags::DETAILED;
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Action signals are signals that may freely be emitted on alive objects from user code.
|
||||
pub fn action(mut self) -> Self {
|
||||
self.flags |= SignalFlags::ACTION;
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// No emissions hooks are supported for this signal.
|
||||
pub fn no_hooks(mut self) -> Self {
|
||||
self.flags |= SignalFlags::NO_HOOKS;
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Varargs signal emission will always collect the arguments, even if there are no signal
|
||||
/// handlers connected.
|
||||
pub fn must_collect(mut self) -> Self {
|
||||
self.flags |= SignalFlags::MUST_COLLECT;
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// The signal is deprecated and will be removed in a future version.
|
||||
pub fn deprecated(mut self) -> Self {
|
||||
self.flags |= SignalFlags::DEPRECATED;
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Explicitly set all flags.
|
||||
///
|
||||
/// This overrides previously set flags on this builder.
|
||||
pub fn flags(mut self, flags: SignalFlags) -> Self {
|
||||
self.flags = flags;
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Class handler for this signal.
|
||||
pub fn class_handler<
|
||||
F: Fn(&SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
|
||||
>(
|
||||
mut self,
|
||||
func: F,
|
||||
) -> Self {
|
||||
self.class_handler = Some(Box::new(func));
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Accumulator for the return values of the signal.
|
||||
///
|
||||
/// This is called if multiple signal handlers are connected to the signal for accumulating the
|
||||
/// return values into a single value.
|
||||
pub fn accumulator<
|
||||
F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,
|
||||
>(
|
||||
mut self,
|
||||
func: F,
|
||||
) -> Self {
|
||||
self.accumulator = Some(Box::new(func));
|
||||
self
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Build the signal.
|
||||
///
|
||||
/// This does not register the signal yet, which only happens as part of object type
|
||||
/// registration.
|
||||
#[must_use = "Signal returned from the builder must be used for it to be registered"]
|
||||
pub fn build(self) -> Signal {
|
||||
let flags = if self.flags
|
||||
& (SignalFlags::RUN_FIRST | SignalFlags::RUN_LAST | SignalFlags::RUN_CLEANUP)
|
||||
== SignalFlags::empty()
|
||||
{
|
||||
self.flags | SignalFlags::RUN_LAST
|
||||
} else {
|
||||
self.flags
|
||||
};
|
||||
|
||||
Signal {
|
||||
name: self.name,
|
||||
flags,
|
||||
param_types: self.param_types.to_vec(),
|
||||
return_type: self.return_type,
|
||||
registration: Mutex::new(SignalRegistration::Unregistered {
|
||||
class_handler: self.class_handler,
|
||||
accumulator: self.accumulator,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Signal {
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Create a new builder for a signal.
|
||||
pub fn builder(name: &str) -> SignalBuilder {
|
||||
assert!(
|
||||
is_canonical_pspec_name(name),
|
||||
"{name} is not a valid canonical signal name",
|
||||
);
|
||||
SignalBuilder {
|
||||
name: name.to_owned(),
|
||||
param_types: Vec::default(),
|
||||
return_type: <()>::static_type().into(),
|
||||
flags: SignalFlags::empty(),
|
||||
class_handler: None,
|
||||
accumulator: None,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Name of the signal.
|
||||
#[inline]
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Flags of the signal.
|
||||
#[inline]
|
||||
pub fn flags(&self) -> SignalFlags {
|
||||
self.flags
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Parameter types of the signal.
|
||||
#[inline]
|
||||
pub fn param_types(&self) -> &[SignalType] {
|
||||
&self.param_types
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Return type of the signal.
|
||||
#[inline]
|
||||
pub fn return_type(&self) -> SignalType {
|
||||
self.return_type
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Signal ID.
|
||||
///
|
||||
/// This will panic if called before the signal was registered.
|
||||
#[inline]
|
||||
pub fn signal_id(&self) -> SignalId {
|
||||
match &*self.registration.lock().unwrap() {
|
||||
SignalRegistration::Unregistered { .. } => panic!("Signal not registered yet"),
|
||||
SignalRegistration::Registered { signal_id, .. } => *signal_id,
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Type this signal was registered for.
|
||||
///
|
||||
/// This will panic if called before the signal was registered.
|
||||
#[inline]
|
||||
pub fn type_(&self) -> Type {
|
||||
match &*self.registration.lock().unwrap() {
|
||||
SignalRegistration::Unregistered { .. } => panic!("Signal not registered yet"),
|
||||
SignalRegistration::Registered { type_, .. } => *type_,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn register(&self, type_: Type) {
|
||||
let mut registration = self.registration.lock().unwrap();
|
||||
|
||||
let (class_handler, accumulator) = match &mut *registration {
|
||||
SignalRegistration::Unregistered {
|
||||
class_handler,
|
||||
accumulator,
|
||||
} => (class_handler.take(), accumulator.take()),
|
||||
SignalRegistration::Registered { .. } => unreachable!(),
|
||||
};
|
||||
|
||||
let return_type = self.return_type;
|
||||
|
||||
let class_handler = class_handler.map(|class_handler| {
|
||||
Closure::new(move |values| unsafe {
|
||||
let instance = gobject_ffi::g_value_get_object(values[0].to_glib_none().0);
|
||||
let res = class_handler(&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
|
||||
})
|
||||
});
|
||||
|
||||
unsafe extern "C" fn accumulator_trampoline(
|
||||
ihint: *mut gobject_ffi::GSignalInvocationHint,
|
||||
return_accu: *mut gobject_ffi::GValue,
|
||||
handler_return: *const gobject_ffi::GValue,
|
||||
data: ffi::gpointer,
|
||||
) -> ffi::gboolean {
|
||||
let accumulator = &*(data as *const (
|
||||
SignalType,
|
||||
Box<
|
||||
dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>,
|
||||
));
|
||||
|
||||
let return_accu = &mut *(return_accu as *mut Value);
|
||||
let handler_return = &*(handler_return as *const Value);
|
||||
let return_type = accumulator.0;
|
||||
|
||||
assert!(
|
||||
handler_return.type_().is_a(return_type.into()),
|
||||
"Signal has a return type of {} but handler returned {}",
|
||||
Type::from(return_type),
|
||||
handler_return.type_()
|
||||
);
|
||||
|
||||
let res = (accumulator.1)(&SignalInvocationHint(*ihint), return_accu, handler_return)
|
||||
.into_glib();
|
||||
|
||||
assert!(
|
||||
return_accu.type_().is_a(return_type.into()),
|
||||
"Signal has a return type of {} but accumulator returned {}",
|
||||
Type::from(return_type),
|
||||
return_accu.type_()
|
||||
);
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
let (accumulator, accumulator_trampoline) =
|
||||
if let (Some(accumulator), true) = (accumulator, return_type != Type::UNIT) {
|
||||
(
|
||||
Box::into_raw(Box::new((return_type, accumulator))),
|
||||
Some::<unsafe extern "C" fn(_, _, _, _) -> _>(accumulator_trampoline),
|
||||
)
|
||||
} else {
|
||||
(ptr::null_mut(), None)
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let signal_id = gobject_ffi::g_signal_newv(
|
||||
self.name.to_glib_none().0,
|
||||
type_.into_glib(),
|
||||
self.flags.into_glib(),
|
||||
class_handler.to_glib_none().0,
|
||||
accumulator_trampoline,
|
||||
accumulator as ffi::gpointer,
|
||||
None,
|
||||
return_type.into_glib(),
|
||||
self.param_types.len() as u32,
|
||||
self.param_types.as_ptr() as *mut _,
|
||||
);
|
||||
*registration = SignalRegistration::Registered {
|
||||
type_,
|
||||
signal_id: SignalId::from_glib(signal_id),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user