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