1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use smallvec::SmallVec;
4 
5 use crate::translate::*;
6 use crate::utils::is_canonical_pspec_name;
7 use crate::Closure;
8 use crate::SignalFlags;
9 use crate::Type;
10 use crate::Value;
11 
12 use std::ptr;
13 use std::sync::Mutex;
14 use std::{fmt, num::NonZeroU32};
15 
16 /// Builder for signals.
17 #[allow(clippy::type_complexity)]
18 pub struct SignalBuilder<'a> {
19     name: &'a str,
20     flags: SignalFlags,
21     param_types: &'a [SignalType],
22     return_type: SignalType,
23     class_handler: Option<
24         Box<dyn Fn(&SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static>,
25     >,
26     accumulator: Option<
27         Box<dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static>,
28     >,
29 }
30 
31 /// Signal metadata.
32 pub struct Signal {
33     name: String,
34     flags: SignalFlags,
35     param_types: Vec<SignalType>,
36     return_type: SignalType,
37     registration: Mutex<SignalRegistration>,
38 }
39 
40 /// Token passed to signal class handlers.
41 pub struct SignalClassHandlerToken(pub(super) *mut gobject_ffi::GTypeInstance);
42 
43 impl fmt::Debug for SignalClassHandlerToken {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>44     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
45         f.debug_tuple("SignalClassHandlerToken")
46             .field(&unsafe { crate::Object::from_glib_borrow(self.0 as *mut gobject_ffi::GObject) })
47             .finish()
48     }
49 }
50 
51 /// Signal invocation hint passed to signal accumulators.
52 #[repr(transparent)]
53 pub struct SignalInvocationHint(gobject_ffi::GSignalInvocationHint);
54 
55 impl SignalInvocationHint {
detail(&self) -> crate::Quark56     pub fn detail(&self) -> crate::Quark {
57         unsafe { from_glib(self.0.detail) }
58     }
59 
run_type(&self) -> SignalFlags60     pub fn run_type(&self) -> SignalFlags {
61         unsafe { from_glib(self.0.run_type) }
62     }
63 }
64 
65 impl fmt::Debug for SignalInvocationHint {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>66     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
67         f.debug_struct("SignalInvocationHint")
68             .field("detail", &self.detail())
69             .field("run_type", &self.run_type())
70             .finish()
71     }
72 }
73 
74 /// In-depth information of a specific signal
75 pub struct SignalQuery(gobject_ffi::GSignalQuery);
76 
77 impl SignalQuery {
78     /// The name of the signal.
signal_name<'a>(&self) -> &'a str79     pub fn signal_name<'a>(&self) -> &'a str {
80         unsafe {
81             let ptr = self.0.signal_name;
82             std::ffi::CStr::from_ptr(ptr).to_str().unwrap()
83         }
84     }
85 
86     /// The ID of the signal.
signal_id(&self) -> SignalId87     pub fn signal_id(&self) -> SignalId {
88         unsafe { SignalId::from_glib(self.0.signal_id) }
89     }
90 
91     /// The instance type this signal can be emitted for.
type_(&self) -> Type92     pub fn type_(&self) -> Type {
93         unsafe { from_glib(self.0.itype) }
94     }
95 
96     /// The signal flags.
flags(&self) -> SignalFlags97     pub fn flags(&self) -> SignalFlags {
98         unsafe { from_glib(self.0.signal_flags) }
99     }
100 
101     /// The return type for the user callback.
return_type(&self) -> SignalType102     pub fn return_type(&self) -> SignalType {
103         unsafe { from_glib(self.0.return_type) }
104     }
105 
106     /// The number of parameters the user callback takes.
n_params(&self) -> u32107     pub fn n_params(&self) -> u32 {
108         self.0.n_params
109     }
110 
111     /// The parameters for the user callback.
param_types(&self) -> SmallVec<[SignalType; 10]>112     pub fn param_types(&self) -> SmallVec<[SignalType; 10]> {
113         unsafe {
114             let types = self.0.param_types;
115             FromGlibContainerAsVec::from_glib_none_num_as_vec(types, self.n_params() as usize)
116                 .into_iter()
117                 .collect::<smallvec::SmallVec<[_; 10]>>()
118         }
119     }
120 }
121 
122 impl fmt::Debug for SignalQuery {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>123     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
124         f.debug_struct("SignalQuery")
125             .field("signal_name", &self.signal_name())
126             .field("type", &self.type_())
127             .field("flags", &self.flags())
128             .field("return_type", &self.return_type())
129             .field("param_types", &self.param_types())
130             .finish()
131     }
132 }
133 /// Signal ID.
134 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
135 pub struct SignalId(NonZeroU32);
136 
137 impl SignalId {
138     /// Create a new Signal Identifier.
139     ///
140     /// # Safety
141     ///
142     /// The caller has to ensure it's a valid signal identifier.
new(id: NonZeroU32) -> Self143     pub unsafe fn new(id: NonZeroU32) -> Self {
144         Self(id)
145     }
146 
147     #[doc(alias = "g_signal_parse_name")]
parse_name(name: &str, type_: Type, force_detail: bool) -> Option<(Self, crate::Quark)>148     pub fn parse_name(name: &str, type_: Type, force_detail: bool) -> Option<(Self, crate::Quark)> {
149         let mut signal_id = std::mem::MaybeUninit::uninit();
150         let mut detail_quark = std::mem::MaybeUninit::uninit();
151         unsafe {
152             let found: bool = from_glib(gobject_ffi::g_signal_parse_name(
153                 name.to_glib_none().0,
154                 type_.into_glib(),
155                 signal_id.as_mut_ptr(),
156                 detail_quark.as_mut_ptr(),
157                 force_detail.into_glib(),
158             ));
159 
160             if found {
161                 Some((
162                     from_glib(signal_id.assume_init()),
163                     crate::Quark::from_glib(detail_quark.assume_init()),
164                 ))
165             } else {
166                 None
167             }
168         }
169     }
170 
171     /// Find a SignalId by its `name`, and the `type` it connects to.
172     #[doc(alias = "g_signal_lookup")]
lookup(name: &str, type_: Type) -> Option<Self>173     pub fn lookup(name: &str, type_: Type) -> Option<Self> {
174         unsafe {
175             let signal_id = gobject_ffi::g_signal_lookup(name.to_glib_none().0, type_.into_glib());
176             if signal_id == 0 {
177                 None
178             } else {
179                 Some(Self::new(NonZeroU32::new_unchecked(signal_id)))
180             }
181         }
182     }
183 
184     /// Queries more in-depth information about the current signal.
185     #[doc(alias = "g_signal_query")]
query(&self) -> SignalQuery186     pub fn query(&self) -> SignalQuery {
187         unsafe {
188             let mut query_ptr = std::mem::MaybeUninit::uninit();
189             gobject_ffi::g_signal_query(self.into_glib(), query_ptr.as_mut_ptr());
190             let query = query_ptr.assume_init();
191             assert_ne!(query.signal_id, 0);
192             SignalQuery(query)
193         }
194     }
195 
196     /// Find the signal name.
197     #[doc(alias = "g_signal_name")]
name<'a>(&self) -> &'a str198     pub fn name<'a>(&self) -> &'a str {
199         unsafe {
200             let ptr = gobject_ffi::g_signal_name(self.into_glib());
201             std::ffi::CStr::from_ptr(ptr).to_str().unwrap()
202         }
203     }
204 }
205 
206 #[doc(hidden)]
207 impl FromGlib<u32> for SignalId {
from_glib(signal_id: u32) -> Self208     unsafe fn from_glib(signal_id: u32) -> Self {
209         assert_ne!(signal_id, 0);
210         Self::new(NonZeroU32::new_unchecked(signal_id))
211     }
212 }
213 
214 #[doc(hidden)]
215 impl IntoGlib for SignalId {
216     type GlibType = u32;
217 
into_glib(self) -> u32218     fn into_glib(self) -> u32 {
219         self.0.into()
220     }
221 }
222 
223 #[derive(Copy, Clone, Hash)]
224 pub struct SignalType(ffi::GType);
225 
226 impl SignalType {
with_static_scope(type_: Type) -> Self227     pub fn with_static_scope(type_: Type) -> Self {
228         Self(type_.into_glib() | gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT)
229     }
230 
static_scope(&self) -> bool231     pub fn static_scope(&self) -> bool {
232         (self.0 & gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT) != 0
233     }
234 
type_(&self) -> Type235     pub fn type_(&self) -> Type {
236         (*self).into()
237     }
238 }
239 
240 impl From<Type> for SignalType {
from(type_: Type) -> Self241     fn from(type_: Type) -> Self {
242         Self(type_.into_glib())
243     }
244 }
245 
246 impl From<SignalType> for Type {
from(type_: SignalType) -> Self247     fn from(type_: SignalType) -> Self {
248         // Remove the extra-bit used for G_SIGNAL_TYPE_STATIC_SCOPE
249         let type_ = type_.0 & (!gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT);
250         unsafe { from_glib(type_) }
251     }
252 }
253 
254 impl PartialEq<Type> for SignalType {
eq(&self, other: &Type) -> bool255     fn eq(&self, other: &Type) -> bool {
256         let type_: Type = (*self).into();
257         type_.eq(other)
258     }
259 }
260 
261 impl std::fmt::Debug for SignalType {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result262     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
263         let type_: Type = (*self).into();
264         f.debug_struct("SignalType")
265             .field("name", &type_.name())
266             .field("static_scope", &self.static_scope())
267             .finish()
268     }
269 }
270 
271 impl std::fmt::Display for SignalType {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result272     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
273         let type_: Type = (*self).into();
274         f.debug_struct("SignalType")
275             .field("name", &type_.name())
276             .field("static_scope", &self.static_scope())
277             .finish()
278     }
279 }
280 
281 #[doc(hidden)]
282 impl FromGlib<ffi::GType> for SignalType {
from_glib(type_: ffi::GType) -> Self283     unsafe fn from_glib(type_: ffi::GType) -> Self {
284         Self(type_)
285     }
286 }
287 
288 #[doc(hidden)]
289 impl IntoGlib for SignalType {
290     type GlibType = ffi::GType;
291 
into_glib(self) -> ffi::GType292     fn into_glib(self) -> ffi::GType {
293         self.0
294     }
295 }
296 
297 impl FromGlibContainerAsVec<Type, *const ffi::GType> for SignalType {
from_glib_none_num_as_vec(ptr: *const ffi::GType, num: usize) -> Vec<Self>298     unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GType, num: usize) -> Vec<Self> {
299         if num == 0 || ptr.is_null() {
300             return Vec::new();
301         }
302 
303         let mut res = Vec::with_capacity(num);
304         for i in 0..num {
305             res.push(from_glib(*ptr.add(i)));
306         }
307         res
308     }
309 
from_glib_container_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self>310     unsafe fn from_glib_container_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self> {
311         // Can't really free a *const
312         unimplemented!();
313     }
314 
from_glib_full_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self>315     unsafe fn from_glib_full_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self> {
316         // Can't really free a *const
317         unimplemented!();
318     }
319 }
320 
321 #[allow(clippy::type_complexity)]
322 enum SignalRegistration {
323     Unregistered {
324         class_handler: Option<
325             Box<
326                 dyn Fn(&SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
327             >,
328         >,
329         accumulator: Option<
330             Box<dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static>,
331         >,
332     },
333     Registered {
334         type_: Type,
335         signal_id: SignalId,
336     },
337 }
338 
339 impl<'a> SignalBuilder<'a> {
340     /// Run the signal class handler in the first emission stage.
run_first(mut self) -> Self341     pub fn run_first(mut self) -> Self {
342         self.flags |= SignalFlags::RUN_FIRST;
343         self
344     }
345 
346     /// Run the signal class handler in the third emission stage.
run_last(mut self) -> Self347     pub fn run_last(mut self) -> Self {
348         self.flags |= SignalFlags::RUN_LAST;
349         self
350     }
351 
352     /// Run the signal class handler in the last emission stage.
run_cleanup(mut self) -> Self353     pub fn run_cleanup(mut self) -> Self {
354         self.flags |= SignalFlags::RUN_CLEANUP;
355         self
356     }
357 
358     /// Signals being emitted for an object while currently being in emission for this very object
359     /// will not be emitted recursively, but instead cause the first emission to be restarted.
no_recurse(mut self) -> Self360     pub fn no_recurse(mut self) -> Self {
361         self.flags |= SignalFlags::NO_RECURSE;
362         self
363     }
364 
365     /// This signal supports "::detail" appendices to the signal name upon handler connections and
366     /// emissions.
detailed(mut self) -> Self367     pub fn detailed(mut self) -> Self {
368         self.flags |= SignalFlags::DETAILED;
369         self
370     }
371 
372     /// Action signals are signals that may freely be emitted on alive objects from user code.
action(mut self) -> Self373     pub fn action(mut self) -> Self {
374         self.flags |= SignalFlags::ACTION;
375         self
376     }
377 
378     /// No emissions hooks are supported for this signal.
no_hooks(mut self) -> Self379     pub fn no_hooks(mut self) -> Self {
380         self.flags |= SignalFlags::NO_HOOKS;
381         self
382     }
383 
384     /// Varargs signal emission will always collect the arguments, even if there are no signal
385     /// handlers connected.
must_collect(mut self) -> Self386     pub fn must_collect(mut self) -> Self {
387         self.flags |= SignalFlags::MUST_COLLECT;
388         self
389     }
390 
391     /// The signal is deprecated and will be removed in a future version.
deprecated(mut self) -> Self392     pub fn deprecated(mut self) -> Self {
393         self.flags |= SignalFlags::DEPRECATED;
394         self
395     }
396 
397     /// Explicitly set all flags.
398     ///
399     /// This overrides previously set flags on this builder.
flags(mut self, flags: SignalFlags) -> Self400     pub fn flags(mut self, flags: SignalFlags) -> Self {
401         self.flags = flags;
402         self
403     }
404 
405     /// Class handler for this signal.
class_handler< F: Fn(&SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static, >( mut self, func: F, ) -> Self406     pub fn class_handler<
407         F: Fn(&SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
408     >(
409         mut self,
410         func: F,
411     ) -> Self {
412         self.class_handler = Some(Box::new(func));
413         self
414     }
415 
416     /// Accumulator for the return values of the signal.
417     ///
418     /// This is called if multiple signal handlers are connected to the signal for accumulating the
419     /// return values into a single value.
accumulator< F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, >( mut self, func: F, ) -> Self420     pub fn accumulator<
421         F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,
422     >(
423         mut self,
424         func: F,
425     ) -> Self {
426         self.accumulator = Some(Box::new(func));
427         self
428     }
429 
430     /// Build the signal.
431     ///
432     /// This does not register the signal yet, which only happens as part of object type
433     /// registration.
build(self) -> Signal434     pub fn build(self) -> Signal {
435         let flags = if self.flags
436             & (SignalFlags::RUN_FIRST | SignalFlags::RUN_LAST | SignalFlags::RUN_CLEANUP)
437             == SignalFlags::empty()
438         {
439             self.flags | SignalFlags::RUN_LAST
440         } else {
441             self.flags
442         };
443 
444         Signal {
445             name: String::from(self.name),
446             flags,
447             param_types: self.param_types.to_vec(),
448             return_type: self.return_type,
449             registration: Mutex::new(SignalRegistration::Unregistered {
450                 class_handler: self.class_handler,
451                 accumulator: self.accumulator,
452             }),
453         }
454     }
455 }
456 
457 impl Signal {
458     /// Create a new builder for a signal.
builder<'a>( name: &'a str, param_types: &'a [SignalType], return_type: SignalType, ) -> SignalBuilder<'a>459     pub fn builder<'a>(
460         name: &'a str,
461         param_types: &'a [SignalType],
462         return_type: SignalType,
463     ) -> SignalBuilder<'a> {
464         assert!(
465             is_canonical_pspec_name(name),
466             "{} is not a valid canonical signal name",
467             name
468         );
469         SignalBuilder {
470             name,
471             param_types,
472             return_type,
473             flags: SignalFlags::empty(),
474             class_handler: None,
475             accumulator: None,
476         }
477     }
478 
479     /// Name of the signal.
name(&self) -> &str480     pub fn name(&self) -> &str {
481         &self.name
482     }
483 
484     /// Flags of the signal.
flags(&self) -> SignalFlags485     pub fn flags(&self) -> SignalFlags {
486         self.flags
487     }
488 
489     /// Parameter types of the signal.
param_types(&self) -> &[SignalType]490     pub fn param_types(&self) -> &[SignalType] {
491         &self.param_types
492     }
493 
494     /// Return type of the signal.
return_type(&self) -> SignalType495     pub fn return_type(&self) -> SignalType {
496         self.return_type
497     }
498 
499     /// Signal ID.
500     ///
501     /// This will panic if called before the signal was registered.
signal_id(&self) -> SignalId502     pub fn signal_id(&self) -> SignalId {
503         match &*self.registration.lock().unwrap() {
504             SignalRegistration::Unregistered { .. } => panic!("Signal not registered yet"),
505             SignalRegistration::Registered { signal_id, .. } => *signal_id,
506         }
507     }
508 
509     /// Type this signal was registered for.
510     ///
511     /// This will panic if called before the signal was registered.
type_(&self) -> Type512     pub fn type_(&self) -> Type {
513         match &*self.registration.lock().unwrap() {
514             SignalRegistration::Unregistered { .. } => panic!("Signal not registered yet"),
515             SignalRegistration::Registered { type_, .. } => *type_,
516         }
517     }
518 
register(&self, type_: Type)519     pub(super) fn register(&self, type_: Type) {
520         let mut registration = self.registration.lock().unwrap();
521 
522         let (class_handler, accumulator) = match &mut *registration {
523             SignalRegistration::Unregistered {
524                 class_handler,
525                 accumulator,
526             } => (class_handler.take(), accumulator.take()),
527             SignalRegistration::Registered { .. } => unreachable!(),
528         };
529 
530         let param_types = self
531             .param_types
532             .iter()
533             .map(|t| t.into_glib())
534             .collect::<Vec<_>>();
535 
536         let class_handler = class_handler.map(|class_handler| {
537             Closure::new(move |values| unsafe {
538                 let instance = gobject_ffi::g_value_get_object(values[0].to_glib_none().0);
539                 class_handler(&SignalClassHandlerToken(instance as *mut _), values)
540             })
541         });
542 
543         unsafe extern "C" fn accumulator_trampoline(
544             ihint: *mut gobject_ffi::GSignalInvocationHint,
545             return_accu: *mut gobject_ffi::GValue,
546             handler_return: *const gobject_ffi::GValue,
547             data: ffi::gpointer,
548         ) -> ffi::gboolean {
549             let accumulator = &**(data
550                 as *const *const (dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool
551                      + Send
552                      + Sync
553                      + 'static));
554             accumulator(
555                 &SignalInvocationHint(*ihint),
556                 &mut *(return_accu as *mut Value),
557                 &*(handler_return as *const Value),
558             )
559             .into_glib()
560         }
561 
562         let (accumulator, accumulator_trampoline) = if let Some(accumulator) = accumulator {
563             (
564                 Box::into_raw(Box::new(accumulator)),
565                 Some::<unsafe extern "C" fn(_, _, _, _) -> _>(accumulator_trampoline),
566             )
567         } else {
568             (ptr::null_mut(), None)
569         };
570 
571         unsafe {
572             let signal_id = gobject_ffi::g_signal_newv(
573                 self.name.to_glib_none().0,
574                 type_.into_glib(),
575                 self.flags.into_glib(),
576                 class_handler.to_glib_none().0,
577                 accumulator_trampoline,
578                 accumulator as ffi::gpointer,
579                 None,
580                 self.return_type.into_glib(),
581                 param_types.len() as u32,
582                 param_types.as_ptr() as *mut _,
583             );
584             *registration = SignalRegistration::Registered {
585                 type_,
586                 signal_id: SignalId::from_glib(signal_id),
587             };
588         }
589     }
590 }
591