Skip to content
This repository was archived by the owner on Jun 8, 2021. It is now read-only.

Commit f874842

Browse files
Merge pull request #192 from sdroege/signal-emit
Implement ObjectExt::emit() for emitting arbitrary signals
2 parents f5bfc69 + b262181 commit f874842

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

src/object.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use types::{self, StaticType};
99
use wrapper::{UnsafeFrom, Wrapper};
1010
use gobject_ffi;
1111
use std::mem;
12+
use std::ptr;
1213

1314
use Value;
1415
use Type;
@@ -355,6 +356,7 @@ pub trait ObjectExt {
355356

356357
fn connect<'a, N, F>(&self, signal_name: N, after: bool, callback: F) -> Result<u64, BoolError>
357358
where N: Into<&'a str>, F: Fn(&[Value]) -> Option<Value> + Send + Sync + 'static;
359+
fn emit<'a, N: Into<&'a str>>(&self, signal_name: N, args: &[&Value]) -> Result<Option<Value>, BoolError>;
358360
}
359361

360362
fn get_property_type<T: IsA<Object>>(obj: &T, property_name: &str) -> Option<Type> {
@@ -486,4 +488,59 @@ impl<T: IsA<Object>> ObjectExt for T {
486488
}
487489
}
488490
}
491+
492+
fn emit<'a, N: Into<&'a str>>(&self, signal_name: N, args: &[&Value]) -> Result<Option<Value>, BoolError> {
493+
let signal_name: &str = signal_name.into();
494+
unsafe {
495+
let type_ = self.get_type();
496+
497+
let mut signal_id = 0;
498+
let mut signal_detail = 0;
499+
500+
let found: bool = from_glib(gobject_ffi::g_signal_parse_name(signal_name.to_glib_none().0,
501+
type_.to_glib(), &mut signal_id,
502+
&mut signal_detail, true.to_glib()));
503+
504+
if !found {
505+
return Err(BoolError("Signal not found"));
506+
}
507+
508+
let mut details = mem::zeroed();
509+
gobject_ffi::g_signal_query(signal_id, &mut details);
510+
if details.signal_id != signal_id {
511+
return Err(BoolError("Signal not found"));
512+
}
513+
514+
if details.n_params != args.len() as u32 {
515+
return Err(BoolError("Incompatible number of arguments"));
516+
}
517+
518+
for i in 0..details.n_params {
519+
let arg_type = *(details.param_types.offset(i as isize)) & (!gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT);
520+
if arg_type != args[i as usize].type_().to_glib() {
521+
return Err(BoolError("Incompatible argument types"));
522+
}
523+
}
524+
525+
let mut c_args: Vec<gobject_ffi::GValue> = Vec::new();
526+
let instance = Value::from(self);
527+
c_args.push(ptr::read(instance.to_glib_none().0));
528+
for arg in args {
529+
c_args.push(ptr::read(arg.to_glib_none().0));
530+
}
531+
532+
let mut return_value = Value::uninitialized();
533+
if details.return_type != gobject_ffi::G_TYPE_NONE {
534+
gobject_ffi::g_value_init(return_value.to_glib_none_mut().0, details.return_type);
535+
}
536+
537+
gobject_ffi::g_signal_emitv(mut_override(c_args.as_ptr()), signal_id, signal_detail, return_value.to_glib_none_mut().0);
538+
539+
if return_value.type_() != Type::Unit && return_value.type_() != Type::Invalid {
540+
Ok(Some(return_value))
541+
} else {
542+
Ok(None)
543+
}
544+
}
545+
}
489546
}

0 commit comments

Comments
 (0)