1use glib::{ControlFlow, WeakRef, subclass::SignalId, translate::*};
4
5use crate::{
6 AccessibleRole, Shortcut, Widget, ffi, prelude::*, subclass::widget::WidgetActionIter,
7};
8
9pub trait WidgetExtManual: IsA<Widget> + 'static {
12 #[doc(alias = "gtk_widget_add_tick_callback")]
48 fn add_tick_callback<P: Fn(&Self, &gdk::FrameClock) -> ControlFlow + 'static>(
49 &self,
50 callback: P,
51 ) -> TickCallbackId {
52 let callback_data: Box<P> = Box::new(callback);
53
54 unsafe extern "C" fn callback_func<
55 O: IsA<Widget>,
56 P: Fn(&O, &gdk::FrameClock) -> ControlFlow + 'static,
57 >(
58 widget: *mut ffi::GtkWidget,
59 frame_clock: *mut gdk::ffi::GdkFrameClock,
60 user_data: glib::ffi::gpointer,
61 ) -> glib::ffi::gboolean {
62 unsafe {
63 let widget: Borrowed<Widget> = from_glib_borrow(widget);
64 let frame_clock = from_glib_borrow(frame_clock);
65 let callback: &P = &*(user_data as *mut _);
66 let res = (*callback)(widget.unsafe_cast_ref(), &frame_clock);
67 res.into_glib()
68 }
69 }
70 let callback = Some(callback_func::<Self, P> as _);
71
72 unsafe extern "C" fn notify_func<
73 O: IsA<Widget>,
74 P: Fn(&O, &gdk::FrameClock) -> ControlFlow + 'static,
75 >(
76 data: glib::ffi::gpointer,
77 ) {
78 unsafe {
79 let _callback: Box<P> = Box::from_raw(data as *mut _);
80 }
81 }
82 let destroy_call = Some(notify_func::<Self, P> as _);
83
84 let id = unsafe {
85 ffi::gtk_widget_add_tick_callback(
86 self.as_ref().to_glib_none().0,
87 callback,
88 Box::into_raw(callback_data) as *mut _,
89 destroy_call,
90 )
91 };
92 TickCallbackId {
93 id,
94 widget: self.upcast_ref().downgrade(),
95 }
96 }
97}
98
99impl<O: IsA<Widget>> WidgetExtManual for O {}
100
101#[derive(Debug)]
102pub struct TickCallbackId {
103 id: u32,
104 widget: WeakRef<Widget>,
105}
106
107impl PartialEq for TickCallbackId {
108 #[inline]
109 fn eq(&self, other: &Self) -> bool {
110 self.id == other.id
111 }
112}
113
114impl TickCallbackId {
115 #[doc(alias = "gtk_widget_remove_tick_callback")]
120 #[doc(alias = "remove_tick_callback")]
121 pub fn remove(self) {
122 if let Some(widget) = self.widget.upgrade() {
123 unsafe {
124 ffi::gtk_widget_remove_tick_callback(widget.to_glib_none().0, self.id);
125 }
126 }
127 }
128}
129
130pub trait WidgetClassManualExt {
149 #[doc(alias = "gtk_widget_class_add_shortcut")]
150 fn add_shortcut(&self, shortcut: &Shortcut);
151
152 #[doc(alias = "gtk_widget_class_add_binding_action")]
153 fn add_binding_action(&self, keyval: gdk::Key, mods: gdk::ModifierType, action_name: &str);
154
155 #[doc(alias = "gtk_widget_class_install_property_action")]
156 fn install_property_action(&self, action_name: &str, property_name: &str);
157
158 #[doc(alias = "gtk_widget_class_query_action")]
159 fn query_action(&self) -> WidgetActionIter;
160
161 #[doc(alias = "gtk_widget_class_get_activate_signal")]
162 #[doc(alias = "get_activate_signal")]
163 fn activate_signal(&self) -> Option<SignalId>;
164
165 #[doc(alias = "gtk_widget_class_get_layout_manager_type")]
166 #[doc(alias = "get_layout_manager_type")]
167 fn layout_manager_type(&self) -> glib::Type;
168
169 #[doc(alias = "gtk_widget_class_get_css_name")]
170 #[doc(alias = "get_css_name")]
171 fn css_name(&self) -> glib::GString;
172
173 #[doc(alias = "gtk_widget_class_get_accessible_role")]
174 #[doc(alias = "get_accessible_role")]
175 fn accessible_role(&self) -> AccessibleRole;
176}
177
178impl<T: IsA<Widget> + glib::object::IsClass> WidgetClassManualExt for glib::Class<T> {
179 fn add_shortcut(&self, shortcut: &Shortcut) {
180 unsafe {
181 let widget_class = self as *const Self as *mut ffi::GtkWidgetClass;
182 ffi::gtk_widget_class_add_shortcut(widget_class, shortcut.to_glib_none().0);
183 }
184 }
185
186 fn add_binding_action(&self, keyval: gdk::Key, mods: gdk::ModifierType, action_name: &str) {
187 let shortcut = Shortcut::new(
188 Some(crate::KeyvalTrigger::new(keyval, mods)),
189 Some(crate::NamedAction::new(action_name)),
190 );
191 self.add_shortcut(&shortcut);
192 }
193
194 fn install_property_action(&self, action_name: &str, property_name: &str) {
195 unsafe {
196 let widget_class = self as *const Self as *mut ffi::GtkWidgetClass;
197 ffi::gtk_widget_class_install_property_action(
198 widget_class,
199 action_name.to_glib_none().0,
200 property_name.to_glib_none().0,
201 );
202 }
203 }
204
205 fn query_action(&self) -> WidgetActionIter {
206 let widget_class = self as *const Self as *mut ffi::GtkWidgetClass;
207 WidgetActionIter::new(widget_class)
208 }
209
210 fn activate_signal(&self) -> Option<SignalId> {
211 unsafe {
212 let widget_class = self as *const Self as *mut ffi::GtkWidgetClass;
213 let signal_id = ffi::gtk_widget_class_get_activate_signal(widget_class);
214 if signal_id == 0 {
215 None
216 } else {
217 Some(from_glib(signal_id))
218 }
219 }
220 }
221
222 fn layout_manager_type(&self) -> glib::Type {
223 unsafe {
224 let widget_class = self as *const Self as *mut ffi::GtkWidgetClass;
225 from_glib(ffi::gtk_widget_class_get_layout_manager_type(widget_class))
226 }
227 }
228
229 fn css_name(&self) -> glib::GString {
230 unsafe {
231 let widget_class = self as *const Self as *mut ffi::GtkWidgetClass;
232 from_glib_none(ffi::gtk_widget_class_get_css_name(widget_class))
233 }
234 }
235
236 fn accessible_role(&self) -> AccessibleRole {
237 unsafe {
238 let widget_class = self as *const Self as *mut ffi::GtkWidgetClass;
239 from_glib(ffi::gtk_widget_class_get_accessible_role(widget_class))
240 }
241 }
242}