1 // Take a look at the license at the top of the repository in the LICENSE file.
2
3 //! `IMPL` Low level signal support.
4
5 use crate::object::ObjectType;
6 use crate::translate::{from_glib, FromGlib, IntoGlib, ToGlibPtr};
7 use ffi::{gboolean, gpointer};
8 use gobject_ffi::{self, GCallback};
9 use libc::{c_char, c_ulong, c_void};
10 use std::mem;
11 use std::num::NonZeroU64;
12
13 /// The id of a signal that is returned by `connect`.
14 ///
15 /// This type does not implement `Clone` to prevent disconnecting
16 /// the same signal handler multiple times.
17 ///
18 /// ```ignore
19 /// use glib::SignalHandlerId;
20 /// use gtk::prelude::*;
21 /// use std::cell::RefCell;
22 ///
23 /// struct Button {
24 /// widget: gtk::Button,
25 /// clicked_handler_id: RefCell<Option<SignalHandlerId>>,
26 /// }
27 ///
28 /// impl Button {
29 /// fn new() -> Self {
30 /// let widget = gtk::Button::new();
31 /// let clicked_handler_id = RefCell::new(Some(widget.connect_clicked(|_button| {
32 /// // Do something.
33 /// })));
34 /// Self {
35 /// widget,
36 /// clicked_handler_id,
37 /// }
38 /// }
39 ///
40 /// fn disconnect(&self) {
41 /// if let Some(id) = self.clicked_handler_id.borrow_mut().take() {
42 /// self.widget.disconnect(id)
43 /// }
44 /// }
45 /// }
46 /// ```
47 #[derive(Debug, Eq, PartialEq)]
48 pub struct SignalHandlerId(NonZeroU64);
49
50 impl SignalHandlerId {
51 /// Returns the internal signal handler ID.
as_raw(&self) -> libc::c_ulong52 pub unsafe fn as_raw(&self) -> libc::c_ulong {
53 self.0.get() as libc::c_ulong
54 }
55 }
56
57 impl FromGlib<c_ulong> for SignalHandlerId {
58 #[inline]
from_glib(val: c_ulong) -> Self59 unsafe fn from_glib(val: c_ulong) -> Self {
60 assert_ne!(val, 0);
61 Self(NonZeroU64::new_unchecked(val as u64))
62 }
63 }
64
65 /// Whether to propagate the signal to the default handler.
66 ///
67 /// Don't inhibit default handlers without a reason, they're usually helpful.
68 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
69 pub struct Inhibit(pub bool);
70
71 #[doc(hidden)]
72 impl IntoGlib for Inhibit {
73 type GlibType = gboolean;
74
75 #[inline]
into_glib(self) -> gboolean76 fn into_glib(self) -> gboolean {
77 self.0.into_glib()
78 }
79 }
80
connect_raw<F>( receiver: *mut gobject_ffi::GObject, signal_name: *const c_char, trampoline: GCallback, closure: *mut F, ) -> SignalHandlerId81 pub unsafe fn connect_raw<F>(
82 receiver: *mut gobject_ffi::GObject,
83 signal_name: *const c_char,
84 trampoline: GCallback,
85 closure: *mut F,
86 ) -> SignalHandlerId {
87 unsafe extern "C" fn destroy_closure<F>(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
88 // destroy
89 Box::<F>::from_raw(ptr as *mut _);
90 }
91 assert_eq!(mem::size_of::<*mut F>(), mem::size_of::<gpointer>());
92 assert!(trampoline.is_some());
93 let handle = gobject_ffi::g_signal_connect_data(
94 receiver,
95 signal_name,
96 trampoline,
97 closure as *mut _,
98 Some(destroy_closure::<F>),
99 0,
100 );
101 assert!(handle > 0);
102 from_glib(handle)
103 }
104
105 #[doc(alias = "g_signal_handler_block")]
signal_handler_block<T: ObjectType>(instance: &T, handler_id: &SignalHandlerId)106 pub fn signal_handler_block<T: ObjectType>(instance: &T, handler_id: &SignalHandlerId) {
107 unsafe {
108 gobject_ffi::g_signal_handler_block(
109 instance.as_object_ref().to_glib_none().0,
110 handler_id.as_raw(),
111 );
112 }
113 }
114
115 #[doc(alias = "g_signal_handler_unblock")]
signal_handler_unblock<T: ObjectType>(instance: &T, handler_id: &SignalHandlerId)116 pub fn signal_handler_unblock<T: ObjectType>(instance: &T, handler_id: &SignalHandlerId) {
117 unsafe {
118 gobject_ffi::g_signal_handler_unblock(
119 instance.as_object_ref().to_glib_none().0,
120 handler_id.as_raw(),
121 );
122 }
123 }
124
125 #[allow(clippy::needless_pass_by_value)]
126 #[doc(alias = "g_signal_handler_disconnect")]
signal_handler_disconnect<T: ObjectType>(instance: &T, handler_id: SignalHandlerId)127 pub fn signal_handler_disconnect<T: ObjectType>(instance: &T, handler_id: SignalHandlerId) {
128 unsafe {
129 gobject_ffi::g_signal_handler_disconnect(
130 instance.as_object_ref().to_glib_none().0,
131 handler_id.as_raw(),
132 );
133 }
134 }
135
136 #[doc(alias = "g_signal_stop_emission_by_name")]
signal_stop_emission_by_name<T: ObjectType>(instance: &T, signal_name: &str)137 pub fn signal_stop_emission_by_name<T: ObjectType>(instance: &T, signal_name: &str) {
138 unsafe {
139 gobject_ffi::g_signal_stop_emission_by_name(
140 instance.as_object_ref().to_glib_none().0,
141 signal_name.to_glib_none().0,
142 );
143 }
144 }
145
146 #[doc(alias = "g_signal_has_handler_pending")]
signal_has_handler_pending<T: ObjectType>( instance: &T, signal_id: crate::subclass::SignalId, detail: Option<crate::Quark>, may_be_blocked: bool, ) -> bool147 pub fn signal_has_handler_pending<T: ObjectType>(
148 instance: &T,
149 signal_id: crate::subclass::SignalId,
150 detail: Option<crate::Quark>,
151 may_be_blocked: bool,
152 ) -> bool {
153 unsafe {
154 from_glib(gobject_ffi::g_signal_has_handler_pending(
155 instance.as_object_ref().to_glib_none().0,
156 signal_id.into_glib(),
157 detail.map_or(0, |d| d.into_glib()),
158 may_be_blocked.into_glib(),
159 ))
160 }
161 }
162