1 // Copyright 2017-2018, The Gtk-rs Project Developers.
2 // See the COPYRIGHT file at the top-level directory of this distribution.
3 // Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5 //! Module that contains the basic infrastructure for subclassing `GObject`.
6
7 use super::object::ObjectImpl;
8 use glib_sys;
9 use gobject_sys;
10 use object::{ObjectExt, ObjectType};
11 use std::fmt;
12 use std::marker;
13 use std::mem;
14 use std::ptr;
15 use translate::*;
16 use {Closure, IsA, IsClassFor, SignalFlags, StaticType, Type, Value};
17
18 /// A newly registered `glib::Type` that is currently still being initialized.
19 ///
20 /// This allows running additional type-setup functions, e.g. for implementing
21 /// interfaces on the type.
22 #[derive(Debug, PartialEq, Eq)]
23 pub struct InitializingType<T>(pub(crate) Type, pub(crate) marker::PhantomData<T>);
24
25 impl<T: ObjectSubclass> InitializingType<T> {
26 /// Adds an interface implementation for `I` to the type.
add_interface<I: IsImplementable<T>>(&mut self)27 pub fn add_interface<I: IsImplementable<T>>(&mut self) {
28 unsafe {
29 let iface_info = gobject_sys::GInterfaceInfo {
30 interface_init: Some(I::interface_init),
31 interface_finalize: None,
32 interface_data: ptr::null_mut(),
33 };
34 gobject_sys::g_type_add_interface_static(
35 self.0.to_glib(),
36 I::static_type().to_glib(),
37 &iface_info,
38 );
39 }
40 }
41 }
42
43 impl<T> ToGlib for InitializingType<T> {
44 type GlibType = glib_sys::GType;
45
to_glib(&self) -> glib_sys::GType46 fn to_glib(&self) -> glib_sys::GType {
47 self.0.to_glib()
48 }
49 }
50
51 /// Trait implemented by structs that implement a `GObject` C instance struct.
52 ///
53 /// The struct must be `#[repr(C)]` and have the parent type's instance struct
54 /// as the first field.
55 ///
56 /// See [`simple::InstanceStruct`] for a basic implementation of this that can
57 /// be used most of the time and should only not be used if additional fields are
58 /// required in the instance struct.
59 ///
60 /// [`simple::InstanceStruct`]: ../simple/struct.InstanceStruct.html
61 pub unsafe trait InstanceStruct: Sized + 'static {
62 /// Corresponding object subclass type for this instance struct.
63 type Type: ObjectSubclass;
64
65 /// Returns the implementation for from this instance struct, that
66 /// is the implementor of [`ObjectImpl`] or subtraits.
67 ///
68 /// [`ObjectImpl`]: ../object/trait.ObjectImpl.html
get_impl(&self) -> &Self::Type69 fn get_impl(&self) -> &Self::Type {
70 unsafe {
71 let data = Self::Type::type_data();
72 let private_offset = data.as_ref().private_offset;
73 let ptr: *const u8 = self as *const _ as *const u8;
74 let priv_ptr = ptr.offset(private_offset);
75 let imp = priv_ptr as *const Option<Self::Type>;
76
77 (*imp).as_ref().expect("No private struct")
78 }
79 }
80
81 /// Returns the class struct for this specific instance.
get_class(&self) -> &<Self::Type as ObjectSubclass>::Class82 fn get_class(&self) -> &<Self::Type as ObjectSubclass>::Class {
83 unsafe { &**(self as *const _ as *const *const <Self::Type as ObjectSubclass>::Class) }
84 }
85 }
86
87 /// Trait implemented by structs that implement a `GObject` C class struct.
88 ///
89 /// The struct must be `#[repr(C)]` and have the parent type's class struct
90 /// as the first field.
91 ///
92 /// See [`simple::ClassStruct`] for a basic implementation of this that can
93 /// be used most of the time and should only not be used if additional fields are
94 /// required in the class struct, e.g. for declaring new virtual methods.
95 ///
96 /// [`simple::ClassStruct`]: ../simple/struct.ClassStruct.html
97 pub unsafe trait ClassStruct: Sized + 'static {
98 /// Corresponding object subclass type for this class struct.
99 type Type: ObjectSubclass;
100
101 /// Override the vfuncs of all parent types.
102 ///
103 /// This is automatically called during type initialization.
override_vfuncs(&mut self) where <<Self::Type as ObjectSubclass>::ParentType as ObjectType>::RustClassType: IsSubclassable<Self::Type>,104 fn override_vfuncs(&mut self)
105 where
106 <<Self::Type as ObjectSubclass>::ParentType as ObjectType>::RustClassType:
107 IsSubclassable<Self::Type>,
108 {
109 unsafe {
110 let base = &mut *(self as *mut _
111 as *mut <<Self::Type as ObjectSubclass>::ParentType as ObjectType>::RustClassType);
112 base.override_vfuncs();
113 }
114 }
115 }
116
117 /// Trait for subclassable class structs.
118 pub unsafe trait IsSubclassable<T: ObjectSubclass>: IsClassFor {
119 /// Override the virtual methods of this class for the given subclass.
120 ///
121 /// This is automatically called during type initialization.
override_vfuncs(&mut self)122 fn override_vfuncs(&mut self);
123 }
124
125 /// Trait for implementable interfaces.
126 pub unsafe trait IsImplementable<T: ObjectSubclass>: StaticType {
127 /// Initializes the interface's virtual methods.
interface_init(iface: glib_sys::gpointer, _iface_data: glib_sys::gpointer)128 unsafe extern "C" fn interface_init(iface: glib_sys::gpointer, _iface_data: glib_sys::gpointer);
129 }
130
131 /// Type-specific data that is filled in during type creation.
132 pub struct TypeData {
133 #[doc(hidden)]
134 pub type_: Type,
135 #[doc(hidden)]
136 pub parent_class: glib_sys::gpointer,
137 #[doc(hidden)]
138 pub interface_data: *const Vec<(glib_sys::GType, glib_sys::gpointer)>,
139 #[doc(hidden)]
140 pub private_offset: isize,
141 }
142
143 unsafe impl Send for TypeData {}
144 unsafe impl Sync for TypeData {}
145
146 impl TypeData {
147 /// Returns the type ID.
get_type(&self) -> Type148 pub fn get_type(&self) -> Type {
149 self.type_
150 }
151
152 /// Returns a pointer to the native parent class.
153 ///
154 /// This is used for chaining up to the parent class' implementation
155 /// of virtual methods.
get_parent_class(&self) -> glib_sys::gpointer156 pub fn get_parent_class(&self) -> glib_sys::gpointer {
157 self.parent_class
158 }
159
160 /// Returns a pointer to the interface implementation specific data.
161 ///
162 /// This is used for interface implementations to store additional data.
get_interface_data(&self, type_: glib_sys::GType) -> glib_sys::gpointer163 pub fn get_interface_data(&self, type_: glib_sys::GType) -> glib_sys::gpointer {
164 unsafe {
165 if self.interface_data.is_null() {
166 return ptr::null_mut();
167 }
168
169 for &(t, p) in &(*self.interface_data) {
170 if t == type_ {
171 return p;
172 }
173 }
174
175 ptr::null_mut()
176 }
177 }
178
179 /// Returns the offset of the private struct in bytes relative to the
180 /// beginning of the instance struct.
get_private_offset(&self) -> isize181 pub fn get_private_offset(&self) -> isize {
182 self.private_offset
183 }
184 }
185
186 #[macro_export]
187 /// Macro for boilerplate of [`ObjectSubclass`] implementations.
188 ///
189 /// [`ObjectSubclass`]: subclass/types/trait.ObjectSubclass.html
190 macro_rules! glib_object_subclass {
191 () => {
192 fn type_data() -> ::std::ptr::NonNull<$crate::subclass::TypeData> {
193 static mut DATA: $crate::subclass::TypeData = $crate::subclass::TypeData {
194 type_: $crate::Type::Invalid,
195 parent_class: ::std::ptr::null_mut(),
196 interface_data: ::std::ptr::null_mut(),
197 private_offset: 0,
198 };
199
200 unsafe { ::std::ptr::NonNull::new_unchecked(&mut DATA) }
201 }
202
203 fn get_type() -> $crate::Type {
204 static ONCE: ::std::sync::Once = ::std::sync::Once::new();
205
206 ONCE.call_once(|| {
207 $crate::subclass::register_type::<Self>();
208 });
209
210 unsafe {
211 let data = Self::type_data();
212 let type_ = data.as_ref().get_type();
213 assert_ne!(type_, $crate::Type::Invalid);
214
215 type_
216 }
217 }
218 };
219 }
220
221 /// The central trait for subclassing a `GObject` type.
222 ///
223 /// Links together the type name, parent type and the instance and
224 /// class structs for type registration and allows subclasses to
225 /// hook into various steps of the type registration and initialization.
226 ///
227 /// See [`register_type`] for registering an implementation of this trait
228 /// with the type system.
229 ///
230 /// [`register_type`]: fn.register_type.html
231 pub trait ObjectSubclass: ObjectImpl + Sized + 'static {
232 /// `GObject` type name.
233 ///
234 /// This must be unique in the whole process.
235 const NAME: &'static str;
236
237 /// If this subclass is an abstract class or not.
238 ///
239 /// By default all subclasses are non-abstract types but setting this to `true` will create an
240 /// abstract class instead.
241 ///
242 /// Abstract classes can't be instantiated and require a non-abstract subclass.
243 ///
244 /// Optional.
245 const ABSTRACT: bool = false;
246
247 /// Parent Rust type to inherit from.
248 type ParentType: ObjectType
249 + FromGlibPtrBorrow<*mut <Self::ParentType as ObjectType>::GlibType>
250 + FromGlibPtrNone<*mut <Self::ParentType as ObjectType>::GlibType>;
251
252 /// The C instance struct.
253 ///
254 /// See [`simple::InstanceStruct`] for an basic instance struct that should be
255 /// used in most cases.
256 ///
257 /// [`simple::InstanceStruct`]: ../simple/struct.InstanceStruct.html
258 // TODO: Should default to simple::InstanceStruct<Self> once associated
259 // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661
260 type Instance: InstanceStruct<Type = Self>;
261
262 /// The C class struct.
263 ///
264 /// See [`simple::ClassStruct`] for an basic instance struct that should be
265 /// used in most cases.
266 ///
267 /// [`simple::ClassStruct`]: ../simple/struct.ClassStruct.html
268 // TODO: Should default to simple::ClassStruct<Self> once associated
269 // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661
270 type Class: ClassStruct<Type = Self>;
271
272 /// Storage for the type-specific data used during registration.
273 ///
274 /// This is usually generated by the [`glib_object_subclass!`] macro.
275 ///
276 /// [`glib_object_subclass!`]: ../../macro.glib_object_subclass.html
type_data() -> ptr::NonNull<TypeData>277 fn type_data() -> ptr::NonNull<TypeData>;
278
279 /// Returns the `glib::Type` ID of the subclass.
280 ///
281 /// This will register the type with the type system on the first call and is usually generated
282 /// by the [`glib_object_subclass!`] macro.
283 ///
284 /// [`glib_object_subclass!`]: ../../macro.glib_object_subclass.html
get_type() -> Type285 fn get_type() -> Type;
286
287 /// Returns the corresponding object instance.
get_instance(&self) -> Self::ParentType288 fn get_instance(&self) -> Self::ParentType {
289 unsafe {
290 let data = Self::type_data();
291 let type_ = data.as_ref().get_type();
292 assert_ne!(type_, Type::Invalid);
293
294 let offset = -data.as_ref().private_offset;
295 assert_ne!(offset, 0);
296
297 let ptr = self as *const Self as *const u8;
298 let ptr = ptr.offset(offset);
299 let ptr = ptr as *mut u8 as *mut <Self::ParentType as ObjectType>::GlibType;
300
301 from_glib_none(ptr)
302 }
303 }
304
305 /// Returns the implementation from an instance.
306 ///
307 /// Panics if called on an object of the wrong type.
from_instance<T: IsA<Self::ParentType>>(obj: &T) -> &Self308 fn from_instance<T: IsA<Self::ParentType>>(obj: &T) -> &Self {
309 unsafe {
310 let data = Self::type_data();
311 let type_ = data.as_ref().get_type();
312 assert_ne!(type_, Type::Invalid);
313
314 assert!(obj.get_type().is_a(&type_));
315
316 let ptr = obj.as_ptr() as *const Self::Instance;
317 (*ptr).get_impl()
318 }
319 }
320
321 /// Additional type initialization.
322 ///
323 /// This is called right after the type was registered and allows
324 /// subclasses to do additional type-specific initialization, e.g.
325 /// for implementing `GObject` interfaces.
326 ///
327 /// Optional
type_init(_type_: &mut InitializingType<Self>)328 fn type_init(_type_: &mut InitializingType<Self>) {}
329
330 /// Class initialization.
331 ///
332 /// This is called after `type_init` and before the first instance
333 /// of the subclass is created. Subclasses can use this to do class-
334 /// specific initialization, e.g. for installing properties or signals
335 /// on the class or calling class methods.
336 ///
337 /// Optional
class_init(_klass: &mut Self::Class)338 fn class_init(_klass: &mut Self::Class) {}
339
340 /// Constructor.
341 ///
342 /// This is called during object instantiation before further subclasses
343 /// are initialized, and should return a new instance of the subclass
344 /// private struct.
345 ///
346 /// Optional, either implement this or `new_with_class()`.
new() -> Self347 fn new() -> Self {
348 unimplemented!();
349 }
350
351 /// Constructor.
352 ///
353 /// This is called during object instantiation before further subclasses
354 /// are initialized, and should return a new instance of the subclass
355 /// private struct.
356 ///
357 /// Different to `new()` above it also gets the class of this type passed
358 /// to itself for providing additional context.
359 ///
360 /// Optional, either implement this or `new()`.
new_with_class(_klass: &Self::Class) -> Self361 fn new_with_class(_klass: &Self::Class) -> Self {
362 Self::new()
363 }
364 }
365
class_init<T: ObjectSubclass>( klass: glib_sys::gpointer, _klass_data: glib_sys::gpointer, ) where <<T as ObjectSubclass>::ParentType as ObjectType>::RustClassType: IsSubclassable<T>,366 unsafe extern "C" fn class_init<T: ObjectSubclass>(
367 klass: glib_sys::gpointer,
368 _klass_data: glib_sys::gpointer,
369 ) where
370 <<T as ObjectSubclass>::ParentType as ObjectType>::RustClassType: IsSubclassable<T>,
371 {
372 let mut data = T::type_data();
373
374 // We have to update the private struct offset once the class is actually
375 // being initialized.
376 {
377 let mut private_offset = data.as_ref().private_offset as i32;
378 gobject_sys::g_type_class_adjust_private_offset(klass, &mut private_offset);
379 (*data.as_mut()).private_offset = private_offset as isize;
380 }
381
382 // Set trampolines for the basic GObject virtual methods.
383 {
384 let gobject_klass = &mut *(klass as *mut gobject_sys::GObjectClass);
385
386 gobject_klass.finalize = Some(finalize::<T>);
387 }
388
389 // And finally peek the parent class struct (containing the parent class'
390 // implementations of virtual methods for chaining up), and call the subclass'
391 // class initialization function.
392 {
393 let klass = &mut *(klass as *mut T::Class);
394 let parent_class =
395 gobject_sys::g_type_class_peek_parent(klass as *mut _ as glib_sys::gpointer)
396 as *mut <T::ParentType as ObjectType>::GlibClassType;
397 assert!(!parent_class.is_null());
398
399 (*data.as_mut()).parent_class = parent_class as glib_sys::gpointer;
400
401 klass.override_vfuncs();
402 T::class_init(klass);
403 }
404 }
405
instance_init<T: ObjectSubclass>( obj: *mut gobject_sys::GTypeInstance, klass: glib_sys::gpointer, )406 unsafe extern "C" fn instance_init<T: ObjectSubclass>(
407 obj: *mut gobject_sys::GTypeInstance,
408 klass: glib_sys::gpointer,
409 ) {
410 glib_floating_reference_guard!(obj);
411
412 // Get offset to the storage of our private struct, create it
413 // and actually store it in that place.
414 let mut data = T::type_data();
415 let private_offset = (*data.as_mut()).private_offset;
416 let ptr: *mut u8 = obj as *mut _ as *mut u8;
417 let priv_ptr = ptr.offset(private_offset);
418 let imp_storage = priv_ptr as *mut Option<T>;
419
420 let klass = &*(klass as *const T::Class);
421
422 let imp = T::new_with_class(klass);
423
424 ptr::write(imp_storage, Some(imp));
425 }
426
finalize<T: ObjectSubclass>(obj: *mut gobject_sys::GObject)427 unsafe extern "C" fn finalize<T: ObjectSubclass>(obj: *mut gobject_sys::GObject) {
428 // Retrieve the private struct, take it out of its storage and
429 // drop it for freeing all associated memory.
430 let mut data = T::type_data();
431 let private_offset = (*data.as_mut()).private_offset;
432 let ptr: *mut u8 = obj as *mut _ as *mut u8;
433 let priv_ptr = ptr.offset(private_offset);
434 let imp_storage = priv_ptr as *mut Option<T>;
435
436 let imp = (*imp_storage).take().expect("No private struct");
437 drop(imp);
438
439 // Chain up to the parent class' finalize implementation, if any.
440 let parent_class = &*(data.as_ref().get_parent_class() as *const gobject_sys::GObjectClass);
441 if let Some(ref func) = parent_class.finalize {
442 func(obj);
443 }
444 }
445
446 /// Register a `glib::Type` ID for `T`.
447 ///
448 /// This must be called only once and will panic on a second call.
449 ///
450 /// The [`glib_object_subclass!`] macro will create a `get_type()` function around this, which will
451 /// ensure that it's only ever called once.
452 ///
453 /// [`glib_object_subclass!`]: ../../macro.glib_object_subclass.html
register_type<T: ObjectSubclass>() -> Type where <<T as ObjectSubclass>::ParentType as ObjectType>::RustClassType: IsSubclassable<T>,454 pub fn register_type<T: ObjectSubclass>() -> Type
455 where
456 <<T as ObjectSubclass>::ParentType as ObjectType>::RustClassType: IsSubclassable<T>,
457 {
458 unsafe {
459 use std::ffi::CString;
460
461 let type_info = gobject_sys::GTypeInfo {
462 class_size: mem::size_of::<T::Class>() as u16,
463 base_init: None,
464 base_finalize: None,
465 class_init: Some(class_init::<T>),
466 class_finalize: None,
467 class_data: ptr::null_mut(),
468 instance_size: mem::size_of::<T::Instance>() as u16,
469 n_preallocs: 0,
470 instance_init: Some(instance_init::<T>),
471 value_table: ptr::null(),
472 };
473
474 let type_name = CString::new(T::NAME).unwrap();
475 if gobject_sys::g_type_from_name(type_name.as_ptr()) != gobject_sys::G_TYPE_INVALID {
476 panic!(
477 "Type {} has already been registered",
478 type_name.to_str().unwrap()
479 );
480 }
481
482 let type_ = from_glib(gobject_sys::g_type_register_static(
483 <T::ParentType as StaticType>::static_type().to_glib(),
484 type_name.as_ptr(),
485 &type_info,
486 if T::ABSTRACT {
487 gobject_sys::G_TYPE_FLAG_ABSTRACT
488 } else {
489 0
490 },
491 ));
492
493 let mut data = T::type_data();
494 (*data.as_mut()).type_ = type_;
495 let private_offset =
496 gobject_sys::g_type_add_instance_private(type_.to_glib(), mem::size_of::<Option<T>>());
497 (*data.as_mut()).private_offset = private_offset as isize;
498
499 T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData));
500
501 type_
502 }
503 }
504
add_signal( type_: glib_sys::GType, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, )505 pub(crate) unsafe fn add_signal(
506 type_: glib_sys::GType,
507 name: &str,
508 flags: SignalFlags,
509 arg_types: &[Type],
510 ret_type: Type,
511 ) {
512 let arg_types = arg_types.iter().map(ToGlib::to_glib).collect::<Vec<_>>();
513
514 gobject_sys::g_signal_newv(
515 name.to_glib_none().0,
516 type_,
517 flags.to_glib(),
518 ptr::null_mut(),
519 None,
520 ptr::null_mut(),
521 None,
522 ret_type.to_glib(),
523 arg_types.len() as u32,
524 arg_types.as_ptr() as *mut _,
525 );
526 }
527
528 #[repr(C)]
529 pub struct SignalInvocationHint(gobject_sys::GSignalInvocationHint);
530
531 impl SignalInvocationHint {
detail(&self) -> ::Quark532 pub fn detail(&self) -> ::Quark {
533 from_glib(self.0.detail)
534 }
535
run_type(&self) -> SignalFlags536 pub fn run_type(&self) -> SignalFlags {
537 from_glib(self.0.run_type)
538 }
539 }
540
541 impl fmt::Debug for SignalInvocationHint {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>542 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
543 f.debug_struct("SignalInvocationHint")
544 .field("detail", &self.detail())
545 .field("run_type", &self.run_type())
546 .finish()
547 }
548 }
549
add_signal_with_accumulator<F>( type_: glib_sys::GType, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, accumulator: F, ) where F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,550 pub(crate) unsafe fn add_signal_with_accumulator<F>(
551 type_: glib_sys::GType,
552 name: &str,
553 flags: SignalFlags,
554 arg_types: &[Type],
555 ret_type: Type,
556 accumulator: F,
557 ) where
558 F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,
559 {
560 let arg_types = arg_types.iter().map(ToGlib::to_glib).collect::<Vec<_>>();
561
562 let accumulator: Box<F> = Box::new(accumulator);
563
564 unsafe extern "C" fn accumulator_trampoline<
565 F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,
566 >(
567 ihint: *mut gobject_sys::GSignalInvocationHint,
568 return_accu: *mut gobject_sys::GValue,
569 handler_return: *const gobject_sys::GValue,
570 data: glib_sys::gpointer,
571 ) -> glib_sys::gboolean {
572 let accumulator: &F = &*(data as *const &F);
573 accumulator(
574 &SignalInvocationHint(*ihint),
575 &mut *(return_accu as *mut Value),
576 &*(handler_return as *const Value),
577 )
578 .to_glib()
579 }
580
581 gobject_sys::g_signal_newv(
582 name.to_glib_none().0,
583 type_,
584 flags.to_glib(),
585 ptr::null_mut(),
586 Some(accumulator_trampoline::<F>),
587 Box::into_raw(accumulator) as glib_sys::gpointer,
588 None,
589 ret_type.to_glib(),
590 arg_types.len() as u32,
591 arg_types.as_ptr() as *mut _,
592 );
593 }
594
595 pub struct SignalClassHandlerToken(*mut gobject_sys::GTypeInstance);
596
597 impl fmt::Debug for SignalClassHandlerToken {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>598 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
599 f.debug_tuple("SignalClassHandlerToken")
600 .field(&unsafe { ::Object::from_glib_borrow(self.0 as *mut gobject_sys::GObject) })
601 .finish()
602 }
603 }
604
add_signal_with_class_handler<F>( type_: glib_sys::GType, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, class_handler: F, ) where F: Fn(&SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,605 pub(crate) unsafe fn add_signal_with_class_handler<F>(
606 type_: glib_sys::GType,
607 name: &str,
608 flags: SignalFlags,
609 arg_types: &[Type],
610 ret_type: Type,
611 class_handler: F,
612 ) where
613 F: Fn(&SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
614 {
615 let arg_types = arg_types.iter().map(ToGlib::to_glib).collect::<Vec<_>>();
616 let class_handler = Closure::new(move |values| {
617 let instance = gobject_sys::g_value_get_object(values[0].to_glib_none().0);
618 class_handler(&SignalClassHandlerToken(instance as *mut _), values)
619 });
620
621 gobject_sys::g_signal_newv(
622 name.to_glib_none().0,
623 type_,
624 flags.to_glib(),
625 class_handler.to_glib_none().0,
626 None,
627 ptr::null_mut(),
628 None,
629 ret_type.to_glib(),
630 arg_types.len() as u32,
631 arg_types.as_ptr() as *mut _,
632 );
633 }
634
add_signal_with_class_handler_and_accumulator<F, G>( type_: glib_sys::GType, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, class_handler: F, accumulator: G, ) where F: Fn(&SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static, G: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,635 pub(crate) unsafe fn add_signal_with_class_handler_and_accumulator<F, G>(
636 type_: glib_sys::GType,
637 name: &str,
638 flags: SignalFlags,
639 arg_types: &[Type],
640 ret_type: Type,
641 class_handler: F,
642 accumulator: G,
643 ) where
644 F: Fn(&SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
645 G: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,
646 {
647 let arg_types = arg_types.iter().map(ToGlib::to_glib).collect::<Vec<_>>();
648
649 let class_handler = Closure::new(move |values| {
650 let instance = gobject_sys::g_value_get_object(values[0].to_glib_none().0);
651 class_handler(&SignalClassHandlerToken(instance as *mut _), values)
652 });
653 let accumulator: Box<G> = Box::new(accumulator);
654
655 unsafe extern "C" fn accumulator_trampoline<
656 G: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,
657 >(
658 ihint: *mut gobject_sys::GSignalInvocationHint,
659 return_accu: *mut gobject_sys::GValue,
660 handler_return: *const gobject_sys::GValue,
661 data: glib_sys::gpointer,
662 ) -> glib_sys::gboolean {
663 let accumulator: &G = &*(data as *const &G);
664 accumulator(
665 &SignalInvocationHint(*ihint),
666 &mut *(return_accu as *mut Value),
667 &*(handler_return as *const Value),
668 )
669 .to_glib()
670 }
671
672 gobject_sys::g_signal_newv(
673 name.to_glib_none().0,
674 type_,
675 flags.to_glib(),
676 class_handler.to_glib_none().0,
677 Some(accumulator_trampoline::<G>),
678 Box::into_raw(accumulator) as glib_sys::gpointer,
679 None,
680 ret_type.to_glib(),
681 arg_types.len() as u32,
682 arg_types.as_ptr() as *mut _,
683 );
684 }
685
signal_override_class_handler<F>( name: &str, type_: glib_sys::GType, class_handler: F, ) where F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,686 pub(crate) unsafe fn signal_override_class_handler<F>(
687 name: &str,
688 type_: glib_sys::GType,
689 class_handler: F,
690 ) where
691 F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
692 {
693 let class_handler = Closure::new(move |values| {
694 let instance = gobject_sys::g_value_get_object(values[0].to_glib_none().0);
695 class_handler(&SignalClassHandlerToken(instance as *mut _), values)
696 });
697
698 let mut signal_id = 0;
699 let found: bool = from_glib(gobject_sys::g_signal_parse_name(
700 name.to_glib_none().0,
701 type_,
702 &mut signal_id,
703 ptr::null_mut(),
704 false.to_glib(),
705 ));
706
707 if !found {
708 panic!("Signal '{}' not found", name);
709 }
710
711 gobject_sys::g_signal_override_class_closure(signal_id, type_, class_handler.to_glib_none().0);
712 }
713
signal_chain_from_overridden( instance: *mut gobject_sys::GTypeInstance, token: &SignalClassHandlerToken, values: &[Value], ) -> Option<Value>714 pub(crate) unsafe fn signal_chain_from_overridden(
715 instance: *mut gobject_sys::GTypeInstance,
716 token: &SignalClassHandlerToken,
717 values: &[Value],
718 ) -> Option<Value> {
719 assert_eq!(instance, token.0);
720 let mut result = Value::uninitialized();
721 gobject_sys::g_signal_chain_from_overridden(
722 values.as_ptr() as *mut Value as *mut gobject_sys::GValue,
723 result.to_glib_none_mut().0,
724 );
725 if result.type_() != Type::Unit && result.type_() != Type::Invalid {
726 Some(result)
727 } else {
728 None
729 }
730 }
731